haml-edge 2.3.100 → 2.3.148

Sign up to get free protection for your applications and to get access to all the features.
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