Ruby excetend multiple class inside Module - ruby

Hello someone can help me? I need to extend multiple class inside one module, i try in this way but not work.
module A
def hello_A
puts "hello from module A"
end
end
module B
extend A
class C
extend A
def self.hello_B_C
puts "Hello from Module B => Class C"
end
end
class D
def self.hello_B_D
puts "Hello from Module B => Class D"
end
end
end
B::C.hello_B_C => #Hello from Module B => Class C
B::C.hello_A => #Hello from module A
B::D.hello_A => #undefined method `hello_A' for B::D:Class
I whold extend module A in Module B, and use hello_A in all subclass of Module B

B::D.hello_A wouldn't work.
when you have this:
class B
extend A
class D
end
end
The class D does not share any functionality with B. B::D is nothing but a namespace.
If you instead did
class B
extend A
class D < self
end
end
Now D inherits all the behavior from B.

Related

How to create an object of a class which is inside a module and inherited another class?

I want to use a method c of class B. For that class A inherits class B inside the module M. Now, how can I create an object of class A and call c?
module M
class A<B
def C
puts "From A"
end
end
class B
def C
puts "From B"
end
end
end
I am getting error " uninitialized constant M::B (NameError)"
I am unable to create object and call c like this:
ob=M::A.new
ob.C
You implement class A that you want to inherit from B before class B. Change this sequence and it will work:
module M
class B
def c
puts "From B"
end
end
class A < B
def c
puts "From A"
end
end
end
obj = M::A.new
ob.c
# From A
I also corrected method named with capital letter. It's possible, but not recommended.
If you run this example, you are getting the following error:
NameError: uninitialized constant M::B
So B is not found. As soon as you add it to your code, everything works fine:
class B
end
module M
class A < B
def c
puts "Test"
end
end
end
ob = M::A.new
ob.c
# >> Test

Ruby: Open Module's singleton

So in a Ruby class, you can use an idiom such as class << self like the following:
class SalesOrganization
def self.find_new_leads
...
end
class << self
include ::NewRelic::Agent::Instrumentation::ControllerInstrumentation
add_transaction_tracer :find_new_leads, :category => :task
end
end
My question is what if SalesOrganization is actually a Module instead of Class. Is this doing what I'm hoping it would do, or am I opening up some black magic that I shouldn't be dabbling with?
# Potentially terrible code
module SalesOrganization
def self.find_new_leads
...
end
class << self
include ::NewRelic::Agent::Instrumentation::ControllerInstrumentation
add_transaction_tracer :find_new_leads, :category => :task
end
end
How do I access a modules singleton class?
No, you're not releasing any black magic. You can define singleton methods on any object, including a module (an instance of the Module class):
module M; end
def M.a
"a"
end
M.a # => "a"
The approaches you suggest work too:
module M
def self.b
"b"
end
end
M.b # => "b"
module M
class << self
def c
"c"
end
end
end
M.c # => "c"
You can also use instance_eval if your method definitions aren't known until runtime:
module M; end
M.instance_eval <<EOF
def d
"d"
end
EOF
M.d # => "d"
Of course, modules like NewRelic... may make assumptions about the classes/modules into which they're included, so you have to be careful there.
I am not sure if I understood what you want to archive. But if you want to write the definition of including C in a module B. And than use C in A after including B, than you can do that this way:
module B
def self.included(base)
base.include C
end
end
class A
include B
# use C
end
That is for your example:
module SalesOrganization
def self.included(base)
base.include ::NewRelic::Agent::Instrumentation::ControllerInstrumentation
base.add_transaction_tracer :find_new_leads, :category => :task
end
def self.find_new_leads
...
end
end
If you now include that SalesOrganization module into a class the class will have the Newrelic stuff included.

How to replicate nested class structure in Ruby

Suppose I have a class A as follows:
class A
class B
end
class C < B
end
...
end
And I want to create a class D that has the same nested class structure as A
class D
Replicate nested class structure of A here
end
I want D to look like:
class D
class B
end
class C < B
end
...
end
So that I can do A::B and D::B with different results
How can I achieve this? Thanks in advance.
class Module
def replicate m
m.constants.each do |sym|
case mm = m.const_get(sym)
when Class then const_set(sym, Class.new(mm.superclass)).replicate(mm)
when Module then const_set(sym, Module.new(mm.superclass)).replicate(mm)
end
end
end
end
class D
replicate A
end
But the superclass part may not be correct with this code.
class A
end
class D
end
[A, D].each do |c|
c.class_eval %Q(
class B
def bar; puts "B#bar in #{c} is not shared" end # <--- new
end
class C < B
def foo; puts "C#foo in #{c}" end
end
)
end
p A.constants
p A::C.instance_methods(false)
p D.constants
p D::C.instance_methods(false)
A::C.new.foo
D::C.new.foo
New
A::B.new.bar
D::B.new.bar
=begin
class B # creates a new class B
def quux; puts "A::B#quux in #{self}" end
end
A::B.new.quux #=> undefined method `quux' for #<A::B:0x101358a98> (NoMethodError)
=end
class A::B # reopens B in A
def quux; puts "A::B#quux in #{self}" end
end
A::B.new.quux
Execution :
$ ruby -w t.rb
["B", "C"]
["foo"]
["B", "C"]
["foo"]
C#foo in A
C#foo in D
New
B#bar in A is not shared
B#bar in D is not shared
A::B#quux in #<A::B:0x10402da28>
It's more duplicating than replicating the whole internal structure, including the methods and possible variables. For this you need reflection, or maybe marshall out and in.
New : If you put something in the text inside %Q(), class_eval will evaluate it for each class, hence it is not shared. B is not independent, you have two different classes A::B and D::B.
If you want to add the same code to both classes, create a module and include it. Ruby creates a proxy which points to the module and inserts the proxy in the chain of pointers starting from the class of the object to its superclass, so that the search method mechanism will look for module's methods after methods of the class and before methods in the superclass.
class D
extend A
end
will define instance methods of A as class (singleton) methods of D. Sounds ugly. I think that you should experiment, display what happens with puts, p, instance_methods, singleton_methods and the like.

calling method in nested module included in class

I have the following configuration:
module A
module B
def foo
puts "foo"
end
end
end
class C
include A
end
c = C.new
c.foo
NoMethodError: undefined method `foo' for #<C:0x8765284>
How do I achieve the above?
Thanks.
Module B is "defined" inside of A, it is not "included" in A. This is why you don't get access to the #foo instance method when you include the A module in C. You could do the following:
class C
include A::B
end
C.new.foo
You can use the included callback to have B include when A is included.
module A
def A.included(klass)
klass.include B
end
module B
def foo
puts "foo"
end
end
end
class C
include A
end
and the following would work
c = C.new
c.foo

Override module method from another module

I want to override a method from a module A from another module B that will monkey-patch A.
http://codepad.org/LPMCuszt
module A
def foo; puts 'A' end
end
module B
def foo; puts 'B'; super; end
end
A.module_eval { include B } # why no override ???
class C
include A
end
# must print 'A B', but only prints 'A' :(
C.new.foo
module A
def foo
puts 'A'
end
end
module B
def foo
puts 'B'
super
end
end
include A # you need to include module A before you can override method
A.module_eval { include B }
class C
include A
end
C.new.foo # => B A
Including a module places it above the module/class that is including it in the class hierarchy. In other words, A#foo is not super of B#foo but rather the other way round.
If you think of including a module as a way of doing multiple inheritance this makes sense, include SomeModule is a way of saying, "Treat SomeModule like it is a parent class for me".
To get the output you wanted you need to reverse the inclusion so that B includes A:
module A
def foo; puts 'A' end
end
module B
def foo; puts 'B'; super; end
end
B.module_eval { include A } # Reversing the inclusion
class C
include B # not include A
end
puts C.new.foo
Edit in response to comment:
Then either include both A and B in C with B included after A:
# A and B as before without including B in A.
class C
include A
include B
end
or patch A in C itself and don't bother with B.
# A as before, no B.
class C
include A
def foo; puts 'B'; super; end
end
The only way for this to work is if the method lookup on C is C -> B -> A and there is no way to do this without including B into C.
This is also one solution to your question. I am trying to achieve with module hooks included. When you include the module A into class C. included callbacks defined in module A is called and executed. We included the module B on-fly. So our module A method foo is overridden by Module B foo to print the superclass module method just called super.
module A
def self.included klass
klass.send(:include, B)
end
def foo
puts 'A'
end
end
module B
def foo
super
puts 'B'
end
end
class C
include A
end
C.new.foo #out put A,B
Another way to accomplish this is to include module B when module A is included.
module A
def foo
puts "this should never be called!"
"a"
end
end
module B
def foo
"b"
end
end
module A
def self.included(base)
base.class_eval do
include B
end
end
end
class C
include A
end
C.new.foo # "b"

Resources