This commit is contained in:
Rikuoh Tsujitani 2024-03-30 22:05:45 +09:00
parent 0ce6b5c4be
commit 68b1d47934
Signed by: riq0h
GPG key ID: 010F09DEA298C717
3 changed files with 137 additions and 25 deletions

View file

@ -295,7 +295,7 @@ refinements独自のスコープを設定できる。有効にするにはusi
## 3/29 ## 3/29
TypeErrorRubyでは例外も例外クラスのインスタンスになっている。TypeErrorは例外オブジェクトのクラス名 TypeErrorRubyでは例外も例外クラスのインスタンスになっている。TypeErrorは例外オブジェクトのクラス名
予期しない補足例外が発生した箇所がbegin〜rescueで囲まれていない場合、例外が発生するとそこで処理を中断してメソッドの呼び出しを1つずつ戻っていく。途中に例外を補足するコードがあればそこから処理を続行する 予期しない捕捉例外が発生した箇所がbegin〜rescueで囲まれていない場合、例外が発生するとそこで処理を中断してメソッドの呼び出しを1つずつ戻っていく。途中に例外を捕捉するコードがあればそこから処理を続行する
backtraceメソッドバックトレース情報を配列にして返す backtraceメソッドバックトレース情報を配列にして返す
messageメソッド例外発生時のエラーメッセージを返す messageメソッド例外発生時のエラーメッセージを返す
NoMethodErrorこれも例外クラスの一つ。存在しないメソッドを呼び出した時に現れる NoMethodErrorこれも例外クラスの一つ。存在しないメソッドを呼び出した時に現れる
@ -303,12 +303,12 @@ ZeroDivisionError0で除算した時に現れる例外クラスの一つ。
例外クラスの指定: 例外クラスの指定:
begin begin
例外が起きうる処理 例外が起きうる処理
rescue 補足したい例外クラス rescue 捕捉したい例外クラス
例外が発生した場合の処理 例外が発生した場合の処理
end end
のような形式で特定の例外が起こった場合にのみ捕捉させることができる のような形式で特定の例外が起こった場合にのみ捕捉させることができる
例外クラスの継承関係すべての例外クラスはExceptionクラスを継承しており、そこから下はStandardErrorのサブクラスとそれ以外の例外クラスに分かれている。 例外クラスの継承関係すべての例外クラスはExceptionクラスを継承しており、そこから下はStandardErrorのサブクラスとそれ以外の例外クラスに分かれている。
rescure節の挙動なにもクラスを指定しなかった場合にはStandardErrorとそのサブクラスが捕捉される。指定した場合はそのクラス自身とサブクラスが捕捉される rescue節の挙動なにもクラスを指定しなかった場合にはStandardErrorとそのサブクラスが捕捉される。指定した場合はそのクラス自身とサブクラスが捕捉される
捕捉すべき対象最上位のExceptionクラスを指定するとNoMemoryErrorなど特殊なエラーも対象に含めてしまうため、通常はStandardErrorかそのサブクラスに捕捉対象を限定すべきである 捕捉すべき対象最上位のExceptionクラスを指定するとNoMemoryErrorなど特殊なエラーも対象に含めてしまうため、通常はStandardErrorかそのサブクラスに捕捉対象を限定すべきである
例外を書く順番:スーパークラスよりも手前にサブクラスを書く 例外を書く順番:スーパークラスよりも手前にサブクラスを書く
retry例外発生時に処理をやり直させることができる。 retry例外発生時に処理をやり直させることができる。
@ -322,5 +322,66 @@ Date.valid_date?:正しい日付かどうか確認できる
ensure:例外の有無にかかわらず処理を実行させる ensure:例外の有無にかかわらず処理を実行させる
392ページから 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

47
main.rb
View file

@ -1,18 +1,37 @@
print 'Text?: ' module Effects
text = gets.chomp def self.reverse
lambda do |words|
words.split(' ').map(&:reverse).join(' ')
end
end
begin def self.echo(rate)
print 'Pattern?: ' lambda do |words|
pattern = gets.chomp words.each_char.map { |c| c == ' ' ? c : c * rate }.join
regexp = Regexp.new(pattern) end
rescue RegexpError => e end
puts "Invalid pattern: #{e.message}"
retry def self.loud(level)
lambda do |words|
words.split(' ').map { |word| word.upcase + '!' * level }.join(' ')
end
end
end end
matches = text.scan(regexp) class WordSynth
if matches.size > 0 def initialize
puts "Matched: #{matches.join(', ')}" @effects = []
else end
puts 'Nothing matched.'
def add_effect(effect)
@effects << effect
end
def play(original_words)
words = original_words
@effects.each do |effect|
words = effect.call(words)
end
words
end
end end

View file

@ -1,14 +1,46 @@
require 'minitest/autorun' require 'minitest/autorun'
require_relative 'main' require_relative 'main'
class RainbowableTest < Minitest::Test class EffectTest < Minitest::Test
def setup def test_reverse
Object.include Rainbowable effect = Effects.reverse
assert_equal 'ybuR si !nuf', effect.call('Ruby is fun!')
end end
def test_rainbow
expected = "\e[31mH\e[32me\e[33ml\e[34ml\e[35mo\e[36m,\e[31m \e[32mw\e[33mo\e[34mr\e[35ml\e[36md\e[31m!\e[0m" def test_echo
assert_equal expected, 'Hello, world!'.rainbow effect = Effects.echo(2)
expected = "\e[31m[\e[32m1\e[33m,\e[34m \e[35m2\e[36m,\e[31m \e[32m3\e[33m]\e[0m" assert_equal 'RRuubbyy iiss ffuunn!!', effect.call('Ruby is fun!')
assert_equal expected, [1, 2, 3].rainbow
effect = Effects.echo(3)
assert_equal 'RRRuuubbbyyy iiisss fffuuunnn!!!', effect.call('Ruby is fun!')
end
def test_loud
effect = Effects.loud(2)
assert_equal 'RUBY!! IS!! FUN!!!', effect.call('Ruby is fun!')
effect = Effects.loud(3)
assert_equal 'RUBY!!! IS!!! FUN!!!!', effect.call('Ruby is fun!')
end
end
class WordSynthTest < Minitest::Test
def test_play_without_effects
synth = WordSynth.new
assert_equal 'Ruby is fun!', synth.play('Ruby is fun!')
end
def test_play_with_reverse
synth = WordSynth.new
synth.add_effect(Effects.reverse)
assert_equal 'ybuR si !nuf', synth.play('Ruby is fun!')
end
def test_play_with_many_effects
synth = WordSynth.new
synth.add_effect(Effects.echo(2))
synth.add_effect(Effects.loud(3))
synth.add_effect(Effects.reverse)
assert_equal '!!!YYBBUURR !!!SSII !!!!!NNUUFF', synth.play('Ruby is fun!')
end end
end end