&&=

||=



@first_name &&= @first_name.trim

@phone ||= '612-777-9311'



@phone = Location.find(:first, ...elided... )&&.phone

?.

&&.

&&.

&&.

A feature is “powerful” when at least one of the following holds:

It can be used to implement something trivial in an pointlessly complicated way. It can cause a lot of damage. Seriously, it seems like 85% percents of the contexts where something is called “powerful,” it really means “useless and dangerous.”



@phone = (loc = Location.find(:first, ...elided... )) && loc.phone

loc

loc

let



@phone = lambda { |loc| loc && loc.phone }.call(Location.find(:first, ...elided... ))

&&.



@phone = Location.find(:first, ...elided... ).andand.phone

@phone = ->(loc){ loc && loc.phone }.call(Location.find(:first, ...elided... ))

Location.find(:first, ...elided... )

andand

andand



class Object

def andand (p = nil)

self or MockReturningMe.new(self)

end

end



class MockReturningMe

instance_methods.reject { |m| m =~ /^__/ }.each { |m| undef_method m }

def initialize(me)

@me = me

end

def method_missing(*args)

@me

end

end

Actually, there is more to it than this, for example the MockReturningMe class is enclosed in a module to minimize namespace pollution. Consult the source and RSpec (links below) for the latest particulars



list_of_lists.detect { ...elided... }.andand.inject(42) { ...elided ... }

send



Location.find(:first, ...elided... ) do |location|

puts location.inspect

end

=> location



returning(Location.find(:first, ...elided... )) do |location|

...elided...

end

=> location



returning([1, 2, 3, 4, 5]) do |arr|

arr.pop

end.map { |n| n * 2 }

=> [2, 4, 6, 8]



Location.find(:first, ...elided... ).tap do |location|

...elided...

end…

Location.find(:first, ...elided... ).tap.some_method

Location.find(:first, ...elided... ).tap do ...elided... end



[1, 2, 3] << 4 << 5

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



[1, 2, 3, 4, 5].pop.map { |n| n * 2 }

=> NoMethodError: undefined method `map' for 5:Fixnum

[1, 2, 3, 4, 5].pop => 5

[1, 2, 3, 4]



[1, 2, 3, 4, 5].tap.pop.map { |n| n * 2 }

=> [2, 4, 6, 8] # or we write...

[1, 2, 3, 4, 5].tap { |arr| arr.pop }.map { |n| n * 2 }

=> [2, 4, 6, 8] # both work

pop

sudo gem install andand



Location.find( …elided… ).phone rescue nil

NoMethodError

nil

NoMethodError

.phone

.phone

NoMethodError

At Mobile Commons , we have to write a lot of code under time constraints. We also work on a fairly distributed basis, which means that writing readable code is not a luxury, it’s a necessity. We can’t afford to be clever for clever’s sake, but if a new idiom helps make our code easier for our colleagues to grasp in a hurry, we embrace it. Here’re some idioms we’ve recently created:Ruby programmers are familiar with the two guarded assignment operatorsand. The typical use for them is when you have a variable that might be nil. For example:You are trimming the first name provided it isn’t nil, and you are assigning ‘612-777-9311’ to the phone if it is nil (or false, but that isn’t important right now). The other day we were discussing the guards and we agreed that we wished there was a guarded method invocation operator. Here’s an example of when you would use it:Meaning, search the location table for the first record matching some criteria, and if you find a location, get its phone. If you don’t, get nil. (Groovy provides this exact functionality, although Groovy usesinstead of) However,won’t work becauseis not a real Ruby operator. So what do we write instead?How about:Note that we need a local variable to make it work without extending the Object class. Note further that although we only need the local variable for one line of code, it is in method scope and we must be careful that we don’t clobber an existingvariable. And when reading this code, we now have to look and see whetheris used again to understand what this line does.This is a scoping problem. if you are going to use variables, you want to restrict their scope as much as possible. It feels like half of what we do when programming is manage side effects like overwriting a variable you are using elsewhere, and the more you can restrict those side effects, the easier programming becomes. Java supports block scoping natively, and languages like Scheme solve this by providing a block scope macro,. And you can roll your own in languages like Javascript that provide anonymous functions. But this seems to get the natural left-to-right order wrong:Well, we are tinkerers and toolsmiths. So let’s roll our own. We can’t usewithout rewriting the Ruby parser, and that seems drastic. So let’s use “andand” in the hope that our non-English-speaking colleagues will forgive us. We want to write:And get the same effect as. This would be bloody trivial if we have a macro facility, but “If wishes were horses then beggars would ride.” Instead, we need to write a method that does some conditional evaluation for us. If the receiver (in this case the result of) is truthy, like an ActiveRecord model, we wantto return it so we can use it. But if it is falsy, we wantto somehow return something that takes any message you send it and returns itself without doing anything. In other words, we want a mock object of sorts. So that’s what we’ll do:Note that because you accept any method using Ruby’s method invocation syntax, you can accept methods with parameters and/or blocks:Some of the other solutions to this problem that usechange Ruby’s syntax. This solution emphasizes syntactic regularity: the goal was to make an “&&.” operation that worked like &&=. &&= looks just like normal assignment, you can use any expression on the RHS, only the semantics are different. The andand method also works just like a normal method invocation, only the semantics are modified.(Formerly called Object#me)Ruby 1.9 includes Object#tap Ruby On Rails includes a similar feature, the returning idiom:Both return the location, not whatever happens inside the block. This is very useful, especially when chaining methods in a pipeline. Sometimes you want to do something for side effects, but continue on with the chain. For example:There are going to be times that using a method instead of a function makes the code more consistent. So let’s imagine what that would look like:This is much nicer when you are “injecting” some extra code into the middle of an expression, such as when adding some poor-man’s-debugging puts statements.Would we ever want to go beyond a block and writeinstead of? Of course we would! Quite often, we want to send several methods to the same receiver. In Smalltalk, the semicolon does this explicitly. In Ruby, we have to be very careful to make sure our methods return self to enable chaining. For example:But if a method doesn’t return the receiver, chaining doesn’t work. That’s why we had to use “returning” in the array example above:That’s because, not. So instead, we write:When you examine the source, you’ll see that tap looks a lot like andand. No surprise, we are doing similar things with slightly different semantics.This implementation of Object#tap has two advantages over the implementation in Ruby 1.9: first, it works in Ruby 1.8. Second, it adds the ability to call another method (like) and not have to include a block.andand and tap both provide the same two benefits: First, they either eliminate (in the case of a method call) or limit in scope (in the case of a block) a local variable. Second, they let you maintain a natural left-to-right order when writing pipelined expressions. They are simple and obvious enough that I feel any unfamiliarity for the reader will be more than outweighed by the cleaner, easier-to-digest code that results from their liberal use.My suggestion is that these two benefits make it worth your while to add these methods to the Object class and use them regularly in your code.. For the source and more information, http://andand.rubyforge.org postscript: Inline RescuesI have now seen two people asking about using an inline rescue instead of andand:Also, one of the alternate solutions seems to use this technique. Obviously, it works for many of the cases you want to try, and you don’t need to add a new method to Object. However, it is—to paraphrase Chalain —“Sneaking up on the Interpreter.”It achieves what we want almost by accident, namely that it rescues, which by coïncidence gives us the result we want. However, it does not communicate our intent. It says that we want to transmute all exceptions into a value of. When someone glances at the code, will they think of? Or will they assume that we are trying to handle exceptions that themethod might throw?And what ifactually throws something serious? In Rails, what happens if a migration is screwed up and there is no phone column? I think we actually want ain that case. The rescue clause will accidentally swallow the exceptions we are trying to catch.I think if you are absolutely certain that you do not care about other exceptions and also if your team uses this idiom extensively so that it does not miscommunicate its intent, you can live a long and happy life using it. However, I would be hesitant to recommend it as a general-purpose solution. andand and some of the other solutions obviously require the code reader to learn a new method name, but after that they offer the exact functionality we need and clearly communicate their intent.

Labels: ruby