haml-edge 2.3.100 → 2.3.148

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 (54) hide show
  1. data/.yardopts +3 -0
  2. data/EDGE_GEM_VERSION +1 -1
  3. data/Rakefile +14 -2
  4. data/VERSION +1 -1
  5. data/extra/haml-mode.el +97 -11
  6. data/extra/sass-mode.el +2 -2
  7. data/lib/haml/engine.rb +2 -2
  8. data/lib/haml/exec.rb +121 -25
  9. data/lib/haml/filters.rb +1 -1
  10. data/lib/haml/helpers/action_view_mods.rb +2 -1
  11. data/lib/haml/helpers/xss_mods.rb +43 -13
  12. data/lib/haml/helpers.rb +38 -17
  13. data/lib/haml/html.rb +13 -4
  14. data/lib/haml/precompiler.rb +24 -3
  15. data/lib/haml/template/plugin.rb +7 -3
  16. data/lib/haml/template.rb +3 -3
  17. data/lib/haml/util.rb +40 -0
  18. data/lib/sass/callbacks.rb +50 -0
  19. data/lib/sass/css.rb +1 -1
  20. data/lib/sass/engine.rb +45 -5
  21. data/lib/sass/error.rb +6 -3
  22. data/lib/sass/files.rb +8 -1
  23. data/lib/sass/plugin/rails.rb +2 -2
  24. data/lib/sass/plugin.rb +260 -28
  25. data/lib/sass/script/color.rb +216 -30
  26. data/lib/sass/script/functions.rb +356 -74
  27. data/lib/sass/script/lexer.rb +7 -4
  28. data/lib/sass/script/number.rb +2 -0
  29. data/lib/sass/script/parser.rb +1 -1
  30. data/lib/sass/script.rb +3 -0
  31. data/lib/sass/tree/node.rb +1 -1
  32. data/lib/sass/tree/root_node.rb +6 -0
  33. data/lib/sass/tree/rule_node.rb +1 -0
  34. data/lib/sass.rb +4 -0
  35. data/test/haml/engine_test.rb +25 -0
  36. data/test/haml/helper_test.rb +81 -1
  37. data/test/haml/html2haml_test.rb +13 -0
  38. data/test/haml/spec/README.md +97 -0
  39. data/test/haml/spec/lua_haml_spec.lua +30 -0
  40. data/test/haml/spec/ruby_haml_test.rb +19 -0
  41. data/test/haml/spec/tests.json +534 -0
  42. data/test/haml/spec_test.rb +0 -0
  43. data/test/haml/template_test.rb +18 -4
  44. data/test/haml/util_test.rb +0 -0
  45. data/test/sass/callbacks_test.rb +61 -0
  46. data/test/sass/css2sass_test.rb +1 -0
  47. data/test/sass/engine_test.rb +70 -14
  48. data/test/sass/functions_test.rb +223 -3
  49. data/test/sass/plugin_test.rb +193 -25
  50. data/test/sass/results/options.css +1 -0
  51. data/test/sass/script_test.rb +5 -5
  52. data/test/sass/templates/options.sass +2 -0
  53. data/test/test_helper.rb +12 -5
  54. metadata +19 -9
data/.yardopts CHANGED
@@ -1,5 +1,8 @@
1
1
  --readme README.md
2
2
  --markup markdown
3
3
  --markup-provider maruku
4
+ --default-return ""
5
+ --hide-void-return
4
6
  --protected
7
+ --no-private
5
8
  --no-highlight
data/EDGE_GEM_VERSION CHANGED
@@ -1 +1 @@
1
- 2.3.100
1
+ 2.3.148
data/Rakefile CHANGED
@@ -57,6 +57,7 @@ task :revision_file do
57
57
  end
58
58
  end
59
59
  Rake::Task[:package].prerequisites.insert(0, :revision_file)
60
+ Rake::Task[:package].prerequisites.insert(0, :submodules)
60
61
 
61
62
  # We also need to get rid of this file after packaging.
62
63
  at_exit { File.delete('REVISION') rescue nil }
@@ -72,7 +73,6 @@ desc "Release a new Haml package to Rubyforge."
72
73
  task :release => [:check_release, :release_elpa, :package] do
73
74
  name = File.read("VERSION_NAME").strip
74
75
  version = File.read("VERSION").strip
75
- sh %{rubyforge login}
76
76
  sh %{rubyforge add_release haml haml "#{name} (v#{version})" pkg/haml-#{version}.gem}
77
77
  sh %{rubyforge add_file haml haml "#{name} (v#{version})" pkg/haml-#{version}.tar.gz}
78
78
  sh %{rubyforge add_file haml haml "#{name} (v#{version})" pkg/haml-#{version}.tar.bz2}
@@ -167,6 +167,18 @@ def mode_unchanged?(mode, version)
167
167
  return false
168
168
  end
169
169
 
170
+ task :submodules do
171
+ if File.exist?(File.dirname(__FILE__) + "/.git")
172
+ sh %{git submodule sync}
173
+ sh %{git submodule update --init}
174
+ elsif !File.exist?(File.dirname(__FILE__) + "/vendor/fssm/lib")
175
+ warn <<WARN
176
+ WARNING: vendor/fssm doesn't exist, and this isn't a git repository so
177
+ I can't get it automatically!
178
+ WARN
179
+ end
180
+ end
181
+
170
182
  task :release_edge do
171
183
  ensure_git_cleanup do
172
184
  puts "#{'=' * 50} Running rake release_edge"
@@ -239,7 +251,7 @@ begin
239
251
  list.exclude('lib/haml/template/*.rb')
240
252
  list.exclude('lib/haml/helpers/action_view_mods.rb')
241
253
  end.to_a
242
- t.options << '--use-cache' if Rake.application.top_level_tasks.include?('redoc')
254
+ t.options << '--incremental' if Rake.application.top_level_tasks.include?('redoc')
243
255
  t.options += FileList.new('yard/*.rb').to_a.map {|f| ['-e', f]}.flatten
244
256
  files = FileList.new('doc-src/*').to_a.sort_by {|s| s.size} + %w[MIT-LICENSE VERSION]
245
257
  t.options << '--files' << files.join(',')
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.3.100
1
+ 2.3.148
data/extra/haml-mode.el CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  ;; Author: Nathan Weizenbaum
6
6
  ;; URL: http://github.com/nex3/haml/tree/master
7
- ;; Version: 2.2.7
7
+ ;; Version: 2.2.18
8
8
  ;; Created: 2007-03-08
9
9
  ;; By: Nathan Weizenbaum
10
10
  ;; Keywords: markup, language, html
@@ -25,6 +25,13 @@
25
25
  (eval-when-compile (require 'cl))
26
26
  (require 'ruby-mode)
27
27
 
28
+ ;; Additional (optional) libraries for fontification
29
+ (require 'css-mode nil nil)
30
+ (require 'textile-mode nil nil)
31
+ (require 'markdown-mode nil nil)
32
+ (require 'javascript-mode "javascript" nil)
33
+
34
+
28
35
  ;; User definable variables
29
36
 
30
37
  (defgroup haml nil
@@ -92,22 +99,33 @@ The line containing RE is matched, as well as all lines indented beneath it."
92
99
  (defconst haml-font-lock-keywords
93
100
  `((,(haml-nested-regexp "\\(?:-#\\|/\\).*") 0 font-lock-comment-face)
94
101
  (,(haml-nested-regexp ":\\w+") 0 font-lock-string-face)
95
- (haml-highlight-interpolation 1 font-lock-variable-name-face prepend)
96
- (haml-highlight-ruby-tag 1 font-lock-preprocessor-face)
97
- (haml-highlight-ruby-script 1 font-lock-preprocessor-face)
98
- ("^ *\\(\t\\)" 1 'haml-tab-face)
99
- ("^!!!.*" 0 font-lock-constant-face)
100
- ("| *$" 0 font-lock-string-face)))
102
+ (haml-highlight-ruby-filter-block 1 font-lock-preprocessor-face)
103
+ (haml-highlight-css-filter-block 1 font-lock-preprocessor-face)
104
+ (haml-highlight-textile-filter-block 1 font-lock-preprocessor-face)
105
+ (haml-highlight-markdown-filter-block 1 font-lock-preprocessor-face)
106
+ (haml-highlight-js-filter-block 1 font-lock-preprocessor-face)
107
+ (haml-highlight-interpolation 1 font-lock-variable-name-face prepend)
108
+ (haml-highlight-ruby-tag 1 font-lock-preprocessor-face)
109
+ (haml-highlight-ruby-script 1 font-lock-preprocessor-face)
110
+ ("^ *\\(\t\\)" 1 'haml-tab-face)
111
+ ("^!!!.*" 0 font-lock-constant-face)
112
+ ("| *$" 0 font-lock-string-face)))
101
113
 
102
114
  (defconst haml-filter-re "^ *:\\w+")
103
115
  (defconst haml-comment-re "^ *\\(?:-\\#\\|/\\)")
104
116
 
105
- (defun haml-fontify-region-as-ruby (beg end)
106
- "Use Ruby's font-lock variables to fontify the region between BEG and END."
117
+ (defun haml-fontify-region (beg end keywords syntax-table syntactic-keywords)
118
+ "Fontify a region between BEG and END using another mode's fontification.
119
+
120
+ KEYWORDS, SYNTAX-TABLE, and SYNTACTIC-KEYWORDS are the values of that mode's
121
+ `font-lock-keywords', `font-lock-syntax-table',
122
+ and `font-lock-syntactic-keywords', respectively."
107
123
  (save-excursion
108
124
  (save-match-data
109
- (let ((font-lock-keywords ruby-font-lock-keywords)
110
- (font-lock-syntactic-keywords ruby-font-lock-syntactic-keywords)
125
+ (let ((font-lock-keywords keywords)
126
+ (font-lock-syntax-table syntax-table)
127
+ (font-lock-syntactic-keywords syntactic-keywords)
128
+ (font-lock-multiline 'undecided)
111
129
  font-lock-keywords-only
112
130
  font-lock-extend-region-functions
113
131
  font-lock-keywords-case-fold-search)
@@ -115,6 +133,74 @@ The line containing RE is matched, as well as all lines indented beneath it."
115
133
  ;; so we have to move the beginning back one char
116
134
  (font-lock-fontify-region (- beg 1) end)))))
117
135
 
136
+ (defun haml-fontify-region-as-ruby (beg end)
137
+ "Use Ruby's font-lock variables to fontify the region between BEG and END."
138
+ (haml-fontify-region beg end ruby-font-lock-keywords nil
139
+ ruby-font-lock-syntactic-keywords))
140
+
141
+ (defun haml-handle-filter (filter-name limit fn)
142
+ "If a FILTER-NAME filter is found within LIMIT, run FN on that filter.
143
+
144
+ FN is passed a pair of points representing the beginning and end
145
+ of the filtered text."
146
+ (when (re-search-forward (haml-nested-regexp (concat ":" filter-name)) limit t)
147
+ (funcall fn (+ 2 (match-beginning 2)) (match-end 2))))
148
+
149
+ (defun haml-fontify-filter-region (filter-name limit &rest fontify-region-args)
150
+ "If a FILTER-NAME filter is found within LIMIT, fontify it.
151
+
152
+ The fontification is done by passing FONTIFY-REGION-ARGS to
153
+ `haml-fontify-region'."
154
+ (haml-handle-filter filter-name limit
155
+ (lambda (beg end)
156
+ (apply 'haml-fontify-region
157
+ (append (list beg end)
158
+ fontify-region-args)))))
159
+
160
+ (defun haml-highlight-ruby-filter-block (limit)
161
+ "If a :ruby filter is found within LIMIT, highlight it."
162
+ (haml-handle-filter "ruby" limit 'haml-fontify-region-as-ruby))
163
+
164
+ (defun haml-highlight-css-filter-block (limit)
165
+ "If a :css filter is found within LIMIT, highlight it.
166
+
167
+ This requires that `css-mode' is available.
168
+ `css-mode' is included with Emacs 23."
169
+ (if (boundp 'css-font-lock-keywords)
170
+ (haml-fontify-filter-region "css" limit css-font-lock-keywords nil nil)))
171
+
172
+ (defun haml-highlight-js-filter-block (limit)
173
+ "If a :javascript filter is found within LIMIT, highlight it.
174
+
175
+ This requires that Karl Landström's \"javascript.el\" be available."
176
+ (if (boundp 'js-font-lock-keywords-3)
177
+ (haml-fontify-filter-region "javascript"
178
+ limit
179
+ js-font-lock-keywords-3
180
+ javascript-mode-syntax-table
181
+ nil)))
182
+
183
+ (defun haml-highlight-textile-filter-block (limit)
184
+ "If a :textile filter is found within LIMIT, highlight it.
185
+
186
+ This requires that `textile-mode' be available.
187
+
188
+ Note that the results are not perfect, since `textile-mode' expects
189
+ certain constructs such as \"h1.\" to be at the beginning of a line,
190
+ and indented Haml filters always have leading whitespace."
191
+ (if (boundp 'textile-font-lock-keywords)
192
+ (haml-fontify-filter-region "textile" limit textile-font-lock-keywords nil nil)))
193
+
194
+ (defun haml-highlight-markdown-filter-block (limit)
195
+ "If a :markdown filter is found within LIMIT, highlight it.
196
+
197
+ This requires that `markdown-mode' be available."
198
+ (if (boundp 'markdown-mode-font-lock-keywords)
199
+ (haml-fontify-filter-region "markdown" limit
200
+ markdown-mode-font-lock-keywords
201
+ markdown-mode-syntax-table
202
+ nil)))
203
+
118
204
  (defun haml-highlight-ruby-script (limit)
119
205
  "Highlight a Ruby script expression (-, =, or ~).
120
206
  LIMIT works as it does in `re-search-forward'."
data/extra/sass-mode.el CHANGED
@@ -4,11 +4,11 @@
4
4
 
5
5
  ;; Author: Nathan Weizenbaum
6
6
  ;; URL: http://github.com/nex3/haml/tree/master
7
- ;; Version: 2.2.7
7
+ ;; Version: 2.2.18
8
8
  ;; Created: 2007-03-15
9
9
  ;; By: Nathan Weizenbaum
10
10
  ;; Keywords: markup, language, css
11
- ;; Package-Requires: ((haml-mode "2.2.7"))
11
+ ;; Package-Requires: ((haml-mode "2.2.18"))
12
12
 
13
13
  ;;; Commentary:
14
14
 
data/lib/haml/engine.rb CHANGED
@@ -88,7 +88,7 @@ module Haml
88
88
  unless ruby1_8?
89
89
  @options[:encoding] = Encoding.default_internal || "utf-8"
90
90
  end
91
- @options.merge! options
91
+ @options.merge! options.reject {|k, v| v.nil?}
92
92
  @index = 0
93
93
 
94
94
  unless [:xhtml, :html4, :html5].include?(@options[:format])
@@ -138,7 +138,7 @@ module Haml
138
138
  # Haml::Engine.new("%p= upcase").render(s) #=> "<p>FOOBAR</p>"
139
139
  #
140
140
  # # s now extends Haml::Helpers
141
- # s.responds_to?(:html_attrs) #=> true
141
+ # s.respond_to?(:html_attrs) #=> true
142
142
  #
143
143
  # `locals` is a hash of local variables to make available to the template.
144
144
  # For example:
data/lib/haml/exec.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'optparse'
2
2
  require 'fileutils'
3
+ require 'rbconfig'
3
4
 
4
5
  module Haml
5
6
  # This module handles the various Haml executables (`haml`, `sass`, `css2sass`, etc).
@@ -67,6 +68,12 @@ module Haml
67
68
  @options[:trace] = true
68
69
  end
69
70
 
71
+ if RbConfig::CONFIG['host_os'] =~ /mswin|windows/i
72
+ opts.on('--unix-newlines', 'Use Unix-style newlines in written files.') do
73
+ @options[:unix_newlines] = true
74
+ end
75
+ end
76
+
70
77
  opts.on_tail("-?", "-h", "--help", "Show this message") do
71
78
  puts opts
72
79
  exit
@@ -105,6 +112,7 @@ module Haml
105
112
 
106
113
  def open_file(filename, flag = 'r')
107
114
  return if filename.nil?
115
+ flag = 'wb' if @options[:unix_newlines] && flag == 'w'
108
116
  File.open(filename, flag)
109
117
  end
110
118
  end
@@ -210,13 +218,23 @@ END
210
218
  def set_opts(opts)
211
219
  super
212
220
 
221
+ opts.on('--watch', 'Watch files or directories for changes.',
222
+ 'The location of the generated CSS can be set using a colon:',
223
+ ' sass --watch input.sass:output.css',
224
+ ' sass --watch input-dir:output-dir') do
225
+ @options[:watch] = true
226
+ end
227
+ opts.on('--update', 'Compile files or directories to CSS.',
228
+ 'Locations are set like --watch.') do
229
+ @options[:update] = true
230
+ end
213
231
  opts.on('-t', '--style NAME',
214
232
  'Output style. Can be nested (default), compact, compressed, or expanded.') do |name|
215
233
  @options[:for_engine][:style] = name.to_sym
216
234
  end
217
- opts.on('-l', '--line-comments',
218
- 'Line Comments. Emit comments in the generated CSS indicating the corresponding sass line.') do
219
- @options[:for_engine][:line_comments] = true
235
+ opts.on('-l', '--line-numbers', '--line-comments',
236
+ 'Emit comments in the generated CSS indicating the corresponding sass line.') do
237
+ @options[:for_engine][:line_numbers] = true
220
238
  end
221
239
  opts.on('-i', '--interactive',
222
240
  'Run an interactive SassScript shell.') do
@@ -225,8 +243,8 @@ END
225
243
  opts.on('-I', '--load-path PATH', 'Add a sass import path.') do |path|
226
244
  @options[:for_engine][:load_paths] << path
227
245
  end
228
- opts.on('--cache-location', 'The path to put cached Sass files. Defaults to .sass-cache.') do |loc|
229
- @options[:for_engine][:cache_location] = path
246
+ opts.on('--cache-location PATH', 'The path to put cached Sass files. Defaults to .sass-cache.') do |loc|
247
+ @options[:for_engine][:cache_location] = loc
230
248
  end
231
249
  opts.on('-C', '--no-cache', "Don't cache to sassc files.") do
232
250
  @options[:for_engine][:cache] = false
@@ -236,34 +254,112 @@ END
236
254
  # Processes the options set by the command-line arguments,
237
255
  # and runs the Sass compiler appropriately.
238
256
  def process_result
239
- if @options[:interactive]
240
- require 'sass'
241
- require 'sass/repl'
242
- ::Sass::Repl.new(@options).run
243
- return
257
+ if @args.first && @args.first.include?(':')
258
+ if @args.size == 1
259
+ @args = @args.first.split(':', 2)
260
+ else
261
+ @options[:update] = true
262
+ end
244
263
  end
245
264
 
265
+ return interactive if @options[:interactive]
266
+ return watch_or_update if @options[:watch] || @options[:update]
246
267
  super
247
- input = @options[:input]
248
- output = @options[:output]
249
268
 
250
- tree =
251
- if input.is_a?(File) && !@options[:check_syntax]
252
- ::Sass::Files.tree_for(input.path, @options[:for_engine])
269
+ begin
270
+ input = @options[:input]
271
+ output = @options[:output]
272
+
273
+ tree =
274
+ if input.is_a?(File) && !@options[:check_syntax]
275
+ ::Sass::Files.tree_for(input.path, @options[:for_engine])
276
+ else
277
+ # We don't need to do any special handling of @options[:check_syntax] here,
278
+ # because the Sass syntax checking happens alongside evaluation
279
+ # and evaluation doesn't actually evaluate any code anyway.
280
+ ::Sass::Engine.new(input.read(), @options[:for_engine]).to_tree
281
+ end
282
+
283
+ input.close() if input.is_a?(File)
284
+
285
+ output.write(tree.render)
286
+ output.close() if output.is_a? File
287
+ rescue ::Sass::SyntaxError => e
288
+ raise e if @options[:trace]
289
+ raise e.sass_backtrace_str("standard input")
290
+ end
291
+ end
292
+
293
+ private
294
+
295
+ def interactive
296
+ require 'sass'
297
+ require 'sass/repl'
298
+ ::Sass::Repl.new(@options).run
299
+ end
300
+
301
+ def watch_or_update
302
+ require 'sass'
303
+ require 'sass/plugin'
304
+ ::Sass::Plugin.options[:unix_newlines] = @options[:unix_newlines]
305
+
306
+ dirs, files = @args.map {|name| name.split(':', 2)}.
307
+ map {|from, to| [from, to || from.gsub(/\..*?$/, '.css')]}.
308
+ partition {|i, _| File.directory? i}
309
+ ::Sass::Plugin.options[:template_location] = dirs
310
+
311
+ ::Sass::Plugin.on_updating_stylesheet do |_, css|
312
+ if File.exists? css
313
+ puts_action :overwrite, :yellow, css
253
314
  else
254
- # We don't need to do any special handling of @options[:check_syntax] here,
255
- # because the Sass syntax checking happens alongside evaluation
256
- # and evaluation doesn't actually evaluate any code anyway.
257
- ::Sass::Engine.new(input.read(), @options[:for_engine]).to_tree
315
+ puts_action :create, :green, css
258
316
  end
317
+ end
259
318
 
260
- input.close() if input.is_a?(File)
319
+ ::Sass::Plugin.on_creating_directory {|dirname| puts_action :directory, :green, dirname}
320
+ ::Sass::Plugin.on_deleting_css {|filename| puts_action :delete, :yellow, filename}
321
+ ::Sass::Plugin.on_compilation_error do |error, _, _|
322
+ unless error.is_a?(::Sass::SyntaxError)
323
+ if error.is_a?(Errno::ENOENT) && error.message =~ /^No such file or directory - (.*)$/ && $1 == @args[1]
324
+ flag = @options[:update] ? "--update" : "--watch"
325
+ error.message << "\n Did you mean: sass #{flag} #{@args[0]}:#{@args[1]}"
326
+ end
261
327
 
262
- output.write(tree.render)
263
- output.close() if output.is_a? File
264
- rescue ::Sass::SyntaxError => e
265
- raise e if @options[:trace]
266
- raise e.sass_backtrace_str("standard input")
328
+ raise error
329
+ end
330
+
331
+ puts_action :error, :red, "#{error.sass_filename} (Line #{error.sass_line}: #{error.message})"
332
+ end
333
+
334
+ if @options[:update]
335
+ ::Sass::Plugin.update_stylesheets(files)
336
+ return
337
+ end
338
+
339
+ puts ">>> Sass is watching for changes. Press Ctrl-C to stop."
340
+
341
+ ::Sass::Plugin.on_template_modified {|template| puts ">>> Change detected to: #{template}"}
342
+ ::Sass::Plugin.on_template_created {|template| puts ">>> New template detected: #{template}"}
343
+ ::Sass::Plugin.on_template_deleted {|template| puts ">>> Deleted template detected: #{template}"}
344
+
345
+ ::Sass::Plugin.watch(files)
346
+ end
347
+
348
+ # @private
349
+ COLORS = { :red => 31, :green => 32, :yellow => 33 }
350
+
351
+ def puts_action(name, color, arg)
352
+ printf color(color, "%11s %s\n"), name, arg
353
+ end
354
+
355
+ def color(color, str)
356
+ raise "[BUG] Unrecognized color #{color}" unless COLORS[color]
357
+
358
+ # Almost any real Unix terminal will support color,
359
+ # so we just filter for Windows terms (which don't set TERM)
360
+ # and not-real terminals, which aren't ttys.
361
+ return str if ENV["TERM"].empty? || !STDOUT.tty?
362
+ return "\e[#{COLORS[color]}m#{str}\e[0m"
267
363
  end
268
364
  end
269
365
 
data/lib/haml/filters.rb CHANGED
@@ -299,7 +299,7 @@ END
299
299
  def compile(precompiler, text)
300
300
  return if precompiler.options[:suppress_eval]
301
301
  src = ::ERB.new(text).src.sub(/^#coding:.*?\n/, '').
302
- sub(/^_erbout = '';/, "").gsub("\n", ';')
302
+ sub(/^_erbout = '';/, "")
303
303
  precompiler.send(:push_silent, src)
304
304
  end
305
305
  end
@@ -26,7 +26,8 @@ module ActionView
26
26
 
27
27
  def set_output_buffer_with_haml(new)
28
28
  if is_haml?
29
- new = String.new(new) if Haml::Util.rails_xss_safe? && new.is_a?(ActionView::SafeBuffer)
29
+ new = String.new(new) if Haml::Util.rails_xss_safe? &&
30
+ new.is_a?(Haml::Util.rails_safe_buffer_class)
30
31
  haml_buffer.buffer = new
31
32
  else
32
33
  set_output_buffer_without_haml new
@@ -19,45 +19,46 @@ module Haml
19
19
  def html_escape_with_haml_xss(text)
20
20
  str = text.to_s
21
21
  return text if str.html_safe?
22
- html_escape_without_haml_xss(str).html_safe!
22
+ Haml::Util.html_safe(html_escape_without_haml_xss(str))
23
23
  end
24
24
 
25
25
  # Output is always HTML safe
26
26
  def find_and_preserve_with_haml_xss(*args, &block)
27
- find_and_preserve_without_haml_xss(*args, &block).html_safe!
27
+ Haml::Util.html_safe(find_and_preserve_without_haml_xss(*args, &block))
28
28
  end
29
29
 
30
30
  # Output is always HTML safe
31
31
  def preserve_with_haml_xss(*args, &block)
32
- preserve_without_haml_xss(*args, &block).html_safe!
32
+ Haml::Util.html_safe(preserve_without_haml_xss(*args, &block))
33
33
  end
34
34
 
35
35
  # Output is always HTML safe
36
36
  def list_of_with_haml_xss(*args, &block)
37
- list_of_without_haml_xss(*args, &block).html_safe!
37
+ Haml::Util.html_safe(list_of_without_haml_xss(*args, &block))
38
38
  end
39
39
 
40
40
  # Input is escaped, output is always HTML safe
41
41
  def surround_with_haml_xss(front, back = front, &block)
42
- surround_without_haml_xss(
43
- haml_xss_html_escape(front),
44
- haml_xss_html_escape(back),
45
- &block).html_safe!
42
+ Haml::Util.html_safe(
43
+ surround_without_haml_xss(
44
+ haml_xss_html_escape(front),
45
+ haml_xss_html_escape(back),
46
+ &block))
46
47
  end
47
48
 
48
49
  # Input is escaped, output is always HTML safe
49
50
  def precede_with_haml_xss(str, &block)
50
- precede_without_haml_xss(haml_xss_html_escape(str), &block).html_safe!
51
+ Haml::Util.html_safe(precede_without_haml_xss(haml_xss_html_escape(str), &block))
51
52
  end
52
53
 
53
54
  # Input is escaped, output is always HTML safe
54
55
  def succeed_with_haml_xss(str, &block)
55
- succeed_without_haml_xss(haml_xss_html_escape(str), &block).html_safe!
56
+ Haml::Util.html_safe(succeed_without_haml_xss(haml_xss_html_escape(str), &block))
56
57
  end
57
58
 
58
59
  # Output is always HTML safe
59
60
  def capture_haml_with_haml_xss(*args, &block)
60
- capture_haml_without_haml_xss(*args, &block).html_safe!
61
+ Haml::Util.html_safe(capture_haml_without_haml_xss(*args, &block))
61
62
  end
62
63
 
63
64
  # Input is escaped
@@ -67,7 +68,7 @@ module Haml
67
68
 
68
69
  # Output is always HTML safe
69
70
  def haml_indent_with_haml_xss
70
- haml_indent_without_haml_xss.html_safe!
71
+ Haml::Util.html_safe(haml_indent_without_haml_xss)
71
72
  end
72
73
 
73
74
  # Input is escaped, haml_concat'ed output is always HTML safe
@@ -79,7 +80,7 @@ module Haml
79
80
 
80
81
  # Output is always HTML safe
81
82
  def escape_once_with_haml_xss(*args)
82
- escape_once_without_haml_xss(*args).html_safe!
83
+ Haml::Util.html_safe(escape_once_without_haml_xss(*args))
83
84
  end
84
85
 
85
86
  private
@@ -93,3 +94,32 @@ module Haml
93
94
  end
94
95
  end
95
96
  end
97
+
98
+ module ActionView
99
+ module Helpers
100
+ module TextHelper
101
+ def concat_with_haml(string)
102
+ if is_haml?
103
+ haml_buffer.buffer.concat(haml_xss_html_escape(string))
104
+ else
105
+ concat_without_haml(string)
106
+ end
107
+ end
108
+ alias_method :concat_without_haml, :concat
109
+ alias_method :concat, :concat_with_haml
110
+
111
+ # safe_concat was introduced in Rails 3.0
112
+ if Haml::Util.has?(:instance_method, self, :safe_concat)
113
+ def safe_concat_with_haml(string)
114
+ if is_haml?
115
+ haml_buffer.buffer.concat(string)
116
+ else
117
+ concat_without_haml(string)
118
+ end
119
+ end
120
+ alias_method :safe_concat_without_haml, :safe_concat
121
+ alias_method :safe_concat, :safe_concat_with_haml
122
+ end
123
+ end
124
+ end
125
+ end
data/lib/haml/helpers.rb CHANGED
@@ -338,22 +338,16 @@ MESSAGE
338
338
  haml_buffer.capture_position = nil
339
339
  end
340
340
 
341
- # @deprecated This will be removed in version 2.4.
342
- # @see #haml_concat
343
- def puts(*args)
344
- warn <<END
345
- DEPRECATION WARNING:
346
- The Haml #puts helper is deprecated and will be removed in version 2.4.
347
- Use the #haml_concat helper instead.
348
- END
349
- haml_concat(*args)
350
- end
351
-
352
341
  # Outputs text directly to the Haml buffer, with the proper indentation.
353
342
  #
354
343
  # @param text [#to_s] The text to output
355
344
  def haml_concat(text = "")
356
- haml_buffer.buffer << haml_indent << text.to_s << "\n"
345
+ unless haml_buffer.options[:ugly] || haml_indent == 0
346
+ haml_buffer.buffer << haml_indent <<
347
+ text.to_s.gsub("\n", "\n" + haml_indent) << "\n"
348
+ else
349
+ haml_buffer.buffer << text.to_s << "\n"
350
+ end
357
351
  ErrorReturn.new("haml_concat")
358
352
  end
359
353
 
@@ -367,6 +361,11 @@ END
367
361
  # If the block is a Haml block or outputs text using \{#haml\_concat},
368
362
  # the text will be properly indented.
369
363
  #
364
+ # `name` can be a string using the standard Haml class/id shorthand
365
+ # (e.g. "span#foo.bar", "#foo").
366
+ # Just like standard Haml tags, these class and id values
367
+ # will be merged with manually-specified attributes.
368
+ #
370
369
  # `flags` is a list of symbol flags
371
370
  # like those that can be put at the end of a Haml tag
372
371
  # (`:/`, `:<`, and `:>`).
@@ -381,7 +380,7 @@ END
381
380
  #
382
381
  # haml_tag :table do
383
382
  # haml_tag :tr do
384
- # haml_tag :td, {:class => 'cell'} do
383
+ # haml_tag 'td.cell' do
385
384
  # haml_tag :strong, "strong!"
386
385
  # haml_concat "data"
387
386
  # end
@@ -417,13 +416,14 @@ END
417
416
  def haml_tag(name, *rest, &block)
418
417
  ret = ErrorReturn.new("haml_tag")
419
418
 
420
- name = name.to_s
421
419
  text = rest.shift.to_s unless [Symbol, Hash, NilClass].any? {|t| rest.first.is_a? t}
422
420
  flags = []
423
421
  flags << rest.shift while rest.first.is_a? Symbol
422
+ name, attrs = merge_name_and_attributes(name.to_s, rest.shift || {})
423
+
424
424
  attributes = Haml::Precompiler.build_attributes(haml_buffer.html?,
425
425
  haml_buffer.options[:attr_wrapper],
426
- rest.shift || {})
426
+ attrs)
427
427
 
428
428
  if text.nil? && block.nil? && (haml_buffer.options[:autoclose].include?(name) || flags.include?(:/))
429
429
  haml_concat "<#{name}#{attributes} />"
@@ -437,8 +437,17 @@ END
437
437
 
438
438
  tag = "<#{name}#{attributes}>"
439
439
  if block.nil?
440
- tag << text.to_s << "</#{name}>"
441
- haml_concat tag
440
+ text = text.to_s
441
+ if text.include?("\n")
442
+ haml_concat tag
443
+ tab_up
444
+ haml_concat text
445
+ tab_down
446
+ haml_concat "</#{name}>"
447
+ else
448
+ tag << text << "</#{name}>"
449
+ haml_concat tag
450
+ end
442
451
  return ret
443
452
  end
444
453
 
@@ -462,6 +471,7 @@ END
462
471
  end
463
472
 
464
473
  # Characters that need to be escaped to HTML entities from user input
474
+ # @private
465
475
  HTML_ESCAPE = { '&'=>'&amp;', '<'=>'&lt;', '>'=>'&gt;', '"'=>'&quot;', "'"=>'&#039;', }
466
476
 
467
477
  # Returns a copy of `text` with ampersands, angle brackets and quotes
@@ -512,6 +522,17 @@ END
512
522
 
513
523
  private
514
524
 
525
+ # Parses the tag name used for \{#haml\_tag}
526
+ # and merges it with the Ruby attributes hash.
527
+ def merge_name_and_attributes(name, attributes_hash = {})
528
+ # skip merging if no ids or classes found in name
529
+ return name, attributes_hash unless name =~ /^(.+?)?([\.#].*)$/
530
+
531
+ return $1 || "div", Buffer.merge_attrs(
532
+ Precompiler.parse_class_and_id($2),
533
+ Haml::Util.map_keys(attributes_hash) {|key| key.to_s})
534
+ end
535
+
515
536
  # Runs a block of code with the given buffer as the currently active buffer.
516
537
  #
517
538
  # @param buffer [Haml::Buffer] The Haml buffer to use temporarily