Writing Readable Ruby
-
The more Ruby I write, the more readable my Ruby becomes. Odd, but the secret seems to be to do nothing the way the Rubyists In Crowd does things. Here's a useful function:
def concat( *args ) ret = '' for a in args do ret += ( a.to_s() ) end return ret end
Four-space indentation is more readable. The
for ... in ...
loop is more readable than theeach
iterator. Putting parentheses after function and method calls improves readability. Always using areturn
statement to return values is another. Rejecting the whole Tim-Toady-loving basket of string notations in favor of just concatenating with the "+" operator is more readable.The Rubyists In Crowd will never think my code is cool. But Monty, my pet python who's looking over my shoulder as I write this, just said, "Martin, that's almost Pythonic."
"Monty, please turn away for a moment. You'll puke over all my papers if you see what I'm about to write."
Here's the official, Rubyists-approved-but-don't-show-Monty version of that function:
def concat(*args) ret = '' args.each {|a| ret += a.to_s} ret end
I'm a big believer in conventions, but I've never seen a language where the conventions always favor the less-readable form. Never.
Or maybe I'm unaware of the deeper secrets of Ruby. Certainly the Rubyists In Crowd knows a lot more about Ruby than I do.
-
@martinrinehart said:
The more Ruby I write, the more readable my Ruby becomes. Odd, but the secret seems to be to do nothing the way the Rubyists In Crowd does things. Here's a useful function:
> def concat( *args ) > ret = '' > for a in args do ret += ( a.to_s() ) end > return ret > end >
Here's the official, Rubyists-approved-but-don't-show-Monty version of that function:
> def concat(*args) > ret = '' > args.each {|a| ret += a.to_s} > ret > end >
personally, I find the second version much more readable, especially when just scanning the code. I takes me about 5 steps to glance at the second version, while it takes about 8-10 steps for the first.
listing the code in the order I see it:
version 1:
( a.to_s() ) end
(line 3)
concat( *args )
(line 1)
for a in args
(line 3)
ret = ''
(line 2)
return ret
(line 4)
do ret +=
(line 3)
(it usually takes 2 - 3 more steps to put everything together)version 2:
{|a| ret += a.to_s}
(line 3)
concat(*args)
(line 1) ( I can usually understand the code by this step)
ret = ''
(line 2)
args.each
(line 3)
ret end
(line 4-5)Everything I don't have listed, I skip.
BTW, my version would be:
def concat(*args) return args.join('') end
-
From a book I'm reading:
UI;;toolbar_names.each do |name| puts name if UI;;toolbar_visible? name end
De-Rubied:
for name in UI;;toolbar_names() puts name if UI;;toolbar_visible?( name ) end
-
It obviously depends on your background. I have no background in any other language, so to me the rubified versions are all more readable than your preferred versions, and that is just fine for both you and I.
Chris
-
I have no background in 'formal' coding so I write it [probably inefficiently] as I think and can understand it - I comment it heavily with ### so I can understand what I was doing months later !
To discuss the niceties of coding syntax is a bit like discussing how many angels can fit on the head of a pin... IF it works it works - sometimes a simple tweak will make it better... sometimes avoiding traps like too many simply named global variables are advisable, BUT if it works it works... -
@cjthompson said:
BTW, my version would be:
> def concat(*args) > return args.join('') > end >
Didn't know that would handle the
to_s()
issue. Thanks. -
I prefer the
each
overfor in
. But I've started usingfor in
for speed concerns some times.
Before I used 4space tab, not I use 2spaces instead, I saw the need to use spaces to maintain formatting but four space was just too much messing about with. And I find 2 spaces fine to read.Though I do like to use explicit
return
.
And I use parentheses for method arguments. -
I like the
for in loop
because it works in Ruby, Python and JavaScript, among many others. (Wikipedia lists 22 languages with this type of loop.)And it does just what it looks like it does.
Ruby:
for item in collection process item end
Python:
for item in collection process item
JavaScript:
for (index in collection) { process collection[index] }
-
@unknownuser said:
Putting parentheses after function and method calls improves readability.
@unknownuser said:
And I use parentheses for method arguments
As do I, whenever possible. I always hated the varience in the early BASIC dialects (my first language,) regarding parameters. There was no standard. Then I picked up an old copy of TurboPascal from the FIT bookstore and learned it. (This was back in the mostly textmode, pre-VGA days.) It was great to have standard parentheses delimited procedure arguments for all functions and procedures. (Never went back to BASIC after that, and have avioded VB whenever I could.)
Just a note, however. There is at least one very important exception to the rule of "always use parentheses" ... that is in the use of super.
If your statement is: super() you are telling Ruby to call the superclass method with an empty argument list, even though the child method may have been passed arguments.
If you want to pass the local arguments on up the inheritance chain (the default,) your statement needs to be: super
You also have a third option of passing a new set of arguments up to the superclass method, different from those the child method was passed. -
@dan rathbun said:
If your statement is: super() you are telling Ruby to call the superclass method with an empty argument list, even though the child method may have been passed arguments.
If you want to pass the local arguments on up the inheritance chain (the default,) your statement needs to be: superIt's
super
a keyword? Hence this exception? -
@unknownuser said:
[Is it because ] super [is ] a keyword? Hence this exception?
I believe so. If you look at the lex.c file in the Ruby source, you'll see there are only 3 keywords that use argument lists: defined?, super and yield.
In the eval.c file, you see these statements are converted into internal C function calls, (like everything else in Ruby.)
Advertisement