teacup 0.0.1.pre → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/.gitignore +5 -3
  2. data/CHANGES.md +26 -0
  3. data/Gemfile +2 -0
  4. data/Gemfile.lock +1 -1
  5. data/LICENSE +26 -0
  6. data/README.md +383 -95
  7. data/Rakefile +8 -36
  8. data/app/app_delegate.rb +14 -0
  9. data/app/controllers/first_controller.rb +71 -0
  10. data/app/controllers/landscape_only_controller.rb +16 -0
  11. data/app/controllers/tableview_controller.rb +0 -0
  12. data/app/styles/main_styles.rb +111 -0
  13. data/app/views/custom_view.rb +4 -0
  14. data/lib/dummy.rb +56 -0
  15. data/lib/teacup/handler.rb +99 -0
  16. data/lib/teacup/layout.rb +22 -74
  17. data/lib/teacup/merge_defaults.rb +45 -0
  18. data/lib/teacup/style.rb +93 -0
  19. data/lib/teacup/stylesheet.rb +242 -0
  20. data/lib/teacup/stylesheet_extensions/rotation.rb +38 -0
  21. data/lib/teacup/version.rb +1 -1
  22. data/lib/teacup/z_core_extensions/ca_layer.rb +6 -0
  23. data/lib/teacup/z_core_extensions/ui_view.rb +119 -0
  24. data/lib/teacup/z_core_extensions/ui_view_controller.rb +179 -0
  25. data/lib/teacup/z_core_extensions/ui_view_getters.rb +34 -0
  26. data/lib/teacup/z_core_extensions/z_handlers.rb +57 -0
  27. data/lib/teacup.rb +16 -33
  28. data/samples/Hai/Rakefile +7 -2
  29. data/samples/Hai/app/app_delegate.rb +2 -2
  30. data/samples/Hai/app/hai_controller.rb +8 -4
  31. data/samples/Hai/styles/iphone.rb +40 -0
  32. data/spec/main_spec.rb +226 -0
  33. data/spec/style_spec.rb +171 -0
  34. data/spec/stylesheet_spec.rb +348 -0
  35. data/spec/view_spec.rb +103 -0
  36. data/teacup.gemspec +13 -13
  37. metadata +47 -46
  38. data/.rspec +0 -2
  39. data/lib/teacup/contributors.rb +0 -7
  40. data/lib/teacup/core_extensions/ui_view.rb +0 -4
  41. data/lib/teacup/core_extensions/ui_view_controller.rb +0 -62
  42. data/lib/teacup/style_sheet.rb +0 -195
  43. data/lib/teacup/view.rb +0 -123
  44. data/pkg/teacup-0.0.0.gem +0 -0
  45. data/pkg/teacup-0.0.1.gem +0 -0
  46. data/proposals/other/README.md +0 -45
  47. data/proposals/other/app/config/application.rb +0 -1
  48. data/proposals/other/app/config/boot.rb +0 -1
  49. data/proposals/other/app/config/initializers/twitter.rb +0 -7
  50. data/proposals/other/app/controllers/events_controller.rb +0 -28
  51. data/proposals/other/app/controllers/venues_controller.rb +0 -4
  52. data/proposals/other/app/db/README.md +0 -16
  53. data/proposals/other/app/db/migrations/20120514201043_create_events.rb +0 -9
  54. data/proposals/other/app/db/migrations/20120514201044_add_price_to_events.rb +0 -5
  55. data/proposals/other/app/db/migrations/20120514201045_create_venues.rb +0 -8
  56. data/proposals/other/app/db/schema.rb +0 -19
  57. data/proposals/other/app/models/event.rb +0 -14
  58. data/proposals/other/app/models/venue.rb +0 -3
  59. data/proposals/other/app/views/events/edit.ipad.rb +0 -8
  60. data/proposals/other/app/views/events/edit.iphone.rb +0 -7
  61. data/proposals/other/app/views/events/show.ipad.rb +0 -2
  62. data/proposals/other/app/views/events/show.iphone.rb +0 -3
  63. data/samples/Hai/styles/ipad.rb +0 -11
  64. data/samples/Hai/styles/ipad_vertical.rb +0 -3
  65. data/spec/spec_helper.rb +0 -5
  66. data/spec/teacup/contributions_spec.rb +0 -13
  67. data/spec/teacup/version_spec.rb +0 -9
@@ -0,0 +1,71 @@
1
+
2
+ class FirstController < UIViewController
3
+
4
+ stylesheet :first
5
+
6
+ layout :root do
7
+ subview(CustomView, :background) do
8
+ @welcome = subview(UILabel, :welcome)
9
+ subview(UILabel, :footer)
10
+ @button = subview(UIButton.buttonWithType(UIButtonTypeRoundedRect), :next_message)
11
+ end
12
+
13
+ @button.addTarget(self, action: :next_message, forControlEvents:UIControlEventTouchUpInside)
14
+ end
15
+
16
+ # used in testing
17
+ def landscape_only
18
+ UIApplication.sharedApplication.windows[0].rootViewController = LandscapeOnlyController.alloc.init
19
+ end
20
+
21
+ def next_view
22
+ landscape_only
23
+ end
24
+
25
+ def next_message
26
+ msg = messages.shift
27
+ if msg
28
+ @welcome.text = msg
29
+ else
30
+ @welcome.text = 'Next example...'
31
+
32
+ @button.removeTarget(self, action: :next_view, forControlEvents:UIControlEventTouchUpInside)
33
+ @button.addTarget(self, action: :next_view, forControlEvents:UIControlEventTouchUpInside)
34
+ end
35
+ end
36
+
37
+ def messages
38
+ @messages ||= [
39
+ 'This is teacup',
40
+ 'Welcome',
41
+ 'This is teacup',
42
+ 'Welcome to teacup',
43
+ 'You can do anything at teacup',
44
+ 'Anything at all',
45
+ 'The only limit is yourself ',
46
+ 'Welcome to teacup',
47
+ 'Welcome to teacup',
48
+ 'This is teacup',
49
+ 'Welcome to teacup',
50
+ 'This is teacup, Welcome',
51
+ 'Yes, this is teacup',
52
+ 'This is teacup and welcome to you who have come to teacup',
53
+ 'Anything is possible at teacup',
54
+ 'You can to anything teacup',
55
+ 'The infinite is possible at teacup',
56
+ 'The unattainable is unknown at teacup',
57
+ 'Welcome to teacup',
58
+ 'This is teacup',
59
+ 'Welcome to teacup',
60
+ 'Welcome',
61
+ 'This is teacup',
62
+ 'Welcome to teacup',
63
+ 'Welcome to teacup',
64
+ ]
65
+ end
66
+
67
+ def shouldAutorotateToInterfaceOrientation(orientation)
68
+ autorotateToOrientation(orientation)
69
+ end
70
+
71
+ end
@@ -0,0 +1,16 @@
1
+
2
+ class LandscapeOnlyController < UIViewController
3
+
4
+ def viewDidLoad
5
+ UIApplication.sharedApplication.windows[0].rootViewController = FirstController.alloc.init
6
+ end
7
+
8
+ def shouldAutorotateToInterfaceOrientation(orientation)
9
+ if orientation == UIDeviceOrientationLandscapeLeft or orientation == UIDeviceOrientationLandscapeRight
10
+ true
11
+ else
12
+ false
13
+ end
14
+ end
15
+
16
+ end
File without changes
@@ -0,0 +1,111 @@
1
+
2
+ Teacup::Stylesheet.new(:first) do
3
+
4
+ # enable orientations on the root view
5
+ style :root,
6
+ left: 0,
7
+ top: 0,
8
+ width: 320,
9
+ height: 480,
10
+ backgroundColor: UIColor.yellowColor,
11
+ portrait: true,
12
+ upside_down: false,
13
+
14
+ layer: {
15
+ cornerRadius: 10.0,
16
+ },
17
+
18
+ landscape: {
19
+ backgroundColor: UIColor.redColor,
20
+ },
21
+
22
+ landscape_left: {
23
+ layer: {
24
+ transform: spin(identity, -pi / 2),
25
+ },
26
+ },
27
+
28
+ landscape_right: {
29
+ layer: {
30
+ transform: spin(identity, pi / 2),
31
+ },
32
+ }
33
+
34
+ style(UILabel, {
35
+ textColor: UIColor.blueColor,
36
+ })
37
+
38
+ style CustomView,
39
+ # for testing how styles override (this gets overridden by any property in
40
+ # a style block, regardless of whether it is in an orientation style)
41
+ portrait: {
42
+ alpha: 0.75
43
+ },
44
+ landscape: {
45
+ alpha: 0.75
46
+ }
47
+
48
+ style(:background, {
49
+ alpha: 0.5,
50
+ left: 10,
51
+ top: 30,
52
+ backgroundColor: UIColor.blackColor,
53
+
54
+ portrait: {
55
+ width: 300,
56
+ height: 440,
57
+ backgroundColor: UIColor.darkGrayColor,
58
+ },
59
+
60
+ landscape: {
61
+ width: 460,
62
+ height: 280,
63
+ alpha: 0.8,
64
+ backgroundColor: UIColor.lightGrayColor,
65
+ },
66
+ })
67
+
68
+ style(:welcome, {
69
+ left: 10,
70
+ top: 40,
71
+ width: 280,
72
+ height: 20,
73
+ text: "Welcome to teacup",
74
+ landscape: {
75
+ left: 90,
76
+ },
77
+ })
78
+
79
+ style(:footer, {
80
+ left: 10,
81
+ top: 410,
82
+ width: 280,
83
+ height: 20,
84
+ text: "This is a teacup example",
85
+ landscape: {
86
+ top: 250,
87
+ left: 90,
88
+ },
89
+ })
90
+
91
+
92
+ style :next_message,
93
+ width: 130,
94
+ height: 20,
95
+ portrait: nil,
96
+ title: "Next Message..."
97
+
98
+ # deliberately declaring this twice for testing purposes
99
+ # (declaring twice extends it)
100
+ style :next_message,
101
+ portrait: {
102
+ left: 150,
103
+ top: 370,
104
+ },
105
+
106
+ landscape: {
107
+ left: 20,
108
+ top: 200,
109
+ }
110
+
111
+ end
@@ -0,0 +1,4 @@
1
+
2
+ class CustomView < UIView
3
+ # not very custom, is it!?
4
+ end
data/lib/dummy.rb ADDED
@@ -0,0 +1,56 @@
1
+ class DummyView < UIView
2
+ private
3
+ def dummy
4
+ setFrame(nil)
5
+ setOpaque(nil)
6
+ end
7
+ end
8
+
9
+ class DummyScrollView < UIScrollView
10
+ private
11
+ def dummy
12
+ setScrollEnabled(nil)
13
+ setShowsVerticalScrollIndicator(nil)
14
+ end
15
+ end
16
+
17
+ class DummyActivityIndicatorView < UIActivityIndicatorView
18
+ private
19
+ def dummy
20
+ setHidesWhenStopped(nil)
21
+ end
22
+ end
23
+
24
+ class DummyLabel < UILabel
25
+ private
26
+ def dummy
27
+ setAdjustsFontSizeToFitWidth(nil)
28
+ end
29
+ end
30
+
31
+ class DummyTextField < UITextField
32
+ private
33
+ def dummy
34
+ setReturnKeyType(nil)
35
+ setAutocapitalizationType(nil)
36
+ setAutocorrectionType(nil)
37
+ setSpellCheckingType(nil)
38
+ end
39
+ end
40
+
41
+ class DummyLayer < CALayer
42
+ private
43
+ def dummy
44
+ setCornerRadius(nil)
45
+ setTransform(nil)
46
+ setMasksToBounds(nil)
47
+ setShadowOffset(nil)
48
+ setShadowOpacity(nil)
49
+ setShadowRadius(nil)
50
+ setShadowOffset(nil)
51
+ setShadowColor(nil)
52
+ setShadowPath(nil)
53
+ setOpaque(nil)
54
+ setTranslucent(nil)
55
+ end
56
+ end
@@ -0,0 +1,99 @@
1
+ # Teacup handlers can modify (or alias) styling methods. For instance, the
2
+ # UIButton class doesn't have a `title` attribute, but we all know that what we
3
+ # *mean* when we say `title: "button title"` is `setTitle("button title",
4
+ # forControlState:UIControlStateNormal)`. A UIButton handler accomplishes this
5
+ # translation.
6
+ #
7
+ # You can write your own handlers!
8
+ #
9
+ # Teacup.handler UIButton, :title do |view, value|
10
+ # view.setTitle(value, forControlState:UIControlStateNormal)
11
+ # end
12
+ #
13
+ # You can declare multiple names in the Teacup.handler method to create aliases
14
+ # for your handler:
15
+ #
16
+ # Teacup.handler UIButton, :returnKeyType, :returnkey { |view, keytype|
17
+ # view.setReturnKeyType(keytype)
18
+ # }
19
+ #
20
+ # Since teacup already supports translating a property like `returnKeyType` into
21
+ # the setter `setReturnKeyType`, you could just use an alias here instead.
22
+ # Assign a hash to `Teacup.alias`:
23
+ #
24
+ # Teacup.alias UIButton, :returnkey => :returnKeyType
25
+ module Teacup
26
+ module_function
27
+
28
+ # applies a Hash of styles, and converts the frame styles (origin, size, top,
29
+ # left, width, height) into one frame property.
30
+ def apply_hash(target, properties)
31
+ properties.each do |key, value|
32
+ Teacup.apply target, key, value
33
+ end
34
+ end
35
+
36
+ # Applies a single style to a target. Delegates to a teacup handler if one is
37
+ # found.
38
+ def apply(target, key, value)
39
+ # note about `debug`: not all objects in this method are a UIView instance,
40
+ # so don't assume that the object *has* a debug method.
41
+
42
+ target.class.ancestors.each do |ancestor|
43
+ if Teacup.handlers[ancestor].has_key? key
44
+ NSLog "#{ancestor.name} is handling #{key} = #{value.inspect}" if target.respond_to? :debug and target.debug
45
+ Teacup.handlers[ancestor][key].call(target, value)
46
+ return
47
+ end
48
+ end
49
+
50
+ # you can send methods to subviews (e.g. UIButton#titleLabel) and CALayers
51
+ # (e.g. UIView#layer) by assigning a hash to a style name.
52
+ if Hash === value
53
+ return Teacup.apply_hash target.send(key), value
54
+ end
55
+
56
+ if key =~ /^set[A-Z]/
57
+ assign = nil
58
+ setter = key.to_s + ':'
59
+ else
60
+ assign = :"#{key}="
61
+ setter = 'set' + key.to_s.sub(/^./) {|c| c.capitalize} + ':'
62
+ end
63
+
64
+ if assign and target.respond_to?(assign)
65
+ NSLog "Setting #{key} = #{value.inspect}" if target.respond_to? :debug and target.debug
66
+ target.send(assign, value)
67
+ elsif target.respondsToSelector(setter)
68
+ NSLog "Calling target(#{key}, #{value.inspect})" if target.respond_to? :debug and target.debug
69
+ target.send(setter, value)
70
+ else
71
+ NSLog "Teacup WARN: Can't apply #{setter.inspect}#{assign and " or " + assign.inspect or ""} to #{target.inspect}"
72
+ end
73
+ end
74
+
75
+ def handlers
76
+ @teacup_handlers ||= Hash.new{ |hash,klass| hash[klass] = {} }
77
+ end
78
+
79
+ def handler klass, *stylenames, &block
80
+ if stylenames.length == 0
81
+ raise TypeError.new "No style names assigned in Teacup[#{klass.inspect}]##handler"
82
+ else
83
+ stylenames.each do |stylename|
84
+ Teacup.handlers[klass][stylename] = block
85
+ end
86
+ end
87
+ self
88
+ end
89
+
90
+ def alias klass, aliases
91
+ aliases.each do |style_alias, stylename|
92
+ Teacup.handlers[klass][style_alias] = proc { |view, value|
93
+ Teacup.apply view, style_name, value
94
+ }
95
+ end
96
+ self
97
+ end
98
+
99
+ end
data/lib/teacup/layout.rb CHANGED
@@ -1,25 +1,27 @@
1
+
1
2
  module Teacup
2
- # Teacup::Layout defines a layout function that can be used to configure the
3
- # layout of views in your application.
3
+ # Teacup::Layout defines a layout and subview function that can be used to
4
+ # declare and configure the layout of views and the view hierarchy in your
5
+ # application.
4
6
  #
5
- # It is included into UIView and UIViewController directly so these functions
6
- # should be available when you need them.
7
+ # This module is included into UIView and UIViewController directly so these
8
+ # functions are available in the places you need them.
7
9
  #
8
10
  # In order to use layout() in a UIViewController most effectively you will want
9
11
  # to define a stylesheet method that returns a stylesheet.
10
12
  #
11
13
  # @example
12
14
  # class MyViewController < UIViewController
13
- # interface(:my_view) do
15
+ # layout(:my_view) do
14
16
  # layout UIImage, :logo
15
17
  # end
16
- #
18
+ #
17
19
  # def stylesheet
18
- # Teacup::Stylesheet::Logo
20
+ # Teacup::Stylesheet[:logo]
19
21
  # end
20
22
  # end
21
- #
22
23
  module Layout
24
+ attr_accessor :stylesheet
23
25
 
24
26
  # Alter the layout of a view
25
27
  #
@@ -58,30 +60,29 @@ module Teacup
58
60
  # subview(UIImage, backgroundColor: UIColor.colorWithImagePattern(image)
59
61
  # }
60
62
  #
61
- def layout(instance, name_or_properties, properties_or_nil=nil, &block)
62
- if properties_or_nil
63
- name = name_or_properties.to_sym
64
- properties = properties_or_nil
65
- elsif Hash === name_or_properties
63
+ def layout(view, name_or_properties=nil, properties_or_nil=nil, &block)
64
+ name = nil
65
+ properties = properties_or_nil
66
+
67
+ if Hash === name_or_properties
66
68
  name = nil
67
69
  properties = name_or_properties
68
- else
70
+ elsif name_or_properties
69
71
  name = name_or_properties.to_sym
70
- properties = nil
71
72
  end
72
73
 
73
- instance.stylesheet = stylesheet
74
- instance.style(properties) if properties
75
- instance.stylename = name if name
74
+ view.stylesheet = stylesheet
75
+ view.stylename = name
76
+ view.style(properties) if properties
76
77
 
77
78
  begin
78
- superview_chain << instance
79
- instance_exec(instance, &block) if block_given?
79
+ superview_chain << view
80
+ instance_exec(view, &block) if block_given?
80
81
  ensure
81
82
  superview_chain.pop
82
83
  end
83
84
 
84
- instance
85
+ view
85
86
  end
86
87
 
87
88
  # Add a new subview to the view heirarchy.
@@ -123,8 +124,6 @@ module Teacup
123
124
  # }
124
125
  #
125
126
  def subview(class_or_instance, *args, &block)
126
- instance = Class === class_or_instance ? class_or_instance.new : class_or_instance
127
-
128
127
  if Class === class_or_instance
129
128
  unless class_or_instance <= UIView
130
129
  raise "Expected subclass of UIView, got: #{class_or_instance.inspect}"
@@ -143,59 +142,8 @@ module Teacup
143
142
  instance
144
143
  end
145
144
 
146
- # Returns a stylesheet to use to style the contents of this controller's
147
- # view.
148
- #
149
- # This method will be queried each time {restyle!} is called, and also
150
- # implicitly # whenever Teacup needs to draw your layout (currently only at
151
- # view load time).
152
- #
153
- # @return Teacup::Stylesheet
154
- #
155
- # @example
156
- #
157
- # def stylesheet
158
- # if [UIDeviceOrientationLandscapeLeft,
159
- # UIDeviceOrientationLandscapeRight].include?(UIDevice.currentDevice.orientation)
160
- # Teacup::Stylesheet::IPad
161
- # else
162
- # Teacup::Stylesheet::IPadVertical
163
- # end
164
- # end
165
- def stylesheet
166
- nil
167
- end
168
-
169
- # Instruct teacup to reapply styles to your subviews
170
- #
171
- # You should call this whenever the return value of your stylesheet meethod
172
- # would change,
173
- #
174
- # @example
175
- # def willRotateToInterfaceOrientation(io, duration: duration)
176
- # restyle!
177
- # end
178
- def restyle!
179
- top_level_view.stylesheet = stylesheet
180
- end
181
-
182
145
  protected
183
146
 
184
- # Get's the top-level UIView for this object.
185
- #
186
- # This can either be 'self' if the current object is in fact a UIView,
187
- # or 'view' if it's a controller.
188
- #
189
- # @return UIView
190
- def top_level_view
191
- case self
192
- when UIViewController
193
- view
194
- when UIView
195
- self
196
- end
197
- end
198
-
199
147
  # Get's the current stack of views in nested calls to layout.
200
148
  #
201
149
  # The view at the end of the stack is the one into which subviews
@@ -0,0 +1,45 @@
1
+ module Teacup
2
+ module_function
3
+
4
+ # Merges two Hashes. This is similar to `Hash#merge`, except the values will
5
+ # be merged recursively (aka deep merge) when both values for a key are
6
+ # Hashes, and values for the *left* argument are preferred over values on the
7
+ # right.
8
+ #
9
+ # If you pass in a third argument, it will be acted upon directly instead of
10
+ # creating a new Hash. Usually used with `merge_defaults!`, which merges values
11
+ # from `right` into `left`.
12
+ def merge_defaults(left, right, target={})
13
+ if target != left
14
+ left.each do |key, value|
15
+ if target.has_key? key and value.is_a?(Hash) and target[key].is_a?(Hash)
16
+ target[key] = Teacup::merge_defaults(target[key], value)
17
+ else
18
+ if value.is_a?(Hash)
19
+ # make a copy of the Hash
20
+ value = Teacup::merge_defaults!({}, value)
21
+ end
22
+ target[key] = value
23
+ end
24
+ end
25
+ end
26
+
27
+ right.each do |key, value|
28
+ if not target.has_key? key
29
+ if value.is_a?(Hash)
30
+ # make a copy of the Hash
31
+ value = Teacup::merge_defaults!({}, value)
32
+ end
33
+ target[key] = value
34
+ elsif value.is_a?(Hash) and left[key].is_a?(Hash)
35
+ target[key] = Teacup::merge_defaults(left[key], value, (left==target ? left[key] : {}))
36
+ end
37
+ end
38
+ target
39
+ end
40
+
41
+ # modifies left by passing it in as the `target`.
42
+ def merge_defaults!(left, right)
43
+ Teacup::merge_defaults(left, right, left)
44
+ end
45
+ end
@@ -0,0 +1,93 @@
1
+ module Teacup
2
+ # The Style class is where the precedence rules are applied. A Style can
3
+ # query the Stylesheet that created it to look up other styles (for
4
+ # `extends:`) and to import other Stylesheets. If it is handed a target (e.g.
5
+ # a `UIView` instance) and orientation, it will merge those in appropriately
6
+ # as well.
7
+ class Style < Hash
8
+ attr_accessor :stylename
9
+ attr_accessor :stylesheet
10
+
11
+ Orientations = [:portrait, :upside_up, :upside_down, :landscape, :landscape_left, :landscape_right]
12
+ Overrides = {
13
+ 0 => [:portrait, :upside_up],
14
+ UIInterfaceOrientationPortrait => [:portrait, :upside_up],
15
+ UIInterfaceOrientationPortraitUpsideDown => [:portrait, :upside_down],
16
+ UIInterfaceOrientationLandscapeLeft => [:landscape, :landscape_left],
17
+ UIInterfaceOrientationLandscapeRight => [:landscape, :landscape_right],
18
+ }
19
+
20
+ # A hash of orientation => true/false. true means the orientation is
21
+ # supported.
22
+ def supports
23
+ @supports ||= {}
24
+ end
25
+
26
+ def supports? orientation_key
27
+ supports.has_key? orientation_key
28
+ end
29
+
30
+ def build(target=nil, orientation=nil, seen={})
31
+ properties = Style.new.update(self)
32
+ properties.stylename = self.stylename
33
+ properties.stylesheet = self.stylesheet
34
+
35
+ # at this point, we really DO need the orientation
36
+ orientation = UIDevice.currentDevice.orientation unless orientation
37
+
38
+ # first, move orientation settings into properties "base" level.
39
+ if orientation
40
+ Overrides[orientation].each do |orientation_key|
41
+ if override = properties.delete(orientation_key)
42
+ # override is first, so it takes precedence
43
+ if override.is_a? Hash
44
+ Teacup::merge_defaults override, properties, properties
45
+ elsif not properties.has_key? orientation_key
46
+ properties[orientation_key] = override
47
+ end
48
+ properties.supports[orientation_key] = properties[orientation_key] ? true : false
49
+ end
50
+ end
51
+ end
52
+
53
+ # delete all of them from `properties`
54
+ Orientations.each do |orientation_key|
55
+ if properties.delete(orientation_key)
56
+ properties.supports[orientation_key] = true
57
+ end
58
+ end
59
+
60
+ # now we can merge extends, and importing. before merging, these will go
61
+ # through the same process that we just finished on the local style
62
+ if stylesheet
63
+ stylesheet.imported_stylesheets.reverse.each do |stylesheet|
64
+ imported_properties = stylesheet.query(self.stylename, target, orientation, seen)
65
+ Teacup::merge_defaults! properties, imported_properties
66
+ end
67
+
68
+ if also_includes = properties.delete(:extends)
69
+ also_includes = [also_includes] unless also_includes.is_a? Array
70
+
71
+ # turn style names into Hashes by querying them on the stylesheet
72
+ # (this does not pass `seen`, because this is a new query)
73
+ also_includes.each do |also_include|
74
+ extended_properties = stylesheet.query(also_include, target, orientation)
75
+ Teacup::merge_defaults! properties, extended_properties
76
+ end
77
+ end
78
+
79
+ # if we know the class of the target, we can apply styles via class
80
+ # inheritance. We do not pass `target` in this case.
81
+ if target
82
+ target.class.ancestors.each do |ancestor|
83
+ extended_properties = stylesheet.query(ancestor, nil, orientation)
84
+ Teacup::merge_defaults!(properties, extended_properties)
85
+ end
86
+ end
87
+ end
88
+
89
+ properties
90
+ end
91
+
92
+ end
93
+ end