Ruby: Is it ok for a method to return an object of different types? - ruby

Is it a good idea to return an object whose type changes depending on the method’s inner logic?
E.g.:
class Error
attr_reader :details
def initialize(details)
#details = details
end
end
def div(a, b)
return Error.new("error: division by zero") if b == 0
a / b
end
# declare foo, bar here
result = div(foo, bar)
if result.is_a?(Error)
puts result.details
else
puts "result of division: #{result}"
end
As you can tell, the div method returns either an Error instance, or an Integer instance.
Is it a bad practice (and why)? Does it violate the single responsibility principle?
By the way, I do get that another option would be to return a hash { error: error, div_result: div_result }, but I’m curious if it could be replaced with only one single object.
Thank you.

You seem to be reinventing the wheel. Ruby already has Exception Handling and it also includes a ZeroDivisionError which is raised when dividing an integer by zero:
def div(a, b)
a / b
end
begin
result = div(6, 0)
puts "result of division: #{result}"
rescue ZeroDivisionError => e
puts "error: #{e.message}"
end
# prints "error: divided by 0"
Note that your div method isn't needed either, you can just as well write result = 6 / 0.
Is it a good idea to return an object whose type changes depending on the method’s inner logic?
"type" is a difficult term in Ruby. I assume you mean something like "an instance of a specific class" like an integer or a string? It really depends. For most methods it would certainly be a good idea, but there are good exceptions to this rule.
Integer#+ for example returns a result based on its argument: (you could argue that these are all subclasses of Numeric)
1 + 2 #=> 3 (Integer)
1 + 2.0 #=> 3.0 (Float)
1 + 2r #=> (3/1) (Rational)
String#index usually returns an integer but it may also return nil to indicate "not found":
"hello".index("o") #=> 4 (Integer)
"hello".index("x") #=> nil (NilClass)
Array#[] returns whatever object is stored at the specified index, thus having arbitrary return values:
a = [123, :foo, "bar"]
a[0] #=> 123 (Integer)
a[1] #=> :foo (Symbol)
a[2] #=> "bar" (String)
a[3] #=> nil (NilClass)

Related

Give the code below, I was told that if a hash is called and pass through as argument, I can't return Nil. Can anyone explain to me how come?

def key_for_min_value(name_hash)
name_hash.max_by {|k, v| 0-v}[0]
end
This was my code to fulfill the test suite for finding the lowest value of a hash (this was for one of my lessons online).
I know there are much easier ways to do this but I had some restrictions, as you can see below:
**A Few Restrictions:
We want you to build this on your own. Some of the following methods are helpful but off limits for this exercise. (We'll cover a few below in more depth in subsequent lessons).
I could not use keys, values, min, sort, min_by to make it pass.
This code returned the key with the lowest value (a hash of key ==> integers) but here was the requirement I could not figure out.
If the method is called and passed an argument of an empty hash, it should return nil.
Only first month programming, so this may be obvious but is there a way to return nil for an empty hash, and keep my existing code intact?
Thanks for your help
To a beginner programmer I would recommend to print all intermediate results of expressions, or work in IRB.
def key_for_min_value(name_hash)
puts
puts "in key_for_min_value with parameter #{name_hash}"
# puts "about to return nil" if name_hash.empty?
# return nil if name_hash.empty?
name_hash.max_by { | item | puts "item=#{item}" }
max = name_hash.max_by do | k, v |
puts "k=#{k} v=#{v} 0 - v = #{0 - v}"
0 - v
end
puts "max=#{max.inspect}, class of value returned by max_by : #{max.class}"
result = name_hash.max_by {|k, v| 0-v}[0]
puts "result=#{result.inspect}"
result
end
key_for_min_value({a: 1, b: 2, c: 3})
key_for_min_value({})
Execution :
$ ruby -w t.rb
in key_for_min_value with parameter {:a=>1, :b=>2, :c=>3}
item=[:a, 1]
item=[:b, 2]
item=[:c, 3]
k=a v=1 0 - v = -1
k=b v=2 0 - v = -2
k=c v=3 0 - v = -3
max=[:a, 1], class of value returned by max_by : Array
result=:a
in key_for_min_value with parameter {}
max=nil, class of value returned by max_by : NilClass
t.rb:15:in `key_for_min_value': undefined method `[]' for nil:NilClass (NoMethodError)
from t.rb:21:in `<main>'
The documentation of enum.max_by says :
Returns the item corresponding to the largest value returned by the
block.
But if the enum is empty, it returns nil, from which you fetch element [0], which causes the error because there is no such method in the NilClass.
If you add return nil if name_hash.empty? at the beginning of the method, you prevent it to happen (with two uncommented lines) :
$ ruby -w t.rb
in key_for_min_value with parameter {:a=>1, :b=>2, :c=>3}
...
in key_for_min_value with parameter {}
about to return nil
There a lot of different possibilities to do what you want. The most obvious one is to literally translate the sentence: "return nil if the hash is empty" into Ruby:
def key_for_min_value(name_hash)
return nil if name_hash.empty?
name_hash.max_by {|k, v| 0-v}[0]
end
Another possibility would be to use the safe navigation operator:
def key_for_min_value(name_hash)
name_hash.max_by {|k, v| 0-v}&.[](0)
end
Yet another way would be to ensure that the value you are trying to index into is never nil:
def key_for_min_value(name_hash)
(name_hash.max_by {|k, v| 0-v} || [])[0]
end
# or
def key_for_min_value(name_hash)
Array(name_hash.max_by {|k, v| 0-v})[0]
end

Non destructively append object to an array with Ruby

So I need to create an instance method for Array that takes two arguments, the size of an array and an optional object that will be appended to an array.
If the the size argument is less than or equal to the Array.length or the size argument is equal to 0, then just return the array. If the optional argument is left blank, then it inputs nil.
Example output:
array = [1,2,3]
array.class_meth(0) => [1,2,3]
array.class_meth(2) => [1,2,3]
array.class_meth(5) => [1,2,3,nil,nil]
array.class_meth(5, "string") => [1,2,3,"string","string"]
Here is my code that I've been working on:
class Array
def class_meth(a ,b=nil)
self_copy = self
diff = a - self_copy.length
if diff <= 0
self_copy
elsif diff > 0
a.times {self_copy.push b}
end
self_copy
end
def class_meth!(a ,b=nil)
# self_copy = self
diff = a - self.length
if diff <= 0
self
elsif diff > 0
a.times {self.push b}
end
self
end
end
I've been able to create the destructive method, class_meth!, but can't seem to figure out a way to make it non-destructive.
Here's (IMHO) a cleaner solution:
class Array
def class_meth(a, b = nil)
clone.fill(b, size, a - size)
end
def class_meth!(a, b = nil)
fill(b, size, a - size)
end
end
I think it should meet all your needs. To avoid code duplication, you can make either method call the other one (but not both simulaneously, of course):
def class_meth(a, b = nil)
clone.class_meth!(a, b)
end
or:
def class_meth!(a, b = nil)
replace(class_meth(a, b))
end
As you problem has been diagnosed, I will just offer a suggestion for how you might do it. I assume you want to pass two and optionally three, not one and optionally two, parameters to the method.
Code
class Array
def self.class_meth(n, arr, str=nil)
arr + (str ? ([str] : [nil]) * [n-arr.size,0].max)
end
end
Examples
Array.class_meth(0, [1,2,3])
#=> [1,2,3]
Array.class_meth(2, [1,2,3])
#=> [1,2,3]
Array.class_meth(5, [1,2,3])
#=> [1,2,3,nil,nil]
Array.class_meth(5, [1,2,3], "string")
#=> [1,2,3,"string","string"]
Array.class_meth(5, ["dog","cat","pig"])
#=> [1,2,3,"string","string"]
Array.class_meth(5, ["dog","cat","pig"], "string")
#=> [1,2,3,"string","string"]
Array.class_meth(5, ["dog","cat","pig"])
#=> ["dog", "cat", "pig", nil, nil]
Array.class_meth(5, ["dog","cat","pig"], "string")
#=> ["dog", "cat", "pig", "string", "string"]
Before withdrawing his answer, #PatriceGahide suggested using Array#fill. That would be an improvement here; i.e., replace the operative line with:
arr.fill(str ? str : nil, arr.size, [n-arr.size,0].max)
self_copy = self does not make a new object - assignment in Ruby never "copies" or creates a new object implicitly.
Thus the non-destructive case works on the same object (the instance the method was invoked upon) as in the destructive case, with a different variable bound to the same object - that is self.equal? self_copy is true.
The simplest solution is to merely use #clone, keeping in mind it is a shallow clone operation:
def class_meth(a ,b=nil)
self_copy = self.clone # NOW we have a new object ..
# .. so we can modify the duplicate object (self_copy)
# down here without affecting the original (self) object.
end
If #clone cannot be used other solutions involve create a new array or obtain an array #slice (returns a new array) or even append (returning a new array) with #+; however, unlike #clone, these generally lock-into returning an Array and not any sub-type as may be derived.
After the above change is made it should also be apparent that it can written as so:
def class_meth(a ,b=nil)
clone.class_meth!(a, b) # create a NEW object; modify it; return it
# (assumes class_meth! returns the object)
end
A more appropriate implementation of #class_meth!, or #class_meth using one of the other forms to avoid modification of the current instance, is left as an exercise.
FWIW: Those are instance methods, which is appropriate, and not "class meth[ods]"; don't be confused by the ill-naming.

Difference between += for Integers/Strings and << For Arrays?

I'm confused about the different results I'm getting when performing simple addition/concatenation on integers, strings and arrays in Ruby. I was under the impression that when assigning variable b to a (see below), and then changing the value of a, that b would remain the same. And it does so in the first two examples. But when I modify Array a in the 3rd example, both a and b are modified.
a = 100
b = a
a+= 5
puts a
puts b
a = 'abcd'
b = a
a += 'e'
puts a
puts b
a = [1,2,3,4]
b = a
a << 5
puts a.inspect
puts b.inspect
The following is what was returned in Terminal for the above code:
Ricks-MacBook-Pro:programs rickthomas$ ruby variablework.rb
105
100
abcde
abcd
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
Ricks-MacBook-Pro:programs rickthomas$
I was given the following explanation by my programming instructor:
Assigning something to a new variable is just giving it an additional label, it doesn't make a copy.
It looks like += is a method, just like <<, and so you'd expect it to behave similarly. But in reality, it's "syntactic sugar", something added to the language to make things easier on developers.
When you run a += 1, Ruby converts that to a = a + 1.
In this case, we're not modifying the Fixnum in a. Instead, we're actually re-assigning on top of it, effectively blowing away the previous value of a.
On the other hand, when you run b << "c", you're modifying the underlying Array by appending the String "c" to it.
My questions are these:
1) He mentions syntactic sugar, but isn't that also what << is, i.e. syntactic sugar for the .push method?
2) Why would it matter if += is syntactic sugar or a more formal method? If there is some difference between the two, then doesn't that mean my previously-understood of syntactic sugar ("syntax within a programming language that is designed to make things easier to read or to express") is incomplete, since this isn't its only purpose?
3) If assigning b to a doesn't make a copy of a, then why doesn't wiping away a's old value mean that b's old value is also wiped away for all 3 cases (Integer, String and Array)?
As you can see, I'm pretty turned around on something that I thought I understood until now. Any help is much appreciated!
You see, names (variable names, like a and b) don't hold any values themselves. They simply point to a value. When you make an assignment
a = 5
then a now points to value 5, regardless of what it pointed to previously. This is important.
a = 'abcd'
b = a
Here both a and b point to the same string. But, when you do this
a += 'e'
It's actually translated to
a = a + 'e'
# a = 'abcd' + 'e'
So, name a is now bound to a new value, while b keeps pointing to "abcd".
a = [1,2,3,4]
b = a
a << 5
There's no assignment here, method << modifies existing array without replacing it. Because there's no replacement, both a and b still point to the same array and one can see the changes made to another.
The answer to 1) and 2) of your question:
The reason why += is syntactic sugar and << is not is fairly simple: += abstracts some of the syntactic expression: a += 1 is just a short version of a = a + 1. << is a method all by itself and is not an alias for push: << can only take one argument, whereas push can take an arbitrary number of arguments: I'm demonstrating this with send here, since [1,2]<<(1,2) is syntactically incorrect:
[1,2].send(:<<, 4, 5) #=> ArgumentError: wrong number of arguments (2 for 1)
push appends all arguments to the array:
[1,2].push(4,5,6) #=> [1,2,4,5,6]
Therefore, << is an irreplaceable part of the ruby array, since there is no equivalent method. One could argue that it is some kind of syntactic sugar for push, with disregard for the differences shown above, since it makes most operations involving appending elements to an array simpler and syntactically more recognizable.
If we go deeper and have a look at the different uses of << throughout ruby:
Push An Element to an array:
[1,2] << 5
concatenate a string to another, here, << is actually an alias for concat
"hello " << "world"
Open up the singleton class and define a method on a class:
class Foo
class << self
def bar
puts 'baz'
end
end
end
And last but not least append self to self in Integers:
1 << 2 #translates to ((1 + 1) + (1 + 1))
We can see that << actually stands for append throughout ruby, since it always appears in a context where something is appended to something already existing. I would therefore rather argue that << is a significant part of the ruby syntax and not syntactic sugar.
And the answer to 3)
The reason why b's assignment is not modified (or wiped of its old value, as you put it) if you use the += operator is just that a += 1, as a short for a = a + 1, reassigns a's value and therefore assigns a new object along with that. << is modifying the original object. You can easily see this using the object_id:
a = 1
b = a
b.object_id == a.object_id #=> true
a += 1
b.object_id == a.object_id #=> false
a = [1,2]
b = a
b.object_id == a.object_id #=> true
a << 3
b.object_id == a.object_id #=> true
There are also some caveats to Integer instances (100, 101) and so on: the same number is always the same object, since it does not make any sense to have multiple instances of, for example 100:
a = 100
b = a
b.object_id == a.object_id #=> true
a += 1
b.object_id == a.object_id #=> false
a -= 1
b.object_id == a.object_id #=> true
This also shows that the value, or the Integer instance (100) is just assigned to the variable, so the variable itself is not an object, it just points to it.
String#+ :: str + other_str → new_str Concatenation—Returns a new String containing other_str concatenated to str.
String#<< :: str << integer → str : Append—Concatenates the given object to str.
<< doesn't create the new object, where as + does.
Sample1:
a = 100
p a.object_id
b = a
p b.object_id
a+= 5
p a.object_id
p b.object_id
puts a
puts b
Output:
201
201
211
201
105
100
Your example:
a = 100
b = a
a+= 5
is equivalent to:
a = 100
b = a
a = 100 + 5
Afterwards a holds a reference to 105 and b still holds a reference to 100. This is how assignment works in Ruby.
You expected += to change the object instance 100. In Ruby, however (quoting the docs):
There is effectively only one Fixnum object instance for any given integer value
So there's only one object instance for 100 and another (but always the same) one for 105. Changing 100 to 105 would change all 100's to 105. Therefore, it is not possible to modify these instances in Ruby, they are fixed.
A String instance on the other hand can be modified and unlike Integer there can be multiple instances for the same sequence of bytes:
a = "abcd"
b = "abcd"
a.equal? b # returns true only if a and b are the same object
# => false
a << "e" concatenates "e" to a, thus changing the receiver: a is still referencing the same object instance.
Other methods like a += "e" return (and assign) a new String: a would reference this new instance afterwards.
The documentation is pretty clear:
str + other_str → new_str
Concatenation—Returns a new String containing other_str concatenated to str.
str << obj → str
Append—Concatenates the given object to str.
I can answer your questions.
1) No, the << method is not syntactic sugar for push. They are both methods with different names. You can have objects in Ruby that define one but not the other (for example String).
2) For a normal method like <<, the only thing that can happen as a result of a << x is that the object that a is pointing to gets modified. The statements a << x or a.push(x) cannot create a new object and change the variable a to point at it. That's just how Ruby works. This kind of thing is called "calling a method".
The reason that += being syntactic sugar matters is that means it can be used to modify a variable without mutating the old object that the variable used to point to. Consider a += x. That statement can modify what object a is pointing to because it is syntactic sugar for an actual assignment to a:
a = a + x
There are two things happening above. First the + method is called on a with one argument of x. Then the return value of the + method, whatever it is, is assigned to the variable a.
3) The reason that your Array case is different is because you chose to mutate the array instead of creating a new array. You could have used += to avoid mutating the array. I think that these six examples that will clear things up for you and show you what is possible in Ruby:
Strings without mutations
a = "xy"
b = a
a += "z"
p a # => "xyz"
p b # => "xy"
Strings with mutations
a = "xy"
b = a
a << "z"
p a # => "xyz"
p b # => "xyz"
Arrays without mutations
a = [1, 2, 3]
b = a
a += [4]
p a # => [1, 2, 3, 4]
p b # => [1, 2, 3]
Arrays with mutations
a = [1, 2, 3]
b = a
a.concat [4]
p a # => [1, 2, 3, 4]
p b # => [1, 2, 3, 4]
Integers without mutations
a = 100
b = a
a += 5
puts a # => 105
puts b # => 100
Integers with mutations
Mutating an integer is actually not possible in Ruby. Writing a = b = 89 actually does create two copies of the number 89, and the number cannot be mutated ever. Only a few, special types of objects behave like this.
Conclusion
You should think of a variable as just a name, and an object as a nameless piece of data.
All objects in Ruby can be used in an immutable way where you never actually modify the contents of an object. If you do it that way, then you don't have to worry about the b variable in our examples changing on its own; b will always point to the same object and that object will never change. The variable b will only change when you do some form of b = x.
Most objects in Ruby can be mutated. If you have several variables referring to the same object and you choose to mutate the object (e.g. by calling push), then that change will affect all the variables that are pointing to the object. You cannot mutate Symbols and Integers.
I guess the above answers explain the reason. Note also that if you want to ensure b is no pointer, you can use b = a.dup instead of b=a (dup for duplicate )
I'll try and answer your question to the best of my ability.
Yes, both are "sugars" but they work differently and as Sergio Tulentsev said, << it's not really a sugar but it's an alias.
And those works as an alias in Unix like languages, it's a shorter shorthand for something named after your liking.
So for the first scenario: += basically what's happening is that you're saying:
for the value 100 assign label 'a'.
for label 'b' assign the value of label 'a'.
for label 'a' take the value of label 'a' and add 5 to label 'a's value and return a new value
print label 'a' #this now holds the value 105
print label 'b' #this now holds the value 100
Under the hood of Ruby this has to do with the += returning a new String when that happens.
For the second scenario: << it's saying:
for value [1,2,3,4] assign label 'a'
for label 'b' assign the value of label 'a'
for label 'a' do the '<<' thing on the value of label 'a'.
print label 'a'
print label 'b'
And if you're applying the << to a string it will modify the existing object and append to it.
So what's different. Well the difference is that the << sugar doesn't act like this:
a is the new value of a + 5
it acts like this:
5 into the value of 'a'
2) Because the way you use the syntactic sugar in this case is making it easier for the
developer to read and understand the code. It's a shorthand.
Well, shorthands, if you call them that instead, do serve diffrent purposes.
The syntactic sugar isn't homogenous ie. it doesn't work the same way for all "sugars".
3) On wiping values:
It's like this.
put value 100 into the label 'a'
put the value of label 'a' into label 'b'
remove label 'a' from the value.
So
a = 100
b = a
a = nil
puts a
puts b
=> 100
Variables in Ruby doesn't hold values they point to values!

How to increment an Integer variable by X without creating a new object instance

How can I increment an Integer variable by X without creating a new object instance?
+= does not work because:
ree-1.8.7-2010.02 > x = 1
1
ree-1.8.7-2010.02 > x.object_id
3
ree-1.8.7-2010.02 > x += 1
2
ree-1.8.7-2010.02 > x.object_id
5
You can't. Not in Ruby, and not in any other programming language I am aware of.
The object which represents the mathematical number 1 will always have the value 1. Mutating the object which represents the mathematical number 1 to suddenly have the value 2 would quite simply be insane, because now all of a sudden 1 + 1 == 4.
Extend your example for a moment. Try this:
x = 2
y = 1 + 1
x.object_id
y.object_id
Every unique number will have its own identity. Ruby's object orientedness goes a bit deeper than you will find with C++ and Java (both of those have the concept of primitives and classes).
What's important is that when you query x the second time for its value the value will be what you expect. Object identifiers don't really matter unless you are the garbage collector.
It gets worse with Bignums
begin
a = 1234567890
puts a.object_id
b = 1234567890
puts b.object_id
end
gave me
10605136
10604960
Execution time is really terrible even if just you organize a simple loop. Primitives shouldn't be ditched from Ruby.
(1..16000).each do
(1..16000).each do
end
end
This itself takes 30-40 seconds to complete (Lenovo T400, Virtualboxed Ubuntu), and you haven't even done something sophisticated.
You can use a helper class:
class Variable
def initialize value = nil
#value = value
end
attr_accessor :value
def method_missing *args, &blk
#value.send(*args, &blk)
end
def to_s
#value.to_s
end
# here's the increment/decrement part
def inc x = 1
#value += x
end
def dec x = 1
#value -= x
end
end
x = Variable.new 1
puts x #=> 1
puts x.object_id #=> 22456116 (or whatever)
x.inc
puts x #=> 2
puts x.object_id #=> 22456116
x.inc 3
puts x #=> 5
puts x.object_id #=> 22456116
More uses of "class Variable" here.

How do I write a Ruby method to handle zero, one, or many inputs?

I've got a Ruby method like the following:
# Retrieve all fruits from basket that are of the specified kind.
def fruits_of_kind(kind)
basket.select { |f| f.fruit_type == kind.to_s }
end
Right now, you can call this like:
fruits_of_kind(:apple) # => all apples in basket
fruits_of_kind('banana') # => all bananas in basket
and so on.
How do I change the method so that it will correctly handle iterable inputs as well as no inputs and nil inputs? For example, I'd like to be able to support:
fruits_of_kind(nil) # => nil
fruits_of_kind(:apple, :banana) # => all apples and bananas in basket
fruits_of_kind([:apple, 'banana']) # => likewise
Is this possible to do idiomatically? If so, what's the best way to write methods so that they can accept zero, one, or many inputs?
You need to use the Ruby splat operator, which wraps all remaining arguments into an Array and passes them in:
def foo (a, b, *c)
#do stuff
end
foo(1, 2) # a = 1, b = 2, c = []
foo(1, 2, 3, 4, 5) #a = 1, b = 2, c = [3, 4, 5]
In your case, something like this should work:
def fruits_of_kind(*kinds)
kinds.flatten!
basket.select do |fruit|
kinds.each do |kind|
break true if fruit.fruit_type == kind.to_s
end == true #if no match is found, each returns the whole array, so == true returns false
end
end
EDIT
I changed the code to flatten kinds so that you can send in a list. This code will handle entering no kinds at all, but if you want to expressly input nil, add the line kinds = [] if kinds.nil? at the beginning.
Use the VARARGS feature of Ruby.
# Retrieve all fruits from basket that are of the specified kind.
# notice the * prefix used for method parameter
def fruits_of_kind(*kind)
kind.each do |x|
puts x
end
end
fruits_of_kind(:apple, :orange)
fruits_of_kind()
fruits_of_kind(nil)
-sasuke
def fruits_of_kind(kind)
return nil if kind.nil?
result = []
([] << kind).flatten.each{|k| result << basket.select{|f| f.fruit_type == k.to_s }}
result
end
The 'splat' operator is probably the best way to go, but there are two things to watch out for: passing in nil or lists. To modify Pesto's solution for the input/output you'd like, you should do something like this:
def fruits_of_kind(*kinds)
return nil if kinds.compact.empty?
basket.select do |fruit|
kinds.flatten.each do |kind|
break true if fruit.fruit_type == kind.to_s
end == true #if no match is found, each returns the whole array, so == true returns false
end
end
If you pass in nil, the * converts it to [nil]. If you want to return nil instead of an empty list, you have to compact it (remove nulls) to [], then return nil if it's empty.
If you pass in a list, like [:apple, 'banana'], the * converts it to [[:apple, 'banana']]. It's a subtle difference, but it's a one-element list containing another list, so you need to flatten kinds before doing the "each" loop. Flattening will convert it to [:apple, 'banana'], like you expect, and give you the results you're looking for.
EDIT: Even better, thanks to Greg Campbell:
def fruits_of_kind(basket, kind)
return nil if kind.nil?
kind_list = ([] << kind).flatten.map{|kind| kind.to_s}
basket.select{|fruit| kind_list.include?(fruit) }
end
OR (using splat)
def fruits_of_kind(*kinds)
return nil if kinds.compact.empty?
kind_list = kinds.flatten.map{|kind| kind.to_s}
basket.select{|fruit| kind_list.include?(fruit.fruit_type) }
end
There's a nicely expressive use of splat as an argument to array creation that handles your last example:
def foo(may_or_may_not_be_enumerable_arg)
arrayified = [*may_or_may_not_be_enumerable_arg]
arrayified.each do |item|
puts item
end
end
obj = "one thing"
objs = ["multiple", "things", 1, 2, 3]
foo(obj)
# one thing
# => ["one thing"]
foo(objs)
# multiple
# things
# 1
# 2
# 3
# => ["multiple", "things", 1, 2, 3]

Resources