狠狠撸

狠狠撸Share a Scribd company logo
メタプログラミング搁耻产测

      LLPlanets
      2011-8-20
        ?征典
   kdmsnr@gmail.com



          1/50
?征典-办诲尘蝉苍谤




      2/50
MF'sbliki




    3/50
Rubyにおける
メタプログラミングとは?



     4/50
内部DSLを
内部DSL
 書くこと
  である
  5/50
プログラミング?語Ruby
8章リフレクションとメタプログラミング
 豊富なリフレクション
    リフレクションAPIを使い、
 メタプログラミングを実現する。
 メタプログラミング
 それは、DSLを書く
     DSLを書くという発想と
 結び付いている。


         6/50
顿厂尝の种类
   byMartinFowler
外部DSL(?語外DSL)
内部DSL(?語内DSL)
?語ワークベンチ→ググって


          7/50
外部顿厂尝の例
    CucumberのGherkin記法
フィーチャ: プロジェクトの閲覧
 ユーザとして、
 プロジェクトを閲覧したい。
 それは、チケットを割り当てるためだ。

 シナリオ: すべてのプロジェクトを?覧表?する
  前提 TextMateプロジェクトがある
  かつ ホームページを表?している
  もし TextMateリンクをクリックする
  ならば TextMateプロジェクトページを表?する

              8/50
内部顿厂尝の例
         tDiaryのテストコード
feature '?記の追記' do
  scenario '?付を指定して新しく?記を書く' do
    append_default_diary('2001-04-23')
    visit '/'
    click_link 2001年04?23?
    within('div.day div.section') {
      page.should have_content
        とりあえず?前の環境では +
        ちゃんと動いているが、 +
        きっと?がいっぱいあるに違いない:-P}


                   9/50
DSLの再来

  DSLに対する関?は急激に?まって
きています。これはRubyコミュニティ
          Rubyコミュニティ
のおかげと?ってもよいでしょう。
のおかげ
―『プログラミングScala』



         10/50
おそらく搁补颈濒蝉
       Railsが発端
        設定よりも規約(CoC)
# usersテーブルとマッピング
class User  ActiveRecord::Base
end




                    11/50
DSLの?的
forプログラマ
  ?産性?理解度?表現?の向上

forプログラマ+ドメイン専?家
            ドメイン専?家
  コミュニケーションの円滑化
  コミュニケーション



            12/50
DSLにあると嬉しい
  byGlennVanderburg
?脈が記述できる
?章のように記述できる
単位が記述できる
使える語彙が豊富である
階層データが記述できる
          13/50
新しい语汇
   語彙をうまく導?
語彙の増加→新しい視点
語彙         視点
  サピア=ウォーフの仮説
  例)BDD(振る舞い駆動開発)

「名前重要」?化


        14/50
新しい?法
   ?法は導?しない

  ?年拒否している機能 があります。
    拒否している機能
それはマクロ,特にLispスタイルのマ
         Lispスタイルのマ
クロです。
クロ
―『まつもとゆきひろコードの世界』



         15/50
メタプログラミング技法の
  分類?概要?応?例



     16/50
RubyでDSLを作る?針
?葉を?つける
?章のように書いていく
Rubyの?法に合わせる



       17/50
コレクションがあってシャッフルし
 たいと思ったら
    思ったら、shu?eと書いて、そ
 れで動かなきゃいけない
    動かなきゃいけないんですよ。
 ―yugui

http://www.atmarkit.co.jp/news/200907/24/
ruby2.html




                    18/50
Rubyの基本的な道具
オブジェクトと変数
メソッドとブロック
制御構?(if,unless,while,...)



            19/50
メソッドチェイン
   a.k.a.流れるようなインタフェース
3.weeks.ago.saturday?

(0..9).map{|i| i + 1 }.reduce(:+)

User.where(:hobby = Ruby).
  order(:nickname).limit(10).offset(20)



                    20/50
カッコの省略
# メソッド呼び出し、引数のハッシュリテラル
establish_connection :adapter = sqlite,
                     :database = dbfile

# ブロック(do ... end)
group :test do gem shoulda end

# if ?
if true then \(^o^)/ else '/(^o^)\' end



                    21/50
オープンクラス
3.hours.from_now # 今から3時間後を求めたい

# あらかじめ以下を定義
class Fixnum
  def hours
    self * 3600
  end

  def from_now
    Time.now + self
  end
end

                      22/50
クラスマクロ
    単なるクラスメソッドの呼び出し
class Book  ActiveRecord::Base
  has_many   :releases
  belongs_to :publisher
  validates_presence_of :title, :author
end




                    23/50
?クラス主義とMix-in
module ActiveRecord
  class Base
  # ...
  Base.class_eval do
      include ActiveRecord::Persistence
      extend ActiveModel::Naming
      extend QueryCache::ClassMethods
      extend ActiveSupport::Benchmarkable
      extend ActiveSupport::DescendantsTracker

      include ActiveModel::Conversion
      include Validations



                    24/50
クラスもオブジェクト
# オブジェクトIDを持っている
Fixnum.object_id # = 2156200840

# 任意のモジュールで機能拡張できる
target.extend ActiveModel::Naming
# 変数に代?できる
fxn = Fixnum
fxn.name         # = Fixnum



                    25/50
戻り値がクラスのメソッド
        a.k.a.ミミックメソッド
# Camping by _why
class Index  R /     # = Here
  def get
    render :index
  end
  # ...



                      26/50
演算?もメソッド
require 'open-uri'
require 'hpricot'
doc = Hpricot open http://www.ruby-lang.org/ja

# 「/」で要素を検索している
doc / :div.post / :h3 # = 実?結果




                    27/50
まとまったタスクの记述
             Chefのレシピ
directory /tmp/monkey do
  owner root
  group root
  mode 0755
  action :create
end




                    28/50
ブロック付メソッド呼出し
recipe = Recipe.new(:TKG)
recipe.step ?卵に醤油を?れよくかき混ぜる。
recipe.step 箸で茶碗の飯に適当な窪みを作る。
recipe.step 卵を窪みに流し込み、飯と混ぜる。

# 上のコードを意味的にまとめると
Recipe.create(:TKG) do
  step ?卵に醤油を?れよくかき混ぜる。
  step 箸で茶碗の飯に適当な窪みを作る。
  step 卵を窪みに流し込み、飯と混ぜる。
end


              29/50
ブロックの「?脉」で评価
             instance_eval
class Recipe
  def self.create block
    obj = self.new
    obj.instance_eval block
    obj
  end
  # ...



                    30/50
eval族
instance_eval,class_eval
instance_exec,class_exec
eval



              31/50
method_missing
        a.k.a.ゴーストメソッド
require 'ostruct'
ost = OpenStruct.new
ost.iofjklffhdlsakf = 'めちゃくちゃなメソッド'

# 呼び出し
ost.iofjklffhdlsakf # = 実?結果



                  32/50
もっとメタプログラミング



     33/50
ennnnnd
      http://redmine.ruby-lang.org/issues/5054


module MyModule
  class MyClass
    def my_method
      10.times do
        if rand  0.5
          p :small
        ennnnnd # = Here


                        34/50
各種ライブラリ
ParseTree(1.8only)
Rubinius(処理系),RubyParser
Ripper(1.9標準添付)
Racc(パーザジェネレータ)
rparsec(パーザコンビネータ)

           35/50
Webフレームワークの
 メタプログラミング



     36/50
http://lokka.org/



       37/50
HTTPメソッドとメソッド
get '/admin/posts' do
  # ...
end

put '/admin/posts/:id' do |id|
  # ...
end

delete '/admin/posts/:id' do |id|
  # ...
end


                    38/50
HTTPヘッダとメソッド
get 'index.atom'
  # ...
  content_type 'application/atom+xml',
               :charset = 'utf-8'
  # ...
end




                    39/50
搁耻产测のバージョンの调整
             オープンクラス
unless String.public_method_defined?
                           (:encoding)
  class String
    def encoding(encoding)
      self
    end
  end
end


                    40/50
haml
         HTML作成?の外部DSL
- if locale == settings.default_locale
  - page = Page('home') || Page.new
- else
  - page = Page(home-#{locale})
.section
  .header
    %h2= page.title
  .body= page.body


                    41/50
RSpec
          テスト?の内部DSL
describe App do
  context Access pages do
    it should show index do
      get '/'
      last_response.body.should 
        match('Test Site')
    end
  end
end


                    42/50
短缩メソッドの追加
           特異メソッドの利?
def Page(id)
  Page.get_by_fuzzy_slug(id.to_s)
end

Page(home)




                    43/50
プラグインの追加
          フックメソッドの利?
module Hoptoad
  def self.registered(app)
    app.use HoptoadNotifier::Rack
    # ...
  end




                    44/50
eval
@entry = Entry(id)
type = @entry.class.name.downcase.to_sym
eval @#{type} = @entry




                  45/50
肯定派?
否定派?



 46/50
何も違わん。違うと思うのはお主の
  何も違わん
?の中だけじゃ。
―マスター?ヨーダ




        47/50
Rubyのコードは信頼できないって
? それはコードじゃなくて、コーダー
                コーダー
を信頼してないからだろ?
を信頼してない
―DaveThomas




         48/50
敢えて?うなら
DSL作るの難しい!
英語っぽく書けても?本?はあま
り嬉しくない
DSLを作るならもっと厳密なチェ
ックやエラーメッセージが欲しいか
も

       49/50
Paolo Perrotta(著), ? 征典 (翻訳)
http://www.amazon.co.jp/dp/4048687158
                50/50

More Related Content

20110820 metaprogramming