ログ

学習の記録

チェリー本 5章学んだこと

ハッシュとは

キーとバリューで構成されているオブジェクト。 キーに文字列かシンボルを使うなら、シンボルのほうがいいよねという感じ(書き方も省略できるし、処理もシンボルのほうが値を高速に取り出せる)

colors = {red: "赤", blue: "青"}
colors[:red] #=>赤

上記の形が一般的で、省略形の書き方。 キーがシンボルの場合上記のように書ける。

文字列をキーにもできる(同一ハッシュ内で一つを文字列、一つをハッシュなどの混合はよろしくない)

colors = {"red" => "赤", "blue" => "青"}

colors = {"red" => "赤", :blue => "青"} # よくない例

colors = {
  "red" => "赤"
  "blue" => "青"
  "yellow" => "黄"
} #こんな書き方もできる

省略形に至るまでの書き方は以下。

colors = {:red => "赤", :blue => "青"} # シンボルをキーとしたハッシュ
colors = {:red "赤", :blue "青"} # ハッシュロケット(=>)を省略
colors = {red: "赤", blue: "青"} # キーのダブルコロン(:)を後ろにもってくる

ハッシュに値を追加

  colors[:yellow] = "黄色"

  colors
=> {:red=>"赤", :blue=>"青", :yellow=>"黄色"}

ハッシュの値をキーを使って取り出す

colors[:yellow]
=> "黄色"

ハッシュの値にシンボルを格納

colors = {red: "赤", blue: "青", yellow: "黄色", green: :deep_green} #値もシンボル

シンボルとは

使い方も定義も文字列と似ているオブジェクト。

  • 文字列と比べ、処理速度が速い
  • シンボルに破壊的変更はできない(エラーになる)
  • 破壊的変更ができないので思わぬエラーに遭遇しない(参照)
  • 値が同じであれば同じオブジェクト

文字列と違うところは

  • 値が同じのものがあれば同一オブジェクト(文字列はそれぞれ別のオブジェクト)
a = :name
b = :name

a.object_id
=> 72028 

b.object_id
=> 72028 # 同じオブジェクト

キーワード引数とは

ハッシュのキーで省略形シンボルの記法と似たメソッドの引数の記法。 デフォルト値有り、無しの定義パターンがある。 コードの可読性が上がる。 シンボル、ハッシュとは無関係

def color_changer(main_color, red: true, blue: true) #実引数はデフォルト値
end

color_changer("green", red: true, blue: false) #仮引数側だけ見ても何をtrueか何をfalseか想像しやすい

実引数のデフォルト値で良いならメソッド呼び出し時引数省略可能

color_changer("green", red: true)

メソッド実引数のキーワード引数のデフォルト値省略

def color_changer(main_color, red: , blue: )
end

シンボルの省略形っぽいけどキーワード引数のデフォルト値がない記法。 キーワード引数。 メソッド呼び出しの時にデフォルト値がないキーワード引数を省略するとエラー

color_changer(main_color, red:true) #エラー

キーワード引数を使っているメソッドの引数には、仮引数でハッシュを渡すことができる

mix_color = {red: true, blue: true, yellow: true}

def color_changer(main_color, red: , blue: ,yellow:)
end

color_changer("green", **mix_color) 

メソッド定義時の実引数にないハッシュを渡すことはできない、メソッド定義時に渡せる引数を定義しないといけない

mix_color = {red: true, blue: true, yellow: true}

def color_changer(main_color, red: , blue:)
end

color_changer("green", red: false, blue: false, **mix_color) #ArgumentError

まとめ

文字列とシンボルは似ているもの ハッシュにおいて、シンボルをキーにすると書き方を省略できるし、文字列かシンボルで選ぶならシンボルがキーの方がベター。 ハッシュでシンボルをよく使っているからシンボルに値が格納できると思い込んでいたけど、ハッシュだから値が格納できていた。キーでシンボルを使っていただけ、ハッシュそのものとシンボルは別物。

文字列と似ているもの。

配列は値を格納するオブジェクト、ハッシュはキーとバリュー(値)をセットで格納するオブジェクト。

わかったこと

・シンボルは同じ値であれば同じオブジェクト(参照のこと)(一方、文字列は値が同じものがあろうがそれぞれ別のオブジェクト) ・イミュータブル(破壊的変更不可)

メソッドのキーワード引数はキーがシンボルのハッシュの形

感想

キーワード引数とハッシュのキーがシンボル、かつ値がシンボルとなった時の挙動がわかりきってないのでまたこの章に戻ってきます。

チェリー本4章 学んだこと

・スコープ ・メソッド内での変数はメソッド内でしか使えない、呼び出せない

num = 1

def hoge
  str = 'a'
end

puts num => 1
puts str => #エラー

・ブロック内もブロック外(ローカル変数)も同じ変数名が使える(使うのは好ましくない)
もし同じ名前の変数があればブロック内ではローカル変数よりもブロック内の変数が優先される

num = 1

def hoge
  num = 2
  puts num
end

puts num #=>1
hoge #=>2

・ブロックは、1行でかけるコードでは{}、複数行はdo...end

nums = [1,2,3,4,5]

# 中身は1行
nums.each {|n| n * 2}

# 複数行 
nums.each do |n|
  str = '数字は'
  after_num << n * 2
end

・concatは破壊的(危険)、"+"で配列合体は非破壊的

nums = [1,2,3,4,5]
str = ['a','b','c']

nums.concat(str)
#=> [1, 2, 3, 4, 5, "a", "b", "c"]
nums # 破壊的
#=> [1, 2, 3, 4, 5, "a", "b", "c"]
nums = [1,2,3,4,5]
str = ['a','b','c']

nums + str
=> [1, 2, 3, 4, 5, "a", "b", "c"]
nums # 非破壊的
=> [1, 2, 3, 4, 5]
str # 非破壊的
=> ["a", "b", "c"]

・可変長引数は該当部分は配列化、が結構便利そう
(splat演算子)を配列の入った変数の前に置くと展開する(配列を解除して中身だけ出すみたいな)(配列の配列状態を回避できる)
nums = [[1,2],[3,4]] *nums # [1,2,3,4]を期待したが、シンタックスエラー
Array#flattenで良いのでは?と思い調べました。
*(splat演算子)は配列同士の連結のリファクタリングの際に使えそう 可変長引数と配列解除と覚える

  nums = [3,4]
  [1,2]+ nums +[5,6] #=> [1, 2, 3, 4, 5, 6]
  nums = [3,4]
  [1,2,*nums,5,6] #=> [1, 2, 3, 4, 5, 6]

(&:to_i)などの(&:)の条件が知れた
・ブロックパラメータが1個
・ブロックの中で呼び出すメソッドに引数がない
・ブロックの中で、ブロックパラメータに対してメソッドを1回呼び出す以外の処理がない

・Rangeに対して.to_aで配列化、一つ一つの要素にできる (1..10).to_a #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] #()がないとエラー

・Array.newにブロックを渡すと引数の要素にindexの値が入る

Array.new(10){|n| puts n}
0
1
2
3
4
5
6
7
8
9
=> [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]

配列にデフォルト値を渡す場合、破壊的変更をすると全ての要素に影響が出る。(参照の関係)これを回避するためにはデフォルト値をブロックで渡す

・繰り返し処理(eachとか)のメソッドの大半はブロックなしで呼び出すとEnumeratorオブジェクトを返す、よってEnumeratorクラスのメソッドが使える(だからwith_indexメソッドが呼び出せる)

nums = [1,2,3,4,5,6,7,8,9,10]
nums.delete_if.with_index do |n, i| 
  n.modulo(2) == 0 && i.odd?
end

・2次元、3次元配列は()でいい感じにできる

(hoge,huga),hoge_hoge = [[1,2],3]

()や( , )を使うことで要素を抽出して変数に入れたりできる(ややこいのは変わりない)

・{}.hgoehogeのようにブロックの後にメソッドチェーンが使える

・配列は加工できるものと思う

・breakはeach、while,until,for文で使える

・breakは繰り返し処理からの脱却、returnはメソッドからの脱却
returnはメソッドで使う(使わない方が好ましい)

組み込みメソッド

delete_if

each_with_index

with_index(mapと組み合わせたりしていろんな条件に対応)

Enumerator#with_index(mapなどで加工しつつ、添え字も取得できる、引数を渡せば添え字の開始を0じゃなく任意の数字にできる)

テストの書き方、考え方

  1. テストファイルを作る、実行ファイルを作る
  2. テストメソッド作る、絶対通りそうなテストを書くor期待するテストを書く、テストを走らせる、テストが通らないことを確認する
  3. 実行ファイルにメソッド作る、メソッドに絶対テストが通りそうな仮実装のコードを書く(テストに書いた期待する結果やtrue)、テストを実行する、テストが通ることを確認する
  4. テストが通ったことを確認したら、テストファイルに意味あるテストコードを書いてなかったら書く(要件に合うテスト)、テストが通ることを確認する
  5. 別のテストパターンを書く
  6. テスト実行、失敗を確認する
  7. テストが通るように実行ファイルにコードを書く(とりあえず動くもの)
  8. テストが通ることを確認する
  9. ここまでテストが書けて、要件を満たすコードが書けたらリファクタリングできるか考える(より綺麗なコード)
  10. テストが通ったらさらにリファクタリングできるか考える(組み込みメソッドでさらに簡潔にできるか、多重代入は使えないか )

感想

本を読み進める前に、自分でどうやったら実装できるか考えてコードを書いてみました。
相変わらず一つの方法しか考えないこと、これでいけるっしょと深く考えないところは改善しないとと感じますが、概ね参考書に近いコードが書けました。
自作メソッドの作り方やテスト駆動をチュートリアル形式で取り組めました。
上級編のリファクタリングは自分にはまだまだできないなーと思いつつコードがすごく簡潔になりびっくりしました。
簡単と感じてもまずは動かしてみる、使い方に慣れていこうと思います。
あとブログの書き方下手だから上手くなりたい・・
一つのテーマで深掘りできそうなことがあればそれで1記事書いてみたいと思います。

https://qiita.com/wasu/items/7aeb6d32fcf51cf04a57

参考、引用: 著者 伊藤淳一 さん「プロを目指す人のためのRuby入門<改訂2版>」 出版社 技術評論社 (2021/11/29) 4章P102~P166

チェリー本3章 学んだこと

わかったこと

・テストファイル名、クラス名、メソッド名に適した名前の付け方がある、テストフレームワークのメソッドがあり、それを使って期待する結果、期待する結果に対する処理を書いてそれが通るかテストする

  1. 実行ファイルとテストファイルは基本分ける、テストファイルからはrequre_relativeで実行ファイルを読み込む必要がある hoge_hoge.rb(実行ファイル)、hoge_hoge_test.rb(テストファイル)
  2. hoge_hoge_test.rbのクラス名にHogeHogeTest < MiniTest::Test(継承)、requireで以下のように読み込む
    require 'minitest/autorun'
    require_relative '../hoge_hoge' # .rb省略可
  3. メソッド名はtest_hoge_hoge
    以上の命名が好ましい

・エラー(errors)は検証自体ができなかったこと、失敗(failures)はテストすることはできたけど自分が書いた望む結果にならなかったことを表す

・期待の動作は一言一句合わないとテスト失敗する

class FizzBuzzTest < Minitest::Test
  def test_fizz_buzz
    assert_equal 'FizzBuZZ', fizz_buzz(15) # 'fizzbuzz'と書くのが正しい
  end
end

❯ ruby fizz_buzz.rb
Run options: --seed 43955

# Running:

F

Finished in 0.000627s, 1594.8966 runs/s, 12759.1730 assertions/s.

  1) Failure:
FizzBuzzTest#test_fizz_buzz [fizz_buzz.rb:42]:
Expected: "FizzBuZZ"
  Actual: "FizzBuzz"

1 runs, 8 assertions, 1 failures, 0 errors, 0 skips

感想

テストの全体的な雰囲気を掴むことができました
テストファイル作ってコード書き始めたいと思いました

https://www.wakuwakubank.com/posts/861-git-markdown/ https://verse-type.co.jp/column/hp_absolutepath-relativepath/

参考、引用: 著者 伊藤淳一 さん「プロを目指す人のためのRuby入門<改訂2版>」 出版社 技術評論社 (2021/11/29) 3章P86~P98

チェリー本2章 学んだこと

変数名、メソッド名:スネークケース

num = 1
nums = [1,2,3]
favorite_food = "りんご"

def hoge_hoge
end

Javaのように変数だけ宣言とかしない、エラーになる

変数、メソッド名:数字始めはエラー

1_hoge #エラー
2hgoehoge #エラー

定数

NAME = "太郎"

変数:_始めは、宣言するけど使わない

hour = 1
min = 10
_sec = 25

メソッド名:_書き始めはあまりない

def _hoge_hoge
end

スネークケース

hoge_hoge

キャメルケース

hogeHoge

JavaScriptの変数宣言。 Rubyでは一般的でない。

パスカルケース(アッパーキャメルケース)

UserName

クラス名の命名規則

多重代入(paizaでよく使うイメージ)

# 多重代入
name, age = "yuzi",16

# 普通に変数に値を代入するやり方
name = "yuzi"
age = 16

上記は同等、お互いに無関係な値の場合は理解しづらいので下のやり方で代入する方が良い でも多重代入の方が1行でスッキリ感じる・・

sports, food = "野球","りんご"

上記のような全く関係ないものはよくなさそう

参考になったこと

・ケースバイケースだけど、戻り値があるものが式、変数に代入しようとするとエラーになるものが文(やろうと思えば戻り値を活用できる)

num = 1
lucky_num = 2

result = 
  if num == lucky_num
    "当選"
  else
    "落選"
  end

puts result 

・"+演算子"での文字連結は式展開(#{})の下位互換

・returnも使えるが、使わない方が主流 最後に評価された式がメソッドの戻り値 returnはメソッドを途中で脱出するときに使われることが多い

・戻り値 == 返り値 rubyでは戻り値にreturnを書かない方が好ましい 脱出するときに使うと良い 戻り値として返せるものを変数に入れることができる

・メソッドでの()省略は引数がないとき

あまり使わなさそう、頭の片隅に置くくらいで良さそうなこと

・ ;で文を複数記述できる

puts "a"; puts "b"
a
b
=> nil

・ \で文が続いていることを表せる

irb(main):018* "hoge".slice \
irb(main):019> 2
=> "g"

・通常""を使う、''は改行文字などをそのまま出力したいときに使う。 ""の中で、'’の挙動にしたかったら""の中のエスケープ文字、改行文字の前で\を入力する。

puts "こん\tにちは"
こん    にちは
=> nil

puts "こん\\tにちは"
こん\tにちは
=> nil

・if,elsifの後にthenを書くと、一文で書ける 普通のif文しか使ってなかったからわかりにくい・・

nilJavaのnullと同義、何もない false,nilが偽で、それ以外が真 偽 = falseとnil それ以外が真

box = "ball"
if box
  "ボールが入っています"
else
  "ボールは入っていません"
end

boxに何か入っているから、true スッキリした書き方ができる

box = "ball"

a = 
if box
  "ボールが入っています"
else
  "ボールは入っていません"
end

puts a # =>"ボールが入っています"

変数にif文の結果を格納できる

例題

fizzbuzzプログラムを作成する

def fizz_buzz(n)
  if n.modulo(15) == 0
    "#{n.to_s} FizzBuzz"
  elsif n.modulo(5) == 0
    "#{n.to_s} Buzz"
  elsif n.modulo(3) == 0
    "#{n.to_s} Fizz"
  else
    n
  end
end

number = 1..30
number.each do |num|
  puts fizz_buzz(num)
end

ruby fizz_buzz.rb
1
2
3 Fizz
4
5 Buzz
6 Fizz
7
8
9 Fizz
10 Buzz
11
12 Fizz
13
14
15 FizzBuzz
16
17
18 Fizz
19
20 Buzz
21 Fizz
22
23
24 Fizz
25 Buzz
26
27 Fizz
28
29
30 FizzBuzz

要件と違いますが、渡した値、空白、Fizz or Buzz or FizzBuzzで表示するようにしました

感想

戻り値を活用する、メソッドの自作、 メソッドの引数に別のメソッドの戻り値に使う、を使いこなせるようになりたいと感じた。 本の内容全部吸収するぞ!と意気込んで隅々読んでたらめちゃ時間かかりました\(^o^)/

https://qiita.com/jnchito/items/077f6d541d53152aa680
https://github.com/rubocop/ruby-style-guide
https://docs.ruby-lang.org/ja/latest/doc/spec=2fvariables.html#const
https://www.javadrive.jp/ruby/string/index2.html
https://docs.ruby-lang.org/ja/latest/doc/spec=2foperator.html#not
https://qiita.com/jnchito/items/4e47559a4c821474233a

参考、引用: 著者 伊藤淳一 さん「プロを目指す人のためのRuby入門<改訂2版>」 出版社 技術評論社 (2021/11/29) 2章P22~P83

初投稿

このブログでは書籍の要約、得た知識をアウトプットしていきます。

現在チェリー本を読み進めています。

はじめに本の読み方、意識的な部分を書き残しておこうと思います。

書籍の読み方

1、まず全体を読む

2、読みながら重要と感じたところに印を書き込む、サンプルコードを動かす、(コードのアイデアが出てきたら書いて動かしてみる)、要約したい内容と感じたら下書きに控える、章読破を目指す

3、内容が難しく理解できない場合はインデックス作成の読み方に切り替え、読み終えることをゴールにする

各章の例題

1回目は書籍を読みながら同じようにコードを書いてもOK

2回目は問題文だけ読んで何も見ずに自分でコードを書いてみる(リファレンス、ググって参考にしつつ手と頭を使ってコードを書く) その後、コードが書けたら書籍の解答例と照らし合わせて、リファクタリングできそうと感じたらやる

3回、4回とチャレンジする

ブログの書き方

1、章ごとにまとめる、自分が重要だと思ったところだけを書く(情報を削げるほど良い)

2、自分の感想を積極的に書く

3、自分の言葉で説明する

時間はかかりそうですが、上記の方針で読み進めていこうと思います。

参考:https://blog.jnito.com/entry/2018/01/23/075856 https://zenn.dev/jnchito/books/how-to-read-ruby-reference

参考、引用: 著者 伊藤淳一 さん「プロを目指す人のためのRuby入門<改訂2版>」 出版社 技術評論社 (2021/11/29) 1章P2~P20