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,77 @@
|
|
1
|
+
require 'mullet/html/parser/attribute'
|
2
|
+
require 'mullet/html/parser/constants'
|
3
|
+
require 'mullet/html/parser/input_stream'
|
4
|
+
|
5
|
+
module Mullet; module HTML; module Parser
|
6
|
+
|
7
|
+
# Element where the parser has seen the start tag but not yet seen the end
|
8
|
+
# tag.
|
9
|
+
class OpenElement
|
10
|
+
|
11
|
+
XMLNS_ATTRIBUTE = 'xmlns'
|
12
|
+
XMLNS_ATTRIBUTE_PREFIX = XMLNS_ATTRIBUTE + ':'
|
13
|
+
|
14
|
+
attr_reader :parent, :qualified_name, :prefix, :local_name, :uri
|
15
|
+
attr_reader :attributes, :namespace_declarations
|
16
|
+
|
17
|
+
def initialize(parent, qualified_name, raw_attributes)
|
18
|
+
# namespace prefix to URI map
|
19
|
+
@namespace_declarations = Hash.new()
|
20
|
+
|
21
|
+
@parent = parent
|
22
|
+
|
23
|
+
process_namespace_declarations(raw_attributes)
|
24
|
+
@qualified_name = qualified_name
|
25
|
+
@prefix, @local_name = extract_prefix_and_local_name(qualified_name)
|
26
|
+
@uri = resolve_prefix_to_uri(@prefix)
|
27
|
+
|
28
|
+
@attributes = to_namespace_aware_attributes(raw_attributes)
|
29
|
+
end
|
30
|
+
|
31
|
+
def resolve_prefix_to_uri(prefix)
|
32
|
+
uri = @namespace_declarations.fetch(prefix, nil)
|
33
|
+
if uri == nil && @parent != nil
|
34
|
+
return @parent.resolve_prefix_to_uri(prefix)
|
35
|
+
end
|
36
|
+
return uri
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def declare_namespace(raw_attribute_name, uri)
|
42
|
+
if raw_attribute_name.start_with?(XMLNS_ATTRIBUTE_PREFIX)
|
43
|
+
prefix = raw_attribute_name[XMLNS_ATTRIBUTE_PREFIX.length()..-1]
|
44
|
+
else
|
45
|
+
prefix = nil
|
46
|
+
end
|
47
|
+
@namespace_declarations.store(prefix, uri)
|
48
|
+
end
|
49
|
+
|
50
|
+
def process_namespace_declarations(raw_attributes)
|
51
|
+
raw_attributes.each do |attribute_name, attribute_value|
|
52
|
+
if attribute_name.start_with?(XMLNS_ATTRIBUTE)
|
53
|
+
declare_namespace(attribute_name, attribute_value)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def extract_prefix_and_local_name(qualified_name)
|
59
|
+
name_parts = qualified_name.split(':', 2)
|
60
|
+
prefix = (name_parts.size() > 1) ? name_parts[0] : nil
|
61
|
+
local_name = (name_parts.size() > 1) ? name_parts[1] : qualified_name
|
62
|
+
return [prefix, local_name]
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_namespace_aware_attributes(raw_attributes)
|
66
|
+
attributes = []
|
67
|
+
raw_attributes.each do |qualified_name, attribute_value|
|
68
|
+
prefix, local_name = extract_prefix_and_local_name(qualified_name)
|
69
|
+
uri = resolve_prefix_to_uri(prefix)
|
70
|
+
attributes << Attribute.new(local_name, prefix, uri, attribute_value)
|
71
|
+
end
|
72
|
+
|
73
|
+
return attributes
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end; end; end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'mullet/html/parser/open_element'
|
2
|
+
require 'mullet/html/parser/tokenizer'
|
3
|
+
require 'mullet/template_error'
|
4
|
+
|
5
|
+
module Mullet; module HTML; module Parser
|
6
|
+
|
7
|
+
# SAX parser that reports elements in the order they appear in the input.
|
8
|
+
# Does not move elements to another parent.
|
9
|
+
class SimpleParser
|
10
|
+
|
11
|
+
# special namespace URI indicating parser generated an implicit end tag
|
12
|
+
IMPLICIT_END_TAG_NS_URI = 'http://pukkaone.github.com/mullet/end-tag'
|
13
|
+
|
14
|
+
# Constructor
|
15
|
+
#
|
16
|
+
# @param [DefaultHandler] handler
|
17
|
+
# object to receive events
|
18
|
+
def initialize(handler)
|
19
|
+
@handler = handler
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse(input)
|
23
|
+
@open_element = nil
|
24
|
+
@handler.start_document()
|
25
|
+
|
26
|
+
tokenizer = Tokenizer.new(input)
|
27
|
+
tokenizer.each do |token|
|
28
|
+
case token[:type]
|
29
|
+
when :Doctype
|
30
|
+
doctype(token[:name], token[:publicId], token[:systemId])
|
31
|
+
when :StartTag
|
32
|
+
start_tag(token[:name], token[:data])
|
33
|
+
when :EndTag
|
34
|
+
end_tag(token[:name])
|
35
|
+
when :Characters, :SpaceCharacters
|
36
|
+
characters(token[:data])
|
37
|
+
when :CDATA
|
38
|
+
cdata(token[:data])
|
39
|
+
when :Comment
|
40
|
+
comment(token[:data])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
@handler.end_document()
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def doctype(name, public_id, system_id)
|
50
|
+
@handler.doctype(name, public_id, system_id)
|
51
|
+
end
|
52
|
+
|
53
|
+
def start_tag(name, attributes)
|
54
|
+
# Push open element onto stack.
|
55
|
+
element = OpenElement.new(@open_element, name, attributes)
|
56
|
+
@open_element = element
|
57
|
+
|
58
|
+
@handler.start_element_namespace(
|
59
|
+
element.local_name,
|
60
|
+
element.attributes,
|
61
|
+
element.prefix,
|
62
|
+
element.uri,
|
63
|
+
element.namespace_declarations)
|
64
|
+
end
|
65
|
+
|
66
|
+
def pop_open_element()
|
67
|
+
element = @open_element
|
68
|
+
if @open_element != nil
|
69
|
+
@open_element = @open_element.parent
|
70
|
+
end
|
71
|
+
return element
|
72
|
+
end
|
73
|
+
|
74
|
+
def raise_mismatched_end_tag(name)
|
75
|
+
raise TemplateError.new("End tag </#{name}> has no matching start tag")
|
76
|
+
end
|
77
|
+
|
78
|
+
def end_tag(name)
|
79
|
+
element = pop_open_element()
|
80
|
+
if element == nil
|
81
|
+
raise_mismatched_end_tag(name)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Generate implicit end tags up to this element.
|
85
|
+
while element.qualified_name != name
|
86
|
+
# KLUDGE: Indicate a generated implicit end tag by passing a special
|
87
|
+
# value for the namespace URI.
|
88
|
+
@handler.end_element_namespace(name, nil, IMPLICIT_END_TAG_NS_URI)
|
89
|
+
|
90
|
+
element = pop_open_element()
|
91
|
+
if element == nil
|
92
|
+
raise_mismatched_end_tag(name)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
@handler.end_element_namespace(element.qualified_name, nil, nil)
|
97
|
+
end
|
98
|
+
|
99
|
+
def characters(data)
|
100
|
+
@handler.characters(data)
|
101
|
+
end
|
102
|
+
|
103
|
+
def cdata(data)
|
104
|
+
@handler.cdata_block(data)
|
105
|
+
end
|
106
|
+
|
107
|
+
def processing_instruction(data)
|
108
|
+
@handler.processing_instruction(data)
|
109
|
+
end
|
110
|
+
|
111
|
+
def comment(data)
|
112
|
+
# FIXME: The HTML5 tokenizer treats <? as a bogus comment and emits it as
|
113
|
+
# a comment. If the comment begins with ? then turn it into a processing
|
114
|
+
# instruction. The problem is any legitimate comment beginning with ?
|
115
|
+
# will also be turned into a processing instruction.
|
116
|
+
if data.start_with?('?')
|
117
|
+
last_index = data.length() - 1
|
118
|
+
if last_index > 0 && data[last_index] == '?'
|
119
|
+
last_index -= 1
|
120
|
+
end
|
121
|
+
processing_instruction(data[1..last_index])
|
122
|
+
else
|
123
|
+
@handler.comment(data)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end; end; end
|