## 3/16 Rubyの真偽値はfalseまたはnil以外はすべてtrue:Ruby固有の特徴 if文の戻り値を変数に代入できる:greeting = if country == 'japan' elsif...のように書ける メソッド名はスネークケースで書く:hello_world のような形式 %記法でエスケープが不要になる:%!unkoburi!のように囲える ヒアドキュメント:<<-識別子 テキスト 識別子 の形式で複数行の文章を格納できる。式展開も使える。 <<-を途中で使うとインデントされる。引数として渡すこともできる。ヒアドキュメントを二つ使うと配列を作れる(これすごい便利じゃないか?) 配列の結合:[10,20,30].join で全部くっつく unless:ifの逆 でもこれ逆に頭がこんがらがりそう ==true , ==false は冗長なので使わない:それはそうだ case文:絶対に使うべき局面でもなぜか忘却してif文を使ってしまう message = case xxx when 'yyy' end のように使う 三項演算子:絶対に使うべき局面なのになぜか忘却して以下略 式 ? 真だった場合の処理 : 偽だった場合の処理 のように使う メソッドにデフォルト値の引数を付ける:def greet(country = 'japan')などで引数なしでjapanが引数として扱われる。(x, y=x)のようにするとyが無指定の場合にxと同じ値として扱われる !で終わるメソッドは破壊的メソッドだが、ついていないからといって破壊的ではないとは限らない:concatは付いていないが破壊的 エンドレスメソッド定義 endがいらない:def greet = 'hello!' lengthとsizeはどちらも”まったく”同じメソッド:なにか違うはずだろと思っていたのに…… 標準ライブラリと組み込みライブラリはイコールではない:同じだと思ってた putsとprintの差は改行の有無だが、pはオブジェクトそのものがメソッドの戻り値になる(p 123の後に123を参照すると123が戻ってくる、putsの場合はnil)、ppはpよりも整形してきれいに出力してくれる。pはオブジェクトをStringではなくinspectに変換している 配列で元の大きい添字を指定すると間の値はnilで埋められる:a=[1,2,3] a[4]=50などとすると[1,2,3,nil,50]となる 配列はa << 2 などで最後に要素を追加できる:コードを見た覚えがある割には自分で使ったことはなかった 削除はdelete.at(n)で行う。delete(n)だとnに一致する要素がまとめて削除される divmodというメソッドは商と余りを配列で返す 14.divmod(3)は[4,2]になる delete_ifメソッドを使うとdo |x|で条件を別に記述できる Rubyプログラマはfor文を使わない:確かに例文でほとんど出てこないので気にかかっていた。たまたまかと思いきや本当に使わないのか 配列の要素を順番に取り出す作業はeachメソッド、要素をどう扱うかはブロック(ブロックの中身に書くコード)の役割:ごっちゃになっていたのでようやく納得した 変数名の重複により他のものが参照できなくなることをシャドーイングという do endの代わりに{}でブロックをくくることもできる:僕が最初にうまく理解できなかった理由はこれだな .mapを使うとブロックの戻り値が配列の要素となる新しい配列が作成される:new = numbers.map { |n| n * 10}で配列numbersを10倍にした新しい配列が作れる 112ページまで ## 3/17 numbers.select {|n| n.even?} : このようにselectメソッドを使うと条件を満たした配列のみを作成できる。この例では偶数のみの配列が生成される numbers.find : findメソッドは戻り値が真になった最初の値のみを返す numbers.sum : 名前通り配列の要素を合計できる。文字列でも使える('')単純な連結ならjoinメソッドの方が楽だがsumは文字列の加工に優れる &:メソッド名でシンプルに書ける:ブロックパラメータが1つ、ブロックの中のメソッドに引数がない、メソッドを1回呼び出す以外の処理がない、といった条件をすべて満たすと [1,2,3,4,5,6].select{|n| n.odd?}を[1,2,3,4,5,6,].select{&:odd?}のように簡潔に書ける。演算子を使っている場合は不可能 (1..5)←これはRangeという名前のオブジェクトだった!:ただのそういう感じの簡略記法かと思っていた。点が三つだと5は含まれなくなる (1..5).to_aで値が連続する配列を作ることができる:これ””””答え””””だ。こういうものがあるといいと思ってた RBG変換器の実装を通じて:これたぶんもっと短くなる方法ありそうだな……と思っていたらすぐ下でsumを使った記法が書かれていた。ぜひものにしたい 123ページまで ## 3/19 to_intsメソッドのリファクタリングを通じて:空の配列を用意して、ほかの配列をループ処理した結果を空の配列に詰め込んでいくような処理の大半はmapメソッドに置き換えることができる……らしい 上級編に書かれていた多重代入➜scanメソッド➜mapメソッドを呼ぶからの&シンボ➜エンドレスメソッドの流れはカードバトのフィニッシのコンボみがある a.values_at(0,2,4)この形式で取得したい要素を複数指定できる。 a[a.size - 1]この形式で最後の要素を取得できる a[-1]これでもいける a.lastこれもいける a[開始地点,範囲] = 置き換える数字 で要素を置き換えられる a.concat(b)でaを破壊的にbと結合する(bは破壊されない) e, *f = 100,200,300このような書き方をするとはみ出した数字を含めた配列がfに代入される e, * = 100,200,300 この場合は100のみがeに格納されて他は無視される e, = 100,200,300 これも同じ a, *b, c, d = 1,2,3,4,5 この場合は間に挟まれた残りの要素がbに入る(2,3) 配列を配列にpushで代入する場合、スプラット演算子をつけなければ多重配列になる 上記の特性を活かしてwhen節で配列を複数の条件として展開できる 上記の特性を活かして簡潔な形で配列を連結させることもできる[-1, 0, *a, 4, 5] %w記法:これはフォーマッタが教えてくれた。%W大文字を使うとタブ文字なども使える 'Ruby'.chars この形式で文字を一文字ずつ分解して配列にできる 'Ruby,Java,Python'.split(',') 文字列から配列を作る a = Array.new(5, 0) 配列に初期値を設定して作る方法。この例では5つの0が配列に入る a = Array.new(10) {|n| n % 3 + 1} ブロックを使った初期値の設定例。引数の数だけ呼ばれてブロックの中身が要素の添字になる 第2引数デフォルト値を指定するとすべての配列が同じ文字列オブジェクトを参照するため、破壊的メソッドですべてが置き換わる ミュータブルとイミュータブル:イミュータブルなオブジェクトは破壊的変更の影響を受けない。主に数値、シンボル、真偽値、nil、Rangeはイミュータブル freezeメソッドを使うとイミュータブルなオブジェクトにすることができる with_indexはeach以外でも使えるmapやdelete_ifなど : Enumeratorクラスに属するものはwith_indexを呼び出せる 配列の要素分だけブロックパラメータを用意すると各要素の値が別々の変数に格納される ブロックパラメータを丸括弧で囲うとwith_indexなどで他のブロックが必要になる場合でも上記の挙動を実現できる 番号指定パラメータ:_1 このような形式でブロックに格納する変数を指定できる do..endの代わりに使う{}は結合度が高い:異なった解釈をする場合があるのでブロックに丸括弧が必須 しかしながらdo..endと{}は基本的には同じなのでendの後ろにドットをつけて.joinなどをつけても機能する 151ページまで ## 3/20 始点を持たない範囲オブジェクト:(10..) これで10以上を表す。そんなことできるんだ。逆も可能 numbers[2..]などで3番目以降の要素を取得する (nil..nil)で全範囲オブジェクトを作成可能 timesメソッド 5.times {|n| sum += n} などのように使う:知っているはずなのにこれまで使う機会がなかった 1ずつ増減させながら処理したい場合はupto/downtoメソッドが便利: 10upto(14) {|n| a << n} のような形式で1ずつ14まで増える配列が作れる 一定の数を増減させる場合はstepメソッドを使う : 1.step(10,2) {|n| a << n} これで2ずつ10未満まで増える while文 while 真である条件 処理 endで書く:Rubyだと影が薄い気がする。逆バージョンのuntil文もある for文 使わないけど一応ある: for n in numbers sum+= n endのように書く eachとの違いはローカル変数がforの外でも使えるところ 意図的に無限ループを作る:loop do 処理 end throwとcatch: これRubyでもあるんだ……と思っていたが他の言語のthrowとは意味が違っていた。breakの強化バージョンとして使う。catch :tag do ループ処理1 ループ処理2 throw :tag endで内側から一気に外側まで抜ける breakとreturnの違い:breakは繰り返し処理からの脱出だが、returnはメソッドからの脱出になる redo 繰り返し処理をやり直す:RPGの質問みたいなことができる countで制限回数を指定できる エイリアスメソッドがたくさんある理由:他の言語との整合性、直感性、あとからもっといい名前をつけた、英語との一体感 ここから第五章 ハッシュとはキーと値の組み合わせでデータを管理するオブジェクト:他の言語では連想配列やディクショナリ、マップと呼ばれている { キー1 => 値1, キー2 => 値2} ハッシュリテラルとブロックの見分け方:ロケットでキーと値が区切られている(ハッシュ)、ブロックパラメータがある(ブロック)、処理が書かれている(ブロック) ハッシュの利点:大量の値が格納されていても指定したキーに対応する値を高速に取り出せる ハッシュの比較:並び順が違っていてもキーと値の対応が同じであればtrue ハッシュのeachメソッド:ブロックパラメータを1つにするとキーと値が配列に順番に格納される シンボル:他の言語ではあまり見られない特徴らしい。コロンの後に続いて文字列を書くとシンボルリテラルを作ることができる。 シンボルの利点:文字列をよく似ているが整数として扱われるので文字列よりも高速に処理できる シンボルの利点2:同じシンボルは同じオブジェクトとして扱われる。なので大量の同じシンボルは文字列よりもメモリの効率に優れる。 シンボルの利点3:シンボルはイミュータブルなオブジェクトなので破壊的変更ができない シンボルの用途:ハッシュのキーに用いる。文字列よりも高速に値を取り出せる。キーは文字列である必要性がないのでよく使われる。 シンボルの用途2:可読性の向上。特定の数値で任意の状態を表すと計算効率はいいが可読性が悪い。シンボルを使うと効率をあまり犠牲にせずに可読性を高められる シンボルの利用でロケットを省略する:{japan => 'yen'}このように書くものを{japan: 'yen'}こうして書ける。圧倒的に記述量が減る。 両方ともシンボルにする: {japan: :yen} かなり使われているらしい ハッシュのキーはそれぞれ別のデータ型でも問題ないが推奨はされない。一方で値の方はよく混在する(例:人物目録を作る際は名前が文字列、歳が数値、人間関係が配列、電話番号がハッシュなどになったりする) キーワード引数:buy_burger(menu, drink: true, potato: true) end シンボルと似たような形式で可読性の高い引数を設定できる アスタリスク二個でハッシュの変数を指定すると中身をキーワード引数として利用できる メソッド定義側のキーボード引数はシンボルっぽいだけであってシンボルではない:しかし呼び出す側はれっきとしたシンボルである(紛らわしすぎる) ハッシュで使われるメソッド色々:keys(キーを配列として返す)、values(ハッシュの値を配列として返す)、has_key?(読んで字のごとく) 定義されていないキーワードを同時に受け取るにはアスタリスク2個の引数を最後に用意する 189ページまで ## 3/21 最後の引数がハッシュであればハッシュリテラルの{}を省略できる:楽だが運用に注意を要しそう メソッドの第1引数にハッシュを渡そうとする場合は必ず()を付けてメソッドを呼び出す必要がある ハッシュをto_aメソッドで配列に変換すると二次元配列になって返る 逆もできるがキーと値の組み合わせが配列に入った二次元配列になっている必要がある h = Hash.new { 'hello' } : Hash.newとブロックを組み合わせてデフォルト値を返すことで破壊的変更の影響を避けられる ...引数を使うと通常の引数とキーワード引数をまとめて委譲できる:先頭のいくつかの引数を取り出すこともできる %sでシンボルを作成できる。%iでシンボルの配列を作成できる 条件分岐内で直接変数に代入するテクニック(値が取得できれば真、できなければ偽) if currency = find_currencty(country) 処理 end &.演算子を使ってメソッドを呼び出すとnilの場合はnil、nilでない場合はその結果が返ってくる nilガード: limit ||= 10の形式でnilまたはfalseであれば10を代入するというような機能を持つ。nil以外の値を入れておきたいが書き換えられたくない場合に使う trueならtrue、falseならfalseというような条件分岐を書く場合はエクスクラメーションマーク2個を使った真偽値の型変換が有効に使える ここから第6章 正規表現ってマジで苦手だ。これまでもなるべく避けて生きてきたがついにTAMESAREの時が来たらしい 「書籍を読んでいると思ったらWebページに誘導された……なにを言っているのかわからねえと思うが」になった \d は1文字の半角数字を表す 文字の個数を限定するときは {n,m} や {n} というメタ文字を使う(量指定子) {n,m} は「直前の文字が n 個以上、m 個以下」の意味を表す また、 {n} とすれば「ちょうど n 文字」の意味になる 「AまたはBのいずれか1文字」表す場合は [AB] と書く [a-z] と書くと、「aまたはbまたはcまたは・・・yまたはz」の意味になる。 ただし、[-az] や [az-] のように、ハイフンが [ ] の最初、または最後に置かれると「ハイフン1文字」の意味に変わる。 なので [-az] や [az-] は「aまたはzまたはハイフンのいずれか1文字」の意味になる。 209ページまで ## 3/22 文字がない場合も指定する時は?を使う。これも量指定子の一つ。2文字以上の文字列に対しても使える。(ABC)?でABCがある、またはなし、を意味する ドットで「任意の一文字」を表すことができる 直前の文字が1文字以上、を表すには+を使う。これも量指定子。0文字以上の場合は*を使う キャプチャ:丸括弧で文字列を囲うと連番が付けられる $1,$2というように指定する キャプチャの除外:(:? )の形式で:?を先頭に加える \w で英単語を構成する文字 = [a-zA-Z0-9_]を意味する(RubyとJavaScript) A以外の任意の文字:[^A]で表せる 最小量指定子:*?や+?にすると最長ではなく最短のマッチを返す 素の^は行頭を表すメタ文字:^ + で行頭からスペースが1文字以上続く、という意味になる 素の$は行末を表すメタ文字:^ +$で行頭から行末までスペースが1文字以上続くという意味になる | でOR条件 [AB^] このように後方に^をつけると「AでもBでもない文字1文字」という意味に変わる /b 単語の境界を表す:\bt\bというような書き方でtメソッドを抜き出すようなテクニックがある (?<=abc) : この書き方で文字列の直後の位置にマッチする。肯定の後読みと言う (?=abc):この書き方で文字列の直前の位置にマッチする。肯定の先読みと言う (?)でキャプチャに名前を付けられる m[:name] シンボルで指定する。文字列でもできる 左辺に正規表現リテラルを置いて=~演算子を使うとキャプチャの名前がローカル変数に割り当てられる:ようは#{year}で(?)の中身が返る ↑変数に一旦入れると機能しない 組み込み変数:$~でオブジェクト全体、$&でマッチした部分全体、$1などでキャプチャを取得できる scanメソッド:引数で渡した正規表現にマッチする部分を配列に入れて返す '123 456 789'.scan(/\d+/)で["123","456","789"]が返る ↑正規表現に()があるとキャプチャされた部分が二次元配列の内側に入って返る。グループ化はしたいがキャプチャはしたくない(全体を取得したい)場合は(?:)で除外を行う []に正規表現を渡すと、文字列から正規表現にマッチした部分を抜き出す: text[/\d{3}-\d{4}/]で"123-4567" ↑マッチする部分が複数ある場合は最初にマッチした文字列のみ返る キャプチャを使うと第2引数で何番目のキャプチャを取得するか指定できる: tex[/(\d+)年(\d+)月(\d+)日/, 3]で"17"が返る キャプチャに名前を付けていると第2引数も名前で指定できる sliceメソッドは[]のエイリアスメソッドでつまり同じ効果を持つ:slice!で破壊的に取り除かれる splitメソッドに正規表現を渡すとマッチした文字列を区切り文字にして分解して配列として返す:text.split(/,|-/) でカンマまたはハイフンを区切り文字にするの意味になる gsubメソッド:第1引数の正規表現にマッチした文字列を第2引数の文字列で置き換える text.gsub(',', ':')で123,456が123−456になる。ハッシュに渡すこともできる。hash = {',' => ':'} text.gsub(/,|-/, hash)で123,456-789が123:456/789になる 第2引数を渡す代わりにブロックの戻り値で置き換える文字列を指定できる:text.gsub(/,|-/){ |matched| matched == ',' ? ':' : '/' } gsubとキャプチャを組み合わせて文字列を置換する:text.gsub(/(\d+)年(\d+)月(\d+)日/, '\1-\2-\3') このように連番指定は\1、\2の形で行う ↑ただし文字列をシングルクオートで囲うかダブルクオートで囲うかで書き方がかなり変わる。後者の場合はバックスラッシュが2つ必要なのでかなり面倒。そこでブロックを使うやり方も考慮に入る。: text.gsub(/\(d+)年(\d+)月(\d+)日/) do "#{$1}-#{$2}-#{$3}" end キャプチャが文字列の場合は\kのように先頭に\kを加える なお、公式リファレンスではブロックを使う方法が推奨されている プログラムの作成を通じて:これはいいものだ Regexp.new : 正規表現オブジェクトを作成する %r!文字!: スラッシュをエスケープせずに正規表現を作る %r{文字}:こっちのほうがわかりやすそう 正規表現オプション: /iは大文字小文字を区別しない /mはドットを改行文字にもマッチさせる /xオプションは改行やスペースが無視されコメントが書ける Ragexp.last_match : 正規表現のマッチやキャプチャを取得できる。フォーマッタにかけるとこれに置き換わる match? : マッチするとtrue、しなければfalseを返すのは他と同じだが内容を書き換えないので高速に処理できる 231ページまで ## 3/24 クラスの利点:堅牢なプログラムを作ることができる ↑nilではなくちゃんとエラーが返ってきたり、内容の変更を防止できる クラス:すべてのオブジェクトが属するもの。クラスが同じであれば使えるメソッドも同じ。 オブジェクト、インスタンス、レシーバ:クラスをもとにして作られたデータの塊がオブジェクト、場合によってはインスタンスと呼ぶこともある。メソッドとの関係を説明する場合においてはレシーバと呼ぶこともある。 ↑「2行目でUserオブジェクトのfirst_nameメソッドを呼び出しています。ここでのfirst_nameメソッドのレシーバはuserです」というように使う。 ↑つまり「メソッドを呼び出された側」というニュアンスを強調する時にレシーバと呼ぶ メソッド:オブジェクトが持つ動作をメソッドと呼ぶ。他のプログラミング言語では関数やサブルーチンと呼ばれている。 属性(プロパティ、アトリビュート):オブジェクトから取得したり設定できる値のことを属性と呼ぶ。 クラス名は必ず大文字で始める User.new : オブジェクトを作成する。この際にinitializeメソッドが呼ばれる。他の言語ではコンストラクタと呼ばれている。 インスタンスメソッドの定義:クラス構文の内部でメソッドを定義するとインスタンスメソッドになる。Class.methodの形式で呼び出せるようになる インスタンス変数:同じオブジェクトの内部で共有される変数。頭に@がつく。 ローカル変数のスコープ:その変数が宣言された位置から自身が宣言されたメソッドまたはブロックの終わりまで。ローカル変数は参照する前に必ず値を代入して作成しなければならない。 ↑インスタンス変数は作成する前にいきなり参照してもエラーにならずnilが返る インスタンス変数はクラスの外部から参照できず、したい場合は参照用のメソッドを作る必要がある イコールで終わるメソッド名:name=(value)のような形式でインスタンス変数を外部から変更するメソッドを作る時などに使われる。これをセッターメソッドと呼ぶ。アクセサメソッドとも呼ぶ 単純にインスタンス変数の内容を外部から読み書きするぶんにはattr_accessorが使える:これ「ゼロわか」でやったな。フォーマッタにかけるとこれに書き換わる。読み取り専用のattr_readerメソッド、書き込み専用のattr_writerなどもある。 クラスメソッドの定義:頭にself.のついたメソッドはクラスメソッドになる。そのクラスに関連しているがインスタンスに含まれるデータは使わないメソッドを定義する場合に使われる。class << self 処理 endとしてもよい メソッドの表記:インスタンスメソッドを表す場合にクラス名#メソッド名と書くことがある。クラスメソッドの場合はクラス名.メソッド名、またはクラス名::メソッド名と書く 255ページから ## 3/25 例題を通じて: かなりメソッドが使われている印象を受けた Minitestではsetupメソッドを定義するとテストメソッドの実行前に毎回setupメソッドが呼び出される メモ化:インスタンス変数とnilガードを使ってデータを保持できる def twitter_data @twitter_data ||= begin 処理 end end こうするとtwitter_dataメソッドを呼び出した時だけAPIからデータを取得する処理が実行される。2回目以降の呼び出しでは@twitter_dataに保存された値が返却されるだけなのでプログラムのパフォーマンスが向上する 遅延処理化:メモ化と同様にインスタンス変数とnilガードを使う。 class Foo def bar @bar ||= なんかむっちゃ重い処理 end end barメソッドを呼び出さない限り重い初期化処理が走らないため、プログラムのパフォーマンスを最適化しやすくなる。 selfキーワード:インスタンス自身を表すキーワード。Javaにおけるthisキーワードとほぼ同じ。自動的に省略されているが明示的に呼び出すこともできる セッターメソッドを呼び出す際にはselfを付ける:さもなければローカル変数の呼び出しと解釈される 継承:is-aの関係で理解する。「DVD is a product」は違和感がないのでProductをスーパークラスとしてDVDをサブクラスに置いても適切な継承関係である 標準ライブラリの継承関係:BasicObjectクラスが頂点で次がObjectクラス、次いでString、Numeric、Array、Hashが君臨している。 なにひとつ定義していないクラスでもObjectクラスを自動的に継承しているため関連するメソッドを呼び出せる 270ページから ## 3/26 superクラスでスーパークラスの処理を呼ぶ:super(引数)で呼び出せる。引数の数が同じだった場合は引数なしですべて引き渡すことができる。 オーバーライド:サブクラスではスーパークラスと同名のメソッドを定義することで、スーパークラスの処理を上書きできる アスタリスク引数の意図:superメソッドに引数をそのまま全部渡したい。このメソッドでは引数を使わないがsuperメソッドで必要になるので渡したい、という意味 意図2:余分に渡された引数を無視したい。メソッド内でsuperキーワードが使われていない場合は「余分に渡された引数を無視する」という意味になる publicメソッド:クラスの外部からでも自由に呼び出せるメソッド。initialize以外のインスタンスメソッドはデフォルトでpublic privateメソッド:外部に公開されないメソッド。すなわちクラスの内部でのみ使えるメソッドのこと。 Rubyのprivateメソッド:サブクラスからは呼び出せる。オーバーライドもできる。 Rubyのprivateメソッド2:クラスメソッドはprivateキーワードの下に定義してもprivateにならない。class << selfの構文を使うと回避できる privateに引数を渡す:private :foo, :bar の形式で引数を渡すと既存のメソッドがprivateメソッドになる メソッド定義と同時にprivateメソッドにする:private def fooの形式で行う protectedメソッド:外部に公開したくないが同じクラスやサブクラスの中ではレシーバ付きで呼び出したい時に使う 定数をクラスの外部から直接参照する:クラス名::定数名 Rubyの定数は再代入可能:確実に防ぎたい場合はfreezeメソッドを使う クラスインスタンス変数:インスタンスの作成とは無関係にクラス自身が保持しているデータ(クラス自身のインスタンス変数) クラス変数:アットマークを2つ重ねた変数。同一の変数として代入・参照可能。 グローバル変数:$マークから変数名を始める。プログラムのどこからでも参照できる。 エイリアスメソッドの作成:alias 新しい名前 元の名前で定義できる メソッドの削除:undef 削除するメソッドの名前で定義を削除できる 入れ子になったクラスの定義:クラスの内部に別のクラスを定義することもできる。外側のクラス::内側のクラスで参照できる。 クラスに可視性を設定することは通常できない:したい場合はprivate_constantを使う 演算子もメソッドとして再定義できる:たとえば==を使った比較を直感的にしたい時などに使える equal?:object_idが等しい場合にtrueを返す。つまりまったく同じインスタンスかどうかを判断する場合に使う eql?:==より厳格な等値判定を行う。1==1.0はtrueだが1.eql?(1.0)はfalse。主に2つのオブジェクトがハッシュのキーとして同じかどうかを判定することに用いられる オープンクラス:変更に対してオープンなクラスのこと。Railsではこの概念を活用して様々なメソッドを追加している モンキーパッチ:既存のメソッドを上書きして挙動を変更する 特異メソッド:オブジェクト単位で挙動を変える。def alice.shuffleなどの形式で記述するとaliceのオブジェクトのみがshuffleメソッドを持つ クラスメソッドの正体:実際は特定のクラスの特異メソッド ダックタイピング:オブジェクトのクラスがなんであろうとメソッドが呼び出せれば良しとするプログラミングスタイルのこと。もしそれがアヒルのように歩き、アヒルのように鳴くのなら、それはアヒルであるということ。 動的型付け言語における突然のエラーを防止する方法:あえて同じ名前のメソッドを定義してわかりやすいエラーを起こさせる respond+to?:そのオブジェクトに対して特定のメソッドが呼び出し可能か確認できる オーバーロード:静的型付け言語において引数のデータ型や個数の違いに応じて同じ名前のメソッドを複数定義できる機能。動的型付け言語のRubyにはない考え方。代わりにis_a?メソッドで引数のクラスを確認したり、to_iメソッドで数値に変換したりなどして同様の仕組みを実現する 316ページから ## 3/27 モジュールの用途:継承を使わずにクラスにインスタンスメソッドを追加する。もしくは上書きする。2つ目は複数のクラスに対して共通の特異メソッドを追加する。3つ目はクラス名や定数名の衝突を防ぐために名前空間を作る。4つ目は関数的メソッドを定義する。5つ目はシングルトンオブジェクトのように扱って設定値などを保持する モジュールの作り方:module モジュール名 定義 end モジュールの特徴:モジュールからインスタンスを作成することはできない。また、ほかのモジュールやクラスを継承することもできない ミックスイン:モジュールをクラスにincludeして機能を追加すること extend:モジュール内のメソッドをそのクラスの特異メソッドにすることができる 特殊な呼び出し方:クラス名.includeまたはクラス名.extendの形式でも呼び出せる 文字列を1文字ずつループ処理する場合はeach_charメソッドを使う:これ知らなんだ 例題を通して:リファクタリングの一部を先に実践できたところにほのかな成長を感じた include_modules:includeされているモジュールの配列が返る ancestors:モジュールのみならずスーパークラスの情報も返る 333ページから ## 3/28 Enumerableモジュール:配列やハッシュ、範囲など、何かしらの繰り返し処理ができるクラスにincludeされているモジュール。map、select、find、countなどのメソッドが定義されている。eachメソッドを実装していれば使えるようになる Comparableモジュール:比較演算を可能にするモジュール。include先のクラスで<=>演算子を実装すると使用可能になる。 Kernelモジュールの秘密:ObjectクラスがKernelモジュールをincludeしているのでどこでも使える トップレベル:クラス構文やモジュール構文に囲まれていない一番外側をトップレベルと言う。ここではmainという名のObjectクラスのインスタンスがselfとして存在している クラス以外のオブジェクトにextendする:この場合、モジュールのメソッドはextendしたオブジェクトの特異メソッドになる トップレベルにメソッドを定義すると:Objectクラスに定義される。つまりトップレベルに定義したメソッドは事実上のグローバルメソッドになる 名前空間としてのモジュール:モジュール構文の中にクラス定義を書くと「そのモジュールに属するクラス」という意味になるので、同名のクラスがあっても名前の衝突は発生しなくなる 入れ子なしで名前空間付きのクラスを定義する:名前空間として使うモジュールがすでにどこかに定義されている場合は、モジュール構文やクラス構文を入れ子にしなくてもモジュール名::クラス名のような形でクラスを定義することもできる クラスの探索:Rubyではクラスやモジュールの入れ子関係を順に外側に向かってクラスを探索する モジュールに特異メソッドを定義する:モジュール単体でそのメソッドを呼び出したい時、モジュール自身に特異メソッドを定義すれば直接モジュール名.メソッド名の形式でメソッドを呼び出すことができる module_functionメソッド:モジュールではミックスインとしてもモジュールの特異メソッドとしても使えるメソッドをこれで定義できる ↑module_functionメソッドを引数なしで呼び出した場合は、そこから下に定義されたメソッドがすべてモジュール関数になる Mathモジュールに定義されている定数:自然対数の底を表すMath::Eと円周率を表すMath::PIがそれぞれ定義されている シングルトンパターン:アプリケーション内で唯一のオブジェクトを作る手法のことをシングルトンパターンと呼ぶ メソッドが探索される順番:直近のクラス➜内部のモジュール➜スーパークラス➜Objectクラス➜Kernalモジュール➜BasicObject prepend:include以外の方法でメソッドをミックスインする方法。同名のメソッドがあったときにミックスインしたクラスよりも先にモジュールのメソッドが呼ばれる refinements:独自のスコープを設定できる。有効にするにはusingというメソッドを使う。通常はクラス構文とモジュール構文の内部で使う。トップレベルでも使用できるが、有効範囲はusingが呼び出された場所からファイルの最後までになる 二重コロンとドットの違い:名前空間を区切ったり定数を参照したりするときは二重コロンを使い、メソッドを呼び出す場合はドットを使うのが典型的な使い分け。ただしメソッドの呼び出しに関しては二重コロンも使おうと思えば使える。逆はできない 366ページから ## 3/29 TypeError:Rubyでは例外も例外クラスのインスタンスになっている。TypeErrorは例外オブジェクトのクラス名 予期しない捕捉:例外が発生した箇所がbegin〜rescueで囲まれていない場合、例外が発生するとそこで処理を中断してメソッドの呼び出しを1つずつ戻っていく。途中に例外を捕捉するコードがあればそこから処理を続行する backtraceメソッド:バックトレース情報を配列にして返す messageメソッド:例外発生時のエラーメッセージを返す NoMethodError:これも例外クラスの一つ。存在しないメソッドを呼び出した時に現れる ZeroDivisionError:0で除算した時に現れる例外クラスの一つ。 例外クラスの指定: begin 例外が起きうる処理 rescue 捕捉したい例外クラス 例外が発生した場合の処理 end のような形式で特定の例外が起こった場合にのみ捕捉させることができる 例外クラスの継承関係:すべての例外クラスはExceptionクラスを継承しており、そこから下はStandardErrorのサブクラスとそれ以外の例外クラスに分かれている。 rescue節の挙動:なにもクラスを指定しなかった場合にはStandardErrorとそのサブクラスが捕捉される。指定した場合はそのクラス自身とサブクラスが捕捉される 捕捉すべき対象:最上位のExceptionクラスを指定するとNoMemoryErrorなど特殊なエラーも対象に含めてしまうため、通常はStandardErrorかそのサブクラスに捕捉対象を限定すべきである 例外を書く順番:スーパークラスよりも手前にサブクラスを書く retry:例外発生時に処理をやり直させることができる。 rescue retry end ただし無限ループを防ぐために回数を制限するのが望ましい raiseの引数:第1引数に例外クラス、第2引数にエラーメッセージを渡すとRuntimeErrorクラス以外の任意の例外クラスで例外を発生させることができる full_message:例外のクラス名、エラーメッセージ、バックトレースをすべて出力するメソッド Date.valid_date?:正しい日付かどうか確認できる ensure:例外の有無にかかわらず処理を実行させる 392ページから ## 3/30 ensureの代わりにブロックを使う File.open('some.txt', 'w') do |file| file << 'Hello' end 上記のような形式で「使用したら必ずリソースを解放する」といった処理をブロック付きメソッドに任せることができる。 例外処理のelse Rubyの例外処理では例外が発生しなかった場合に実行されるelse節を書くこともできる。ただし使われるケースはあまり多くない 例外処理と戻り値:例外発生せず最後まで正常に処理が進んだ場合はbegin節の最後の式が戻り値になる。捕捉された場合はrescue節の最後の式が戻り値になる ensure節ではreturnを使わない:使うと正常時も例外発生時もensureの値がメソッドの戻り値になる パース:特定の書式に従って文字列を解析し、プログラムで利用可能な別のデータ構造に変換すること rescue修飾子:rescueを修飾子として用いるとbegin endを勝利略できる。`例外が発生しそうな処理 rescue 例外が発生した時の処理`という形で記述する ↑ただし補足する例外クラスを指定することはできない。rescue修飾子ではStandardErrorとそのサブクラスのみが捕捉される $!と$@に格納される例外情報:Rubyでは最後に発生した例外は組み込み変数の$!に格納される。またバクトレース情報は$@に格納される begin/endを省略できるケース:メソッドの中身全体が例外処理で囲まれている場合は省略できる。また、do/endブロックの内部でも省略できる rescueした例外を再度発生させる:rescue節の中でraiseメソッドを使うこともできる。この時、raiseメソッドの引数を省略するとrescue節で捕捉した例外をもう一度発生させることができる 独自の例外クラスを定義する:StandardErrorクラスかそのサブクラスを継承することで、独自の例外クラスを定義できる ここから10章 yield:渡されたブロックを実行するためにメソッド内で使う block_given?:ブロックが渡されている場合にtrueを返す ブロックを引数として明示的に受け取る:ブロックを引数として受け取る場合は引数名の前に&をつける。また、そのブロックを実行する場合はcallメソッドを使う ブロックを引数にするメリット:ブロックを他のメソッドに引き渡せるようになる。また、渡されたブロックに対してメソッドを呼び出し、必要な情報を取得したりブロックに対するなにかしらの操作を実行したりできるようになる Proc:ブロックをオブジェクト化するためのクラス。なんらかの処理そのものを表している。Proc.newにブロックを渡すことにより作成できる。実行する時はcallメソッドを使う。 Procオブジェクトの作り方まとめ Proc.new { |a, b| a + b} proc { |a, b| a + b } ->(a,b) {a + b } lamda { |a, b| a + b} ->を使う記述をラムダリテラルと呼ぶ ラムダはProc.newよりも引数のチェックが厳格になる lamda?:ProcクラスのインスタンスがProc.newとして作られたのかラムダとして作られたのか判断してくれる メソッドチェーンを使ってコードを書く:あるメソッドを呼び出す➜その戻り値のメソッドを呼び出す➜またその戻り値のメソッドを呼び出す……と次々とメソッドを呼び出していくコーディングスタイルのことをメソッドチェーンと呼ぶ def self.loud(level) ->(words) do words .split(' ') .map { |word| word.upcase + '!' * level } .join(' ') end end このようにメソッドごとに改行させるスタイルもメソッドチェーンではよく見かける inject:畳み込み演算を行うメソッド Procオブジェクトを===で呼び出す:case文のwhen節でProcオブジェクトを使えるようにするためにこのような方法が設けられている Procオブジェクトをブロックとして渡すには:引数の前に&を付けなければならない。この時の&の役割は単にProcオブジェクトをブロックと認識させるのみならず、厳密には右辺のオブジェクトにto_procメソッドを呼び出し、その戻り値として得られたProcオブジェクトをブロックを利用するメソッドに与えている Procオブジェクトとクロージャ:通常、メソッドの引数やローカル変数は実行が終わると参照できなくなるが、Procオブジェクト内ではメソッドの実行が完了しても引き続きアクセスし続けることができる。生成時のコンテキスト(変数情報など)を保持している関数をクロージャ(関数閉包)と呼ぶ ここから11章 パターンマッチ:比較的新しい機能。条件分岐の一種。配列やハッシュの構造に着目して条件分岐させたい時に有効 パターンマッチの構文 case 式 in パターン1 パターン1にマッチした時の処理 in パターン2 パターン1にマッチせず、パターン2にマッチした時の処理 else パターン1にも2にもマッチしなかった時の処理 end パターンマッチのハッシュ:in節で値を省略してキーだけを書いた場合は自動的にキーと同じ名前のローカル変数が作成され、そこに値が代入される valueパターン:in節に数値や文字列を直接指定できる利用パターン。thenを使って条件にマッチした時の処理を一行で書くこともできる。ただし、case文とは異なりパターンが1つもマッチしないと例外が発生する。else節を容易することで回避できる variableパターン:in節のパターンに変数を書いてローカル変数の宣言と代入を同時に行う利用パターン。in節で事前に定義された変数の値を参照したい時はピン演算子(^)を用いる。ただし指定できる変数はローカル変数のみで、インスタンス変数を使おうとすると構文エラーが起きる。 451ページから ## 3/31 arrayパターン:in節に[]を使って配列の構造パターンを指定する利用パターン。[]の中に書いた変数には対応する要素の値が代入される case [1,2,3] in[a,b,c] end 変数ではなく数値や文字列をそのままin節に指定すると「その値と等しいこと」がマッチの条件になる アンダースコアで始まる変数:これは「任意の要素」を表現する目的で例外的にin節で2回以上使うことができる in節で*を使うと任意の長さの要素を指定したことになる hashパターン:in節に{}を使ってハッシュの構造パターンを指定する利用パターン。値に変数を指定すると、その変数に対応する値が格納される case {name: 'Alice', age: 20} in {name: name, age: age} "name=#{name}, age=#{age}" end 値の変数を省略するとキーと同じ名前の変数に値が代入される hashパターンではハッシュの各要素がin節で指定したパターン(キーと値、またはキーのみ)に部分一致すればマッチしたと判定される。ただし、in節に{}を書いた場合は例外的に「空のハッシュに完全一致」することがマッチの条件になる hashパターンのin節はkey:value形式のパターンしか許容されていない。key => value形式を使おうとすると構文エラーが発生する in節に書くのはあくまでパターン:パターンは一見、配列やハッシュのように見える場合があるが、これらはあくまで記法を似せただけの「パターン」である。 asパターン:パターンマッチでマッチしたオブジェクトを変数に代入する利用パターン case {name: 'Alice', age: 20, gender :female} in {name: String => name, age: 18.. => age} "name=#{name}, age=#{age}" end 一番外側に=>変数名と書くとマッチしたオブジェクト全体を取得できる alternativeパターン:2つ以上のパターンを指定し、どれかに1つマッチすればマッチしたと見なす利用パターン case 2 in 0 | 1 | 2 'matched' end arrayパターン、hashパターン、asパターンとは組み合わせられるがvariableパターンとはできない findパターン:アスタリスクを2回使って「前と後ろにある任意の要素」をパターンとして表現できるRuby3.0以降の機能を活かしたパターン。これにより、配列野中から特定のパターンに合致する部分を抜き出すことができる。 case [13, 11, 9, 6, 12, 10, 15, 5, 7, 14] in[*, 10.. => a, 10.. => b, 10.. => c, *] "a=#{a}, b=#{b}, c=#{c}" end ガード式: case 式 in パターン if 条件式 パターンにマッチし、なおかつ条件式が真になった場合に実行する処理 end このような形式でin節に条件式を追加できる。case節の式がin節のパターンにマッチすることに加え、この条件式も真になった場合にin節に対応する処理が実行される。以上の条件式をガード式と言う 1行パターンマッチ:Rubyのパターンマッチではcase節を省略して"評価したい式 in パターン"を一行で書くこともできる。マッチすればtrue、しなければfalseが返る [1,2,3] in [Integer, Integer, Integer] # => true [1,2, 'x'] in [Integer, Integer, Integer] # => false また、1行パターンマッチは"式 => パターン"という記法も用意されている。主にパターンマッチを使った変数代入を利用するために使う 変数のスコープに関する注意点:Rubyのパターンマッチは独自の変数スコープを作らないので、すでに同名のローカル変数が存在していると意図せず上書きされる可能性がある。パターンマッチ内で新たに定義された変数は外部でも使用できる ここから第12章 よく発生する例外クラスとその原因 NameError:単純なタイプミスであることが多いが、外部ファイルやライブラリのrequireを忘れている場合にも発生することがある NoMethodError:存在しないメソッドや可視性が制限されているため呼び出せないメソッドを呼び出そうとした場合に発生する。特にレシーバがnilになっているケースは非常に多いとされる TypeError:期待しない型がメソッドの引数に渡された時に発生する ArgumentError:引数の数が違ったり、期待する値ではなかったりした場合に発生する ZeroDivisionError:整数を0で除算しようとした時に発生する SystemStackError:スタックが溢れた時に発生する。特に間違ってメソッドを再帰呼び出しした場合に発生する LoadError:requireやrequire_relativeの実行に失敗した時に発生する SyntaxError:構文エラー。endやカンマの数に過不足がある、カッコがきちんと閉じられていないなどの原因で起こる Segmentation fault:略してセグフォ。SEGVと呼ばれることもある。Ruby本体や拡張ライブラリに不具合がある時に発生する極めて稀なエラー。 tap:ブロックパラメータにレシーバをそのまま渡すメソッド。ブロックの戻り値は無視され、tapメソッド全体の戻り値はレシーバ自身になる debug.gemの代表的なコマンド: step/s 実行を1行進めて停止する。その行にメソッド呼び出しがあればそのメソッドの中に入って停止する(ステップイン) next/n 実行を1行進めて停止する。その行にメソッド呼び出しがあればそのメソッドを実行してから次の行で停止する(ステップオーバー) finish/fin 現在実行中のメソッドを最後まで実行し、呼び出し元に戻ってきたところで停止する(ステップアウト) continue/c プログラムを再開する。停止すべきポイント(ブレークポイント)がなければ、そのプログラムの最後までプログラムを実行する p/pp Rubyのpやppのように指定された式の値を表示する リターン 直前に実行したコマンドを繰り返す help/h 使用可能なコマンドとその説明を表示する。help+コマンド名で特定のコマンドのヘルプを表示することもできる quit/q デバッガを途中で終了する パソコンの前から離れる:実際これで解決することがプログラミングに限らずよくある 504ページから ## 4/1 日付や時刻を扱うクラス:Dateクラスは日付を扱い、TimeクラスとDateTimeクラスは日付と時刻を扱う。このうちTimeクラスだけが組み込みライブラリになっているのでrequireせずに使える。現在ではDateTimeクラスは非推奨になっている。 ファイルやディレクトリを扱うクラス:FileクラスとDirクラスは組み込みライブラリなのでrequireせずに使える。 File.open('./lib/fizz_buzz.rb', 'r') do |f| puts f.readlines.count end また、ファイルのコピーや削除などを便利に実行するためのFileUtilsモジュールも存在する。 require 'fileutils' FileUtils.mv('./lib/hello_world.txt', './lib/hello_world.rb') Pathnameクラス:パス名をオブジェクト指向らしく扱うクラス。たとえば自分自身がファイルかどうかを返すメソッドや、新しいパス文字列を組み立てるメソッドが定義されている 特定の形式のファイルを読み書きする:CSVを読み書きする場合はCSVクラスが便利に使える。カンマ区切りだけでなくタブ区切りのファイルを読み書きすることもできる。同様に、JSONやYAMLに対応したクラスも存在する 環境変数の取得:ENVという組み込み定数に環境変数が格納されている。値を取得する場合はハッシュと同じ要領で[]を使う 組み込み定数:ENVやARGVはRubyで最初からObjectクラスに定義されている定数である。このような定数を組み込み定数を呼ぶ。このほかにも標準出力を表すSTDOUTやRubyのバージョン番号を表すRUBY_VERSIONなどがある 警告の出力:警告を出力したい場合は-W:deprecatedというオプション付きでプログラムを実行する eval:受け取った文字列をRubyのコードとして実行する code = '[1, 2, 3].map { |n| n * 10}' eval(code) # => [10, 20, 30] バッククォートリテラル:バッククォートで囲まれた文字列をOSコマンドとして実行する。代わりに%xを使うこともできる Rake:Rubyで作られているビルドツール。Rakefileという名前のファイルにタスクを定義して用いる task :hello_world do puts 'Hello, world!' end 上記はRakefileに"hello_world"という名前のタスクを定義している DSLとはなにか:Domain Specific Languageの略で、ドメイン固有言語またはドメイン特化言語と訳される。「なにか特別な目的を実現するために定義された、人間にとって読みやすく機械にとっても処理しやすいテキストファイルの記述ルール」と言える。 Faker:本物っぽいテストデータを準備したりする時にする使用するgem Awesome Print gem:オブジェクトの情報を見やすく整形してくれるgem Gemfileのバージョン指定 gem 'faker' # Bundlerに任せる gem 'faker', '2.17.0' # 2.17.0に固定 gem 'faker', '>= 2.17.0' # 2.17.0以上 gem 'faker', '~> 2.17.0' # 2.17.0以上かつ2.18未満 gem 'faker', '~> 2.17' # 2.17以上、3.0未満 型検査のニーズ:型情報が事前に提供されていればメソッド名のタイプミスのような些細なミスを実行する前に検出することができる。また、IDEなどと連携して型情報に基づくコードの入力補完やコードジャンプなども行えるようになる typeprof:型情報を自動生成するためのコマンド。生成には目的のメソッドやクラスを実行するプログラムが必要とされる Sttep:型検査を行うためのツール untyped:任意の型を表す -> void:メソッドの戻り値がないことを表す RailsのMinitest:testメソッド+文字列+ブロックの形式で書くことができる。また、Railsではassert_differenceやassert_not_equalなど素のMinitestにはない検証メソッドも用意されている Rails独自の規約:@で始まる変数はコントローラからビューにデータを渡すために使う変数として解釈されうる Railsのyield:レイアウトのビューから特定のビューを挿入するために用いられることが多い ## 4/2