How to Prepend Classmethods

How to prepend classmethods

The problem is that even though you're prepending the module, ClassMethods is still getting extended in. You could do this to get what you want:

module Extensions
module ClassMethods
def bar
'Extended Bar!'
end
end

def self.prepended(base)
class << base
prepend ClassMethods
end
end
end

Note that Extensions itself could be either prepended or included in Foo. The important part is prepending ClassMethods.

Ruby prepend doesn't work for class method

Singleton classes do not work that way. You need to explicitly prepend the methods to the eigenclass of SomeClass:

module PrependedModule
module ClassMethods
def klass_method
puts 'PrependedModule klass_method'
end
end

def instance_method_a
puts 'PrepenedModule instance method'
end
end

class SomeClass
# prepending to the class
prepend PrependedModule
class << self
# prepending to the eigenclass
prepend PrependedModule::ClassMethods
end

def self.klass_method
puts 'SomeClass klass_method'
end

def instance_method_a
puts 'SomeClass instance_method'
end
end

require / extend ClassMethod from a separate file

Rails sometimes loses track of constants during autoloading and reloading and needs some help.

This can either be an explicit dependency:

# lib/things.rb
require_dependency 'things/class_methods' # <- tells Rails that we depend on this
require_relative 'things/class_methods'

module Things
extend ClassMethods

# ...
end

Or by using a fully qualified contant:

# lib/things.rb
require_relative 'things/class_methods'

module Things
extend ::Things::ClassMethods

# ...
end

It might be enough to use extend Things::ClassMethods, provided that you don't have another Things module nested under Things.

Which approach works, seems to depend on your class structure and autoloading configuration.

How to add a classmethod in Python dynamically

How I achieved it:

@classmethod
def search_url(cls):
if not hasattr(cls, '_search_url'):
setattr(cls, '_search_url', reverse('%s-search' % cls._meta.model_name))
return cls._search_url

Rails concern how to call ClassMethods from InstanceMethod

self.class.weight_to_kg(weight)

Add class methods through include

If I understand you correctly, you really just want to use ActiveSupport::Concern:

module PetWorthy
extend ActiveSupport::Concern

included do
validates :was_pet, inclusion: [true, 'yes']
end

def pet #instance method
end

module ClassMethods
def find_petworthy_animal
# ...
end
end
end

class Kitty
include PetWorthy
end

Kitty.find_petworthy_animal.pet

You (hopefully obviously) don't need to use the included method if you don't have any behavior to trigger on include, but I put it in just to demonstrate.

Overriden method still gets called

According to the pry trace you posted, the method you wanted to monkey patch is a class method of AdServeModel, not a instance method.

  • The problem with your Associations module approach is, you are calling Module#prepend to prepend the module to the existing class, however, you wrote a self.included hook method which will only be called when the module is included (not prepended). You should write Module#prepended hook instead.

  • The problem with the directly overriding approach is, you were actually overriding the instance method, rather than the class method. It should be something like this:

require 'couchbase/model'

class AdServeModel < Couchbase::Model
class << self
# save the original method for future use, if necessary
alias_method :orig_belongs_to, :belongs_to

def belongs_to(attr_name)
@belongsToAttributes ||= []
@belongstoAttributes << attr_name

create_attr attr_name.to_s
attribute belongs_to_string.concat(attr_name.to_s).to_sym
end

def belongsToAttributes
@belongsToAttributes
end
end
end

Can I add class methods and instance methods from the same module?

There is a common idiom for that. It makes use of included object model hook. This hook gets invoked every time when a module is included to a module/class

module MyExtensions
def self.included(base)
# base is our target class. Invoke `extend` on it and pass nested module with class methods.
base.extend ClassMethods
end

def mod1
"mod1"
end

module ClassMethods
def mod2
"mod2"
end
end
end

class Testing
include MyExtensions
end

t = Testing.new
puts t.mod1
puts Testing::mod2
# >> mod1
# >> mod2

I personally like to group instance method to a nested module as well. But this is less accepted practice, as far as I know.

module MyExtensions
def self.included(base)
base.extend ClassMethods
base.include(InstanceMethods)

# or this, if you have an old ruby and the line above doesn't work
# base.send :include, InstanceMethods
end

module InstanceMethods
def mod1
"mod1"
end
end

module ClassMethods
def mod2
"mod2"
end
end
end

How can I dynamically create class methods for a class in python

You can dynamically add a classmethod to a class by simple assignment to the class object or by setattr on the class object. Here I'm using the python convention that classes start with capital letters to reduce confusion:

# define a class object (your class may be more complicated than this...)
class A(object):
pass

# a class method takes the class object as its first variable
def func(cls):
print 'I am a class method'

# you can just add it to the class if you already know the name you want to use
A.func = classmethod(func)

# or you can auto-generate the name and set it this way
the_name = 'other_func'
setattr(A, the_name, classmethod(func))


Related Topics



Leave a reply



Submit