Permalink
Browse files

Merge branch 'master' of github.com:rubymotion/BubbleWrap

  • Loading branch information...
clayallsopp committed Aug 16, 2012
2 parents 58775e7 + 958f7c9 commit 0cc62e8b600d2ee82fb63ab5d653d2f1f7ffe4c4
View
@@ -10,7 +10,7 @@ require 'bubble-wrap/test'
Motion::Project::App.setup do |app|
app.name = 'testSuite'
app.identifier = 'io.bubblewrap.testSuite'
- app.specs_dir = './spec/motion/'
+ app.specs_dir = './spec/motion'
end
namespace :spec do
View
@@ -1,3 +1,4 @@
require 'bubble-wrap/loader'
BubbleWrap.require('motion/core/ns_url_request.rb')
+BubbleWrap.require('motion/core.rb')
BubbleWrap.require('motion/http.rb')
@@ -3,8 +3,10 @@ class NSURLRequest
# Provides a to_s method so we can use inspect in instances and get
# valuable information.
def to_s
- "#<#{self.class}:#{self.object_id} - url: #{self.URL.description}, cache policy: #{self.cachePolicy}, Pipelining: #{self.HTTPShouldUsePipelining}, main doc url: #{mainDocumentURL},\
- timeout: #{self.timeoutInterval}, network service type: #{self.networkServiceType} >"
+ "#<#{self.class}:#{self.object_id} - url: #{self.URL.description},
+ headers: #{self.allHTTPHeaderFields.inspect},
+ cache policy: #{self.cachePolicy}, Pipelining: #{self.HTTPShouldUsePipelining}, main doc url: #{mainDocumentURL},\
+ timeout: #{self.timeoutInterval}, network service type: #{self.networkServiceType} >"
end
end
@@ -13,7 +13,13 @@ def []=(key, value)
end
def [](key)
- storage.objectForKey storage_key(key)
+ value = storage.objectForKey storage_key(key)
+
+ # RubyMotion currently has a bug where the strings returned from
+ # standardUserDefaults are missing some methods (e.g. to_data).
+ # And because the returned object is slightly different than a normal
+ # String, we can't just use `value.is_a?(String)`
+ value.class.to_s == 'String' ? value.dup : value
end
def merge(values)
View
@@ -19,38 +19,37 @@ module HTTP
# end
#
def self.get(url, options={}, &block)
- options[:action] = block if block_given?
- HTTP::Query.new(url, :get, options)
+ create_query(url, :get, options, block)
end
# Make a POST request
def self.post(url, options={}, &block)
- options[:action] = block if block_given?
- HTTP::Query.new(url, :post, options)
+ create_query(url, :post, options, block)
end
# Make a PUT request
def self.put(url, options={}, &block)
- options[:action] = block if block_given?
- HTTP::Query.new(url, :put, options)
+ create_query(url, :put, options, block)
end
# Make a DELETE request
def self.delete(url, options={}, &block)
- options[:action] = block if block_given?
- HTTP::Query.new(url, :delete, options)
+ create_query(url, :delete, options, block)
end
# Make a HEAD request
def self.head(url, options={}, &block)
- options[:action] = block if block_given?
- HTTP::Query.new(url, :head, options)
+ create_query(url, :head, options, block)
end
# Make a PATCH request
def self.patch(url, options={}, &block)
- options[:action] = block if block_given?
- HTTP::Query.new(url, :patch, options)
+ create_query(url, :patch, options, block)
+ end
+
+ def self.create_query(url, method, options, block)
+ options[:action] = block if block
+ HTTP::Query.new(url, method, options)
end
# Response class wrapping the results of a Query's response
@@ -95,7 +94,7 @@ class Query
attr_reader :response_headers
attr_reader :response_size
attr_reader :options
-
+ CLRF = "\r\n"
# ==== Parameters
# url<String>:: url of the resource to download
# http_method<Symbol>:: Value representing the HTTP method to use
@@ -157,15 +156,18 @@ def connection(connection, didReceiveData:received_data)
end
def connection(connection, willSendRequest:request, redirectResponse:redirect_response)
- @redirection ||= 0
- @redirection += 1
- log "##{@redirection} HTTP redirection: #{request} - #{self.description}"
- new_request = request.mutableCopy
- # new_request.setValue(@credentials.inspect, forHTTPHeaderField:'Authorization') # disabled while we figure this one out
- new_request.setAllHTTPHeaderFields(@headers) if @headers
- @connection.cancel
- @connection = create_connection(new_request, self)
- new_request
+ @redirect_count ||= 0
+ @redirect_count += 1
+ log "##{@redirect_count} HTTP redirect_count: #{request.inspect} - #{self.description}"
+
+ if @redirect_count >= 30
+ @response.error_message = "Too many redirections"
+ @request.done_loading!
+ call_delegator_with_response
+ nil
+ else
+ request
+ end
end
def connection(connection, didFailWithError: error)
@@ -212,13 +214,38 @@ def create_request
cachePolicy:@cache_policy,
timeoutInterval:@timeout)
request.setHTTPMethod(@method)
+ set_content_type
request.setAllHTTPHeaderFields(@headers)
request.setHTTPBody(@body)
patch_nsurl_request(request)
request
end
+ def set_content_type
+ return if headers_provided?
+ return if (@method == "GET" || @method == "HEAD")
+ @headers ||= {}
+ @headers["Content-Type"] = case @format
+ when :json
+ "application/json"
+ when :xml
+ "application/xml"
+ when :text
+ "text/plain"
+ else
+ if @format == :form_data || @payload_or_files_were_appended
+ "multipart/form-data; boundary=#{@boundary}"
+ else
+ "application/x-www-form-urlencoded"
+ end
+ end
+ end
+
+ def headers_provided?
+ @headers && @headers.keys.find {|k| k.downcase == 'content-type'}
+ end
+
def create_request_body
return nil if (@method == "GET" || @method == "HEAD")
return nil unless (@payload || @files)
@@ -227,59 +254,35 @@ def create_request_body
append_payload(body) if @payload
append_files(body) if @files
- append_body_boundary(body) if @set_body_to_close_boundary
- set_content_type
+ append_body_boundary(body) if @payload_or_files_were_appended
log "Built HTTP body: \n #{body.to_str}"
body
end
- def set_content_type
- # if no headers provided, set content-type automatically
- if @headers.nil? || !@headers.keys.find {|k| k.downcase == 'content-type'}
- @headers ||= {}
- @headers["Content-Type"] = case @format
- when :json
- "application/json"
- when :xml
- "application/xml"
- when :text
- "text/plain"
- else
- if @format == :form_data || @set_body_to_close_boundary
- "multipart/form-data; boundary=#{@boundary}"
- else
- "application/x-www-form-urlencoded"
- end
- end
- end
- end
-
def append_payload(body)
if @payload.is_a?(NSData)
body.appendData(@payload)
+ elsif @payload.is_a?(String)
+ body.appendData(@payload.dataUsingEncoding NSUTF8StringEncoding)
else
append_form_params(body)
end
body
end
def append_form_params(body)
- if @payload.is_a?(String)
- body.appendData(@payload.dataUsingEncoding NSUTF8StringEncoding)
- else
- list = process_payload_hash(@payload)
- list.each do |key, value|
- form_data = NSMutableData.new
- s = "--#{@boundary}\r\n"
- s += "Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n"
- s += value.to_s
- s += "\r\n"
- form_data.appendData(s.dataUsingEncoding NSUTF8StringEncoding)
- body.appendData(form_data)
- end
- @set_body_to_close_boundary = true
+ list = process_payload_hash(@payload)
+ list.each do |key, value|
+ form_data = NSMutableData.new
+ s = "--#{@boundary}\r\n"
+ s += "Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n"
+ s += value.to_s
+ s += "\r\n"
+ form_data.appendData(s.dataUsingEncoding NSUTF8StringEncoding)
+ body.appendData(form_data)
end
+ @payload_or_files_were_appended = true
body
end
@@ -294,7 +297,7 @@ def append_files(body)
file_data.appendData("\r\n".dataUsingEncoding NSUTF8StringEncoding)
body.appendData(file_data)
end
- @set_body_to_close_boundary = true
+ @payload_or_files_were_appended = true
body
end
@@ -307,7 +310,16 @@ def create_url(url_string)
convert_payload_to_url if @payload.is_a?(Hash)
url_string += "?#{@payload}"
end
- NSURL.URLWithString(url_string.stringByAddingPercentEscapesUsingEncoding NSUTF8StringEncoding)
+ url = NSURL.URLWithString(url_string.stringByAddingPercentEscapesUsingEncoding NSUTF8StringEncoding)
+
+ validate_url(url)
+ url
+ end
+
+ def validate_url(url)
+ if !NSURLConnection.canHandleRequest(NSURLRequest.requestWithURL(url))
+ raise InvalidURLError, "Invalid URL provided (Make sure you include a valid URL scheme, e.g. http:// or similar)."
+ end
end
def convert_payload_to_url
@@ -344,14 +356,14 @@ def escape_line_feeds(hash)
return nil if hash.nil?
escaped_hash = {}
- hash.each{|k,v| escaped_hash[k] = v.gsub("\n", '\\n') }
+ hash.each{|k,v| escaped_hash[k] = v.gsub("\n", CLRF) }
escaped_hash
end
def patch_nsurl_request(request)
request.instance_variable_set("@done_loading", false)
- def request.done_loading; @done_loading; end
+ def request.done_loading?; @done_loading; end
def request.done_loading!; @done_loading = true; end
end
@@ -369,3 +381,5 @@ def create_connection(request, delegate)
end
end
end
+
+class InvalidURLError < StandardError; end
@@ -117,8 +117,8 @@ def locationManager(manager, didFailWithError:error)
if @retries > @options[:retries]
error(Error::LOCATION_UNKNOWN)
else
- self.locationManager.stopUpdatingLocation
- self.locationManager.startUpdatingLocation
+ self.location_manager.stopUpdatingLocation
+ self.location_manager.startUpdatingLocation
end
when KCLErrorNetwork
error(Error::NETWORK_FAILURE)
@@ -0,0 +1,5 @@
+.repl_history
+build
+resources/*.nib
+resources/*.momd
+resources/*.storyboardc
View
@@ -0,0 +1,3 @@
+source :rubygems
+
+gem 'bubble-wrap', '~> 1.1.0'
@@ -0,0 +1,4 @@
+## Location Demo
+
+A bubble-wrap demo to show how to use location API.
+
View
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+$:.unshift("/Library/RubyMotion/lib")
+require 'motion/project'
+require 'bubble-wrap/location'
+require 'bubble-wrap/http'
+require 'bubble-wrap/core'
+
+Motion::Project::App.setup do |app|
+ app.name = 'location'
+end
@@ -0,0 +1,8 @@
+class AppDelegate
+ def application(application, didFinishLaunchingWithOptions:launchOptions)
+ @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
+ places_list_controller = PlacesListController.alloc.init
+ @window.rootViewController = places_list_controller
+ @window.makeKeyAndVisible
+ end
+end
@@ -0,0 +1,30 @@
+class PlacesListController < UITableViewController
+ attr_accessor :places_list
+
+ def viewDidLoad
+ @places_list = []
+ Places.load(self)
+ view.dataSource = view.delegate = self
+ end
+
+ def viewWillAppear(animated)
+ view.reloadData
+ end
+
+ def tableView(tableView, numberOfRowsInSection:section)
+ @places_list.size
+ end
+
+ def reloadData
+ view.reloadData
+ end
+
+ CellID = 'CellIdentifier'
+ def tableView(tableView, cellForRowAtIndexPath:indexPath)
+ cell = tableView.dequeueReusableCellWithIdentifier(CellID) || UITableViewCell.alloc.initWithStyle(UITableViewCellStyleSubtitle, reuseIdentifier:CellID)
+ placeItem= @places_list[indexPath.row]
+ cell.textLabel.text = placeItem
+ cell
+ end
+
+end
@@ -0,0 +1,15 @@
+class Places
+ API_KEY = ""
+ #See google places documentation at https://developers.google.com/places/documentation/ to obtain a key
+
+ def self.load(places_list_controller)
+ BW::Location.get do |result|
+ BW::Location.stop
+ BubbleWrap::HTTP.get("https://maps.googleapis.com/maps/api/place/search/json?location=#{result[:to].latitude},#{result[:to].longitude}&radius=500&sensor=false&key=#{API_KEY}") do |response|
+ names = BW::JSON.parse(response.body.to_str)["results"].map{|r| r["name"]}
+ places_list_controller.places_list = names
+ places_list_controller.reloadData
+ end
+ end
+ end
+end
@@ -0,0 +1,9 @@
+describe "Application 'google_location'" do
+ before do
+ @app = UIApplication.sharedApplication
+ end
+
+ it "has one window" do
+ @app.windows.size.should == 1
+ end
+end
Oops, something went wrong.

0 comments on commit 0cc62e8

Please sign in to comment.