Module: Arrow::HTMLUtilities

Overview

A collection of HTML utility functions

Constant Summary collapse

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>
}

Class Method Summary collapse

Class Method Details

.escape_html(string) ⇒ Object

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

.make_html_for_object(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

.make_object_html_wrapper(object) ⇒ 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