Skip to content

Commit

Permalink
Merge branch 'master' into any_instance_of
Browse files Browse the repository at this point in the history
Conflicts:
	lib/rr/double_definitions/strategies/scope/instance_of_class.rb
	lib/rr/space.rb
  • Loading branch information
Brian Takita committed Mar 29, 2010
2 parents 14cd9cc + 9e2f368 commit 6621c93
Show file tree
Hide file tree
Showing 36 changed files with 333 additions and 2,383 deletions.
4 changes: 4 additions & 0 deletions CHANGES
@@ -1,3 +1,7 @@
0.10.11
- Added RR.blank_slate_whitelist
- Fixed class_eval method redefinition warning in jruby

0.10.10
- Suite passes for Ruby 1.9.1

Expand Down
2 changes: 1 addition & 1 deletion VERSION.yml
@@ -1,5 +1,5 @@
---
:build:
:minor: 10
:patch: 10
:patch: 11
:major: 0
2 changes: 2 additions & 0 deletions lib/rr.rb
Expand Up @@ -2,6 +2,8 @@
require 'rubygems'
require 'forwardable'

require "#{dir}/rr/blank_slate"

require "#{dir}/rr/errors/rr_error"
require "#{dir}/rr/errors/subject_does_not_implement_method_error"
require "#{dir}/rr/errors/subject_has_different_arity_error"
Expand Down
17 changes: 17 additions & 0 deletions lib/rr/blank_slate.rb
@@ -0,0 +1,17 @@
module RR
module BlankSlate
class << self
def call(klass)
klass.instance_eval do
instance_methods.each do |unformatted_method_name|
method_name = unformatted_method_name.to_s
unless method_name =~ /^_/ || Space.blank_slate_whitelist.any? {|whitelisted_method_name| method_name == whitelisted_method_name}
alias_method "__blank_slated_#{method_name}", method_name
undef_method method_name
end
end
end
end
end
end
end
@@ -1,20 +1,9 @@
module RR
module DoubleDefinitions
class DoubleDefinitionCreateBlankSlate
class << self
def blank_slate_methods
instance_methods.each do |m|
unless m =~ /^_/ || m.to_s == 'object_id' || m.to_s == 'respond_to?' || m.to_s == 'method_missing' || m.to_s == 'instance_eval' || m.to_s == 'instance_exec'
alias_method "__blank_slated_#{m}", m
undef_method m
end
end
end
end

def initialize(double_definition_create, &block) #:nodoc:
@double_definition_create = double_definition_create
respond_to?(:class) ? self.class.blank_slate_methods : __blank_slated_class.blank_slate_methods
BlankSlate.call(respond_to?(:class) ? self.class : __blank_slated_class)

if block_given?
if block.arity == 1
Expand Down
Expand Up @@ -25,7 +25,7 @@ def do_call
end

def add_double_to_instance(instance, *args)
double_injection = space.double_injection(instance, method_name)
double_injection = Injections::DoubleInjection.create(instance, method_name)
Double.new(double_injection, definition)
#####
if args.last.is_a?(ProcFromBlock)
Expand Down
2 changes: 1 addition & 1 deletion lib/rr/double_definitions/strategies/scope/instance.rb
Expand Up @@ -5,7 +5,7 @@ module Scope
class Instance < ScopeStrategy
protected
def do_call
double_injection = space.double_injection(subject, method_name)
double_injection = Injections::DoubleInjection.create(subject, method_name)
Double.new(double_injection, definition)
end
end
Expand Down
Expand Up @@ -30,13 +30,12 @@ def do_call
instance_of_subject_double_definition_create.strong if definition.verify_method_signature?
instance_of_subject_double_definition_create.stub(subject)
instance_of_subject_double_definition_create.call(:new) do |*args|
#####
add_double_to_instance(subject.allocate, *args)
end
end

def add_double_to_instance(instance, *args)
double_injection = space.double_injection(instance, method_name)
double_injection = Injections::DoubleInjection.create(instance, method_name)
Double.new(double_injection, definition)
#####
if args.last.is_a?(ProcFromBlock)
Expand All @@ -45,7 +44,7 @@ def add_double_to_instance(instance, *args)
instance.__send__(:initialize, *args)
end
instance
end
end
end
end
end
Expand Down
63 changes: 59 additions & 4 deletions lib/rr/injections/double_injection.rb
Expand Up @@ -4,6 +4,57 @@ module Injections
# A double_injection has 0 to many Double objects. Each Double
# has Argument Expectations and Times called Expectations.
class DoubleInjection < Injection
class << self
def create(subject, method_name)
instances[subject][method_name.to_sym] ||= begin
new(subject, method_name.to_sym, (class << subject; self; end)).bind
end
end

def exists?(subject, method_name)
instances.include?(subject) && instances[subject].include?(method_name.to_sym)
end

def reset
instances.each do |subject, method_double_map|
method_double_map.keys.each do |method_name|
reset_double(subject, method_name)
end
end
end

def verify(*subjects)
subjects = Injections::DoubleInjection.instances.keys if subjects.empty?
subjects.each do |subject|
instances.include?(subject) &&
instances[subject].keys.each do |method_name|
verify_double(subject, method_name)
end &&
instances.delete(subject)
end
end

# Verifies the DoubleInjection for the passed in subject and method_name.
def verify_double(subject, method_name)
Injections::DoubleInjection.instances[subject][method_name].verify
ensure
reset_double subject, method_name
end

# Resets the DoubleInjection for the passed in subject and method_name.
def reset_double(subject, method_name)
double_injection = Injections::DoubleInjection.instances[subject].delete(method_name)
Injections::DoubleInjection.instances.delete(subject) if Injections::DoubleInjection.instances[subject].empty?
double_injection.reset
end

def instances
@instances ||= HashWithObjectIdKey.new do |hash, subject_object|
hash.set_with_object_id(subject_object, {})
end
end
end

attr_reader :subject_class, :method_name, :doubles

MethodArguments = Struct.new(:arguments, :block)
Expand Down Expand Up @@ -34,8 +85,8 @@ def bind
bind_method_with_alias
end
else
space.method_missing_injection(subject)
space.singleton_method_added_injection(subject)
Injections::MethodMissingInjection.create(subject)
Injections::SingletonMethodAddedInjection.create(subject)
end
else
bind_method
Expand All @@ -50,6 +101,7 @@ def verify
double.verify
end
end

# RR::DoubleInjection#reset removes the injected dispatcher method.

# It binds the original method implementation on the subject
Expand Down Expand Up @@ -100,7 +152,10 @@ def bypass_bound_method

protected
def subject_is_proxy_for_method?(method_name_in_question)
!(class << @subject; self; end).
!(
class << @subject;
self;
end).
instance_methods.
detect {|method_name| method_name.to_sym == method_name_in_question.to_sym}
end
Expand All @@ -122,7 +177,7 @@ def bind_method
subject_class.class_eval(<<-METHOD, __FILE__, __LINE__ + 1)
def #{@method_name}(*args, &block)
arguments = MethodArguments.new(args, block)
RR::Space.double_injection(#{subject}, :#{@method_name}).dispatch_method(arguments.arguments, arguments.block)
RR::Injections::DoubleInjection.create(#{subject}, :#{@method_name}).dispatch_method(arguments.arguments, arguments.block)
end
METHOD
end
Expand Down
6 changes: 6 additions & 0 deletions lib/rr/injections/injection.rb
@@ -1,6 +1,12 @@
module RR
module Injections
class Injection
class << self
def instances
@instances ||= HashWithObjectIdKey.new
end
end

include Space::Reader

attr_reader :subject
Expand Down
14 changes: 13 additions & 1 deletion lib/rr/injections/method_missing_injection.rb
@@ -1,6 +1,18 @@
module RR
module Injections
class MethodMissingInjection < Injection
class << self
def create(subject)
instances[subject] ||= begin
new(subject).bind
end
end

def exists?(subject)
instances.include?(subject)
end
end

def initialize(subject)
@subject = subject
@placeholder_method_defined = false
Expand Down Expand Up @@ -48,7 +60,7 @@ class << subject; self; end
def bind_method
returns_method = <<-METHOD
def method_missing(method_name, *args, &block)
RR::Space.method_missing_injection(self).dispatch_method(method_name, args, block)
RR::Injections::MethodMissingInjection.create(self).dispatch_method(method_name, args, block)
end
METHOD
subject_class.class_eval(returns_method, __FILE__, __LINE__ - 4)
Expand Down
17 changes: 14 additions & 3 deletions lib/rr/injections/singleton_method_added_injection.rb
@@ -1,6 +1,18 @@
module RR
module Injections
class SingletonMethodAddedInjection < Injection
class << self
def create(subject)
instances[subject] ||= begin
new(subject).bind
end
end

def exists?(subject)
instances.include?(subject)
end
end

def initialize(subject)
@subject = subject
@placeholder_method_defined = false
Expand All @@ -18,12 +30,11 @@ def singleton_method_added(method_name)
end

memoized_subject = subject
memoized_space = space
memoized_original_method_alias_name = original_method_alias_name
subject_class.__send__(:alias_method, original_method_alias_name, :singleton_method_added)
subject_class.__send__(:define_method, :singleton_method_added) do |method_name_arg|
if memoized_space.double_injection_exists?(memoized_subject, method_name_arg)
memoized_space.double_injection(memoized_subject, method_name_arg).send(:deferred_bind_method)
if Injections::DoubleInjection.exists?(memoized_subject, method_name_arg)
Injections::DoubleInjection.create(memoized_subject, method_name_arg).send(:deferred_bind_method)
end
send(memoized_original_method_alias_name, method_name_arg)
end
Expand Down
4 changes: 2 additions & 2 deletions lib/rr/method_dispatches/method_missing_dispatch.rb
Expand Up @@ -13,7 +13,7 @@ def initialize(subject, method_name, args, block)
end

def call
if space.double_injection_exists?(subject, method_name)
if Injections::DoubleInjection.exists?(subject, method_name)
space.record_call(subject, method_name, args, block)
@double = find_double_to_attempt

Expand Down Expand Up @@ -50,7 +50,7 @@ def call_implementation
end

def double_injection
space.double_injection(subject, method_name)
Injections::DoubleInjection.create(subject, method_name)
end

def_delegators 'self.class', :original_method_missing_alias_name
Expand Down
2 changes: 1 addition & 1 deletion lib/rr/recorded_calls.rb
Expand Up @@ -40,7 +40,7 @@ def match_error(spy_verification)
attr_accessor :ordered_index

def double_injection_exists_error(spy_verification)
unless space.double_injection_exists?(spy_verification.subject, spy_verification.method_name)
unless Injections::DoubleInjection.exists?(spy_verification.subject, spy_verification.method_name)
RR::Errors::SpyVerificationErrors::DoubleInjectionNotFoundError.new(
"A Double Injection for the subject and method call:\n" <<
"#{spy_verification.subject.inspect}\n" <<
Expand Down

0 comments on commit 6621c93

Please sign in to comment.