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
Related
I am trying to understand concepts of including or inheriting a module inside a class. Whenever I read i get new ways to include or inherit a module inside a class. So just want to know how many ways are there. Here are the examples I am sharing:
Example 1
module TimeExtensions
refine Fixnum do
def minutes; self * 60; end
end
end
class MyApp
using TimeExtensions
def initialize
p 2.minutes
end
end
Example 2
VAL = 'Global'
module Foo
VAL = 'Foo Local'
class Bar
def value1
VAL
end
end
end
class Foo::Bar
def value2
VAL
end
end
Example 3
module Foo
def foo
puts 'heyyyyoooo!'
end
end
class Bar
include Foo
end
Out of the three, only the last one includes a module into the class. That is, it adds the methods from the module to the class.
The first one is called refinement. If instead of refining Fixnum you just added a #minutes method to it, Fixnum will have that method for everyone that uses it, as long as your code is loaded. This might cause conflicts with other implementations of the same method (for example active record's #minutes) and leads to obscure, hard to debug issues. Instead, you can refine the Fixnum class and it will have that method only in the scope where you added the refinement with using.
It has some issues and it's not very widely used. But for the purposes of this question, the differences between including a module and using a refinement are:
including will add methods to the class where you do the inclusion, while refinements make other classes behave differently in the context where they are used
including is semantical (all objects will have the new included methods), while refinements are lexical (after you close the class, if you reopen it again, you won't see the refined methods)
The second one is scoping the class inside the module. This doesn't add methods anywhere. It is just due to the way constants are searched that if the constant (in this case VAL) isn't found in the current class, it is searched further up the tree. It's not that simple actually, if you want more details, you can read here.
In the description on the left side panel, it says,
"The demo code we're about to show you includes a fancy trick: if you want to end a Ruby statement without going to a new line, you can just type a semicolon. This is a time saver when you're writing something very short, like an empty class or method definition."
Why would we wan to make an empty class? Why wouldn't we just leave it blank?
Thanks for any clarification.
You may want a custom error class that does nothing special except use its name to convey something:
class MySpecialError < Error; end
Or you may want to start by declaring a class and then tack on your functionality later (no problem with that because ruby classes are dynamic):
class Foo; end
def Foo.frobnicate; "something" ; end
Though in ruby, you could just as well do
Foo = Class.new
(The difference is that class Foo; end won't clear an already existing Foo class, whereas with Class.new you're starting from scratch).
Is it possible to remove some of the inherited methods in Ruby? I mean, I can override it, but is there any other way?
Class ABC
end
a = ABC.new
puts a.id
Here, the method id is inherited from Object along with other methods like tap,class,type etc. I want to remove such methods.
Edit: I'm using Ruby 1.8.7
Yes - undef_method :foo will prevent any calls to the method foo (contrasted with remove_method :foo, which removes the method from the child, but still passes through up the inheritance chain).
Once again, though, why do you want to remove things like id?
You can always create a blank slate class to derive from:
class BlankSlate
instance_methods.each do |m|
undef_method(m) unless (m.match(/^__/))
end
end
This should strip out all methods except for the internal ones that you're not supposed to mess with, like __send__.
As tadman said you can make a BlankSlate object, or in ruby 1.9, there is the BasicObject class that has a bare minimum of methods. A quick google search turned up this for further reading: http://www.humbug.in/docs/ruby-best-practices/I_sect13_d1e2654.html
It appears that Rails already has BlankSlate built in: http://rubydoc.info/docs/rails/2.3.8/BlankSlate
I want to add a foo method to Ruby's Kernel module, so I can write foo(obj) anywhere and have it do something to obj. Sometimes I want a class to override foo, so I do this:
module Kernel
private # important; this is what Ruby does for commands like 'puts', etc.
def foo x
if x.respond_to? :foo
x.foo # use overwritten method.
else
# do something to x.
end
end
end
this is good, and works. but, what if I want to use the default Kernel::foo in some other object that overwrites foo? Since I've got an instance method foo, I've lost the original binding to Kernel::foo.
class Bar
def foo # override behaviour of Kernel::foo for Bar objects.
foo(3) # calls Bar::foo, not the desired call of Kernel::foo.
Kernel::foo(3) # can't call Kernel::foo because it's private.
# question: how do I call Kernel::foo on 3?
end
end
Is there any clean way to get around this? I'd rather not have two different names, and I definitely don't want to make Kernel::foo public.
You can use the super keyword to call the superclass's implementation from a overridden method.
class Bar
def foo # override behaviour of Kernel::foo for Bar objects.
super
# do something else here
end
end
For a more general solution than just super (super wont always work), also see this thread:
How to access a shadowed global function in Ruby?
Just use alias or alias_method before you redefine Kernel.foo to keep a reference to the original version.
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.