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.

Ruby, muito mais que reflexivo

1,551 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
  • Be the first to comment

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

×