mullet 0.0.0 → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/mullet/container.rb +8 -4
- data/lib/mullet/default_model.rb +9 -9
- data/lib/mullet/default_nested_model.rb +7 -6
- data/lib/mullet/html/attribute_command.rb +8 -4
- data/lib/mullet/html/attributes.rb +22 -0
- data/lib/mullet/html/command.rb +4 -3
- data/lib/mullet/html/command_element_renderer.rb +19 -0
- data/lib/mullet/html/element.rb +41 -0
- data/lib/mullet/html/element_renderer.rb +261 -0
- data/lib/mullet/html/filtered_element_handler.rb +87 -0
- data/lib/mullet/html/for_element_renderer.rb +47 -0
- data/lib/mullet/html/if_element_renderer.rb +46 -0
- data/lib/mullet/html/layout.rb +48 -0
- data/lib/mullet/html/message.rb +55 -0
- data/lib/mullet/html/message_attribute_command.rb +30 -0
- data/lib/mullet/html/model_attribute_command.rb +30 -0
- data/lib/mullet/html/page_builder.rb +152 -0
- data/lib/mullet/html/parser/attribute.rb +8 -0
- data/lib/mullet/html/parser/constants.rb +1061 -0
- data/lib/mullet/html/parser/default_handler.rb +27 -0
- data/lib/mullet/html/parser/input_stream.rb +711 -0
- data/lib/mullet/html/parser/open_element.rb +77 -0
- data/lib/mullet/html/parser/simple_parser.rb +128 -0
- data/lib/mullet/html/parser/tokenizer.rb +1085 -0
- data/lib/mullet/html/remove_mode.rb +30 -0
- data/lib/mullet/html/static_text_renderer.rb +20 -0
- data/lib/mullet/html/template.rb +44 -0
- data/lib/mullet/html/template_builder.rb +208 -63
- data/lib/mullet/html/template_loader.rb +77 -39
- data/lib/mullet/html/template_parser.rb +48 -0
- data/lib/mullet/html/unless_element_renderer.rb +24 -0
- data/lib/mullet/model.rb +2 -5
- data/lib/mullet/render_context.rb +24 -18
- data/lib/mullet/tilt.rb +37 -0
- data/lib/mullet/version.rb +2 -1
- data/lib/mullet.rb +1 -0
- metadata +58 -11
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'mullet/template_error'
|
2
|
+
|
3
|
+
module Mullet; module HTML
|
4
|
+
|
5
|
+
# Specifies what to remove.
|
6
|
+
class RemoveMode
|
7
|
+
# remove tag, and preserve children of element
|
8
|
+
TAG = RemoveMode.new()
|
9
|
+
|
10
|
+
# preserve tag, and remove children of element
|
11
|
+
CONTENT = RemoveMode.new()
|
12
|
+
|
13
|
+
# remove tag and children of element
|
14
|
+
ELEMENT = RemoveMode.new()
|
15
|
+
|
16
|
+
def self.value_of(argument)
|
17
|
+
string = argument.downcase()
|
18
|
+
if string == 'element'
|
19
|
+
return ELEMENT
|
20
|
+
elsif string == 'tag'
|
21
|
+
return TAG
|
22
|
+
elsif string == 'content'
|
23
|
+
return CONTENT
|
24
|
+
else
|
25
|
+
raise TemplateError.new("invalid remove argument '%{argument}'")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end; end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Mullet; module HTML
|
2
|
+
|
3
|
+
# Renders static markup and text. May end with an unclosed start tag under
|
4
|
+
# the assumption a subsequent static text fragment closes the tag.
|
5
|
+
class StaticTextRenderer
|
6
|
+
|
7
|
+
# Constructor
|
8
|
+
#
|
9
|
+
# @param [String] text
|
10
|
+
# rendered tags and text
|
11
|
+
def initialize(text)
|
12
|
+
@text = text
|
13
|
+
end
|
14
|
+
|
15
|
+
def render(render_context)
|
16
|
+
render_context << @text
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end; end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'mullet/container'
|
2
|
+
require 'mullet/render_context'
|
3
|
+
|
4
|
+
module Mullet; module HTML
|
5
|
+
|
6
|
+
# Template containing static text and dynamically generated content.
|
7
|
+
class Template
|
8
|
+
include Container
|
9
|
+
|
10
|
+
RETURN_EMPTY_STRING = Proc.new { '' }
|
11
|
+
|
12
|
+
def initialize()
|
13
|
+
super
|
14
|
+
@on_missing = RETURN_EMPTY_STRING
|
15
|
+
@on_nil = RETURN_EMPTY_STRING
|
16
|
+
end
|
17
|
+
|
18
|
+
def on_missing(strategy)
|
19
|
+
@on_missing = strategy
|
20
|
+
return self
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_nil(strategy)
|
24
|
+
@on_nil = strategy
|
25
|
+
return self
|
26
|
+
end
|
27
|
+
|
28
|
+
def render(render_context)
|
29
|
+
render_children(render_context)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Renders the template.
|
33
|
+
#
|
34
|
+
# @param [Object] data
|
35
|
+
# provides data to render
|
36
|
+
# @param [#<<] output
|
37
|
+
# where to write rendered output
|
38
|
+
def execute(data, output)
|
39
|
+
render_context = RenderContext.new(data, @on_missing, @on_nil, output)
|
40
|
+
render(render_context)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end; end
|
@@ -1,46 +1,65 @@
|
|
1
|
-
require '
|
1
|
+
require 'mullet/html/attributes'
|
2
2
|
require 'mullet/html/command'
|
3
|
+
require 'mullet/html/element'
|
4
|
+
require 'mullet/html/element_renderer'
|
5
|
+
require 'mullet/html/for_element_renderer'
|
6
|
+
require 'mullet/html/if_element_renderer'
|
7
|
+
require 'mullet/html/parser/default_handler'
|
8
|
+
require 'mullet/html/parser/simple_parser'
|
9
|
+
require 'mullet/html/remove_mode'
|
10
|
+
require 'mullet/html/static_text_renderer'
|
11
|
+
require 'mullet/html/template'
|
12
|
+
require 'mullet/html/unless_element_renderer'
|
13
|
+
require 'mullet/template_error'
|
3
14
|
require 'set'
|
4
15
|
|
5
16
|
module Mullet; module HTML
|
6
17
|
|
7
18
|
# Handles SAX events to build a template.
|
8
|
-
class TemplateBuilder <
|
19
|
+
class TemplateBuilder < Parser::DefaultHandler
|
9
20
|
include Command
|
10
21
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
22
|
+
COMMANDS = Set[
|
23
|
+
ACTION,
|
24
|
+
ALT,
|
25
|
+
ALT_MESSAGE,
|
26
|
+
ATTR,
|
27
|
+
ATTR_MESSAGE,
|
16
28
|
ESCAPE_XML,
|
17
29
|
FOR,
|
30
|
+
HREF,
|
18
31
|
IF,
|
19
32
|
INCLUDE,
|
33
|
+
REMOVE,
|
34
|
+
SRC,
|
20
35
|
TEXT,
|
21
36
|
TEXT_MESSAGE,
|
22
|
-
|
23
|
-
|
24
|
-
|
37
|
+
TITLE,
|
38
|
+
TITLE_MESSAGE,
|
39
|
+
UNLESS,
|
40
|
+
VALUE,
|
41
|
+
VALUE_MESSAGE]
|
42
|
+
START_CDATA = '<![CDATA['
|
43
|
+
END_CDATA = ']]>'
|
25
44
|
|
26
|
-
|
45
|
+
attr_reader :template
|
27
46
|
|
28
|
-
# This is a stack of elements where this handler has seen the start tag and
|
29
|
-
# not yet seen the end tag.
|
30
|
-
@openElements = []
|
31
|
-
|
32
|
-
# stack of current containers to add renderers to
|
33
|
-
@containers = []
|
34
|
-
|
35
|
-
@staticText = ""
|
36
|
-
@template = nil
|
37
|
-
|
38
47
|
# Constructor
|
39
48
|
#
|
40
49
|
# @param [TemplateLoader] loader
|
41
50
|
# template loader to use to load included template files
|
42
51
|
def initialize(loader)
|
43
52
|
@loader = loader
|
53
|
+
|
54
|
+
# Stack of elements where this handler has seen the start tag and not yet
|
55
|
+
# seen the end tag.
|
56
|
+
@open_elements = []
|
57
|
+
|
58
|
+
# stack of current containers to add renderers to
|
59
|
+
@containers = []
|
60
|
+
|
61
|
+
@static_text = ''
|
62
|
+
@template = nil
|
44
63
|
end
|
45
64
|
|
46
65
|
# Adds renderer to current container.
|
@@ -48,7 +67,7 @@ module Mullet; module HTML
|
|
48
67
|
# @param [#render] renderer
|
49
68
|
# renderer to add
|
50
69
|
def add_child(renderer)
|
51
|
-
@containers.last.add_child(renderer)
|
70
|
+
@containers.last().add_child(renderer)
|
52
71
|
end
|
53
72
|
|
54
73
|
# Deletes renderer from current container.
|
@@ -56,7 +75,7 @@ module Mullet; module HTML
|
|
56
75
|
# @param [#render] renderer
|
57
76
|
# renderer to delete
|
58
77
|
def delete_child(renderer)
|
59
|
-
@containers.last.delete_child(renderer)
|
78
|
+
@containers.last().delete_child(renderer)
|
60
79
|
end
|
61
80
|
|
62
81
|
# Partitions the attributes into ordinary and command attributes.
|
@@ -65,77 +84,203 @@ module Mullet; module HTML
|
|
65
84
|
# input attributes
|
66
85
|
# @param [Hash] ns
|
67
86
|
# hash of namespace prefix to uri mappings
|
68
|
-
# @param [#store]
|
87
|
+
# @param [#store] ordinary_attributes
|
69
88
|
# hash will receive name to value mappings for ordinary attributes
|
70
|
-
# @param [#store]
|
89
|
+
# @param [#store] command_attributes
|
71
90
|
# hash will receive name to value mappings for command attributes
|
72
91
|
# @return [Boolean] true if any command attribute found
|
73
|
-
def find_commands(attributes, ns,
|
74
|
-
|
92
|
+
def find_commands(attributes, ns, ordinary_attributes, command_attributes)
|
93
|
+
found_command = false
|
75
94
|
attributes.each do |attr|
|
76
|
-
if attr.
|
77
|
-
|
78
|
-
if
|
79
|
-
|
95
|
+
if attr.localname.start_with?(DATA_PREFIX)
|
96
|
+
command_name = attr.localname.slice(DATA_PREFIX.length()..-1)
|
97
|
+
if COMMANDS.include?(command_name)
|
98
|
+
command_attributes.store(command_name, attr.value)
|
99
|
+
found_command = true
|
100
|
+
end
|
101
|
+
elsif attr.uri == NAMESPACE_URI || attr.prefix == NAMESPACE_PREFIX
|
102
|
+
command_name = attr.localname
|
103
|
+
if !COMMANDS.include?(command_name)
|
104
|
+
raise TemplateError("invalid command '#{command_name}'")
|
80
105
|
end
|
81
|
-
|
82
|
-
|
106
|
+
command_attributes.store(command_name, attr.value)
|
107
|
+
found_command = true
|
83
108
|
else
|
84
|
-
|
85
|
-
|
109
|
+
attribute_name = [attr.prefix, attr.localname].compact().join(':')
|
110
|
+
ordinary_attributes.store(attribute_name, attr.value)
|
86
111
|
end
|
87
112
|
end
|
88
113
|
|
89
114
|
ns.each do |prefix, uri|
|
90
115
|
if uri != NAMESPACE_URI
|
91
|
-
|
92
|
-
|
116
|
+
attribute_name = ['xmlns', prefix].compact().join(':')
|
117
|
+
ordinary_attributes.store(attribute_name, uri)
|
93
118
|
end
|
94
119
|
end
|
95
120
|
|
96
|
-
return
|
121
|
+
return found_command
|
97
122
|
end
|
98
123
|
|
99
|
-
def
|
100
|
-
|
101
|
-
|
102
|
-
|
124
|
+
def append_static_text(data)
|
125
|
+
@static_text << data
|
126
|
+
end
|
127
|
+
|
128
|
+
def end_static_text()
|
129
|
+
if !@static_text.empty?()
|
130
|
+
add_child(StaticTextRenderer.new(@static_text))
|
131
|
+
@static_text = ''
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# Marks the most deeply nested open element as having content.
|
136
|
+
def set_has_content()
|
137
|
+
if !@open_elements.empty?()
|
138
|
+
@open_elements.last().has_content = true
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def start_document()
|
143
|
+
@template = Template.new()
|
144
|
+
@containers.push(@template)
|
145
|
+
end
|
146
|
+
|
147
|
+
def end_document()
|
148
|
+
end_static_text()
|
149
|
+
end
|
150
|
+
|
151
|
+
def doctype(name, public_id, system_id)
|
152
|
+
text = "<!DOCTYPE #{name}"
|
153
|
+
|
154
|
+
if public_id
|
155
|
+
text << %( PUBLIC "#{public_id}")
|
156
|
+
end
|
157
|
+
|
158
|
+
if system_id
|
159
|
+
text << %( "#{system_id}")
|
160
|
+
end
|
161
|
+
|
162
|
+
text << '>'
|
163
|
+
append_static_text(text)
|
164
|
+
end
|
165
|
+
|
166
|
+
def create_element_renderer(element, command_attributes)
|
167
|
+
renderer = nil
|
168
|
+
|
169
|
+
variable_name = command_attributes.fetch(IF, nil)
|
170
|
+
if variable_name != nil
|
171
|
+
renderer = IfElementRenderer.new(element, variable_name)
|
103
172
|
end
|
104
|
-
tag << name
|
105
173
|
|
106
|
-
|
107
|
-
|
108
|
-
if
|
109
|
-
|
174
|
+
if renderer == nil
|
175
|
+
variable_name = command_attributes.fetch(UNLESS, nil)
|
176
|
+
if variable_name != nil
|
177
|
+
renderer = UnlessElementRenderer.new(element, variable_name)
|
110
178
|
end
|
111
|
-
tag = attribute.localname << '="' << attribute.value << '"'
|
112
179
|
end
|
113
180
|
|
114
|
-
|
115
|
-
|
116
|
-
if
|
117
|
-
|
181
|
+
if renderer == nil
|
182
|
+
variable_name = command_attributes.fetch(FOR, nil)
|
183
|
+
if variable_name != nil
|
184
|
+
renderer = ForElementRenderer.new(element, variable_name)
|
118
185
|
end
|
119
186
|
end
|
120
187
|
|
121
|
-
|
122
|
-
|
188
|
+
if renderer == nil
|
189
|
+
renderer = ElementRenderer.new(element)
|
190
|
+
end
|
191
|
+
|
192
|
+
renderer.configure_commands(command_attributes, @loader)
|
193
|
+
return renderer
|
123
194
|
end
|
124
195
|
|
125
196
|
def start_element_namespace(name, attributes, prefix, uri, ns)
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
197
|
+
set_has_content()
|
198
|
+
|
199
|
+
ordinary_attributes = Attributes.new()
|
200
|
+
command_attributes = Attributes.new()
|
201
|
+
found_command = find_commands(
|
202
|
+
attributes, ns, ordinary_attributes, command_attributes)
|
203
|
+
|
204
|
+
qualified_name = [prefix, name].compact().join(':')
|
205
|
+
element = Element.new(qualified_name, ordinary_attributes)
|
206
|
+
@open_elements.push(element)
|
207
|
+
|
208
|
+
if found_command
|
209
|
+
end_static_text()
|
210
|
+
|
211
|
+
element.has_command = true
|
212
|
+
renderer = create_element_renderer(element, command_attributes)
|
213
|
+
add_child(renderer)
|
214
|
+
|
215
|
+
@containers.push(renderer)
|
132
216
|
else
|
133
|
-
|
217
|
+
append_static_text(element.render_start_tag(element.attributes))
|
134
218
|
end
|
135
219
|
end
|
136
220
|
|
137
|
-
def
|
138
|
-
|
221
|
+
def configure_remove_command(element, renderer)
|
222
|
+
case renderer.remove_mode
|
223
|
+
when RemoveMode::TAG
|
224
|
+
if !renderer.has_command && !renderer.has_dynamic_content
|
225
|
+
# Discard tag, but preserve the children.
|
226
|
+
delete_child(renderer)
|
227
|
+
renderer.children.each do |child|
|
228
|
+
add_child(child)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
when RemoveMode::CONTENT
|
232
|
+
if !renderer.has_command
|
233
|
+
# Discard children. Statically render the tag.
|
234
|
+
delete_child(renderer)
|
235
|
+
|
236
|
+
append_static_text(element.render_start_tag(element.attributes))
|
237
|
+
append_static_text(element.render_end_tag())
|
238
|
+
end
|
239
|
+
when RemoveMode::ELEMENT
|
240
|
+
# Discard element and all its content.
|
241
|
+
delete_child(renderer)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def end_element_namespace(name, prefix, uri)
|
246
|
+
element = @open_elements.pop()
|
247
|
+
if element.has_command
|
248
|
+
end_static_text()
|
249
|
+
|
250
|
+
renderer = @containers.pop()
|
251
|
+
if renderer.has_dynamic_content
|
252
|
+
# Discard children because the content will be replaced at render
|
253
|
+
# time.
|
254
|
+
renderer.clear_children()
|
255
|
+
end
|
256
|
+
|
257
|
+
configure_remove_command(element, renderer)
|
258
|
+
elsif uri != Parser::SimpleParser::IMPLICIT_END_TAG_NS_URI
|
259
|
+
append_static_text(element.render_end_tag())
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def characters(data)
|
264
|
+
set_has_content()
|
265
|
+
append_static_text(data)
|
266
|
+
end
|
267
|
+
|
268
|
+
def cdata_block(data)
|
269
|
+
append_static_text(START_CDATA)
|
270
|
+
characters(data)
|
271
|
+
append_static_text(END_CDATA)
|
272
|
+
end
|
273
|
+
|
274
|
+
def comment(data)
|
275
|
+
append_static_text('<!--')
|
276
|
+
characters(data)
|
277
|
+
append_static_text('-->')
|
278
|
+
end
|
279
|
+
|
280
|
+
def processing_instruction(data)
|
281
|
+
append_static_text('<?')
|
282
|
+
characters(data)
|
283
|
+
append_static_text('?>')
|
139
284
|
end
|
140
285
|
end
|
141
286
|
|
@@ -1,55 +1,93 @@
|
|
1
|
-
require '
|
1
|
+
require 'mullet/html/template'
|
2
|
+
require 'mullet/html/template_parser'
|
2
3
|
|
3
|
-
module Mullet
|
4
|
+
module Mullet; module HTML
|
4
5
|
|
5
|
-
|
6
|
-
|
6
|
+
# Loads templates from files, and caches them for fast retrieval of already
|
7
|
+
# loaded templates.
|
8
|
+
#
|
9
|
+
# By default, templates render an empty string when a variable is not found
|
10
|
+
# or its value is null. Call the `on_missing` and `on_nil` methods to
|
11
|
+
# configure how templates loaded by this loader should handle missing and nil
|
12
|
+
# values respectively.
|
13
|
+
class TemplateLoader
|
14
|
+
|
15
|
+
attr_accessor :template_path
|
7
16
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
17
|
+
# Constructor
|
18
|
+
#
|
19
|
+
# @param [String] template_path
|
20
|
+
# name of directory to load templates from
|
21
|
+
def initialize(template_path)
|
22
|
+
@template_path = template_path
|
23
|
+
@template_cache = Hash.new()
|
24
|
+
@parser = TemplateParser.new(self)
|
25
|
+
@on_missing = Template::RETURN_EMPTY_STRING
|
26
|
+
@on_nil = Template::RETURN_EMPTY_STRING
|
27
|
+
end
|
28
|
+
|
29
|
+
# Sets block to execute on attempt to render a variable that was not found.
|
30
|
+
#
|
31
|
+
# @param [Proc] strategy
|
32
|
+
# The value returned from block will be rendered.
|
33
|
+
# @return [TemplateLoader] this object to allow method call chaining
|
34
|
+
def on_missing(strategy)
|
35
|
+
@on_missing = strategy
|
36
|
+
return self
|
12
37
|
end
|
13
|
-
tag << name
|
14
38
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
39
|
+
# Sets block to execute on attempt to render a nil value.
|
40
|
+
#
|
41
|
+
# @param [Proc] strategy
|
42
|
+
# The value returned from block will be rendered.
|
43
|
+
# @return [TemplateLoader] this object to allow method call chaining
|
44
|
+
def on_nil(strategy)
|
45
|
+
@on_nil = strategy
|
46
|
+
return self
|
21
47
|
end
|
22
48
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
49
|
+
# Loads named template.
|
50
|
+
#
|
51
|
+
# @param [String] uri
|
52
|
+
# file name optionally followed by `#`_id_
|
53
|
+
def load(uri)
|
54
|
+
id = nil
|
55
|
+
hash_index = uri.index('#')
|
56
|
+
if hash_index
|
57
|
+
id = uri[(hash_index + 1)..-1]
|
58
|
+
uri = uri[0...hash_index]
|
27
59
|
end
|
60
|
+
|
61
|
+
return load_file(uri, id)
|
28
62
|
end
|
29
63
|
|
30
|
-
|
31
|
-
return tag
|
32
|
-
end
|
64
|
+
private
|
33
65
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
66
|
+
def get_cache_key(file_name, id)
|
67
|
+
cache_key = File.join(@template_path, file_name)
|
68
|
+
if id != nil
|
69
|
+
cache_key << '#' << id
|
70
|
+
end
|
71
|
+
return cache_key
|
38
72
|
end
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
73
|
+
|
74
|
+
def parse_file(file_name, id)
|
75
|
+
template_file = File.join(@template_path, file_name)
|
76
|
+
template = @parser.parse_file(template_file, id)
|
77
|
+
|
78
|
+
template.on_missing(@on_missing).on_nil(@on_nil)
|
79
|
+
return template
|
43
80
|
end
|
44
|
-
end
|
45
81
|
|
46
|
-
|
47
|
-
|
82
|
+
def load_file(file_name, id)
|
83
|
+
cache_key = get_cache_key(file_name, id)
|
84
|
+
template = @template_cache.fetch(cache_key, nil)
|
85
|
+
if template == nil
|
86
|
+
template = parse_file(file_name, id)
|
87
|
+
@template_cache.store(cache_key, template)
|
88
|
+
end
|
89
|
+
return template
|
90
|
+
end
|
48
91
|
end
|
49
|
-
end
|
50
92
|
|
51
|
-
|
52
|
-
f = File.open("login.html")
|
53
|
-
parser.parse(f)
|
54
|
-
f.close
|
55
|
-
end
|
93
|
+
end; end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'mullet/html/filtered_element_handler'
|
2
|
+
require 'mullet/html/parser/simple_parser'
|
3
|
+
require 'mullet/html/template_builder'
|
4
|
+
|
5
|
+
module Mullet; module HTML
|
6
|
+
|
7
|
+
class TemplateParser
|
8
|
+
|
9
|
+
def initialize(loader)
|
10
|
+
@loader = loader
|
11
|
+
end
|
12
|
+
|
13
|
+
# Parses template from string.
|
14
|
+
#
|
15
|
+
# @param [String] source
|
16
|
+
# string to parse
|
17
|
+
# @return [Template] template
|
18
|
+
def parse(source)
|
19
|
+
template_builder = TemplateBuilder.new(@loader)
|
20
|
+
parser = Parser::SimpleParser.new(template_builder)
|
21
|
+
parser.parse(source)
|
22
|
+
return template_builder.template
|
23
|
+
end
|
24
|
+
|
25
|
+
# Parses template from file.
|
26
|
+
#
|
27
|
+
# @param [String] file_name
|
28
|
+
# name of file containing template
|
29
|
+
# @param [String] id
|
30
|
+
# If `nil`, then the template is the entire file, otherwise the
|
31
|
+
# template is the content of the element having an `id` attribute
|
32
|
+
# value equal to this argument.
|
33
|
+
# @return [Template] template
|
34
|
+
def parse_file(file_name, id)
|
35
|
+
template_builder = TemplateBuilder.new(@loader)
|
36
|
+
handler = (id == nil) ?
|
37
|
+
template_builder : FilteredElementHandler.new(template_builder, id)
|
38
|
+
|
39
|
+
parser = Parser::SimpleParser.new(handler)
|
40
|
+
File.open(file_name) do |file|
|
41
|
+
parser.parse(file)
|
42
|
+
end
|
43
|
+
|
44
|
+
return template_builder.template
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end; end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'mullet/html/if_element_renderer'
|
2
|
+
|
3
|
+
module Mullet; module HTML
|
4
|
+
|
5
|
+
# Renders an element if variable is false.
|
6
|
+
class UnlessElementRenderer < IfElementRenderer
|
7
|
+
|
8
|
+
# Constructor
|
9
|
+
#
|
10
|
+
# @param [Element] element
|
11
|
+
# element to render
|
12
|
+
# @param [String] variable_name
|
13
|
+
# name of variable containing condition
|
14
|
+
def initialize(element, variable_name)
|
15
|
+
super(element, variable_name)
|
16
|
+
@variable_name = variable_name.to_sym()
|
17
|
+
end
|
18
|
+
|
19
|
+
def should_render_element(render_context)
|
20
|
+
return !super
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end; end
|
data/lib/mullet/model.rb
CHANGED
@@ -1,10 +1,7 @@
|
|
1
1
|
module Mullet
|
2
2
|
|
3
|
-
# A model responds to the method `
|
4
|
-
# returning the variable value.
|
5
|
-
# returns the value `NOT_FOUND` instead of raising an exception. A model
|
6
|
-
# class must include this module because the implementation calls
|
7
|
-
# `is_a?(Model)` to determine if an object satisfies the concept of a model.
|
3
|
+
# A model responds to the method `get_variable_value` taking a variable name
|
4
|
+
# argument and returning the variable value.
|
8
5
|
module Model
|
9
6
|
|
10
7
|
# special value indicating variable name was not found
|