simple-view 0.1.3 → 0.5

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.
Files changed (64) hide show
  1. data/.gitignore +1 -0
  2. data/Gemfile.lock +1 -1
  3. data/README.md +14 -7
  4. data/Rakefile +3 -7
  5. data/app/app_delegate.rb +2 -0
  6. data/app/simple_view_controller.rb +33 -15
  7. data/app/user_info_controller.rb +67 -0
  8. data/app/view_anchoring_controller.rb +27 -0
  9. data/lib/simple-view.rb +1 -7
  10. data/lib/simple_view/extensions/fixnum.rb +9 -0
  11. data/lib/simple_view/extensions/string.rb +16 -3
  12. data/lib/simple_view/extensions/ui_color.rb +2 -2
  13. data/lib/simple_view/extensions/ui_font.rb +2 -2
  14. data/lib/simple_view/extensions/ui_image.rb +2 -2
  15. data/lib/simple_view/extensions/ui_view.rb +48 -81
  16. data/lib/simple_view/layout.rb +1 -1
  17. data/lib/simple_view/styles.rb +4 -4
  18. data/lib/simple_view/version.rb +1 -1
  19. data/lib/simple_view/view_builder.rb +250 -0
  20. data/lib/simple_view/view_proxy.rb +22 -44
  21. data/spec/acceptance/view_anchoring_controller_spec.rb +82 -0
  22. data/spec/extensions/fixnum_spec.rb +15 -0
  23. data/spec/extensions/string_spec.rb +1 -1
  24. data/spec/extensions/ui_color_spec.rb +1 -1
  25. data/spec/extensions/ui_font_spec.rb +1 -1
  26. data/spec/extensions/ui_image_spec.rb +1 -1
  27. data/spec/extensions/ui_view_spec.rb +1 -17
  28. data/spec/layout_spec.rb +15 -0
  29. data/spec/styles_spec.rb +17 -0
  30. data/spec/view_builder_spec.rb +229 -0
  31. data/spec/view_proxy_spec.rb +172 -0
  32. metadata +18 -44
  33. data/lib/simple_view/builders/helpers/has_background_color.rb +0 -10
  34. data/lib/simple_view/builders/helpers/has_color.rb +0 -9
  35. data/lib/simple_view/builders/helpers/has_font.rb +0 -9
  36. data/lib/simple_view/builders/helpers/has_text_color.rb +0 -11
  37. data/lib/simple_view/builders/helpers/has_tint_color.rb +0 -10
  38. data/lib/simple_view/builders/ui_activity_indicator_view_builder.rb +0 -12
  39. data/lib/simple_view/builders/ui_button_builder.rb +0 -32
  40. data/lib/simple_view/builders/ui_control_builder.rb +0 -9
  41. data/lib/simple_view/builders/ui_image_view_builder.rb +0 -38
  42. data/lib/simple_view/builders/ui_label_builder.rb +0 -18
  43. data/lib/simple_view/builders/ui_progress_view_builder.rb +0 -28
  44. data/lib/simple_view/builders/ui_search_bar_builder.rb +0 -31
  45. data/lib/simple_view/builders/ui_segmented_control_builder.rb +0 -28
  46. data/lib/simple_view/builders/ui_slider_builder.rb +0 -52
  47. data/lib/simple_view/builders/ui_switch_builder.rb +0 -10
  48. data/lib/simple_view/builders/ui_tab_bar_builder.rb +0 -20
  49. data/lib/simple_view/builders/ui_table_view_builder.rb +0 -15
  50. data/lib/simple_view/builders/ui_table_view_cell_builder.rb +0 -19
  51. data/lib/simple_view/builders/ui_text_field_builder.rb +0 -8
  52. data/lib/simple_view/builders/ui_text_view_builder.rb +0 -8
  53. data/lib/simple_view/builders/ui_toolbar_builder.rb +0 -11
  54. data/lib/simple_view/builders/ui_view_builder.rb +0 -58
  55. data/spec/builders/ui_activity_indicator_view_builder_spec.rb +0 -12
  56. data/spec/builders/ui_button_builder_spec.rb +0 -12
  57. data/spec/builders/ui_control_builder_spec.rb +0 -5
  58. data/spec/builders/ui_image_view_builder_spec.rb +0 -31
  59. data/spec/builders/ui_progress_view_builder_spec.rb +0 -12
  60. data/spec/builders/ui_segmented_control_builder_spec.rb +0 -13
  61. data/spec/builders/ui_table_view_builder_spec.rb +0 -12
  62. data/spec/builders/ui_table_view_cell_builder_spec.rb +0 -17
  63. data/spec/builders/ui_view_builder_spec.rb +0 -35
  64. data/spec/simple_view_spec.rb +0 -193
@@ -1,7 +1,7 @@
1
1
  module SimpleView
2
2
  module Layout
3
3
  def setup view, locals = {}, &block
4
- proxy = SimpleView::ViewProxy.new view, locals
4
+ proxy = ViewProxy.new view, locals
5
5
  proxy.instance_eval &block if block_given?
6
6
  end
7
7
  end
@@ -1,14 +1,14 @@
1
1
  module SimpleView
2
2
  class Styles
3
- @@repo = {}
3
+ @repo = {}
4
4
 
5
5
  def self.define name, options = {}
6
- existing = @@repo[name] || {}
7
- @@repo[name] = existing.update(options)
6
+ @repo[name] ||= {}
7
+ @repo[name].merge! options
8
8
  end
9
9
 
10
10
  def self.for name
11
- @@repo[name]
11
+ @repo[name] || {}
12
12
  end
13
13
  end
14
14
  end
@@ -1,3 +1,3 @@
1
1
  module SimpleView
2
- VERSION = "0.1.3"
2
+ VERSION = "0.5"
3
3
  end
@@ -0,0 +1,250 @@
1
+ module SimpleView
2
+ class ViewBuilder
3
+ attr_reader :view
4
+ attr_accessor :top, :left, :bottom, :right, :width, :height
5
+
6
+ # first args (optional): bounds
7
+ # second args (optional): options
8
+ def self.view_for klass, *args
9
+ if args.nil? || args.size == 0
10
+ bounds = CGRectZero
11
+ options = {}
12
+ elsif args[0].is_a?(Hash)
13
+ bounds = CGRectZero
14
+ options = args[0]
15
+ else
16
+ bounds = args[0]
17
+ options = args.size > 1 ? args[1] : {}
18
+ end
19
+
20
+ builder = ViewBuilder.new klass, options
21
+ builder.size_within bounds
22
+ builder.view
23
+ end
24
+
25
+ def initialize klass, options = {}
26
+ options = extended_options_with_style klass, options
27
+ convert_primitives_to_objects_in_hash options
28
+
29
+ @view = view_for_class klass, klass, options
30
+ setValuesForKeysWithDictionary options
31
+ end
32
+
33
+ def convert_primitives_to_objects_in_hash options
34
+ options.each do |k,v|
35
+ options[k] = STRUCTS_MAP[v.class].call(v) if STRUCTS_MAP.has_key?(v.class)
36
+ end
37
+ end
38
+
39
+ def extended_options_with_style klass, options = {}
40
+ style_options = Styles.for(klass) || {}
41
+ style_names = options.delete(:styles)
42
+
43
+ if style_names.is_a?(Symbol)
44
+ style = Styles.for style_names
45
+ style_options.merge!(style) unless style.nil?
46
+
47
+ elsif style_names.is_a?(Array)
48
+ style_names.each do |style_name|
49
+ style = Styles.for style_name
50
+ style_options.merge!(style) unless style.nil?
51
+ end
52
+ end
53
+
54
+ style_options.merge options
55
+ end
56
+
57
+ def view_for_class klass, root_klass, options = {}
58
+ if VIEWS_MAP.key?(klass)
59
+ VIEWS_MAP[klass].call root_klass, options
60
+ else
61
+ view_for_class klass.superclass, root_klass, options
62
+ end
63
+ end
64
+
65
+ def size_within bounds
66
+ frame = @view.frame
67
+
68
+ if width.nil? && height.nil? && right.nil? && bottom.nil?
69
+ @view.sizeToFit
70
+ else
71
+ max_width = bounds.size.width
72
+ max_height = bounds.size.height
73
+
74
+ if width.nil?
75
+ self.width = 0.0
76
+ elsif width > 0 && width <= 1
77
+ if right.nil?
78
+ self.left ||= 0
79
+ self.right = max_width - max_width * width
80
+ else
81
+ self.left = max_width - max_width * width
82
+ end
83
+ end
84
+
85
+ if height.nil?
86
+ self.height = 0.0
87
+ elsif height > 0 && height <= 1
88
+ if bottom.nil?
89
+ self.top ||= 0
90
+ self.bottom = max_height - max_height * height
91
+ else
92
+ self.top = max_height - max_height * height
93
+ end
94
+ end
95
+
96
+ @view.autoresizingMask = UIViewAutoresizingNone
97
+ @view.autoresizingMask |= UIViewAutoresizingFlexibleTopMargin if top.nil?
98
+ @view.autoresizingMask |= UIViewAutoresizingFlexibleLeftMargin if left.nil?
99
+ @view.autoresizingMask |= UIViewAutoresizingFlexibleBottomMargin if bottom.nil?
100
+ @view.autoresizingMask |= UIViewAutoresizingFlexibleRightMargin if right.nil?
101
+ @view.autoresizingMask |= UIViewAutoresizingFlexibleWidth if !left.nil? && !right.nil?
102
+ @view.autoresizingMask |= UIViewAutoresizingFlexibleHeight if !top.nil? && !bottom.nil?
103
+
104
+ if !left.nil? && !right.nil?
105
+ frame.origin.x = left
106
+ frame.size.width = max_width - left - right
107
+ elsif !right.nil?
108
+ frame.origin.x = max_width - width - right
109
+ frame.size.width = width
110
+ elsif !left.nil?
111
+ frame.origin.x = left
112
+ frame.size.width = width
113
+ else
114
+ frame.origin.x = max_width / 2 - width / 2
115
+ frame.size.width = width
116
+ end
117
+
118
+ if !top.nil? && !bottom.nil?
119
+ frame.origin.y = top
120
+ frame.size.height = max_height - top - bottom
121
+ elsif !bottom.nil?
122
+ frame.origin.y = max_height - height - bottom
123
+ frame.size.height = height
124
+ elsif !top.nil?
125
+ frame.origin.y = top
126
+ frame.size.height = height
127
+ else
128
+ frame.origin.y = max_height / 2 - height / 2
129
+ frame.size.height = height
130
+ end
131
+
132
+ @view.frame = frame
133
+ end
134
+ end
135
+
136
+ def setValue value, forUndefinedKey: key
137
+ if key.end_with?('Color') || key.end_with?('color')
138
+ view.setValue value.to_color, forKey: key
139
+ elsif key.end_with?('Font') || key.end_with?('font')
140
+ view.setValue value.to_font, forKey: key
141
+ elsif key.end_with?('Image') || key.end_with?('image')
142
+ view.setValue value.to_image, forKey: key
143
+ elsif key == 'layer'
144
+ view.layer.setValuesForKeysWithDictionary value
145
+ else
146
+ view.setValue value, forKey: key
147
+ end
148
+ end
149
+
150
+ def setTop value
151
+ @top = value
152
+ end
153
+
154
+ def setLeft value
155
+ @left = value
156
+ end
157
+
158
+ def setBottom value
159
+ @bottom = value
160
+ end
161
+
162
+ def setRight value
163
+ @right = value
164
+ end
165
+
166
+ def setWidth value
167
+ @width = value
168
+ end
169
+
170
+ def setHeight value
171
+ @height = value
172
+ end
173
+
174
+ def setBackground_color color
175
+ view.backgroundColor = color.to_color
176
+ end
177
+
178
+ def setText_color color
179
+ view.textColor = color.to_color
180
+ end
181
+
182
+ def setTint_color color
183
+ @view.tintColor = color.to_color
184
+ end
185
+
186
+ STRUCTS_MAP = {
187
+ CGAffineTransform => Proc.new {|v| NSValue.valueWithCGAffineTransform(v) },
188
+ CGPoint => Proc.new {|v| NSValue.valueWithCGPoint(v) },
189
+ CGRect => Proc.new {|v| NSValue.valueWithCGRect(v) },
190
+ CGSize => Proc.new {|v| NSValue.valueWithCGSize(v) },
191
+ UIEdgeInsets => Proc.new {|v| NSValue.valueWithUIEdgeInsets(v) },
192
+ UIOffset => Proc.new {|v| NSValue.valueWithUIOffset(v) }
193
+ }
194
+
195
+ VIEWS_MAP = {
196
+ UIView => Proc.new {|klass, options| klass.alloc.initWithFrame CGRectZero },
197
+ UIControl => Proc.new {|klass, options| klass.alloc.init },
198
+ UIActionSheet => Proc.new {|klass, options|
199
+ title = options.delete(:title) || ''
200
+ delegate = options.delete(:delegate)
201
+ cancel_button_title = options.delete(:cancelButtonTitle) || options.delete(:cancel_button_title)
202
+ destructive_button_title = options.delete(:destructiveButtonTitle) || options.delete(:destructive_button_title)
203
+ other_button_titles = options.delete(:otherButtonTitles) || options.delete(:other_button_titles)
204
+
205
+ klass.alloc.initWithTitle title,
206
+ delegate: delegate,
207
+ cancelButtonTitle: cancel_button_title,
208
+ destructiveButtonTitle: destructive_button_title,
209
+ otherButtonTitles: other_button_titles, nil
210
+ },
211
+ UIActivityIndicatorView => Proc.new{|klass, options|
212
+ style = options.delete(:style) || UIActivityIndicatorViewStyleWhite
213
+ klass.alloc.initWithActivityIndicatorStyle style
214
+ },
215
+ UIButton => Proc.new{|klass, options|
216
+ button_type = options.delete(:buttonType) || options.delete(:button_type) || UIButtonTypeRoundedRect
217
+ klass.buttonWithType button_type
218
+ },
219
+ UIImageView => Proc.new{|klass, options|
220
+ image = options.delete(:image)
221
+ highlighted_image = options.delete(:highlightedImage) || options.delete(:highlighted_image)
222
+
223
+ if !image.nil? && !highlighted_image.nil?
224
+ klass.alloc.initWithImage image.to_image, highlightedImage: highlighted_image.to_image
225
+ elsif !image.nil?
226
+ klass.alloc.initWithImage image.to_image
227
+ else
228
+ klass.alloc.initWithFrame CGRectZero
229
+ end
230
+ },
231
+ UIProgressView => Proc.new{|klass, options|
232
+ style = options.delete(:style) || UIProgressViewStyleDefault
233
+ klass.alloc.initWithProgressViewStyle style
234
+ },
235
+ UISegmentedControl => Proc.new{|klass, options|
236
+ items = options.delete(:items) || []
237
+ klass.alloc.initWithItems items
238
+ },
239
+ UITableView => Proc.new{|klass, options|
240
+ style = options.delete(:style) || UITableViewStylePlain
241
+ klass.alloc.initWithFrame CGRectZero, style: style
242
+ },
243
+ UITableViewCell => Proc.new{|klass, options|
244
+ style = options.delete(:style) || UITableViewCellStyleDefault
245
+ identifier = options.delete(:reuseIdentifier) || options.delete(:reuse_identifier)
246
+ klass.alloc.initWithStyle style, reuseIdentifier: identifier
247
+ }
248
+ }
249
+ end
250
+ end
@@ -1,12 +1,12 @@
1
1
  module SimpleView
2
2
  class ViewProxy
3
- attr_reader :view
3
+ attr_reader :view, :locals
4
4
 
5
5
  def initialize view = nil, locals = {}
6
6
  @view = view
7
7
  @locals = locals
8
8
 
9
- if @locals
9
+ if !@locals.nil?
10
10
  @locals.each do |k, v|
11
11
  self.class.send :attr_accessor, k
12
12
  self.instance_variable_set "@#{k}", v
@@ -14,56 +14,34 @@ module SimpleView
14
14
  end
15
15
  end
16
16
 
17
- def build_view klass, options = {}
18
- builder_class = "#{klass}Builder"
19
-
20
- if SimpleView::Builders.const_defined? builder_class
21
- SimpleView::Builders.const_get(builder_class).new.build klass, options
22
- else
23
- if klass < UIControl
24
- SimpleView::Builders::UIControlBuilder.new.build klass, options
25
- else
26
- SimpleView::Builders::UIViewBuilder.new.build klass, options
27
- end
28
- end
29
- end
30
-
31
17
  def add klass, options = {}, &block
32
- subview = build_view klass, options
18
+ subview = create klass, options, &block
19
+ view.addSubview(subview) unless view.nil?
20
+ subview
21
+ end
33
22
 
34
- @view.addSubview(subview) unless @view.nil?
23
+ def create klass, options = {}, &block
24
+ bounds = view.nil? ? CGRectZero : view.bounds
25
+ subview = ViewBuilder.view_for klass, bounds, options
35
26
 
36
27
  if block_given?
37
- child_layout = ViewProxy.new(subview, @locals)
38
- child_layout.instance_eval &block
28
+ child_layout = ViewProxy.new subview, locals
29
+ child_layout.instance_exec subview, &block
39
30
  end
40
31
 
41
- subview.sizeToFit if options[:width].nil? && options[:height].nil? && options[:right].nil? && options[:bottom].nil?
42
- subview.invalidate_size
43
32
  subview
44
33
  end
45
34
 
46
- def activity_indicator(options = {}, &block) add(::UIActivityIndicatorView, options, &block); end
47
- def button(options = {}, &block) add(::UIButton, options, &block); end
48
- def date_picker(options = {}, &block) add(::UIDatePicker, options, &block); end
49
- def image_view(options = {}, &block) add(::UIImageView, options, &block); end
50
- def label(options = {}, &block) add(::UILabel, options, &block); end
51
- def page_control(options = {}, &block) add(::UIPageControl, options, &block); end
52
- def picker_view(options = {}, &block) add(::UIPickerView, options, &block); end
53
- def progress_view(options = {}, &block) add(::UIProgressView, options, &block); end
54
- def rect(options = {}, &block) add(::UIView, options, &block); end
55
- def scroll_view(options = {}, &block) add(::UIScrollView, options, &block); end
56
- def search_bar(options = {}, &block) add(::UISearchBar, options, &block); end
57
- def segmented_control(options = {}, &block) add(::UISegmentedControl, options, &block); end
58
- def slider(options = {}, &block) add(::UISlider, options, &block); end
59
- def stepper(options = {}, &block) add(::UIStepper, options, &block); end
60
- def switch(options = {}, &block) add(::UISwitch, options, &block); end
61
- def tab_bar(options = {}, &block) add(::UITabBar, options, &block); end
62
- def table_view(options = {}, &block) add(::UITableView, options, &block); end
63
- def table_view_cell(options = {}, &block) add(::UITableViewCell, options, &block); end
64
- def text_field(options = {}, &block) add(::UITextField, options, &block); end
65
- def text_view(options = {}, &block) add(::UITextView, options, &block); end
66
- def toolbar(options = {}, &block) add(::UIToolbar, options, &block); end
67
- def web_view(options = {}, &block) add(::UIWebView, options, &block); end
35
+ [::UIActionSheet, ::UIActivityIndicatorView, ::UIButton, ::UIDatePicker, ::UIImageView, ::UILabel,
36
+ ::UIPageControl, ::UIPickerView, ::UIProgressView, ::UIScrollView, ::UISearchBar, ::UISegmentedControl,
37
+ ::UISlider, ::UIStepper, ::UISwitch, ::UITabBar, ::UITableView, ::UITableViewCell, ::UITextField, ::UITextView,
38
+ ::UIToolbar, ::UIWebView].each do |klass|
39
+ shorthand = "#{klass}"[2..-1].underscore.to_sym
40
+ define_method(shorthand) do |*args, &block|
41
+ options = args[0] || {}
42
+ add klass, options, &block
43
+ end
44
+ end
45
+ def rect(options = {}, &block) add(::UIView, options, &block); end
68
46
  end
69
47
  end
@@ -0,0 +1,82 @@
1
+ describe 'ViewAnchoringController' do
2
+ tests ViewAnchoringController
3
+
4
+ BLOCK_SIZE = 20
5
+
6
+ it "should have a view anchored to the four sides of the parent view" do
7
+ view = controller.view.find('fill')
8
+ view.frame.should == controller.view.bounds
9
+ end
10
+
11
+ it "should have a view anchored to top left corner" do
12
+ view = controller.view.find('tl')
13
+ view.frame.origin.x.should == 0
14
+ view.frame.origin.y.should == 0
15
+ view.frame.size.width.should == BLOCK_SIZE
16
+ view.frame.size.height.should == BLOCK_SIZE
17
+ end
18
+
19
+ it "should have a view anchored to top and centered" do
20
+ view = controller.view.find('tc')
21
+ view.center.x.should == controller.view.bounds.size.width / 2
22
+ view.frame.origin.y.should == 0
23
+ view.frame.size.width.should == BLOCK_SIZE
24
+ view.frame.size.height.should == BLOCK_SIZE
25
+ end
26
+
27
+ it "should have a view anchored to top right corner" do
28
+ view = controller.view.find('tr')
29
+ view.frame.origin.x.should == controller.view.bounds.size.width - BLOCK_SIZE
30
+ view.frame.origin.y.should == 0
31
+ view.frame.size.width.should == BLOCK_SIZE
32
+ view.frame.size.height.should == BLOCK_SIZE
33
+ end
34
+
35
+ it "should have a view anchored to middle left corner" do
36
+ view = controller.view.find('ml')
37
+ view.frame.origin.x.should == 0
38
+ view.center.y.should == controller.view.bounds.size.height / 2
39
+ view.frame.size.width.should == BLOCK_SIZE
40
+ view.frame.size.height.should == BLOCK_SIZE
41
+ end
42
+
43
+ it "should have a view anchored to middle and centered" do
44
+ view = controller.view.find('mc')
45
+ view.center.x.should == controller.view.bounds.size.width / 2
46
+ view.center.y.should == controller.view.bounds.size.height / 2
47
+ view.frame.size.width.should == BLOCK_SIZE
48
+ view.frame.size.height.should == BLOCK_SIZE
49
+ end
50
+
51
+ it "should have a view anchored to middle right corner" do
52
+ view = controller.view.find('mr')
53
+ view.frame.origin.x.should == controller.view.bounds.size.width - BLOCK_SIZE
54
+ view.center.y.should == controller.view.bounds.size.height / 2
55
+ view.frame.size.width.should == BLOCK_SIZE
56
+ view.frame.size.height.should == BLOCK_SIZE
57
+ end
58
+
59
+ it "should have a view anchored to bottom left corner" do
60
+ view = controller.view.find('bl')
61
+ view.frame.origin.x.should == 0
62
+ view.frame.origin.y.should == controller.view.bounds.size.height - BLOCK_SIZE
63
+ view.frame.size.width.should == BLOCK_SIZE
64
+ view.frame.size.height.should == BLOCK_SIZE
65
+ end
66
+
67
+ it "should have a view anchored to bottom and centered" do
68
+ view = controller.view.find('bc')
69
+ view.center.x.should == controller.view.bounds.size.width / 2
70
+ view.frame.origin.y.should == controller.view.bounds.size.height - BLOCK_SIZE
71
+ view.frame.size.width.should == BLOCK_SIZE
72
+ view.frame.size.height.should == BLOCK_SIZE
73
+ end
74
+
75
+ it "should have a view anchored to bottom right corner" do
76
+ view = controller.view.find('br')
77
+ view.frame.origin.x.should == controller.view.bounds.size.width - BLOCK_SIZE
78
+ view.frame.origin.y.should == controller.view.bounds.size.height - BLOCK_SIZE
79
+ view.frame.size.width.should == BLOCK_SIZE
80
+ view.frame.size.height.should == BLOCK_SIZE
81
+ end
82
+ end