Unable to use dot syntax for ruby hash
Hash
does not have dot-syntax for it's keys. OpenStruct
does:
require 'ostruct'
hash = {:name => 'John'}
os = OpenStruct.new(hash)
p os.name #=> "John"
NOTE: Does not work with nested hashes.
Access Ruby Hash Using Dotted Path Key String
Just split on a dot in the path and iterate over this to find the right hash?
path.split(".").inject(hash) { |hash, key| hash[key] }
Alternatively you can build a new hash by iterating recursively over the whole structure:
def convert_hash(hash, path = "")
hash.each_with_object({}) do |(k, v), ret|
key = path + k
if v.is_a? Hash
ret.merge! convert_hash(v, key + ".")
else
ret[key] = v
end
end
end
Ruby dot notation to nested hash keys
Try this
f = "root/sub-1/sub-2/file"
f.split("/").reverse.inject{|a,n| {n=>a}} #=>{"root"=>{"sub-1"=>{"sub-2"=>"file"}}}
hash['key'] to hash.key in Ruby
>> require 'ostruct'
=> []
>> foo = {'bar'=>'baz'}
=> {"bar"=>"baz"}
>> foo_obj = OpenStruct.new foo
=> #<OpenStruct bar="baz">
>> foo_obj.bar
=> "baz"
>>
Classic hash to dot-notation hash
Here's the cleanest solution I could come up with right now:
def dot_it(object, prefix = nil)
if object.is_a? Hash
object.map do |key, value|
if prefix
dot_it value, "#{prefix}.#{key}"
else
dot_it value, "#{key}"
end
end.reduce(&:merge)
else
{prefix => object}
end
end
Test:
input = {a: {b: {"1" => 1, "2" => 2}, d: "Something"}, b: {c: 1}}
p dot_it input
Output:
{"a.b.1"=>1, "a.b.2"=>2, "a.d"=>"Something", "b.c"=>1}
How to transform dot-notation string keys in a Hash into a nested Hash?
This code may need to be refactored but it works for the input you have given.
hash = {
:axis => [1,2],
"coord.x" => [12,13],
"coord.y" => [14,15],
}
new_hash = {}
hash.each do |key, val|
new_key, new_sub_key = key.to_s.split('.')
new_key = new_key.to_sym
unless new_sub_key.nil?
new_sub_key = new_sub_key.to_sym
new_hash[new_key] = {} if new_hash[new_key].nil?
new_hash[new_key].merge!({new_sub_key => val})
else
new_hash.store(key, val)
end
end
new_hash # => {:axis=>[1, 2], :coord=>{:x=>[12, 13], :y=>[14, 15]}}
What does &. (ampersand dot) mean in Ruby?
It is called the Safe Navigation Operator. Introduced in Ruby 2.3.0, it lets you call methods on objects without worrying that the object may be nil
(Avoiding an undefined method for nil:NilClass
error), similar to the try
method in Rails.
So you can write
@person&.spouse&.name
instead of
@person.spouse.name if @person && @person.spouse
From the Docs:
my_object.my_method
This sends the
my_method
message tomy_object
. Any
object can be a receiver but depending on the method's visibility
sending a message may raise aNoMethodError
.You may use
&.
to designate a receiver, thenmy_method
is not invoked
and the result isnil
when the receiver isnil
. In that case, the
arguments ofmy_method
are not evaluated.
How to make a chained dot notation work for nested hash keys using Ruby Metapraogramming
Your test doesn't work because conf.a2 returns a Hash (which doesn't respond to the message a3). I can't tell exactly what you're trying to accomplish, but it looks like you could make your tests pass by ensuring that whenever you return a value that would have been a Hash, that value becomes an instance of your Config class.
One thing that's odd, is you have defined attr_accessors for a flat list of names, but you're accessing the names in a structured way, not as the flat list you've defined.
If you want to access your configuration in a structured way, how about something like this? Trying not to depart too far from what you have:
class Config
def initialize(args)
if args.is_a? Hash
args.each do |k, v|
next if v.nil?
if v.is_a?(Hash)
instance_variable_set("@#{k}", Config.new(v))
else
instance_variable_set("@#{k}", v)
end
end
else
raise ArgumentError, "Invalid argument. Supply a Hash instead of #{args.class}"
end
end
def method_missing(name, *args)
if name.to_s.end_with?('=')
instance_variable_set("@#{name.to_s.sub(/=$/, '')}", *args)
else
instance_variable_get("@#{name}", *args)
end
end
end
Related Topics
Convert an Array of Integers into an Array of Strings in Ruby
Directory Layout for Pure Ruby Project
Rails 4 How to Ignore Pending Migrations
Multiple Sinatra Apps Using Rack-Mount
Active Admin - Refresh Second Drop Down Based on First Drop Down, Ruby on Rails
Heroku Wrongly Detecting My Node App as a Ruby App
Prepend a Single Line to File with Ruby
Rails Fixtures Not Loading with Rspec
Find() with Nil When There Are No Records
Finding the Session Id in Rails 3
How to Spawn a Child Process in Ruby
Install Any Version of Ruby with Rvm on Mavericks
Jekyll - Generating JSON Files Alongside the HTML Files
How to Wrap the Invocation of a Ruby Method by Including a Module