Common Idioms - Appendixes - Metaprogramming Ruby 2: Program Like the Ruby Pros (2014)

Metaprogramming Ruby 2: Program Like the Ruby Pros (2014)

Part 3. Appendixes

Appendix 1. Common Idioms

This appendix is a mixed bag of popular Ruby idioms. They aren’t really “meta,” so they don’t fit into the main story of this book. However, they’re so common and they’re the foundation of so many metaprogramming spells that you’ll probably want to get familiar with them.

Mimic Methods

Much of Ruby’s appeal comes from its flexible syntax. You can find an example of this flexiblity even in the most basic program:

puts 'Hello, world'

Newcomers to Ruby often mistake puts for a language keyword, when it’s actually a method. People usually leave out the parentheses when calling puts, so it doesn’t look like a method. Reinsert the parentheses, and the nature of puts becomes obvious:

puts('Hello, world')

Thanks to disguised method calls such as this one, Ruby manages to provide many useful function-like methods while keeping the core of the language relatively small and uncluttered.

This simple idea of dropping parentheses from method calls is used quite often by expert coders. Sometimes you’ll want to keep the parentheses because they make a method’s nature obvious—or maybe because the parser requires the parentheses to make sense of a complex line of code. Other times, you’ll want to drop the parentheses to make the code cleaner or to make a method look like a keyword, as is the case with puts.

For another example of flexible syntax, think of object attributes, which are actually methods in disguise:

common_idioms/mimic_methods.rb

class C

def my_attribute=(value)

@p = value

end

def my_attribute

@p

end

end

obj = C.new

obj.my_attribute = 'some value'

obj.my_attribute # => "some value"

Writing obj.my_attribute = ’some value’ is the same as writing obj.my_attribute=(’some value’), but it looks cleaner.

What should we call disguised methods such as my_attribute and my_attribute=? Let’s take a cue from zoology: an animal that disguises itself as another species is said to employ “mimicry.” Following that pattern, a method call that disguises itself as something else, such as puts orobj.my_attribute=, can be called a Spell: Mimic Method.

Mimic Methods are a very simple concept, but the more you look into Ruby, the more you find creative uses for them. For example, access modifiers such as private and protected are Mimic Methods, as are Class Macros (Class Macro) such as attr_reader. Popular libraries provide further examples. Here is one such example.

The Camping Example

The following snippet of code comes from an application written with the Camping web framework. It binds the /help URL to a specific controller action:

class Help < R '/help'

def get

# rendering for HTTP GET...

Class Help seems to inherit from a class named R. But what’s that quirky little string right after R? You might assume that Ruby would simply refuse this syntax, until you realize that R is actually a Mimic Method that takes a string and returns an instance of Class. That is the class that Helpactually inherits from. (If the notion of a method returning a class sounds strange to you, consider that Ruby classes are just objects, as you can read in Chapter 2, Monday: The Object Model.)

Thanks to creative tricks such as this one, Camping feels less like a Ruby web framework and more like a domain-specific language for web development. In general, this is a good thing, as I argue in Appendix 2, Domain-Specific Languages.

Attribute Trouble

Object attributes (which I describe in Mimic Methods) contain a hidden trap for the unsuspecting programmer:

common_idioms/attribute_trouble.rb

class MyClass

attr_accessor :my_attribute

def set_attribute(n)

my_attribute = n

end

end

obj = MyClass.new

obj.set_attribute 10

obj.my_attribute # => nil

This result is probably not what you expected. The problem is that the code in set_attribute is ambiguous. Ruby has no way of knowing whether this code is an assignment to a local variable called my_attribute or a call to a Mimic Method (Mimic Method) called my_attribute=. When in doubt, Ruby defaults to the first option. It defines a variable called my_attribute, which immediately falls out of scope.

To steer clear of this problem, use self explicitly when you assign to an attribute of the current object. Continuing from the previous example:

class MyClass

def set_attribute(n)

*

self.my_attribute = n

end

end

obj.set_attribute 10

obj.my_attribute # => 10

If you’re a jaded Ruby expert, you might ask yourself a subtle question that completely escaped me while writing the first edition of this book. What if MyClass#my_attribute= happens to be private? In What private Really Means, I said that you cannot call a private method with an explicit self receiver—so it seems that you’re out of luck in this (exceedingly rare) case. The answer to this conundrum is one of Ruby’s few ad-hoc exceptions. Attribute setters such as my_attribute= can be called with self even if they’re private:

class MyClass

private :my_attribute

end

obj.set_attribute 11 # No error!

obj.send :my_attribute # => 11

Nil Guards

Most Ruby beginners looking through someone else’s code are perplexed by this exotic idiom:

common_idioms/nil_guards.rb

a ||= []

In this example, the value to the right happens to be an empty array, but it could be any assignable value. The ||= is actually a syntax shortcut for the following:

a || (a = [])

To understand this code, you need to understand the details of the “or” operator (||). Superficially, the || operator simply returns true if either of the two operands is true—but there is some subtlety to this. Here’s the way that || actually works.

Remember that in a Boolean operation, any value is considered true with the exception of nil and false. If the first operand is true, then || simply returns the first operand, and the second operand is never evaluated. If the first operand is not true, then || evaluates and returns the second operand instead. This means the result will be true unless both operands are false, which is consistent with the intuitive notion of an or operator.

Now you can see that the previous code has the same effect as this:

ifdefined?(a) && a

a

else

a = []

end

You can translate this code as this: “If a is nil, or false, or hasn’t even been defined yet, then make it an empty array and give me its value; if it’s anything else, just give me its value.” In such cases, experienced Ruby coders generally consider the ||= operator more elegant and readable than anif. You’re not limited to arrays, so you can use the same idiom to initialize just about anything. This idiom is sometimes called a Spell: Nil Guard, because it’s used to make sure that a variable is not nil.

Nil Guards are also used quite often to initialize instance variables. Look at this class:

class C

def initialize

@a = []

end

def elements

@a

end

end

By using a Nil Guard, you can rewrite the same code more succinctly:

class C

def elements

@a ||= []

end

end

The previous code initializes the instance variable at the latest possible moment, when it’s actually accessed. This idiom is called a Spell: Lazy Instance Variable. Sometimes, as in the earlier example, you manage to replace the whole initialize method with one or more Lazy Instance Variables.

Nil Guards and Boolean Values

Nil Guards have one quirk that is worth mentioning: they don’t work well with Boolean values. Here is an example:

def calculate_initial_value

puts "called: calculate_initial_value"

false

end

b = nil

2.times do

b ||= calculate_initial_value

end

<=

called: calculate_initial_value

called: calculate_initial_value

The Nil Guard in the code above doesn’t seem to work—calculate_initial_value is called twice, instead of once as you might expect. To see where the problem is, let’s write the if equivalent of that Nil Guard.

ifdefined?(b) && b

# if b is already defined and neither nil nor false:

b

else

# if b is undefined, nil or false:

b = calculate_initial_value

end

If you look at this if-based translation of a Nil Guard, you will see that Nil Guards are unable to distinguish false from nil. In our previous example, b is false, so the Nil Guard reinitializes it every time.

This little wrinkle of Nil Guards usually goes unnoticed, but it can also cause the occasional hard-to-spot bug. For this reason, you shouldn’t use Nil Guards to initialize variables that can have false (or nil, for that matter) as a legitimate value.

Self Yield

When you pass a block to a method, you expect the method to call back to the block with yield. A twist on callbacks is that an object can also pass itself to the block. Let’s see how this can be useful.

The Faraday Example

In the Faraday HTTP library, you typically initialize an HTTP connection with a URL and a block:

common_idioms/faraday_example.rb

require 'faraday'

conn = Faraday.new("https://twitter.com/search") do |faraday|

faraday.response :logger

faraday.adapter Faraday.default_adapter

faraday.params["q"] = "ruby"

faraday.params["src"] = "typd"

end

response = conn.get

response.status # => 200

This code sets the parameters for the connection. If you wish, you can get the same results by passing a hash of parameters to Faraday.new—but the block-based style has the advantage of making it clear that all the statements in the block are focusing on the same object. If you like this style, you might want to peek inside Faraday’s source code and see how it is implemented. Faraday.new actually creates and returns a Faraday::Connection object:

gems/faraday-0.8.8/lib/faraday.rb

module Faraday

class << self

def new(url = nil, options = {})

# ...

Faraday::Connection.new(url, options, &block)

end

# ...

The interesting stuff happens in Faraday::Connection#initialize. This method accepts an optional block and yields the newly created Connection object to the block:

gems/faraday-0.8.8/lib/faraday/connection.rb

module Faraday

class Connection

def initialize(url = nil, options = {})

# ...

yield self if block_given?

# ...

end

# ...

This simple idiom is known as a Spell: Self Yield. Self Yields are pretty common in Ruby—even instance_eval and class_eval optionally yield self to the block, although this feature is rarely used in practice:

common_idioms/self_yield_in_eval.rb

String.class_eval do |klass|

klass # => String

end

For a more creative example of a Self Yield, you can check out the tap method.

The tap() Example

In Ruby, it’s common to find long chains of method calls such as this:

common_idioms/tap.rb

['a', 'b', 'c'].push('d').shift.upcase.next # => "B"

Chains of calls are frowned upon in most languages (and sometimes referred to as “train wrecks”). Ruby’s terse syntax makes call chains generally more readable, but they still present a problem: if you have an error somewhere along the chain, it can be difficult to track down the error.

For example, maybe you’re worried that the call to shift is not returning what you expect. To confirm your suspicions, you break the chain and print out the result of shift (or set a breakpoint in your debugger):

temp = ['a', 'b', 'c'].push('d').shift

puts temp

x = temp.upcase.next

<=

a

This is a clumsy way to debug your code. If you don’t want to split the call chain, you can use the tap method to slip intermediate operations into the middle of a call chain:

['a', 'b', 'c'].push('d').shift.tap {|x| puts x }.upcase.next

<=

a

The tap method already exists on Kernel. However, it’s a good exercise to imagine how you would write it yourself if it weren’t already provided by Ruby:

class Object

def tap

yield self

self

end

end

Symbol#to_proc()

This exotic spell is popular among black-belt Ruby programmers. When I stumbled upon this spell for the first time, I had trouble understanding the reasoning behind it. It’s easier to get there by taking one small step at a time.

Look at this code:

common_idioms/symbol_to_proc.rb

names = ['bob', 'bill', 'heather']

names.map {|name| name.capitalize } # => ["Bob", "Bill", "Heather"]

Focus on the block—a simple “one-call block” that takes a single argument and calls a single method on that argument. One-call blocks are very common in Ruby, especially (but not exclusively) when you’re dealing with arrays.

In a language such as Ruby, which prides itself on being succinct and to the point, even a one-call block looks verbose. Why do you have to go through the trouble of creating a block, with curly braces and all, just to ask Ruby to call a method? The idea of Symbol#to_proc is that you can replace a one-call block with a shorter construct. Let’s start with the smallest piece of information you need, which is the name of the method that you want to call, as a symbol:

:capitalize

You want to convert the symbol to a one-call block like this:

{|x| x.capitalize }

As a first step, you can add a method to the Symbol class, which converts the symbol to a Proc object:

class Symbol

*

def to_proc

*

Proc.new {|x| x.send(self) }

*

end

end

See how this method works? If you call it on, say, the :capitalize symbol, it returns a proc that takes an argument and calls capitalize on the argument. Now you can use to_proc and the & operator to convert a symbol to a Proc and then to a block:

names = ['bob', 'bill', 'heather']

*

names.map(&:capitalize.to_proc) # => ["Bob", "Bill", "Heather"]

You can make this code even shorter. As it turns out, you can apply the & operator to any object, and it will take care of converting that object to a Proc by calling to_proc. (You didn’t think we picked the name of the to_proc method randomly, did you?) So, you can simply write the following:

names = ['bob', 'bill', 'heather']

*

names.map(&:capitalize) # => ["Bob", "Bill", "Heather"]

That’s the trick known as Spell: Symbol To Proc. Neat, huh?

The good news is that you don’t have to write Symbol#to_proc, because it’s already provided by Ruby. In fact, Ruby’s implementation of Symbol#to_proc also supports blocks with more than one argument, which are required by methods such as inject:

# without Symbol#to_proc:

[1, 2, 5].inject(0) {|memo, obj| memo + obj } # => 8

# with Symbol#to_proc:

[1, 2, 5].inject(0, &:+) # => 8

# cool!