mullet 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/lib/mullet/container.rb +8 -4
  2. data/lib/mullet/default_model.rb +9 -9
  3. data/lib/mullet/default_nested_model.rb +7 -6
  4. data/lib/mullet/html/attribute_command.rb +8 -4
  5. data/lib/mullet/html/attributes.rb +22 -0
  6. data/lib/mullet/html/command.rb +4 -3
  7. data/lib/mullet/html/command_element_renderer.rb +19 -0
  8. data/lib/mullet/html/element.rb +41 -0
  9. data/lib/mullet/html/element_renderer.rb +261 -0
  10. data/lib/mullet/html/filtered_element_handler.rb +87 -0
  11. data/lib/mullet/html/for_element_renderer.rb +47 -0
  12. data/lib/mullet/html/if_element_renderer.rb +46 -0
  13. data/lib/mullet/html/layout.rb +48 -0
  14. data/lib/mullet/html/message.rb +55 -0
  15. data/lib/mullet/html/message_attribute_command.rb +30 -0
  16. data/lib/mullet/html/model_attribute_command.rb +30 -0
  17. data/lib/mullet/html/page_builder.rb +152 -0
  18. data/lib/mullet/html/parser/attribute.rb +8 -0
  19. data/lib/mullet/html/parser/constants.rb +1061 -0
  20. data/lib/mullet/html/parser/default_handler.rb +27 -0
  21. data/lib/mullet/html/parser/input_stream.rb +711 -0
  22. data/lib/mullet/html/parser/open_element.rb +77 -0
  23. data/lib/mullet/html/parser/simple_parser.rb +128 -0
  24. data/lib/mullet/html/parser/tokenizer.rb +1085 -0
  25. data/lib/mullet/html/remove_mode.rb +30 -0
  26. data/lib/mullet/html/static_text_renderer.rb +20 -0
  27. data/lib/mullet/html/template.rb +44 -0
  28. data/lib/mullet/html/template_builder.rb +208 -63
  29. data/lib/mullet/html/template_loader.rb +77 -39
  30. data/lib/mullet/html/template_parser.rb +48 -0
  31. data/lib/mullet/html/unless_element_renderer.rb +24 -0
  32. data/lib/mullet/model.rb +2 -5
  33. data/lib/mullet/render_context.rb +24 -18
  34. data/lib/mullet/tilt.rb +37 -0
  35. data/lib/mullet/version.rb +2 -1
  36. data/lib/mullet.rb +1 -0
  37. 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