Metaprogramming 101
Upcoming SlideShare
Loading in...5
×
 

Metaprogramming 101

on

  • 3,000 views

 

Statistics

Views

Total Views
3,000
Views on SlideShare
2,806
Embed Views
194

Actions

Likes
5
Downloads
66
Comments
0

6 Embeds 194

http://coderwall.com 166
http://twitter.com 7
http://us-w1.rockmelt.com 7
https://twitter.com 6
http://www.slideshare.net 5
http://paper.li 3

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Metaprogramming 101 Metaprogramming 101 Presentation Transcript

  • Metaprogramming 101Nando Vieira
  • codeplane.com.br
  • ode.c om.brhow toc
  • O que veremosobject model, method dispatching,evaluation, hooks, DSLs.
  • selfsempre será o receiver padrão.
  • person.name!"#"$%"!
  • class User attr_accessor :first_name, :last_name def fullname "#{first_name} #{last_name}" endend
  • class User attr_accessor :first_name, :last_name def initialize(options = {}) options.each do |name, value| send("#{name}=", value) end endendUser.new({ :first_name => "John", :last_name => "Doe"})
  • selfarmazena as variáveis de instância.
  • class User attr_accessor :first_name, :last_nameenduser = User.newuser.first_name = "John"user.last_name = "Doe"user.instance_variables#=> ["@last_name", "@first_name"]
  • variáveis de instânciaisso se aplica a todos os objetos.
  • class Config @directory = "/some/directory" @environment = :productionendConfig.instance_variables#=> ["@environment", "@directory"]
  • singleton_classmetaclasse, eigenclass, ghostclass.
  • class Config class << self endend
  • RUBY 1.9class Config singleton_class.class do # your code here endend
  • RUBY 1.8class Object unless Object.respond_to?(:singleton_class) def singleton_class class << self; self; end end endend
  • class Config def self.root_dir @root_dir end def self.root_dir=(dir) @root_dir = dir endend
  • class Config class << self attr_accessor :root_dir endend
  • estendendo o selfadicionando novos métodos.
  • person = Object.newdef person.name "John Doe"endperson.name#=> "John Doe"
  • person.singleton_methods#=> ["name"]
  • estendendo o selfadicionando novos métodos em classes.
  • class Config def Config.root_dir "/some/path" endendConfig.root_dir#=> "/some/path"
  • Config.singleton_methods#=> ["root_dir"]
  • class Config puts self == Configend#=> true
  • class Config def Config.root_dir "/some/path" endendConfig.root_dir#=> "/some/path"
  • métodos de classeeles não existem no Ruby.
  • métodoslookup + dispatching.
  • method lookupup and right.
  • BasicObject class << BasicObject Object class << Object Module class << Module Class class << Class Person class << Person person class << person person.name
  • NoMethodError
  • method dispatchingexecução de métodos.
  • person.name
  • person.send :name
  • person.send :say, "hello"
  • person.__send__ :name
  • person.public_send :name
  • class Person attr_accessor :name, :age, :email def initialize(options = {}) options.each do |name, value| send("#{name}=", value) "#{name}=" end endend
  • evaluationclass_eval, instance_eval,instance_exec, eval.
  • class_evala.k.a. module_eval.
  • class Person; endPerson.class_eval do puts self == Personend#=> true
  • class Person; endPerson.class_eval <<-RUBY puts self == PersonRUBY#=> true
  • class Person; endPerson.class_eval do def self.some_class_method end def some_instance_method endend
  • class Person; endmodule Helpers # some code hereendPerson.class_eval do include Helpersend
  • class Person class_eval <<-RUBY, __FILE__, __LINE__ def some_method # some code end RUBYend
  • class Person class_eval <<-RUBY, __FILE__, __LINE__ def some_method raise "ffffuuuuuuuuuu" end RUBYendbegin Person.new.some_methodrescue Exception => error error.backtrace # ["person.rb:3:in `some_method", "person.rb:10"]end
  • instance_evala.k.a. class_eval para instâncias.
  • Person = Class.newperson = Person.newPerson.respond_to?(:class_eval) #=> truePerson.respond_to?(:instance_eval) #=> trueperson.respond_to?(:class_eval) #=> falseperson.respond_to?(:instance_eval) #=> true
  • instance_execa.k.a. instance_eval on redbull.
  • require "ostruct"john = OpenStruct.new(:name => "John Doe")block = proc do |time = nil| puts name puts timeendjohn.instance_eval(&block)#=> John Doe#=> #<OpenStruct name="John Doe">john.instance_exec(Time.now, &block)#=> John Doe#=> 2011-07-08 11:44:01 -0300
  • evalevaluation com contexto configurável.
  • def get_binding name = "John Doe" bindingendeval("defined?(name)")#=> nileval("defined?(name)", get_binding)#=> "local-variable"eval("name", get_binding)#=> "John Doe"
  • hooksinterceptando eventos do Ruby.
  • módulos & classesincluded, const_missing, extended,inherited, initialize_clone,initialize_copy, initialize_dup.
  • includedexecutado toda vez que um módulo éincluído.
  • module Ffffffuuu def self.included(base) base.class_eval do include InstanceMethods extend ClassMethods end end module InstanceMethods # some instance methods end module ClassMethods # some class methods endend
  • class Person include FfffffuuuendPerson.singleton_class.included_modules#=> [Ffffffuuu::ClassMethods, Kernel]Person.included_modules#=> [Ffffffuuu::InstanceMethods, Ffffffuuu, Kernel]
  • métodosmethod_added, method_missing,method_removed, method_undefined,singleton_method_added,singleton_method_removed,singleton_method_undefined
  • method_missingexecutado toda vez que um método nãofor encontrado.
  • class Logger attr_accessor :output LEVELS = [ :debug, :info, :warn, :error, :critical ] def initialize(output) @output = output end def log(level, message) output << "[#{level}] #{message}n" endend
  • logger = Logger.new(STDOUT)logger.log :debug, "Fffffuuuuu"
  • class Logger attr_accessor :output LEVELS = [ :debug, :info, :warn, :error, :critical ] def initialize(output) @output = output end def log(level, message) output << "[#{level}] #{message}n" end def method_missing(name, *args, &block) return send(:log, name, args.first) if LEVELS.include?(name) super endend
  • def respond_to?(method, include_private = false) return true if LEVELS.include?(method.to_sym) superend
  • DSLsfuckyeah.
  • interfaces fluenteschaining.
  • @message = Message.new@message.to("john").from("mary").text("bring milk.")@message.deliver#=> "mary said: john, bring milk."
  • class Message def to(name) @to = name self end def from(name) @from = name self end def text(message) @text = message self endend
  • module FluentAttribute def fluent_attr(*names) names.each do |name| class_eval <<-RUBY, __FILE__, __LINE__ def #{name}(value) # def to(value) @#{name} = value # @to = value self # self end # end RUBY end endend
  • class Message extend FluentAttribute fluent_attr :from, :to, :textend
  • dúvidas?
  • obrigadohttp://nandovieira.com.br.