teacup 1.0.4 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -5,3 +5,4 @@ resources/*.nib
5
5
  resources/*.momd
6
6
  resources/*.storyboardc
7
7
  teacup-*.gem
8
+ /.dat*
data/Gemfile.lock CHANGED
@@ -1,14 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- teacup (1.0.3)
4
+ teacup (1.2.2)
5
5
  rake
6
6
 
7
7
  GEM
8
8
  remote: http://rubygems.org/
9
9
  specs:
10
10
  diff-lcs (1.1.3)
11
- rake (0.9.2.2)
11
+ rake (10.0.2)
12
12
  rspec (2.10.0)
13
13
  rspec-core (~> 2.10.0)
14
14
  rspec-expectations (~> 2.10.0)
@@ -0,0 +1,22 @@
1
+ Teacup::Stylesheet.new :custom do
2
+ style :container,
3
+ frame: [[0, 0], [100, 20]]
4
+
5
+ style :label,
6
+ text: 'custom label',
7
+ frame: [[0, 0], [100, 20]]
8
+ end
9
+
10
+ class CustomTeacupClass
11
+ include Teacup::Layout
12
+
13
+ def initialize
14
+ self.stylesheet = :custom
15
+ end
16
+
17
+ def create_container
18
+ layout(UIView, :container) do
19
+ subview(UILabel, :label)
20
+ end
21
+ end
22
+ end
data/lib/teacup/layout.rb CHANGED
@@ -116,9 +116,9 @@ module Teacup
116
116
  # prevents the calling of restyle! until we return to this method
117
117
  should_restyle = Teacup.should_restyle_and_block
118
118
 
119
- unless view.stylesheet
120
- view.stylesheet = stylesheet
121
- end
119
+ # assign the 'teacup_next_responder', which is queried for a stylesheet if
120
+ # one is not explicitly assigned to the view
121
+ view.teacup_next_responder = self
122
122
  view.stylename = name
123
123
  if properties
124
124
  view.style(properties) if properties
@@ -126,7 +126,13 @@ module Teacup
126
126
 
127
127
  if block_given?
128
128
  superview_chain << view
129
- instance_exec(view, &block) if block_given?
129
+ begin
130
+ instance_exec(view, &block) if block_given?
131
+ rescue NoMethodError => e
132
+ NSLog("Exception executing layout(#{view.inspect}) in #{self.inspect} (stylesheet=#{stylesheet})")
133
+ raise e
134
+ end
135
+
130
136
  superview_chain.pop
131
137
  end
132
138
 
data/lib/teacup/style.rb CHANGED
@@ -28,60 +28,77 @@ module Teacup
28
28
  supports[orientation_key]
29
29
  end
30
30
 
31
- def build(target=nil, orientation=nil, seen={})
32
- properties = Style.new.update(self)
31
+ def build(target=nil, rotation_orientation=nil, seen={})
32
+ properties = Style.new
33
33
  properties.stylename = self.stylename
34
34
  properties.stylesheet = self.stylesheet
35
35
 
36
- # at this point, we really DO need the orientation
37
- unless orientation
36
+ # if we have an orientation, only apply those styles. otherwise apply the
37
+ # entire style, including the current orientation.
38
+ if rotation_orientation
39
+ # in order to preserve the "local-first" override, we need to *delete*
40
+ # the keys in imported_stylesheets and extended_properties that are
41
+ # present in this style - even though we don't ultimately *apply* the
42
+ # styles
43
+ delete_keys = self.keys
44
+ orientation = rotation_orientation
45
+ else
46
+ delete_keys = []
47
+ properties.update(self)
38
48
  orientation = UIApplication.sharedApplication.statusBarOrientation
39
49
  end
40
50
 
41
51
  # first, move orientation settings into properties "base" level.
42
52
  if orientation
43
53
  Overrides[orientation].each do |orientation_key|
44
- if override = properties.delete(orientation_key)
54
+ if override = self[orientation_key]
45
55
  # override is first, so it takes precedence
46
56
  if override.is_a? Hash
47
57
  Teacup::merge_defaults override, properties, properties
48
58
  end
49
- properties.supports[orientation_key] = !!override
50
59
  end
51
60
  end
52
61
  end
53
62
 
54
63
  # delete all of them from `properties`
55
64
  Orientations.each do |orientation_key|
56
- if properties.delete(orientation_key)
65
+ if self[orientation_key]
57
66
  properties.supports[orientation_key] = true
58
67
  end
68
+ properties.delete(orientation_key)
59
69
  end
60
70
 
61
71
  # now we can merge extends, and importing. before merging, these will go
62
72
  # through the same process that we just finished on the local style
63
73
  if stylesheet && stylesheet.is_a?(Teacup::Stylesheet)
64
74
  stylesheet.imported_stylesheets.reverse.each do |stylesheet|
65
- imported_properties = stylesheet.query(self.stylename, target, orientation, seen)
75
+ imported_properties = stylesheet.query(self.stylename, target, rotation_orientation, seen)
76
+ delete_keys.each do |key|
77
+ imported_properties.delete(key)
78
+ end
66
79
  Teacup::merge_defaults! properties, imported_properties
67
80
  end
68
81
 
69
- if also_includes = properties.delete(:extends)
82
+ if also_includes = self[:extends]
70
83
  also_includes = [also_includes] unless also_includes.is_a? Array
71
84
 
72
85
  # turn style names into Hashes by querying them on the stylesheet
73
86
  # (this does not pass `seen`, because this is a new query)
74
87
  also_includes.each do |also_include|
75
- extended_properties = stylesheet.query(also_include, target, orientation)
88
+ extended_properties = stylesheet.query(also_include, target, rotation_orientation)
89
+ delete_keys.each do |key|
90
+ extended_properties.delete(key)
91
+ end
76
92
  Teacup::merge_defaults! properties, extended_properties
77
93
  end
78
94
  end
95
+ properties.delete(:extends)
79
96
 
80
97
  # if we know the class of the target, we can apply styles via class
81
98
  # inheritance. We do not pass `target` in this case.
82
99
  if target
83
100
  target.class.ancestors.each do |ancestor|
84
- extended_properties = stylesheet.query(ancestor, nil, orientation)
101
+ extended_properties = stylesheet.query(ancestor, nil, rotation_orientation)
85
102
  Teacup::merge_defaults!(properties, extended_properties)
86
103
  end
87
104
  end
@@ -2,7 +2,7 @@
2
2
  # Teacup::Stylesheet.new :main do
3
3
  # style :root,
4
4
  # # stays centered and grows in height
5
- # autoresizingMask: left|right|height
5
+ # autoresizingMask: flexible_left|flexible_right|flexible_height
6
6
  # end
7
7
  module Teacup
8
8
  class Stylesheet
@@ -1,5 +1,5 @@
1
1
  module Teacup
2
2
 
3
- VERSION = '1.0.4'
3
+ VERSION = '1.2.2'
4
4
 
5
5
  end
@@ -9,6 +9,10 @@ class UIView
9
9
  # The current stylename that is used to look up properties in the stylesheet.
10
10
  attr_reader :stylename
11
11
 
12
+ # Any class that includes Teacup::Layout gets a `layout` method, which assigns
13
+ # itself as the 'teacup_next_responder'.
14
+ attr_accessor :teacup_next_responder
15
+
12
16
  # Enable debug messages for this object
13
17
  attr_accessor :debug
14
18
 
@@ -19,7 +23,7 @@ class UIView
19
23
  # @param Symbol stylename
20
24
  def stylename=(new_stylename)
21
25
  @stylename = new_stylename
22
- restyle! if Teacup.should_restyle?
26
+ restyle!
23
27
  end
24
28
 
25
29
  # Alter the stylesheet of this view.
@@ -36,7 +40,6 @@ class UIView
36
40
  should_restyle = Teacup.should_restyle_and_block
37
41
 
38
42
  @stylesheet = new_stylesheet
39
- subviews.each{ |subview| subview.set_stylesheet_quickly(new_stylesheet) }
40
43
 
41
44
  if should_restyle
42
45
  Teacup.should_restyle!
@@ -44,9 +47,25 @@ class UIView
44
47
  end
45
48
  end
46
49
 
47
- def set_stylesheet_quickly(new_stylesheet)
48
- @stylesheet = new_stylesheet
49
- subviews.each{ |subview| subview.set_stylesheet_quickly(new_stylesheet) }
50
+ def stylesheet
51
+ super
52
+ # is a stylesheet assigned explicitly?
53
+ retval = @stylesheet
54
+
55
+ # the 'teacup_next_responder' is assigned in the `layout` method, and links
56
+ # any views created there to the custom class (could be a controller, could
57
+ # be any class that includes Teacup::Layout). That responder is checked
58
+ # next, but only if it wouldn't result in a circular loop.
59
+ if ! retval && @teacup_next_responder && teacup_next_responder != self
60
+ retval = @teacup_next_responder.stylesheet
61
+ end
62
+
63
+ # lastly, go up the chain; either a controller or superview
64
+ if ! retval && nextResponder
65
+ retval = nextResponder.stylesheet
66
+ end
67
+
68
+ return retval
50
69
  end
51
70
 
52
71
  def restyle!(orientation=nil)
@@ -94,6 +113,8 @@ class UIView
94
113
  end
95
114
 
96
115
  case original_constraint.relative_to
116
+ when nil
117
+ constraint.relative_to = nil
97
118
  when UIView
98
119
  constraint.relative_to = original_constraint.relative_to
99
120
  when :self
@@ -111,6 +132,17 @@ class UIView
111
132
  end
112
133
  end
113
134
 
135
+ if original_constraint.relative_to && ! constraint.relative_to
136
+ puts "Could not find #{original_constraint.relative_to.inspect}"
137
+ container = self
138
+ tab = ' '
139
+ while container && constraint.relative_to.nil?
140
+ tab << '->'
141
+ puts "#{tab} #{container.stylename.inspect}"
142
+ container = container.superview
143
+ end
144
+ end
145
+
114
146
  # the return value, for the map
115
147
  constraint.nslayoutconstraint
116
148
  end
@@ -157,6 +189,7 @@ class UIView
157
189
  # TODO: This should be in a style-sheet!
158
190
  UIView.setAnimationDuration(options[:duration]) if options[:duration]
159
191
  UIView.setAnimationCurve(options[:curve]) if options[:curve]
192
+ UIView.setAnimationDelay(options[:delay]) if options[:delay]
160
193
  self.stylename = stylename
161
194
  UIView.commitAnimations
162
195
  end
@@ -172,6 +205,7 @@ class UIView
172
205
  UIView.beginAnimations(nil, context: nil)
173
206
  UIView.setAnimationDuration(style[:duration]) if style[:duration]
174
207
  UIView.setAnimationCurve(style[:curve]) if style[:curve]
208
+ UIView.setAnimationDelay(options[:delay]) if options[:delay]
175
209
  style(style)
176
210
  UIView.commitAnimations
177
211
  end
@@ -69,8 +69,8 @@ class UIViewController
69
69
  # stylesheet = :ipadhorizontal
70
70
  def stylesheet=(new_stylesheet)
71
71
  @stylesheet = new_stylesheet
72
- if self.view
73
- self.view.stylesheet = new_stylesheet
72
+ if self.viewLoaded?
73
+ self.view.restyle!
74
74
  end
75
75
  end
76
76
 
@@ -99,36 +99,27 @@ class UIViewController
99
99
  parent_class = parent_class.superclass
100
100
  end
101
101
 
102
+ should_restyle = Teacup.should_restyle_and_block
103
+
102
104
  if my_stylesheet and not self.stylesheet
103
105
  self.stylesheet = my_stylesheet
104
106
  end
105
107
 
106
108
  if layout_definition
107
109
  stylename, properties, block = layout_definition
108
- should_restyle = Teacup.should_restyle_and_block
109
110
  layout(view, stylename, properties, &block)
110
- Teacup.should_restyle! if should_restyle
111
111
  end
112
112
 
113
- layoutDidLoad
114
- end
115
-
116
- alias old_viewWillAppear viewWillAppear
113
+ if should_restyle
114
+ Teacup.should_restyle!
115
+ self.view.restyle!
116
+ end
117
117
 
118
- def viewWillAppear(animated)
119
- old_viewWillAppear(animated)
120
- self.view.restyle! unless @teacup_view_appeared
121
118
  if defined? NSLayoutConstraint
122
119
  self.view.apply_constraints
123
120
  end
124
- @teacup_view_appeared = true
125
- end
126
121
 
127
- alias old_viewDidDisappear viewDidDisappear
128
-
129
- def viewDidDisappear(animated)
130
- old_viewDidDisappear(animated)
131
- @teacup_view_appeared = false
122
+ layoutDidLoad
132
123
  end
133
124
 
134
125
  def layoutDidLoad
@@ -1,22 +1,21 @@
1
1
  # Methods to retrieve a subview using the stylename as a key
2
- # Kinda similar to jQuery-style $().find('stylename')
2
+ # Kinda similar to jQuery-style $(el).find('stylename')
3
3
  class UIView
4
4
 
5
- # get one subview by stylename or class
5
+ # get one subview by stylename or class. If the receiver matches, it will be
6
+ # returned
6
7
  # my_view.viewWithStylename :button => #<UIButton..>
7
8
  # my_view.viewWithStylename UIButton => #<UIButton..>
8
9
  def viewWithStylename name_or_class
9
- if name_or_class.is_a? Class
10
- view = subviews.find { |view| view.is_a? name_or_class }
11
- else
12
- view = subviews.find { |view| view.stylename == name_or_class }
13
- end
10
+ return self if self._teacup_check_stylename(name_or_class)
11
+
12
+ view = subviews.find { |view| view._teacup_check_stylename(name_or_class) }
14
13
  return view if view
15
14
 
16
15
  # found_subview will get assigned to the view we want, but the subview is
17
16
  # what is returned.
18
17
  found_subview = nil
19
- view = subviews.find {|subview| found_subview = subview.viewWithStylename(name_or_class) }
18
+ view = subviews.find { |subview| found_subview = subview.viewWithStylename(name_or_class) }
20
19
  return found_subview if view
21
20
 
22
21
  nil # couldn't find it
@@ -27,17 +26,21 @@ class UIView
27
26
  # my_view.viewsWithStylename UIButton => [#<UIButton..>, #<UIButton...>]
28
27
  def viewsWithStylename name_or_class
29
28
  r = []
29
+ r << self if self._teacup_check_stylename(name_or_class)
30
+
30
31
  subviews.each do |view|
31
- if name_or_class.is_a? Class
32
- if view.is_a? name_or_class
33
- r << view
34
- end
35
- elsif view.stylename == name_or_class
36
- r << view
37
- end
32
+ r << view if view._teacup_check_stylename(name_or_class)
38
33
  r.concat view.viewsWithStylename name_or_class
39
34
  end
40
35
  r
41
36
  end
42
37
 
38
+ def _teacup_check_stylename(name_or_class)
39
+ if name_or_class.is_a? Class
40
+ self.is_a? name_or_class
41
+ else
42
+ self.stylename == name_or_class
43
+ end
44
+ end
45
+
43
46
  end
@@ -0,0 +1,23 @@
1
+ describe "Any class that includes Teacup::Layout" do
2
+ before do
3
+ @subject = CustomTeacupClass.new
4
+ end
5
+
6
+ it "should be able to have a stylesheet" do
7
+ @subject.stylesheet.class.should == Teacup::Stylesheet
8
+ end
9
+
10
+ it "should be able to layout and create views" do
11
+ @subject.create_container.should != nil
12
+ end
13
+
14
+ it "should have a container and label that are styled" do
15
+ container = @subject.create_container
16
+ container.frame.size.width.should == 100
17
+ container.frame.size.height.should == 20
18
+ container.subviews.length.should == 1
19
+ label = container.subviews[0]
20
+ label.text.should == 'custom label'
21
+ end
22
+
23
+ end
data/spec/main_spec.rb CHANGED
@@ -25,9 +25,9 @@ describe "Application 'Teacup'" do
25
25
  it "root view should be styled as :root" do
26
26
  @root_view.stylename.should == :root
27
27
  @root_view.frame.origin.x.should == 0
28
- @root_view.frame.origin.y.should == 0
28
+ @root_view.frame.origin.y.should == 20
29
29
  @root_view.frame.size.width.should == 320
30
- @root_view.frame.size.height.should == 480
30
+ @root_view.frame.size.height.should == 460
31
31
  @root_view.backgroundColor.should == UIColor.yellowColor
32
32
  end
33
33
 
data/spec/style_spec.rb CHANGED
@@ -136,6 +136,7 @@ describe "Teacup::Style" do
136
136
  it 'should respect precedence rules' do
137
137
  sheet = Teacup::Stylesheet.new do
138
138
  style :style1,
139
+ landscape: { tag: 1 },
139
140
  portrait: { text: "extended", tag: 1 }
140
141
  end
141
142
 
@@ -144,9 +145,13 @@ describe "Teacup::Style" do
144
145
  style2[:text] = "text"
145
146
  style2[:extends] = :style1
146
147
 
148
+ built = style2.build(nil)
149
+ built[:tag].should == 1
150
+ built[:text].should == 'text'
151
+
147
152
  built = style2.build(nil, UIInterfaceOrientationPortrait)
148
153
  built[:tag].should == 1
149
- built[:text].should == "text"
154
+ built[:text].should == nil
150
155
  end
151
156
 
152
157
  it 'should respect merge based on class inheritance' do
@@ -172,4 +177,27 @@ describe "Teacup::Style" do
172
177
  built[:baz].should == 'baz'
173
178
  end
174
179
 
180
+ it 'should not apply default styles when orientation is specified ' do
181
+ sheet = Teacup::Stylesheet.new do
182
+ style :style1,
183
+ top: 10,
184
+ left: 8,
185
+ landscape: { width: 100 },
186
+ portrait: { width: 100 }
187
+ style :style2,
188
+ top: 10,
189
+ left: 8,
190
+ landscape: { width: 100 },
191
+ portrait: { width: 100 }
192
+ end
193
+
194
+ style3 = Teacup::Style.new
195
+ style3.stylesheet = sheet
196
+
197
+ built = style3.build(UIInterfaceOrientationPortrait)
198
+ built[:top].should == nil
199
+ built[:left].should == nil
200
+ built[:width].should == nil
201
+ end
202
+
175
203
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: teacup
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.2.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-02 00:00:00.000000000 Z
12
+ date: 2013-02-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -70,6 +70,7 @@ files:
70
70
  - app/controllers/first_controller.rb
71
71
  - app/controllers/landscape_only_controller.rb
72
72
  - app/controllers/tableview_controller.rb
73
+ - app/custom_class.rb
73
74
  - app/styles/main_styles.rb
74
75
  - app/views/custom_view.rb
75
76
  - lib/dummy.rb
@@ -101,6 +102,7 @@ files:
101
102
  - samples/Hai/spec/main_spec.rb
102
103
  - samples/Hai/styles/iphone.rb
103
104
  - samples/README.md
105
+ - spec/custom_class_spec.rb
104
106
  - spec/main_spec.rb
105
107
  - spec/style_spec.rb
106
108
  - spec/stylesheet_spec.rb
@@ -133,6 +135,7 @@ signing_key:
133
135
  specification_version: 3
134
136
  summary: A community-driven DSL for creating user interfaces on iOS.
135
137
  test_files:
138
+ - spec/custom_class_spec.rb
136
139
  - spec/main_spec.rb
137
140
  - spec/style_spec.rb
138
141
  - spec/stylesheet_spec.rb