i_trope
i_trope

Reputation: 1604

TypeError while adding key/value pair to hash during iteration

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

Answers (3)

ian
ian

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

tihom
tihom

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

sawa
sawa

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

Related Questions