Search code examples
httptwitterrubymotion

Get HTTP response body as string (BubbleWrap for RubyMotion)


Using RubyMotion (for the first time!), I want to use Twitter's search API to retrieve some recent tweets for some users so have put together the class below.

The value of tweets is always an empty array. I suspect that BW::HTTP.get(url) spawns its own thread which is causing the issue.

Really, I just want twitter_search_results to return response.body.to_str but I am not sure how to do this.

How do I use RubyMotion (or BubbleWrap) to put an array of Tweet objects into my UIViewController?

class TweetsController
  def initialize
    @twitter_accounts = %w(dhh google)
    @tweets = []
  end

  def tweets
    twitter_search_results
    puts @tweets.count
    @tweets
  end

  def create_tweets(response)
    BW::JSON.parse(response)["results"].each do |result|
      @tweets << Tweet.new(result)
    end
  end

  def twitter_search_results
    query = @twitter_accounts.map{ |account| "from:#{account}" }.join(" OR ")
    url = "http://search.twitter.com/search.json?q=#{query}"
    BW::HTTP.get(url) do |response|
      create_tweets(response.body.to_str)
    end
  end
end

class TwitterViewController < UIViewController
  def viewDidLoad
    super
    self.view.backgroundColor = UIColor.blueColor
    @table = UITableView.alloc.initWithFrame(self.view.bounds)
    self.view.addSubview @table
    @table.dataSource = self
    @tweets_controller = TweetsController.new
  end

  def initWithNibName(name, bundle: bundle)
    super
    self.tabBarItem = UITabBarItem.alloc.initWithTitle(
      "Twitter",
      image: UIImage.imageNamed('twitter.png'),
      tag: 1)
    self
  end

  def tableView(tableView, numberOfRowsInSection: section)
    @tweets_controller.tweets.length
  end

  def tableView(tableView, cellForRowAtIndexPath: indexPath)
    @reuse_id = "Tweet"
    cell = UITableViewCell.alloc.initWithStyle(UITableViewCellStyleDefault, reuseIdentifier:@reuse_id)
    cell.textLabel.text = @tweets_controller.tweets[indexPath.row].text
    return cell
  end
end

class Tweet
  attr_reader :created_at, :from_user, :text
  def initialize(tweet_result)
    @created_at = tweet_result["created_at"]
    @from_user = tweet_result["from_user"]
    @text = tweet_result["text"]
  end
end

Solution

  • Full controller code below. I've also put the project on GitHub

    class TweetsController
      def initialize
        @twitter_accounts = %w(dhh google)
        @tweets = []
        create_tweets
      end
    
      def tweets
        @tweets
      end
    
      def create_tweets
        json_data = twitter_search_results.dataUsingEncoding(NSUTF8StringEncoding)
        e = Pointer.new(:object)
        dict = NSJSONSerialization.JSONObjectWithData(json_data, options:0, error: e)
        dict["results"].each do |result|
          p result.class
          p result
          @tweets << Tweet.new(result)
        end
      end
    
      def twitter_search_results
        query = @twitter_accounts.map{ |account| "from:#{account}" }.join(" OR ")
        url_string = "http://search.twitter.com/search.json?q=#{query}"
        url_string_escaped = url_string.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
        url = NSURL.URLWithString(url_string_escaped)
        request = NSURLRequest.requestWithURL(url)
        response = nil
        error = nil
        data = NSURLConnection.sendSynchronousRequest(request, returningResponse: response, error: error)
        raise "BOOM!" unless (data.length > 0 && error.nil?)
        json = NSString.alloc.initWithData(data, encoding: NSUTF8StringEncoding)
      end
    end