haml 2.0.0 → 2.0.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.

@@ -0,0 +1 @@
1
+ (release)
data/Rakefile CHANGED
@@ -19,7 +19,9 @@ require 'rake/testtask'
19
19
 
20
20
  Rake::TestTask.new do |t|
21
21
  t.libs << 'lib'
22
- t.pattern = 'test/**/*_test.rb'
22
+ test_files = FileList['test/**/*_test.rb']
23
+ test_files.exclude('test/rails/*')
24
+ t.test_files = test_files
23
25
  t.verbose = true
24
26
  end
25
27
  Rake::Task[:test].send(:add_comment, <<END)
@@ -53,13 +55,15 @@ end
53
55
  Rake::Task[:package].prerequisites.insert(0, :revision_file)
54
56
 
55
57
  # We also need to get rid of this file after packaging.
56
- Rake::Task[:package].enhance { File.delete('REVISION') if File.exists?('REVISION') }
58
+ at_exit { File.delete('REVISION') rescue nil }
57
59
 
60
+ desc "Install Haml as a gem."
58
61
  task :install => [:package] do
59
62
  sudo = RUBY_PLATFORM =~ /win32/ ? '' : 'sudo'
60
63
  sh %{#{sudo} gem install --no-ri pkg/haml-#{File.read('VERSION').strip}}
61
64
  end
62
65
 
66
+ desc "Release a new Haml package to Rubyforge. Requires the NAME and VERSION flags."
63
67
  task :release => [:package] do
64
68
  name, version = ENV['NAME'], ENV['VERSION']
65
69
  raise "Must supply NAME and VERSION for release task." unless name && version
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.0.0
1
+ 2.0.1
@@ -914,9 +914,16 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
914
914
  #
915
915
  # === Haml Options
916
916
  #
917
- # Options can be set by setting the hash <tt>Haml::Template.options</tt>
918
- # from <tt>environment.rb</tt> in Rails,
919
- # or by passing an options hash to Haml::Engine.
917
+ # Options can be set by setting the <tt>Haml::Template.options</tt> hash
918
+ # in <tt>environment.rb</tt> in Rails...
919
+ #
920
+ # Haml::Template.options[:output] = :html5
921
+ #
922
+ # ...or by setting the <tt>Merb::Config[:haml]</tt> hash in <tt>init.rb</tt> in Merb...
923
+ #
924
+ # Merb::Config[:haml][:output] = :html5
925
+ #
926
+ # ...or by passing an options hash to Haml::Engine.new.
920
927
  # Available options are:
921
928
  #
922
929
  # [<tt>:output</tt>] Determines the output format. The default is :xhtml.
@@ -927,7 +934,8 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
927
934
  # [<tt>:escape_html</tt>] Sets whether or not to escape HTML-sensitive characters in script.
928
935
  # If this is true, = behaves like &=;
929
936
  # otherwise, it behaves like !=.
930
- # <b>Note that this escapes tag attributes.</b>
937
+ # Note that if this is set, != should be used for yielding to subtemplates
938
+ # and rendering partials.
931
939
  # Defaults to false.
932
940
  #
933
941
  # [<tt>:suppress_eval</tt>] Whether or not attribute hashes and Ruby scripts
@@ -114,7 +114,7 @@ module Haml
114
114
  result = html_escape(result) if escape_html
115
115
 
116
116
  has_newline = result.include?("\n")
117
- if in_tag && (@options[:ugly] || !has_newline || preserve_tag)
117
+ if in_tag && !nuke_inner_whitespace && (@options[:ugly] || !has_newline || preserve_tag)
118
118
  @buffer << result
119
119
  @real_tabs -= 1
120
120
  return
@@ -199,7 +199,7 @@ module Haml
199
199
  @@tab_cache = {}
200
200
  # Gets <tt>count</tt> tabs. Mostly for internal use.
201
201
  def tabs(count = 0)
202
- tabs = count + @tabulation
202
+ tabs = [count + @tabulation, 0].max
203
203
  @@tab_cache[tabs] ||= ' ' * tabs
204
204
  end
205
205
 
@@ -45,11 +45,11 @@ module Haml
45
45
 
46
46
  # Creates a new instace of Haml::Engine that will compile the given
47
47
  # template string when <tt>render</tt> is called.
48
- # See README.rdoc for available options.
48
+ # See the Haml module documentation for available options.
49
49
  #
50
50
  #--
51
51
  # When adding options, remember to add information about them
52
- # to README.rdoc!
52
+ # to lib/haml.rb!
53
53
  #++
54
54
  #
55
55
  def initialize(template, options = {})
@@ -73,13 +73,20 @@ module Haml
73
73
  raise Haml::Error, "Invalid format #{@options[:format].inspect}"
74
74
  end
75
75
 
76
- @template = template.rstrip #String
76
+ @template = template.rstrip + "\n-#\n-#"
77
77
  @to_close_stack = []
78
78
  @output_tabs = 0
79
79
  @template_tabs = 0
80
80
  @index = 0
81
81
  @flat_spaces = -1
82
82
  @newlines = 0
83
+ @precompiled = ''
84
+ @merged_text = ''
85
+ @tab_change = 0
86
+
87
+ if @template =~ /\A(\s*\n)*[ \t]+\S/
88
+ raise SyntaxError.new("Indenting at the beginning of the document is illegal.", ($1 || "").count("\n"))
89
+ end
83
90
 
84
91
  if @options[:filters]
85
92
  warn <<END
@@ -90,8 +97,8 @@ END
90
97
  end
91
98
 
92
99
  precompile
93
- rescue Haml::Error
94
- $!.backtrace.unshift "#{@options[:filename]}:#{@index + $!.line_offset + @options[:line] - 1}" if @index
100
+ rescue Haml::Error => e
101
+ e.backtrace.unshift "#{@options[:filename]}:#{(e.line ? e.line + 1 : @index) + @options[:line] - 1}" if @index
95
102
  raise
96
103
  end
97
104
 
@@ -5,13 +5,12 @@ module Haml
5
5
 
6
6
  # By default, an error is taken to refer to the line of the template
7
7
  # that was being processed when the exception was raised.
8
- # However, if line_offset is non-zero, it's added to that line number
9
- # to get the line to report for the error.
10
- attr_reader :line_offset
8
+ # However, if line is non-nil, it + 1 is used instead.
9
+ attr_reader :line
11
10
 
12
- def initialize(message = nil, line_offset = 0)
11
+ def initialize(message = nil, line = nil)
13
12
  super(message)
14
- @line_offset = line_offset
13
+ @line = line
15
14
  end
16
15
  # :startdoc:
17
16
  end
@@ -1,5 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/../haml'
2
2
  require 'optparse'
3
+ require 'fileutils'
3
4
 
4
5
  module Haml
5
6
  # This module contains code for working with the
@@ -128,8 +129,9 @@ END
128
129
  dir = File.join(dir, 'haml')
129
130
 
130
131
  if File.exists?(dir)
131
- puts "Directory #{dir} already exists."
132
- exit
132
+ print "Directory #{dir} already exists, overwrite [y/N]? "
133
+ exit if gets !~ /y/i
134
+ FileUtils.rm_rf(dir)
133
135
  end
134
136
 
135
137
  begin
@@ -265,8 +265,8 @@ module Haml
265
265
 
266
266
  #
267
267
  # call-seq:
268
- # haml_tag(name, attributes = {}) {...}
269
- # haml_tag(name, text, attributes = {}) {...}
268
+ # haml_tag(name, *flags, attributes = {}) {...}
269
+ # haml_tag(name, text, *flags, attributes = {}) {...}
270
270
  #
271
271
  # Creates an HTML tag with the given name and optionally text and attributes.
272
272
  # Can take a block that will be executed
@@ -274,6 +274,11 @@ module Haml
274
274
  # If the block is a Haml block or outputs text using puts,
275
275
  # the text will be properly indented.
276
276
  #
277
+ # <tt>flags</tt> is a list of symbol flags
278
+ # like those that can be put at the end of a Haml tag
279
+ # (<tt>:/</tt>, <tt>:<</tt>, and <tt>:></tt>).
280
+ # Currently, only <tt>:/</tt> and <tt>:<</tt> are supported.
281
+ #
277
282
  # For example,
278
283
  #
279
284
  # haml_tag :table do
@@ -304,34 +309,46 @@ module Haml
304
309
  # </tr>
305
310
  # </table>
306
311
  #
307
- def haml_tag(name, attributes = {}, alt_atts = {}, &block)
312
+ def haml_tag(name, *rest, &block)
308
313
  name = name.to_s
314
+ text = rest.shift if rest.first.is_a? String
315
+ flags = []
316
+ flags << rest.shift while rest.first.is_a? Symbol
317
+ attributes = Haml::Precompiler.build_attributes(haml_buffer.html?,
318
+ haml_buffer.options[:attr_wrapper],
319
+ rest.shift || {})
320
+
321
+ if text.nil? && block.nil? && (haml_buffer.options[:autoclose].include?(name) || flags.include?(:/))
322
+ puts "<#{name}#{attributes} />"
323
+ return nil
324
+ end
309
325
 
310
- text = nil
311
- if attributes.is_a? String
312
- text = attributes
313
- attributes = alt_atts
326
+ if flags.include?(:/)
327
+ raise Error.new("Self-closing tags can't have content.") if text
328
+ raise Error.new("Illegal nesting: nesting within a self-closing tag is illegal.") if block
314
329
  end
315
330
 
316
- attributes = Haml::Precompiler.build_attributes(
317
- haml_buffer.html?, haml_buffer.options[:attr_wrapper], attributes)
331
+ tag = "<#{name}#{attributes}>"
332
+ if block.nil?
333
+ tag << text.to_s << "</#{name}>"
334
+ puts tag
335
+ return
336
+ end
318
337
 
319
- if text.nil? && block.nil? && haml_buffer.options[:autoclose].include?(name)
320
- puts "<#{name}#{attributes} />"
321
- return nil
338
+ if text
339
+ raise Error.new("Illegal nesting: content can't be both given to haml_tag :#{name} and nested within it.")
322
340
  end
323
341
 
324
- puts "<#{name}#{attributes}>"
325
- unless text && text.empty?
326
- tab_up
327
- # Print out either the text (using push_text) or call the block and add an endline
328
- if text
329
- puts(text)
330
- elsif block
331
- block.call
332
- end
333
- tab_down
342
+ if flags.include?(:<)
343
+ tag << capture_haml(&block).strip << "</#{name}>"
344
+ puts tag
345
+ return
334
346
  end
347
+
348
+ puts tag
349
+ tab_up
350
+ block.call
351
+ tab_down
335
352
  puts "</#{name}>"
336
353
  nil
337
354
  end
@@ -7,56 +7,93 @@ if defined?(ActionView) and not defined?(Merb::Plugins)
7
7
  end
8
8
  alias_method :render_without_haml, :render
9
9
  alias_method :render, :render_with_haml
10
+
11
+ # Rails >2.1
12
+ if instance_methods.include?('output_buffer')
13
+ def output_buffer_with_haml
14
+ return haml_buffer.buffer if is_haml?
15
+ output_buffer_without_haml
16
+ end
17
+ alias_method :output_buffer_without_haml, :output_buffer
18
+ alias_method :output_buffer, :output_buffer_with_haml
19
+
20
+ def set_output_buffer_with_haml(new)
21
+ if is_haml?
22
+ haml_buffer.buffer = new
23
+ else
24
+ set_output_buffer_without_haml new
25
+ end
26
+ end
27
+ alias_method :set_output_buffer_without_haml, :output_buffer=
28
+ alias_method :output_buffer=, :set_output_buffer_with_haml
29
+ end
10
30
  end
11
31
 
12
32
  # This overrides various helpers in ActionView
13
33
  # to make them work more effectively with Haml.
14
34
  module Helpers
15
35
  # :stopdoc:
16
- module CaptureHelper
17
- def capture_with_haml(*args, &block)
18
- # Rails' #capture helper will just return the value of the block
19
- # if it's not actually in the template context,
20
- # as detected by the existance of an _erbout variable.
21
- # We've got to do the same thing for compatibility.
22
- block_is_haml =
23
- begin
24
- eval('_hamlout', block)
25
- true
26
- rescue
27
- false
36
+ # In Rails <=2.1, we've got to override considerable capturing infrastructure.
37
+ # In Rails >2.1, we can make do with only overriding #capture
38
+ # (which no longer behaves differently in helper contexts).
39
+ unless ActionView::Base.instance_methods.include?('output_buffer')
40
+ module CaptureHelper
41
+ def capture_with_haml(*args, &block)
42
+ # Rails' #capture helper will just return the value of the block
43
+ # if it's not actually in the template context,
44
+ # as detected by the existance of an _erbout variable.
45
+ # We've got to do the same thing for compatibility.
46
+ block_is_haml =
47
+ begin
48
+ eval('_hamlout', block)
49
+ true
50
+ rescue
51
+ false
52
+ end
53
+
54
+ if block_is_haml && is_haml?
55
+ capture_haml(*args, &block)
56
+ else
57
+ capture_without_haml(*args, &block)
28
58
  end
59
+ end
60
+ alias_method :capture_without_haml, :capture
61
+ alias_method :capture, :capture_with_haml
29
62
 
30
- if block_is_haml && is_haml?
31
- capture_haml(*args, &block)
32
- else
33
- capture_without_haml(*args, &block)
63
+ def capture_erb_with_buffer_with_haml(*args, &block)
64
+ if is_haml?
65
+ capture_haml_with_buffer(*args, &block)
66
+ else
67
+ capture_erb_with_buffer_without_haml(*args, &block)
68
+ end
34
69
  end
70
+ alias_method :capture_erb_with_buffer_without_haml, :capture_erb_with_buffer
71
+ alias_method :capture_erb_with_buffer, :capture_erb_with_buffer_with_haml
35
72
  end
36
- alias_method :capture_without_haml, :capture
37
- alias_method :capture, :capture_with_haml
38
73
 
39
- def capture_erb_with_buffer_with_haml(*args, &block)
40
- if is_haml?
41
- capture_haml_with_buffer(*args, &block)
42
- else
43
- capture_erb_with_buffer_without_haml(*args, &block)
74
+ module TextHelper
75
+ def concat_with_haml(string, binding = nil)
76
+ if is_haml?
77
+ haml_buffer.buffer.concat(string)
78
+ else
79
+ concat_without_haml(string, binding)
80
+ end
44
81
  end
82
+ alias_method :concat_without_haml, :concat
83
+ alias_method :concat, :concat_with_haml
45
84
  end
46
- alias_method :capture_erb_with_buffer_without_haml, :capture_erb_with_buffer
47
- alias_method :capture_erb_with_buffer, :capture_erb_with_buffer_with_haml
48
- end
49
-
50
- module TextHelper
51
- def concat_with_haml(string, binding = nil)
52
- if is_haml?
53
- haml_buffer.buffer.concat(string)
54
- else
55
- concat_without_haml(string, binding)
85
+ else
86
+ module CaptureHelper
87
+ def capture_with_haml(*args, &block)
88
+ if is_haml?
89
+ capture_haml(*args, &block)
90
+ else
91
+ capture_without_haml(*args, &block)
92
+ end
56
93
  end
94
+ alias_method :capture_without_haml, :capture
95
+ alias_method :capture, :capture_with_haml
57
96
  end
58
- alias_method :concat_without_haml, :concat
59
- alias_method :concat, :concat_with_haml
60
97
  end
61
98
 
62
99
  module TagHelper
@@ -109,28 +109,15 @@ END
109
109
  end.join(';') + ';'
110
110
  end
111
111
 
112
- Line = Struct.new("Line", :text, :unstripped, :index, :spaces, :tabs)
112
+ Line = Struct.new(:text, :unstripped, :index, :spaces, :tabs)
113
113
 
114
114
  def precompile
115
- @precompiled = ''
116
- @merged_text = ''
117
- @tab_change = 0
118
-
119
115
  old_line = Line.new
120
- (@template + "\n-#\n-#").split(/\r\n|\r|\n/).each_with_index do |text, index|
121
- line = Line.new text.strip, text.lstrip.chomp, index
116
+ @template.split(/\r\n|\r|\n/).each_with_index do |text, index|
117
+ @next_line = line = Line.new(text.strip, text.lstrip.chomp, index)
122
118
  line.spaces, line.tabs = count_soft_tabs(text)
123
119
 
124
- if line.text.empty?
125
- process_indent(old_line) if flat? && !old_line.text.empty?
126
-
127
- unless flat?
128
- newline
129
- next
130
- end
131
-
132
- push_flat(old_line)
133
- old_line.text, old_line.unstripped, old_line.spaces = '', '', 0
120
+ if line.text.empty? && !flat?
134
121
  newline
135
122
  next
136
123
  end
@@ -154,7 +141,7 @@ END
154
141
  end
155
142
 
156
143
  if old_line.spaces != old_line.tabs * 2
157
- raise SyntaxError.new(<<END.strip, 1 + old_line.index - @index)
144
+ raise SyntaxError.new(<<END.strip, old_line.index)
158
145
  #{old_line.spaces} space#{old_line.spaces == 1 ? ' was' : 's were'} used for indentation. Haml must be indented using two spaces.
159
146
  END
160
147
  end
@@ -165,7 +152,7 @@ END
165
152
  resolve_newlines
166
153
 
167
154
  if !flat? && line.tabs - old_line.tabs > 1
168
- raise SyntaxError.new(<<END.strip, 2 + old_line.index - @index)
155
+ raise SyntaxError.new(<<END.strip, line.index)
169
156
  #{line.spaces} spaces were used for indentation. Haml must be indented using two spaces.
170
157
  END
171
158
  end
@@ -307,7 +294,10 @@ END
307
294
  # Renders a block of text as plain text.
308
295
  # Also checks for an illegally opened block.
309
296
  def push_plain(text)
310
- raise SyntaxError.new("Illegal nesting: nesting within plain text is illegal.", 1) if @block_opened
297
+ if @block_opened
298
+ raise SyntaxError.new("Illegal nesting: nesting within plain text is illegal.", @next_line.index)
299
+ end
300
+
311
301
  push_text text
312
302
  end
313
303
 
@@ -545,6 +535,7 @@ END
545
535
 
546
536
  preserve_tag = options[:preserve].include?(tag_name)
547
537
  nuke_inner_whitespace ||= preserve_tag
538
+ preserve_tag &&= !options[:ugly]
548
539
 
549
540
  case action
550
541
  when '/'; self_closing = xhtml?
@@ -573,8 +564,8 @@ END
573
564
  attributes = parse_class_and_id(attributes)
574
565
  Buffer.merge_attrs(attributes, static_attributes) if static_attributes
575
566
 
576
- raise SyntaxError.new("Illegal nesting: nesting within a self-closing tag is illegal.", 1) if @block_opened && self_closing
577
- raise SyntaxError.new("Illegal nesting: content can't be both given on the same line as %#{tag_name} and nested within it.", 1) if @block_opened && !value.empty?
567
+ raise SyntaxError.new("Illegal nesting: nesting within a self-closing tag is illegal.", @next_line.index) if @block_opened && self_closing
568
+ raise SyntaxError.new("Illegal nesting: content can't be both given on the same line as %#{tag_name} and nested within it.", @next_line.index) if @block_opened && !value.empty?
578
569
  raise SyntaxError.new("There's no Ruby code for #{action} to evaluate.") if parse && value.empty?
579
570
  raise SyntaxError.new("Self-closing tags can't have content.") if self_closing && !value.empty?
580
571
 
@@ -641,7 +632,7 @@ END
641
632
  conditional << ">" if conditional
642
633
 
643
634
  if @block_opened && !line.empty?
644
- raise SyntaxError.new('Illegal nesting: nesting within a tag that already has content is illegal.', 1)
635
+ raise SyntaxError.new('Illegal nesting: nesting within a tag that already has content is illegal.', @next_line.index)
645
636
  end
646
637
 
647
638
  open = "<!--#{conditional} "
@@ -662,7 +653,7 @@ END
662
653
 
663
654
  # Renders an XHTML doctype or XML shebang.
664
655
  def render_doctype(line)
665
- raise SyntaxError.new("Illegal nesting: nesting within a header command is illegal.", 1) if @block_opened
656
+ raise SyntaxError.new("Illegal nesting: nesting within a header command is illegal.", @next_line.index) if @block_opened
666
657
  doctype = text_for_doctype(line)
667
658
  push_text doctype if doctype
668
659
  end
@@ -758,8 +749,8 @@ END
758
749
  def count_soft_tabs(line)
759
750
  spaces = line.index(/([^ ]|$)/)
760
751
  if line[spaces] == ?\t
761
- return nil if line.strip.empty?
762
- raise SyntaxError.new(<<END.strip, 2)
752
+ return 0, 0 if line.strip.empty?
753
+ raise SyntaxError.new(<<END.strip, @next_line.index)
763
754
  A tab character was used for indentation. Haml must be indented using two spaces.
764
755
  Are you sure you have soft tabs enabled in your editor?
765
756
  END