Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save okunokentaro/7f2595ca2a8b88fe08fa6e754d2a5574 to your computer and use it in GitHub Desktop.
Save okunokentaro/7f2595ca2a8b88fe08fa6e754d2a5574 to your computer and use it in GitHub Desktop.
JSerがRubyやるので備忘録
2015/06/05 にQiitaに投稿した記事のアーカイブです
---
@armorik83です。なにやら最近は完全に[Angular芸人](http://qiita.com/armorik83/items/5542daed0c408cb9f605)と呼ばれるようになったのですが、一方でRuby知識はド素人、今まで避け続けてきたもんだから仕方がない。で、思い立ったので学び始めます。理由はご想像にお任せ。
以下の文体ですが、他言語にはある程度長けていても、Rubyは一切やったことがない、というレベルを想定しています。比較対象は主にJavaScript ES6、自分用なので雑です。
# バージョン
JavaScriptのバージョンは`ES n`で表現するが、基本的にはブラウザの実装次第。Rubyはインタプリタ自体のバージョンを指す。インタプリタといっても、Ruby 1.9からは[YARV](http://ja.wikipedia.org/wiki/YARV)というVM上で動いてるらしい。
最新は執筆時点で`2.1.6`, `2.2.2`。この2系統あたりを見ておけばいいのかな、[`1.9.3`はサポート終了してるらしい](https://www.ruby-lang.org/ja/news/2015/02/23/support-for-ruby-1-9-3-has-ended/)ので、今回は`2.0`以降に絞って学ぶ。
## 読むもの
ざっと[`2.0.0`のマニュアル](http://docs.ruby-lang.org/ja/2.0.0/doc/index.html)を読んでいく。`2.1`, `2.2`前提で学ぶとやんごとなき事情でハマる恐れがあるので、あとで知識を上書きする。
リンク先は全て2.0.0にしているので、参照される方は注意。
## 目安にするコーディングスタイル
右も左も分かってないので、とりあえず以下のものを参照する。
> https://github.com/cookpad/styleguide/blob/master/ruby.ja.md
# 特徴
『[はじめに](http://docs.ruby-lang.org/ja/2.0.0/doc/spec=2fintro.html)』の引用。調べなくても想像つくものと、つかないものに分ける。
## 想像つく
- インタプリタ
- 変数に型が無い (動的型付け)
- ユーザによるメモリ管理が不要
- 全てがオブジェクト
- クラス、継承、メソッド
- ブロック付きメソッド呼び出し(イテレータ)
- クロージャ(※でもJSとは全然違った)
- 強力な文字列操作/正規表現
- 多倍長整数
- 例外処理機能
- OSへの直接アクセス
## 想像つかん
- 変数宣言が不要
- 特異メソッド
- モジュールによるMix-in
- ダイナミックローディング
スクリプト言語はJavaScriptとPHPの経験があるので、ざっと見て馴染みないなーというものを下に分けた。CLIでのHello Worldとかはパスだパス!
# 基礎構文
## ステートメント
1行1ステートメント。セミコロンなし。1行2ステートメント以上書きたいときに限りセミコロンで区切る。
|JS|Ruby|
|:--|:--|
|いつも付けてる|要らない|
## コメント行
`#`を使う。行末まで有効。行頭、行中でも構わない。
|JS|Ruby|
|:--|:--|
|`//`|`#`|
## コメントブロック
`=begin`, `=end`を使う。**埋め込みドキュメント**と名付けられていて、JSの`/*...*/`とは想定が異なる。
|JS|Ruby|
|:--|:--|
|`/*`, `*/`|`=begin`, `=end`|
## 変数と定数
> Ruby の変数と定数の種別は変数名の最初の一文字によって、ローカル変数、インスタンス変数、クラス変数、 グローバル変数、定数のいずれかに区別されます。
> http://docs.ruby-lang.org/ja/2.0.0/doc/spec=2fvariables.html
ローカル変数だけでなく、インスタンス変数も格納された時点から有効になる。クラス変数が`static`で宣言できるのはTypeScriptの特徴。グローバル変数の比較は一例。
|JS|Ruby|TypeScript|
|:--|:--|:--|
|`var foobar = 42;`|`foobar = 42`||
|`this.instanceVar = 42;`|`@instanceVar = 42`||
|`ClassName.classVar = 42;`|`@@classVar = 42`|`static classVar = 42;`|
|`const FOO_BAR = 42;`|`FOO_BAR = 42`||
|`window.foobar = 42;`|`$foobar = 42`||
## ローカル変数のスコープ
> 宣言した位置からその変数が宣言されたブロック、メソッド定義、またはクラス/モジュール定義の終りまでです。
> http://docs.ruby-lang.org/ja/2.0.0/doc/spec=2fvariables.html
以下も参照する。
> https://github.com/cookpad/styleguide/blob/master/ruby.ja.md#変数
## 全てがオブジェクト
一例。
- [String](http://ruby-doc.org/core-2.2.2/String.html)
- [Integer](http://ruby-doc.org/core-2.2.2/Integer.html)
- [Float](http://ruby-doc.org/core-2.2.2/Float.html)
- [Regexp](http://ruby-doc.org/core-2.2.2/Regexp.html)
- [Time](http://ruby-doc.org/core-2.2.2/Time.html)
数値型は`Integer`, `Float`になるんだな。[`Numeric`](http://docs.ruby-lang.org/ja/2.1.0/class/Numeric.html)はAbstractなので後回し。
## 演算子
> http://docs.ruby-lang.org/ja/2.0.0/doc/symref.html
- `+` `-` `*` `/` `%` おなじみ
- `**` 累乗
- `+=` 自己代入([可能な構文はここ](http://docs.ruby-lang.org/ja/1.9.3/doc/spec=2foperator.html#selfassign))
- `<` `>` `<=` `>=` 比較
- `&&` `||` `!` and, or, not
- `&` `|` `<<` `>>` `^` `~` ビット演算
## 文字列
> http://docs.ruby-lang.org/ja/2.0.0/doc/spec=2fliteral.html#string
シングルクオートとダブルクオートに挙動の違いがあるのはPHPと同じ。JSではES6よりTemplate stringsが使える
```js:js
var name = 'armorik83';
var str1 = 'hello ${name}'; // hello ${name}
var str2 = "hello ${name}"; // hello ${name}
var str3 = `hello ${name}`; // hello armorik83
```
```rb:ruby
name = 'armorik83'
str1 = 'hello #{name}' # hello \#{name}
str2 = "hello #{name}" # hello armorik83
```
## 正規表現
`/abc/`で正規表現リテラルなのはJSと同じ。[Docs](http://docs.ruby-lang.org/ja/2.0.0/doc/spec=2fregexp.html)をざっと見た感じJSとそんなに変わらないが、モードにいくつか違いがありそうだ。
## 破壊的メソッドと値渡し・参照渡し
> http://docs.ruby-lang.org/ja/2.0.0/doc/spec=2fcall.html
メソッド名の後に`!`が付くと破壊的メソッド。公式が行っているものの慣習らしく、言語仕様として定められているわけではない。
あと、[Rubyでは常に値渡し](http://magazine.rubyist.net/?0032-CallByValueAndCallByReference)らしい。ただ、オブジェクトなので[参照の値渡し](http://magazine.rubyist.net/?0032-CallByValueAndCallByReference#l4)ということだ。副作用でハマったらこの辺を疑うってことで。
## 真偽値を返すメソッド
> 慣用的に、真偽値を返すタイプのメソッドを示すために使われます。
> http://docs.ruby-lang.org/ja/2.0.0/doc/symref.html#q
JSとかで、キャメルケースで`isFoo`とかするやつ。慣習的にRubyでは`isFoo`しない。
|なにがしの言語|Ruby|
|:--|:--|
|`isEmpty()`|`empty?`|
## 配列
> http://docs.ruby-lang.org/ja/2.0.0/class/Array.html
```js:js
var arr = [1, 2, 3];
arr[1] = 4;
console.log(arr); // [1, 4, 3]
```
```rb:ruby
arr = [1, 2, 3]
arr[1] = 4;
p arr # [1, 4, 3]
```
### 範囲指定
> http://docs.ruby-lang.org/ja/2.0.0/class/Range.html
こういう構文だと覚えるより、Rangeリテラルを与えていると考えた方がよさそう。
```js:js
var arr = [1, 2, 3, 4];
console.log(arr[1..3]); // SyntaxError: Unexpected number
console.log(arr[1...3]); // SyntaxError: Unexpected number
console.log(arr.slice(1, 4)); // [2, 3, 4]
console.log(arr.slice(1, 3)); // [2, 3]
```
```rb:ruby
arr = [1, 2, 3, 4]
p arr[1..3] # [2, 3, 4]
p arr[1...3] # [2, 3]
```
### 逆から
```js:js
var arr = [1, 2, 3, 4];
console.log(arr.slice(-1)[0]); // 4
console.log(arr.slice(-2, -1)[0]); // 3
```
```rb:ruby
arr = [1, 2, 3, 4]
p arr[-1] # 4
p arr[-2] # 3
```
おおっ、JS地味につらい…。(比較にすらなってない)
## %記法
```rb:ruby
words = ['foo', 'bar', 'baz']
words = %w(foo bar baz)
```
`Array<String>`は下のようにも書ける。[コーディングスタイル](https://github.com/cookpad/styleguide/blob/master/ruby.ja.md#配列)ではこちらを推奨していた。
## ハッシュ
> http://docs.ruby-lang.org/ja/2.0.0/class/Hash.html
JSでいうObject型、他の言語でいう連想配列、辞書のあたり。
```js:js
var price1 = {'apple': 2000, 'orange': 1500, 'grape': 3000};
console.log(price1['apple']);
var price2 = {apple: 2000, orange: 1500, grape: 3000};
console.log(price2.apple);
```
```rb:ruby
price1 = { 'apple' => 2000, 'orange' => 1500, 'grape' => 3000 }
p price1['apple'] # 2000
price2 = { apple: 2000, orange: 1500, grape: 3000 }
p price2[:apple] # 2000
```
`apple:`で宣言すると、参照時は`:apple`という[Symbolリテラル](http://docs.ruby-lang.org/ja/2.0.0/class/Symbol.html)形式なのが特徴的。
# 制御構造
## if, unless
> Rubyでは`if`を繋げるのは`elsif`であり、`else if`(Cのように)でも `elif`(shのように)でもないことに注意してください。
> http://docs.ruby-lang.org/ja/2.0.0/doc/spec=2fcontrol.html#if
`end`ってのもJSからすると驚きがデカい。
```rb:ruby
if cond
# ...
elsif cond
# ...
else
# ...
end
```
後置`if`という書き方もある。
```rb:ruby
if user.active?
send_mail_to(user)
end
send_mail_to(user) if user.active?
```
三項演算子はちゃんとある。`if`内代入もある。個人的には`if`内代入は使わない。
`unless`は鳥肌もので、JSで`if (!arg) { return; }`のように書くことに馴染んでいる自分としては、こんな逆転する構文は面倒にしか見えない。
コーディングスタイルで推奨どころか**SHOULD**扱いなので、そういうものかーと思いながら見てる。
## case
```rb:ruby
case cond
when val1
# ...
when val2
# ...
else
# ...
end
```
## for
```js:js
var hash = {a: 1, b: 2, c: 3};
for (let k in hash) {
if (hash.hasOwnProperty(k)) {
let v = hash[k];
console.log(k, v);
}
}
```
```rb:ruby
hash = {a: 1, b: 2, c: 3}
for k, v in hash
p k, v
end
```
意外なことにJSの`for`文(`for (var i; i < len; i++)`みたいな)とRubyの`for`文は全く別物だった。JSの`for-in`文が近い。
### その他の繰り返し
`while`文はまだ馴染みがあるが、`times`, `upto`, `downto`などのメソッドはかなり新鮮。慣れるまでは毎回調べそう。
上の例は`each`メソッドでこうも書ける。`do`必須。
```rb:ruby
hash = {a: 1, b: 2, c: 3}
hash.each do |k, v|
p k, v
end
```
# 関数・クラス・メソッド宣言
## def
比較に使うJSはオーソドックスな書き方にしている。
```js:js
function square(n) {
return n * n;
}
console.log(square(3)); // 9
```
```rb:ruby
def square n
n * n
end
p square(3) # 9
```
## class, initialize
JSの`constructor`のように、`def initialize`を定義する。
```js:js
class Component {
constructor(store) {
this.store = store;
}
}
```
```rb:ruby
class Component
def initialize store
@store = store
end
end
```
## newとアクセサ
```js:js
class User {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
var u = new User('armorik83', 83);
console.log(u.name); // "armorik83"
console.log(u.age); // 83
```
```rb:ruby
class User
def initialize name, age
@name = name
@age = age
end
end
u = User.new('armorik83', 83)
p u.name # NoMethodError
p u.age # NoMethodError
```
`NoMethodError`となるので、アクセサの宣言が必要らしい。
- `attr_accessor`
- `attr_reader`
- `attr_writer`
> http://docs.ruby-lang.org/ja/2.0.0/class/Module.html#I_ATTR_ACCESSOR
```rb:ruby
class User
def initialize name, age
@name = name
@age = age
end
attr_accessor :name, :age
end
u = User.new('armorik83', 83)
p u.name # "armorik83"
p u.age # 83
```
なるほど。
## インスタンスメソッド
```js:js
class User {
constructor(name, age) {
this.name = name;
this.age = age;
}
isAdult() {
return 20 <= this.age;
}
}
var u = new User('armorik83', 83);
console.log(u.isAdult()); // true
var c = new User('child', 8);
console.log(c.isAdult()); // false
```
```rb:ruby
class User
def initialize name, age
@name = name
@age = age
end
def adult?
20 <= @age
end
end
u = User.new('armorik83', 83)
p u.adult? # true
c = User.new('child', 8)
p c.adult? # false
```
ここだけ見ると、OOPL経験者なら戸惑うところは無さそう。
## クラスメソッド、クラス変数
```rb:ruby
class ClassName
@@classVar = 42
def ClassName.methodName
# ...
end
end
```
クラス変数は[コーディングスタイル](https://github.com/cookpad/styleguide/blob/master/ruby.ja.md#変数)で**MUST NOT**だった。
## 継承
```rb:ruby
class Base
def initialize prop
@prop = prop
end
def print
p @prop
end
end
class Concrete < Base
def initialize prop, childProp
super prop
@childProp = childProp
end
def printAll
p @prop, @childProp
end
end
base = Base.new('a')
base.print
c = Concrete.new('b', 2)
c.print
c.printAll
```
あまりいい例とは言えん。
# 馴染みがなくて用途が分かってないもの
以下雑多。
## Proc
クロージャっぽいもの? Rubyに第一級関数は無いようで、Procで実現しているようだ。アプリケーションを書いたことがないので想像が付いてない。
## 特異メソッド
インスタンスにメソッドを足せるらしい。使い道想像できず。
## Mix-in
必要になったら覚えたい。
## 2.1, 2.2の新機能
公式ソースではないので、ググるキッカケ的に。
- [Ruby 2.1.0リリース!注目の新機能を見てみましょう](http://techracho.bpsinc.jp/baba/2013_12_26/15026)
- [Ruby2.2の変更点と新機能の紹介](http://allabout.co.jp/gm/gc/452102/)
# ちょっとは読めるようになった
そもそも、どの解説記事を読むにも構文が分かっておらず読めなかったので、今回はその問題を潰す目的。Rubyらしい文化、Ruby最高ってなる機能はまだまだ全然分かってないので、まあぼちぼち…。
以下まさかりやオススメ記事が並ぶと大変嬉しいです。それでは。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment