D IT Y

タマキ工務店のIT日記

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

f:id:shirotamaki:20210619091936p:plain

🍒 はじめに

チェリー本輪読会の第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

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

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

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

f:id:shirotamaki:20210620132803p:plain String#length (Ruby 3.0.0 リファレンスマニュアル)

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

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

require、require_relatve、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週目)