What does a ruby method ending with an "=" mean?
See the available methods in this print out:
2.2.0 :066 > obj.methods(false)
=> [:label=, :label, :description=, :description, :thumbnail=, :thumbnail, :attribution=, :attribution, :license=, :license, :logo=, :logo, :see_also=, :seeAlso=, :see_also, :seeAlso, :related=, :related, :within=, :within, :metadata=, :metadata, :sequences=, :sequences, :structures=, :structures, :viewing_hint=, :viewingHint=, :viewing_hint, :viewingHint, :viewing_direction=, :viewingDirection=, :viewing_direction, :viewingDirection, :service=, :service]
For example whats this difference between label= and label?
foo= is no different than any other method, except:
it requires precisely one argument and
Ruby permits you to add spaces before the = character.
class Foo
def foo=(other)
puts 'hi'
end
end
Foo.new.foo = 7
hi
class Goo
def goo=
puts 'hi'
end
end
Goo.new.goo=
Ruby says, "I'm waiting for an argument...". So we provide one:
4
and then she complains about what she asked you to do:
#=> ArgumentError: wrong number of arguments (1 for 0)
= methods are typically used to create a setter for an instance variable (if attr_acccessor or attr_writer is not used):
class Foo
def initialize(foo)
#foo=foo
end
# getter
def foo
#foo
end
# setter
def foo=(other)
#foo = other
end
end
f = Foo.new('dog')
f.foo
#=> "dog"
f.foo = 'cat'
#=> "cat"
f.foo
#=> "cat"
the methods ending with "=" are setting the instance variable
look at the answer here: why-use-rubys-attr-accessor-attr-reader-and-attr-writer
It is equivalent of setter methods in other languages, it is just convention so it looks more natural to say
obj.description="Fun Site"
vs
obj.setDescription("Fun Site")
There is nothing special about methods that end in =
You can see this by running the code below:
def bob=
puts "bob="
end
p send('bob='.to_sym)
What is special is the '=' infix operator. When you write self.bob = "bill". It is interpreted as self.send('bob='.to_sym, "bill").
Putting a ? at the end of a method is a hint that it returns a boolean (true/false). Methods that end in ! hint that the method affects the instance. See String#chomp vs String#chomp.
You can find out more about ruby operators at http://www.tutorialspoint.com/ruby/ruby_operators.htm and more about naming conventions at https://github.com/bbatsov/ruby-style-guide#naming
Related
How can I pass an argument to the definition of a singleton method of [] on A, in other words A['some_argument']?
class A
def self.[]
# some_argument
end
end
Just as to any other method, using argument list:
class A
def self.[](arg)
puts arg
end
end
A[1]
# => 1
Good answers are already given, but I think they miss to mention an important point.
The method [], when used ordinarily in the form foo[params] is actually in syntax sugar form. The underlying method name is [], and calling it in the underlying form would be foo.[](params).
Syntax sugar plays around with syntax, and transforms a method call in the form foo[params] into foo.[](params). But that does not work in method definition, so you have to define such method in the underlying form, not in the syntax sugar form.
class A
def self.[](*args)
puts args
end
end
> A[1,2,3]
1
2
3
You can also implement "set" functionality
class A
def self.[]=(key, value)
puts "#{key} = #{value}"
end
end
A['one'] = '1'
# one = 1
Is there a simple way to extend a functionality of a standard library class like String inside a module without affecting anything outside of it? Example (won't work):
module Foo
class String
def hello
"hello #{self}!"
end
end
class Bar
def greet name
name.hello
end
end
end
Result I'm looking for:
Foo::Bar.new.greet 'Tom' #=> hello Tom!
'Tom'.hello #=> NoMethodError
I'm aware of solutions like creating MyString < String with desired functionality, but I would rather not call MyString.new('foo') every time I want to use a string inside the module.
I realise this may not be considered good practice, I'm just looking to expand my understanding of the language.
What you're looking for is Refinement:
Refinements are designed to reduce the impact of monkey patching on
other users of the monkey-patched class. Refinements provide a way to
extend a class locally.
module Foo
refine String do
def hello
"hello #{self}!"
end
end
end
puts 'Tom'.hello
#=> undefined method `hello' for "Tom":String
using Foo
puts 'Tom'.hello
#=> hello Tom!
Using refinement inside Bar class:
# Without refinement
class Bar
def greet(name)
name.hello
end
end
puts Bar.new.greet('Tom')
#=> undefined method `hello' for "Tom":String
# With refinement
class Bar
using Foo
def greet(name)
name.hello
end
end
puts Bar.new.greet('Tom')
#=> hello Tom!
For the complete info about scoping, method lookup and stuff look into docs link I've provided :)
P.S. Be aware, that Rubinius developers are philosophically opposed to Refinements and thus will never implement them (c) Jörg W Mittag.
Write a class of the same name then use require_relative (or similar method) to include it.
class Date
def itis
puts "It is " + self.to_s
end
Example:
[1] pry(main)> require_relative 'date.rb'
=> true
[2] pry(main)> require 'date'
=> true
[3] pry(main)> Date.new(2018, 10, 9).itis
It is 2018-10-09
=> nil
How's it possible in ruby ?
class Test
# Creating singleton method
def self.some_singleton_method(param1)
puts param1
end
end
# calling singleton method by creating method on fly as a parameter to it
Test.some_singleton_method def method_name(some_param)
# do something
end
## method_name
I've tried many places looking around, can't come up with an idea how's it's working.
Thanks!
It is possible, since def is keyword, that creates new method in current scope, which is Object since you're calling it on the "top" level, i.e. not inside any class. Starting from Ruby 2.1, def returns method name as a symbol, so your code is actually equivalent to
name = def method_name(some_param)
// do something
end
Test.some_singleton_method(name) # outputs "method_name"
EDIT: Thanks to Cary Swoveland for clarification that def is actually a keyword and not a method.
Here are two ways to do that.
#1
class Test
def self.doit(m)
send(m) yield
end
end
Test.doit(:hello) do
puts 'hi'
end
#=> :hello
Test.new.hello
#=> "hi"`.
#2
class Test
def self.doit(str)
eval(str)
end
end
Test.doit "def hello; puts 'hi'; end"
#=> :hello
Test.new.hello
#=> "hi"`.
I want an instance of my custom class to have the same methods and behavior as its superclass unless a specific method is invoked on it that returns something (like next, which returns the next Numeric in the sequence). It should act in this case like a String.
class MyNumber < Numeric
...
end
val = MyNumber.new(1)
# acts like a regular Numeric
val.next
#=> 2
val
#=> "Hello 2!"
puts "Hey #{val}"
#=> "Hey Hello 2!"
In the situation above, I guess I would just redefine to_s.
You define the inspect method on that class. For example, if you modify String#inspect as:
class String
def inspect; self * 2 end
end
then you get:
"Hello" # => "HelloHello"
I suppose you wanted this:
class MyNumber < Numeric
def inspect; "Hey #{self}" end
end
Note that interpolation "#{}" uses to_s and not inspect, so this does not cause infinite recursion.
I am having a bit trouble to understand when "super" can be called and when not. In the below example the super method leads to a no superclass error.
class Bacterium
def eats
puts "Nam"
end
end
class Bacterium
def eats
super # -> no superclass error
puts "Yam"
end
end
b = Bacterium.new
b.eats
But this works:
class Fixnum
def times
super # -> works
puts "done"
end
end
5.times { |i| puts i.to_s }
Is 5 not just also an instance of Fixnum. And am I not redefining an existing method like in the Bacterium example above?
No, not really. Fixnum inherits from Integer class, and you are in fact overriding Integer#times, so super works, as it calls implementation from the parent.
In order to achieve something similar when monkeypatching, you should alias method before redefining it, and there call it by alias.
class Bacterium
alias_method :eats_original, :eats
def eats
eats_original # -> "Nam"
puts "Yam"
end
end
Class reopening is not a form of inheritance and super is of no use there.
Just as Mladen said, and you can check that with Class#superclass:
irb> Fixnum.superclass
=> Integer
And does Integer implement #times?:
irb> Integer.instance_methods.grep /times/
=> [:times]
Yes it does.
So, in a simplified way, we can say, that super invokes the method you are in of a superclass. In your case the superclass of a Bacterium is Object, which doesn't implement #eats.
I said this is very simplified, because look at this example:
module One
def hi
" World" << super()
end
end
module Two
def hi
"Hello" << super()
end
end
class SayHi
def hi
"!!!"
end
end
h = SayHi.new
h.extend(One)
h.extend(Two)
puts h.hi
#=> Hello World!!
Don't take to serious what I wrote here, it is actually tip of the iceberg of the Ruby object model, which is important to understand (I am still learning it) - then you will get most, or all of those concepts.
Use some Google-fu for "Ruby object model"...