Ruby on Rails module include module - ruby-on-rails

I want to include a module in a rails helper(is also a module).
The helper is:
module SportHelper
.....
end
And the module is:
module Formula
def say()
....
end
end
Now, I want to use the method say in SportHelper. What should I do?
If I write like this:
module SportHelper
def speak1()
require 'formula'
extend Formula
say()
end
def speak2()
require 'formula'
extend Formula
say()
end
end
This will work, but I don't want to do so, I just want to add the methods on the helper module,not every methods.

You need just to include this module in your helper:
require 'formula'
module SportHelper
include Formula
def speak1
say
end
def speak2
say
end
end
Maybe you don't need this line require 'formula', if it's already in the load path. For check this you can inspect $LOAD_PATH variable. For more information see this answer.
Basic difference between extend and include is that include is for adding methods to an instance of a class and extend is for adding class methods.
module Foo
def foo
puts 'heyyyyoooo!'
end
end
class Bar
include Foo
end
Bar.new.foo # heyyyyoooo!
Bar.foo # NoMethodError: undefined method ‘foo’ for Bar:Class
class Baz
extend Foo
end
Baz.foo # heyyyyoooo!
Baz.new.foo # NoMethodError: undefined method ‘foo’ for #<Baz:0x1e708>
And if you use extend inside the object method, it will adding methods to an instance of a class, but they would be available only inside this one method.

I think directly include should work
module SportHelper
include SportHelper
.........
end
end
I tested like below:
module A
def test
puts "aaaa"
end
end
module B
include A
def test1
test
end
end
class C
include B
end
c = C.new()
c.test1 #=> aaaa
It should work.

Related

Call method of included module from class

I have a use case where I have class A which includes module B.
class A
include B
def do_one_thing
# override module's method. do something different instead
end
def do_another_thing
# Call `do_one_thing` from here,
# but call the module's method, not the one I overrode above.
end
end
module B
included do
def do_one_thing
# ...
end
end
# some other methods
end
As shown above, I'm calling do_one_thing from do_another_thing. My problem is that I need to call the module's method (i.e. the super method). Is this possible in Rails?
To property use the included method, you'll need your B module to extend ActiveSupport::Concern but that won't give you the behaviour you want.
If I were you I'd abandon that pattern and use simple native Ruby module patterns:
module B
def do_one_thing
puts 'in module'
# ...
end
# some other methods
end
class A
include B
def do_one_thing
super
puts 'in class'
# override module's method. do something different instead
end
def do_another_thing
do_one_thing
# Call `do_one_thing` from here,
# but call the module's method, not the one I overrode above.
end
end
A.new.do_one_thing
The above code will correctly use the module inheritance you are looking for.
Read more about Ruby module inheritance here
You can 'save' included method before override
module B
extend ActiveSupport::Concern
included do
def do_one_thing
puts 'do_one_thing'
end
end
end
class A
include B
alias_method :old_do_one_thing, :do_one_thing
def do_one_thing
puts "I'd rather do this"
end
def do_another_thing
old_do_one_thing
end
end
a= A.new
a.do_one_thing
a.do_another_thing

How to create several class and instance methods in Rails model

I am doing this
def self.a
...
end
def a
class.a
end
But for several method I would have to replicate instance methods.
I was thinking in a module
module A
def a; end
end
And then use it in my model like this:
extend A
include A
But I am not sure where to put it according Rails folder structure, or even if to put module inside my model.
Any advice?
Opt 1 - Extend Self
If you want to have all of your instance methods as class methods as well, you can simply use extend self
class A
def foo
...
end
def bar
...
end
extend self
end
This would allow you to call foo as either A.foo or A.new.foo.
Opt 2 - Included Module
If you only want some of your instance methods to be available as class methods, then you should create a module as you proposed. You could put that module in the lib/ folder and either require it or add lib to your autoload paths.
You can also include the module directly in the class like so:
class A
def not_shared
...
end
module SharedMethods
def foo
...
end
def bar
...
end
end
extend SharedMethods
include SharedMethods
end
Opt 3 - Delegate
If you're using Rails (or just ActiveSupport), you can also make use of the delegate method it adds to class/module.
class A
def not_shared
...
end
def foo
...
end
def bar
...
end
delegate :foo, :bar, to: 'self.class'
end
See here for details:
http://rdoc.info/docs/rails/3.0.0/Module:delegate
You you want to create a module, like shared_methods.rb, you'd put the file in the /lib directory.
You would include the module like this:
class NewClass
include SharedMethods
...
end

Rails: dynamically define class method based on parent class name within module/concern

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!
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
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
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
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

How to alias a class method within a module?

I am using Ruby v1.9.2 and the Ruby on Rails v3.2.2 gem. I had the following module
module MyModule
extend ActiveSupport::Concern
included do
def self.my_method(arg1, arg2)
...
end
end
end
and I wanted to alias the class method my_method. So, I stated the following (not working) code:
module MyModule
extend ActiveSupport::Concern
included do
def self.my_method(arg1, arg2)
...
end
# Note: the following code doesn't work (it raises "NameError: undefined
# local variable or method `new_name' for #<Class:0x00000101412b00>").
def self.alias_class_method(new_name, old_name)
class << self
alias_method new_name, old_name
end
end
alias_class_method :my_new_method, :my_method
end
end
In other words, I thought to extend the Module class someway in order to add an alias_class_method method available throughout MyModule. However, I would like to make it to work and to be available in all my Ruby on Rails application.
Where I should put the file related to the Ruby core extension of the Module class? Maybe in the Ruby on Rails lib directory?
How should I properly "extend" the Module class in the core extension file?
Is it the right way to proceed? That is, for example, should I "extend" another class (Object, BasicObject, Kernel, ...) rather than Module? or, should I avoid implementing the mentioned core extension at all?
But, more important, is there a Ruby feature that makes what I am trying to accomplish so that I don't have to extend its classes?
You could use define_singleton_method to wrap your old method under a new name, like so:
module MyModule
def alias_class_method(new_name, old_name)
define_singleton_method(new_name) { old_name }
end
end
class MyClass
def my_method
puts "my method"
end
end
MyClass.extend(MyModule)
MyClass.alias_class_method(:my_new_method, :my_method)
MyClass.my_new_method # => "my method"
Answering your comment, you wouldn't have to extend every single class by hand. The define_singleton_method is implemented in the Object class. So you could simply extend the Object class, so every class should have the method available...
Object.extend(MyModule)
Put this in an initializer in your Rails app and you should be good to go...
I found an answer on this website: http://engineering.lonelyplanet.com/2012/12/09/monitoring-our-applications-ruby-methods/
The solution is to use class_eval with a block. That enables using variables from the enclosing scope.
module Alias
def trigger
#trigger = true
end
def method_added(name)
if #trigger
#trigger = false
with_x = "#{name}_with_x"
without_x = "#{name}_without_x"
define_method(with_x) do
"#{send(without_x)} with x"
end
alias_method without_x, name
alias_method name, with_x
end
end
def singleton_method_added(name)
if #trigger
#trigger = false
with_x = "#{name}_with_x"
without_x = "#{name}_without_x"
define_singleton_method(with_x) do
"singleton #{send(without_x)} with x"
end
singleton_class.class_eval do
alias_method without_x, name
alias_method name, with_x
end
end
end
end
class TestAlias
extend Alias
trigger
def self.foo
'foo'
end
trigger
def bar
'bar'
end
end
TestAlias.foo # => 'singleton foo with x'
TestAlias.new.bar # => 'bar with x'
If you don't have singleton_class then you should probably upgrade your version of Ruby. If that's not possible you can do this:
class Object
def singleton_class
class << self
self
end
end
end
The accepted answer was confusing and did not work.
class Module
def alias_class_method(new_name, old_name)
define_singleton_method(new_name, singleton_method(old_name))
end
end
module MyModule
def self.my_method
'my method'
end
end
MyModule.alias_class_method(:my_new_method, :my_method)
MyModule.my_new_method # => "my_method"

What does #self.included(base) do in Ruby on Rails' Restful Authentication?

I thought we would do
helper_method :current_user, :logged_in?, :authorized?
to make these controller methods available for use as helper methods in views. But in Restful Authentication's lib/authenticated_system.rb, I see:
# Inclusion hook to make #current_user and #logged_in?
# available as ActionView helper methods.
def self.included(base)
base.send :helper_method, :current_user, :logged_in?, :authorized? if base.respond_to? :helper_method
end
Why is it done this way instead of that single line? Also, I don't see included being called anywhere.
The self.included function is called when the module is included. It allows methods to be executed in the context of the base (where the module is included).
More info: a ruby mixin tutorial.
Out of the same reason which Peter has mentioned I would like to add an example so that it's easy for the newbie developers to understand self.included(base) and self.extended(base) :
module Module1
def fun1
puts 'fun1 from Module1'
end
def self.included(_base)
def fun2
puts 'fun2 from Module1'
end
end
def self.extended(_base)
def fun3
puts 'fun3 from Module1'
end
end
end
module Module2
def foo
puts 'foo from Module2'
end
def self.extended(_base)
def bar
puts 'bar from Module2'
end
end
end
class Test
include Module1
extend Module2
def abc
puts 'abc form Test'
end
end
class Test2
extend Module1
end
Test.new.abc #=> abc form Test
Test.new.fun1 #=> fun1 from Module1
Test.new.fun2 #=> fun2 from Module1
Test.foo #=> foo from Module2
Test.bar #=> bar from Module2
Test.new.fun3 #=> **NoMethodError** (undefined method `fun3' ..)
*Test2*.fun3 #=> fun3 from Module1
extend : methods will be accessible as class methods
include : methods will be available as instance methods
"base" in self.extended(base) / self.included(base) :
The base parameter in the static extended method will be either an
instance object or class object of the class that extended the module
depending whether you extend a object or class, respectively.
When a class includes a module the module’s self.included method will
be invoked. The base parameter will be a class object for the class
that includes the module.
When the AuthenticatedSystem method is included using the include method, the self.included method is triggered with whatever it was included into being the argument of base.
The code you've shown calls helper_method and defines some helpful helpers, but only if the base has a helper_method method.
It's done that way so including the module can set up the helper methods as well as adding additional methods to the class.
As it is the first result when searching Google for "self.included(base)" I will try to give a small example on how it works. I don't know how much it differs from the restful-authentication-approach.
It is basically used to make methods from one module available in another module.
module One
def hello
puts 'hello from module One'
end
end
module Two
def self.included(base)
base.class_eval do
include One
end
end
end
class ExampleClass
include Two
end
ExampleClass.new.hello # => hello from module One
Want to digger into self.included and self.extended ?
Please look at here: https://ruby-doc.org/core-2.2.1/Module.html#method-i-included

Resources