Simple Detect Solution Causing Difficulties - ruby

I have the following code, which is supposed to provide a simple true-false wrapper over Array#detect, which is nil-element.
class Array
def any &expr
if (self.detect expr)
return true
else
return false
end
end
end
For some weird reason, no matter what is passed to &expr, it ALWAYS returns true! Why is this?

The documentation for Enumerable#detect says that it can optionally take one argument. If it doesn't find the element that matched your block, it returns this argument. In your case, you're passing a Proc object, expr to detect, and not passing a block. This causes detect to return an enumerator, which won't be interpreted as a "falsy" value.
I think instead you want self.detect &expr to pass an actual block instead of a Proc.

Related

Does if call == method?

I just found out that Ruby provides no way to override boolean conversion method.(How to create an Object who act as a False in Ruby)
I am trying to create an object, and track whenever it is passed to an if condition.
However, when I executed the following piece of code, 2222222222222222 wasn't being printed.
class Null
def ==(other)
p 2222222222222222
p caller
super
end
end
null = Null.new
if null
end
Does this mean that if doesn't call ==? Is there a method that if calls in an object to evaluate the Truth-yness of it?
Alternatively, is there a way to track where if object is used for object?
I'm making a large scale change and it would be unreasonable to string search all if conditions in our code base. I'd much rather create a special object and log/alert whenever if object is used.
There are only ever two objects considered "falsey": nil and false. Everything else is truthy.
So no, if my_obj doesn't call my_obj#== nor anything else. As long as the object is neither nil nor false, it's evaluated as true.
As far as I can tell, there's no way to track if an object is "evaluated as boolean", or used in if or unless.
An equivalent of if my_obj would be:
unless my_obj.equal? nil || my_obj.equal? false
# code
end

In Ruby, is an if/elsif/else statement's subordinate block the same as a 'block' that is passed as a parameter?

I was doing some reading on if/elsif/else in Ruby, and I ran into some differences in terminology when describing how control expressions work.
In the Ruby Programming Wikibooks (emphasis added):
A conditional Branch takes the result of a test expression and executes a block of code depending whether the test expression is true or false.
and
An if expression, for example, not only determines whether a subordinate block of code will execute, but also results in a value itself.
Ruby-doc.org, however, does not mention blocks at all in the definitions:
The simplest if expression has two parts, a “test” expression and a “then” expression. If the “test” expression evaluates to a true then the “then” expression is evaluated.
Typically, when I have read about 'blocks' in Ruby, it has almost always been within the context of procs and lambdas. For example, rubylearning.com defines a block:
A Ruby block is a way of grouping statements, and may appear only in the source adjacent to a method call; the block is written starting on the same line as the method call's last parameter (or the closing parenthesis of the parameter list).
The questions:
When talking about blocks of code in Ruby, are we talking about
the group of code that gets passed in to a method or are we simply
talking about a group of code in general?
Is there a way to easily differentiate between the two (and is there
a technical difference between the two)?
Context for these questions: I am wondering if referring to the code inside of conditionals as blocks will be confusing to to new Ruby programmers when they are later introduced to blocks, procs, and lambdas.
TL;DR if...end is an expression, not a block
The proper use of the term block in Ruby is the code passed to a method in between do...end or curly braces {...}. A block can be and often is implicitly converted into a Proc within a method by using the &block syntax in the method signature. This new Proc is an object with its own methods that can be passed to other methods, stored in variables and data structures, called repeatedly, etc...
def block_to_proc(&block)
prc = block
puts prc
prc.class
end
block_to_proc { 'inside the block' }
# "#<Proc:0x007fa626845a98#(irb):21>"
# => Proc
In the code above, a Proc is being implicitly created with the block as its body and assigned to the variable block. Likewise, a Proc (or a lambda, a type of Proc) can be "expanded" into blocks and passed to methods that are expecting them, by using the &block syntax at the end of an arguments list.
def proc_to_block
result = yield # only the return value of the block can be saved, not the block itself
puts result
result.class
end
block = Proc.new { 'inside the Proc' }
proc_to_block(&block)
# "inside the Proc"
# => String
Although there's somewhat of a two-way street between blocks and Procs, they're not the same. Notice that to define a Proc we had to pass a block to Proc.new. Strictly speaking a block is just a chunk of code passed to a method whose execution is deferred until explicitly called. A Proc is defined with a block, its execution is also deferred until called, but it is a bonafide object just like any other. A block cannot survive on its own, a Proc can.
On the other hand, block or block of code is sometimes casually used to refer to any discreet chunk of code enclosed by Ruby keywords terminating with end: if...else...end, begin...rescue...end, def...end, class...end, module...end, until...end. But these are not really blocks, per se, and only really resemble them on the surface. Often they also have deferred execution until some condition is met. But they can stand entirely on their own, and always have return values. Ruby-doc.org's use of "expression" is more accurate.
From wikipedia
An expression in a programming language is a combination of one or
more explicit values, constants, variables, operators, and functions
that the programming language interprets (according to its particular
rules of precedence and of association) and computes to produce ("to
return", in a stateful environment) another value.
This is why you can do things like this
return_value = if 'expression'
true
end
return_value # => true
Try doing that with a block
return_value = do
true
end
# SyntaxError: (irb):24: syntax error, unexpected keyword_do_block
# return_value = do
# ^
A block is not an expression on its own. It needs either yield or a conversion to a Proc to survive. What happens when we pass a block to a method that doesn't want one?
puts("indifferent") { "to blocks" }
# "indifferent"
# => nil
The block is totally lost, it disappears with no return value, no execution, as if it never existed. It needs yield to complete the expression and produce a return value.
class Object
def puts(*args)
super
yield if block_given?
end
end
puts("mindful") { "of blocks" }
# "mindful"
# => "of blocks"

Ruby calling hash values returns nil

I have a code
def pitch_class(note)
note_hash = {:C=>0, :D=>2, :E=>4, :F=>5, :G=>7, :A=>9, :B=>11}
note_hash[:note]
end
but whenever I try to call the value inside it returns nil.
pitch_class("C")
#=> nil
How can I call the values using the key as the argument?
Thanks!
"C" != :C. Therefore, pitch_class(:C) will work.
You can also use String#to_sym to force the argument inside the function, if you want to be able to accept a string argument. Or you can create the hash with string keys in the first place.
EDIT: Also, :note is not note.
EDIT2: As a performance tweak, I'd rather have note_hash declared outside the method, rather than instantiating it each time the method is called. Stuffing it into a class constant (NOTE_HASH) would be the best way to handle it.
You hardcoded :note symbol instead of reading parameter passed to your method:
def pitch_class(note)
note_hash = {:C=>0, :D=>2, :E=>4, :F=>5, :G=>7, :A=>9, :B=>11}
note_hash[note.to_sym]
end

On method called on double, expectations about the argument

I have created a double, I am executing code that will call it with a method and a huge hash as a argument, I want to verify one key of the argument, and then return a specific hash.
This is what I am doing
before :each do
allow(#my_double).to receive(:do_stuff).and_return({stuff: 42})
end
it "can do stuff" do
expect(#my_double).to receive(:do_stuff) do |arg|
expect(arg).to be_a(Hash)
expect(arg[:my_arg]).to eq(3)
end
TestObject.stuff() # will invoke do_stuff on the double
end
What happens is, the first time do_stuff is called, it returns true which is the result of the receive block, but on subsequent calls(tested in pry) it correctly returns {stuff: 42} but since the first call is wrong, my method exceptions out when it tries to call[:stuff] on the return.
I am trying to let allow define the behaviour of the double so I don't want to put the return in the bottom of the expect.. but is there any way around it?
Figured out the answer is to use an as yet undocumented argument matcher hash_including much like my first comment
expect(#my_double).to receive(:do_stuff).with(hash_including(my_arg: 3))
This works nicely.

Returning a value of ruby is strange

could anyone tell me the return value of this function give the parameter listed blew:
def sequence(*enumerables)
enumerables.each do |enumerable|
print "#{enumerable},"
end
end
a,b,c = [1,2,3],4..6,'a'..'e'
value = sequence(a,b,c)
print value
why the value is evaluated to be:
[[1,2,3],4..6,"a".."e"]
Remember that the last thing left on the stack is the return value of your method. This is always the case. If the return value is important, you must pay close attention to how you exit from your method.
The each method returns what it has been iterating over. Since the each is the last statement in your method, stack-wise, that value gets returned.
You can fix this by returning nothing:
def sequence(*enumerables)
enumerables.each do |enumerable|
print "#{enumerable},"
end
return
end
This approach is generally frowned on as the return method seems out of place. If the caller of this method is not expecting any particular return value, then it's not necessary.
The alternative is to return something useful:
def sequence(*enumerables)
enumerables.join(",")
end
puts sequence(a,b,c)
It's often the case that methods which do not set an expectation for a particular return value may return an arbitrary one.
enumerables is an array. The splat (*) operator causes this.
The return value of sequence is the return value of enumerables.each which is enumerables
A simple example:
def foo(*args)
args
end
foo(1,2,3,4) == [1,2,3,4] # true
You're returning enumerables, which is an array containing all the arguments to the method.
What did you expect value to contain? You haven't made any explicit attempt to return anything, so whatever value the last statement in the method resolves to "falls off" the method to become its return value.

Resources