D IT Y

タマキ工務店のIT日記

チェリー本輪読会 第5週目まとめ

f:id:shirotamaki:20210619091936p:plain

🍒 はじめに

チェリー本輪読会の第5週目のエントリーになります。

輪読会の概要については第1週目にまとめています。

🍒 輪読会 第5週目まとめ

第4章4.8.1〜第4章4.8.8まで

期間:2021年06月21日〜2021年06月25日

each_with_indexメソッド

これまで、eachメソッドを使って繰り返し処理を行ってきましたが、繰り返し処理をしつつかつ処理している要素の添え字(インデックス)も習得したいとき、このメソッドの出番になります。

ブロックの第2引数に添え字(インデックス)渡すことができます。添え字は、0からカウントします。

Enumerable#each_with_index (Ruby 3.0.0 リファレンスマニュアル)

irb(main):007:0> records = [ '存在しません', 'Please Please Me', 'With
The Beatles' ]
=> ["存在しません", "Please Please Me", "With The Beatles"]
irb(main):008:0> records.each_with_index { |record, i| puts "#{i}枚目の
アルバムは #{record}" }
0枚目のアルバムは 存在しません
1枚目のアルバムは Please Please Me
2枚目のアルバムは With The Beatles
=> ["存在しません", "Please Please Me", "With The Beatles"]

引数を指定することで、添え字を0以外から始めることもできます。

records.each.with_index(1) として、添え字を1から開始させています。

irb(main):029:0> records = [ 'Please Please Me', 'With The Beatles', 'A
 Hard Days Night' ]
=> ["Please Please Me", "With The Beatles", "A Hard Days Night"]
irb(main):030:0> records.each.with_index(1) { |record, i| puts  "#{i}
目のアルバムは #{record}" }
1枚目のアルバムは Please Please Me
2枚目のアルバムは With The Beatles
3枚目のアルバムは A Hard Days Night
=> ["Please Please Me", "With The Beatles", "A Hard Days Night"]

mapメソッドとwith_indexメソッドの組み合わせ

mapメソッドを組み合わせて使ってみましょう。

配列になって戻り値が返ってきます。

irb(main):013:0> records = [ '存在しません', 'Please Please Me', 'With
The Beatles' ]
=> ["存在しません", "Please Please Me", "With The Beatles"]
irb(main):014:0> records.map.with_index { |record, i| "#{i}枚目のアルバ
ムは #{record}" }
=>
["0枚目のアルバムは 存在しません",
 "1枚目のアルバムは Please Please Me",
 "2枚目のアルバムは With The Beatles"]

mapメソッドも引数を渡すことで添え字の始める数字を変更できます。

irb(main):033:0> records = [ 'Please Please Me', 'With The Beatles', 'A
 Hard Days Night' ]
=> ["Please Please Me", "With The Beatles", "A Hard Days Night"]
irb(main):034:0> records.map.with_index(1) { |record, i| puts "#{i}枚目
のアルバムは #{record}" }
1枚目のアルバムは Please Please Me
2枚目のアルバムは With The Beatles
3枚目のアルバムは A Hard Days Night
=> [nil, nil, nil]

Enumeratorクラス

with_indexメソッドは、Enumeratorクラスのインスタンスメソッドです。

Enumeratorクラスとは、each 以外のメソッドにも Enumerable の機能を提供するためのラッパークラスになります。(ラッパークラスとは、オブジェクト指向プログラミング言語で、他のクラスやプログラムの中でオブジェクトとして扱いたい対象を、クラスとして定義したもの)Enumerable(列挙可能な、数え上げられるの意)とは、Enumerableモジュールのことを指します。

f:id:shirotamaki:20210709132937p:plain

class Enumerator (Ruby 3.0.0 リファレンスマニュアル)

module Enumerable (Ruby 3.0.0 リファレンスマニュアル)module Enumerable (Ruby 3.0.0 リファレンスマニュアル)

まとめると、EnumeratorクラスはEnumerableモジュールをincludeしていることになります。 さまざまな継承しているメソッドを利用できます。

f:id:shirotamaki:20210709213238p:plain

他にも、Arrayクラス、Rangeクラスなど「繰り返し処理に関連するメソッドはEnumerableモジュールに定義されていることが多いです。

f:id:shirotamaki:20210709133015p:plain

以下、ブロックなしでメソッドを呼び出した場合、そのメソッドのクラスが返ってくるようになっていますが、以下で呼び出すとEnumeratorが返ってきます。これにより、Enumeratorクラスであることが確認できます。

irb(main):015:0> records = [ '存在しません', 'Please Please Me', 'With
The Beatles' ]
=> ["存在しません", "Please Please Me", "With The Beatles"]
irb(main):016:0> records.each
=> #<Enumerator: ...>
irb(main):017:0> records.map
=> #<Enumerator: ...>

File.openメソッド

テキストファイルへ文字列を書き込む際に利用します

ファイルがopenされた後、処理が実行され完了すると自動でcloseされます。他の言語だとopenするとcloseは手動で行うことが多いようですがFile.openメソッドを利用すれば、Rubyがよしなに処理してくれます。エイリアスメソッドとして、File.newが用意されていますが、こちらブロックを渡すことができないため注意が必要です。

class File (Ruby 3.0.0 リファレンスマニュアル)

適当なファイルを準備し、ファイルに書き込んでみます。

irb(main):005:1* File.open("./beatles.text", "w") do |file|
irb(main):006:1* file.puts("1枚目のアルバムは Please Please Me")
irb(main):007:1* file.puts("2枚目のアルバムは With The Beatles")
irb(main):008:1* file.puts("3枚目のアルバムは A Hard Days Night")
irb(main):009:0> end
=> nil

ファイルの中身を確認してみます。ちゃんと書き込みが行なわれています。

shiro@shiro:~/rindokukai$ cat beatles.text
1枚目のアルバムは Please Please Me
2枚目のアルバムは With The Beatles
3枚目のアルバムは A Hard Days Night

do...endより、 {} のほうが結合度が強い

ブロックで使える2つの記法。

基本的にどっちを使っても結果は同じですが、結合度が違うので注意が必要です。

下記のrecords配列をdo...endを使い処理してみます。

deleteメソッドを使い、引数に渡した文字列が配列の中に存在する場合は削除されます。

irb(main):017:0> records = ['1st', '2nd', '3rd']
=> ["1st", "2nd", "3rd"]
irb(main):018:1* records.delete('1st') do
irb(main):019:1*   '見つかりません'
irb(main):020:0> end
=> "1st"
irb(main):021:0> records
=> ["2nd", "3rd"]

配列に存在しない場合は、ブロックの中身が実行され見つかりませんと返ってきます。

irb(main):025:0> records = ['1st', '2nd', '3rd']
=> ["1st", "2nd", "3rd"]
irb(main):026:1* records.delete('4th') do
irb(main):027:1*   '見つかりません'
irb(main):028:0> end
=> "見つかりません"

()を省略しても、同じ動きになります。

irb(main):005:1* records.delete '4th' do
irb(main):006:1*   '見つかりません'
irb(main):007:0> end
=> "見つかりません"

次に、do...end を、{}へ置き換えてみます。

エラーになります。これは、{}の結合度が高いため、records.delete '4th'と認識されずに、'4th' { '見つかりません' }と解釈されて処理されてしまうためです。

irb(main):008:0> records.delete '4th' { '見つかりません' }
/Users/shiro/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0/gems/irb-1.3.6/lib/irb/workspace.rb:116:in `eval': (irb):8: syntax error, unexpected '{', expecting end-of-input (SyntaxError)
records.delete '4th' { '見つかりません' }
                     ^

()で囲うことでエラーを解決できます。

可読性からいっても、引数に()は付けたほうが良いと思われます。records.delete ('4th')

irb(main):009:0> records.delete ('4th') { '見つかりません' }
=> "見つかりません"

メソッドチェーン

変数を使わずにメソッドの戻り値に対して直接ほかのメソッドを呼び出していくコーディングスタイルのことをメソッドチェーンと呼びます。

個人的にも、Rubyキマってるね!(後述)と言いたくなる記法のひとつで、一筆書きのようにスラスラ〜と書けたら、とても気持ちよさそうです。

mapメソッドを使い、best_records変数を用意して書いてみます。

irb(main):032:0> records = ['1st', '2nd', '3rd']
=> ["1st", "2nd", "3rd"]
irb(main):033:0> best_records = records.map { |record| "#{record}アルバム" }
irb(main):034:0> best_records.join('')
=> "1stアルバムと2ndアルバムと3rdアルバム"

メソッドチェーンを使って書き換えてみます。

irb(main):037:0> records = ['1st', '2nd', '3rd']
=> ["1st", "2nd", "3rd"]
irb(main):038:0> records.map { |record| "#{record}アルバム" }.join('')
=> "1stアルバムと2ndアルバムと3rdアルバム"

do...end を使って書くこともできますが、どちらかと言うと{}を利用するほうが読みやすく、推奨されています。

APIドキュメント

APIドキュメントって何だろう?」

チェリー本にも頻繁に出てくる用語ですが、疑問に思い輪読会で取り上げてみました。 参加されていた受講生の方も同じ疑問を持たれており、過去に直接著者の伊藤さんがこの問いに答えているドキュメントを共有してもらいました。(フィヨルドブートキャンプ用のドキュメントのためブログへは非公開)

私の元々持っていたAPIの言葉としてのイメージはこうでした。

  • Application Programming Interfaceの略。
  • アプリケーションとプログラムをつなぐ何かのこと。アプリケーションとプログラムを繋ぐ接点のこと。
  • Twitterやインスタグラムなど、外部のアプリケーションを簡単に利用できる仕組みのこと。

このように、ぼんやりとした理解でいました。

上記の理解が間違っているわけではないですが、APIという言葉は非常に幅が広い用語であり、今回のAPIドキュメントについての答えとしては不十分です。 共有してもらった情報を元に再定義してみたいと思います。

  • APIとは、プログラマに対して用意されている公式に公開されている便利な機能のことを指します。何かしたい実装があるときに「これを使うと(APIという機能)簡単にこんなことが出来て、こんな結果が返ってくる。車輪の再発明をする必要はないですよ」ということです。 Rubyには無数のAPIがあります。Enumeratorクラスにはeachメソッドがあり、また他にも多くのクラスやメソッドがあります。チェリー本で出てくるAPIドキュメントとは、これらのクラスやメソッドなどのAPI(公式に公開されている機能)の説明が書かれているドキュメントを指しています。 チェリー本で指しているAPIドキュメントとは、るりまのことなんです。

TwitterやインスタグラムなどのAPI(WebAPIという)も言い換えると、「Twitterの色々な機能を簡単に呼び出して使えるようにしたので、自由に使ってご自身のプログラムに取り入れてくだい」ということです。APIを使うと簡単にTwitterやインスタグラムなどの機能を利用できるので、ゼロからプログラミングする必要がなく開発の効率があがります。

下記は、今回APIの疑問について情報を共有いただいたSaki さん(id:Saki-Htr)と、フィヨルドブートキャンプのアドバイザーでもあるうづら さん(id:udzura)とのTwitter上でのやり取りになります。

こちらのやり取りもとても参考になりました。(Sakiさん、情報共有ありがとうございました!)

HackMDの =記法

輪読会では、HackMDを使いファイルを共有し、参加者が気づきや感想を書き込めるようにしています。

Markdownが使え共同編集ができ、そして軽い。便利なエディタです。 HackMDの使い方 - HackMD

そんな日々お世話になっているHackMDですが、コードブロックに行番号を明示できることを教えてもらいました。コードを書き込むことも多いのですが、コードブロックの後ろに= と記入するだけで、行番号を表示できます。多くの言語をサポートしており、=bash =ruby などのように入力することで、その言語のリストは自動補完されます。

機能紹介 - HackMD

Rubyをキメると気持ちいい

輪読会からは脱線しますが、Rubyを学習する中でMatzさん関連のweb記事を読むことが増え、その際にふと見かけた気になる言葉がありました。

Rubyをキメると気持ちいい

Rubyはプログラミングの「たのしさ」を最大化することを目標として設計、開発されていることは知っていましたが、キメるってどういうことだろう?と、ちょっとした興味で、メンターさんに質問してみました。その際、メンターさんに教えていただいた動画がこちらになります。他にも、メンターさんから「Rubyをキメた」経験などもお伺いでき、改めてRubyの「たのしさ」「気持ちよさ」がわかった気がします。

プログラミング梁山泊(前編) - まつもとゆきひろ - ニコニコ動画

プログラミング梁山泊(後編) - まつもとゆきひろ - ニコニコ動画

発言箇所は、後編の18:50〜20:30の質疑応答でのやり取りにて出てきます。

参考書籍

🍒 まとめ

今週は、いろいろな言葉の意味について深堀りすることができて良かったです。

プログラマは「言語化能力が大事」とよく耳にしますが、輪読会が言語化の良いトレーニングにもなっていると感じています。

読んだ内容についてHackMDへ書き込み、その後自分の言葉でその内容について考えを述べ説明したり、質問したり答えたり、また感想を述べたりします。自分の考えを相手に簡潔にわかりやすく伝えるため、「どのような言葉で伝えればいいのか?どの順番で伝えるべきか?」など、言語化する上でいろいろと考えます。 もちろん、輪読会でなくても日報を書く時やチャットでのやり取りなど、普段から言語化を意識することは多いです。しかし、輪読会では自分以外のメンバーの言語化をリアルタイムに体感でき、自分とは違う言語化を見聞きすることでとても学びがあります。例えば、自分が伝えたい物事に対して、「それはこういう事ですね。例えば○○が△△と表現できますね」など、言語化した物事に対してレビューを受けている感覚です。これは非常に勉強になります。具体的にしか表現できなかったことを抽象的な言葉一言で説明することができたり、その逆に抽象的すぎる物事を具体的に説明することができたり。それまで理解できなかったことが、パッと理解できる。輪読会の大きな効用のひとつでもあります。

言語化。 プログラミングに限らず普段から心がけていきたいものです。

では、また来週!(次回、第6週目)