Reputation: 1604
I think I misunderstand hashes as concerns the code below:
require 'rest-client'
require 'json'
def get_from_mashable
res = JSON.load(RestClient.get('http://mashable.com/stories.json'))
res["hot"].map do |story|
s = {title: story["title"], category: story["channel"]}
add_upvotes(s)
end
end
def add_upvotes(hash)
hash.map do |story|
temp = {upvotes: 1}
if story[:category] == "Tech"
temp[:upvotes] *= 10
elsif story[:category] == "Business"
temp[:upvotes] *= 5
else
temp[:upvotes] *= 3
end
end
hash.each {|x| puts x}
end
get_from_mashable()
I get the following error from this:
ex_teddit_api_news.rb:16:in `[]': no implicit conversion of Symbol into Integer (TypeError)
I am trying to add an upvotes
key and corresponding integer value into each hash created from the JSON object in get_from_mashable
. In the loop, I am not trying to erase the content of each hash and replace it with only the new key/value pair, which I have a feeling I may be doing.
Any help is appreciated.
Upvotes: 0
Views: 141
Reputation: 12251
There are several problems with the code, but the one that's causing the error is that hash.map do |story|
is iterating over a single hash's keys and values one by one as if it were an array of [k,v,k,v…]
and then [some key]
is being called against story
, a string, and causing a type error (String#[index]
is what Ruby thinks you want to call, hence the complaints about not being able to convert a symbol to an integer).
The code's intent implies that an array holding hashes should be used and thus story
should be holding a hash. This can be seen more easily with some slight alterations to the code:
def get_from_mashable
#res = JSON.load(RestClient.get('http://mashable.com/stories.json'))
res = {"hot" => [{"title" => "abc", "channel" => "xyz"}]}
res["hot"].map do |story|
s = {title: story["title"], category: story["channel"]}
add_upvotes(s)
end
end
def add_upvotes(hash)
p hash
#<snip!>
Calling get_from_mashable
will result in {:title=>"abc", :category=>"xzy"}
being printed.
If we then output that via each
, we can see that map
is either the wrong choice of method (as it's using each
underneath), or the wrong type of object was chosen to be passed:
hash.each {|x| puts x }
# title
# abc
# category
# xzy
That means that hash.map do |story|
on its first loop has "title"
in the story
variable, so calls like story[:category]
will fail with an error.
With some small changes, the code should do what it appears to need to:
def add_upvotes(story)
story[:upvotes] = 1
# No need for the map
if story[:category] == "Tech"
story[:upvotes] *= 10
elsif story[:category] == "Business"
story[:upvotes] *= 5
else
story[:upvotes] *= 3
end
story
end
def get_from_mashable
#res = JSON.load(RestClient.get('http://mashable.com/stories.json'))
# Stand in for the network call
res = {"hot" => [
{"title" => "techie stuff", "channel" => "Tech"},
{"title" => "biznass", "channel" => "Business"},
{"title" => "something else", "channel" => "xyz"},
]}
stories = res["hot"].map do |story|
s = {title: story["title"], category: story["channel"]}
add_upvotes(s)
end
stories
end
get_from_mashable()
Which outputs:
[
{:title=>"techie stuff", :category=>"Tech", :upvotes=>10},
{:title=>"biznass", :category=>"Business", :upvotes=>5},
{:title=>"something else", :category=>"xyz", :upvotes=>3}
]
Far more useful.
Upvotes: 0
Reputation: 8003
This returns an array of hash, where each hash has the keys title, category and upvotes.
require 'rest-client'
require 'json'
def get_from_mashable
res = JSON.load(RestClient.get('http://mashable.com/stories.json'))
res["hot"].map do |story|
s = {title: story["title"], category: story["channel"], upvotes: get_upvotes(story["channel"]) }
end
end
def get_upvotes(category)
case category
when "Tech"
10
when "Business"
5
else
3
end
end
get_from_mashable()
Upvotes: 1
Reputation: 168091
Since you have not provided sufficient information, we can only guess, but most likely, story
is an array, not a hash.
Upvotes: 1