Ruby Metaprogramming
-
Upload
nando-vieira -
Category
Technology
-
view
3.231 -
download
0
Transcript of Ruby Metaprogramming
RUBY METAPROGRAMMING.
@fnando
AVISOS.
TUDO É OBJETO.INCLUINDO CLASSES.
MUITO CÓDIGO.
VARIÁVEIS DE CLASSE.
class MyLib @@name = "mylib" def self.name @@name endend
MyLib.name#=> “mylib”
class MyOtherLib < MyLib @@name = "myotherlib"end
MyOtherLib.name#=> “myotherlib”
MyLib.name#=> “myotherlib”
VARIÁVEIS DE CLASSE SÃO
COMPARTILHADAS.
VARIÁVEIS DE INSTÂNCIA.
class MyLib @name = "mylib" def self.name @name endend
MyLib.name#=> “mylib”
class MyOtherLib < MyLib @name = "myotherlib"end
MyOtherLib.name#=> “myotherlib”
MyLib.name#=> “mylib”
VARIÁVEIS DE INSTÂNCIA
PERTENCEMAO OBJETO.
METACLASSE.
class MyLib class << self endend
class MyLib # ruby 1.9.2+ singleton_class.class_eval do endend
class Object def singleton_class class << self; self; end endend unless Object.respond_to?(:singleton_class)
class MyLib class << self attr_accessor :name endend
MyLib.name = "mylib"MyLib.name#=> mylib
BLOCOS.
MÉTODOS PODEM RECEBER BLOCOS.
def run(&block)end
BLOCOS PODEMSER EXECUTADOS.
def run(&block) yield arg1, arg2end
def run(&block) block.call(arg1, arg2)end
def run(&block) block[arg1, arg2]end
def run(&block) block.(arg1, arg2)end
# ruby 1.9+
METACLASSE, BLOCOS E
VARIÁVEL DE INSTÂNCIA.
MyLib.configure do |config| config.name = "mylib"end
class MyLib class << self attr_accessor :name end def self.configure(&block) yield self endend
EVALUATION.
eval, class_eval, e instance_eval
MyLib.class_eval <<-RUBY "running inside class"RUBY#=> “running inside class”
MyLib.class_eval do "running inside class"end#=> “running inside class”
handler = proc { self.kind_of?(MyLib)}
handler.call#=> false
handler = proc { self.kind_of?(MyLib)}
lib.instance_eval(&handler)#=> true
BLOCOS, METACLASSE, VARIÁVEIS DE
INSTÂNCIA, EVALUATION.
MyLib.configure do self.name = "mylib" name #=> “mylib”end
class MyLib class << self attr_accessor :name end def self.configure(&block) instance_eval(&block) endend
DEFINIÇÃO DE MÉTODOS.
MONKEY PATCHING.
class Integer def kbytes self * 1024 endend
128.kbytes#=> 131072
define_method.
MyLib.class_eval do define_method "name" do @name end
define_method "name=" do |name| @name = name endend
lib = MyLib.newlib.name = "mynewname"lib.name#=> “mynewname”
EVALUATION.
MyLib.class_eval <<-RUBY def self.name "mylib" end
def name "mylib's instance" endRUBY
MyLib.class_eval do def self.name "mylib" end def name "mylib's instance" endend
MyLib.name#=> “mylib”
MyLib.new.name#=> “mylib’s instance”
BLOCOS, EVALUATION,
DEFINIÇÃO DE MÉTODOS.
MyLib.class_eval do name "mylib" name #=> “mylib”end
class MyLib def self.accessor(method) class_eval <<-RUBY def self.#{method}(*args) if args.size.zero? @#{method} else @#{method} = args.last end end RUBY end accessor :nameend
MyLib.class_eval do name "mylib" name #=> “mylib”end
configure do name "mylib"
name #=> “mylib”end
def configure(&block) MyLib.instance_eval(&block)end
DISCLAIMER.
METHOD MISSING.
MyLib.new.invalid
NoMethodError: undefined method ‘invalid’ for #<MyLib:0x10017e2f0>
class MyLib NAMES = { :name => "mylib’s instance" }
def method_missing(method, *args) if NAMES.key?(method.to_sym) NAMES[method.to_sym] else super end endend
class MyLib #...
def respond_to?(method, include_private = false) if NAMES.key?(method.to_sym) true else super end endend
lib.name#=> “mylib’s instance”
lib.respond_to?(:name)#=> true
MIXINS.
class MyLib extend Accessor accessor :nameend
class MyOtherLib extend Accessor accessor :nameend
module Accessor def accessor(name) class_eval <<-RUBY def self.#{name}(*args) if args.size.zero? @#{name} else @#{name} = args.last end end RUBY endend
MONKEY PATCHING, MIXINS,
EVALUATION, DYNAMIC
DISPATCHING E HOOKS.
class Conference < ActiveRecord::Base has_permalinkend
"welcome to QConSP".to_permalink#=> “welcome-to-qconsqp”
class String def to_permalink self.downcase.gsub(/[^[a-z0-9]-]/, "-") endend
class Conference < ActiveRecord::Base before_validation :generate_permalink
def generate_permalink write_attribute :permalink, name.to_s.to_permalink endend
module Permalinkend
ActiveRecord::Base.send :include, Permalink
module Permalink def self.included(base) base.send :extend, ClassMethods endend
module Permalink # ... module ClassMethods def has_permalink class_eval do before_validation :generate_permalink include InstanceMethods end end endend
module Permalink # ... module InstanceMethods def generate_permalink write_attribute :permalink, name.to_s.to_permalink end endend
conf = Conference.create(:name => "QConSP 2010")conf.permalink#=> "qconsp-2010"
ENTÃO...
METAPROGRAMMING É
COMPLICADO.
MAS NEM TANTO.
APRENDA RUBY.
OBRIGADO.
nandovieira.com.brsimplesideias.com.br
spesa.com.brgithub.com/fnando
@fnando