Last active
December 5, 2018 14:28
-
-
Save hanachin/b5e308bdbe487e1ad6324bcd27d290d8 to your computer and use it in GitHub Desktop.
TracePointのenable(target: )は戻り値を書き換えるときべんり ref: https://qiita.com/hanachin_/items/d5e243048900344b2146
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 2.6.0-devで動く | |
using Module.new { | |
refine(Object) do | |
def fizzbuzz_env(*ns) | |
Module.new { | |
# このRefinementsのモジュールをあとで使うので取っておく | |
r = refine(Integer) { | |
# methodがRubyで定義されていないとenableのtargetに指定できないため | |
# Refinementsで再定義 | |
def to_s | |
super | |
end | |
} | |
refine(Object) { | |
# fizzbuzzの環境ではメソッド名が数字のメソッドを定義しておく | |
# 以下はfizzbuzz, fizz, buzzに対応したメソッドの定義 | |
ns.each do |n| | |
if n % 3 == 0 && n % 5 == 0 | |
define_method(:"#{n}") { "fizzbuzz" } | |
elsif n % 3 == 0 | |
define_method(:"#{n}") { "fizz" } | |
elsif n % 5 == 0 | |
define_method(:"#{n}") { "buzz" } | |
end | |
end | |
# 普通の数字はmethod_missingで拾う | |
def method_missing(name, *) | |
return super unless name.match?(/\A\d+\z/) | |
name.to_s | |
end | |
# 普通にputs 1と呼ぶとRefinementsで定義したto_sが呼ばれない、to_sを呼ぶ処理を入れる | |
def puts(*args) | |
super(*args.map(&:to_s)) | |
end | |
define_method(:fizzbuzz) { |&block| | |
# このTracePointはenableするときにtargetが絞られている | |
# Integerのto_sにしか反応しないので色々なガード条件を考える必要がない! べんり! | |
# ガード条件を1つも書かずに雑に書き換えてOKです | |
rewrite = TracePoint.new(:return) { |tp| | |
tp.return_value[0..-1] = __send__(tp.return_value) | |
} | |
# Integer.public_instance_method(:to_s)だとrefineしたメソッドが取れない | |
# また、Cで書かれているメソッドはtargetに指定できない | |
# なので先程のRefinementsの中でRubyで定義したto_sをr経由で参照する | |
# このfizzbuzzメソッドにわたしたブロックの中でIntegerをputsしたりto_sすると | |
# fizzbuzz化した文字がかえる。 | |
rewrite.enable(target: r.public_instance_method(:to_s), &block) | |
} | |
} | |
} | |
end | |
end | |
} | |
using fizzbuzz_env(*1..100) | |
# fizzbuzz化した文字がでる | |
fizzbuzz do | |
puts *1..16 | |
end | |
puts "-" * 16 | |
# こっちは普通の数字がでる | |
puts *1..16 | |
puts "-" * 16 | |
# ふつうの文字はfizzbuzz化しない | |
fizzbuzz do | |
puts "1" | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
% ./ruby -v --disable-gems /tmp/tp.rb | |
ruby 2.6.0dev (2018-12-04 trunk 66199) [x86_64-linux] | |
1 | |
2 | |
fizz | |
4 | |
buzz | |
fizz | |
7 | |
8 | |
fizz | |
buzz | |
11 | |
fizz | |
13 | |
14 | |
fizzbuzz | |
16 | |
---------------- | |
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
---------------- | |
1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment