I would like to know how to remove the method Kernel.Array.rand. When the user tries to call it, it should give an error; any kind of error would do.
I tried as below. I tried Kernel.Array and Kernel::Array instead of Random, but they did not work too.
class << Random; self; end.send :remove_method, :rand
Using my IRB I saw that:
2.0.0-p195 :028 > Kernel.Array.rand
ArgumentError: wrong number of arguments (0 for 1)
from (irb):28:in `Array'
from (irb):28
And was even available in the autocomplete with tab.
Tried the rand because was necessary to avoid any use of random method. So I need to remove also sample and shuffle from the Array.
But look what I get:
class << Array; self; end.send :remove_method, :sample
NameError: method `sample' not defined in Class
from (irb):31:in `remove_method'
from (irb):31
So, I would still know how to remove a method from the Array, in that case should be related to the Kernel.Array.
You can use undef_method (the difference with remove_method is that undef_method will walk up the inheritance chain)
rand # => 0.3417719504956065
Kernel.send :undef_method, :rand # private method, have to use `send`
rand # ~> -:5:in `<main>': undefined local variable or method `rand' for main:Object (NameError)
Update
Ah, you are confused. There is a Kernel::Array method, which is completely different from Array the class. Also, there's no need to obfuscate your code with those eigenclass constructs. You can do simply this:
module Kernel
undef_method :rand
end
class Array
undef_method :sample
end
rand # ~> -:9:in `<main>': undefined local variable or method `rand' for main:Object (NameError)
[1, 2].sample # ~> -:10:in `<main>': undefined method `sample' for [1, 2]:Array (NoMethodError)
Related
Why can't we initialize TrueClass in Ruby? I get this:
TrueClass.new # => NoMethodError: undefined method `new' for TrueClass:Class
But, superclass of TrueClass is Object.
Similarly we are unable to initialize NilClass and FalseClass
I just wanted to know how that is possible even if that is the child class of Object. If we wanted to write a class similar to this how can we achieve it?
I just wanted to know how that is possible even if that is the child class of Object. If we wanted to write a class similar to this how can we achieve it?
You can undefine inherited methods using the undef keyword. Since new is a class method, you'll have to use undef inside the class's singleton class. That would look like this:
class <<MyClass
undef new
end
MyClass.new # NoMethodError: undefined method `new' for MyClass:Class
I just wanted to know how that is possible even if that is the child class of Object.
It works by undefining allocate and new. Here's the corresponding C code:
rb_undef_alloc_func(rb_cTrueClass);
rb_undef_method(CLASS_OF(rb_cTrueClass), "new");
You can achieve a similar result in Ruby via undef_method:
class FooClass
::FOO = new # <- this will be the only Foo instance
class << self
undef_method :allocate
undef_method :new
end
end
FooClass.new #=> NoMethodError: undefined method `new' for FooClass:Class
FooClass.allocate #=> NoMethodError: undefined method `allocate' for FooClass:Class
FOO #=> #<FooClass:0x007fddc284c478>
"similar", because TrueClass.allocate doesn't actually raise a NoMethodError, but a TypeError:
TrueClass.allocate #=> TypeError: allocator undefined for TrueClass
Unfortunately, rb_undef_alloc_func is not available from within Ruby. We could mimic the behavior by overriding allocate:
class FooClass
class << self
def allocate
raise TypeError, "allocator undefined for #{self}"
end
undef_method :new
end
end
FooClass.allocate #=> TypeError: allocator undefined for FooClass
Not sure, which approach is cleaner.
The above changes prevent you from creating an instance via new, but there are other ways:
FOO #=> #<FooClass:0x007fddc284c478>
FOO.dup #=> #<FooClass:0x007fad721122c8>
FOO.clone #=> #<FooClass:0x007f83bc157ba0>
Marshal.load(Marshal.dump(FOO)) #=> #<FooClass:0x007f83bc13e330>
To account for all these special cases, Ruby' stdlib provides the Singleton module:
require 'singleton'
class Foo
include Singleton
end
It works by making allocate and new private methods: (among other changes)
Foo.new #=> NoMethodError: private method `new' called for Foo:Class
Foo.allocate #=> NoMethodError: private method `new' called for
And it adds instance which returns an instance: (or the instance, there's only one)
Foo.instance #=> #<Foo:0x007fdca11117e8>
Imagine I want to write my own math operators like "+"
The simple version would be:
def plus(a,b)
return a+b
end
But this is not what the real "+" does.
I want 3.add(4) # =>7
But how do I tell ruby to take the object that I used my method on?
I tried
def add(c)
return self+c
end
But I get the error message:
:in <main>': private methodadd' called for 3:Fixnum (NoMethodError)
The problem
You defined the method:
def add(c)
return self + c
end
and attempted to use it thus:
3.add(4) #=> NoMethodError: private method `add' called for 3:Fixnum
Understanding this error message
This error message tells you exactly what the problem is. I think your problem is simply that you don't understand how Ruby invokes methods on objects.
When Ruby sees 3.add(4) it first looks at the receiver, 3, and determines:
3.class #=> Fixnum
This tells it where the method add is defined: in the class Fixnum or in one of Fixnum's ancestor's classes or modules.
So it looks for it there, doesn't find it, and issues an error message. We can confirm it's not there:
Fixnum.instance_methods.include?(:add)
#=> false
So where is add defined?
You did define it, though, so where is it? Let's find out:
method(:add).owner
#=> Object
Object.instance_methods.include?(:add)
#=> false
Object.instance_methods returns an array of all of public instance methods defined on Object and Object's ancestors. add is not among those, so we conclude add is a protected or private method:
Object.protected_instance_methods.include?(:add)
#=> false
Object.private_instance_methods.include?(:add)
#=> true
Let's try invoking that method on an instance of Object:
Object.new.add(4)
#=> NoMethodError:
# private method `add' called for #<Object:0x007fdb6a27fa68>
That makes sense, considering that Object#add is private. We can, however invoke private methods with Object#send:
Object.new.send(:add,4)
#NoMethodError: undefined method `+' for #<Object:0x007fdb6a28e068>
As an exercise, make sure you understand the steps Ruby took that led to her raising this exception (that the instance method + is not defined on Object, or equivalently, that the instance of Object does not have a method +).
By the way, where did you define add? By that, I mean what what was the value of self when you defined it? Let's see:
self #=> main
self.class #=> Object
We see that add must be defined on the class for which its receiver is an instance. (A mouthful, yes, but it's important, so make sure you understand that).
Why is Object#add private rather than public?
Consider:
def greet
puts 'hi'
end
class A
end
A.private_instance_methods.include?(:add)
#=> true
A.new.send(:greet)
#=> 'hi'
The is because A inherits greet from Object:
A.ancestors.include?(Object) #=> true
If Object#greet were public, every built-in class and every class you define would have a public instance method greet. That would result in a great deal of misery. (Suppose you had a method great and mistyped it greet!) Even the private greet could cause trouble.)
Where should add be defined?
Since add.class => Fixnum, we define it thus:
class Fixnum
def add(other)
self + other
end
end
Fixnum.instance_methods.include?(:add) #=> true
3.add(4) #=> 7
Had I included the line puts "self#{self}" after class Fixnum it would have printed "Fixnum". Salting your code with puts statements that show the value of self often helps in understanding what's going on.
One last thing:
method(:add).owner
#=> NameError: undefined method `add' for class `Object'
Why did this not return Fixnum? Since method has no explicit receiver (i.e., no xx.method), Ruby assumes the receiver to be self, which here is:
self #=> main
so she looks for the method method in self.class => Object, and you know what she finds (or, I should say, doesn't find). Instead, we need to write:
Fixnum.instance_method(:add).owner #=> Fixnum
or
3.method(:add).owner #=> Fixnum
Here 3 can of course be replaced by any instance of Fixnum.
Note I've simplified this explanation somewhat. In searching for a method, Ruby also looks in the receiver's singleton class. This is not an issue for immediate objects (numbers, symbols, true, false and nil), however, as they do not have singleton classes:
3.singleton_class #=> TypeError: can't define singleton
By contrast, for example:
[1,2].singleton_class #=> #<Class:#<Array:0x007fbcf18c01a8>>
The plus-sign (+) in ruby can be overridden pretty much like any other method (you can look for operator-overloading):
class MyOperator
attr_accessor :text
def initialize(text)
#text = text
end
def +(operand)
"#{self.text} #{operand.text}"
end
def to_s
self.text
end
end
a = MyOperator.new "Hello"
b = MyOperator.new "World"
puts (a+b)
So there is not much magic to it. But you have to be careful if the overloading the operators make sense in your context.
I'm trying to use reflective methods in Ruby, and running into a behavior that I find really surpising.
The following examples seems to work differently in IRB and when called a ruby script:
Example 1:
def myfun; end
p respond_to?(:myfun)
In IRb, this says 'true',
In script: 'false'.
Example 2:
ml = methods
def myfun; end
p methods - ml
In IRb, this says [:myfun].
In script: [].
I found this under 1.8, 1.9 MRI, JRuby 1.5.6, etc - so I assume this is normal.
Why is the difference?
I was pretty sure 'respond_to?' is the way to see if a method is available - why is that not working in the above case?
This function - method on "main" object - is defined as private in ruby script.
You can check this easily:
ml = private_methods
def myfun; end
p private_methods - ml #=> [:myfun]
p respond_to?(:myfun, true) #=> true
If you call it explicitly on self you will get an error:
self.myfun
# NoMethodError: private method ‘myfun’ called for main:Object
On the other hand, in IRB your method is defined as public. Under the hood it looks something like this:
class Object
def irb_binding
# this is where your entered code is evaluated
def myfun; :ok; end # you can define methods in other methods
self.myfun # and they are public by default
end
end
p irb_binding # :ok
IRB could easily evaluate at the top level but instead it creates a separate environment with the method so that local variables are not shared:
require "irb"
foo = :ok
IRB.start
#>> foo
# NameError: undefined local variable or method `foo' for main:Object
I think methods being public is just a coincidence due to the implementation and it doesn't matter much. These methods are temporary anyway.
I have a variable lets call it #foo. I expect it to be a string so I call #foo.downcase. Sometimes it's nil and i'll get this error:
NoMethodError: undefined method `downcase' for nil:NilClass
from (irb):4
from /Users/schneems/.rvm/rubies/ruby-1.9.2-p290/bin/irb:16:in `<main>
What I want to do is write some code to tell me that nil is actually #foo
NoMethodError: undefined method `downcase' on variable #foo, variable is a nil:NilClass
from (irb):4
from /Users/schneems/.rvm/rubies/ruby-1.9.2-p290/bin/irb:16:in `<main>
To do something like this, I would need to get the name of the variable programatically.
Question: Is it possible to get the name of a variable programmatically ruby?
I'm looking for something that produces an output like this:
#foo.magical_variable_method #=> '#foo'
bar.magical_variable_method #=> 'bar'
AweSome.magical_variable_method #=> 'AweSome'
$wat.magical_variable_method #=> '$wat'
I don't want the value of the variable, nor do i care if it is nil. I want the human readable name of the variable. Is it possible to get the name of a variable programmatically ruby?
What you want is kinda mess.
Here's proper way for this task:
#foo && #foo.downcase
Or you could use rails library:
require 'active_support'
#foo.try(:downcase)
There isn't currently any way to do this.
Variables are just references, not objects themselves. If you use dot notation to call a method, like downcase, that method is operating on an object, not a variable. And the object in your example is the singleton nil; if nil in one place were to have a property assigned to it naming the variable it was assigned to, that same property would apply to all nils.
Even more generally, one object may have many variables/references pointing to it, so there would be no good way of determining which variable name should be saved in the object. However, there is some sort of special treatment in Ruby for assigning a class to a constant; in that case, the class object does remember the name of the first constant it's assigned to, e.g.:
$ irb
1.9.3p194 :001 > Foo = Class.new do
1.9.3p194 :002 > attr_accessor :foo
1.9.3p194 :003?> end
=> Foo
1.9.3p194 :004 > Bar = Foo
=> Foo
1.9.3p194 :005 > Foo.name
=> "Foo"
1.9.3p194 :006 > Bar.name
=> "Foo"
You can get the instance variable from the symbol with instance_variable_get(:#foo)
which would just give you the value.
But you could do this:
puts "I'm gonna call #foo now, people"
some_obj.instance_variable_get(:#foo)
You could also do a method_missing hook for the attrs you wanted to watch. Don't create accessor methods for #foo and catch the call in method_missing and forward it to some generic implementation such as instance_variable_get
Untested attempt:
def method_missing(method_name, *args)
super(method_name, *args) unless watched_attributes.include?(method_name)
attr = ":##{method_name.to_str}"
log.debug "Calling watched attribute #{attr}"
val = instance_variable_get(method_name)
log.debug "#{attr} was nil omg!" unless val
val
end
Edit: Probably the best way (see mu's comment) is to just make sure you're working with a string:
#foo.to_s.downcase
You don't need to get the "name" to do this. You can just use a conditional:
# Downcased if #foo's a string, empty string otherwise:
(String === #foo)? #foo.downcase : ''
Or, if you're going to be doing this in lots of places, and don't want to have to wrap each one in a conditional, monkey-patch NilClass and add a dummy downcase method:
class NilClass
def downcase
return ''
end
end
Hope that helps!
When answering another question, I realized that the following program does not quite do what I thought it does.
puts "test"
self.puts "test" # => private method `puts' called for main:Object (NoMethodError)
The exception surprises me, as I always thought that top-level method calls would be resolved by the main object instance, but this doesn't seem to be the case.
Who's the actual receiver of the first call and how is it resolved? Is this a special rule that only applies to method calls at the top-level scope?
Here is a good discussion that talks about this question.
The top level methods, which are provided by Kernel, are automatically included to the Object class. This means the Kernel methods will appear in everything.
The error private method 'puts' called for main:Object (NoMethodError) is just stating that puts exists but is privately scoped.
ree-1.8.7-2011.03 :001 > puts "test"
test
ree-1.8.7-2011.03 :004 > self.send(:puts, "hi" )
hi
UPDATE
There is no magic for Kernel methods. There is no scope hopping or anything. I think the confusion lines in what the scope is when using self. You do not have access to private methods using self.
class PutsTest
def success_puts
private_puts
end
def failed_puts
# trying to access a private method from self
self.private_puts
end
private
def private_puts
puts 'hi'
end
end
By using self, you are changing the scope from calling the method inside of PutsTest to calling from the outside of PutsTest
ree-1.8.7-2011.03 :095 > test = PutsTest.new
ree-1.8.7-2011.03 :096 > test.success_puts
hi
ree-1.8.7-2011.03 :097 > test.failed_puts
NoMethodError: private method `private_puts' called for #<PutsTest:0xd62c48>