How do you get a reference to the enclosing module in ruby?
module Foo
##variable=1
def variable
##variable
end
class A
def somemethod
puts "variable=#{Foo.variable}" #<--this won't run, resolving Foo
# as the class instead of the module
end
end
class Foo
... # doesn't matter what's here
end
end
I ran into this question caused by naming confusion. While the names are easy enough to fix, I"m wondering what the "correct" way is to do this in ruby. If I try to run this it seems like ruby is trying to resolve Foo.variable as Foo::Foo.variable which of course fails. It seems like there should be a simple way in the language to refer to the outer module method.
You can get the outer module reference by adding the :: prefix to Foo:
::Foo.variable
In your example code:
module Foo
##variable=1
def variable
##variable
end
class A
def somemethod
puts "variable=#{::Foo.variable}"
end
end
class Foo
... # doesn't matter what's here
end
end
Related
I am working with a lot of pre-existing files, classes, and modules and trying to come up with better namespacing for the different components of the framework. I've been using modules as a way to namespace mainly because this seems like the standard convention (and being able to 'include' different parts of the framework could be useful).
The problem is that there was a ton of classes underneath the global namespace that should exist underneath a module. For example, let's say there is a class that was simply defined as:
class FirstClass
def meth
puts "HELLO"
end
end
But now I want to have this class within a module:
Using Double Colons:
module Foo; end
class Foo::FirstClass
def meth
puts 'HELLO'
end
end
Using Module Blocks:
module Foo
class FirstClass
def meth
puts 'HELLO'
end
end
Using double colons is a lot cleaner and also a lot easier to implement since I am changing many class definitions. Both of these ways work and I thought that they are both effectively the same thing, but evidently they are not. The double colon method seems to result in a different namespace within each class compared to the module block. For instance, with two classes underneath "Foo":
Using Module Blocks:
module Foo
class FirstClass
def meth
puts 'HELLO'
end
end
class SecondClass
def meth
FirstClass.new.meth
end
end
end
Foo::SecondClass.new.meth
Using Double Colons:
module Foo; end
class Foo::FirstClass
def meth
puts 'HELLO'
end
end
class Foo::SecondClass
def meth
FirstClass.new.meth
end
end
Foo::SecondClass.new.meth
The code works when using module blocks, but doesn't work with double colons. With the double colons, NameError is raised because it resolves FirstClass as Foo::SecondClass::FirstClass (instead of Foo::FirstClass), which doesn't exist.
This can easily be solved by including Foo in SecondClass, but how come this isn't done by default?
Note: I'm using Ruby 2.1.5, which I know is outdated, but I get the same results on repl.it with ruby 2.5.5p157: https://repl.it/#joep2/Colon-vs-Block-Namespacing
It may seem counter-intuitive, but constant lookup in Ruby is done using current lexical scope, i.e. the current lexical nesting level (location in the source code), not the semantic nesting level.
This can be tested by inspecting Module.nesting, which prints the current lexical scope:
class Foo::SecondClass
pp Module.nesting # -> [Foo::SecondClass]
end
module Foo
class SecondClass
pp Module.nesting # -> [Foo::SecondClass, Foo]
end
end
Since Ruby uses this nesting level for symbol lookup, it means in the situation where you try to look up FirstClass within nesting [Foo::SecondClass], Ruby will not find it.
However when you try to look it up within nesting [Foo::SecondClass, Foo], it will find FirstClass under Foo, just like you expect.
To get around this, you could do:
class Foo::SecondClass
def meth
Foo::FirstClass.new.meth
end
end
Which will now work as you expect, since you provided the necessary lookup hint for FirstClass, and told Ruby it is inside Foo.
I'm playing with some of the very basics of ruby mixins, and for some reason can't access behavior from my module.
Running this on Ruby Fiddle:
module Cats
MEOW = "meow meow meow"
def Cats.meow?
return Cats::MEOW
end
end
class Example
include Cats
def sample
return "it's a sample"
end
end
e = Example.new
puts e.sample
puts e.meow?
This keeps returning NoMethodError: undefined method 'meow?' for #
My understanding of how mixins should work from tutorialspoint makes me feel like I should be able to validly call e.meow?, and get back the same result I would get from calling Cats.meow?.
Here's the code in RubyFiddle.
Incredibly basic, but any ideas where I'm falling down here?
As it turns out, I was being overly specific when defining Cats.meow?. If you want to use a module as a mixin you'll want to define your methods more generally, not with respect to their specific module namespace.
So instead of
def Cats.meow?
...
end
it should have been
def meow?
...
end
This lets you call e.meow?, since the method definition no longer limits it just to the Cats namespace.
Whoops.
As a general rule to using include and extend in Ruby:
If you want to use your module as a namespace
module Outer
module Inner
def self.my_method
"namespaced method!"
end
end
end
You use it like this Outer::Inner::my_method or Outer::Inner.my_method.
And if you want to use the module as a mixin:
# In some cases it makes sense to use names ending in -able, since it expreses
# what kind of messages you can send to an instance or class that mixes
# this module in.
# Like Devise's Recoverable module: https://github.com/plataformatec/devise/blob/f39c6fd92774cb66f96f546d8d5e8281542b4e78/lib/devise/models/recoverable.rb#L24
module Fooable
def foo
"#{self} has been foo'ed!"
end
end
Then you can include it (instances of Something obtain #foo):
class Something
include Fooable # Now Something.new can receive the #foo message.
end
Something.new.foo
=> "#<Something:0x0055c2dc104650> has been foo'ed!"
Or you can extend it (Something itself obtains #foo as a class message):
class Something
extend Fooable # Now Something can receive the #foo message.
end
Something.foo
=> "Something has been foo'ed!"
I'm trying to figure out how to get the name of the class that called a module function in a plugin-based application of mine.
caller seems to give me a file/line number, which is workable, but seems a bit hacky and not idiomatic.
Example code:
module AwesomeModule
def self.get_caller
puts #some unknown code here
end
end
class AwesomeClass
def initialize
AwesomeModule::get_caller
end
end
a = AwesomeClass.new # ideal return => "AwesomeClass"
You typically use ruby modules by including them. Try this:
module AwesomeModule
def get_caller
self.class
end
end
class AwesomeClass
include AwesomeModule
def initialize
get_caller
end
end
a = AwesomeClass.new # "AwesomeClass"
Also, note that in your question get_caller is being called on the AwesomeModule module itself, further complicating the issue.
I found an interesting problem: http://rubeque.com/problems/fixing-bad-code-the-wrong-way/solutions
Generally we have a simple class (notice that we don't have attr_accessor here):
class Foo
def itnialize(name)
self.foo = name
end
def set_bar
self.bar = 'it will fail..'
end
end
I thought that ruby will raise no method error when I call Foo.new but it passes without any problems. The code will fail when I try Foo.new.bar
How is it possible and how to access Foo.new.foo variable?
You have a typo and have miss-spelt initialize as itnialize so it won't be being called - so no error.
It looks like you're trying to create an instance variable - to do so you need, somewhere, to define it with the # prefix. So you might do:
def initialize(name)
#foo = name
end
which would then mean you are able to access #foo inside the class.
self.foo can only ever refer to a method foo, so you need to define that method if you want to call it, either explicitly or by using one of the attr variants.
However, in this case, you could just do
def set_bar
#bar = 'it will succeed!'
end
hereafter is my piece of code that I want to simplify in order to avoid passing an extra argument on each call. In fact, my usecase is that M is a user library without the definition of context argument on each method. check is a method that is not defined by the user.
# User code
module M
def do_something(context)
puts "Called from #{context}"
context.check
end
module_function :do_something
end
# Application code
class Bar
def check
puts "Checking from #{self}..."
end
end
class Foo < Bar
def do_stuff(scope, method)
scope.send method, self
end
end
# Executed by user
Foo.new.do_stuff M, :do_something
Is there a way to do the same think without passing self as an input argument to do_something method in order to retrieve check method ?
# User code
module M
def do_something
called_from_object = ???
puts "Called from #{called_from_object}"
called_from_object.check
end
module_function :do_something
end
# Application code
class Bar
def check
puts "Checking from #{self}..."
end
end
class Foo < Bar
def do_stuff(scope, method)
scope.send methood
end
end
# Executed by user
Foo.new.do_stuff M, :do_something
Thanks for your support!
Came across this post while looking for an answer for my own purposes.
Didn't find one that was appropriate, so I dug through the Ruby source and put together an extension. I've bundled it as a gem- should install without any problem so long as you are using Ruby 1.9.1:
sudo gem install sender
This will not work with Ruby 1.8, as 1.8 has a different model for tracking frames.
http://rubygems.org/gems/sender
Not what you're asking for, but if Foo were to include M would that allow you do achieve what you're after? e.g.
module M
def do_something
puts "I am going to use the test method from the including class"
test
end
end
class Foo
include M
def test
puts "In Foo's test method"
end
def do_stuff
do_something
end
end
and then you can do:
irb(main):019:0> Foo.new.do_stuff
I am going to use the test method from the including class
In Foo's test method
If the idea is to have a module provide some general functionality and have the specifics in a class then this is a fairly common pattern in ruby, e.g. the Comparable module requiring the including class to implement <=>.