Starting in ruby 1.9 you could use the new syntax for symbols inside of hashes
Before 1.9
{:a => 'b'}
1.9 and later
{a:'b'}
But why isn't there a similar thing for symbols that contain strings that cannot be easily converted {:"a-b" => 'c'} like
{"a-b": 'c'}
Is there something in the Ruby lexical parser that would prevent this from happening? or fundamental reason why this was not also implemented?
Because Matz decided against it:
Iff {'key': 'value'} means {:key => 'value'} I have no objection.
[but later on...]
The discussion has gone away in the wind without making any consensus.
So I marked this 'rejected'. My point is clearly stated in the first comment.
Cited from https://bugs.ruby-lang.org/issues/4801
Related
I was playing with IRB (Ruby 2.5.1) when I noticed this:
irb(main):020:0> h
=> {3=>4, :aaa=>false}
irb(main):021:0> h.count
=> 2
However, this method doesn't exist in Ruby docs.
A quick test shows that hsh.count gives the same result as hsh.keys.count, and Hash.ancestors contains Enumerable.
What exactly is Hash#count?
You seem to have gotten most of the way there... it's Enumerable#count.
Technically, hsh.keys.count is counting the keys, and hsh.count is counting the pairs (as would be yielded by hsh.each), but those are identical values in practice, because each pair has a unique key.
I am pretty new to ruby and sinatra but basically I have this route:
put '/user_list/:user_id' do
puts request.params["model"]
end
and it returns the following
{"password":"36494092d7d5682666ac04f62d624141","username":"nicholas","user_id":106,"firstname":"Nicholas","email":"nicholas#macpractice.com","is_admin":0,"lastname":"Rose","privileges":""}
I am now having a hard time accessing values of each of those. It doesn't really seem to be in hash format so I can't really do
request.params["model"][:password]
It just returns nil..
I just need to know what I can do to access those variables, or how to configure my request parameters to be in a good format to access variables.
Try request.params["model"]["password"]
A Hash's keys can consist of both symbols and strings. However, a string key is different than a symbol key.
Note the following:
h = {:name => 'Charles', "name" => 'Something else'}
h[:name] #=> 'Charles'
h["name"] #=> 'Something else'
EDIT:
In your particular situation, it appears request.params["model"] returns a string instead of a hash. There is a method String#[] which is a means of getting a substring.
s = "Winter is coming"
s["Winter"] #=> "Winter"
s["Summer"] #=> nil
This would explain your comments.
There are a couple things you can do to remedy your specific situation. I have found the most simplest way to be using JSON. (I'm sure there are others and maybe those will surface through other answers or through comments.)
require 'json'
hash_of_params = JSON.load(request.params["model"]).to_hash
hash_of_params["password"] #=> "36494092d7d5682666ac04f62d624141"
The standard Hash treats strings and symbols differently, and I'd be willing to bet that's what's happening in this case.
Use request.params["model"]["password"] to get the password.
The exception to that is when working with a HashWithIndifferentAccess which is part of ActiveSupport. For hashes of that type, either strings or symbols can be used to access the same elements.
Try the below,it will work too:
request.params["model"][:password.to_s]
I'm looking for a way to parse ordinal numbers (first, second, third, etc) in Ruby and convert them to integers. Do you know of any libraries that do this?
I was half-way through asking this question when I realized that the chronic gem does this as part of the process of parsing dates. After installing the gem, you can convert ordinal numbers to integers pretty easily:
irb(main):001:0> require 'chronic'
=> true
irb(main):002:0> Chronic::Numerizer.numerize("eighty-fifth").to_i
=> 85
Edit: Unfortunately, it seems that chronic doesn't correctly parse the ordinal "second":
irb(main):003:0> Chronic::Numerizer.numerize("twenty-second").to_i
=> 20
The reason for this is that chronic is designed to parse dates and times, and "second" could be either an ordinal number or a unit of time in that context. To solve this problem, you can monkey patch chronic's Numerizer class with this line:
Chronic::Numerizer::ORDINALS.insert(1, ['second', '2'])
Now it works:
irb(main):005:0> Chronic::Numerizer.numerize("eighty-second").to_i
=> 82
If you are actually using chronic for its intended purpose though, you probably won't want to screw with its internals. In that case, you can copy the source code from Chronic::Numerizer into a new class and use that one instead. Don't forget to add ['second', '2'] to the ORDINALS constant in the new class.
There's a gem called numerouno which seems to be specifically targeted at this, if Chronic doesn't fit your use case.
I've been using a gem called deordinalize (https://rubygems.org/gems/deordinalize) which seems to do the trick nicely - just make sure you downcase before calling;
>> require 'deordinalize'
>> 'Forty-Second'.downcase.deordinalize
=> 42
To correctly parse the ordinal "second":
you have now to monkey patch Numerizer class with this line
SINGLE_ORDINALS.insert(1, ['second', 2])
So while a ruby String is globally unique, a ruby Symbol is not, because it's stored by id somewhere in the background:
http://thoughtsincomputation.com/posts/ruby-symbols-what-are-they
...which means using symbols use less memory, given that you have a specified set of values the symbol can be (you don't want to turn every string of user-entered text into a symbol for example).
My question is, while there is definitely a performance benefit of using symbols, is it worth it in the end? I'm asking because, for example, I write most of my hashes using symbols:
my_hash = {:_id => "123", :key => "value"}
But in the ruby-mongo-driver, all the keys are returned as strings:
mongo_hash = {"_id" => "123", "key" => "value"}
So if I were to use both my hash and the mongo hash the same way, I'd have to do:
mongo_hash = Model.collection.find_one(:key => "value")
#=> {"_id" => "123", "key" => "value"}
mongo_hash.symbolize_keys!
#=> {:_id => "123", :key => "value"}
But that just adds another layer to the application:
Create a bunch of strings for the keys in memory.
Now create a symbol for each string (already in memory after the first time this is done).
Now destroy the strings we just created.
It seems like something's wrong there... either everything should be symbols or strings, there shouldn't be conversion back and forth, at least in this case.
What do you think about this? Is this okay? Is this even a problem, or is the ruby garbage collector and all that (haven't gone there yet) okay with this?
Unless you're seriously pushing the constraints of your server/system, the benefits or drawbacks of either method are going to be negligible.
When using a library that absolutely requires that you give it a string-keyed hash, it is obviously better to simply use strings, as it keeps your code clear and concise, and eliminates the need for you to cast the keys to strings.
Ruby aims to make programming more enjoyable for the developer, and makes no claim to be the most efficient. When I use Ruby, I take this to heart and use Symbols for the keys in my hashes simply because it makes them easier to read.
When it comes down to it, it's personal preference, and you won't notice a speed increase/decrease either way. Unless you're running into speed/memory constraint issues, you've got nothing to worry about. Other parts of the Ruby standard library will begin to fall apart before this becomes an issue.
"Premature optimization is the root of all evil" -- Donald Knuth
When I first started reading about and learning ruby, I read something about the power of ruby symbols over strings: symbols are stored in memory only once, while strings are stored in memory once per string, even if they are the same.
For instance: Rails' params Hash in the Controller has a bunch of keys as symbols:
params[:id] or
params[:title]...
But other decently sized projects such as Sinatra and Jekyll don't do that:
Jekyll:
post.data["title"] or
post.data["tags"]...
Sinatra:
params["id"] or
params["title"]...
This makes reading new code a little tricky, and makes it hard to transfer code around and to figure out why using symbols isn't working. There are many more examples of this and it's kind of confusing. Should we or shouldn't we be using symbols in this case? What are the advantages of symbols and should we be using them here?
In ruby, after creating the AST, each symbol is represented as a unique integer. Having symbols as hash keys makes the computing a lot faster, as the main operation is comparison.
Symbols are not garbage collected AFAIK, so that might be a thing to watch out for, but except for that they really are great as hash keys.
One reason for the usage of strings may be the usage of yaml to define the values.
require 'yaml'
data = YAML.load(<<-data
one:
title: one
tag: 1
two:
title: two
tag: 2
data
) #-> {"one"=>{"title"=>"one", "tag"=>1}, "two"=>{"title"=>"two", "tag"=>2}}
You may use yaml to define symbol-keys:
require 'yaml'
data = YAML.load(<<-data
:one:
:title: one
:tag: 1
:two:
:title: two
:tag: 2
data
) #-> {:one=>{:title=>"one", :tag=>1}, :two=>{:title=>"two", :tag=>2}}
But in the yaml-definition symbols look a bit strange, strings looks more natural.
Another reason for strings as keys: Depending on the use case, it can be reasonable to sort by keys, but you can't sort symbols (at least not without a conversion to strings).
The main difference is that multiple symbols representing a single value are identical whereas this is not true with strings. For example:
irb(main):007:0> :test.object_id
=> 83618
irb(main):008:0> :test.object_id
=> 83618
irb(main):009:0> :test.object_id
=> 83618
3 references to the symbol :test, all the same object.
irb(main):010:0> "test".object_id
=> -605770378
irb(main):011:0> "test".object_id
=> -605779298
irb(main):012:0> "test".object_id
=> -605784948
3 references to the string "test", all different objects.
This means that using symbols can potentially save a good bit of memory depending on the application. It is also faster to compare symbols for equality since they are the same object, comparing identical strings is much slower since the string values need to be compared instead of just the object ids.
I usually use strings for almost everything except things like hash keys where I really want a unique identifier, not a string