As I'm reading different Ruby books, I've noticed that Ruby classes can be defined within other Ruby classes or modules. Here's an example of a class within a class:
class Outerclass
def foobar
puts "FOOBAR"
end
class Innerclass
def barfoo
puts "BARFOO"
end
end
end
Here's some code that I ran in IRB to try to understand this conceptually:
oc = Outerclass.new # => #<Outerclass:0x00000100a46478>
Outerclass.instance_methods(false) # => [:foobar]
ic = Outerclass::Innerclass.new # => #<Outerclass::Innerclass:0x00000100a0b120>
ic = Outerclass::Innerclass.instance_methods(false) # => [:barfoo]
Here are my questions:
When the ruby interpreter first encounters my Class definition code above, does it go through the methods I've written and store it somewhere? I know that the instance method "foobar" doesn't actually get run since there's no call being made to it within the Outerclass definition.
Piggybacking off the 1st question, what about when Ruby encounters the class Innerclass? What happens here?
In general, what are some reasons why you would want to have classes within classes? Are there any advantages to doing this?
Does an instance of Outerclass know anything about the class Innerclass?
Does an instance of Innerclass know anything about the class Outerclass?
Appreciate any help you can provide!
When the interpreter is going through this file, it is assigning classes like this:
OuterClass = Class.new do
def foobar
puts "FOOBAR"
end
InnerClass = Class.new do
def barfoo
puts "BARFOO"
end
end
end
So when Ruby encounters the nested class, it assigns it to constant InnerClass which is assigned to constant OuterClass They have no relation to each other whatsoever.
The InnerClass has no inheritance to OuterClass:
InnerClass.ancestors
=> [InnerClass, Object, Kernel, BasicObject]
When you call OuterClass::InnerClass constant you are refering to the InnerClass constant that is namespaced under the OuterClass contstant which equals the Class.new statement assigned to it.
A good book to read about this is "Metaprogramming Ruby". It goes into the details of classes, singletons, modules etc.
Jörg W Mittag put it best in his comment on Michael Papile's answer:
There is no inner and outer class. There are just two completely and utterly unrelated classes. One just happens to be assigned to a constant namespaced inside the other.
Related
How can I find out the constructs (methods, constants, etc.) defined in a module?
Let's say there's require 'observer', and I would like to see all that are defined within 'observer'. How can I?
Short answer: You can't, not with absolute certainty.
Long answer: This a product of how Ruby is a very dynamic language at its core and imposes almost no constraints on what a require statement might do. Any number of modules and classes can be created by a library, and there's no requirement for these to be grouped together neatly.
Even if you go through the trouble of taking a snapshot of all defined classes and methods before you require it, and then another one after to find out what's been added there's no assurance you've captured them all. Some classes might be loaded or defined well after the require statement is finished.
The best way to find out is to read through the source. There you'll see all the different modules and classes that could be defined even if they're not triggered by your code.
Reflection tools like methods help to a degree, but it's also highly misleading. Methods can be defined at a later point in time, you may need to exercise the code more thoroughly for them to show up.
If you use pry, simply do ls ModuleName
ls shows all the available methods and instance variables of a certain module or class or instance. More about pry: http://pryrepl.org/
Or you can do
ModuleName.instance_methods to get instance_methods
ModuleName.instance_variables to get instance_variables
As another answer state, it's almost impossible (still doable in a brittle way) to get a full picture of what you require by just an arbitrary require
imo, this kind of implementation itself is brittle and prone to error, unless its your own module and you have full control of the API. But still not a good idea.
If I do not understand the question wrong.
You can do like this, to read the property of Module.
Example:
1st Version:
require "nokogiri"
p Nokogiri.methods # It will print for you all methods in that Module,
# also available methods from ruby.
2nd Version
x = require "nokogiri"
p x.methods #available methods there private, public, protected methods and etc...
p x.private_methods # prints bunch of private methods, [:Nokogiri]
You want to execute Observer methods from outside the module you wish to examine. Here is an example of what you might do.
module Observer
def self.show_all(mod)
puts "owner of methods = #{mod.methods(false)}"
puts "owner of instance methods = #{mod.instance_methods(false)}"
puts "instance variables = #{mod.instance_variables}"
puts "ancestors = #{mod.ancestors}"
puts "included modules = #{mod.included_modules}"
end
end
module A
module B
include Comparable
#a = 1
def self.b; end
def c; end
module C
end
end
end
Observer.show_all(A::B)
# owner of methods = [:b]
# owner of instance methods = [:c]
# instance variables = [:#a]
# ancestors = [A::B, Comparable]
# included modules = [Comparable]
class D; end
class E<D; end
class F<E
include Comparable
#a = 1
def self.e; end
def f; end
end
Observer.show_all(F)
# owner of methods = [:e]
# owner of instance methods = [:f]
# instance variables = [:#a]
# ancestors = [F, Comparable, E, D, Object, Kernel, BasicObject]
# included modules = [Comparable, Kernel]
I am really confused why the methods in modules B and C are mixed in to the class in module A when I use include C. Does include somehow recursively mix in with all classes below the namespace where it is called?
module A
class AClass
def a_method_
end
end
end
module B
extend self
def b_method_
end
end
module C
extend self
include B
def c_method_
puts A::AClass.new.methods.grep /_method_/
end
end
C.c_method_
puts "----"
include C
c_method_
With the result that before the include, the AClass instance correctly only has method a_method_, but after the include it has access to the other two methods as well.
a_method_
----
a_method_
c_method_
b_method_
Can someone please help explain this?
If you change the tail end of your code to this:
C.c_method_
puts self.inspect
puts "----"
include C
c_method_
you should help you see what's going on. That will give you this output:
a_method_
main
----
a_method_
c_method_
b_method_
So what is this main business? Chuck has a nice summary over in this answer:
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).
That means that saying this at the top level:
include C
is the same as saying:
Object.send(:include, C)
Adding things to Object pollutes everything.
You might find this illuminating:
puts Object.instance_methods.grep /_method_/
# c_method_
# b_method_
Your methods have been added to everything, not just AClass! And to really demonstrate the weirdness, try changing that last bit to:
class D
include C
puts Object.instance_methods.grep /_method_/
end
No more output! You've stumbled upon one of the weird, intentional behaviors of Ruby's main (the implicit receiver when nothing else is specified). The basic motivation is that if you define a method in main, you want to be able to call it anywhere:
def foo
end
# now all of these work:
class A
foo
end
module B
foo
end
A.new.instance_eval { foo }
A.singleton_class.class_eval { foo }
This isn't about scope resolution either; if you change that to foo = :bar you'll get NameErrors. This is for stuff like puts and gets where you generally don't care who the receiver is when you call them. But this behavior doesn't jive at all with Ruby's object model, so matz hacked it in: every method defined in main gets added to Object as an instance method. Since everything is an object, the rest works as expected.
I know there are "instance methods", "class methods" but what are these types of methods called, for eg:
s1 = "This is my STRING!"
def s1.m1
downcase
end
p s1 # => "This is my STRING!"
p s1.m1 # => "this is my string!"
What type of method is the "m1" method called on the s1 "instance" of the "string" class? It's really weird because I didn't know this was possible at all if I try:
s2 = "This is ANOTHER string"
s2.m1 # => Won't work!
Which kind of makes sense, but not sure why defining methods like m1 on instances on a class are useful at all.
They are called singleton methods, and can be defined as follows:
class Person
def favorite_meal
"Big Mac"
end
end
Fred, Joe = 2.times.map { Person.new }
def Fred.favorite_meal
"Le Big Mac"
end
Joe.favorite_meal #=> Big Mac
Fred.favorite_meal #=> Le Big Mac
Other ways to define the same singleton method would be:
Fred.define_singleton_method :favorite_meal do "Le Big Mac" end
And:
class << Fred
def favorite_meal
"Le Big Mac"
end
end
May the force be with you.
UPDATE: Answering the 2 questions from the comment.
Let me start by the 2nd one. It is up to you, whether you use a constant or a variable. It is perfectly OK to write fred = Person.new. But:
Objects with distinct properties often deserve proper names, which are properly capialized.
There is a useful gem I wrote, y_support/name_magic, that works by assigning to constants.
Install it by gem install y_support, and try:
require 'y_support/name_magic'
class Dog
include NameMagic
def speak; puts "Bow wow!" end
end
Spot, Rover = 2.times.map { Dog.new }
Now the Dog class knows its instances, and the instances know their names.
Dog.instances.map { |dog| dog.name } #=> :Spot, :Rover
Dog.instances.names # the simpler way to say the same
This is not useful in this particular example (and extremely useful elsewhere), but in any case, it gave me a habit of giving objects with personalities capitlized proper names.
As for the 1st question, def Fred.foobar is the most basic, one-off singleton method definition. If you want to define several singleton methods, or alias, or include a module in the singleton class, use class << Fred:
module Foo
def bar; "Fretbar!" end
end
class << Fred
include Foo
alias le_favorite favorite_meal
end
Fred.bar #=> Fretbar!
Fred.le_favorite #=> "Le Big Mac"
The most advanced things are possible with Fred.define_singleton_method syntax, and with the 4th way, which I have not mentioned earlier:
local_var = 42
Fred.singleton_class.class_exec do
define_method :baz do local_var + 1 end
end
Fred.baz #=> 43
This way uses closures, which retain binding to the variable local_var. Try it out
local_var = 32
Fred.baz #=> 33
So this is what's special about the syntax with closures, and it is often a godsend that magically solves nasty programming problems.
They are called object Singleton Methods.
A example i can think of where you could use that:
You have a special logging class and you have to limit the logging to only one instance because you want your logging file to be clean and tidy.
Maybe not the best example, but if your interested in the use cases, look for use cases for the Singleton Pattern and you should find your answers there.
They are called singleton method. Here is some way to check those:
s1 = "This is my STRING!"
def s1.m1
downcase
end
klass= s1.singleton_class # => #<Class:#<String:0x902d4e8>>
klass.instance_methods(false) # => [:m1]
s1.method(:m1).owner # => #<Class:#<String:0x902d4e8>>
s1.singleton_methods # => [:m1]
but not sure why defining methods like m1 on instances on a class are useful at all.
These singleton method(m1) can only be called only by s1,as you defined it inside the singleton class of s1. But not by any other instances of the String class. These are needed when you are having some behaviors that are unique to the object,irrespective of the fact that,if they are belonging to the same class or different class(s).
s2.m1 # => Won't work!
Because you didn't define it inside the singleton class of s1.
"(...)but not sure why defining methods like m1 on instances on a class are useful at all."
It makes this behaviour possible:
class Test
def self.some_meth
end
end
Test is just an instance of Class, and some_method is added to this specific instance.
p Test.singleton_methods #=> [:some_meth]
Im reading Metaprogramming in Ruby.
Here are two code snippets from the book:
my_var = "Success"
MyClass = Class.new do
puts "#{my_var} in the class definition!"
define_method :my_method do
puts "#{my_var} in the method!"
end
end
MyClass.new.my_method
⇒ Success in the class definition!
Success in the method!
and:
def define_methods
shared = 0
Kernel.send :define_method, :counter do
shared
end
Kernel.send :define_method, :inc do |x|
shared += x
end
end
define_methods
counter # => 0
inc(4)
counter # => 4
I wonder why one doesnt have to use dynamic dispatch (use of Kernel.send) when defining the method in the first example while one has to use it in the second example.
I given it some thoughts but cant understand it.
Thanks!
Module#define_method is private. Private methods can only be called without a receiver. So, in the second example, you need to use reflection (i.e. send) to circumvent the access restrictions.
Note that the first example still uses dynamic dispatch. In fact, in Ruby, everything (except variable access and some builtin operators) uses dynamic dispatch.
Contrary to what the book says, it works without Kernel.send, you just need a context where the class for self is including Kernel - which is almost always the case.
for example, if you do this in the main scope, it's there:
irb(main):024:0> self.class.ancestors
=> [Object, Kernel, BasicObject]
So, using
define_method :counter do
shared
end
works fine.
You only need that trick if within the current context Kernel is not included, e.g. if you're inside a plain BasicObject, or some user created descendant class.
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