Class: Hoshi::View

Inherits:
Object
  • Object
show all
Defined in:
lib/hoshi/view.rb,
lib/hoshi/view/svg.rb,
lib/hoshi/view/html.rb,
lib/hoshi/view/rss2.rb,
lib/hoshi/view/html3.rb,
lib/hoshi/view/html4.rb,
lib/hoshi/view/html5.rb,
lib/hoshi/view/xhtml.rb,
lib/hoshi/view/xhtml1.rb,
lib/hoshi/view/xhtml2.rb,
lib/hoshi/view/xhtml1_strict.rb,
lib/hoshi/view/html4_frameset.rb,
lib/hoshi/view/xhtml1_frameset.rb,
lib/hoshi/view/html4_transitional.rb,
lib/hoshi/view/xhtml1_transitional.rb

Overview

The View class is the super-class for views you create with Hoshi. More likely, though, you’ll be using one of View’s many sub-classes as the super-class for your view, like this:

class MyView < Hoshi::View :html5

or

class MyView < Hoshi::View::XHTML1Frameset

Of course, using View[] is the preferred method for the sake of brevity. When you create a view class, you’ll want to define one or more methods that eventually call View#render, which turns your view into HTML. (Private methods and methods that build up state do not need to do so.)

Direct Known Subclasses

HTML, RSS2, SVG

Defined Under Namespace

Classes: HTML, HTML3, HTML4, HTML4Frameset, HTML4Transitional, HTML5, RSS2, SVG, ValidationError, XHTML, XHTML1, XHTML1Frameset, XHTML1Transitional, XHTML2

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeView

Returns a new instance of View.



112
113
114
115
# File 'lib/hoshi/view.rb', line 112

def initialize
	@tcache = {}
	clear!
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(mname, *args, &b) ⇒ Object

Dynamically add tags if the view class for this object is permissive.



210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/hoshi/view.rb', line 210

def method_missing(mname, *args, &b)
	if self.class.permissive?
		self.class.tag mname
		if b
			send mname, *args, &b
		else
			send mname, *args
		end
	else
		super
	end
end

Class Method Details

.[](doctype) ⇒ Object

This method choses, based on the provided doctype, the proper sub-class of View. Generally, you’ll be using this rather than sub-classing View directly. The doctype argument is case- and underscore-insensitive, and valid arguments are names of View subclasses that are inside the View namespace.



56
57
58
59
60
61
62
63
# File 'lib/hoshi/view.rb', line 56

def self.[] doctype
	doctype = doctype.to_s.downcase.gsub('_', '')
	const_get(constants.find { |c| 
		cl = const_get c
		(cl.ancestors.include?(self) && 
		 c.to_s.downcase == doctype) rescue false
	}) rescue nil
end

.build(*args, &block) ⇒ Object

Create and render a view via a block.



97
98
99
100
101
# File 'lib/hoshi/view.rb', line 97

def self.build(*args, &block)
	c = new(*args)
	c.instance_eval(&block)
	c.render
end

.content_typeObject

This is overridden in HTML/XHTML, and you’ll definitely want to override it if you subclass View directly.



105
106
107
# File 'lib/hoshi/view.rb', line 105

def self.content_type
	'application/octet-stream'
end

.dtd!(dtd) ⇒ Object

Sets the doctype declaration for this class.



66
67
68
69
# File 'lib/hoshi/view.rb', line 66

def self.dtd! dtd
	dtd += "\n"
	define_method(:doctype) { append! dtd }
end

.open_tags(*names) ⇒ Object

A short-hand for creating multiple tags that are left open.



43
44
45
# File 'lib/hoshi/view.rb', line 43

def self.open_tags *names
	names.map { |n| tag n, :none }
end

.permissive!Object

Free-form tags. Basically, dynamic tag creation by method_missing.



76
77
78
# File 'lib/hoshi/view.rb', line 76

def self.permissive!
	@permissive = true
end

.permissive?Boolean

Returns true if we add tags to this class on the fly.

Returns:

  • (Boolean)


81
82
83
# File 'lib/hoshi/view.rb', line 81

def self.permissive?
	@permissive
end

.self_closing_tags(*names) ⇒ Object



47
48
49
# File 'lib/hoshi/view.rb', line 47

def self.self_closing_tags *names
	names.map { |n| tag n, :self }
end

.strict!Object

Only the tags already specified are allowed. No dynamic tag creation. This is the default.



87
88
89
# File 'lib/hoshi/view.rb', line 87

def self.strict!
	@permissive = false
end

.strict?Boolean

Returns true if we do not add tags to the class on the fly.

Returns:

  • (Boolean)


92
93
94
# File 'lib/hoshi/view.rb', line 92

def self.strict?
	!permissive?
end

.tag(name, close_type = nil) ⇒ Object

This creates an instance method for this view which appends a tag. Most of these are handled for you. The arguments to this method match those to Tag.new. See also View.permissive!. tag(‘h1’) def show_an_h1 h1 “I have been shown” end



24
25
26
27
28
29
30
31
32
33
34
# File 'lib/hoshi/view.rb', line 24

def self.tag(name, close_type = nil)
	define_method(name) { |*opts,&b|
		if b
			tag name, close_type, *opts, &b
		else
			tag name, close_type, *opts
		end
	}
	# Inline tags.
	define_method("_#{name}") { |*opts| _tag name, close_type, *opts }
end

.tags(*names) ⇒ Object

A short-hand for creating multiple tags via View.tag. For tags that do not require closing, see View.open_tags.



38
39
40
# File 'lib/hoshi/view.rb', line 38

def self.tags *names
	names.map &method(:tag)
end

Instance Method Details

#_tag(tname, close_type = nil, inside = '', opts = {}) ⇒ Object

An inline tag; it just returns a string rather than updating the view object in place. Useful for things like p “Here is a paragraph and a #‘link’, :href => ‘/’.”



161
162
163
164
# File 'lib/hoshi/view.rb', line 161

def _tag(tname, close_type = nil, inside = '', opts = {})
	t = otag(tname, close_type)
	t.render(inside, opts)
end

#append!(x) ⇒ Object

Appends something to the document. The comment, decl, and various tag methods call this.



168
169
170
171
# File 'lib/hoshi/view.rb', line 168

def append! x
	current << x
	x
end

#clear!Object

Clears the current state of this view.



118
119
120
121
# File 'lib/hoshi/view.rb', line 118

def clear!
	self.tree = []
	self.current = tree
end

#comment(*a) ⇒ Object

Adds a comment.



128
129
130
131
132
133
134
# File 'lib/hoshi/view.rb', line 128

def comment(*a)
	if a.include?('--')
		raise ValidationError, "Comments can't include '--'."
	else
		append! "<!-- #{a} -->"
	end
end

#doc(&b) ⇒ Object

If you’re tired of typing “doctypenhtml” every single time.



174
175
176
177
# File 'lib/hoshi/view.rb', line 174

def doc &b
	doctype
	html &b
end

#doctypeObject



70
71
72
73
# File 'lib/hoshi/view.rb', line 70

def doctype
	comment "No doctype defined; are you sub-classing View directly " \
		"and not calling dtd!()?"
end

#entity(e) ⇒ Object



136
137
138
# File 'lib/hoshi/view.rb', line 136

def entity e
	raw "&#{e};"
end

#otag(*a) ⇒ Object



123
124
125
# File 'lib/hoshi/view.rb', line 123

def otag(*a)
	@tcache[a] ||= Tag.new(*a)
end

#raw(*things) ⇒ Object

Appends one or more non-escaped strings to the document.



186
187
188
# File 'lib/hoshi/view.rb', line 186

def raw *things
	append! things.join
end

#renderObject

Returns the string representation of the document. This is what you want to eventually call.



192
193
194
# File 'lib/hoshi/view.rb', line 192

def render
	tree.flatten.map(&:to_s).join
end

#render_cgi(extra_headers = {}) ⇒ Object

Prints the string representation of the docutment, with HTTP headers. Useful for one-off CGI scripts. Takes an optional hash argument for headers (Content-Type and Status are set by default). See CGI#header for information on how the header hash should look.



200
201
202
203
204
205
206
207
# File 'lib/hoshi/view.rb', line 200

def render_cgi(extra_headers = {})
	h = { 
		'type' => self.class.content_type,
		'status' => 'OK',
	}.merge(extra_headers)

	CGI.new.out(h) { render }
end

#safe(*things) ⇒ Object

Turns things in to strings, properly escapes them, and appends them to the document.



181
182
183
# File 'lib/hoshi/view.rb', line 181

def safe *things
	append! CGI.escapeHTML(things.map(&:to_s).join("\n"))
end

#tag(tname, close_type = nil, *opts, &b) ⇒ Object

Appends a tag to the current document, for when a tag is only needed once or has a name that is not a valid method name.



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/hoshi/view.rb', line 142

def tag(tname, close_type = nil, *opts, &b)
	t = otag(tname, close_type)

	if b
		old, self.current = current, []
		# These two lines let you do 'asdf { "jkl" }' like Markaby.
		r = b.call
		current << r.to_s if current.empty?
		inside, self.current = current.map(&:to_s).join, old
	elsif opts.first.kind_of? String
		inside = CGI.escapeHTML(opts.shift)
	end

	append! t.render(inside, opts.first || {})
end