merbjedi-haml 2.1.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 (177) hide show
  1. data/FAQ +138 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +332 -0
  4. data/REVISION +1 -0
  5. data/Rakefile +184 -0
  6. data/VERSION +1 -0
  7. data/bin/css2sass +7 -0
  8. data/bin/haml +9 -0
  9. data/bin/html2haml +7 -0
  10. data/bin/sass +8 -0
  11. data/extra/haml-mode.el +434 -0
  12. data/extra/sass-mode.el +98 -0
  13. data/init.rb +8 -0
  14. data/lib/haml.rb +1025 -0
  15. data/lib/haml/buffer.rb +255 -0
  16. data/lib/haml/engine.rb +268 -0
  17. data/lib/haml/error.rb +22 -0
  18. data/lib/haml/exec.rb +395 -0
  19. data/lib/haml/filters.rb +276 -0
  20. data/lib/haml/helpers.rb +465 -0
  21. data/lib/haml/helpers/action_view_extensions.rb +45 -0
  22. data/lib/haml/helpers/action_view_mods.rb +181 -0
  23. data/lib/haml/html.rb +218 -0
  24. data/lib/haml/precompiler.rb +896 -0
  25. data/lib/haml/shared.rb +45 -0
  26. data/lib/haml/template.rb +51 -0
  27. data/lib/haml/template/patch.rb +58 -0
  28. data/lib/haml/template/plugin.rb +72 -0
  29. data/lib/haml/util.rb +77 -0
  30. data/lib/haml/version.rb +47 -0
  31. data/lib/sass.rb +1062 -0
  32. data/lib/sass/css.rb +388 -0
  33. data/lib/sass/engine.rb +501 -0
  34. data/lib/sass/environment.rb +33 -0
  35. data/lib/sass/error.rb +35 -0
  36. data/lib/sass/plugin.rb +203 -0
  37. data/lib/sass/plugin/merb.rb +56 -0
  38. data/lib/sass/plugin/rails.rb +24 -0
  39. data/lib/sass/repl.rb +44 -0
  40. data/lib/sass/script.rb +38 -0
  41. data/lib/sass/script/bool.rb +13 -0
  42. data/lib/sass/script/color.rb +97 -0
  43. data/lib/sass/script/funcall.rb +28 -0
  44. data/lib/sass/script/functions.rb +122 -0
  45. data/lib/sass/script/lexer.rb +144 -0
  46. data/lib/sass/script/literal.rb +60 -0
  47. data/lib/sass/script/number.rb +231 -0
  48. data/lib/sass/script/operation.rb +30 -0
  49. data/lib/sass/script/parser.rb +142 -0
  50. data/lib/sass/script/string.rb +42 -0
  51. data/lib/sass/script/unary_operation.rb +21 -0
  52. data/lib/sass/script/variable.rb +20 -0
  53. data/lib/sass/tree/attr_node.rb +64 -0
  54. data/lib/sass/tree/comment_node.rb +30 -0
  55. data/lib/sass/tree/debug_node.rb +22 -0
  56. data/lib/sass/tree/directive_node.rb +50 -0
  57. data/lib/sass/tree/file_node.rb +27 -0
  58. data/lib/sass/tree/for_node.rb +29 -0
  59. data/lib/sass/tree/if_node.rb +27 -0
  60. data/lib/sass/tree/mixin_def_node.rb +18 -0
  61. data/lib/sass/tree/mixin_node.rb +34 -0
  62. data/lib/sass/tree/node.rb +97 -0
  63. data/lib/sass/tree/rule_node.rb +120 -0
  64. data/lib/sass/tree/variable_node.rb +24 -0
  65. data/lib/sass/tree/while_node.rb +20 -0
  66. data/rails/init.rb +1 -0
  67. data/test/benchmark.rb +99 -0
  68. data/test/haml/engine_test.rb +852 -0
  69. data/test/haml/helper_test.rb +224 -0
  70. data/test/haml/html2haml_test.rb +92 -0
  71. data/test/haml/markaby/standard.mab +52 -0
  72. data/test/haml/mocks/article.rb +6 -0
  73. data/test/haml/results/content_for_layout.xhtml +15 -0
  74. data/test/haml/results/eval_suppressed.xhtml +9 -0
  75. data/test/haml/results/filters.xhtml +62 -0
  76. data/test/haml/results/helpers.xhtml +93 -0
  77. data/test/haml/results/helpful.xhtml +10 -0
  78. data/test/haml/results/just_stuff.xhtml +68 -0
  79. data/test/haml/results/list.xhtml +12 -0
  80. data/test/haml/results/nuke_inner_whitespace.xhtml +40 -0
  81. data/test/haml/results/nuke_outer_whitespace.xhtml +148 -0
  82. data/test/haml/results/original_engine.xhtml +20 -0
  83. data/test/haml/results/partial_layout.xhtml +5 -0
  84. data/test/haml/results/partials.xhtml +21 -0
  85. data/test/haml/results/render_layout.xhtml +3 -0
  86. data/test/haml/results/silent_script.xhtml +74 -0
  87. data/test/haml/results/standard.xhtml +42 -0
  88. data/test/haml/results/tag_parsing.xhtml +23 -0
  89. data/test/haml/results/very_basic.xhtml +5 -0
  90. data/test/haml/results/whitespace_handling.xhtml +89 -0
  91. data/test/haml/rhtml/_av_partial_1.rhtml +12 -0
  92. data/test/haml/rhtml/_av_partial_2.rhtml +8 -0
  93. data/test/haml/rhtml/action_view.rhtml +62 -0
  94. data/test/haml/rhtml/standard.rhtml +54 -0
  95. data/test/haml/template_test.rb +204 -0
  96. data/test/haml/templates/_av_partial_1.haml +9 -0
  97. data/test/haml/templates/_av_partial_1_ugly.haml +9 -0
  98. data/test/haml/templates/_av_partial_2.haml +5 -0
  99. data/test/haml/templates/_av_partial_2_ugly.haml +5 -0
  100. data/test/haml/templates/_layout.erb +3 -0
  101. data/test/haml/templates/_layout_for_partial.haml +3 -0
  102. data/test/haml/templates/_partial.haml +8 -0
  103. data/test/haml/templates/_text_area.haml +3 -0
  104. data/test/haml/templates/action_view.haml +47 -0
  105. data/test/haml/templates/action_view_ugly.haml +47 -0
  106. data/test/haml/templates/breakage.haml +8 -0
  107. data/test/haml/templates/content_for_layout.haml +10 -0
  108. data/test/haml/templates/eval_suppressed.haml +11 -0
  109. data/test/haml/templates/filters.haml +66 -0
  110. data/test/haml/templates/helpers.haml +95 -0
  111. data/test/haml/templates/helpful.haml +11 -0
  112. data/test/haml/templates/just_stuff.haml +83 -0
  113. data/test/haml/templates/list.haml +12 -0
  114. data/test/haml/templates/nuke_inner_whitespace.haml +32 -0
  115. data/test/haml/templates/nuke_outer_whitespace.haml +144 -0
  116. data/test/haml/templates/original_engine.haml +17 -0
  117. data/test/haml/templates/partial_layout.haml +3 -0
  118. data/test/haml/templates/partialize.haml +1 -0
  119. data/test/haml/templates/partials.haml +12 -0
  120. data/test/haml/templates/render_layout.haml +2 -0
  121. data/test/haml/templates/silent_script.haml +40 -0
  122. data/test/haml/templates/standard.haml +42 -0
  123. data/test/haml/templates/standard_ugly.haml +42 -0
  124. data/test/haml/templates/tag_parsing.haml +21 -0
  125. data/test/haml/templates/very_basic.haml +4 -0
  126. data/test/haml/templates/whitespace_handling.haml +87 -0
  127. data/test/linked_rails.rb +12 -0
  128. data/test/sass/css2sass_test.rb +193 -0
  129. data/test/sass/engine_test.rb +752 -0
  130. data/test/sass/functions_test.rb +96 -0
  131. data/test/sass/more_results/more1.css +9 -0
  132. data/test/sass/more_results/more1_with_line_comments.css +26 -0
  133. data/test/sass/more_results/more_import.css +29 -0
  134. data/test/sass/more_templates/_more_partial.sass +2 -0
  135. data/test/sass/more_templates/more1.sass +23 -0
  136. data/test/sass/more_templates/more_import.sass +11 -0
  137. data/test/sass/plugin_test.rb +208 -0
  138. data/test/sass/results/alt.css +4 -0
  139. data/test/sass/results/basic.css +9 -0
  140. data/test/sass/results/compact.css +5 -0
  141. data/test/sass/results/complex.css +87 -0
  142. data/test/sass/results/compressed.css +1 -0
  143. data/test/sass/results/expanded.css +19 -0
  144. data/test/sass/results/import.css +29 -0
  145. data/test/sass/results/line_numbers.css +49 -0
  146. data/test/sass/results/mixins.css +95 -0
  147. data/test/sass/results/multiline.css +24 -0
  148. data/test/sass/results/nested.css +22 -0
  149. data/test/sass/results/parent_ref.css +13 -0
  150. data/test/sass/results/script.css +16 -0
  151. data/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
  152. data/test/sass/results/subdir/subdir.css +3 -0
  153. data/test/sass/results/units.css +11 -0
  154. data/test/sass/script_test.rb +152 -0
  155. data/test/sass/templates/_partial.sass +2 -0
  156. data/test/sass/templates/alt.sass +16 -0
  157. data/test/sass/templates/basic.sass +23 -0
  158. data/test/sass/templates/bork.sass +2 -0
  159. data/test/sass/templates/bork2.sass +2 -0
  160. data/test/sass/templates/compact.sass +17 -0
  161. data/test/sass/templates/complex.sass +309 -0
  162. data/test/sass/templates/compressed.sass +15 -0
  163. data/test/sass/templates/expanded.sass +17 -0
  164. data/test/sass/templates/import.sass +11 -0
  165. data/test/sass/templates/importee.sass +19 -0
  166. data/test/sass/templates/line_numbers.sass +13 -0
  167. data/test/sass/templates/mixins.sass +76 -0
  168. data/test/sass/templates/multiline.sass +20 -0
  169. data/test/sass/templates/nested.sass +25 -0
  170. data/test/sass/templates/parent_ref.sass +25 -0
  171. data/test/sass/templates/script.sass +101 -0
  172. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
  173. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
  174. data/test/sass/templates/subdir/subdir.sass +6 -0
  175. data/test/sass/templates/units.sass +11 -0
  176. data/test/test_helper.rb +21 -0
  177. metadata +273 -0
@@ -0,0 +1,231 @@
1
+ require 'sass/script/literal'
2
+
3
+ module Sass::Script
4
+ class Number < Literal # :nodoc:
5
+
6
+ attr_reader :numerator_units, :denominator_units
7
+
8
+ PRECISION = 1000.0
9
+
10
+ def initialize(value, numerator_units = [], denominator_units = [])
11
+ super(value)
12
+ @numerator_units = numerator_units
13
+ @denominator_units = denominator_units
14
+ normalize!
15
+ end
16
+
17
+ def plus(other)
18
+ if other.is_a? Number
19
+ operate(other, :+)
20
+ elsif other.is_a?(Color)
21
+ other.plus(self)
22
+ else
23
+ Sass::Script::String.new(self.to_s + other.to_s)
24
+ end
25
+ end
26
+
27
+ def minus(other)
28
+ if other.is_a? Number
29
+ operate(other, :-)
30
+ else
31
+ raise NoMethodError.new(nil, :minus)
32
+ end
33
+ end
34
+
35
+ def unary_minus
36
+ Number.new(-value, numerator_units, denominator_units)
37
+ end
38
+
39
+ def times(other)
40
+ if other.is_a? Number
41
+ self.operate(other, :*)
42
+ elsif other.is_a? Color
43
+ other.times(self)
44
+ else
45
+ raise NoMethodError.new(nil, :times)
46
+ end
47
+ end
48
+
49
+ def div(other)
50
+ if other.is_a? Number
51
+ operate(other, :/)
52
+ else
53
+ raise NoMethodError.new(nil, :div)
54
+ end
55
+ end
56
+
57
+ def mod(other)
58
+ if other.is_a?(Number)
59
+ unless other.unitless?
60
+ raise Sass::SyntaxError.new("Cannot modulo by a number with units: #{other.inspect}.")
61
+ end
62
+ operate(other, :%)
63
+ else
64
+ raise NoMethodError.new(nil, :mod)
65
+ end
66
+ end
67
+
68
+ def eq(other)
69
+ Sass::Script::Bool.new(super.to_bool &&
70
+ self.numerator_units.sort == other.numerator_units.sort &&
71
+ self.denominator_units.sort == other.denominator_units.sort)
72
+ end
73
+
74
+ def gt(other)
75
+ raise NoMethodError.new(nil, :gt) unless other.is_a?(Number)
76
+ operate(other, :>)
77
+ end
78
+
79
+ def gte(other)
80
+ raise NoMethodError.new(nil, :gt) unless other.is_a?(Number)
81
+ operate(other, :>=)
82
+ end
83
+
84
+ def lt(other)
85
+ raise NoMethodError.new(nil, :gt) unless other.is_a?(Number)
86
+ operate(other, :<)
87
+ end
88
+
89
+ def lte(other)
90
+ raise NoMethodError.new(nil, :gt) unless other.is_a?(Number)
91
+ operate(other, :<=)
92
+ end
93
+
94
+ def to_s
95
+ raise Sass::SyntaxError.new("#{inspect} isn't a valid CSS value.") unless legal_units?
96
+ inspect
97
+ end
98
+
99
+ def inspect
100
+ value =
101
+ if self.value.is_a?(Float) && (self.value.infinite? || self.value.nan?)
102
+ self.value
103
+ elsif int?
104
+ self.value.to_i
105
+ else
106
+ (self.value * PRECISION).round / PRECISION
107
+ end
108
+ "#{value}#{unit_str}"
109
+ end
110
+
111
+ def to_i
112
+ super unless int?
113
+ return value
114
+ end
115
+
116
+ def int?
117
+ value % 1 == 0.0
118
+ end
119
+
120
+ def unitless?
121
+ numerator_units.empty? && denominator_units.empty?
122
+ end
123
+
124
+ def legal_units?
125
+ (numerator_units.empty? || numerator_units.size == 1) && denominator_units.empty?
126
+ end
127
+
128
+ protected
129
+
130
+ def operate(other, operation)
131
+ this = self
132
+ if [:+, :-].include?(operation)
133
+ if unitless?
134
+ this = this.coerce(other.numerator_units, other.denominator_units)
135
+ else
136
+ other = other.coerce(numerator_units, denominator_units)
137
+ end
138
+ end
139
+ # avoid integer division
140
+ value = (:/ == operation) ? this.value.to_f : this.value
141
+ result = value.send(operation, other.value)
142
+
143
+ if result.is_a?(Numeric)
144
+ Number.new(result, *compute_units(this, other, operation))
145
+ else # Boolean op
146
+ Bool.new(result)
147
+ end
148
+ end
149
+
150
+ def coerce(num_units, den_units)
151
+ Number.new(if unitless?
152
+ self.value
153
+ else
154
+ self.value * coercion_factor(self.numerator_units, num_units) /
155
+ coercion_factor(self.denominator_units, den_units)
156
+ end, num_units, den_units)
157
+ end
158
+
159
+ def coercion_factor(from_units, to_units)
160
+ # get a list of unmatched units
161
+ from_units, to_units = sans_common_units(from_units, to_units)
162
+
163
+ if from_units.size != to_units.size || !convertable?(from_units | to_units)
164
+ raise Sass::SyntaxError.new("Incompatible units: '#{from_units.join('*')}' and '#{to_units.join('*')}'.")
165
+ end
166
+
167
+ from_units.zip(to_units).inject(1) {|m,p| m * conversion_factor(p[0], p[1]) }
168
+ end
169
+
170
+ def compute_units(this, other, operation)
171
+ case operation
172
+ when :*
173
+ [this.numerator_units + other.numerator_units, this.denominator_units + other.denominator_units]
174
+ when :/
175
+ [this.numerator_units + other.denominator_units, this.denominator_units + other.numerator_units]
176
+ else
177
+ [this.numerator_units, this.denominator_units]
178
+ end
179
+ end
180
+
181
+ def unit_str
182
+ rv = numerator_units.join("*")
183
+ if denominator_units.any?
184
+ rv << "/"
185
+ rv << denominator_units.join("*")
186
+ end
187
+ rv
188
+ end
189
+
190
+ def normalize!
191
+ return if unitless?
192
+ @numerator_units, @denominator_units = sans_common_units(numerator_units, denominator_units)
193
+
194
+ @denominator_units.each_with_index do |d, i|
195
+ if convertable?(d) && (u = @numerator_units.detect(&method(:convertable?)))
196
+ @value /= conversion_factor(d, u)
197
+ @denominator_units.delete_at(i)
198
+ @numerator_units.delete_at(@numerator_units.index(u))
199
+ end
200
+ end
201
+ end
202
+
203
+ # A hash of unit names to their index in the conversion table
204
+ CONVERTABLE_UNITS = {"in" => 0, "cm" => 1, "pc" => 2, "mm" => 3, "pt" => 4}
205
+ CONVERSION_TABLE = [[ 1, 2.54, 6, 25.4, 72 ], # in
206
+ [ nil, 1, 2.36220473, 10, 28.3464567], # cm
207
+ [ nil, nil, 1, 4.23333333, 12 ], # pc
208
+ [ nil, nil, nil, 1, 2.83464567], # mm
209
+ [ nil, nil, nil, nil, 1 ]] # pt
210
+
211
+ def conversion_factor(from_unit, to_unit)
212
+ res = CONVERSION_TABLE[CONVERTABLE_UNITS[from_unit]][CONVERTABLE_UNITS[to_unit]]
213
+ return 1.0 / conversion_factor(to_unit, from_unit) if res.nil?
214
+ res
215
+ end
216
+
217
+ def convertable?(units)
218
+ Array(units).all?(&CONVERTABLE_UNITS.method(:include?))
219
+ end
220
+
221
+ def sans_common_units(units1, units2)
222
+ units2 = units2.dup
223
+ # Can't just use -, because we want px*px to coerce properly to px*mm
224
+ return units1.map do |u|
225
+ next u unless j = units2.index(u)
226
+ units2.delete_at(j)
227
+ nil
228
+ end.compact, units2
229
+ end
230
+ end
231
+ end
@@ -0,0 +1,30 @@
1
+ require 'sass/script/string'
2
+ require 'sass/script/number'
3
+ require 'sass/script/color'
4
+ require 'sass/script/functions'
5
+ require 'sass/script/unary_operation'
6
+
7
+ module Sass::Script
8
+ class Operation # :nodoc:
9
+ def initialize(operand1, operand2, operator)
10
+ @operand1 = operand1
11
+ @operand2 = operand2
12
+ @operator = operator
13
+ end
14
+
15
+ def inspect
16
+ "(#{@operator.inspect} #{@operand1.inspect} #{@operand2.inspect})"
17
+ end
18
+
19
+ def perform(environment)
20
+ literal1 = @operand1.perform(environment)
21
+ literal2 = @operand2.perform(environment)
22
+ begin
23
+ literal1.send(@operator, literal2)
24
+ rescue NoMethodError => e
25
+ raise e unless e.name.to_s == @operator.to_s
26
+ raise Sass::SyntaxError.new("Undefined operation: \"#{literal1} #{@operator} #{literal2}\".")
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,142 @@
1
+ require 'sass/script/lexer'
2
+
3
+ module Sass
4
+ module Script
5
+ class Parser
6
+ def initialize(str, line, offset, filename = nil)
7
+ @filename = filename
8
+ @lexer = Lexer.new(str, line, offset)
9
+ end
10
+
11
+ def parse_interpolated
12
+ expr = assert_expr :expr
13
+ assert_tok :right_bracket
14
+ expr
15
+ end
16
+
17
+ def parse
18
+ expr = assert_expr :expr
19
+ raise Sass::SyntaxError.new("Unexpected #{@lexer.peek.type} token.") unless @lexer.done?
20
+ expr
21
+ end
22
+
23
+ def self.parse(*args)
24
+ new(*args).parse
25
+ end
26
+
27
+ private
28
+
29
+ # Defines a simple left-associative production.
30
+ # name is the name of the production,
31
+ # sub is the name of the production beneath it,
32
+ # and ops is a list of operators for this precedence level
33
+ def self.production(name, sub, *ops)
34
+ class_eval <<RUBY
35
+ def #{name}
36
+ return unless e = #{sub}
37
+ while tok = try_tok(#{ops.map {|o| o.inspect}.join(', ')})
38
+ e = Operation.new(e, assert_expr(#{sub.inspect}), tok.type)
39
+ end
40
+ e
41
+ end
42
+ RUBY
43
+ end
44
+
45
+ def self.unary(op, sub)
46
+ class_eval <<RUBY
47
+ def unary_#{op}
48
+ return #{sub} unless try_tok(:#{op})
49
+ UnaryOperation.new(assert_expr(:unary_#{op}), :#{op})
50
+ end
51
+ RUBY
52
+ end
53
+
54
+ production :expr, :concat, :comma
55
+
56
+ def concat
57
+ return unless e = or_expr
58
+ while sub = or_expr
59
+ e = Operation.new(e, sub, :concat)
60
+ end
61
+ e
62
+ end
63
+
64
+ production :or_expr, :and_expr, :or
65
+ production :and_expr, :eq_or_neq, :and
66
+ production :eq_or_neq, :relational, :eq, :neq
67
+ production :relational, :plus_or_minus, :gt, :gte, :lt, :lte
68
+ production :plus_or_minus, :times_div_or_mod, :plus, :minus
69
+ production :times_div_or_mod, :unary_minus, :times, :div, :mod
70
+
71
+ unary :minus, :unary_div
72
+ unary :div, :unary_not # For strings, so /foo/bar works
73
+ unary :not, :funcall
74
+
75
+ def funcall
76
+ return paren unless name = try_tok(:ident)
77
+ # An identifier without arguments is just a string
78
+ unless try_tok(:lparen)
79
+ warn(<<END)
80
+ DEPRECATION WARNING:
81
+ On line #{name.line}, character #{name.offset}#{" of '#{@filename}'" if @filename}
82
+ Implicit strings have been deprecated and will be removed in version 2.4.
83
+ '#{name.value}' was not quoted. Please add double quotes (e.g. "#{name.value}").
84
+ END
85
+ Script::String.new(name.value)
86
+ else
87
+ args = arglist || []
88
+ assert_tok(:rparen)
89
+ Script::Funcall.new(name.value, args)
90
+ end
91
+ end
92
+
93
+ def arglist
94
+ return unless e = concat
95
+ return [e] unless try_tok(:comma)
96
+ [e, *arglist]
97
+ end
98
+
99
+ def paren
100
+ return variable unless try_tok(:lparen)
101
+ e = assert_expr(:expr)
102
+ assert_tok(:rparen)
103
+ return e
104
+ end
105
+
106
+ def variable
107
+ return string unless c = try_tok(:const)
108
+ Variable.new(c.value)
109
+ end
110
+
111
+ def string
112
+ return literal unless first = try_tok(:string)
113
+ return first.value unless try_tok(:begin_interpolation)
114
+ mid = parse_interpolated
115
+ last = assert_tok(:string)
116
+ Operation.new(first.value, Operation.new(mid, last.value, :plus), :plus)
117
+ end
118
+
119
+ def literal
120
+ (t = try_tok(:number, :color, :bool)) && (return t.value)
121
+ end
122
+
123
+ # It would be possible to have unified #assert and #try methods,
124
+ # but detecting the method/token difference turns out to be quite expensive.
125
+
126
+ def assert_expr(name)
127
+ (e = send(name)) && (return e)
128
+ raise Sass::SyntaxError.new("Expected expression, was #{@lexer.done? ? 'end of text' : "#{@lexer.peek.type} token"}.")
129
+ end
130
+
131
+ def assert_tok(*names)
132
+ (t = try_tok(*names)) && (return t)
133
+ raise Sass::SyntaxError.new("Expected #{names.join(' or ')} token, was #{@lexer.done? ? 'end of text' : "#{@lexer.peek.type} token"}.")
134
+ end
135
+
136
+ def try_tok(*names)
137
+ peeked = @lexer.peek
138
+ peeked && names.include?(peeked.type) && @lexer.token
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,42 @@
1
+ require 'sass/script/literal'
2
+
3
+ module Sass::Script
4
+ class String < Literal # :nodoc:
5
+ INTERPOLATION = /(^|[^\\])\#\{([^}]*)\}/
6
+ #TODO pass line & char context to perform
7
+ def perform(environment)
8
+ interpolated = @value.gsub(INTERPOLATION) do |match|
9
+ "#{$1}#{Sass::Script.resolve($2, 0, 0, environment)}"
10
+ end
11
+ Sass::Script::String.new(interpolated)
12
+ end
13
+
14
+ def plus(other)
15
+ Sass::Script::String.new(self.to_s + other.to_s)
16
+ end
17
+
18
+ def minus(other)
19
+ Sass::Script::String.new("#{self.to_s}-#{other.to_s}")
20
+ end
21
+
22
+ def unary_minus
23
+ Sass::Script::String.new("-#{self.to_s}")
24
+ end
25
+
26
+ def div(other)
27
+ Sass::Script::String.new("#{self.to_s}/#{other.to_s}")
28
+ end
29
+
30
+ def unary_div
31
+ Sass::Script::String.new("/#{self.to_s}")
32
+ end
33
+
34
+ def funcall(other)
35
+ Sass::Script::String.new("#{self.to_s}(#{other.to_s})")
36
+ end
37
+
38
+ def to_s
39
+ @value
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,21 @@
1
+ module Sass::Script
2
+ class UnaryOperation # :nodoc:
3
+ def initialize(operand, operator)
4
+ @operand = operand
5
+ @operator = operator
6
+ end
7
+
8
+ def inspect
9
+ "(#{@operator.inspect} #{@operand.inspect})"
10
+ end
11
+
12
+ def perform(environment)
13
+ operator = "unary_#{@operator}"
14
+ literal = @operand.perform(environment)
15
+ literal.send(operator)
16
+ rescue NoMethodError => e
17
+ raise e unless e.name.to_s == operator.to_s
18
+ raise Sass::SyntaxError.new("Undefined unary operation: \"#{@operator} #{literal}\".")
19
+ end
20
+ end
21
+ end