Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Metaprogramming + Ds Ls

1,135 views

Published on

Published in: Technology, Business
  • Be the first to comment

  • Be the first to like this

Metaprogramming + Ds Ls

  1. 1. metaprogramming + domain specific languages
  2. 2. %  cat  ddfreyne.txt DENIS  DEFREYNE ============== web:          http://stoneship.org twitter:  ddfreyne nanoc:  a  static  ruby  web  site  publishing  system http://nanoc.stoneship.org/ %  _
  3. 3. what is metaprogramming?
  4. 4. Metaprogramming is the writing of computer programs that write or manipulate other programs (or themselves) as their data.
  5. 5. class  Person    attr_reader  :friends end
  6. 6. class  Document  <  ActiveRecord::Base    has_many  :pages end
  7. 7. task  :test  do    puts  "Hello,  I  am  a  rake  task!" end
  8. 8. example (i)
  9. 9. class  Bob    my_attr_reader  :foo,  :bar end
  10. 10. class  Module    def  my_attr_reader(*fields)        fields.each  do  |field|            class_eval  "                def  #{field}                    @#{field}                end            "        end    end end
  11. 11. class  Module    def  my_attr_reader(*fields)        fields.each  do  |field|            class_eval  "                def  #{field}                    @#{field}                end            "        end    end end
  12. 12. def  #{field}    @#{field} end
  13. 13. def  foo    @foo end
  14. 14. def  bar    @bar end
  15. 15. class  Module    def  my_attr_reader(*fields)        fields.each  do  |field|            class_eval  "                def  #{field}                    @#{field}                end            "        end    end end
  16. 16. DEMO
  17. 17. example (ii)
  18. 18. class  Module    def  my_attr_reader(*fields)        fields.each  do  |field|            class_eval  "                def  #{field}                    @#{field}                end            "        end    end end
  19. 19. class  Module    def  battr_reader(*fields)        fields.each  do  |field|            class_eval  "                def  #{field}?                    !!@#{field}                end            "        end    end end
  20. 20. class  Bob    battr_reader  :foo,  :bar end p  bob.foo? p  bob.bar?
  21. 21. DEMO
  22. 22. example (iii)
  23. 23. <p>Hello.  My  name  is  <%=  @first_name  %>.</p>
  24. 24. template  =  "<p>Hello.  My  name  is  <%=    @first_name  %>.</p>" @first_name  =  "Bob" p  ERB.new(template).result
  25. 25. DEMO
  26. 26. example (iv)
  27. 27. class  Product    def  initialize        @title  =  "My  First  Ruby  Book"        @id        =  "39t8zfeg"    end end template  =  "<p>Product  <%=    @id  %>  has  title  <%=  @title  %>.</p>" product  =  Product.new #  TODO  use  the  product  details   p  ERB.new(template).result
  28. 28. 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)    end end
  29. 29. 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)    end end
  30. 30. class  Product    def  initialize        @title  =  "My  First  Ruby  Book"        @id        =  "39t8zfeg"    end end
  31. 31. class  Product    def  initialize        @title  =  "My  First  Ruby  Book"        @id        =  "39t8zfeg"    end    def  get_binding        binding    end end
  32. 32. def  get_binding    binding end
  33. 33. def  get_binding    binding end
  34. 34. def  binding    binding end
  35. 35. def  binding    binding end SystemStackError:  stack  level  too  deep
  36. 36. template  =  "<p>Product  <%=    @id  %>  has  title  <%=  @title  %>.</p>" product  =  Product.new p  ERB.new(template).result
  37. 37. template  =  "<p>Product  <%=    @id  %>  has  title  <%=  @title  %>.</p>" product  =  Product.new p  ERB.new(template).result(product.get_binding)
  38. 38. DEMO
  39. 39. example (v)
  40. 40. compile  '/articles/*/'  do    filter  :erb    filter  :bluecloth    layout  'article'    filter  :rubypants end
  41. 41. my-­‐site/    config.yaml    Rules    content/    layouts/    lib/
  42. 42. … simpler process  /oo/  do  |item|    puts  "I  am  rule  /oo/!"    puts  "I  am  processing  #{item.inspect}!" end
  43. 43. class  Item    attr_reader  :identifier    def  initialize(identifier)        @identifier  =  identifier    end end
  44. 44. items  =  [    Item.new('foo'),    Item.new('foobar'),    Item.new('quxbar'),    Item.new('moo') ] magically_load_rules items.each  do  |item|    magically_process(item) end
  45. 45. 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
  46. 46. class  Application    def  initialize        @rules  =  []    end    def  load_rules        rules_content  =  File.read('Rules')        dsl  =  DSL.new(@rules)        dsl.instance_eval(rules_content)    end    ⋮
  47. 47. class  Application    def  initialize        @rules  =  []    end    def  load_rules        rules_content  =  File.read('Rules')        dsl  =  DSL.new(@rules)        dsl.instance_eval(rules_content)    end    ⋮
  48. 48. class  Bob    def  initialize        @secret  =  "abc"    end end
  49. 49. bob  =  Bob.new p  bob.secret NoMethodError:  undefined  method  `secret'    for  #<Bob:0x574324>
  50. 50. bob  =  Bob.new p  bob.instance_eval  {  @secret  } abc
  51. 51. bob  =  Bob.new p  bob.instance_eval  "@secret" abc
  52. 52. class  Application    def  initialize        @rules  =  []    end    def  load_rules        rules_content  =  File.read('Rules')        dsl  =  DSL.new(@rules)        dsl.instance_eval(rules_content)    end    ⋮
  53. 53.    ⋮    def  process(item)        rule  =  rules.find  do  |r|            r.applicable_to?(item)        end        rule.apply_to(item)    end end
  54. 54. class  DSL    def  initialize(rules)        @rules  =  rules    end    def  process(pattern,  &block)        @rules  <<  Rule.new(pattern,  block)    end end
  55. 55. class  DSL    def  initialize(rules)        @rules  =  rules    end    def  process(pattern,  &block)        @rules  <<  Rule.new(pattern,  block)    end end
  56. 56. process  /oo/  do  |item|    puts  "I  am  rule  /oo/!"    puts  "I  am  processing  #{item.inspect}!" end
  57. 57. process  /oo/  do  |item|    puts  "I  am  rule  /oo/!"    puts  "I  am  processing  #{item.inspect}!" end
  58. 58. items  =  [    Item.new('foo'),    Item.new('foobar'),    Item.new('quxbar'),    Item.new('moo') ] app  =  App.new app.load_rules items.each  do  |item|    app.process(item) end
  59. 59. DEMO
  60. 60. example (vi)
  61. 61. process  /oo/  do  |item|    puts  "I  am  rule  /oo/!"    puts  "I  am  processing  #{item.inspect}!" end
  62. 62. process  /oo/  do    puts  "I  am  rule  /oo/!"    puts  "I  am  processing  #{item.inspect}!" end
  63. 63. class  RuleContext    def  initialize(item)        @item  =  item    end end
  64. 64. 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
  65. 65. 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
  66. 66. process  /oo/  do    puts  "I  am  rule  /oo/!"    puts  "I  am  processing  #{@item.inspect}!" end
  67. 67. process  /oo/  do    puts  "I  am  rule  /oo/!"    puts  "I  am  processing  #{item.inspect}!" end
  68. 68. class  RuleContext    def  initialize(item)        @item  =  item    end end
  69. 69. class  RuleContext    def  initialize(item)        @item  =  item    end    def  item        @item    end end
  70. 70. process  /oo/  do    puts  "I  am  rule  /oo/!"    puts  "I  am  processing  #{item.inspect}!" end
  71. 71. DEMO
  72. 72. ‣ The Ruby Object Model and Metaprogramming http://www.pragprog.com/screencasts/v- dtrubyom/the-ruby-object-model-and- metaprogramming ‣ How nanocʼs Rules DSL Works http://stoneship.org/journal/2009/how- nanocs-rules-dsl-works/
  73. 73. you can haz questions?
  74. 74. k thx bai

×