メタプログラミング実践 - shinjuku.rb #18

  • 1,569 views
Uploaded on

shinjuku.rb #18で発表しました

shinjuku.rb #18で発表しました

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,569
On Slideshare
0
From Embeds
0
Number of Embeds
9

Actions

Shares
Downloads
8
Comments
0
Likes
4

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. メタプログラミング実践@shokaishinjuku.rb #182013/06/26
  • 2. •@shokai (しょうかい)•初参加•趣味:料理、glitch、プログラミング•Sinatra派•minitest派
  • 3. せっかく新宿に来たのだから聖地巡礼しよう!!→ 小屋が見つからない靴が濡れて足痛い
  • 4. 引きこもってコード書いてたらネタが溜まってきたので放出していきたい
  • 5. メタプログラミングとは
  • 6. 「コードを記述するコード を記述すること」(p.11)
  • 7. なるほどわからん
  • 8. 実際やってみたらわかった!やってみるの大事
  • 9. 今日はメタプログラミングを使って実装してみた3つのGemをご紹介いたします
  • 10. % gem install skypeSkype Desktop APIのラッパーMac/Linux対応https://github.com/shokai/skype-rubymethod_missingを使用
  • 11. require rubygemsrequire skype# チャットSkype.message("shokaishokai", "電話かけます")# 電話Skype.call("shokaishokai")call関数やmessage関数はgem内に実装されていないしかしなぜか呼び出せる
  • 12. module Skypedef self.method_missing(name, *args)self.exec "#{name.upcase} #{args.join( )}"endendmethod_missingSkype Desktop API"CALL shokaishokai""MESSAGE shokaishokai こんにちは"Query文字列をSkype.appに送るだけの簡単仕様実装されていない関数の呼び出しを受け取る関数Skype.execの中身はMac/Linux別々に実装
  • 13. • method_missingはAPIのラッパーを作るのに便利• (APIに規則性がある場合のみ)• API側が変わっても、gemを修正する必要がない• 例:”CALL shokaishokai” が “CALLTO shokaishokai”に仕様変更されても、Skype.callto “shokaishokai” で呼び出せる• Twitter gem等でも使われている
  • 14. % gem install babascriptコンピュータが得意な事はコンピュータが、人間が得意な事は馬場くん  がやってくれる言語https://github.com/masuilab/babascriptinstance_eval, method_missingを使用@takumibaba
  • 15. % baba -e アイス買ってきて("#{rand 5}本")baba -e ’コード’もしくはbaba ファイル名
  • 16. 結果
  • 17. #!/usr/bin/env babaif 0 < Time.now.hour and Time.now.hour < 5もう寝ろ!!else意識を高めてコードを書こう!endwake-up.bb% baba wake-up.bb実行ただのRuby…ではなく日本語で書いた部分を馬場君が実行してくれる
  • 18. class Foodef initialize@name = "bar"endendfoo = Foo.newfoo.instance_eval doputs @name # => "bar"endinstance_evalbabaコマンドの中身 = instance_evalFile.open(fname) do |f|BabaScript::Baba.instance_eval f.readendコードやブロックをそのインスタンスのコンテキストで実行するfooのコンテキストで実行されるのでアクセサが無いプロパティ@nameも読める
  • 19. module BabaScriptclass Babadef self.method_missing(name, *args)## (略) Androidにnameとargsを送信するendendendRubyの関数名には日本語が使える→ method_missingで全部取れるFile.open(fname) do |f|BabaScript::Baba.instance_eval f.readend
  • 20. • instance_eval + method_missingで言語が歪む• エラーメッセージがわかりにくくなるので、何でもかんでもinstance_evalするとコード追えなくなる• rspecなど、英語っぽいDSLで書けるgemで使われているはず
  • 21. 人間を関数のように扱えるようになるスマホアプリ+人間に命令を送る構文を追加したプログラム言語→ 人間とプログラム言語の新しい関係
  • 22. % gem install event_emitter全てのクラス/インスタンスにイベント機能を追加できるhttps://github.com/shokai/event_emittermix-in, instance_evalを使用(これメタプログラミングじゃない気がする!)
  • 23. class Crawlerinclude EventEmitterdef start(urls)Thread.new dourls.each do |url|beginemit :get, url, HTTParty.get(url).bodyrescue => eemit :error, url, eendemit :completeendendendendcrawler = Crawler.newcrawler.once :error do |err|STDERR.puts eexit 1endcrawler.on :get do |url, page_data|puts "page #{url} get!!"puts page_dataendcrawler.start ["http://shokai.org", "http://example.com", "http://github.com"]mix-inイベント発行イベント受信
  • 24. class Fooinclude EventEmitterendclass宣言時にinclude → instance全てにイベント機能が付くEventEmitter.apply Timeclassにapply → class methodとしてイベント機能が付くnow = Time.nowEventEmitter.apply nowinstanceにapply → そのinstanceだけにイベント機能が付く(特異メソッド)全てのオブジェクトにイベント機能を追加できる非同期プログラミングに大変便利
  • 25. module EventEmitterdef self.included(klass)klass.__send__ :include, InstanceMethodsenddef self.apply(object)object.extend InstanceMethodsendmodule InstanceMethodsdef __events@__events ||= []enddef on(type, params={}, &block)## 略enddef emit(type, *data)## 略endendendincludeされた時に呼び出される特異メソッド注入用module内のインスタンスメソッドとプロパティが注入されるprivate methodを強引に呼ぶ
  • 26. • なぜincludedで受けてもう一度includeを呼んでいるか?というと• gemのネームスペース直下をそのままincludeさせるのが嫌だった• 子moduleに機能を集約したい
  • 27. メソッドが増えているmix-in前後を比較
  • 28. • included関数でincludeを受け止めて、複数includeしちゃう事も可能• 動物とか犬とか人間とかの階層分けオブジェクト指向ではなく、機能レベルでの抽象化に向いてる気がする• Sinatraのプラグイン機構に使われている• EventEmitterはブラウザ用JavaScript版もありますhttps://github.com/shokai/event_emitter.js
  • 29. Sinatra::RocketIOでも使っているSinatraでNode.jsのSocket.IOのような事ができるRubygemwebsocket/comet対応
  • 30. おわり
  • 31. 質問などあれば•@shokai•お気軽に•お声かけください