hp12c
01 April 2014

Rubyでカウンタを作る最新の方法があると聞いて...

呼び出す度に数値が1づつ増えたり減ったりするカウンタを、Rubyで書くとしたらどうやりますか?

こんな感じですか。

class Counter
 def initialize(init=1)
 @current = init
 end
 
 def inc
 @current += 1
 end
 def dec
 @current -= 1
 end
end
c = Counter.new
c.inc # => 2
c.inc # => 3
c.inc # => 4
c.inc # => 5
c.dec # => 4
c.dec # => 3
c.dec # => 2
c.dec # => 1

あるいはEnumeratorを使ったこんな感じですか。

def counter(op=:+, init=1)
 Enumerator.new do |y|
 cur = init
 loop { y << cur; cur = cur.send(op, 1) }
 end
end
inc = counter
inc.next # => 1
inc.next # => 2
inc.next # => 3
inc.next # => 4
dec = counter(:-, 10)
dec.next # => 10
dec.next # => 9
dec.next # => 8
dec.next # => 7

それとも、stepとか使いますか。

def counter(n=1, by=1)
 n.step(by:by)
end
inc = counter
inc.next # => 1
inc.next # => 2
inc.next # => 3
inc.next # => 4
dec = counter(10, -1)
dec.next # => 10
dec.next # => 9
dec.next # => 8
dec.next # => 7

最新式カウンタ

でも、どうやらそうじゃないらしいんですよ、最新のやり方は。

こうやるらしいんです...。

AprFl.set
def inc
 1
end

incメソッドを定義して初期値をセットすればいいらしいのです。

ほんとですかね?

実行してみます。

inc # => 1
inc # => 2
inc # => 3
inc # => 4

なるほど。カウントアップしてる...。

decもやってみますね。

AprFl.set
def dec
 10
end
dec # => 10
dec # => 9
dec # => 8
dec # => 7

ほぅ。カウントダウンしている...。

それで、名前はincdecじゃなくてもいいようなんですよ。

AprFl.set
def increment
 1
end
increment # => 1
increment # => 2
increment # => 3
increment # => 4
def decrement_for_me
 10
end
decrement_for_me # => 10
decrement_for_me # => 9
decrement_for_me # => 8
decrement_for_me # => 7

へぇ。

Counterクラスでもイケるそうなんです。

AprFl.set
class Counter
 def initialize(init)
 @init = init
 end
 def inc
 @init
 end
end
c = Counter.new(3)
c.inc # => 3
c.inc # => 4
c.inc # => 5
c.inc # => 6

引数も取れるらしい。

c.inc # => 7
c.inc # => 8
c.inc(2) # => 10
c.inc # => 11
c.inc(3) # => 14
c.inc # => 15

はぁ。

初期値に数字以外をセットするとどうなりますか?

def inc
 "hello, world!"
end
inc # => "hello, world!"
inc # => "hello, world!"
inc # => "hello, world!"
inc # => "hello, world!"
def dec(chr)
 chr.next
end
dec('A') # => "B"
dec('A') # => "B"
dec('A') # => "B"
dec('A') # => "B"

普通の挙動ですね。

しかし、世の中知らないことだらけですよ。Rubyにこんなやり方あるなんて!

ということで、Rubyでカウンタを作る最新の方法を紹介しました!





いやいや、AprFl.set、置いてけって。

module AprFl
 def self.set
 t = Time.now
 define_aprfl_method if [t.mon, t.day] == [4, 1]
 end
 def self.define_aprfl_method
 TracePoint.trace(:return) do |tp|
 k, m, v = tp.defined_class, tp.method_id, tp.return_value
 op = 
 case m
 when /^inc/ then :+
 when /^dec/ then :-
 else next
 end
 k.class_eval {
 undef_method m
 define_method(m) { |*a, &b| v.send(op, (a.first||1)) rescue v }
 }
 end
 end
end

またTracePointねたですか。


関連記事:

Rubyでワンタイムメソッドを実装して「スパイ大作戦」を敢行せよ!


(追記:2014年4月2日) stepの例を追加しました。



Please enable JavaScript to view the comments powered by Disqus. blog comments powered by Disqus
ruby_pack8

100円〜で好評発売中!
M'ELBORNE BOOKS


AltStyle によって変換されたページ (->オリジナル) /