metaprogramming + ds ls

74
metaprogramming + domain specific languages

Upload: arrrrcamp

Post on 22-Jun-2015

844 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Metaprogramming + Ds Ls

metaprogramming+

domainspecific

languages

Page 2: Metaprogramming + Ds Ls

%  cat  ddfreyne.txt

DENIS  DEFREYNE==============

web:          http://stoneship.orgtwitter:  ddfreyne

nanoc:  a  static  ruby  web  site  publishing  systemhttp://nanoc.stoneship.org/

%  _

Page 3: Metaprogramming + Ds Ls

what is metaprogramming?

Page 4: Metaprogramming + Ds Ls

Metaprogramming is the writing of computer

programs that write or manipulate other

programs (or themselves) as their data.

Page 5: Metaprogramming + Ds Ls

class  Person

   attr_reader  :friends

end

Page 6: Metaprogramming + Ds Ls

class  Document  <  ActiveRecord::Base

   has_many  :pages

end

Page 7: Metaprogramming + Ds Ls

task  :test  do    puts  "Hello,  I  am  a  rake  task!"end

Page 8: Metaprogramming + Ds Ls

example (i)

Page 9: Metaprogramming + Ds Ls

class  Bob    my_attr_reader  :foo,  :barend

Page 10: Metaprogramming + Ds Ls

class  Module

   def  my_attr_reader(*fields)        fields.each  do  |field|

           class_eval  "                def  #{field}                    @#{field}                end            "

       end    end

end

Page 11: Metaprogramming + Ds Ls

class  Module

   def  my_attr_reader(*fields)        fields.each  do  |field|

           class_eval  "                def  #{field}                    @#{field}                end            "

       end    end

end

Page 12: Metaprogramming + Ds Ls

def  #{field}    @#{field}end

Page 13: Metaprogramming + Ds Ls

def  foo    @fooend

Page 14: Metaprogramming + Ds Ls

def  bar    @barend

Page 15: Metaprogramming + Ds Ls

class  Module

   def  my_attr_reader(*fields)        fields.each  do  |field|

           class_eval  "                def  #{field}                    @#{field}                end            "

       end    end

end

Page 16: Metaprogramming + Ds Ls

DEMO

Page 17: Metaprogramming + Ds Ls

example (ii)

Page 18: Metaprogramming + Ds Ls

class  Module

   def  my_attr_reader(*fields)        fields.each  do  |field|

           class_eval  "                def  #{field}                    @#{field}                end            "

       end    end

end

Page 19: Metaprogramming + Ds Ls

class  Module

   def  battr_reader(*fields)        fields.each  do  |field|

           class_eval  "                def  #{field}?                    !!@#{field}                end            "

       end    end

end

Page 20: Metaprogramming + Ds Ls

class  Bob    battr_reader  :foo,  :barend

p  bob.foo?p  bob.bar?

Page 21: Metaprogramming + Ds Ls

DEMO

Page 22: Metaprogramming + Ds Ls

example (iii)

Page 23: Metaprogramming + Ds Ls

<p>Hello.  My  name  is  <%=  @first_name  %>.</p>

Page 24: Metaprogramming + Ds Ls

template  =  "<p>Hello.  My  name  is  <%=    @first_name  %>.</p>"

@first_name  =  "Bob"

p  ERB.new(template).result

Page 25: Metaprogramming + Ds Ls

DEMO

Page 26: Metaprogramming + Ds Ls

example (iv)

Page 27: Metaprogramming + Ds Ls

class  Product    def  initialize        @title  =  "My  First  Ruby  Book"        @id        =  "39t8zfeg"    endend

template  =  "<p>Product  <%=    @id  %>  has  title  <%=  @title  %>.</p>"

product  =  Product.new

#  TODO  use  the  product  details  p  ERB.new(template).result

Page 28: Metaprogramming + Ds Ls

class  Product    def  initialize        @title  =  "My  First  Ruby  Book"        @id        =  "39t8zfeg"    end

   def  print        template  =  "<p>Product  <%=            @id  %>  has  title  <%=  @title  %>.</p>"

       puts  ERB.new(template).result(binding)    endend

Page 29: Metaprogramming + Ds Ls

class  Product    def  initialize        @title  =  "My  First  Ruby  Book"        @id        =  "39t8zfeg"    end

   def  print        template  =  "<p>Product  <%=            @id  %>  has  title  <%=  @title  %>.</p>"

       puts  ERB.new(template).result(binding)    endend

Page 30: Metaprogramming + Ds Ls

class  Product

   def  initialize        @title  =  "My  First  Ruby  Book"        @id        =  "39t8zfeg"    end

end

Page 31: Metaprogramming + Ds Ls

class  Product

   def  initialize        @title  =  "My  First  Ruby  Book"        @id        =  "39t8zfeg"    end

   def  get_binding        binding    end

end

Page 32: Metaprogramming + Ds Ls

def  get_binding    bindingend

Page 33: Metaprogramming + Ds Ls

def  get_binding    bindingend

Page 34: Metaprogramming + Ds Ls

def  binding    bindingend

Page 35: Metaprogramming + Ds Ls

def  binding    bindingend

SystemStackError:  stack  level  too  deep

Page 36: Metaprogramming + Ds Ls

template  =  "<p>Product  <%=    @id  %>  has  title  <%=  @title  %>.</p>"

product  =  Product.new

p  ERB.new(template).result

Page 37: Metaprogramming + Ds Ls

template  =  "<p>Product  <%=    @id  %>  has  title  <%=  @title  %>.</p>"

product  =  Product.new

p  ERB.new(template).result(product.get_binding)

Page 38: Metaprogramming + Ds Ls

DEMO

Page 39: Metaprogramming + Ds Ls

example (v)

Page 40: Metaprogramming + Ds Ls

compile  '/articles/*/'  do    filter  :erb    filter  :bluecloth

   layout  'article'

   filter  :rubypantsend

Page 41: Metaprogramming + Ds Ls

my-­‐site/    config.yaml    Rules    content/    layouts/    lib/

Page 42: Metaprogramming + Ds Ls

process  /oo/  do  |item|    puts  "I  am  rule  /oo/!"    puts  "I  am  processing  #{item.inspect}!"end

… simpler

Page 43: Metaprogramming + Ds Ls

class  Item

   attr_reader  :identifier

   def  initialize(identifier)        @identifier  =  identifier    end

end

Page 44: Metaprogramming + Ds Ls

items  =  [    Item.new('foo'),    Item.new('foobar'),    Item.new('quxbar'),    Item.new('moo')]

magically_load_rules

items.each  do  |item|    magically_process(item)end

Page 45: Metaprogramming + Ds Ls

class  Rule

   def  initialize(pattern,  block)        @pattern  =  pattern        @block      =  block    end

   def  applicable_to?(item)        item.identifier  =~  @pattern    end

   def  apply_to(item)        @block.call(item)    end

end

Page 46: Metaprogramming + Ds Ls

class  Application

   def  initialize        @rules  =  []    end

   def  load_rules        rules_content  =  File.read('Rules')        dsl  =  DSL.new(@rules)        dsl.instance_eval(rules_content)    end

   ⋮

Page 47: Metaprogramming + Ds Ls

class  Application

   def  initialize        @rules  =  []    end

   def  load_rules        rules_content  =  File.read('Rules')        dsl  =  DSL.new(@rules)        dsl.instance_eval(rules_content)    end

   ⋮

Page 48: Metaprogramming + Ds Ls

class  Bob

   def  initialize        @secret  =  "abc"    end

end

Page 49: Metaprogramming + Ds Ls

bob  =  Bob.newp  bob.secret

NoMethodError:  undefined  method  `secret'    for  #<Bob:0x574324>

Page 50: Metaprogramming + Ds Ls

bob  =  Bob.newp  bob.instance_eval  {  @secret  }

abc

Page 51: Metaprogramming + Ds Ls

bob  =  Bob.newp  bob.instance_eval  "@secret"

abc

Page 52: Metaprogramming + Ds Ls

class  Application

   def  initialize        @rules  =  []    end

   def  load_rules        rules_content  =  File.read('Rules')        dsl  =  DSL.new(@rules)        dsl.instance_eval(rules_content)    end

   ⋮

Page 53: Metaprogramming + Ds Ls

   ⋮

   def  process(item)        rule  =  rules.find  do  |r|            r.applicable_to?(item)        end

       rule.apply_to(item)    end

end

Page 54: Metaprogramming + Ds Ls

class  DSL

   def  initialize(rules)        @rules  =  rules    end

   def  process(pattern,  &block)        @rules  <<  Rule.new(pattern,  block)    end

end

Page 55: Metaprogramming + Ds Ls

class  DSL

   def  initialize(rules)        @rules  =  rules    end

   def  process(pattern,  &block)        @rules  <<  Rule.new(pattern,  block)    end

end

Page 56: Metaprogramming + Ds Ls

process  /oo/  do  |item|    puts  "I  am  rule  /oo/!"    puts  "I  am  processing  #{item.inspect}!"end

Page 57: Metaprogramming + Ds Ls

process  /oo/  do  |item|    puts  "I  am  rule  /oo/!"    puts  "I  am  processing  #{item.inspect}!"end

Page 58: Metaprogramming + Ds Ls

items  =  [    Item.new('foo'),    Item.new('foobar'),    Item.new('quxbar'),    Item.new('moo')]

app  =  App.newapp.load_rules

items.each  do  |item|    app.process(item)end

Page 59: Metaprogramming + Ds Ls

DEMO

Page 60: Metaprogramming + Ds Ls

example (vi)

Page 61: Metaprogramming + Ds Ls

process  /oo/  do  |item|    puts  "I  am  rule  /oo/!"    puts  "I  am  processing  #{item.inspect}!"end

Page 62: Metaprogramming + Ds Ls

process  /oo/  do    puts  "I  am  rule  /oo/!"    puts  "I  am  processing  #{item.inspect}!"end

Page 63: Metaprogramming + Ds Ls

class  RuleContext

   def  initialize(item)        @item  =  item    end

end

Page 64: Metaprogramming + Ds Ls

class  Rule

   def  initialize(pattern,  block)        @pattern  =  pattern        @block      =  block    end

   def  applicable_to?(item)        item.identifier  =~  @pattern    end

   def  apply_to(item)        #  original  way:        @block.call(item)    end

end

Page 65: Metaprogramming + Ds Ls

class  Rule

   def  initialize(pattern,  block)        @pattern  =  pattern        @block      =  block    end

   def  applicable_to?(item)        item.identifier  =~  @pattern    end

   def  apply_to(item)        rule_context  =  RuleContext.new(item)        rule_context.instance_eval(&@block)    end

end

Page 66: Metaprogramming + Ds Ls

process  /oo/  do    puts  "I  am  rule  /oo/!"    puts  "I  am  processing  #{@item.inspect}!"end

Page 67: Metaprogramming + Ds Ls

process  /oo/  do    puts  "I  am  rule  /oo/!"    puts  "I  am  processing  #{item.inspect}!"end

Page 68: Metaprogramming + Ds Ls

class  RuleContext

   def  initialize(item)        @item  =  item    end

end

Page 69: Metaprogramming + Ds Ls

class  RuleContext

   def  initialize(item)        @item  =  item    end

   def  item        @item    end

end

Page 70: Metaprogramming + Ds Ls

process  /oo/  do    puts  "I  am  rule  /oo/!"    puts  "I  am  processing  #{item.inspect}!"end

Page 71: Metaprogramming + Ds Ls

DEMO

Page 72: Metaprogramming + Ds Ls

‣ The Ruby Object Modeland Metaprogramminghttp://www.pragprog.com/screencasts/v-dtrubyom/the-ruby-object-model-and-metaprogramming

‣ How nanocʼs Rules DSL Workshttp://stoneship.org/journal/2009/how-nanocs-rules-dsl-works/

Page 73: Metaprogramming + Ds Ls

you can hazquestions?

Page 74: Metaprogramming + Ds Ls

k thx bai