bubble-wrap 0.4.0 → 1.0.0.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,50 +1,49 @@
1
1
  require File.expand_path('../../../../lib/bubble-wrap/requirement/path_manipulation', __FILE__)
2
2
 
3
3
  describe BubbleWrap::Requirement::PathManipulation do
4
-
5
- subject do
6
- o = Object.new
7
- o.extend BubbleWrap::Requirement::PathManipulation
8
- o
4
+
5
+ before do
6
+ @subject = Object.new
7
+ @subject.extend BubbleWrap::Requirement::PathManipulation
9
8
  end
10
9
 
11
10
  describe '#convert_caller_to_path' do
12
11
  it 'strips off from the second-to-last colon' do
13
- subject.convert_caller_to_path("/fake/:path:91:in `fake_method'").
12
+ @subject.convert_caller_to_path("/fake/:path:91:in `fake_method'").
14
13
  should == '/fake/:path'
15
14
  end
16
15
 
17
16
  it 'leaves plain old paths unmolested' do
18
- subject.convert_caller_to_path("/fake/path").
17
+ @subject.convert_caller_to_path("/fake/path").
19
18
  should == '/fake/path'
20
19
  end
21
20
  end
22
21
 
23
22
  describe '#convert_to_absolute_path' do
24
23
  it 'converts relative paths to absolute paths' do
25
- subject.convert_to_absolute_path('foo')[0].should == '/'
24
+ @subject.convert_to_absolute_path('foo')[0].should == '/'
26
25
  end
27
26
 
28
27
  it "doesn't modify absolute paths" do
29
- subject.convert_to_absolute_path('/foo').should == '/foo'
28
+ @subject.convert_to_absolute_path('/foo').should == '/foo'
30
29
  end
31
30
  end
32
31
 
33
32
  describe '#strip_up_to_last_lib' do
34
33
  it 'strips off from the last lib' do
35
- subject.strip_up_to_last_lib('/fake/lib/dir/lib/foo').
34
+ @subject.strip_up_to_last_lib('/fake/lib/dir/lib/foo').
36
35
  should == '/fake/lib/dir'
37
36
  end
38
37
 
39
38
  it "doesn't modify the path otherwise" do
40
- subject.strip_up_to_last_lib('/fake/path').
39
+ @subject.strip_up_to_last_lib('/fake/path').
41
40
  should == '/fake/path'
42
41
  end
43
42
  end
44
43
 
45
44
  describe "#convert_to_relative" do
46
45
  it 'strips off the root portion' do
47
- subject.convert_to_relative('/foo/bar/baz', '/foo').
46
+ @subject.convert_to_relative('/foo/bar/baz', '/foo').
48
47
  should == 'bar/baz'
49
48
  end
50
49
  end
@@ -3,68 +3,69 @@ require 'bubble-wrap'
3
3
 
4
4
  describe BubbleWrap::Requirement do
5
5
 
6
- subject{ BubbleWrap::Requirement }
6
+ before do
7
+ @subject = BubbleWrap::Requirement
8
+ end
7
9
 
8
10
  describe '.scan' do
9
11
  before do
10
- subject.paths = {}
12
+ @subject.paths = {}
13
+ @root_path = File.expand_path('../../../', __FILE__)
11
14
  end
12
15
 
13
- let(:root_path) { File.expand_path('../../../', __FILE__) }
14
-
15
16
  it 'asking for a not-yet-found file raises an exception' do
16
- proc do
17
- subject.find('foo')
18
- end.should raise_error
17
+ should.raise(Exception) do
18
+ @subject.find('foo')
19
+ end
19
20
  end
20
21
 
21
22
  it 'finds the specified file' do
22
- subject.scan(root_path, 'motion/core.rb')
23
- subject.paths.keys.first.should == 'motion/core.rb'
23
+ @subject.scan(@root_path, 'motion/core.rb')
24
+ @subject.paths.keys.first.should == 'motion/core.rb'
24
25
  end
25
26
 
26
27
  it 'finds multiple files according to spec' do
27
- subject.scan(root_path, 'motion/**/*.rb')
28
- subject.files.size.should > 1
28
+ @subject.scan(@root_path, 'motion/**/*.rb')
29
+ @subject.files.size.should > 1
29
30
  end
30
31
 
31
32
  it 'never depends on itself' do
32
- subject.scan(root_path, 'motion/core.rb') do
33
+ @subject.scan(@root_path, 'motion/core.rb') do
33
34
  file('motion/core.rb').depends_on 'motion/core.rb'
34
35
  end
35
- subject.file('motion/core.rb').file_dependencies.should == []
36
+ @subject.file('motion/core.rb').file_dependencies.should == []
36
37
  end
37
38
 
38
39
  it 'can depend on another file' do
39
- subject.scan(root_path, 'motion/*.rb') do
40
+ @subject.scan(@root_path, 'motion/*.rb') do
40
41
  file('motion/http.rb').depends_on('motion/core.rb')
41
42
  end
42
- subject.file('motion/http.rb').file_dependencies.should be_one
43
+ @subject.file('motion/http.rb').file_dependencies.size.should == 1
43
44
  end
44
45
 
45
46
  it 'can use a framework' do
46
- subject.scan(root_path, 'motion/core.rb') do
47
+ @subject.scan(@root_path, 'motion/core.rb') do
47
48
  file('motion/core.rb').uses_framework('FakeFramework')
48
49
  end
49
- subject.file('motion/core.rb').frameworks.should include('FakeFramework')
50
+ @subject.file('motion/core.rb').frameworks.member?('FakeFramework').should == true
50
51
  end
51
52
 
52
53
  it "figures out the root of the project" do
53
- subject.scan(File.join(root_path, 'lib/bubble-wrap.rb'), 'motion/core.rb')
54
- subject.paths.values.first.root.should == root_path
54
+ @subject.scan(File.join(@root_path, 'lib/bubble-wrap.rb'), 'motion/core.rb')
55
+ @subject.paths.values.first.root.should == @root_path
55
56
  end
56
57
 
57
58
  describe '.frameworks' do
58
59
  it 'includes UIKit by default' do
59
- subject.frameworks.should include('UIKit')
60
+ @subject.frameworks.member?('UIKit').should == true
60
61
  end
61
62
 
62
63
  it 'includes Foundation by default' do
63
- subject.frameworks.should include('Foundation')
64
+ @subject.frameworks.member?('Foundation').should == true
64
65
  end
65
66
 
66
67
  it 'includes CoreGraphics by default' do
67
- subject.frameworks.should include('CoreGraphics')
68
+ @subject.frameworks.member?('CoreGraphics').should == true
68
69
  end
69
70
  end
70
71
  end
@@ -1,3 +1,4 @@
1
+ require 'mocha-on-bacon'
1
2
  require File.expand_path('../motion_stub.rb', __FILE__)
2
3
  require 'bubble-wrap'
3
4
 
@@ -10,7 +11,7 @@ describe BubbleWrap do
10
11
 
11
12
  describe '.require' do
12
13
  it 'delegates to Requirement.scan' do
13
- BW::Requirement.should_receive(:scan)
14
+ BW::Requirement.expects(:scan)
14
15
  BW.require('foo')
15
16
  end
16
17
  end
data/motion/core/app.rb CHANGED
@@ -67,6 +67,11 @@ module BubbleWrap
67
67
  UIScreen.mainScreen.applicationFrame
68
68
  end
69
69
 
70
+ # Main Screen bounds. Useful when starting the app
71
+ def bounds
72
+ UIScreen.mainScreen.bounds
73
+ end
74
+
70
75
  # Application Delegate
71
76
  def delegate
72
77
  UIApplication.sharedApplication.delegate
@@ -52,7 +52,7 @@ module BubbleWrap
52
52
  # The same as `.width` and `.height` but
53
53
  # compensating for screen rotation (which
54
54
  # can do your head in).
55
- def widthForOrientation(o=orientation)
55
+ def width_for_orientation(o=orientation)
56
56
  return height if (o == :landscape_left) || (o == :landscape_right)
57
57
  width
58
58
  end
@@ -60,7 +60,7 @@ module BubbleWrap
60
60
  # The same as `.width` and `.height` but
61
61
  # compensating for screen rotation (which
62
62
  # can do your head in).
63
- def heightForOrientation(o=orientation)
63
+ def height_for_orientation(o=orientation)
64
64
  return width if (o == :landscape_left) || (o == :landscape_right)
65
65
  height
66
66
  end
@@ -0,0 +1,91 @@
1
+ # Usage example:
2
+ #
3
+ # class ExampleViewController < UIViewController
4
+ # include BW::KVO
5
+ #
6
+ # def viewDidLoad
7
+ # @label = create_ui_label()
8
+ #
9
+ # observe(@label, "text") do |old_value, new_value|
10
+ # puts "Changed #{old_value} to #{new_value}"
11
+ # end
12
+ # end
13
+ #
14
+ # end
15
+ #
16
+ # @see https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i
17
+ module BubbleWrap
18
+ module KVO
19
+ COLLECTION_OPERATIONS = [ NSKeyValueChangeInsertion, NSKeyValueChangeRemoval, NSKeyValueChangeReplacement ]
20
+ DEFAULT_OPTIONS = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
21
+
22
+ def observe(target, key_path, &block)
23
+ target.addObserver(self, forKeyPath:key_path, options:DEFAULT_OPTIONS, context:nil) unless registered?(target, key_path)
24
+ add_observer_block(target, key_path, &block)
25
+ end
26
+
27
+ def unobserve(target, key_path)
28
+ return unless registered?(target, key_path)
29
+
30
+ target.removeObserver(self, forKeyPath:key_path)
31
+ remove_observer_block(target, key_path)
32
+ end
33
+
34
+ def unobserve_all
35
+ return if @targets.nil?
36
+
37
+ @targets.each do |target, key_paths|
38
+ key_paths.each_key do |key_path|
39
+ target.removeObserver(self, forKeyPath:key_path)
40
+ end
41
+ end
42
+ remove_all_observer_blocks
43
+ end
44
+
45
+ # Observer blocks
46
+
47
+ private
48
+ def registered?(target, key_path)
49
+ !@targets.nil? && !@targets[target].nil? && @targets[target].has_key?(key_path)
50
+ end
51
+
52
+ def add_observer_block(target, key_path, &block)
53
+ return if target.nil? || key_path.nil? || block.nil?
54
+
55
+ @targets ||= {}
56
+ @targets[target] ||= {}
57
+ @targets[target][key_path] ||= []
58
+ @targets[target][key_path] << block
59
+ end
60
+
61
+ def remove_observer_block(target, key_path)
62
+ return if @targets.nil? || target.nil? || key_path.nil?
63
+
64
+ key_paths = @targets[target]
65
+ if !key_paths.nil? && key_paths.has_key?(key_path)
66
+ key_paths.delete(key_path)
67
+ end
68
+ end
69
+
70
+ def remove_all_observer_blocks
71
+ @targets.clear unless @targets.nil?
72
+ end
73
+
74
+ # NSKeyValueObserving Protocol
75
+
76
+ def observeValueForKeyPath(key_path, ofObject:target, change:change, context:context)
77
+ key_paths = @targets[target] || {}
78
+ blocks = key_paths[key_path] || []
79
+ blocks.each do |block|
80
+ args = [ change[NSKeyValueChangeOldKey], change[NSKeyValueChangeNewKey] ]
81
+ args << change[NSKeyValueChangeIndexesKey] if collection?(change)
82
+ block.call(*args)
83
+ end
84
+ end
85
+
86
+ def collection?(change)
87
+ COLLECTION_OPERATIONS.include?(change[NSKeyValueChangeKindKey])
88
+ end
89
+
90
+ end
91
+ end
@@ -8,14 +8,16 @@ module BubbleWrap
8
8
  end
9
9
 
10
10
  def []=(key, value)
11
- defaults = NSUserDefaults.standardUserDefaults
12
- defaults.setObject(value, forKey: storage_key(key.to_s))
13
- defaults.synchronize
11
+ storage.setObject(value, forKey: storage_key(key.to_s))
12
+ storage.synchronize
14
13
  end
15
14
 
16
15
  def [](key)
17
- defaults = NSUserDefaults.standardUserDefaults
18
- defaults.objectForKey storage_key(key.to_s)
16
+ storage.objectForKey storage_key(key.to_s)
17
+ end
18
+
19
+ def storage
20
+ NSUserDefaults.standardUserDefaults
19
21
  end
20
22
 
21
23
  def storage_key(key)
data/motion/core/time.rb CHANGED
@@ -1,8 +1,19 @@
1
1
  class Time
2
+
2
3
  def self.iso8601(time)
3
- formatter = NSDateFormatter.alloc.init
4
- formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
5
- formatter.timeZone = NSTimeZone.timeZoneWithAbbreviation "UTC"
6
- formatter.dateFromString time
4
+ cached_date_formatter("yyyy-MM-dd'T'HH:mm:ss'Z'").
5
+ dateFromString(time)
7
6
  end
7
+
8
+ private
9
+
10
+ def self.cached_date_formatter(dateFormat)
11
+ Thread.current[:date_formatters] ||= {}
12
+ Thread.current[:date_formatters][dateFormat] ||=
13
+ NSDateFormatter.alloc.init.tap do |formatter|
14
+ formatter.dateFormat = dateFormat
15
+ formatter.timeZone = NSTimeZone.timeZoneWithAbbreviation "UTC"
16
+ end
17
+ end
18
+
8
19
  end
data/motion/http.rb CHANGED
@@ -21,38 +21,38 @@ module BubbleWrap
21
21
  # end
22
22
  #
23
23
  def self.get(url, options={}, &block)
24
- delegator = block_given? ? block : options.delete(:action)
25
- HTTP::Query.new( url, :get, options.merge({:action => delegator}) )
24
+ create_query url, :get, options, block
26
25
  end
27
26
 
28
27
  # Make a POST request
29
28
  def self.post(url, options={}, &block)
30
- delegator = block_given? ? block : options.delete(:action)
31
- HTTP::Query.new( url, :post, options.merge({:action => delegator}) )
29
+ create_query url, :post, options, block
32
30
  end
33
31
 
34
32
  # Make a PUT request
35
33
  def self.put(url, options={}, &block)
36
- delegator = block_given? ? block : options.delete(:action)
37
- HTTP::Query.new( url, :put, options.merge({:action => delegator}) )
34
+ create_query url, :put, options, block
38
35
  end
39
36
 
40
37
  # Make a DELETE request
41
38
  def self.delete(url, options={}, &block)
42
- delegator = block_given? ? block : options.delete(:action)
43
- HTTP::Query.new( url, :delete, options.merge({:action => delegator}) )
39
+ create_query url, :delete, options, block
44
40
  end
45
41
 
46
42
  # Make a HEAD request
47
43
  def self.head(url, options={}, &block)
48
- delegator = block_given? ? block : options.delete(:action)
49
- HTTP::Query.new( url, :head, options.merge({:action => delegator}) )
44
+ create_query url, :head, options, block
50
45
  end
51
46
 
52
47
  # Make a PATCH request
53
48
  def self.patch(url, options={}, &block)
54
- delegator = block_given? ? block : options.delete(:action)
55
- HTTP::Query.new( url, :patch, options.merge({:action => delegator}) )
49
+ create_query url, :patch, options, block
50
+ end
51
+
52
+ private
53
+ def self.create_query(url, method, options, passed_block)
54
+ options[:action] = passed_block if passed_block
55
+ HTTP::Query.new( url, method, options )
56
56
  end
57
57
 
58
58
  # Response class wrapping the results of a Query's response
@@ -113,12 +113,8 @@ module BubbleWrap
113
113
  @credentials = options.delete(:credentials) || {}
114
114
  @credentials = {:username => '', :password => ''}.merge(@credentials)
115
115
  @timeout = options.delete(:timeout) || 30.0
116
- headers = options.delete(:headers)
117
- if headers
118
- @headers = {}
119
- headers.each{|k,v| @headers[k] = v.gsub("\n", '\\n') } # escaping LFs
120
- end
121
- @cachePolicy = options.delete(:cache_policy) || NSURLRequestUseProtocolCachePolicy
116
+ @headers = escape_line_feeds(options.delete :headers)
117
+ @cache_policy = options.delete(:cache_policy) || NSURLRequestUseProtocolCachePolicy
122
118
  @options = options
123
119
  @response = HTTP::Response.new
124
120
  initiate_request(url)
@@ -127,16 +123,22 @@ module BubbleWrap
127
123
  connection
128
124
  end
129
125
 
130
- def generate_get_params(payload, prefix=nil)
126
+ def generate_params(payload, prefix=nil)
131
127
  list = []
132
128
  payload.each do |k,v|
133
129
  if v.is_a?(Hash)
134
130
  new_prefix = prefix ? "#{prefix}[#{k.to_s}]" : k.to_s
135
- param = generate_get_params(v, new_prefix)
131
+ param = generate_params(v, new_prefix)
132
+ list << param
133
+ elsif v.is_a?(Array)
134
+ v.each do |val|
135
+ param = prefix ? "#{prefix}[#{k}][]=#{val}" : "#{k}[]=#{val}"
136
+ list << param
137
+ end
136
138
  else
137
139
  param = prefix ? "#{prefix}[#{k}]=#{v}" : "#{k}=#{v}"
140
+ list << param
138
141
  end
139
- list << param
140
142
  end
141
143
  return list.flatten
142
144
  end
@@ -147,16 +149,16 @@ module BubbleWrap
147
149
 
148
150
  unless @payload.nil?
149
151
  if @payload.is_a?(Hash)
150
- params = generate_get_params(@payload)
152
+ params = generate_params(@payload)
151
153
  @payload = params.join("&")
152
154
  end
153
155
  url_string = "#{url_string}?#{@payload}" if @method == "GET"
154
156
  end
155
-
156
- p "BubbleWrap::HTTP building a NSRequest for #{url_string}" if SETTINGS[:debug]
157
+ #this method needs a refactor when the specs are done. (especially this utf8 escaping part)
158
+ log "BubbleWrap::HTTP building a NSRequest for #{url_string}"
157
159
  @url = NSURL.URLWithString(url_string.stringByAddingPercentEscapesUsingEncoding NSUTF8StringEncoding)
158
160
  @request = NSMutableURLRequest.requestWithURL(@url,
159
- cachePolicy:@cachePolicy,
161
+ cachePolicy:@cache_policy,
160
162
  timeoutInterval:@timeout)
161
163
  @request.setHTTPMethod @method
162
164
  @request.setAllHTTPHeaderFields(@headers) if @headers
@@ -168,11 +170,8 @@ module BubbleWrap
168
170
  end
169
171
 
170
172
  # NSHTTPCookieStorage.sharedHTTPCookieStorage
171
-
172
173
  @connection = create_connection(request, self)
173
- @request.instance_variable_set("@done_loading", false)
174
- def @request.done_loading; @done_loading; end
175
- def @request.done_loading!; @done_loading = true; end
174
+ patch_nsurl_request
176
175
  end
177
176
 
178
177
  def connection(connection, didReceiveResponse:response)
@@ -188,7 +187,7 @@ module BubbleWrap
188
187
  end
189
188
 
190
189
  def connection(connection, willSendRequest:request, redirectResponse:redirect_response)
191
- p "HTTP redirected #{request.description}" if SETTINGS[:debug]
190
+ log "HTTP redirected #{request.description}"
192
191
  new_request = request.mutableCopy
193
192
  # new_request.setValue(@credentials.inspect, forHTTPHeaderField:'Authorization') # disabled while we figure this one out
194
193
  new_request.setAllHTTPHeaderFields(@headers) if @headers
@@ -200,7 +199,7 @@ module BubbleWrap
200
199
  def connection(connection, didFailWithError: error)
201
200
  UIApplication.sharedApplication.networkActivityIndicatorVisible = false
202
201
  @request.done_loading!
203
- NSLog"HTTP Connection failed #{error.localizedDescription}" if SETTINGS[:debug]
202
+ log "HTTP Connection failed #{error.localizedDescription}"
204
203
  @response.error_message = error.localizedDescription
205
204
  call_delegator_with_response
206
205
  end
@@ -225,15 +224,37 @@ module BubbleWrap
225
224
  # NSURLCredentialPersistenceNone,
226
225
  # NSURLCredentialPersistenceForSession,
227
226
  # NSURLCredentialPersistencePermanent
228
- p "auth challenged, answered with credentials: #{credentials.inspect}" if SETTINGS[:debug]
227
+ log "auth challenged, answered with credentials: #{credentials.inspect}"
229
228
  new_credential = NSURLCredential.credentialWithUser(credentials[:username], password:credentials[:password], persistence:NSURLCredentialPersistenceForSession)
230
229
  challenge.sender.useCredential(new_credential, forAuthenticationChallenge:challenge)
231
230
  else
232
231
  challenge.sender.cancelAuthenticationChallenge(challenge)
233
- p 'Auth Failed :('
232
+ log 'Auth Failed :('
234
233
  end
235
234
  end
236
235
 
236
+
237
+ private
238
+
239
+ def log(message)
240
+ NSLog message if SETTINGS[:debug]
241
+ end
242
+
243
+ def escape_line_feeds(hash)
244
+ return nil if hash.nil?
245
+ escaped_hash = {}
246
+
247
+ hash.each{|k,v| escaped_hash[k] = v.gsub("\n", '\\n') }
248
+ escaped_hash
249
+ end
250
+
251
+ def patch_nsurl_request
252
+ @request.instance_variable_set("@done_loading", false)
253
+
254
+ def @request.done_loading; @done_loading; end
255
+ def @request.done_loading!; @done_loading = true; end
256
+ end
257
+
237
258
  def call_delegator_with_response
238
259
  if @delegator.respond_to?(:call)
239
260
  @delegator.call( @response, self )