11

I want to dynamically generate a class method in a Mixin, based on the class name that include this Mixin.

Here is my current code:

module MyModule  
  extend ActiveSupport::Concern  

  # def some_methods  
  #   ...  
  # end  

  module ClassMethods  

    # Here is where I'm stuck...
    define_method "#{self.name.downcase}_status" do  
      # do something...  
    end  

  end  
end  

class MyClass < ActiveRecord::Base  
  include MyModule  
end  

# What I'm trying to achieve:
MyClass.myclass_status

But this give me the following method name:

MyClass.mymodule::classmethods_status  

Getting the base class name inside the method definition works (self, self.name...) but I can't make it works for the method name...

So far, I've tried

define_method "#{self}"
define_method "#{self.name"
define_method "#{self.class}"
define_method "#{self.class.name}"
define_method "#{self.model_name}"
define_method "#{self.parent.name}"

But none of this seems to do the trick :/

Is there any way I can retrieve the base class name (not sure what to call the class that include my module). I've been struggling with this problem for hours now and I can't seem to figure out a clean solution :(

Thanks!

4 Answers 4

9

I found a clean solution: using define_singleton_method (available in ruby v1.9.3)

module MyModule  
  extend ActiveSupport::Concern  

  included do
    define_singleton_method "#{self.name}_status" do
      # do stuff
    end
  end

  # def some_methods  
  #   ...  
  # end  

  module ClassMethods  
    # Not needed anymore!
  end  
end  
Sign up to request clarification or add additional context in comments.

Comments

7

You can't do it like that - at this point it is not yet known which class (or classes) are including the module.

If you define a self.included method it will be called each time the module is included and the thing doing the including will be passed as an argument. Alternatively since you are using AS::Concern you can do

included do 
  #code here is executed in the context of the including class
end

1 Comment

Thanks for the explanation. I used define_singleton_method inside the included do #... end block: define_singleton_method "#{self.name}_status" do #... end `
1

You can do something like this:

module MyModule
  def self.included(base)
    (class << base; self; end).send(:define_method, "#{base.name.downcase}_status") do
      puts "Hey!"
  end

  base.extend(ClassMethods)
end

  module ClassMethods
    def other_method
      puts "Hi!"
    end
  end
end

class MyClass
  include MyModule
end

MyClass.myclass_status
MyClass.other_method

Comments

1

Works for extend:

module MyModule  
  def self.extended who
    define_method "#{who.name.downcase}_status" do
      p "Inside"
    end
  end
end  

class MyClass  
  extend MyModule  
end  

MyClass.myclass_status

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.