なにこれ
Rubyのチェリー本を読んで、感想をメモしたノートをコピー&ペーストしただけの記事です。
人に伝えるつもりで書いてませんので、申し訳有りませんがご了承ください。
自分の頭の中にインデックスを作るのが目的です。
第1章〜4章
rubyは漢字とかひらがなでも変数名にできる。でも基本やらない。
%!%とかで囲んだりすると、シングルorダブルクオートで囲むみたいになる
ヒアドキュメントは長い文字列とか改行する文字を書く時に使う。SQLをべた書きとか。
「?a」って書くと一文字の文字列で認識されるのなんで?
IntとかFloatの数値は全てNumericのサブクラス。
2進数で計算してるから、回り込み問題あり
デフォルト引数はメソッドでもTime.nowでも色々できるよ
「?」で終わるメソッドは慣習で真偽値を返すもの
「!」で終わるメソッドは、エラーを返したり注意する処理を書く。破壊的メソッドの慣習もある。
呼び出したオブジェクトの状態を変更するメソッドを破壊的メソッドと呼ぶ
変数名は「!」と「?」で終わらせるとエラー出るよ
全く同じ実装で名前だけ異なるのをエイリアスメソッドという。好みで選んでもok
式(返り値を変数に代入する)と文(返り値がない)がある
a.object_idでオブジェクトIDが見れる。代入したやつは参照代入だからIDが同じ
putsとprintはto_sで表示、一般用。pはinspectメソッドっていう開発者向け表示
配列に代入する時、番号を飛ばすとnilで埋められる
delete_ifもeachの代わりになる
Rangeオブジェクト(範囲) ピリオド2個か3個で条件違う。最後を含むか含まないか
lastメソッドで配列の最後を取れて、引数で「最後から何個目を取得」が指定できる。firstもしかり
「|」は積集合
「-」は差集合を求める。左の配列から右の配列に含まれる要素を取り除く
[1,2,3] - [3,4,5] = 戻り値:1,2
「&」は積集合
setクラスっていう集合を扱うクラスあり
配列を展開して「複数の引数」として渡したい時は、配列の前に「*」を置く。色々用途あり
個数に制限のない引数を可変長引数と言う
「%w(a b)」で文字列の配列として扱える。空白が改行扱い。「%i」だとシンボルになる。wとiの単語の意味は不明
ミュータブル=変動する、イミュータブル=不変
each_with_indexみたいにmap.with_indexメソッドもある。
.each.with_indexだと引数1を渡すと1から開始になる。逆に_だと渡せない
配列で引数を渡す時、配列の中身文の引数を書くと展開されて書ける。はみ出すとnil
第一引数は、展開する配列。第二引数はindex。第一で()内に展開すると展開してeachできる
File.open("./sample.txt", "w") do |file|
file.puts("1")
end
これでファイルに記述できるの凄い。初めて知った。
do..endと { } は結合度が違う➡️優先度の問題。引数つき「{ }」は「( )」が必須
➡️でも基本()つけるから起こらないよなあ。こんな仕様があるんだ、程度でおk
配列にはいっぱいAPIがある。自分でやりたい処理を書くよりまずドキュメントを読め
mapの後ろにjoinで配列ごとに処理できる。ruby版メソッドチェーン
uptoとdowntoで良い感じに数値の配列をいじれる!
untilっていうwhileの否定文(unlessみたいな)のもある
rubyのfor文の特徴は、for文内で定義した変数がfor文外でも使えること!!
ブロックを使うかの違いを意識せよ
一生繰り返すloopメソッドなるものが存在する
変数にwhile文とかを入れられる。そしてbreakは引数を持てる。階層のbreakは、その階層から出るだけ
throw catchで絶対抜けるマン。シンボルで引数いる。タグっていう
rubyは暗黙的に最後に評価された値を返り値(return(してる
breakとreturnは処理と役割がぜんぜん違う
次の処理へ飛ばすnext、やりなおしのredo
5章
hash同士の比較、キーバリューの順番が違くてもtrueが変える。どれかの値が違うとfalse
これで失敗した時のkeyの値が変える。今回はjapan1
p a.delete('japan1'){ |key| "hoge: #{key}"}
当たり前だけどハッシュとシンボルは別物。シンボルは内部で整数として扱う
シンボルはイミュータブルオブジェクト
キーワード引数は def test(hoge: “fuga”) end // test(hoge: “piyo”) みたいなやつ
アスタリスク2個でハッシュを展開できる
options = {}でハッシュをキーワード引数で取れる。疑似キーワード引数っていう。エラーが絶対起きない引数(nilが返される)。でもこういう表現は便利っぽいけどあんまり好きじゃない。推奨されてない。
**othersでキーワード引数の他に任意のハッシュ引数を取れる
to_a(array)とto_h(hash)で配列にしたりハッシュにしたり出来る
Hash[変数名]とかArray[変数名]でハッシュとか配列に操作できる
has.newする時は「( )」じゃなくて波括弧の「{ }」でブロック引数で返してあげるとobject_idが毎回変わる
これだと追加したコードに引数がどんどん増える
h=Hash.new {|hash,key| hash[key]='hello'}
p h
p h[:foo]
p h[:bar]
p h
シンボルでも文字列展開はできる!
p :"#{name.upcase}"
respond_to?
メソッドは、そのメソッドが使えるかどうかを真偽値で返す
p 'apple'.respond_to?('include?') # true
if文は返り値をチェックするから、この2つは意味同じ。ただ条件比較か代入なのかややこしいから、前者が好き。
def a(b)
c={japan: 'yen'}
c[b]
end
c=a(:japan) # これと
if c = a(:japan) #これは同じ意味
c.upcase # このif文とupcaseも同じ
end
c = c&.upcase # このif文とupcaseも同じ(ぼっち演算子)
puts c
「||=」は自己代入。nilかfalseだったら右辺を代入。a += 1と似てる理由。a = a || 1 みたいな?
a = nil
p a ||= 10 # 10
b = 1
p b ||= 10 # 1
2回繰り返すイメージの「!!」
p !!true # true
p !!1 # true
p !!false # false
下記2つの例は意味同じ。役たちそう
def user_exists?
# user = "a"
# if user
# true
# else
# false
# end
!!true # trueが変える
!!false # falseが変える
end
p user_exists?
6 正規表現
rubyの正規表現をテストできるサイト
https://rubular.com/
\d
メタ文字。半角数字にマッチ
JavaScriptの「g」
グローバルオプション。gあり=一致する文字列全て。gなし=1件ヒットで終了
vscodeのcommand + Fの「■*」で正規表現見れるやん!
文字列のパターンを見つけろ!
{n,m}
文字列を指定する。量子定子(ていこ)っていう。
[AB]
A or Bいずれかの1文字
[a-z]
aからzの文字
[09-]
0 or 9 or -
の検索になる。ハイフンの位置でめっちゃ変わる!
[]
空白スペース文字(半角、全角)も使える!
?
もしくはなし
.
任意の一文字
+
直前の文字が1枚以上
()
囲んだ部分がキャプチャされて連番がつけられる。別の扱いされる??
$
()
で囲んだ部分を抽出。$1,$2
みたいな
*
任意(直前)の文字が0文字以上ある。0も含まれまっせ
?:
グループ化しない
\w
[a-zA-Z0-9_]
と同じ意味。[]
で囲まなくてもええんやで。\w+で同じ文字を繰り返す
+と*は最後までやりきっちゃう。貪欲にworkしちゃう
^
例)[^a]
: A以外の任意の文字
(.*?)
最短のマッチを結果で返す。最小量子定子という
\n
改行文字。正規表現で指定すると行ごと削除して詰めてくれる!
|
or条件
=~
rubyの条件比較。一致した文字の番号を返す + 不一致ならnilを返す(つまり偽)
match
配列で一致&グループ化したものを返す。配列。m[0]
で取れる。
(?\d)
メタ文字。シンボルor文字列で取れる
応用⬇️
if /(?<year>\d+)年(\d)月(\d)日/ =~ text
puts year # year
end
ただし必ず左に正規表現を置く必要あり。変数は駄目?
scan
一致を返す。グループ化すると配列
[ ]
正規表現書ける。基本通り何でも使える
text = '123-45'
p text[/(\d{3})(-)/, 2]
slice
[ ]
のエイリアスメソッド
slice!は破壊的
split
区切る場所を正規表現で書ける
t = '123,456-789'
p t.split(/,/)
gsub
置き換え
t = '123,456-789'
p t.gsub(/(,).+(-)/, '\1fuga\2hoge') # "123,unko-hoge789"
t = '123,456-789'
p t.gsub(/(?<fuga>,)(\d+)/, '\k<fuga>fuga\1aaa') # "123,fugaaaa-789"
t = '123,456-789'
hash = { ',' => ":::::" }
p t.gsub(/,/, hash)
t = '123,456-789'
p t.gsub(/,/) { |m| m == ',' ? '::::' : '//////'}
おまけ
# p 'HELLO' =~ /hello/i # 大文字小文字無視
# regexp = Regexp.new('hello', Regexp::IGNORECASE)
# p 'HELLO' =~ regexp
# p "Hello\nBye #hoge" =~ /Hello.Bye/xm # コメントと改行を「.」で認識
text = "1977年"
text =~ /(\d+)年/
p $~ # #<MatchData "1977年" 1:"1977">
p $& # "1977年"
p Regexp.last_match(1) # "1977"
$で始まるのを組み込み変数というらしい
7章 クラス
クラスを使う理由:堅牢だから。値を勝手に書き換えられないから?
クラスのオブジェクト=インスタンスと同義
レシーバとメッセージと呼ばれる場合がある。
次の場合、userがレシーバ
first_nameというメッセージを送っていると表現できる
user = User.new('Bob', 'Python', 30)
user.first_name
attr_accessor
はオブジェクトの読み書きを許可する。
# attr_accessorがない場合
a.first_name = 'ありす' # undefined method `first_name
# attr_accessorがあると
a.first_name = 'ありす' # ありす 代入できる!
initializeは自動的にprivateが付与される。
private以下のメソッドは呼び出すとprivate method
full_name' called`と言われる
ローカル変数はアンダースコアで始める場合がある
存在しないインスタンス変数にアクセスするとnilが返る
次のようなメソッドを用意すると、メソッドっぽいけどインスタンス変数に代入できる
def name=(v)
@name = v
end
user.name='fuga'
attr_readerは読み込み専用、attr_writerは書き込み専用
a.name = ('2') #writer
p a.name # reader
豆知識:クラスは上書きできる
インスタンスによって内部のデータが違う
インスタンスメソッド
a = User.newみたいに、aには使えるのがインスタンスメソッド
class << self \n クラスメソッド
ってやってもクラスメソッドを宣言できる。
こっちはselfがいらない。でも一般的じゃないらしい
ローカル変数に代入するのか、クラスのインスタンス変数に代入するかは大きく違う
a = User.new("hoge")
def name1
name = '1'
end
p a.name # “hoge”
def name2
self.name = '2'
end
p a.name # “2”
インスタンスメソッドからクラスメソッドは呼び出せない
逆にクラスメソッドからはインスタンスメソッドを呼び出せない
極端な例だけど、クラス作成時にクラスメソッドを呼び出せる。でもインスタンス化すると呼び出せない。
インスタンスメソッドは、そのインスタンスごとに変更を加えたい場合(save!など)
クラスメソッドは、すべてのデータに変更を加えたい場合(all, searchとか全体に影響するもの)
インスタンスメソッド内でクラス名.クラスメソッド(selfの)したら、一応クラスメソッドを呼び出せる
継承で、サブクラスはスーパークラスの1種(is-a) DVD is a Productみたいな?
全てObjectクラスを継承している。だから生成したクラスでto_sやnil?が使える。
余談:オーバーライドしたメソッドでsuperすると一行上に出力されるのね><
privateメソッドは、レシーバー(user)を指定して呼び出せないから、クラスの外から呼び出せない。
privateメソッドは継承してもオーバーライドできる。
クラスメソッドはprivateが効かないけど、<< selfを使えばprivateにできる。private_class_methodっていうおまじないもある。
protectedはレシーバー(user)のインスタンスメソッドから呼び出せる。直接呼び出すとエラー出る。
privateはレシーバーすら設定できないけど、protectedはレシーバーを元に呼び出せる!!!
定数はメソッドの内部で作成はできない。必ずクラス構文の直下
配列だったり順番を指定すると定数でも再代入される。freezeとか関係するところに注意!
エイリアスの設定方法
alias new_method old_method
undefでメソッドを消せる
変数に代入しながらメソッド呼び出し
old_method=(value)
a.old_method = "value"
equal?はobject_idを参照
==はオブジェクトの内容が正しいか
eql?はハッシュのキーが違う場合を見る
===はcase分のwhenで使う
rubyはクラスの継承に制限がない
既存の実装を上書きして挙動を返ることをモンキーパッチ
特定のオブジェクトに紐づくものを特異メソッド(def alice.hello)など
クラスメソッドも実際は特異メソッド。selfでクラス自身を指定してるからね
ダックタイピングしてる
8章
モジュールからインスタンスは作成できない
他のモジュールやクラスを継承できない
ミックスイン
rubyだとモジュールをクラスに追加すること。includeとextendの種類は関係なし
モジュールもprivateメソッドを使える!
extendで特異メソッド(classメソッド)で使える。selfないと使えないよ!
all?メソッド。全て真ならtrue。ブロック引数を持てるみたい
includeでインスタンスにmodule先をメソッドを許可するっぽい。レシーバーでミックスインのメソッドが使える。
Enumerableモジュールがある。こいつがmapとかfindを持ってる!
Comparableモジュールが演算子を持ってる。includeすれば好きな演算子に変更できる
<=>
が鍵を持ってる!UFO演算子っていうらしい
selfはmainクラスを継承
ObjectはKernelモジュールをincludeしてる。だから全てでputsメソッドとかが使える!
特定のインスタンスにmoduleをextendできる
クラスは親1つしか継承できない。モジュールは複数で継承できる
モジュールの中にクラスを作ることが出来る。
モジュールファンクションメソッドを使うと、ミックスイン&特異メソッドとして使える!?でもprivateメソッドになる
ただし他のクラスにミックスインするとprivateメソッドになる。
モジュールはインスタンス化できない。
ancestorsメソッドでどの順番でメソッド探索されるか見れる
prependでincludeしたmoduleのメソッドが優先される
呼び出した順番に寄って変わる。最初に見つかったやつを返す。find_byと同じですね
prependした瞬間に呼び出す位置が変わる!
refineでメソッドの範囲を明示できる
::
(コロン)と.
(ドット)どちらでもメソッド呼び出しを使える
9 例外処理
例外はどこでも投げれるけど、適切な範囲で運用しないといけない
rescueの後ろにクラス名を書くと、そのクラスのエラーをキャッチできるよ!
rescue NoMethodError => e
NoMethodErrprはNameErrorを継承してるから、rescue NameErrorでcatchできる
ていうか継承してるクラスだったら何でもキャッチできる。StandardErrorとか大本のExceptionクラスとか
retry
で例外になっても再開できる。無限ループになりやすいので注意
raise
で例外に投げられる。エラーメッセージ添えられる。
安易にrescueは使うな。思わぬエラーが生まれる。基本は異常終了か共通処理にまかせて
例外処理(beginとrescueの間)の範囲を狭めろ。原因範囲が少なくてデバックが楽になるから
引数だけのエラーをチェックするとかにしたほうが良い?
例外処理より条件分岐の方がパフォーマンスとか含めて良い。ドキュメント読め
ensureで通常終了、例外時どちらでも処理を実行できる
elseで例外が発生しなかった時の処理をかける
例外処理にも返り値はある。ensureは出力だけで返り理はないっぽい?
ensureでreturnするとそれが返り値になる。絶対やるなよ!
10 yield procとは
yieldを使うとブロックを引数で取ってきて使える
ブロック無しでyieldが呼ばれるとエラー吐く
yieldに引数を持たせられるよ
block_given?でtrue or falseを返す
procはブロックをオブジェクト化するためのクラス。callで呼べる。procメソッドでもおk
procオブジェクトを引数で渡すには、&が必要。渡す側と受け取る側の両方で。➡️省略できます!
block.callは引数がなかったらnilになる。
でも、次の2つは引数チェックが厳格。一致しないとエラーになります
proc = ->(a,b){ a+b }
proc = lambda { |a,b| a+b }
to_procっていう裏でよしなにやってるメソッドがある。
次の2つの出力結果が同じ理由
p ['Ruby', 'Java', 'Perl'].map { |s| s.upcase }
p ['Ruby', 'Java', 'Perl'].map(&:upcase)
&
でブロック引数を受け取る。
シンボルの:upcase
で裏側でto_procメソッドが動く。
ブロックで渡された変数?にupcaseメソッドが適用&返される
upcaseが適用できる理由は、引数がないから(?)
Proc.newはreturnかbreakすると処理をすべてやめる
lambdaは処理のループを抜けて次の処理で進む。この違いがある
11 デバック技法
バックトレースは下が古い。上に書けて新しくなっていく。下が重要にしてほしい
初歩的だけどエラーログを下から順におっていこう。
実行されたメソッドとか順番でログが出るから!
ちなNameErrorはNoMethodErrorの親クラス
SystemStackErrorは再帰的な状況に発生しやすい
最近よく見る
tapデバッグ。ブロックの引数をそのまま戻り値として返す。
a='hello'.split('').tap{|s|p s}.join('-').tap{|s|p s}
pメソッドも戻り値が出力した値らしいから、途中で差し込んでも問題ない
putsメソッドは戻り値がnilなのでダメです。あああ〜
Rakeコマンドは、まとまった処理(タスク)を実行するのに適している
descで説明、namespaceも使える。「:」コロン1個でok