In Ruby, I can define a method foo=(bar):
irb(main):001:0> def foo=(bar)
irb(main):002:1> p "foo=#{bar}"
irb(main):003:1> end
=> nil
Now I'd like to check if it has been defined,
irb(main):004:0> defined?(foo=)
SyntaxError: compile error
(irb):4: syntax error, unexpected ')'
from (irb):4
from :0
What is the proper syntax to use here? I assume there must be a way to escape "foo=" such that it is parsed and passed correctly to the defined? operator.
The problem is that the foo= method is designed to be used in assignments. You can use defined? in the following way to see what's going on:
defined?(self.foo=())
#=> nil
defined?(self.foo = "bar")
#=> nil
def foo=(bar)
end
defined?(self.foo=())
#=> "assignment"
defined?(self.foo = "bar")
#=> "assignment"
Compare that to:
def foo
end
defined?(foo)
#=> "method"
To test if the foo= method is defined, you should use respond_to? instead:
respond_to?(:foo=)
#=> false
def foo=(bar)
end
respond_to?(:foo=)
#=> true
You can check if a method exists by using the respond_to? method, and you pass it a symbol, e.g. bar.respond_to?(:foo=) to see if the object bar has a method foo=. If you want to know if instances of a class respond to a method you can use method_defined? on the class (or module), e.g. Foo.method_defined?(:bar=).
defined? isn't a method, but an operator which returns a description of the operand (or nil if it is not defined, which is why it can be used in an if statement). The operand can be any expression, i.e. a constant, a variable, an assignment, a method, a method call, etc. The reason why it doesn't work when you do defined?(foo=) is because of the parentheses, skip them and it should work more or less as expected. That being said, defined? is a pretty weird operator, and no one uses it to test for the existence of methods.
Related
IRB appears to have strange behaviour when defining a method called !.
To reproduce this, enter the following into IRB:
def !
puts "foo"
end
Upon creating the method, IRB infinitely prints foo:
irb(main):001:0> def !
irb(main):002:1> puts "foo"
irb(main):003:1> end
foo
foo
foo
...
As far as I know, you can't directly call a method named ! from Ruby syntax; you have to use send instead. Edit: You can invoke ! as a prefix operator; it's just negation: !x
Why does this definition cause IRB to loop infinitely? Does IRB rely on a method named ! for printing its prompt or something similar?
I'm using Ruby 2.4.3 and IRB 0.9.6 on Windows 10.
tl;dr: Overriding ! outside of a class is a very weird thing to do! There are countless ways that you can "break" ruby by doing crazy things like this - so you may find it fun to play around with such strange ideas, but obviously don't do this in important code!
In ruby, all classes inherit from the top-level base class: BasicObject. This class defines top-level object negation - i.e. Whenever you write
!foo
this is actually calling a method called ! on your object foo:
foo.send(:!)
This makes it possible (although it's a very rare thing to do!) to redefine the method on a specific class. For example, when implementing the null object pattern you could do something like this:
class NullObject
def !
true
end
end
my_null = NullObject.new
!!my_null #=> false
(Normally, the only objects that would return false in the above line are nil and false!)
Now then, back to your example. What you actually did here was define a method called ! on the class Object (and didn't call super to trigger the original method!). In other words, you basically re-defined the response a fundamental method that gets used all over the place internally. Something, somewhere (??) got confused by this bizarre behaviour and failed non-gracefully.
irb(main):001:0> def !
irb(main):002:1> puts "foo"
irb(main):003:1> super # <-- !! This stops it from breaking completely !!
irb(main):004:1> end
=> :!
irb(main):005:0* method(:!)
foo
foo
=> #<Method: Object#!>
irb(main):006:0> method(:!).source_location
foo
foo
=> ["(irb)", 1]
irb(main):007:0> method(:!).super_method
foo
foo
=> #<Method: BasicObject#!>
Here are some other ways you could re-define methods to cause bizarre behaviour/errors, for example:
def nil?
true
end
# Will now die in weird ways!
class String
def ===(other)
true
end
end
"ruby" === "awesome"
#=> true
When you define a method, it returns a symbol with the same name as the method. Is there a point to this? Or is it just there as validation that you created it?
Like so:
def something
...
end
# => :something
IRb always displays the result of calling inspect on the value of the last expression that was evaluated. It doesn't matter whether that expression is a literal expression, a conditional expression, a message send, a class definition expression or a method definition expression.
Everything returns a value in Ruby, i.e. everything is an expression, there is no such thing as a statement in Ruby.
In the past, the return value of a method definition expression was undefined. Most Ruby implementations simply returned nil from a method definition expression, but Rubinius for example returned the CompiledMethod object for the method that was defined.
With Ruby 2.1, the return value of a method definition expression was standardized to be the Symbol corresponding to the method's name. This allows you to use the method definition expression as an argument in methods that expect the name of a method as an argument.
Some examples:
# Before Ruby 2.0:
def foo; end
private :foo
# After Ruby 2.0:
private def foo; end # similar for `protected`, `public`, `module_function`
# Before Ruby 2.0:
def map; end
alias_method :collect, :map
# After Ruby 2.0:
alias_method :collect, def map; end
On a personal note, I would have preferred a method definition expression to evaluate to an UnboundMethod object corresponding to that method, and methods like public, private, protected, alias_method, module_function etc. should be amended to accept UnboundMethods in addition to Symbols and Strings.
The person who proposed this had in mind a usage like this:
private def foo
...
end
protected def bar
...
end
Methods such as public, private, protected take symbols as arguments. The point was to make use of this syntax.
All method defs return symbols in Ruby >=2.1 (not just the ones in IRB).
For example:
class Foo
p def bar; end
end
# => prints :bar
Why is this interesting?
You may have noticed that there are many methods, particularly class-level methods, that take the symbolized name of another method as an argument. You may be familiar with before_filter in Rails controllers. Since method defs return symbols, you could potentially do this:
class MyController < ApplicationController
before_filter def my_filter
# do stuff
end
end
IRB respects the ruby standard “the result of last executed statement is returned from method.” Imagine the code:
def a
def b
# do stuff
end
end
What is the result of execution this code? It follows:
a
# => :b
a.class
# => Symbol < Object
That said, IRB executes the method definition and returns/prints out it’s result. Which is, apparently, a Symbol instance.
I recently came across some code using a method call consisting of the format object.(arg1, arg2) without seeing a good explanation of how it works. See this sample code:
class TestServiceObject
def call
'method'
end
end
TestServiceObject.new.()
# => 'method'
What's the term for this kind of shorthand?
The dot-parentheses notation is a shorthand way for passing arguments to the implicit call method on a Ruby object:
foo = lambda {|bar| puts bar}
foo.call('baz')
#=> baz
foo.('baz')
foo.call('baz') === foo.('baz')
#=> true
Also note that the following notations are also valid (and equivalent) invocations of the call method:
foo['baz']
#=> baz
foo::('baz')
#=> baz
In your example, you're explicitly overriding the call method on the TestServiceObject class such that it returns the string 'method' when called. Accordingly, you can explicitly override the the call method to accept arguments:
class TestServiceObject
def call(foo=nil)
foo || 'method'
end
end
TestServiceObject.new.()
#=> method
TestServicesObject.new.('bar')
#=> bar
UPDATE:
As commenter #LoganSerman duly notes, the shorthand operator appears to work on anything that responds to call, which is validated in part by the following example:
m = 12.method("+")
m.call(3)
#=> 15
m.(3)
#=> 15
UPDATE 2:
As commenter #Stefan also points out from the documentation on Proc#call:
prc.() invokes prc.call() with the parameters given. It’s a syntax sugar to hide “call”.
foo.(bar, baz)
is interpreted as
foo.call(bar, baz)
just like
foo + bar
is interpreted as
foo.+(bar)
or
foo[bar, baz] = quux
is interpreted as
foo.[]=(bar, baz, quux)
The intention is to make calling function-like objects look similar to calling methods:
foo.(bar, baz) # function
foo(bar, baz) # method
Despite claims in other answers to this question, it has nothing to do with an "implicit call method" (Ruby doesn't even have implicit methods, only Scala does) or the indexing operator.
The indexing operator is translated into a different method call ([]) and not into a call to call:
o = Object.new
def o.call(*args); "`call` called with #{args.join(', ')}" end
o.(42)
# => "`call` called with 42"
o[42]
# NoMethodError: undefined method `[]' for #<Object:0xdeadbeefc0ffee>
def o.[](*args); "`[]` called with #{args.join(', ')}" end
o[42]
# => "`[]` called with 42"
obj.(args) is just a feature provided through the parser. Not technically an alias, but it simply has the same effect as invoking obj.call(args) on an object that defines the call method.
I was playing with method definition and calling to them in the main of IRB.
def show
p "hi"
end
#=> nil
show
#"hi"
#=> "hi"
self.show
#"hi"
#=> "hi"
The above are good and understood.
Now let's try something different:
def Foo
p "hi"
end
#=> nil
Foo
#NameError: uninitialized constant Foo
#from (irb):4
#from C:/Ruby193/bin/irb:12:in `<main>'
While the call to Foo has thrown an error as above,how does the below remove that?
self.Foo
#"hi"
#=> "hi"
In Ruby, you can call methods without a receiver and without an argument list. However, this means that there is an ambiguity: does foo mean "call method foo on the implicit receiver self without arguments, i.e. equivalent to self.foo()" or does it mean "dereference the variable foo"? Ruby can't know which you mean, so there are some simple rules.
For a local variable, the rule is that foo is always a method call, unless foo is statically known at parse time to be a local variable. So, when is it statically known to be a variable? When there was an assignment to that variable which was parsed (but not necessarily executed!) before the use.
Example:
foo # method call
if false
foo = 42 # will never be executed, but *will* be parsed
end
foo # variable dereference, since the `foo` assignment was parsed
For constant variables, the rule is even simpler: Foo is always interpreted as a constant dereference. Period.
So, how do you call a method with such a name? Easy: like I said, the ambiguity arises only for method calls with no argument list and no explicit receiver. So, if we add either one or both of those, Ruby will know that we are trying to call a method and not dereference a variable:
foo()
self.foo
self.foo()
Foo()
self.Foo
self.Foo()
Of course, in the example you gave above, only the first one will work. When you define a method at the top-level, it is added as a private method to Object, and private methods can only be called without an explicit receiver, even if that receiver is self. So, self.Foo won't work, because Foo is private. (Except in IRb, where, for convenience reasons, top-level methods are public.)
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!