%w(hashrockets spaceships bangbangs)

> non-optimized bits & pieces <

Tripping Over Method & Local Variable

As you know, ruby always tries hard to get out of the programmer’s way most of the time. One good example is when u invoke a method that doesn’t require any argument:

1
2
3
4
5
6
def mm
  :ok
end

mm   # >> :ok
mm() # >> :ok

Almost always, to invoke mm, mm is preferred over mm(), doing it the mm() way is so un-rubyish. Yet this flexibility tripped us over today, consider the following:

1
2
3
4
5
6
7
8
9
10
11
12
describe Thing do
  let(:alien) { Factory(:thing, name: 'alien') }
  let(:robot) { Factory(:thing, name: 'robot') }

  %w{alien robot}.each do |thing|
    context "as #{thing}" do
      let(:subject) { thing }
      let(:thing) { send(thing) }
      it { should be_macho }
    end
  end
end

When we ran the above spec, we get undefined method 'macho' for "alien":String (NoMethodError) .. why ??

Here’s our intended behaviour:

1
2
3
4
5
6
7
8
9
10
11
12
describe Thing do
  let(:alien) { Factory(:thing, name: 'alien') } # defines alien()
  let(:robot) { Factory(:thing, name: 'robot') } # defines robot()

  %w{alien robot}.each do |thing|  # set local var thing
    context "as #{thing}" do
      let(:subject) { thing }      # defines subject() to return thing()
      let(:thing) { send(thing) }  # defines thing() to return the evaluate alien() or robot()
      it { should be_macho }
    end
  end
end

This is what happened instead:

1
2
3
4
5
6
7
8
9
10
11
12
describe Thing do
  let(:alien) { Factory(:thing, name: 'alien') } # defines alien()
  let(:robot) { Factory(:thing, name: 'robot') } # defines robot()

  %w{alien robot}.each do |thing| # set local var thing
    context "as #{thing}" do
      let(:subject) { thing }     # ** defines subject() to return the local var thing
      let(:thing) { send(thing) } # ** defines thing() which never gets invoked
      it { should be_macho }
    end
  end
end

To fix the problem, we can either:

  • avoid confusing names by renaming the local variable thing to _thing & amend all its intended usage accordingly (which include let(:thing) { send(thing) } to let(:thing) { send(_thing) }), OR

  • be explicte when invoking method by rewriting let(:subject) { thing } as let(:subject) { thing() }

ArgumentError Is Simple

What do you get if u invoke a method with the wrong number of arguments ?? It throws in ur face ArgumentError … it doesn’t try to be polite, you are at fault since you are the one that breaches the contract !!

1
2
3
4
5
6
def m0
  :ok
end

m0    # >> :ok
m0(1) # >> (...) wrong number of arguments (1 for 0) (ArgumentError)

It tells you that it is expecting 0 argument, yet you have passed it 1 argument. Let’s have another one:

1
2
3
4
5
6
7
def m2(x, y)
  :ok
end

m2       # >> (...) wrong number of arguments (0 for 2) (ArgumentError)
m2(1)    # >> (...) wrong number of arguments (1 for 2) (ArgumentError)
m2(1, 2) # >> :ok

Pretty readable rite ?

Enforcing the Rightful Owner With FactoryGirl

We use thoughtbot’s FactoryGirl extensively in our daily spec (& feature) writing. One recent problem we encounter is the failure to correctly set the associations between the following 2 example models.

1
2
3
4
5
6
7
class Blog < ActiveRecord::Base
  has_many :comments
end

class Comment < ActiveRecord::Base
  belongs_to :blog
end

The factory definitions are as follow:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FactoryGirl.define do
  factory :comment do
    # (blah blah)
    blog
  end
end

FactoryGirl.define do
  factory :blog do
    # (blah blah)

    factory :commented_blog do
      comments { [association(:comment)] }
    end
  end
end

The problem with the above definitions is that calling Factory(:commented_blog) creates 2 blogs & 1 comment instead of the expected 1 blog & 1 comment, and the comment isn’t owned by the intended blog.

Fixing this problem turns up to be pretty simple, all we need to do is when creating a comment, we enforces the desired ownership:

1
2
3
4
5
6
7
8
9
10
FactoryGirl.define do
  factory :blog do
    # (blah blah)

    factory :commented_blog do
      # Explicte declaring the rightful owner of the comment
      after_create {|blog| Factory(:comment, blog: blog) }
    end
  end
end

If you have some time to spare, u really should take a good read of this doc

Ways a Method Takes Arguments (2)

6. Required hash argument

1
2
3
4
5
6
7
8
9
10
class HTML
  def self.div(attrs)
    attrs = attrs.map{|k,v| "#{k}='#{v}'" }.join(' ')
    "<div #{attrs}></div>"
  end
end

HTML.div                                   # ArgumentError
HTML.div({:id => 'body'})                  # >> "<div id="body"></div>"
HTML.div({:class => 'red', :id => 'body'}) # >> "<div class="red" id="body"></div>"

Well, the {...} isn’t necessary when dealing with hash argument as the only or last argument, thus the above can be rewritten as:

1
2
HTML.div(:id => 'body')                  # >> "<div id="body"></div>"
HTML.div(:class => 'red', :id => 'body') # >> "<div class="red" id="body"></div>"

And using the newer (1.9) json-like hash, we can again rewrite the above as:

1
2
HTML.div(id: 'body')               # >> "<div id="body"></div>"
HTML.div(class: 'red', id: 'body') # >> "<div class="red" id="body"></div>"

7. Optional hash argument

1
2
3
4
5
6
7
8
9
10
class HTML
  def self.div(attrs = {})
    attrs = attrs.map{|k,v| "#{k}='#{v}'" }.join(' ')
    "<div #{attrs}></div>"
  end
end

HTML.div                           # >> "<div ></div>"
HTML.div(id: 'body')               # >> "<div id="body"></div>"
HTML.div(class: 'red', id: 'body') # >> "<div class="red" id="body"></div>"

Let’s say we want id attribute to be always present, & when unspecified, we auto-generate one:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class HTML
  class << self
    def div(attrs = {})
      attrs[:id] ||= "div-#{count}"

      attrs = attrs.map{|k,v| "#{k}='#{v}'" }.join(' ')
      "<div #{attrs}></div>"
    end

    def count
      @count ||= 0
      @count += 1
    end
  end
end

HTML.div(id: 'body')   # >> "<div id="body"></div>"
HTML.div(class: 'red') # >> "<div class="red" id="div-1"></div>"

8. Mixed arguments with last as optional hash

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class HTML
  class << self
    def element(tag, attrs = {})
      attrs[:id] ||= "#{tag}-#{count}"

      attrs = attrs.map{|k,v| "#{k}='#{v}'" }.join(' ')
      "<#{tag} #{attrs}></#{tag}>"
    end

    def count
      @count ||= 0
      @count += 1
    end
  end
end

HTML.element                        # >> ArgumentError
HTML.element('div')                 # >> "<div id="div-1"></div>"
HTML.element('div', {id: 'body'})   # >> "<div id="body"></div>"
HTML.element('div', {class: 'red'}) # >> "<div class="red" id="div-2"></div>"

Again, the {...} isn’t necessary when dealing with hash argument as the only or last argument, thus the above can be rewritten as:

1
2
HTML.element('div', id: 'body')   # >> "<div id="body"></div>"
HTML.element('div', class: 'red') # >> "<div class="red" id="div-3"></div>"

Ways a Method Takes Arguments (1)

1. Argument is required

1
2
3
4
5
6
7
8
class Writer
  def self.type(w)
    "#{w}"
  end
end

Writer.type      # >> ArgumentError
Writer.type("1") # >> "1"

2. Argument is optional

1
2
3
4
5
6
7
8
class Writer
  def self.type(w = nil)
    "#{w}"
  end
end

Writer.type      # >> ""
Writer.type("1") # >> "1"

3. One argument is required while the other optional

1
2
3
4
5
6
7
8
9
class Writer
  def self.type(w1, w2 = nil)
    "#{w1}#{w2}"
  end
end

Writer.type           # >> ArgumentError
Writer.type("1")      # >> "1"
Writer.type("1", "2") # >> "12"

4. Any number of arguments is ok

1
2
3
4
5
6
7
8
9
class Writer
  def self.type(*w) # "*" is known as "splat" operator
    w.join('')
  end
end

Writer.type                # >> ""
Writer.type("1")           # >> "1"
Writer.type("1", "2", "3") # >> "123"

Say “hello” to the splat operator *, a greedy fellow that swallows up all arguments, from its position onwards, the assigned variable (w in the above example) becomes an array that contains all the captured arguments.

1
2
3
4
5
def showme(*args)
  args
end

showme(1, 2, 3, 4) # >> [1, 2, 3, 4]

5. One argument is required while the rest are optional & can be any number

1
2
3
4
5
6
7
8
9
class Writer
  def self.type(w1, *w) # again, we have the "*" (splat) operator
    "w1" + w.join("")
  end
end

Writer.type                # >> ArgumentError
Writer.type("1")           # >> "1"
Writer.type("1", "2", "3") # >> "123"

Yet Another Way to Access Vim Buffers

How do you quickly access a particular buffer (amongst a long list of buffers) in vim? For ages, i’ve been using :ls, followed by :b<id>, where <id> is the id of a particular buffer.

Recently, i’ve discovered yet another way to acheive it using BufExplorer, to install it, download the latest version & save it to ~/.vim/bundle, then:

1
2
$ cd ~/.vim/bundle
$ unzip bufexplorer.zip

Restart your vim, open several files, & try \be (backslash + b + e), you are then presented with BufExplorer, & within it, u can goto a specific buffer with:

  • search with /, followed by enter, or
  • goto that line with :<lineno>, followed by enter, or
  • simply :b<id>

If you want to be able to goto BufExplorer by doing CTRL-b, just add the following line to ur ~/.vimrc:

1
nnoremap <C-B> :BufExplorer<cr>

Alternatively, you may wanna remap how the command :ls works by doing the following instead:

1
cabbrev ls :BufExplorer

If you prefer loading BufExplorer in horizontal or vertical split, you may wanna try:

  • \bs (backslash + b + s) for horizontal split
  • \bv (backslash + b + s) for vertical split

Pick the one u like & have fun !!

3 Ways to Define Class Methods

There are 3 ways to create class methods in ruby:

Probably when you just need one
1
2
3
4
5
6
7
class Thing
  def self.all
    :everything
  end
end

Thing.all # >> :everything
Probably when you need several
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Thing
  class << self

    def self.all
      :everything
    end

    def self.some
      :something
    end

  end
end

Thing.all  # >> :everything
Thing.some # >> :something
Probably when you are going bananas
1
2
3
4
5
6
7
class Thing
  def Thing.all
    :everything
  end
end

Thing.all # >> :everything

If you work with me & u use the last one, i’ll hunt u down & haunt you :P

What You Should Know Abt ActiveRecord’s Callbacks

I’m a fan of ActiveRecord’s callbacks, as i see it a clean way to get things done in the life-cycle of a model instance. Yet, today a couple of us just tripped over the following:

1
2
3
4
5
6
7
8
9
10
class Thing < ActiveRecord::Base
  before_create :reset_pretty_flag

private

  def reset_pretty_flag
    # Let's KISS for now, even though the logic is flawed :P
    self.pretty = name.downcase.include?('pretty')
  end
end

The problem with Thing#reset_pretty_flag is that in the unfortunate case that thing isn’t pretty, its creation fails. Why ?? Cos when thing isn’t pretty, a false is returned, & this halts the create executation chain. The workaround is therefore to return a true always:

1
2
3
4
def reset_pretty_flag
  self.pretty = name.downcase.include?('pretty')
  true # any other non nil/false value will work as well
end

To learn more, i strongly encourage a good read on ActiveRecord’s callbacks

Method Aliasing

Method aliasing is what every budding rubyists should pick up. This is done using Module#alias_method:

1
2
3
4
5
6
7
8
class Thing
  def size; :xl; end
  alias_method :mass, :size
end

thing = Thing.new
thing.size # >> xl
thing.mass # >> xl

To say that it is simple aliasing is abit deceiving. Under the hood, ruby creates a copy of the original method Thing#size, thus, even if you change the original method, the new method Thing#mass still points to the same method. Here’s an extension of the above example:

1
2
3
4
5
6
7
8
class Thing
  # Redefining the original method
  def size; :xxl; end
end

thing = Thing.new
thing.size # >> xxl
thing.mass # >> xl

It is important to note that the last technique isn’t encouraged in proper software engineering, yet it can really be useful when u need a quick hack on somebody’s code, just to patch & get things done.

If u have some time to spare, you should read more abt yehuda’s case against rails’ alias_method_chain .