Ruby, muito mais que reflexivo

1,498 views

Published on

ParseTree permite formas bastante avançadas de reflexão sobre código Ruby.
Com seu uso, podemos até mudar completamente a forma como o código Ruby é interpretado!

A palestra passa por alguns usos divertidos e interessantes, desde análise estática de
código, até técnicas para construção de Domain Specific Languages.

Published in: Technology, Education
0 Comments
10 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,498
On SlideShare
0
From Embeds
0
Number of Embeds
28
Actions
Shares
0
Downloads
39
Comments
0
Likes
10
Embeds 0
No embeds

No notes for slide




















  • outlines
    errors






























  • mapreduce.rb


















  • Ruby, muito mais que reflexivo

    1. 1. Ruby muito mais do que reflexivo! fabio.kung@caelum.com.br
    2. 2. Reflexão p = Person.new p.class # => Person p.methods # => [quot;instance_variablesquot;, quot;classquot;, ..., quot;to_squot;] Person.instance_methods # => [quot;instance_variablesquot;, ..., to_squot;]
    3. 3. Dinamismo
    4. 4. Metaprogramação
    5. 5. Metaprogramação class Aluno end marcos = Aluno.new marcos.respond_to? :programa # => false class Professor def ensina(aluno) def aluno.programa quot;puts 'agora sei programar'quot; end end end knuth = Professor.new knuth.ensina marcos marcos.respond_to? :programa # => true marcos.programa # => quot;puts 'agora sei programar'quot;
    6. 6. “Skilled programmers can write better programmers than they can hire” -- Giles Bowkett
    7. 7. Code as Data
    8. 8. User.detect { |u| u.name == 'John' && u.age == 22 } # SELECT * FROM users WHERE users.name = 'John' AND users.age = 22 User.select { |u| [1, 2, 3, 4].include? u.id } # SELECT * FROM users WHERE users.id IN (1,2,3,4)
    9. 9. ParseTree class class Person Person nil scope def say_hi defn puts quot;hiquot; say_hi scope args end block end call nil puts arglist str “hi”
    10. 10. ParseTree s(:class, :Person, class Person nil, s(:scope, def say_hi s(:defn, :say_hi, puts quot;hiquot; s(:args), end s(:scope, s(:block, end s(:call, nil, :puts, s(:arglist, s(:str, quot;hiquot;))))))))
    11. 11. Feedback Editores/IDEs
    12. 12. class nil scope Person defn say_hi args scope block require 'parse_tree' call puts nil arglist tree = ParseTree.new.process(...) tree[0][2][0][2] str “hi” # => s(:scope, s(:block, s(:call, nil, :puts, s(:arglist, ...))))
    13. 13. SexpProcessor class TheProcessor < SexpProcessor def process_call(node) # ... process node end def process_class(node) # ... process node end def process_scope(node) # ... process node end end
    14. 14. SexpProcessor class TheProcessor < SexpProcessor def process_call(node) # ... ast = ParseTree.new.process(...) process node new_ast = TheProcessor.new.process(ast) end def process_class(node) # ... process node end def process_scope(node) # ... process node end end
    15. 15. class nil scope Person defn say_hi args scope block class RenameProcessor < SexpProcessor call def process_defn(node) puts nil arglist name = node.shift str args = process(node.shift) scope = process(node.shift) “hi” s(:defn, :quot;new_#{name}quot;, args, scope) end end
    16. 16. Flog Flog shows you the most torturous code you wrote. class Test   def blah         # 11.2 = The more painful the     a = eval quot;1+1quot; # 1.2 + 6.0 + code, the higher the score.     if a == 2 then # 1.2 + 1.2 + 0.4 + The higher the score, the       puts quot;yayquot;   # 1.2     end harder it is to test.   end end
    17. 17. roodi Ruby Object Oriented Design Inferometer • ClassLineCountCheck • ClassNameCheck • CyclomaticComplexityBlockCheck • CyclomaticComplexityMethodCheck • EmptyRescueBodyCheck • MethodLineCountCheck • MethodNameCheck • ParameterNumberCheck • ...
    18. 18. merb-action-args class Posts < Merb::Controller def create(post) # post = params[:post] @post = Post.new(post) @post.save end # ... end
    19. 19. Heckle Think you write good tests? Not bloody likely... Put it to the test with heckle. It’ll put your code into submission in seconds.
    20. 20. Outros • Reek (== roodi) • Flay • Rufus • ...
    21. 21. Ambition User.select { |u| u.name == 'John' && u.age == 22 } # SELECT * FROM users WHERE users.name = 'John' AND users.age = 22 # quot;(&(name=jon)(age=21))quot;
    22. 22. Ambition User.select { |u| u.name == 'John' && u.age == 22 } # SELECT * FROM users WHERE users.name = 'John' AND users.age = 22 # quot;(&(name=jon)(age=21))quot; User.select { |u| [1, 2, 3, 4].include? u.id } # SELECT * FROM users WHERE users.id IN (1,2,3,4)
    23. 23. Ambition User.select { |u| u.name == 'John' && u.age == 22 } # SELECT * FROM users WHERE users.name = 'John' AND users.age = 22 # quot;(&(name=jon)(age=21))quot; User.select { |u| [1, 2, 3, 4].include? u.id } # SELECT * FROM users WHERE users.id IN (1,2,3,4) User.select { |u| u.friends.name =~ /bi/ } # SELECT * FROM users LEFT OUTER JOIN ... WHERE friends.name ~ 'bi'
    24. 24. Ambition User.select { |u| u.name == 'John' && u.age == 22 } # SELECT * FROM users WHERE users.name = 'John' AND users.age = 22 # quot;(&(name=jon)(age=21))quot; User.select { |u| [1, 2, 3, 4].include? u.id } # SELECT * FROM users WHERE users.id IN (1,2,3,4) User.select { |u| u.friends.name =~ /bi/ } # SELECT * FROM users LEFT OUTER JOIN ... WHERE friends.name ~ 'bi' User.select { |u| ... }.sort_by { |u| u.name } # SELECT * FROM users WHERE ... ORDER BY users.name
    25. 25. ParseTree Manipulation http://martinfowler.com/dslwip/ParseTreeManipulation.html
    26. 26. Rfactor $$$ class Banco def transfere(origem, destino, valor) s(:class, puts quot;iniciando transferenciaquot; :Banco, puts quot;por favor, aguarde...quot; nil, # ... s(:scope, end s(:block, s(:defn, def incrementa_juros(taxa) :transfere, # ... s(:args, :origem, :destino, :valor),end s(:scope, end s(:block, s(:call, nil, :puts, s(:arglist, s(:str, quot;iniciando transferenciaquot;))), s(:call, nil, :puts, s(:arglist, s(:str, quot;por favor, aguarde...quot;)))))), s(:defn, :incrementa_juros, s(:args, :taxa), s(:scope, s(:block, s(:nil)))))))
    27. 27. Ruby2Ruby var bloco = function() { alert(quot;hey, I'm a functionquot;); } bloco.toString();
    28. 28. Ruby2Ruby var bloco = function() { alert(quot;hey, I'm a functionquot;); } bloco.toString(); bloco = lambda do puts quot;hey, I'm a blockquot; end bloco.to_ruby # => quot;proc { puts(quot;hey, I'm a blockquot;) }quot;
    29. 29. metaprogramação: como fica o código gerado?
    30. 30. serialização de código
    31. 31. require 'mapreduce_enumerable' (1..100).to_a.dmap do |item| item * 2 end http://romeda.org/blog/2007/04/mapreduce-in-36-lines-of-ruby.html
    32. 32. Ofuscação
    33. 33. Ruby2Java
    34. 34. Ruby2Java
    35. 35. • rb2js: http://rb2js.rubyforge.org • red-js: http://wiki.github.com/jessesielaff/red
    36. 36. JRuby compiler2.rb
    37. 37. Geradores • Gráficos • UML • ...
    38. 38. Código Nativo (problema) • ruby_parser • Ripper (1.9) • JRuby ParseTree
    39. 39. Dúvidas? Obrigado! fabio.kung@caelum.com.br http://fabiokung.com twitter: fabiokung

    ×