teacup 1.0.4 → 1.2.2

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
@@ -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