haml 3.0.25 → 3.1.0.alpha.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of haml might be problematic. Click here for more details.

Files changed (212) hide show
  1. data/.yardopts +1 -1
  2. data/CONTRIBUTING +0 -1
  3. data/EDGE_GEM_VERSION +1 -0
  4. data/MIT-LICENSE +1 -1
  5. data/README.md +10 -175
  6. data/Rakefile +56 -84
  7. data/VERSION +1 -1
  8. data/VERSION_NAME +1 -1
  9. data/init.rb +1 -1
  10. data/lib/haml.rb +14 -12
  11. data/lib/haml/engine.rb +1 -1
  12. data/lib/haml/exec.rb +19 -316
  13. data/lib/haml/helpers/action_view_extensions.rb +1 -1
  14. data/lib/haml/html.rb +69 -76
  15. data/lib/haml/precompiler.rb +34 -41
  16. data/lib/haml/railtie.rb +4 -6
  17. data/lib/haml/template/plugin.rb +6 -16
  18. data/lib/haml/util.rb +91 -107
  19. data/lib/haml/version.rb +7 -0
  20. data/test/benchmark.rb +2 -9
  21. data/test/haml/engine_test.rb +195 -92
  22. data/test/haml/html2haml/erb_tests.rb +0 -14
  23. data/test/haml/util_test.rb +32 -0
  24. data/test/test_helper.rb +0 -39
  25. metadata +96 -324
  26. data/bin/css2sass +0 -13
  27. data/bin/sass +0 -8
  28. data/bin/sass-convert +0 -7
  29. data/extra/haml-mode.el +0 -753
  30. data/extra/sass-mode.el +0 -207
  31. data/lib/haml/util/subset_map.rb +0 -101
  32. data/lib/sass.rb +0 -29
  33. data/lib/sass/callbacks.rb +0 -52
  34. data/lib/sass/css.rb +0 -294
  35. data/lib/sass/engine.rb +0 -720
  36. data/lib/sass/environment.rb +0 -143
  37. data/lib/sass/error.rb +0 -198
  38. data/lib/sass/files.rb +0 -160
  39. data/lib/sass/less.rb +0 -382
  40. data/lib/sass/plugin.rb +0 -279
  41. data/lib/sass/plugin/configuration.rb +0 -221
  42. data/lib/sass/plugin/generic.rb +0 -15
  43. data/lib/sass/plugin/merb.rb +0 -37
  44. data/lib/sass/plugin/rack.rb +0 -47
  45. data/lib/sass/plugin/rails.rb +0 -32
  46. data/lib/sass/plugin/staleness_checker.rb +0 -123
  47. data/lib/sass/repl.rb +0 -58
  48. data/lib/sass/script.rb +0 -63
  49. data/lib/sass/script/bool.rb +0 -18
  50. data/lib/sass/script/color.rb +0 -491
  51. data/lib/sass/script/css_lexer.rb +0 -29
  52. data/lib/sass/script/css_parser.rb +0 -31
  53. data/lib/sass/script/funcall.rb +0 -77
  54. data/lib/sass/script/functions.rb +0 -861
  55. data/lib/sass/script/interpolation.rb +0 -70
  56. data/lib/sass/script/lexer.rb +0 -337
  57. data/lib/sass/script/literal.rb +0 -236
  58. data/lib/sass/script/node.rb +0 -112
  59. data/lib/sass/script/number.rb +0 -423
  60. data/lib/sass/script/operation.rb +0 -95
  61. data/lib/sass/script/parser.rb +0 -401
  62. data/lib/sass/script/string.rb +0 -67
  63. data/lib/sass/script/string_interpolation.rb +0 -93
  64. data/lib/sass/script/unary_operation.rb +0 -57
  65. data/lib/sass/script/variable.rb +0 -48
  66. data/lib/sass/scss.rb +0 -17
  67. data/lib/sass/scss/css_parser.rb +0 -46
  68. data/lib/sass/scss/parser.rb +0 -855
  69. data/lib/sass/scss/rx.rb +0 -126
  70. data/lib/sass/scss/sass_parser.rb +0 -11
  71. data/lib/sass/scss/script_lexer.rb +0 -15
  72. data/lib/sass/scss/script_parser.rb +0 -25
  73. data/lib/sass/scss/static_parser.rb +0 -40
  74. data/lib/sass/selector.rb +0 -361
  75. data/lib/sass/selector/abstract_sequence.rb +0 -62
  76. data/lib/sass/selector/comma_sequence.rb +0 -82
  77. data/lib/sass/selector/sequence.rb +0 -237
  78. data/lib/sass/selector/simple.rb +0 -113
  79. data/lib/sass/selector/simple_sequence.rb +0 -136
  80. data/lib/sass/tree/charset_node.rb +0 -37
  81. data/lib/sass/tree/comment_node.rb +0 -128
  82. data/lib/sass/tree/debug_node.rb +0 -36
  83. data/lib/sass/tree/directive_node.rb +0 -75
  84. data/lib/sass/tree/extend_node.rb +0 -65
  85. data/lib/sass/tree/for_node.rb +0 -55
  86. data/lib/sass/tree/if_node.rb +0 -69
  87. data/lib/sass/tree/import_node.rb +0 -102
  88. data/lib/sass/tree/mixin_def_node.rb +0 -48
  89. data/lib/sass/tree/mixin_node.rb +0 -111
  90. data/lib/sass/tree/node.rb +0 -464
  91. data/lib/sass/tree/prop_node.rb +0 -220
  92. data/lib/sass/tree/root_node.rb +0 -163
  93. data/lib/sass/tree/rule_node.rb +0 -261
  94. data/lib/sass/tree/variable_node.rb +0 -39
  95. data/lib/sass/tree/warn_node.rb +0 -42
  96. data/lib/sass/tree/while_node.rb +0 -36
  97. data/test/haml/util/subset_map_test.rb +0 -91
  98. data/test/sass/callbacks_test.rb +0 -61
  99. data/test/sass/conversion_test.rb +0 -1218
  100. data/test/sass/css2sass_test.rb +0 -364
  101. data/test/sass/data/hsl-rgb.txt +0 -319
  102. data/test/sass/engine_test.rb +0 -2267
  103. data/test/sass/extend_test.rb +0 -1348
  104. data/test/sass/functions_test.rb +0 -556
  105. data/test/sass/less_conversion_test.rb +0 -653
  106. data/test/sass/more_results/more1.css +0 -9
  107. data/test/sass/more_results/more1_with_line_comments.css +0 -26
  108. data/test/sass/more_results/more_import.css +0 -29
  109. data/test/sass/more_templates/_more_partial.sass +0 -2
  110. data/test/sass/more_templates/more1.sass +0 -23
  111. data/test/sass/more_templates/more_import.sass +0 -11
  112. data/test/sass/plugin_test.rb +0 -433
  113. data/test/sass/results/alt.css +0 -4
  114. data/test/sass/results/basic.css +0 -9
  115. data/test/sass/results/compact.css +0 -5
  116. data/test/sass/results/complex.css +0 -86
  117. data/test/sass/results/compressed.css +0 -1
  118. data/test/sass/results/expanded.css +0 -19
  119. data/test/sass/results/import.css +0 -31
  120. data/test/sass/results/import_charset.css +0 -4
  121. data/test/sass/results/import_charset_1_8.css +0 -4
  122. data/test/sass/results/import_charset_ibm866.css +0 -4
  123. data/test/sass/results/line_numbers.css +0 -49
  124. data/test/sass/results/mixins.css +0 -95
  125. data/test/sass/results/multiline.css +0 -24
  126. data/test/sass/results/nested.css +0 -22
  127. data/test/sass/results/options.css +0 -1
  128. data/test/sass/results/parent_ref.css +0 -13
  129. data/test/sass/results/script.css +0 -16
  130. data/test/sass/results/scss_import.css +0 -31
  131. data/test/sass/results/scss_importee.css +0 -2
  132. data/test/sass/results/subdir/nested_subdir/nested_subdir.css +0 -1
  133. data/test/sass/results/subdir/subdir.css +0 -3
  134. data/test/sass/results/units.css +0 -11
  135. data/test/sass/results/warn.css +0 -0
  136. data/test/sass/results/warn_imported.css +0 -0
  137. data/test/sass/script_conversion_test.rb +0 -314
  138. data/test/sass/script_test.rb +0 -470
  139. data/test/sass/scss/css_test.rb +0 -916
  140. data/test/sass/scss/rx_test.rb +0 -156
  141. data/test/sass/scss/scss_test.rb +0 -1122
  142. data/test/sass/scss/test_helper.rb +0 -37
  143. data/test/sass/templates/_imported_charset_ibm866.sass +0 -4
  144. data/test/sass/templates/_imported_charset_utf8.sass +0 -4
  145. data/test/sass/templates/_partial.sass +0 -2
  146. data/test/sass/templates/alt.sass +0 -16
  147. data/test/sass/templates/basic.sass +0 -23
  148. data/test/sass/templates/bork1.sass +0 -2
  149. data/test/sass/templates/bork2.sass +0 -2
  150. data/test/sass/templates/bork3.sass +0 -2
  151. data/test/sass/templates/bork4.sass +0 -2
  152. data/test/sass/templates/compact.sass +0 -17
  153. data/test/sass/templates/complex.sass +0 -305
  154. data/test/sass/templates/compressed.sass +0 -15
  155. data/test/sass/templates/expanded.sass +0 -17
  156. data/test/sass/templates/import.sass +0 -12
  157. data/test/sass/templates/import_charset.sass +0 -7
  158. data/test/sass/templates/import_charset_1_8.sass +0 -4
  159. data/test/sass/templates/import_charset_ibm866.sass +0 -9
  160. data/test/sass/templates/importee.less +0 -2
  161. data/test/sass/templates/importee.sass +0 -19
  162. data/test/sass/templates/line_numbers.sass +0 -13
  163. data/test/sass/templates/mixin_bork.sass +0 -5
  164. data/test/sass/templates/mixins.sass +0 -76
  165. data/test/sass/templates/multiline.sass +0 -20
  166. data/test/sass/templates/nested.sass +0 -25
  167. data/test/sass/templates/nested_bork1.sass +0 -2
  168. data/test/sass/templates/nested_bork2.sass +0 -2
  169. data/test/sass/templates/nested_bork3.sass +0 -2
  170. data/test/sass/templates/nested_bork4.sass +0 -2
  171. data/test/sass/templates/nested_mixin_bork.sass +0 -6
  172. data/test/sass/templates/options.sass +0 -2
  173. data/test/sass/templates/parent_ref.sass +0 -25
  174. data/test/sass/templates/script.sass +0 -101
  175. data/test/sass/templates/scss_import.scss +0 -11
  176. data/test/sass/templates/scss_importee.scss +0 -1
  177. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +0 -2
  178. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +0 -3
  179. data/test/sass/templates/subdir/subdir.sass +0 -6
  180. data/test/sass/templates/units.sass +0 -11
  181. data/test/sass/templates/warn.sass +0 -3
  182. data/test/sass/templates/warn_imported.sass +0 -4
  183. data/vendor/fssm/LICENSE +0 -20
  184. data/vendor/fssm/README.markdown +0 -55
  185. data/vendor/fssm/Rakefile +0 -59
  186. data/vendor/fssm/VERSION.yml +0 -5
  187. data/vendor/fssm/example.rb +0 -9
  188. data/vendor/fssm/fssm.gemspec +0 -77
  189. data/vendor/fssm/lib/fssm.rb +0 -33
  190. data/vendor/fssm/lib/fssm/backends/fsevents.rb +0 -36
  191. data/vendor/fssm/lib/fssm/backends/inotify.rb +0 -26
  192. data/vendor/fssm/lib/fssm/backends/polling.rb +0 -25
  193. data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +0 -131
  194. data/vendor/fssm/lib/fssm/monitor.rb +0 -26
  195. data/vendor/fssm/lib/fssm/path.rb +0 -91
  196. data/vendor/fssm/lib/fssm/pathname.rb +0 -502
  197. data/vendor/fssm/lib/fssm/state/directory.rb +0 -57
  198. data/vendor/fssm/lib/fssm/state/file.rb +0 -24
  199. data/vendor/fssm/lib/fssm/support.rb +0 -63
  200. data/vendor/fssm/lib/fssm/tree.rb +0 -176
  201. data/vendor/fssm/profile/prof-cache.rb +0 -40
  202. data/vendor/fssm/profile/prof-fssm-pathname.html +0 -1231
  203. data/vendor/fssm/profile/prof-pathname.rb +0 -68
  204. data/vendor/fssm/profile/prof-plain-pathname.html +0 -988
  205. data/vendor/fssm/profile/prof.html +0 -2379
  206. data/vendor/fssm/spec/path_spec.rb +0 -75
  207. data/vendor/fssm/spec/root/duck/quack.txt +0 -0
  208. data/vendor/fssm/spec/root/file.css +0 -0
  209. data/vendor/fssm/spec/root/file.rb +0 -0
  210. data/vendor/fssm/spec/root/file.yml +0 -0
  211. data/vendor/fssm/spec/root/moo/cow.txt +0 -0
  212. data/vendor/fssm/spec/spec_helper.rb +0 -14
@@ -1,29 +0,0 @@
1
- module Sass
2
- module Script
3
- # This is a subclass of {Lexer} for use in parsing plain CSS properties.
4
- #
5
- # @see Sass::SCSS::CssParser
6
- class CssLexer < Lexer
7
- private
8
-
9
- def token
10
- important || super
11
- end
12
-
13
- def string(re, *args)
14
- if re == :uri
15
- return unless uri = scan(URI)
16
- return [:string, Script::String.new(uri)]
17
- end
18
-
19
- return unless scan(STRING)
20
- [:string, Script::String.new((@scanner[1] || @scanner[2]).gsub(/\\(['"])/, '\1'), :string)]
21
- end
22
-
23
- def important
24
- return unless s = scan(IMPORTANT)
25
- [:raw, s]
26
- end
27
- end
28
- end
29
- end
@@ -1,31 +0,0 @@
1
- require 'sass/script'
2
- require 'sass/script/css_lexer'
3
-
4
- module Sass
5
- module Script
6
- # This is a subclass of {Parser} for use in parsing plain CSS properties.
7
- #
8
- # @see Sass::SCSS::CssParser
9
- class CssParser < Parser
10
- private
11
-
12
- # @private
13
- def lexer_class; CssLexer; end
14
-
15
- # We need a production that only does /,
16
- # since * and % aren't allowed in plain CSS
17
- production :div, :unary_plus, :div
18
-
19
- def string
20
- return number unless tok = try_tok(:string)
21
- return tok.value unless @lexer.peek && @lexer.peek.type == :begin_interpolation
22
- end
23
-
24
- # Short-circuit all the SassScript-only productions
25
- alias_method :interpolation, :concat
26
- alias_method :or_expr, :div
27
- alias_method :unary_div, :ident
28
- alias_method :paren, :string
29
- end
30
- end
31
- end
@@ -1,77 +0,0 @@
1
- require 'sass/script/functions'
2
-
3
- module Sass
4
- module Script
5
- # A SassScript parse node representing a function call.
6
- #
7
- # A function call either calls one of the functions in {Script::Functions},
8
- # or if no function with the given name exists
9
- # it returns a string representation of the function call.
10
- class Funcall < Node
11
- # The name of the function.
12
- #
13
- # @return [String]
14
- attr_reader :name
15
-
16
- # The arguments to the function.
17
- #
18
- # @return [Array<Script::Node>]
19
- attr_reader :args
20
-
21
- # Don't set the context for child nodes if this is `url()`,
22
- # since `url()` allows quoted strings.
23
- #
24
- # @param context [Symbol]
25
- # @see Node#context=
26
- def context=(context)
27
- super unless @name == "url"
28
- end
29
-
30
- # @param name [String] See \{#name}
31
- # @param name [Array<Script::Node>] See \{#args}
32
- def initialize(name, args)
33
- @name = name
34
- @args = args
35
- super()
36
- end
37
-
38
- # @return [String] A string representation of the function call
39
- def inspect
40
- "#{name}(#{args.map {|a| a.inspect}.join(', ')})"
41
- end
42
-
43
- # @see Node#to_sass
44
- def to_sass(opts = {})
45
- "#{dasherize(name, opts)}(#{args.map {|a| a.to_sass(opts)}.join(', ')})"
46
- end
47
-
48
- # Returns the arguments to the function.
49
- #
50
- # @return [Array<Node>]
51
- # @see Node#children
52
- def children
53
- @args
54
- end
55
-
56
- protected
57
-
58
- # Evaluates the function call.
59
- #
60
- # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
61
- # @return [Literal] The SassScript object that is the value of the function call
62
- # @raise [Sass::SyntaxError] if the function call raises an ArgumentError
63
- def _perform(environment)
64
- args = self.args.map {|a| a.perform(environment)}
65
- ruby_name = name.gsub('-', '_')
66
- unless Haml::Util.has?(:public_instance_method, Functions, ruby_name) && ruby_name !~ /^__/
67
- opts(Script::String.new("#{name}(#{args.map {|a| a.perform(environment)}.join(', ')})"))
68
- else
69
- opts(Functions::EvaluationContext.new(environment.options).send(ruby_name, *args))
70
- end
71
- rescue ArgumentError => e
72
- raise e unless e.backtrace.any? {|t| t =~ /:in `(block in )?(#{name}|perform)'$/}
73
- raise Sass::SyntaxError.new("#{e.message} for `#{name}'")
74
- end
75
- end
76
- end
77
- end
@@ -1,861 +0,0 @@
1
- module Sass::Script
2
- # Methods in this module are accessible from the SassScript context.
3
- # For example, you can write
4
- #
5
- # $color = hsl(120deg, 100%, 50%)
6
- #
7
- # and it will call {Sass::Script::Functions#hsl}.
8
- #
9
- # The following functions are provided:
10
- #
11
- # ## RGB Functions
12
- #
13
- # \{#rgb}
14
- # : Converts an `rgb(red, green, blue)` triplet into a color.
15
- #
16
- # \{#rgba}
17
- # : Converts an `rgba(red, green, blue, alpha)` quadruplet into a color.
18
- #
19
- # \{#red}
20
- # : Gets the red component of a color.
21
- #
22
- # \{#green}
23
- # : Gets the green component of a color.
24
- #
25
- # \{#blue}
26
- # : Gets the blue component of a color.
27
- #
28
- # \{#mix}
29
- # : Mixes two colors together.
30
- #
31
- # ## HSL Functions
32
- #
33
- # \{#hsl}
34
- # : Converts an `hsl(hue, saturation, lightness)` triplet into a color.
35
- #
36
- # \{#hsla}
37
- # : Converts an `hsla(hue, saturation, lightness, alpha)` quadruplet into a color.
38
- #
39
- # \{#hue}
40
- # : Gets the hue component of a color.
41
- #
42
- # \{#saturation}
43
- # : Gets the saturation component of a color.
44
- #
45
- # \{#lightness}
46
- # : Gets the lightness component of a color.
47
- #
48
- # \{#adjust_hue #adjust-hue}
49
- # : Changes the hue of a color.
50
- #
51
- # \{#lighten}
52
- # : Makes a color lighter.
53
- #
54
- # \{#darken}
55
- # : Makes a color darker.
56
- #
57
- # \{#saturate}
58
- # : Makes a color more saturated.
59
- #
60
- # \{#desaturate}
61
- # : Makes a color less saturated.
62
- #
63
- # \{#grayscale}
64
- # : Converts a color to grayscale.
65
- #
66
- # \{#complement}
67
- # : Returns the complement of a color.
68
- #
69
- # ## Opacity Functions
70
- #
71
- # \{#alpha} / \{#opacity}
72
- # : Gets the alpha component (opacity) of a color.
73
- #
74
- # \{#rgba}
75
- # : Sets the alpha component of a color.
76
- #
77
- # \{#opacify} / \{#fade_in #fade-in}
78
- # : Makes a color more opaque.
79
- #
80
- # \{#transparentize} / \{#fade_out #fade-out}
81
- # : Makes a color more transparent.
82
- #
83
- # ## String Functions
84
- #
85
- # \{#unquote}
86
- # : Removes the quotes from a string.
87
- #
88
- # \{#quote}
89
- # : Adds quotes to a string.
90
- #
91
- # ## Number Functions
92
- #
93
- # \{#percentage}
94
- # : Converts a unitless number to a percentage.
95
- #
96
- # \{#round}
97
- # : Rounds a number to the nearest whole number.
98
- #
99
- # \{#ceil}
100
- # : Rounds a number up to the nearest whole number.
101
- #
102
- # \{#floor}
103
- # : Rounds a number down to the nearest whole number.
104
- #
105
- # \{#abs}
106
- # : Returns the absolute value of a number.
107
- #
108
- # ## Introspection Functions
109
- #
110
- # \{#type_of}
111
- # : Returns the type of a value.
112
- #
113
- # \{#unit}
114
- # : Returns the units associated with a number.
115
- #
116
- # \{#unitless}
117
- # : Returns whether a number has units or not.
118
- #
119
- # \{#comparable}
120
- # : Returns whether two numbers can be added or compared.
121
- #
122
- # These functions are described in more detail below.
123
- #
124
- # ## Adding Custom Functions
125
- #
126
- # New Sass functions can be added by adding Ruby methods to this module.
127
- # For example:
128
- #
129
- # module Sass::Script::Functions
130
- # def reverse(string)
131
- # assert_type string, :String
132
- # Sass::Script::String.new(string.value.reverse)
133
- # end
134
- # end
135
- #
136
- # There are a few things to keep in mind when modifying this module.
137
- # First of all, the arguments passed are {Sass::Script::Literal} objects.
138
- # Literal objects are also expected to be returned.
139
- # This means that Ruby values must be unwrapped and wrapped.
140
- #
141
- # Most Literal objects support the {Sass::Script::Literal#value value} accessor
142
- # for getting their Ruby values.
143
- # Color objects, though, must be accessed using {Sass::Script::Color#rgb rgb},
144
- # {Sass::Script::Color#red red}, {Sass::Script::Color#blue green}, or {Sass::Script::Color#blue blue}.
145
- #
146
- # Second, making Ruby functions accessible from Sass introduces the temptation
147
- # to do things like database access within stylesheets.
148
- # This is generally a bad idea;
149
- # since Sass files are by default only compiled once,
150
- # dynamic code is not a great fit.
151
- #
152
- # If you really, really need to compile Sass on each request,
153
- # first make sure you have adequate caching set up.
154
- # Then you can use {Sass::Engine} to render the code,
155
- # using the {file:SASS_REFERENCE.md#custom-option `options` parameter}
156
- # to pass in data that {EvaluationContext#options can be accessed}
157
- # from your Sass functions.
158
- #
159
- # Within one of the functions in this module,
160
- # methods of {EvaluationContext} can be used.
161
- #
162
- # ### Caveats
163
- #
164
- # When creating new {Literal} objects within functions,
165
- # be aware that it's not safe to call {Literal#to_s #to_s}
166
- # (or other methods that use the string representation)
167
- # on those objects without first setting {Node#options= the #options attribute}.
168
- module Functions
169
- # The context in which methods in {Script::Functions} are evaluated.
170
- # That means that all instance methods of {EvaluationContext}
171
- # are available to use in functions.
172
- class EvaluationContext
173
- # The options hash for the {Sass::Engine} that is processing the function call
174
- #
175
- # @return [{Symbol => Object}]
176
- attr_reader :options
177
-
178
- # @param options [{Symbol => Object}] See \{#options}
179
- def initialize(options)
180
- @options = options
181
-
182
- # We need to include this individually in each instance
183
- # because of an icky Ruby restriction
184
- class << self; include Sass::Script::Functions; end
185
- end
186
-
187
- # Asserts that the type of a given SassScript value
188
- # is the expected type (designated by a symbol).
189
- # For example:
190
- #
191
- # assert_type value, :String
192
- # assert_type value, :Number
193
- #
194
- # Valid types are `:Bool`, `:Color`, `:Number`, and `:String`.
195
- # Note that `:String` will match both double-quoted strings
196
- # and unquoted identifiers.
197
- #
198
- # @param value [Sass::Script::Literal] A SassScript value
199
- # @param type [Symbol] The name of the type the value is expected to be
200
- def assert_type(value, type)
201
- return if value.is_a?(Sass::Script.const_get(type))
202
- raise ArgumentError.new("#{value.inspect} is not a #{type.to_s.downcase}")
203
- end
204
- end
205
-
206
- instance_methods.each { |m| undef_method m unless m.to_s =~ /^__/ }
207
-
208
-
209
- # Creates a {Color} object from red, green, and blue values.
210
- #
211
- # @param red [Number]
212
- # A number between 0 and 255 inclusive,
213
- # or between 0% and 100% inclusive
214
- # @param green [Number]
215
- # A number between 0 and 255 inclusive,
216
- # or between 0% and 100% inclusive
217
- # @param blue [Number]
218
- # A number between 0 and 255 inclusive,
219
- # or between 0% and 100% inclusive
220
- # @see #rgba
221
- # @return [Color]
222
- def rgb(red, green, blue)
223
- assert_type red, :Number
224
- assert_type green, :Number
225
- assert_type blue, :Number
226
-
227
- Color.new([red, green, blue].map do |c|
228
- v = c.value
229
- if c.numerator_units == ["%"] && c.denominator_units.empty?
230
- next v * 255 / 100.0 if (0..100).include?(v)
231
- raise ArgumentError.new("Color value #{c} must be between 0% and 100% inclusive")
232
- else
233
- next v if (0..255).include?(v)
234
- raise ArgumentError.new("Color value #{v} must be between 0 and 255 inclusive")
235
- end
236
- end)
237
- end
238
-
239
- # @see #rgb
240
- # @overload rgba(red, green, blue, alpha)
241
- # Creates a {Color} object from red, green, and blue values,
242
- # as well as an alpha channel indicating opacity.
243
- #
244
- # @param red [Number]
245
- # A number between 0 and 255 inclusive
246
- # @param green [Number]
247
- # A number between 0 and 255 inclusive
248
- # @param blue [Number]
249
- # A number between 0 and 255 inclusive
250
- # @param alpha [Number]
251
- # A number between 0 and 1
252
- # @return [Color]
253
- #
254
- # @overload rgba(color, alpha)
255
- # Sets the opacity of a color.
256
- #
257
- # @example
258
- # rgba(#102030, 0.5) => rgba(16, 32, 48, 0.5)
259
- # rgba(blue, 0.2) => rgba(0, 0, 255, 0.2)
260
- #
261
- # @param color [Color]
262
- # @param alpha [Number]
263
- # A number between 0 and 1
264
- # @return [Color]
265
- def rgba(*args)
266
- case args.size
267
- when 2
268
- color, alpha = args
269
-
270
- assert_type color, :Color
271
- assert_type alpha, :Number
272
-
273
- unless (0..1).include?(alpha.value)
274
- raise ArgumentError.new("Alpha channel #{alpha.value} must be between 0 and 1 inclusive")
275
- end
276
-
277
- color.with(:alpha => alpha.value)
278
- when 4
279
- red, green, blue, alpha = args
280
- rgba(rgb(red, green, blue), alpha)
281
- else
282
- raise ArgumentError.new("wrong number of arguments (#{args.size} for 4)")
283
- end
284
- end
285
-
286
- # Creates a {Color} object from hue, saturation, and lightness.
287
- # Uses the algorithm from the [CSS3 spec](http://www.w3.org/TR/css3-color/#hsl-color).
288
- #
289
- # @param hue [Number] The hue of the color.
290
- # Should be between 0 and 360 degrees, inclusive
291
- # @param saturation [Number] The saturation of the color.
292
- # Must be between `0%` and `100%`, inclusive
293
- # @param lightness [Number] The lightness of the color.
294
- # Must be between `0%` and `100%`, inclusive
295
- # @return [Color] The resulting color
296
- # @see #hsla
297
- # @raise [ArgumentError] if `saturation` or `lightness` are out of bounds
298
- def hsl(hue, saturation, lightness)
299
- hsla(hue, saturation, lightness, Number.new(1))
300
- end
301
-
302
- # Creates a {Color} object from hue, saturation, and lightness,
303
- # as well as an alpha channel indicating opacity.
304
- # Uses the algorithm from the [CSS3 spec](http://www.w3.org/TR/css3-color/#hsl-color).
305
- #
306
- # @param hue [Number] The hue of the color.
307
- # Should be between 0 and 360 degrees, inclusive
308
- # @param saturation [Number] The saturation of the color.
309
- # Must be between `0%` and `100%`, inclusive
310
- # @param lightness [Number] The lightness of the color.
311
- # Must be between `0%` and `100%`, inclusive
312
- # @param alpha [Number] The opacity of the color.
313
- # Must be between 0 and 1, inclusive
314
- # @return [Color] The resulting color
315
- # @see #hsl
316
- # @raise [ArgumentError] if `saturation`, `lightness`, or `alpha` are out of bounds
317
- def hsla(hue, saturation, lightness, alpha)
318
- assert_type hue, :Number
319
- assert_type saturation, :Number
320
- assert_type lightness, :Number
321
- assert_type alpha, :Number
322
-
323
- unless (0..1).include?(alpha.value)
324
- raise ArgumentError.new("Alpha channel #{alpha.value} must be between 0 and 1")
325
- end
326
-
327
- original_s = saturation
328
- original_l = lightness
329
- # This algorithm is from http://www.w3.org/TR/css3-color#hsl-color
330
- h, s, l = [hue, saturation, lightness].map { |a| a.value }
331
- raise ArgumentError.new("Saturation #{s} must be between 0% and 100%") unless (0..100).include?(s)
332
- raise ArgumentError.new("Lightness #{l} must be between 0% and 100%") unless (0..100).include?(l)
333
-
334
- Color.new(:hue => h, :saturation => s, :lightness => l, :alpha => alpha.value)
335
- end
336
-
337
- # Returns the red component of a color.
338
- #
339
- # @param color [Color]
340
- # @return [Number]
341
- # @raise [ArgumentError] If `color` isn't a color
342
- def red(color)
343
- assert_type color, :Color
344
- Sass::Script::Number.new(color.red)
345
- end
346
-
347
- # Returns the green component of a color.
348
- #
349
- # @param color [Color]
350
- # @return [Number]
351
- # @raise [ArgumentError] If `color` isn't a color
352
- def green(color)
353
- assert_type color, :Color
354
- Sass::Script::Number.new(color.green)
355
- end
356
-
357
- # Returns the blue component of a color.
358
- #
359
- # @param color [Color]
360
- # @return [Number]
361
- # @raise [ArgumentError] If `color` isn't a color
362
- def blue(color)
363
- assert_type color, :Color
364
- Sass::Script::Number.new(color.blue)
365
- end
366
-
367
- # Returns the hue component of a color.
368
- #
369
- # See [the CSS3 HSL specification](http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV).
370
- #
371
- # Calculated from RGB where necessary via [this algorithm](http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV).
372
- #
373
- # @param color [Color]
374
- # @return [Number] between 0deg and 360deg
375
- # @see #adjust_hue
376
- # @raise [ArgumentError] if `color` isn't a color
377
- def hue(color)
378
- assert_type color, :Color
379
- Sass::Script::Number.new(color.hue, ["deg"])
380
- end
381
-
382
- # Returns the saturation component of a color.
383
- #
384
- # See [the CSS3 HSL specification](http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV).
385
- #
386
- # Calculated from RGB where necessary via [this algorithm](http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV).
387
- #
388
- # @param color [Color]
389
- # @return [Number] between 0% and 100%
390
- # @see #saturate
391
- # @see #desaturate
392
- # @raise [ArgumentError] if `color` isn't a color
393
- def saturation(color)
394
- assert_type color, :Color
395
- Sass::Script::Number.new(color.saturation, ["%"])
396
- end
397
-
398
- # Returns the hue component of a color.
399
- #
400
- # See [the CSS3 HSL specification](http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV).
401
- #
402
- # Calculated from RGB where necessary via [this algorithm](http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV).
403
- #
404
- # @param color [Color]
405
- # @return [Number] between 0% and 100%
406
- # @see #lighten
407
- # @see #darken
408
- # @raise [ArgumentError] if `color` isn't a color
409
- def lightness(color)
410
- assert_type color, :Color
411
- Sass::Script::Number.new(color.lightness, ["%"])
412
- end
413
-
414
- # Returns the alpha component (opacity) of a color.
415
- # This is 1 unless otherwise specified.
416
- #
417
- # This function also supports the proprietary Microsoft
418
- # `alpha(opacity=20)` syntax.
419
- #
420
- # @overload def alpha(color)
421
- # @param color [Color]
422
- # @return [Number]
423
- # @see #opacify
424
- # @see #transparentize
425
- # @raise [ArgumentError] If `color` isn't a color
426
- def alpha(*args)
427
- if args.all? do |a|
428
- a.is_a?(Sass::Script::String) && a.type == :identifier &&
429
- a.value =~ /^[a-zA-Z]+\s*=/
430
- end
431
- # Support the proprietary MS alpha() function
432
- return Sass::Script::String.new("alpha(#{args.map {|a| a.to_s}.join(", ")})")
433
- end
434
-
435
- opacity(*args)
436
- end
437
-
438
- # Returns the alpha component (opacity) of a color.
439
- # This is 1 unless otherwise specified.
440
- #
441
- # @param color [Color]
442
- # @return [Number]
443
- # @see #opacify
444
- # @see #transparentize
445
- # @raise [ArgumentError] If `color` isn't a color
446
- def opacity(color)
447
- assert_type color, :Color
448
- Sass::Script::Number.new(color.alpha)
449
- end
450
-
451
- # Makes a color more opaque.
452
- # Takes a color and an amount between 0 and 1,
453
- # and returns a color with the opacity increased by that value.
454
- #
455
- # For example:
456
- #
457
- # opacify(rgba(0, 0, 0, 0.5), 0.1) => rgba(0, 0, 0, 0.6)
458
- # opacify(rgba(0, 0, 17, 0.8), 0.2) => #001
459
- #
460
- # @param color [Color]
461
- # @param amount [Number]
462
- # @return [Color]
463
- # @see #transparentize
464
- # @raise [ArgumentError] If `color` isn't a color,
465
- # or `number` isn't a number between 0 and 1
466
- def opacify(color, amount)
467
- adjust(color, amount, :alpha, 0..1, :+)
468
- end
469
- alias_method :fade_in, :opacify
470
-
471
- # Makes a color more transparent.
472
- # Takes a color and an amount between 0 and 1,
473
- # and returns a color with the opacity decreased by that value.
474
- #
475
- # For example:
476
- #
477
- # transparentize(rgba(0, 0, 0, 0.5), 0.1) => rgba(0, 0, 0, 0.4)
478
- # transparentize(rgba(0, 0, 0, 0.8), 0.2) => rgba(0, 0, 0, 0.6)
479
- #
480
- # @param color [Color]
481
- # @param amount [Number]
482
- # @return [Color]
483
- # @see #opacify
484
- # @raise [ArgumentError] If `color` isn't a color,
485
- # or `number` isn't a number between 0 and 1
486
- def transparentize(color, amount)
487
- adjust(color, amount, :alpha, 0..1, :-)
488
- end
489
- alias_method :fade_out, :transparentize
490
-
491
- # Makes a color lighter.
492
- # Takes a color and an amount between 0% and 100%,
493
- # and returns a color with the lightness increased by that value.
494
- #
495
- # For example:
496
- #
497
- # lighten(hsl(0, 0%, 0%), 30%) => hsl(0, 0, 30)
498
- # lighten(#800, 20%) => #e00
499
- #
500
- # @param color [Color]
501
- # @param amount [Number]
502
- # @return [Color]
503
- # @see #darken
504
- # @raise [ArgumentError] If `color` isn't a color,
505
- # or `number` isn't a number between 0% and 100%
506
- def lighten(color, amount)
507
- adjust(color, amount, :lightness, 0..100, :+, "%")
508
- end
509
-
510
- # Makes a color darker.
511
- # Takes a color and an amount between 0% and 100%,
512
- # and returns a color with the lightness decreased by that value.
513
- #
514
- # For example:
515
- #
516
- # darken(hsl(25, 100%, 80%), 30%) => hsl(25, 100%, 50%)
517
- # darken(#800, 20%) => #200
518
- #
519
- # @param color [Color]
520
- # @param amount [Number]
521
- # @return [Color]
522
- # @see #lighten
523
- # @raise [ArgumentError] If `color` isn't a color,
524
- # or `number` isn't a number between 0% and 100%
525
- def darken(color, amount)
526
- adjust(color, amount, :lightness, 0..100, :-, "%")
527
- end
528
-
529
- # Makes a color more saturated.
530
- # Takes a color and an amount between 0% and 100%,
531
- # and returns a color with the saturation increased by that value.
532
- #
533
- # For example:
534
- #
535
- # saturate(hsl(120, 30%, 90%), 20%) => hsl(120, 50%, 90%)
536
- # saturate(#855, 20%) => #9e3f3f
537
- #
538
- # @param color [Color]
539
- # @param amount [Number]
540
- # @return [Color]
541
- # @see #desaturate
542
- # @raise [ArgumentError] If `color` isn't a color,
543
- # or `number` isn't a number between 0% and 100%
544
- def saturate(color, amount)
545
- adjust(color, amount, :saturation, 0..100, :+, "%")
546
- end
547
-
548
- # Makes a color less saturated.
549
- # Takes a color and an amount between 0% and 100%,
550
- # and returns a color with the saturation decreased by that value.
551
- #
552
- # For example:
553
- #
554
- # desaturate(hsl(120, 30%, 90%), 20%) => hsl(120, 10%, 90%)
555
- # desaturate(#855, 20%) => #726b6b
556
- #
557
- # @param color [Color]
558
- # @param amount [Number]
559
- # @return [Color]
560
- # @see #saturate
561
- # @raise [ArgumentError] If `color` isn't a color,
562
- # or `number` isn't a number between 0% and 100%
563
- def desaturate(color, amount)
564
- adjust(color, amount, :saturation, 0..100, :-, "%")
565
- end
566
-
567
- # Changes the hue of a color while retaining the lightness and saturation.
568
- # Takes a color and a number of degrees (usually between -360deg and 360deg),
569
- # and returns a color with the hue rotated by that value.
570
- #
571
- # For example:
572
- #
573
- # adjust-hue(hsl(120, 30%, 90%), 60deg) => hsl(180, 30%, 90%)
574
- # adjust-hue(hsl(120, 30%, 90%), 060deg) => hsl(60, 30%, 90%)
575
- # adjust-hue(#811, 45deg) => #886a11
576
- #
577
- # @param color [Color]
578
- # @param amount [Number]
579
- # @return [Color]
580
- # @raise [ArgumentError] If `color` isn't a color, or `number` isn't a number
581
- def adjust_hue(color, degrees)
582
- assert_type color, :Color
583
- assert_type degrees, :Number
584
- color.with(:hue => color.hue + degrees.value)
585
- end
586
-
587
- # Mixes together two colors.
588
- # Specifically, takes the average of each of the RGB components,
589
- # optionally weighted by the given percentage.
590
- # The opacity of the colors is also considered when weighting the components.
591
- #
592
- # The weight specifies the amount of the first color that should be included
593
- # in the returned color.
594
- # The default, 50%, means that half the first color
595
- # and half the second color should be used.
596
- # 25% means that a quarter of the first color
597
- # and three quarters of the second color should be used.
598
- #
599
- # For example:
600
- #
601
- # mix(#f00, #00f) => #7f007f
602
- # mix(#f00, #00f, 25%) => #3f00bf
603
- # mix(rgba(255, 0, 0, 0.5), #00f) => rgba(63, 0, 191, 0.75)
604
- #
605
- # @overload mix(color1, color2, weight = 50%)
606
- # @param color1 [Color]
607
- # @param color2 [Color]
608
- # @param weight [Number] between 0% and 100%
609
- # @return [Color]
610
- # @raise [ArgumentError] if `color1` or `color2` aren't colors,
611
- # or `weight` isn't a number between 0% and 100%
612
- def mix(color1, color2, weight = Number.new(50))
613
- assert_type color1, :Color
614
- assert_type color2, :Color
615
- assert_type weight, :Number
616
-
617
- unless (0..100).include?(weight.value)
618
- raise ArgumentError.new("Weight #{weight} must be between 0% and 100%")
619
- end
620
-
621
- # This algorithm factors in both the user-provided weight
622
- # and the difference between the alpha values of the two colors
623
- # to decide how to perform the weighted average of the two RGB values.
624
- #
625
- # It works by first normalizing both parameters to be within [-1, 1],
626
- # where 1 indicates "only use color1", -1 indicates "only use color 0",
627
- # and all values in between indicated a proportionately weighted average.
628
- #
629
- # Once we have the normalized variables w and a,
630
- # we apply the formula (w + a)/(1 + w*a)
631
- # to get the combined weight (in [-1, 1]) of color1.
632
- # This formula has two especially nice properties:
633
- #
634
- # * When either w or a are -1 or 1, the combined weight is also that number
635
- # (cases where w * a == -1 are undefined, and handled as a special case).
636
- #
637
- # * When a is 0, the combined weight is w, and vice versa
638
- #
639
- # Finally, the weight of color1 is renormalized to be within [0, 1]
640
- # and the weight of color2 is given by 1 minus the weight of color1.
641
- p = weight.value/100.0
642
- w = p*2 - 1
643
- a = color1.alpha - color2.alpha
644
-
645
- w1 = (((w * a == -1) ? w : (w + a)/(1 + w*a)) + 1)/2.0
646
- w2 = 1 - w1
647
-
648
- rgb = color1.rgb.zip(color2.rgb).map {|v1, v2| v1*w1 + v2*w2}
649
- alpha = color1.alpha*p + color2.alpha*(1-p)
650
- Color.new(rgb + [alpha])
651
- end
652
-
653
- # Converts a color to grayscale.
654
- # This is identical to `desaturate(color, 100%)`.
655
- #
656
- # @param color [Color]
657
- # @return [Color]
658
- # @raise [ArgumentError] if `color` isn't a color
659
- # @see #desaturate
660
- def grayscale(color)
661
- desaturate color, Number.new(100)
662
- end
663
-
664
- # Returns the complement of a color.
665
- # This is identical to `adjust-hue(color, 180deg)`.
666
- #
667
- # @param color [Color]
668
- # @return [Color]
669
- # @raise [ArgumentError] if `color` isn't a color
670
- # @see #adjust_hue #adjust-hue
671
- def complement(color)
672
- adjust_hue color, Number.new(180)
673
- end
674
-
675
- # Removes quotes from a string if the string is quoted,
676
- # or returns the same string if it's not.
677
- #
678
- # @param str [String]
679
- # @return [String]
680
- # @raise [ArgumentError] if `str` isn't a string
681
- # @see #quote
682
- # @example
683
- # unquote("foo") => foo
684
- # unquote(foo) => foo
685
- def unquote(str)
686
- assert_type str, :String
687
- Sass::Script::String.new(str.value, :identifier)
688
- end
689
-
690
- # Add quotes to a string if the string isn't quoted,
691
- # or returns the same string if it is.
692
- #
693
- # @param str [String]
694
- # @return [String]
695
- # @raise [ArgumentError] if `str` isn't a string
696
- # @see #unquote
697
- # @example
698
- # quote("foo") => "foo"
699
- # quote(foo) => "foo"
700
- def quote(str)
701
- assert_type str, :String
702
- Sass::Script::String.new(str.value, :string)
703
- end
704
-
705
- # Inspects the type of the argument, returning it as an unquoted string.
706
- # For example:
707
- #
708
- # type-of(100px) => number
709
- # type-of(asdf) => string
710
- # type-of("asdf") => string
711
- # type-of(true) => bool
712
- # type-of(#fff) => color
713
- # type-of(blue) => color
714
- #
715
- # @param obj [Literal] The object to inspect
716
- # @return [String] The unquoted string name of the literal's type
717
- def type_of(obj)
718
- Sass::Script::String.new(obj.class.name.gsub(/Sass::Script::/,'').downcase)
719
- end
720
-
721
- # Inspects the unit of the number, returning it as a quoted string.
722
- # Complex units are sorted in alphabetical order by numerator and denominator.
723
- # For example:
724
- #
725
- # unit(100) => ""
726
- # unit(100px) => "px"
727
- # unit(3em) => "em"
728
- # unit(10px * 5em) => "em*px"
729
- # unit(10px * 5em / 30cm / 1rem) => "em*px/cm*rem"
730
- #
731
- # @param number [Literal] The number to inspect
732
- # @return [String] The unit(s) of the number
733
- # @raise [ArgumentError] if `number` isn't a number
734
- def unit(number)
735
- assert_type number, :Number
736
- Sass::Script::String.new(number.unit_str, :string)
737
- end
738
-
739
- # Inspects the unit of the number, returning a boolean indicating if it is unitless.
740
- # For example:
741
- #
742
- # unitless(100) => true
743
- # unitless(100px) => false
744
- #
745
- # @param number [Literal] The number to inspect
746
- # @return [Bool] Whether or not the number is unitless
747
- # @raise [ArgumentError] if `number` isn't a number
748
- def unitless(number)
749
- assert_type number, :Number
750
- Sass::Script::Bool.new(number.unitless?)
751
- end
752
-
753
- # Returns true if two numbers are similar enough to be added, subtracted, or compared.
754
- # For example:
755
- #
756
- # comparable(2px, 1px) => true
757
- # comparable(100px, 3em) => false
758
- # comparable(10cm, 3mm) => true
759
- #
760
- # @param number1 [Number]
761
- # @param number2 [Number]
762
- # @return [Bool] indicating if the numbers can be compared.
763
- # @raise [ArgumentError] if `number1` or `number2` aren't numbers
764
- def comparable(number1, number2)
765
- assert_type number1, :Number
766
- assert_type number2, :Number
767
- Sass::Script::Bool.new(number1.comparable_to?(number2))
768
- end
769
-
770
- # Converts a decimal number to a percentage.
771
- # For example:
772
- #
773
- # percentage(100px / 50px) => 200%
774
- #
775
- # @param value [Number] The decimal number to convert to a percentage
776
- # @return [Number] The percentage
777
- # @raise [ArgumentError] If `value` isn't a unitless number
778
- def percentage(value)
779
- unless value.is_a?(Sass::Script::Number) && value.unitless?
780
- raise ArgumentError.new("#{value.inspect} is not a unitless number")
781
- end
782
- Sass::Script::Number.new(value.value * 100, ['%'])
783
- end
784
-
785
- # Rounds a number to the nearest whole number.
786
- # For example:
787
- #
788
- # round(10.4px) => 10px
789
- # round(10.6px) => 11px
790
- #
791
- # @param value [Number] The number
792
- # @return [Number] The rounded number
793
- # @raise [Sass::SyntaxError] if `value` isn't a number
794
- def round(value)
795
- numeric_transformation(value) {|n| n.round}
796
- end
797
-
798
- # Rounds a number up to the nearest whole number.
799
- # For example:
800
- #
801
- # ciel(10.4px) => 11px
802
- # ciel(10.6px) => 11px
803
- #
804
- # @param value [Number] The number
805
- # @return [Number] The rounded number
806
- # @raise [Sass::SyntaxError] if `value` isn't a number
807
- def ceil(value)
808
- numeric_transformation(value) {|n| n.ceil}
809
- end
810
-
811
- # Rounds down to the nearest whole number.
812
- # For example:
813
- #
814
- # floor(10.4px) => 10px
815
- # floor(10.6px) => 10px
816
- #
817
- # @param value [Number] The number
818
- # @return [Number] The rounded number
819
- # @raise [Sass::SyntaxError] if `value` isn't a number
820
- def floor(value)
821
- numeric_transformation(value) {|n| n.floor}
822
- end
823
-
824
- # Finds the absolute value of a number.
825
- # For example:
826
- #
827
- # abs(10px) => 10px
828
- # abs(-10px) => 10px
829
- #
830
- # @param value [Number] The number
831
- # @return [Number] The absolute value
832
- # @raise [Sass::SyntaxError] if `value` isn't a number
833
- def abs(value)
834
- numeric_transformation(value) {|n| n.abs}
835
- end
836
-
837
- private
838
-
839
- # This method implements the pattern of transforming a numeric value into
840
- # another numeric value with the same units.
841
- # It yields a number to a block to perform the operation and return a number
842
- def numeric_transformation(value)
843
- assert_type value, :Number
844
- Sass::Script::Number.new(yield(value.value), value.numerator_units, value.denominator_units)
845
- end
846
-
847
- def adjust(color, amount, attr, range, op, units = "")
848
- assert_type color, :Color
849
- assert_type amount, :Number
850
- unless range.include?(amount.value)
851
- raise ArgumentError.new("Amount #{amount} must be between #{range.first}#{units} and #{range.last}#{units}")
852
- end
853
-
854
- # TODO: is it worth restricting here,
855
- # or should we do so in the Color constructor itself,
856
- # and allow clipping in rgb() et al?
857
- color.with(attr => Haml::Util.restrict(
858
- color.send(attr).send(op, amount.value), range))
859
- end
860
- end
861
- end