haml-edge 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. data/EDGE_GEM_VERSION +1 -0
  2. data/FAQ +138 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +332 -0
  5. data/REVISION +1 -0
  6. data/Rakefile +226 -0
  7. data/VERSION +1 -0
  8. data/bin/css2sass +7 -0
  9. data/bin/haml +9 -0
  10. data/bin/html2haml +7 -0
  11. data/bin/sass +8 -0
  12. data/extra/edge_gem_watch.rb +13 -0
  13. data/extra/haml-mode.el +596 -0
  14. data/extra/sass-mode.el +200 -0
  15. data/init.rb +8 -0
  16. data/lib/haml/buffer.rb +255 -0
  17. data/lib/haml/engine.rb +268 -0
  18. data/lib/haml/error.rb +22 -0
  19. data/lib/haml/exec.rb +395 -0
  20. data/lib/haml/filters.rb +275 -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/helpers.rb +488 -0
  24. data/lib/haml/html.rb +222 -0
  25. data/lib/haml/precompiler.rb +904 -0
  26. data/lib/haml/shared.rb +45 -0
  27. data/lib/haml/template/patch.rb +58 -0
  28. data/lib/haml/template/plugin.rb +72 -0
  29. data/lib/haml/template.rb +42 -0
  30. data/lib/haml/util.rb +88 -0
  31. data/lib/haml/version.rb +47 -0
  32. data/lib/haml.rb +1044 -0
  33. data/lib/sass/css.rb +388 -0
  34. data/lib/sass/engine.rb +495 -0
  35. data/lib/sass/environment.rb +46 -0
  36. data/lib/sass/error.rb +35 -0
  37. data/lib/sass/plugin/merb.rb +56 -0
  38. data/lib/sass/plugin/rails.rb +24 -0
  39. data/lib/sass/plugin.rb +204 -0
  40. data/lib/sass/repl.rb +51 -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 +29 -0
  44. data/lib/sass/script/functions.rb +134 -0
  45. data/lib/sass/script/lexer.rb +148 -0
  46. data/lib/sass/script/literal.rb +82 -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 +9 -0
  51. data/lib/sass/script/unary_operation.rb +21 -0
  52. data/lib/sass/script/variable.rb +20 -0
  53. data/lib/sass/script.rb +38 -0
  54. data/lib/sass/tree/attr_node.rb +64 -0
  55. data/lib/sass/tree/comment_node.rb +30 -0
  56. data/lib/sass/tree/debug_node.rb +22 -0
  57. data/lib/sass/tree/directive_node.rb +50 -0
  58. data/lib/sass/tree/file_node.rb +27 -0
  59. data/lib/sass/tree/for_node.rb +29 -0
  60. data/lib/sass/tree/if_node.rb +27 -0
  61. data/lib/sass/tree/mixin_def_node.rb +18 -0
  62. data/lib/sass/tree/mixin_node.rb +35 -0
  63. data/lib/sass/tree/node.rb +99 -0
  64. data/lib/sass/tree/rule_node.rb +161 -0
  65. data/lib/sass/tree/variable_node.rb +24 -0
  66. data/lib/sass/tree/while_node.rb +21 -0
  67. data/lib/sass.rb +1062 -0
  68. data/rails/init.rb +1 -0
  69. data/test/benchmark.rb +99 -0
  70. data/test/haml/engine_test.rb +795 -0
  71. data/test/haml/helper_test.rb +228 -0
  72. data/test/haml/html2haml_test.rb +108 -0
  73. data/test/haml/markaby/standard.mab +52 -0
  74. data/test/haml/mocks/article.rb +6 -0
  75. data/test/haml/results/content_for_layout.xhtml +15 -0
  76. data/test/haml/results/eval_suppressed.xhtml +9 -0
  77. data/test/haml/results/filters.xhtml +62 -0
  78. data/test/haml/results/helpers.xhtml +93 -0
  79. data/test/haml/results/helpful.xhtml +10 -0
  80. data/test/haml/results/just_stuff.xhtml +68 -0
  81. data/test/haml/results/list.xhtml +12 -0
  82. data/test/haml/results/nuke_inner_whitespace.xhtml +40 -0
  83. data/test/haml/results/nuke_outer_whitespace.xhtml +148 -0
  84. data/test/haml/results/original_engine.xhtml +20 -0
  85. data/test/haml/results/partial_layout.xhtml +5 -0
  86. data/test/haml/results/partials.xhtml +21 -0
  87. data/test/haml/results/render_layout.xhtml +3 -0
  88. data/test/haml/results/silent_script.xhtml +74 -0
  89. data/test/haml/results/standard.xhtml +162 -0
  90. data/test/haml/results/tag_parsing.xhtml +23 -0
  91. data/test/haml/results/very_basic.xhtml +5 -0
  92. data/test/haml/results/whitespace_handling.xhtml +89 -0
  93. data/test/haml/rhtml/_av_partial_1.rhtml +12 -0
  94. data/test/haml/rhtml/_av_partial_2.rhtml +8 -0
  95. data/test/haml/rhtml/action_view.rhtml +62 -0
  96. data/test/haml/rhtml/standard.rhtml +54 -0
  97. data/test/haml/template_test.rb +204 -0
  98. data/test/haml/templates/_av_partial_1.haml +9 -0
  99. data/test/haml/templates/_av_partial_1_ugly.haml +9 -0
  100. data/test/haml/templates/_av_partial_2.haml +5 -0
  101. data/test/haml/templates/_av_partial_2_ugly.haml +5 -0
  102. data/test/haml/templates/_layout.erb +3 -0
  103. data/test/haml/templates/_layout_for_partial.haml +3 -0
  104. data/test/haml/templates/_partial.haml +8 -0
  105. data/test/haml/templates/_text_area.haml +3 -0
  106. data/test/haml/templates/action_view.haml +47 -0
  107. data/test/haml/templates/action_view_ugly.haml +47 -0
  108. data/test/haml/templates/breakage.haml +8 -0
  109. data/test/haml/templates/content_for_layout.haml +10 -0
  110. data/test/haml/templates/eval_suppressed.haml +11 -0
  111. data/test/haml/templates/filters.haml +66 -0
  112. data/test/haml/templates/helpers.haml +95 -0
  113. data/test/haml/templates/helpful.haml +11 -0
  114. data/test/haml/templates/just_stuff.haml +83 -0
  115. data/test/haml/templates/list.haml +12 -0
  116. data/test/haml/templates/nuke_inner_whitespace.haml +32 -0
  117. data/test/haml/templates/nuke_outer_whitespace.haml +144 -0
  118. data/test/haml/templates/original_engine.haml +17 -0
  119. data/test/haml/templates/partial_layout.haml +3 -0
  120. data/test/haml/templates/partialize.haml +1 -0
  121. data/test/haml/templates/partials.haml +12 -0
  122. data/test/haml/templates/render_layout.haml +2 -0
  123. data/test/haml/templates/silent_script.haml +40 -0
  124. data/test/haml/templates/standard.haml +42 -0
  125. data/test/haml/templates/standard_ugly.haml +42 -0
  126. data/test/haml/templates/tag_parsing.haml +21 -0
  127. data/test/haml/templates/very_basic.haml +4 -0
  128. data/test/haml/templates/whitespace_handling.haml +87 -0
  129. data/test/haml/util_test.rb +87 -0
  130. data/test/linked_rails.rb +12 -0
  131. data/test/sass/css2sass_test.rb +193 -0
  132. data/test/sass/engine_test.rb +709 -0
  133. data/test/sass/functions_test.rb +109 -0
  134. data/test/sass/more_results/more1.css +9 -0
  135. data/test/sass/more_results/more1_with_line_comments.css +26 -0
  136. data/test/sass/more_results/more_import.css +29 -0
  137. data/test/sass/more_templates/_more_partial.sass +2 -0
  138. data/test/sass/more_templates/more1.sass +23 -0
  139. data/test/sass/more_templates/more_import.sass +11 -0
  140. data/test/sass/plugin_test.rb +213 -0
  141. data/test/sass/results/alt.css +4 -0
  142. data/test/sass/results/basic.css +9 -0
  143. data/test/sass/results/compact.css +5 -0
  144. data/test/sass/results/complex.css +87 -0
  145. data/test/sass/results/compressed.css +1 -0
  146. data/test/sass/results/expanded.css +19 -0
  147. data/test/sass/results/import.css +29 -0
  148. data/test/sass/results/line_numbers.css +49 -0
  149. data/test/sass/results/mixins.css +95 -0
  150. data/test/sass/results/multiline.css +24 -0
  151. data/test/sass/results/nested.css +22 -0
  152. data/test/sass/results/parent_ref.css +13 -0
  153. data/test/sass/results/script.css +16 -0
  154. data/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
  155. data/test/sass/results/subdir/subdir.css +3 -0
  156. data/test/sass/results/units.css +11 -0
  157. data/test/sass/script_test.rb +250 -0
  158. data/test/sass/templates/_partial.sass +2 -0
  159. data/test/sass/templates/alt.sass +16 -0
  160. data/test/sass/templates/basic.sass +23 -0
  161. data/test/sass/templates/bork.sass +2 -0
  162. data/test/sass/templates/bork2.sass +2 -0
  163. data/test/sass/templates/compact.sass +17 -0
  164. data/test/sass/templates/complex.sass +309 -0
  165. data/test/sass/templates/compressed.sass +15 -0
  166. data/test/sass/templates/expanded.sass +17 -0
  167. data/test/sass/templates/import.sass +11 -0
  168. data/test/sass/templates/importee.sass +19 -0
  169. data/test/sass/templates/line_numbers.sass +13 -0
  170. data/test/sass/templates/mixins.sass +76 -0
  171. data/test/sass/templates/multiline.sass +20 -0
  172. data/test/sass/templates/nested.sass +25 -0
  173. data/test/sass/templates/parent_ref.sass +25 -0
  174. data/test/sass/templates/script.sass +101 -0
  175. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
  176. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
  177. data/test/sass/templates/subdir/subdir.sass +6 -0
  178. data/test/sass/templates/units.sass +11 -0
  179. data/test/test_helper.rb +21 -0
  180. metadata +278 -0
@@ -0,0 +1,82 @@
1
+ module Sass::Script
2
+ class Literal # :nodoc:
3
+ require 'sass/script/string'
4
+ require 'sass/script/number'
5
+ require 'sass/script/color'
6
+ require 'sass/script/bool'
7
+
8
+ attr_reader :value
9
+
10
+ def initialize(value = nil)
11
+ @value = value
12
+ end
13
+
14
+ def perform(environment)
15
+ self
16
+ end
17
+
18
+ def and(other)
19
+ to_bool ? other : self
20
+ end
21
+
22
+ def or(other)
23
+ to_bool ? self : other
24
+ end
25
+
26
+ def eq(other)
27
+ Sass::Script::Bool.new(self.class == other.class && self.value == other.value)
28
+ end
29
+
30
+ def neq(other)
31
+ Sass::Script::Bool.new(!eq(other).to_bool)
32
+ end
33
+
34
+ def unary_not
35
+ Sass::Script::Bool.new(!to_bool)
36
+ end
37
+
38
+ def concat(other)
39
+ Sass::Script::String.new("#{self.to_s} #{other.to_s}")
40
+ end
41
+
42
+ def comma(other)
43
+ Sass::Script::String.new("#{self.to_s}, #{other.to_s}")
44
+ end
45
+
46
+ def plus(other)
47
+ Sass::Script::String.new(self.to_s + other.to_s)
48
+ end
49
+
50
+ def minus(other)
51
+ Sass::Script::String.new("#{self.to_s}-#{other.to_s}")
52
+ end
53
+
54
+ def div(other)
55
+ Sass::Script::String.new("#{self.to_s}/#{other.to_s}")
56
+ end
57
+
58
+ def unary_minus
59
+ Sass::Script::String.new("-#{self.to_s}")
60
+ end
61
+
62
+ def unary_div
63
+ Sass::Script::String.new("/#{self.to_s}")
64
+ end
65
+
66
+ def inspect
67
+ value.inspect
68
+ end
69
+
70
+ def to_bool
71
+ true
72
+ end
73
+
74
+ def ==(other)
75
+ eq(other).to_bool
76
+ end
77
+
78
+ def to_i
79
+ raise Sass::SyntaxError.new("#{self.inspect} is not an integer.")
80
+ end
81
+ end
82
+ end
@@ -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
+ super
24
+ end
25
+ end
26
+
27
+ def minus(other)
28
+ if other.is_a? Number
29
+ operate(other, :-)
30
+ else
31
+ super
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
+ super
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, :gte) unless other.is_a?(Number)
81
+ operate(other, :>=)
82
+ end
83
+
84
+ def lt(other)
85
+ raise NoMethodError.new(nil, :lt) unless other.is_a?(Number)
86
+ operate(other, :<)
87
+ end
88
+
89
+ def lte(other)
90
+ raise NoMethodError.new(nil, :lte) 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 :end_interpolation
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_expr(:string)
116
+ Operation.new(first.value, Operation.new(mid, last, :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.next
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,9 @@
1
+ require 'sass/script/literal'
2
+
3
+ module Sass::Script
4
+ class String < Literal # :nodoc:
5
+ def to_s
6
+ @value
7
+ end
8
+ end
9
+ 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
@@ -0,0 +1,20 @@
1
+ module Sass
2
+ module Script
3
+ class Variable # :nodoc:
4
+ attr_reader :name
5
+
6
+ def initialize(name)
7
+ @name = name
8
+ end
9
+
10
+ def inspect
11
+ "!#{name}"
12
+ end
13
+
14
+ def perform(environment)
15
+ (val = environment.var(name)) && (return val)
16
+ raise SyntaxError.new("Undefined variable: \"!#{name}\".")
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,38 @@
1
+ require 'strscan'
2
+ require 'sass/script/variable'
3
+ require 'sass/script/funcall'
4
+ require 'sass/script/operation'
5
+ require 'sass/script/literal'
6
+ require 'sass/script/parser'
7
+
8
+ module Sass
9
+ # This module contains various SassScript-related functionality.
10
+ module Script
11
+ # :stopdoc:
12
+ # The character that begins a variable.
13
+ VARIABLE_CHAR = ?!
14
+
15
+ # The regular expression used to parse variables
16
+ MATCH = /^!([a-zA-Z_]\w*)\s*((?:\|\|)?=)\s*(.+)/
17
+
18
+ # The regular expression used to validate variables without matching
19
+ VALIDATE = /^![a-zA-Z_]\w*$/
20
+
21
+ def self.resolve(value, line, offset, environment)
22
+ parse(value, line, offset).perform(environment).to_s
23
+ end
24
+
25
+ def self.parse(value, line, offset, filename = nil)
26
+ Parser.parse(value, line, offset, filename)
27
+ rescue Sass::SyntaxError => e
28
+ if e.message == "SassScript error"
29
+ e.instance_eval do
30
+ @message += ": #{value.dump}."
31
+ end
32
+ end
33
+ e.sass_line = line
34
+ raise e
35
+ end
36
+ # :startdoc:
37
+ end
38
+ end
@@ -0,0 +1,64 @@
1
+ module Sass::Tree
2
+ class AttrNode < Node
3
+ attr_accessor :name, :value
4
+
5
+ def initialize(name, value, options)
6
+ @name = name
7
+ @value = value
8
+ super(options)
9
+ end
10
+
11
+ def ==(other)
12
+ self.class == other.class && name == other.name && value == other.value && super
13
+ end
14
+
15
+ def to_s(tabs, parent_name = nil)
16
+ if value[-1] == ?;
17
+ raise Sass::SyntaxError.new("Invalid attribute: #{declaration.dump} (This isn't CSS!).", @line)
18
+ end
19
+ real_name = name
20
+ real_name = "#{parent_name}-#{real_name}" if parent_name
21
+
22
+ if value.empty? && children.empty?
23
+ raise Sass::SyntaxError.new("Invalid attribute: #{declaration.dump}.", @line)
24
+ end
25
+
26
+ join_string = case @style
27
+ when :compact; ' '
28
+ when :compressed; ''
29
+ else "\n"
30
+ end
31
+ spaces = ' ' * (tabs - 1)
32
+ to_return = ''
33
+ if !value.empty?
34
+ to_return << "#{spaces}#{real_name}:#{@style == :compressed ? '' : ' '}#{value};#{join_string}"
35
+ end
36
+
37
+ children.each do |kid|
38
+ to_return << kid.to_s(tabs, real_name) << join_string
39
+ end
40
+
41
+ (@style == :compressed && parent_name) ? to_return : to_return[0...-1]
42
+ end
43
+
44
+ protected
45
+
46
+ def perform!(environment)
47
+ @name = interpolate(@name, environment)
48
+ @value = @value.is_a?(String) ? interpolate(@value, environment) : @value.perform(environment).to_s
49
+ super
50
+ end
51
+
52
+ private
53
+
54
+ def declaration
55
+ ":#{name} #{value}"
56
+ end
57
+
58
+ def invalid_child?(child)
59
+ if !child.is_a?(AttrNode) && !child.is_a?(CommentNode)
60
+ "Illegal nesting: Only attributes may be nested beneath attributes."
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,30 @@
1
+ require 'sass/tree/node'
2
+
3
+ module Sass::Tree
4
+ class CommentNode < Node
5
+ attr_accessor :lines
6
+ attr_accessor :value
7
+
8
+ def initialize(value, options)
9
+ @lines = []
10
+ @value = value[2..-1].strip
11
+ super(options)
12
+ end
13
+
14
+ def ==(other)
15
+ self.class == other.class && value == other.value && lines == other.lines
16
+ end
17
+
18
+ def silent?
19
+ !!@options[:silent]
20
+ end
21
+
22
+ def to_s(tabs = 0, parent_name = nil)
23
+ return if (@style == :compressed || silent?)
24
+
25
+ spaces = ' ' * (tabs - 1)
26
+ spaces + "/* " + ([value] + lines.map {|l| l.text}).
27
+ map{|l| l.sub(%r{ ?\*/ *$},'')}.join(@style == :compact ? ' ' : "\n#{spaces} * ") + " */"
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,22 @@
1
+ module Sass
2
+ module Tree
3
+ class DebugNode < Node
4
+ def initialize(expr, options)
5
+ @expr = expr
6
+ super(options)
7
+ end
8
+
9
+ protected
10
+
11
+ def _perform(environment)
12
+ res = @expr.perform(environment)
13
+ if filename
14
+ STDERR.puts "#{filename}:#{line} DEBUG: #{res}"
15
+ else
16
+ STDERR.puts "Line #{line} DEBUG: #{res}"
17
+ end
18
+ []
19
+ end
20
+ end
21
+ end
22
+ end