Allyl Isocyanate
Allyl Isocyanate

Reputation: 13626

Defining class methods in Ruby

Typically when writing a model in Rails you use a DSL to setup various aspects of derived objects, for example:

class Question < ActiveRecord::Base
  has_one :category
  validates_presence_of :category
end

In this case, "has_one" and "validates_presence_of" create associations and validation call backs on models instantiated from Question.

I want to add a new method called "parent" to be used when defining a class:

class Question
  attr_accessor :category

  parent :category
end

q = Question.new
q.category = 'a category'
puts q.parent
-> 'a category'

So when objects are instantiated from class, they should have the method "parent" defined.

How do I do this? My first thought was to use a module, but this isn't an instance method, or a class method.

Upvotes: 1

Views: 187

Answers (1)

Pablo Fernandez heelhook
Pablo Fernandez heelhook

Reputation: 12583

I believe this is what you are looking for:

module QuestionParent
  module ClassMethods
    def inherited(descendant)
      descendant.instance_variable_set(:@parent, parent.dup)
      super
    end

    def parent(args=nil)
      @parent ||= args
    end
  end

  module InstanceMethods
    def parent
      self.send self.class.parent.to_sym
    end
  end

  def self.included(receiver)
    receiver.extend         ClassMethods
    receiver.send :include, InstanceMethods
  end
end

class Question
  include QuestionParent

  attr_accessor :category

  parent :category
end

Which produces:

q = Question.new
q.category = 'a category'
puts q.parent

a category

What this does is add a class method parent that will define the class variable @parent, when an instance calls the parent in the InstanceMethod the @parent symbol (here is category) is called.

Upvotes: 2

Related Questions