Get Value From Hash Based on String - ruby

I have a hash looks like :
response = {
data: {
target_file: "file.jpg"
}
}
and have a string "data.target_file"
What I want is how can I access target_file value based on that string, like accessing with response[:data][:target_file]
how can I convert as dinamically from string "data.target_file" to response[:data][:target_file]
so I don't want use something like response["#{string.split('.')[0]}".to_sym]["#{string.split('.')[1]}".to_sym]

You can use split like you've shown to convert the keys into a string array, then map the strings into symbols and finally dig the hash whilst extracting the array elements as arguments with the splat operator *:
response.dig(*"data.target_file".split(".").map(&:to_sym))
If you see yourself repeating this code, you can extend the Hash class and add a method that does it:
class Hash
def dot(path)
self.dig(*path.split(".").map(&:to_sym))
end
end
Then you would simply use:
response.dot("data.target_file")

Related

Format array of date_time in hash during hash to json conversion

so I have a class whose hash representation looks like this.
{"dateTime"=>[1484719381, 1484719381], "dateTime1"=>[1484719381, 1484719381]}
The dateTime here is is a unix formatted dateTime array.
I am trying to convert this hash to an equivalent of json_string for which I am using hash.to_json. Is there any way through which I can modify the format of date_time when calling to_json. The resulting json should look like this
'{"dateTime1":["2017-01-18T06:03:01+00:00","2017-01-18T06:03:01+00:00"]}'
Basically I am looking for an implementation that can be called during hash.to_json.
You cannot make this part of Hash#to_json without damaging that method dramatically because:
You would need to manipulate the #to_json for multiple other classes
Those are Integers which is valid JSON and changing this would be awful
That is not the string representation of a Time object in Ruby so you need to string format it anyway
Instead you would have to modify the Hash values to represent in the desired fashion e.g.
h= {"dateTime"=>[1484719381, 14848723546], "dateTime1"=>[1484234567, 1484719381]}
h.transform_values do |v|
v.map do |int|
Time.at(int, in: '+00:00').strftime("%Y-%m-%dT%H:%M:%S%z")
end
end
#=> {"dateTime"=>[
# "2017-01-18T06:03:01+0000",
# "2440-07-15T05:25:46+0000"],
# "dateTime1"=>[
# "2017-01-12T15:22:47+0000",
# "2017-01-18T06:03:01+0000"]}
You could then call to_json on the resulting object to get your desired result.

Is there a method to get the value of key in ruby and store it in a variable

I am trying to get the value of a key and trying to store it in an array
Below is the sample code,
require 'rubygems'
require 'json'
opt=[]
response_assigned = {
"poll_id": 1194
}
opt << [JSON.parse(response_assigned)['poll_id']]
By using ruby, I have tried to convert poll_id variable into string,
opt << [JSON.parse(response_assigned)['poll_id'].to_s,channel_id]
but it is throwing same error.
'convert_encoding': {:poll_id=>1194} is not like a string (TypeError)
response_assigned is already a Hash. You can access the values via :[]; there's no need to use JSON.parse here. (This method is used for converting JSON strings into hashes, like the object you already have!)
Also, a more subtle note: There are two distinct types of object in ruby: String and Symbol.
By defining your object like this: {"poll_id": 1194}, you have made the hash key a symbol. It's equivalent to writing this: {poll_id: 1194}, or this: {:poll_id => 1194}.
Therefore, in order to access the value, you can use:
opt << response_assigned[:poll_id]
If you want to make the hash key a String instead of a Symbol, you could write:
response_assigned = {
"poll_id" => 1194
}
opt << response_assigned["poll_id"]

How to select keys from hash and strip parts of the keyname with ruby

I have a config hash in my ruby project and I want to pick certain keys with their value to have them as a separate hash.
Project.config.to_h.select{ |k,v| k[/db_/] }
=> {:db_name => value, .... }
This returns me nicely all the k,v that I need. But I also want to strip the db_ from the keynames so that it returns me
=> {:name => value, ....}
I tried something like
Project.config.to_h.select{ |k,v| k[/db_/] }.each_key { |k| k.to_s.gsub(/db_/) }
But it returns the same hash like the above example. Any idea or suggestions to get this as a smooth one or two liner?
inject to the rescue (assuming the db_ is in the beginning):
Project.config.to_h.inject({}) do | a, (k, v) |
k =~ /\Adb_/ ? a.update($' => v) : a
end
inject can be used to iterate through an enumerable data structure and build any kind of output in the course.
$' is a magic variable containing the portion of the string after a successful regexp match.
So let's break down your solution and see what's wrong with it:
Project.config.to_h.select{ |k,v| k[/db_/] }.each_key { |k| k.to_s.gsub(/db_/) }
So:
k.to_s.gsub(/db_/)
is creating a new object (and not mutating the keys like you would expect), in this case an enumerator, when you don't pass gsub a second argument it returns an enumerator, so let's assume you did:
k.to_s.gsub(/db_/, "")
This would be creating new objects and not mutating the keys in the hash(to_s would create a new string object, and gsub doesn't mutate, instead creates a new object, gsub! is the mutant version)
Now let's assume the keys were strings and you could even mutate them (with gsub!), ruby would not let you mutate them in place, else ruby hash would be broken, when a string is used as a key it is frozen, see http://ruby-doc.org/core-2.2.2/Hash.html#5B-5D-3D-method
key should not have its value changed while it is in use as a key (an unfrozen String passed as a key will be duplicated and frozen).
So with this knowledge how would I implement this:
Project.config.to_h.each_with_object({}) do |(k,v), hsh|
next unless k[/db_/] # skip every key that doesn't match the regex (if you want the keys to not have part of them stripped then you can use an if/else along with the next line)
hsh[k.to_s.sub(/db_/, "")] = v
end

Store functions in hash

I know that in Ruby you can create hash maps like this:
hash = {"name"=>"John"}
But is it possible to have a hash map of methods:
hash = {"v"=> show_version}
and when calling hash["v"] either to execute the show_version function, or to return some kind on pointer that passed to some special method, to execute the function from the hash?
What I am trying to achieve, is to have a hash map of methods, instead of using a case/when construction, as it looks too verbose to me.
Not exactly like this, no. You need to get a hold of the Method proxy object for the method and store that in the Hash:
hash = { 'v' => method(:show_version) }
And you need to call the Method object:
hash['v'].()
Method duck-types Proc, so you could even store simple Procs alongside Methods in the Hash and there would be no need to distinguish between them, because both of them are called the same way:
hash['h'] = -> { puts 'Hello' }
hash['h'].()
# Hello

A string (thats looks like an array) into an array Ruby

I have an output from an API that look like this... (its a string)
[[2121212,212121,asd],[2323232,23232323,qasdasd]]
Its a string - not an array. I want to convert it to an array and then extract the first two elements in each array in the nested array to:
[2121212,212121],[2323232,23232323]
What's the best way to do this ruby? I could use regexp and extract - but basically the string is already an array, however the class is a string.
I tried
array.push(response)
but that just put the string in to the array as one element. I guess what would be nice is a to_array method
You will need to use regular expression anyway if not eval (shrudder...), this is the shortest one
str = "[[2121212,212121,asd],[2323232,23232323,qasdasd],[2424242,24242424,qasdasd]]"
p str.scan(/(\d+),(\d+)/)
=>[["2121212", "212121"], ["2323232", "23232323"], ["2424242", "24242424"]]
Assuming this is a JSON response (and if so, it is badly malformed and you should talk to the people that are responsible for this) you could write something like:
require 'json'
input= '[[2121212,212121,Asd],[2323232,23232323,qasdasd]]'
input.gsub!(/([A-Za-z ]+)/,'"\1"')
json = JSON.parse input
output = json.map{|x| x[0...2]}
p output
this prints
[[2121212, 212121], [2323232, 23232323]]
Using eval is very bad but I have no other easy option.
test_str = "[[2121212,212121,asd],[2323232,23232323,qasdasd]]"
test_str.gsub!(/([a-z]+)/) do
"'#{$1}'"
end
=> "[[2121212,212121,'asd'],[2323232,23232323,'qasdasd']]"
test_array = eval(test_str)
=> [[2121212, 212121, "asd"], [2323232, 23232323, "qasdasd"]]
test_array.each do |element|
element.delete(element.last)
end
=> [[2121212, 212121], [2323232, 23232323]]

Resources