How to prepend classmethods
The problem is that even though you're prepending the module, ClassMethods
is still getting extend
ed 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 callingModule#prepend
toprepend
the module to the existing class, however, you wrote aself.included
hook method which will only be called when the module is included (not prepended). You should writeModule#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
Why Does Ruby on Rails Use Http://0.0.0.0:3000 Instead of Http://Localhost:3000
How to Get a Stack Trace Object in Ruby
Gem Install Pg Can Not Bind to Libpq
Sidekiq: Ensure All Jobs on the Queue Are Unique
How to Validate Members of an Array Field
Activerecord Select Except Columns
How to Resolve Rails Model Namespace Collision
How to Find the Ruby Interpreter
Fail VS. Raise in Ruby:Should We Really Believe the Style Guide
Is There a Less Intrusive Alternative to Rspec's 'Should_Receive'
Test Whether a Variable Equals Either One of Two Values
Writing Over Previously Output Lines in the Command Prompt with Ruby
Making Multiple Http Requests Asynchronously
How to Override a Column in Rails Model
Is It a Bad Practice to List Ruby Version in Both Gemfile and .Ruby-Version Dotfile