Created
March 25, 2020 16:43
-
-
Save okunokentaro/7f2595ca2a8b88fe08fa6e754d2a5574 to your computer and use it in GitHub Desktop.
JSerがRubyやるので備忘録
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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