sass 3.1.0 → 3.3.0

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 (260) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING +1 -1
  3. data/MIT-LICENSE +2 -2
  4. data/README.md +29 -17
  5. data/Rakefile +43 -9
  6. data/VERSION +1 -1
  7. data/VERSION_DATE +1 -0
  8. data/VERSION_NAME +1 -1
  9. data/bin/sass +6 -1
  10. data/bin/sass-convert +6 -1
  11. data/bin/scss +6 -1
  12. data/ext/mkrf_conf.rb +27 -0
  13. data/lib/sass/cache_stores/base.rb +7 -3
  14. data/lib/sass/cache_stores/chain.rb +3 -2
  15. data/lib/sass/cache_stores/filesystem.rb +5 -7
  16. data/lib/sass/cache_stores/memory.rb +1 -1
  17. data/lib/sass/cache_stores/null.rb +2 -2
  18. data/lib/sass/callbacks.rb +2 -1
  19. data/lib/sass/css.rb +168 -53
  20. data/lib/sass/engine.rb +502 -174
  21. data/lib/sass/environment.rb +151 -111
  22. data/lib/sass/error.rb +7 -7
  23. data/lib/sass/exec.rb +176 -60
  24. data/lib/sass/features.rb +40 -0
  25. data/lib/sass/importers/base.rb +46 -7
  26. data/lib/sass/importers/deprecated_path.rb +51 -0
  27. data/lib/sass/importers/filesystem.rb +113 -30
  28. data/lib/sass/importers.rb +1 -0
  29. data/lib/sass/logger/base.rb +30 -0
  30. data/lib/sass/logger/log_level.rb +45 -0
  31. data/lib/sass/logger.rb +12 -0
  32. data/lib/sass/media.rb +213 -0
  33. data/lib/sass/plugin/compiler.rb +194 -104
  34. data/lib/sass/plugin/configuration.rb +18 -25
  35. data/lib/sass/plugin/merb.rb +1 -1
  36. data/lib/sass/plugin/staleness_checker.rb +37 -11
  37. data/lib/sass/plugin.rb +10 -13
  38. data/lib/sass/railtie.rb +2 -1
  39. data/lib/sass/repl.rb +5 -6
  40. data/lib/sass/script/css_lexer.rb +8 -4
  41. data/lib/sass/script/css_parser.rb +5 -2
  42. data/lib/sass/script/functions.rb +1547 -618
  43. data/lib/sass/script/lexer.rb +122 -72
  44. data/lib/sass/script/parser.rb +304 -135
  45. data/lib/sass/script/tree/funcall.rb +306 -0
  46. data/lib/sass/script/{interpolation.rb → tree/interpolation.rb} +43 -13
  47. data/lib/sass/script/tree/list_literal.rb +77 -0
  48. data/lib/sass/script/tree/literal.rb +45 -0
  49. data/lib/sass/script/tree/map_literal.rb +64 -0
  50. data/lib/sass/script/{node.rb → tree/node.rb} +30 -12
  51. data/lib/sass/script/{operation.rb → tree/operation.rb} +33 -21
  52. data/lib/sass/script/{string_interpolation.rb → tree/string_interpolation.rb} +14 -4
  53. data/lib/sass/script/{unary_operation.rb → tree/unary_operation.rb} +21 -9
  54. data/lib/sass/script/tree/variable.rb +57 -0
  55. data/lib/sass/script/tree.rb +15 -0
  56. data/lib/sass/script/value/arg_list.rb +36 -0
  57. data/lib/sass/script/value/base.rb +238 -0
  58. data/lib/sass/script/value/bool.rb +40 -0
  59. data/lib/sass/script/{color.rb → value/color.rb} +256 -74
  60. data/lib/sass/script/value/deprecated_false.rb +55 -0
  61. data/lib/sass/script/value/helpers.rb +155 -0
  62. data/lib/sass/script/value/list.rb +128 -0
  63. data/lib/sass/script/value/map.rb +70 -0
  64. data/lib/sass/script/value/null.rb +49 -0
  65. data/lib/sass/script/{number.rb → value/number.rb} +115 -62
  66. data/lib/sass/script/{string.rb → value/string.rb} +9 -11
  67. data/lib/sass/script/value.rb +12 -0
  68. data/lib/sass/script.rb +35 -9
  69. data/lib/sass/scss/css_parser.rb +2 -12
  70. data/lib/sass/scss/parser.rb +657 -230
  71. data/lib/sass/scss/rx.rb +17 -12
  72. data/lib/sass/scss/static_parser.rb +37 -6
  73. data/lib/sass/scss.rb +0 -1
  74. data/lib/sass/selector/abstract_sequence.rb +35 -3
  75. data/lib/sass/selector/comma_sequence.rb +29 -14
  76. data/lib/sass/selector/sequence.rb +371 -74
  77. data/lib/sass/selector/simple.rb +28 -13
  78. data/lib/sass/selector/simple_sequence.rb +163 -36
  79. data/lib/sass/selector.rb +138 -36
  80. data/lib/sass/shared.rb +3 -5
  81. data/lib/sass/source/map.rb +196 -0
  82. data/lib/sass/source/position.rb +39 -0
  83. data/lib/sass/source/range.rb +41 -0
  84. data/lib/sass/stack.rb +126 -0
  85. data/lib/sass/supports.rb +228 -0
  86. data/lib/sass/tree/at_root_node.rb +82 -0
  87. data/lib/sass/tree/comment_node.rb +34 -29
  88. data/lib/sass/tree/content_node.rb +9 -0
  89. data/lib/sass/tree/css_import_node.rb +60 -0
  90. data/lib/sass/tree/debug_node.rb +3 -3
  91. data/lib/sass/tree/directive_node.rb +33 -3
  92. data/lib/sass/tree/each_node.rb +9 -9
  93. data/lib/sass/tree/extend_node.rb +20 -6
  94. data/lib/sass/tree/for_node.rb +6 -6
  95. data/lib/sass/tree/function_node.rb +12 -4
  96. data/lib/sass/tree/if_node.rb +2 -15
  97. data/lib/sass/tree/import_node.rb +11 -5
  98. data/lib/sass/tree/media_node.rb +27 -11
  99. data/lib/sass/tree/mixin_def_node.rb +15 -4
  100. data/lib/sass/tree/mixin_node.rb +27 -7
  101. data/lib/sass/tree/node.rb +69 -35
  102. data/lib/sass/tree/prop_node.rb +47 -31
  103. data/lib/sass/tree/return_node.rb +4 -3
  104. data/lib/sass/tree/root_node.rb +20 -4
  105. data/lib/sass/tree/rule_node.rb +37 -26
  106. data/lib/sass/tree/supports_node.rb +38 -0
  107. data/lib/sass/tree/trace_node.rb +33 -0
  108. data/lib/sass/tree/variable_node.rb +10 -4
  109. data/lib/sass/tree/visitors/base.rb +5 -8
  110. data/lib/sass/tree/visitors/check_nesting.rb +67 -52
  111. data/lib/sass/tree/visitors/convert.rb +134 -53
  112. data/lib/sass/tree/visitors/cssize.rb +245 -51
  113. data/lib/sass/tree/visitors/deep_copy.rb +102 -0
  114. data/lib/sass/tree/visitors/extend.rb +68 -0
  115. data/lib/sass/tree/visitors/perform.rb +331 -105
  116. data/lib/sass/tree/visitors/set_options.rb +125 -0
  117. data/lib/sass/tree/visitors/to_css.rb +259 -95
  118. data/lib/sass/tree/warn_node.rb +3 -3
  119. data/lib/sass/tree/while_node.rb +3 -3
  120. data/lib/sass/util/cross_platform_random.rb +19 -0
  121. data/lib/sass/util/multibyte_string_scanner.rb +157 -0
  122. data/lib/sass/util/normalized_map.rb +130 -0
  123. data/lib/sass/util/ordered_hash.rb +192 -0
  124. data/lib/sass/util/subset_map.rb +11 -2
  125. data/lib/sass/util/test.rb +9 -0
  126. data/lib/sass/util.rb +565 -39
  127. data/lib/sass/version.rb +27 -15
  128. data/lib/sass.rb +39 -4
  129. data/test/sass/cache_test.rb +15 -0
  130. data/test/sass/compiler_test.rb +223 -0
  131. data/test/sass/conversion_test.rb +901 -107
  132. data/test/sass/css2sass_test.rb +94 -0
  133. data/test/sass/engine_test.rb +1059 -164
  134. data/test/sass/exec_test.rb +86 -0
  135. data/test/sass/extend_test.rb +933 -837
  136. data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
  137. data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
  138. data/test/sass/functions_test.rb +995 -136
  139. data/test/sass/importer_test.rb +338 -18
  140. data/test/sass/logger_test.rb +58 -0
  141. data/test/sass/more_results/more_import.css +2 -2
  142. data/test/sass/plugin_test.rb +114 -30
  143. data/test/sass/results/cached_import_option.css +3 -0
  144. data/test/sass/results/filename_fn.css +3 -0
  145. data/test/sass/results/import.css +2 -2
  146. data/test/sass/results/import_charset.css +1 -0
  147. data/test/sass/results/import_charset_1_8.css +1 -0
  148. data/test/sass/results/import_charset_ibm866.css +1 -0
  149. data/test/sass/results/import_content.css +1 -0
  150. data/test/sass/results/script.css +1 -1
  151. data/test/sass/results/scss_import.css +2 -2
  152. data/test/sass/results/units.css +2 -2
  153. data/test/sass/script_conversion_test.rb +43 -1
  154. data/test/sass/script_test.rb +380 -36
  155. data/test/sass/scss/css_test.rb +257 -75
  156. data/test/sass/scss/scss_test.rb +2322 -110
  157. data/test/sass/source_map_test.rb +887 -0
  158. data/test/sass/templates/_cached_import_option_partial.scss +1 -0
  159. data/test/sass/templates/_double_import_loop2.sass +1 -0
  160. data/test/sass/templates/_filename_fn_import.scss +11 -0
  161. data/test/sass/templates/_imported_content.sass +3 -0
  162. data/test/sass/templates/_same_name_different_partiality.scss +1 -0
  163. data/test/sass/templates/bork5.sass +3 -0
  164. data/test/sass/templates/cached_import_option.scss +3 -0
  165. data/test/sass/templates/double_import_loop1.sass +1 -0
  166. data/test/sass/templates/filename_fn.scss +18 -0
  167. data/test/sass/templates/import_charset.sass +2 -0
  168. data/test/sass/templates/import_charset_1_8.sass +2 -0
  169. data/test/sass/templates/import_charset_ibm866.sass +2 -0
  170. data/test/sass/templates/import_content.sass +4 -0
  171. data/test/sass/templates/same_name_different_ext.sass +2 -0
  172. data/test/sass/templates/same_name_different_ext.scss +1 -0
  173. data/test/sass/templates/same_name_different_partiality.scss +1 -0
  174. data/test/sass/templates/single_import_loop.sass +1 -0
  175. data/test/sass/templates/subdir/import_up1.scss +1 -0
  176. data/test/sass/templates/subdir/import_up2.scss +1 -0
  177. data/test/sass/test_helper.rb +1 -1
  178. data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
  179. data/test/sass/util/normalized_map_test.rb +51 -0
  180. data/test/sass/util_test.rb +183 -0
  181. data/test/sass/value_helpers_test.rb +181 -0
  182. data/test/test_helper.rb +45 -5
  183. data/vendor/listen/CHANGELOG.md +228 -0
  184. data/vendor/listen/CONTRIBUTING.md +38 -0
  185. data/vendor/listen/Gemfile +30 -0
  186. data/vendor/listen/Guardfile +8 -0
  187. data/vendor/{fssm → listen}/LICENSE +1 -1
  188. data/vendor/listen/README.md +315 -0
  189. data/vendor/listen/Rakefile +47 -0
  190. data/vendor/listen/Vagrantfile +96 -0
  191. data/vendor/listen/lib/listen/adapter.rb +214 -0
  192. data/vendor/listen/lib/listen/adapters/bsd.rb +112 -0
  193. data/vendor/listen/lib/listen/adapters/darwin.rb +85 -0
  194. data/vendor/listen/lib/listen/adapters/linux.rb +113 -0
  195. data/vendor/listen/lib/listen/adapters/polling.rb +67 -0
  196. data/vendor/listen/lib/listen/adapters/windows.rb +87 -0
  197. data/vendor/listen/lib/listen/dependency_manager.rb +126 -0
  198. data/vendor/listen/lib/listen/directory_record.rb +371 -0
  199. data/vendor/listen/lib/listen/listener.rb +225 -0
  200. data/vendor/listen/lib/listen/multi_listener.rb +143 -0
  201. data/vendor/listen/lib/listen/turnstile.rb +28 -0
  202. data/vendor/listen/lib/listen/version.rb +3 -0
  203. data/vendor/listen/lib/listen.rb +40 -0
  204. data/vendor/listen/listen.gemspec +22 -0
  205. data/vendor/listen/spec/listen/adapter_spec.rb +183 -0
  206. data/vendor/listen/spec/listen/adapters/bsd_spec.rb +36 -0
  207. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +37 -0
  208. data/vendor/listen/spec/listen/adapters/linux_spec.rb +47 -0
  209. data/vendor/listen/spec/listen/adapters/polling_spec.rb +68 -0
  210. data/vendor/listen/spec/listen/adapters/windows_spec.rb +30 -0
  211. data/vendor/listen/spec/listen/dependency_manager_spec.rb +107 -0
  212. data/vendor/listen/spec/listen/directory_record_spec.rb +1225 -0
  213. data/vendor/listen/spec/listen/listener_spec.rb +169 -0
  214. data/vendor/listen/spec/listen/multi_listener_spec.rb +174 -0
  215. data/vendor/listen/spec/listen/turnstile_spec.rb +56 -0
  216. data/vendor/listen/spec/listen_spec.rb +73 -0
  217. data/vendor/listen/spec/spec_helper.rb +21 -0
  218. data/vendor/listen/spec/support/adapter_helper.rb +629 -0
  219. data/vendor/listen/spec/support/directory_record_helper.rb +55 -0
  220. data/vendor/listen/spec/support/fixtures_helper.rb +29 -0
  221. data/vendor/listen/spec/support/listeners_helper.rb +156 -0
  222. data/vendor/listen/spec/support/platform_helper.rb +15 -0
  223. metadata +344 -271
  224. data/lib/sass/less.rb +0 -382
  225. data/lib/sass/script/bool.rb +0 -18
  226. data/lib/sass/script/funcall.rb +0 -162
  227. data/lib/sass/script/list.rb +0 -76
  228. data/lib/sass/script/literal.rb +0 -245
  229. data/lib/sass/script/variable.rb +0 -54
  230. data/lib/sass/scss/sass_parser.rb +0 -11
  231. data/test/sass/less_conversion_test.rb +0 -653
  232. data/vendor/fssm/README.markdown +0 -55
  233. data/vendor/fssm/Rakefile +0 -59
  234. data/vendor/fssm/VERSION.yml +0 -5
  235. data/vendor/fssm/example.rb +0 -9
  236. data/vendor/fssm/fssm.gemspec +0 -77
  237. data/vendor/fssm/lib/fssm/backends/fsevents.rb +0 -36
  238. data/vendor/fssm/lib/fssm/backends/inotify.rb +0 -26
  239. data/vendor/fssm/lib/fssm/backends/polling.rb +0 -25
  240. data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +0 -131
  241. data/vendor/fssm/lib/fssm/monitor.rb +0 -26
  242. data/vendor/fssm/lib/fssm/path.rb +0 -91
  243. data/vendor/fssm/lib/fssm/pathname.rb +0 -502
  244. data/vendor/fssm/lib/fssm/state/directory.rb +0 -57
  245. data/vendor/fssm/lib/fssm/state/file.rb +0 -24
  246. data/vendor/fssm/lib/fssm/support.rb +0 -63
  247. data/vendor/fssm/lib/fssm/tree.rb +0 -176
  248. data/vendor/fssm/lib/fssm.rb +0 -33
  249. data/vendor/fssm/profile/prof-cache.rb +0 -40
  250. data/vendor/fssm/profile/prof-fssm-pathname.html +0 -1231
  251. data/vendor/fssm/profile/prof-pathname.rb +0 -68
  252. data/vendor/fssm/profile/prof-plain-pathname.html +0 -988
  253. data/vendor/fssm/profile/prof.html +0 -2379
  254. data/vendor/fssm/spec/path_spec.rb +0 -75
  255. data/vendor/fssm/spec/root/duck/quack.txt +0 -0
  256. data/vendor/fssm/spec/root/file.css +0 -0
  257. data/vendor/fssm/spec/root/file.rb +0 -0
  258. data/vendor/fssm/spec/root/file.yml +0 -0
  259. data/vendor/fssm/spec/root/moo/cow.txt +0 -0
  260. data/vendor/fssm/spec/spec_helper.rb +0 -14
@@ -1,13 +1,4 @@
1
- require 'set'
2
- require 'sass/script/string'
3
- require 'sass/script/number'
4
- require 'sass/script/color'
5
- require 'sass/script/functions'
6
- require 'sass/script/unary_operation'
7
- require 'sass/script/interpolation'
8
- require 'sass/script/string_interpolation'
9
-
10
- module Sass::Script
1
+ module Sass::Script::Tree
11
2
  # A SassScript parse node representing a binary operation,
12
3
  # such as `$a + $b` or `"foo" + 1`.
13
4
  class Operation < Node
@@ -15,12 +6,12 @@ module Sass::Script
15
6
  attr_reader :operand2
16
7
  attr_reader :operator
17
8
 
18
- # @param operand1 [Script::Node] The parse-tree node
9
+ # @param operand1 [Sass::Script::Tree::Node] The parse-tree node
19
10
  # for the right-hand side of the operator
20
- # @param operand2 [Script::Node] The parse-tree node
11
+ # @param operand2 [Sass::Script::Tree::Node] The parse-tree node
21
12
  # for the left-hand side of the operator
22
13
  # @param operator [Symbol] The operator to perform.
23
- # This should be one of the binary operator names in {Lexer::OPERATORS}
14
+ # This should be one of the binary operator names in {Sass::Script::Lexer::OPERATORS}
24
15
  def initialize(operand1, operand2, operator)
25
16
  @operand1 = operand1
26
17
  @operand2 = operand2
@@ -35,14 +26,13 @@ module Sass::Script
35
26
 
36
27
  # @see Node#to_sass
37
28
  def to_sass(opts = {})
38
- pred = Sass::Script::Parser.precedence_of(@operator)
39
29
  o1 = operand_to_sass @operand1, :left, opts
40
30
  o2 = operand_to_sass @operand2, :right, opts
41
31
  sep =
42
32
  case @operator
43
33
  when :comma; ", "
44
34
  when :space; " "
45
- else; " #{Lexer::OPERATORS_REVERSE[@operator]} "
35
+ else; " #{Sass::Script::Lexer::OPERATORS_REVERSE[@operator]} "
46
36
  end
47
37
  "#{o1}#{sep}#{o2}"
48
38
  end
@@ -55,29 +45,51 @@ module Sass::Script
55
45
  [@operand1, @operand2]
56
46
  end
57
47
 
48
+ # @see Node#deep_copy
49
+ def deep_copy
50
+ node = dup
51
+ node.instance_variable_set('@operand1', @operand1.deep_copy)
52
+ node.instance_variable_set('@operand2', @operand2.deep_copy)
53
+ node
54
+ end
55
+
58
56
  protected
59
57
 
60
58
  # Evaluates the operation.
61
59
  #
62
60
  # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
63
- # @return [Literal] The SassScript object that is the value of the operation
61
+ # @return [Sass::Script::Value] The SassScript object that is the value of the operation
64
62
  # @raise [Sass::SyntaxError] if the operation is undefined for the operands
65
63
  def _perform(environment)
66
- literal1 = @operand1.perform(environment)
67
- literal2 = @operand2.perform(environment)
64
+ value1 = @operand1.perform(environment)
65
+
66
+ # Special-case :and and :or to support short-circuiting.
67
+ if @operator == :and
68
+ return value1.to_bool ? @operand2.perform(environment) : value1
69
+ elsif @operator == :or
70
+ return value1.to_bool ? value1 : @operand2.perform(environment)
71
+ end
72
+
73
+ value2 = @operand2.perform(environment)
74
+
75
+ if (value1.is_a?(Sass::Script::Value::Null) || value2.is_a?(Sass::Script::Value::Null)) &&
76
+ @operator != :eq && @operator != :neq
77
+ raise Sass::SyntaxError.new(
78
+ "Invalid null operation: \"#{value1.inspect} #{@operator} #{value2.inspect}\".")
79
+ end
68
80
 
69
81
  begin
70
- opts(literal1.send(@operator, literal2))
82
+ opts(value1.send(@operator, value2))
71
83
  rescue NoMethodError => e
72
84
  raise e unless e.name.to_s == @operator.to_s
73
- raise Sass::SyntaxError.new("Undefined operation: \"#{literal1} #{@operator} #{literal2}\".")
85
+ raise Sass::SyntaxError.new("Undefined operation: \"#{value1} #{@operator} #{value2}\".")
74
86
  end
75
87
  end
76
88
 
77
89
  private
78
90
 
79
91
  def operand_to_sass(op, side, opts)
80
- return "(#{op.to_sass(opts)})" if op.is_a?(List)
92
+ return "(#{op.to_sass(opts)})" if op.is_a?(Sass::Script::Tree::ListLiteral)
81
93
  return op.to_sass(opts) unless op.is_a?(Operation)
82
94
 
83
95
  pred = Sass::Script::Parser.precedence_of(@operator)
@@ -1,4 +1,4 @@
1
- module Sass::Script
1
+ module Sass::Script::Tree
2
2
  # A SassScript object representing `#{}` interpolation within a string.
3
3
  #
4
4
  # @see Interpolation
@@ -60,20 +60,30 @@ module Sass::Script
60
60
  [@before, @mid, @after].compact
61
61
  end
62
62
 
63
+ # @see Node#deep_copy
64
+ def deep_copy
65
+ node = dup
66
+ node.instance_variable_set('@before', @before.deep_copy) if @before
67
+ node.instance_variable_set('@mid', @mid.deep_copy)
68
+ node.instance_variable_set('@after', @after.deep_copy) if @after
69
+ node
70
+ end
71
+
63
72
  protected
64
73
 
65
74
  # Evaluates the interpolation.
66
75
  #
67
76
  # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
68
- # @return [Sass::Script::String] The SassScript string that is the value of the interpolation
77
+ # @return [Sass::Script::Value::String]
78
+ # The SassScript string that is the value of the interpolation
69
79
  def _perform(environment)
70
80
  res = ""
71
81
  before = @before.perform(environment)
72
82
  res << before.value
73
83
  mid = @mid.perform(environment)
74
- res << (mid.is_a?(Sass::Script::String) ? mid.value : mid.to_s)
84
+ res << (mid.is_a?(Sass::Script::Value::String) ? mid.value : mid.to_s)
75
85
  res << @after.perform(environment).value
76
- opts(Sass::Script::String.new(res, before.type))
86
+ opts(Sass::Script::Value::String.new(res, before.type))
77
87
  end
78
88
 
79
89
  private
@@ -1,12 +1,17 @@
1
- module Sass::Script
1
+ module Sass::Script::Tree
2
2
  # A SassScript parse node representing a unary operation,
3
3
  # such as `-$b` or `not true`.
4
4
  #
5
5
  # Currently only `-`, `/`, and `not` are unary operators.
6
6
  class UnaryOperation < Node
7
- # @param operand [Script::Node] The parse-tree node
8
- # for the object of the operator
9
- # @param operator [Symbol] The operator to perform
7
+ # @return [Symbol] The operation to perform
8
+ attr_reader :operator
9
+
10
+ # @return [Script::Node] The parse-tree node for the object of the operator
11
+ attr_reader :operand
12
+
13
+ # @param operand [Script::Node] See \{#operand}
14
+ # @param operator [Symbol] See \{#operator}
10
15
  def initialize(operand, operator)
11
16
  @operand = operand
12
17
  @operator = operator
@@ -26,7 +31,7 @@ module Sass::Script
26
31
  (operand =~ Sass::SCSS::RX::IDENT) == 0)
27
32
  operand = "(#{@operand.to_sass(opts)})"
28
33
  end
29
- op = Lexer::OPERATORS_REVERSE[@operator]
34
+ op = Sass::Script::Lexer::OPERATORS_REVERSE[@operator]
30
35
  op + (op =~ /[a-z]/ ? " " : "") + operand
31
36
  end
32
37
 
@@ -38,20 +43,27 @@ module Sass::Script
38
43
  [@operand]
39
44
  end
40
45
 
46
+ # @see Node#deep_copy
47
+ def deep_copy
48
+ node = dup
49
+ node.instance_variable_set('@operand', @operand.deep_copy)
50
+ node
51
+ end
52
+
41
53
  protected
42
54
 
43
55
  # Evaluates the operation.
44
56
  #
45
57
  # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
46
- # @return [Literal] The SassScript object that is the value of the operation
58
+ # @return [Sass::Script::Value] The SassScript object that is the value of the operation
47
59
  # @raise [Sass::SyntaxError] if the operation is undefined for the operand
48
60
  def _perform(environment)
49
61
  operator = "unary_#{@operator}"
50
- literal = @operand.perform(environment)
51
- literal.send(operator)
62
+ value = @operand.perform(environment)
63
+ value.send(operator)
52
64
  rescue NoMethodError => e
53
65
  raise e unless e.name.to_s == operator.to_s
54
- raise Sass::SyntaxError.new("Undefined unary operation: \"#{@operator} #{literal}\".")
66
+ raise Sass::SyntaxError.new("Undefined unary operation: \"#{@operator} #{value}\".")
55
67
  end
56
68
  end
57
69
  end
@@ -0,0 +1,57 @@
1
+ module Sass::Script::Tree
2
+ # A SassScript parse node representing a variable.
3
+ class Variable < Node
4
+ # The name of the variable.
5
+ #
6
+ # @return [String]
7
+ attr_reader :name
8
+
9
+ # The underscored name of the variable.
10
+ #
11
+ # @return [String]
12
+ attr_reader :underscored_name
13
+
14
+ # @param name [String] See \{#name}
15
+ def initialize(name)
16
+ @name = name
17
+ @underscored_name = name.gsub(/-/, "_")
18
+ super()
19
+ end
20
+
21
+ # @return [String] A string representation of the variable
22
+ def inspect(opts = {})
23
+ "$#{dasherize(name, opts)}"
24
+ end
25
+ alias_method :to_sass, :inspect
26
+
27
+ # Returns an empty array.
28
+ #
29
+ # @return [Array<Node>] empty
30
+ # @see Node#children
31
+ def children
32
+ []
33
+ end
34
+
35
+ # @see Node#deep_copy
36
+ def deep_copy
37
+ dup
38
+ end
39
+
40
+ protected
41
+
42
+ # Evaluates the variable.
43
+ #
44
+ # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
45
+ # @return [Sass::Script::Value] The SassScript object that is the value of the variable
46
+ # @raise [Sass::SyntaxError] if the variable is undefined
47
+ def _perform(environment)
48
+ val = environment.var(name)
49
+ raise Sass::SyntaxError.new("Undefined variable: \"$#{name}\".") unless val
50
+ if val.is_a?(Sass::Script::Value::Number) && val.original
51
+ val = val.dup
52
+ val.original = nil
53
+ end
54
+ val
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,15 @@
1
+ # The module containing nodes in the SassScript parse tree. These nodes are
2
+ # all subclasses of {Sass::Script::Tree::Node}.
3
+ module Sass::Script::Tree
4
+ end
5
+
6
+ require 'sass/script/tree/node'
7
+ require 'sass/script/tree/variable'
8
+ require 'sass/script/tree/funcall'
9
+ require 'sass/script/tree/operation'
10
+ require 'sass/script/tree/unary_operation'
11
+ require 'sass/script/tree/interpolation'
12
+ require 'sass/script/tree/string_interpolation'
13
+ require 'sass/script/tree/literal'
14
+ require 'sass/script/tree/list_literal'
15
+ require 'sass/script/tree/map_literal'
@@ -0,0 +1,36 @@
1
+ module Sass::Script::Value
2
+ # A SassScript object representing a variable argument list. This works just
3
+ # like a normal list, but can also contain keyword arguments.
4
+ #
5
+ # The keyword arguments attached to this list are unused except when this is
6
+ # passed as a glob argument to a function or mixin.
7
+ class ArgList < List
8
+ # Whether \{#keywords} has been accessed. If so, we assume that all keywords
9
+ # were valid for the function that created this ArgList.
10
+ #
11
+ # @return [Boolean]
12
+ attr_accessor :keywords_accessed
13
+
14
+ # Creates a new argument list.
15
+ #
16
+ # @param value [Array<Value>] See \{List#value}.
17
+ # @param keywords [Hash<String, Value>, NormalizedMap<Value>] See \{#keywords}
18
+ # @param separator [String] See \{List#separator}.
19
+ def initialize(value, keywords, separator)
20
+ super(value, separator)
21
+ if keywords.is_a?(Sass::Util::NormalizedMap)
22
+ @keywords = keywords
23
+ else
24
+ @keywords = Sass::Util::NormalizedMap.new(keywords)
25
+ end
26
+ end
27
+
28
+ # The keyword arguments attached to this list.
29
+ #
30
+ # @return [NormalizedMap<Value>]
31
+ def keywords
32
+ @keywords_accessed = true
33
+ @keywords
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,238 @@
1
+ module Sass::Script::Value
2
+ # The abstract superclass for SassScript objects.
3
+ #
4
+ # Many of these methods, especially the ones that correspond to SassScript operations,
5
+ # are designed to be overridden by subclasses which may change the semantics somewhat.
6
+ # The operations listed here are just the defaults.
7
+ class Base
8
+ # Returns the Ruby value of the value.
9
+ # The type of this value varies based on the subclass.
10
+ #
11
+ # @return [Object]
12
+ attr_reader :value
13
+
14
+ # The source range in the document on which this node appeared.
15
+ #
16
+ # @return [Sass::Source::Range]
17
+ attr_accessor :source_range
18
+
19
+ # Creates a new value.
20
+ #
21
+ # @param value [Object] The object for \{#value}
22
+ def initialize(value = nil)
23
+ @value = value.freeze
24
+ end
25
+
26
+ # Sets the options hash for this node,
27
+ # as well as for all child nodes.
28
+ # See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
29
+ #
30
+ # @param options [{Symbol => Object}] The options
31
+ attr_writer :options
32
+
33
+ # Returns the options hash for this node.
34
+ #
35
+ # @return [{Symbol => Object}]
36
+ # @raise [Sass::SyntaxError] if the options hash hasn't been set.
37
+ # This should only happen when the value was created
38
+ # outside of the parser and \{#to\_s} was called on it
39
+ def options
40
+ return @options if @options
41
+ raise Sass::SyntaxError.new(<<MSG)
42
+ The #options attribute is not set on this #{self.class}.
43
+ This error is probably occurring because #to_s was called
44
+ on this value within a custom Sass function without first
45
+ setting the #options attribute.
46
+ MSG
47
+ end
48
+
49
+ # The SassScript `==` operation.
50
+ # **Note that this returns a {Sass::Script::Value::Bool} object,
51
+ # not a Ruby boolean**.
52
+ #
53
+ # @param other [Value] The right-hand side of the operator
54
+ # @return [Sass::Script::Value::Bool] True if this value is the same as the other,
55
+ # false otherwise
56
+ def eq(other)
57
+ Sass::Script::Value::Bool.new(self.class == other.class && value == other.value)
58
+ end
59
+
60
+ # The SassScript `!=` operation.
61
+ # **Note that this returns a {Sass::Script::Value::Bool} object,
62
+ # not a Ruby boolean**.
63
+ #
64
+ # @param other [Value] The right-hand side of the operator
65
+ # @return [Sass::Script::Value::Bool] False if this value is the same as the other,
66
+ # true otherwise
67
+ def neq(other)
68
+ Sass::Script::Value::Bool.new(!eq(other).to_bool)
69
+ end
70
+
71
+ # The SassScript `==` operation.
72
+ # **Note that this returns a {Sass::Script::Value::Bool} object,
73
+ # not a Ruby boolean**.
74
+ #
75
+ # @param other [Value] The right-hand side of the operator
76
+ # @return [Sass::Script::Value::Bool] True if this value is the same as the other,
77
+ # false otherwise
78
+ def unary_not
79
+ Sass::Script::Value::Bool.new(!to_bool)
80
+ end
81
+
82
+ # The SassScript `=` operation
83
+ # (used for proprietary MS syntax like `alpha(opacity=20)`).
84
+ #
85
+ # @param other [Value] The right-hand side of the operator
86
+ # @return [Script::Value::String] A string containing both values
87
+ # separated by `"="`
88
+ def single_eq(other)
89
+ Sass::Script::Value::String.new("#{to_s}=#{other.to_s}")
90
+ end
91
+
92
+ # The SassScript `+` operation.
93
+ #
94
+ # @param other [Value] The right-hand side of the operator
95
+ # @return [Script::Value::String] A string containing both values
96
+ # without any separation
97
+ def plus(other)
98
+ if other.is_a?(Sass::Script::Value::String)
99
+ return Sass::Script::Value::String.new(to_s + other.value, other.type)
100
+ end
101
+ Sass::Script::Value::String.new(to_s + other.to_s)
102
+ end
103
+
104
+ # The SassScript `-` operation.
105
+ #
106
+ # @param other [Value] The right-hand side of the operator
107
+ # @return [Script::Value::String] A string containing both values
108
+ # separated by `"-"`
109
+ def minus(other)
110
+ Sass::Script::Value::String.new("#{to_s}-#{other.to_s}")
111
+ end
112
+
113
+ # The SassScript `/` operation.
114
+ #
115
+ # @param other [Value] The right-hand side of the operator
116
+ # @return [Script::Value::String] A string containing both values
117
+ # separated by `"/"`
118
+ def div(other)
119
+ Sass::Script::Value::String.new("#{to_s}/#{other.to_s}")
120
+ end
121
+
122
+ # The SassScript unary `+` operation (e.g. `+$a`).
123
+ #
124
+ # @param other [Value] The right-hand side of the operator
125
+ # @return [Script::Value::String] A string containing the value
126
+ # preceded by `"+"`
127
+ def unary_plus
128
+ Sass::Script::Value::String.new("+#{to_s}")
129
+ end
130
+
131
+ # The SassScript unary `-` operation (e.g. `-$a`).
132
+ #
133
+ # @param other [Value] The right-hand side of the operator
134
+ # @return [Script::Value::String] A string containing the value
135
+ # preceded by `"-"`
136
+ def unary_minus
137
+ Sass::Script::Value::String.new("-#{to_s}")
138
+ end
139
+
140
+ # The SassScript unary `/` operation (e.g. `/$a`).
141
+ #
142
+ # @param other [Value] The right-hand side of the operator
143
+ # @return [Script::Value::String] A string containing the value
144
+ # preceded by `"/"`
145
+ def unary_div
146
+ Sass::Script::Value::String.new("/#{to_s}")
147
+ end
148
+
149
+ # Returns the hash code of this value. Two objects' hash codes should be
150
+ # equal if the objects are equal.
151
+ #
152
+ # @return [Fixnum] The hash code.
153
+ def hash
154
+ value.hash
155
+ end
156
+
157
+ def eql?(other)
158
+ self == other
159
+ end
160
+
161
+ # @return [String] A readable representation of the value
162
+ def inspect
163
+ value.inspect
164
+ end
165
+
166
+ # @return [Boolean] `true` (the Ruby boolean value)
167
+ def to_bool
168
+ true
169
+ end
170
+
171
+ # Compares this object with another.
172
+ #
173
+ # @param other [Object] The object to compare with
174
+ # @return [Boolean] Whether or not this value is equivalent to `other`
175
+ def ==(other)
176
+ eq(other).to_bool
177
+ end
178
+
179
+ # @return [Fixnum] The integer value of this value
180
+ # @raise [Sass::SyntaxError] if this value isn't an integer
181
+ def to_i
182
+ raise Sass::SyntaxError.new("#{inspect} is not an integer.")
183
+ end
184
+
185
+ # @raise [Sass::SyntaxError] if this value isn't an integer
186
+ def assert_int!; to_i; end
187
+
188
+ # Returns the separator for this value. For non-list-like values or the
189
+ # empty list, this will be `nil`. For lists or maps, it will be `:space` or
190
+ # `:comma`.
191
+ #
192
+ # @return [Symbol]
193
+ def separator; nil; end
194
+
195
+ # Returns the value of this value as a list.
196
+ # Single values are considered the same as single-element lists.
197
+ #
198
+ # @return [Array<Value>] This value as a list
199
+ def to_a
200
+ [self]
201
+ end
202
+
203
+ # Returns the value of this value as a hash. Most values don't have hash
204
+ # representations, but [Map]s and empty [List]s do.
205
+ #
206
+ # @return [Hash<Value, Value>] This value as a hash
207
+ # @raise [Sass::SyntaxError] if this value doesn't have a hash representation
208
+ def to_h
209
+ raise Sass::SyntaxError.new("#{inspect} is not a map.")
210
+ end
211
+
212
+ # Returns the string representation of this value
213
+ # as it would be output to the CSS document.
214
+ #
215
+ # @return [String]
216
+ def to_s(opts = {})
217
+ Sass::Util.abstract(self)
218
+ end
219
+ alias_method :to_sass, :to_s
220
+
221
+ # Returns whether or not this object is null.
222
+ #
223
+ # @return [Boolean] `false`
224
+ def null?
225
+ false
226
+ end
227
+
228
+ protected
229
+
230
+ # Evaluates the value.
231
+ #
232
+ # @param environment [Sass::Environment] The environment in which to evaluate the SassScript
233
+ # @return [Value] This value
234
+ def _perform(environment)
235
+ self
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,40 @@
1
+ module Sass::Script::Value
2
+ # A SassScript object representing a boolean (true or false) value.
3
+ class Bool < Base
4
+ # The true value in SassScript.
5
+ #
6
+ # This is assigned before new is overridden below so that we use the default implementation.
7
+ TRUE = new(true)
8
+
9
+ # The false value in SassScript.
10
+ #
11
+ # This is assigned before new is overridden below so that we use the default implementation.
12
+ FALSE = new(false)
13
+
14
+ # We override object creation so that users of the core API
15
+ # will not need to know that booleans are specific constants.
16
+ #
17
+ # @param value A ruby value that will be tested for truthiness.
18
+ # @return [Bool] TRUE if value is truthy, FALSE if value is falsey
19
+ def self.new(value)
20
+ value ? TRUE : FALSE
21
+ end
22
+
23
+ def eq(other)
24
+ return other.eq(self) if other.is_a?(DeprecatedFalse)
25
+ super
26
+ end
27
+
28
+ # The Ruby value of the boolean.
29
+ #
30
+ # @return [Boolean]
31
+ attr_reader :value
32
+ alias_method :to_bool, :value
33
+
34
+ # @return [String] "true" or "false"
35
+ def to_s(opts = {})
36
+ @value.to_s
37
+ end
38
+ alias_method :to_sass, :to_s
39
+ end
40
+ end