teacup 0.0.1.pre → 0.3.1

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