Map method in Javascript and Ruby

Tags: javascript, ruby
Publish Date: 2014-11-06

The map method in Ruby (defined in the Enumerable module) is one of the most commonly used methods among Ruby developers. However, in the Javascript world, it only became cross-browser compatible since IE9.

In Ruby, #map allows you to run a block of code on every element in an "enumerable object" and returns the results in an Array.
By an "enumerable object", I mean Ruby classes that includes the Enumerable module, such as Array, Hash and Set.

In the following example, we have a 2-dimensional array, in which every sub-array contains the first name and last name as two separate array elements. By providing a block of code to the map method, we can return the full names as a string and store them in an array.

  split_names = [ ["Carmelo", "Anthony"], 
                  ["Rajon", "Rondo"], 
                  ["Tim", "Duncan"], 
                  ["Derrick", "Rose"] ]

  names = split_names.map{ |elem| "#{elem[0]} #{elem[1]}" }

  names #=> ["Carmelo Anthony", "Rajon Rondo", "Tim Duncan", "Derrick Rose"]

In Javascript, the same can be done with the map method, which takes an annonymous function:

  var split_names = [ ["Carmelo", "Anthony"], 
                      ["Rajon", "Rondo"], 
                      ["Tim", "Duncan"], 
                      ["Derrick", "Rose"] ]

  var names = split_names.map(function(elem){
    return elem[0] + " " + elem[1];
  });

  names #=> ["Carmelo Anthony", "Rajon Rondo", "Tim Duncan", "Derrick Rose"]

In Ruby, instead of providing a block to the map method, we can also use a "shortcut", IF the block of code we want to run is a method that every element can respond to.
Let's say from the previous 2-dimensional array, we only want the last names instead of the full names.
We can grab the last names by calling #pop on every element.

  split_names = [ ["Carmelo", "Anthony"], 
                  ["Rajon", "Rondo"], 
                  ["Tim", "Duncan"], 
                  ["Derrick", "Rose"] ]

  names = split_names.map(&:pop) # shortcut for map{ |elem| elem.pop }

  names #=> ["Anthony", "Rondo", "Duncan", "Rose"]

Use modules as mixins in Ruby

Tags: ruby
Publish Date: 2014-11-04
A little revision on mixins
In many programmaing languages (such as Java), it is a common practice to use inheritance to share methods among classes.
In Ruby, however, there is another way to share methods: mixins. Let's look at the following example:
  class Animal
    def run
	  "I'm running"
	end
  end

  class Dog < Animal
  end

  class Mouse < Animal
  end

  gromit = Dog.new
	
  gromit.run
  #=> "I'm running"
All animals can run, but not all animals can hunt. So maybe it wouldn't make sense to define methods that are related to hunting in the Animal class. Instead, it might be a better idea to define these methods in a separate module.
module Hunting
  def chase_rabbit
    "I'm chasing rabbit"
  end
end
We can include module Hunting in our Dog class, so that the chase_rabbit method will be available as a instance variable. It is also worth to notice that the included module will be inserted in the class hierarchy chain.
class Dog < Animal
  include Hunting
end

gromit.chase_rabbit
#=> "I'm chasing rabbit"
Dog.ancestors.inspect
#=> [Dog, Hunting, Animal, Object, Kernel, BasicObject]
In the following example, we can see that the superclass has acquired methods by including a module. These methods can still be overriden by its subclasses. Again, please pay notice to what happens the class hierachy once a module has been included.
module Breedable
  def breed
    "breeding [original implementation]"
  end
end

class Animal
  include Breedable

  def run
	"I'm running"
  end
end

class Dog
  include Hunting

  def breed
    "breeding puppies"
  end
end

gromit = Dog.new
mickey = Mouse.new
gromit.breed #=> "breeding puppies"
mickey.breed #=> "breeding [original implementation]"

Dog.ancestors.inspect #=> [Dog, Hunting, Animal, Breedable, Object, Kernel, BasicObject]
In the previous example, we have made methods in modules available as instance methods.
However, we can also make them available as "class methods".
    module Countable
      def count_breed
        "Counting #{self.name} class"
      end
    end
  
The methods within Countable can then be included as class methods by one of the two following ways:
  class Dog
    class << self
      include Countable
    end

    include Hunting

    def breed
      "breeding puppies"
    end
  end
  Dog.count_breed #=> "Counting Dog class"
  
Or:
    class Dog
      extend Countable
      
	  include Hunting

      def breed
        "breeding puppies"
      end
    end
    Dog.count_breed #=> "Counting Dog class"
  
Again, pay attention to the class hierarchy. In this case, extend a module (or include within class << self) will not insert the module Countable in our class hierarchy.
  	Dog.ancestors.inspect #=> [Dog, Hunting, Animal, Breedable, Object, Kernel, BasicObject]