Class: Haml::Engine

Inherits:
Object show all
Includes:
Precompiler
Defined in:
lib/haml/engine.rb

Overview

This is the class where all the parsing and processing of the Haml template is done. It can be directly used by the user by creating a new instance and calling to_html to render the template. For example:

template = File.read('templates/really_cool_template.haml')
haml_engine = Haml::Engine.new(template)
output = haml_engine.to_html
puts output

Constant Summary

Constants included from Precompiler

Precompiler::COMMENT, Precompiler::DIV_CLASS, Precompiler::DIV_ID, Precompiler::DOCTYPE_OR_UNESCAPE, Precompiler::DOCTYPE_REGEX, Precompiler::ELEMENT, Precompiler::ESCAPE, Precompiler::FILTER, Precompiler::FLAT_SCRIPT, Precompiler::LITERAL_VALUE_REGEX, Precompiler::MID_BLOCK_KEYWORDS, Precompiler::MULTILINE_CHAR_VALUE, Precompiler::PLAIN_TEXT, Precompiler::SANITIZE, Precompiler::SCRIPT, Precompiler::SILENT_COMMENT, Precompiler::SILENT_SCRIPT, Precompiler::SPECIAL_CHARACTERS

Constants included from Util

Util::RUBY_VERSION

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Util

#def_static_method, #enum_with_index, #has?, #map_hash, #map_keys, #map_vals, #powerset, #ruby1_8?, #static_method_name, #to_hash

Constructor Details

#initialize(template, options = {}) ⇒ Engine

Creates a new instace of Haml::Engine that will compile the given template string when render is called. See the Haml module documentation for available options.

– When adding options, remember to add information about them to lib/haml.rb! ++



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/haml/engine.rb', line 60

def initialize(template, options = {})
  @options = {
    :suppress_eval => false,
    :attr_wrapper => "'",

    # Don't forget to update the docs in lib/haml.rb if you update these
    :autoclose => %w[meta img link br hr input area param col base],
    :preserve => %w[textarea pre],

    :filename => '(haml)',
    :line => 1,
    :ugly => false,
    :format => :xhtml,
    :escape_html => false
  }
  @options.merge! options
  @index = 0

  unless [:xhtml, :html4, :html5].include?(@options[:format])
    raise Haml::Error, "Invalid format #{@options[:format].inspect}"
  end

  # :eod is a special end-of-document marker
  @template = (template.rstrip).split(/\r\n|\r|\n/) + [:eod, :eod]
  @template_index = 0
  @to_close_stack = []
  @output_tabs = 0
  @template_tabs = 0
  @flat = false
  @newlines = 0
  @precompiled = ''
  @to_merge = []
  @tab_change  = 0
  @temp_count = 0

  if @options[:filters]
    warn <<END
DEPRECATION WARNING:
The Haml :filters option is deprecated and will be removed in version 2.2.
Filters are now automatically registered.
END
  end

  precompile
rescue Haml::Error => e
  e.backtrace.unshift "#{@options[:filename]}:#{(e.line ? e.line + 1 : @index) + @options[:line] - 1}" if @index
  raise
end

Instance Attribute Details

#indentationObject

A string containing the indentation used for the Haml document. nil if the indentation is ambiguous (for example, for a single-level document).



29
30
31
# File 'lib/haml/engine.rb', line 29

def indentation
  @indentation
end

#optionsObject

Allow reading and writing of the options hash



20
21
22
# File 'lib/haml/engine.rb', line 20

def options
  @options
end

#precompiledObject

This string contains the source code that is evaluated to produce the Haml document.



24
25
26
# File 'lib/haml/engine.rb', line 24

def precompiled
  @precompiled
end

Instance Method Details

#def_method(object, name, *local_names) ⇒ Object

Defines a method on object with the given name that renders the template and returns the result as a string.

If object is a class or module, the method will instead by defined as an instance method. For example:

t = Time.now
Haml::Engine.new("%p\n  Today's date is\n  .date= self.to_s").def_method(t, :render)
t.render #=> "<p>\n  Today's date is\n  <div class='date'>Fri Nov 23 18:28:29 -0800 2007</div>\n</p>\n"

Haml::Engine.new(".upcased= upcase").def_method(String, :upcased_div)
"foobar".upcased_div #=> "<div class='upcased'>FOOBAR</div>\n"

The first argument of the defined method is a hash of local variable names to values. However, due to an unfortunate Ruby quirk, the local variables which can be assigned must be pre-declared. This is done with the local_names argument. For example:

# This works
obj = Object.new
Haml::Engine.new("%p= foo").def_method(obj, :render, :foo)
obj.render(:foo => "Hello!") #=> "<p>Hello!</p>"

# This doesn't
obj = Object.new
Haml::Engine.new("%p= foo").def_method(obj, :render)
obj.render(:foo => "Hello!") #=> NameError: undefined local variable or method `foo'

Note that Haml modifies the evaluation context (either the scope object or the “self” object of the scope binding). It extends Haml::Helpers, and various instance variables are set (all prefixed with “haml”).



241
242
243
244
245
246
# File 'lib/haml/engine.rb', line 241

def def_method(object, name, *local_names)
  method = object.is_a?(Module) ? :module_eval : :instance_eval

  object.send(method, "def #{name}(_haml_locals = {}); #{precompiled_with_ambles(local_names)}; end",
              @options[:filename], @options[:line])
end

#html4?Boolean

True if the format is HTML4

Returns:

  • (Boolean)


42
43
44
# File 'lib/haml/engine.rb', line 42

def html4?
  @options[:format] == :html4
end

#html5?Boolean

True if the format is HTML5

Returns:

  • (Boolean)


47
48
49
# File 'lib/haml/engine.rb', line 47

def html5?
  @options[:format] == :html5
end

#html?Boolean

True if the format is any flavor of HTML

Returns:

  • (Boolean)


37
38
39
# File 'lib/haml/engine.rb', line 37

def html?
  html4? or html5?
end

#render(scope = Object.new, locals = {}, &block) ⇒ Object Also known as: to_html

Processes the template and returns the result as a string.

scope is the context in which the template is evaluated. If it’s a Binding or Proc object, Haml uses it as the second argument to Kernel#eval; otherwise, Haml just uses its #instance_eval context.

Note that Haml modifies the evaluation context (either the scope object or the “self” object of the scope binding). It extends Haml::Helpers, and various instance variables are set (all prefixed with “haml”). For example:

s = "foobar"
Haml::Engine.new("%p= upcase").render(s) #=> "<p>FOOBAR</p>"

# s now extends Haml::Helpers
s.responds_to?(:html_attrs) #=> true

locals is a hash of local variables to make available to the template. For example:

Haml::Engine.new("%p= foo").render(Object.new, :foo => "Hello, world!") #=> "<p>Hello, world!</p>"

If a block is passed to render, that block is run when yield is called within the template.

Due to some Ruby quirks, if scope is a Binding or Proc object and a block is given, the evaluation context may not be quite what the user expects. In particular, it’s equivalent to passing eval("self", scope) as scope. This won’t have an effect in most cases, but if you’re relying on local variables defined in the context of scope, they won’t work.



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/haml/engine.rb', line 144

def render(scope = Object.new, locals = {}, &block)
  buffer = Haml::Buffer.new(scope.instance_variable_get('@haml_buffer'), options_for_buffer)

  if scope.is_a?(Binding) || scope.is_a?(Proc)
    scope_object = eval("self", scope)
    scope = scope_object.instance_eval{binding} if block_given?
  else
    scope_object = scope
    scope = scope_object.instance_eval{binding}
  end

  set_locals(locals.merge(:_hamlout => buffer, :_erbout => buffer.buffer), scope, scope_object)

  scope_object.instance_eval do
    extend Haml::Helpers
    @haml_buffer = buffer
  end

  eval(@precompiled, scope, @options[:filename], @options[:line])

  # Get rid of the current buffer
  scope_object.instance_eval do
    @haml_buffer = buffer.upper
  end

  buffer.buffer
end

#render_proc(scope = Object.new, *local_names) ⇒ Object

Returns a proc that, when called, renders the template and returns the result as a string.

scope works the same as it does for render.

The first argument of the returned proc is a hash of local variable names to values. However, due to an unfortunate Ruby quirk, the local variables which can be assigned must be pre-declared. This is done with the local_names argument. For example:

# This works
Haml::Engine.new("%p= foo").render_proc(Object.new, :foo).call :foo => "Hello!"
  #=> "<p>Hello!</p>"

# This doesn't
Haml::Engine.new("%p= foo").render_proc.call :foo => "Hello!"
  #=> NameError: undefined local variable or method `foo'

The proc doesn’t take a block; any yields in the template will fail.



194
195
196
197
198
199
200
201
202
203
204
# File 'lib/haml/engine.rb', line 194

def render_proc(scope = Object.new, *local_names)
  if scope.is_a?(Binding) || scope.is_a?(Proc)
    scope_object = eval("self", scope)
  else
    scope_object = scope
    scope = scope_object.instance_eval{binding}
  end

  eval("Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {};" +
       precompiled_with_ambles(local_names) + "}\n", scope, @options[:filename], @options[:line])
end

#xhtml?Boolean

True if the format is XHTML

Returns:

  • (Boolean)


32
33
34
# File 'lib/haml/engine.rb', line 32

def xhtml?
  not html?
end