This question already has answers here:
Is there any difference between the `:key => "value"` and `key: "value"` hash notations?
(5 answers)
Closed 7 years ago.
I am struggling to understand difference between :symbol and text: with regards to the colon placement. My understanding is that when we use :symbol we are referring to this object and whatever it contains, where as text: is used to assign a value to the text like we would a variable. Is this correct or could someone elaborate on the usage. Thank you.
:whatever is a symbol, you've got that part right.
When you're using a hash, this was how you used to define it in 1.8x ruby:
{:key => value, :another_key => another_value}
This is known as the hashrocket syntax. In ruby 1.9x, this changed to:
{key: value, another_key: another_value}
There is backward compatibility that will still load the hashrocket syntax... But, in 1.9, 'key:' is a symbol
the {:key => value} is the old hash syntax in ruby, now we have a new hash syntax that is more like json so
{:key => value}
is the same as
{key: value}
The old one, we’re all familiar with is:
old_hash = {:simon => "Talek", :lorem => "Ipsum"}
This is all nice and dandy, but it could be simpler and cleaner. Check out the Ruby 1.9 style, it sort of resembles JSON:
new_hash = {simon: "Talek", lorem: "Ipsum"}
But now you look closer and ask, “But previously the key was a symbol explicitly, what’s with this now?”.
Well you’re right, the new notation is sort of a syntactic sugar for the most common style of hashes out there, the so called symbol to object hash. If you do this in the irb, you’ll see ruby returning the old school hash, with the symbols used as keys:
> new_hash = {simon: "Talek", lorem: "Ipsum"}
=> {:simon=>"Talek", :lorem=>"Ipsum"}
If you need to have arbitrary objects as your hash keys, you’ll still have to do it old school.
ref:http://breakthebit.org/post/8453341914/ruby-1-9-and-the-new-hash-syntax
Related
Is there any difference between :key => "value" (hashrocket) and key: "value" (Ruby 1.9) notations?
If not, then I would like to use key: "value" notation. Is there a gem that helps me to convert from :x => to x: notations?
Yes, there is a difference. These are legal:
h = { :$in => array }
h = { :'a.b' => 'c' }
h[:s] = 42
but these are not:
h = { $in: array }
h = { 'a.b': 'c' } # but this is okay in Ruby2.2+
h[s:] = 42
You can also use anything as a key with => so you can do this:
h = { C.new => 11 }
h = { 23 => 'pancakes house?' }
but you can't do this:
h = { C.new: 11 }
h = { 23: 'pancakes house?' }
The JavaScript style (key: value) is only useful if all of your Hash keys are "simple" symbols (more or less something that matches /\A[a-z_]\w*\z/i, AFAIK the parser uses its label pattern for these keys).
The :$in style symbols show up a fair bit when using MongoDB so you'll end up mixing Hash styles if you use MongoDB. And, if you ever work with specific keys of Hashes (h[:k]) rather than just whole hashes (h = { ... }), you'll still have to use the colon-first style for symbols; you'll also have to use the leading-colon style for symbols that you use outside of Hashes. I prefer to be consistent so I don't bother with the JavaScript style at all.
Some of the problems with the JavaScript-style have been fixed in Ruby 2.2. You can now use quotes if you have symbols that aren't valid labels, for example:
h = { 'where is': 'pancakes house?', '$set': { a: 11 } }
But you still need the hashrocket if your keys are not symbols.
key: "value" is a convenience feature of Ruby 1.9; so long as you know your environment will support it, I see no reason not to use it. It's just much easier to type a colon than a rocket, and I think it looks much cleaner. As for there being a gem to do the conversion, probably not, but it seems like an ideal learning experience for you, if you don't already know file manipulation and regular expressions.
Ruby hash-keys assigned by hash-rockets can facilitate strings for key-value pairs (e.g. 's' => x) whereas key assignment via symbols (e.g. key: "value" or :key => "value") cannot be assigned with strings. Although hash-rockets provide freedom and functionality for hash-tables, specifically allowing strings as keys, application performance may be slower than if the hash-tables were to be constructed with symbols as hash-keys. The following resources may be able to clarify any differences between hashrockets and symbols:
Ryan Sobol's Symbols in Ruby
Ruby Hashes Exaplained by Erik Trautman
The key: value JSON-style assignments are a part of the new Ruby 1.9 hash syntax, so bear in mind that this syntax will not work with older versions of Ruby. Also, the keys are going to be symbols. If you can live with those two constraints, new hashes work just like the old hashes; there's no reason (other than style, perhaps) to convert them.
Doing :key => value is the same as doing key: value, and is really just a convenience. I haven't seen other languages that use the =>, but others like Javascript use the key: value in their Hash-equivalent datatypes.
As for a gem to convert the way you wrote out your hashes, I would just stick with the way you are doing it for your current project.
*Note that in using key: value the key will be a symbol, and to access the value stored at that key in a foo hash would still be foo[:key].
This question already has answers here:
What does map(&:name) mean in Ruby?
(17 answers)
Closed 8 years ago.
I saw it in some sample Ruby code someone had posted. It was something like:
a.sort_by(&:name)
where a is an array or ActiveRecord objects and :name is one of the attributes.
I have never seen &:name and Ruby's Symbol class documentation says nothing about it. Probably something really simple. :)
Unary Ampersand is address of a function/block/lambda
In this case, it means that the .sort_by function will use each a's element's function named name for comparison
Mostly it used for something else, like this:
[1,2,3].map{ |x| x.to_s } # ['1','2','3']
That could be shortened as:
[1,2,3].map(&:to_s)
So, in your case, a.sort_by(&:name) is a shorthand to:
a.sort_by{ |x| x.name }
I'm reading The "Rails 3 Way" and on page 39, it shows a code sample of the match :to => redirect method. In that method the following code exists. Whilst I know what modulo does with numbers, I'm unsure what the % is doing below because both path and params are clearly not numbers. If anyone can help me understand the use of % in this situation, I'd appreciate it.
proc { |params| path % params }
That's probably the String#% method which works a lot like sprintf does in other languages:
'%05d' % 10
# => "00010"
It can take either a single argument or an array:
'%.3f %s' % [ 10.341412, 'samples' ]
# => "10.341 samples"
Update: As Philip points out, this method also takes a hash:
'%{count} %{label}' % { count: 20, label: 'samples' }
# => "20 samples"
Of course, this is presuming that path is a String. In Ruby you never really know for sure unless you carefully read the code. It's unlikely, but it could be % meaning modulo.
The thing you can be sure of is it's calling method % on path.
It does string interpolation. In the simplest case, it's equivalent to:
"foo %s baz" % 'bar'
#=> "foo bar baz"
However, you can use more complex format specifiers to interpolate from Array or Hash objects too, such as the Rails params hash. See the String#% and Kernel#sprintf methods for details on how to construct a valid format specification.
Here is the code:
def autocomplete
if(params[:terms])
key = params[:terms]
customers = Customer.where(:$or => [
{:first_name => Regexp.new(/^#{key}/i)},
{:last_name => Regexp.new(/^#{key}/i)},
{:email => Regexp.new(/^#{key}/i)},
#{:phone => Regexp.new(/^#{key}[d+]/i)},
{:phone => Regexp.new(/^#{key.gsub(/\D+/,'')}/)},
{:zip_code => key.to_i },
{:street1 => Regexp.new(/#{key}/i)},
{:street2 => Regexp.new(/#{key}/i)}
]
)
The gsub method suggested by Tin Man gets me almost there - it strips any non-Digit characters from the search string only when searching in the :phone field in my DB.
The last problem is that the :phone field in the DB might actually have non-Digits in it (and I want to allow users to enter phone numbers however they want), so I need to temporarily ignore dashes when I'm searching (using find() in Mongo)
Not sure if I should do it at this level in the autocomplete function or if I should do it in the autocomplete.js module...
SUMMARY - I want to :phone.gsub(/\D+/,'') but gsub only works on strings, not a reference like this.
Some things I see:
Regexp.new(/^#{key}[d+]/i)}
[\d+] is nonsense. Drop the surrounding [].
For:
{:zip_code => key.to_i },
Don't convert the zipcode to an integer. Some zip codes are hyphenated, which will drop the trailing value. Also, unless you intend to perform math on the value, leave it as a string.
What is $or? Using a global is usually a sign of code-smell. There are few reasons to use one in Ruby, and I've never found a good use for one in my code, and it's something that can usually be refactored out easily using a constant.
I think you actually answered my question by pointing out the key.to_i for ZIP - that's actually exactly what I WANT to do with Phone Number - strip out all the dashes, spaces, brackets, etc. I am going to give that a try.
No, no, no, no. to_i won't do what you want. '0-1'.to_i => 0 and '0.1'.to_i => 0. Instead you want to strip out all non-numeric characters from the string using gsub, then you're done:
'0.1'.gsub(/\D+/, '')
=> "01"
'123-456-7890'.gsub(/\D+/, '')
=> "1234567890"
'(123) 456 7890'.gsub(/\D+/, '')
=> "1234567890"
'0.1'.gsub(/\D+/, '').to_i
=> 1
Note what happened above when to_i received the "01", the leading zero was removed because it wasn't significant for the representation of an Fixnum. You can force it to display using a string format, but why? A phone number is NOT a numeric value, it's a string value, even though it is a bunch of numbers. We NEVER need to do addition on them, or any math, so it's senseless to convert it to an integer. Keep it as a string of digits.
I'm working for almost 4 weeks with Ruby on Rails now, so consider me as a beginner.
When performing a conditional find query, I need to compare a part of an integer (put in a string..) with another integer.
#invs = Inv.find(:all, :conditions => {:cnr => INTEGER_TO_BE_COMPARED_TO })
Well, I found a way to get a certain part of an integer and wrote the following method:
def get_part_of_int
#r = Integer((#cnr % 10000000)/100000.0)
#r = "%02d" % #r
#r.to_s
end
This should give the output #r = 01 from #cnr = 40138355
The target is to only show invs with e.g. 01 as second and third digit.
I'm using:
Rails 3.2.8
Ruby 1.9.3p194
Thank you all in advance.
== Edit: ==
I realised there is no question mark in my post.. And there is some confusion.
The value of the column name cnr should be stripped to the 2nd and 3rd digit and be compared to a string e.g. 01.
Thank you #Salil for you suggestion.
However this doesn't work.. But I understand the way of using it. The following will convert the string :cnr to :nr.
Inv.find(:all, :conditions => {:cnr.to_s[1,2] => '01' })
Is there a way to compare a part of the value of the column with e.g. 01?
Maybe I should think the other way around. Is it possible to search for cnrs with the 2nd and 3rd digit e.g. 01? The trick is that these numbers are always as 2nd and 3rd digit. I assume a fuzzy search with e.g. Solr doesn't work, because when searching for 01 I don't want the cnr 40594013.
Can this be done in some way?
Thank you in advance and my apologies for confusing you.
if your question is how to get the second and third digit from a integer?
You can use following
40138355.to_s[1,2] ##This will give you "01"
EDITED Ref:- Substring
#invs = Inv.find(:all, :conditions => ["SUBSTRING(cnr,1,2) =?", #cnr.to_s[1,2] ])