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].
Related
The following is a stored value for datatype defined as text
text_field = "[{\"shop_id\"=>110, \"budget\"=>\"040\"}, {\"shop_id\"=>111, \"budget\"=>173}, {\"shop_id\"=>141, \"budget\"=>344}, {\"shop_id\"=>142, \"budget\"=>\"020\"}, {\"shop_id\"=>144, \"budget\"=>\"220\"}]"
Thus defined, it is for all intents and operational purposes a ruby String class. The contents represent an array of hashes.
How can this string become the array of hashes so that one can call
text_field_array.each do |hash|
shop = Shop.find(hash[shop_id])
shop_budget = shop.budget + hash[budget]
[...]
end
Use eval
> eval(text_field)
=> [{"shop_id"=>110, "budget"=>"040"},
{"shop_id"=>111, "budget"=>173},
{"shop_id"=>141, "budget"=>344},
{"shop_id"=>142, "budget"=>"020"},
{"shop_id"=>144, "budget"=>"220"}]
NOTE: Be careful about it. Make sure the text doesn't have malicious code in the string. Read more about it here https://ruby-hacking-guide.github.io/security.html
I have the following hash. Using ruby, I want to get the value of "runs". I can't figure out how to do it. If I do my_hash['entries'], I can dig down that far. If I take that value and dig down lower, I get this error:
no implicit conversion of String into Integer:
{"id"=>2582, "entries"=>[{"id"=>"7", "runs"=>[{"id"=>2588, ...
Assuming that you want to lookup values by id, Array#detect comes to the rescue:
h = {"id"=>2582, "entries"=>[{"id"=>"7", "runs"=>[{"id"=>2588}]}]}
# ⇓⇓⇓⇓⇓⇓⇓ lookup element with id = 7
h['entries'].detect { |e| e['id'] == 7 }['runs']
.detect { |e| e['id'] == 2588 }
#⇒ { "id" => 2588 }
As you have an array inside the entries so you can access it using an index like this:
my_hash["entries"][0]["runs"]
You need to follow the same for accessing values inside the runs as it is also an array.
Hope this helps.
I'm not sure about your hash, as it's incomplete. So , guessing you have multiple run values like:
hash = {"id"=>2582, "entries"=>[{"id"=>"7", "runs"=>[{"id"=>2588}]},
{"id"=>"8", "runs"=>[{"id"=>2589}]},
{"id"=>"9", "runs"=>[{"id"=>2590}]}]}
Then, you can do
hash["entries"].map{|entry| entry["runs"]}
OUTPUT
[[{"id"=>2588}], [{"id"=>2589}], [{"id"=>2590}]]
I am writing a simple proggramming language with scala parser. So far no trouble, but im worrying about the relation function name / variable name against reserved words.
I'va already addded some special functions like "floor" ~ gexp or "top" ~ gexp and i dont want anybody using this language being able to name a function or a variable like them. I have not found yet a way to check this.
in Ruby i would write something like
rule varname
lowerid &{ |id| id[0].is_not_reserved } <VarNameNode>
but i dont know how would i write this in scala
def varName : Parser[StringValue] = lowerid
You can use the ^? operator:
def varName: Parser[StringValue] = lowerid ^? ({
case id if !isReserved(id) => id
}, { id => s"Error: $id is reserved." })
I have a non-Rails project in which I am loading some settings from a YAML file:
config = YAML::load File.open("#{LOG_ROOT}/config/database.yml")
I can only access this hash like config["host"], config["username"] etc.
I want indifferent access so I can use both :host and "host".
The reason is, that one of the gems in the project to which I am passing this hash seems to be accessing it using symbols and it fails currently.
What is the best way to create a hash with indifferent access in this scenario?
You lose nothing except a few kB of disk space by installing the Active Support gem. In your code, you require only the function you want:
require 'active_support/core_ext/hash/indifferent_access'
That way, you can be sure you are not getting anything else to mess up your namespace.
Let the config hash return the value for the stringified version of the key:
config = {"host"=>"value1", "Username"=>"Tom"}
config.default_proc = proc{|h, k| h.key?(k.to_s) ? h[k.to_s] : nil}
p config[:host] #=> "value1"
The default_proc runs everytime when a key is not found in the hash. Note this is only half of indifferent access: config["host"] will result in nil if the key :host is present. If that has to work too:
config.default_proc = proc do |h, k|
case k
when String then sym = k.to_sym; h[sym] if h.key?(sym)
when Symbol then str = k.to_s; h[str] if h.key?(str)
end
end
See the comments about limitations of this approach (tltr: separate values for :a and 'a' are possible, does not take into account Hash.delete and others).
I have found several websites pointing to using the following code to add support for custom parameter formats:
ActionController::Base.param_parsers[Mime::PLIST] = lambda do |body|
str = StringIO.new(body)
plist = CFPropertyList::List.new({:data => str.string})
CFPropertyList.native_types(plist.value)
end
This one here is for the Apple plist format, which is what I am looking to do. However, using Rails 3.2.1, The dev server won't start, saying that param_parsers is undefined. I cannot seam to find any documentation for it being deprecated or any alternative to use, just that it is indeed included in the 2.x documentation and not the 3.x documentation.
Is there any other way in Rails 3 to support custom parameter formats in POST and PUT requests?
The params parsing moved to a Rack middleware. It is now part of ActionDispatch.
To register new parsers, you can either redeclare the use of the middleware like so:
MyRailsApp::Application.config.middleware.delete "ActionDispatch::ParamsParser"
MyRailsApp::Application.config.middleware.use(ActionDispatch::ParamsParser, {
Mime::PLIST => lambda do |body|
str = StringIO.new(body)
plist = CFPropertyList::List.new({:data => str.string})
CFPropertyList.native_types(plist.value)
end
})
or you can change the constant containing the default parsers like so
ActionDispatch::ParamsParser::DEFAULT_PARSERS[Mime::PLIST] = lambda do |body|
str = StringIO.new(body)
plist = CFPropertyList::List.new({:data => str.string})
CFPropertyList.native_types(plist.value)
end
The first variant is probably the cleanest. But you need to be aware that the last one to replace the middleware declaration wins there.