Pastie now auto-senses if line-wrap is a bad or good idea. Feedback?
## mark a section (Learn more)
require 'class_constants' class Class def mock(klass, method_name, new_method_body) @mocked_classes ||= [] @mocked_classes << klass mock_class = Class.new(klass) mock_class.class_eval(%Q{ def #{method_name.to_s}(*args) #{new_method_body} end}) set_constant(klass.name, mock_class) end def unmock @mocked_classes.each do |klass| set_constant(klass.name, klass) end end end unit_test do class Engine attr_reader :num_of_cylinders def initialize(num_of_cylinders) @num_of_cylinders = num_of_cylinders end def speed 44 end end class Car def initialize @engine = Engine.new(6) end def speed @engine.speed end def num_of_cylinders @engine.num_of_cylinders end end class ClassMockTest < Test::Unit::TestCase def test_mocking Car.mock(Engine, :speed, 24) assert_equal(24, Car.new.speed) assert_equal(6, Car.new.num_of_cylinders) assert_equal(44, Engine.new(4).speed) # only effects references inside the class 'Car' Car.unmock end def test_unmocking Car.mock(Engine, :speed, 24) assert_equal(24, Car.new.speed) Car.unmock assert_equal(44, Car.new.speed) end end end # # class_constants.rb # class Class def get_constant(constant_name) namespace_segments(constant_name).inject(self) { |scope, name| scope.const_get(name) } end def set_constant(constant_name, value) namespaces = namespace_segments(constant_name) if namespaces.size > 1 context = get_constant(namespaces[0..-2].join) context.const_set(namespaces[-1], value) else self.const_set(constant_name, value) end end def namespace_segments(name) name.sub(/^::/,'').split("::") end end unit_test do module A class One end end class Two def self.value "the number two" end end class Three def self.value "the number three" end end class ClassConstantsTest < Test::Unit::TestCase def test_get_constant assert_equal(A::One, self.class.get_constant('A::One')) end def test_set_constant new_class = Class.new assert_nothing_raised{self.class.set_constant('A::One', new_class)} assert_equal(new_class, self.class.get_constant('A::One')) assert_nothing_raised{self.class.set_constant('Two', Three)} assert_equal(Three.value, self.class.get_constant('Two').value) end def test_const_set self.class.const_set('Const1', 1) assert_equal(1, Const1) class1 = Class.new class2 = Class.new self.class.const_set('Const2', class1) assert_equal(class1, Const2) self.class.const_set('Const2', class2) assert_equal(class2, Const2) class3 = Class.new self.class.const_set('Const3', class3) Const3.const_set('Const2', class1) assert_equal(class1, Const3::Const2) assert_equal(class2, Const2) assert_equal(class2, Const2.new.class) assert_equal(class1, Const3::Const2.new.class) Const3.const_set('Const2', class2) assert_equal(class2, Const3::Const2.new.class) end module Module1 class Class1 end end class Class2 attr_reader :var1 def initialize @var1 = Module1::Class1.new end end class Class1a end def test_constant_resolution original_class1 = Module1::Class1 assert_equal(Module1::Class1, Class2.new.var1.class) Module1.const_set('Class1', Class1a) assert_equal(Class1a, Class2.new.var1.class) assert_equal("ClassConstantsTest::Module1::Class1", original_class1.name) Module1.const_set('Class1', original_class1) assert_equal(Module1::Class1, Class2.new.var1.class) class1b = Class.new Module1.const_set('Class1', class1b) assert_equal(class1b, Class2.new.var1.class) assert_equal("ClassConstantsTest::Module1::Class1", class1b.name) assert_equal("ClassConstantsTest::Module1::Class1", original_class1.name) end end end
This paste will be private.
From the Design Piracy series on my blog: