I'm new to rspec. The following syntax is confusing:
describe MyClass::Something do
What does Something refer to? The rspec tests I'm looking over contain the above line. However MyClass doesn't contain anything related to Something.
You are confused by Ruby syntax, not RSpec syntax. MyClass is a module, and Something is a class or module inside the MyClass module. The :: is the scope resolution operator to tell Ruby which Something you are looking for.
module Foo
class Bar
def say_hello
puts "hello"
end
end
end
foo = Foo::Bar.new
foo.say_hello
#prints "hello"
See http://ruby-doc.org/docs/ProgrammingRuby/html/tut_modules.html for more on modules.
This is not related to Rspec. The answer you are seeking is that Something is an inner class or module within MyClass. Something refers to a class/module named Something within the class/module MyClass. Here is an example:
class MyClass
module Something
end
end
Related
Apologies if this has been asked before (I couldnt find it) but once I declare a class in Ruby using IRB, after several lines of additional code, is there any way of viewing a specific class and what it contains later on? I am looking to add a function to an existing class, and need to call the class in order to see what it contains? In addition, if there is no functionality in IRB, is there in PRY?
You can use show-source method in pry:
class Foo
def a
end
end
show-source Foo
or its shortcut $:
$ Foo
Outputs:
class Foo
def a
end
end
I have two classes. I want to namespace them. I also have a bit of functionality that they share. I do something like this:
module Talker
def say_bye
puts 'bye'
end
class Bob
include Talker
def say_yo
puts 'yo'
end
end
class Tom
include Talker
def say_hello
puts 'hello'
end
end
end
These are all valid method calls.
Talker::Bob.new.say_yo
Talker::Bob.new.say_bye
Talker::Tom.new.say_hello
Talker::Tom.new.say_bye
I was told: "This include is going to include Bob again. You should close the Talker module before starting a class that includes Talker." Can somebody explain to me if I'm doing something that results in unexpected ruby behavior or is considered taboo? Is it a bad practice to include a module like this from inside a class within that module? What might be a criticism for this pattern? Should I use inheritance here?
I figured it out. The include ends up being somewhat recursive. The code above will do things like this:
Talker::Bob::Bob
Talker::Bob::Tom
Talker::Bob::Bob::Bob::Tom::Bob::Tom
And that is not something to have. So he was right when he said it would re-include the other classes in the module into each class that includes the module.
Given this example:
module A
module B
def foo
puts 'foo'
end
extend A::B
end
end
What does this extend A::B do?
It extends module A::B with itself, essentially make method foo available on module object A::B itself.
Without that line, you are not able to call A::B.foo in your code.
You may want to read more on Ruby extend aModule vs include aModule.
I have a module with a class variable in it
module Abc
##variable = "huhu"
def self.get_variable
##variable
end
class Hello
def hola
puts Abc.get_variable
end
end
end
a = Abc::Hello.new
a.hola
Is it possible to get ##variable inside Hello without using get_variable method? I mean something like Abc.variable would be nice. Just curious.
You cannot access ##variable directly (i.e., Abc.variable) within the scope of the Hello class in the module Abc. Why? Because, when the Ruby interpreter sees something like Abc.variable, it would think variable as class/module method of Abc.
It is important to think the Ruby way when programming in Ruby.
try this
Abc.class_variable_get(:variable)
What I'm trying to find out is whether there is some sort of equivalence to what I see in Groovy as ExpandoMetaClasses. I've been reading about Open Classes but I can't quite see what level of scoping Ruby allows of the class modifications.
Borrowing an example from the blog above, in Groovy, I could modify Java's String class and add a method to it like so:
String.metaClass.shout = {->
return delegate.toUpperCase()
}
println "Hello MetaProgramming".shout()
// output
// HELLO METAPROGRAMMING
And I think that Ruby would have you redefine the class and possibly alias it (please help clarify my misunderstandings at this point):
class String
def foo
"foo"
end
end
puts "".foo # prints "foo"
In Groovy, there are ways to scope the redefinition of core Java library methods to single instances or to a group of instances using Categories, which feel similar to what I would define as mixins in Ruby.
What are the ways to scope open classes to specific instances or to subsets of modules?
If I were to install a gem that had redefined some core class, would only that module be affected, or would any .rb file I include that gem with be affected with it?
Apologies in advance for making some possible assumptions on both Ruby and Groovy, I'm new to both but have been trying to find equivalence between the two.
Ruby's classes are never "closed". So when you say:
class String
def omg!
self.replace "OMG"
end
end
You are defining the omg! method on the String class. Unlike in Groovy, which requires the usage of a special metaclass concept, Ruby classes are always open, period.
If you wanted to modify a particular set of Strings, you could do this:
module Magic
def presto
puts "OMG A HAT!"
end
end
class Array
include Magic
end
x = "Hello".extend(Magic)
puts x #=> Hello
x.presto #=> OMG A HAT!
[].presto #=> OMG A HAT!
def x.really?
true
end
x.really? #=> true
Effectively, a module is a collection of methods that can be added to a class or specific instances.
So you can either open a class directly or add new methods to a class using a module. You can also open an instance directly or add new methods to an instance using a module. That's because a class is just an instance of Class ;) Pretty nifty!
In addition to what Yehuda said, instances in Ruby also have metaclasses (technically called "singleton classes"), accessed with class <<whatever. For example, to redo Yehuda's Magic example with a singleton class:
x = "Hello"
class <<x
include Magic
def magical?
true
end
end
x.presto #=> OMG A HAT!
x.magical? #=> true
"Something else".magical? #=> NoMethodError
There's no scoping on modifications to classes. As soon as a class is modified, the modified class is accessible to all later requires and following code.