Presented at the November '07 ThoughtWorks UK Away Day, the talk was centered around the various techniques used to create and mold your objects and domain model using declaritive, self-inspecting, and self-modifying code.
15. Introspection in Action class Person def initialize(name, age, sex) @name = name @age = age @sex = sex end end Person.new('Farooq', 23, :male) Did we just think in a for-loop?!
16. Introspection in Action class Person def initialize(attributes) attributes.each do |attr, val| instance_variable_set("@#{attr}", val) end end end Person.new :name => 'Farooq', :age => '23', :sex => :male
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32. You can define methods on the fly too! define_method :say_hello do puts "Hello World!" end
33.
34.
35. Dynamic Method Definition in Action class Person attr_reader :name, sex end class Person { string name, sex; public string Name { get {return name;} } public string Sex { get {return sex;} } }
36. Dynamic Method Definition in Action class Object def Object.attr_reader(*attrs) attrs.each do |attr| define_method(attr) do instance_variable_get("@#{attr}") end end end end
37. Dynamic Method Definition in Action class Object def Object.attr_reader(*attrs) attrs.each do |attr| define_method(attr) do instance_variable_get("@#{attr}") end end end end
38. Another example: Lazy Loading class Person List<Person> friends; public List<Person> Friends { get { friends = friends ?? LoadFriends(); return friends; } }
40. Lazy Loading class Object def self.lazy_loaded_attr(*attrs) attrs.each do |attr| define_method(attr) do eval "@#{attr} ||= load_#{attr}" end end end end
41. Lazy Loading class Person lazy_loaded_attr :friends, :children, :parents end class Person List<Person> friends, children, parents; public List<Person> Friends { get { friends = friends ?? LoadFriends(); return friends; } } public List<Person> Children { get { children = children ?? LoadChildren(); return children; } } public List<Person> Parents { get { parents = parents ?? LoadParents(); return parents; } } }
42. Declarative code class Album < ActiveRecord::Base has_many :tracks belongs_to :artist acts_as_taggable has_many :lyrics, :through => :tracks end
43. Declarative code with define_method class Album < ActiveRecord::Base has_many :tracks end class Album < ActiveRecord::Base def tracks Track.find :all, :conditions => "album_id=#{id}" end end define_method :tracks …
44. Declarative code with define_method class ActiveRecord::Base def self.has_many(records) define_method(records) do foreign_key = "#{self.name.underscore}_id" klass = records.to_s.classify.constantize klass.find :all, :conditions => "#{foreign_key}=#{id}" end end end
45. Person Person walk() define_method :walk define_method :everyone ? Person everyone() Define instance method: Define class method:
46. Person Person walk() define_method :walk define_method :everyone Person' Person' everyone() Define instance method: Define class method:
47. Person Person walk() define_method :walk define_method :everyone Person' Person' everyone() Define instance method: Define class method: Person everyone()
48.
49.
50.
51.
52.
53. Decorator Pattern with Aliasing class LoginService alias_method :original_login, :login def login(user,pass) log_event "#{user} logging in" original_login(user,pass) end end
54. Decorator Pattern with Aliasing class LoginService alias_method_chain :login, :logging def login_with_logging(user,pass) log_event "#{user} logging in" login_without_logging(user,pass) end end