Search code examples
rubyclass-variables

Setting new class variables inside a module


I have a plugin I have been working on that adds publishing to ActiveRecord classes. I extend my classes with my publisher like so:

class Note < ActiveRecord::Base
  # ...
  publishable :related_attributes => [:taggings]
end

My publisher is structured like:

module Publisher

  def self.included(base)
    base.send(:extend, ClassMethods)

    @@publishing_options = [] # does not seem to be available
  end

  module ClassMethods

    def publishable options={}
      include InstanceMethods

      @@publishing_options = options

      # does not work as class_variable_set is a private method
      # self.class_variable_set(:@@publishing_options, options)

      # results in: uninitialized class variable @@publishing_options in Publisher::ClassMethods
      puts "@@publishing_options: #{@@publishing_options.inspect}"

      # ...
    end

    # ...

  end

  module InstanceMethods

    # results in: uninitialized class variable @@publishing_options in Publisher::InstanceMethods
    def related_attributes
      @@publishing_options[:related_attributes]
    end

    # ...
  end

end

Any ideas on how to pass options to publishable and have them available as a class variable?


Solution

  • I am presuming that you want one set of publishing_options per class. In that case you just want to prefix your variable with a single @. Remember the class itself is an instance of the class Class so when you are in the context of a class method you actually want to set an instance variable on your class. Something like the following:

    module Publishable
      module ClassMethods
        def publishable(options)
          @publishing_options = options
        end
    
        def publishing_options
          @publishing_options
        end
      end
    
      def self.included(base)
        base.extend(ClassMethods)
      end
    end
    

    Then if ActiveRecord::Base is extended as follows:

    ActiveRecord::Base.send :include, Publishable
    

    You can do:

    class Note < ActiveRecord::Base
      publishable :related_attributes => [:taggings]
    end
    
    class Other < ActiveRecord::Base
      publishable :related_attributes => [:other]
    end
    
    Note.publishing_options
    => {:related_attributes=>[:taggings]}
    
    Other.publishing_options
    => {:related_attributes=>[:other]}