lib/surrogate/endower.rb in surrogate-0.2.0 vs lib/surrogate/endower.rb in surrogate-0.3.0
- old
+ new
@@ -1,8 +1,8 @@
class Surrogate
- # adds surrogate behaviour to your class / singleton class / instances
+ # Adds surrogate behaviour to your class / singleton class / instances
#
# please refactor me!
class Endower
def self.endow(klass, &playlist)
new(klass, &playlist).endow
@@ -20,33 +20,35 @@
end
private
def endow_klass
- a_hatchery_for klass
+ add_hatchery_to klass
+ klass.extend ClassMethods
enable_defining_methods klass
record_initialization_for_instances_of klass
remember_invocations_for_instances_of klass
remember_invocations_for_instances_of klass.singleton_class
- hijack_instantiation_of klass
- can_get_a_new klass
end
def endow_singleton_class
- hatchery = a_hatchery_for singleton
+ hatchery = add_hatchery_to singleton
enable_defining_methods singleton
singleton.module_eval &playlist if playlist
- klass.instance_variable_set :@surrogate, Hatchling.new(klass, hatchery)
+ klass.instance_variable_set :@hatchling, Hatchling.new(klass, hatchery)
klass
end
- # yeesh :( try to find a better way to do this
+ # yeesh :( pretty sure there isn't a better way to do this
def record_initialization_for_instances_of(klass)
def klass.method_added(meth)
- return unless meth == :initialize && !@hijacking_initialize
+ return if meth != :initialize || @hijacking_initialize
@hijacking_initialize = true
current_initialize = instance_method :initialize
+
+ # `define' records the args while maintaining the old behaviour
+ # we have to do it stupidly like this because there is no to_proc on an unbound method
define :initialize do |*args, &block|
current_initialize.bind(self).call(*args, &block)
end
ensure
@hijacking_initialize = false
@@ -59,58 +61,48 @@
def singleton
klass.singleton_class
end
- def can_get_a_new(klass)
- klass.extend Module.new {
- # use a module so that the method is inherited (important for substitutability)
- def clone
- new_klass = Class.new self
- surrogate = @surrogate
- Surrogate.endow new_klass do
- surrogate.api_methods.each do |method_name, options|
- define method_name, options.to_hash, &options.default_proc
- end
- end
- @hatchery.api_methods.each do |method_name, options|
- new_klass.define method_name, options.to_hash, &options.default_proc
- end
- new_klass
- end
- }
- end
-
def remember_invocations_for_instances_of(klass)
klass.send :define_method, :invocations do |method_name|
- @surrogate.invocations method_name
+ @hatchling.invocations method_name
end
end
- def a_hatchery_for(klass)
+ def add_hatchery_to(klass)
klass.instance_variable_set :@hatchery, Surrogate::Hatchery.new(klass)
end
- def hijack_instantiation_of(klass)
- # use a module so that the method is inherited (important for substitutability)
- klass.extend Module.new {
- def new(*args)
- instance = allocate
- hatchery = @hatchery
- instance.instance_eval { @surrogate = Hatchling.new instance, hatchery }
- instance.send :initialize, *args
- instance
- end
- }
- end
-
def enable_defining_methods(klass)
def klass.define(method_name, options={}, &block)
@hatchery.define method_name, options, block
end
def klass.api_method_names
@hatchery.api_method_names
end
+ end
+ end
+
+
+ # use a module so that the method is inherited (important for substitutability)
+ module ClassMethods
+ def clone
+ hatchling, hatchery = @hatchling, @hatchery
+ Class.new self do
+ Surrogate.endow self do
+ hatchling.api_methods.each { |name, options| define name, options.to_hash, &options.default_proc }
+ end
+ hatchery.api_methods.each { |name, options| define name, options.to_hash, &options.default_proc }
+ end
+ end
+
+ # Custom new, because user can define initialize, and ivars should be set before it
+ def new(*args)
+ instance = allocate
+ instance.instance_variable_set :@hatchling, Hatchling.new(instance, @hatchery)
+ instance.send :initialize, *args
+ instance
end
end
end