Railsチュートリアル 第4章 - Rails風味のRubyを学ぶ…クラス

「実際にオブジェクトをいくつか定義してみる」というパートまで至りました。

# コンストラクタ

## リテラルコンストラクタ

Rubyでは、文字列(String)・配列(Array)・ハッシュ(Hash)・範囲(Range)などのクラスに対し、当該オブジェクトのインスタンスを暗黙的に作成する記法が存在します。Railsチュートリアルでは、こうした記法を「リテラルコンストラクタ」と呼んでいます。以下はリテラルコンストラクタの例です。

```irb:リテラルコンストラクタの例
# 文字列のリテラルコンストラクタ
>> s = "foobar"
=> "foobar"
>> s.class
=> String

# 配列のリテラルコンストラクタ
>> ar = ['foo', 'bar']
=> ["foo", "bar"]
>> ar.class
=> Array
```

％記法も、Railsチュートリアルでいうところのリテラルコンストラクタの一種です。

```irb:％記法の例
# %qによる文字列のリテラルコンストラクタ
>> s = %q[foo bar'baz']
=> "foo bar'baz'"
>> s.class
=> String

# %wによる配列のリテラルコンストラクタ
>> ar = %w[foo bar baz]
=> ["foo", "bar", "baz"]
>> ar.class
=> Array
```

## 名前付きコンストラクタ

暗黙のリテラルコンストラクタが存在する一方、明示的に同等の名前付きコンストラクタを呼び出して使うことも可能です。名前付きコンストラクタは、クラス名に対して`new`メソッド[^名前付きコンストラクタ詳細解説]を呼び出すことにより実行されます。

[^名前付きコンストラクタ詳細解説]: 実際には、`Class#new`メソッド（自身もメソッドである）は、内部でクラスのインスタンスを生成する`Class#allocate`メソッドと、インスタンスを初期化する`Object#initialize`メソッドを実行しています。このあたりの話は、Rubyの言語仕様についての突っ込んだ話になり、Railsチュートリアルの範疇を超えます。

```irb:名前付きコンストラクタの例
# 文字列の名前付きコンストラクタ
>> s = String.new("foobar")
=> "foobar"
>> s.class
=> String

# 配列の名前付きコンストラクタ
>> ar = Array.new(['foo', 'bar'])
=> ["foo", "bar"]
>> ar.class
=> Array
```

### ハッシュの名前付きコンストラクタ

ハッシュの名前付きコンストラクタ`Hash.new`の引数は、ハッシュの内容そのものではなく、ハッシュのデフォルト値（キーが存在しない場合の値）を与えるために用いられます。`Hash.new`の引数がない場合、ハッシュのデフォルト値は`nil`となります。

```irb:ハッシュの名前付きコンストラクタ
>> h = Hash.new()
=> {}
>> h[:foo]  # 存在しないキー(:foo)の値を取り出してみる
=> nil
>> h
=> {}  # 存在しないキー(:foo)の値を取り出しても、ハッシュの中身に変化はない

>> h = Hash.new(0)  # 存在しないキーのデフォルト値を0としてハッシュを作成する
=> {}
>> h[:foo]  # 存在しないキー(:foo)の値を取り出してみる
=> 0
>> h
=> {}  # 存在しないキー(:foo)の値を取り出しても、ハッシュの中身に変化はない
```

ハッシュの名前付きコンストラクタにブロックを与えることにより、「存在しないキーの値を取り出すと、指定したキーに対する値を自動でセットする」という動作を定義することも可能です。

```irb:「存在しないキーの値を取り出すと、指定したキーに対する値を自動でセットする」ハッシュの例
>> h = Hash.new(){|h,k| h[k] = 0}
=> {}
>> h[:foo]  # 存在しないキー(:foo)の値を取り出してみる
=> 0
>> h
=> {:foo=>0}  # :fooというキーに対し、0という値がセットされている
```

# 演習 - コンストラクタ

## 1. 1から10の範囲オブジェクトを生成するリテラルコンストラクタは何でしたか? (復習です)

```irb:
>> 1..10
=> 1..10
```

## 2. 今度はRangeクラスとnewメソッドを使って、1から10の範囲オブジェクトを作ってみてください

```irb:
>> r = Range.new(1,10)
=> 1..10
>> r.class
=> Range
```

## 3. 比較演算子==を使って、上記２つの課題で作ったそれぞれのオブジェクトが同じであることを確認してみてください。 

```irb:

>> rr = 1..10
=> 1..10
>> rr.class
=> Range
>> r == rr
=> true
```

# クラスメソッドとインスタンスメソッド

メソッドがクラス自身に対して呼び出されるとき、当該メソッドをクラスメソッド[^クラスメソッド詳細解説]といいます。`new`メソッドはクラスメソッドの例です。

クラスの`new`メソッドを呼び出した場合、その戻り値は、当該クラスの個別オブジェクトとなります。クラスに属する個別オブジェクトのことをインスタンスと呼びます。

`length`や`equal?`といった、インスタンスに対して呼び出すメソッドはインスタンスメソッドと呼ばれます。

[^クラスメソッド詳細解説]: より厳密に言えば、Rubyにおいて「クラスメソッド」と呼ばれるものは、`Class`というクラスのインスタンスメソッドです。ただ、このあたりの話は、Rubyの言語仕様についての突っ込んだ話になり、Railsチュートリアルの範疇を超えます。

# クラス継承

`Class#superclass`メソッドにより、オブジェクトのクラス階層を調べていくことができます。

```irb:
>> s = String.new("foobar")
=> "foobar"
>> s.class.superclass
=> Object
>> s.class.superclass.superclass
=> BasicObject
>> s.class.superclass.superclass.superclass
=> nil
```

![String.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/7c0db5d5-e530-c8e7-b8b4-01106958ba9c.png)

Rubyにおける全てのクラスは、`BasicObject`クラスを継承しています。また、ほとんどのクラスは、`BasicObject`を基底クラスとする`Object`クラスを継承しています。

## とにかくクラスを作ってみる

ある単語を前からと後ろからのどちらから読んでも同じ (つまり回文になっている) ならば`true`を返す`palindrome?`メソッドを含む、`Word`というクラスを作ってみます。

```irb:とにかくWordクラスを作ってみる
>> class Word
>>   def palindrome?(string)
>>     string == string.reverse
>>   end
>> end
=> :palindrome?
```

このクラスは、以下のように使うことができます。

```irb:
>> w = Word.new  # Wordオブジェクトを作成する
=> #<Word:0x000055e4debd1320>
>> w.palindrome?("foobar")
=> false
>> w.palindrome?("level")
=> true

>> w.class.superclass    
=> Object
```

`Word`クラスが`Object`クラスを直接継承していることは注目に値します。Rubyのクラス定義においては、基底クラスを明示しなければ、暗黙的に`Object`クラスを継承します。

## 既存クラスから継承したクラスを作る

…ちょっと待ってください。文字列を引数に取るメソッドを作るためだけに、`Object`クラスを直接継承する新しいクラスを定義するのもおかしな話ですよね。単語は文字列なのだから、`Word`クラスは`String`クラスを継承して作られるべきではないでしょうか…

というわけで、今度は`String`クラスを継承した`Word`クラスを定義します。

```irb:Stringクラスを継承したWordクラスを作る
>> class Word < String
>>   def palindrome?  
>>     self == self.reverse
>>   end
>> end
=> :palindrome?
```

このクラスは、以下のように使うことができます。

```irb:
>> s = Word.new("level")  # 新しいWordを作成し、"level"で初期化する
=> "level"
>> s.palindrome?  # Wordが回文かどうか調べる
=> true
>> s.length  # WordはStringで使える全てのクラスを継承している
=> 5
```

`Word`クラスの継承階層を調べてみましょう。

```irb:
>> s.class.superclass
=> String
>> s.class.superclass.superclass
=> Object
```

UMLのクラス図は以下のようになります。

![Word.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/5235798a-f315-e948-0f1c-b78427c21143.png)

# 演習 - クラス継承

## 1.1. `Range`クラスの継承階層を調べてみてください。

```irb:Rangeクラスの継承階層
>> Range.superclass
=> Object
>> Range.superclass.superclass
=> BasicObject
>> Range.superclass.superclass.superclass
=> nil
```

![Range.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/2cbd6d0e-6969-e688-a19e-a6acbf5b954e.png)

## 1.2. 同様にして、`Hash`と`Symbol`クラスの継承階層も調べてみてください。

```irb:Hashクラスの継承階層
>> Hash.superclass
=> Object
>> Hash.superclass.superclass
=> BasicObject
>> Hash.superclass.superclass.superclass
=> nil
```

![Hash.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/b29a878b-eea7-0b33-5762-1e5ec87e6cca.png)

```irb:Symbolクラスの継承階層
>> Symbol.superclass
=> Object
>> Symbol.superclass.superclass
=> BasicObject
>> Symbol.superclass.superclass.superclass
=> nil
```

![Symbol.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/f05a8370-7a98-ddf7-4a5a-3d83eabdaa1b.png)

## 余談 - `Class`クラスの継承階層

```irb:Classクラスの継承階層
>> Class.superclass
=> Module
>> Class.superclass.superclass
=> Object
>> Class.superclass.superclass.superclass
=> BasicObject
>> Class.superclass.superclass.superclass.superclass
=> nil
```

![Class.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/d3a33144-1c45-150a-5637-62de15228c05.png)

`Range`、`Hash`、`Symbol`、`Class`の継承階層をひとまとめにすると、以下のようになります。

![Class.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/e9e9e047-6f43-b237-a097-85642ca56645.png)

## 2. [リスト 4.15](https://railstutorial.jp/chapters/rails_flavored_ruby?version=5.1#code-word_class)にある`self.reverse`の`self`を省略し、`reverse`と書いてもうまく動くことを確認してみてください。 

```irb:
>> class Word < String
>>   def palindrome?
>>     self == reverse  # self.reverseのself.を省略
>>   end
>> end
=> :palindrome?

>> s = Word.new("level")
=> "level"
>> s.palindrome?
=> true
>> s.length
=> 5
```

確かにうまく動いています。

# 組み込みクラスの変更

Rubyでは、組み込みクラスそのものを拡張したり、組み込みクラスのメソッドの動作を変更することも可能です。

```irb:Stringクラスにpalindrome?メソッドを追加する例
>> class String
>>   def palindrome?
>>     self == self.reverse
>>   end
>> end
=> :palindrome?

>> "deified".palindrome?
=> true
```

## `blank?`メソッド

Rails[^ActiveSupport]によって追加されるメソッドの一つです。

```irb:blank?メソッドの動作例
>> "".blank?
=> true
>> "    ".empty?
=> false
>> "    ".blank?
=> true
>> nil.blank?
=> true
```

* [blank?メソッドのソースコード](https://github.com/rails/rails/blob/d66e7835bea9505f7003e5038aa19b6ea95ceea1/activesupport/lib/active_support/core_ext/object/blank.rb)
  * 最も基底では、`Object`クラスに定義されている
  * `blank?`の否定を返す`present?`というメソッドも定義されている
  * `NilClass#blank?`、`FalseClass#blank?`は常に`true`を返す
  * `TrueClass#blank?`は常に`false`を返す
  * `String`、`Array`、`Hash`、`Numeric`、`Time`に対する`blank?`の定義は上書きされている

## Railsによる、配列に対する追加メソッド

実は、配列に対する`second`、`third`、`fourth`、`fifth`、`forty_two`というメソッドも、Rails[^ActiveSupport]によって組み込みクラス`Array`に追加されたメソッドです。

```irb:second,third,forty_twoの用例
>> [*('a'..'z')].second
=> "b"

>> [*('a'..'z')].third 
=> "c"

>> [*(1..42)].forty_two
=> 42
```

[^ActiveSupport]: 厳密には、Railsが使っているActiveSupportというライブラリです。

# 演習 - 組み込みクラスの変更

## 1.1. `palindrome?`メソッドを使って、“racecar”が回文であり、“onomatopoeia”が回文でないことを確認してみてください。

```irb:
>> "racecar".palindrome?
=> true
>> "onomatopoeia".palindrome?
=> false
```

## 1.2. 南インドの言葉「Malayalam」は回文でしょうか?

```irb:
>> "Malayalam".palindrome?
=> false
>> "Malayalam".downcase.palindrome?
=> true
```

大文字小文字を区別しないようにすれば、回文になるようです。

## 2. [リスト 4.16](https://railstutorial.jp/chapters/rails_flavored_ruby?version=5.1#code-string_shuffle_two)を参考に、Stringクラスにshuffleメソッドを追加してみてください。

> ```Ruby:Railsチュートリアルより、リスト4.16（「?」を適切なメソッドに置き換える）
class String
  def shuffle
    self.?('').?.?
  end
end
"foobar".shuffle
=> "borafo"
> ```

```irb:
>> class String
>>   def shuffle
>>     self.split('').shuffle.join
>>   end
>> end
=> :shuffle

>> "foobar".shuffle
=> "obfora"  # 結果は実行するごとに変わります
```

処理順序としては、以下の通りでしたね。

1. `split('')`メソッドにより、文字列を1文字ずつの配列に変換する
2. `shuffle`メソッドにより、元の配列と同じ内容を持ち、要素の順番だけが異なる配列を生成する
3. `join`メソッドにより、配列を一つの文字列に変換する

## 3. リスト 4.16のコードにおいて、`self.`を削除してもうまく動くことを確認してください。 

これまでの`shuffle`メソッドの定義を消去するため、一旦Rails Consoleから抜けた上で、再びRails Consoleを起動します。そのうえで、以下のコードを入力していきます。

```irb:
>> class String
>>   def shuffle
>>     split('').shuffle.join  # self.を削除
>>   end
>> end
=> :shuffle

>> "foobar".shuffle
=> "oaobrf"  # 結果は実行するごとに変わります
```

確かにうまく動きますね。

# Railsのコントローラクラス

```irb:Railsのコントローラクラスの継承関係
>> controller = StaticPagesController.new
=> #<StaticPagesController:0x000055de496db6e0 @_action_has_layout=true, @_routes=nil, @_request=nil, @_response=nil>

>> controller.class
=> StaticPagesController
>> controller.class.superclass
=> ApplicationController
>> controller.class.superclass.superclass
=> ActionController::Base
>> controller.class.superclass.superclass.superclass
=> ActionController::Metal
>> controller.class.superclass.superclass.superclass.superclass
=> AbstractController::Base
>> controller.class.superclass.superclass.superclass.superclass.superclass
=> Object
>> controller.class.superclass.superclass.superclass.superclass.superclass.superclass
=> BasicObject
>> controller.class.superclass.superclass.superclass.superclass.superclass.superclass.superclass
=> nil
```

継承関係を表すクラス図は以下のようになります。

![StaticPagesController.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/08fb1946-5957-43d5-b31d-ab2d60c2d210.png)

# 演習 - Railsのコントローラクラス

## 1. 第2章で作ったToyアプリケーションのディレクトリでRailsコンソールを開き、`User.new`と実行することでuserオブジェクトが生成できることを確認してみましょう。

```irb:
>> u = User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>
```

## 2. 生成したuserオブジェクトのクラスの継承階層を調べてみてください。 

```irb:
>> u.class 
=> User(id: integer, name: string, email: string, created_at: datetime, updated_at: datetime)
>> u.class.superclass
=> ApplicationRecord(abstract)
>> u.class.superclass.superclass
=> ActiveRecord::Base
>> u.class.superclass.superclass.superclass
=> Object
>> u.class.superclass.superclass.superclass.superclass
=> BasicObject
>> u.class.superclass.superclass.superclass.superclass.superclass
=> nil
```

![User.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/fdfb91d1-417b-ae59-e351-85ddd79bcbb7.png)

# ユーザークラス

ここで、Railsコンソールから抜け、`sample_app`の開発環境に戻ります。その上で、以下の`User`クラスを、`/example_user.rb`に作成します。

```ruby:/example_user.rb
class User
  attr_accessor :name, :email

  def initialize(attributes = {})
    @name  = attributes[:name]
    @email = attributes[:email]
  end

  def formatted_email
    "#{@name} <#{@email}>"
  end
end
```

「当該`User`クラスでは、DBを扱わない」というのが一つのポイントです。DBを扱うとなると、「DBのマイグレーション処理」等、Rails特有の処理が多数発生し、クラスやメソッドの振る舞いも純粋なRubyからかけ離れていきます。今回は、DBを扱わないので、クラスやメソッドの振る舞いは純粋なRubyに近いものになります。

## `attr_accesor`メソッド

```Ruby:
attr_accessor :name, :email
```

`attr_accessor`というのは、インスタンス変数に対する読み取り・書き込み両方を行うためのメソッドを用意するメソッドです。このコードでは、インスタンス変数`@name`と`@email`に対する読み取り・書き込み[^読み取り・書き込み両方ということについて]を行うためのメソッドが用意されるということです。VBAの`Property Get`と`Property Set`をセットにしたもの」に近いものでしょうか。

[^読み取り・書き込み両方ということについて]: 読み取りのみであれば`attr_reader`、書き込みのみであれば`attr_writer`という名前のメソッドを使います。

以下のコードは、先ほど記述した`attr_accesor`と同じメソッドを定義するコードです。

```Ruby:
def name=(str)
  @name = str
end

def name
  @name
end

def email=(str)
  @email = str
end

def email
  @email
end
```

`attr_accessor`については、以下のような説明も参考になるかと思われます。

* [Railsから入った人へ【attr_accessor】って？ - Qiita](https://qiita.com/Hassan/items/0e034a1d42b2335936e6) - @Hassan 氏による説明。
* [Rubyのattr_accessorって何？[和訳] - bryankawaの日記](http://bryankawa.hatenablog.com/entry/2017/01/28/150537)

## `initialize`メソッド

```Ruby:
def initialize(attributes = {})
  @name  = attributes[:name]
  @email = attributes[:email]
end
```

`initialize`というのは、Rubyの特殊なクラスメソッドの一つです。クラスメソッドを`new`したとき（今回だと`User.new`したときですね）に自動で呼び出され、メソッド内の記述に基づいてインスタンス変数を初期化します。Java等でいうところのコンストラクタですね。

今回の`initialize`メソッドは、デフォルトの引数として空のハッシュを一つ取ります。当該ハッシュは、`initialize`メソッド内部では`attributes`という名前で使われます。Rubyでは、存在しないキーに対するハッシュの値は`nil`であるため、`attributes[:name]`・`attributes[:email]`はいずれも`nil`となり、最終的には`@name=nil, @email=nil`となります。

## `formatted_email`メソッド

```ruby:
def formatted_email
  "#{@name} <#{@email}>"
end
```

`formatted_email`メソッドは、文字列の式展開を利用し、`@name`と`@email`に割り当てられた値をユーザのメールアドレスとして構成するメソッドです。`@name`と`@email`はいずれも`User`クラスのインスタンス変数であり、`formatted_email`メソッドでもそのまま使うことができます。

## 自作した`User`クラスを使ってみる

`example_user.rb`を作成したRails環境のルートディレクトリでRailsコンソールを実行します。以降はRailsコンソールでの入力と、その応答です。

```irb:自作Userクラスを使ってみる
>> require './example_user'  # example_userのコードを読み込む
=> true

>> example = User.new
=> #<User:0x000055de496ee8d0 @name=nil, @email=nil>
>> example.name  # :attributes[:name]は存在しないのでnil
=> nil
>> example.name = "Example User"  # 名前を代入する
=> "Example User"
>> example.email = "user@example.com"  # メールアドレスを代入する
=> "user@example.com"
>> example.formatted_email
=> "Example User <user@example.com>"
```

* `./example_user`は、カレントディレクトリのexample_userファイルを指す
  * `.`は、Unixのカレントディレクトリを指す
* `new`メソッドで空のexample_userを作成する
  * この時点では`@name`・`@email`とも`nil`
* 対応する属性にそれぞれ手動で値を代入している
  * `attr_accessor`を定義しているので、このような形で代入できる

以上が動作のポイントでしょうか。

### マスアサインメント

```irb:マスアサインメントの例
>> user = User.new(name: "Michael Hartl", email: "mhartl@example.com")
=> #<User:0x000055de49681780 @name="Michael Hartl", @email="mhartl@example.com">
>> user.formatted_email
=> "Michael Hartl <mhartl@example.com>"
```

`User`クラスに属する`user`オブジェクトが、生成時点で`@name="Michael Hartl", @email="mhartl@example.com"`となっていますね。

例えば今回の自作`User`クラスの場合、`new`メソッドの引数にハッシュを与えることにより、インスタンス変数が定義済みのインスタンスを生成することができます。こうした技法を「マスアサインメント」といいます。Railsアプリケーションでも広く使われる技法だそうです。

この章の学習内容との関係で言えば、「（メソッドの最後の引数なので）ハッシュの波括弧が省略されている」というのは一つのポイントですね。

なお、マスアサインメントに関係して、以下のような概念が後々登場することになりますが、それはまた別の話です。

* マスアサインメント脆弱性
* マスアサインメント脆弱性への対策であるStrong Parameters

# 演習 - ユーザークラス

## 1.1. Userクラスで定義されているname属性を修正して、first_name属性とlast_name属性に分割してみましょう。

`User#attr_accessor`を書き換えていきます。

```ruby:User#attr_accessorの実装変更
attr_accessor :first_name, :last_name, :email
```

この部分を実装すると、`User.new`の挙動が以下のようになります。

```irb:
>> example = User.new            
=> #<User:0x000055de48a8d7a8 @first_name=nil, @last_name=nil, @email=nil>
```

## 1.2. また、それらの属性を使って "Michael Hartl" といった文字列を返すfull_nameメソッドを定義してみてください。

1.1.に引き続き、`User#full_name`メソッドを追加します。

```ruby:User#full_nameの実装
def full_name
  "#{@first_name} #{@last_name}"
end
```

この部分まで実装したときの、`User#full_name`の挙動は以下の通りになります。

```irb:
>> example.first_name = "Michael"
=> "Michael"
>> example.last_name = "Hartl"
=> "Hartl"
>> example.full_name
=> "Michael Hartl"
```

最初、`{@last_name}`の前の`#`を入れ忘れてしまい、`"Michael {@last_name}"`のような戻り値が出力されて「？？？」となりました。こういうイージーミスはやってしまいがちですよね。

## 1.3. 最後に、`formatted_email`メソッドの`name`の部分を、`full_name`に置き換えてみましょう (元々の結果と同じになっていれば成功です)

1.2.に引き続き、`User#formatted_email`メソッドを書き換えていきます。

```ruby:User#formatted_emailの実装変更
def formatted_email
  "#{full_name} <#{@email}>"
end
```

この部分まで実装したときの、`User#formatted_email`の挙動は以下の通りになります。

```irb:
>> example.first_name = "Michael"
=> "Michael"
>> example.last_name = "Hartl"
=> "Hartl"
>> example.email = "user@example.com"  
=> "user@example.com"
>> example.formatted_email
=> "Michael Hartl <user@example.com>"
```

## 2. "Hartl, Michael" といったフォーマット (苗字と名前がカンマ+半角スペースで区切られている文字列) で返す`alphabetical_name`メソッドを定義してみましょう。

1.3.に引き続き、`User#alphabetical_name`メソッドを追加します。

```ruby:User#alphabetical_nameの実装
def alphabetical_name
  "#{@last_name}, #{@first_name}"
end
```

`User#alphabetical_name`の挙動は以下の通りになります。

```irb:
>> require './example_user'
=> true
>> example = User.new 
=> #<User:0x000055de49caed60 @first_name=nil, @last_name=nil, @email=nil>
>> example.first_name = "Michael"
=> "Michael"
>> example.last_name = "Hartl"
=> "Hartl"
>> example.alphabetical_name
=> "Hartl, Michael"
```

期待通りの挙動になりましたね。

## 3. `full_name.split`と`alphabetical_name.split(’, ’).reverse`の結果を比較し、同じ結果になるかどうか確認してみましょう。

2.まで完了した後に、Rails Consoleで以下のコードを入力していきます。

```irb:
>> example.full_name.split == example.alphabetical_name.split(', ').reverse
=> true
>> example.full_name.split
=> ["Michael", "Hartl"]
>> example.alphabetical_name.split(', ').reverse
=> ["Michael", "Hartl"]
```

同じ結果になっているようです。