Class: Hamlit::HamlBuffer

Inherits:
Object show all
Includes:
HamlHelpers, HamlUtil
Defined in:
lib/hamlit/parser/haml_buffer.rb

Overview

This class is used only internally. It holds the buffer of HTML that is eventually output as the resulting document. It’s called from within the precompiled code, and helps reduce the amount of processing done within ‘instance_eval`ed code.

Constant Summary collapse

ID_KEY =
'id'.freeze
CLASS_KEY =
'class'.freeze
DATA_KEY =
'data'.freeze

Constants included from HamlHelpers

Hamlit::HamlHelpers::HTML_ESCAPE, Hamlit::HamlHelpers::HTML_ESCAPE_ONCE_REGEX, Hamlit::HamlHelpers::HTML_ESCAPE_REGEX

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from HamlUtil

#balance, #check_encoding, #check_haml_encoding, #contains_interpolation?, #handle_interpolation, #html_safe, #human_indentation, #inspect_obj, #rails_xss_safe?, #silence_warnings, #slow_unescape_interpolation, #unescape_interpolation

Methods included from HamlHelpers

action_view?, #block_is_haml?, #capture_haml, #escape_once, #find_and_preserve, #haml_concat, #haml_indent, #haml_tag, #haml_tag_if, #html_attrs, #html_escape, #init_haml_helpers, #is_haml?, #list_of, #non_haml, #precede, #succeed, #surround, #tab_down, #tab_up, #with_tabs

Methods included from Hamlit::HamlHelpers::XssMods

#capture_haml_with_haml_xss, #escape_once_with_haml_xss, #find_and_preserve_with_haml_xss, #haml_concat_with_haml_xss, #haml_indent_with_haml_xss, #html_escape_with_haml_xss, included, #list_of_with_haml_xss, #precede_with_haml_xss, #preserve_with_haml_xss, #succeed_with_haml_xss, #surround_with_haml_xss

Constructor Details

#initialize(upper = nil, options = {}) ⇒ HamlBuffer

Returns a new instance of HamlBuffer.

Parameters:

  • upper (Buffer) (defaults to: nil)

    The parent buffer

  • options ({Symbol => Object}) (defaults to: {})

    An options hash. See Haml::Engine#options_for_buffer



98
99
100
101
102
103
104
105
106
107
108
# File 'lib/hamlit/parser/haml_buffer.rb', line 98

def initialize(upper = nil, options = {})
  @active     = true
  @upper      = upper
  @options    = options
  @buffer     = new_encoded_string
  @tabulation = 0

  # The number of tabs that Engine thinks we should have
  # @real_tabs + @tabulation is the number of tabs actually output
  @real_tabs = 0
end

Instance Attribute Details

#active=(value) ⇒ Boolean (writeonly)

Returns:

  • (Boolean)

See Also:



45
46
47
# File 'lib/hamlit/parser/haml_buffer.rb', line 45

def active=(value)
  @active = value
end

#bufferString

The string that holds the compiled HTML. This is aliased as ‘_erbout` for compatibility with ERB-specific code.

Returns:

  • (String)


22
23
24
# File 'lib/hamlit/parser/haml_buffer.rb', line 22

def buffer
  @buffer
end

#capture_positionFixnum?

nil if there’s no capture_haml block running, and the position at which it’s beginning the capture if there is one.

Returns:

  • (Fixnum, nil)


41
42
43
# File 'lib/hamlit/parser/haml_buffer.rb', line 41

def capture_position
  @capture_position
end

#options{String => Object}

The options hash passed in from Haml::Engine.

Returns:

See Also:

  • Haml::Options#for_buffer


28
29
30
# File 'lib/hamlit/parser/haml_buffer.rb', line 28

def options
  @options
end

#upperBuffer

The Buffer for the enclosing Haml document. This is set for partials and similar sorts of nested templates. It’s ‘nil` at the top level (see #toplevel?).

Returns:

  • (Buffer)


35
36
37
# File 'lib/hamlit/parser/haml_buffer.rb', line 35

def upper
  @upper
end

Class Method Details

.merge_attrs(to, from) ⇒ {String => String}

Merges two attribute hashes. This is the same as ‘to.merge!(from)`, except that it merges id, class, and data attributes.

ids are concatenated with ‘“_”`, and classes are concatenated with `“ ”`. data hashes are simply merged.

Destructively modifies both ‘to` and `from`.

Parameters:

  • to ({String => String})

    The attribute hash to merge into

  • from ({String => #to_s})

    The attribute hash to merge from

Returns:

  • ({String => String})

    ‘to`, after being merged



229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/hamlit/parser/haml_buffer.rb', line 229

def self.merge_attrs(to, from)
  from[ID_KEY] = ::Hamlit::HamlCompiler.filter_and_join(from[ID_KEY], '_') if from[ID_KEY]
  if to[ID_KEY] && from[ID_KEY]
    to[ID_KEY] << "_#{from.delete(ID_KEY)}"
  elsif to[ID_KEY] || from[ID_KEY]
    from[ID_KEY] ||= to[ID_KEY]
  end

  from[CLASS_KEY] = ::Hamlit::HamlCompiler.filter_and_join(from[CLASS_KEY], ' ') if from[CLASS_KEY]
  if to[CLASS_KEY] && from[CLASS_KEY]
    # Make sure we don't duplicate class names
    from[CLASS_KEY] = (from[CLASS_KEY].to_s.split(' ') | to[CLASS_KEY].split(' ')).sort.join(' ')
  elsif to[CLASS_KEY] || from[CLASS_KEY]
    from[CLASS_KEY] ||= to[CLASS_KEY]
  end

  from.keys.each do |key|
    next unless from[key].kind_of?(Hash) || to[key].kind_of?(Hash)

    from_data = from.delete(key)
    # forces to_data & from_data into a hash
    from_data = { nil => from_data } if from_data && !from_data.is_a?(Hash)
    to[key] = { nil => to[key] } if to[key] && !to[key].is_a?(Hash)

    if from_data && !to[key]
      to[key] = from_data
    elsif from_data && to[key]
      to[key].merge! from_data
    end
  end

  to.merge!(from)
end

Instance Method Details

#active?Boolean

Whether or not this buffer is currently being used to render a Haml template. Returns ‘false` if a subtemplate is being rendered, even if it’s a subtemplate of this buffer’s template.

Returns:

  • (Boolean)


78
79
80
# File 'lib/hamlit/parser/haml_buffer.rb', line 78

def active?
  @active
end

#adjust_tabs(tab_change) ⇒ Object

Modifies the indentation of the document.

Parameters:

  • tab_change (Fixnum)

    The number of tabs by which to increase or decrease the document’s indentation



134
135
136
# File 'lib/hamlit/parser/haml_buffer.rb', line 134

def adjust_tabs(tab_change)
  @real_tabs += tab_change
end

#attributes(class_id, obj_ref, *attributes_hashes) ⇒ Object



195
196
197
198
199
200
201
202
203
# File 'lib/hamlit/parser/haml_buffer.rb', line 195

def attributes(class_id, obj_ref, *attributes_hashes)
  attributes = class_id
  attributes_hashes.each do |old|
    self.class.merge_attrs(attributes, Hash[old.map {|k, v| [k.to_s, v]}])
  end
  self.class.merge_attrs(attributes, parse_object_ref(obj_ref)) if obj_ref
  ::Hamlit::HamlCompiler.build_attributes(
    html?, @options[:attr_wrapper], @options[:escape_attrs], @options[:hyphenate_data_attrs], attributes)
end

#format_script(result, preserve_script, in_tag, preserve_tag, escape_html, nuke_inner_whitespace, interpolated, ugly) ⇒ Object

the number of arguments here is insane, but passing in an options hash instead of named arguments causes a significant performance regression



140
141
142
143
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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/hamlit/parser/haml_buffer.rb', line 140

def format_script(result, preserve_script, in_tag, preserve_tag, escape_html, nuke_inner_whitespace, interpolated, ugly)
  result_name = escape_html ? html_escape(result.to_s) : result.to_s

  if ugly
    result = nuke_inner_whitespace ? result_name.strip : result_name
    result = preserve(result, preserve_script, preserve_tag)
    fix_textareas!(result) if toplevel? && result.include?('<textarea')
    return result
  end

  # If we're interpolated,
  # then the custom tabulation is handled in #push_text.
  # The easiest way to avoid it here is to reset @tabulation.
  if interpolated
    old_tabulation = @tabulation
    @tabulation = 0
  end

  in_tag_no_nuke = in_tag && !nuke_inner_whitespace
  preserved_no_nuke = in_tag_no_nuke && preserve_tag
  tabulation = !preserved_no_nuke && @real_tabs

  result = nuke_inner_whitespace ? result_name.strip : result_name.rstrip
  result = preserve(result, preserve_script, preserve_tag)

  has_newline = !preserved_no_nuke && result.include?("\n")

  if in_tag_no_nuke && (preserve_tag || !has_newline)
    @real_tabs -= 1
    @tabulation = old_tabulation if interpolated
    return result
  end

  unless preserved_no_nuke
    # Precompiled tabulation may be wrong
    result = "#{tabs}#{result}" if !interpolated && !in_tag && @tabulation > 0

    if has_newline
      result.gsub! "\n", "\n#{tabs(tabulation)}"

      # Add tabulation if it wasn't precompiled
      result = "#{tabs(tabulation)}#{result}" if in_tag_no_nuke
    end

    fix_textareas!(result) if toplevel? && result.include?('<textarea')

    if in_tag_no_nuke
      result = "\n#{result}\n#{tabs(tabulation-1)}"
      @real_tabs -= 1
    end
    @tabulation = old_tabulation if interpolated
    result
  end
end

#html4?Boolean

Returns Whether or not the format is HTML4.

Returns:

  • (Boolean)

    Whether or not the format is HTML4



58
59
60
# File 'lib/hamlit/parser/haml_buffer.rb', line 58

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

#html5?Boolean

Returns Whether or not the format is HTML5.

Returns:

  • (Boolean)

    Whether or not the format is HTML5.



63
64
65
# File 'lib/hamlit/parser/haml_buffer.rb', line 63

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

#html?Boolean

Returns Whether or not the format is any flavor of HTML.

Returns:

  • (Boolean)

    Whether or not the format is any flavor of HTML



53
54
55
# File 'lib/hamlit/parser/haml_buffer.rb', line 53

def html?
  html4? or html5?
end

#push_text(text, tab_change, dont_tab_up) ⇒ Object

Appends text to the buffer, properly tabulated. Also modifies the document’s indentation.

Parameters:

  • text (String)

    The text to append

  • tab_change (Fixnum)

    The number of tabs by which to increase or decrease the document’s indentation

  • dont_tab_up (Boolean)

    If true, don’t indent the first line of ‘text`



117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/hamlit/parser/haml_buffer.rb', line 117

def push_text(text, tab_change, dont_tab_up)
  if @tabulation > 0
    # Have to push every line in by the extra user set tabulation.
    # Don't push lines with just whitespace, though,
    # because that screws up precompiled indentation.
    text.gsub!(/^(?!\s+$)/m, tabs)
    text.sub!(tabs, '') if dont_tab_up
  end

  @real_tabs += tab_change
  @buffer << text
end

#rstrip!Object

Remove the whitespace from the right side of the buffer string. Doesn’t do anything if we’re at the beginning of a capture_haml block.



207
208
209
210
211
212
213
214
# File 'lib/hamlit/parser/haml_buffer.rb', line 207

def rstrip!
  if capture_position.nil?
    buffer.rstrip!
    return
  end

  buffer << buffer.slice!(capture_position..-1).rstrip
end

#tabulationFixnum

Returns The current indentation level of the document.

Returns:

  • (Fixnum)

    The current indentation level of the document



83
84
85
# File 'lib/hamlit/parser/haml_buffer.rb', line 83

def tabulation
  @real_tabs + @tabulation
end

#tabulation=(val) ⇒ Object

Sets the current tabulation of the document.

Parameters:

  • val (Fixnum)

    The new tabulation



90
91
92
93
# File 'lib/hamlit/parser/haml_buffer.rb', line 90

def tabulation=(val)
  val = val - @real_tabs
  @tabulation = val > -1 ? val : 0
end

#toplevel?Boolean

Returns Whether or not this buffer is a top-level template, as opposed to a nested partial.

Returns:

  • (Boolean)

    Whether or not this buffer is a top-level template, as opposed to a nested partial



69
70
71
# File 'lib/hamlit/parser/haml_buffer.rb', line 69

def toplevel?
  upper.nil?
end

#xhtml?Boolean

Returns Whether or not the format is XHTML.

Returns:

  • (Boolean)

    Whether or not the format is XHTML



48
49
50
# File 'lib/hamlit/parser/haml_buffer.rb', line 48

def xhtml?
  not html?
end