kreek kreek - 2 months ago 8
Ruby Question

ruby class instance variable configuration pattern

I'm trying to make a DSL like configuration for classes that include a module but to have the configured variable available to both class and instance methods seems to require littering the module with access methods. Is there a more elegant way to do this?

module DogMixin
class << self
def included(base)
base.extend ClassMethods
end
end

module ClassMethods
def breed(value)
@dog_breed = value
end

def dog_breed
@dog_breed
end
end
end

class Foo
include DogMixin

breed :havanese
end

puts Foo.dog_breed
# not implemented but should be able to do this as well
f = Foo.new
f.dog_breed

Answer

Your example is a bit weird I think :) Anyway, one way to avoid writing the accessors (the assignment - accessor is problematic in my eyes - especially in the given example) is to define constants, as in the example below. If however you need runtime-assignments, please edit your question (and thus render this answer invalid :) except you want to mess with runtime constant assignment, which is possible but messy).

module DogMixin
  # **include** DogMixin to get `Class.dog_breed`
  class << self
    def included(base)
      def base.dog_breed
        self::DOG_BREED || "pug"
      end
    end
  end

  # **extend** DogMixin to get `instance.dog_breed`
  def dog_breed
    self.class.const_get(:DOG_BREED) || "pug"
  end
end

class Foomer
  DOG_BREED = 'foomer'
  extend  DogMixin
  include DogMixin
end

f = Foomer.new
puts Foomer.dog_breed
puts f.dog_breed

# If I understand you correctly, this is the most important (?):
f.dog_breed == Foomer.dog_breed #=> true

It took some reading of (In Ruby) allowing mixed-in class methods access to class constants to get the Instance-And-Class Constant lookup from a module, but it works. I am not sure if I really like the solution though. Good question, although you could add a little detail.

Comments