Ruby, etc

Learn all the things

He who enjoys doing and enjoys what he has done is happy. - Fortune Cookie

Exploring Arrays - Part 4

combination

combination(n) { |c| block } → ary 
combination(n) → an_enumerator

Next method up for discussion is combination, when I saw this my first thought was “OH wow!! I can make games!!”. Being able to generate datasets I think is key to making a game. Being able to make a list of combinations, then pick on at random I think is cool. Lets try it

1
2
3
4
5
6
>> bad_guys = [:ogre, :giant, :zombie]
=> [:ogre, :giant, :zombie]
>> bad_guys.combination(2).to_a
=> [[:ogre, :giant], [:ogre, :zombie], [:giant, :zombie]]
>> bad_guys.combination(2).to_a.sample(1).flatten
=> [:giant, :zombie]

Lets build an array of bad guys, generate all the combinations of 2 badguys, choose a set of 2 at random and flatten it. Here is the list of bad guys for our awesome game. Cool huh? Doesn’t this just make you want to stop everything and make a game now? Ok, maybe it is just me. :)

compact

compact → new_ary 
Returns a copy of self with all nil elements removed.

I recently used this on a project (with help from a friend, Thanks Corey!) where I had 1 or 2 items and if I had two I wanted to be $100-200 but if just one I wanted it to be $100 or $200.

1
2
3
4
5
6
7
8
9
10
11
12
13
>> price_a = "$100"
=> "$100"
>> price_b = "$200"
=> "$200"
>> [price_a, price_b].compact.join("-")
=> "$100-$200"

>> price_a = "$100"
=> "$100"
>> price_b = nil
=> nil
>> [price_a, price_b].compact.join("-")
=> "$100"

Cool huh? previously I had something hideous like

1
2
3
4
5
6
7
8
9
if price_a.present? && price_b.present?
 "#{price_a}-#{price_b}"
elsif price_a.present?
  price_a
elsif price_b.present?
  price_b
else
  ""
end

Gross right? uh. I hate hate if structures like that just for checking if something has value. Following Avdi Grimm and reading his book “Much Ado about Naught” and his Confident Ruby has given me ideas to get around this type of coding! Using compact is great for this since it throws away any nils. Note this returns a copy of the array not changing it (as it would if it was compact!).

compact!

compact! → ary or nil
Removes nil elements from the array. Returns nil if no changes were made, otherwise returns ary.

Here’s what I just said, the ! changes the array and if nothing changed it just returns nil.

concat

concat(other_ary) → ary 
Appends the elements of other_ary to self.

Concatenates one array into the other. Also could use + … let me try it.

1
2
3
4
5
6
7
8
9
10
>> colors = [:red, :green, :blue]
=> [:red, :green, :blue]
>> colors.concat([:yellow, :orange])
=> [:red, :green, :blue, :yellow, :orange]
>> colors
=> [:red, :green, :blue, :yellow, :orange]

>> colors = [:red, :green, :blue] + [:yellow, :orange]
>> colors
=> [:red, :green, :blue, :yellow, :orange]

So, looks like they both will add arrays and the arrays are identical. Depending on the context, I think i might like the concat better.

count

count → int 
count(obj) → int
count { |item| block } → int

I think I knew count could count particular items but I forgot. Trying it out:

1
2
3
4
5
6
>> items = [:potion, :food, :food, :weapon, :potion]
=> [:potion, :food, :food, :weapon, :potion]
>> items.count(:potion)
=> 2
>> items.count(:food)
=> 2

So imagine if you were writing a game, and showing stats for things in your bag you could do something like this. The last one takes a block.

cycle

cycle(n=nil) {|obj| block } → nil 
cycle(n=nil) → an_enumerator

Cycle will iterate through an array going through each item n times or forever

1
2
3
4
5
6
7
8
9
10
11
12
>> levels = [:one, :two, :three, :four, :five]
>> levels.cycle(2) { |level| puts "level #{level}" }
level one
level two
level three
level four
level five
level one
level two
level three
level four
level five

This cycles through the array 2 times. Hmm that makes me wonder if I can use this as sort of a state machine?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>> status = [:draft, :review, :publish]
=> [:draft, :review, :publish]
>> status.cycle(1)
=> #<Enumerator: [:draft, :review, :publish]:cycle(1)>
>> states = status.cycle(1)
=> #<Enumerator: [:draft, :review, :publish]:cycle(1)>
>> states.next
=> :draft
>> states.next
=> :review
>> states.next
=> :publish
>> states.next
StopIteration: iteration reached an end
         from (irb):62:in `next'
        from (irb):62
        from /Users/nolastowe/.rvm/rubies/ruby-1.9.3-p392/bin/irb:16:in `<main>'

Hmm interesting. Well maybe needs some work. :) Next is a method for dealing with loops… not sure if its great to be using with cycle, its just something that came to my head when I was playing around.

This is enough for now, next blog post will start with delete.

Exploring Arrays - Part 3

Continuing going through the array methods, using Ruby 1.9.3

Element Reference

ary[index] → obj or nil

ary[start, length] → new_ary or nil

ary[range] → new_ary or nil

slice(index) → obj or nil

slice(start, length) → new_ary or nil

slice(range) → new_ary or nil

Ok, so we’ve got the “normal” way to access an array element, simply using the name of the array, [ index ]. If item is not found at index it returns nil.

Then we have passing a start index and a length. A friend was working on rubykoans.com had question I couldn’t answer - Why is ary[4,0] an empty array and not nil?

1
2
3
4
5
6
7
8
9
10
>> ary = %w(one two three four)
=> ["one", "two", "three", "four"]
>> ary[0,0]    #expected
=> []
>> ary.index(ary.last)    # index of last item is 3
=> 3
>> ary[4,0]    # not expected, no index of 4 exists ?? why return empty array 
=> []
>> ary[5,0]    # expected, no index of 5
=> nil

The docs say

1
Returns nil if the index (or starting index) are out of range.

So yes, thats very confusing… why is it returning an empty array for last_index+1 of the array??

Moving on .. Passing a range is another way to access elements

I tried accessing an index greater than the end and it works as expected

1
2
3
4
5
6
>> ary[0..3]                        # all the elements
=> ["one", "two", "three", "four"]
>> ary[1..2]                        # just index 1 and 2
=> ["two", "three"]
>> ary[1..5]                        # accessing off the end of array
=> ["two", "three", "four"]

It looks as though slice is alias for [ ] … so everything should work the same.

Element Assignment

ary[index] = obj → obj

ary[start, length] = obj or other_ary or nil → obj or other_ary or nil

ary[range] = obj or other_ary or nil → obj or other_ary or nil

1
2
3
4
>> ary[0,2] = %w(uno dos)
=> ["uno", "dos"]
>> ary
=> ["uno", "dos", "three", "four"]

Starting at index 0 and for 2 elements, replace with a new array .. works! Never used that before! Cool

also you can use it to clear out values

1
2
3
4
5
6
>> ary
=> ["uno", "dos", "three", "four"]
>> ary[0,2] = nil
=> nil
>> ary
=> [nil, "three", "four"]

assoc(obj) → new_ary or nil

This works on an array which is a collection of arrays, and this method will find the first array where the first key matches obj. Odd, not sure when I would use this.

at(index) → obj or nil

Same thing as ary[index] .. maybe it would read better, but I’m so used the [ ] syntax, I will probably use that syntax

clear → ary

Clear, removes all elements in the array. Didn’t know this was there.

collect/map

collect {|item| block } → new_ary

map {|item| block } → new_ary

collect → an_enumerator

map → an_enumerator

Not the same collect that is in enumerable, it runs the block for each item in the array and returns an array of results.

1
2
3
4
5
6
7
8
9
10
>> %w(red blue green yellow orange).collect { |w| w.upcase }
=> ["RED", "BLUE", "GREEN", "YELLOW", "ORANGE"]

>> %w(red blue green yellow orange).map(&:upcase)
=> ["RED", "BLUE", "GREEN", "YELLOW", "ORANGE"]

>> %w(red blue green yellow orange).map(&:upcase).object_id
=> 70349437828620
>> %w(red blue green yellow orange).object_id
=> 70349434016460

You can give it a block or a “symbol to proc”, that is the funny &: followed by a method name. When I first saw that I said what the heck is that? and what is it doing? I mean, how do you google for something like that? I finally found out what it was called…”symbol to proc” and now I use it everywhere it makes sense. So Map and Collect appear to be synonyms here. Did not know that… Usually, I use collect over map since that makes more sense to me, you are collecting results.

That is all for this post, I can replace arrays in to arrays, now I know that collect and map are the same on arrays. Still there is the nagging problem of why on a 4 element array ary[4,0] returns an empty array instead of nil. Anyone know?

Other posts in this series:

Exploring Arrays - Part 2

My second blog post on the topic. Between the writings of this post and part 1 Ruby 2.0 was released on its 20th birthday! But I am going to stick with Ruby 1.9.3 for this series, maybe after I am done I’ll see what changed for 2.0

Array Documentation http://ruby-doc.org/core-1.9.3/Array.html

BTW, to make an array you can use the %w and space separated list of values, I will use that here to save on typing.

ary & other_ary → new_ary

Set Intersection—Returns a new array containing elements common to the two arrays, with no duplicates.

Oooh this sounds like math, specifically Set Theory. I did this in college but didn’t remember the ‘no duplicates’ part so I looked it up. The definition for Intersection from wikipedia is “the intersection of two sets A and B is the set that contains all elements of A that also belong to B (or equivalently, all elements of B that also belong to A), but no other elements.” So no room for duplicates there either.

Lets try it:

1
2
3
4
5
6
7
8
>> cookie_ingredients = %w(butter eggs sugar salt)
=> ["butter", "eggs", "sugar", "salt"]

>> pancake_ingredients = %w(vanilla sugar baking_powder, eggs)
=> ["vanilla", "sugar", "baking_powder,", "eggs"]

>> cookie_ingredients & pancake_ingredients
=> ["eggs", "sugar"]

If I wanted to know what ingredients I need to be sure to get enough of for baking I could make some arrays like that and get the intersection of them. Whoa I thought & for bitwise operation? Well Yes it is!! But that is for Fixnum objects. With arrays the & is an intersection! Cool .. polymorphism for the win!

Next is the * operator with two usages:

ary * int → new_ary

ary * str → new_string

Repetition—With a String argument, equivalent to self.join(str). Otherwise, returns a new array built by concatenating the int copies of self.

Lets try the * int out first:

1
2
3
4
5
>> week = %w(Sunday Monday Tuesday Wednesday Thursday Friday Saturday)
=> ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]

>> week * 4
=> ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]

I made an array for days of the week, then used * 4 to make a 4 week month. Seems pretty awesome to something like this without having to loop to build arrays.. if I didn’t use that I would have to write code like this:

1
2
3
4
5
6
7
8
>> four_week = []
=> []
>> 4.times do
?> four_week << week
>> end

>> four_week
=> [["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]]

Hmm can’t figure out a way to make it a single array, so I call flatten

1
2
>> four_week.flatten
=> ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]

That all being said, if you want to combine an array 4 times, use * and it is easy :)

There’s other ways that might be better, but you get the idea. Much shorter to use the * int :) lets try the other version.

1
2
3
4
>> title = %w(Samuel E. Jones)
=> ["Samuel", "E.", "Jones"]
>> title * " "
=> "Samuel E. Jones"

The parameter after the * is the character to join with, basically it is calling join.

1
2
>> title.join(" ")
=> "Samuel E. Jones"

I probably would use join since that makes it more clear to the reader what you are doing and it is more common. But if you are going for ruby golf, then use the * ” ”

ary + other_ary → new_ary

Array concatenation, simply adding two arrays.

1
2
3
4
5
6
>> meals = %w(breakfast lunch dinner)
=> ["breakfast", "lunch", "dinner"]
>> snacks = %w(snack1 snack2)
=> ["snack1", "snack2"]
>> buy_food = meals + snacks
=> ["breakfast", "lunch", "dinner", "snack1", "snack2"]

Easy, next array difference.

ary - other_ary → new_ary

Array Difference---Returns a new array that is a copy of the original array, removing any items that also appear in other_ary. (If you need set-like behavior, see the library class Set.)
1
2
3
4
5
6
>> colors = %w(red purple blue green yellow orange)
=> ["red", "purple", "blue", "green", "yellow", "orange"]
>> primary_colors = %w(red blue yellow)
=> ["red", "blue", "yellow"]
>> secondary_colors = colors - primary_colors
=> ["purple", "green", "orange"]

Also pretty straight forward.

ary << obj → ary

Append—Pushes the given object on to the end of this array. This expression returns the array itself, so several appends may be chained together.

Commonly called the shovel operator you can add something to the end of the array, and since it returns an array you can do it multiple times

1
2
3
4
5
6
7
8
>> colors = []
=> []
>> colors << "red"
=> ["red"]
>> colors << "blue"
=> ["red", "blue"]
>> colors << "green" << "orange"
=> ["red", "blue", "green", "green", "orange"]

Chaining << is just like chaining other methods:

1
2
>> "first name".gsub(" ","_").upcase
=> "FIRST_NAME"

which is basically

1
2
>> colors.<<("red").<<("green")
=> ["red", "green"]

without the extra parenthesis. Cool, I hadn’t realized you could chain << before now!

Next, a method with a funny name. <=>

ary <=> other_ary → -1, 0, +1 or nil

Comparison—Returns an integer (-1, 0, or +1) if this array is less than, equal to, or greater than other_ary. Each object in each array is compared (using <=>). If any value isn’t equal, then that inequality is the return value. If all the values found are equal, then the return is based on a comparison of the array lengths. Thus, two arrays are “equal” according to Array#<=> if and only if they have the same length and the value of each element is equal to the value of the corresponding element in the other array.

I’ve only seen this used when writing custom methods to determine equality, but it seems pretty straight forward. I will play with it when I play around with enumerable.

ary == other_ary → bool

Equality—Two arrays are equal if they contain the same number of elements and if each element is equal to (according to Object.==) the corresponding element in the other array.
1
2
3
4
5
6
>> [1,2] == [2,1]
=> false
>> [1,2,3] == [1,2]
=> false
>> [1,2] == [1,2]
=> true

To be equal they have to have the same number of elements and same ordering of elements. The first and last examples show that.

I didn’t learn anything earth shattering this time, but it is a good review of some basic arrays and set operations.

Exploring Arrays - Part 1

Everytime that I have to lookup something with hashes or arrays, I find lots of methods that I didn’t know about, so I thought I’d do an experiment where I will learn about each one and write some examples and try to understand how to use it. I kind of picture someone sitting next to me as I do this, reading the docs and trying them out with me.

Ruby 1.9.3 Array Documentation

Class Methods

Class methods always start with the name of the class, dot, followed by method name. For example, we can call Time.now as a class method on the Time class, which returns a new Time object initialized with the current time.

Docs say:

[](*args)

[](*args)
Returns a new array populated with the given objects.

There are three usage examples in the docs, lets try them out and see what they do, first:

1
2
3
4
>> Array.[](1)
=> [1]
>> Array.[](1,2,3)
=> [1, 2, 3]

The method name is [] and the params is *args which is the splat operator which takes any number of objects. Interesting I’ve never seen this used in the real world. I am sure its used cleverly, I just don’t see it! I showed this to a friend Danielle Sucher and she said:

I actually always think it’s nifty that something like a[0] can be called with a.send(:[], 0) instead. Makes it possible to do stuff like a.try(:[], 0) or a.tap{}.send(:[], 0).

Thanks!! Moving on..

1
2
>> Array['a','b','c']
=> ["a", "b", "c"]

Returns array with the contents of *args just as it says. This is one way you can be “confident” of your code as Avdi talked about in Confident Coding . If you want an array, make sure its an array! if its not an array it will put it inside an array like this:

1
2
3
4
>> Array(1)
=> [1]
>> Array([1])
=> [1]

Parentheses is optional in ruby so these are the same:

1
2
3
4
5
6
>> Array 1
=> [1]
>> Array [1]
=> [1]
>> Array([1,2,3]) == Array[1,2,3]
=> true

Looks funny without the () doesn’t? I almost always use () for methods. Helps later on if you decided to add more things on that line you don’t have to go back and add them. See Avdi’s RubyTapas Episode 024 Incidental Change $9 a month screencasts that come out 3x week, so good!! Sign up now! :)

And lastly, the way you might normally create arrays, with [ *args ]. I tried to dig through Kernel to see if [] was a method on kernel that would call Array.new but I couldn’t find anything. So I am still puzzled about how this actually works. Maybe a reader has an insight?

1
2
>> [1,2,3]
=> [1, 2, 3]

Array.new

new(size=0, obj=nil)
new(array)
new(size) {|index| block }
Returns a new array.

So if no params, default is size 0 and value of index 0 is nil

1
2
3
4
>> a = Array.new
=> []
>> a[0]
=> nil

Creates an empty array. Default value is nil.

If you pass a single param, it makes an array of that size.

1
2
3
4
>> a = Array.new(5)
=> [nil, nil, nil, nil, nil]
>> a.size
=> 5

Creates an array with 5 elements with the default value is nil

If we pass two params, the second is the default value of the empty elements

1
2
3
4
5
6
7
8
>> a = Array.new(5, "-empty-")
=> ["-empty-", "-empty-", "-empty-", "-empty-", "-empty-"]
>> a[0]
=> "-empty-"
>> a[1]
=> "-empty-"
>> a[0].object_id == a[1].object_id
=> true

So the default value of each element is the string “-empty-” and they are in fact the same object.

Lets create an array of basic family members, adding it to her_side and his_side. Then I added another family member to his_side and prove they are copies of the parents and not the same object.

Second version is passing an array to Array

1
2
3
4
5
6
7
8
9
10
11
12
>> parents = ["mom", "dad"]
=> ["mom", "dad"]
>> her_side = Array.new(parents)
=> ["mom", "dad"]
>> his_side = Array.new(parents)
=> ["mom", "dad"]
>> her_side == his_side
=> true
>> his_side << "grandma"
=> ["mom", "dad", "grandma"]
>> her_side == his_side
=> false

And finally the third form uses a block:

1
2
>> b = Array.new(5) { |index| "-#{index}-" }
=> ["-0-", "-1-", "-2-", "-3-", "-4-"]

Interesting, maybe if you wanted an array like this

1
2
>> b = Array.new(5) { |index| index* 5 }
=> [0, 5, 10, 15, 20]

Cool!

try_convert(obj) -> array or nil

Tries to convert obj into an array, using to_ary method. Returns the converted array or nil if obj cannot be converted for any reason. This method can be used to check if an argument is an array.
1
2
3
4
>> Array.try_convert(1)
=> nil
>> Array.try_convert([1,2,3])
=> [1, 2, 3]

Hmm, so I guess this would be good if you only want to return array if its an array and nil otherwise. Never seen it used myself but it be a way to write confident code if you only want to respond to nil or array and use a bunch of if statements.

Cool, I had fun poking at ruby array class methods and trying things out. Be sure and checkout the gotchas in the docs. I hope I was able to shed some light or at least make you think about some of the public methods of arrays. If you have some insight on how some of these work, please leave a note in the comments.

Thank you to Danielle Sucher @DanielleSucher for helping by proof-reading this post as I am working on improving my writing.

Next post in this series will be on instance methods!

Reading Books Cover-to-Cover

I wanted to buy “Practical Object-Orientated Design in Ruby” by Sandi Metz when it first came out, and I had a hard time justifying it because there are many books I have bought and have not read all the way through. So I thought I’d do an experiment in reading a tech book cover-to-cover and then I’ll buy “poodr”. So my first cover-to-cover read was Eloquent Ruby by Russ Olsen. Not all books should be read cover-to-cover but when you read a book cover-to-cover you’ll discover a few things:

  • what topics are there and how deep they are
  • what topics are not
  • the sequence and structure of the book, about where things are so its easier to flip back to review

And lastly, you’ll be able to speak authoritatively to someone when you say “Read this book!”

I bought Eloquent Ruby perhaps 1.5 years ago, and after the first couple chapters decided it was the most awesome book ever and how much smarter I would have been had I gotten it sooner. I read maybe 1/3 of the way through, I skipped around some, the testing chapters and the metaprogramming. Even with skipping around in the book, I quickly became an evangelist for this book. I told every ruby developer I encountered to buy it, I even got a copy for my last company. It’s just plain good, you’ll learn the ruby idioms and why. I’ve been programming since I was 13 and got pretty good at memorizing the syntax of things, not truly understanding why or how, but “type this thing to do that thing”. But Eloquent Ruby helped me understand why behind the syntax. Now that I understand “why”, it is so much easier to remember without relying on memorization.

That is why I chose this book to read as my first cover-to-cover read.

I needed a way to keep track of my progress since I use different devices and software (mac, iphone, ipad, android nexus) I can’t rely on a cloud service to “sync my place” across all of them. I use an Evernote note with all the chapters as a checkbox list. Plus, I love checking things off a list. I would see my progress and be able to pick back up where I left off each reading session. The chapters in Eloquent Ruby are pretty short, so it was easy to read in small chunks of time. I read it at break at work, on the bike at the gym, riding in car, just about anywhere. It took a couple months to get through all the chapters this way.

It didn’t take long to realize one of the benefits of reading cover-to-cover. When I was almost done with the book, a friend was having problems with some concept in ruby and I remembered there was a chapter about it, near the beginning of the book. I flipped around a few minutes and found the prefect chapter for her to read. Had I not read it cover-to-cover I may not have known that content was there or wouldn’t have been as confident recommending it and my “find it in this chapter” instructions.

My “reward” for finishing Eloquent Ruby was to get Sandi Metz’s book “Practical Object-Orientated Programming in Ruby”.

I followed the same process and created a list of chapters in Evernote, planning to read them in bits at home, gym and work breaks. At only 247 pages, it is quite a bit shorter than Eloquent Ruby with 447 pages so I knew it would take alot less time.

Chapter 1 came easily enough and I checked it off. Then I was surprised to find out what followed was that I could not put the book down. Instead of my next reading time or gym appointment, I read till 2 in the morning, picked back up and finished it the next morning (it probably helped that I was home sick with the weekend to myself). I was so excited about what I was learning, I wanted to stop reading and refactor code I wrote a few days ago. I so wanted to skip ahead to Chapter 9 on tests. However, I stuck to original plan of cover-to-cover and read all the way through. It is an incredible book.

I say incredible not just because “I learned the right way” but because it validated so many instincts and gut feelings I have about class design. Having those things in writing gives a source to “cite” in discussions and confidence to say “Yes, this is how we will do this thing”.

So as a result of my experiment I would recommend these two things to anyone wanting to improve their knowledge of ruby:

  1. Get these two books.
  2. Read them cover-to-cover.

I’m confident that you will enjoy both the information and the reading experience.

BTW these are affiliate links, maybe I’ll earn enough to get a cup of coffee eventually.

Simple Breadcrumbs

I needed a simple breadcrumb module/class that would let me set the first crumb and add to it later. I looked at www.ruby-toolbox.com and saw a bunch, none of them looked simple enough for me. I already had a template so I dont care about changing that…so I whipped up my own breadcrumbs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Breadcrumb

  Crumb = Struct.new(:name, :link)

  attr_reader :crumbs

  def initialize(name = "Home", link = "/")
    @crumbs = []
    self.add(name, link)
  end

  def add(name, link)
    @crumbs << Crumb.new(name,link)
  end

end

After watching www.rubytapas.com talk about using Struct (I had never really used it before or understood why not just make a class). At first I defined crumb outside of Breadcrumb, then after I had tests, moved inside and it still worked. It seems a bit odd, to have that inside Breadcrumb, but its only accessible inside Breadcrumb so I guess that is good.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
describe Breadcrumb do

  describe '#new' do

    it 'sets default crumb of Home /' do
      @breadcrumb = Breadcrumb.new
      @breadcrumb.should have(1).crumb
      @breadcrumb.crumbs.first.name.should == 'Home'
      @breadcrumb.crumbs.first.link.should == '/'
    end

    it 'sets initial crumb of Main /main' do
      @breadcrumb = Breadcrumb.new('Main', '/main')
      @breadcrumb.should have(1).crumb
      @breadcrumb.crumbs.first.name.should == 'Main'
      @breadcrumb.crumbs.first.link.should == '/main'
    end

  end

  describe '#add' do

    it 'a second crumb' do
      @breadcrumb = Breadcrumb.new
      @breadcrumb.add('Products', '/products')
      @breadcrumb.should have(2).crumbs
    end

  end

output of spec doc

1
2
3
4
5
6
Breadcrumb
  #new
    sets default crumb of Home /
    sets initial crumb of Main /main
  #add
    a second crumb

I did a codereview on twitter and got some good comments, and my code is better because of it! Thanks @benhamil and @therealadam. See the comments on initial versions of the code.

Using ActiveModel to Validate Input

The other day I was working a project where I had to validate some input before running a query:

Say I have a database of friends and their address, and I want to find all friends with at least 3 letters of the name and an optional zipcode. The controller looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def index
  @name = clean_name(params[:name])
  @zip = params[:zip]
  if @name.present? && @name.size > 2
    if @zip.present? && @zip.match(/^\d{5}$/)
      @friends = Property.where( "name like ?", "%#{@name}%").where("zip_code = ?", @zip)
    else
      @friends = Property.where( "name like ? ", "%#{@name}%")
    end
  else
    @friends = []
  end
end

private

def clean_name(str = "")
  str.gsub(/mrs?|miss|ms|jr|sr/i, "").strip if str.present?
end

Ugly huh? Too many if statement and validation and checking for blanks. I was in a rush, so I was trying to get it out there and move on with life, but when I needed the same validation in another action, I figured it was time to bite the bullet and Do It The Right Way.

I started off with a plain old ruby object (PORO) in lib directory so I can validate the params for a search query there (in past, I’ve put objects like this in models since its sort of a model, just not a database model, so .. I am 50/50 on the issue. Meh. I’ll figure out the best location later if need be).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class SearchParams

  attr_reader :name, :zip_code

  def initialize(args)
    @name = clean_name(args[:name])
    @zip_code = args[:zip_code]
  end

  private

  def clean_name(str = "")
    str.gsub(/mrs?|miss|ms|jr|sr/i, "").strip if str.present?
  end

end

Then for the controller:

1
2
3
4
5
6
7
8
9
10
11
12
def index
  @search_params = SearchParams.new(params)
  if @name.present? && @name.size > 2
    if @zip.present? && @zip.match(/^\d{5}$/)
      @friends = Property.where( "name like ?", "%#{@search_params.name}%").where("zip_code = ?", @search_params.zip)
    else
      @friends = Property.where( "name like ? ", "%#{@search_params.name}%")
    end
  else
    @friends = []
  end
end

And now that it param in its own class, its much easier to test (I personally despise testing controllers)..and that private method is out of the controller, yay!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
describe SearchParams do
  it "should initialize the Search object" do
    @search = SearchParams.new(name: "blah", zip_code: "12345")
    @search.name.should == "blah"
    @search.zip_code.should == "12345"
  end

  context "clean name" do

    it "should clean name modifiers from search query" do
      keywords = %w(mr mrs miss jr sr)
      keywords.each do |keyword|
        @search = SearchParams.new(name: "#{keyword} Bob", zip_code: "12345")
        @search.name.should == "Bob"
      end

      keywords.each do |keyword|
        @search = SearchParams.new(name: "blah #{keyword.upcase!}", zip_code: "12345")
        @search.name.should == "Bob"
      end
    end

  end
end

That first test is just sort of a sanity test, to make sure everything is working. I may delete it later. Then I test cleaning the modifiers both lowercase and uppercase to confirm the case insensitivity of the regex (maybe not necessary). The each loop there actually makes several tests in loop.

Better but not by much. Lets add validations from http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html and see if we can cut down on those ugly if statements.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class SearchParams
  include ActiveModel::Validations
  validates :name, presence: true, length: { minimum: 3 }
  validates :zip_code, format: /^\d{5}$/, allow_blank: true

  attr_reader :name, :zip_code

  def initialize(args)
    @name = clean_name(args[:name])
    @zip_code = args[:zip_code]
  end

  private

  def clean_name(str = "")
    str.gsub(/mrs?|miss|ms|jr|sr/i, "").strip if str.present?
  end
end

Awesome. Now the controller code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def index
  @search_params = SearchParams.new(params)

  if @search_params.valid?
    if @search_params.zip_code.present?
      @friends = Friend.where( "name like ?", "%#{@search_params.name}%").where("zip_code = ?", @search_params.zip_code)
    else
      @friends = Friend.where( "name like ? ", "%#{@search_params.name}%")
    end
  else
    @friends = []
  end

end

Looks better, we can just do a .valid? call to see if the name is of valid length and the zipcode (if its provided) meets the the requirements of 5 digits. Nicely refactored and now its easier to test. Now we can test the validations:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
context "validations" do
  it "should not be valid for name length of 1" do
    @search = SearchParams.new(name: "b")
    @search.should_not be_valid
  end

  it "should be valid for name length of 3" do
    @search = SearchParams.new(name: "bla")
    @search.should be_valid
  end

  it "should allow blank for zip_code" do
    @search = SearchParams.new(name: "blah", zip_code: "")
    @search.should be_valid
  end

  it "should not allow 1 for zip_code" do
    @search = SearchParams.new(name: "blah", zip_code: "1")
    @search.should_not be_valid
  end
end

BTW since there is a method called valid? and it returns a boolean (obviously with the ? at end) in rspec you can just do be_whatever to call that method in your tests.

Beautiful!! … I sleep better tonight knowing I’ve made beautiful code :) :) :) :)

Better Code Through Code Reviews

For one of my projects we have started doing code reviews. We use github, work in a branch, then submit a pull request for review. Looking at github you can see a nice diff of the changes and you are able to add comments. So github is one way. You could also just use

1
git diff  master..myawesomebranch 

And get a decent diff.

I prefer to code review live if the other person is available in person (screensharing would work too). It makes it easy to ask why this, and did you consider this and then after discussion you can make a note of what to change.

Its super easy to nit pick at someones code, after all programming is alot of your personal style. But there are sometimes where you say “umm ok thats different, cool lets move on” and sometimes where you can say “hmm, what do you think of this instead” like for example

1
2
3
  unless something == "something" && !this.method(that) do
     // this awesome thing
  end

yes it works (but I didn’t question if it works or not, I’m thinking of humans reading this code later!), but lets consider:

1
2
3
  if something != "something" && this.method(that) do
     // this awesome thing
  end

I think its a little more readable, but when I make suggestions I like to open the door for discussion, and perhaps I don’t understand all the code and it gives the other person to explain it. Sometimes they answer with “oh well i didn’t write that part” .. That is OK!! when I do a code review I am taking it as you saying “hey this code was my responsibility, I added some code, fixed some confusing parts and submit it you for review.”

I rarely do git blame to see who did something because it doesn’t matter most of the time who did that weird bit of code. Most likely it was a build up of code and the author didn’t stop to think about refactoring, or he/she was under time constraints. That’s the normal evolution of programming and we are trying to break that habit with reviews. But if I find a confusing bit of code that I can’t figure out, then maybe I’ll do git blame to see who last edited that so I can go to them and ask for some help in understanding it. Coding is never a perfect process. This is why code reviews are good.

I like code reviews alot and have done them at a few different companies and with people having the right attitudes it goes a long way to making better code.

Caps in Ruby Are Constants

Everything in Ruby that starts with a capital letter is a constant, meaning you can’t change its value. That means:

1
2
3
4
API_USER
API_PASSWORD

Talk

Are constants, here they are as you normally might see them:

1
2
3
4
5
API_USER = 'devuser'
API_PASSWORD = "h1%3am1"

Class Talk < ActiveRecord::Base
end

I’ve seen people use const_get(“string”) to get the objectived (yes I make up my own words, I don’t know what you would call this? perhaps constantized? keep reading) of a string like:

1
2
3
4
5
6
>> t = Object.const_get("Talk")
=> Talk(id: integer, conference_id: integer, person_id: integer, title: string, description: text, slides_url: string, video_url: string, start_time: datetime, end_time: datetime, created_at: datetime, updated_at: datetime)
>> intro_talk = t.new(title: "Intro to Rails")

t.ancestors[0]
=> Talk(id: integer, conference_id: integer, person_id: integer, title: string, description: text, slides_url: string, video_url: string, start_time: datetime, end_time: datetime, created_at: datetime, updated_at: datetime)

Crazy, huh? We look up the constant “Talk” (a subclass of ActiveRecord) and assign it to ‘t’ and use that to instantiate a new record. I don’t know why you’d do this, but this is what it’s doing and since today I learned that any uppercased ruby identifier is an constant that all makes perfect sense. We can look at the first ancestors and see its ancestor is Talk.

Playing With RubyKoans

From time to time I run through the rubykoans…each time remembering or picking up something new. I’m such a dork, I keep a log of the dates in a spreadsheet. I first did these in Dec 2009, then again in July 2010, May 2011 and now I am going through them again. I remember the first time I did a few, I was amazed “how did they do that!?!?!” and dug through the source to see how it works. I immediately emailed Joe O’Brien and Jim Weirich at edgecase.com and thanked them! Joe thanked me for my kind words and Jim said they were inspired by the book Little Lisper.

When I first did these in 2009, it was a github repo that you cloned. Now you can go to www.rubykoans.com and download a zipfile or work on them through the browser! Few months ago I was bored with no real computer, so I attempted the browser based koans on my Samsung Tablet. It was kinda hard to do the special symbols so I don’t really recommend doing it on a tablet unless you merely wanted to kill time like I did. :)