Roll With IT

tamakiの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週目)

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

f:id:shirotamaki:20210619091936p:plain

🍒 はじめに

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

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

🍒 輪読会 第4週目まとめ

第4章4.6.4〜第4章4.7.14まで

期間:2021年06月14日〜2021年06月18日

リファクタリングすべきポイントは「繰り返し処理」部分

先週取り掛かったコードをリファクタリングしました。

リファクタリングとは?

外から見た振る舞いは保ったまま、理解や修正が簡単になるように内部のコードを改善することです。 出典:チェリー本

DRY(Don't repeat yourself)の原則に従い行います。

DRY原則 | プログラマが知るべき97のこと)

簡単な例。

以下は、引数ひとつに対し一行で記述した例です。

irb(main):210:1* def add_second_name(vo, gu, ba, dr)
irb(main):211:1*   puts vo.to_s + 'Ramone'
irb(main):212:1*   puts gu.to_s + 'Ramone'
irb(main):213:1*   puts ba.to_s + 'Ramone'
irb(main):214:1*   puts dr.to_s + 'Ramone'
irb(main):215:0> end
=> :add_second_name
irb(main):216:0>
irb(main):217:0> add_second_name('Joey', 'Johnny', 'DeeDee', 'Marky')
JoeyRamone
JohnnyRamone
DeeDeeRamone
MarkyRamone
=> nil

以下は、each文を使い配列で処理しています。

繰り返し書いている箇所をまとめることができ、DRYに従ったリファクタリングと言えます。

irb(main):218:1* def add_second_name(vo, gu, ba, dr)
irb(main):219:2*   [vo, gu, ba, dr].each do |n|
irb(main):220:2*     puts n.to_s + 'Ramone'
irb(main):221:1*   end
irb(main):222:0> end
=> :add_second_name
irb(main):223:0> add_second_name('Joey', 'Johnny', 'DeeDee', 'Marky')
JoeyRamone
JohnnyRamone
DeeDeeRamone
MarkyRamone
=> ["Joey", "Johnny", "DeeDee", "Marky"]

添字を使った配列の取得方法

配列[位置、取得する長さ]

下記は、2つ目の要素から3つ分を取り出すコードです。

irb(main):001:0> ramones = ["Joey", "Johnny", "DeeDee", "Marky"]
=> ["Joey", "Johnny", "DeeDee", "Marky"]
irb(main):002:0> ramones[1,3]
=> ["Johnny", "DeeDee", "Marky"]

他にもさまざま取り出し方法があります。

正の値を指定することで配列を取り出すことは問題なく理解できていましたが、負の値を指定した際に取り出す方法の理解が曖昧でした。

改めて見直してみます。

irb(main):234:0> ramones = ["Joey", "Johnny", "DeeDee", "Marky"]
=> ["Joey", "Johnny", "DeeDee", "Marky"]
irb(main):235:0> ramones[-1]
=> "Marky"
irb(main):236:0> ramones[-3]
=> "Johnny"

2番目の要素を指定してみます。正の値で指定した動きと同じです。

しかし、取り出しをスタートする地点から右に数えて取得しています。

irb(main):013:0> ramones = ["Joey", "Johnny", "DeeDee", "Marky"]
=> ["Joey", "Johnny", "DeeDee", "Marky"]
irb(main):014:0> ramones[-3, 2]
=> ["Johnny", "DeeDee"]

他に、lastメソッド配列の最後の要素を取得できます。

引数を指定してあげることで、

最後の要素から順番に指定した分要素を取り出せます。

ちなみに、lastとまったく動きが逆になるfirstメソッドもあります。

irb(main):019:0> ramones = ["Joey", "Johnny", "DeeDee", "Marky"]
=> ["Joey", "Johnny", "DeeDee", "Marky"]
irb(main):020:0> ramones.last
=> "Marky"
irb(main):021:0> ramones.last(2)
=> ["DeeDee", "Marky"]

concatメソッド

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

2つの配列を連結したいときに使うメソッドです。

Excelの、CONCATENATE 関数 を思い出しました。 当時、Excel表計算していた際は大変お世話になった関数です。

CONCATENATE 関数 - Office サポート

irb(main):022:0> ramones =  ["Joey", "Johnny", "DeeDee", "Marky"]
=> ["Joey", "Johnny", "DeeDee", "Marky"]
irb(main):023:0> kana = ["ジョーイ", "ジョニー", "ディーディー", "マーキー"]
=> ["ジョーイ", "ジョニー", "ディーディー", "マーキー"]
irb(main):024:0> ramones.concat(kana)
=> ["Joey", "Johnny", "DeeDee", "Marky", "ジョーイ", "ジョニー", "ディーディー", "マーキー"]

ramones変数は変更されます。(破壊的)

kana変数は変更されません。

irb(main):025:0> ramones
=> ["Joey", "Johnny", "DeeDee", "Marky", "ジョーイ", "ジョニー", "ディーディー", "マーキー"]
irb(main):026:0> kana
=> ["ジョーイ", "ジョニー", "ディーディー", "マーキー"]

ちなみに、 + を使っても連結できますが、こちらは非破壊的なので変数は変更されません。

irb(main):027:0> ramones =  ["Joey", "Johnny", "DeeDee", "Marky"]
=> ["Joey", "Johnny", "DeeDee", "Marky"]
irb(main):028:0> kana = ["ジョーイ", "ジョニー", "ディーディー", "マーキー"]
=> ["ジョーイ", "ジョニー", "ディーディー", "マーキー"]
irb(main):029:0> ramones + kana
=> ["Joey", "Johnny", "DeeDee", "Marky", "ジョーイ", "ジョニー", "ディーディー", "マーキー"]
irb(main):030:0> ramones
=> ["Joey", "Johnny", "DeeDee", "Marky"]
irb(main):031:0> kana
=> ["ジョーイ", "ジョニー", "ディーディー", "マーキー"]

チェリー本では、concatメソッドは破壊的なメソッドなため、思わぬ不具合を与えてしまい兼ねないため、+演算子を使うことを推奨しています。

キャット?カット?

輪読会恒例になりつつある?笑 「どう発音するか?」問題で盛り上がりました。 イギリス英語、アメリカ英語で違いがあるようです。

CONCATENATE | Cambridge Dictionary による英語での発音

確か、canもイギリスだと「カン」と言っているのを思い出しました。

でもビートルズはキャンって歌っている…

せっかくなので調べてみました。なるほど、納得!

ビートルズはアメリカ英語で歌っていた(230) - ★ビートルズを誰にでも分かりやすく解説するブログ★

# frozen_string_literal: true

普段、Rubyのコードを書く際におまじないのように書いている下記のコード。

# frozen_string_literal: true

こちらも疑問に思ったため調べてみました。

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

凍結されるのはオブジェクトであり、変数ではありません。代入などで変数の指すオブジェクトが変化してしまうことは freeze では防げません。 freeze が防ぐのは、 `破壊的な操作' と呼ばれるもの一般です

frozen_string_literal はマジックコメントといい、# frozen_string_literal: true と書くことで、上記のるりまで説明があるように文字列が最初からfreezeされるようです。ただし、文字列リテラルに限られます。

文字列リテラルとは?

リテラル (Ruby 3.0.0 リファレンスマニュアル)

破壊的メソッドと非破壊的メソッドの見分け方

まずはるりまを読む。これが鉄則です。

例えば、先程のconcatメソッド。るりまにはこう書いてあります。

  • 配列 other を自身の末尾に破壊的に連結します。

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

! で終わるメソッド

エクスクラメーションマーク(感嘆符)が付くメソッドは、全て破壊的なメソッドであると思っていましたが、これは勘違いでした。!で終わるメソッドは、慣習的に「使用する際には注意が必要ですよ」という意味を持っているだけで、必ずしも破壊的メソッドになるわけではありません。ここは注意が必要です。

cocatメソッドのように、! が付かなくても破壊的なメソッドは存在します。

他には、deleteメソッド、clearメソッドも、!が付かない破壊的メソッドです。

以下は、Matzさんのツイートになります。

なるほど。納得できました。

配列の和集合、差集合、積集合

irb(main):001:0> ramones_a = ["Joey", "Johnny"]
=> ["Joey", "Johnny"]
irb(main):002:0> ramones_b = ["DeeDee", "Marky"]
=> ["DeeDee", "Marky"]
irb(main):003:0> ramones_a | ramones_b
=> ["Joey", "Johnny", "DeeDee", "Marky"]
irb(main):002:0> ramones_a = ["Joey", "Johnny", "DeeDee"]
=> ["Joey", "Johnny", "DeeDee"]
irb(main):003:0> ramones_b = ["DeeDee", "Marky"]
=> ["DeeDee", "Marky"]
irb(main):004:0> ramones_a - ramones_b
=> ["Joey", "Johnny"]
irb(main):001:0> ramones_a = ["Joey", "Johnny", "DeeDee"]
=> ["Joey", "Johnny", "DeeDee"]
irb(main):002:0> ramones_b = ["DeeDee", "Marky"]
=> ["DeeDee", "Marky"]
irb(main):003:0> ramones_a & ramones_b
=> ["DeeDee"]

上記と同じことがしたい場合、RubyにはSetクラスが用意されています。一般的にはSetクラスを使って集合演算を行います。

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

splat展開

*を使って1つの引数ではなく、「複数の引数」として配列を展開することができます。

*splat展開なしの場合。

二次元配列になります。入れ子のデータ構造のことです。

irb(main):001:0> ramones = ["Joey", "Johnny", "DeeDee", "Marky"]
=> ["Joey", "Johnny", "DeeDee", "Marky"]
irb(main):002:0> name = []
=> []
irb(main):003:0> name.push(ramones)
=> [["Joey", "Johnny", "DeeDee", "Marky"]]

*splat展開ありの場合。

一次元配列で格納できます。

irb(main):001:0> ramones = ["Joey", "Johnny", "DeeDee", "Marky"]
=> ["Joey", "Johnny", "DeeDee", "Marky"]
irb(main):002:0> name = []
=> []
irb(main):003:0> name.push(*ramones)
=> ["Joey", "Johnny", "DeeDee", "Marky"]

メソッドの可変長引数(variable arguments)

コンピュータプログラムの一部として定義された関数などに渡される引数のうち、あらかじめ数が固定されておらず、任意の数(あるいは事前に定められた範囲の数)を取ることができるものを可変長引数(可変引数、可変個引数)といいいます。チェリー本では、「個数に制限のない引数」と説明されています。

  • splat展開がない場合
    • joinメソッドを使い、引数に渡した配列の文字列を間に挟み連結しした文字列を返します。
    • 引数が配列じゃない場合は、エラーになります。
irb(main):004:1* def greeting(names)
irb(main):005:1* "#{names.join('')}、ハロー!!"
irb(main):006:0> end
=> :greeting
irb(main):007:0> greeting([ "DeeDee", "Marky"])
=> "DeeDeeとMarky、ハロー!!"
irb(main):008:0> greeting( "DeeDee", "Marky")
(irb):4:in `greeting': wrong number of arguments (given 2, expected 1) (ArgumentError)
  from (irb):8:in `<main>'
  from /Users/shiro/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0/gems/irb-1.3.6/exe/irb:11:in `<top (required)>'
    from /Users/shiro/.rbenv/versions/3.0.0/bin/irb:23:in `load'
  from /Users/shiro/.rbenv/versions/3.0.0/bin/irb:23:in `<main>'
  • splat展開をした場合
    • *name とすることで、greeting("DeeDee", "Marky") としている引数が配列として展開されて、joinメソッドに渡されています。
irb(main):009:1* def greeting(*names)
irb(main):010:1* "#{names.join('')}、ハロー!!"
irb(main):011:0> end
irb(main):012:0*
=> :greeting
irb(main):013:0> greeting("DeeDee", "Marky")
=> "DeeDeeとMarky、ハロー!!"

splatは、アスタリスクという意味でもあるようです。

splatの意味・使い方・読み方|英辞郎 on the WEB

個人的にはこのゲームのイメージから英語の意味を紐付けたりしました。

スプラトゥーン2 | Nintendo Switch | 任天堂

%記法

配列を[ ] を使わずに作成できます。%w %W を使います。

  • %w の場合
    • スペース区切りで配列に格納されます。
irb(main):023:0> ramones = %w(We are Ramones! Hey\nho\nlet's\ngo!!)
=> ["We", "are", "Ramones!", "Hey\\nho\\nlet's\\ngo!!"]
irb(main):024:0> puts ramones
We
are
Ramones!
Hey\nho\nlet's\ngo!!
  • %W 大文字の場合。
    • 改行文字\n タブ文字\tなどは、irb上の返り値では、そのまま出力されるが、変数などに代入しputsなどで出力すると実際に改行、タブで区切られ出力されます。
irb(main):021:0> ramones = %W(We are Ramones! Hey\nho\nlet's\ngo!!)
=> ["We", "are", "Ramones!", "Hey\nho\nlet's\ngo!!"]
irb(main):022:0> puts ramones
We
are
Ramones!
Hey
ho
let's
go!!
=> nil

\n や\t は文字コードではなくバックスラッシュ記法です。

リテラル (Ruby 3.0.0 リファレンスマニュアル)

charsメソッド、splitメソッド

charsメソッドは、文字列を一文字一文字分解して配列にするメソッドです。

irb(main):025:0> 'RAMONES'.chars
=> ["R", "A", "M", "O", "N", "E", "S"]

splitメソッドは、引数で渡した区切り文字(今回は,で区切っている)で文字列を配列に分解するメソッドです。

irb(main):027:0> 'Joey, Johnny, DeeDee, Marky'.split(',')
=> ["Joey", " Johnny", " DeeDee", " Marky"]

chars の読み方

今週2回目の「どう発音するか?」問題。笑

今回はcharsがターゲットになりました。 元々の単語は、character になります。

チャー派とキャラ派。どちらもいい勝負でしたが、結果は....? ちなみに私はチャー派で、ギタリストのcharに馴染みがあるため、自然とチャーと言ってました。

結論ですが、どっちでもいいらしいです。笑

ですが、こういった小ネタ的な話題で盛り上がれるのも輪読会のひとつの楽しみでもあります。

ちなみに、Paizaが取ったアンケートではチャー派の勝利です!!

Array.new

配列は[ ] で作成することが多いですが、Array.newを使って作成する方法もあります。

ちなみに、[ ] はメソッドでもあります。

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

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

下記、同じ意味のコードです。

irb(main):029:0> ramones = []
=> []
irb(main):030:0> ramones = Array.new
=> []

第1引数を渡すと、その個数分の要素が追加されます。初期値はnilです。

第2引数を渡すと、要素が置き換わります。

irb(main):032:0> ramones = Array.new(4)
=> [nil, nil, nil, nil]
irb(main):033:0> ramones = Array.new(4, 'Hey')
=> ["Hey", "Hey", "Hey", "Hey"]

ミュータブル、イミュータブル

普段馴染みのない単語なので、意味を忘れがちなミュータブル、イミュータブル。

ミュータブルmutable(変更可能な)と、イミュータブルimmutable(変更できない)が「どっちがどっち?」と、ごっちゃになるが、ミュータント・タートルズで覚えることにしました。突然変異。

あと、illiegal < = > ligalの対義語と同じ法則なので、覚えておきたいと思います。

Rubyにはイミュータブルなクラスや値がいくつかあります。基本のデータ型は下記の4つです。

  • 数値(Integerクラス、Floatクラス)
  • シンボル(Symbolクラス)
  • true / false
  • nil

言い替えると、Integerクラスやシンボルなどは、そもそも破壊的なメソッドは存在しないということです。

参考書籍

🍒 まとめ

今週は、配列や繰り返し処理ついて深堀りしていくことができました。

破壊的メソッドについて、深く考えて使うことがなかったのですが、今週の学びを通してプログラムに不具合を与えかねない危険なメソッドであることが理解できました。ミュータブル、イミュータブルも今回しっかり学べ理解することができました。

「同じ値で同一のオブジェクト」なのか?「同じ値で異なるオブジェクト」なのか?意識してプログラムを書く必要があります。今後、不具合が起きたときに、今回学んだことを活かしデバックしていきたいと思います。

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

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

f:id:shirotamaki:20210619091936p:plain

🍒 はじめに

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

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

🍒 輪読会 第3週目まとめ

第4章4.1.1〜第4章4.6.5まで

期間:2021年06月07日〜2021年06月11日

今週から第4章の「配列や繰り返し処理を理解する」へ突入!

hex と ints

  • hexは、16進数(hexadecimal numberの略)のことです。

  • 進数の英語表現

    • 2進数: binary number
    • 8進数: octal number
    • 10進数: decimal number
    • 16進数: hexadecimal number

進数 - Wikipedia

  • ints は、integer(整数型)のことです。

でもなぜ? int ではなくて、 ints なのか?

以下、メンターさんに質問してみたところ回答をいただきました。

Ruby界隈はrailsの影響で特に配列が入ってる変数は複数形にするという文化が強いからできた略語に見えますね。

JavaC言語などでは、int と表現されるようです。

なるほど…ややこしい...汗

プログラミングでよく使う英単語のまとめ【随時更新】 - Qiita

ちなみに、るりま(Rubyリファレンスマニュアル)でsが付く単語が他にもありました。

arguments(実引数)を、args と表現、

parameters(仮引数)を、params と表現してありました。

仮引数(parameter)と実引数(argument)

この2つの「引数」もややこしいので、整理したいと思います。

まずは、parameterから

  • メソッドを定義するときに受け取る引数のこと。
  • 仮引数のこと。仮引数とは、「プログラム言語・数学などで関数を定義しているところに書かれている仮の数字・変数(パラメーター)」のことを指す。
  • params(パラムス)、またはparam(パラム)と略する。

paramsハッシュ 特殊な使い方

argument

  • メソッドを呼び出すときに、メソッドに渡す値や変数のこと。
  • 実引数のこと。実引数は、「プログラムの実行時に関数に引き渡される値となる引数」のことを指す。
  • args(アーグス) と略する。

paramsとargsの例

定義したcalculate(n)nがparams

呼び出しているcalculate(100)100がargs

irb(main):013:1* def calculate(n)
irb(main):014:1*   puts n * 10
irb(main):015:0> end
=> :calculate
irb(main):016:0> calculate(100)
1000
=> nil

配列を使った多重代入

  • 基本形
irb(main):017:0* a, b = 1, 2
=> [1, 2]
  • 応用編

競プロでよく使うパターン

標準入力からスペース区切りの数値を受け取り、配列にして返します。

irb(main):019:0> gets.split.map(&:to_i)
100 200 300 400 500
=> [100, 200, 300, 400, 500]

split('foo')で、区切ることもできます。

+ を区切りで指定してみます。

irb(main):022:0> gets.split('+').map(&:to_i)
100+200+300+400+500
=> [100, 200, 300, 400, 500]

do..end と  { } の使い分け

do...end、{} ともに、ブロックの範囲を表しています。

eachメソッドを例に説明します。

do..endがブロックの範囲です。eachメソッドで「配列の要素を最初から最後まで取り出す」指示を実行し、取り出した要素を順にブロックへ渡しています。

# 公式
変数名.each do |ブロック変数|
    繰り返したい処理
end

irb(main):037:0> beatles = ["YEAH!","YEAH!YEAH!","YEAH!YEAH!YEAH!"]
=> ["YEAH!", "YEAH!YEAH!", "YEAH!YEAH!YEAH!"]
irb(main):038:1* beatles.each do |x|
irb(main):039:1*   puts "ビートルズがやってくる#{x}"
irb(main):040:0> end
ビートルズがやってくるYEAH!
ビートルズがやってくるYEAH!YEAH!
ビートルズがやってくるYEAH!YEAH!YEAH!
=> ["YEAH!", "YEAH!YEAH!", "YEAH!YEAH!YEAH!"]

{ }ブロックで書き換えてみます。

同じ結果が返ります。1行でコンパクトに書きたいときは {}ブロック を使うとよさそうです。

irb(main):001:0> beatles = ["YEAH!","YEAH!YEAH!","YEAH!YEAH!YEAH!"]
=> ["YEAH!", "YEAH!YEAH!", "YEAH!YEAH!YEAH!"]
irb(main):002:0> beatles.each { |x| puts "ビートルズがやってくる#{x}" }
ビートルズがやってくるYEAH!
ビートルズがやってくるYEAH!YEAH!
ビートルズがやってくるYEAH!YEAH!YEAH!
=> ["YEAH!", "YEAH!YEAH!", "YEAH!YEAH!YEAH!"]

map / collect(エイリアス) メソッド

今のところ、一番使ったメソッドナンバーワンのmapメソッド。

輪読会でも好きなメソッドとして一番名前が上がっていました。

チェリー本にも記載がありましたが、配列処理の大半はmapでいけます。

空の配列を用意して、ほかの配列をループ処理した結果を空の配列に詰め込んでいくような処理の大半は、mapメソッドに置き換えることができるはずです。

irb(main):040:0> names = ["Lennon", "McCartney", "Harrison", "Starr"]
=> ["Lennon", "McCartney", "Harrison", "Starr"]
irb(main):041:0> names.map { |n|  "Mr." + n }
=> ["Mr.Lennon", "Mr.McCartney", "Mr.Harrison", "Mr.Starr"]

ちなみに、eachで書き換えるとこうなります。

irb(main):036:0> names = ["Lennon", "McCartney", "Harrison", "Starr"]
=> ["Lennon", "McCartney", "Harrison", "Starr"]
irb(main):037:1* name_mr = []
=> []
irb(main):038:0> names.each { |n| name_mr << "Mr." + n }
=> ["Lennon", "McCartney", "Harrison", "Starr"]
irb(main):039:0> name_mr
=> ["Mr.Lennon", "Mr.McCartney", "Mr.Harrison", "Mr.Starr"]

slect / find_all(エイリアス) メソッド

戻り値が真trueの要素を集めた配列を返すメソッドです。真になる要素がひとつもなかった場合は空の配列を返します。ブロックを省略した場合は、各要素に対しブロックを評価し真になった値の配列を返すような Enumerator を返します。class Enumerator (Ruby 2.5.0 リファレンスマニュアル)

ブロックなしでメソッドを呼ぶと返ってくる値について、メソッドのクラスが返ってくるようです。

irb(main):003:0> [1,2,3,4,5].select { |num| num.even? }
=> [2, 4]

irb(main):004:0> [1,3,5].select { |num| num.even? }
=> []

irb(main):005:0> [1,2,3,4,5].select
=> #<Enumerator: [1, 2, 3, 4, 5]:select>

reject メソッド

selectメソッドの反対。戻り値が偽falseになった要素を返します。

rejectは、拒否するの意。

5で割り切れない数だけを返します。

irb(main):014:0> [1,5,10,12,15,100,202,500 ].reject { |n| n % 5 == 0 }
=> [1, 12, 202]

find / detect(エイリアス) メソッド

findメソッドは、selectと似ていますが、ブロックの戻り値が真になった「最初」の要素を返します。

irb(main):021:0> [10,50,111,200,333].find { |n| n.odd? }
=> 111

inject / reduce(エイリアス) メソッド

たたみ込み演算を行うメソッドです。

まず、ブロックの第1引数には、メソッドの引数を入れ、その後は第2引数へブロックの戻り値を順番に入れていきます。

irb(main):022:0> num = [10, 100, 1000, 10000]
=> [10, 100, 1000, 10000]
irb(main):023:0> num.inject(1) { |result, n| result + n }
=> 11111
  • まずは、resultへ1が入ります。
  • その後、1 + n の nへ、配列から取り出した10が入ります。 1+ 10=11 この結果がresultへ入る。
  • その後、11 + n  の nへ、配列から取り出した100が入ります。 11+100=111 この結果がresultへ入る。
  • その後、111 + n  の nへ、配列から取り出した1000が入ります。 111+1000=1111 この結果がresultへ入る。
  • その後、1111 + n  の nへ、配列から取り出した10000が入ります。 111+10000=11111 この結果がresultへ入る。
  • 結果、11111 が戻り値になります。

&:メソッド名で短くキメる

ブロックの中身を短く簡潔に書く方法です。

競プロでよく使っている記法だったので理解しやすかったです。

以下の条件のときに使えます。

  • ブロック引数が1個
  • ブロックの中で呼び出すメソッドには引数がない
  • ブロックの中では、ブロック引数に対してメソッド1回呼び出す以外の処理がない
irb(main):026:0> ["1", "2", "3"].map{|v| v.to_i}
=> [1, 2, 3]

irb(main):028:0> ["1", "2", "3"].map(&:to_i)
=> [1, 2, 3]

範囲 Range

範囲オブジェクトは、Rangeクラスのオブジェクトです。

FizzBuzz問題をはじめ、いろんな場面で応用が効くので覚えておきたいオブジェクトです。

# 公式
(1..10) 1 2 3 4 5 6 7 8 9 10  最後の値を含む
(1...10) 1 2 3 4 5 6 7 8 9 最後の値を含まない

irb(main):031:1* (1..10).each do |n|
irb(main):032:1*   puts "#{n}回目のYEAH!"
irb(main):033:0> end
1回目のYEAH!
2回目のYEAH!
3回目のYEAH!
4回目のYEAH!
5回目のYEAH!
6回目のYEAH!
7回目のYEAH!
8回目のYEAH!
9回目のYEAH!
10回目のYEAH!
=> 1..10

irb(main):001:1* (1...10).each do |n|
irb(main):002:1*   puts "#{n}回目のYEAH!"
irb(main):003:0> end
1回目のYEAH!
2回目のYEAH!
3回目のYEAH!
4回目のYEAH!
5回目のYEAH!
6回目のYEAH!
7回目のYEAH!
8回目のYEAH!
9回目のYEAH!
=> 1...10

範囲オブジェクトで、to_aメソッドすると、配列になります。

(1..5).to_a など、繰り返し処理にも応用できます。

irb(main):004:0> (1..5).to_a
=> [1, 2, 3, 4, 5]

irb(main):005:0> (1..5)
=> 1..5

*splat展開でも同じように処理できます。[] で囲います。

irb(main):006:1* [*1..5]
=> [1, 2, 3, 4, 5]

irb(main):007:0> [1..5]
=> [1..5]

[ ] もメソッド

String#[] (Ruby 3.0.0 リファレンスマニュアル)

[] もメソッドなのは知りませんでした。

指定した位置(添字)の文字を返します。

irb(main):015:0> "TheBeatles"[3]
=> "B"

範囲オブジェクトと組み合わせてみます。

irb(main):012:0> name = "TheBeatles"
=> "TheBeatles"
irb(main):013:0> name[3..6]
=> "Beat"

著者の伊藤さんに質問してみた

輪読会内で解決できなかった疑問を直接質問してみました(第2週目に取り組んだ内容)

直接著者に質問できる輪読会。改めて凄いです....

伊藤さん(id:JunichiIto)、ご回答ありがとうございました!

質問内容

「Minitestのテストが失敗した場合のログについて」

今日のチェリー本の輪読会で3.3「FizzBuzzプログラムのテスト自動化」(p.76~)の項目を読み、テストコードと同じような流れで実際にモブプロ形式でテストをやっていたのですが、失敗した時に表示されるログのdiffの部分が分かりそうで分からないみたいな状態になってしまったので質問したいと思います。

# p.76より抜粋
 1) Failure:
FizzBuzzTest#test_fizz-buzz [lib/fizz_buzz.rb:23]:
--- expected
+++ actual
@@ -1 +1,2 @@
-"Fizz Buzz"
+# encoding: US-ASCII
+"16"

このログの中の、

@@ -1 +1,2 @@

の数字が具体的に何を表しているのかがよく分からなかったので、わかりやすく解説してもらえると嬉しいです。よろしくお願いします。

回答

Minitestは内部的にdiffコマンドを実行してdiffを表示しているはずです。

というわけで、Unixのdiffコマンドの仕様を調べるのが良さそうです。

この場合はUnified形式の説明が該当しそうです。

【Linux】diffコマンドで二つのファイルを比較する - Man On a Mission

冒頭で「--- 1つ目のファイル名」と「+++ 2つ目のファイル名」が表示されます。 その後に「@@ -1つ目のファイルの開始行と表示行数 +2つ目のファイルの開始行と表示行数 @@」が表示され、続いて該当箇所の内容が出力されます。

上記、最初の差異を例に取ると、「@@ -1,7 +1,6 @@」は、a.txtの1行目から7行分、b.txtでは1行目から6行分に該当する箇所が表示されていることを意味しています。 次の差異、「@@ -9,3 +8,4 @@」は、a.txtの9行目から3行分、b.txtでは8行目から4行分に街頭する箇所の表示を意味しています。

この説明で考えると、-1 +1,2

  • 1 = 期待値の1行目を表示中(つまり"Fizz Buzz"を指す)
  • +1,2 = 実際の値の1行目から2行分を表示中(つまり# encoding: US-ASCII"16"を指す)

ということになると思います。

TDD とは?

コラムで取り上げられていたテスト駆動開発

輪読会メンバーの yana_giさん(id:yana_g)に教えていただいた、TDDの権威、@t_wadaさんの動画を見てみました。

TDDについて理解しやすい。おすすめ動画です。

f:id:shirotamaki:20210625172120p:plain
「ライオンに怒られる」http://www.publickey1.jp/2018/t_wada01.gif

動画:50 分でわかるテスト駆動開発

channel9.msdn.com

以下、動画内容をまとめと感想になります。

  • TDDのゴール「動作するきれいなコード Kent Beck
  • 2つの道がある。
    • きれいな設計を考えてきれいなコードを書く。(完璧主義)
    • 書いて動かしてからきれいにしていく。(堕落、焦り、恐れ) ← TDDはこっち。
  • TDDのサイクル
    1. 次の目標を考える
    2. その目標を示すテストを書く
    3. そのテストを実行して失敗させる(Red)
    4. 目的のコードを書く
    5. 2で書いたテストを成功させる(Green)
    6. テストが通るまでリファクタリングを行う(Refactor)
    7. 1~6を繰り返す
  • TDDと黄金の回転

  • リファクタリング
    • リファクタリングの軸はブレやすい。(忙しいから。後でいいか。とりあえず動けばいいし。直近で恩恵はないし。自己満だし…)
    • つねにプログラミングの中に組み込もう。TDDの中に組み込む。
    • テストは増やすのは簡単だが減らすのは難しい。
  • 具体的に検証内容を書く(こうなってほしい)
  • ゴールから書いていく。(具体的な例を元に逆算して考えることがポイント)
  • 「ゴールはこうなるから、こうなってほしい」と、具体的に。
  • 小さく考えて、積み上げていくイメージ。
  • 問題を小さく分割し、To-Do リストを作成する。
  • 「テストコードにバグがあったらどうする?」問題。
    • テストから先に書いてエラーを出す。その後に実装する。

競プロでテストを書いてみた

TDDに触発され、早速競プロでもテストを書いてみました。 A問題なのですごく簡単なテストですが、今後はB、C問題でも書けるようになりたいと思います。

A - kcal

def atcoder(x, y)
  if x == y
    x
  else
    3 - x - y
  end
end


require 'minitest/autorun'

class AtcoderTest < Minitest::Test
  def test_atocoder
    assert_equal 1, atcoder(2,0)
    assert_equal 2, atcoder(2,2)
  end
end

参考書籍

🍒 まとめ

先週に続き例題問題では、Minitestを実際に動かすことでテストの理解がより深まりました。 また、TDDについて深堀りすることができたのも良かったです。今後も競プロでMinitestを書いてみたりと日頃から使うことで慣れていきたいと思います。

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

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

🍒 はじめに

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

第1週目のエントリーはこちら

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

🍒 輪読会 第2週目まとめ

第2章2.9.1〜第3章3.4まで

期間:2021年05月31日〜2021年06月04日

ビット演算

  • ビット
    • ビットは、コンピュータの世界における「0か1が入る箱」(1bit)のことを指しています。コンピュータが処理する最小単位です。ちなみに、この箱の数が8個集まるとbyteバイト(8bit = 1byte)となります。ビット - Wikipedia
  • ビット演算
    • ビット(0か1)に着目して、そのON/ OFFを操作すること。これをビット演算と言います。
  • ビット演算子
    • ビット演算子とは、整数に対してビット単位で演算を行う演算子のことです。
    • &|など。(演算子とは、式を記述する際に用いる演算内容を表す記号などのことです)

以下、ビット演算を使い2進数の数字を演算してみます。

0b は、数値の頭につけると2進数の表記になります。返り値は10進数です。

(8進数は、0、16進数は0xです)

以下は、10進数の4649を、頭に0bと付けることで2進数で表現しています。

irb(main):031:0> 0b1001000101001
=> 4649

.to_s(2) とすることで、結果を2進数で確認できるようにしています。

irb(main):018:0> (0b1111).to_s(2)
=> "1111"
  • & ビット積

2つを比較して、どちらも1なら1、どちらか片方が0の場合は0を返します。

irb(main):019:0> (0b1111 & 0b1010).to_s(2)
=> "1010"
  • | ビット和

2つを比較して、どちらかが1なら1、どちらも0の場合は0を返します。

irb(main):001:0> (0b1111 | 0b1010).to_s(2)
=> "1111"
irb(main):002:0> (0b1110 | 0b1010).to_s(2)
=> "1110"

2つを比較して、どちか片方だけ1なら1、どちらも0またはどちらも1の場合は0を返します。

irb(main):025:0> (0b1010 ^ 0b00110).to_s(2)
=> "1100"
  • >> 右ビットシフト

スイッチのON/OFFの状態を、右に1個ずらします。

irb(main):039:0> (0b1100 >> 0b1).to_s(2)
=> "110"
irb(main):040:0> (0b1100 >> 0b10).to_s(2)
=> "11"
  • << 左ビットシフト

スイッチのON/OFFの状態を、左に1個ずらします。

irb(main):028:0> (0b1000 << 0b1).to_s(2)
=> "10000"
irb(main):029:0> (0b1000 << 0b10).to_s(2)
=> "100000"

数値クラス(Numeric)

  • Integerクラス(整数)
  • Floatクラス(実数、少数)
  • Ratinalクラス(有理数
  • Complexクラス (複素数

複素数がよくwakaran状態だったので深堀りしてみました。

  • 実数  real number(実際に存在する数)
  • 虚数 imaginary number(想像上の数)
  • 複素数(complex number 複合、混合)

    • 実数+虚数の組み合わせを複素数といいます。
  • 有理数 は整数および分数のことを指します。

  • 無理数 は分数で表せない √2、π(円周率)などを指します。

これ以上深追いすると沼から抜け出せそうにないのでこのへんで切り上げたいと思います。 データサイエンス難しい…!

ちなみに最近読んでいる本をご紹介。数学的な考え方が勉強になりました

www.hyuki.com

Rubyの式の評価基準

大原則、Rubyでは「左辺から順番に式を評価」していきます。

  • &&の戻り値と評価を終了するタイミング

左から評価された式は、式全体のまたはが確定すると終了になります。

全部、の場合は最後に評価された値が返ります。以下のGeogeが返ってきてる例です。

今回の例は文字列を&&で比較していますが、文字列の内容は関係ありません。文字列であれば真の評価となります。

irb(main):056:0> "Paul" && "Paul" && "Paul"
=> "Paul"
irb(main):057:0> "Paul" && "Ringo" && "Jhon" && "George"
=> "George"

false と、nilが存在する場合は、そこで式の評価が終了となり、false、nilが返ってきます。

irb(main):058:0> "Paul" && nil && "Paul"
=> nil
irb(main):059:0> "Paul" && false && "Paul"
=> false
  • || の戻り値と評価を終了するタイミング

||を使う場合も同じルールに沿って評価されますが、||は「またはor」と訳せるので演算子の違いによる戻り値の変化に注意が必要です。以下は、PaulまたはRingとなりますが、'Paul' の時点でと評価されるのでPaulが返ります。

irb(main):074:0> "Paul" || "Ringo"
=> "Paul"

以下は、falsenilが左辺にありますが、Ringoを評価した時点でなら全体もになるので、最初のRingoが返ってきています。

irb(main):078:0> nil || "Ringo" || "Jhon"
=> "Ringo"
irb(main):079:0> false || "Ringo" || "Jhon"
=> "Ringo"

演算子の優先順位

普段、優先順位を気にすることが少ない演算子

andorは条件分岐ではあまり使われないようです。用途としては制御フロー(コンピュータプログラムで、命令が実行される流れを定めたもの)に 向いています。

高い
        !
        &&
        ||
        not
        and or
低い

if文と反対の意味で使えるunless文

条件が偽になった場合に処理を実行する条件分岐です。

まずは、普通のif文で表現してみます。!= は、値が違えばOKと判断されます。

irb(main):085:0> shot_count = 9
=> 9
irb(main):086:1* if shot_count != 10
irb(main):087:1* puts "ざんねん!"
irb(main):088:1* else
irb(main):089:1* puts "ストライク!"
irb(main):090:0> end
ざんねん!
=> nil

次は、unless文を使って書き換えてみます。

irb(main):117:0> shot_count = 7
=> 7
irb(main):118:1* unless shot_count == 10
irb(main):119:1* puts "ざんねん!"
irb(main):120:1* else
irb(main):121:1* puts "ストライク!"
irb(main):122:0> end
ざんねん!
=> nil

複数の条件を指定する時に便利なcase文

elsifでも表現できますが、「比較したいオブジェクトや式」があり、そこを基準に「場合分け」したい場合に使うとシンプルに書けます。

case 比較したいオブジェクトや式
when11に一致する場合の処理
when22に一致する場合の処理
else
    どれにも一致しない場合の処理
end

まずは、elsifを使ったパターン。

irb(main):012:0> name = 'Paul'
=> "Paul"
irb(main):013:1* if  name === 'Ringo'
irb(main):014:1*  "I play the drums!"
irb(main):015:1* elsif name == 'Paul'
irb(main):016:1* "I play the bass guitar!"
irb(main):017:1* else
irb(main):018:1* "I play the guitar!"
irb(main):019:0> end
=> "I play the bass guitar!"

case文を使い書き換えてみます。

case name が基準となり、nameがtrueを返したら実行されます。elsifを使ったパターンと比べても可読性がよくシンプルに書くことができます。 

irb(main):020:0> name = 'Paul'
=> "Paul"
irb(main):021:1* case name
irb(main):022:1* when 'Ringo'
irb(main):023:1* "I play the drums!"
irb(main):024:1* when 'Paul'
irb(main):025:1* "I play the bass guitar!"
irb(main):026:1* else
irb(main):027:1* "I play the guitar!"
irb(main):028:0> end
=> "I play the bass guitar!"

三項演算子

コードレビューを何度か受けて使えるようになり、今は普段から意識して使っている三項演算子

コードを短く書くことができるので、何となくイケてる感じがだせるので好きです笑。輪読会でも一行でバシッと書けてカッコいい!という意見が多かった人気の書き方です。

とはいえ、何でもかんでも使えばいいものではないようで、可読性には注意する必要があります。

  • 公式 式 ? 真だった場合の処理 : 偽だった場合の処理

当時、コードレビューで指摘を受けたコードを取り上げたいと思います。

まずは、自分で考えて書いたベーシックなif文のプログラムです。

if options["y"]
  year = options["y"].to_i
else
  year = Date.today.year
end

上記のif文を三項演算子で書き換えてみます。スッキリ!

year = options["y"] ? options["y"].to_i : Date.today.year

角谷さんにレビューしてもらった話

少し前の出来事ですが、三項演算子 ternary operatorについてもうひとつ。

TwitterでBadコードと、Goodコードをツイートしたところ、 なんと、角谷さんにレビューしていだきました!

Badコードの例

自分なにり考えてみたGoodコードの例

角谷さんにレビューいただいたGreatコードの例

odd と even の覚え方

odd(奇数)even(偶数)をいつも取り違えてしまう問題...

覚え方について輪読会で質問してみました(輪読会はこういった小さな疑問も気軽に聞けるのがいいですね) みんなの覚え方を聞いて面白く参考になりました。

  • oddは3文字なので奇数。evenは4文字なので偶数。
  • デヴィット・ボウイ(odd eyes、Space Oddity)

これまた完全な余談ですが、デヴィット・ボウイの名前を聞くとなぜか曲より先に思い出してしまう戦場のメリークリスマス。「メリークリスマス、ミスターローレンス!」声に出して言いたくなる名台詞です。

メソッド定義はメソッド名の symbol が返り値になる

メソッドを定義すると返ってくる、:foo

気になって調べたところ、メソッド名のシンボルでした。

irb(main):017:1* def foo
irb(main):018:1* end
=> :foo

エイリアスメソッド alias method

メソッドの別名のことです

るりまにも書いてありましたが、最初はまったくわかっていませんでした(気づきませんでした)。

自分でエイリアスメソッドを定義することも可能です。

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

aliasという英単語、プログラミング学習を始めてから初めて知った言葉のひとつだけど、「偽名」という意味で使うことを今日犯罪ドキュメンタリーを見ていて知った。

トミーさん(id:eatplaynap329)が取り上げていたエイリアスの補足情報!なるほど〜おもしろい!

require、require_relative、loadの使い分け

requireは、「re(再び)quire(求める)〜を必要とする、要求する」の意味があります。 標準ライブラリやgem(外部ライブラリ)は、事前にライブラリを読み込まないと使えません。 ライブラリを読み込む際には、ファイルへrequire 'ライブラリ名' と書きます。

まずは、requirerequire_relativeの使い分けについてです。 結論としては、ライブラリやgemをrequireするときはrequireを使い、自前で書いたコードを読み込むときはrequire_relativeが望ましいようです。

requireは、自分が今実行しているディレクトリ(カレントディレクトリ)が基点になります。

require_relativeは、自分のファイルパスが起点として、読み込むファイルを指定できます。

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

$ tree
    /rindokukai
          └── /ruby-book
                ├── /lib
                │   └── rgb.rb
                └── /test
                    └── rgb_test.rb
  • require

自分が今いるディレクトリが基点になります。

下記の例では相対パスを記述しています。実行しているパスが基点になりますので、下記で記述しているパスの意味は、ruby-bookの一段上のディレクトリを基点(つまり/rindokukaiディレクトリに今いるという事)としてrequireする。と表しています。例えば、/libディレクトリに移動してテストを実行しすると、エラーが表示されます。

require 'minitest/autorun'
require './ruby-book/lib/rgb'

または、相対パスではなく、絶対パスを記述することでrequireすることもできます。

絶対パスを記述すれば、自分が今いるディレクトリは関係ないので予測しづらいエラーを回避できます。

require 'minitest/autorun'
require '/Users/shiro/rindokukai/ruby-book/lib/rgb'
  • require_relative

現在のrgb_test.rbファイルを基点として指定します。下記はrgb_test.rbファイルにに記述してあります。自分のファイルパスが起点となりますので、自作のプログラムではrequire_relativeが推奨されています。

require 'minitest/autorun'
require_relative '../lib/rgb'
  • load

無条件に毎回読み込みが行なわれます。逆にrequireは一度しか読み込まれません。一般的に、loadは設定などのファイルを読みこませることが主な用途のようです。load絶対パスの指定が必要になります。

putsメソッド、printメソッド、pメソッド

こちも似たようなメソッドの代表格になります。

ひとつずつ見ていきたいと思います。

  • putsメソッド
    • 出力後に改行される
    • 要素ごとに改行される
    • 配列をputsすると各要素が改行されて出力される
    • 呼び出すメソッドはto_s (Stringを返す)
    • 戻り値はnil
irb(main):044:0* a = 1
=> 1
irb(main):045:0> puts a
1
=> nil
irb(main):046:0> a.class
=> Integer

irb(main):029:0> puts [1,2,3]
1
2
3
=> nil
  • printメソッド
    • 出力後に改行されない
    • 呼び出すメソッドはto_s (Stringを返す)
    • 戻り値はnil
irb(main):042:0> print [1,2,3]
[1, 2, 3]=> nil
irb(main):043:0> print 123
123=> nil
irb(main):047:0> p [1,2,3]
[1, 2, 3]
=> [1, 2, 3]

irb(main):067:0> p "123\nabc\t"
"123\nabc\t"
=> "123\nabc\t"

Minitestを使うためにはrequireが必要

Minitestとは、テストを自動化するためのテスティングフレームワークです。

library minitest/unit (Ruby 1.9.3)

Rubyには最初からインストールされています。

しかし使用するためには、`require 'minitest/autorun' と書き、ライブラリを事前に読み込む必要があります。

また、classに継承するためにはMinitest::Testと書く必要があります。(クラスの継承)

require 'minitest/autorun'

class MusicTest < Minitest::Test
    def test_music
        asser_equal 'BEATLES', 'beatles'.upcase
  end
end

Minitestで使用する主要な3つのメソッド

以下の検証メソッドを使います。他にもたくさんメソッドが容易されているようですが、チェリー本では以下3つだけが使用されています。まずはこの3つを使いこなせるようにしたいと思います。

  • assert_equal b, a aがbと等しい場合はパスする。
  • assert a aが真であればパスする。
  • refute a aが偽であればパスする。

assert は「結びつける、〜ということを断言する」の意。

refute は、「〜の誤りを証明する」の意

assertion (アサーション)とは、オブジェクトや式を評価して、期待された結果が得られるかどうかをチェックするコードのことです。

refureメソッドとassert_notメソッドの違い

上記のrefuteメソッドと似たassert_notメソッドなるものが存在します。

輪読会で上記の疑問が持ち上がり、卒業生の(id:masuyama13)さんのブログを参考にさせていだきました。

Ruby refute と assert_not の違いを調査 - No Solution for Life

irb

irb は Interactive Ruby の略です。interactive(双方向、対話式) irb を使うと、Ruby の式を標準入力から簡単に入力・実行することができます。

library irb (Ruby 3.0.0 リファレンスマニュアル)

普段からirbを使い実際の動きを確認するようにしていますが、今までちゃんと活用できていないことを痛感しました。その中でもirbを起動する場所(カレントディレクトリ)が影響することについては、まったく知りませんでした。どこで起動しても同じものだと思っていました。

こういった普段何気なく使っているツール等についても、輪読会を通してinteractiveに学習することで、気付きがあり学ぶことができています。

参考書籍

🍒 まとめ

自信のなかったMinitestの項目を無事終えることができました。

第3章は、プラクティスを進める上でテストコードが必須ではなかったため当時は軽く読み流していました。そのためwakaran状態だったのですが、今回輪読会を通してwakaru に変わり、今週も輪読会効果は絶大でした!

特に、モブプロのドライバーとして自分で手を動かしながらコードを確認することができたのが大きかったです。エラーコードを出したり、パスさせたり、「何がどうなっているのか?」実際に動かしてみることが理解の助けになりました。

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

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

f:id:shirotamaki:20210619091936p:plain

🍒 はじめに

チェリー本の輪読会に参加し4週間が経ちました。 https://shirotamaki.hatenablog.com/about 6月29日に登壇するLT会【初心者歓迎】Ruby LT会@オンライン - connpassのネタ探しも兼ね、輪読会で学んだことをブログ記事にまとめたいと思います。

まずは第1週目のまとめ記事になります。2週目以降については随時エントリーしていきたいと思います。

では早速。

フィヨルドブートキャンプでは、有志が集い輪読会が開催されています。

主催者の トミー さん(id:eatplaynap329)の呼び掛けにより始まった輪読会(トミーさんいつもありがとうございます!)

今ではレギュラーメンバー7名に加え、日によりますがラジオ参加を含めると最大16名近く集まる一大派閥? 笑 です。 オンライン上の集まりとあって、始めた当初はぎこちなかったのですが、今ではみんなとワイワイ楽しく開催しています。

まずは簡単に輪読会の概要を書いてから、本題の学んだ内容を書いていきたいと思います。

🍒 概要

課題本

gihyo.jp

通称:チェリー本 (当ブログでは今後チェリー本と記載を統一させていただきます)

輪読会の目的

  • Rubyを楽しむ
  • チェリー本を深く理解する
  • 得た知識をみんなで共有する
  • 疑問をたくさん持ち、著者の伊藤さんに直接質問してみる(伊藤さんはフィヨルドブートキャンプのメンターもされています)

輪読会の形式

  • 特に期限を設けた輪読会ではないため、第1章から順番に読み進めていく形式を取っています。
  • 必要に応じてモブプロを行い、実際に動きを確認しながら進めていきます。

参加条件

開催日時・場所

  • 平日 9:00〜10:00
  • Discordの輪読会チャンネル

🍒 輪読会 第1週目まとめ

では本題へ。

第1週目で学んだことについて書きたいと思います。

第1章1.1.1〜第2章2.8.6まで

期間:2021年05月25日〜2021年05月28日

Rubyのバージョンは?

Rubyのバージョンは「3.0.0」で進めていくことにしました。(輪読会スタート当時の安定版は3.0.1)

本書はRuby2.4.0を元に書かれていますが、必要に応じて著者の伊藤さんのQiita記事で補完すれば、バージョンは3.0.0で問題なさそうです。

Ruby 3.0で発生する「プロを目指す人のためのRuby入門」との差異について - Qiita

Rubyのバージョンの見方

例: 3.0.0

Ruby のバージョンは、major.minor.teeny という3つの形式で表されています。

  • majorバージョンは、アーキテクチャやコンセプトの変更が行われるとバージョンアップします。
  • minorバージョンは、大幅な仕様変更や機能追加されるとバージョンアップします。
  • teenyバージョンは、軽微な仕様変更、小さな機能追加等が行われるとバージョンアップします。(teenyは「小さな」の意)
$ ruby -v
ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19]

エディタは何を使うの?

エディタについては、各々自由に好きなものを使うことになっています。

しかし、参加メンバーに伺うとRubyMineが圧倒的多数を占めていました。 私自身、VSCodeとRubyMineしか使ったことがなく使用歴も浅いため、RubyMineの便利さにまだそこまでメリットを感じていませんでした。しかし、長くRubyMineを使っている方や現役のプログラマの方のご意見を伺うと(著者の伊藤さんもRubyMineを愛用している)、「Rubyを使うならRubyMine!!」と、圧倒的な人気を誇っているようで、Rubyを書くことに適したとても拡張性の高いエディタであるのは間違いなさそうです。まだまだ使いこなせていないので、輪読会を通してRubyMineとも仲良くなりたいと思います。

丸め誤差

チェリー本ではコラムの項目で取り上げられている内容ですが、きちんと理解できていなかったため輪読会では時間を多めに取り見直しました。同じ受講生の方が、この話題をブートキャンプ内で取り上げておりそちらのまとめた日報を参考にさせていただきました。

他、以下書籍も参考にしました。

キタミ式イラストIT塾 基本情報技術者 令和03年:書籍案内|技術評論社

実際にirbを使い動かしてみます。 コンピュータの計算では、10進数を2進数へ変換して計算されるため以下のような結果となります。

irb#1(main):001:0> 0.1 * 3.0
=> 0.30000000000000004

Rational(有理数クラス)を使うことで丸め誤差問題を解決できます。 有理数とは、「整数および分数」のことです。

irb#1(main):003:0> 0.1r * 3.0r
=> (3/10)   

# 10分の3 

rationalizeメソッドを使うことでRationalクラスの数値に変換できます。

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

irb#1(main):008:0> a = 0.1
=> 0.1
irb#1(main):009:0> b = 3.0
=> 3.0
irb#1(main):010:0> d = a.rationalize * b.rationalize
=> (3/10)

小数点に戻したい場合は、to_ffはfloatのf。浮動小数点数の意。

irb#1(main):011:0> d.to_f
=> 0.3

Rubyでは(Ruby以外の言語でもよく発生するらしい)丸め誤差問題を回避するため、上記の対応を行う必要があります。少数を扱う計算で思わぬ結果に出くわしたとき、今回の件を思い出し対処したいと思います。

falseとnil以外はすべて真(true)

Rubyの真偽値。 falsenilであれば偽になる。他の言語だと珍しいことのようです。 各言語におけるtrue/falseまとめ - 昼メシ物語

if文のelseは省略可能

条件分岐で多用しているif文。else(elsifも同様)が不要なのは知らなかったです。 今までずっと付けていた気がする....汗。今後は外していきます。

後置if

Rubyのif文は修飾子として文の後ろに置くことができます。 まずは通常のif文から。

irb(main):004:0> x = "foo"
=> "foo"
irb(main):005:1* if x == "foo"
irb(main):006:1*   puts "bar"
irb(main):007:1* end
bar
=> nil

後置ifを使い書き換えてみます。 一行でシンプルに書けます。競プロとかで使いこなしたいです。

irb(main):008:0" puts result = "bar" if x == "foo"
bar
=> nil

printfメソッドとsprintfメソッドの違い

printfsprintfメソッドのfは、formatから来ています。formatはエイリアスメソッド。 指定されたフォーマットの文字列を作成することができるメソッドです。

  • pritntfメソッドは、整形した文字列をコンソールに出力する。
  • sprintfメソッドは、整形した文字列をオブジェクトにして返す。

%bは、整数を2進数表現で出力する指定子です。 Kernel.#format (Ruby 3.0.0 リファレンスマニュアル)

printfメソッド

nilが返ってきます。

irb(main):005:0> printf('%b', 4)
100=> nil

sprintfメソッド

文字列オブジェクトが返ってきます。

irb(main):006:0> sprintf('%b', 4)
=> "100"

メソッド名は「ひらがな」「漢字」、そして「絵文字」もOK

普段、英語表記でしかメソッド名を命名したことがなかったので読み直してみて改めて驚きました。

絵文字もメソッド名にできるなんて遊び心があって面白いですね。

irb(main):004:1* def ちぇりー
irb(main):005:1*   puts "さくらんぼ"
irb(main):006:1* end
=> :ちぇりー
irb(main):007:0> ちぇりー
さくらんぼ
=> nil

irb(main):008:1* def 錯乱坊
irb(main):009:1*   puts "赤い果物"
irb(main):010:1* end
=> :錯乱坊
irb(main):011:0> 錯乱坊
赤い果物
=> nil

irb(main):012:1* def 🍒🍒🍒
irb(main):013:1*   puts "絵文字"
irb(main):014:0> end
=> :🍒🍒🍒
irb(main):015:0>  🍒🍒🍒
絵文字
=> nil

returnは、メソッドを途中で脱出するときに使われることが多い

普段は省略されることの多いreturn文

他の言語経験者だと違和感が強いらしいです。

returnを書かなくても結果は同じ。以下は書いているパターン。

irb(main):007:1* def add(a,b)
irb(main):008:1*   return a + b
irb(main):009:1* end
=> :add
irb(main):010:0> add(5,7)
=> 12

上記の使い方とは別で、returnはメソッドを途中で脱出するときに使わることが多いです。 下記、条件が一致したときにメソッドをすぐに終了させる例です。

irb(main):014:1* def min(x, y)
irb(main):015:2*   if x < y
irb(main):016:2*     return "xの方が小さい"
irb(main):017:1*   end
irb(main):018:1*   "yの方が小さい"
irb(main):019:1* end
=> :min
irb(main):020:0> min(4, 6)
=> "xの方が小さい"
irb(main):021:0> min(7, 3)
=> "yの方が小さい"

ガード節(Guard Clause)

Rubyに限らず、多くのプログラミング言語リファクタリングで有用な実装手法です。 「ガード節」「ガード条件」「ガード構文」などと呼ばれています。

return foo if bar (barがtrueだったらfooを実行)といった形式を覚えておきたいです。

ちなみに、ガード節を書いた文の下一行は空けておくのがお作法らしいです。

また、完全なる余談ですが、ブログを執筆している今日6月18日はポールマッカトニーの誕生日です。 ハッピーバースデーポール!!

irb(main):016:1* def play(name)
irb(main):017:1*   return 'nameを入力してください' if name.nil?
irb(main):018:1*
irb(main):019:2*   if name == 'Paul'
irb(main):020:2*     'I play bass guitar!'
irb(main):021:2*   elsif name == 'Ring'
irb(main):022:2*     'I play drums!'
irb(main):023:2*   else
irb(main):024:2*     'I play guitar'
irb(main):025:1*   end
irb(main):026:0> end
=> :play
irb(main):027:0> play('Paul')
=> "I play bass guitar!"
irb(main):028:0> play(nil)
=> "nameを入力してください"
irb(main):029:0>

参考書籍

🍒 まとめ

第一週目を終えた率直な感想としては、「え?こんなこと書いてあったけ?」の連続で、改めて人間は忘れる生き物であると思い知らされました。

忘却曲線 - Wikipedia

しかし、何度も読み返すことで知識が定着し、そこから多くの学びを得ることができているのは間違いありません。良い教科書を何度も読み直すことの大切さを改めて痛感し、知識が知恵になっている感覚です。 また、輪読会の効果をとても感じています。疑問を持ちその場で共有し解決していけることや、自分では読み取れなかった情報を他のメンバーからの共有で気づけたりなど、これは一人では得れない学びです。

今回記事にまとめた第1週目は、本書を読み進めると同時に輪読会の進め方の意見を出し合いつつ、時間配分、司会決めなどルール整備も行いました。ルール整備とはいってもガチガチな取り決めはなく、上記輪読会の目的に沿って、まずは「楽しむ」を念頭におき、みんなでワイワイやっています。

まだ始まったばかりですが、会の前後では雑談をしたり、「チェリー本終わったら別の本でもやりたいですね〜」と、次回の候補本の話しがあったり、輪読会を通して同じ目標を持つ仲間ができとても楽しいです。

今後も上記スケジュールで随時開催しておりますので、気になった受講生の方はもちろん、卒業生、メンター、アドバイザーのみなさん!ぜひ遊びに来てください!お待ちしております〜!

最後に、著者の 伊藤さん(id:JunichiIto)、卒業生でもあり先輩プログラマの 森塚さん(id:sanfrecce-osaka)には日頃から多くのアドバイスをいただき感謝申し上げます!

今後ともどうぞよろしくお願いします!!

初めてのLT会vol.7を開催しました

f:id:shirotamaki:20210427213411p:plain
初めてのLT会vol.7

はじめに

2021年4月24(土)にフィヨルドブートキャンプ内で開催されたLT会。 今回、開催内容についてまとめましたのでブログに書きたいと思います。

speakerdeck.com

フィヨルドブートキャンプとは?

プログラマーとして転職を目指せるだけのスキルを身につけることを目標としたオンラインプログラミングスクールです。 現在、私もここで学習しておりプログラマ転職を目指しています。幅広く網羅された学習カリキュラムや豪華メンター陣。卒業までに平均900時間かかると言われており、日々の学習はとても大変ですが、メンターや卒業生、そして受講生同士との距離が近く、とてもアットホームなスクールです。

bootcamp.fjord.jp

そもそもLTって何?

LT(エルティー)は Lightning Talk(ライトニングトーク)の略で、Lightning は「稲妻」という意味。 5分程度の短いプレゼンのことで、短いこと以外基本的にルールはありません。 フィヨルドブートキャンプ内で行われるLT会は、主に「初めてLTをする方」向けの受講生が自主的に行うイベントになります。 Remoを使い、オンライン上で開催しています。

remo.co

LT(Lightning Talk)の歴史

giantech.jp

テーマ「プログラミング学習を通して得た成長」

今回のテーマは「成長」 6名の登壇者に皆さんそれぞれが学び感じた「成長」について発表してもらいました。

登壇者

@kasai441さん 「ログをみてできるようになること」

つい焦ってログを見ずに先走ってしまう傾向のある私には、改めてログの大事さが分かり勉強になりました。「英語は嫌だな〜」「ログ見ないでも何とかなるでしょ〜」と、理由を付けて避けてきましたが、しっかりとログを読む訓練をすることが、今後先の成長につながると思いました。逃げずに向き合いたいと思います!トップバッターという緊張感の中、とても落ち着いておられ、声も聞き取りやすく素敵でした。

speakerdeck.com

@udaikueさん 自分の学習ペースをつかむまで」

カープファンのudaさん。2番セカンドの大役を真正面から受け止め、そして打ち返す。とても素晴らしい発表でした! フィヨルドブートキャンプはカリキュラム量も膨大なので、そう簡単には卒業できません。私も同じく未経験からのスタートのため、今後先の事が不安になることも多く、udaさんの悩みにとても共感できました。自分の悩みや考えにしっかりと向き合い、自分の言葉で伝える。そんな姿に胸打たれました。「プラクティスファースト」この言葉は胸にしっかりと刻みたいと思います。

speakerdeck.com

@Hossoさん 「焦らずじっくり学習に取り組む大切さ」

ベーシストのHossoさん。リズムよく軽快な発表内容でとても聞きやすく楽しく拝聴できました。 自分も焦って進めてうまくいかない事が多いのでとても勉強になる内容でした。「負のスパイラル」まさにこの状態に陥ることがよくあり、他人は他人と、頭では分かっていても、つい気になってしまい上手くいかない(無限ループ)...。この悪循環にはまり込まないように、少しでも目に見える形でのアウトプットを意識し、焦らず学習に取り組んでいきたいと思いました。 speakerdeck.com

@otomiさん 「Rackから見るミドルウェアの世界」

先のプラクティスの内容なため少し難しい内容でしたが、そんな未経験者にも分かりやすい発表内容で、ミドルウェアの世界を垣間見ることができとても勉強になりました。特に、実演(デモ)では実際に動くコードを発表されていてイメージしやすく分かりやすかったです。DJ活動もされているotomiさん、LT後の質疑応答でDJの話になりましたが、好きなことに熱く面白くお話しできるのってとても素敵だなと思いました。 speakerdeck.com

@shirotamaki 「Rubyリファレンスマニュアルと仲良くなろう」

私のLT。前回ブログにまとめた内容を元にLT資料を作成しました。現在、Rubyのプラクティスに取り組み日々お世話になっている公式ドキュメント。今回発表することで、改めて一次情報の大切さを痛感した学びの多いLTでした。

以下、みなさんから頂いたあたたかいお言葉を一部ご紹介!

  • るりまとの付き合い方がとても参考になりました!一次情報大事!
  • 公式ドキュメントの大切さを改めて感じましたー!自分も逃げずにしっかり向き合おうと思いました。
  • 自分もRubyのプラクティスに入ったばかりのころはるびまを読むことに苦手意識があったのですが、結局欲しい情報は公式ドキュメントに全部書いてあるんですよね。 自分は現在比較的るびまの読み方に慣れてきた頃なんですが、改めてるびまをどう読めばいいか考えるきっかけになりました。また、一次情報の重要性も再認識しました。 イシューから始めよ、読んでみようと思います!
  • るりま難しいですよね!!技術書を読んだりるりまのヘルプで語彙を増やしたりという、始めたばかりの頃知りたかった具体的なアドバイスがたくさんあってよかったです!

speakerdeck.com

@kamiokanさん 「フィヨルドブートキャンプに参加して私の身に起きた8つの変化」

今回、LT登壇順は公平を期するために「あみだくじ」で行いました。そんな中決まった登壇最後のkamiokanさんの番。大トリにふさわしいとてもダイナミックな楽しいLTでした!フィヨルドブートキャンプに参加して起きた8つの変化。そのすべてが共感できました。なかでも7番目の『「わからない」ということに絶望しなくなった。』コツコツと積み上げ、「わからない」は伸びしろであるとポジティブに捉えること。絶望することはまったくない。とても勇気をもらえました。

speakerdeck.com

オーガナイザーとしての感想

以上、6名の方にご登壇いただいた今回のLT会。 皆さんそれぞれが学んだこと、感じたことをスライドにし、そして言葉にし自由に発表する、とても素敵な楽しい会でした! オンライン上という事もあり、北は北海道、南は沖縄まで幅広い方にご参加いただきました。 (メンターやアドバイザー、卒業生、そして現役生、参加人数は40名ほど) ご視聴いただいた方とは、オンラインのためチャット上でのやり取りになりましたが、とても盛り上がり皆さんに楽しんでもらえた会となりました。

今回、企画運営から携わらせていただきましたが、とても貴重な経験になりました。 普段学習では使わない、keynoteやRemo などのアプリケーションを覚えるよい機会にもなりました。

今回、オーガーナイザーをやろうと思ったきっかけでもある、Yusukeさんのブログ記事。 まさに、コンフォートゾーンを抜け成長できたとても貴重な経験になりました。 yskmtg.hatenablog.com www.lifehacker.jp

ゼロかイチでは大違い。メンターの伊藤さんがおっしゃっていた通り、 ゼロからイチになった瞬間、今回のテーマでもある一番の「成長」を感じた、そんなLT会でした。

さいごに

今回で第7回を終えた「初めてのLT会」

フィヨルドブートキャンプのLT会の目的にもある「LTの練習」

こんなにもよい環境でLTができる機会はあまりないのではないか?終わってみて改めて感じます。 LT会後に頂戴したアンケート結果や、チャットや日報などでいただくあたたかいお言葉やアドバイス

まだ登壇されたことのないフィヨルド生にはぜひ!登壇をオススメします! そして、まだ参加されたことのないフィヨルド生の方は、ぜひ一度参加してみてください!

ご登壇、ご参加いただいた皆さん、 そして運営のkomagataさん、machidaさん、 この度はこのような貴重な機会をいただきありがとうございました!

Rubyリファレンスマニュアル(公式ドキュメント)を読み解く

出典:photoAC

目次

はじめに

フィヨルドブートキャンプに参加し早いもので2ヶ月が経ちました。
FJORD BOOT CAMP(フィヨルドブートキャンプ)

bootcamp.fjord.jp

現在はRubyの学習に取り組んでいます。
そんな中、今回はRubyを扱う上では避けては通れない「Rubyリファレンスマニュアル」について書きたいと思い、久しぶりにブログを開きました。 今回テーマに取り上げたのは、私自身が公式ドキュメントの内容を読み解く力が弱く、苦手意識(理解が難しい…😓)があるのが理由です。アウトプットをすることで少しでもRubyリファレンスマニュアルと仲良くなれればと思い書いてみることにしました✍️

リファレンスマニュアルとは

リファレンスマニュアルとは - コトバンク
リファレンスとは - IT用語辞典 e-Words

一次情報の重要性

Rubyに限らずプログラミング言語には、公式ドキュメントが存在します。プログラミング学習において調べ物をするとき、まずは「一次情報」を確認するように言われます。

「一次情報を死守せよ」というのは、私の大先輩であり、師匠の一人が私にかつて授けてくれた教えの一つだが、これは実に正しく、真実にたどり着くための道の入り口であり、出口でもある。 安宅和人
引用:噛みしめることを大切にしよう - ニューロサイエンスとマーケティングの間 - Between Neuroscience and Marketing

学習当初(独学時)は、Qiitaやブログ記事など、取っつきやすい情報に触れ、そこから知りたい情報を得ていました。公式ドキュメントの存在は知っていましたが、難しさから避けていました。簡単に手っ取り早く理解できる、安易で分かりやすい記事に飛びつき、そこから情報を得て理解していた気になっていたと思います。
もちろん、正確で有益な情報も多くあると思いますが、初学者の私にとってはその判断が難しく、不正確な情報を掴まされることも多くあったと思います。

その後、フィヨルドブートキャンプで学習を進めることで、公式ドキュメントの重要性を理解し、何よりもまずは「一次情報」から確認する習慣を付けるようにしました。

Ruby公式ドキュメント

以下、公式ドキュメントとRubyリファレンスマニュアルは同義として書いています。

Rubyの公式ドキュメント

Rubyのバージョンごとに選択が可能になっています。 全て日本語であります。他の言語だと英語しかないものもあり、英語が苦手な私に取ってはとてもありがたいです😆

docs.ruby-lang.org

検索サーチサイト

Rubyリファレンスマニュアルには検索機能が付いていません。下記のサイトから調べたい用語等を入力し検索をかけ、リファレンスマニュアルに飛ぶことができます。

docs.ruby-lang.org

検索のTips

下記のサイトを参考に、chromeの検索バーからショートカットで飛べるように設定しました。 るりまを開く手間が省け時短になります。他のサイトでも応用がきくため活用しています。

既定の検索エンジンを設定する - パソコン - Google Chrome ヘルプ
ChromeでRuby関連の検索を楽にする - Re: 醤油の一升瓶じゃあ戦えない

なぜ難しいのか?

ここからが本題。

なぜ難しいのか?私なりの見解は以下です。

  • 分からない用語、記号が多すぎる。
  • 技術書独特の言い回し(文章構造が理解しづらい)
  • そもそもRubyの基本を理解していない

大きくこの3つが要因かと思っています。(あくまでも個人的な見解です)

まずは、分からない用語、記号が多すぎる。

公式ドキュメントは初学者を対象にしているわけではないため、Rubyで使う専門用語がバンバン出てきます。また、独自の表現方法である記号等もあります。Rubyを書籍等で一通り学んだレベルでは、なかなか理解できない用語も多いです。それが読み解く上で障害になっており、気づけばヤックシェービング状態に陥り抜け出せないでいることが多くあります...🐐

yak shaving(ヤックシェービング / ヤクの毛を刈る
これは「ある問題を解こうと思ったら別の問題が出てきて、それを解こうと思ったらさらに別の問題が出てきて…」ということが延々と続く状況を表しています。
yak shaving - ウィクショナリー日本語版

まさに蟻地獄にハマっていくかのごとく、どんどん深いところまで引きずられ、気づいたら全然別のところにいた(別のことをやっていた)なんて事も多く、時間が溶けていきます💦
個人的にはWikipediaのリンクを辿り、思考の旅に出ている感覚が嫌いではないので、ヤックシェービングで刈りまくろ〜とかなってしまいますが、いかんせん目的が「放浪」ではなく、たどり着きたい場所が明確に存在する「旅」なので、あまりフラフラしてばかりもいられないのが現実です。また、目的のない放浪になると、好きな方向に逃げがちなので、公式ドキュメントの難解さからつい外れて違うことをしてしまっていることが多くあります🧳

次に、技術書独特の言い回し(文章構造が理解しづらい)

技術書独特の言い回しが、普段、小説などの平易な簡単な文章にしか触れていない私にとっては難解で、理解するのが難しい要因にもなっています。現代に出された本なら読み解けますが、古典など何十年、何百年前の本を読み、「結局、何が言いたいんだ?」となるのと似た感覚に陥ります。 普段から、やわらかなソフトな食べ物ばかりよく噛まずに食べてきたツケが、今ここで歯と顎の退化として現れているのを感じます🦷

最後に、そもそもRubyの基本を理解していない

これを言ってしまうと、「イチから出直して来い!」となりますが、 インスタンス、クラス、モジュール、メソッド、変数やブロックや、その他いろいろ。Rubyの基本を理解していないことには、公式ドキュメントに書かれたものは、理解できないのは当たり前です📚 

どう立ち向かうのか?(読み解くのか?)

一言でいうと「真正面からぶつかって取り組んでいくしかない。」そう考えます。 裏技、テクニック的なこと、近道はあるのかもしれませんが、結局は遠回りが一番の近道だと思いました。また、一度に全部を理解しようとする。この考えもよくなく、少しづつ、一歩づつ理解に努めることで、「忘れた、理解できない。」そうなればまた立ち返って見直す。この繰り返し(反復)しかないと思います。この反復行動を習慣化することで、数カ月先、数年先の自分自身の成長に大きく影響すると思いました。

具体的な対応策

分からない用語、記号が多すぎる

まずは、公式ドキュメントで使われている記号を理解する。
このマニュアルのヘルプ (Ruby 3.0.0 リファレンスマニュアル)
「->」、「.#」、「#」など、公式ドキュメント独特の表現方法があります。何より一番始めに理解したい項目です。

ヘルプの読み方については以下が参考になりました。
Rubyリファレンスマニュアルの読み方をやさしく解説 - Qiita

その後、公式ドキュメントを読み進める上で、分からない用語に出くわしたら以下を確認。Ruby関連の技術書やソースが信用できるWeb情報等でも構わないと思います。
Ruby用語集 (Ruby 3.0.0 リファレンスマニュアル)
Rubyで使われる記号の意味(正規表現の複雑な記号は除く) (Ruby 3.0.0 リファレンスマニュアル)

上述した、ヤックシェービングにハマり倒して目的を失わないように注意しながら、公式ドキュメントを読み解くことに集中します。目的は、公式ドキュメントにあるメソッドやモジュールなどを自分のやりたいことに当てはめ、問題を解決したり、作りたいものを作ることです。

技術書独特の言い回し(文章構造が理解しづらい)

小さく分ける。
単語だったり、コードの一文だったり、分かる範囲で小さく切り分けて考えます。 全体で何を言っているのか分からない場合、小さく切り分けて、何言っているか分かるところまで分解していくしかないと思います。 また、これは言い回しとは違いますが、記載されているコードを実際に手元で確認し動きを見ることも大事だと思います。コードだけ見てても何が何だか分からないものも多いです。読み解く上で、コードを実際に打ち込んでみて、どんな動きをするのか?確認するようにしています。それから、「自分の言葉で言い換えてみる。」これも実践するように心がけています。難しい言い回しなら自分で言い換えてみる。理解するひとつの助けになっています。

そして、最終的にはやはり「慣れ」しかない。 こればっかりは、数をこなすしかないと思っています。

慣れない分野の文献は、誰にとっても難しい
Amazon.co.jp: 独学大全――絶対に「学ぶこと」をあきらめたくない人のための55の技法 eBook: 読書猿: Kindleストア

そもそもRubyの基本を理解していない

技術書を活用する。
体系的に学ぶのには一番適していると思います。
私は、以下の順で難易度を上げRubyの学習をしてきました。 まだまだ理解が十分ではなく、身につけられていない事も多いので、分からないことに出くわすたびに読み返しています。

book.impress.co.jp

gihyo.jp

gihyo.jp

こちらは、最近購入した技術書です。
同じ受講生の@eatplaynap329 さんから教えていただき、メソッド等の概要を掴む助けとして活用したいと思います。

tanoshiiruby.github.io

その他

アウトプットする。

誰かに説明する。自分に説明する。
上述した、自分の言葉で言い換えると同じですが、これも理解を深める上ではとても大切だと感じます。 ノートに書き出す、日報、ブログ、Twitterなどを活用して行うよう意識します。

質問する。助けを求める。

ひとりで悩んでても答えが出ないのなら、諦めることも大事。 必ず誰かが救いの手を差し伸べてくれると思います。

時間をあける

寝る。ご飯を食べる。散歩する。全然別のことをする…
意外にも原因はそこにあるもしれません。 人間休まず働き続けるのは困難です。時間をあけることで、頭の中が整理され、パッと答えが出ることもあります。自然の摂理に従います。

心持ち

ここまで、どのように立ち向かい、乗り越え、理解していくか書きましたが、 とは言っても「心折れる瞬間」は度々訪れます。

  • 何度読み返しても分からない。
  • 何が分からないかが分からない。
  • 何をすればいいかすら分からない。
  • 思考停止…😭

これまで幾度となく、このような気持ちになり心折れ、自分がどこにいるのか、どっちを向いているのか分からなくなることが多々ありました。今でもこの感じが消えることはなく、最近は慣れてきましたが、分からないことと共存している感じを覚えます。しかし、ずっと分からないことが同じではなく、つねにアップデートしているので、今日分からないことは明日分かっているし、明日分からないことは3日後には分かっている感じで、分からないことと共に成長している感じです。

この「何がわからないのかもわからない」というやつ。これはすごくツラいですが、プログラマーにとっては非常によくある状態です。
わからないときの心持ちについて - komagataのブログ

フィヨルドブートキャンプのメンターであるkomagataさんや、他のメンターの方も仰っていましたが、何十年もプログラマとして活躍されてきた方ですら、「分からない」はなくならいと言っていました。

まだまだ修行の身で、その境地に行き着くまでには長い年月がかかりそうですが、

「はいはい、わからないわからない、ワロスワロス

このような境地に辿り着けるように努力を続けたいと思います💪

さいごに

冒頭で一次情報を確認することに触れていながら、Qiita、ブログ記事等を載せていますが、あくまで参考資料(補助教材)として確認する意識を忘れないようにしたいと思います。 ルーツは公式ドキュメントであること。そしてルーツ以外の情報に触れる際は信用できるソースであるかを確認すること。
これからも、公式ドキュメントとは長い付き合いになり、ここから多くの学びを得ていくことと思います。今回ブログに書くことで、少しは仲良くなれた気がしています。今後も継続して読み解き、使い倒せるように努力したいと思います😆

「わかったつもり」は一種の安定状態であり、この状態を壊すことはもちろん、今の自分の理解が不十分であると自覚すること自体、ひどく難しい。逆に言えば、矛盾や齟齬に行き当たり苦しむことは、この安定状態を脱する絶好の機会であり、自分の理解を一段進めるリソースですらある。
Amazon.co.jp: わかったつもり~読解力がつかない本当の原因~ (光文社新書) eBook: 西林 克彦: Kindleストア