Refer to a class without explicitly mentioning its namespace - ruby

I have a class within several modules: This::Is::A::Long::ClassName. Is there any way, within one script or method, to make ClassName available without having to reference the namespace? Instead of writing:
This::Is::A::Long::ClassName.do_something
This::Is::A::Long::ClassName.do_something_else
This::Is::A::Long::ClassName.do_something_different
is anything as below possible?
include This::Is::A::Long
ClassName.do_something
ClassName.do_something_else
ClassName.do_something_different

If you are using modules for namespacing, the code you posted should work, see this example:
module Long
module Name
class ClassName
end
end
end
ClassName
# => ... uninitialized constant ClassName (NameError)
include Long::Name
ClassName
# => Long::Name::ClassName

Ruby has no equivalent to C++ using namespace, and you can not reference a class without being in the right namespace, but you can always make it a variable since a class is also an object
long_class = This::Is::A::Long::ClassName
long_class.do_something
long_class.do_something_else
# and so on
EDIT
An include does not put you in the right namespace, it includes the methods & classes in the module you are including (that is, it puts the module in the classes ancestors) and is therefore most certainly not suitable for your needs: Consider the following:
module This
module Is
module A
def foo
puts 'A#foo'
end
def bar
puts 'A#bar'
end
class ClassName
end
end
end
end
Now, you may not want to write This::Is::A::ClassName in another class, let's say:
class C
def foo
puts 'C#foo'
end
end
class B < C
include This::Is::A
end
Now, B.new.foo still puts out C#foo, right? Wrong. Since you included the module, the method has been overwritten.

Related

Ruby Class namespacing with modules: Why do I get NameError with double colons but not module blocks?

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.

Meaning of Syntax for Ruby Module

I've been going through some tutorials to find this information, but haven't seen anything that directly addresses it.
I've seen several times on modules the following syntax:
module MyModule
def run()
puts "running"
end
end
I've also seen syntax that looks like this:
module MyModule
def MyModule.run()
puts "running"
end
end
What's the advantage to including the module name before the method and vice versa?
module MyModule
def MyModule.run()
puts "running"
end
end
is exactly the same as:
module MyModule
def self.run()
puts "running"
end
end
Usually def self.run is used, because it's better when you have to change the module name and it's more idiomatic. I don't see any advantages in writing def MyModule.run.
This has nothing to do with modules. This is just normal method definition syntax.
The syntax for a method definition in Ruby is
def <target>.<selector>(<parameters>)
# …
end
For example:
def foo.bar(baz)
end
This will define a method named bar on the object referenced by foo (more precisely, in the singleton class of the object referenced by foo), with a single mandatory positional parameter whose binding is named baz.
Like with message sends, you can leave out the target, and Ruby will use an implicit default. In a message send, the implicit default is self, with a method definition, the default is the so-called default definee, which is usually the closest lexically enclosing module definition body.
So,
def MyModule.run
means "define a method named run on the object MyModule (or more precisely in the singleton class of the object MyModule)", whereas
def run
means "define a method named run in the default definee", i.e. the closest lexically enclosing module definition body, which in this case is MyModule.
The second version defines run as an instance method of MyModule, the first version defines run as an instance method of the singleton class of MyModule, which we sometimes call a "module method" or "module function".
Note that the first version is usually more idiomatically written as
def self.run
This is about using a module as a static namespace vs using a module as a mixin. Have a look at the following code (with output in comments):
module MyModule
def MyModule.run()
puts "#{self}: running"
end
def run()
puts "#{self}: running"
end
end
class Foo
include MyModule
end
MyModule.run #MyModule: running
foo = Foo.new
foo.run #<Foo:0x007f9b269bf028>: running
In the first usage, the module is basically just acting as a namespace to which you attach a method.
In the second, the module is mixed in to the class Foo. This means that it acts as if the run method was defined within the foo class in the first place; you could, if you wished, refer to instance variables #bar which aren't defined in the module, but only in the Foo class.
I guess both are same but in case when we call module method inside class then we have to give
ModuleName.method_name()
So that it can understand that this method is required for included or that particular module

Ruby - gain class and instance methods from a module which includes another module?

Apologies for the title, suggestions to make it clearer are welcome.
I have created a module (we'll denote this by M) which, when included inside a class, will cause it to obtain new class methods and instance methods (Apologies if my terminology is incorrect). This is achieved by = class F including the A::ModuleInstanceMethods module in the code below.
Now that I've done that, I am trying to create a new module (we'll call this new module M') which includes the module M, such that when M' is included in a class, the class should gain the appropriate class and instance methods as per class F. This is where I get stuck. Examples of such a class is G in the code below.
I'd also like classes which include module M'' (module M'' will includes M') to have the same functionality. An example will be class H in the code below. The same should go for classes which include M''' (which itself includes M''), classes which M'''' (which itself includes M'''), and so on. It's pretty similar to an inheritance hierarchy.
If my textual explanation is confusing, do read the code below. In particular, I'd like to resolve the failures caused by calling G.class_method_one and H.class_method_one, but I lack the knowledge to do so.
I know it is possible to just extend the A::ModuleClassMethods module in the classes that I'm interested in, but I wish to avoid doing this. The same could also be achieved by manually adding the portion of the self.included function in A::ModuleInstanceMethods with the base.instance_of? Class, but if possible I'd like to do it programatically instead of copying and pasting the same code in many different sites.
module A
module ModuleClassMethods
def class_method_one
2
end
end
module ModuleInstanceMethods
def instance_method_one
3
end
def self.included(base)
if base.instance_of? Class
base.extend(A::ModuleClassMethods)
elsif base.instance_of? Module
# Intended functionality:
# When modules that `include` A::ModuleInstanceMethods are themselves
# included in a class (such as module `A::D` included in class `F`),
# class `F` will get the functions defined in the A::ModuleClassMethods
# module as class level methods
end
end
end
module D
include A::ModuleInstanceMethods
end
module E
include D
end
end
class F
include A::ModuleInstanceMethods
end
class G
include A::D
end
class H
include A::E
end
F.class_method_one # 2
F.new.instance_method_one # 3
G.new.instance_method_one # 3
# below statement fails
# G.class_method_one
H.new.instance_method_one # 3
# below statement fails
# H.class_method_one
Thank you.
I've seem to have figured it out. This solution makes use of module_eval. For modules, it adds a self.included function which calls A::ModuleInstanceMethods.included. I wouldn't mind learning about more elegant solutions.
module A
module ModuleClassMethods
def class_method_one
2
end
end
module ModuleInstanceMethods
def instance_method_one
3
end
def self.included(base)
if base.instance_of? Class
base.extend(A::ModuleClassMethods)
elsif base.instance_of? Module
base.module_eval {
def self.included(base)
A::ModuleInstanceMethods.included(base)
end
}
end
end
end
end

ruby modules: using data from a class definition in a module

i've got a module that wants to use data provided by the class that included it - but at the class level, not the instance level.
the goal is to have class 'metadata' provided to a module that the class includes, so that the module can use the metadata during the included call.
this works:
module Bar
def value
#value
end
def baz
puts "the value is: #{value}"
end
end
module Foo
def self.included(mod)
mod.extend(Bar)
mod.baz
end
end
class MyClass
#value = "my class defined this"
include Foo
end
the output of this code is
the value is: my class defined this
i'm not sure if the use of #value is good or not... it seems odd to me that i require this to be set before the include Foo happens, not from a technical perspective (i know why it's required to be done in this order) but from an idiomatic or usability perspective.
... is there a better way / more idiomatic way of accomplishing this?
If you really want to use the class metadata in the moment you're including a module, given the 'included' method runs on its own scope, it's best to have a class method providing the metadata to it.
Also, if the metadata is not going to be manipulated, its better to declare it as a constant.
module Bar
def self.included(base)
puts "the value is: #{base.metadata}"
end
end
class MyClass
VALUE = "MyClass metadata"
def self.metadata
VALUE
end
include Bar
end
class OtherClass
VALUE = "OtherClass metadata"
def self.metadata
VALUE
end
include Bar
end
Of course you can declare the metadata anyway you want, as long as its accessible by a class method to your Module.
Also, its not common to do these kind of metadata manipulation in the module's 'included' method and the necessity of ordering your statements on the class level is a bit brittle, so you might want to try to find a different solution to your original problem instead.
If you want to the class to pass an argument to the mixin, then why not use one of the Ruby constructs that actually does allow passing an argument?
class Object
private
def Bar(metadata)
Module.new do
include Bar
define_singleton_method(:included) do |base|
puts "the value is: #{metadata}"
end
end
end
end
module Bar
# put common behavior here
end
class MyClass
include Bar 'MyClass metadata'
end
class OtherClass
include Bar 'OtherClass metadata'
end
This is a pretty common idiom that is for example used by the delegate library in the stdlib.

Writing Ruby Libraries - hiding methods from outside the module

I'm writing a Ruby library which has a module with a bunch of classes inside it. Many of these classes need to be usable and modifiable by calling scripts, but I don't want (some of) the initializers to be visible/callable:
module MyLib
class Control
def initialize
# They can use this
end
def do_stuff
Helper.new('things')
end
end
class Helper
# Shouldn't be visible
def initialize(what)
#what = what
end
def shout
#what
end
end
end
c = MyLib::Control.new
h = c.do_stuff
p h.shout
# => "things"
# ^ All of this is desired
# v This is undesirable
p MyLib::Helper.new('!')
# => <MyLib::Helper #what='!'>
If it's a simple thing, then I'd also appreciate the generated RDoc not even include the .new method for the Helper class either. Any ideas?
Thanks for reading!
My original answer was completely wrong, as #Matthew pointed out. But there are other workarounds. For instance, you can assign an anonymous class to a class variable on Control, and still define methods as normal by using class_eval:
module MyLib
class Control
def initialize
end
def do_stuff
##helper.new('things')
end
##helper = Class.new
##helper.class_eval do
def initialize(what)
#what = what
end
def shout
#what
end
end
end
end
The snippet
c = MyLib::Control.new
h = c.do_stuff
p h.shout
still writes "things", but now there's no way to access ##helper except through the class variable. If someone really wants to access it my reopening the Control class or using class_eval, there's nothing to stop them, but that's just something you have to deal with in a dynamic language.
I chose to assign the anonymous class to a class variable so that it would only be created once; but if you don't care about redefining the anonymous class many times, there's no reason it couldn't be an instance variable.
Ruby has access control.

Resources