Difference between `:provider => ' value '` and `provider: 'value'` - ruby

To describe a hash for carrierwave configurations, I write like:
{
provider: 'AWS',
aws_access_key_id: ENV["aws_access_key_id"],
aws_secret_access_key: ENV["aws_secret_access_key"],
}
However, tutorials seem the advice to write:
{
:provider => 'AWS'
:aws_access_key_id => ENV["aws_access_key_id"],
:aws_secret_access_key => ENV["aws_secret_access_key"],
}
What is the difference between the two? Is there good reason to use one over the other?

There is no difference.
nitz#comp:~$ irb
irb(main):001:0> {a:1}
=> {:a=>1}
This is a new syntax for specifying hashes with keys that are symbols, which is the "normal" way (as far as I can see) of defining hashes.
Also see What are the benefits of the new hash syntax in Ruby 1.9?

It's the new syntax for ruby 1.9+, just a syntactic sugar, that's all.
http://breakthebit.org/post/8453341914/ruby-19-and-the-new-hash-syntax
I prefer to use the new as older syntax might get deprecated in near future.

This "JSON" syntax was added in ruby 1.9 http://effectif.com/ruby/update-your-project-for-ruby-19-hash-syntax
The only difference is that you can't do things like dashes with it:
:'foo-moo' => 2

Related

How to use YAML.load with handlers

irb(main):001:0> a="run: yes"
=> "run: yes"
irb(main):002:0> require 'yaml'
=> true
irb(main):003:0> YAML.load a
=> {"run"=>true}
irb(main):004:0> YAML.load(a, handlers => {'bool#yes' = identity})
SyntaxError: (irb):4: syntax error, unexpected '=', expecting =>
YAML.load(a, handlers => {'bool#yes' = identity})
^
from /usr/bin/irb:11:in `<main>
I want the yaml val is yes and i google find the handler will help.
But seems i do not use correct syntax.
I try to search related docs but fail.
The problems with the listed code are
that handlers isn't defined anywhere, you likely wanted :handlers
that identity isn't defined anywhere, maybe wanted :identity that
you are missing a > on your hash rocket (=>).
So to get this code to run it should (likely) look like
YAML.load("run: yes", :handlers => {'bool#yes' => :identity})
However, so far as I know the second parameter to YAML.load is a filename.
If you are able to change the input YAML, simply quoting the value "yes" will cause it come through as a string
YAML.load("a: 'yes'")
# => {"a"=>"yes"}
If you require the un-quoted string 'yes' in the YAML to be treated as 'yes', not true in ruby after parsing. I cobbled this together (with help from this question), using Psych::Handler and Pysch::Parser. Though I'm not sure if there's another easier/better way to do this without having to hack this all together like this.
require 'yaml'
class MyHandler < Psych::Handlers::DocumentStream
def scalar(value, anchor, tag, plain, quoted, style)
if value == 'yes'
super(value, anchor, tag, plain, true, style)
else
super(value, anchor, tag, plain, quoted, style)
end
end
end
def my_parse(yaml)
parser = Psych::Parser.new(MyHandler.new{|node| return node})
parser.parse yaml
false
end
my_parse("a: yes").to_ruby
# => {"a"=>"yes"}
my_parse("a: 'yes'").to_ruby
# => {"a"=>"yes"}
my_parse("a: no").to_ruby
# => {"a"=>false}
Sidenote in the console (and the source):
YAML
# => Psych

In which version of ruby appeared ':' instead '=>'?

I mean
some: true
vs
:some => true
I have problem with compatibility my Rails version and Ruby version and I have to know in which version appeared only : instead =>.
I don't know how to find this kind of info by Google.
This is a feature introduced into Ruby 1.9:
{ example: 'key' }
# => { :example => 'key' }
This is similar to how JavaScript and other languages define their dictionary-type structures. The keys generated this way are always Symbol-type.
It's also possible to mix and match:
variable = :foo
{ example: 'key', 'string' => 'stored', variable => 'thing' }
# => {:example=>"key", "string"=>"stored", :foo=>"thing"}
This is a good thing because the x: approach is more limited. If you want dots in your keys, for example, you'll need to use the older style.

How can I find entries that match a certain array of values with the mongo ruby driver

I know I can find entries in mongodb that match a certain array of values natively via this command:
db.vendors.find({"somearray.property": { $in: ["value1","value2"]}})
But how can I do this with the ruby driver 'mongo' gem?
col.find("somearray.property" => ["value1","value2"])
Regards
You can do it like this:
col.find("somearray.property" => { '$in' => ["value1","value2"] })
Not sure to understand what you mean by the "ruby driver" but if you are using mongoid (which I recommend when dealing with mongodb) you can do
col.where(:'somearray.property'.in => ["val1", "val2"])
More informations here

Annotating Ruby structures to include anchors/references on #to_yaml

I have some large hashes (>10⁵ keys) with interlocking structures. They're stored on disk as YAML. I'd like to avoid duplication by using anchors and references in the YAML, but I haven't been able to figure out if there's a way to do it implicitly in the hash such that the #to_yaml method will label the anchor nodes properly.
Desired YAML:
---
parent1:
common-element-1: &CE1
complex-structure-goes: here
parent2:
uncomment-element-1:
blah: blah
<<: *CE1
Ruby code:
hsh = {
'parent1' => {
'common-element-1' => {
'complex-structure-goes' => 'here',
},
'parent2' => {
'uncommon-element-1' => {
'blah' => 'blah',
},
'<<' => '*CE1',
},
}
The reference is quite straightforward -- but how to embed the &CE1 anchor in the 'common-element-1' item in the Ruby hash?
I want to work as much as possible with native Ruby primitive types (like Hash) rather than mucking about with builders and emitters and such -- and I definitely don't want to write the YAML manually!
I've looked at Read and write YAML files without destroying anchors and aliases? and its relative, among other places, but haven't found an answer yet -- at least not that I've understood.
Thanks!
If you use the same Ruby object, the YAML library will set up references for you:
> common = {"ohai" => "I am common"}
> doc = {"parent1" => {"id" => 1, "stuff" => common}, "parent2" => {"id" => 2, "stuff" => common}}
> puts doc.to_yaml
---
parent1:
id: 1
stuff: &70133422893680
ohai: I am common
parent2:
id: 2
stuff: *70133422893680
I'm not sure there's a straightforward way of defining Hashes that are subsets of each other, though. Perhaps tweaking your structure a bit would be warranted?

Exact opposite to Ruby's CGI.parse method?

I'd like to do some sanitization of query params.
I parse the query with CGI.parse, then I delete some params, but I can't find an opposite method to build the query.
I don't really want to do something like
params.map{|n,v| "#{CGI.escape n}=#{CGI.escape v.to_s}"}.join("&")
There's got to be a simpler way. Is there?
There is a nice method in URI module:
require 'uri'
URI.encode_www_form("q" => "ruby", "lang" => "en") #=> "q=ruby&lang=en"
If you're using Rails (or don't mind pulling in ActiveSupport), then you can use to_param (AKA to_query):
{ :a => '&', :b => 'Where is pancake house?', :c => ['an', 'array'] }.to_param
# a=%26&b=Where+is+pancake+house%3F&c%5B%5D=an&c%5B%5D=array
to_param handles arrays a little differently than your version though, it'll put out c[]=an&c[]=array rather than just c=an&c=array.
While there's no better answer, I'll put up the method which I'm using now.
def build_query(params)
params.map do |name,values|
values.map do |value|
"#{CGI.escape name}=#{CGI.escape value}"
end
end.flatten.join("&")
end
I am not sure if the following is a simplification, but it avoids expanding the (key, value) pairs of a hash.
params.map{|qq| qq.map{|q| CGI.escape(q)}.join('=')}.join('&')

Resources