Working with anonymous modules in Ruby - ruby

Suppose I make a module as follows:
m = Module.new do
class C
end
end
Three questions:
Other than a reference to m, is there a way I can access C and other things inside m?
Can I give a name to the anonymous module after I've created it (just as if I'd typed "module ...")?
How do I delete the anonymous module when I'm done with it, such that the constants it defines are no longer present?

Three answers:
Yes, using ObjectSpace. This code makes c refer to your class C without referencing m:
c = nil
ObjectSpace.each_object { |obj|
c = obj if (Class === obj and obj.name =~ /::C$/)
}
Of course this depends on there being no other classes named C anywhere in the program, but you get the idea.
Yes, sort of. If you just assign it to a constant, like M = m, then m.name will return "M" instead of nil, and references like M::C will work. Actually, when I do this and type M::C in irb, I get #<Module:0x9ed509c>::C, but maybe that's a bug.
I think it should be garbage collected once there are no references to it, i.e. when there are no instances or subtypes of m or C, and m is set to a different value or goes out of scope. If you assigned it to a constant as in the above point, you would need to change it to a different value too (though changing constants is generally ill-advised).

Define a NamedModule
Once way to handle this is to define your own kind of module that can be initialized with a name.
class NamedModule < Module
attr_accessor :name
def initialize(name, &block)
super(&block)
self.name = name
end
def to_s
[self.class.name, name, object_id].join(':')
end
end
Then you can do this:
piracy = NamedModule.new("Piracy") do
def berate
puts "Yer a #{adjectives.sample} #{nouns.sample}!"
end
private
def adjectives
%w[yella-bellied landlubbing]
end
def nouns
%w[scallywag bilge-drinker]
end
end
Sailor = Class.new
Sailor.send(:include, piracy)
Sailor.new.berate #=> "Yer a yella-bellied scallywag!"
Defining to_s gives you nice output in ancestors:
Sailor.ancestors
#=> [Sailor, NamedModule:Piracy:70169997844420, Object, Kernel, BasicObject]
Update - use the Named gem
After my colleague and I had experimented with this, he wrote a small gem implementation. Check out the Named gem - Rubygems and Github.

I tried wdebeaum's second answert in Ruby 1.9.3-p0 and it didn't work.
M::C returned NameError: uninitialized constant M::C and M.constants returns []
So you should try the approach suggested here
m = Module.new do
class self::C
end
end
And you can use m::C as usual.

Related

Dynamically define a super method for an instance of a class in Ruby

Say we have a class that we cannot change,
class C
def foo
super
puts "Low!"
end
end
We'll need to dynamically define the method foo in something that we'll be able to inject into C's ancestry chain. The behavior of super must be specific to a given object, not class-wide. We'll be able to enclose that logic into an anonymous module (let's name it for now):
module M
def foo
puts "High!"
end
end
Extending an instance of C with the module:
c = C.new
c.extend(M)
c.foo
# High!
will not work since we've put the method from the module before the method we've defined in the class. Looking at our object's ancestors
c.singleton_class.ancestors
# => [#<Class:#<C:0x00005652be630b20>>, M, C, ...]
I came up with an ugly workaround, which is redefining the methods from our class in our singleton_class, i.e.
c.define_singleton_method(:foo, c.class.instance_method(:foo))
c.foo
# High!
# Low!
While this works (does it work? I've tested it for a bit and it seems to, but I'm no longer certain), I wonder whether I'm missing something obvious and there's an easier way to dynamically define a "super" method for an instance of a class.
To be clear, we want to be able to extend another instance of C with another module, i.e.
C.new.extend(Module.new do
def foo
puts "Medium!"
end
end).foo
# Medium!
# Low!
and have its output not tainted by other instances.
Now that I understand you're trying to work around an issue in some third-party code, I can suggest a more reasonable solution. In the code below, I'm thinking that B and C are defined by the gem and you don't want to change their source code, but you want to inject some code into the place where C#foo calls B#foo.
class B
def foo
puts "Highest!"
end
end
class C < B
def foo
super
puts "Low!"
end
end
module CE
def foo
super
foo_injected
end
end
C.include(CE)
module M
def foo_injected
puts "High!"
end
end
c = C.new
c.extend(M)
p c.singleton_class.ancestors
c.foo
The output is:
[#<Class:#<C:0x000055ce443366a8>>, M, C, CE, B, Object, Kernel, BasicObject]
Highest!
High!
Low!

Dynamic constant assignment

class MyClass
def mymethod
MYCONSTANT = "blah"
end
end
gives me the error:
SyntaxError: dynamic constant assignment error
Why is this considered a dynamic constant? I'm just assigning a string to it.
Your problem is that each time you run the method you are assigning a new value to the constant. This is not allowed, as it makes the constant non-constant; even though the contents of the string are the same (for the moment, anyhow), the actual string object itself is different each time the method is called. For example:
def foo
p "bar".object_id
end
foo #=> 15779172
foo #=> 15779112
Perhaps if you explained your use case—why you want to change the value of a constant in a method—we could help you with a better implementation.
Perhaps you'd rather have an instance variable on the class?
class MyClass
class << self
attr_accessor :my_constant
end
def my_method
self.class.my_constant = "blah"
end
end
p MyClass.my_constant #=> nil
MyClass.new.my_method
p MyClass.my_constant #=> "blah"
If you really want to change the value of a constant in a method, and your constant is a String or an Array, you can 'cheat' and use the #replace method to cause the object to take on a new value without actually changing the object:
class MyClass
BAR = "blah"
def cheat(new_bar)
BAR.replace new_bar
end
end
p MyClass::BAR #=> "blah"
MyClass.new.cheat "whee"
p MyClass::BAR #=> "whee"
Because constants in Ruby aren't meant to be changed, Ruby discourages you from assigning to them in parts of code which might get executed more than once, such as inside methods.
Under normal circumstances, you should define the constant inside the class itself:
class MyClass
MY_CONSTANT = "foo"
end
MyClass::MY_CONSTANT #=> "foo"
If for some reason though you really do need to define a constant inside a method (perhaps for some type of metaprogramming), you can use const_set:
class MyClass
def my_method
self.class.const_set(:MY_CONSTANT, "foo")
end
end
MyClass::MY_CONSTANT
#=> NameError: uninitialized constant MyClass::MY_CONSTANT
MyClass.new.my_method
MyClass::MY_CONSTANT #=> "foo"
Again though, const_set isn't something you should really have to resort to under normal circumstances. If you're not sure whether you really want to be assigning to constants this way, you may want to consider one of the following alternatives:
Class variables
Class variables behave like constants in many ways. They are properties on a class, and they are accessible in subclasses of the class they are defined on.
The difference is that class variables are meant to be modifiable, and can therefore be assigned to inside methods with no issue.
class MyClass
def self.my_class_variable
##my_class_variable
end
def my_method
##my_class_variable = "foo"
end
end
class SubClass < MyClass
end
MyClass.my_class_variable
#=> NameError: uninitialized class variable ##my_class_variable in MyClass
SubClass.my_class_variable
#=> NameError: uninitialized class variable ##my_class_variable in MyClass
MyClass.new.my_method
MyClass.my_class_variable #=> "foo"
SubClass.my_class_variable #=> "foo"
Class attributes
Class attributes are a sort of "instance variable on a class". They behave a bit like class variables, except that their values are not shared with subclasses.
class MyClass
class << self
attr_accessor :my_class_attribute
end
def my_method
self.class.my_class_attribute = "blah"
end
end
class SubClass < MyClass
end
MyClass.my_class_attribute #=> nil
SubClass.my_class_attribute #=> nil
MyClass.new.my_method
MyClass.my_class_attribute #=> "blah"
SubClass.my_class_attribute #=> nil
SubClass.new.my_method
SubClass.my_class_attribute #=> "blah"
Instance variables
And just for completeness I should probably mention: if you need to assign a value which can only be determined after your class has been instantiated, there's a good chance you might actually be looking for a plain old instance variable.
class MyClass
attr_accessor :instance_variable
def my_method
#instance_variable = "blah"
end
end
my_object = MyClass.new
my_object.instance_variable #=> nil
my_object.my_method
my_object.instance_variable #=> "blah"
MyClass.new.instance_variable #=> nil
In Ruby, any variable whose name starts with a capital letter is a constant and you can only assign to it once. Choose one of these alternatives:
class MyClass
MYCONSTANT = "blah"
def mymethod
MYCONSTANT
end
end
class MyClass
def mymethod
my_constant = "blah"
end
end
Constants in ruby cannot be defined inside methods. See the notes at the bottom of this page, for example
You can't name a variable with capital letters or Ruby will asume its a constant and will want it to keep it's value constant, in which case changing it's value would be an error an "dynamic constant assignment error". With lower case should be fine
class MyClass
def mymethod
myconstant = "blah"
end
end
Ruby doesn't like that you are assigning the constant inside of a method because it risks re-assignment. Several SO answers before me give the alternative of assigning it outside of a method--but in the class, which is a better place to assign it.
Many thanks to Dorian and Phrogz for reminding me about the array (and hash) method #replace, which can "replace the contents of an array or hash."
The notion that a CONSTANT's value can be changed, but with an annoying warning, is one of Ruby's few conceptual mis-steps -- these should either be fully immutable, or dump the constant idea altogether. From a coder's perspective, a constant is declarative and intentional, a signal to other that "this value is truly unchangeable once declared/assigned."
But sometimes an "obvious declaration" actually forecloses other, future useful opportunities. For example...
There are legitimate use cases where a "constant's" value might really need to be changed: for example, re-loading ARGV from a REPL-like prompt-loop, then rerunning ARGV thru more (subsequent) OptionParser.parse! calls -- voila! Gives "command line args" a whole new dynamic utility.
The practical problem is either with the presumptive assumption that "ARGV must be a constant", or in optparse's own initialize method, which hard-codes the assignment of ARGV to the instance var #default_argv for subsequent processing -- that array (ARGV) really should be a parameter, encouraging re-parse and re-use, where appropriate. Proper parameterization, with an appropriate default (say, ARGV) would avoid the need to ever change the "constant" ARGV. Just some 2¢-worth of thoughts...

Confusing behaviour of const_get in Ruby?

According to the documentation mod.const_get(sym) "Returns the value of the named constant in mod."
I also know that const_get by default may look up the inheritance chain of the receiver. So the following works:
class A; HELLO = :hello; end
class B < A; end
B.const_get(:HELLO) #=> :hello
I also know that classes in Ruby subclass Object, so that you can use const_get to look up 'global' constants even though the receiver is a normal class:
class C; end
C.const_get(:Array) #=> Array
However, and this is where i'm confused -- modules do not subclass Object. So why can I still look up 'global' constants from a module using const_get? Why does the following work?
module M; end
M.const_get(:Array) #=> Array
If the documentation is correct - const_get simply looks up the constant defined under the receiver or its superclasses. But in the code immediately above, Object is not a superclass of M, so why is it possible to look up Array ?
Thanks
You are correct to be confused... The doc didn't state that Ruby makes a special case for lookup of constants in Modules and has been modified to state this explicitly. If the constant has not been found in the normal hierarchy, Ruby restarts the lookup from Object, as can be found in the source.
Constant lookup by itself can be bit confusing. Take the following example:
module M
Foo = :bar
module N
# Accessing Foo here is fine:
p Foo # => bar
end
end
module M::N
# Accessing Foo here isn't
p Foo # => uninitialized constant M::N::Foo
end
p M::N.const_get :Foo # => uninitialized constant M::N::Foo
In both places, though, accessing Object level constants like Array is fine (thank god!). What's going on is that Ruby maintains a list of "opened Module definitions". If a constant has an explicit scope, say LookHereOnly::Foo, then only LookHereOnly and its included modules will be searched. If no scope is specified (like Foo in the example above), Ruby will look through the opened module definitions to find the constant Foo: M::N, then M and finally Object. The topmost opened module definition is always Object.
So M::N.const_get :Foo is equivalent to accessing Foo when the opened classes are only M::N and Object, like in the last part of my example.
I hope I got this right, coz I'm still confused by constant lookups myself :-)
I came up with the following script to load name spaced constants:
def load_constant(name)
parts = name.split('::')
klass = Module.const_get(parts.shift)
klass = klass.const_get(parts.shift) until parts.empty?
klass
end
As long as we are not checking for errors you can:
def load_constant(name)
name.split('::').inject(Module) do |mod_path, mod_to_find|
mod_path.const_get(mod_to_find)
end
end

Detecting that a method was not overridden

Say, I have the following 2 classes:
class A
def a_method
end
end
class B < A
end
Is it possible to detect from within (an instance of) class B that method a_method is only defined in the superclass, thus not being overridden in B?
Update: the solution
While I have marked the answer of Chuck as "accepted", later Paolo Perrota made me realize that the solution can apparently be simpler, and it will probably work with earlier versions of Ruby, too.
Detecting if "a_method" is overridden in B:
B.instance_methods(false).include?("a_method")
And for class methods we use singleton_methods similarly:
B.singleton_methods(false).include?("a_class_method")
If you're using Ruby 1.8.7 or above, it's easy with Method#owner/UnboundMethod#owner.
class Module
def implements_instance_method(method_name)
instance_method(method_name).owner == self
rescue NameError
false
end
end
class A
def m1; end
def m2; end
end
class B < A
def m1; end
def m3; end
end
obj = B.new
methods_in_class = obj.class.instance_methods(false) # => ["m1", "m3"]
methods_in_superclass = obj.class.superclass.instance_methods(false) # => ["m2", "m1"]
methods_in_superclass - methods_in_class # => ["m2"]
you can always to the following and see if its defined there:
a = A.new
a.methods.include?(:method)
Given an object b which is an instance of B, you can test to see whether b's immediate superclass has a_method:
b.class.superclass.instance_methods.include? 'a_method'
Notice that the test is against the method name, not a symbol or a method object.
"thus not being overridden in B" - Just knowing that the method is only defined in A is difficult because you can define the method on an individual instances of A and B... so I think it's going to be difficult to test that a_method is only defined on A, because you'd have to round up all the subclasses and subinstances in the system and test them...

What is "main" in Ruby?

If I run this file as "ruby x.rb":
class X
end
x = X.new
What is the thing that is calling "X.new"?
Is it an object/process/etc?
Everything in Ruby occurs in the context of some object. The object at the top level is called "main". It's basically an instance of Object with the special property that any methods defined there are added as instance methods of Object (so they're available everywhere).
So we can make a script consisting entirely of:
puts object_id
#a = 'Look, I have instance variables!'
puts #a
and it will print "105640" and "Look, I have instance variables!".
It's not something you generally need to concern yourself with, but it is there.
The top-level caller is an object main, which is of class Object.
Try this ruby program:
p self
p self.class
It's the X class. You're invoking the method "new" that creates an object of class X. So, if you run this text as a script, Ruby:
creates a new class X which is a subclass of Object, and which automatically (as a subclass of Object) inherits some methods, of which new is one.
sets up a name x
calls the new method on that new class X, creating an X instance object; x gets a reference to that object.
It's the ruby interpreter running the line
x = X.new
As with many scripting languages, the script is interpreted from top to bottom rather than having a standard entry point method like most compiled languages.
As Charlie Martin said, X.new is a call to the constructor on the X class, which returns an object of type X, stored in variable x.
Based on your title, I think you're looking for a bit more. Ruby has no need for a main, it executes code in the order that it sees it. So dependencies must be included before they are called.
So your main is any procedural-style code that is written outside of a class or module definition.
main is the object in the context of which the top level code is executed. Which means that self at the top level refers to the main object:
$ ruby -e 'p self'
main
And that ruby follows the main's method lookup chain to determine which method to call:
$ ruby -e 'p singleton_class.ancestors'
[#<Class:#<Object:0x00007f9e9fdee230>>, Object, Kernel, BasicObject]
There could be more, but that's what you get from the get-go.
main itself is an instance of Object:
$ ruby -e 'p self.class'
Object
It has a singleton class with 2 methods (a method and an alias to be more precise):
$ ruby -e 'p singleton_class.instance_methods(false)'
[:inspect, :to_s]
$ ruby -e 'p singleton_methods'
[:inspect, :to_s]
It's defined here.
As you can see its to_s method returns "main" (overrides the Object's behavior), which is what you get when you do p self.
You can think that the code you execute is put into a main's method, after which the method is called. Along the lines of:
main = Object.new
class Object
def main.go
<your code here>
end
end
main.go
That is a rough idea. Let me justify it in a couple of steps.
In Ruby you can actually nest methods, but every time you call the outer method, the inner one gets defined/redefined. More importantly, it's defined as an instance method of the enclosing class:
class A
def m
def m2; end
end
end
A.new.m
p A.instance_methods(false) # [:m2, :m]
The same happens here, but the enclosing class in this case is the singleton class of A:
class A
class << self
def m
def m2; end
end
end
end
A.m
p A.singleton_class.instance_methods(false) # [:m2, :m]
And what if we use the def self.<name> notation?
class A
def self.m
def m2; end
end
end
A.m
p A.singleton_class.instance_methods(false) # [:m]
p A.instance_methods(false) # [:m2]
So, self. affects only m, m2 becomes an instance method of A.
Actually, instead of self there can be some random object:
o = Object.new
A = Class.new do
def o.m
def m2; end
end
end
o.m
p o.singleton_class.instance_methods(false) # [:m]
p A.instance_methods(false) # [:m2]
I had to use Class.new because with class o wouldn't be visible inside the class definition.
Or actually I hadn't:
class A
o = Object.new
def o.m
def m2; end
end
o.m
p o.singleton_class.instance_methods(false) # [:m]
p A.instance_methods(false) # [:m2]
end
But let's ignore this branch of thought.
A couple of changes and you get this:
main = Object.new
Object.class_eval do
def main.go
#a = 1
def m2
puts #a
end
m2 # 1
end
end
main.go
p Object.instance_methods(false) # [:m2]
p main.instance_variables # [:#a]
I had to use class_eval for it to not complain that I'm trying to redefine the Object constant.
You can also add:
def main.to_s
"main"
end
main.instance_eval { alias inspect to_s }
for completeness.
Another way is to use global variables:
$main = Object.new
class Object
def $main.go
#a = 1
def m2
puts #a
end
m2 # 1
end
end
$main.go
p Object.instance_methods(false) # [:m2]
p $main.instance_variables # [:#a]
Of course variables main/$main and the go method don't exist. But no more flaws come to mind when I think about this idea. The idea that it works as if your code is put into a main's method and executed by running the method.
Also this kind of explains why methods defined at the top level are visible everywhere:
a.rb:
f
$ ruby -e 'def f; puts "f"; end; require "./a"'
f
Because they become instance methods of Object.
And you can use instance variables, which are instance variables of the main object.
UPD I noticed that you can't define constants (in the usualy way), classes and modules in main.go. So the abstraction appears to be leaky. I might try to amend it:
Object.class_eval do
<your constants, classes, modules, methods>
def main.go
<the rest of the code>
end
end
But at this point I'd rather say, that at the top level self points to the main object, and the current class reference to the Object class. More on class references here.

Resources