[ANN] Elements of Ruby Style

  • Thread starter Jeremy McAnally
  • Start date
J

Jeremy McAnally

Hello all,
I'm happy announce a project that I've been working on for a little while.

I've noticed that a lot of posts on the mailing are "what's the most
rubyish way to do (x)?" where x could be transversing a file and
matching regexes to looping through records in a database to switching
between two logic branches. So, seeing this, I thought, why not give
these people a refernece? Instead of having to type out a long answer
every time, why not give them a Fine Manual to read?

So I began work on Elements of Ruby: a descriptive style manual, that
is, that this manual will only describe the typical style used in the
language, and should not be used as a way to prescribe style. I want
it to be used as a learning tool and to answer questions about the
best style in a given situation rather than to spawn religious
arguments about style.

The problem is that I havent gotten very far yet (darn you holidays
and book deadlines! ;)). Actually, that's why I'm posting here: I
need your help. I've managed to build a small list of items so far
(viewable at http://www.elementsofrubystyle.com/ ), but I want to add
more. So I thought I would open discussion here for input. I want it
to be useful to everyone, so everyone should have some input, yes?

I have a Rails applicatio built to power it, but I want to nail down a
fairly final list of things before I populate its database and deploy
it. After it's deployed, then you will be able to submit comments on
each element (e.g., to voice an exception or add to it) and submit
examples for each one (that will be integrated and properly
attributed) or suggest new things to be added/changed.

Anyhow, look at the list, and let's talk about what should be on there.

Visit http://www.elementsofrubystyle.com/ .

--Jeremy

--
My free Ruby e-book:
http://www.humblelittlerubybook.com/book/

My blogs:
http://www.mrneighborly.com/
http://www.rubyinpractice.com/
 
J

Justin Bailey

Anyhow, look at the list, and let's talk about what should be on there.

Visit http://www.elementsofrubystyle.com/ .

I like what you've got and for most cases I agree with your style
guidelines. I've been programming Ruby for about 1.5 years and have
created several gems for distribution, so I've seen many of the issues
you cover.

My comments:

* A section on commenting code, especially so it is RDoc compatible
(i.e. place all text in contiguous lines starting with #, or use
=begin, =end for particularly long comments).

* When commenting, indicate the type of object returned and the type
of those accepted. Not in the strong-typing sense, but for
documentation purposes. Trying to figure out what methods are
available on objects returned can be a real trial-and-error process if
it's not well documented.

* (Personal style) - Place all "assertion" handling code at the
beginning of each method. For example:

def some_method(arg1, arg)
raise "Arg1 cannot be nil" if arg1.nil?
raise "Arg1 must be a number" unless arg1.is_a?(Numeric)
...

I've found its a nice way to document what a method considers legal.

* (Personal Style) - Don't use a string to define a new method unless
you need interpolation. You usually only need it when code within the
method must be different based on some conditional.

* Finally, I think you should make explicit mention of the DRY principle.

A few specific points I don't agree with or have questions about:

* 2.h.i - " There is no advantage ... " - Single quoted strings do
not interpolate, while double-quoted do. You seem to be stating there
is no difference between them.

* 2.h.iii - "Multi-line strings should be expressed ..." - You mention
that here-docs should not be used if interpolation is needed. I'm not
sure why, because interpolation works fine in here docs.

* 2.c.ii - "Curly braces should be used if the return value is
desired" - Why? This isn't a style I've seen much in the wild. Is it
used throughout the Rails source?

* 2.c.iii - "Use parametrized variables rather than accessing scope
variables" - This seems to say you shouldn't take advantage of the
closure property of blocks (i.e. that in-scope references are carried
around and can be used). If that's true, why? If not, a clarification
should be made.

Hope this helps. Looks like you are off to a great start. Is an RSS
feed going to be available soon?

Justin
 
J

James Britt

Jeremy said:
Hello all,
I'm happy announce a project that I've been working on for a little while.

I've noticed that a lot of posts on the mailing are "what's the most
rubyish way to do (x)?" where x could be transversing a file and
matching regexes to looping through records in a database to switching
between two logic branches. So, seeing this, I thought, why not give
these people a refernece? Instead of having to type out a long answer
every time, why not give them a Fine Manual to read?

See also

http://wiki.rubygarden.org/Ruby/page/show/RubyStyleGuide
http://wiki.rubygarden.org/Ruby/page/show/RubyIdioms
 
D

Daniel Finnie

I think that's a good idea, but I have some questions about some items:

2.b.vi. If a your method has a block parameter, try to use yield rather
than accepting it as a variable and calling call on it.
--> What is the reasoning behind this? I'm not trying to criticize (yet
;-), but it seems like The Ruby Way is not doing this. For example, $_
= "hollywood"; scan(/o/); isn't preferred over "hollywood".scan(/o/).

2.b.viii and 2.b.x seem to be very similar, perhaps merge them?

2.c.ii says "curly braces" while 2.c.i just says "braces." Also, what
if you want something's return value but you do it on multiple lines?
Either that never happens, so the rule isn't necessary, or it happens
and then you have a conflict in the rules.

2.e.i Use try catch to control flow rather than rescue blocks
--> Do you mean catch/throw? I don't recall a try/catch in Ruby and a
quick Googling finds nothing.

2.f I think a lot of these need some example code (before and after).
What is a statement modifier? &&, !, etc?

2.h.i There is no advantage to using single quotes or double quotes
other than safety
--> Double quotes allow interpolation and have more escape sequences.
What is "safety" in this context?

2.h.ii Don’t combine string literals and variables using +; rather,
use interpolation
--> What if I want to append something to an existing string? Should I
use existingString = "#{existingString}#{newString}" or existingString
<< newString? (Or +=?)

2.h.iii I think a previous email went over this.

3.b.i Should have an example.

3.b.v Is a repeat of 2.g.i, although maybe it is important enough to be
repeated!
 
R

Rimantas Liubertas

* 2.h.iii - "Multi-line strings should be expressed ..." - You mention
that here-docs should not be used if interpolation is needed. I'm not
sure why, because interpolation works fine in here docs.
<...>

It depends.

puts <<MARKER
... double quoted string rules apply here
MARKER

puts <<"MARKER"
... double quoted string rules apply here
MARKER

puts <<'MARKER'
... single quoted string rules apply here - no interpolation
MARKER


Regards,
Rimantas
 
J

Jeremy McAnally

2.b.vi. If a your method has a block parameter, try to use yield rather
than accepting it as a variable and calling call on it.
--> What is the reasoning behind this? I'm not trying to criticize (yet
;-), but it seems like The Ruby Way is not doing this. For example, $_
=3D "hollywood"; scan(/o/); isn't preferred over "hollywood".scan(/o/).

My personal reasoning is that you end up with less confusion as to
what's going on when simply looking at the code. You know that yield
yeilds, but an object may have a call method. Secondly, when calling
the method, it's cleaner when calling. You get:

mymethod { puts "Go go gadget method!" }

as opposed to...

mymethod(lambda { puts "Go go gadget lambda!" })

Just personal preference I suppose.
2.c.ii says "curly braces" while 2.c.i just says "braces." Also, what
if you want something's return value but you do it on multiple lines?
Either that never happens, so the rule isn't necessary, or it happens
and then you have a conflict in the rules.

True, I'll fix that.
2.e.i Use try catch to control flow rather than rescue blocks
--> Do you mean catch/throw? I don't recall a try/catch in Ruby and a
quick Googling finds nothing.

You're right; that's C# on the brain (and shows how often I use catch/throw=
;)).
2.f I think a lot of these need some example code (before and after).
What is a statement modifier? &&, !, etc?

No, a statement modifier is like this:

puts "Do only if I'm true!" if me =3D=3D true

Examples will be provided to clear up any confusion.
2.h.i There is no advantage to using single quotes or double quotes
other than safety
--> Double quotes allow interpolation and have more escape sequences.
What is "safety" in this context?

"Advantage" should say "speed advantage"; in other languages (i.e.,
PHP) there is a different in how these things are handled, thus
affecting speed during certain operations.

I'm not sure why I put safety there; probably something to do with
escape sequences. Ill have to look back at my more annotated version
and clear that up.
2.h.ii Don=82=C4=F4t combine string literals and variables using +; rathe= r,
use interpolation
--> What if I want to append something to an existing string? Should I
use existingString =3D "#{existingString}#{newString}" or existingString
<< newString? (Or +=3D?)

Probably, yes, any of those. I'm mostly referring to not doing
something like this:

mystring =3D "This is what " + your_name + " is looking for in " + that_pla=
ce

That's how I did strings when I first came to Ruby, but it's not very
pretty; it's just my PHP roots showing. Plus, using interpolation
gives you an automatic to_s.

Thanks for the feedback all! I'm working on some revisions and such
right now, but keep it coming. :)

--Jeremy

--=20
My free Ruby e-book:
http://www.humblelittlerubybook.com/book/

My blogs:
http://www.mrneighborly.com/
http://www.rubyinpractice.com/
 
D

dblack

Hi --

My personal reasoning is that you end up with less confusion as to
what's going on when simply looking at the code. You know that yield
yeilds, but an object may have a call method. Secondly, when calling
the method, it's cleaner when calling. You get:

mymethod { puts "Go go gadget method!" }

as opposed to...

mymethod(lambda { puts "Go go gadget lambda!" })

It sounds like you guys are talking about two different things. (I'm
not sure how Daniel's example relates to the yield/call matter.)
Also, Jeremy, I thought what you were talking about was this:

def meth
yield
end

vs.

def meth(&block)
block.call
end

In neither case do you need to create a lambda explicitly; the method
calling syntax would be exactly the same:

meth { puts "whatever" }


David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)
 
D

Daniel Finnie

I'm not sure how Daniel's example relates to the yield/call matter.

It's kind of a null issue now, IMO, now that the method of passing
blocks is cleared up, but this is what I meant:

$_ = "hello"
scan(/l/)
This example has a receiver that is not explicit (not in the sense that
the receiver is self but that it is not on that line). This method is
falling out of favor for the above reason.

def meth
yield
end
This example also has a yield with no explicit receiver as defined
above. If the above example is going out of favor, why is this one the
preferred method?
Also, Jeremy, I thought what you were talking about was this:

def meth
yield
end

vs.

def meth(&block)
block.call
end

This is what I was referring to as well, if it isn't obvious from my
other replies I'm sorry.
 
D

dblack

Hi --

It's kind of a null issue now, IMO, now that the method of passing blocks is
cleared up, but this is what I meant:

$_ = "hello"
scan(/l/)
This example has a receiver that is not explicit (not in the sense that the
receiver is self but that it is not on that line). This method is falling
out of favor for the above reason.

def meth
yield
end
This example also has a yield with no explicit receiver as defined above. If
the above example is going out of favor, why is this one the preferred
method?

yield is a keyword, though, not a method, so they're not exactly
commensurate. But in any case, it's not that receiverless method
calls are out of favor, but more the implicit use of $_ as a receiver.
It's actually something I've seen so little of, and so little
discussion of, that I'm not sure what people's current thinking is on
it. But it's not connected to yield, which doesn't have a receiver at
all, nor to the general practice of leaving off receivers where
possible.


David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)
 
K

khaines

My personal reasoning is that you end up with less confusion as to
what's going on when simply looking at the code. You know that yield
yeilds, but an object may have a call method. Secondly, when calling
the method, it's cleaner when calling. You get:

mymethod { puts "Go go gadget method!" }

as opposed to...

mymethod(lambda { puts "Go go gadget lambda!" })

Just personal preference I suppose.

This isn't making sense to me. "hollywood".scan(/o/) doesn't have
anything to do with using yield rather than explicitly call()ing a block
via a variable.

And what you say, to yield rather than accepting a block param explicitly
and then using call() on it, it true, but that really doesn't affect the
semantics of the calling API, as you show in your example.


class Foo
def a
yield
end

def b(&blk)
blk.call
end
end

z = Foo.new
z.a {7}
z.b {7}


It's the same calling semantics. The advantage when writing code is
really just that code which uses yield is faster and looks better than
code that explicitly calls the block.

Probably, yes, any of those. I'm mostly referring to not doing
something like this:

mystring = "This is what " + your_name + " is looking for in " + that_place

That's how I did strings when I first came to Ruby, but it's not very
pretty; it's just my PHP roots showing. Plus, using interpolation
gives you an automatic to_s.

I think it's a good idea to discuss the reasons, here.

Sometimes, + is what you want. When dealing with strings, + will give you
a new String. If you just want to combine two things, though, << is often
your best bet because it simply modifies the string it is called on
instead of creating a new String, and

a << b

looks a lot better than

"#{a}#{b}"


Kirk Haines
 
J

Jeremy McAnally

It's the same calling semantics. The advantage when writing code is
really just that code which uses yield is faster and looks better than
code that explicitly calls the block.

Ack! You guys are right. Senior moment (actually, it was a I stayed
up til 3:30am writing and then worked all day moment...but same effect
;)). That was one that I had picked up from another page or ML post;
I'm sure I had reasons but now that I look at it it doesn't make
sense. My mistake!
I think it's a good idea to discuss the reasons, here.

Sometimes, + is what you want. When dealing with strings, + will give you
a new String. If you just want to combine two things, though, << is often
your best bet because it simply modifies the string it is called on
instead of creating a new String, and

a << b

looks a lot better than

"#{a}#{b}"

Right, that's why I said literals. When I combine two string objects,
I usually use + just because semantically it makes more sense, but
when there's a string literal involved, I usually use interpolation.
I think this is a preference thing, but I always thought that was
general practice. Please do correct me if I'm wrong.

--Jeremy

--
My free Ruby e-book:
http://www.humblelittlerubybook.com/book/

My blogs:
http://www.mrneighborly.com/
http://www.rubyinpractice.com/
 
F

Felipe Navas

Maybe some example... would be nice ;)

Ack! You guys are right. Senior moment (actually, it was a I stayed
up til 3:30am writing and then worked all day moment...but same effect
;)). That was one that I had picked up from another page or ML post;
I'm sure I had reasons but now that I look at it it doesn't make
sense. My mistake!


Right, that's why I said literals. When I combine two string objects,
I usually use + just because semantically it makes more sense, but
when there's a string literal involved, I usually use interpolation.
I think this is a preference thing, but I always thought that was
general practice. Please do correct me if I'm wrong.

--Jeremy

--
My free Ruby e-book:
http://www.humblelittlerubybook.com/book/

My blogs:
http://www.mrneighborly.com/
http://www.rubyinpractice.com/
 
D

dblack

Hi --

This seems to be a style thing I only see in my own code, but which I
consider very helpful when reading code: put two spaces before
statement modifiers.

I'd have written:

def some_method(arg1, arg)
raise "Arg1 cannot be nil" if arg1.nil?
raise "Arg1 must be a number" unless arg1.is_a?(Numeric)
...

(In this case, I'd probably line them up, too...)

Since this is the only place I use two spaces in source code, it
slightly stands out and visually seperates the statement from the
modifier, which is especially important if you don't use syntax
highlighting.

Any comments?

I have a bit of a preference for not doing that. It detaches the
modifier from the modifiee (?), with a slight tendency to make it look
like a new statement is starting.

But lining up might counteract that effect.


David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,144
Latest member
KetoBaseReviews
Top