My personal dev blog

Thoughts about DevOps stuff and more

Some Ruby Regex Tips

| Comments

I haven’t been fan to the regular expresion myself, but they are very useful and I try to learn each day to use their potencial.

I going to write down here some tips that I have found useful and I like to remember. I hope this helps anyone else.

First it’s important to remember that the Strings are very powerfull per se and sometimes there is no need for a regular expresions. For example:

1
2
1.9.3-p0 :000 > 'Here is some ramdom text'.include? 'ramdom'
 => true

There are a lot of interesting methods for Strings and I love them, but let’s see some cases for regex:

The tipical base case is the previous one, check if there is some text or pattern inside one string. This can be done by doing:

1
/ramdom/ =~ 'Here is some ramdom text'

This will return the position in the string where the pattern start and nil if the pattern doesn’t match. You can use it in a if stament to see if this match. The positive value that indicate the position will count as true for the if, so we can follow with our workflow.

The string that match with the pattern will be stored in a special var. From $1 to $9 are reserved for this purpose. But, nine vars? Yes, because we can search for more than one pattern and store their values in different variables. Those patterns are called groups and are delimited by parentesis. Lets see it:

1
2
3
4
5
6
7
/.*(first).*(second)/ =~ 'Something first and second'
1.9.3-p0 :001 > /.*(first).*(second)/ =~ 'Something first and second'
=> 0
1.9.3-p0 :002 > $1
=> "first"
1.9.3-p0 :003 > $2
=> "second"

Oviously is is very simple and silly example. Well this is very basic, but what I wanted to talk about is how to work better with those groups and special variables. Groups are used for capturing text, but also to define alternatives in a patterns. For example:

1
2
3
4
files = %w( home.png party.jpg party_music.mp3 )
#  => ["home.png", "party.jpg", "party_music.mp3"] 
photos = files.select { |f| /\w+\.(png|jpg)/ =~ f }
#  => ["home.png", "party.jpg"]

So the pattern will match eigther with /\w+\.png/ or /\w+\.jpg/. This is very useful and is tipical from any language or tool that support regex, but is good to know. But one interesting thing that I have learnt recently is how to avoid to feed the special variables with the matches’ results.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# We have those sentences:
1.9.3-p0 :001 > senteces = [
1.9.3-p0 :002 >   'John is crazy',
1.9.3-p0 :003 >   'Anne is crazy',
1.9.3-p0 :004 >   'Peter is crazy',
1.9.3-p0 :005 >   'John is kidding'
]
#  => ["John is crazy", "Anne is crazy", "Peter is crazy", "John is kidding"]

# We want to check what is says about 'John' or 'Anne'
1.9.3-p0 :006 > senteces.each do |sentence|
1.9.3-p0 :007 >   if /(John|Anne) is (\w+)$/ =~ sentence
1.9.3-p0 :008 >     puts "#{$1} -> #{$2}"
1.9.3-p0 :009 >   end
1.9.3-p0 :010 > end
John -> crazy
Anne -> crazy
John -> kidding

But there is a nicer way to save the matches, we can store them in our own variables:

1
2
3
4
5
6
7
8
1.9.3-p0 :011 > senteces.each do |sentence|
1.9.3-p0 :012 >   if /(?<name>John|Anne) is (?<wat>\w+)$/ =~ sentence
1.9.3-p0 :013 >     puts "#{name} -> #{wat}"
1.9.3-p0 :014 >   end
1.9.3-p0 :015 > end
John -> crazy
Anne -> crazy
John -> kidding

And you also can ignore any group. I found this useful at the step_definitions for Cucumber. Here is one example I did time ago:

1
2
3
4
When /^the calculator (divide|substract) the (\d+) (?:by|to) the (\d+)$/ do |command, arg1, arg2|
  @output = `ruby bin/rcalc #{command} #{@first} #{@second}`.chomp
  $?.success?.should be_true
end

Cucumber checks for this regex againts the features and pass the groups founded to the block (as command, arg1 and arg2). In this perticular case I want a expresion that matched with that kind of sentence but I didn’t want to store by or to. Mostly beacuse Cucumber highlight the groups matched at the output and I didn’t want for those words. I just wanted reuse the regex to both cases. Anyways, I found (?:regex) interesting and useful.

Well, I don’t know if someone find this useful, but at least I got this written down as alternative to my bad memory :-P

Oh, btw, If you are going to use regular expresions in Ruby I higly recomended you Rubular. Which is an awesome online Ruby regular expresion editor. Has some nice quick reference and check on-the-fly all your expresions and cases. Really cool :-)

The Symbol.to_proc Trick

| Comments

Sometimes I find myself saying: “must be a better way to do this”. And sometimes, there are :-)

This is the case of processing the elements of a list. Let’s see it in an example:

I have a object shop_list which is a string with a list of element separated by comas

1
2
1.9.3-p0 :002 > shop_list
 => "oranges, eggs, oat, water"

when I split them I get:

1
2
1.9.3-p0 :003 > shop_list.split(',')
 => ["oranges", " eggs", " oat", " water"]

But some of the new elements of the list have a space before them. And I need the list with no spaces to send it to another object, method, app or whatever which doesn’t like those extra spaces. I can remove them like this:

1
2
1.9.3-p0 :004 > shop_list.split(',').map { |e| e.strip }
 => ["oranges", "eggs", "oat", "water"]

But at Ruby 1.9 we have a simpler way to do the same and is more concise:

1
2
1.9.3-p0 :005 > shop_list.split(',').map(&:strip)
 => ["oranges", "eggs", "oat", "water"]

So this:

1
2
3
4
# name_args = "oranges, eggs, oat, water"
shop_list = name_args.split(',').map do |item|
  item.strip
end

is the same as this:

1
2
# name_args = "oranges, eggs, oat, water"
shop_list = name_args.split(',').map(&:strip)

The reason is because there is a method called to_proc that convert an object prefixed with an ampersand (&) in a method to call. Ruby will see the symbol (:strip) and it will try to convert it into a Proc to call the block with the list from the map and invoking the method strip at each one of the elements from the list.

Ok, this is not the best explanation ever but I like the new concise form :-)

Hashes at Ruby1.9 Are Sexy

| Comments

Probably everybody knew that, but I didn’t when I readed at the Programming Ruby book.

I was use to the no so sexy syntax for the hashes in Ruby:

1
numbers = { "one" => "uno", "two" => "dos", "three" => "tres" }

Although is very common to see them at code using symbols as keys and split the elements into lines:

1
2
3
4
5
numbers = {
  :one   => "uno",
  :two   => "dos",
  :three => "tres"
}

which, actually, looks nicer… (at least to me)

But in Ruby 1.9 they decide that if this was so common, maybe it could me a good idea simplify it. So now we can do the same by doing:

1
2
3
4
5
numbers = {
  one:   "uno",
  two:   "dos",
  three: "tres"
}

It is less verbose and, I think, more natural.

Back With Ruby

| Comments

Long time ago (thanks to a good friend) I felt in love with Ruby (I think it was around 2001), but I didn’t get much into it until years later (2005) when I did some stuff at work. All these years I’ve been thinking about come back to learn Ruby and write some code, but you know… time, work…

Now I’m free and have some free time for me to learn all the thing I want, so I’ll do so :-)

After (buy and) read some books from The Pragmatic Bookself I decided to give a try to the famous Programming Ruby. I checked the new version and I realised the book was really improved from the previous ones. Ruby 1.9 and really better explanations about the differents subjects.

Even at the first chapters when they explain very basic thinks that I already knew, I learn a lot of new things with each page. It really worths to read it :-)

I will write here some notes about things I learn (or re-learn) with this and other books. I hope be useful for somebody. Anyway, it will be for me :-P

Happy reading and happy hacking ;-)

The Classic: Hello World!

| Comments

1
puts 'Hello world!'

Hi :-)

This is Yet Another Dev Blog. I got already one for GNOME and Distros’ stuff, but I just wanted to try this blog tool made for developers, Octopress, and see if is easier to share code and ideas.

Actually, some times I just need a place to save my gist with some comments or exaplanation. Other I just want to express some crazy technical ideas, so I think Github is a good place for this sort of things :-P

I warning you that I’ll probably talk a lot about Ruby, Chef, DevOps, BDD, Vagrant and more similar stuff that I’m crazy about right now :-)

See you soon and Happy Hacking!