sugarcube 0.11.3 → 0.12

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.
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  pkg/
2
2
  *.gem
3
3
  .DS_Store
4
+ /build/
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --markup markdown - LICENSE
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- sugarcube
1
+ SugarCube
2
2
  =========
3
3
 
4
4
  Some sugar for your cocoa, or your [tea][sweettea].
@@ -8,14 +8,14 @@ About
8
8
 
9
9
  CocoaTouch/iOS is a *verbose* framework. These extensions hope to make
10
10
  development in rubymotion more enjoyable by tacking "UI" methods onto the base
11
- classes (String, Fixnum, Numeric). With sugarcube, you can create a color from an
11
+ classes (String, Fixnum, Numeric). With SugarCube, you can create a color from an
12
12
  integer or symbol, or create a UIFont or UIImage from a string.
13
13
 
14
14
  Some UI classes are opened up as well, like adding the '<<' operator to a UIView
15
15
  instance, instead of view.addSubview(subview), you can use the more idiomatic:
16
16
  view << subview.
17
17
 
18
- The basic idea of sugarcube is to turn some operations on their head. Insead of
18
+ The basic idea of SugarCube is to turn some operations on their head. Insead of
19
19
 
20
20
  UIApplication.sharedApplication.openURL(NSURL.URLWithString(url))
21
21
 
@@ -25,7 +25,7 @@ How about:
25
25
 
26
26
  **DISCLAIMER**
27
27
 
28
- It is possible that you *will not like sugarcube*. That is perfectly fine!
28
+ It is possible that you *will not like SugarCube*. That is perfectly fine!
29
29
  Some people take milk in their coffee, some take sugar. Some crazy maniacs
30
30
  don't even *drink* coffee, if you can imagine that... All I'm saying is: to each
31
31
  their own. You should checkout [BubbleWrap][] for another take on
@@ -45,11 +45,14 @@ Installation
45
45
 
46
46
  gem install sugarcube
47
47
 
48
+ # in Rakefile
49
+ require 'sugarcube'
50
+
48
51
  # or in Gemfile
49
52
  gem 'sugarcube'
50
53
 
51
- # in Rakefile
52
- require 'sugarcube'
54
+ # in terminal
55
+ $ bundle install
53
56
 
54
57
  Examples
55
58
  ========
@@ -114,7 +117,8 @@ Shorthands and hash-like access to the coder/decoder objects.
114
117
  coder['key'] = self.value
115
118
  self.value = decoder['key']
116
119
 
117
- # but if you want to store booleans and such in the MOST compact way:
120
+ # but if you want to store booleans and such (in their C form,
121
+ # which will take up less space I suppose):
118
122
  coder.set('sugarcube_is_neat', toBool:self.is_sugarcube_neat?)
119
123
  self.sugarcube_is_neat = decoder.bool('sugarcube_is_neat')
120
124
 
@@ -160,6 +164,11 @@ recurring events)
160
164
  ignoring the time components. `start_of_day` and `end_of_day` methods help
161
165
  you here. They are akin to `floor` and `ceil`, if you consider the time to
162
166
  be the "floating" component, and the date to be the nearest "integer".
167
+ 4. Formatting is made easier with `NSDate#string_with_style(NSDateStyleConstant or Symbol)`
168
+ and `NSDate#string_with_format(format_string)`. See
169
+ <http://www.unicode.org/reports/tr35/tr35-25.html#Date_Format_Patterns> for
170
+ the formatters, they take getting used to, coming from `strftime`, but they
171
+ are much more powerful and locale-aware.
163
172
 
164
173
  ```
165
174
  (main)> now = NSDate.new # Time.new is the same thing
@@ -358,6 +367,11 @@ This is the "big daddy". Lots of sugar here...
358
367
  :change.uicontrolevent # => UIControlEventValueChanged
359
368
  :all.uicontrolevent # => UIControlEventAllEvents
360
369
  :blue.uicolor # UIColor.blueColor
370
+
371
+ # these are really handy for custom buttons - touch_start means the finger is inside the button, touch_stop is outside the button or canceled
372
+ :touch_start # => UIControlEventTouchDown | UIControlEventTouchDragEnter
373
+ :touch_stop # => UIControlEventTouchUpInside | UIControlEventTouchCancel | UIControlEventTouchDragExit
374
+
361
375
  # all CSS colors are supported, and alpha
362
376
  # (no "grey"s, only "gray"s, consistent with UIKit, which only provides "grayColor")
363
377
  :firebrick.uicolor(0.25) # => 0xb22222.uicolor(0.25)
@@ -385,16 +399,28 @@ image = "my_image".uiimage
385
399
  image.uicolor # => UIColor.colorWithPatternImage(image)
386
400
  ```
387
401
 
388
- ###### Image Manipulation
402
+ ###### Image Manipulation - VERY handy!
389
403
 
390
404
  ```ruby
391
405
  image.scale_to [37, 37]
392
406
  image.rounded # default: 5 pt radius
393
407
  image.rounded(10)
394
408
 
395
- # these both use UIEdgeInsetsZero (for now)
409
+ image.in_rect([[10, 10], [100, 100]]) # get part of an image
410
+
411
+ image.darken # => good for "pressed" buttons
412
+ image.darken(brightness: -0.5, saturation: -0.2) # these are the defaults
413
+
414
+ image.rotate(:left)
415
+ image.rotate(:right)
416
+ image.rotate(:flip) # 180° - if you have a better name, let me know!
417
+ image.rotate(45.degrees)
418
+
419
+ # default insets are UIEdgeInsetsZero
396
420
  image.tileable
421
+ image.tileable(insets)
397
422
  image.stretchable
423
+ image.stretchable(insets)
398
424
  ```
399
425
 
400
426
  UIAlertView
@@ -530,7 +556,7 @@ UIActivityIndicatorView.gray
530
556
  -----------
531
557
 
532
558
  Inspired by [BubbleWrap's][BubbleWrap] `when` method, but I prefer jQuery-style
533
- verbs and sugarcube symbols.
559
+ verbs and SugarCube symbols.
534
560
 
535
561
  ```ruby
536
562
  button = UIButton.alloc.initWithFrame([0, 0, 10, 10])
@@ -715,13 +741,13 @@ date2.same_day? date1
715
741
  :key.get_default # => NSUserDefaults.standardUserDefaults.objectForKey(:key)
716
742
  ```
717
743
 
718
- This is strange, and backwards, which is just sugarcube's style. But there is
744
+ This is strange, and backwards, which is just SugarCube's style. But there is
719
745
  one advantage to doing it this way. Compare these two snippets:
720
746
 
721
747
  ```ruby
722
748
  # BubbleWrap
723
749
  App::Persistance[:test] = { my: 'test' }
724
- # sugarcube
750
+ # SugarCube
725
751
  :test.set_default { my: 'test' }
726
752
  # k, BubbleWrap looks better
727
753
 
@@ -743,19 +769,26 @@ test[:my] = 'new'
743
769
  CoreGraphics
744
770
  --------------
745
771
 
746
- ###### Is it `CGMakeRect` or `CGRectMake`?
772
+ ###### Is it `CGMakeRect` or `CGRectMake`? What arguments does `CGRect.new` take?
747
773
 
748
- Instead, just use `Rect`, `Size` and `Point`. They will happily convert most
749
- sensible arguments into a `Rect/Size/Point`, which can be treated as a `CGRect`
750
- object OR as an `Array` (woah).
774
+ Instead, just use the coercion methods `Rect()`, `Size()` and `Point()`. They
775
+ will happily convert most sensible (and some non-sensible) arguments into a
776
+ `CGRect/CGSize/CGPoint` struct. For more CoreGraphics additions, you should use
777
+ [geomotion][] by [Clay Allsopp][]. It adds methods to `CGRect`, `CGPoint`, and
778
+ `CGSize` to make these structures more rubyesque (these methods used to be part
779
+ of SugarCube, but were removed in an attempt to decrease the amount of
780
+ duplicated code).
751
781
 
752
- These are namespaced in `SugarCube::CoreGraphics` module, but I recommend you
753
- `include SugarCube::CoreGraphics` in app_delegate.rb.
782
+ [geomotion]: https://github.com/clayallsopp
783
+ [Clay Allsopp]: https://github.com/clayallsopp/geomotion
784
+
785
+ These are namespaced in the `SugarCube::CoreGraphics` module, but I recommend
786
+ you `include SugarCube::CoreGraphics` in app_delegate.rb.
754
787
 
755
788
  ```ruby
756
- f = Rect(view.frame) # converts a CGRect into a Rect
757
- o = Point(view.frame.origin) # converts a CGPoint into a Point
758
- s = Size(view.frame.size) # converts a CGSize into a Size
789
+ f = Rect(view.frame) # the identity function - returns a copy of the CGRect
790
+ o = Point(view.frame.origin) # returns a copy of CGPoint
791
+ s = Size(view.frame.size) # returns a copy of CGSize
759
792
 
760
793
  # lots of other conversions are possible.
761
794
  # a UIView or CALayer => view.frame
@@ -763,103 +796,19 @@ f = Rect(view)
763
796
  # 4 numbers
764
797
  f = Rect(x, y, w, h)
765
798
  # or two arrays
799
+ f = Rect([x, y], [w, h])
800
+ # one array
801
+ f = Rect([[x, y], [w, h]])
802
+ f = Rect([x, y, w, h])
803
+ # a CGPoint and CGSize
766
804
  p = Point(x, y) # or just [x, y] works, too
767
805
  s = Size(w, h) # again, [w, h] is fine
768
806
  f = Rect(p, s)
769
- # like I said, a straight-up array of nested arrays is fine, too.
770
- f = Rect([[x, y], [w, h]])
771
- ```
772
-
773
- ###### CG{Rect,Point,Size} is a *real boy*!
774
-
775
- These methods get defined in a module (`SugarCube::CG{Rect,Size,Point}Extensions`),
776
- and included in `CGRect` *and* `Rect`. The idea is that you do not have to
777
- distinguish between the two objects.
778
-
779
- These methods all use the methods as described in [CGGeometry Reference][], e.g.
780
- `CGRectContainsPoint`, `CGRectIntersectsRect`, etc.
781
-
782
- ```ruby
783
- # intersection / contains
784
- Point(0, 0).intersects?(Rect(-1, -1, 2, 2)) # => true
785
- # if a Point intersects a Rect, the Rect intersects the Point, right?
786
- Rect(-1, -1, 2, 2).intersects? Point(0, 0) # => true
787
-
788
- # CGRect and the gang are real Ruby objects. Let's treat 'em that way!
789
- view.frame.contains? Point(10, 10) # in this case, contains? and intersects? are synonyms
790
- view.frame.intersects? Rect(0, 0, 10, 10) # <= but this one
791
- view.frame.contains? Rect(0, 0, 10, 10) # <= and this one are different.
792
-
793
- # CGRect has factory methods for CGRectEmpty, CGRectNull, and - KINDA - CGRectInfinite
794
- # BUT, there is a bug (?) right now where CGRectIsInfinite(CGRectInfinite) returns false.
795
- # so instead, I've built my own infinite? method that checks for the special "Infinite" value
796
- > CGRect.infinite
797
- => [[0, 0], [Infinity, Infinity]]
798
- > CGRect.infinite.infinite?
799
- => true
800
- > CGRect.null
801
- => [[Infinity, Infinity], [0.0, 0.0]]
802
- > CGRect.null.null?
803
- => true
804
- > CGRect.empty
805
- => [[0.0, 0.0], [0.0, 0.0]]
806
- > CGRect.empty.empty?
807
- => true
808
- ```
809
-
810
- A lot of the methods in CGGeometry Reference are available as instance methods
811
-
812
- ```ruby
813
- view.frame.left # => CGRectGetMinX(view.frame)
814
- view.frame.right # => CGRectGetMaxX(view.frame)
815
- view.frame.top # => CGRectGetMinY(view.frame)
816
- view.frame.bottom # => CGRectGetMaxY(view.frame)
817
- view.frame.width # => CGRectGetWidth(view.frame)
818
- view.frame.height # => CGRectGetHeight(view.frame)
819
- view.frame.center # => Point(CGRectGetMidX(view.frame), CGRectGetMidY(view.frame))
820
-
821
- view.frame.intersection(another_rect) # => CGRectIntersection(view.frame, another_rect)
822
- view.frame + another_rect # => CGRectUnion(view.frame, another_rect)
823
- view.frame + a_point # => CGRectOffset(view.frame, a_point.x, a_point.y)
824
- view.frame + a_offset # => CGRectOffset(view.frame, a_offset.horizontal, a_offset.vertical)
825
- view.frame + edgeinsets # => UIEdgeInsetsInsetRect(view.frame, edgeinsets)
826
- view.frame + a_size # => CGRectInset(view.frame, -a_size.width, -a_size.height)
827
- # Adding a size to a view keeps the view's CENTER in the same place, but
828
- # increases its size by `size.width,size.height`. it's the same as using
829
- # UIEdgeInsets with top == bottom, and left == right
830
- > Rect(0, 0, 10, 10).center
831
- => Point(5.0, 5.0) # note the center
832
- > Rect(0, 0, 10, 10) + Size(10, 10)
833
- => Rect([-10.0, -10.0],{30.0 × 30.0}) # origin and size changed, but...
834
- > (Rect(0, 0, 10, 10) + Size(10, 10)).center
835
- => Point(5.0, 5.0)
836
- # See? It's bigger, but the center hasn't moved.
807
+ # any combination of the two
808
+ f = Rect(p, [w, h])
809
+ f = Rect([x, y], s)
837
810
  ```
838
811
 
839
- `to_hash/from_hash`, and notice here that I used `inspect`, to show that it is a
840
- little more readable.
841
-
842
- **NOTE** As of today, Aug. 25, 2012, rubymotion v1.22, the `inspect` method in SugarCube is not
843
- being called. I think this is a bug... this worked before!
844
-
845
- ```ruby
846
- > Rect(0, 0, 10, 10).to_hash
847
- => {"Width"=>10.0, "Height"=>10.0, "Y"=>0.0, "X"=>0.0}
848
- > puts CGRect.from_hash(Rect(0, 0, 1, 1).to_hash).inspect
849
- CGRect([0.0, 0.0],{1.0 × 1.0})
850
- ```
851
-
852
- `to_s/from_s`, which rely on `NSStringFromCGRect/CGRectFromString` (et. al.)
853
-
854
- ```ruby
855
- > Rect(0, 0, 10, 10).to_s
856
- => "{{0, 0}, {10, 10}}"
857
- > puts CGRect.from_s Rect(0, 0, 10, 10).to_s
858
- {{0, 0}, {10, 10}}
859
- ```
860
-
861
- [CGGeometry Reference]: https://developer.apple.com/library/mac/documentation/graphicsimaging/reference/CGGeometry/Reference/reference.html
862
-
863
812
  CoreLocation
864
813
  --------------
865
814
 
@@ -1126,3 +1075,45 @@ true.blank? # => false
1126
1075
  ['a'].blank? # => false
1127
1076
  {a: 'a'}.blank? # => false
1128
1077
  ```
1078
+
1079
+ Gestures
1080
+ --------
1081
+
1082
+ Sugarcube's gesture support is very similar to BubbleWrap's, and it's entirely
1083
+ possible that the two will be merged into one thing. But SugarCube is all about
1084
+ extending base classes, whereas BubbleWrap tends to add *new* classes to do the
1085
+ heavy lifting. Plus the options you pass to SugarCube are very different, and
1086
+ the prefix is "on" instead of "when" (e.g. "on_pan" instead of "when_panned")
1087
+
1088
+ Gestures are an "opt-in" extension. In your Rakefile, add
1089
+ `require 'sugarcube-gestures'`.
1090
+
1091
+ ```ruby
1092
+ require 'sugarcube-gestures'
1093
+
1094
+ view.on_pan { |gesture|
1095
+ location = gesture.view.locationInView(view)
1096
+ }
1097
+
1098
+ # other gesture methods, with common options:
1099
+ view.on_tap # use system defaults
1100
+ view.on_tap(1) # number of taps
1101
+ view.on_tap(taps: 1, fingers: 1) # number of taps and number of fingers
1102
+
1103
+ view.on_pinch # no options
1104
+ view.on_rotate # no options
1105
+
1106
+ view.on_swipe # use system defaults
1107
+ view.on_swipe :left
1108
+ view.on_swipe(direction: :left, fingers: 1)
1109
+ view.on_swipe(direction: UISwipeGestureRecognizerDirectionLeft, fingers: 1)
1110
+
1111
+ view.on_pan # use system defaults
1112
+ view.on_pan(2) # minimum and maximum fingers required
1113
+ view.on_pan(fingers: 2)
1114
+ view.on_pan(min_fingers: 2, max_fingers: 3)
1115
+
1116
+ view.on_press # use system defaults
1117
+ view.on_press(1.5) # duration
1118
+ view.on_press(duration: 1.5, taps: 1, fingers: 1)
1119
+ ```
data/Rakefile CHANGED
@@ -1 +1,3 @@
1
- require 'bundler/gem_tasks'
1
+ $:.unshift('/Library/RubyMotion/lib')
2
+ require 'motion/project'
3
+ require './lib/sugarcube'
@@ -0,0 +1,4 @@
1
+ include SugarCube::CoreGraphics
2
+
3
+ class AppDelegate
4
+ end
@@ -0,0 +1,23 @@
1
+ unless defined?(Motion::Project::Config)
2
+ raise "The sugarcube gem must be required within a RubyMotion project Rakefile."
3
+ end
4
+
5
+
6
+ Motion::Project::App.setup do |app|
7
+ # scans app.files until it finds app/ (the default)
8
+ # if found, it inserts just before those files, otherwise it will insert to
9
+ # the end of the list
10
+ insert_point = 0
11
+ app.files.each_index do |index|
12
+ file = app.files[index]
13
+ if file =~ /^(?:\.\/)?app\//
14
+ # found app/, so stop looking
15
+ break
16
+ end
17
+ insert_point = index + 1
18
+ end
19
+
20
+ Dir.glob(File.join(File.dirname(__FILE__), 'sugarcube-gestures/**/*.rb')).reverse.each do |file|
21
+ app.files.insert(insert_point, file)
22
+ end
23
+ end
@@ -0,0 +1,134 @@
1
+ # BubbleWrap has these same methods, but the logic and options are a little
2
+ # different. In the spirit of open source, I am blatantly copying their code,
3
+ # changing it to suit my needs, and offering it here
4
+ class UIView
5
+
6
+ # a generic gesture adder, but using sugarcube_add_gesture, which handles the block
7
+ def on_gesture(klass, options={}, &proc)
8
+ recognizer = klass.alloc.initWithTarget(self, action:'sugarcube_handle_gesture:')
9
+ options.each do |method, value|
10
+ recognizer.send(method, value)
11
+ end
12
+ sugarcube_add_gesture(proc, recognizer)
13
+ end
14
+
15
+ def on_tap(taps_or_options=nil, &proc)
16
+ taps = nil
17
+ fingers = nil
18
+
19
+ if taps_or_options
20
+ if taps_or_options.is_a? Hash
21
+ taps = taps_or_options[:taps] || taps
22
+ fingers = taps_or_options[:fingers] || fingers
23
+ else
24
+ taps = taps_or_options
25
+ end
26
+ end
27
+
28
+ recognizer = UITapGestureRecognizer.alloc.initWithTarget(self, action:'sugarcube_handle_gesture:')
29
+ recognizer.numberOfTapsRequired = taps if taps
30
+ recognizer.numberOfTouchesRequired = fingers if fingers
31
+ sugarcube_add_gesture(proc, recognizer)
32
+ end
33
+
34
+ def on_pinch(&proc)
35
+ recognizer = UIPinchGestureRecognizer.alloc.initWithTarget(self, action:'sugarcube_handle_gesture:')
36
+ sugarcube_add_gesture(proc, recognizer)
37
+ end
38
+
39
+ def on_rotate(&proc)
40
+ recognizer = UIRotationGestureRecognizer.alloc.initWithTarget(self, action:'sugarcube_handle_gesture:')
41
+ sugarcube_add_gesture(proc, recognizer)
42
+ end
43
+
44
+ def on_swipe(direction_or_options=nil, &proc)
45
+ direction = UISwipeGestureRecognizerDirectionRight
46
+ fingers = nil
47
+
48
+ if direction_or_options
49
+ if direction_or_options.is_a? Hash
50
+ direction = direction_or_options[:direction] || direction
51
+ fingers = direction_or_options[:fingers] || fingers
52
+ else
53
+ direction = direction_or_options
54
+ end
55
+ end
56
+
57
+ case direction
58
+ when :left
59
+ direction = UISwipeGestureRecognizerDirectionLeft
60
+ when :right
61
+ direction = UISwipeGestureRecognizerDirectionRight
62
+ when :up
63
+ direction = UISwipeGestureRecognizerDirectionUp
64
+ when :down
65
+ direction = UISwipeGestureRecognizerDirectionDown
66
+ end
67
+
68
+ recognizer = UISwipeGestureRecognizer.alloc.initWithTarget(self, action:'sugarcube_handle_gesture:')
69
+ recognizer.direction = direction if direction
70
+ recognizer.numberOfTouchesRequired = fingers if fingers
71
+ sugarcube_add_gesture(proc, recognizer)
72
+ end
73
+
74
+ def on_pan(fingers_or_options=nil, &proc)
75
+ fingers = nil
76
+ min_fingers = nil
77
+ max_fingers = nil
78
+
79
+ if fingers_or_options
80
+ if fingers_or_options.is_a? Hash
81
+ fingers = fingers_or_options[:fingers] || fingers
82
+ min_fingers = fingers_or_options[:min_fingers] || min_fingers
83
+ max_fingers = fingers_or_options[:max_fingers] || max_fingers else
84
+ fingers = fingers_or_options
85
+ end
86
+ end
87
+
88
+ recognizer = UIPanGestureRecognizer.alloc.initWithTarget(self, action:'sugarcube_handle_gesture:')
89
+ sugarcube_add_gesture(proc, recognizer)
90
+ end
91
+
92
+ def on_press(duration_or_options=nil, &proc)
93
+ duration = nil
94
+ taps = nil
95
+ fingers = nil
96
+
97
+ if duration_or_options
98
+ if duration_or_options.is_a? Hash
99
+ duration = duration_or_options[:duration] || duration
100
+ taps = duration_or_options[:taps] || taps
101
+ fingers = duration_or_options[:fingers] || fingers
102
+ else
103
+ duration = duration_or_options
104
+ end
105
+ end
106
+
107
+ recognizer = UILongPressGestureRecognizer.alloc.initWithTarget(self, action:'sugarcube_handle_gesture:')
108
+ recognizer.minimumPressDuration = duration if duration
109
+ recognizer.numberOfTapsRequired = taps if taps
110
+ recognizer.numberOfTouchesRequired = fingers if fingers
111
+ sugarcube_add_gesture(proc, recognizer)
112
+ end
113
+
114
+ private
115
+ def sugarcube_handle_gesture(recognizer)
116
+ handler = @sugarcube_recognizers[recognizer]
117
+ if handler.arity == 0
118
+ handler.call
119
+ else
120
+ handler.call(recognizer)
121
+ end
122
+ end
123
+
124
+ # Adds the recognizer and keeps a strong reference to the Proc object.
125
+ def sugarcube_add_gesture(proc, recognizer)
126
+ self.addGestureRecognizer(recognizer)
127
+
128
+ @sugarcube_recognizers = {} unless @sugarcube_recognizers
129
+ @sugarcube_recognizers[recognizer] = proc
130
+
131
+ recognizer
132
+ end
133
+
134
+ end