How to use a string to find a symbol in a hash - ruby

I have a string:
category = "cupcakes"
I need to see if this hash has that string, converted to a symbol, as a key:
products = {
:cupcakes => [{:title => "chocolate", :flavor => "chocolate"}, {:title => "summer special", :flavor => "pink cake"}],
:cookies => [{:title => "chocolate bliss", :flavor => "chocolate chip"}, {:title => "breakfast surprise", :flavor => "oatmeal raisin"}]
}
This one does not work because category is a string, not a symbol.
products.key?(category)
This one does not work because :cupcake is a unique symbol, and we are just creating another symbol.
products.key?(category.to_sym)

I think this comes from a misunderstanding of how symbols work. Every symbol with the same content is absolutely identical down to having the same object_id. Symbols with different content are always different. This is in contrast to strings where they may have identical content but a different object_id, or where one moment a string might contain one thing and the next it's completely different despite having the same object_id.
Ruby's object_id values are just what they say they are, "object identifiers", and are a way of saying "object number".
Now the string "cupcake" and the symbol :cupcake are not the same:
"cupcake" == :cupcake
# => false
If you do the conversion, they are:
"cupcake".to_sym == :cupcake
# => true
The real problem is you're expecting :cupcake and :cupcakes to be the same thing. Ruby doesn't understand English rules and semantics, so as far as its concerned those are two completely different things.
If you're using ActiveSupport you can do things like:
"cupcake".pluralize.to_sym == :cupcakes
# => true
That requires an additional library, but the good news is it comes with things like Rails by default.
In any case, the way you've defined your data you need to reference it as something like:
products[:cupcakes]
products["cupcake".to_sym]
products["cupcake".pluralize.to_sym]

Related

Match value if other are not matched

I have this Ruby map:
FIXED_COUNTRY_TO_PHONE = {
'FI' => '+358501111',
'RU' => '4019900780',
'SE' => '+4672345678',
'UA' => '0123456789',
'KZ' => '0123456789'
}.freeze
How I can set some final value for example '*' => '1234567' if the other values are not matching?
FIXED_COUNTRY_TO_PHONE = Hash.new('1234567').merge({
'FI' => '+358501111',
'RU' => '4019900780',
'SE' => '+4672345678',
'UA' => '0123456789',
'KZ' => '0123456789'
}).freeze
But simple
DEFAULT = "1234567".freeze
FIXED_COUNTRY_TO_PHONE["FI"] || DEFAULT
#=> "+358501111"
FIXED_COUNTRY_TO_PHONE["??"] || DEFAULT
#=> "1234567"
Looks also nice
You can use Hash#default= to set the default value:
hash = {
'FI' => '+358501111',
'RU' => '4019900780',
'SE' => '+4672345678',
'UA' => '0123456789',
'KZ' => '0123456789'
}
hash.default = '1234567'
hash['UK']
#=> '1234567'
There are two main ways of dealing with this problem. #llya assigns a default value to the hash, #fl00r applies the default when the hash is evaluated for a non-existing key, causing nil to be returned.
llya shows one way of implementing the default value. It is very clear but uses a few lines of code. Two other ways of doing that deserve mention (though I am not suggesting they are in any sense better than how llya has done it).
Set the default then add the key-value pairs:
hash = Hash.new('1234567').
merge('FI'=>'+358501111', 'RU'=>'4019900780', 'SE'=>'+4672345678',
'UA'=>'0123456789', 'KZ'=>'0123456789').
freeze
hash['oh, my']
#=> "1234567"
Use Object#tap
hash = { 'FI'=>'+358501111', 'RU'=>'4019900780', 'SE'=>'+4672345678',
'UA'=>'0123456789', 'KZ'=>'0123456789'
}.tap { |h| h.default = '1234567' }.
freeze
hash['oh, my']
#=> "1234567"
A variantof fl00r's || DEFALULT approach, which arguably reads better, is to use Hash#fetch:
hash = { 'FI'=>'+358501111', 'RU'=>'4019900780', 'SE'=>'+4672345678',
'UA'=>'0123456789', 'KZ'=>'0123456789' }
DEFAULT = "1234567"
hash.fetch('oh, my', DEFAULT)
#=> "1234567"
hash[key] || DEFAULT clearly cannot be used if hash has a key whose value may be nil or false, though that is not an issue here.
Both approaches have pros and cons. Setting a default value avoids the need for the retrieval of values (which may be done in multiple places) to be concerned about whether the hash contains a particular key, but on the other hand readers of those parts of the code may not be aware (or have forgotten) that the hash was defined with a default value. If the || DEFAULT approach is used there is the possibility that the coder may forget to include || DEFAULT in one or more places where the hash is referenced. In terms of code maintenance I would think it's a toss-up, provided the constant DEFAULT is defined in close proximity to the hash, and commented suitably.
It seems to me that it's generally best to use a default value, and wherever the hash is referenced remind readers that it has a default value, either with a comment or a suggestive name for the hash (e.g., applies_to_oranges_with_default).

In Ruby, how to choose whether a symbol or string to be used in a given scenario?

I see this answer in various websites:
If the contents (the sequence of characters) of the object are
important, use a string If the identity of the object is important,
use a symbol
But, what does this actually mean? Please give me an explanation which even a layman can understand.
a = :foo
b = :foo
a and b refer to the same object in memory (same identity)
a.object_id # => 898908
b.object_id # => 898908
Strings behave differently
a = 'foo'
b = 'foo'
a.object_id # => 70127643805220
b.object_id # => 70127643805200
So, you use strings to store data and perform manipulations on data (replace characters or whatnot) and you use symbols to name things (keys in a hash or something). Also see this answer for more use cases for symbol.

What is the use of symbols?

I heard that two symbols with the same name create only one memory area, but two strings with the same content create two memory areas.
What is the use of symbols?
Is symbol like a variable? If so, how can I assign a value to a symbol?
If I allocate memory only once for symbols with the same name, what am I doing with the symbols?
Ok, so the misunderstanding probably stems from this:
A symbol is not a variable, it is a value. like 9 is a value that is a number.
A symbol is a value that is kinda of roughly a string... it's just not a string that you can change... and because you can't change it, we can use a shortcut -> all symbols with the same name/value are stored in the same memory-spot (to save space).
You store the symbol into a variable, or use the value somewhere - eg as the key of a hash.... this last is probably one of the most common uses of a symbol.
you make a hash that contains key-value pairs eg:
thing_attrs = {:name => "My thing", :colour => "blue", :size => 6}
thing_attrs[:colour] # 'blue'
In this has - the symbols are the keys you can use any object as a key, but symbols are good to use as they use english words, and are thus easy to understand what you're storing/fetching... much better than, say numbers. Imagine you had:
thing_attrs = {0 => "My thing", 1 => "blue", 2 => 6}
thing_attrs[1] # => "blue"
It would be annoying and hard to remember that attribute 1 is the colour... it's much nicer to give names that you can read when you're reading the code. Thus we have two options: a string, or a symbol.
There would be very little difference between the two. A string is definitely usable eg:
thing_attrs = {"name" => "My thing", "colour" => "blue", "size" => 6}
thing_attrs["colour"] # 'blue'
except that as we know... symbols use less memory. Not a lot less, but enough less that in a large program, over time, you will notice it.
So it has become a ruby-standard to use symbols instead.
A Symbol is the most basic Ruby object you can create. It's just a name and an internal ID. Symbols are useful because a given symbol name refers to the same object throughout a Ruby program. Symbols are more efficient than strings. Two strings with the same contents are two different objects, but for any given name there is only one Symbol object. This can save both time and memory.
# p039symbol.rb
# use the object_id method of class Object
# it returns an integer identifier for an object
puts "string".object_id
puts "string".object_id
puts :symbol.object_id
puts :symbol.object_id
>ruby p039symbol.rb
21066960
21066930
132178
132178
>Exit code: 0
I find it most helpful to think of symbols as strings without all the fancy string features.
Their main use is as the name of other things in your program.
For example, say you have a hash of user information.
You could do
user = { 'name' => 'Tim', 'age' => 20 }
Here the hash keys are strings.
This is fine, but it's really overkill.
Strings have lots of fancy methods like substitution and smart capitalization, and they are mutable (i.e. string objects can be changed in place).
You are never going to change hash keys, so you don't need any of that.
Thus, it's better just to use symbols
user = { :name => 'Tim', :age => 20 }
Another place symbols show up is referring to class methods.
Say I have the following class
class Foo
def initialize(bar)
#bar = bar
end
end
If I need access to the value of #bar from outside of Foo I need to add a getter method to Foo.
That would look like this
class Foo
def initialize(bar)
#bar = bar
end
def bar
bar
end
end
However, this is a pretty common thing to want to do, so ruby provides shorthand as follows
class Foo
attribute_reader :bar
def initialize(bar)
#bar = bar
end
end
This tells Foo to create for us the method we added by hand in the previous version.
As you can see, we refer to the #bar variable using a symbol.
In answer to your second question, no, a symbol is not a variable.
You can't "assign it a value."
However, as you can see, symbols can sometimes be used to refer to variables.

Rails Hash Format

Which is the preferred hash format for Rails? Or is one of them wrong?
User.create(:name => "John")
or
User.create(name: "John")
Can I do
User.create(:name "John")
or
User.create(name: => "John")
The ruby 1.9's way is to do User.create(name: 'John'). The older fashion is to do User.create(:name => 'John'). Other solutions will not works.
You just need to realise the semantics of the different symbols.
In here:
User.create(:name => "John")
You have a symbol :user mapped with linking operator=>.
In here:
User.create(name: "John")
You have linking operator :.
These two are wrong:
User.create(:name "John")
Here you have symbol and then no link from key to value at all.
This too:
User.create(name: => "John")?
You have two links once : and once =>.
I think your biggest issue is that you do not completely undertand the meaning of symbols in Ruby. Read here.
Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
If you want to study rails, I highly recommend a git repo(https://github.com/bbatsov/rails-style-guide), it can help you write good style rails code, hopefully useful to you.

Ruby => operator... eg: :text => /Log In/

What does this do? I find the example here, but other than what it does, what does it mean? I can't find anything on google because well, I am not sure what '=>' is even called in this context.
More examples here:
http://mechanize.rubyforge.org/mechanize/EXAMPLES_rdoc.html
In :text => /Log In/, you are passing a hash to page's link_with function, and the key in the hash is :text and its corresponding value is /Log In/.
Basically: :x => y means that :x is a key in a hash that maps to a value of y.
passing hashes to functions like this allows you to have something like (but not exactly) named parameters.
UPDATE:
A symbol of the form :something is called.... a symbol! You can think of them sort of like global string constants (but they're not quite the same). Now, when you think back to something like:
login_page.form_with(:action => '/account/login.php')
What you're actually doing is constructing a new hash on the fly. You create a new element in the hash, where the key is a string with the value "action", and the value of that element is "/account/login.php" (in this case, also a string, but I'm pretty sure you can store other things in hashes besides strings).
...whew! It's been a while since I've worked with Ruby. I hope I got that all correct. ;)
Some good looking pages here (more can be found by searching google for "ruby symbol")
http://glu.ttono.us/articles/2005/08/19/understanding-ruby-symbols
http://www.troubleshooters.com/codecorn/ruby/symbols.htm#_What_are_symbols
It associates a value with an index for hashes.
obj.method :text => /Log In/
is shorthand for
obj.method {:text => /Log In/}
It's used to create a hash expression, as in { key => value }.
Also, when used as the last parameter in a method call, the { } are not needed, so the key => value can appear alone.
>> p({:a => 1, :b => 2})
{:a=>1, :b=>2}
=> nil
>> p :c=>3, :d=>4
{:d=>4, :c=>3}
=> nil
>> t = { :e=>5, :f=>6 }
=> {:f=>6, :e=>5}
This shorthand is really nice in poetry mode, where a literal hash following a method name would look like a block.

Resources