Collections

Ruby contains a number of collection classes – these are classes that can be used to store collections of data.

The most important collection classes in Ruby are Array and Hash. In addition, a Set class was recently added to the language.

Each of these collection classes includes the Enumerable module as a mixin. Thus, they share a common set of methods provided by Enumerable.

The Enumerable module provides iterator methods that can be used to iterate through (and operate on) each element in a collection.

Arrays are used extensively in Rails controllers:

def index
  @posts = Post.all
end

Arrays

Arrays hold collections of object references that can be indexed (zero-based).
Ex.

> a = [33.3, "hi", 2]
> a[0]                   # => 33.3

A wide variety of methods are provided for the Array class. E.g., positive numbers index from the start of the array, negative numbers from the end, index a range a[1..2], sort, include?, reverse, length, first, last, <<, push, pop, etc.
Ex.

> a[1..2]          # => ["hi", 2]
> a << 5     # => [33.3, "hi", 2, 5]
> a[-1]            # => 5
> a.include? 2     #=> true

Hashes

A Hash is an associative array (key-value pairs) where the key and value may be any objects, separated by the => symbol. You index into a hash using keys.
Ex.

phone = {’home’=> 1, ’mobile’=> 2, ’work’=> 3}
or better yet:
phone = {:home => 1, :mobile => 2, :work => 3}
> phone[:home]        # => 1
> phone.key(1)        # => :home
> phone.key?(:home)   # => true
> phone.value?(1)     # => true

Nested Collections

To create a multidimensional collection, nest one collection inside another.
Ex.

> ary = [["red", "green", "blue"], [1,2,3],
          ["Alpha", "Beta", "Gamma"]]
> ary[2][1]       # => "Beta"
 
> hsh = {"Chicago"=>{"nickname"=>"The Windy City",
      "state"=>"IL"}, "New York City"=>{"nickname"=>"
      The Big Apple", "state"=>"NY"}}
> hsh["Chicago"]["nickname"]      # => "The Windy City"

Code Blocks

A block consists of multiple lines of code, enclosed in curly braces, that can be passed as a parameter to a method.

Using this feature it is easy to build code libraries which can delegate varying functionality to code blocks to be built later.

Important: A block may appear only in the source if it is adjacent to a method call (on the same line as the method call’s last parameter).

A block is invoked using the yield statement.
Ex.

def three_times
  yield
  yield
  yield
end
 
> three_times {puts "Hello"}
will print "Hello" three times.

Iterators

In Ruby, the various loop structures are rarely used – it is more common to use iterators.

The defining feature of an iterator method is that it invokes a block of code, applying it to each element in a collection.

A collection class that includes the Enumerable module is required to supply an each method. This method must yield the successive members of the collection.

Iterators work because you can pass parameters into blocks. Ex. The each method in the Enumerable module works something like:

def each
    for each item in the collection # this is psuedocode
        yield(item)
    end
end
 
> a = [33.3, "hi", 2]
> a.each {|element| puts element}
  33.3
  "hi"
  2
  => [33.3, "hi", 2]

Here’s an iterator used in a Rails view:

<tbody>
  <% @posts.each do |post| %>
    <tr>
    <td><%= post.title %></td>
      <td><%= post.body %></td>
      <td><%= link_to ’Show’, post %></td>
      <td><%= link_to ’Edit’, edit_post_path(post)%></td>
      <td><%= link_to ’Destroy’, post, method: :delete
        , data: { confirm: ’Are you sure?’ } %></td>
    </tr>
  <% end %>
</tbody>