Ruby on Rails - Ruby’s Swiss Army Knife: The Enumerable Module - ruby on rails tutorial - rails guides - rails tutorial - ruby rails
What is Ruby’s Swiss Army Knife?
- Ruby’s Enumerable module is a kind of Swiss Army Knife, capable of solving a variety of problems with specific, compact tools.
![learn ruby tutorial - representation of ruby on rail swiss knife -ruby example](https://wikitechy.com/tutorials/ruby-on-rails/img/ruby-on-rails-images/ruby-on-rail-swiss-knife-representation.png)
Learn ruby - ruby tutorial - representation of ruby on rail swiss knife - ruby examples - ruby programs
- In many suitations where publics write Ruby that isn’t natural, similar to Java or Python in style, it’s because they don’t have a deep understanding of the smart tools offered by Enumerable. Enumerable is one of Ruby’s modules. In Ruby, a module is a collection of methods, classes and/or constants inside a particular namespace. A namespace is a unique environment or naming scheme that prevents collisions in behavior. In case, we can have two methods called #each in my program, and use them at the same time, as long as they are in a different namespace. The Enumerable module can be mixed into any class that creates objects that may need to be compared, sorted, examined, or categorized. If you’ve worked with Arrays or Hashes in Ruby, you may have already performed these kinds of operations on them, iterating over them with #each or sorting array items with #sort. Enumerable allows you to quickly implement these kinds of behaviors in your own classes. Before we joint into creating a class that utilizes Enumerable, let’s take a look at five Enumerable methods that will give you some idea of the power of this module. The following five methods are
- #collect,
- #select,
- #reject,
- #detect,
- #inject.
- They can solve problems in one line that would otherwise require writing more complex conditional logic from scratch.
- A deep knowledge of each of these methods will make you a much better Ruby programmer.
ruby on rails tutorial tags - ruby , rail , ruby on rails , rail forum , ruby on rails tutorial , ruby tutorial , rails guides , rails tutorial , learn ruby
Going beyond #each
- Learning #each is often the moment when programmers coming from other languages start to appreciate the uniqueness of Ruby.
![learn ruby tutorial - #each graph in ruby on rail swiss knife -ruby example](https://wikitechy.com/tutorials/ruby-on-rails/img/ruby-on-rails-images/ruby-on-rail-swiss-knife-each-graph.png)
Learn ruby - ruby tutorial - #each graph in ruby on rail swiss knife - ruby examples - ruby programs
Sample Code:
names = ['Apple', 'Orange', 'Pine Apple']
for name in names
puts name
end
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
You can write:
names = ['Apple', 'Orange', 'Pine Apple']
names.each do |name|
puts name
end
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
Or, even more briefly:
names = ['Apple', 'Orange', 'Pine Apple']
names.each { |name| puts name }
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
- While some programmers feel Ruby’s #each syntax is more readable than a for loop, it’s not necessarily less effusive.
- Even so, using #each is the most common way for Rubyists to handle iteration.
- Many people learning Ruby will stop here. Having learned #each, they will add conditional logic to #each blocks to perform tasks that “The Ects” are built to handle.
- If your code is scattered with usage of the #each method, you will probably benefit from learning about some of the other methods in Enumerable.
#collect
- Also known by another name you may be familiar with - #map - #collect allows you to loop over objects and add the return value of each loop to an array.
- You’ll see many beginner Ruby programmers do this instead:
names = ['Apple', 'Orange', 'Pine Apple']
uppercase_names = []
names.each do |name|
uppercase_names << name.upcase end uppercase_names #=> ["APPLE", "ORANGE", "PINE APPLE"]
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
You can achieve the same thing using #collect as follows:
names = ['Apple', 'Orange', 'Pine Apple']
uppercase_names = names.collect { |name| name.upcase }
uppercase_names #=> ['APPLE', 'ORANGE', 'PINE APPLE']
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
#select
- The #select method permits you loop over a collection and return a list of objects for which a particular expression returns true.
- In other words, take a collection of objects and ‘select’ those that meet a certain criteria, discarding the rest.
![#select checkbox in ruby on rail swiss knife](https://wikitechy.com/tutorials/ruby-on-rails/img/ruby-on-rails-images/ruby-on-rail-swiss-knife-#select-checkbox.png)
Learn ruby - ruby tutorial - #select checkbox in ruby on rail swiss knife - ruby examples - ruby programs
Sample Code:
cockles_and_mussels = ['alive', 'dead', 'dead', 'alive', 'alive', 'dead']
alive_alive_oh = []
cockles_and_mussels.each do |cockle_or_mussel|
if cockle_or_mussel == 'alive'
alive_alive_oh << cockle_or_mussel end end alive_alive_oh #=> ["alive", "alive", "alive"]
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
Here’s what a solution looks like using #select:
cockles_and_mussels = ['alive', 'dead', 'dead', 'alive', 'alive', 'dead']
alive_alive_oh = cockles_and_mussels.select do |cockle_or_mussel|
cockle_or_mussel == 'alive'
end
alive_alive_oh #=> ['alive', 'alive', 'alive']
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
- We can see that any object passed into the block that is calculated as part of a true/false expression and returns true will be added to an array.
#reject
The #reject method is very similar to #select, but the inverse.
- It will leave behind any objects for which the expression returns true, and add only those that return false to the resulting array.
Sample Code:
cockles_and_mussels = ['alive', 'dead', 'dead', 'alive', 'alive', 'dead']
alive_alive_oh = cockles_and_mussels.reject do |cockle_or_mussel|
cockle_or_mussel == 'dead'
end
alive_alive_oh #=> ['alive', 'alive', 'alive']
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
- Choosing between #select and #reject is often a matter of style.
- Both can be used to solve similar problems effectively.
#detect
- The #detect method (also implemented as #find) is similar to #select, but instead of returning a collection of objects that match the given criteria, it will “detect” the first matching element it finds and return only that object.
songs = [
{ title: 'Mad World', artist: 'Gary Jules', is_sad: true },
{ title: 'California Gurls', artist: 'Katy Perry', is_sad: false },
{ title: 'Needle in the Hay', artist: 'Elliott Smith', is_sad: true },
{ title: 'Happy', artist: 'Pharrell Williams', is_sad: false }
]
sad_song_to_play_now = songs.detect { |song| song[:is_sad] }
sad_song_to_play_now #=> { title: 'Mad World', artist: 'Gary Jules', is_sad: true }
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
#inject
- The #inject method is wonderfully useful, though often misunderstood.
- It’s an excellent tool for building up data structures, or adding values together.
- It’s often used to sum up numbers into a total.
- Here’s an example of that, and then we’ll joint into a slightly different usage:
shopping_cart = [
{ name: 'Vermillion Ink', price: 12.99 },
{ name: 'Azure Ink', price: 9.99 },
{ name: 'LAMY Safari Fountain Pen', price: 49.95 }
]
order_total = shopping_cart.inject(0) do |total, item|
total + item[:price]
end
order_total #=> 72.93
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
- Unlike the other “Ect” methods, #inject passes two values to the block. The left-hand value is the accumulator.
- It starts at 0 (the argument to inject is the starting value) and will accumulate the result of the expression in the block.
- The right-hand argument is the object being iterated over.
We can also use #inject to build up data structures. Let’s say we have an array of some employee data:
customer = [['full_name', 'Lois Lane'], ['position', 'Journalist']]
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
This looks like the kind of data you might extract from a CSV file. It’s in a format we can work with, but we can do better. Let’s use #inject to construct a Hash from this data.
- This is a really useful tool. You have noticed that we are passing an argument to #inject: an empty hash.
- This will be used as the initial value of the “result” or accumulator variable.
- We start with this object and then build it up with each successive iteration over the elements in the array.
- A few other useful Enumerable methods:
customer = [['full_name', 'Lois Lane'], ['position', 'Journalist']]
customer.inject({}) do |result, element|
result[element.first] = element.last
result
end
customer #=> { "full_name"=>"Lois Lane", "position"=>"Journalist" }
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
#any
- The #any method returns true if any element in the collection match the given expression.
pet_names = ['pluto', 'scooby', 'nyan']
find_scooby = pet_names.any? { | pet | pet == 'scooby' }
find_scooby #=> true
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
- The #all method returns true if all elements in the collection match the given expression.
ages = [ 19, 59, 70, 23, 140 ]
valid = ages.all? { | age | age > 0 && age <= 122 } valid #=> false
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
#all #each_with_index
- A slight enhancement to the #each method, #each_with_index iterates over the element in the collection, as well as providing its index.
online_opponents = Hash.new
%w(joe87 potatahead coolguy415 ).each_with_index do |item, index|
online_opponents[item] = index
end
online_opponents #=> {"joe87"=>0, "potatahead"=>1, "coolguy415"=>2}
Clicking "Copy Code" button will copy the code into the clipboard - memory. Please paste(Ctrl+V) it in your destination. The code will get pasted. Happy coding from Wikitechy - ruby on rails tutorial - rails guides - ruby rails - rubyonrails - learn ruby on rails - team
#include?
- The #include? method will return true if any elements in the collection are equal to the given object.
- Object equality is tested using `==` (this post provides a good explanation of the different types of equality in Ruby).
superhero_names = ['Wonder Woman', 'Batman', 'Superman']
awesome = superhero_names.include? 'Wonder Woman'
awesome #=> true