lib/caricature/isolator.rb in caricature-0.7.6 vs lib/caricature/isolator.rb in caricature-0.7.7
- old
+ new
@@ -1,303 +1,303 @@
-require 'rubygems'
-require 'uuidtools'
-require File.dirname(__FILE__) + '/messenger'
-require File.dirname(__FILE__) + '/descriptor'
-
-module Caricature
-
- # Groups the methods for interception together
- # this is a mix-in for the created isolations for classes
- module Interception
-
- # the class methods of this intercepting object
- module ClassMethods
-
- # the context of this isolation instance.
- # this context takes care of responding to method calls etc.
- def isolation_context
- @___context___
- end
-
- # Replaces the call to the proxy with the one you create with this method.
- # You can specify more specific criteria in the block to configure the expectation.
- #
- # Example:
- #
- # an_isolation.class.when_receiving(:a_method) do |method_call|
- # method_call.with(3, "a").return(5)
- # end
- #
- # is equivalent to:
- #
- # an_isolation.class.when_receiving(:a_method).with(3, "a").return(5)
- #
- # You will most likely use this method when you want your stubs to return something else than +nil+
- # when they get called during the run of the test they are defined in.
- def when_receiving(method_name, &block)
- isolation_context.create_class_override method_name, &block
- end
-
- # Verifies whether the specified method has been called
- # You can specify constraints in the block
- #
- # The most complex configuration you can make currently is one that is constrained by arguments.
- # This is most likely to be extended in the future to allow for more complex verifications.
- #
- # Example:
- #
- # an_isolation.class.did_receive?(:a_method) do |method_call|
- # method_call.with(3, "a")
- # end.should.be.successful
- #
- # is equivalent to:
- #
- # an_isolation.class.did_receive?(:a_method).with(3, "a").should.be.successful
- #
- # You will probably be using this method only when you're interested in whether a method has been called
- # during the course of the test you're running.
- def did_receive?(method_name, &block)
- isolation_context.class_verify method_name, &block
- end
-
- end
-
- # mixes in the class methods of this module when it gets included in a class.
- def self.included(base)
- base.extend ClassMethods
- end
-
- # the context of this isolation instance.
- # this context takes care of responding to method calls etc.
- def isolation_context
- self.class.isolation_context
- end
-
- # Replaces the call to the proxy with the one you create with this method.
- # You can specify more specific criteria in the block to configure the expectation.
- #
- # Example:
- #
- # an_isolation.when_receiving(:a_method) do |method_call|
- # method_call.with(3, "a").return(5)
- # end
- #
- # is equivalent to:
- #
- # an_isolation.when_receiving(:a_method).with(3, "a").return(5)
- #
- # You will most likely use this method when you want your stubs to return something else than +nil+
- # when they get called during the run of the test they are defined in.
- def when_receiving(method_name, &block)
- isolation_context.create_override method_name, &block
- end
-
- # Replaces the call to the class of the proxy with the one you create with this method.
- # You can specify more specific criteria in the block to configure the expectation.
- #
- # Example:
- #
- # an_isolation.when_class_receives(:a_method) do |method_call|
- # method_call.with(3, "a").return(5)
- # end
- #
- # is equivalent to:
- #
- # an_isolation.when_class_receives(:a_method).with(3, "a").return(5)
- #
- # You will most likely use this method when you want your stubs to return something else than +nil+
- # when they get called during the run of the test they are defined in.
- def when_class_receives(method_name, &block)
- self.class.when_receiving method_name, &block
- end
-
- # Verifies whether the specified method has been called
- # You can specify constraints in the block
- #
- # The most complex configuration you can make currently is one that is constrained by arguments.
- # This is most likely to be extended in the future to allow for more complex verifications.
- #
- # Example:
- #
- # an_isolation.did_receive?(:a_method) do |method_call|
- # method_call.with(3, "a")
- # end.should.be.successful
- #
- # is equivalent to:
- #
- # an_isolation.did_receive?(:a_method).with(3, "a").should.be.successful
- #
- # You will probably be using this method only when you're interested in whether a method has been called
- # during the course of the test you're running.
- def did_receive?(method_name, &block)
- isolation_context.verify method_name, &block
- end
-
- # Verifies whether the specified class method has been called
- # You can specify constraints in the block
- #
- # The most complex configuration you can make currently is one that is constrained by arguments.
- # This is likely to be extended in the future to allow for more complex verifications.
- #
- # Example:
- #
- # an_isolation.did_class_receive?(:a_method) do |method_call|
- # method_call.with(3, "a")
- # end.should.be.successful
- #
- # is equivalent to:
- #
- # an_isolation.did_class_receive?(:a_method).with(3, "a").should.be.successful
- #
- # You will probably be using this method only when you're interested in whether a method has been called
- # during the course of the test you're running.
- def did_class_receive?(method_name, &block)
- self.class.did_receive?(method_name, &block)
- end
-
- # Initializes the underlying subject
- # It expects the constructor parameters if they are needed.
- def with_subject(*args, &b)
- isolation_context.instance = self.class.superclass.new *args
- b.call self if b
- self
- end
-
- end
-
- # A base class for +Isolator+ objects
- # to stick with the +Isolation+ nomenclature the strategies for creating isolations
- # are called isolators.
- # An isolator functions as a barrier between the code in your test and the
- # underlying type/instance. It allows you to take control over the value
- # that is returned from a specific method, if you want to pass the method call along to
- # the underlying instance etc. It also contains the ability to verify if a method
- # was called, with which arguments etc.
- class Isolator
-
- # holds the isolation created by this isolator
- attr_reader :isolation
-
- # holds the subject of this isolator
- attr_reader :subject
-
- # holds the descriptor for this type of object
- attr_reader :descriptor
-
- # creates a new instance of an isolator
- def initialize(context)
- @context = context
- end
-
- # builds up the isolation class instance
- def build_isolation(klass, inst=nil)
- pxy = create_isolation_for klass
- @isolation = pxy.new
- @subject = inst
- initialize_messenger
- end
-
- # initializes the messaging strategy for the isolator
- def initialize_messenger
- raise NotImplementedError
- end
-
- # Creates the new class name for the isolation
- def class_name(subj)
- nm = subj.respond_to?(:class_eval) ? subj.demodulize : subj.class.demodulize
- @class_name = "#{nm}#{UUIDTools::UUID.random_create.to_s.gsub /-/, ''}"
- @class_name
- end
-
- # Sets up the necessary instance variables for the isolation
- def initialize_isolation(klass, context)
- pxy = klass.new
- pxy.instance_variable_set("@___context___", context)
- pxy
- end
-
-
- class << self
-
- # Creates the actual proxy object for the +subject+ and initializes it with a
- # +recorder+ and +expectations+
- # This is the actual isolation that will be used to in your tests.
- # It implements all the methods of the +subject+ so as long as you're in Ruby
- # and just need to isolate out some classes defined in a statically compiled language
- # it should get you all the way there for public instance methods at this point.
- # when you're going to isolation for usage within a statically compiled language type
- # then you're bound to most of their rules. So you need to either isolate interfaces
- # or mark the methods you want to isolate as virtual in your implementing classes.
- def for(context)
- context.recorder ||= MethodCallRecorder.new
- context.expectations ||= Expectations.new
- new(context)
- end
- end
- end
-
- # A proxy to Ruby objects that records method calls
- # this implements all the instance methods that are defined on the class.
- class RubyIsolator < Isolator
-
- # implemented template method for creating Ruby isolations
- def initialize(context)
- super
- klass = @context.subject.respond_to?(:class_eval) ? @context.subject : @context.subject.class
- inst = @context.subject.respond_to?(:class_eval) ? nil : @context.subject
- # inst = @context.subject.respond_to?(:class_eval) ? @context.subject.new : @context.subject
- @descriptor = RubyObjectDescriptor.new klass
- build_isolation klass, inst
- end
-
- # initializes the messaging strategy for the isolator
- def initialize_messenger
- @context.messenger = RubyMessenger.new @context.expectations, @subject
- end
-
- # creates the ruby isolator for the specified subject
- def create_isolation_for(subj)
- imembers = @descriptor.instance_members
- cmembers = @descriptor.class_members
-
- klass = Object.const_set(class_name(subj), Class.new(subj))
- klass.class_eval do
-
- include Interception
-
- # access to the proxied subject
- def ___super___
- isolation_context.instance
- end
-
- imembers.each do |mn|
- mn = mn.name.to_s.to_sym
- define_method mn do |*args|
- b = nil
- b = Proc.new { yield } if block_given?
- isolation_context.send_message(mn, nil, *args, &b)
- end
- end
-
- def initialize(*args)
- self
- end
-
- cmembers.each do |mn|
- mn = mn.name.to_s.to_sym
- define_cmethod mn do |*args|
- return if mn.to_s =~ /$(singleton_)?method_added/ and args.first.to_s =~ /$(singleton_)?method_added/
- b = nil
- b = Proc.new { yield } if block_given?
- isolation_context.send_class_message(mn, nil, *args, &b)
- end
- end
-
- end
-
- klass
- end
-
-
- end
-
+require 'rubygems'
+require 'uuidtools'
+require File.dirname(__FILE__) + '/messenger'
+require File.dirname(__FILE__) + '/descriptor'
+
+module Caricature
+
+ # Groups the methods for interception together
+ # this is a mix-in for the created isolations for classes
+ module Interception
+
+ # the class methods of this intercepting object
+ module ClassMethods
+
+ # the context of this isolation instance.
+ # this context takes care of responding to method calls etc.
+ def isolation_context
+ @___context___
+ end
+
+ # Replaces the call to the proxy with the one you create with this method.
+ # You can specify more specific criteria in the block to configure the expectation.
+ #
+ # Example:
+ #
+ # an_isolation.class.when_receiving(:a_method) do |method_call|
+ # method_call.with(3, "a").return(5)
+ # end
+ #
+ # is equivalent to:
+ #
+ # an_isolation.class.when_receiving(:a_method).with(3, "a").return(5)
+ #
+ # You will most likely use this method when you want your stubs to return something else than +nil+
+ # when they get called during the run of the test they are defined in.
+ def when_receiving(method_name, &block)
+ isolation_context.create_class_override method_name, &block
+ end
+
+ # Verifies whether the specified method has been called
+ # You can specify constraints in the block
+ #
+ # The most complex configuration you can make currently is one that is constrained by arguments.
+ # This is most likely to be extended in the future to allow for more complex verifications.
+ #
+ # Example:
+ #
+ # an_isolation.class.did_receive?(:a_method) do |method_call|
+ # method_call.with(3, "a")
+ # end.should.be.successful
+ #
+ # is equivalent to:
+ #
+ # an_isolation.class.did_receive?(:a_method).with(3, "a").should.be.successful
+ #
+ # You will probably be using this method only when you're interested in whether a method has been called
+ # during the course of the test you're running.
+ def did_receive?(method_name, &block)
+ isolation_context.class_verify method_name, &block
+ end
+
+ end
+
+ # mixes in the class methods of this module when it gets included in a class.
+ def self.included(base)
+ base.extend ClassMethods
+ end
+
+ # the context of this isolation instance.
+ # this context takes care of responding to method calls etc.
+ def isolation_context
+ self.class.isolation_context
+ end
+
+ # Replaces the call to the proxy with the one you create with this method.
+ # You can specify more specific criteria in the block to configure the expectation.
+ #
+ # Example:
+ #
+ # an_isolation.when_receiving(:a_method) do |method_call|
+ # method_call.with(3, "a").return(5)
+ # end
+ #
+ # is equivalent to:
+ #
+ # an_isolation.when_receiving(:a_method).with(3, "a").return(5)
+ #
+ # You will most likely use this method when you want your stubs to return something else than +nil+
+ # when they get called during the run of the test they are defined in.
+ def when_receiving(method_name, &block)
+ isolation_context.create_override method_name, &block
+ end
+
+ # Replaces the call to the class of the proxy with the one you create with this method.
+ # You can specify more specific criteria in the block to configure the expectation.
+ #
+ # Example:
+ #
+ # an_isolation.when_class_receives(:a_method) do |method_call|
+ # method_call.with(3, "a").return(5)
+ # end
+ #
+ # is equivalent to:
+ #
+ # an_isolation.when_class_receives(:a_method).with(3, "a").return(5)
+ #
+ # You will most likely use this method when you want your stubs to return something else than +nil+
+ # when they get called during the run of the test they are defined in.
+ def when_class_receives(method_name, &block)
+ self.class.when_receiving method_name, &block
+ end
+
+ # Verifies whether the specified method has been called
+ # You can specify constraints in the block
+ #
+ # The most complex configuration you can make currently is one that is constrained by arguments.
+ # This is most likely to be extended in the future to allow for more complex verifications.
+ #
+ # Example:
+ #
+ # an_isolation.did_receive?(:a_method) do |method_call|
+ # method_call.with(3, "a")
+ # end.should.be.successful
+ #
+ # is equivalent to:
+ #
+ # an_isolation.did_receive?(:a_method).with(3, "a").should.be.successful
+ #
+ # You will probably be using this method only when you're interested in whether a method has been called
+ # during the course of the test you're running.
+ def did_receive?(method_name, &block)
+ isolation_context.verify method_name, &block
+ end
+
+ # Verifies whether the specified class method has been called
+ # You can specify constraints in the block
+ #
+ # The most complex configuration you can make currently is one that is constrained by arguments.
+ # This is likely to be extended in the future to allow for more complex verifications.
+ #
+ # Example:
+ #
+ # an_isolation.did_class_receive?(:a_method) do |method_call|
+ # method_call.with(3, "a")
+ # end.should.be.successful
+ #
+ # is equivalent to:
+ #
+ # an_isolation.did_class_receive?(:a_method).with(3, "a").should.be.successful
+ #
+ # You will probably be using this method only when you're interested in whether a method has been called
+ # during the course of the test you're running.
+ def did_class_receive?(method_name, &block)
+ self.class.did_receive?(method_name, &block)
+ end
+
+ # Initializes the underlying subject
+ # It expects the constructor parameters if they are needed.
+ def with_subject(*args, &b)
+ isolation_context.instance = self.class.superclass.new *args
+ b.call self if b
+ self
+ end
+
+ end
+
+ # A base class for +Isolator+ objects
+ # to stick with the +Isolation+ nomenclature the strategies for creating isolations
+ # are called isolators.
+ # An isolator functions as a barrier between the code in your test and the
+ # underlying type/instance. It allows you to take control over the value
+ # that is returned from a specific method, if you want to pass the method call along to
+ # the underlying instance etc. It also contains the ability to verify if a method
+ # was called, with which arguments etc.
+ class Isolator
+
+ # holds the isolation created by this isolator
+ attr_reader :isolation
+
+ # holds the subject of this isolator
+ attr_reader :subject
+
+ # holds the descriptor for this type of object
+ attr_reader :descriptor
+
+ # creates a new instance of an isolator
+ def initialize(context)
+ @context = context
+ end
+
+ # builds up the isolation class instance
+ def build_isolation(klass, inst=nil)
+ pxy = create_isolation_for klass
+ @isolation = pxy.new
+ @subject = inst
+ initialize_messenger
+ end
+
+ # initializes the messaging strategy for the isolator
+ def initialize_messenger
+ raise NotImplementedError
+ end
+
+ # Creates the new class name for the isolation
+ def class_name(subj)
+ nm = subj.respond_to?(:class_eval) ? subj.demodulize : subj.class.demodulize
+ @class_name = "#{nm}#{UUIDTools::UUID.random_create.to_s.gsub /-/, ''}"
+ @class_name
+ end
+
+ # Sets up the necessary instance variables for the isolation
+ def initialize_isolation(klass, context)
+ pxy = klass.new
+ pxy.instance_variable_set("@___context___", context)
+ pxy
+ end
+
+
+ class << self
+
+ # Creates the actual proxy object for the +subject+ and initializes it with a
+ # +recorder+ and +expectations+
+ # This is the actual isolation that will be used to in your tests.
+ # It implements all the methods of the +subject+ so as long as you're in Ruby
+ # and just need to isolate out some classes defined in a statically compiled language
+ # it should get you all the way there for public instance methods at this point.
+ # when you're going to isolation for usage within a statically compiled language type
+ # then you're bound to most of their rules. So you need to either isolate interfaces
+ # or mark the methods you want to isolate as virtual in your implementing classes.
+ def for(context)
+ context.recorder ||= MethodCallRecorder.new
+ context.expectations ||= Expectations.new
+ new(context)
+ end
+ end
+ end
+
+ # A proxy to Ruby objects that records method calls
+ # this implements all the instance methods that are defined on the class.
+ class RubyIsolator < Isolator
+
+ # implemented template method for creating Ruby isolations
+ def initialize(context)
+ super
+ klass = @context.subject.respond_to?(:class_eval) ? @context.subject : @context.subject.class
+ inst = @context.subject.respond_to?(:class_eval) ? nil : @context.subject
+ # inst = @context.subject.respond_to?(:class_eval) ? @context.subject.new : @context.subject
+ @descriptor = RubyObjectDescriptor.new klass
+ build_isolation klass, inst
+ end
+
+ # initializes the messaging strategy for the isolator
+ def initialize_messenger
+ @context.messenger = RubyMessenger.new @context.expectations, @subject
+ end
+
+ # creates the ruby isolator for the specified subject
+ def create_isolation_for(subj)
+ imembers = @descriptor.instance_members
+ cmembers = @descriptor.class_members
+
+ klass = Object.const_set(class_name(subj), Class.new(subj))
+ klass.class_eval do
+
+ include Interception
+
+ # access to the proxied subject
+ def ___super___
+ isolation_context.instance
+ end
+
+ imembers.each do |mn|
+ mn = mn.name.to_s.to_sym
+ define_method mn do |*args|
+ b = nil
+ b = Proc.new { yield } if block_given?
+ isolation_context.send_message(mn, nil, *args, &b)
+ end
+ end
+
+ def initialize(*args)
+ self
+ end
+
+ cmembers.each do |mn|
+ mn = mn.name.to_s.to_sym
+ define_cmethod mn do |*args|
+ return if mn.to_s =~ /$(singleton_)?method_added/ and args.first.to_s =~ /$(singleton_)?method_added/
+ b = nil
+ b = Proc.new { yield } if block_given?
+ isolation_context.send_class_message(mn, nil, *args, &b)
+ end
+ end
+
+ end
+
+ klass
+ end
+
+
+ end
+
end
\ No newline at end of file