trying to find documentation on ruby's trailing if usage - ruby

I'm working in the RSpec book (page 121) and am being presented with a bit of code that is apparently self evident and clear. It's not self evident for me, and I'm hoping someone can help me understand.
I'm coming to ruby from c# so please use small words :)
Here's the original code
def total_match_count
count = 0
secret = #secret.split('')
#guess.split('').map do |n|
if secret.include?(n)
secret.delete_at(secret.index(n))
count += 1
end
end
count
end
here's the refactor
def total_match_count
secret = #secret.split('')
#guess.split('').inject(0) do |count, n|
count + (delete_first(secret, n) ? 1 : 0)
end
end
def delete_first(code, n)
code.delete_at(code.index(n)) if code.index(n)
end
Again, this is supposed to be so obvious as to need no comment.
I'm not understanding the trailing "if code.index(n)" bit and I can't find any documentation on using the keywords "ruby trailing if"
Obviously I'm missing something basic.

Ruby Post-Conditions as Syntactic Sugar
In Ruby, almost everything is an expression, and keywords like if and unless can be used as expression modifiers that follow an expression. Some languages refer to these as post-conditions, but the general idea is that:
if 1 == 1
puts true
end
is intended to be equivalent to:
puts true if 1 == 1
The post-condition can sometimes make the intent of the code clearer, or create a more natural flow. The parser differentiates between the :if and :if_mod tokens that internally represent the "normal" if-statement and its matching post-condition, but from a programmer's perspective the post-conditions are (or should be) largely syntactic sugar to make certain expressions easier or cleaner to read and write.
You don't ever need post-conditions in Ruby, but you will often find them in idiomatic Ruby code. If you don't grok them, or don't find that they improve the readability of your code, then feel free to ignore them until and unless they seem useful to you.

This:
code.delete_at(code.index(n)) if code.index(n)
is the same as this:
if code.index(n)
code.delete_at(code.index(n))
end
Some people think the one-liner is easier to read. It's a matter of style--when lines become long, the "trailing if" can be a gotcha, as you might not think to read to the end of the line to realize it has a condition attached. Use judiciously.
Ruby also has unless, which can be used in the "trailing" form too:
do_stuff unless no_on_second_thought

Related

Ruby's if / else in methods

EDIT: I've received answers about refactoring to a ternary operation. While I'm aware that that's possible with all the languages below, that wasn't necessarily my intent with the original question about style. I've edited the snippets to reflect this.
I am curious if it's idiomatic or preferred to always use an else when using if/else in a method.
For example, in JS, this is stylistically acceptable (and sometimes preferred)
function jsFunc(x) {
if (x == 0) {
// do a bunch of stuff here
return answer;
}
// do something else
return differentAnswer;
}
and I've also seen a similar style in Python:
def py_func(x):
if x == 0:
# do a bunch of stuff here
return answer
# do something here
return differentAnswer
but from the Ruby I've seen, it's always:
def ruby_method(x)
if x == 0
# do a bunch of stuff here
answer
else
# do something else
differentAnswer
end
end
I've also gotten a comment that not using an else in Ruby seems messier. Do Rubyists prefer the explicit else? (Also curious a lot of the language is implicit.)
It actually depends.
Guard clause returns are actually used in Ruby quite often. They are even encouraged by the widely accepted style guide.
However, guard clauses are used in corner cases. So you have to ask yourself what are the possible values of x and how often is it actually 0?
If it's rarely 0 and it's somewhat special, the return at the start is perfectly acceptable (and encouraged).
For example, this is a perfectly serviceable (even though not optimal) implementation of factorial:
def factorial(n)
return 1 if n.zero?
n * factorial(n.pred)
end
Reason being that 0 is definitely a corner case.
If, on the other hand, the 'Yes' and 'No' cases are both likely and normal, this symmetry should be visually represented in the code (if - else).
For example, consider a robot deciding what to do on a traffic light:
def take_action(light)
if light.green?
go
elsif light.yellow?
prepare_to_go
elsif light.red?
wait
end
end
You can write it with guard clauses, but it sounds weird. All of the possible colours are equally a "main" colour.
Either way, in this specific case there is a more concise alternative:
x.zero? ? 'Yes' : 'No'
I think this is due to the fact that in Ruby we have implicit return and Ruby developers tend to dislike the use of return. In fact, the alternative to your snippet would be
def ruby_method(x)
return "Yes" if x.zero?
"No"
end
Kinda strange I think

Handle ARGV in Ruby without if...else block

In a blog post about unconditional programming Michael Feathers shows how limiting if statements can be used as a tool for reducing code complexity.
He uses a specific example to illustrate his point. Now, I've been thinking about other specific examples that could help me learn more about unconditional/ifless/forless programming.
For example in this cat clone there is an if..else block:
#!/usr/bin/env ruby
if ARGV.length > 0
ARGV.each do |f|
puts File.read(f)
end
else
puts STDIN.read
end
It turns out ruby has ARGF which makes this program much simpler:
#!/usr/bin/env ruby
puts ARGF.read
I'm wondering if ARGF didn't exist how could the above example be refactored so there is no if..else block?
Also interested in links to other illustrative specific examples.
Technically you can,
inputs = { ARGV => ARGV.map { |f| File.open(f) }, [] => [STDIN] }[ARGV]
inputs.map(&:read).map(&method(:puts))
Though that's code golf and too clever for its own good.
Still, how does it work?
It uses a hash to store two alternatives.
Map ARGV to an array of open files
Map [] to an array with STDIN, effectively overwriting the ARGV entry if it is empty
Access ARGV in the hash, which returns [STDIN] if it is empty
Read all open inputs and print them
Don't write that code though.
As mentioned in my answer to your other question, unconditional programming is not about avoiding if expressions at all costs but about striving for readable and intention revealing code. And sometimes that just means using an if expression.
You can't always get rid of a conditional (maybe with an insane number of classes) and Michael Feathers isn't advocating that. Instead it's sort of a backlash against overuse of conditionals. We've all seen nightmare code that's endless chains of nested if/elsif/else and so has he.
Moreover, people do routinely nest conditionals inside of conditionals. Some of the worst code I've ever seen is a cavernous nightmare of nested conditions with odd bits of work interspersed within them. I suppose that the real problem with control structures is that they are often mixed with the work. I'm sure there's some way that we can see this as a form of single responsibility violation.
Rather than slavishly try to eliminate the condition, you could simplify your code by first creating an array of IO objects from ARGV, and use STDIN if that list is empty.
io = ARGV.map { |f| File.new(f) };
io = [STDIN] if !io.length;
Then your code can do what it likes with io.
While this has strictly the same number of conditionals, it eliminates the if/else block and thus a branch: the code is linear. More importantly, since it separates gathering data from using it, you can put it in a function and reuse it further reducing complexity. Once it's in a function, we can take advantage of early return.
# I don't have a really good name for this, but it's a
# common enough idiom. Perl provides the same feature as <>
def arg_files
return ARGV.map { |f| File.new(f) } if ARGV.length;
return [STDIN];
end
Now that it's in a function, your code to cat all the files or stdin becomes very simple.
arg_files.each { |f| puts f.read }
First, although the principle is good, you have to consider other things that are more importants such as readability and perhaps speed of execution.
That said, you could monkeypatch the String class to add a read method and put STDIN and the arguments in an array and start reading from the beginning until the end of the array minus 1, so stopping before STDIN if there are arguments and go on until -1 (the end) if there are no arguments.
class String
def read
File.read self if File.exist? self
end
end
puts [*ARGV, STDIN][0..ARGV.length-1].map{|a| a.read}
Before someone notices that I still use an if to check if a File exists, you should have used two if's in your example to check this also and if you don't, use a rescue to properly inform the user.
EDIT: if you would use the patch, read about the possible problems at these links
http://blog.jayfields.com/2008/04/alternatives-for-redefining-methods.html
http://www.justinweiss.com/articles/3-ways-to-monkey-patch-without-making-a-mess/
Since the read method isn't part of String the solutions using alias and super are not necessary, if you plan to use a Module, here is how to do that
module ReadString
def read
File.read self if File.exist? self
end
end
class String
include ReadString
end
EDIT: just read about a safe way to monkey patch, for your documentation see https://solidfoundationwebdev.com/blog/posts/writing-clean-monkey-patches-fixing-kaminari-1-0-0-argumenterror-comparison-of-fixnum-with-string-failed?utm_source=rubyweekly&utm_medium=email

Why are else statements discouraged in Ruby?

I was looking for a Ruby code quality tool the other day, and I came across the pelusa gem, which looks interesting. One of the things it checks for is the number of else statements used in a given Ruby file.
My question is, why are these bad? I understand that if/else statements often add a great deal of complexity (and I get that the goal is to reduce code complexity) but how can a method that checks two cases be written without an else?
To recap, I have two questions:
1) Is there a reason other than reducing code complexity that else statements could be avoided?
2) Here's a sample method from the app I'm working on that uses an else statement. How would you write this without one? The only option I could think of would be a ternary statement, but there's enough logic in here that I think a ternary statement would actually be more complex and harder to read.
def deliver_email_verification_instructions
if Rails.env.test? || Rails.env.development?
deliver_email_verification_instructions!
else
delay.deliver_email_verification_instructions!
end
end
If you wrote this with a ternary operator, it would be:
def deliver_email_verification_instructions
(Rails.env.test? || Rails.env.development?) ? deliver_email_verification_instructions! : delay.deliver_email_verification_instructions!
end
Is that right? If so, isn't that way harder to read? Doesn't an else statement help break this up? Is there another, better, else-less way to write this that I'm not thinking of?
I guess I'm looking for stylistic considerations here.
Let me begin by saying that there isn't really anything wrong with your code, and generally you should be aware that whatever a code quality tool tells you might be complete nonsense, because it lacks the context to evaluate what you are actually doing.
But back to the code. If there was a class that had exactly one method where the snippet
if Rails.env.test? || Rails.env.development?
# Do stuff
else
# Do other stuff
end
occurred, that would be completely fine (there are always different approaches to a given thing, but you need not worry about that, even if programmers will hate you for not arguing with them about it :D).
Now comes the tricky part. People are lazy as hell, and thusly code snippets like the one above are easy targets for copy/paste coding (this is why people will argue that one should avoid them in the first place, because if you expand a class later you are more likely to just copy and paste stuff than to actually refactor it).
Let's look at your code snippet as an example. I'm basically proposing the same thing as #Mik_Die, however his example is equally prone to be copy/pasted as yours. Therefore, would should be done (IMO) is this:
class Foo
def initialize
#target = (Rails.env.test? || Rails.env.development?) ? self : delay
end
def deliver_email_verification_instructions
#target.deliver_email_verification_instructions!
end
end
This might not be applicable to your app as is, but I hope you get the idea, which is: Don't repeat yourself. Ever. Every time you repeat yourself, not only are you making your code less maintainable, but as a result also more prone to errors in the future, because one or even 99/100 occurrences of whatever you've copied and pasted might be changed, but the one remaining occurrence is what causes the #disasterOfEpicProportions in the end :)
Another point that I've forgotten was brought up by #RayToal (thanks :), which is that if/else constructs are often used in combination with boolean input parameters, resulting in constructs such as this one (actual code from a project I have to maintain):
class String
def uc(only_first=false)
if only_first
capitalize
else
upcase
end
end
end
Let us ignore the obvious method naming and monkey patching issues here, and focus on the if/else construct, which is used to give the uc method two different behaviors depending on the parameter only_first. Such code is a violation of the Single Responsibility Principle, because your method is doing more than one thing, which is why you should've written two methods in the first place.
def deliver_email_verification_instructions
subj = (Rails.env.test? || Rails.env.development?) ? self : delay
subj.deliver_email_verification_instructions!
end

Does using curly braces go against the "Ruby way"?

I've been using Ruby for about two weeks, and I've not been programming for too terribly long, but I'm coming at the language from a C-style background (C++, C#, etc). Anyway - a good friend and mentor of mine was looking at some Ruby that I'd written the other day, and he told me that he'd smack me if he caught me using curly braces in Ruby again.
Well, I just found out about Builder yesterday, via this About.com article, and the example that they have posted uses curly braces. Is there a different way to do this, or do you have to use curly braces with Builder?
This may seem like a minor point, but I'm new to Ruby, and I don't want to let myself develop any bad habits. What do you guys think?
While some people go with "braces for one-liners, do-end for multi-liners", I personally find the following rule the most logical:
use do-end when your block has side-effects (typically, with each and related methods) and
use braces when your block is without side-effects (map, inject and alike)
This logic goes well with method chaining issue that Matt wrote about.
One benefit of this approach is that it is going to make you think about side-effects every time you write a block, and they are very important, although sometimes overlooked by coders with no functional programming background.
Another way to put it, without involving side-effects terminology would be:
use do-end for blocks that perform
use { and } for blocks that return
Here are couple of articles with more info:
http://onestepback.org/index.cgi/Tech/Ruby/BraceVsDoEnd.rdoc
http://talklikeaduck.denhaven2.com/2007/10/02/ruby-blocks-do-or-brace
Idiomatic ruby is
method_name {|param| param.do_something} # squigglies for one liners
# do/end for multi-line
method_name do |param|
param.do_something
end
One reason for this is for chaining, foo.map {|f| f.num}.reduce(0) {|memo, i| memo + i} looks nicer then hanging a method call off of an end like
foo.map do |f|
f.num
end.reduce(0) do |memo, i|
memo + i
end
There is just something strange about calling a method off of end, even though syntactically the two are equivalent.
The usual convention is { ... } blocks for one-liners and do ... end for multi-liners. I generally follow this convention but should I ever be king I think I would use do .. end more often.
An occasional issue with {} is that {} binds more tightly than do end so the only way to write a poetry-mode block for a method that also has parameters is to use do end, otherwise the block will be part of the parameter and will not be not passed directly to the method.
def f x
yield x
end
f 123 do |n| p n end # works
f 123 { |n| p n } # does not work
f(123) { |n| p n } # works, of course
Of course, if you wanted to attach a block to a parameter in poetry mode, then you win with {} followed by do end.
def g ; p ['g', yield] end
def f x; p ['f', yield] end
f g { 2 } do 3 end
["g", 2]
["f", 3]
Finally, and contrary to some of the advice you have received here, a ; is not needed before end.
"The Ruby way" doesn't advocate any specific style. If they didn't want you to have the option to use curly braces, it wouldn't be in the language. That said, conform to your team's coding style (if you're working with a team).
Most Ruby code I've seen uses end in place of curly braces, but I don't use Ruby so I can't say for sure that this is the preferred style. Ruby has more than one way of doing things -- you can use whichever way pleases you (within reason).

Building a "Semi-Natural Language" DSL in Ruby

I'm interested in building a DSL in Ruby for use in parsing microblog updates. Specifically, I thought that I could translate text into a Ruby string in the same way as the Rails gem allows "4.days.ago". I already have regex code that will translate the text
#USER_A: give X points to #USER_B for accomplishing some task
#USER_B: take Y points from #USER_A for not giving me enough points
into something like
Scorekeeper.new.give(x).to("USER_B").for("accomplishing some task").giver("USER_A")
Scorekeeper.new.take(x).from("USER_A").for("not giving me enough points").giver("USER_B")
It's acceptable to me to formalize the syntax of the updates so that only standardized text is provided and parsed, allowing me to smartly process updates. Thus, it seems it's more a question of how to implement the DSL class. I have the following stub class (removed all error checking and replaced some with comments to minimize paste):
class Scorekeeper
attr_accessor :score, :user, :reason, :sender
def give(num)
# Can 'give 4' or can 'give a -5'; ensure 'to' called
self.score = num
self
end
def take(num)
# ensure negative and 'from' called
self.score = num < 0 ? num : num * -1
self
end
def plus
self.score > 0
end
def to (str)
self.user = str
self
end
def from(str)
self.user = str
self
end
def for(str)
self.reason = str
self
end
def giver(str)
self.sender = str
self
end
def command
str = plus ? "giving ##{user} #{score} points" : "taking #{score * -1} points from ##{user}"
"##{sender} is #{str} for #{reason}"
end
end
Running the following commands:
t = eval('Scorekeeper.new.take(4).from("USER_A").for("not giving me enough points").giver("USER_B")')
p t.command
p t.inspect
Yields the expected results:
"#USER_B is taking 4 points from #USER_A for not giving me enough points"
"#<Scorekeeper:0x100152010 #reason=\"not giving me enough points\", #user=\"USER_A\", #score=4, #sender=\"USER_B\">"
So my question is mainly, am I doing anything to shoot myself in the foot by building upon this implementation? Does anyone have any examples for improvement in the DSL class itself or any warnings for me?
BTW, to get the eval string, I'm mostly using sub/gsub and regex, I figured that's the easiest way, but I could be wrong.
Am I understanding you correctly: you want to take a string from a user and cause it to trigger some behavior?
Based on the two examples you listed, you probably can get by with using regular expressions.
For example, to parse this example:
#USER_A: give X points to #USER_B for accomplishing some task
With Ruby:
input = "#abe: give 2 points to #bob for writing clean code"
PATTERN = /^#(.+?): give ([0-9]+) points to #(.+?) for (.+?)$/
input =~ PATTERN
user_a = $~[1] # => "abe"
x = $~[2] # => "2"
user_b = $~[3] # => "bob"
why = $~[4] # => "writing clean code"
But if there is more complexity, at some point you might find it easier and more maintainable to use a real parser. If you want a parser that works well with Ruby, I recommend Treetop: http://treetop.rubyforge.org/
The idea of taking a string and converting it to code to be evaled makes me nervous. Using eval is a big risk and should be avoided if possible. There are other ways to accomplish your goal. I'll be happy to give some ideas if you want.
A question about the DSL you suggest: are you going to use it natively in another part of your application? Or do just plan on using it as part of the process to convert the string into the behavior you want? I'm not sure what is best without knowing more, but you may not need the DSL if you are just parsing the strings.
This echoes some of my thoughts on a tangental project (an old-style text MOO).
I'm not convinced that a compiler-style parser is going to be the best way for the program to deal with the vaguaries of english text. My current thoughts have me splitting up the understanding of english into seperate objects -- so a box understands "open box" but not "press button", etc. -- and then having the objects use some sort of DSL to call centralised code that actually makes things happen.
I'm not sure that you've got to the point where you understand how the DSL is actually going to help you. Maybe you need to look at how the english text gets turned into DSL, first. I'm not saying that you don't need a DSL; you might very well be right.
As for hints as to how to do that? Well, I think if I were you I would be looking for specific verbs. Each verb would "know" what sort of thing it should expect from the text around it. So in your example "to" and "from" would expect a user immediately following.
This isn't especially divergent from the code you've posted here, IMO.
You might get some milage out of looking at the answers to my question. One commenter pointed me to the Interpreter Pattern, which I found especially enlightening: there's a nice Ruby example here.
Building on #David_James' answer, I've come up with a regex-only solution to this since I'm not actually using the DSL anywhere else to build scores and am merely parsing out points to users. I've got two patterns that I'll use to search:
SEARCH_STRING = "#Scorekeeper give a healthy 4 to the great #USER_A for doing something
really cool.Then give the friendly #USER_B a healthy five points for working on this.
Then take seven points from the jerk #USER_C."
PATTERN_A = /\b(give|take)[\s\w]*([+-]?[0-9]|one|two|three|four|five|six|seven|eight|nine|ten)[\s\w]*\b(to|from)[\s\w]*#([a-zA-Z0-9_]*)\b/i
PATTERN_B = /\bgive[\s\w]*#([a-zA-Z0-9_]*)\b[\s\w]*([+-]?[0-9]|one|two|three|four|five|six|seven|eight|nine|ten)/i
SEARCH_STRING.scan(PATTERN_A) # => [["give", "4", "to", "USER_A"],
# ["take", "seven", "from", "USER_C"]]
SEARCH_STRING.scan(PATTERN_B) # => [["USER_B", "five"]]
The regex might be cleaned up a bit, but this allows me to have syntax that allows a few fun adjectives while still pulling the core information using both "name->points" and "points->name" syntaxes. It does not allow me to grab the reason, but that's so complex that for now I'm going to just store the entire update, since the whole update will be related to the context of each score anyway in all but outlier cases. Getting the "giver" username can be done elsewhere as well.
I've written up a description of these expressions as well, in hopes that other people might find that useful (and so that I can go back to it and remember what that long string of gobbledygook means :)

Resources