>> 古い記事: ゲームなどでVLゴシックフォントを使用(同梱)する場合の扱い・ライセンスについてのメモ
<< 新しい記事: Ruby/Tk: TkFrame を使って listbox+scrollbar を配置する

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Ruby: eval からブロック付きメソッドへ、書き方を順に変えてみる

例として配列もどき、メディアプレーヤなんかで使いそうな PlayList クラスを使う。

class PlayList
  def initialize( arr )
    @track_list = arr
  end
end

PlayList.track_list のそれぞれの要素に対応して (それぞれの要素を使って)何らかの「処理」をしたくなったとする。
さらに、汎用的にする(使いまわせるようにする)ために、 「処理」の内容は呼び出す側で指定できるようにする、という場合を考えてみる。

ブロック付きメソッド(イテレータ)よく分からん、でも eval なら知ってるしよく使う、 という人はこんな感じにするんじゃないでしょうか。
(いや、ツッコミ入るでしょうが説明のためということで…)

class PlayList
  def initialize( arr )
    @track_list = arr
  end

  def each( str )
    @track_list.each do |track|
      eval str
    end
  end
end

pl = PlayList.new( ["track1", "track2", "track3"] )

pl.each( %Q! puts "\#{track}" ! )

結果:

track1
track2
track3

「処理」の内容を呼び出す側で指定することができた。

処理を変更する場合も

pl.each( %Q! print "\#{track}\n" ! )

などと呼び出す側で変更できる。

ただし、処理が複雑になるとややこしくなるし、 eval を使うこの方法はできれば使いたくない。 この時点でもうすでに #{} を使って さらに # をエスケープしたりしていて、 かなりいやな雰囲気が漂っている。

Ruby ハチドリ本 にも 「 経験の浅いプログラマは、杖をつくようにevalを使ってしまうことがある。 自分のコードでevalを使いたくなったときには、 使わずに済ませる方法がないか、よく考えた方がよい。」 (p279) とある。


上の方法だと「処理」を文字列としてメソッドに渡したが、 文字列ではなく Proc オブジェクトを渡すようにしてみる。 落ち着いて見れば上のとやってることは大体一緒です。こわくないです。

class PlayList
  def initialize( arr )
    @track_list = arr
  end

  def each( proc_b )
    @track_list.each do |track|
      proc_b.call( track )
    end
  end
end

pl = PlayList.new( ["track1", "track2", "track3"] )

proc_a = Proc.new {|x| puts x }

pl.each( proc_a )

(実行結果は上のと同じなので以後も省略)

「文字列+eval」に比べるとすっきりしてかなりいい感じになった。 もうこれでもいいんじゃないかとも思える。


proc_a は一時的なオブジェクトとして使っているだけなので、これをなくしてみる。 当然、こうしても同じように動作する。

# proc_a = Proc.new {|x| puts x }
# pl.each( proc_a )
# ↓
pl.each( Proc.new {|x| puts x } )

さらに、もっと省略できる。

pl.each{|x| puts x }

この場合は、メソッド定義の方には '&' を付けなければいけない。

def each( &proc_b )

この時点ではこんな感じ。

class PlayList
  def initialize( arr )
    @track_list = arr
  end

  def each( &proc_b )
    @track_list.each do |track|
      proc_b.call( track )
    end
  end
end

pl = PlayList.new( ["track1", "track2", "track3"] )

pl.each{|x| puts x }

ちょっと脱線して Javascript で書いてみた。動くけど適当です。

function PlayList( arr ){
  self = this;
  self.track_list = arr;
  self.each = function( proc ){
    for( n in self.track_list ){
      proc( self.track_list[n] );
    }
  };
}

var pl = new PlayList( ["track1", "track2", "track3"] );

pl.each( function( x ){ alert( x ); } );

で、さらによく見ると proc_b も一時的に使ってるだけなので、 これも省略できるんじゃない? という訳で yield の登場。

class PlayList
  def initialize( arr )
    @track_list = arr
  end

  def each()
    @track_list.each do |track|
      yield( track )
    end
  end
end

pl = PlayList.new( ["track1", "track2", "track3"] )

pl.each{|x| puts x }

かなりすっきりして、ブロック付きメソッドの紹介記事なんかで よく見かける形になった。 さらに、Ruby ではメソッド呼び出しの括弧は省略できるので

yield track

としても良い。

感想など

いきなり yield を使った例が出てきて 「こういうのが Ruby的なスタイル」 というふうに提示され、 「明示的に書くには Proc も使える」 みたいなブロック付きメソッドの解説を見かけるけど、 泥臭い書き方から洗練された(抽象的な)書き方へと並べた方が 自分みたいな素人には分かりやすいかもと思ってやってみた。

こういう用途で eval が使いたくなったら ブロック付きメソッドに置き換えられないか検討してみるのが良さそう。


ひるがえって、 これから初めてHTMLを勉強しようという右も左も分からない相手に、 「こんにちのHTMLでは構造と形式を分離しなければならないのである。 なぜならそのほうがべんりで正しいのである。 構造とはこれこれで形式とはこれこれのことである。 であるから、 fontというタグは使っては、 いけません」なんて告げてみても、 実感として理解してもらえるかどうか分からない。 言っている内容が正しいか否かでなく、 教育の問題、 勉強する側からみれば学習の問題だ。 こんなジョークがある。 「新しい数学教育は完全に成功した! 小学生に 3+4 はいくつか尋ねたら、 相手は立派な答をした――いわく『加法は可換だから 4+3 に等しい』」

参考(外部リンクなど)


プログラミング言語 Ruby

>> 古い記事: ゲームなどでVLゴシックフォントを使用(同梱)する場合の扱い・ライセンスについてのメモ
<< 新しい記事: Ruby/Tk: TkFrame を使って listbox+scrollbar を配置する
** ホームに戻る

コメント

コメントの投稿

管理者にだけ表示を許可する

|
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。