Category Archives: Ruby

Ruby Tuesday – Enumerable#reduce aka inject

Today’s Ruby Tuesday is Enumerable#reduce, also known as Enumerable#inject.

Enumerable#reduce works against an enum and takes a initial value for the accumulator and two parameter block. The first parameter to the block is the current accumulated value, and second parameter is the current element in the iteration. If no accumulator value is specified, the first item in the enum is taken to be used as the accumulator value.

["baz","Supercalifragilisticexpialidocious", "qwerty"].reduce("") do |shortest, item|
  item.length < shortest.length ? item : shortest
end
# => ""
["baz","Supercalifragilisticexpialidocious", "qwerty"].reduce do |longest, item|
  item.length > longest.length ? item : longest
end
# => "Supercalifragilisticexpialidocious"
["baz", "Supercalifragilisticexpialidocious", "qwerty"].reduce do |shortest, item|
  item.length < shortest.length ? item : shortest
end
# => "baz"

Calling reduce on an empty enum just returns the accumulator, or if no initial value for the accumulator given returns the result of calling first on the enum, which in the case of Array is nil.

[].reduce(:accum){|accum, item| accum * item}
# => :accum
[].reduce{|accum, item| accum * item}
# => nil

Enumerable#reduce can also take a symbol instead of a block, which is the name of the method to invoke on the accumulator value. This form of reduce also takes an initial accumulator value, or uses the first item as the accumulator.

[1, 2, 3, 4, 5].reduce(:+)
# => 15
[1, 2, 3, 4, 5].reduce(:*)
# => 120
[1, 2, 3, 4, 5].reduce(10, :*)
# => 1200
[100, 10, 2].reduce(:/)
# => 5
[100, 10, 2].reduce(1_000_000, :/)
# => 500

–Proctor

Ruby Tuesday – Enumerable#map aka collect

Today’s Ruby Tuesday method is Enumerable#map, also known as Enumerable#collect.

Enumerable#map is a function with a long lineage. Enumerable#map takes a set of items, and maps the inputs onto a new set of values via a transformation function, or in the case of Ruby, a block.

[1, 2, 3, 4].map{ |x| x + 1 }
# => [2, 3, 4, 5]
[1, 2, 3, 4].map{ |x| x * x }
# => [1, 4, 9, 16]

In Ruby, the map method is an alias of Enumerable#collect.

[1, 2, 3, 4].map{ |x| x * x }
# => [1, 4, 9, 16]
[1, 2, 3, 4].collect{ |x| x * x }
# => [1, 4, 9, 16]

Ruby also has some ways of taking existing methods, and passing them as the block to be invoked by the map function. If we want to do a transform by calling a method on the object passed to the block, we can prepend the name of the method with a &: and pass that to the map function as an argument.

['i', 'b', 'm'].map{ |x| x.upcase }
=> ["I", "B", "M"]
['i', 'b', 'm'].map(&:upcase)
=> ["I", "B", "M"]

You want to be careful with this though, as not all functions on an object are transformation functions but may modify the underlying object, which may cause confusion to readers of your code if they are expecting the original enumeration to be unchanged.

items = ['i', 'b', 'm']
# => ["i", "b", "m"]
items.map(&:upcase)
# => ["I", "B", "M"]
items
# => ["i", "b", "m"]
items = ['i', 'b', 'm']
# => ["i", "b", "m"]
items.map(&:upcase!)
#=> ["I", "B", "M"]
items
# => ["I", "B", "M"]

Ruby Tuesday – Array#flatten

Today’s Ruby Tuesday is Array#flatten.

Array#flatten returns a new array that has been recursively flattened into a one dimensional array.

a = [1, [:a, :b, :c], 3]
# [1, [:a, :b, :c], 3]
b = a.flatten
# [1, :a, :b, :c, 3]
b
# [1, :a, :b, :c, 3]
a
# [1, [:a, :b, :c], 3]

c = [1, [2, [3, 4, [5 ,6]]]]
# [1, [2, [3, 4, [5, 6]]]]
d = c.flatten
# [1, 2, 3, 4, 5, 6]
c
# [1, [2, [3, 4, [5, 6]]]]
d
# [1, 2, 3, 4, 5, 6]

[1, 2, 3].flatten
# [1, 2, 3]

Ruby also provides a method #flatten! which mutates the state of the object if you happen to require that behavior. And note, that calling flatten! on an array will return nil if the array was not modified.

c2 = [1, [2, [3, 4, [5 ,6]]]]
# [1, [2, [3, 4, [5, 6]]]]
c2.flatten!
# [1, 2, 3, 4, 5, 6]
c2
# [1, 2, 3, 4, 5, 6]

[1, 2, 3].flatten!
# nil

–Proctor

Ruby Tuesday – Enumerable#max

Today’s Ruby function in Enumerable#max.

Enumerable#max will find the largest item in an enum of items that are Comparable.

This means it works against numbers, strings, symbols, or more, as long as that type includes the module Comparable.

[5, 67, 30, 102, 3, 1].max
#=> 102
['baz', 'bar', 'foo', 'xray', 'z', 'a'].max
#=> "z"
[:foo, :bar, :baz, :snafu].max
#=> :snafu

Enumerable#max can also take a block of two arguments, allowing you to find the max based off of another property of those objects, such as the length:

['baz', 'bar', 'foo', 'xray', 'z', 'a'].max {|a, b| a.length <=> b.length}
=> "xray"

–Proctor

Ruby Tuesday – Ranges

This weeks edition of Ruby Tuesday is about ranges. Ranges are Ruby’s way to create an interval of values.

Ranges take a beginning and ending value, which can be inclusive,

(10..20).to_a
# [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

or exclusive, specified by using ... instead of ..

(10...20).to_a
# [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

And creating a “invalid” range, will result in a empty set of values, and not throw an exception.

(20..10).to_a
# []

Ranges can be used not only against integer values, but Dates and Strings as well

(Date.today..(Date.today+10)).to_a
# [#<Date: 2014-11-08 ((2456970j,0s,0n),+0s,2299161j)>,
#  #<Date: 2014-11-09 ((2456971j,0s,0n),+0s,2299161j)>,
#  #<Date: 2014-11-10 ((2456972j,0s,0n),+0s,2299161j)>,
#  #<Date: 2014-11-11 ((2456973j,0s,0n),+0s,2299161j)>,
#  #<Date: 2014-11-12 ((2456974j,0s,0n),+0s,2299161j)>,
#  #<Date: 2014-11-13 ((2456975j,0s,0n),+0s,2299161j)>,
#  #<Date: 2014-11-14 ((2456976j,0s,0n),+0s,2299161j)>,
#  #<Date: 2014-11-15 ((2456977j,0s,0n),+0s,2299161j)>,
#  #<Date: 2014-11-16 ((2456978j,0s,0n),+0s,2299161j)>,
#  #<Date: 2014-11-17 ((2456979j,0s,0n),+0s,2299161j)>,
#  #<Date: 2014-11-18 ((2456980j,0s,0n),+0s,2299161j)>]

('a'..'z').to_a
# ["a", "b", "c", "d", "e", "f", "g", "h",
#  "i", "j", "k", "l", "m", "n", "o", "p",
#  "q", "r", "s", "t", "u", "v", "w", "x",
#  "y", "z"]

In fact Ranges can be created from any type that implements the <=> operator.

Be warned though, just because you can create a Range, doesn’t mean that you can turn every Range into an Array as above.

(1.0..2.0).to_a
TypeError: can't iterate from Float
from (pry):58:in `each'

There is more that you can do with Ranges, such as checking if a value is in the range, or stepping through the values, but some of the methods on Range have requirements that certain methods be declared on the type the range is operating on.

–Proctor

Ruby Tuesday – Enumerable#include?

I was going to write up another method in the Ruby standard library, but was going to use the include? in some of the examples, so I decided I should just start with include?.

The #include? method is part of the Enumerable module, and when passed and object, it returns true if the object is in the enum.

This works not only for arrays:

[1, 2, 3, 5, 8, 13, 21].include? 4
#=> false
[1, 2, 3, 5, 8, 13, 21].include? 5
#=> true

But also strings:

'banana'.include? 's'
#=> false
'banana'.include? 'a'
#=> true

And maps:

{a: 1, b: 2, c: 3}.include? :a
#=> true
{a: 1, b: 2, c: 3}.include? :q
#=> false
{a: 1, b: 2, c: 3}.include? 1
#=> false

Which if you notice checks if the object is one of the keys in the map.

And because it uses the == operator, it works on coercing datatypes, so we are able to find a floating point version of a number in a list of integers:

[1, 2, 3, 5, 8, 13, 21].include? 1.0
#=> true
[1, 2, 3, 5, 8, 13, 21].include? 1.1
=> false

And the beauty of this is that if you want this behavior on one of your classes or modules, you just include the Enumerable module and implement the #each method, and the Enumerable module will take care of this behavior for you.

Ruby Tuesday

In the spirit of blogging more, and not just working on my episodes of Functional Geekery, I am going to do some series of posts about Ruby. These first sets will be taking a tip from Eric Normand of LispCast about picking out some functions in the language and documenting them.

So with that, I am announcing a new “series” on the blog Ruby Tuesday. Every Tuesday for the time being, I will be publishing some method of the Ruby language, and posting it here, with some examples of how they can be used. I will do some that I use often, and hopefully try and pull some out that are hidden gems to me, and hopefully others who are working in Ruby.

As I go on, I would love to know some of your favorites as well.

–Proctor

Shelling out in Ruby

One of the things that is nice about Ruby is the ability to use it for scripting. Ruby makes it nice and easy to shell out to run standard *nix commands.

The problem is, the nice simple way that seems to be the most common, is also the least safe. I’m looking at you backticks.

#!/usr/env ruby

result = `gerp -e 'some regex' foo`
puts "<time to process result>"
puts "All Good"

And when we run the above, we see that our script completed, even though we really bombed out trying to run gerp instead of grep.

sh: gerp: command not found
<time to process result>
All Good

Oops.

Sure we get a warning gerp: command not found, but the script still proceeds to plow ahead and do any other side effects that it is setup to do, although something went wrong earlier.

This has become one of the biggest thorns in my side at work.

Lucky the technical solution to this is straight forward, so I want to share it with readers of this blog so you can stop making the mistake of using backticks to shell out commands, and use a solution that does not cover up issues in production.

#!/usr/env ruby

require 'open3'

def execute_syscall(cmd)
  results, error, status = Open3.capture3(cmd)
  raise error unless status.success?

  results
end

result = execute_syscall "gerp -e 'some regex' foo"
puts "<time to process result>"
puts "All Good"

First we require open3. Open3 allows us to be able to capture the results, the error stream, and the status. This way, we can check if the status of the command was anything other than success, and if not, we raise the error we get from STDERR.

Now when we run it, the script stops in its tracks. Not only that, but our script returns a failure error code as well.

> ruby script_demo.rb
script_demo.rb:7:in `execute_syscall': sh: gerp: command not found (RuntimeError)
	from script_demo.rb:12:in `&lt;main&gt;'
> echo $?
1

That way we can know that something went wrong in our program, especially when it is setup as a cron job or as some other unsupervised task.

Hope this can save you some headaches and frustration on your end as well.

–Proctor

Creating a Ruby Rack Middleware for Application Version Id

If you are developing an application that uses the Ruby rack framework, and most Ruby application frameworks and servers do, it is pretty simple to create your own rack middleware.

In this post I outline how simple it is go create a new middleware for your rack application. In fact, I did something very similar in one of the web services I worked on so that we could get the exact version of the code that our app was running against for troubleshooting purposes. I suggested we add a version identifier to all responses so we could log the requests, the responses and their response codes, and have the version of the running code in every response as well. This would help us troubleshoot failures that are not failing anymore, or failed “intermittently” because they might be hitting one of two load balanced servers in case someone updated one server, but not the other, such as for A-B testing.

This was actually a very easy thing to do by taking advantage of rack’s middleware capability. The code below was all that it took to create a new piece of middleware to give us version identifiers on each response.

module Middleware
  class VersionIdentifier
    def initialize(app, version_id)
      @app = app
      @version_id = version_id
    end

    def call(env)
      @app.call(env).tap do |_status, headers, _body|
        headers["version-id"] = @version_id
      end
    end

    private
      attr_reader :version_id
  end
end

In the above source, we create a initialize method which takes app, which is the rack application that this middleware component is wrapping, and version_id, which is how we will identify the version of the application is running.

The next step to define the standard rack protocol of call(env). In this, since we are only concerned about the response, we call the next rack component by invoking call on @app which we got when the middleware was constructed. This could be another piece of middleware, or it could be the actual application, but we don’t care about specifics, which is part of the beauty of the way middleware for rack works. What we do care about is the return of the call to @app.call(env), since we are interested in modifying the response headers. We do this with using the tap method on all Ruby objects, and adding a new entry to the header hash with the key version-id and the value that we got on creation for @version_id.

That is all there is to creating a rack middleware component to add a version identifier to the headers for every response that is served by the rack web server.

To use this middleware, we first need to determine what the will represent the version of our app. For this example, we will use the git SHA that represents the code we are running against, since we are assuming we are behaving and there is no code running in production that is not checked into source control. We add this to our startup script/configuration file, e.g. config.ru.

git_sha = `git rev-parse HEAD`

Once we have that settled, we just declare we are going to use our middleware, and we pass in the git_sha that we found above.

use Middleware::VersionIdentifier, git_sha

We start up our application and voilĂ , we have a version identifier getting returned on every response with the header of version-id.

$ curl -i "localhost:9292"
HTTP/1.1 200 OK
version-id: 7df6e26a3dd1d3d05130e054fbcb1b878d965767
Content-Length: 7

Howdy!
$

The full source code can be found at https://github.com/stevenproctor/versionid-middleware-example.

Chef: knife “FATAL: X nodes found, but does not have the required attribute to establish the connection.”

A couple of weeks ago I was trying to do a chef-deploy using the knife ssh command from Chef and specifying the role, but was getting the following error:

chef-repo proctor$ knife ssh "role:reporting" "sudo chef-deploy"
FATAL: 12 nodes found, but does not have the required attribute to establish the connection. Try setting another attribute to open the connection using --attribute.

When I tried to do a search of nodes using the knife search command, I was getting another error:

chef-repo proctor$ knife search node role:reporting
ERROR: knife encountered an unexpected error
This may be a bug in the 'search' knife command or plugin
Please collect the output of this command with the `-VV` option before filing a bug report.
Exception: NoMethodError: undefined method `name' for #<Hash:0x007fa8d9914f40>

I could do a knife ssh and do a chef-deploy if I did a manual listing of the servers.

chef-repo proctor$ knife ssh -m "reportingserver.qualified.domain" "sudo chef-deploy"

I knew we had the servers setup with the chef gem at version 10.24.0, and had thought I was setup with 10.24.0 locally as well. When I double checked my local version of the chef gem I saw I was actually on 10.20.0 locally. After uninstalling the chef gem, and installing to target 10.24.0 to match the servers, everything started working as expected.

Hopefully, you encounter errors similar to the above this will save you some time, and help you learn from my problem, and serve as a notice to double check the versions of the chef gem between your local environment and your servers.

–Proctor