bubble-wrap 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/.gitignore +0 -1
  2. data/.yardopts +2 -0
  3. data/CHANGELOG.md +15 -0
  4. data/Gemfile +1 -1
  5. data/Gemfile.lock +24 -0
  6. data/HACKING.md +2 -2
  7. data/README.md +363 -21
  8. data/Rakefile +6 -2
  9. data/lib/bubble-wrap.rb +0 -1
  10. data/lib/bubble-wrap/all.rb +4 -0
  11. data/lib/bubble-wrap/camera.rb +7 -0
  12. data/lib/bubble-wrap/core.rb +3 -2
  13. data/lib/bubble-wrap/ext/motion_project_app.rb +2 -2
  14. data/lib/bubble-wrap/http.rb +1 -0
  15. data/lib/bubble-wrap/loader.rb +19 -12
  16. data/lib/bubble-wrap/location.rb +6 -0
  17. data/lib/bubble-wrap/reactor.rb +10 -0
  18. data/lib/bubble-wrap/requirement.rb +11 -3
  19. data/lib/bubble-wrap/rss_parser.rb +2 -0
  20. data/lib/bubble-wrap/ui.rb +4 -0
  21. data/lib/bubble-wrap/version.rb +1 -1
  22. data/motion/core.rb +8 -2
  23. data/motion/core/app.rb +34 -6
  24. data/motion/core/device.rb +10 -1
  25. data/motion/core/device/camera.rb +219 -0
  26. data/motion/core/device/camera_wrapper.rb +45 -0
  27. data/motion/core/ns_url_request.rb +10 -0
  28. data/motion/core/persistence.rb +7 -0
  29. data/motion/core/pollute.rb +1 -2
  30. data/motion/core/string.rb +23 -0
  31. data/motion/http.rb +142 -83
  32. data/motion/location/location.rb +152 -0
  33. data/motion/location/pollute.rb +5 -0
  34. data/motion/reactor.rb +105 -0
  35. data/motion/reactor/default_deferrable.rb +9 -0
  36. data/motion/reactor/deferrable.rb +126 -0
  37. data/motion/reactor/eventable.rb +24 -0
  38. data/motion/reactor/future.rb +22 -0
  39. data/motion/reactor/periodic_timer.rb +27 -0
  40. data/motion/reactor/queue.rb +60 -0
  41. data/motion/reactor/timer.rb +25 -0
  42. data/motion/rss_parser.rb +131 -0
  43. data/motion/shortcut.rb +18 -0
  44. data/motion/{core → ui}/gestures.rb +15 -9
  45. data/motion/ui/pollute.rb +5 -0
  46. data/motion/{core → ui}/ui_control.rb +0 -0
  47. data/motion/{core → ui}/ui_view_controller.rb +0 -0
  48. data/resources/atom.xml +1705 -0
  49. data/spec/lib/bubble-wrap/ext/motion_project_app_spec.rb +7 -11
  50. data/spec/lib/bubble-wrap/requirement_spec.rb +4 -4
  51. data/spec/lib/bubble-wrap_spec.rb +2 -2
  52. data/spec/motion/core/app_spec.rb +118 -14
  53. data/spec/motion/core/device/camera_spec.rb +130 -0
  54. data/spec/motion/core/device/camera_wrapper_spec.rb +45 -0
  55. data/spec/motion/core/device_spec.rb +0 -50
  56. data/spec/motion/core/gestures_spec.rb +5 -0
  57. data/spec/motion/core/persistence_spec.rb +24 -2
  58. data/spec/motion/core/string_spec.rb +55 -0
  59. data/spec/motion/core_spec.rb +72 -1
  60. data/spec/motion/http_spec.rb +100 -65
  61. data/spec/motion/location/location_spec.rb +152 -0
  62. data/spec/motion/reactor/eventable_spec.rb +40 -0
  63. data/spec/motion/reactor_spec.rb +163 -0
  64. data/spec/motion/rss_parser_spec.rb +36 -0
  65. metadata +75 -16
data/.gitignore CHANGED
@@ -1,6 +1,5 @@
1
1
  .rake_tasks~
2
2
  pkg/*
3
- Gemfile.lock
4
3
  build/
5
4
  .DS_Store
6
5
  .repl_history
data/.yardopts ADDED
@@ -0,0 +1,2 @@
1
+ lib/**/*.rb
2
+ motion/**/*.rb
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## 1.1.0
2
+
3
+ [Commit history](https://github.com/rubymotion/BubbleWrap/compare/1.0...1.1])
4
+ * Added `BubbleWrap::Reactor`, a simplified implementation of the Event Machine API on top of GCD.
5
+ * Added upload support to the HTTP wrapper.
6
+ * Added `BubbleWrap.create_uuid` to generate a uuid string.
7
+ * Added a program progress proc option to the HTTP wrapper.
8
+ * Added a RSS parser.
9
+ * Added a camera wrapper.
10
+ * Split the various wrappers in self contained and requirable libraries.
11
+ * Added a wrapper around the location/gps APIs.
12
+ * Added a merge method to the persistence layer so multiple values can
13
+ be saved at once.
14
+ * Added a way to create `UIColor` instances using a hex string: `'#FF8A19'.to_color` or color keyword: `'blue'.to_color`, `'dark_gray'.to_color`.
15
+
1
16
  ## 1.0.0
2
17
 
3
18
  * Improved the integration with RubyMotion build system.
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in bubble-wrap.gemspec
4
- gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,24 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ bubble-wrap (1.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ bacon (1.1.0)
10
+ metaclass (0.0.1)
11
+ mocha (0.12.0)
12
+ metaclass (~> 0.0.1)
13
+ mocha-on-bacon (0.2.0)
14
+ mocha (>= 0.9.8)
15
+ rake (0.9.2.2)
16
+
17
+ PLATFORMS
18
+ ruby
19
+
20
+ DEPENDENCIES
21
+ bacon
22
+ bubble-wrap!
23
+ mocha-on-bacon
24
+ rake
data/HACKING.md CHANGED
@@ -20,7 +20,7 @@ require 'bubble-wrap'
20
20
  When `bubble-wrap` is required it immediately requires `bubble-wrap/loader` which sets up the infrastructure needed to manipulate the `Rakefile` build process. Once that is done we can freely call
21
21
 
22
22
  ```ruby
23
- BubbleWrap.require 'motion/core**/*.rb'
23
+ BubbleWrap.require 'motion/core/**/*.rb'
24
24
  ```
25
25
 
26
26
  `BubbleWrap.require` (or simply `BW.require`) is used to include
@@ -36,7 +36,7 @@ of `BW::Requirement` and thus has access to all it's class methods.
36
36
  The most common use cases are setting file dependencies:
37
37
 
38
38
  ```ruby
39
- BW.require('motion/core**/*.rb') do
39
+ BW.require('motion/core/**/*.rb') do
40
40
  file('motion/core/device/screen.rb').depends_on 'motion/core/device.rb'
41
41
  end
42
42
  ```
data/README.md CHANGED
@@ -13,16 +13,16 @@ gem install bubble-wrap
13
13
 
14
14
  ## Setup
15
15
 
16
- 1. Edit the `Rakefile` of your RubyMotion project and add the following require line.
16
+ 1. Edit the `Rakefile` of your RubyMotion project and add the following require line:
17
17
 
18
18
  ```ruby
19
19
  require 'bubble-wrap'
20
20
  ```
21
21
 
22
22
  BubbleWrap is split into multiple modules so that you can easily choose which parts
23
- are included at compile-time.
23
+ are included at compile-time.
24
24
 
25
- The above example requires all the wrappers/helpers. If you wish to only
25
+ The above example requires the `core` and `http` modules. If you wish to only
26
26
  include the core modules use the following line of code instead:
27
27
 
28
28
  ```ruby
@@ -35,6 +35,42 @@ If you wish to only include the `HTTP` wrapper:
35
35
  require 'bubble-wrap/http'
36
36
  ```
37
37
 
38
+ If you wish to only include the `RSS Parser` wrapper:
39
+
40
+ ```ruby
41
+ require 'bubble-wrap/rss_parser'
42
+ ```
43
+
44
+ If you wish to only include the `Reactor` wrapper:
45
+
46
+ ```ruby
47
+ require 'bubble-wrap/reactor'
48
+ ```
49
+
50
+ If you wish to only include the UI-related wrappers:
51
+
52
+ ```ruby
53
+ require 'bubble-wrap/ui'
54
+ ```
55
+
56
+ If you wish to only include the `Camera` wrapper:
57
+
58
+ ```ruby
59
+ require 'bubble-wrap/camera'
60
+ ```
61
+
62
+ If you wish to only include the `Location` wrapper:
63
+
64
+ ```ruby
65
+ require 'bubble-wrap/location'
66
+ ```
67
+
68
+ If you want to include everything (ie kitchen sink mode) you can save time and do:
69
+
70
+ ```ruby
71
+ require 'bubble-wrap/all'
72
+ ```
73
+
38
74
 
39
75
  Note: **DON'T** use `app.files =` in your Rakefile to set up your files once you've required BubbleWrap.
40
76
  Make sure to append onto the array or use `+=`.
@@ -56,6 +92,44 @@ use the versioned gem.
56
92
 
57
93
  ## Core
58
94
 
95
+ ### Misc
96
+
97
+ UUID generator:
98
+ ```ruby
99
+ BubbleWrap.create_uuid
100
+ => "68ED21DB-82E5-4A56-ABEB-73650C0DB701"
101
+ ```
102
+
103
+ Localization (using `NSBundle.mainBundle.localizedStringForKey`):
104
+ ```ruby
105
+ BubbleWrap.localized_string(:foo, 'fallback')
106
+ => "fallback"
107
+ ```
108
+
109
+ Color conversion:
110
+ ```ruby
111
+ BubbleWrap.rgba_color(23, 45, 12, 0.4)
112
+ => #<UIDeviceRGBColor:0x6db6ed0>
113
+ BubbleWrap.rgb_color(23, 45, 12)
114
+ => #<UIDeviceRGBColor:0x8ca88b0>
115
+ 'blue'.to_color
116
+ => #<UICachedDeviceRGBColor:0xda535c0>
117
+ 'dark_gray'.to_color
118
+ => #<UICachedDeviceWhiteColor:0x8bb5be0>
119
+ '#FF8A19'.to_color
120
+ => #<UIDeviceRGBColor:0x8d54110>
121
+ ```
122
+
123
+ Debug flag:
124
+ ```ruby
125
+ BubbleWrap.debug?
126
+ => false
127
+ BubbleWrap.debug = true
128
+ => true
129
+ BubbleWrap.debug?
130
+ => true
131
+ ```
132
+
59
133
  ### App
60
134
 
61
135
  A module with useful methods related to the running application
@@ -73,6 +147,8 @@ A module with useful methods related to the running application
73
147
  # creates and shows an alert message.
74
148
  > App.run_after(0.5) { p "It's #{Time.now}" }
75
149
  # Runs the block after 0.5 seconds.
150
+ > App.open_url("http://matt.aimonetti.net")
151
+ # Opens the url using the device's browser. (accepts a string url or an instance of `NSURL`.
76
152
  > App::Persistence['channels'] # application specific persistence storage
77
153
  # ['NBC', 'ABC', 'Fox', 'CBS', 'PBS']
78
154
  > App::Persistence['channels'] = ['TF1', 'France 2', 'France 3']
@@ -94,6 +170,7 @@ Other available methods:
94
170
  A collection of useful methods about the current device:
95
171
 
96
172
  Examples:
173
+
97
174
  ```ruby
98
175
  > Device.iphone?
99
176
  # true
@@ -119,23 +196,26 @@ Examples:
119
196
  # 320
120
197
  ```
121
198
 
122
- ### Gestures
199
+ ### Camera
123
200
 
124
- Extra methods on `UIView` for working with gesture recognizers. A gesture recognizer can be added using a normal Ruby block, like so:
201
+ Added interface for better camera access:
125
202
 
126
203
  ```ruby
127
- view.whenTapped do
128
- UIView.animateWithDuration(1,
129
- animations:lambda {
130
- # animate
131
- # @view.transform = ...
132
- })
133
- end
134
- ```
135
-
136
- There are similar methods for pinched, rotated, swiped, panned, and pressed (for long presses). All of the methods return the actual recognizer object, so it is possible to set the delegate if more fine-grained control is needed.
204
+ # Uses the front camera
205
+ BW::Device.camera.front.picture(media_types: [:movie, :image]) do |result|
206
+ image_view = UIImageView.alloc.initWithImage(result[:original_image])
207
+ end
137
208
 
209
+ # Uses the rear camera
210
+ BW::Device.camera.rear.picture(media_types: [:movie, :image]) do |result|
211
+ image_view = UIImageView.alloc.initWithImage(result[:original_image])
212
+ end
138
213
 
214
+ # Uses the photo library
215
+ BW::Device.camera.any.picture(media_types: [:movie, :image]) do |result|
216
+ image_view = UIImageView.alloc.initWithImage(result[:original_image])
217
+ end
218
+ ```
139
219
 
140
220
  ### JSON
141
221
 
@@ -248,21 +328,51 @@ iso8601 formatted string into a Time instance.
248
328
  => 2012-05-31 21:41:33 +0200
249
329
  ```
250
330
 
251
- ### UIControl / UIButton
331
+ ## Location
252
332
 
253
- Helper methods to give `UIButton` a Ruby-like interface. Ex:
333
+ Added interface for Ruby-like GPS access:
254
334
 
255
335
  ```ruby
256
- button.when(UIControlEventTouchUpInside) do
257
- self.view.backgroundColor = UIColor.redColor
336
+ BW::Location.get do |result|
337
+ p "From Lat #{result[:from].latitude}, Long #{result[:from].longitude}"
338
+ p "To Lat #{result[:to].latitude}, Long #{result[:to].longitude}"
258
339
  end
259
340
  ```
260
341
 
342
+ Also available is `BW::Location.get_significant`, for monitoring significant location changes.
343
+
344
+ ## UI
345
+
346
+ ### Gestures
347
+
348
+ Extra methods on `UIView` for working with gesture recognizers. A gesture recognizer can be added using a normal Ruby block, like so:
349
+
350
+ ```ruby
351
+ view.whenTapped do
352
+ UIView.animateWithDuration(1,
353
+ animations:lambda {
354
+ # animate
355
+ # @view.transform = ...
356
+ })
357
+ end
358
+ ```
359
+
360
+ There are similar methods for pinched, rotated, swiped, panned, and pressed (for long presses). All of the methods return the actual recognizer object, so it is possible to set the delegate if more fine-grained control is needed.
361
+
261
362
  ### UIViewController
262
363
 
263
364
  A custom method was added to `UIViewController` to return the content
264
365
  frame of a view controller.
265
366
 
367
+ ### UIControl / UIButton
368
+
369
+ Helper methods to give `UIButton` a Ruby-like interface. Ex:
370
+
371
+ ```ruby
372
+ button.when(UIControlEventTouchUpInside) do
373
+ self.view.backgroundColor = UIColor.redColor
374
+ end
375
+ ```
266
376
 
267
377
  ## HTTP
268
378
 
@@ -295,16 +405,248 @@ BubbleWrap::HTTP.post("http://foo.bar.com/", {payload: data}) do |response|
295
405
  json = BubbleWrap::JSON.parse(response.body.to_str)
296
406
  p json['id']
297
407
  elsif response.status_code.to_s =~ /40\d/
298
- alert("Login failed") # helper provided by the kernel file in this repo.
408
+ App.alert("Login failed")
299
409
  else
300
- alert(response.error_message)
410
+ App.alert(response.error_message)
301
411
  end
302
412
  end
303
413
  ```
304
414
 
415
+ A `:download_progress` option can also be passed. The expected object
416
+ would be a Proc that takes two arguments: a float representing the
417
+ amount of data currently received and another float representing the
418
+ total amount of data expected.
419
+
420
+
421
+ ## RSS Parser
422
+ **Since: > version 1.0.0**
423
+
424
+ The RSS Parser provides an easy interface to consume RSS feeds in an
425
+ asynchronous (non blocking) way.
426
+
427
+
428
+ ```ruby
429
+ feed_parser = BW::RSSParser.new("http://feeds2.feedburner.com/sdrbpodcast")
430
+ feed_parser.parse do |item|
431
+ # called asynchronously as items get parsed
432
+ p item.title
433
+ end
434
+ ```
435
+
436
+ The yielded RSS item is of type `RSSParser::RSSItem` and has the
437
+ following attributes:
438
+
439
+ * title
440
+ * description
441
+ * link
442
+ * guid
443
+ * pubDate
444
+ * enclosure
445
+
446
+ The item can be converted into a hash by calling `to_hash` on it.
447
+
448
+ ### Delegate
449
+ **Since: > version 1.0.0**
450
+
451
+ You can also designate a delegate to the parser and implement change
452
+ state callbacks:
453
+
454
+ ```ruby
455
+ feed_parser = BW::RSSParser.new("http://feeds.feedburner.com/sdrbpodcast")
456
+ feed_parser.delegate = self
457
+ feed.parse do |item|
458
+ p item.title
459
+ end
460
+
461
+ # Delegate method
462
+ def when_parser_initializes
463
+ p "The parser is ready!"
464
+ end
465
+
466
+ def when_parser_parses
467
+ p "The parser started parsing the document"
468
+ end
469
+
470
+ def when_parser_is_done
471
+ p "The feed is entirely parsed, congratulations!"
472
+ end
473
+ ```
474
+
475
+ These delegate methods are optional, however, you might find the
476
+ `when_parser_is_done` callback useful if you collected all the items and
477
+ want to process all at once for instance.
478
+
479
+ ### Parsing a remote content or actual data
480
+
481
+ You have the choice to initialize a parser instance with a string
482
+ representing an URL, an instance of `NSURL` or my specifying that the
483
+ passed param is some data to parse directly.
484
+
485
+ ```ruby
486
+ # string representing an url:
487
+ feed_parser = BW::RSSParser.new("http://feeds2.feedburner.com/sdrbpodcast")
488
+ # a NSURL instance:
489
+ url = NSURL.alloc.initWithString("http://matt.aimonetti.net/atom.xml")
490
+ feed_parser = BW::RSSParser.new(url)
491
+ # Some data
492
+ feed = File.read('atom.xml')
493
+ feed_parser = BW::RSSParser.new(feed, true)
494
+ ```
495
+
496
+
497
+ ## Reactor
498
+ **Since: > version 1.0.0**
499
+
500
+ `BubbleWrap::Reactor` is a simplified, mostly complete implementation of
501
+ the [Event Machine](http://rubyeventmachine.com/) API. In fact
502
+ `BubbleWrap::Reactor` is aliased to `EM` in the runtime environment.
503
+
504
+ ### Deferables
505
+
506
+ BubbleWrap provides both a `Deferrable` mixin and a `DefaultDeferrable`
507
+ class, which simply mixes in deferrable behaviour if you don't want to
508
+ implement your own.
305
509
 
510
+ A deferrable is an object with four states: unknown, successful, failure
511
+ and timeout. When you initially create a deferrable it is in an unknown
512
+ state, however you can assign callbacks to be run when the object
513
+ changes to either successful or failure state.
514
+
515
+ #### Success
516
+
517
+ ```ruby
518
+ > d = EM::DefaultDeferrable.new
519
+ => #<BubbleWrap::Reactor::DefaultDeferrable:0x6d859a0>
520
+ > d.callback { |what| puts "Great #{what}!" }
521
+ => [#<Proc:0x6d8a1e0>]
522
+ > d.succeed "justice"
523
+ Great justice!
524
+ => nil
525
+ ```
526
+
527
+ #### Failure
528
+
529
+ ```ruby
530
+ > d = EM::DefaultDeferrable.new
531
+ => #<BubbleWrap::Reactor::DefaultDeferrable:0x8bf3ee0>
532
+ > d.errback { |what| puts "Great #{what}!" }
533
+ => [#<Proc:0x8bf3ef0>]
534
+ > d.fail "sadness"
535
+ Great sadness!
536
+ => nil
537
+ ```
538
+
539
+ #### Timeout
540
+
541
+ ```ruby
542
+ > d = EM::DefaultDeferrable.new
543
+ => #<BubbleWrap::Reactor::DefaultDeferrable:0x8bf5910>
544
+ > d.errback { puts "Great scott!" }
545
+ => [#<Proc:0x8bf6350>]
546
+ > d.timeout 2
547
+ => #<BubbleWrap::Reactor::Timer:0x6d920a0 @timer=#<__NSCFTimer:0x6d91990>>
548
+ # wait...
549
+ > Great scott!
550
+ ```
551
+
552
+ ### Timers
553
+
554
+ *All timers can be cancelled using `EM.cancel_timer`.*
555
+
556
+ #### One-shot timers
557
+
558
+ ```ruby
559
+ > EM.add_timer 1.0 do
560
+ > puts "Great scott!"
561
+ > end
562
+ => 146335904
563
+ > Great scott!
564
+ ```
565
+
566
+ #### Periodic timers
567
+
568
+ ```ruby
569
+ > count = 0
570
+ => 0
571
+ > timer = EM.add_periodic_timer 1.0 do
572
+ > count = count + 1
573
+ > puts "Great scott!"
574
+ > (count < 10) || EM.cancel_timer(timer)
575
+ > end
576
+ => 146046832
577
+ > Great scott!
578
+ Great scott!
579
+ Great scott!
580
+ Great scott!
581
+ Great scott!
582
+ Great scott!
583
+ Great scott!
584
+ Great scott!
585
+ Great scott!
586
+ Great scott!
587
+ ```
588
+
589
+ ### Scheduling operations
590
+
591
+ You can use `EM.schedule` to schedule blocks to be executed
592
+ asynchronously. BubbleWrap deviates from the EventMachine
593
+ API here in that it also provides `EM.schedule_on_main` which
594
+ makes sure that the task is run asynchronously, but on the
595
+ application's main thread - this is necessary if you are
596
+ updating the user interface.
597
+
598
+ ```ruby
599
+ > EM.schedule { puts Thread.current.object_id }
600
+ 146027920
601
+ => nil
602
+ > EM.schedule_on_main { puts Thread.current.object_id }
603
+ 112222480
604
+ => nil
605
+ ```
606
+
607
+ ### Deferrable operations
608
+
609
+ You can also use `EM.defer` in much the same way as `EM.schedule`
610
+ with one important difference, you can pass in a second `proc`
611
+ which will be called when the first has completed, and be passed
612
+ it's result as an argument. Just like `EM.schedule`, `EM.defer`
613
+ also has an `EM.defer_on_main` version.
614
+
615
+ ```ruby
616
+ > operation = proc { 99 }
617
+ => #<Proc:0x6d763c0>
618
+ > callback = proc { |speed| puts speed >= 99 ? "Time travel!" : "Conventional travel!" }
619
+ => #<Proc:0x8bd3910>
620
+ > EM.defer(operation, callback)
621
+ => nil
622
+ Time travel!
623
+ ```
624
+
625
+ ### Events
626
+
627
+ Although not part of the EventMachine API, BubbleWrap provides
628
+ an `Eventable` mixin for use instrumenting objects with simple
629
+ event triggering behaviour. `BubbleWrap::Reactor` uses this
630
+ behind the scenes in several places, and as it's a very handy
631
+ idiom it is available as a public API.
632
+
633
+ ```ruby
634
+ > o = Class.new { include EM::Eventable }.new
635
+ => #<#<Class:0x6dc1310>:0x6dc2ec0>
636
+ > o.on(:november_5_1955) { puts "Ow!" }
637
+ => [#<Proc:0x6dc6300>]
638
+ > o.on(:november_5_1955) { puts "Flux capacitor!" }
639
+ => [#<Proc:0x6dc6300>, #<Proc:0x6dc1ba0>]
640
+ > o.trigger(:november_5_1955)
641
+ Ow!
642
+ Flux capacitor!
643
+ => [nil, nil]
644
+ ```
645
+
646
+ # Suggestions?
306
647
 
307
648
  Do you have a suggestion for a specific wrapper? Feel free to open an
308
649
  issue/ticket and tell us about what you are after. If you have a
309
650
  wrapper/helper you are using and are thinking that others might enjoy,
310
651
  please send a pull request (with tests if possible).
652
+