haml 1.8.0 → 2.0.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 (82) hide show
  1. data/FAQ +138 -0
  2. data/MIT-LICENSE +1 -1
  3. data/{README → README.rdoc} +66 -3
  4. data/Rakefile +111 -147
  5. data/VERSION +1 -1
  6. data/bin/css2sass +0 -0
  7. data/bin/haml +0 -0
  8. data/bin/html2haml +0 -0
  9. data/bin/sass +0 -0
  10. data/init.rb +6 -1
  11. data/lib/haml/buffer.rb +121 -63
  12. data/lib/haml/engine.rb +67 -44
  13. data/lib/haml/error.rb +16 -6
  14. data/lib/haml/exec.rb +37 -7
  15. data/lib/haml/filters.rb +213 -68
  16. data/lib/haml/helpers/action_view_extensions.rb +1 -1
  17. data/lib/haml/helpers/action_view_mods.rb +57 -9
  18. data/lib/haml/helpers.rb +105 -61
  19. data/lib/haml/html.rb +6 -6
  20. data/lib/haml/precompiler.rb +268 -132
  21. data/lib/haml/template/patch.rb +9 -2
  22. data/lib/haml/template/plugin.rb +61 -10
  23. data/lib/haml/template.rb +3 -6
  24. data/lib/haml.rb +464 -201
  25. data/lib/sass/constant/color.rb +13 -13
  26. data/lib/sass/constant/literal.rb +7 -7
  27. data/lib/sass/constant/number.rb +9 -9
  28. data/lib/sass/constant/operation.rb +4 -4
  29. data/lib/sass/constant/string.rb +3 -3
  30. data/lib/sass/constant.rb +22 -22
  31. data/lib/sass/css.rb +104 -31
  32. data/lib/sass/engine.rb +120 -39
  33. data/lib/sass/error.rb +1 -1
  34. data/lib/sass/plugin/merb.rb +48 -12
  35. data/lib/sass/plugin/rails.rb +10 -4
  36. data/lib/sass/plugin.rb +22 -3
  37. data/lib/sass/tree/attr_node.rb +5 -5
  38. data/lib/sass/tree/directive_node.rb +2 -7
  39. data/lib/sass/tree/node.rb +1 -12
  40. data/lib/sass/tree/rule_node.rb +39 -31
  41. data/lib/sass/tree/value_node.rb +1 -1
  42. data/lib/sass.rb +157 -12
  43. data/test/benchmark.rb +67 -80
  44. data/test/haml/engine_test.rb +318 -81
  45. data/test/haml/helper_test.rb +52 -16
  46. data/test/haml/results/content_for_layout.xhtml +1 -2
  47. data/test/haml/results/eval_suppressed.xhtml +2 -4
  48. data/test/haml/results/filters.xhtml +44 -15
  49. data/test/haml/results/helpers.xhtml +2 -3
  50. data/test/haml/results/just_stuff.xhtml +2 -6
  51. data/test/haml/results/nuke_inner_whitespace.xhtml +34 -0
  52. data/test/haml/results/nuke_outer_whitespace.xhtml +148 -0
  53. data/test/haml/results/original_engine.xhtml +3 -7
  54. data/test/haml/results/partials.xhtml +1 -0
  55. data/test/haml/results/tag_parsing.xhtml +1 -6
  56. data/test/haml/results/very_basic.xhtml +2 -4
  57. data/test/haml/results/whitespace_handling.xhtml +13 -21
  58. data/test/haml/template_test.rb +8 -15
  59. data/test/haml/templates/_partial.haml +1 -0
  60. data/test/haml/templates/filters.haml +48 -7
  61. data/test/haml/templates/helpers.haml +9 -9
  62. data/test/haml/templates/just_stuff.haml +1 -2
  63. data/test/haml/templates/nuke_inner_whitespace.haml +26 -0
  64. data/test/haml/templates/nuke_outer_whitespace.haml +144 -0
  65. data/test/haml/templates/tag_parsing.haml +0 -3
  66. data/test/haml/test_helper.rb +15 -0
  67. data/test/sass/engine_test.rb +84 -34
  68. data/test/sass/plugin_test.rb +1 -1
  69. data/test/sass/results/import.css +2 -2
  70. data/test/sass/results/mixins.css +95 -0
  71. data/test/sass/results/multiline.css +24 -0
  72. data/test/sass/templates/import.sass +4 -1
  73. data/test/sass/templates/importee.sass +4 -0
  74. data/test/sass/templates/mixins.sass +76 -0
  75. data/test/sass/templates/multiline.sass +20 -0
  76. metadata +65 -53
  77. data/lib/haml/helpers/action_view_mods.rb.rej +0 -30
  78. data/lib/haml/util.rb +0 -18
  79. data/lib/sass/constant.rb.rej +0 -42
  80. data/test/haml/runner.rb +0 -16
  81. data/test/profile.rb +0 -65
  82. data/test/sass/engine_test.rb.rej +0 -18
data/lib/haml/helpers.rb CHANGED
@@ -34,25 +34,44 @@ module Haml
34
34
  # include Haml::Helpers
35
35
  # end
36
36
  # context.init_haml_helpers
37
- # context.open :p, "Stuff"
38
- #
37
+ # context.haml_tag :p, "Stuff"
38
+ #
39
39
  def init_haml_helpers
40
- @haml_is_haml = true
41
- @haml_stack = [Haml::Buffer.new]
40
+ @haml_buffer = Haml::Buffer.new(@haml_buffer, Haml::Engine.new('').send(:options_for_buffer))
42
41
  nil
43
42
  end
44
43
 
45
44
  # call-seq:
46
- # find_and_preserve(input)
45
+ # non_haml { ... }
46
+ #
47
+ # Runs a block of code in a non-Haml context
48
+ # (i.e. #is_haml? will return false).
49
+ #
50
+ # This is mainly useful for rendering sub-templates such as partials in a non-Haml language,
51
+ # particularly where helpers may behave differently when run from Haml.
52
+ #
53
+ # Note that this is automatically applied to Rails partials.
54
+ def non_haml
55
+ was_active = @haml_buffer.active?
56
+ @haml_buffer.active = false
57
+ res = yield
58
+ @haml_buffer.active = was_active
59
+ res
60
+ end
61
+
62
+ # call-seq:
63
+ # find_and_preserve(input, tags = haml_buffer.options[:preserve])
47
64
  # find_and_preserve {...}
48
- #
49
- # Isolates the whitespace-sensitive tags in the string and uses preserve
50
- # to convert any endlines inside them into HTML entities for endlines.
51
- def find_and_preserve(input = '', &block)
65
+ #
66
+ # Uses preserve to convert any newlines inside whitespace-sensitive tags
67
+ # into the HTML entities for endlines.
68
+ # @tags@ is an array of tags to preserve.
69
+ # It defaults to the value of the <tt>:preserve</tt> option.
70
+ def find_and_preserve(input = '', tags = haml_buffer.options[:preserve], &block)
52
71
  return find_and_preserve(capture_haml(&block)) if block
53
72
 
54
73
  input = input.to_s
55
- input.gsub(/<(textarea|code|pre)([^>]*)>(.*?)(<\/\1>)/im) do
74
+ input.gsub(/<(#{tags.map(&Regexp.method(:escape)).join('|')})([^>]*)>(.*?)(<\/\1>)/im) do
56
75
  "<#{$1}#{$2}>#{preserve($3)}</#{$1}>"
57
76
  end
58
77
  end
@@ -67,7 +86,7 @@ module Haml
67
86
  def preserve(input = '', &block)
68
87
  return preserve(capture_haml(&block)) if block
69
88
 
70
- input.gsub(/\n/, '&#x000A;').gsub(/\r/, '')
89
+ input.chomp("\n").gsub(/\n/, '&#x000A;').gsub(/\r/, '')
71
90
  end
72
91
 
73
92
  alias_method :flatten, :preserve
@@ -107,14 +126,14 @@ module Haml
107
126
  def list_of(array, &block) # :yields: item
108
127
  to_return = array.collect do |i|
109
128
  result = capture_haml(i, &block)
110
-
129
+
111
130
  if result.count("\n") > 1
112
131
  result.gsub!("\n", "\n ")
113
132
  result = "\n #{result.strip}\n"
114
133
  else
115
134
  result.strip!
116
135
  end
117
-
136
+
118
137
  "<li>#{result}</li>"
119
138
  end
120
139
  to_return.join("\n")
@@ -153,17 +172,17 @@ module Haml
153
172
  # <strong>baz</strong>
154
173
  #
155
174
  def tab_up(i = 1)
156
- buffer.tabulation += i
175
+ haml_buffer.tabulation += i
157
176
  end
158
177
 
159
- # Increments the number of tabs the buffer automatically adds
178
+ # Decrements the number of tabs the buffer automatically adds
160
179
  # to the lines of the template.
161
180
  #
162
- # See tab_up.
181
+ # See also tab_up.
163
182
  def tab_down(i = 1)
164
- buffer.tabulation -= i
183
+ haml_buffer.tabulation -= i
165
184
  end
166
-
185
+
167
186
  # Surrounds the given block of Haml code with the given characters,
168
187
  # with no whitespace in between.
169
188
  # For example:
@@ -187,10 +206,10 @@ module Haml
187
206
  def surround(front, back = nil, &block)
188
207
  back ||= front
189
208
  output = capture_haml(&block)
190
-
209
+
191
210
  "#{front}#{output.chomp}#{back}\n"
192
211
  end
193
-
212
+
194
213
  # Prepends the given character to the beginning of the Haml block,
195
214
  # with no whitespace between.
196
215
  # For example:
@@ -205,7 +224,7 @@ module Haml
205
224
  def precede(char, &block)
206
225
  "#{char}#{capture_haml(&block).chomp}\n"
207
226
  end
208
-
227
+
209
228
  # Appends the given character to the end of the Haml block,
210
229
  # with no whitespace between.
211
230
  # For example:
@@ -222,7 +241,7 @@ module Haml
222
241
  def succeed(char, &block)
223
242
  "#{capture_haml(&block).chomp}#{char}\n"
224
243
  end
225
-
244
+
226
245
  # Captures the result of the given block of Haml code,
227
246
  # gets rid of the excess indentation,
228
247
  # and returns it as a string.
@@ -235,35 +254,35 @@ module Haml
235
254
  # the local variable <tt>foo</tt> would be assigned to "<p>13</p>\n".
236
255
  #
237
256
  def capture_haml(*args, &block)
238
- capture_haml_with_buffer(buffer.buffer, *args, &block)
257
+ capture_haml_with_buffer(haml_buffer.buffer, *args, &block)
239
258
  end
240
259
 
241
260
  # Outputs text directly to the Haml buffer, with the proper tabulation
242
261
  def puts(text = "")
243
- buffer.buffer << (' ' * buffer.tabulation) << text.to_s << "\n"
262
+ haml_buffer.buffer << (' ' * haml_buffer.tabulation) << text.to_s << "\n"
244
263
  nil
245
264
  end
246
265
 
247
266
  #
248
267
  # call-seq:
249
- # open(name, attributes = {}) {...}
250
- # open(name, text, attributes = {}) {...}
268
+ # haml_tag(name, attributes = {}) {...}
269
+ # haml_tag(name, text, attributes = {}) {...}
251
270
  #
252
271
  # Creates an HTML tag with the given name and optionally text and attributes.
253
272
  # Can take a block that will be executed
254
273
  # between when the opening and closing tags are output.
255
274
  # If the block is a Haml block or outputs text using puts,
256
275
  # the text will be properly indented.
257
- #
276
+ #
258
277
  # For example,
259
278
  #
260
- # open :table do
261
- # open :tr do
262
- # open :td, {:class => 'cell'} do
263
- # open :strong, "strong!"
279
+ # haml_tag :table do
280
+ # haml_tag :tr do
281
+ # haml_tag :td, {:class => 'cell'} do
282
+ # haml_tag :strong, "strong!"
264
283
  # puts "data"
265
284
  # end
266
- # open :td do
285
+ # haml_tag :td do
267
286
  # puts "more_data"
268
287
  # end
269
288
  # end
@@ -285,19 +304,24 @@ module Haml
285
304
  # </tr>
286
305
  # </table>
287
306
  #
288
- def open(name, attributes = {}, alt_atts = {}, &block)
307
+ def haml_tag(name, attributes = {}, alt_atts = {}, &block)
308
+ name = name.to_s
309
+
289
310
  text = nil
290
311
  if attributes.is_a? String
291
312
  text = attributes
292
313
  attributes = alt_atts
293
314
  end
294
315
 
295
- if text.nil? && block.nil?
296
- puts "<#{name}#{Haml::Precompiler.build_attributes(buffer.options[:attr_wrapper], attributes)} />"
316
+ attributes = Haml::Precompiler.build_attributes(
317
+ haml_buffer.html?, haml_buffer.options[:attr_wrapper], attributes)
318
+
319
+ if text.nil? && block.nil? && haml_buffer.options[:autoclose].include?(name)
320
+ puts "<#{name}#{attributes} />"
297
321
  return nil
298
322
  end
299
323
 
300
- puts "<#{name}#{Haml::Precompiler.build_attributes(buffer.options[:attr_wrapper], attributes)}>"
324
+ puts "<#{name}#{attributes}>"
301
325
  unless text && text.empty?
302
326
  tab_up
303
327
  # Print out either the text (using push_text) or call the block and add an endline
@@ -311,61 +335,81 @@ module Haml
311
335
  puts "</#{name}>"
312
336
  nil
313
337
  end
314
-
338
+
339
+ # Characters that need to be escaped to HTML entities from user input
340
+ HTML_ESCAPE = { '&'=>'&amp;', '<'=>'&lt;', '>'=>'&gt;', '"'=>'&quot;', "'"=>'&#039;', }
341
+
342
+ # Returns a copy of <tt>text</tt> with ampersands, angle brackets and quotes
343
+ # escaped into HTML entities.
344
+ def html_escape(text)
345
+ text.to_s.gsub(/[\"><&]/) { |s| HTML_ESCAPE[s] }
346
+ end
347
+
348
+ # Escapes HTML entities in <tt>text</tt>, but without escaping an ampersand
349
+ # that is already part of an escaped entity.
350
+ def escape_once(text)
351
+ text.to_s.gsub(/[\"><]|&(?!([a-zA-Z]+|(#\d+));)/) { |s| HTML_ESCAPE[s] }
352
+ end
353
+
354
+ # Returns whether or not the current template is a Haml template.
355
+ #
356
+ # This function, unlike other Haml::Helpers functions,
357
+ # also works in other ActionView templates,
358
+ # where it will always return false.
359
+ def is_haml?
360
+ !@haml_buffer.nil? && @haml_buffer.active?
361
+ end
362
+
315
363
  private
316
364
 
317
365
  # Gets a reference to the current Haml::Buffer object.
318
- def buffer
319
- @haml_stack[-1]
366
+ def haml_buffer
367
+ @haml_buffer
320
368
  end
321
-
369
+
322
370
  # Gives a proc the same local "_hamlout" and "_erbout" variables
323
371
  # that the current template has.
324
- def bind_proc(&proc)
325
- _hamlout = buffer
372
+ def haml_bind_proc(&proc)
373
+ _hamlout = haml_buffer
326
374
  _erbout = _hamlout.buffer
327
375
  proc { |*args| proc.call(*args) }
328
376
  end
329
-
377
+
330
378
  # Performs the function of capture_haml, assuming <tt>local_buffer</tt>
331
379
  # is where the output of block goes.
332
380
  def capture_haml_with_buffer(local_buffer, *args, &block)
333
381
  position = local_buffer.length
334
-
382
+
335
383
  block.call *args
336
-
384
+
337
385
  captured = local_buffer.slice!(position..-1)
338
-
386
+
339
387
  min_tabs = nil
340
388
  captured.each do |line|
341
389
  tabs = line.index(/[^ ]/)
342
390
  min_tabs ||= tabs
343
391
  min_tabs = min_tabs > tabs ? tabs : min_tabs
344
392
  end
345
-
393
+
346
394
  result = captured.map do |line|
347
395
  line[min_tabs..-1]
348
396
  end
349
397
  result.to_s
350
398
  end
351
399
 
352
- # Returns whether or not the current template is a Haml template.
353
- #
354
- # This function, unlike other Haml::Helpers functions,
355
- # also works in other ActionView templates,
356
- # where it will always return false.
357
- def is_haml?
358
- @haml_is_haml
359
- end
360
-
361
400
  include ActionViewExtensions if self.const_defined? "ActionViewExtensions"
362
401
  end
363
402
  end
364
403
 
365
- module ActionView
366
- class Base # :nodoc:
367
- def is_haml?
368
- false
369
- end
404
+ class Object
405
+ # Haml overrides various ActionView helpers,
406
+ # which call an #is_haml? method
407
+ # to determine whether or not the current context object
408
+ # is a proper Haml context.
409
+ # Because ActionView helpers may be included in non-ActionView::Base classes,
410
+ # it's a good idea to define is_haml? for all objects.
411
+ def is_haml?
412
+ false
370
413
  end
371
414
  end
415
+
data/lib/haml/html.rb CHANGED
@@ -59,7 +59,7 @@ module Haml
59
59
  String.new
60
60
  else
61
61
  lines = text.split("\n")
62
-
62
+
63
63
  lines.map do |line|
64
64
  line.strip!
65
65
  "#{tabulate(tabs)}#{'\\' if Haml::Engine::SPECIAL_CHARACTERS.include?(line[0])}#{line}\n"
@@ -73,7 +73,7 @@ module Haml
73
73
  def self.options
74
74
  @@options
75
75
  end
76
-
76
+
77
77
  TEXT_REGEXP = /^(\s*).*$/
78
78
 
79
79
  class ::Hpricot::Doc
@@ -129,14 +129,14 @@ module Haml
129
129
 
130
130
  class ::Hpricot::Elem
131
131
  def to_haml(tabs = 0)
132
- output = "#{tabulate(tabs)}"
132
+ output = "#{tabulate(tabs)}"
133
133
  if HTML.options[:rhtml] && name[0...5] == 'haml:'
134
134
  return output + HTML.send("haml_tag_#{name[5..-1]}",
135
135
  CGI.unescapeHTML(self.innerHTML))
136
136
  end
137
137
 
138
138
  output += "%#{name}" unless name == 'div' && (attributes.include?('id') || attributes.include?('class'))
139
-
139
+
140
140
  if attributes
141
141
  output += "##{attributes['id']}" if attributes['id']
142
142
  attributes['class'].split(' ').each { |c| output += ".#{c}" } if attributes['class']
@@ -144,10 +144,10 @@ module Haml
144
144
  remove_attribute('class')
145
145
  output += haml_attributes if attributes.length > 0
146
146
  end
147
-
147
+
148
148
  output += "/" if children.length == 0
149
149
  output += "\n"
150
-
150
+
151
151
  self.children.each do |child|
152
152
  output += child.to_haml(tabs + 1)
153
153
  end