Can anybody explain def self.extended(base), what does it mean here or any idea?
module Paperclip
module Storage
module Dropbox
def self.extended(base)
base.instance_eval do
#options[:dropbox_options] ||= {}
#options[:path] = nil if #options[:path] ==
self.class.default_options[:path]
#options[:dropbox_visibility] ||= "public"
#path_generator = PathGenerator.new(self, #options)
#dropbox_client # Force creation of dropbox_client
end
end
end
end
end
The self.extended method is called when the module is extended. It allows methods to be executed in the context of the base (where the module is extended).
You can try it yourself and understand this with a simple example code. Just paste in a file ruby file and run it.
Example for self.extended
module A
def self.extended(base)
puts "#{self} extended in #{base}"
end
end
class Apple
extend A
end
# This should print: "A extended in Apple"
Example for self.included
module A
def self.included(base)
puts "#{self} included in #{base}"
end
end
class Apple
include A
end
# This should print: "A included in Apple"
You can read more here: http://juixe.com/techknow/index.php/2006/06/15/mixins-in-ruby/
Related
I know that we can define the included callback for any individual module.
Is there any way to define a callback that is invoked whenever any module gets included in another module or class? The callback would then preferably have access to both the module included, and the class/module where it is included.
I cannot think or find a builtin way in Ruby to do it.
One alternative would be to monkey patch the Module class directly to create the callback. To do it we can add some wrapper methods around the original methods include and extend to force the execution of our defined callbacks each time the include or extend methods are called.
Something along the following lines should work:
class Module
def self.before
m_include = instance_method(:include)
m_extend = instance_method(:extend)
define_method(:include) do |*args, &block|
included_callback(args[0])
m_include.bind(self).call(*args, &block)
end
define_method(:extend) do |*args, &block|
extend_callback(args[0])
m_extend.bind(self).call(*args, &block)
end
end
def included_callback(mod_name)
puts "#{self} now has included Module #{mod_name}"
end
def extend_callback(mod_name)
puts "#{self} now has extended Module #{mod_name}"
end
before
end
An example to test that it works:
module Awesome
def bar
puts "bar"
end
def self.baz
puts "baz"
end
end
class TestIncludeAwesome
include Awesome
end
class TestExtendAwesome
extend Awesome
end
The example code should print as output the following:
> TestIncludeAwesome now has included Module Awesome
> TestExtendAwesome now has extended Module Awesome
class D
def self.callback(mod)
include mod
end
end
module M
def hello
puts 'hi'
end
def self.included(klass)
D.callback(self) unless klass == D
end
end
class C
include M
end
C.new.hello #=> 'hi'
D.new.hello #=> 'hi'
When C includes M, M::included is executed with klass#=>C. Since klass == D is false, D.callback(M) is executed. callback includes M in class D, then M::included is executed with klass#=>D. Since klass == D is now true, M is not included into D a second time.
module Gym
def self.included(class_or_module)
class_or_module.send(:include, InstanceMethods)
class_or_module.extend(ClassMethods)
end
module ClassMethods
def build
end
end
module InstanceMethods
def open
end
def book_for_practice
end
def close
end
end
end
this is an example in the Ruby's Object Lifecycle Callbacks section of RubyMonk. I don't understand how it's supposed to work or what the point of this is. self.included should just document how the two modules within Gym get used, right? why does class_or_module then get sent/extended? why doesn't it get saved in some sort of arrays that document the lifecyle, like in the examples leading up to this one, such as
##extended_objects = []
def self.extended_objects
##extended_objects
end
def self.extended(class_or_module)
##extended_objects << class_or_module
It's not just documentation. self.included is a callback method that gets called as soon as the module is being included in any other module or class.
Instance methods are included via send, class or module methods via extend in that example.
Find out more in the Ruby documentation.
Let me answer your Question One by one.
1: self.included should just document how the two modules within Gym get used ?
module A
def instance_methods_1
p 'hello instance_methods_1'
end
def instance_methods_2
p 'hello instance_methods_2'
end
module KlassMethods
def klass_methods_1
p 'Hello!! klass_methods_1'
end
def klass_methods_2
p 'Hello!! klass_methods_2'
end
end
end
class B
include A # instead of writing two piece of code like this we could wrap in one using `self.included` method Hook
extend A::KlassMethods
end
B.new.instance_methods_1
B.new.instance_methods_2
B.klass_methods_1
B.klass_methods_2
Another version of same program with method hook using self.included
module A
# this is special method one of the methods hook in ruby.
def self.included(base)
base.extend(KlassMethods)
end
def instance_methods_1
p 'hello instance_methods_1'
end
def instance_methods_2
p 'hello instance_methods_2'
end
module KlassMethods
def klass_methods_1
p 'Hello!! klass_methods_1'
end
def klass_methods_2
p 'Hello!! klass_methods_2'
end
end
end
class B
include A
end
B.new.instance_methods_1
B.new.instance_methods_2
B.klass_methods_1
B.klass_methods_2
2: self.included
To know more about included hook and
Ruby Hook
3: why does class_or_module then get sent/extended ?
module AddAdditionalProperty
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def add_additional_property
p 'ClassMethods::add_additional_property'
end
end
end
module ActiveRecord
class Base
def test
p 'Base test Method'
end
end
end
ActiveRecord::Base.send(:include, AddAdditionalProperty)
ActiveRecord::Base.add_additional_property
## Another version of same Program
module AddAdditionalProperty
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def add_additional_property
p 'ClassMethods::add_additional_property'
end
end
end
module ActiveRecord
class Base
include AddAdditionalProperty
def test
p 'Base test Method'
end
end
end
ActiveRecord::Base.add_additional_property
Hope this answer help you !!!
I have Ruby class into which I want to include both class and instance methods. Following the pattern described here, I'm currently using the following:
class SomeObject
include SomeObject::Ability
def self.some_builder_method(params)
# use some_class_method ...
end
end
module SomeObject::Ability
module ClassMethods
def some_class_method(param)
# ...
end
end
def self.included(klass)
klass.extend(ClassMethods)
end
def some_instance_method
# ...
end
end
I'd rather not make two separate modules (one being included and the other being extended), because all the methods in my module logically fit together. On the other hand, this pattern a) requires me to define an additional ClassMethods module and b) requires me to write a boilerplate self.included method for every module.
Is there a better way to do this?
Edit 1: I've found another way, but I'm unsure if this is better than the first.
module Concern
def included(base)
# Define instance methods.
instance_methods.each do |m|
defn = instance_method(m)
base.class_eval { define_method(m, defn) }
end
# Define class methods.
(self.methods - Module.methods).each do |m|
unless m == __method__
base.define_singleton_method(m, &method(m))
end
end
end
end
module SomeModule
extend Concern
def self.class_m
puts "Class"
end
def instance_m
puts "Instance"
end
end
class Allo
include SomeModule
end
Allo.class_m # => "Class"
Allo.new.instance_m # => "Instance"
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.
In the code below, I would like to call the class method done of the class that includes the module from inside self.hello
Explanation:
A::bonjour will call Mod::hello so will B::ciao
I would like to be able to detect the "calling class" (A or B) in Mod::hello in order to be able to call the A::done or B::done
module Mod
def self.hello
puts "saying hello..."
end
end
class A
include Mod
def self.bonjour
Mod::hello
end
def self.done
puts "fini"
end
end
class B
include Mod
def self.ciao
Mod::hello
end
def self.done
puts "finitto"
end
end
While (perhaps) not as clean as Niklas' answer, it's still easily doable, and IMO cleaner than the usage pattern shown in the OP which relies on knowing which module is mixed in.
(I prefer not having to pass an argument to mixin methods like this when other means exist.)
The output:
pry(main)> A::bonjour
saying hello...
fini
pry(main)> B::ciao
saying hello...
finitto
The guts:
module Mod
module ClassMethods
def hello
puts "saying hello..."
done
end
end
def self.included(clazz)
clazz.extend ClassMethods
end
end
The modified class declarations, removing the explicit module reference:
class A
include Mod
def self.bonjour
hello
end
def self.done
puts "fini"
end
end
class B
include Mod
def self.ciao
hello
end
def self.done
puts "finitto"
end
end
You may also supply a default implementation of done:
module Mod
module ModMethods
def hello
puts "saying hello..."
done
end
def done
throw "Missing implementation of 'done'"
end
end
def self.included(clazz)
clazz.extend ModMethods
end
end
As a comment to this post points out, if the snippet in the OP is a faithful representation of the actual usecase, you might as well use extend (instead of include), leaving everything cleaner:
module Mod
def hello
puts "saying hello..."
done
end
def done
raise NotImplementError("Missing implementation of 'done'")
end
end
And the classes using extend:
class A
extend Mod
def self.bonjour
hello
end
def self.done
puts "fini"
end
end
I'm writing a module in Ruby 1.9.2 that defines several methods. When any of these methods is called, I want each of them to execute a certain statement first.
module MyModule
def go_forth
a re-used statement
# code particular to this method follows ...
end
def and_multiply
a re-used statement
# then something completely different ...
end
end
But I want to avoid putting that a re-used statement code explicitly in every single method. Is there a way to do so?
(If it matters, a re-used statement will have each method, when called, print its own name. It will do so via some variant of puts __method__.)
Like this:
module M
def self.before(*names)
names.each do |name|
m = instance_method(name)
define_method(name) do |*args, &block|
yield
m.bind(self).(*args, &block)
end
end
end
end
module M
def hello
puts "yo"
end
def bye
puts "bum"
end
before(*instance_methods) { puts "start" }
end
class C
include M
end
C.new.bye #=> "start" "bum"
C.new.hello #=> "start" "yo"
This is exactly what aspector is created for.
With aspector you don't need to write the boilerplate metaprogramming code. You can even go one step further to extract the common logic into a separate aspect class and test it independently.
require 'aspector'
module MyModule
aspector do
before :go_forth, :add_multiply do
...
end
end
def go_forth
# code particular to this method follows ...
end
def and_multiply
# then something completely different ...
end
end
You can implement it with method_missing through proxy Module, like this:
module MyModule
module MyRealModule
def self.go_forth
puts "it works!"
# code particular to this method follows ...
end
def self.and_multiply
puts "it works!"
# then something completely different ...
end
end
def self.method_missing(m, *args, &block)
reused_statement
if MyModule::MyRealModule.methods.include?( m.to_s )
MyModule::MyRealModule.send(m)
else
super
end
end
def self.reused_statement
puts "reused statement"
end
end
MyModule.go_forth
#=> it works!
MyModule.stop_forth
#=> NoMethodError...
You can do this by metaprogramming technique, here's an example:
module YourModule
def included(mod)
def mod.method_added(name)
return if #added
#added = true
original_method = "original #{name}"
alias_method original_method, name
define_method(name) do |*args|
reused_statement
result = send original_method, *args
puts "The method #{name} called!"
result
end
#added = false
end
end
def reused_statement
end
end
module MyModule
include YourModule
def go_forth
end
def and_multiply
end
end
works only in ruby 1.9 and higher
UPDATE: and also can't use block, i.e. no yield in instance methods
I dunno, why I was downvoted - but a proper AOP framework is better than meta-programming hackery. And thats what OP was trying to achieve.
http://debasishg.blogspot.com/2006/06/does-ruby-need-aop.html
Another Solution could be:
module Aop
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def before_filter(method_name, options = {})
aop_methods = Array(options[:only]).compact
return if aop_methods.empty?
aop_methods.each do |m|
alias_method "#{m}_old", m
class_eval <<-RUBY,__FILE__,__LINE__ + 1
def #{m}
#{method_name}
#{m}_old
end
RUBY
end
end
end
end
module Bar
def hello
puts "Running hello world"
end
end
class Foo
include Bar
def find_hello
puts "Running find hello"
end
include Aop
before_filter :find_hello, :only => :hello
end
a = Foo.new()
a.hello()
It is possible with meta-programming.
Another alternative is Aquarium. Aquarium is a framework that implements Aspect-Oriented Programming (AOP) for Ruby. AOP allow you to implement functionality across normal object and method boundaries. Your use case, applying a pre-action on every method, is a basic task of AOP.