haml 3.2.0.alpha.13 → 3.2.0.alpha.14

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.

data/Rakefile CHANGED
@@ -15,7 +15,7 @@ end
15
15
 
16
16
  desc "Benchmark Haml against ERb. TIMES=n sets the number of runs, default is 1000."
17
17
  task :benchmark do
18
- sh "ruby test/benchmark.rb #{ENV['TIMES']}"
18
+ sh "ruby benchmark.rb #{ENV['TIMES']}"
19
19
  end
20
20
 
21
21
  Rake::TestTask.new do |t|
@@ -16,7 +16,7 @@ module Haml
16
16
  # The options hash passed in from {Haml::Engine}.
17
17
  #
18
18
  # @return [{String => Object}]
19
- # @see Haml::Engine#options_for_buffer
19
+ # @see Haml::Options#for_buffer
20
20
  attr_accessor :options
21
21
 
22
22
  # The {Buffer} for the enclosing Haml document.
@@ -1,17 +1,58 @@
1
1
  require 'cgi'
2
2
 
3
3
  module Haml
4
- module Compiler
4
+ class Compiler
5
5
  include Haml::Util
6
6
 
7
- private
7
+ attr_accessor :options
8
+
9
+ def initialize(options)
10
+ @options = options
11
+ @output_tabs = 0
12
+ @to_merge = []
13
+ @precompiled = ''
14
+ end
15
+
16
+ def compile(node)
17
+ parent = instance_variable_defined?('@node') ? @node : nil
18
+ @node = node
19
+ if node.children.empty?
20
+ send(:"compile_#{node.type}")
21
+ else
22
+ send(:"compile_#{node.type}") {node.children.each {|c| compile c}}
23
+ end
24
+ ensure
25
+ @node = parent
26
+ end
27
+
28
+ if RUBY_VERSION < "1.9"
29
+ # The source code that is evaluated to produce the Haml document.
30
+ #
31
+ # In Ruby 1.9, this is automatically converted to the correct encoding
32
+ # (see {file:REFERENCE.md#encodings the `:encoding` option}).
33
+ #
34
+ # @return [String]
35
+ def precompiled
36
+ @precompiled
37
+ end
38
+ else
39
+ def precompiled
40
+ encoding = Encoding.find(@options[:encoding])
41
+ return @precompiled.force_encoding(encoding) if encoding == Encoding::BINARY
42
+ return @precompiled.encode(encoding)
43
+ end
44
+ end
45
+
46
+ def precompiled_with_return_value
47
+ precompiled + ";" + precompiled_method_return_value
48
+ end
8
49
 
9
50
  # Returns the precompiled string with the preamble and postamble
10
51
  def precompiled_with_ambles(local_names)
11
52
  preamble = <<END.gsub("\n", ";")
12
53
  begin
13
54
  extend Haml::Helpers
14
- _hamlout = @haml_buffer = Haml::Buffer.new(haml_buffer, #{options_for_buffer.inspect})
55
+ _hamlout = @haml_buffer = Haml::Buffer.new(haml_buffer, #{options.for_buffer.inspect})
15
56
  _erbout = _hamlout.buffer
16
57
  END
17
58
  postamble = <<END.gsub("\n", ";")
@@ -23,6 +64,8 @@ END
23
64
  preamble + locals_code(local_names) + precompiled + postamble
24
65
  end
25
66
 
67
+ private
68
+
26
69
  # Returns the string used as the return value of the precompiled method.
27
70
  # This method exists so it can be monkeypatched to return modified values.
28
71
  def precompiled_method_return_value
@@ -154,10 +197,10 @@ END
154
197
  push_generated_script(
155
198
  "_hamlout.attributes(#{inspect_obj(t[:attributes])}, #{object_ref}#{attributes_hashes})")
156
199
  concat_merged_text(
157
- if t[:self_closing] && xhtml?
200
+ if t[:self_closing] && @options.xhtml?
158
201
  " />" + (t[:nuke_outer_whitespace] ? "" : "\n")
159
202
  else
160
- ">" + ((if t[:self_closing] && html?
203
+ ">" + ((if t[:self_closing] && @options.html?
161
204
  t[:nuke_outer_whitespace]
162
205
  else
163
206
  !block_given? || t[:preserve_tag] || t[:nuke_inner_whitespace]
@@ -215,22 +258,27 @@ END
215
258
 
216
259
  def compile_filter
217
260
  unless filter = Filters.defined[@node.value[:name]]
218
- raise Error.new("Filter \"#{@node.value[:name]}\" is not defined.", @node.line - 1)
261
+ name = @node.value[:name]
262
+ if ["maruku", "textile"].include?(name)
263
+ raise Error.new("To use the \"#{name}\" filter, please install the haml-contrib gem.", @node.line - 1)
264
+ else
265
+ raise Error.new("Filter \"#{name}\" is not defined.", @node.line - 1)
266
+ end
219
267
  end
220
268
  filter.internal_compile(self, @node.value[:text])
221
269
  end
222
270
 
223
271
  def text_for_doctype
224
272
  if @node.value[:type] == "xml"
225
- return nil if html?
273
+ return nil if @options.html?
226
274
  wrapper = @options[:attr_wrapper]
227
275
  return "<?xml version=#{wrapper}1.0#{wrapper} encoding=#{wrapper}#{@node.value[:encoding] || "utf-8"}#{wrapper} ?>"
228
276
  end
229
277
 
230
- if html5?
278
+ if @options.html5?
231
279
  '<!DOCTYPE html>'
232
280
  else
233
- if xhtml?
281
+ if @options.xhtml?
234
282
  if @node.value[:version] == "1.1"
235
283
  '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
236
284
  elsif @node.value[:version] == "5"
@@ -246,7 +294,7 @@ END
246
294
  end
247
295
  end
248
296
 
249
- elsif html4?
297
+ elsif @options.html4?
250
298
  case @node.value[:type]
251
299
  when "strict"; '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">'
252
300
  when "frameset"; '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">'
@@ -260,7 +308,7 @@ END
260
308
  # does not output the result.
261
309
  def push_silent(text, can_suppress = false)
262
310
  flush_merged_text
263
- return if can_suppress && options[:suppress_eval]
311
+ return if can_suppress && @options.suppress_eval?
264
312
  @precompiled << "#{resolve_newlines}#{text}\n"
265
313
  @output_line += text.count("\n") + 1
266
314
  end
@@ -321,7 +369,7 @@ END
321
369
  # If `opts[:preserve_script]` is true, Haml::Helpers#find_and_flatten is run on
322
370
  # the result before it is added to `@buffer`
323
371
  def push_script(text, opts = {})
324
- return if options[:suppress_eval]
372
+ return if @options.suppress_eval?
325
373
 
326
374
  args = %w[preserve_script in_tag preserve_tag escape_html nuke_inner_whitespace]
327
375
  args.map! {|name| opts[name.to_sym]}
@@ -442,9 +490,10 @@ END
442
490
  end
443
491
 
444
492
  def prerender_tag(name, self_close, attributes)
493
+ # TODO: consider just passing in the damn options here
445
494
  attributes_string = Compiler.build_attributes(
446
- html?, @options[:attr_wrapper], @options[:escape_attrs], @options[:hyphenate_data_attrs], attributes)
447
- "<#{name}#{attributes_string}#{self_close && xhtml? ? ' /' : ''}>"
495
+ @options.html?, @options[:attr_wrapper], @options[:escape_attrs], @options[:hyphenate_data_attrs], attributes)
496
+ "<#{name}#{attributes_string}#{self_close && @options.xhtml? ? ' /' : ''}>"
448
497
  end
449
498
 
450
499
  def resolve_newlines
@@ -478,17 +527,5 @@ END
478
527
  raise SyntaxError.new("[HAML BUG] Undefined entry in Haml::Compiler@to_merge.")
479
528
  end
480
529
  end
481
-
482
- def compile(node)
483
- parent = instance_variable_defined?('@node') ? @node : nil
484
- @node = node
485
- if node.children.empty?
486
- send(:"compile_#{node.type}")
487
- else
488
- send(:"compile_#{node.type}") {node.children.each {|c| compile c}}
489
- end
490
- ensure
491
- @node = parent
492
- end
493
530
  end
494
531
  end
@@ -1,3 +1,6 @@
1
+ require 'forwardable'
2
+
3
+ require 'haml/options'
1
4
  require 'haml/helpers'
2
5
  require 'haml/buffer'
3
6
  require 'haml/parser'
@@ -16,13 +19,13 @@ module Haml
16
19
  # output = haml_engine.render
17
20
  # puts output
18
21
  class Engine
19
- include Parser
20
- include Compiler
22
+ extend Forwardable
23
+ include Haml::Util
21
24
 
22
- # The options hash.
25
+ # The Haml::Options instance.
23
26
  # See {file:REFERENCE.md#options the Haml options documentation}.
24
27
  #
25
- # @return [{Symbol => Object}]
28
+ # @return Haml::Options
26
29
  attr_accessor :options
27
30
 
28
31
  # The indentation used in the Haml document,
@@ -32,42 +35,14 @@ module Haml
32
35
  # @return [String]
33
36
  attr_accessor :indentation
34
37
 
35
- # @return [Boolean] Whether or not the format is XHTML.
36
- def xhtml?
37
- not html?
38
- end
39
-
40
- # @return [Boolean] Whether or not the format is any flavor of HTML.
41
- def html?
42
- html4? or html5?
43
- end
38
+ attr_accessor :compiler
39
+ attr_accessor :parser
44
40
 
45
- # @return [Boolean] Whether or not the format is HTML4.
46
- def html4?
47
- @options[:format] == :html4
48
- end
49
-
50
- # @return [Boolean] Whether or not the format is HTML5.
51
- def html5?
52
- @options[:format] == :html5
53
- end
41
+ # Tilt currently depends on these moved methods, provide a stable API
42
+ def_delegators :compiler, :precompiled, :precompiled_method_return_value
54
43
 
55
- if RUBY_VERSION < "1.9"
56
- # The source code that is evaluated to produce the Haml document.
57
- #
58
- # In Ruby 1.9, this is automatically converted to the correct encoding
59
- # (see {file:REFERENCE.md#encodings the `:encoding` option}).
60
- #
61
- # @return [String]
62
- def precompiled
63
- @precompiled
64
- end
65
- else
66
- def precompiled
67
- encoding = Encoding.find(@options[:encoding])
68
- return @precompiled.force_encoding(encoding) if encoding == Encoding::BINARY
69
- return @precompiled.encode(encoding)
70
- end
44
+ def options_for_buffer
45
+ @options.for_buffer
71
46
  end
72
47
 
73
48
  # Precompiles the Haml template.
@@ -77,57 +52,18 @@ module Haml
77
52
  # see {file:REFERENCE.md#options the Haml options documentation}
78
53
  # @raise [Haml::Error] if there's a Haml syntax error in the template
79
54
  def initialize(template, options = {})
80
- @options = {
81
- :suppress_eval => false,
82
- :attr_wrapper => "'",
83
- # Don't forget to update the docs in doc-src/REFERENCE.md
84
- # if you update these
85
- :autoclose => %w[meta img link br hr input area param col base],
86
- :preserve => %w[textarea pre code],
87
- :filename => '(haml)',
88
- :line => 1,
89
- :ugly => false,
90
- :format => :xhtml,
91
- :escape_html => false,
92
- :escape_attrs => true,
93
- :hyphenate_data_attrs => true,
94
- }
95
-
96
- @index = nil # explicitily initialize to avoid warnings
55
+ @options = Options.new(options)
97
56
 
98
- template = check_haml_encoding(template) do |msg, line|
57
+ @template = check_haml_encoding(template) do |msg, line|
99
58
  raise Haml::Error.new(msg, line)
100
59
  end
101
60
 
102
- set_up_encoding(options, template)
61
+ initialize_encoding options[:encoding]
103
62
 
104
- @options.merge! options.reject {|k, v| v.nil?}
105
- @index = 0
63
+ @parser = Parser.new(@template, @options)
64
+ @compiler = Compiler.new(@options)
106
65
 
107
- @options[:format] = :xhtml if @options[:mime_type] == 'text/xml'
108
-
109
- unless [:xhtml, :html4, :html5].include?(@options[:format])
110
- raise Haml::Error, "Invalid output format #{@options[:format].inspect}"
111
- end
112
-
113
- # :eod is a special end-of-document marker
114
- @template = (template.rstrip).split(/\r\n|\r|\n/) + [:eod, :eod]
115
- @template_index = 0
116
- @to_close_stack = []
117
- @output_tabs = 0
118
- @template_tabs = 0
119
- @flat = false
120
- @newlines = 0
121
- @precompiled = ''
122
- @to_merge = []
123
- @tab_change = 0
124
-
125
- compile(parse)
126
- rescue Haml::Error => e
127
- if @index || e.line
128
- e.backtrace.unshift "#{@options[:filename]}:#{(e.line ? e.line + 1 : @index) + @options[:line] - 1}"
129
- end
130
- raise
66
+ @compiler.compile(@parser.parse)
131
67
  end
132
68
 
133
69
  # Processes the template and returns the result as a string.
@@ -173,7 +109,7 @@ module Haml
173
109
  # @return [String] The rendered template
174
110
  def render(scope = Object.new, locals = {}, &block)
175
111
  parent = scope.instance_variable_defined?('@haml_buffer') ? scope.instance_variable_get('@haml_buffer') : nil
176
- buffer = Haml::Buffer.new(parent, options_for_buffer)
112
+ buffer = Haml::Buffer.new(parent, @options.for_buffer)
177
113
 
178
114
  if scope.is_a?(Binding) || scope.is_a?(Proc)
179
115
  scope_object = eval("self", scope)
@@ -190,8 +126,7 @@ module Haml
190
126
  @haml_buffer = buffer
191
127
  end
192
128
 
193
- eval(precompiled + ";" + precompiled_method_return_value,
194
- scope, @options[:filename], @options[:line])
129
+ eval(@compiler.precompiled_with_return_value, scope, @options[:filename], @options[:line])
195
130
  ensure
196
131
  # Get rid of the current buffer
197
132
  scope_object.instance_eval do
@@ -233,7 +168,7 @@ module Haml
233
168
  end
234
169
 
235
170
  eval("Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {};" +
236
- precompiled_with_ambles(local_names) + "}\n", scope, @options[:filename], @options[:line])
171
+ compiler.precompiled_with_ambles(local_names) + "}\n", scope, @options[:filename], @options[:line])
237
172
  end
238
173
 
239
174
  # Defines a method on `object` with the given name
@@ -277,45 +212,19 @@ module Haml
277
212
  def def_method(object, name, *local_names)
278
213
  method = object.is_a?(Module) ? :module_eval : :instance_eval
279
214
 
280
- object.send(method, "def #{name}(_haml_locals = {}); #{precompiled_with_ambles(local_names)}; end",
215
+ object.send(method, "def #{name}(_haml_locals = {}); #{compiler.precompiled_with_ambles(local_names)}; end",
281
216
  @options[:filename], @options[:line])
282
217
  end
283
218
 
284
- protected
285
-
286
- # Returns a subset of \{#options}: those that {Haml::Buffer} cares about.
287
- # All of the values here are such that when `#inspect` is called on the hash,
288
- # it can be `Kernel#eval`ed to get the same result back.
289
- #
290
- # See {file:REFERENCE.md#options the Haml options documentation}.
291
- #
292
- # @return [{Symbol => Object}] The options hash
293
- def options_for_buffer
294
- {
295
- :autoclose => @options[:autoclose],
296
- :preserve => @options[:preserve],
297
- :attr_wrapper => @options[:attr_wrapper],
298
- :ugly => @options[:ugly],
299
- :format => @options[:format],
300
- :encoding => @options[:encoding],
301
- :escape_html => @options[:escape_html],
302
- :escape_attrs => @options[:escape_attrs],
303
- :hyphenate_data_attrs => @options[:hyphenate_data_attrs],
304
- }
305
- end
306
-
307
219
  private
308
220
 
309
221
  if RUBY_VERSION < "1.9"
310
- def set_up_encoding(options, template)
311
- options
222
+ def initialize_encoding(given_value)
312
223
  end
313
224
  else
314
- def set_up_encoding(options, template)
315
- @options.tap do |ops|
316
- ops[:encoding] = Encoding.default_internal || template.encoding
317
- ops[:encoding] = "utf-8" if ops[:encoding].name == "US-ASCII"
318
- ops[:encoding] = ops[:encoding].name if ops[:encoding].is_a?(Encoding)
225
+ def initialize_encoding(given_value)
226
+ unless given_value
227
+ @options.encoding = Encoding.default_internal || @template.encoding
319
228
  end
320
229
  end
321
230
  end
@@ -298,82 +298,5 @@ END
298
298
  output.close() if output.is_a? File
299
299
  end
300
300
  end
301
-
302
- # The `html2haml` executable.
303
- class HTML2Haml < Generic
304
- # @param args [Array<String>] The command-line arguments
305
- def initialize(args)
306
- super
307
- @module_opts = {}
308
- end
309
-
310
- # Tells optparse how to parse the arguments.
311
- #
312
- # @param opts [OptionParser]
313
- def set_opts(opts)
314
- opts.banner = <<END
315
- Usage: html2haml [options] [INPUT] [OUTPUT]
316
-
317
- Description: Transforms an HTML file into corresponding Haml code.
318
-
319
- Options:
320
- END
321
-
322
- opts.on('-e', '--erb', 'Parse ERb tags.') do
323
- @module_opts[:erb] = true
324
- end
325
-
326
- opts.on('--no-erb', "Don't parse ERb tags.") do
327
- @options[:no_erb] = true
328
- end
329
-
330
- opts.on('-r', '--rhtml', 'Deprecated; same as --erb.') do
331
- @module_opts[:erb] = true
332
- end
333
-
334
- opts.on('--no-rhtml', "Deprecated; same as --no-erb.") do
335
- @options[:no_erb] = true
336
- end
337
-
338
- opts.on('-x', '--xhtml', 'Parse the input using the more strict XHTML parser.') do
339
- @module_opts[:xhtml] = true
340
- end
341
-
342
- opts.on("--html-attributes", "Use HTML style attributes instead of Ruby hash style.") do
343
- @module_opts[:html_style_attributes] = true
344
- end
345
-
346
- unless RUBY_VERSION < "1.9"
347
- opts.on('-E ex[:in]', 'Specify the default external and internal character encodings.') do |encoding|
348
- external, internal = encoding.split(':')
349
- Encoding.default_external = external if external && !external.empty?
350
- Encoding.default_internal = internal if internal && !internal.empty?
351
- end
352
- end
353
-
354
- super
355
- end
356
-
357
- # Processes the options set by the command-line arguments,
358
- # and runs the HTML compiler appropriately.
359
- def process_result
360
- super
361
-
362
- require 'haml/html'
363
-
364
- input = @options[:input]
365
- output = @options[:output]
366
-
367
- @module_opts[:erb] ||= input.respond_to?(:path) && input.path =~ /\.(rhtml|erb)$/
368
- @module_opts[:erb] &&= @options[:no_erb] != false
369
-
370
- output.write(::Haml::HTML.new(input, @module_opts).render)
371
- rescue ::Haml::Error => e
372
- raise "#{e.is_a?(::Haml::SyntaxError) ? "Syntax error" : "Error"} on line " +
373
- "#{get_line e}: #{e.message}"
374
- rescue LoadError => err
375
- handle_load_error(err)
376
- end
377
- end
378
301
  end
379
302
  end