compass 0.13.alpha.4 → 0.13.alpha.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. checksums.yaml +7 -0
  2. data/README.markdown +2 -3
  3. data/Rakefile +91 -5
  4. data/VERSION.yml +1 -1
  5. data/examples/compass/images/emblem-a043c4f148.png +0 -0
  6. data/examples/compass/images/flag-03c3b29b35.png +0 -0
  7. data/examples/compass/images/flag-21cfbfbfc8.png +0 -0
  8. data/examples/css3/extensions/fancy-fonts/templates/project/Prociono.otf +0 -0
  9. data/features/command_line.feature +2 -6
  10. data/features/step_definitions/command_line_steps.rb +1 -0
  11. data/frameworks/compass/stylesheets/compass/_css3.scss +0 -1
  12. data/frameworks/compass/stylesheets/compass/_support.scss +353 -35
  13. data/frameworks/compass/stylesheets/compass/css3/_animation.scss +49 -48
  14. data/frameworks/compass/stylesheets/compass/css3/_appearance.scss +4 -8
  15. data/frameworks/compass/stylesheets/compass/css3/_background-clip.scss +15 -19
  16. data/frameworks/compass/stylesheets/compass/css3/_background-origin.scss +17 -19
  17. data/frameworks/compass/stylesheets/compass/css3/_background-size.scss +4 -8
  18. data/frameworks/compass/stylesheets/compass/css3/_border-radius.scss +37 -39
  19. data/frameworks/compass/stylesheets/compass/css3/_box-shadow.scss +45 -20
  20. data/frameworks/compass/stylesheets/compass/css3/_box-sizing.scss +6 -8
  21. data/frameworks/compass/stylesheets/compass/css3/_box.scss +12 -13
  22. data/frameworks/compass/stylesheets/compass/css3/_columns.scss +46 -26
  23. data/frameworks/compass/stylesheets/compass/css3/_deprecated-support.scss +272 -0
  24. data/frameworks/compass/stylesheets/compass/css3/_filter.scss +17 -10
  25. data/frameworks/compass/stylesheets/compass/css3/_flexbox.scss +134 -281
  26. data/frameworks/compass/stylesheets/compass/css3/_font-face.scss +5 -5
  27. data/frameworks/compass/stylesheets/compass/css3/_hyphenation.scss +14 -11
  28. data/frameworks/compass/stylesheets/compass/css3/_images.scss +77 -67
  29. data/frameworks/compass/stylesheets/compass/css3/_inline-block.scss +15 -6
  30. data/frameworks/compass/stylesheets/compass/css3/_opacity.scss +6 -2
  31. data/frameworks/compass/stylesheets/compass/css3/_pie.scss +1 -73
  32. data/frameworks/compass/stylesheets/compass/css3/_regions.scss +7 -6
  33. data/frameworks/compass/stylesheets/compass/css3/_selection.scss +45 -17
  34. data/frameworks/compass/stylesheets/compass/css3/_shared.scss +4 -261
  35. data/frameworks/compass/stylesheets/compass/css3/_text-shadow.scss +1 -1
  36. data/frameworks/compass/stylesheets/compass/css3/_transform.scss +24 -32
  37. data/frameworks/compass/stylesheets/compass/css3/_transition.scss +102 -152
  38. data/frameworks/compass/stylesheets/compass/css3/_user-interface.scss +42 -27
  39. data/frameworks/compass/stylesheets/compass/typography/_vertical_rhythm.scss +2 -1
  40. data/frameworks/compass/stylesheets/compass/typography/links/_hover-link.scss +1 -1
  41. data/frameworks/compass/stylesheets/compass/typography/lists/_horizontal-list.scss +2 -2
  42. data/frameworks/compass/stylesheets/compass/typography/lists/_inline-list.scss +1 -1
  43. data/frameworks/compass/stylesheets/compass/typography/text/_ellipsis.scss +1 -1
  44. data/frameworks/compass/stylesheets/compass/utilities/_sass.scss +2 -0
  45. data/frameworks/compass/stylesheets/compass/utilities/color/_brightness.scss +12 -0
  46. data/frameworks/compass/stylesheets/compass/utilities/color/_contrast.scss +36 -12
  47. data/frameworks/compass/stylesheets/compass/utilities/general/_float.scss +6 -2
  48. data/frameworks/compass/stylesheets/compass/utilities/general/_hacks.scss +23 -4
  49. data/frameworks/compass/stylesheets/compass/utilities/general/_min.scss +1 -1
  50. data/frameworks/compass/stylesheets/compass/utilities/sass/_lists.scss +16 -0
  51. data/frameworks/compass/stylesheets/compass/utilities/sass/_maps.scss +19 -0
  52. data/frameworks/compass/stylesheets/compass/utilities/sprites/_base.scss +25 -18
  53. data/frameworks/compass/stylesheets/compass/utilities/sprites/_sprite-img.scss +3 -1
  54. data/frameworks/compass/stylesheets/compass/utilities/tables/_borders.scss +3 -3
  55. data/lib/compass.rb +1 -1
  56. data/lib/compass/browser_support.rb +1 -1
  57. data/lib/compass/caniuse.rb +247 -0
  58. data/lib/compass/configuration/adapters.rb +7 -1
  59. data/lib/compass/sass_extensions/functions.rb +5 -0
  60. data/lib/compass/sass_extensions/functions/constants.rb +2 -2
  61. data/lib/compass/sass_extensions/functions/cross_browser_support.rb +176 -1
  62. data/lib/compass/sass_extensions/functions/display.rb +24 -19
  63. data/lib/compass/sass_extensions/functions/env.rb +37 -8
  64. data/lib/compass/sass_extensions/functions/gradient_support.rb +10 -13
  65. data/lib/compass/sass_extensions/functions/math.rb +31 -13
  66. data/lib/compass/sass_extensions/functions/sprites.rb +48 -25
  67. data/lib/compass/sass_extensions/monkey_patches/browser_support.rb +42 -13
  68. data/lib/compass/sass_extensions/sprites/image.rb +14 -4
  69. data/lib/compass/sass_extensions/sprites/image_methods.rb +19 -3
  70. data/lib/compass/sprite_importer/content.erb +8 -7
  71. data/lib/compass/watcher/project_watcher.rb +75 -42
  72. data/lib/compass/watcher/watch.rb +35 -17
  73. data/test/fixtures/sprites/public/images/focus/ten-by-ten.png +0 -0
  74. data/test/fixtures/sprites/public/images/focus/ten-by-ten_active.png +0 -0
  75. data/test/fixtures/sprites/public/images/focus/ten-by-ten_focus.png +0 -0
  76. data/test/fixtures/sprites/public/images/focus/ten-by-ten_hover.png +0 -0
  77. data/test/fixtures/sprites/public/images/focus/ten-by-ten_target.png +0 -0
  78. data/test/fixtures/stylesheets/compass/config.rb +1 -0
  79. data/test/fixtures/stylesheets/compass/css/animation-with-legacy-ie.css +1 -9
  80. data/test/fixtures/stylesheets/compass/css/animation.css +1 -9
  81. data/test/fixtures/stylesheets/compass/css/appearance.css +3 -0
  82. data/test/fixtures/stylesheets/compass/css/background-clip.css +4 -8
  83. data/test/fixtures/stylesheets/compass/css/background-origin.css +4 -8
  84. data/test/fixtures/stylesheets/compass/css/background-size.css +3 -10
  85. data/test/fixtures/stylesheets/compass/css/border_radius.css +3 -3
  86. data/test/fixtures/stylesheets/compass/css/{box-sizeing.css → box-sizing.css} +2 -2
  87. data/test/fixtures/stylesheets/compass/css/box_shadow.css +15 -5
  88. data/test/fixtures/stylesheets/compass/css/brightness.css +14 -0
  89. data/test/fixtures/stylesheets/compass/css/browser-support.css +306 -0
  90. data/test/fixtures/stylesheets/compass/css/color.css +18 -0
  91. data/test/fixtures/stylesheets/compass/css/columns.css +27 -18
  92. data/test/fixtures/stylesheets/compass/css/filters.css +6 -6
  93. data/test/fixtures/stylesheets/compass/css/flexbox.css +84 -111
  94. data/test/fixtures/stylesheets/compass/css/fonts.css +1 -1
  95. data/test/fixtures/stylesheets/compass/css/gradients.css +53 -53
  96. data/test/fixtures/stylesheets/compass/css/grid_background.css +11 -11
  97. data/test/fixtures/stylesheets/compass/css/hyphenation.css +2 -4
  98. data/test/fixtures/stylesheets/compass/css/lists.css +6 -12
  99. data/test/fixtures/stylesheets/compass/css/regions.css +2 -2
  100. data/test/fixtures/stylesheets/compass/css/selection.css +41 -4
  101. data/test/fixtures/stylesheets/compass/css/sprites_with_explicit_separator.css +16 -0
  102. data/test/fixtures/stylesheets/compass/css/support.css +62 -0
  103. data/test/fixtures/stylesheets/compass/css/transform.css +64 -136
  104. data/test/fixtures/stylesheets/compass/css/transition.css +27 -45
  105. data/test/fixtures/stylesheets/compass/css/typography/links/hover-link.css +4 -0
  106. data/test/fixtures/stylesheets/compass/css/user-interface.css +34 -7
  107. data/test/fixtures/stylesheets/compass/css/utilities.css +7 -7
  108. data/test/fixtures/stylesheets/compass/css/vertical_rhythm.css +6 -9
  109. data/test/fixtures/stylesheets/compass/images/flag_states-sc42d7bf926.png +0 -0
  110. data/test/fixtures/stylesheets/compass/images/flag_states/foo.png +0 -0
  111. data/test/fixtures/stylesheets/compass/images/flag_states/foo_active.png +0 -0
  112. data/test/fixtures/stylesheets/compass/images/flag_states/foo_focus.png +0 -0
  113. data/test/fixtures/stylesheets/compass/images/flag_states/foo_hover.png +0 -0
  114. data/test/fixtures/stylesheets/compass/images/flag_states/foo_target.png +0 -0
  115. data/test/fixtures/stylesheets/compass/sass/animation-with-legacy-ie.scss +1 -3
  116. data/test/fixtures/stylesheets/compass/sass/appearance.scss +5 -0
  117. data/test/fixtures/stylesheets/compass/sass/background-clip.scss +0 -5
  118. data/test/fixtures/stylesheets/compass/sass/background-origin.scss +0 -5
  119. data/test/fixtures/stylesheets/compass/sass/background-size.scss +0 -5
  120. data/test/fixtures/stylesheets/compass/sass/{box-sizeing.scss → box-sizing.scss} +1 -1
  121. data/test/fixtures/stylesheets/compass/sass/box_shadow.scss +2 -0
  122. data/test/fixtures/stylesheets/compass/sass/brightness.scss +12 -0
  123. data/test/fixtures/stylesheets/compass/sass/browser-support.scss +30 -0
  124. data/test/fixtures/stylesheets/compass/sass/color.scss +22 -0
  125. data/test/fixtures/stylesheets/compass/sass/filters.scss +1 -0
  126. data/test/fixtures/stylesheets/compass/sass/flexbox.scss +84 -40
  127. data/test/fixtures/stylesheets/compass/sass/gradients.sass +3 -2
  128. data/test/fixtures/stylesheets/compass/sass/selection.scss +29 -4
  129. data/test/fixtures/stylesheets/compass/sass/sprites_with_explicit_separator.scss +7 -0
  130. data/test/fixtures/stylesheets/compass/sass/support.scss +137 -0
  131. data/test/fixtures/stylesheets/compass/sass/transition.scss +0 -3
  132. data/test/fixtures/stylesheets/compass/sass/typography/links/hover-link.scss +3 -0
  133. data/test/fixtures/stylesheets/compass/sass/user-interface.scss +16 -5
  134. data/test/fixtures/stylesheets/compass/sass/utilities.scss +4 -4
  135. data/test/fixtures/stylesheets/envtest/css/env.css +4 -4
  136. data/test/fixtures/stylesheets/envtest/tmp/env.css +4 -4
  137. data/test/integrations/sprites_test.rb +30 -1
  138. data/test/test_helper.rb +2 -2
  139. data/test/units/caniuse_test.rb +115 -0
  140. data/test/units/command_line_test.rb +1 -0
  141. data/test/units/sass_extensions_test.rb +5 -0
  142. data/test/units/sprites/image_test.rb +12 -0
  143. data/test/units/sprites/sprite_map_test.rb +11 -0
  144. data/test/units/watcher/project_watcher_test.rb +26 -18
  145. metadata +96 -42
  146. data/examples/compass/src/pie.scss +0 -110
  147. data/frameworks/compass/stylesheets/compass/css3/_transform-legacy.scss +0 -87
  148. data/frameworks/compass/templates/pie/LICENSE +0 -12
  149. data/frameworks/compass/templates/pie/LICENSE-APACHE2.txt +0 -13
  150. data/frameworks/compass/templates/pie/LICENSE-GPL2.txt +0 -278
  151. data/frameworks/compass/templates/pie/PIE.htc +0 -96
  152. data/frameworks/compass/templates/pie/manifest.rb +0 -39
  153. data/frameworks/compass/templates/pie/pie.scss +0 -74
  154. data/lib/compass/sass_extensions/functions/utility.rb +0 -10
  155. data/test/fixtures/stylesheets/compass/css/pie.css +0 -23
  156. data/test/fixtures/stylesheets/compass/sass/pie.scss +0 -47
@@ -1,3 +1,5 @@
1
+ @import "compass/typography/text/replacement";
2
+
1
3
  // @doc off
2
4
  // Example 1:
3
5
  //
@@ -76,4 +78,4 @@ $sprite-image-default-height: $sprite-default-size !default;
76
78
  // The name of the image in the sprite folder should be `$img-name`
77
79
  @mixin sprite-replace-text-with-dimensions ($map, $sprite, $offset-x: 0, $offset-y: 0){
78
80
  @include sprite-replace-text ($map, $sprite, true, $offset-x, $offset-y);
79
- }
81
+ }
@@ -9,7 +9,7 @@
9
9
  th, td {
10
10
  border-top: $width solid $color; } }
11
11
  th {
12
- &:first-child #{if($legacy-support-for-ie6, ', &.first', '')} {
12
+ &:first-child #{if(support-legacy-browser(ie, "6"), ', &.first', null)} {
13
13
  border-right: $width solid $color; } } }
14
14
 
15
15
  @mixin inner-table-borders($width: 2px, $color: black) {
@@ -24,7 +24,7 @@
24
24
 
25
25
  // IE8 ignores rules that are included on the same line as :last-child
26
26
  // see http://www.richardscarrott.co.uk/posts/view/ie8-last-child-bug for details
27
- @if $legacy-support-for-ie6 or $legacy-support-for-ie7 or $legacy-support-for-ie8 {
27
+ @if support-legacy-browser(ie, "8") {
28
28
  &.last {
29
29
  border-right-width: 0px; } } }
30
30
 
@@ -32,7 +32,7 @@
32
32
  tr:last-child {
33
33
  th, td {
34
34
  border-bottom-width: 0px; } }
35
- @if $legacy-support-for-ie6 or $legacy-support-for-ie7 or $legacy-support-for-ie8 {
35
+ @if support-legacy-browser(ie, "8") {
36
36
  tr.last {
37
37
  th, td {
38
38
  border-bottom-width: 0px; } } } } }
@@ -29,7 +29,7 @@ module Compass
29
29
  extend QuickCache
30
30
  end
31
31
 
32
- %w(watcher configuration frameworks app_integration compiler).each do |lib|
32
+ %w(watcher configuration frameworks app_integration compiler caniuse).each do |lib|
33
33
  require "compass/#{lib}"
34
34
  end
35
35
 
@@ -2,7 +2,7 @@ module Compass
2
2
  module BrowserSupport
3
3
  extend self
4
4
 
5
- ASPECTS = %w(webkit moz o ms svg pie css2)
5
+ ASPECTS = %w(webkit moz o ms svg css2)
6
6
 
7
7
  SIMPLE_FUNCTIONS = {
8
8
  "image" => %w(), # No browsers implement this yet.
@@ -0,0 +1,247 @@
1
+ require 'json'
2
+ require 'singleton'
3
+ class Compass::CanIUse
4
+ include Singleton
5
+
6
+ DATA_FILE_NAME = File.join(Compass.base_directory, "data", "caniuse.json")
7
+ DATA_FEATURE_FILES = Dir.glob(File.join(Compass.base_directory, "data", "caniuse_extras", "**", "*.json"))
8
+
9
+ def initialize
10
+ @data = JSON.parse(File.read(DATA_FILE_NAME))
11
+ # support ad-hoc features
12
+ DATA_FEATURE_FILES.each do |feature_file|
13
+ feature_name = File.basename(feature_file, ".json")
14
+ # if the feature doesn't exist in the master `caniuse.json`
15
+ if @data["data"][feature_name].nil?
16
+ @data["data"][feature_name] = JSON.parse(File.read(feature_file))
17
+ end
18
+ end
19
+ end
20
+
21
+ # The browser names from caniuse are ugly.
22
+ PUBLIC_BROWSER_NAMES = Hash.new {|h, k| k}
23
+ PUBLIC_BROWSER_NAMES.update(
24
+ "and_chr" => "android-chrome",
25
+ "and_ff" => "android-firefox",
26
+ "android" => "android",
27
+ "bb" => "blackberry",
28
+ "chrome" => "chrome",
29
+ "firefox" => "firefox",
30
+ "ie" => "ie",
31
+ "ie_mob" => "ie-mobile",
32
+ "ios_saf" => "ios-safari",
33
+ "op_mini" => "opera-mini",
34
+ "op_mob" => "opera-mobile",
35
+ "opera" => "opera",
36
+ "safari" => "safari"
37
+ )
38
+ CAN_I_USE_NAMES = Hash.new {|h, k| k}
39
+ CAN_I_USE_NAMES.update(PUBLIC_BROWSER_NAMES.invert)
40
+
41
+ # Returns all the known browsers according to caniuse
42
+ def browsers
43
+ @browsers ||= @data["agents"].keys.map{|b| PUBLIC_BROWSER_NAMES[b] }.sort
44
+ end
45
+
46
+ # Returns the prefix corresponding to a particular browser
47
+ def prefix(browser, version = nil)
48
+ assert_valid_browser browser
49
+ assert_valid_version browser, version if version
50
+ data = browser_data(browser)
51
+ p = if data["prefix_exceptions"] && data["prefix_exceptions"][version]
52
+ data["prefix_exceptions"][version]
53
+ else
54
+ data["prefix"]
55
+ end
56
+ "-#{p}"
57
+ end
58
+
59
+ # returns all possible prefixes a browser might use.
60
+ def all_prefixes(browser)
61
+ assert_valid_browser browser
62
+ data = browser_data(browser)
63
+ prefixes = ["-#{data["prefix"]}"]
64
+ if data["prefix_exceptions"]
65
+ prefixes += data["prefix_exceptions"].values.uniq.map{|p| "-#{p}"}
66
+ end
67
+ prefixes
68
+ end
69
+
70
+ # returns the prefixes needed by the list of browsers given
71
+ def prefixes(browsers = browsers)
72
+ result = browsers.map{|b| all_prefixes(b) }
73
+ result.flatten!
74
+ result.uniq!
75
+ result.sort!
76
+ result
77
+ end
78
+
79
+ def browser_minimums(capability, prefix = nil)
80
+ assert_valid_capability capability
81
+ browsers = prefix.nil? ? browsers() : browsers_with_prefix(prefix)
82
+ browsers.inject({}) do |m, browser|
83
+ version = versions(browser).find do |version|
84
+ support = browser_support(browser, version, capability)
85
+ if prefix.nil?
86
+ support !~ /\bn\b/ && support !~ /\bx\b/
87
+ else
88
+ actual_prefix = prefix(browser, version)
89
+ support !~ /\bn\b/ && support =~ /\bx\b/ && prefix == actual_prefix
90
+ end
91
+ end
92
+ m.update(browser => version) if version
93
+ m
94
+ end
95
+ end
96
+
97
+ # How many users would be omitted if support for the given browser starts
98
+ # with the given version.
99
+ def omitted_usage(browser, min_version)
100
+ assert_valid_browser browser
101
+ usage = 0
102
+ versions(browser).each do |version|
103
+ return usage if version == min_version
104
+ usage += usage(browser, version)
105
+ end
106
+ raise ArgumentError, "#{min_version} is not a version for #{browser}"
107
+ end
108
+
109
+ # returns the list of browsers that use the given prefix
110
+ def browsers_with_prefix(prefix)
111
+ assert_valid_prefix prefix
112
+ prefix = "-" + prefix unless prefix.start_with?("-")
113
+ browsers.select {|b| all_prefixes(b).include?(prefix) }
114
+ end
115
+
116
+ SPEC_VERSION_MATCHERS = Hash.new do |h, k|
117
+ h[k] = /##{k}\b/
118
+ end
119
+
120
+ CAPABILITY_MATCHERS = {
121
+ :full_support => lambda {|support, capability| !support ^ (capability =~ /\by\b/) },
122
+ :partial_support => lambda {|support, capability| !support ^ (capability =~ /\ba\b/) },
123
+ :prefixed => lambda {|support, capability| !support ^ (capability =~ /\bx\b/) },
124
+ :spec_versions => lambda {|versions, capability| versions.any? {|v| capability =~ SPEC_VERSION_MATCHERS[v] } }
125
+ }
126
+
127
+ # Return whether the capability matcher the options specified.
128
+ # For each capability option in the options the capability will need to match it.
129
+ def capability_matches(support, capability_options_list)
130
+ capability_options_list.any? do |capability_options|
131
+ capability_options.all? {|c, v| CAPABILITY_MATCHERS[c].call(v, support)}
132
+ end
133
+ end
134
+
135
+ # returns the percentage of users (0-100) that would be affected if the prefix
136
+ # was not used with the given capability.
137
+ def prefixed_usage(prefix, capability, capability_options_list)
138
+ assert_valid_prefix prefix
139
+ assert_valid_capability capability
140
+ usage = 0
141
+ browsers_with_prefix(prefix).each do |browser|
142
+ versions(browser).each do |version|
143
+ next unless prefix == prefix(browser, version)
144
+ support = browser_support(browser, version, capability)
145
+ if capability_matches(support, capability_options_list) and support =~ /\bx\b/
146
+ usage += usage(browser, version)
147
+ end
148
+ end
149
+ end
150
+ usage
151
+ end
152
+
153
+ # Returns whether the given minimum version of a browser
154
+ # requires the use of a prefix for the stated capability.
155
+ def requires_prefix(browser, min_version, capability, capability_options_list)
156
+ assert_valid_browser browser
157
+ assert_valid_capability capability
158
+ found_version = false
159
+ versions(browser).each do |version|
160
+ found_version ||= version == min_version
161
+ next unless found_version
162
+ support = browser_support(browser, version, capability)
163
+ if capability_matches(support, capability_options_list) and support =~ /\bx\b/
164
+ return prefix(browser, version)
165
+ end
166
+ end
167
+ raise ArgumentError, "#{min_version} is not a version for #{browser}" unless found_version
168
+ nil
169
+ end
170
+
171
+ # Returns the versions of a browser. If the min_usage parameter is provided,
172
+ # only those versions having met the threshold of user percentage.
173
+ #
174
+ # @param min_usage a decimal number betwee 0 and 100
175
+ def versions(browser, min_usage = 0)
176
+ assert_valid_browser browser
177
+ versions = browser_data(browser)["versions"].compact
178
+ return versions if min_usage == 0
179
+ versions.select {|v| browser_data(browser)["usage_global"][v] > min_usage }
180
+ end
181
+
182
+ # The list of capabilities tracked by caniuse.
183
+ def capabilities
184
+ @capabilities ||= @data["data"].keys.select do |cap|
185
+ cats = @data["data"][cap]["categories"]
186
+ cats.any?{|cat| cat =~ /CSS/ }
187
+ end.sort
188
+ end
189
+
190
+ # the usage % for a given browser version.
191
+ def usage(browser, version)
192
+ browser_data(browser)["usage_global"][version]
193
+ end
194
+
195
+
196
+ def inspect
197
+ "Compass::CanIUse(#{browsers.join(", ")})"
198
+ end
199
+
200
+ # the browser data assocated with a given capability
201
+ def capability_data(capability)
202
+ @data["data"][capability]
203
+ end
204
+
205
+ def browser_support(browser, version, capability)
206
+ capability_data(capability)["stats"][CAN_I_USE_NAMES[browser]][version]
207
+ end
208
+
209
+ # the metadata assocated with a given browser
210
+ def browser_data(browser)
211
+ @data["agents"][CAN_I_USE_NAMES[browser]]
212
+ end
213
+
214
+ # efficiently checks if a prefix is valid
215
+ def assert_valid_prefix(prefix)
216
+ @known_prefixes ||= Set.new(prefixes(browsers))
217
+ unless @known_prefixes.include?(prefix)
218
+ raise ArgumentError, "#{prefix} is not known browser prefix."
219
+ end
220
+ end
221
+
222
+ # efficiently checks if a browser is valid
223
+ def assert_valid_browser(browser)
224
+ @known_browsers ||= Set.new(browsers)
225
+ @known_browsers.include?(browser)
226
+ unless @known_browsers.include?(browser)
227
+ raise ArgumentError, "#{browser} is not known browser."
228
+ end
229
+ end
230
+
231
+ # efficiently checks if a capability is valid
232
+ def assert_valid_capability(capability)
233
+ @known_capabilities ||= Set.new(capabilities)
234
+ unless @known_capabilities.include?(capability)
235
+ raise ArgumentError, "#{capability} is not known browser capability."
236
+ end
237
+ nil
238
+ end
239
+
240
+ def assert_valid_version(browser, *versions)
241
+ versions.each do |v|
242
+ unless versions(browser).include?(v)
243
+ raise ArgumentError, "#{v} is not known version for #{browser}."
244
+ end
245
+ end
246
+ end
247
+ end
@@ -4,7 +4,13 @@ module Compass
4
4
  # adapt to various consumers of configuration data
5
5
  module Adapters
6
6
  def to_compiler_arguments(additional_options = {})
7
- [project_path, sass_path, css_path, to_sass_engine_options.merge(additional_options)]
7
+ engine_opts = to_sass_engine_options.merge(additional_options)
8
+ # we have to pass the quiet option in the nested :sass hash to disambiguate it from the compass compiler's own quiet option.
9
+ if engine_opts.has_key?(:quiet)
10
+ engine_opts[:sass] ||= {}
11
+ engine_opts[:sass][:quiet] = engine_opts.delete(:quiet)
12
+ end
13
+ [project_path, sass_path, css_path, engine_opts]
8
14
  end
9
15
 
10
16
  def to_sass_plugin_options
@@ -1,4 +1,9 @@
1
1
  module Compass::SassExtensions::Functions
2
+ module SassDeclarationHelper
3
+ def register_sass_function(*args)
4
+ Sass::Script::Functions.declare(*args)
5
+ end
6
+ end
2
7
  end
3
8
 
4
9
  %w(
@@ -1,6 +1,6 @@
1
1
  module Compass::SassExtensions::Functions::Constants
2
- if defined?(Sass::Script::List)
3
- POSITIONS = /top|bottom|left|right|center/
2
+ POSITIONS = /top|bottom|left|right|center/
3
+ if defined?(Sass::Script::Value::List)
4
4
  def is_position(position)
5
5
  Sass::Script::Bool.new(position.is_a?(Sass::Script::String) && !!(position.value =~ POSITIONS))
6
6
  end
@@ -28,12 +28,13 @@ module Compass::SassExtensions::Functions::CrossBrowserSupport
28
28
 
29
29
  # Check if any of the arguments passed require a vendor prefix.
30
30
  def prefixed(prefix, *args)
31
+ assert_type prefix, :String
31
32
  aspect = prefix.value.sub(/^-/,"")
32
33
  needed = args.any?{|a| a.respond_to?(:supports?) && a.supports?(aspect)}
33
34
  Sass::Script::Bool.new(needed)
34
35
  end
35
36
 
36
- %w(webkit moz o ms svg pie css2).each do |prefix|
37
+ %w(webkit moz o ms svg css2).each do |prefix|
37
38
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
38
39
  # Syntactic sugar to apply the given prefix
39
40
  # -moz($arg) is the same as calling prefix(-moz, $arg)
@@ -44,6 +45,7 @@ module Compass::SassExtensions::Functions::CrossBrowserSupport
44
45
  end
45
46
 
46
47
  def prefix(prefix, *objects)
48
+ assert_type prefix, :String if prefix.is_a?(Sass::Script::Value::Base)
47
49
  prefix = prefix.value if prefix.is_a?(Sass::Script::String)
48
50
  prefix = prefix[1..-1] if prefix[0] == ?-
49
51
  if objects.size > 1
@@ -67,4 +69,177 @@ module Compass::SassExtensions::Functions::CrossBrowserSupport
67
69
  CSS2FallbackValue.new(value, css2_value)
68
70
  end
69
71
 
72
+ # The known browsers.
73
+ #
74
+ # If prefix is given, limits the returned browsers to those using the specified prefix.
75
+ def browsers(prefix = nil)
76
+ browsers = if prefix
77
+ assert_type prefix, :String
78
+ Compass::CanIUse.instance.browsers_with_prefix(prefix.value)
79
+ else
80
+ Compass::CanIUse.instance.browsers
81
+ end
82
+ list(browsers.map{|b| identifier(b)}, :comma)
83
+ end
84
+ Sass::Script::Functions.declare(:browsers, [])
85
+ Sass::Script::Functions.declare(:browsers, [:prefix])
86
+
87
+ # The known capabilities of browsers.
88
+ def browser_capabilities
89
+ list(Compass::CanIUse.instance.capabilities.map{|c| identifier(c)}, :comma)
90
+ end
91
+ Sass::Script::Functions.declare(:browser_capabilities, [])
92
+
93
+ # The versions for the given browser.
94
+ def browser_versions(browser)
95
+ assert_type browser, :String
96
+ list(Compass::CanIUse.instance.versions(browser.value).map{|v| quoted_string(v)}, :comma)
97
+ rescue ArgumentError => e
98
+ raise Sass::SyntaxError.new(e.message)
99
+ end
100
+ Sass::Script::Functions.declare(:browser_versions, [:browser])
101
+
102
+ # whether the browser uses a prefix for the given capability at the version
103
+ # specified or a later version. Returns the prefix it requires, or null.
104
+ def browser_requires_prefix(browser, version, capability, capability_options)
105
+ assert_type browser, :String
106
+ assert_type version, :String
107
+ assert_type capability, :String
108
+ p = Compass::CanIUse.instance.requires_prefix(browser.value,
109
+ version.value,
110
+ capability.value,
111
+ unbox_capability_options_list(capability_options))
112
+ p ? identifier(p) : null()
113
+ rescue ArgumentError => e
114
+ raise Sass::SyntaxError.new(e.message)
115
+ end
116
+ Sass::Script::Functions.declare(:browser_requires_prefix, [:browser, :version, :capability])
117
+
118
+ # the prefix for the given browser.
119
+ def browser_prefix(browser, version = nil)
120
+ assert_type browser, :String
121
+ identifier(Compass::CanIUse.instance.prefix(browser.value))
122
+ rescue ArgumentError => e
123
+ raise Sass::SyntaxError.new(e.message)
124
+ end
125
+ Sass::Script::Functions.declare(:browser_prefix, [:browser])
126
+ Sass::Script::Functions.declare(:browser_prefix, [:browser, :version])
127
+
128
+ # The prefixes used by the given browsers.
129
+ def browser_prefixes(browsers)
130
+ browsers = list(browsers, :comma) if browsers.is_a?(Sass::Script::Value::String)
131
+ assert_type browsers, :List
132
+ browser_strings = browsers.value.map {|b| assert_type(b, :String); b.value }
133
+ prefix_strings = Compass::CanIUse.instance.prefixes(browser_strings)
134
+ list(prefix_strings.map {|p| identifier(p)}, :comma)
135
+ rescue ArgumentError => e
136
+ raise Sass::SyntaxError.new(e.message)
137
+ end
138
+ Sass::Script::Functions.declare(:browser_prefixes, [:browsers])
139
+
140
+ # The percent of users that are omitted by setting the min_version of browser
141
+ # as specified.
142
+ def omitted_usage(browser, min_version)
143
+ assert_type browser, :String
144
+ assert_type min_version, :String
145
+ number(Compass::CanIUse.instance.omitted_usage(browser.value, min_version.value))
146
+ end
147
+ Sass::Script::Functions.declare(:omitted_usage, [:browser, :min_version])
148
+
149
+ # The percent of users relying on a particular prefix
150
+ def prefix_usage(prefix, capability, capability_options)
151
+ assert_type prefix, :String
152
+ assert_type capability, :String
153
+ number(Compass::CanIUse.instance.prefixed_usage(prefix.value,
154
+ capability.value,
155
+ unbox_capability_options_list(capability_options)))
156
+ rescue ArgumentError => e
157
+ raise Sass::SyntaxError.new(e.message)
158
+ end
159
+ Sass::Script::Functions.declare(:prefix_usage, [:prefix, :capability])
160
+
161
+ # Compares two browser versions. Returning:
162
+ #
163
+ # * 0 if they are the same
164
+ # * <0 if the first version is less than the second
165
+ # * >0 if the first version is more than the second
166
+ def compare_browser_versions(browser, version1, version2)
167
+ assert_type browser, :String
168
+ assert_type version1, :String
169
+ assert_type version2, :String
170
+ index1 = index2 = nil
171
+ Compass::CanIUse.instance.versions(browser.value).each_with_index do |v, i|
172
+ index1 = i if v == version1.value
173
+ index2 = i if v == version2.value
174
+ break if index1 && index2
175
+ end
176
+ unless index1
177
+ raise Sass::SyntaxError.new("#{version1} is not a version for #{browser}")
178
+ end
179
+ unless index2
180
+ raise Sass::SyntaxError.new("#{version2} is not a version for #{browser}")
181
+ end
182
+ number(index1 <=> index2)
183
+ end
184
+ Sass::Script::Functions.declare(:compare_browser_versions, [:browser, :version1, :version2])
185
+
186
+ # Returns a map of browsers to the first version the capability became available
187
+ # without a prefix.
188
+ #
189
+ # If a prefix is provided, only those browsers using that prefix will be returned
190
+ # and the minimum version will be when it first became available as a prefix or
191
+ # without a prefix.
192
+ #
193
+ # If a browser does not have the capability, it will not included in the map.
194
+ def browser_minimums(capability, prefix = null())
195
+ assert_type capability, :String
196
+ assert_type(prefix, :String) unless prefix == null()
197
+ mins = Compass::CanIUse.instance.browser_minimums(capability.value, prefix.value)
198
+ Sass::Script::Value::Map.new(mins.inject({}) do |m, (h, k)|
199
+ m[identifier(h)] = quoted_string(k)
200
+ m
201
+ end)
202
+ end
203
+ Sass::Script::Functions.declare(:browser_minimums, [:capability])
204
+ Sass::Script::Functions.declare(:browser_minimums, [:capability, :prefix])
205
+
206
+ private
207
+
208
+ def unbox_capability_options_list(capability_options_list)
209
+ if capability_options_list.is_a?(Sass::Script::Value::Map)
210
+ [unbox_capability_options(capability_options_list)]
211
+ elsif capability_options_list.is_a?(Sass::Script::Value::List)
212
+ capability_options_list.to_a.map{|opts| unbox_capability_options(opts) }
213
+ else
214
+ assert_type capability_options_list, :List
215
+ end
216
+ end
217
+
218
+ CAPABILITY_OPTION_KEYS = {
219
+ "full-support" => :full_support,
220
+ "partial-support" => :partial_support,
221
+ "prefixed" => :prefixed,
222
+ "spec-versions" => :spec_versions,
223
+ }
224
+
225
+ CAPABILITY_OPTION_UNBOXER = {
226
+ :full_support => lambda {|v| v.to_bool },
227
+ :partial_support => lambda {|v| v.to_bool },
228
+ :prefixed => lambda {|v| v.to_bool },
229
+ :spec_versions => lambda {|versions| versions.to_a.map {|v| v.value } }
230
+ }
231
+
232
+ def unbox_capability_options(capability_options)
233
+ assert_type capability_options, :Map
234
+ result = {}
235
+ capability_options.value.each do |k, v|
236
+ assert_type k, :String
237
+ key = CAPABILITY_OPTION_KEYS[k.value]
238
+ unless key
239
+ raise Sass::SyntaxError, "#{k} is not valid capability option"
240
+ end
241
+ result[key] = CAPABILITY_OPTION_UNBOXER[key].call(v)
242
+ end
243
+ result
244
+ end
70
245
  end