Short hand way to evaluate args in ruby - ruby

I am currently using the following code in a ruby program to evaluate variable length arguments that are passed to a method. The program is running however I'm wondering if there is a short hand way to write this.
Should have been more specific in my original description, trying to rewrite the Inject method for the Array class (hence the witty name...)
Therefore it needs to be able to accept a maximum of two args, and a minimum 0 if a block is given.
array.inject(:+)
array.inject{ |output, num| output + num }
array.inject(arg, :+)
array.inject(arg) { |output, num| output + num }
The most difficult case/s to handle are the first and forth where the 1 arg can be either a Fixnum or a Symbol. As mentioned, the code works, just looking for ways to tidy it up.
class Array
def enjict(*args)
if args.length == 2 && args[0].is_a?(Fixnum) && args[1].is_a?(Symbol)
start, symbol = args
elsif args.length == 1
raise ArgumentError unless args.first.is_a?(Symbol) || args.first.is_a?(Fixnum)
symbol = args.first if args.first.is_a?(Symbol)
start = args.first if args.first.is_a?(Fixnum)
else
raise ArgumentError unless block_given?
end
copiedArray = dup
start = copiedArray.shift unless start
if block_given?
copiedArray.each { |num| start = yield(start, num) }
else
copiedArray.each { |num| start = start.send(symbol, num) }
end
start
end
end

The sad truth is: it's messy, and there's nothing you can do about it. Almost all Ruby implementations implement Enumerable#inject with privileged access to the interpreter internals, including introspection of the arguments. MRI, YARV, MRuby implement it in C, MacRuby and RubyMotion in Objective-C, XRuby and JRuby in Java, Ruby.NET and IronRuby in C#, Topaz in RPython, Cardinal in PIR, and so on.
This is something that is simply not available to Ruby code.
Only Rubinius implements it in Ruby.
You can use a similar trick by (ab)using the fact that the default argument expression for an optional parameter can be any arbitrarily complex Ruby expression and that local variables of those expressions become local variables of the method. This is a common trick for figuring out whether an argument was passed or not:
def inject(initial=(no_initial = true; nil), sym=(no_sym = true; nil))
sym, initial = initial, nil if !block_given && no_sym
# and so on …
end

Judging from the conditions, how about refactoring your method arguments to:
def enjict(start, symbol, *options, &block)
e = proc{ raise ArgumentError if options.length > 0 && !block_given? }
e.call
if start.is_a?(Fixnum) && symbol.is_a?(Symbol)
# do something you want
else
e.call
end
end

Related

How does Ruby's #count method deal with nil values?

I'm doing Ruby exercises for the Odin Project (programming newcomer), and we're tasked with recreating Ruby's #count method. Given an array like:
nil_list = [false, false, nil]
Observations:
nil_list.count == 3, its length.
nil_list.count(nil) == 1, the number of times nil is present in the list.
nil_list given a block behaves as expected.
When I try to recreate it, here's what I come up with:
module Enumerable
def my_count (find = nil)
result = 0
for i in self
if block_given?
result += 1 if yield(i)
elsif find != nil
result += 1 if i == find
else return self.length
end
end
return result
end
end
The problem here is that this doesn't actually count nils if we enter nil in as an argument, since this is the same (according to my code) as there not being an argument.
ie, nil_list.my_count(nil) == 3 instead of 1.
While typing this question I had a slightly different idea:
module Enumerable
def my_count (find = "")
result = 0
for i in self
if block_given?
result += 1 if yield(i)
elsif find != ""
result += 1 if i == find
else return self.length
end
end
return result
end
end
So this fixes the problem I was having with searches for nil, but now nil_list.count("") == 0 whereas nil_list.my_count("") == 3. Same issue, just relocated to "" which I assume doesn't ever get used.
At this point I'm just curious: how does the actual count method prevent this issue from happening?
You can write def my_count(*args) and check then length of args. I'd write:
module Enumerable
def my_count(*args)
case
when args.size > 1
raise ArgumentError
when args.size == 1
value = args.first
reduce(0) { |acc, x| value == x ? acc + 1 : acc }
when block_given?
reduce(0) { |acc, x| yield(x) ? acc + 1 : acc }
else
reduce(0) { |acc, x| acc + 1 }
end
end
end
The ugly truth is: in most Ruby implementations, Enumerable#count isn't actually written in Ruby. In MRI, YARV and MRuby, it's written in C, in JRuby and XRuby, it's written in Java, in IronRuby and Ruby.NET, it's written in C#, in MacRuby, it's written in Objective-C, in MagLev, it's written in Smalltalk, in Topaz, it's written in RPython, in Cardinal, it's written in PIR or PASM, and so on. And it not only is not written in Ruby, it's also got privileged access to the internals of the execution engine, in particular, it can access the arguments that were passed, which you cannot do from Ruby.
Such overloaded methods appear all over the core library and standard library, but they can't easily be written in Ruby. The implementers cheat by either writing them in languages that do support overloading (e.g. C# or Java), or they give them privileged access to the internals of the execution engine.
The standard workaround in Ruby is to (ab)use the fact that the default value of an optional parameter is just a normal Ruby expression and that local variables in a default value expression are visible inside the method body:
def my_count(find = (find_passed = false; nil))
if find_passed # find was passed
# do something
else
# do something else
end
end
A second possibility is to use some unforgeable unique token as the default value:
undefined = Object.new
define_method(:my_count) do |find = undefined|
if undefined.equal?(find) # find was not passed
# do something
else
# do something else
end
end

What do c == self and yield do?

Can you help me understand what this class does and how we can make use of it?
class Integer
def myt
c=0
until c == self
yield(c)
c+=1
end
self
end
end
Thank you.
x = Integer.new
x.myt
I tried to test it but it doesn't work. Error is: "no block given (yield)"
Also, in my book it says to test like this:
5.myt (|| puts "I'm on iteration #{i}! "} but it also gives an error - not sure why or what this line of code means.
allonhadaya and PNY did a good job explaining the purpose (enumeration) of the myt method.
Regarding your two questions mentioned in the title:
1.) What does 'c == self' do?
The '==' operator checks whether the integer c and Integer object you instantiate, are equal in value. If they are, the expression evaluates to true.
2.) What does 'yield' do?
The 'yield' statement passes control from the current method to a block which has been provided to the method. Blocks are ruby's implementation of a closure which, simple put, means that a method can be "extended" by calling the method with a block of additional code as long as the method supports a block (ie. incorporates yield statements)
The method seems to be a times implementation.
Basically 5.times { |i| puts i } and 5.myt { |i| puts i } will do exactly the same thing.
First, it sets a counter to 0, c = 0. Then you have a conditional where it checks if c is equal with self which will always be the integer attached to the method myt. It, then yields the counter and return self when is done.
Looks like it enumerates the values between zero inclusively and self exclusively.
allon#ahadaya:~$ irb
irb(main):001:0> class Integer
irb(main):002:1> def myt
irb(main):003:2> c=0
irb(main):004:2> until c == self
irb(main):005:3> yield(c)
irb(main):006:3> c+=1
irb(main):007:3> end
irb(main):008:2> self
irb(main):009:2> end
irb(main):010:1> end
=> nil
irb(main):011:0> 5.myt { |i| puts i }
0
1
2
3
4
=> 5
irb(main):012:0>
Using the example your book gave --
5.myt {|i| puts "I'm on iteration #{i}! "}
#You were missing an object in the pipes and a curly bracket before the pipes (not parentheses)
Allows you to see the internal workings of your myt method. Initializing variable c with a value of 0 the method executes an until look until the condition "c == self" is satisfied. Self references the object, here 5, which the method is acting on.
Therefore ...
def myt
until c == 5 #Until this is true
yield(c) #Do this .. here yield will do whatever the block specified
c+=1 #Increment on each iteration the value of variable c by 1
end #closing the until loop
self #return self
end
The yield within the method passes control from your method to the parameter, a block, back to the method.
Yield therefore allows you to build methods which can have similar patterns but with block you customize it to do your particular need.
If instead of putting each number maybe all you want to do is put the odd integers between 0 and the integer you call the method on --
5.myt {|i| puts i if i.odd?} # returns I am odd: 1 and I am odd: 3
I would suggest that you write your own blocks here to see how yield works and how you can keep the same method but pass in different blocks and create different method outputs!

Use of yield and return in Ruby

Can anyone help me to figure out the the use of yield and return in Ruby. I'm a Ruby beginner, so simple examples are highly appreciated.
Thank you in advance!
The return statement works the same way that it works on other similar programming languages, it just returns from the method it is used on.
You can skip the call to return, since all methods in ruby always return the last statement. So you might find method like this:
def method
"hey there"
end
That's actually the same as doing something like:
def method
return "hey there"
end
The yield on the other hand, excecutes the block given as a parameter to the method. So you can have a method like this:
def method
puts "do somthing..."
yield
end
And then use it like this:
method do
puts "doing something"
end
The result of that, would be printing on screen the following 2 lines:
"do somthing..."
"doing something"
Hope that clears it up a bit. For more info on blocks, you can check out this link.
yield is used to call the block associated with the method. You do this by placing the block (basically just code in curly braces) after the method and its parameters, like so:
[1, 2, 3].each {|elem| puts elem}
return exits from the current method, and uses its "argument" as the return value, like so:
def hello
return :hello if some_test
puts "If it some_test returns false, then this message will be printed."
end
But note that you don't have to use the return keyword in any methods; Ruby will return the last statement evaluated if it encounters no returns. Thus these two are equivelent:
def explicit_return
# ...
return true
end
def implicit_return
# ...
true
end
Here's an example for yield:
# A simple iterator that operates on an array
def each_in(ary)
i = 0
until i >= ary.size
# Calls the block associated with this method and sends the arguments as block parameters.
# Automatically raises LocalJumpError if there is no block, so to make it safe, you can use block_given?
yield(ary[i])
i += 1
end
end
# Reverses an array
result = [] # This block is "tied" to the method
# | | |
# v v v
each_in([:duck, :duck, :duck, :GOOSE]) {|elem| result.insert(0, elem)}
result # => [:GOOSE, :duck, :duck, :duck]
And an example for return, which I will use to implement a method to see if a number is happy:
class Numeric
# Not the real meat of the program
def sum_of_squares
(to_s.split("").collect {|s| s.to_i ** 2}).inject(0) {|sum, i| sum + i}
end
def happy?(cache=[])
# If the number reaches 1, then it is happy.
return true if self == 1
# Can't be happy because we're starting to loop
return false if cache.include?(self)
# Ask the next number if it's happy, with self added to the list of seen numbers
# You don't actually need the return (it works without it); I just add it for symmetry
return sum_of_squares.happy?(cache << self)
end
end
24.happy? # => false
19.happy? # => true
2.happy? # => false
1.happy? # => true
# ... and so on ...
Hope this helps! :)
def cool
return yield
end
p cool {"yes!"}
The yield keyword instructs Ruby to execute the code in the block. In this example, the block returns the string "yes!". An explicit return statement was used in the cool() method, but this could have been implicit as well.

How to redefine a Ruby constant without warning?

I'm running some Ruby code which evals a Ruby file every time its date changes. In the file, I have constant definitions, like
Tau = 2 * Pi
and, of course, they make the interpreter display the unwanted "already initialized constant" warning every time, so, I'd like to have the following functions:
def_if_not_defined(:Tau, 2 * Pi)
redef_without_warning(:Tau, 2 * Pi)
I could avoid the warning by writing all my constant definitions like this:
Tau = 2 * Pi unless defined?(Tau)
but it is inelegant and a bit wet (not DRY).
Is there a better way to def_if_not_defined? And how to redef_without_warning?
--
Solution thanks to Steve:
class Object
def def_if_not_defined(const, value)
mod = self.is_a?(Module) ? self : self.class
mod.const_set(const, value) unless mod.const_defined?(const)
end
def redef_without_warning(const, value)
mod = self.is_a?(Module) ? self : self.class
mod.send(:remove_const, const) if mod.const_defined?(const)
mod.const_set(const, value)
end
end
A = 1
redef_without_warning :A, 2
fail 'unit test' unless A == 2
module M
B = 10
redef_without_warning :B, 20
end
fail 'unit test' unless M::B == 20
--
This question is old. The above code is only necessary for Ruby 1.8. In Ruby 1.9, P3t3rU5's answer produces no warning and is simply better.
The following module may do what you want. If not it may provide some pointers to your solution
module RemovableConstants
def def_if_not_defined(const, value)
self.class.const_set(const, value) unless self.class.const_defined?(const)
end
def redef_without_warning(const, value)
self.class.send(:remove_const, const) if self.class.const_defined?(const)
self.class.const_set(const, value)
end
end
And as an example of using it
class A
include RemovableConstants
def initialize
def_if_not_defined("Foo", "ABC")
def_if_not_defined("Bar", "DEF")
end
def show_constants
puts "Foo is #{Foo}"
puts "Bar is #{Bar}"
end
def reload
redef_without_warning("Foo", "GHI")
redef_without_warning("Bar", "JKL")
end
end
a = A.new
a.show_constants
a.reload
a.show_constants
Gives the following output
Foo is ABC
Bar is DEF
Foo is GHI
Bar is JKL
Forgive me if i've broken any ruby taboos here as I am still getting my head around some of the Module:Class:Eigenclass structure within Ruby
Another approach, using $VERBOSE, to suppress warnings, is discussed here: http://mentalized.net/journal/2010/04/02/suppress_warnings_from_ruby/
Update 2020/5/6: In response to the comment that the link is now dead, I am pasting an example here from my old project, though I can't say whether and in what circumstances it is a good approach:
original_verbose = $VERBOSE
$VERBOSE = nil # suppress warnings
# do stuff that raises warnings you don't care about
$VERBOSE = original_verbose
If you want to redefine a value then don't use constants, use a global variable instead ($tau = 2 * Pi), but that's not a good practice too. You should make it an instance variable of a suitable class.
For the other case, Tau = 2 * Pi unless defined?(Tau) is perfectly alright and the most readable, therefore the most elegant solution.
Unless the values of the constants are pretty weird (i.e. you have constants set to nil or false), the best choice would be to use the conditional assignment operator: Tau ||= 2*Pi
This will set Tau to 2π if it is nil, false or undefined, and leave it alone otherwise.

Understanding Ruby Enumerable#map (with more complex blocks)

Let's say I have a function
def odd_or_even n
if n%2 == 0
return :even
else
return :odd
end
end
And I had a simple enumerable array
simple = [1,2,3,4,5]
And I ran it through map, with my function, using a do-end block:
simple.map do
|n| odd_or_even(n)
end
# => [:odd,:even,:odd,:even,:odd]
How could I do this without, say, defining the function in the first place? For example,
# does not work
simple.map do |n|
if n%2 == 0
return :even
else
return :odd
end
end
# Desired result:
# => [:odd,:even,:odd,:even,:odd]
is not valid ruby, and the compiler gets mad at me for even thinking about it. But how would I implement an equivalent sort of thing, that works?
edit
In reality, the solution to my problem matters to me a lot less than the motivation/reasoning behind it, to help me understand more how ruby blocks work :)
You're so close. Just remove the returns and you're golden.
This is because the block passed to map is a proc (i.e. created with Proc.new), and not a lambda. A return within a proc doesn't just jump out of the proc- it jumps out of the method that executed (i.e. called call on) the proc. A return within a lambda, on the other hand, jumps out of only the lambda.
The proc method returns a lambda in Ruby 1.8, and a Proc in Ruby 1.9. It's probably best to just not use this method and be explicit with which construct you want to use.
I'm guessing you were either in IRB or a plain ruby script when you were trying this out.
a = Proc.new { return }
a.call # fails. Nothing to return from.
def foobar
a = Proc.new { return }
a.call
puts 'hello' # not reached. The return within the proc causes execution to jump out of the foobar method.
end
foobar # succeeds, but does not print 'hello'. The return within the proc jumps out of the foobar method.
b = lambda { return }
b.call # succeeds. The return only returns from the lambda itself.
def bazquux
b = lambda { return }
b.call
puts 'hello' # this is reached. The lambda only returned from itself.
end
bazquux # succeeds, and prints 'hello'
The lesson to learn from this is to use implicit returns unless you can't, I guess.
I suspect this may be a duplicate question, but to give a value out of a block, use next
simple.map do |n|
if n%2 == 0
next :even
else
next :odd
end
end
Shortest variant using Andrew's answer:
simple.map { |n| next :even if n % 2 == 0; :odd }

Resources