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]
# [1, :a, :b, :c, 3]
# [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]
# [1, [2, [3, 4, [5, 6]]]]
# [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]]]]
# [1, 2, 3, 4, 5, 6]
# [1, 2, 3, 4, 5, 6]

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



Leave a Comment

Erlang Thursday – lists:max/1

Today’s Erlang function is lists:max/1.

lists:max/1 takes one argument, a list of at least one term, and returns the item that has the greatest value when compared to the other items in the list. The list can be composed of any Erlang term:

lists:max([1, 39, 7, 63, 27, 52, 16]).
% 63
lists:max([q, w, a, r, c, f, m, b]).      
% w
lists:max([[1, 2, 3], [1, 2, 4]]).
% [1,2,4]

Erlang has a distinct order between the different types of terms,

number < atom < reference < fun < port < pid < tuple < list < bit string

allowing for the list passed to lists:max/1 to be comprised of disparate types.

lists:max([1, 2, 3, 4, a]).         
% a
lists:max([1, a, [foo, bar], {baz}]).
% [foo,bar]

And because a string in Erlang is just a list of numbers under the covers, we can even compare strings.

lists:max(["foo", "bar", "baz", "snafu"]).

If you pass an empty list to lists:max/1 a no function clause matching error will be raised, since it expects the list to be at least composed of one term.

** exception error: no function clause matching lists:max([]) (lists.erl, line 326)

What are some of your favorite Erlang functions, or even just ones you would like to see a future Erlang Thursday post about?

And don't forget to check out the last Tuesday's Ruby Tuesday on Enumerable#max, if you would like a comparison between Erlang's max function and Ruby's max method.



Leave a Comment

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"



Leave a Comment


I have a confession to make, I have been spoiled by Planet Clojure by Baishampayan Ghose when starting to learn Clojure, I immediately started looking for the planet feed for Erlang.

In the last 2 years, I managed to find a site of an old planet feed for Erlang, but it never was available, and after some asking around, I never got any status on if it was still viable. After that, I realized that it was going to be up to me to put together a planet feed for Erlang since I was looking for one.

So with that said, I am happy to announce a new Planet Feed for all things Erlang – While the site doesn’t look pretty at this point, it is live and updating, and will be getting a nicer look to it soon, but my goal was to get it live first.

I would love for this feed to be a place where people both new and old to the Erlang community can subscribe to to find out what is going on across the whole Erlang ecosystem, from Erlang and OTP, to the virtual machines, to languages on the VM such as Elixir, Lisp Flavored Erlang, and Prolog.

In order for that dream to be realized though, I need your help to find sites where people are talking about what they are doing with Erlang, so we can get them added to the feed.

If you have a site, or know someone who does, please submit a pull request to the project with their name and site feed.

Also large thanks to Baishampayan Ghose for his support by giving advice of what he does for Planet Clojure.

Thank you in advance for you help, and spreading the word,


Leave a Comment

Erlang Thursday – lists:seq

My goal of these Erlang Thursday’s for the next while will be to show off the “corresponding” functions in Erlang for the Ruby methods I highlight on Tuesday. I am hoping that by having these Erlang Thursday line up with the Ruby Tuesday for the week, that I can make Erlang be less foreign and intimidating by establishing a common thread of discussion. I would love to know your thoughts on how well this secondary goal is working for you the reader.

That being said, since I talked about Ruby’s Range this week, today’s Erlang function is lists:seq/2 and lists:seq/3.

If you remember from the sidebar of last weeks Erlang Thursday, the number at the end of the function name means the arity (number of arguments) of the function.

The function lists:seq/2 takes a beginning and an ending integer and produces a list of integers including both the beginning and ending value.

lists:seq(1, 10).     
% [1,2,3,4,5,6,7,8,9,10]
lists:seq(1, 1). 
% [1]

The 3-arity version of lists:seq introduces the increment as the third argument:

lists:seq(1, 10, 3).  
% [1,4,7,10]

The increment value can be negative as well, allowing for counting down from one number to another.

lists:seq(20, 10, -1).
% [20,19,18,17,16,15,14,13,12,11,10]
lists:seq(20, 10, -5).
% [20,15,10]

The list:seq functions will throw an exception if given invalid starting and ending values, unlike the Ruby Range which returns an empty set.

lists:seq(10, 1).   
% ** exception error: no function clause matching lists:seq(10,1) (lists.erl, line 241)
lists:seq(1, 10, 0).
% ** exception error: no true branch found when evaluating an if expression
%      in function  lists:seq/3 (lists.erl, line 262)
lists:seq(1, 10, -2).
% ** exception error: no true branch found when evaluating an if expression
%      in function  lists:seq/3 (lists.erl, line 262)
lists:seq(10, 1, 2).
% ** exception error: no true branch found when evaluating an if expression
%      in function  lists:seq/3 (lists.erl, line 262)



Leave a Comment

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, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

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

# [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.

# []

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

# [#<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", "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.

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.



1 Comment

Erlang Thursday – lists:member/2

To go with this weeks Ruby Tuesday post about Enumerable#include?, I decided I would highlight Erlang’s counterpart, lists:member/2.

Sidebar for those unfamiliar with Erlang: lists:member/2 is read as the function member with arity 2, which is found in the lists module. Arity being the number of arguments that the function takes. The module is important, because modules are the containers in which all functions must live — primarily because modules are the unit of code reloading in Erlang — but that way you know which specific member function is being referred to.

All that being said, the function member, in the lists module, takes two arguments: the item being looked for which is an Erlang term, and the list of Erlang terms to check; and returns true if the term is found in the list. An Erlang term is just a piece of data which can be of any of the Erlang data types.

For ability to try this out, the expression is normal, and the return value is the line that starts with the % symbol, which is the Erlang comment, to allow for copy and pasting into the Erlang shell erl.

It can be something as simple for checking if a number is in a list of numbers:

lists:member(4, [1, 2, 3, 5, 8, 13, 21]).
% false
lists:member(13, [1, 2, 3, 5, 8, 13, 21]).
% true

or if an atom is in a list of atoms:

lists:member(c, [a, b, c, d]).   
% true
lists:member(q, [a, b, c, d]).   
% false

or list of more complex terms such as a tuple, or tuples with lists inside them:

lists:member({d, 4}, [{a, 1}, {b, 2}, {c, 3}, {d, 4}]).
% true
lists:member({'Foo', [bar, baz]}, [a, 1, {'Foo', [bar, baz]}]). 
% true
lists:member({fu, [bar, baz]}, [a, 1, {'Foo', [bar, baz]}]).    
% false

or even an integer, or “character”, in a string:

lists:member($a, "banana").
% true
lists:member(97, "banana").
% true
lists:member($A, "banana").
% false

Which if you look carefully enough, you might be able to get the hint that a string in Erlang is really just a list of integers.

Hope this is an interesting comparison between Ruby and Erlang, and my give you some insight into Erlang if you are unfamiliar with the language.



Leave a Comment

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.

, ,

1 Comment

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.



Leave a Comment

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


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?


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 $?

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.


, ,

Leave a Comment