haml 2.2.24 → 3.0.0.beta.1

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

Potentially problematic release.


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

Files changed (168) hide show
  1. data/.yardopts +0 -1
  2. data/README.md +91 -151
  3. data/REMEMBER +11 -1
  4. data/Rakefile +73 -55
  5. data/VERSION +1 -1
  6. data/VERSION_NAME +1 -1
  7. data/bin/css2sass +7 -1
  8. data/bin/sass-convert +7 -0
  9. data/extra/haml-mode.el +2 -1
  10. data/lib/haml/buffer.rb +22 -4
  11. data/lib/haml/engine.rb +5 -1
  12. data/lib/haml/exec.rb +231 -46
  13. data/lib/haml/filters.rb +19 -8
  14. data/lib/haml/helpers.rb +47 -20
  15. data/lib/haml/helpers/action_view_extensions.rb +2 -4
  16. data/lib/haml/helpers/action_view_mods.rb +11 -8
  17. data/lib/haml/helpers/xss_mods.rb +13 -2
  18. data/lib/haml/html.rb +179 -48
  19. data/lib/haml/html/erb.rb +141 -0
  20. data/lib/haml/precompiler.rb +40 -15
  21. data/lib/haml/railtie.rb +1 -5
  22. data/lib/haml/root.rb +3 -0
  23. data/lib/haml/template.rb +4 -14
  24. data/lib/haml/util.rb +120 -30
  25. data/lib/haml/version.rb +25 -2
  26. data/lib/sass.rb +5 -1
  27. data/lib/sass/callbacks.rb +50 -0
  28. data/lib/sass/css.rb +40 -191
  29. data/lib/sass/engine.rb +170 -74
  30. data/lib/sass/environment.rb +8 -2
  31. data/lib/sass/error.rb +163 -25
  32. data/lib/sass/files.rb +31 -28
  33. data/lib/sass/plugin.rb +268 -87
  34. data/lib/sass/plugin/rails.rb +9 -4
  35. data/lib/sass/repl.rb +1 -1
  36. data/lib/sass/script.rb +31 -29
  37. data/lib/sass/script/bool.rb +1 -0
  38. data/lib/sass/script/color.rb +290 -23
  39. data/lib/sass/script/css_lexer.rb +22 -0
  40. data/lib/sass/script/css_parser.rb +28 -0
  41. data/lib/sass/script/funcall.rb +22 -3
  42. data/lib/sass/script/functions.rb +523 -33
  43. data/lib/sass/script/interpolation.rb +42 -0
  44. data/lib/sass/script/lexer.rb +169 -52
  45. data/lib/sass/script/literal.rb +58 -9
  46. data/lib/sass/script/node.rb +79 -1
  47. data/lib/sass/script/number.rb +20 -5
  48. data/lib/sass/script/operation.rb +49 -3
  49. data/lib/sass/script/parser.rb +162 -28
  50. data/lib/sass/script/string.rb +50 -2
  51. data/lib/sass/script/unary_operation.rb +25 -2
  52. data/lib/sass/script/variable.rb +21 -4
  53. data/lib/sass/scss.rb +14 -0
  54. data/lib/sass/scss/css_parser.rb +39 -0
  55. data/lib/sass/scss/parser.rb +683 -0
  56. data/lib/sass/scss/rx.rb +112 -0
  57. data/lib/sass/scss/script_lexer.rb +13 -0
  58. data/lib/sass/scss/script_parser.rb +25 -0
  59. data/lib/sass/tree/comment_node.rb +69 -27
  60. data/lib/sass/tree/debug_node.rb +7 -2
  61. data/lib/sass/tree/directive_node.rb +41 -35
  62. data/lib/sass/tree/for_node.rb +6 -0
  63. data/lib/sass/tree/if_node.rb +13 -1
  64. data/lib/sass/tree/import_node.rb +52 -27
  65. data/lib/sass/tree/mixin_def_node.rb +18 -0
  66. data/lib/sass/tree/mixin_node.rb +41 -6
  67. data/lib/sass/tree/node.rb +197 -70
  68. data/lib/sass/tree/prop_node.rb +152 -57
  69. data/lib/sass/tree/root_node.rb +118 -0
  70. data/lib/sass/tree/rule_node.rb +193 -96
  71. data/lib/sass/tree/variable_node.rb +9 -5
  72. data/lib/sass/tree/while_node.rb +4 -0
  73. data/test/benchmark.rb +5 -5
  74. data/test/haml/engine_test.rb +147 -10
  75. data/test/haml/{rhtml/_av_partial_1.rhtml → erb/_av_partial_1.erb} +1 -1
  76. data/test/haml/{rhtml/_av_partial_2.rhtml → erb/_av_partial_2.erb} +1 -1
  77. data/test/haml/{rhtml/action_view.rhtml → erb/action_view.erb} +1 -1
  78. data/test/haml/{rhtml/standard.rhtml → erb/standard.erb} +0 -0
  79. data/test/haml/helper_test.rb +91 -24
  80. data/test/haml/html2haml/erb_tests.rb +410 -0
  81. data/test/haml/html2haml_test.rb +210 -66
  82. data/test/haml/results/filters.xhtml +1 -1
  83. data/test/haml/results/just_stuff.xhtml +2 -0
  84. data/test/haml/spec_test.rb +44 -0
  85. data/test/haml/template_test.rb +22 -2
  86. data/test/haml/templates/helpers.haml +0 -13
  87. data/test/haml/templates/just_stuff.haml +2 -0
  88. data/test/haml/util_test.rb +48 -0
  89. data/test/sass/callbacks_test.rb +61 -0
  90. data/test/sass/conversion_test.rb +884 -0
  91. data/test/sass/css2sass_test.rb +99 -18
  92. data/test/sass/data/hsl-rgb.txt +319 -0
  93. data/test/sass/engine_test.rb +1049 -131
  94. data/test/sass/functions_test.rb +398 -47
  95. data/test/sass/more_results/more_import.css +1 -1
  96. data/test/sass/more_templates/more_import.sass +3 -3
  97. data/test/sass/plugin_test.rb +184 -10
  98. data/test/sass/results/compact.css +1 -1
  99. data/test/sass/results/complex.css +5 -5
  100. data/test/sass/results/compressed.css +1 -1
  101. data/test/sass/results/expanded.css +1 -1
  102. data/test/sass/results/import.css +3 -1
  103. data/test/sass/results/mixins.css +12 -12
  104. data/test/sass/results/nested.css +1 -1
  105. data/test/sass/results/options.css +1 -0
  106. data/test/sass/results/parent_ref.css +4 -4
  107. data/test/sass/results/script.css +3 -3
  108. data/test/sass/results/scss_import.css +15 -0
  109. data/test/sass/results/scss_importee.css +2 -0
  110. data/test/sass/script_conversion_test.rb +153 -0
  111. data/test/sass/script_test.rb +137 -70
  112. data/test/sass/scss/css_test.rb +811 -0
  113. data/test/sass/scss/rx_test.rb +156 -0
  114. data/test/sass/scss/scss_test.rb +871 -0
  115. data/test/sass/scss/test_helper.rb +37 -0
  116. data/test/sass/templates/alt.sass +2 -2
  117. data/test/sass/templates/bork1.sass +2 -0
  118. data/test/sass/templates/bork3.sass +2 -0
  119. data/test/sass/templates/bork4.sass +2 -0
  120. data/test/sass/templates/import.sass +4 -4
  121. data/test/sass/templates/importee.sass +3 -3
  122. data/test/sass/templates/line_numbers.sass +1 -1
  123. data/test/sass/templates/mixin_bork.sass +5 -0
  124. data/test/sass/templates/mixins.sass +2 -2
  125. data/test/sass/templates/nested_bork1.sass +2 -0
  126. data/test/sass/templates/nested_bork2.sass +2 -0
  127. data/test/sass/templates/nested_bork3.sass +2 -0
  128. data/test/sass/templates/nested_bork4.sass +2 -0
  129. data/test/sass/templates/nested_mixin_bork.sass +6 -0
  130. data/test/sass/templates/options.sass +2 -0
  131. data/test/sass/templates/parent_ref.sass +2 -2
  132. data/test/sass/templates/script.sass +69 -69
  133. data/test/sass/templates/scss_import.scss +10 -0
  134. data/test/sass/templates/scss_importee.scss +1 -0
  135. data/test/sass/templates/units.sass +10 -10
  136. data/test/test_helper.rb +20 -8
  137. data/vendor/fssm/LICENSE +20 -0
  138. data/vendor/fssm/README.markdown +55 -0
  139. data/vendor/fssm/Rakefile +59 -0
  140. data/vendor/fssm/VERSION.yml +5 -0
  141. data/vendor/fssm/example.rb +9 -0
  142. data/vendor/fssm/fssm.gemspec +77 -0
  143. data/vendor/fssm/lib/fssm.rb +33 -0
  144. data/vendor/fssm/lib/fssm/backends/fsevents.rb +36 -0
  145. data/vendor/fssm/lib/fssm/backends/inotify.rb +26 -0
  146. data/vendor/fssm/lib/fssm/backends/polling.rb +25 -0
  147. data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +131 -0
  148. data/vendor/fssm/lib/fssm/monitor.rb +26 -0
  149. data/vendor/fssm/lib/fssm/path.rb +91 -0
  150. data/vendor/fssm/lib/fssm/pathname.rb +502 -0
  151. data/vendor/fssm/lib/fssm/state/directory.rb +57 -0
  152. data/vendor/fssm/lib/fssm/state/file.rb +24 -0
  153. data/vendor/fssm/lib/fssm/support.rb +63 -0
  154. data/vendor/fssm/lib/fssm/tree.rb +176 -0
  155. data/vendor/fssm/profile/prof-cache.rb +40 -0
  156. data/vendor/fssm/profile/prof-fssm-pathname.html +1231 -0
  157. data/vendor/fssm/profile/prof-pathname.rb +68 -0
  158. data/vendor/fssm/profile/prof-plain-pathname.html +988 -0
  159. data/vendor/fssm/profile/prof.html +2379 -0
  160. data/vendor/fssm/spec/path_spec.rb +75 -0
  161. data/vendor/fssm/spec/root/duck/quack.txt +0 -0
  162. data/vendor/fssm/spec/root/file.css +0 -0
  163. data/vendor/fssm/spec/root/file.rb +0 -0
  164. data/vendor/fssm/spec/root/file.yml +0 -0
  165. data/vendor/fssm/spec/root/moo/cow.txt +0 -0
  166. data/vendor/fssm/spec/spec_helper.rb +14 -0
  167. metadata +94 -14
  168. data/test/sass/templates/bork.sass +0 -2
@@ -0,0 +1,141 @@
1
+ require 'cgi'
2
+ require 'erubis'
3
+ require 'ruby_parser'
4
+
5
+ module Haml
6
+ class HTML
7
+ # A class for converting ERB code into a format that's easier
8
+ # for the {Haml::HTML} Hpricot-based parser to understand.
9
+ #
10
+ # Uses [Erubis](http://www.kuwata-lab.com/erubis)'s extensible parsing powers
11
+ # to parse the ERB in a reliable way,
12
+ # and [ruby_parser](http://parsetree.rubyforge.org/)'s Ruby knowledge
13
+ # to figure out whether a given chunk of Ruby code starts a block or not.
14
+ #
15
+ # The ERB tags are converted to HTML tags in the following way.
16
+ # `<% ... %>` is converted into `<haml:silent> ... </haml:silent>`.
17
+ # `<%= ... %>` is converted into `<haml:loud> ... </haml:loud>`.
18
+ # Finally, if either of these opens a Ruby block,
19
+ # `<haml:block> ... </haml:block>` will wrap the entire contents of the block -
20
+ # that is, everything that should be indented beneath the previous silent or loud tag.
21
+ class ERB < Erubis::Basic::Engine
22
+ # Compiles an ERB template into a HTML document containing `haml:` tags.
23
+ #
24
+ # @param template [String] The ERB template
25
+ # @return [String] The output document
26
+ # @see Haml::HTML::ERB
27
+ def self.compile(template)
28
+ new(template).src
29
+ end
30
+
31
+ # `html2haml` doesn't support HTML-escaped expressions.
32
+ def escaped_expr(code)
33
+ raise Haml::Error.new("html2haml doesn't support escaped expressions.")
34
+ end
35
+
36
+ # The ERB-to-Hamlized-HTML conversion has no preamble.
37
+ def add_preamble(src); end
38
+
39
+ # The ERB-to-Hamlized-HTML conversion has no postamble.
40
+ def add_postamble(src); end
41
+
42
+ # Concatenates the text onto the source buffer.
43
+ #
44
+ # @param src [String] The source buffer
45
+ # @param text [String] The raw text to add to the buffer
46
+ def add_text(src, text)
47
+ src << text
48
+ end
49
+
50
+ # Concatenates a silent Ruby statement onto the source buffer.
51
+ # This uses the `<haml:silent>` tag,
52
+ # and may close and/or open a Ruby block with the `<haml:block>` tag.
53
+ #
54
+ # In particular, a block is closed if this statement is some form of `end`,
55
+ # opened if it's a block opener like `do`, `if`, or `begin`,
56
+ # and both closed and opened if it's a mid-block keyword
57
+ # like `else` or `when`.
58
+ #
59
+ # @param src [String] The source buffer
60
+ # @param code [String] The Ruby statement to add to the buffer
61
+ def add_stmt(src, code)
62
+ src << '</haml:block>' if block_closer?(code) || mid_block?(code)
63
+ src << '<haml:silent>' << h(code) << '</haml:silent>' unless code.strip == "end"
64
+ src << '<haml:block>' if block_opener?(code) || mid_block?(code)
65
+ end
66
+
67
+ # Concatenates a Ruby expression that's printed to the document
68
+ # onto the source buffer.
69
+ # This uses the `<haml:silent>` tag,
70
+ # and may open a Ruby block with the `<haml:block>` tag.
71
+ # An expression never closes a block.
72
+ #
73
+ # @param src [String] The source buffer
74
+ # @param code [String] The Ruby expression to add to the buffer
75
+ def add_expr_literal(src, code)
76
+ src << '<haml:loud>' << h(code) << '</haml:loud>'
77
+ src << '<haml:block>' if block_opener?(code)
78
+ end
79
+
80
+ # `html2haml` doesn't support debugging expressions.
81
+ def add_expr_debug(src, code)
82
+ raise Haml::Error.new("html2haml doesn't support debugging expressions.")
83
+ end
84
+
85
+ private
86
+
87
+ # HTML-escaped some text (in practice, always Ruby code).
88
+ # A utility method.
89
+ #
90
+ # @param text [String] The text to escape
91
+ # @return [String] The escaped text
92
+ def h(text)
93
+ CGI.escapeHTML(text)
94
+ end
95
+
96
+ # Returns whether the code is valid Ruby code on its own.
97
+ #
98
+ # @param code [String] Ruby code to check
99
+ # @return [Boolean]
100
+ def valid_ruby?(code)
101
+ RubyParser.new.parse(code)
102
+ rescue Racc::ParseError => e
103
+ false
104
+ end
105
+
106
+ # Checks if a string of Ruby code opens a block.
107
+ # This could either be something like `foo do |a|`
108
+ # or a keyword that requires a matching `end`
109
+ # like `if`, `begin`, or `case`.
110
+ #
111
+ # @param code [String] Ruby code to check
112
+ # @return [Boolean]
113
+ def block_opener?(code)
114
+ valid_ruby?(code + "\nend") ||
115
+ valid_ruby?(code + "\nwhen foo\nend")
116
+ end
117
+
118
+ # Checks if a string of Ruby code closes a block.
119
+ # This is always `end` followed optionally by some method calls.
120
+ #
121
+ # @param code [String] Ruby code to check
122
+ # @return [Boolean]
123
+ def block_closer?(code)
124
+ valid_ruby?("begin\n" + code)
125
+ end
126
+
127
+ # Checks if a string of Ruby code comes in the middle of a block.
128
+ # This could be a keyword like `else`, `rescue`, or `when`,
129
+ # or even `end` with a method call that takes a block.
130
+ #
131
+ # @param code [String] Ruby code to check
132
+ # @return [Boolean]
133
+ def mid_block?(code)
134
+ return if valid_ruby?(code)
135
+ valid_ruby?("if foo\n#{code}\nend") || # else, elsif
136
+ valid_ruby?("begin\n#{code}\nend") || # rescue, ensure
137
+ valid_ruby?("case foo\n#{code}\nend") # when
138
+ end
139
+ end
140
+ end
141
+ end
@@ -146,7 +146,6 @@ END
146
146
  class Line < Struct.new(:text, :unstripped, :full, :index, :precompiler, :eod)
147
147
  alias_method :eod?, :eod
148
148
 
149
- # @private
150
149
  def tabs
151
150
  line = self
152
151
  @tabs ||= precompiler.instance_eval do
@@ -332,15 +331,23 @@ END
332
331
  def flush_merged_text
333
332
  return if @to_merge.empty?
334
333
 
335
- text, tab_change = @to_merge.inject(["", 0]) do |(str, mtabs), (type, val, tabs)|
334
+ str = ""
335
+ mtabs = 0
336
+ newlines = 0
337
+ @to_merge.each do |type, val, tabs|
336
338
  case type
337
339
  when :text
338
- [str << val.inspect[1...-1], mtabs + tabs]
340
+ str << val.inspect[1...-1]
341
+ mtabs += tabs
339
342
  when :script
340
343
  if mtabs != 0 && !@options[:ugly]
341
344
  val = "_hamlout.adjust_tabs(#{mtabs}); " + val
342
345
  end
343
- [str << "\#{#{val}}", 0]
346
+ str << "\#{#{"\n" * newlines}#{val}}"
347
+ mtabs = 0
348
+ newlines = 0
349
+ when :newlines
350
+ newlines += val
344
351
  else
345
352
  raise SyntaxError.new("[HAML BUG] Undefined entry in Haml::Precompiler@to_merge.")
346
353
  end
@@ -348,10 +355,11 @@ END
348
355
 
349
356
  @precompiled <<
350
357
  if @options[:ugly]
351
- "_hamlout.buffer << \"#{text}\";"
358
+ "_hamlout.buffer << \"#{str}\";"
352
359
  else
353
- "_hamlout.push_text(\"#{text}\", #{tab_change}, #{@dont_tab_up_next_text.inspect});"
360
+ "_hamlout.push_text(\"#{str}\", #{mtabs}, #{@dont_tab_up_next_text.inspect});"
354
361
  end
362
+ @precompiled << "\n" * newlines
355
363
  @to_merge = []
356
364
  @dont_tab_up_next_text = false
357
365
  end
@@ -396,14 +404,14 @@ END
396
404
 
397
405
  no_format = @options[:ugly] &&
398
406
  !(opts[:preserve_script] || opts[:preserve_tag] || opts[:escape_html])
399
- output_temp = "(haml_very_temp = haml_temp; haml_temp = nil; haml_very_temp)"
400
- out = "_hamlout.#{static_method_name(:format_script, *args)}(#{output_temp});"
407
+ output_expr = "(#{text}\n)"
408
+ static_method = "_hamlout.#{static_method_name(:format_script, *args)}"
401
409
 
402
410
  # Prerender tabulation unless we're in a tag
403
411
  push_merged_text '' unless opts[:in_tag]
404
412
 
405
413
  unless block_opened?
406
- @to_merge << [:script, no_format ? "#{text}\n" : "haml_temp = #{text}\n#{out}"]
414
+ @to_merge << [:script, no_format ? "#{text}\n" : "#{static_method}(#{output_expr});"]
407
415
  concat_merged_text("\n") unless opts[:in_tag] || opts[:nuke_inner_whitespace]
408
416
  @newlines -= 1
409
417
  return
@@ -413,7 +421,7 @@ END
413
421
 
414
422
  push_silent "haml_temp = #{text}"
415
423
  newline_now
416
- push_and_tabulate([:loud, "_hamlout.buffer << #{no_format ? "#{output_temp}.to_s;" : out}",
424
+ push_and_tabulate([:loud, "_hamlout.buffer << #{no_format ? "haml_temp.to_s;" : "#{static_method}(haml_temp);"}",
417
425
  !(opts[:in_tag] || opts[:nuke_inner_whitespace] || @options[:ugly])])
418
426
  end
419
427
 
@@ -491,10 +499,12 @@ END
491
499
  @template_tabs -= 1
492
500
  end
493
501
 
502
+ # This is a class method so it can be accessed from {Haml::Helpers}.
503
+ #
494
504
  # Iterates through the classes and ids supplied through `.`
495
505
  # and `#` syntax, and returns a hash with them as attributes,
496
506
  # that can then be merged with another attributes hash.
497
- def parse_class_and_id(list)
507
+ def self.parse_class_and_id(list)
498
508
  attributes = {}
499
509
  list.scan(/([#.])([-_a-zA-Z0-9]+)/) do |type, property|
500
510
  case type
@@ -531,9 +541,18 @@ END
531
541
  quote_escape = attr_wrapper == '"' ? "&quot;" : "&apos;"
532
542
  other_quote_char = attr_wrapper == '"' ? "'" : '"'
533
543
 
544
+ if attributes['data'].is_a?(Hash)
545
+ attributes = attributes.dup
546
+ attributes =
547
+ Haml::Util.map_keys(attributes.delete('data')) {|name| "data-#{name}"}.merge(attributes)
548
+ end
549
+
534
550
  result = attributes.collect do |attr, value|
535
551
  next if value.nil?
536
552
 
553
+ value = filter_and_join(value, ' ') if attr == :class
554
+ value = filter_and_join(value, '_') if attr == :id
555
+
537
556
  if value == true
538
557
  next " #{attr}" if is_html
539
558
  next " #{attr}=#{attr_wrapper}#{attr}#{attr_wrapper}"
@@ -557,6 +576,11 @@ END
557
576
  result.compact.sort.join
558
577
  end
559
578
 
579
+ def self.filter_and_join(value, separator)
580
+ value = [value] unless value.is_a?(Array)
581
+ return value.flatten.collect {|item| item ? item.to_s : nil}.compact.join(separator)
582
+ end
583
+
560
584
  def prerender_tag(name, self_close, attributes)
561
585
  attributes_string = Precompiler.build_attributes(html?, @options[:attr_wrapper], attributes)
562
586
  "<#{name}#{attributes_string}#{self_close && xhtml? ? ' /' : ''}>"
@@ -744,7 +768,7 @@ END
744
768
 
745
769
  object_ref = "nil" if object_ref.nil? || @options[:suppress_eval]
746
770
 
747
- attributes = parse_class_and_id(attributes)
771
+ attributes = Precompiler.parse_class_and_id(attributes)
748
772
  attributes_hashes.map! do |syntax, attributes_hash|
749
773
  if syntax == :old
750
774
  static_attributes = parse_static_hash(attributes_hash)
@@ -761,7 +785,7 @@ END
761
785
  raise SyntaxError.new("There's no Ruby code for #{action} to evaluate.", last_line - 1) if parse && value.empty?
762
786
  raise SyntaxError.new("Self-closing tags can't have content.", last_line - 1) if self_closing && !value.empty?
763
787
 
764
- self_closing ||= !!( !block_opened? && value.empty? && @options[:autoclose].include?(tag_name) )
788
+ self_closing ||= !!(!block_opened? && value.empty? && @options[:autoclose].any? {|t| t === tag_name})
765
789
  value = nil if value.empty? && (block_opened? || self_closing)
766
790
 
767
791
  dont_indent_next_line =
@@ -1030,8 +1054,7 @@ END
1030
1054
 
1031
1055
  def resolve_newlines
1032
1056
  return unless @newlines > 0
1033
- flush_merged_text unless @to_merge.all? {|type, *_| type == :text}
1034
- @precompiled << "\n" * @newlines
1057
+ @to_merge << [:newlines, @newlines]
1035
1058
  @newlines = 0
1036
1059
  end
1037
1060
 
@@ -1055,6 +1078,8 @@ END
1055
1078
  when :script
1056
1079
  last[1].gsub!(/\(haml_temp, (.*?)\);$/, '(haml_temp.rstrip, \1);')
1057
1080
  rstrip_buffer! index - 1
1081
+ when :newlines
1082
+ rstrip_buffer! index - 1
1058
1083
  else
1059
1084
  raise SyntaxError.new("[HAML BUG] Undefined entry in Haml::Precompiler@to_merge.")
1060
1085
  end
@@ -3,11 +3,7 @@
3
3
  # Yehuda promises there will be soon,
4
4
  # and once there is we should switch to that.
5
5
 
6
- if defined?(ActiveSupport) && Haml::Util.has?(:public_method, ActiveSupport, :on_load)
7
- # Rails 3.0.0.beta.2+
8
- ActiveSupport.on_load(:action_view) {Haml.init_rails(binding)}
9
- elsif defined?(Rails::Railtie)
10
- # Rails 3.0.0.beta1
6
+ if defined?(Rails::Railtie)
11
7
  module Haml
12
8
  class Railtie < Rails::Railtie
13
9
  initializer :haml do
@@ -0,0 +1,3 @@
1
+ module Haml
2
+ ROOT_DIR = File.expand_path("../../..", __FILE__)
3
+ end
@@ -1,6 +1,4 @@
1
1
  require 'haml/engine'
2
- require 'haml/helpers/action_view_mods'
3
- require 'haml/helpers/action_view_extensions'
4
2
 
5
3
  module Haml
6
4
  # The class that keeps track of the global options for Haml within Rails.
@@ -19,11 +17,7 @@ module Haml
19
17
  #
20
18
  # @return [Boolean] Whether the XSS integration was enabled.
21
19
  def try_enabling_xss_integration
22
- return false unless (ActionView::Base.respond_to?(:xss_safe?) && ActionView::Base.xss_safe?) ||
23
- # We check for ActiveSupport#on_load here because if we're loading Haml that way, it means:
24
- # A) we're in Rails 3 so XSS support is always on, and
25
- # B) we might be in Rails 3 beta 3 where the load order is broken and xss_safe? is undefined
26
- (defined?(ActiveSupport) && Haml::Util.has?(:public_method, ActiveSupport, :on_load))
20
+ return false unless ActionView::Base.respond_to?(:xss_safe?) && ActionView::Base.xss_safe?
27
21
 
28
22
  Haml::Template.options[:escape_html] = true
29
23
 
@@ -59,14 +53,10 @@ else
59
53
  require 'haml/template/patch'
60
54
  end
61
55
 
62
- # Enable XSS integration. Use Rails' after_initialize method
56
+ # Enable XSS integration. Use Rails' after_initialize method if possible
63
57
  # so that integration will be checked after the rails_xss plugin is loaded
64
58
  # (for Rails 2.3.* where it's not enabled by default).
65
- #
66
- # If we're running under Rails 3, though, we don't want to use after_intialize,
67
- # since Haml loading has already been deferred via ActiveSupport.on_load.
68
- if defined?(Rails.configuration.after_initialize) &&
69
- !(defined?(ActiveSupport) && Haml::Util.has?(:public_method, ActiveSupport, :on_load))
59
+ if defined?(Rails.configuration.after_initialize)
70
60
  Rails.configuration.after_initialize {Haml::Template.try_enabling_xss_integration}
71
61
  else
72
62
  Haml::Template.try_enabling_xss_integration
@@ -87,7 +77,7 @@ if Haml::Util.rails_root
87
77
  FileUtils.cp(haml_init_file, rails_init_file) unless FileUtils.cmp(rails_init_file, haml_init_file)
88
78
  end
89
79
  rescue SystemCallError
90
- warn <<END
80
+ Haml::Util.haml_warn <<END
91
81
  HAML WARNING:
92
82
  #{rails_init_file} is out of date and couldn't be automatically updated.
93
83
  Please run `haml --rails #{File.expand_path(Haml::Util.rails_root)}' to update it.
@@ -2,6 +2,7 @@ require 'erb'
2
2
  require 'set'
3
3
  require 'enumerator'
4
4
  require 'stringio'
5
+ require 'haml/root'
5
6
 
6
7
  module Haml
7
8
  # A module containing various useful functions.
@@ -16,7 +17,7 @@ module Haml
16
17
  # @param file [String] The filename relative to the Haml root
17
18
  # @return [String] The filename relative to the the working directory
18
19
  def scope(file)
19
- File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), file)
20
+ File.join(Haml::ROOT_DIR, file)
20
21
  end
21
22
 
22
23
  # Converts an array of `[key, value]` pairs to a hash.
@@ -103,6 +104,17 @@ module Haml
103
104
  end
104
105
  end
105
106
 
107
+ # Restricts a number to falling within a given range.
108
+ # Returns the number if it falls within the range,
109
+ # or the closest value in the range if it doesn't.
110
+ #
111
+ # @param value [Numeric]
112
+ # @param range [Range<Numeric>]
113
+ # @return [Numeric]
114
+ def restrict(value, range)
115
+ [[value, range.first].max, range.last].min
116
+ end
117
+
106
118
  # Concatenates all strings that are adjacent in an array,
107
119
  # while leaving other elements as they are.
108
120
  # For example:
@@ -123,6 +135,29 @@ module Haml
123
135
  end
124
136
  end
125
137
 
138
+ # Destructively strips whitespace from the beginning and end
139
+ # of the first and last elements, respectively,
140
+ # in the array (if those elements are strings).
141
+ #
142
+ # @param arr [Array]
143
+ # @return [Array] `arr`
144
+ def strip_string_array(arr)
145
+ arr.first.lstrip! if arr.first.is_a?(String)
146
+ arr.last.rstrip! if arr.last.is_a?(String)
147
+ arr
148
+ end
149
+
150
+ # Returns information about the caller of the previous method.
151
+ #
152
+ # @param entry [String] An entry in the `#caller` list, or a similarly formatted string
153
+ # @return [[String, Fixnum, (String, nil)]] An array containing the filename, line, and method name of the caller.
154
+ # The method name may be nil
155
+ def caller_info(entry = caller[1])
156
+ info = entry.scan(/^(.*?):(-?.*?)(?::.*`(.+)')?$/).first
157
+ info[1] = info[1].to_i
158
+ info
159
+ end
160
+
126
161
  # Silence all output to STDERR within a block.
127
162
  #
128
163
  # @yield A block in which no output will be printed to STDERR
@@ -133,6 +168,26 @@ module Haml
133
168
  $stderr = the_real_stderr
134
169
  end
135
170
 
171
+ @@silence_warnings = false
172
+ # Silences all Haml warnings within a block.
173
+ #
174
+ # @yield A block in which no Haml warnings will be printed
175
+ def silence_haml_warnings
176
+ old_silence_warnings = @@silence_warnings
177
+ @@silence_warnings = true
178
+ yield
179
+ ensure
180
+ @@silence_warnings = old_silence_warnings
181
+ end
182
+
183
+ # The same as `Kernel#warn`, but is silenced by \{#silence\_haml\_warnings}.
184
+ #
185
+ # @param msg [String]
186
+ def haml_warn(msg)
187
+ return if @@silence_warnings
188
+ warn(msg)
189
+ end
190
+
136
191
  ## Cross Rails Version Compatibility
137
192
 
138
193
  # Returns the root of the Rails application,
@@ -182,30 +237,6 @@ module Haml
182
237
  ActionPack::VERSION::TINY == "0.beta")
183
238
  end
184
239
 
185
- # Returns whether this environment is using ActionPack
186
- # version 3.0.0.beta.3 or greater.
187
- #
188
- # @return [Boolean]
189
- def ap_geq_3_beta_3?
190
- # The ActionPack module is always loaded automatically in Rails >= 3
191
- return false unless defined?(ActionPack) && defined?(ActionPack::VERSION)
192
-
193
- version =
194
- if defined?(ActionPack::VERSION::MAJOR)
195
- ActionPack::VERSION::MAJOR
196
- else
197
- # Rails 1.2
198
- ActionPack::VERSION::Major
199
- end
200
- version >= 3 &&
201
- ((defined?(ActionPack::VERSION::TINY) &&
202
- ActionPack::VERSION::TINY.is_a?(Fixnum) &&
203
- ActionPack::VERSION::TINY >= 1) ||
204
- (defined?(ActionPack::VERSION::BUILD) &&
205
- ActionPack::VERSION::BUILD =~ /beta(\d+)/ &&
206
- $1.to_i >= 3))
207
- end
208
-
209
240
  # Returns an ActionView::Template* class.
210
241
  # In pre-3.0 versions of Rails, most of these classes
211
242
  # were of the form `ActionView::TemplateFoo`,
@@ -251,10 +282,6 @@ module Haml
251
282
  raise Haml::Error.new("Expected #{text.inspect} to be HTML-safe.")
252
283
  end
253
284
 
254
- # The class for the Rails SafeBuffer XSS protection class.
255
- # This varies depending on Rails version.
256
- #
257
- # @return [Class]
258
285
  def rails_safe_buffer_class
259
286
  return ActionView::SafeBuffer if defined?(ActionView::SafeBuffer)
260
287
  ActiveSupport::SafeBuffer
@@ -269,6 +296,42 @@ module Haml
269
296
  Haml::Util::RUBY_VERSION[0] == 1 && Haml::Util::RUBY_VERSION[1] < 9
270
297
  end
271
298
 
299
+ # Checks that the encoding of a string is valid in Ruby 1.9
300
+ # and cleans up potential encoding gotchas like the UTF-8 BOM.
301
+ # If it's not, yields an error string describing the invalid character
302
+ # and the line on which it occurrs.
303
+ #
304
+ # @param str [String] The string of which to check the encoding
305
+ # @yield [msg] A block in which an encoding error can be raised.
306
+ # Only yields if there is an encoding error
307
+ # @yieldparam msg [String] The error message to be raised
308
+ # @return [String] `str`, potentially with encoding gotchas like BOMs removed
309
+ def check_encoding(str)
310
+ if ruby1_8?
311
+ return str.gsub(/\A\xEF\xBB\xBF/, '') # Get rid of the UTF-8 BOM
312
+ elsif str.valid_encoding?
313
+ # Get rid of the Unicode BOM if possible
314
+ if str.encoding.name =~ /^UTF-(8|16|32)(BE|LE)?$/
315
+ return str.gsub(Regexp.new("\\A\uFEFF".encode(str.encoding.name)), '')
316
+ else
317
+ return str
318
+ end
319
+ end
320
+
321
+ encoding = str.encoding
322
+ newlines = Regexp.new("\r\n|\r|\n".encode(encoding).force_encoding("binary"))
323
+ str.force_encoding("binary").split(newlines).each_with_index do |line, i|
324
+ begin
325
+ line.encode(encoding)
326
+ rescue Encoding::UndefinedConversionError => e
327
+ yield <<MSG.rstrip, i + 1
328
+ Invalid #{encoding.name} character #{e.error_char.dump}
329
+ MSG
330
+ end
331
+ end
332
+ return str
333
+ end
334
+
272
335
  # Checks to see if a class has a given method.
273
336
  # For example:
274
337
  #
@@ -295,6 +358,32 @@ module Haml
295
358
  ruby1_8? ? enum.enum_with_index : enum.each_with_index
296
359
  end
297
360
 
361
+ # A version of `Enumerable#enum_cons` that works in Ruby 1.8 and 1.9.
362
+ #
363
+ # @param enum [Enumerable] The enumerable to get the enumerator for
364
+ # @param n [Fixnum] The size of each cons
365
+ # @return [Enumerator] The consed enumerator
366
+ def enum_cons(enum, n)
367
+ ruby1_8? ? enum.enum_cons(n) : enum.each_cons(n)
368
+ end
369
+
370
+ # A version of `Enumerable#enum_slice` that works in Ruby 1.8 and 1.9.
371
+ #
372
+ # @param enum [Enumerable] The enumerable to get the enumerator for
373
+ # @param n [Fixnum] The size of each slice
374
+ # @return [Enumerator] The consed enumerator
375
+ def enum_slice(enum, n)
376
+ ruby1_8? ? enum.enum_slice(n) : enum.each_slice(n)
377
+ end
378
+
379
+ # Returns the ASCII code of the given character.
380
+ #
381
+ # @param c [String] All characters but the first are ignored.
382
+ # @return [Fixnum] The ASCII code of `c`.
383
+ def ord(c)
384
+ ruby1_8? ? c[0] : c.ord
385
+ end
386
+
298
387
  ## Static Method Stuff
299
388
 
300
389
  # The context in which the ERB for \{#def\_static\_method} will be run.
@@ -348,9 +437,10 @@ module Haml
348
437
  # @param erb [String] The template for the method code
349
438
  def def_static_method(klass, name, args, *vars)
350
439
  erb = vars.pop
440
+ info = caller_info
351
441
  powerset(vars).each do |set|
352
442
  context = StaticConditionalContext.new(set).instance_eval {binding}
353
- klass.class_eval(<<METHOD)
443
+ klass.class_eval(<<METHOD, info[0], info[1])
354
444
  def #{static_method_name(name, *vars.map {|v| set.include?(v)})}(#{args.join(', ')})
355
445
  #{ERB.new(erb).result(context)}
356
446
  end