honkster-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 (176) hide show
  1. data/FAQ +138 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +332 -0
  4. data/Rakefile +198 -0
  5. data/VERSION.yml +4 -0
  6. data/bin/css2sass +7 -0
  7. data/bin/haml +9 -0
  8. data/bin/html2haml +7 -0
  9. data/bin/sass +8 -0
  10. data/extra/haml-mode.el +596 -0
  11. data/extra/sass-mode.el +137 -0
  12. data/init.rb +8 -0
  13. data/lib/haml/buffer.rb +255 -0
  14. data/lib/haml/engine.rb +268 -0
  15. data/lib/haml/error.rb +22 -0
  16. data/lib/haml/exec.rb +395 -0
  17. data/lib/haml/filters.rb +276 -0
  18. data/lib/haml/helpers/action_view_extensions.rb +45 -0
  19. data/lib/haml/helpers/action_view_mods.rb +181 -0
  20. data/lib/haml/helpers.rb +468 -0
  21. data/lib/haml/html.rb +218 -0
  22. data/lib/haml/precompiler.rb +901 -0
  23. data/lib/haml/shared.rb +45 -0
  24. data/lib/haml/template/patch.rb +58 -0
  25. data/lib/haml/template/plugin.rb +72 -0
  26. data/lib/haml/template.rb +51 -0
  27. data/lib/haml/util.rb +77 -0
  28. data/lib/haml/version.rb +25 -0
  29. data/lib/haml.rb +1043 -0
  30. data/lib/sass/css.rb +388 -0
  31. data/lib/sass/engine.rb +499 -0
  32. data/lib/sass/environment.rb +33 -0
  33. data/lib/sass/error.rb +35 -0
  34. data/lib/sass/plugin/merb.rb +56 -0
  35. data/lib/sass/plugin/rails.rb +24 -0
  36. data/lib/sass/plugin.rb +203 -0
  37. data/lib/sass/repl.rb +51 -0
  38. data/lib/sass/script/bool.rb +13 -0
  39. data/lib/sass/script/color.rb +97 -0
  40. data/lib/sass/script/funcall.rb +28 -0
  41. data/lib/sass/script/functions.rb +122 -0
  42. data/lib/sass/script/lexer.rb +152 -0
  43. data/lib/sass/script/literal.rb +80 -0
  44. data/lib/sass/script/number.rb +231 -0
  45. data/lib/sass/script/operation.rb +30 -0
  46. data/lib/sass/script/parser.rb +142 -0
  47. data/lib/sass/script/string.rb +18 -0
  48. data/lib/sass/script/unary_operation.rb +21 -0
  49. data/lib/sass/script/variable.rb +20 -0
  50. data/lib/sass/script.rb +38 -0
  51. data/lib/sass/tree/attr_node.rb +64 -0
  52. data/lib/sass/tree/comment_node.rb +34 -0
  53. data/lib/sass/tree/debug_node.rb +22 -0
  54. data/lib/sass/tree/directive_node.rb +50 -0
  55. data/lib/sass/tree/file_node.rb +27 -0
  56. data/lib/sass/tree/for_node.rb +29 -0
  57. data/lib/sass/tree/if_node.rb +27 -0
  58. data/lib/sass/tree/mixin_def_node.rb +18 -0
  59. data/lib/sass/tree/mixin_node.rb +34 -0
  60. data/lib/sass/tree/node.rb +99 -0
  61. data/lib/sass/tree/rule_node.rb +120 -0
  62. data/lib/sass/tree/variable_node.rb +24 -0
  63. data/lib/sass/tree/while_node.rb +20 -0
  64. data/lib/sass.rb +1062 -0
  65. data/rails/init.rb +1 -0
  66. data/test/benchmark.rb +99 -0
  67. data/test/haml/engine_test.rb +782 -0
  68. data/test/haml/helper_test.rb +224 -0
  69. data/test/haml/html2haml_test.rb +92 -0
  70. data/test/haml/markaby/standard.mab +52 -0
  71. data/test/haml/mocks/article.rb +6 -0
  72. data/test/haml/results/content_for_layout.xhtml +15 -0
  73. data/test/haml/results/eval_suppressed.xhtml +9 -0
  74. data/test/haml/results/filters.xhtml +62 -0
  75. data/test/haml/results/helpers.xhtml +93 -0
  76. data/test/haml/results/helpful.xhtml +10 -0
  77. data/test/haml/results/just_stuff.xhtml +68 -0
  78. data/test/haml/results/list.xhtml +12 -0
  79. data/test/haml/results/nuke_inner_whitespace.xhtml +40 -0
  80. data/test/haml/results/nuke_outer_whitespace.xhtml +148 -0
  81. data/test/haml/results/original_engine.xhtml +20 -0
  82. data/test/haml/results/partial_layout.xhtml +5 -0
  83. data/test/haml/results/partials.xhtml +21 -0
  84. data/test/haml/results/render_layout.xhtml +3 -0
  85. data/test/haml/results/silent_script.xhtml +74 -0
  86. data/test/haml/results/standard.xhtml +42 -0
  87. data/test/haml/results/tag_parsing.xhtml +23 -0
  88. data/test/haml/results/very_basic.xhtml +5 -0
  89. data/test/haml/results/whitespace_handling.xhtml +89 -0
  90. data/test/haml/rhtml/_av_partial_1.rhtml +12 -0
  91. data/test/haml/rhtml/_av_partial_2.rhtml +8 -0
  92. data/test/haml/rhtml/action_view.rhtml +62 -0
  93. data/test/haml/rhtml/standard.rhtml +54 -0
  94. data/test/haml/template_test.rb +204 -0
  95. data/test/haml/templates/_av_partial_1.haml +9 -0
  96. data/test/haml/templates/_av_partial_1_ugly.haml +9 -0
  97. data/test/haml/templates/_av_partial_2.haml +5 -0
  98. data/test/haml/templates/_av_partial_2_ugly.haml +5 -0
  99. data/test/haml/templates/_layout.erb +3 -0
  100. data/test/haml/templates/_layout_for_partial.haml +3 -0
  101. data/test/haml/templates/_partial.haml +8 -0
  102. data/test/haml/templates/_text_area.haml +3 -0
  103. data/test/haml/templates/action_view.haml +47 -0
  104. data/test/haml/templates/action_view_ugly.haml +47 -0
  105. data/test/haml/templates/breakage.haml +8 -0
  106. data/test/haml/templates/content_for_layout.haml +10 -0
  107. data/test/haml/templates/eval_suppressed.haml +11 -0
  108. data/test/haml/templates/filters.haml +66 -0
  109. data/test/haml/templates/helpers.haml +95 -0
  110. data/test/haml/templates/helpful.haml +11 -0
  111. data/test/haml/templates/just_stuff.haml +83 -0
  112. data/test/haml/templates/list.haml +12 -0
  113. data/test/haml/templates/nuke_inner_whitespace.haml +32 -0
  114. data/test/haml/templates/nuke_outer_whitespace.haml +144 -0
  115. data/test/haml/templates/original_engine.haml +17 -0
  116. data/test/haml/templates/partial_layout.haml +3 -0
  117. data/test/haml/templates/partialize.haml +1 -0
  118. data/test/haml/templates/partials.haml +12 -0
  119. data/test/haml/templates/render_layout.haml +2 -0
  120. data/test/haml/templates/silent_script.haml +40 -0
  121. data/test/haml/templates/standard.haml +42 -0
  122. data/test/haml/templates/standard_ugly.haml +1 -0
  123. data/test/haml/templates/tag_parsing.haml +21 -0
  124. data/test/haml/templates/very_basic.haml +4 -0
  125. data/test/haml/templates/whitespace_handling.haml +87 -0
  126. data/test/linked_rails.rb +12 -0
  127. data/test/sass/css2sass_test.rb +193 -0
  128. data/test/sass/engine_test.rb +655 -0
  129. data/test/sass/functions_test.rb +96 -0
  130. data/test/sass/more_results/more1.css +9 -0
  131. data/test/sass/more_results/more1_with_line_comments.css +26 -0
  132. data/test/sass/more_results/more_import.css +29 -0
  133. data/test/sass/more_templates/_more_partial.sass +2 -0
  134. data/test/sass/more_templates/more1.sass +23 -0
  135. data/test/sass/more_templates/more_import.sass +11 -0
  136. data/test/sass/plugin_test.rb +208 -0
  137. data/test/sass/results/alt.css +4 -0
  138. data/test/sass/results/basic.css +9 -0
  139. data/test/sass/results/compact.css +5 -0
  140. data/test/sass/results/complex.css +87 -0
  141. data/test/sass/results/compressed.css +1 -0
  142. data/test/sass/results/expanded.css +19 -0
  143. data/test/sass/results/import.css +29 -0
  144. data/test/sass/results/line_numbers.css +49 -0
  145. data/test/sass/results/mixins.css +95 -0
  146. data/test/sass/results/multiline.css +24 -0
  147. data/test/sass/results/nested.css +22 -0
  148. data/test/sass/results/parent_ref.css +13 -0
  149. data/test/sass/results/script.css +16 -0
  150. data/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
  151. data/test/sass/results/subdir/subdir.css +3 -0
  152. data/test/sass/results/units.css +11 -0
  153. data/test/sass/script_test.rb +250 -0
  154. data/test/sass/templates/_partial.sass +2 -0
  155. data/test/sass/templates/alt.sass +16 -0
  156. data/test/sass/templates/basic.sass +23 -0
  157. data/test/sass/templates/bork.sass +2 -0
  158. data/test/sass/templates/bork2.sass +2 -0
  159. data/test/sass/templates/compact.sass +17 -0
  160. data/test/sass/templates/complex.sass +309 -0
  161. data/test/sass/templates/compressed.sass +15 -0
  162. data/test/sass/templates/expanded.sass +17 -0
  163. data/test/sass/templates/import.sass +11 -0
  164. data/test/sass/templates/importee.sass +19 -0
  165. data/test/sass/templates/line_numbers.sass +13 -0
  166. data/test/sass/templates/mixins.sass +76 -0
  167. data/test/sass/templates/multiline.sass +20 -0
  168. data/test/sass/templates/nested.sass +25 -0
  169. data/test/sass/templates/parent_ref.sass +25 -0
  170. data/test/sass/templates/script.sass +101 -0
  171. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
  172. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
  173. data/test/sass/templates/subdir/subdir.sass +6 -0
  174. data/test/sass/templates/units.sass +11 -0
  175. data/test/test_helper.rb +21 -0
  176. metadata +272 -0
@@ -0,0 +1,181 @@
1
+ if defined?(ActionView) and not defined?(Merb::Plugins)
2
+ module ActionView
3
+ class Base # :nodoc:
4
+ def render_with_haml(*args, &block)
5
+ options = args.first
6
+
7
+ # If render :layout is used with a block,
8
+ # it concats rather than returning a string
9
+ # so we need it to keep thinking it's Haml
10
+ # until it hits the sub-render
11
+ if is_haml? && !(options.is_a?(Hash) && options[:layout] && block_given?)
12
+ return non_haml { render_without_haml(*args, &block) }
13
+ end
14
+ render_without_haml(*args, &block)
15
+ end
16
+ alias_method :render_without_haml, :render
17
+ alias_method :render, :render_with_haml
18
+
19
+ # Rails >2.1
20
+ if Haml::Util.has?(:instance_method, self, :output_buffer)
21
+ def output_buffer_with_haml
22
+ return haml_buffer.buffer if is_haml?
23
+ output_buffer_without_haml
24
+ end
25
+ alias_method :output_buffer_without_haml, :output_buffer
26
+ alias_method :output_buffer, :output_buffer_with_haml
27
+
28
+ def set_output_buffer_with_haml(new)
29
+ if is_haml?
30
+ haml_buffer.buffer = new
31
+ else
32
+ set_output_buffer_without_haml new
33
+ end
34
+ end
35
+ alias_method :set_output_buffer_without_haml, :output_buffer=
36
+ alias_method :output_buffer=, :set_output_buffer_with_haml
37
+ end
38
+ end
39
+
40
+ # This overrides various helpers in ActionView
41
+ # to make them work more effectively with Haml.
42
+ module Helpers
43
+ # :stopdoc:
44
+ # In Rails <=2.1, we've got to override considerable capturing infrastructure.
45
+ # In Rails >2.1, we can make do with only overriding #capture
46
+ # (which no longer behaves differently in helper contexts).
47
+ unless Haml::Util.has?(:instance_method, ActionView::Base, :output_buffer)
48
+ module CaptureHelper
49
+ def capture_with_haml(*args, &block)
50
+ # Rails' #capture helper will just return the value of the block
51
+ # if it's not actually in the template context,
52
+ # as detected by the existance of an _erbout variable.
53
+ # We've got to do the same thing for compatibility.
54
+
55
+ if is_haml? && block_is_haml?(block)
56
+ capture_haml(*args, &block)
57
+ else
58
+ capture_without_haml(*args, &block)
59
+ end
60
+ end
61
+ alias_method :capture_without_haml, :capture
62
+ alias_method :capture, :capture_with_haml
63
+
64
+ def capture_erb_with_buffer_with_haml(buffer, *args, &block)
65
+ if is_haml?
66
+ capture_haml(*args, &block)
67
+ else
68
+ capture_erb_with_buffer_without_haml(buffer, *args, &block)
69
+ end
70
+ end
71
+ alias_method :capture_erb_with_buffer_without_haml, :capture_erb_with_buffer
72
+ alias_method :capture_erb_with_buffer, :capture_erb_with_buffer_with_haml
73
+ end
74
+
75
+ module TextHelper
76
+ def concat_with_haml(string, binding = nil)
77
+ if is_haml?
78
+ haml_buffer.buffer.concat(string)
79
+ else
80
+ concat_without_haml(string, binding)
81
+ end
82
+ end
83
+ alias_method :concat_without_haml, :concat
84
+ alias_method :concat, :concat_with_haml
85
+ end
86
+ else
87
+ module CaptureHelper
88
+ def capture_with_haml(*args, &block)
89
+ if Haml::Helpers.block_is_haml?(block)
90
+ capture_haml(*args, &block)
91
+ else
92
+ capture_without_haml(*args, &block)
93
+ end
94
+ end
95
+ alias_method :capture_without_haml, :capture
96
+ alias_method :capture, :capture_with_haml
97
+ end
98
+ end
99
+
100
+ module TagHelper
101
+ def content_tag_with_haml(name, *args, &block)
102
+ return content_tag_without_haml(name, *args, &block) unless is_haml?
103
+
104
+ preserve = haml_buffer.options[:preserve].include?(name.to_s)
105
+
106
+ if block_given? && block_is_haml?(block) && preserve
107
+ return content_tag_without_haml(name, *args) {preserve(&block)}
108
+ end
109
+
110
+ returning content_tag_without_haml(name, *args, &block) do |content|
111
+ return Haml::Helpers.preserve(content) if preserve && content
112
+ end
113
+ end
114
+
115
+ alias_method :content_tag_without_haml, :content_tag
116
+ alias_method :content_tag, :content_tag_with_haml
117
+ end
118
+
119
+ class InstanceTag
120
+ # Includes TagHelper
121
+
122
+ def haml_buffer
123
+ @template_object.send :haml_buffer
124
+ end
125
+
126
+ def is_haml?
127
+ @template_object.send :is_haml?
128
+ end
129
+
130
+ alias_method :content_tag_without_haml, :content_tag
131
+ alias_method :content_tag, :content_tag_with_haml
132
+ end
133
+
134
+ module FormTagHelper
135
+ def form_tag_with_haml(url_for_options = {}, options = {}, *parameters_for_url, &proc)
136
+ if is_haml?
137
+ if block_given?
138
+ oldproc = proc
139
+ proc = haml_bind_proc do |*args|
140
+ concat "\n"
141
+ tab_up
142
+ oldproc.call(*args)
143
+ tab_down
144
+ concat haml_indent
145
+ end
146
+ concat haml_indent
147
+ end
148
+ res = form_tag_without_haml(url_for_options, options, *parameters_for_url, &proc) + "\n"
149
+ concat "\n" if block_given?
150
+ res
151
+ else
152
+ form_tag_without_haml(url_for_options, options, *parameters_for_url, &proc)
153
+ end
154
+ end
155
+ alias_method :form_tag_without_haml, :form_tag
156
+ alias_method :form_tag, :form_tag_with_haml
157
+ end
158
+
159
+ module FormHelper
160
+ def form_for_with_haml(object_name, *args, &proc)
161
+ if block_given? && is_haml?
162
+ oldproc = proc
163
+ proc = haml_bind_proc do |*args|
164
+ tab_up
165
+ oldproc.call(*args)
166
+ tab_down
167
+ concat haml_indent
168
+ end
169
+ concat haml_indent
170
+ end
171
+ form_for_without_haml(object_name, *args, &proc)
172
+ concat "\n" if block_given? && is_haml?
173
+ end
174
+ alias_method :form_for_without_haml, :form_for
175
+ alias_method :form_for, :form_for_with_haml
176
+ end
177
+ # :startdoc:
178
+ end
179
+ end
180
+ end
181
+
@@ -0,0 +1,468 @@
1
+ require 'haml/helpers/action_view_mods'
2
+ require 'haml/helpers/action_view_extensions'
3
+
4
+ module Haml
5
+ # This module contains various helpful methods to make it easier to do
6
+ # various tasks. Haml::Helpers is automatically included in the context
7
+ # that a Haml template is parsed in, so all these methods are at your
8
+ # disposal from within the template.
9
+ module Helpers
10
+ self.extend self
11
+
12
+ @@action_view_defined = defined?(ActionView)
13
+ @@force_no_action_view = false
14
+
15
+ # Returns whether or not ActionView is installed on the system.
16
+ def self.action_view?
17
+ @@action_view_defined
18
+ end
19
+
20
+ # Note: this does *not* need to be called
21
+ # when using Haml helpers normally
22
+ # in Rails.
23
+ #
24
+ # Initializes the current object
25
+ # as though it were in the same context
26
+ # as a normal ActionView rendering
27
+ # using Haml.
28
+ # This is useful if you want to use the helpers in a context
29
+ # other than the normal setup with ActionView.
30
+ # For example:
31
+ #
32
+ # context = Object.new
33
+ # class << context
34
+ # include Haml::Helpers
35
+ # end
36
+ # context.init_haml_helpers
37
+ # context.haml_tag :p, "Stuff"
38
+ #
39
+ def init_haml_helpers
40
+ @haml_buffer = Haml::Buffer.new(@haml_buffer, Haml::Engine.new('').send(:options_for_buffer))
41
+ nil
42
+ end
43
+
44
+ # call-seq:
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
+ yield
58
+ ensure
59
+ @haml_buffer.active = was_active
60
+ end
61
+
62
+ # call-seq:
63
+ # find_and_preserve(input, tags = haml_buffer.options[:preserve])
64
+ # find_and_preserve {...}
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)
71
+ return find_and_preserve(capture_haml(&block)) if block
72
+
73
+ input = input.to_s
74
+ input.gsub(/<(#{tags.map(&Regexp.method(:escape)).join('|')})([^>]*)>(.*?)(<\/\1>)/im) do
75
+ "<#{$1}#{$2}>#{preserve($3)}</#{$1}>"
76
+ end
77
+ end
78
+
79
+ # call-seq:
80
+ # preserve(input)
81
+ # preserve {...}
82
+ #
83
+ # Takes any string, finds all the endlines and converts them to
84
+ # HTML entities for endlines so they'll render correctly in
85
+ # whitespace-sensitive tags without screwing up the indentation.
86
+ def preserve(input = '', &block)
87
+ return preserve(capture_haml(&block)) if block
88
+
89
+ input.chomp("\n").gsub(/\n/, '&#x000A;').gsub(/\r/, '')
90
+ end
91
+
92
+ alias_method :flatten, :preserve
93
+
94
+ # Takes an Enumerable object and a block
95
+ # and iterates over the object,
96
+ # yielding each element to a Haml block
97
+ # and putting the result into <tt><li></tt> elements.
98
+ # This creates a list of the results of the block.
99
+ # For example:
100
+ #
101
+ # = list_of([['hello'], ['yall']]) do |i|
102
+ # = i[0]
103
+ #
104
+ # Produces:
105
+ #
106
+ # <li>hello</li>
107
+ # <li>yall</li>
108
+ #
109
+ # And
110
+ #
111
+ # = list_of({:title => 'All the stuff', :description => 'A book about all the stuff.'}) do |key, val|
112
+ # %h3= key.humanize
113
+ # %p= val
114
+ #
115
+ # Produces:
116
+ #
117
+ # <li>
118
+ # <h3>Title</h3>
119
+ # <p>All the stuff</p>
120
+ # </li>
121
+ # <li>
122
+ # <h3>Description</h3>
123
+ # <p>A book about all the stuff.</p>
124
+ # </li>
125
+ #
126
+ def list_of(array, &block) # :yields: item
127
+ to_return = array.collect do |i|
128
+ result = capture_haml(i, &block)
129
+
130
+ if result.count("\n") > 1
131
+ result.gsub!("\n", "\n ")
132
+ result = "\n #{result.strip}\n"
133
+ else
134
+ result.strip!
135
+ end
136
+
137
+ "<li>#{result}</li>"
138
+ end
139
+ to_return.join("\n")
140
+ end
141
+
142
+ # Returns a hash containing default assignments for the xmlns and xml:lang
143
+ # attributes of the <tt>html</tt> HTML element.
144
+ # It also takes an optional argument for the value of xml:lang and lang,
145
+ # which defaults to 'en-US'.
146
+ # For example,
147
+ #
148
+ # %html{html_attrs}
149
+ #
150
+ # becomes
151
+ #
152
+ # <html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en-US' lang='en-US'>
153
+ #
154
+ def html_attrs(lang = 'en-US')
155
+ {:xmlns => "http://www.w3.org/1999/xhtml", 'xml:lang' => lang, :lang => lang}
156
+ end
157
+
158
+ # Increments the number of tabs the buffer automatically adds
159
+ # to the lines of the template.
160
+ # For example:
161
+ #
162
+ # %h1 foo
163
+ # - tab_up
164
+ # %p bar
165
+ # - tab_down
166
+ # %strong baz
167
+ #
168
+ # Produces:
169
+ #
170
+ # <h1>foo</h1>
171
+ # <p>bar</p>
172
+ # <strong>baz</strong>
173
+ #
174
+ def tab_up(i = 1)
175
+ haml_buffer.tabulation += i
176
+ end
177
+
178
+ # Decrements the number of tabs the buffer automatically adds
179
+ # to the lines of the template.
180
+ #
181
+ # See also tab_up.
182
+ def tab_down(i = 1)
183
+ haml_buffer.tabulation -= i
184
+ end
185
+
186
+ # Surrounds the given block of Haml code with the given characters,
187
+ # with no whitespace in between.
188
+ # For example:
189
+ #
190
+ # = surround '(', ')' do
191
+ # %a{:href => "food"} chicken
192
+ #
193
+ # Produces:
194
+ #
195
+ # (<a href='food'>chicken</a>)
196
+ #
197
+ # and
198
+ #
199
+ # = surround '*' do
200
+ # %strong angry
201
+ #
202
+ # Produces:
203
+ #
204
+ # *<strong>angry</strong>*
205
+ #
206
+ def surround(front, back = nil, &block)
207
+ back ||= front
208
+ output = capture_haml(&block)
209
+
210
+ "#{front}#{output.chomp}#{back}\n"
211
+ end
212
+
213
+ # Prepends the given character to the beginning of the Haml block,
214
+ # with no whitespace between.
215
+ # For example:
216
+ #
217
+ # = precede '*' do
218
+ # %span.small Not really
219
+ #
220
+ # Produces:
221
+ #
222
+ # *<span class='small'>Not really</span>
223
+ #
224
+ def precede(char, &block)
225
+ "#{char}#{capture_haml(&block).chomp}\n"
226
+ end
227
+
228
+ # Appends the given character to the end of the Haml block,
229
+ # with no whitespace between.
230
+ # For example:
231
+ #
232
+ # click
233
+ # = succeed '.' do
234
+ # %a{:href=>"thing"} here
235
+ #
236
+ # Produces:
237
+ #
238
+ # click
239
+ # <a href='thing'>here</a>.
240
+ #
241
+ def succeed(char, &block)
242
+ "#{capture_haml(&block).chomp}#{char}\n"
243
+ end
244
+
245
+ # Captures the result of the given block of Haml code,
246
+ # gets rid of the excess indentation,
247
+ # and returns it as a string.
248
+ # For example, after the following,
249
+ #
250
+ # .foo
251
+ # - foo = capture_haml(13) do |a|
252
+ # %p= a
253
+ #
254
+ # the local variable <tt>foo</tt> would be assigned to "<p>13</p>\n".
255
+ #
256
+ def capture_haml(*args, &block)
257
+ buffer = eval('_hamlout', block.binding) rescue haml_buffer
258
+ with_haml_buffer(buffer) do
259
+ position = haml_buffer.buffer.length
260
+
261
+ block.call(*args)
262
+
263
+ captured = haml_buffer.buffer.slice!(position..-1).split(/^/)
264
+
265
+ min_tabs = nil
266
+ captured.each do |line|
267
+ tabs = line.index(/[^ ]/) || line.length
268
+ min_tabs ||= tabs
269
+ min_tabs = min_tabs > tabs ? tabs : min_tabs
270
+ end
271
+
272
+ captured.map do |line|
273
+ line[min_tabs..-1]
274
+ end.join
275
+ end
276
+ end
277
+
278
+ def puts(*args) # :nodoc:
279
+ warn <<END
280
+ DEPRECATION WARNING:
281
+ The Haml #puts helper is deprecated and will be removed in version 2.4.
282
+ Use the #haml_concat helper instead.
283
+ END
284
+ haml_concat *args
285
+ end
286
+
287
+ # Outputs text directly to the Haml buffer, with the proper tabulation
288
+ def haml_concat(text = "")
289
+ haml_buffer.buffer << haml_indent << text.to_s << "\n"
290
+ nil
291
+ end
292
+
293
+ # Returns the string that should be used to indent the current line
294
+ def haml_indent
295
+ ' ' * haml_buffer.tabulation
296
+ end
297
+
298
+ #
299
+ # call-seq:
300
+ # haml_tag(name, *flags, attributes = {}) {...}
301
+ # haml_tag(name, text, *flags, attributes = {}) {...}
302
+ #
303
+ # Creates an HTML tag with the given name and optionally text and attributes.
304
+ # Can take a block that will be executed
305
+ # between when the opening and closing tags are output.
306
+ # If the block is a Haml block or outputs text using haml_concat,
307
+ # the text will be properly indented.
308
+ #
309
+ # <tt>flags</tt> is a list of symbol flags
310
+ # like those that can be put at the end of a Haml tag
311
+ # (<tt>:/</tt>, <tt>:<</tt>, and <tt>:></tt>).
312
+ # Currently, only <tt>:/</tt> and <tt>:<</tt> are supported.
313
+ #
314
+ # For example,
315
+ #
316
+ # haml_tag :table do
317
+ # haml_tag :tr do
318
+ # haml_tag :td, {:class => 'cell'} do
319
+ # haml_tag :strong, "strong!"
320
+ # haml_concat "data"
321
+ # end
322
+ # haml_tag :td do
323
+ # haml_concat "more_data"
324
+ # end
325
+ # end
326
+ # end
327
+ #
328
+ # outputs
329
+ #
330
+ # <table>
331
+ # <tr>
332
+ # <td class='cell'>
333
+ # <strong>
334
+ # strong!
335
+ # </strong>
336
+ # data
337
+ # </td>
338
+ # <td>
339
+ # more_data
340
+ # </td>
341
+ # </tr>
342
+ # </table>
343
+ #
344
+ def haml_tag(name, *rest, &block)
345
+ name = name.to_s
346
+ text = rest.shift.to_s unless [Symbol, Hash, NilClass].any? {|t| rest.first.is_a? t}
347
+ flags = []
348
+ flags << rest.shift while rest.first.is_a? Symbol
349
+ attributes = Haml::Precompiler.build_attributes(haml_buffer.html?,
350
+ haml_buffer.options[:attr_wrapper],
351
+ rest.shift || {})
352
+
353
+ if text.nil? && block.nil? && (haml_buffer.options[:autoclose].include?(name) || flags.include?(:/))
354
+ haml_concat "<#{name}#{attributes} />"
355
+ return nil
356
+ end
357
+
358
+ if flags.include?(:/)
359
+ raise Error.new("Self-closing tags can't have content.") if text
360
+ raise Error.new("Illegal nesting: nesting within a self-closing tag is illegal.") if block
361
+ end
362
+
363
+ tag = "<#{name}#{attributes}>"
364
+ if block.nil?
365
+ tag << text.to_s << "</#{name}>"
366
+ haml_concat tag
367
+ return
368
+ end
369
+
370
+ if text
371
+ raise Error.new("Illegal nesting: content can't be both given to haml_tag :#{name} and nested within it.")
372
+ end
373
+
374
+ if flags.include?(:<)
375
+ tag << capture_haml(&block).strip << "</#{name}>"
376
+ haml_concat tag
377
+ return
378
+ end
379
+
380
+ haml_concat tag
381
+ tab_up
382
+ block.call
383
+ tab_down
384
+ haml_concat "</#{name}>"
385
+ <<MESSAGE
386
+ <h1><code>haml_tag</code> outputs directly to the Haml template.
387
+ Disregard its return value and use the <code>-</code> operator.</h1>
388
+ MESSAGE
389
+ end
390
+
391
+ # Characters that need to be escaped to HTML entities from user input
392
+ HTML_ESCAPE = { '&'=>'&amp;', '<'=>'&lt;', '>'=>'&gt;', '"'=>'&quot;', "'"=>'&#039;', }
393
+
394
+ # Returns a copy of <tt>text</tt> with ampersands, angle brackets and quotes
395
+ # escaped into HTML entities.
396
+ def html_escape(text)
397
+ text.to_s.gsub(/[\"><&]/) { |s| HTML_ESCAPE[s] }
398
+ end
399
+
400
+ # Escapes HTML entities in <tt>text</tt>, but without escaping an ampersand
401
+ # that is already part of an escaped entity.
402
+ def escape_once(text)
403
+ text.to_s.gsub(/[\"><]|&(?!([a-zA-Z]+|(#\d+));)/) { |s| HTML_ESCAPE[s] }
404
+ end
405
+
406
+ # Returns whether or not the current template is a Haml template.
407
+ #
408
+ # This function, unlike other Haml::Helpers functions,
409
+ # also works in other ActionView templates,
410
+ # where it will always return false.
411
+ def is_haml?
412
+ !@haml_buffer.nil? && @haml_buffer.active?
413
+ end
414
+
415
+ # Returns whether or not +block+ is defined directly in a Haml template.
416
+ def block_is_haml?(block)
417
+ eval('_hamlout', block.binding)
418
+ true
419
+ rescue
420
+ false
421
+ end
422
+
423
+ private
424
+
425
+ # call-seq:
426
+ # with_haml_buffer(buffer) {...}
427
+ #
428
+ # Runs the block with the given buffer as the currently active buffer.
429
+ def with_haml_buffer(buffer)
430
+ @haml_buffer, old_buffer = buffer, @haml_buffer
431
+ old_buffer.active, was_active = false, old_buffer.active? if old_buffer
432
+ @haml_buffer.active = true
433
+ yield
434
+ ensure
435
+ @haml_buffer.active = false
436
+ old_buffer.active = was_active if old_buffer
437
+ @haml_buffer = old_buffer
438
+ end
439
+
440
+ # Gets a reference to the current Haml::Buffer object.
441
+ def haml_buffer
442
+ @haml_buffer
443
+ end
444
+
445
+ # Gives a proc the same local "_hamlout" and "_erbout" variables
446
+ # that the current template has.
447
+ def haml_bind_proc(&proc)
448
+ _hamlout = haml_buffer
449
+ _erbout = _hamlout.buffer
450
+ proc { |*args| proc.call(*args) }
451
+ end
452
+
453
+ include ActionViewExtensions if self.const_defined? "ActionViewExtensions"
454
+ end
455
+ end
456
+
457
+ class Object
458
+ # Haml overrides various ActionView helpers,
459
+ # which call an #is_haml? method
460
+ # to determine whether or not the current context object
461
+ # is a proper Haml context.
462
+ # Because ActionView helpers may be included in non-ActionView::Base classes,
463
+ # it's a good idea to define is_haml? for all objects.
464
+ def is_haml?
465
+ false
466
+ end
467
+ end
468
+