Railsチュートリアル 第4章 - Rails風味のRubyを学ぶ …titleヘルパーが読めるようになるまで

# `rails console`

Railsチュートリアル本文にあるとおり、これから「`rails console`をツールとしてRubyを学んでいこう」というパートになります。

## `~/.irbrc`を編集し、irbに[Railsチュートリアルの推奨設定](https://railstutorial.jp/chapters/rails_flavored_ruby?version=5.1#sec-strings_and_methods)を適用する

irbにおけるRailsチュートリアルの推奨設定の内容は以下です。

* irbのプロンプトを簡潔な表示に置き換える
* irbの自動インデント機能をオフにする

当該設定を適用するためには、Railsが動作している環境で`~/.irbrc`を編集する必要があります。

私がセットアップしたDocker環境では、nanoエディタがインストールされておらず、先にインストールする必要がありました。当該Docker環境のOSはDebian 9.5なので、nanoエディタは以下の手順でインストールできました。

```:bash
# apt-get update
# apt-get install -y nano
```

nanoエディタをインストールしたら、`~/.irbrc`の内容を以下のように書き換え、変更を保存します。

```:~/.irbrc
IRB.conf[:PROMPT_MODE] = :SIMPLE
IRB.conf[:AUTO_INDENT_MODE] = false
```

```:bash
# pwd
/var/www/sample_app

# rails console
Running via Spring preloader in process 948
Loading development environment (Rails 5.1.6)
>> 
```

Railsチュートリアルの推奨設定が適用されたようです。

## 文字列の連結

ここから、`rails console`の中でRuby言語の世界を探索してみることにします。

```irb
>> first_name = "Michael"
=> "Michael"
>> "#{first_name} Hertl"
=> "Michael Hertl"
```

↑「文字列の式展開」というやり方があるのですね。実は初めて知りました。

```irb
>> first_name = "Michael"
=> "Michael"
>> last_name = "Hertl"
=> "Hertl"
>> first_name + " " + last_name
=> "Michael Hertl"
>> "#{first_name} #{last_name}"
=> "Michael Hertl"
```

↑「文字列変数と空白文字と文字列変数を結合する」「式展開を使って文字列変数を結合する」両方の方式で文字列変数を結合してみています。

## 文字列の画面出力

```irb
>> puts "foo"
foo
=> nil
>> print "foo"
foo=> nil
>> print "foo\n"
foo
=> nil
```

* `puts`や`print`の戻り値は`nil`であり、標準出力への文字列の出力は副作用としてのものである
* `puts`は文字列の最後に自動で改行コードを追加する一方、`print`は文字列の最後に自動で改行コードを追加しない

## シングルクォート内の文字列

```irb
>> 'foo'
=> "foo"
>> 'foo' + 'bar'
=> "foobar"
>> '#{foo} bar'
=> "\#{foo} bar"
>> '\n'
=> "\\n"
>> 'Newlines (\n) and tabs (\t) both use the backslash character \.'
=> "Newlines (\\n) and tabs (\\t) both use the backslash character \\."
```

* シングルクォート内の文字列では、特殊文字が解釈されない
* 特殊文字の解釈の有無以外は、シングルクォート内の文字列もダブルクォート内の文字列も挙動は同じである

## 日本語が入力できない…？

私のDockerコンテナにおいては、次の演習に取り掛かるのに際して、シェル・Railsコンソールで日本語が入力できないことが問題になりました。

どうやら原因は、「使用していたDockerコンテナに、日本語を含むロケール関係の機能一式がインストールされていなかった」ということのようでした。

以下の通り、ロケール関係の機能一式をインストールした上で、Dockerコンテナ上で動いているDebianの環境変数`LANG`を変更することにより、シェル・Railsコンソール日本語入力ができるようになりました。

```:bash
# apt-get update
# apt-get install locales locales-all
# export LANG=en_US.UTF-8
```

問題解決にあたっては、以下のWebサイトを参考にさせていただきました。ありがとうございます。

* [Dockerコンテナで文字化けが発生した場合の直し方 - /var/www/yatta47.log](https://yatta47.hateblo.jp/entry/2016/10/15/114701)
* [docker公式イメージと文字コード - @masarakki - Qiita](https://qiita.com/masarakki/items/0bdcefce99da6e8cbdac)

## 演習

### 1.city変数に適当な市区町村を、prefecture変数に適当な都道府県を代入してください。

市区町村を`越谷市`、都道府県を`埼玉県`にしてやってみます。

```irb:
>> city = "越谷市"
=> "越谷市"

>> prefecture = "埼玉県"
=> "埼玉県"
```

### 2. 先ほど作った変数と式展開を使って、「東京都 新宿区」のような住所の文字列を作ってみましょう。出力にはputsを使ってください。

以下に示す通り、方法は2つあります。両方やってみます。

```irb:
>> puts prefecture + " " + city
埼玉県 越谷市
=> nil

>> puts "#{prefecture} #{city}"
埼玉県 越谷市
=> nil
```

### 3. 上記の文字列の間にある半角スペースをタブに置き換えてみてください。(ヒント: 改行文字と同じで、タブも特殊文字です)

タブ文字は`\t`という特殊文字として表されます。

```irb:
>> puts "#{prefecture}\t#{city}"
埼玉県	越谷市
=> nil
```

### 4. タブに置き換えた文字列を、ダブルクォートからシングルクォートに置き換えてみるとどうなるでしょうか?

```irb:
>> puts prefecture + '\t' + city
埼玉県\t越谷市
=> nil

>> puts '#{prefecture}\t#{city}'
#{prefecture}\t#{city}
=> nil
```

シングルクォート内においては、そもそも`#{}`も展開されないのですね。その点を見落としており、`puts '#{prefecture}\t#{city}'`の結果に最初驚きました。

# オブジェクト

## オブジェクトとメッセージの受け渡し

Rubyでは、全ての値はオブジェクトです。例えば、`true`、`nil`、`""`（空文字列）、`RUBY_VERSION`（Rubyの組み込み定数の一種）といったものもオブジェクトです。

あらゆるオブジェクトはメソッドを持ちます。例えば、文字列は`length`というメソッドや`empty?`というメソッドに応答できます。

```irb:
>> "".length
=> 0

>> "".empty?
=> true

>> "foobar".length
=> 6

>> "foobar".empty?
=> false
```

## 分岐構文の例

以下は分岐構文の例です。irb内でブロック形式の分岐構文を書けるのですね。

```irb:
>> s = "foobar"
=> "foobar"
>> if s.empty?
>>   "The string is empty"
>> else
>>   "The string is nonempty"
>> end
=> "The string is nonempty"
```

これまた分岐構文の例です。`elsif`で条件文を複数連ねていっています。

```irb:
>> s = "foobar"
=> "foobar"
>> if s.nil?
>>   "The variable is nil"
>> elsif s.empty?
>>   "The string is empty"
>> elsif s.include?("foo")
>>   "The string includes 'foo'"
>> end
=> "The string includes 'foo'"
```

## falsyな値

Javascript界隈において、「`boolean`として評価した場合に`false`として評価される値」のことを「falsyな値」といいます。falsyの対義語はtruthyで、こちらは「`boolean`として評価した場合に`true`として評価される値」を意味します。

Rubyにおけるfalsyなオブジェクト（Rubyでは、全ての値はオブジェクトです）は、`false`自身と`nil`の2つしか存在しません。

```irb:
!!false
=> false

!!nil
=> false
```

Javascriptでfalsyとされるオブジェクトに相当する`0`、`-0`、`""`（空文字列）、`Float::NAN`（非数）といったオブジェクトも、Rubyではtruthyです。

```irb:
>> !!0
=> true

>> !!-0
=> true

>> !!""
=> true

>> !!Float::NAN
=> true
```

## 演習…オブジェクトとメッセージ受け渡し

### 1. "racecar" の文字列の長さはいくつですか? `length`メソッドを使って調べてみてください。

```irb:
>> "racecar".length
=> 7
```

### 2. `reverse`メソッドを使って、"racecar"の文字列を逆から読むとどうなるか調べてみてください。

```irb:
>> "racecar".reverse
=> "racecar"
```

### 3. 変数`s`に "racecar" を代入してください。その後、比較演算子 (==) を使って変数sと`s.reverse`の値が同じであるかどうか、調べてみてください。

```irb:
>> s = "racecar"
=> "racecar"

>> s == s.reverse
=> true
```

### 4. [リスト 4.9](https://railstutorial.jp/chapters/rails_flavored_ruby?version=5.1#code-palindrome_if)を実行すると、どんな結果になるでしょうか? 変数`s`に "onomatopoeia" という文字列を代入するとどうなるでしょうか?

```irb:
>> s = "racecar"
=> "racecar"

>> puts "It's a palindrome!" if s == s.reverse
It's a palindrome!
=> nil

>> s = "onomatopoeia"
=> "onomatopoeia"

>> puts "It's a palindrome!" if s == s.reverse
=> nil
```

## irb内でのメソッド定義

以下のように、irb内でメソッドを定義することも可能です。

```irb:
>> def string_message(str = '')
>>   if str.empty?
>>     "It's an empty string!"
>>   else
>>     "The string is nonempty."
>>   end
>> end
=> :string_message
>> puts string_message("foobar")
The string is nonempty.
=> nil
>> puts string_message("")
It's an empty string!
=> nil
>> puts string_message
It's an empty string!
=> nil
```

* メソッドの引数は省略できる
* Rubyのメソッドには「暗黙の戻り値がある」
* メソッドで引数の変数名にどんな名前を使っても、メソッドの呼び出し側には何の影響も生じない

上述の点が大切なポイントでしょうか。

## 演習…メソッドの定義

### 1. [リスト 4.10](https://railstutorial.jp/chapters/rails_flavored_ruby?version=5.1#code-palindrome_tester)のFILL_INの部分を適切なコードに置き換え、回文かどうかをチェックするメソッドを定義してみてください。

```irb:
>> def palindrome_tester(s)
>>   if s.reverse == s
>>     puts "It's a palindrome!"
>>   else
>>     puts "It's not a palindrome."
>>   end
>> end
=> :palindrome_tester
```

### 2. 上で定義したメソッドを使って “racecar” と “onomatopoeia” が回文かどうかを確かめてみてください。

```irb:
>> palindrome_tester("racecar")
It's a palindrome!
=> nil

>> palindrome_tester("onomatopoeia")
It's not a palindrome.
=> nil
```

### 3. `palindrome_tester("racecar")`に対してnil?メソッドを呼び出し、戻り値がnilであるかどうかを確認してみてください。

```irb:
>> palindrome_tester("racecar").nil?
It's a palindrome!
=> true
```

* `puts`は副作用で標準出力に文字列が出力されるのであり、戻り値は`nil`である
* Rubyのメソッドは、明示的に戻り値を指定しなければ、メソッド内で最後に評価された式の値が戻り値となる

上述の挙動を考えると、1.で定義した`palindrome_tester`の戻り値は、確かに常に`nil`になりますね。

## 余談…演算子もメソッドである

余談ですが、Rubyにおいては、演算子もメソッドの一種として実装されています。例えば、以下の2つの表現は同じメソッドの呼び出しになります。

```irb:
>> 17 + 42
=> 59

>> 17.+(42)
=> 59
```