Module: Arrow::HTMLUtilities

Included in:
HtmlInspectableObject, Logger::ArrayOutputter, Logger::HtmlOutputter, Service, Template::Node
Defined in:
lib/arrow/mixins.rb

Overview

A collection of HTML utility functions

Constant Summary

THREAD_DUMP_KEY =

The name of the Thread-local variable to keep the serialized-object cache in (i.e., Thread[ THREAD_DUMP_KEY ] = {}). The cache is keyed by object_id

:__to_html_cache__
HASH_HTML_CONTAINER =

The HTML fragment to wrap around Hash objects

%{<div class="hash-members">%s</div>}
HASH_PAIR_HTML =

The HTML fragment to use for pairs of a Hash

%{<div class="hash-pair %s">\n} +
%{<div class="key">%s</div>\n} +
%{<div class="value">%s</div>\n} +
%{</div>\n}
ARRAY_HTML_CONTAINER =

The HTML fragment to wrap around Array objects

%{<ol class="array-members"><li>%s</li></ol>}
IMMEDIATE_OBJECT_HTML_CONTAINER =

The HTML fragment to wrap around immediate objects

%{<div class="immediate-object">%s</div>}
OBJECT_HTML_CONTAINER =

The HTML fragment to wrap around objects other than Arrays and Hashes.

%{<div id="object-%d" class="object %s">%s</div>}
IVAR_HTML_FRAGMENT =

The HTML fragment to use for instance variables inside of object DIVs.

%Q{
  <div class="%s">
  <div class="name">%s</div>
  <div class="value">%s</div>
  </div>
}

Instance Method Summary

Instance Method Details

- (Object) escape_html(string)

Escape special characters in the given string for display in an HTML inspection interface. This escapes common invisible characters like tabs and carriage-returns in additional to the regular HTML escapes.



170
171
172
173
174
175
176
177
178
179
# File 'lib/arrow/mixins.rb', line 170

def escape_html( string )
  return "nil" if string.nil?
  string = string.inspect unless string.is_a?( String )
  string.
    gsub(/&/, '&amp;').
    gsub(/</, '&lt;').
    gsub(/>/, '&gt;').
    gsub(/\n/, '&#8629;').
    gsub(/\t/, '&#8594;')
end

- (Object) make_html_for_object(object)

Return an HTML fragment describing the specified object.



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/arrow/mixins.rb', line 183

def make_html_for_object( object )
  return object.html_inspect if 
    object.respond_to?( :html_inspect ) && ! object.is_a?( HtmlInspectableObject )
  object_html = []

  case object
  when Hash
    object_html << "\n<!-- Hash -->\n"
    if object.empty?
      object_html << '{}'
    else
      object_html << HASH_HTML_CONTAINER % [
        object.collect {|k,v|
          pairclass = v.instance_variables.empty? ? 
            "simple-hash-pair" :
            "complex-hash-pair"
          HASH_PAIR_HTML % [
            pairclass,
            make_html_for_object(k),
            make_html_for_object(v),
            ]
        }
      ]
    end

  when Array
    object_html << "\n<!-- Array -->\n"
    if object.empty?
      object_html << '[]'
    else
      object_html << ARRAY_HTML_CONTAINER % [
        object.collect {|o| make_html_for_object(o) }.join('</li><li>')
      ]
    end

  else
    if object.instance_variables.empty?
      return IMMEDIATE_OBJECT_HTML_CONTAINER %
        [ HTMLUtilities.escape_html(object.inspect) ]
    else
      object_html << make_object_html_wrapper( object )
    end
  end

  return object_html.join("\n")
end

- (Object) make_object_html_wrapper(object)

Wrap up the various parts of a complex object in an HTML fragment. If the object has already been wrapped, returns a link to the previous rendering instead.



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
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/arrow/mixins.rb', line 234

def make_object_html_wrapper( object )

  # If the object has been rendered already, just return a link to the previous
  # HTML fragment
  Thread.current[ THREAD_DUMP_KEY ] ||= {}
  if Thread.current[ THREAD_DUMP_KEY ].key?( object.object_id )
    return %Q{<a href="#object-%d" class="cache-link" title="jump to previous details">%s</a>} % [
      object.object_id,
      %{&rarr; %s #%d} % [ object.class.name, object.object_id ]
    ]
  else
    Thread.current[ THREAD_DUMP_KEY ][ object.object_id ] = true
  end

  # Assemble the innards as an array of parts
  parts = [
    %{<div class="object-header">},
    %{<span class="object-class">#{object.class.name}</span>},
    %{<span class="object-id">##{object.object_id}</span>},
    %{</div>},
    %{<div class="object-body">},
  ]

  object.instance_variables.sort.each do |ivar|
    value = object.instance_variable_get( ivar )
    html = make_html_for_object( value )
    classes = %w[instance-variable]
    if value.instance_variables.empty? && !value.respond_to?( :values_at )
      classes << 'simple'
    else
      classes << 'complex'
    end
    parts << IVAR_HTML_FRAGMENT % [ classes.join(' '), ivar, html ]
  end

  parts << %{</div>}

  # Make HTML class names out of the object's namespaces
  namespaces = object.class.name.downcase.split(/::/)
  classes = []
  namespaces.each_index do |i|
    classes << namespaces[0..i].join('-') + '-object'
  end

  # Glue the whole thing together and return it
  return OBJECT_HTML_CONTAINER % [
    object.object_id,
    classes.join(" "),
    parts.join("\n")
  ]
end