I noticed some interesting use of ||= as below -
Code 1
array_1 ||= begin
(1..5).to_a.map {|el| el*10}
end
puts array_1.to_s # [10,20,30,40,50]
So I executed its following modified version -
Code 2
array_2 ||= def some_method
(1..5).to_a.map {|el| el*10}
end
puts array_2 # prints nothing
puts array_2.class # NilClass
puts some_method.to_s # [10,20,30,40,50]
Why does array_2 gets initialised to nil?
Is it possible to invoke some_method using array_2 object? how?
UPDATE
This is what I did for question 2
array_2 ||= "We've got #{def some_method;(1..5).to_a.map {|el| el*10};end;array_2.send(:some_method)}"
puts array_2 # We've got [10, 20, 30, 40, 50]
The return value of a method definition expression (def) is implementation-defined. Most Ruby implementations simply return nil from a def expression, but Rubinius, for example, returns the compiled code of the method wrapped up in a CompiledMethod object.
When you declare any method it will simply return nil but when you call any method it will return the o/p of the last line return in that method unless you used return keyword.
Following should work for you
def some_method
return (1..5).to_a.map {|el| el*10}
end
array_2 ||=some_method
Related
I understand that
def a(&block)
block.call(self)
end
and
def a()
yield self
end
lead to the same result, if I assume that there is such a block a {}. My question is - since I stumbled over some code like that, whether it makes any difference or if there is any advantage of having (if I do not use the variable/reference block otherwise):
def a(&block)
yield self
end
This is a concrete case where i do not understand the use of &block:
def rule(code, name, &block)
#rules = [] if #rules.nil?
#rules << Rule.new(code, name)
yield self
end
The only advantage I can think of is for introspection:
def foo; end
def bar(&blk); end
method(:foo).parameters #=> []
method(:bar).parameters #=> [[:block, :blk]]
IDEs and documentation generators could take advantage of this. However, it does not affect Ruby's argument passing. When calling a method, you can pass or omit a block, regardless of whether it is declared or invoked.
The main difference between
def pass_block
yield
end
pass_block { 'hi' } #=> 'hi'
and
def pass_proc(&blk)
blk.call
end
pass_proc { 'hi' } #=> 'hi'
is that, blk, an instance of Proc, is an object and therefore can be passed to other methods. By contrast, blocks are not objects and therefore cannot be passed around.
def pass_proc(&blk)
puts "blk.is_a?(Proc)=#{blk.is_a?(Proc)}"
receive_proc(blk)
end
def receive_proc(proc)
proc.call
end
pass_proc { 'ho' }
blk.is_a?(Proc)=true
#=> "ho"
I have a method that looks like this:
def calculate_the_thing(hsh)
hsh[:x] + hsh[:y] + hsh[:z]
end
which takes something like this:
{:x => 5, :y => nil, :z => 2, :a => 5}
I'd like to patch some classes so that when the + method gets a nil value, it treats it as zero. Seems reasonable. How might I do that?
As #jforberg points out, you can just use the #to_i method which will return 0 for nil.
def calculate_the_thing(hsh)
hsh[:x].to_i + hsh[:y].to_i + hsh[:z].to_i
end
Alternatively, you can also define the hash with an automatic default value...
hsh = Hash.new{0}
But if you have a method that explicitly puts nil as a hash value that will override the default value.
You need to monkey-patch Nilclass to coerce nil to an integer. Here is the code:
class NilClass
def coerce(n)
return [0, n] if n.is_a? Numeric
super
end
end
1 + nil
#=> 1
Have a look at this thread - In Ruby, how does coerce() actually work? - to understand the concept of coerce.
However, there is an issue with above code:
nil + 1
#=> undefined method `+' for nil:NilClass (NoMethodError)
To fix this problem, you will have to define + method on NilClass
class NilClass
def +(param)
param + self
end
end
nil + 1
#=> 1
If we try to get adventurous and try:
nil * 10
#=> undefined method `*' for nil:NilClass (NoMethodError)
By being adventurous, lets handle all such undefined methods by implementing our own method_missing handler.
class NilClass
def method_missing m, *args, &block
args.first.send(m, self, &block) if args.size == 1
end
end
p nil * 1
#=> 0
Next, lets try:
nil + "hello"
# '+': can't convert NilClass to String (NilClass#to_str gives NilClass) (TypeError)
Lets fix this as well
class NilClass
def to_str
""
end
end
nil + "hello"
#=> "hello"
Next, lets try this:
nil + [1,2,3]
#=> '+': can't convert NilClass to Array (NilClass#to_ary gives NilClass) (TypeError)
Lets fix it:
class NilClass
def to_ary
[]
end
end
nil + [1,2,3]
#=> [1, 2, 3]
We now have this version of NilClass:
class NilClass
def coerce(n)
return [0, n] if n.is_a? Numeric
super
end
def method_missing m, *args, &block
args.first.send(m, self, &block) if args.size == 1
end
def to_str
""
end
def to_ary
[]
end
end
Caution:: Above code shows that what you want to do can be done. However, this should be used only for experimental and learning purpose. It is really not feasible to make nil behave like other operand in all operations and you will end up monkey-patching NilClass to no end.
Hence, its better to stay off from this kind of monkey patching to avoid scary surprises to future Rubyists who will be maintaining your code.
I'm trying to add an instance method foo to Ruby's Array class
so when it's invoked, the array's string elements are changed to string "foo".
This can be done easily by monkey patching Ruby's String and Array classes.
class String
def foo
replace "foo"
end
end
class Array
def foo
self.each {|x| x.foo if x.respond_to? :foo }
end
end
a = ['a', 1, 'b']
a.foo
puts a.join(", ") # you get 'foo, 1, foo' as expected
Now I'm trying to rewrite the above using Ruby 2's refinements feature.
I'm using Ruby version 2.2.2.
The following works (in a file, eg. ruby test.rb, but not in irb for some reason)
module M
refine String do
def foo
replace "foo"
end
end
end
using M
s = ''
s.foo
puts s # you get 'foo'
However, I can't get it to work when adding foo onto the Array class.
module M
refine String do
def foo
replace "foo"
end
end
end
using M
module N
refine Array do
def foo
self.each {|x| x.foo if x.respond_to? :foo }
end
end
end
using N
a = ['a', 1, 'b']
a.foo
puts a.join(", ") # you get 'a, 1, b', not 'foo, 1, foo' as expected
There're two issues:
After you refine a class with a new method, respond_to? does not work even when you can invoke
the method on an object. Try adding puts 'yes' if s.respond_to? :foo
as the last line in the second code snippet, you'll see 'yes' is not printed.
In my Array refinement, the String#foo is out of scope. If you remove if x.respond_to? :foo from
the Array#foo, you'll get the error undefined method 'foo' for "a":String (NoMethodError). So the question is: how do you make the String#foo refinement visible inside the Array#foo refinement?
How do I overcome these two issues so I can get this to work?
(Please don't offer alternative solutions that don't involve refinement, because this is a theoretical exercise so I can learn how to use refinement).
Thank you.
The respond_to? method does not work and this is documented
here.
The problem is that you can only activate a refinement at top-level
and they are lexical in scope.
One solution would be:
module N
refine String do
def foo
replace 'foobar'
end
end
refine Array do
def foo
self.each do |x|
x.foo rescue x
end
end
end
end
using N
a = ['a', 1, 'b']
p a.foo
puts a.join(", ") # foo, 1, foo
Taking up your example again, a simple solution could be to override the respond_to? method in refinement block :
module M
refine String do
def foo
replace "foo"
end
def respond_to?(name,all=false)
list_methods = self.methods.concat [:foo]
list_methods.include? name
end
end
refine Array do
def foo
self.each {|x| x.foo if x.respond_to? :foo }
end
end
end
using M
a = ['a', 1, 'b']
a.foo
puts a.join(", ") # you get 'foo, 1, foo'
class Array
attr_accessor :arr
def initialize(arr)
#arr = arr
end
def self.second(list)
if list[1] != nil
puts list[1]
else
puts nil
end
end
end
([3, 4, 5]).second
You've second as a class method instead of instance method.
Do this instead.
class Array
def second
if self[1].nil?
puts "Nil value"
else
puts self[1]
end
end
end
And by the way you don't need an attr_accessor. That's a code smell.
The keyword self in the definition of a method makes the method a class and not an instance method.
At the moment your method can be called like this:
Array.second([3, 4, 5])
If you want to call is like this:
[3, 4, 5].second
then you need to change your code to something like this:
class Array
def second
if self[1] != nil
puts self[1]
else
puts nil
end
end
end
Furthermore there is no need to check for nil if you print the nil anyway. This allows us to write the same as:
class Array
def second
puts(self[1])
end
end
[3,4,5].second
#=> 4
[].second
#=>
If you want to explicitly print the string "nil" instead of just nil, change to code to:
puts(self[1] | 'nil')
Or:
puts(self.fetch(1) { 'nil' })
As we know, wo can pass a method to a iterator method by a &: prefix.
For example:
["a", "b"].map(&:upcase) #=> ["A", "B"]
def rettwo
2
end
["a", "b"].map(&:rettwo) #=> [2, 2]
Here is the problem, when I write a method, pass a method with &: prefix to it, I got a error message: "ArgumentError: no receiver given".
Let me show the code:
def a_simple_method &proc
puts proc.class # it shows `Proc`
proc.call
end
def a_iterator_method
puts yield
end
a_simple_method &:rettwo #=> ArgumentError: no receiver given
a_iterator_method &:rettwo #=> ArgumentError: no receiver given
What do I missing, How the map like method of Array handle it
Here's what works. Explanation below.
class String
def rettwo
self + self
end
end
def a_simple_method &proc
proc.call('a')
end
def a_iterator_method
yield 'b'
end
a_simple_method(&:rettwo) # => "aa"
a_iterator_method(&:rettwo) # => "bb"
The &: construct is called Symbol#to_proc. It turns symbol into a proc. This proc expects a receiver as a first argument. The remaining arguments are used to call the proc. You're not passing any arguments, hence the "receiver not given" error.
Here's a demonstration of additional arguments:
class String
def say name
"#{self} #{name}"
end
end
def a_simple_method &proc
proc.call('hello', 'ruby')
end
a_simple_method(&:say) # => "hello ruby"
Here's a definition of Symbol#to_proc from some blog post from 2008. Modern Symbol#to_proc seems to be implemented in C, but this can still help the understanding.
class Symbol
def to_proc
Proc.new { |*args| args.shift.__send__(self, *args) }
end
end