Question

I am trying to map an enumerator coming the the Twitter API. I can successfully map the entire enumerable using test.map(&:attrs) and I can map specific fields however when I try to map the id_str field I get a undefined method error. I can't figure out if my syntax is off or if there are other considerations.

Below is my sample code and output:

print "original output\n"
print test.map(&:attrs)

print "\n\nmap a few fields\n"
print test.map { |e| {  id: e.id, 
                        name: e.name, 
                        screen_name: e.screen_name
                      }}
print "\n\nid_str seems to return a undefined method\n"                    
print test.map { |e| {  id: e.id, 
                        id_str: e.id_str,
                        name: e.name, 
                        screen_name: e.screen_name
                      }}

Generates the following output:

original output
[{:id=>78194111, :id_str=>"78194111", :name=>"Chelsea Peretti", :screen_name=>"ChelseaVPeretti", :location=>"Los Angeles", :description=>"One of the greats!", :url=>"http://t.co/3rRz8qGpeW", :entities=>{:url=>{:urls=>[{:url=>"http://t.co/3rRz8qGpeW", :expanded_url=>"http://www.chelseaperetti.com", :
display_url=>"chelseaperetti.com", :indices=>[0, 22]}]}, :description=>{:urls=>[]}}, :protected=>false, :followers_count=>249943, :friends_count=>740, :listed_count=>4277, :created_at=>"Tue Sep 29 02:35:35 +0000 2009", :favourites_count=>33016, :utc_offset=>-28800, :time_zone=>"Pacific Time (US & Ca
nada)", :geo_enabled=>true, :verified=>true, :statuses_count=>14958, :lang=>"en", :status=>{:created_at=>"Mon Dec 09 00:40:48 +0000 2013", :id=>409845047744409600, :id_str=>"409845047744409600", :text=>"Really looking forward to spending half my life in an apple store", :source=>"<a href=\"http://tw
itter.com/download/iphone\" rel=\"nofollow\">Twitter for iPhone</a>", :truncated=>false, :in_reply_to_status_id=>nil, :in_reply_to_status_id_str=>nil, :in_reply_to_user_id=>nil, :in_reply_to_user_id_str=>nil, :in_reply_to_screen_name=>nil, :geo=>nil, :coordinates=>nil, :place=>nil, :contributors=>ni
l, :retweet_count=>13, :favorite_count=>77, :entities=>{:hashtags=>[], :symbols=>[], :urls=>[], :user_mentions=>[]}, :favorited=>false, :retweeted=>false, :lang=>"en"}, :contributors_enabled=>false, :is_translator=>false, :profile_background_color=>"022330", :profile_background_image_url=>"http://a0
.twimg.com/profile_background_images/777102099/405580aee5a6a6d3f4d608b5bc488149.jpeg", :profile_background_image_url_https=>"https://si0.twimg.com/profile_background_images/777102099/405580aee5a6a6d3f4d608b5bc488149.jpeg", :profile_background_tile=>true, :profile_image_url=>"http://pbs.twimg.com/pro
file_images/378800000812827132/fe8566998e61c0f3e1275af4953a22e9_normal.jpeg", :profile_image_url_https=>"https://pbs.twimg.com/profile_images/378800000812827132/fe8566998e61c0f3e1275af4953a22e9_normal.jpeg", :profile_banner_url=>"https://pbs.twimg.com/profile_banners/78194111/1382904580", :profile_l
ink_color=>"0084B4", :profile_sidebar_border_color=>"FFFFFF", :profile_sidebar_fill_color=>"C0DFEC", :profile_text_color=>"333333", :profile_use_background_image=>true, :default_profile=>false, :default_profile_image=>false, :following=>false, :follow_request_sent=>false, :notifications=>false}]

map a few fields
[{:id=>78194111, :name=>"Chelsea Peretti", :screen_name=>"ChelseaVPeretti"}]

id_str seems to return a undefined method
C:/RailsInstaller/AppCode/first attempt at graph.rb:142:in `block in <main>': undefined method `id_str' for #<Twitter::User:0x2b602f0> (NoMethodError)
        from C:/RailsInstaller/AppCode/first attempt at graph.rb:141:in `map'
        from C:/RailsInstaller/AppCode/first attempt at graph.rb:141:in `<main>'
Was it helpful?

Solution

Pretty new to playing with the Twitter API in Ruby myself, but it turns out that id_str isn't a method on the Ruby Twitter::User objects you're trying to enumerate over. Running a quick check on a particular one, say, test.first.methods will confirm this.

This means you can't access id_str with dot notation. It is however a key to the hashes returned by test.map(&:attrs) so you could amend your above code by doing this:

print test.map { |e| { id: e.attrs[:id],
                       id_str: e.attrs[:id_str],
                       name: e.attrs[:name],
                       screen_name: e.attrs[:screen_name]
               }}

If you are dead set on using dot notation, you could easily convert each hash object into an OpenStruct like this:

friends = test.map { |f| OpenStruct.new(f.attrs) }

Then you could simply do friends.map(&:id_str).

I think the confusion lies in your sample code above. In the first line, your output is an array of hashes. But what you are mapping over is an array of Twitter::User objects. The former has id_str as a key, but the latter does not have such a method.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top