Basic Ruby/Rails question about understanding blocks & block variables - ruby-on-rails

I'm starting to get comfortable with Ruby/Rails but must admit I still look askance when I see an unfamiliar block. take the following code:
(5..10).reduce(0) do |sum, value|
sum + value
end
I know what it does...but, how does one know the order of the parameters passed into a block in Ruby? Are they taken in order? How do you quickly know what they represent?
I'm assuming one must look at the source (or documentation) to uncover what's being yielded...but is there a shortcut? I guess I'm wondering how the old vets quickly discern what a block is doing?!? How should one approach looking at/interpreting blocks?

You just have to look it up in the documentation until you have it memorized. I still have trouble with reduce and a couple others. It's just like trying to remember the argument order for ordinary methods. Programmers have to deal with this problem in pretty much every language.

When you write code, there's no other way than checking the documentation - even if Ruby is quite consistent and coherent in this kind of things, so often you just expect things to work on a particular way.
On the other hand, when you read code, you can just hope that the coder has been smart and kind enough to use consistent variable names. In your example
(5..10).reduce(0) do |sum, value|
sum + value
end
There is a reason if the variables are called sum and value! :-) Something like
(5..10).reduce(0) {|i,j|i+j}
is of course the same, but much less readable. So the lesson here is: write good code and you'll convey some piece of information more than just instructions to a computer!

Related

Ruby on Rails - what is the best practice for accessing Active record Columns

I am really new at rails but i was wondering.
What is the best practice for accessing model column names in rails when doing queries?
like i want to do a order by column called "title" in DESCENDING order. how would i do it (best practice)?
MyModel.order(:title.to_s.concat " DESC").all
MyModel.order("title DESC").all
or something else?
From my experience using hardcoded strings always proves the wrong approach in matters such as this mainly because the code becomes impossible to refactor.
in My IDE (i am using RubyMine) it is showing a nice code completition for the colum symbols so i am guessing will be easier to track the use this way?
Thanks.
In my opinion MyModel.order("title DESC").all is the better choice here. Readability and complexity of the other choice are bad. Although performance might not be a consideration the other choice also scores bad in this section.
Apart from that, you should never write code by your IDE intellisense ability - your code should be navigable and readable in all IDEs. I use Vim and it completes strings as good as it completes symbols so no difference here.
EDIT:
If your order was ASC then you could use MyModel.order(:title).all which is definitely better than MyModel.order("title").all

do record_info and tuple_to_list return the same key order in Erlang?

I.e, if I have a record
-record(one, {frag, left}).
Is record_info(fields, one) going to always return [frag,
left]?
Is tl(tuple_to_list(#one{frag = "Frag", left = "Left"}))
always gonna be ["Frag", "Left"]?
Is this an implementation detail?
Thanks a lot!
The short answer is: yes, as of this writing it will work. The better answer is: it may not work that way in the future, and the nature of the question concerns me.
It's safe to use record_info/2, although relying on the order may be risky and frankly I can't think of a situation where doing so makes sense which implies that you are solving a problem the wrong way. Can you share more details about what exactly you are trying to accomplish so we can help you choose a better method? It could be that simple pattern matching is all you need.
As for the example with tuple_to_list/1, I'll quote from "Erlang Programming" by Cesarini and Thompson:
"... whatever you do, never, ever use the tuple representations of records in your programs. If you do, the authors of this book will disown you and deny any involvement in helping you learn Erlang."
There are several good reasons why, including:
Your code will become brittle - if you later change the number of fields or their order, your code will break.
There is no guarantee that the internal representation of records will continue to work this way in future versions of erlang.
Yes, order is always the same because records represented by tuples for which order is an essential property. Look also on my other answer about records with examples: Syntax Error while accessing a field in a record
Yes, in both cases Erlang will retain the 'original' order. And yes it's implementation as it's not specifically addressed in the function spec or documentation, though it's a pretty safe bet it will stay like that.

Are there any downsides to passing in an Erlang record as a function argument?

Are there any downsides to passing in an Erlang record as a function argument?
There is no downside, unless the caller function and the called function were compiled with different 'versions' of the record.
Some functions from erlangs standard library do indeed use records in their interfaces (I can't recall which ones, right now--but there are a few), but in my humble opinion, the major turnoff is, that the user will have to include your header file, just to use your function.
That seems un-erlangy to me (you don't ever do that normally, unless you're using said functions from the stdlib), creates weird inter-dependencies, and is harder to use from the shell (I wouldn't know from the top of my head how to load & use records from the shell -- I usually just "cheat" by constructing the tuple manually...)
Also, handling records is a bit different from the stuff you usually do, since their keys per default take the atom 'undefined' as value, au contraire to how you usually do it with proplists, for instance (a value that wasn't set just isn't there) -- this might cause some confusion for people who do not normally work a lot with records.
So, all-in-all, I'd usually prefer a proplist or something similar, unless I have a very good reason to use a record. I do usually use records, though, for internal state of for example a gen_server or a gen_fsm; It's somewhat easier to update that way.
I think the biggest downside is that it's not idiomatic. Have you ever seen an API that required you to construct a record and pass it in?
Why would you want to do something that's going to feel foreign to any erlang programmer? There's a convention already in use for optional named arguments to functions. Inventing yet another way without good cause is pointless.

Is there an idiomatic way to order function arguments in Erlang?

Seems like it's inconsistent in the lists module. For example, split has the number as the first argument and the list as the second, but sublists has the list as the first argument and the len as the second argument.
OK, a little history as I remember it and some principles behind my style.
As Christian has said the libraries evolved and tended to get the argument order and feel from the impulses we were getting just then. So for example the reason why element/setelement have the argument order they do is because it matches the arg/3 predicate in Prolog; logical then but not now. Often we would have the thing being worked on first, but unfortunately not always. This is often a good choice as it allows "optional" arguments to be conveniently added to the end; for example string:substr/2/3. Functions with the thing as the last argument were often influenced by functional languages with currying, for example Haskell, where it is very easy to use currying and partial evaluation to build specific functions which can then be applied to the thing. This is very noticeable in the higher order functions in lists.
The only influence we didn't have was from the OO world. :-)
Usually we at least managed to be consistent within a module, but not always. See lists again. We did try to have some consistency, so the argument order in the higher order functions in dict/sets match those of the corresponding functions in lists.
The problem was also aggravated by the fact that we, especially me, had a rather cavalier attitude to libraries. I just did not see them as a selling point for the language, so I wasn't that worried about it. "If you want a library which does something then you just write it" was my motto. This meant that my libraries were structured, just not always with the same structure. :-) That was how many of the initial libraries came about.
This, of course, creates unnecessary confusion and breaks the law of least astonishment, but we have not been able to do anything about it. Any suggestions of revising the modules have always been met with a resounding "no".
My own personal style is a usually structured, though I don't know if it conforms to any written guidelines or standards.
I generally have the thing or things I am working on as the first arguments, or at least very close to the beginning; the order depends on what feels best. If there is a global state which is chained through the whole module, which there usually is, it is placed as the last argument and given a very descriptive name like St0, St1, ... (I belong to the church of short variable names). Arguments which are chained through functions (both input and output) I try to keep the same argument order as return order. This makes it much easier to see the structure of the code. Apart from that I try to group together arguments which belong together. Also, where possible, I try to preserve the same argument order throughout a whole module.
None of this is very revolutionary, but I find if you keep a consistent style then it is one less thing to worry about and it makes your code feel better and generally be more readable. Also I will actually rewrite code if the argument order feels wrong.
A small example which may help:
fubar({f,A0,B0}, Arg2, Ch0, Arg4, St0) ->
{A1,Ch1,St1} = foo(A0, Arg2, Ch0, St0),
{B1,Ch2,St2} = bar(B0, Arg4, Ch1, St1),
Res = baz(A1, B1),
{Res,Ch2,St2}.
Here Ch is a local chained through variable while St is a more global state. Check out the code on github for LFE, especially the compiler, if you want a longer example.
This became much longer than it should have been, sorry.
P.S. I used the word thing instead of object to avoid confusion about what I was talking.
No, there is no consistently-used idiom in the sense that you mean.
However, there are some useful relevant hints that apply especially when you're going to be making deeply recursive calls. For instance, keeping whichever arguments will remain unchanged during tail calls in the same order/position in the argument list allows the virtual machine to make some very nice optimizations.

How does one avoid a large number (between 20 and 30) of embedded "if" statements in Ruby?

I've got a massive script with about 20 embedded if statements (Yay!) that is used to parse through a data file. And in a sense, that's correct because the script should not continue operating if any of those evaluations fail.
But my gut says there's a more elegant way to accomplish the same thing. I'm familiar with the statemachine plugin for rails, but that seems to be overkill (it seems to be overkill).
Any chance there's a slightly more elegant way to reduce the number of embedded 'ifs' either through a workflow, or some other way?
reverse the conditions of the if statements and leave the particular function(if you can). This way you get a lot of if's behind each other instead of nested
This is mostly code specific, but I can suggest 2 ways:
case .. when .. then .. structure.
Effectively using send or eval methods.
One approach is to construct a hash or array in which the contents are Procs that each encapsulate a given conditional. Then you can loop through the procs and test your data against each one.
Just refactor the code and split parts of the conditional sections out to different functions. It will not reduce the nested if deepths but make it more readable.
Otherwise there is very little to say as it is a very generic question.
Use haml :P
(so you dont need to end the if tags..)

Resources