Ruby - Calling a method from a loop within another method - ruby

Here's the problem...
I have a method that I'm calling to strip out characters and convert strings to floats.
def convert_to_float(currency)
return currency.gsub(/regex/, "").to_f
end
I have another method that is receiving string values. What I'm wanting to do is iterate those received strings through the convert_to_float method instead of applying the gsub to each line. Here is what I've got... is this even possible with the way I'm doing this?
def verify_amounts(total,subtotal,tax)
arrayoftotals = [total,subtotal,tax]
arrayoftotals.each do |convert_to_float|
end
ftotal = arrayoftotals[0]
raise "ftotal must be a Float" unless ftotal.kind_of? Float
end
So far its raising the fault stating that the type is not a float which is telling me that the do each loop isn't converting the values.
Help.
Thanks!!!

Sounds like you're looking for map:
arrayoftotals = [total, subtotal, tax].map { |x| convert_to_float(x) }
or, since convert_to_float is a method in the same class as verify_amounts, you could use the Object#method method to write it like this:
arrayoftotals = [total, subtotal, tax].map(&method(:convert_to_float))
For example, this:
class Pancakes
def convert_to_float(currency)
currency.gsub(/[^\d.]/, '').to_f
end
def verify_amounts(total, subtotal, tax)
arrayoftotals = [total, subtotal, tax].map(&method(:convert_to_float))
puts arrayoftotals.inspect
end
end
Pancakes.new.verify_amounts('where1.0', '2.is0', '3.0house')
will give you [1.0, 2.0, 3.0] on the standard output.

Upon closer inspection there are two things going wrong here.
Your syntax to pass a method as an iterative function is wrong.
arrayoftotals.each do |convert_to_float|
end
Works out to be an empty block where the local variable is called convert_to_float. The syntax you're looking for is:
arrayoftotals.each (&method (:convert_to_float))
This passes a Proc object referring to the method convert_to_float as your block.
You are not updating the values within arrayoftotals. So even if convert_to_float was being called, it wouldn't do anything.
Either change gsub to gsub! to destructively sanitize your strings in place, or use map! instead of each to replace each element in the array with the results of calling the function on it. map! is a better choice because it means you won't have to adjust every other usage of convert_to_float.
Putting it all together:
def convert_to_float(currency)
return currency.gsub(/regex/, "").to_f
end
def verify_amounts(total,subtotal,tax)
arrayoftotals = [total,subtotal,tax]
arrayoftotals.map! (&method (:convert_to_float)
ftotal = arrayoftotals[0]
raise "ftotal must be a Float" unless ftotal.kind_of? Float
end

Related

No implicit conversion of Enumerator into Array

I have:
qs = ["all=true", "limit=-1"]
value = ["agent", "service", "token"]
This code:
qs.concat value.map do |val|
"#{field}=#{val}"
end
ends up with the following error:
`concat': no implicit conversion of Enumerator into Array (TypeError)`
whereas this code:
values = value.map do |val|
"field=#{val}"
end
qs.concat values
does not.
What is the difference between them?
Your issue is caused by the different precedences when providing blocks to chained method calls. In your case you use the following code:
qs.concat value.map do |val|
"#{field}=#{val}"
end
Ruby assumes here that you mean the following:
qs.concat(value.map) do |val|
"#{field}=#{val}"
end
That is, Ruby passes the block to the first method (i.e qs.concat) which ignores the block. Since Array#map returns an Enumerator if you don't pass a block, you get your error you saw.
To solve this, you can use the braces form of passing the block, i.e.:
qs.concat value.map { |val|
"#{field}=#{val}"
}
In this form, the block is always passed to the "last" method, u.e. your map.
In any case, if there is any doubt about operator precedence, it is always a good idea to use explicit parenthesis or intermediate variables to make it clear both to human readers as well as the Ruby interpreter how your code is supposed to work.
When you say qs.concat value.map do |val|, what does do belong to? (Hint: not value.map!)
Use parentheses when uncertain.
qs=["all=true", "limit=-1"]
value=["agent", "service", "token"]
qs.concat(value.map do |val|
"field=#{val}"
end)
{...} would be more typical than do...end, and the priority works out so you don't actually need parentheses, as {...} do go to value.map rather than to qs.concat. This also works:
qs=["all=true", "limit=-1"]
value=["agent", "service", "token"]
qs.concat value.map { |val|
"field=#{val}"
}

Ruby Enumerable#find returning mapped value

Does Ruby's Enumerable offer a better way to do the following?
output = things
.find { |thing| thing.expensive_transform.meets_condition? }
.expensive_transform
Enumerable#find is great for finding an element in an enumerable, but returns the original element, not the return value of the block, so any work done is lost.
Of course there are ugly ways of accomplishing this...
Side effects
def constly_find(things)
output = nil
things.each do |thing|
expensive_thing = thing.expensive_transform
if expensive_thing.meets_condition?
output = expensive_thing
break
end
end
output
end
Returning from a block
This is the alternative I'm trying to refactor
def costly_find(things)
things.each do |thing|
expensive_thing = thing.expensive_transform
return expensive_thing if expensive_thing.meets_condition?
end
nil
end
each.lazy.map.find
def costly_find(things)
things
.each
.lazy
.map(&:expensive_transform)
.find(&:meets_condition?)
end
Is there something better?
Of course there are ugly ways of accomplishing this...
If you had a cheap operation, you'd just use:
collection.map(&:operation).find(&:condition?)
To make Ruby call operation only "on a as-needed basis" (as the documentation says), you can simply prepend lazy:
collection.lazy.map(&:operation).find(&:condition?)
I don't think this is ugly at all—quite the contrary— it looks elegant to me.
Applied to your code:
def costly_find(things)
things.lazy.map(&:expensive_transform).find(&:meets_condition?)
end
I would be inclined to create an enumerator that generates values thing.expensive_transform and then make that the receiver for find with meets_condition? in find's block. For one, I like the way that reads.
Code
def costly_find(things)
Enumerator.new { |y| things.each { |thing| y << thing.expensive_transform } }.
find(&:meets_condition?)
end
Example
class Thing
attr_reader :value
def initialize(value)
#value = value
end
def expensive_transform
self.class.new(value*2)
end
def meets_condition?
value == 12
end
end
things = [1,3,6,4].map { |n| Thing.new(n) }
#=> [#<Thing:0x00000001e90b78 #value=1>, #<Thing:0x00000001e90b28 #value=3>,
# #<Thing:0x00000001e90ad8 #value=6>, #<Thing:0x00000001e90ab0 #value=4>]
costly_find(things)
#=> #<Thing:0x00000001e8a3b8 #value=12>
In the example I have assumed that expensive_things and things are instances of the same class, but if that is not the case the code would need to be modified in the obvious way.
I don't think there is a "obvious best general solution" for your problem, which is also simple to use. You have two procedures involved (expensive_transform and meets_condition?), and you also would need - if this were a library method to use - as a third parameter the value to return, if no transformed element meets the condition. You return nil in this case, but in a general solution, expensive_transform might also yield nil, and only the caller knows what unique value would indicate that the condition as not been met.
Hence, a possible solution within Enumerable would have the signature
class Enumerable
def find_transformed(default_return_value, transform_proc, condition_proc)
...
end
end
or something similar, so this is not particularily elegant either.
You could do it with a single block, if you agree to merge the semantics of the two procedures into one: You have only one procedure, which calculates the transformed value and tests it. If the test succeeds, it returns the transformed value, and if it fails, it returns the default value:
class Enumerable
def find_by(default_value, &block)
result = default_value
each do |element|
result = block.call(element)
break if result != default_value
end
end
result
end
You would use it in your case like this:
my_collection.find_by(nil) do |el|
transformed_value = expensive_transform(el)
meets_condition?(transformed_value) ? transformed_value : nil
end
I'm not sure whether this is really intuitive to use...

Ruby yield example explanation?

I'm doing a SaaS course with Ruby. On an exercise, I'm asked to calculate the cartesian product of two sequences by using iterators, blocks and yield.
I ended up with this, by pure guess-and-error, and it seems to work. But I'm not sure about how. I seem to understand the basic blocks and yield usage, but this? Not at all.
class CartProd
include Enumerable
def initialize(a,b)
#a = a
#b = b
end
def each
#a.each{|ae|
#b.each{|be|
yield [ae,be]
}
}
end
end
Some explanation for a noob like me, please?
(PS: I changed the required class name to CartProd so people doing the course can't find the response by googling it so easily)
Let's build this up step-by-step. We will simplify things a bit by taking it out of the class context.
For this example it is intuitive to think of an iterator as being a more-powerful replacement for a traditional for-loop.
So first here's a for-loop version:
seq1 = (0..2)
seq2 = (0..2)
for x in seq1
for y in seq2
p [x,y] # shorthand for puts [x, y].inspect
end
end
Now let's replace that with more Ruby-idiomatic iterator style, explicitly supplying blocks to be executed (i.e., the do...end blocks):
seq1.each do |x|
seq2.each do |y|
p [x,y]
end
end
So far, so good, you've printed out your cartesian product. Now your assignment asks you to use yield as well. The point of yield is to "yield execution", i.e., pass control to another block of code temporarily (optionally passing one or more arguments).
So, although it's not really necessary for this toy example, instead of directly printing the value like above, you can yield the value, and let the caller supply a block that accepts that value and prints it instead.
That could look like this:
def prod(seq1, seq2)
seq1.each do |x|
seq2.each do |y|
yield [x,y]
end
end
end
Callable like this:
prod (1..2), (1..2) do |prod| p prod end
The yield supplies the product for each run of the inner loop, and the yielded value is printed by the block supplied by the caller.
What exactly do you not understand here? You've made an iterator that yields all possible pairs of elements. If you pass CartProd#each a block, it will be executed a.length*b.length times. It's like having two different for cycles folded one into another in any other programming language.
yield simply passes (yields) control to a block of code that has been passed in as part of the method call. The values after the yield keyword are passed into the block as arguments. Once the block has finished execution it passes back control.
So, in your example you could call #each like this:
CartProd.new([1, 2], [3, 4]).each do |pair|
# control is yielded to this block
p pair
# control is returned at end of block
end
This would output each pair of values.

ruby and references. Working with fixnums

I know a bit about ruby way to handle objects and references. The replace stuff, ect ...
I know it d'ont work on fixnum, cause the var is the fixnum. But i wish to change the value of a fixnum inside a function, and that the value changed in the ouside var.
How can i do this ?
I guess i can use a string like this "1" but that's quite dirty.
Ruby will always pass-by-reference (because everything is an object) but Fixnum lacks any methods that allow you to mutate the value. See "void foo(int &x) -> Ruby? Passing integers by reference?" for more details.
You can either return a value that you then assign to your variable, like so:
a = 5
def do_something(value)
return 1 #this could be more complicated and depend on the value passed in
end
a = do_something(a)
or you could wrap your value in an object such as a Hash and have it updated that way.
a = {:value => 5}
def do_something(dict)
dict[:value] = 1
end
do_something(a) #now a[:value] is 1 outside the function
Hope this helps.
You could pass an array with a single number, like [1], or a hash like {value: 1}. Less ugly than a string, as your number itself remains a number, but less overhead than a new class...
When I was building a game I had the same problem you have. There was a numeric score that represented how many zombies you've killed and I needed to manually keep it in sync between Player (that incremented the score), ScoreBar and ScoreScreen (that displayed the score). The solution I've found was creating a separate class for the score that will wrap the value and mutate it:
class Score
def initialize(value = 0)
#value = value
end
def increment
#value += 1
end
def to_i
#value
end
def to_s
#value.to_s
end
end

Elegant way of duck-typing strings, symbols and arrays?

This is for an already existing public API that I cannot break, but I do wish to extend.
Currently the method takes a string or a symbol or anything else that makes sense when passed as the first parameter to send
I'd like to add the ability to send a list of strings, symbols, et cetera. I could just use is_a? Array, but there are other ways of sending lists, and that's not very ruby-ish.
I'll be calling map on the list, so the first inclination is to use respond_to? :map. But a string also responds to :map, so that won't work.
How about treating them all as Arrays? The behavior you want for Strings is the same as for an Array containing only that String:
def foo(obj, arg)
[*arg].each { |method| obj.send(method) }
end
The [*arg] trick works because the splat operator (*) turns a single element into itself or an Array into an inline list of its elements.
Later
This is basically just a syntactically sweetened version or Arnaud's answer, though there are subtle differences if you pass an Array containing other Arrays.
Later still
There's an additional difference having to do with foo's return value. If you call foo(bar, :baz), you might be surprised to get [baz] back. To solve this, you can add a Kestrel:
def foo(obj, arg)
returning(arg) do |args|
[*args].each { |method| obj.send(method) }
end
end
which will always return arg as passed. Or you could do returning(obj) so you could chain calls to foo. It's up to you what sort of return-value behavior you want.
A critical detail that was overlooked in all of the answers: strings do not respond to :map, so the simplest answer is in the original question: just use respond_to? :map.
Since Array and String are both Enumerables, there's not an elegant way to say "a thing that's an Enumberable, but not a String," at least not in the way being discussed.
What I would do is duck-type for Enumerable (responds_to? :[]) and then use a case statement, like so:
def foo(obj, arg)
if arg.respond_to?(:[])
case arg
when String then obj.send(arg)
else arg.each { |method_name| obj.send(method_name) }
end
end
end
or even cleaner:
def foo(obj, arg)
case arg
when String then obj.send(arg)
when Enumerable then arg.each { |method| obj.send(method) }
else nil
end
end
Perhaps the question wasn't clear enough, but a night's sleep showed me two clean ways to answer this question.
1: to_sym is available on String and Symbol and should be available on anything that quacks like a string.
if arg.respond_to? :to_sym
obj.send(arg, ...)
else
# do array stuff
end
2: send throws TypeError when passed an array.
begin
obj.send(arg, ...)
rescue TypeError
# do array stuff
end
I particularly like #2. I severely doubt any of the users of the old API are expecting TypeError to be raised by this method...
Let's say your function is named func
I would make an array from the parameters with
def func(param)
a = Array.new
a << param
a.flatten!
func_array(a)
end
You end up with implementing your function func_array for arrays only
with func("hello world") you'll get a.flatten! => [ "hello world" ]
with func(["hello", "world"] ) you'll get a.flatten! => [ "hello", "world" ]
Can you just switch behavior based on parameter.class.name? It's ugly, but if I understand correctly, you have a single method that you'll be passing multiple types to - you'll have to differentiate somehow.
Alternatively, just add a method that handles an array type parameter. It's slightly different behavior so an extra method might make sense.
Use Marshal to serialize your objects before sending these.
If you don't want to monkeypatch, just massage the list to an appropriate string before the send. If you don't mind monkeypatching or inheriting, but want to keep the same method signature:
class ToBePatched
alias_method :__old_takes_a_string, :takes_a_string
#since the old method wanted only a string, check for a string and call the old method
# otherwise do your business with the map on things that respond to a map.
def takes_a_string( string_or_mappable )
return __old_takes_a_string( string_or_mappable ) if String === string_or_mappable
raise ArgumentError unless string_or_mappable.responds_to?( :map )
# do whatever you wish to do
end
end
Between those 3 types I'd do this
is_array = var.respond_to?(:to_h)
is_string = var.respond_to?(:each_char)
is_symbol = var.respond_to?(:to_proc)
Should give a unique answer for [], :sym, 'str'

Resources