trouble assigning value to nested hash - ruby

I have a nested hash I want to assign a value to, but ruby keeps complaining about it.
the hash:
data = {
name: contact.xpath('./span[1]').text.delete("\r\n").strip,
email: contact.xpath('./a').text,
offices: [
postal: contact.text.split("\r\n")[4].strip,
tel: /(\d{3}[-\.\s]??\d{3}[-\.\s]??\d{4}|\(\d{3}\)\s*\d{3}[-\.\s]??\d{4}|\d{3}[-\.\s]??\d{4})/.match(contact).to_s
],
url: url
}
my assignment
data[:offices][:postal] = ""
error:
Line 42 - data[:offices][:postal] = "" -- in `[]='
#<TypeError: can't convert Symbol into Integer>
I've tried a handful of other syntaxes, but to no avail. Any help is appreciated :)

offices: [
postal: contact.text.split("\r\n")[4].strip,
tel: /(\d{3}[-\.\s]??\d{3}[-\.\s]??\d{4}|\(\d{3}\)\s*\d{3}[-\.\s]??\d{4}|\d{3}[-\.\s]??\d{4})/.match(contact).to_s
],
That is not a nested hash. Use curly braces:
offices: {
postal: contact.text.split("\r\n")[4].strip,
tel: /(\d{3}[-\.\s]??\d{3}[-\.\s]??\d{4}|\(\d{3}\)\s*\d{3}[-\.\s]??\d{4}|\d{3}[-\.\s]??\d{4})/.match(contact).to_s
},

Related

Convert and translate a Ruby hash into a human-readable string

I have the following Ruby hash:
{"limit"=>250, "days_ago"=>14, "days_ago_filter"=>"lt", "key"=>3}
I'd like to convert it to a human-readable string and translate some of the values as necessary:
Limit: 250 - Days Ago: 14 - Days Ago Filter: Less than - Key: D♯, E♭,
So lt, in this case, actually translates to Less than. and 3 for key translates to D♯, E♭.
I'm almost there with this:
variables.map {|k,v| "#{k.split('_').map(&:capitalize).join(' ')}: #{v}"}.join(' - ')
But translating those values is where I'm hitting a snag.
I'd suggest using hashes for mapping out the possible values, e.g.:
days_ago_filter_map = {
"lt" => "Less than",
# ...other cases here...
}
musical_key_map = {
3 => "D♯, E♭",
# ...other cases here...
}
Then you can switch on the key:
variables.map do |key, value|
label = "#{key.split('_').map(&:capitalize).join(' ')}"
formatted_value = case key
when "days_ago_filter" then days_ago_filter_map.fetch(value)
when "key" then musical_key_map.fetch(value)
else value
end
"#{label}: #{formatted_value}"
end.join(' - ')
Note that if you're missing anything in your maps, the above code will raise KeyNotFound errors. You can set a default in your fetch, e.g.
days_ago_filter_map.fetch(value, "Unknown filter")
musical_key_map.fetch(value, "No notes found for that key")
You can create YAML files too for such kind of mappings :
values_for_replacement = {
"lt" => "Less than",
3 => "D♯, E♭"
}
you can try following :
variables.map {|k,v|
value_to_be_replaced = values_for_replacement[v]
"#{k.humanize}: #{(value_to_be_replaced.present? ? value_to_be_replaced : v)}"}.join(' - ')

How do I search within a nested hash for the value of a specific key?

Say I have a hash like this:
[82] pry(main)> commit2
=> {:sha=>"4df2b779ddfcb27761c71e00e2b241bfa06a0950",
:commit=>
{:author=>
{:name=>"asasa asasa",
:email=>"asa#asasad.com",
:date=>2016-08-06 16:24:04 UTC,
:sha=> "876239789879ab9876c8769287698769876fed"},
:committer=>
{:name=>"asasa asasa",
:email=>"asa#asasad.com",
:date=>2016-08-06 16:26:45 UTC},
:message=>
"applies new string literal convention in activerecord/lib\n\nThe current code base is not uniform. After some discussion,\nwe have chosen to go with double quotes by default.",
:tree=>
{:sha=>"7a83cce62195f7b20afea6d6a8873b953d25cb84",
:url=>
"https://api.github.com/repos/rails/rails/git/trees/7a83cce62195f7b20afea6d6a8873b953d25cb84"},
:url=>
"https://api.github.com/repos/rails/rails/git/commits/4df2b779ddfcb27761c71e00e2b241bfa06a0950",
:comment_count=>0},
:url=>
"https://api.github.com/repos/rails/rails/commits/4df2b779ddfcb27761c71e00e2b241bfa06a0950",
:html_url=>
"https://github.com/rails/rails/commit/4df2b779ddfcb27761c71e00e2b241bfa06a0950",
:comments_url=>
"https://api.github.com/repos/rails/rails/commits/4df2b779ddfcb27761c71e00e2b241bfa06a0950/comments"
}
}
}
This hash has many nested hashes, but I want to check to see if any of the nested hashes have a :sha value of 876239789879ab9876c8769287698769876fed.
In the above example, it should return the [:commit][:author] hash, because that one has :sha key whose value is the same as the one we are looking for.
How do I do this?
Here's a recursive method :
data = {a: {b: :c, d: :e}, f: {g: {h: {i: :j}}}}
def find_value_in_nested_hash(data, desired_value)
data.values.each do |value|
case value
when desired_value
return data
when Hash
f = find_value_in_nested_hash(value, desired_value)
return f if f
end
end
nil
end
p find_value_in_nested_hash(data, :e)
# {b=>:c, :d=>:e}
With your example :
repo = { sha: '4df2b779ddfcb27761c71e00e2b241bfa06a0950',
commit: { author: { name: 'asasa asasa',
email: 'asa#asasad.com',
date: '2016-08-06 16:24:04 UTC',
sha: '876239789879ab9876c8769287698769876fed' },
committer: { name: 'asasa asasa',
email: 'asa#asasad.com',
date: '2016-08-06 16:26:45 UTC' },
message: "applies new string literal convention in activerecord/lib\n\nThe current code base is not uniform. After some discussion,\nwe have chosen to go with double quotes by default.",
tree: { sha: '7a83cce62195f7b20afea6d6a8873b953d25cb84',
url: 'https://api.github.com/repos/rails/rails/git/trees/7a83cce62195f7b20afea6d6a8873b953d25cb84' },
url: 'https://api.github.com/repos/rails/rails/git/commits/4df2b779ddfcb27761c71e00e2b241bfa06a0950',
comment_count: 0 },
url: 'https://api.github.com/repos/rails/rails/commits/4df2b779ddfcb27761c71e00e2b241bfa06a0950',
html_url: 'https://github.com/rails/rails/commit/4df2b779ddfcb27761c71e00e2b241bfa06a0950',
comments_url: 'https://api.github.com/repos/rails/rails/commits/4df2b779ddfcb27761c71e00e2b241bfa06a0950/comments' }
p find_value_in_nested_hash(repo, '876239789879ab9876c8769287698769876fed')
#=> {:name=>"asasa asasa", :email=>"asa#asasad.com", :date=>"2016-08-06 16:24:04 UTC", :sha=>"876239789879ab9876c8769287698769876fed"}

How could I parse the XML into hash

I hope I can get the list of hashed like that.
Is there any gem can do me a favor ?
Expected result
[
{
"prog_name": "TAIWAN CTA Index",
"prog_id": 9
},
{
"prog_name": "CTO CTA Index",
"prog_id": 12
},
]
Original input file source.xml
<prog>
<prog_name>TAIWAN CTA Index</prog_name>
<prog_id>9</prog_id>
</prog>
<prog>
<prog_name>CTO CTA Index</prog_name>
<prog_id>12</prog_id>
</prog>
...
You should have a look at Nokogiri. Something like:
#doc = Nokogiri::XML(<IO thing here>)
#doc.xpath('prog').map do |prog_element|
{
'prog_name' => prog_element.xpath('prog_name').content,
'prog_id' => prog_element.xpath('prog_id').content
}
end
would do it for you.

How to I reference an array member in Ruby?

Given this array in Ruby:
myarray = [name: "John", age: 35]
How do I refer to the age?
I tried myarray[:age] but got an error can't convert Symbol into Integer
Update:
I was trying to simplify my question by extracting what I thought my problem is. I may not understand completely.
I'm experimenting with Dashing and trying to send a number to a meter widget. I've created a variable, 'response_raw' and am trying to send it in the third send event. Here's my code:
SCHEDULER.every '1m', :first_in => 0 do
# Get checks
url = "https://#{CGI::escape user}:#{CGI::escape password}#api.pingdom.com/api/2.0/checks"
`enter code here`response = RestClient.get(url, {"App-Key" => api_key})
response = JSON.parse(response.body, :symbolize_names => true)
if response[:checks]
checks = response[:checks].map { |check|
if check[:status] == 'up'
state = 'up'
last_response_time = "#{check[:lastresponsetime]}ms"
response_raw = check[:lastresponsetime]
else
state = 'down'
last_response_time = "DOWN"
response_raw = 0
end
{ name: check[:name], state: state, lastRepsonseTime: last_response_time, pt: response_raw }
}
else
checks = [name: "pingdom", state: "down", lastRepsonseTime: "-", pt: 0]
end
checks.sort_by { |check| check['name'] }
send_event('pingdom', { checks: checks })
send_event('pingdom-meter', { value: checks[:pt] })
end
In CoffeeScript [name: "John", age: 35] is an array containing single object with two properties (name and age).
Here is how it'll look in plain JavaScript:
myarray = [
{
name: "John",
age: 35
}
];
So, answering your question, to access an age you should take the first element of an array and then reference an age property:
myarray[0].age
or
myarray[0]['age']
But, judging from your question, your're probably using wrong data structure. Why don't you want to use a plain object instead of an array?
person = name: "John", age: 35
console.log "#{person.name}'s age is #{person.age}"
Update
It looks like your question is actually about Ruby and not about CoffeeScript. Though, my answer will remain the same.
To access an age you should take the first element of an array and then reference an age property:
myarray[0][:age]
Since myarray is an array, Ruby expects an integer index, but you're giving it symbol :age instead.
I finally figured it out with Leonid's help. Thank you.
I changed:
send_event('pingdom-meter', { value: checks[:pt] })
to
send_event('pingdom-meter', { value: checks[0][:pt] })

Issue in parsing Json response in ruby

#response = Typhoeus::Request.get(FOUR_SQUARE_API_SERVER_ADDRESS+'search?ll=' + current_user.altitude.to_s + "&query="+ params[:query] + FOUR_SQUARE_API_ACESS_CODE)
#venues = ActiveSupport::JSON.decode(#response.body)
#venues['response']['groups'][0]['items'].each do |venue|
venue['name'] //working
venue['name']['location'][0]['address'] //issues
venue['name']['categories'][0]['id'] //issues
end
Please check inline comments for issues.
First of all, the venue['name'] is a scalar, not an array; secondly, venue['location'] (which I think you're trying to access) is not encoded as an array, that's just an object:
location: {
address: "...',
city: "...",
// ...
}
So here you want:
venue['location']
Then, your venue['name']['categories'][0]['id'] will fail because, again, venue['name'] is a scalar; for this one, you want:
venue['categories'][0]['id']

Resources