Variable class idea and request for critique

Hi all,

I'm fairly new to Ruby but really enjoying it. I've been working on a
medium large project that is non rails but uses ActiveRecord and
assorted other pieces of the rails framework. I'd been finding myself
having more and more difficulty writing unit tests as I went because
many of my classes were calling class methods of other classes
internally--such as the models from rails--and these were hard to factor
out. For example:

class ImportantModel < ActiveRecord::Base
end

class Processor
  def self.do_hard_processing(something)
           #....
         end
end

class SomeClass

  def a_method
             #...
             something = ImportantModel.find_by_a_lot_of_stuff(one, two)
             processed = Processor.do_hard_processing(something)
             if _the_time_is_right?(processed)
                #...etc
        end

end

If those had been objects I could have swapped mocks in for them when I
wanted to test SomeClass, but since they're classes--constants by
definition--I couldn't! I know about fixtures to help with this
problem, but sometimes (as in the case of the Processor class) they
aren't really possible, and sometimes you really don't want to involve
the working of a model...you just want to test SomeClass's logic with
some hard coded mock objects.

One solution is pretty simple:

class SomeClass

  attr_accessor :important_model
        attr_accessor :processor

  def initialize
     @important_model = ImportantModel
           @processor = Processor
        end

  def a_method
             something =
    important_model.find_by_a_lot_of_stuff(one, two)
             processed = processor.do_hard_processing(something)
             if _the_time_is_right?(processed)
                #...etc
        end

end

This is an improvement, because now in a testing environment, for
instance, you could set

sc = SomeClass.new
sc.important_model = HardCodedModel
#or even
sc.imporant_model = mockObjectOfSomeSort
#since there's nothing says it has to be a class

But there were two things I didn't like: one, the repetetive
nature--you're writing some variation of important_model 3 times, for
each class you want to make variable Second of all, I wanted to make it
easy to decide on the class/object returned conditionally or
dynamically, with a block, which can save you a lot of time in testing
code (and could be useful in production, for that matter).

The solution I came up with was to add a class method called
variable_class to Object, which would provide an indirect way to refer
to classes like ImportantModel or Processor (or even allow them to be
not classes at all but arbitrary objects), and which had support for a
block.

require 'rubygems'
require 'active_support/inflector'

class Object

  def self.variable_class(klass, accessor_name = nil, &block)
    klass_str = klass.name
    klass_sym = klass_str.to_sym
    klass_translated_str =
  "#{Inflector.underscore(klass_str.tr_s('::','_'))}_class"
    instance_var_sym = "@#{klass_translated_str}".to_sym

    get_method_sym = accessor_name ? accessor_name.to_sym :
                                     klass_translated_str.to_sym
    set_method_sym = "#{get_method_sym.to_s}=".to_sym

    if block_given?

      define_method(get_method_sym) do
        block.call(self)
      end

    else

      define_method(get_method_sym) do
        instance_variable_get(instance_var_sym) ||
instance_variable_set(instance_var_sym,

klass)
      end

      define_method(set_method_sym) do |custom_class|
        instance_variable_set(instance_var_sym, custom_class)
      end

    end
  end

Basically, given two classes (here I'm just going to make them classes
and not note the object possibility anymore)

class One
  def self.do
  puts "one"
  end
end

class Two
  def self.do
       puts "two"
   end
end

All the following will work:

class SimplestCase
   variable_class One

   def test
      one_class.do
   end
end

sc = SimplestCase.new
sc.test #"one"
sc.one_class = Two
sc.test #"two"

The default is to make the class variable settable/gettable with the
underscored name of the class plus _class. Any :: operators get turned
into underscores as well, so Mod::KlassName would become
mod_klass_name_class by default.

If you need a shorter/different name, you can pass it as a symbol in the
second argument slot.

class AlmostAsSimple
   variable_class One, :my_own_name

   def test
      my_own_name.do
   end
end

sc = AlmostAsSimple.new
sc.test #"one"
sc.my_own_name = Two
sc.test #"two"

If you want to use a block, you can do it like so:

class BlockExample
        @@use_two = false

        def self.go_two
           @@use_two = true
        end

  variable_class One do
           @@use_two ? Two : One
        end

        def test
          one_class.do
        end
end

be = BlockExample.new
be.test #"one"
BlockExample.go_two
be.test #"two"

And if you want to use instance rather than class methods / variables in
the block, self is passed along for you.

class BlockExample2

  def initialize
    @use_two = false
  end

        def go_two
           @use_two = true
        end

  def use_two?
              @use_two
  end

  variable_class One do |be2obj|
           be2obj.use_two? ? Two : One
        end

        def test
          one_class.do
        end
end

be2 = BlockExample2.new
be2.test #"one"
be2.go_two
be2.test #"two"

Using this approach, I've been able to actually test the UNITS in my
unit tests, by being able to swap in mocks for classes as well as
objects and isolating the behavior of the class I'm testing. But I
wanted to run it by the people on this fine list to see what suggestions
people had for it before I put it in too many spots. Is there a much
simpler way to accomplish the same? Or something that could be added
now to make it more flexible? Or a way to tighten up the code? I want
it to be as Ruby-like as possible.

Thanks for any critiques or suggestions.

Edmund