Keyword arguments in the method definition must be symbols given in the new-style hash syntax, but in the method call you may use the old-style hash syntax.
Compare this to the current common pattern of using a hash to represent options:
Take care when refactoring old hash-style arguments to the new keyword arguments, while in most cases only the method definition needs to change, the new syntax will raise an ArgumentError when you call it with an argument that isn’t defined in the method signature. This will prevent spelling mistakes that would otherwise cause the call to succeed with a incorrect set of arguments.
You can stop an ArgumentError being raised and deal with arbitrary keyword arguments by using a double-splat (double asterisk) to capture all keywords not already assigned and puts them in a hash:
As well as less lines of boiler-plate code, another win of using keyword arguments is that it avoids the false trap common when dealing with option hashes- when you default an argument you must do so on it’s presence, not on it’s truthiness otherwise you will never be able to set an argument to false:
1234567
options={to_uppercase:false}# incorrect (always overriding nil and false):options[:to_uppercase]||true# => true# correct (allowing nil and false):options.fetch(:to_uppercase,true)# => false
So the result is a useful pattern that replaces a more verbose and error prone one. Just remember kids: don’t refactor for the sake of it. Using keywords arguments will mean your code can’t be used with Ruby 1.9.x anymore and could cause API breaks if users are calling methods with unexpected options.
For more reading about Ruby 2.0 I recommend reading:
Last time I was looking for a job amending my CV in Apple Pages was a pain.
I realised that when working in content & presentation my brain thinks best in HTML & CSS, not in the WYSIWYG terms of a word processor.
Not wanting to re-learn LaTeX, I wrote my CV like a webpage. Compared to a .pages or .doc this is great.
As well as a web page you can print it to PDF easily from a web browser.
Last week I had upgraded the Engine Yard hosted app to run on ruby 1.9.3. As with most of engine yard config it was easy as pressing a button.
All was going well for the app except a cryptic “fatal: bad scan arg format: 1” exception in the logs coming from the Net::HTTP library.
Searching the Ruby source I found that the method rb_scan_args in class.c was causing the error. rb_scan_args is
a helper method that can parse optional arguments.
It turns out that Engine Yard doesn’t restart Nginx on deploy, instance rebuild or even ruby upgrade. This means the Nginx & Passenger had been using ruby 1.9.2 with gems installed for ruby 1.9.3.
A parsing bug in ruby 1.9.2 allowed you to pass blocks to methods preceded by a comma.
The bug only affected blocks with do/end and was fixed in 1.9.3.
There’s no simple pattern to exploit in the relationship between ascii character codes and the distribution or magnitude of roman numerals.
Instead roman_numeral_to_integer is a cleverly constructed function that fits
all the points on the above graph, mapping all the roman numerals to integers. A lookup hash is certainly more easily constructed, read, and maintainable but this wins on cleverness and character count.
For more about a similar ‘Magic Formula’ for the same purpose, and how you could construct it using brute force methods see Golf: Magic Formula for Roman Numerals.
Now lets look at increment. Increment is the value that should be added to sum. Because the sum calculation is one iteration behind it is last_value and not value that should be added.
1
increment=last_value-((2*last_value)%value)
When a smaller numeral is before a larger one it should be subtracted rather than added to the total so the increment will be -last_value when last_value < value, and else will just be last_value
The code works because, for the natural numbers x and y:
x % y ≡ x, when x < y
x % y ≡ 0, when x >= y and y is a factor of x
Note that for any numeral value x all smaller numeral values are factors. For example, L (50) is greater than I (1), V (5), X (10) and all of these are factors.
So when last_value >= value it just added to sum (the right hand side of the subtraction will be 0) and when last_value < value it is turned negative (the right hand side of the subtraction will be last_value * 2).
Going back to the original program it looks like we only save 1 character doing it this way over a ternary if:
123
l-2*l%n# vs.n>l?-l:l
But remember that in the original program last_value and value are both stored in the single variable n. The program relies on the order of evaluation to use the correct value of n whereas a ternary if will evaluate the conditional first so would require a new variable to be used.
Summing up
The method has clever use of a mathematical function for mapping numerals and modulus operation to avoid an if statement. Most of this is done in a single expression and trusts the evaluation order semantics of Ruby.