eimxml 0.0.2 → 0.0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +24 -95
- data/Rakefile.utirake +374 -0
- data/lib/eim_xml.rb +95 -220
- data/lib/eim_xml/dsl.rb +105 -0
- data/lib/eim_xml/formatter.rb +123 -0
- data/lib/eim_xml/formatter/element_wrapper.rb +7 -0
- data/lib/eim_xml/parser.rb +12 -40
- data/lib/eim_xml/xhtml.rb +84 -56
- data/lib/eim_xml/xhtml/dsl.rb +18 -0
- data/{test → spec}/assertions_test.rb +1 -0
- data/spec/dsl_spec.rb +217 -0
- data/spec/eim_xml_spec.rb +441 -0
- data/spec/formatter_spec.rb +260 -0
- data/spec/parser_spec.rb +102 -0
- data/spec/xhtml_spec.rb +524 -0
- metadata +52 -38
- data/README +0 -58
- data/test/eim_xml_test.rb +0 -648
- data/test/parser_test.rb +0 -102
- data/test/xhtml_test.rb +0 -340
@@ -0,0 +1,123 @@
|
|
1
|
+
require "eim_xml"
|
2
|
+
|
3
|
+
module EimXML
|
4
|
+
class Formatter
|
5
|
+
attr_reader :out
|
6
|
+
|
7
|
+
def self.write(element, opt={})
|
8
|
+
opt = {:out=>""}.merge(opt)
|
9
|
+
new(opt).write(element)
|
10
|
+
opt[:out]
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(opt)
|
14
|
+
@out = opt[:out]
|
15
|
+
@preservers = opt[:preservers]
|
16
|
+
@preserve_space = false
|
17
|
+
@indent_string = " "
|
18
|
+
@indent_depth = 0
|
19
|
+
@option = opt.dup.tap{|h| [:out, :preservers].each{|k| h.delete(k)}}
|
20
|
+
end
|
21
|
+
|
22
|
+
def write(src)
|
23
|
+
case src
|
24
|
+
when ElementWrapper
|
25
|
+
write_wrapper(src)
|
26
|
+
when Comment
|
27
|
+
write_comment(src)
|
28
|
+
when Element
|
29
|
+
write_element(src)
|
30
|
+
when PCString
|
31
|
+
write_pcstring(src)
|
32
|
+
else
|
33
|
+
write_string(src.to_s)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def indent(&proc)
|
38
|
+
@indent_depth += 1
|
39
|
+
proc.call
|
40
|
+
ensure
|
41
|
+
@indent_depth -= 1
|
42
|
+
end
|
43
|
+
|
44
|
+
def preserve_space_element?(elm)
|
45
|
+
@preservers && @preservers.any? do |e|
|
46
|
+
case e
|
47
|
+
when Symbol
|
48
|
+
e==elm.name
|
49
|
+
when Class
|
50
|
+
e===elm
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def write_indent
|
56
|
+
out << @indent_string*@indent_depth unless @preserve_space
|
57
|
+
end
|
58
|
+
|
59
|
+
def write_newline
|
60
|
+
out << "\n" unless @preserve_space
|
61
|
+
end
|
62
|
+
|
63
|
+
def write_comment(c)
|
64
|
+
write_indent
|
65
|
+
c.write_to(out)
|
66
|
+
write_newline
|
67
|
+
end
|
68
|
+
|
69
|
+
def write_contents_of(elm)
|
70
|
+
flag = @preserve_space
|
71
|
+
@preserve_space = true if preserve_space_element?(elm)
|
72
|
+
write_newline
|
73
|
+
indent do
|
74
|
+
elm.contents.each do |c|
|
75
|
+
write(c)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
write_indent
|
79
|
+
ensure
|
80
|
+
@preserve_space = flag
|
81
|
+
end
|
82
|
+
|
83
|
+
def write_element(elm)
|
84
|
+
write_indent
|
85
|
+
out << "<"
|
86
|
+
elm.name_and_attributes(out)
|
87
|
+
case elm.contents.size
|
88
|
+
when 0
|
89
|
+
out << " />"
|
90
|
+
write_newline
|
91
|
+
else
|
92
|
+
out << ">"
|
93
|
+
write_contents_of(elm)
|
94
|
+
out << "</#{elm.name}>"
|
95
|
+
write_newline
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def write_pcstring(pcs)
|
100
|
+
pcs.encoded_string.each_line do |l|
|
101
|
+
write_indent
|
102
|
+
out << l
|
103
|
+
end
|
104
|
+
write_newline
|
105
|
+
end
|
106
|
+
|
107
|
+
def write_string(str)
|
108
|
+
PCString.encode(str).each_line do |l|
|
109
|
+
write_indent
|
110
|
+
out << l
|
111
|
+
end
|
112
|
+
write_newline
|
113
|
+
end
|
114
|
+
|
115
|
+
def write_wrapper(wrapper)
|
116
|
+
wrapper.each(@option) do |i|
|
117
|
+
write(i)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
require "eim_xml/formatter/element_wrapper"
|
data/lib/eim_xml/parser.rb
CHANGED
@@ -16,32 +16,23 @@ module EimXML
|
|
16
16
|
module RE
|
17
17
|
EMPTY_ELEMENT = /<([^>]*?)\/>/
|
18
18
|
START_TAG = /<([^>]*?([^\/>]\s*))>/
|
19
|
-
END_TAG = /<\/(\S
|
19
|
+
END_TAG = /<\/(\S+?)\s*>/
|
20
20
|
ATTRIBUTE = /\s+([^=\s]+)\s*=\s*('(.*?)'|"(.*?)")/m
|
21
21
|
STRING = /[^<]+/
|
22
22
|
end
|
23
23
|
|
24
|
-
def initialize(src
|
24
|
+
def initialize(src)
|
25
25
|
@scanner = StringScanner.new(src)
|
26
|
-
@
|
27
|
-
@space_holder_res = []
|
28
|
-
space_holders.each do |i|
|
29
|
-
if i.is_a?(Regexp)
|
30
|
-
@space_holder_res << i
|
31
|
-
else
|
32
|
-
@space_holders << i.to_sym
|
33
|
-
end
|
34
|
-
end
|
26
|
+
@scanner.scan(/\s*<\?.*?\?>\s*/)
|
35
27
|
end
|
36
28
|
|
37
|
-
def parse
|
38
|
-
@scanner.scan(/\s+/) unless hold_space
|
29
|
+
def parse
|
39
30
|
if @scanner.scan(RE::EMPTY_ELEMENT)
|
40
|
-
parse_empty_element
|
31
|
+
parse_empty_element
|
41
32
|
elsif @scanner.scan(RE::START_TAG)
|
42
|
-
parse_start_tag
|
33
|
+
parse_start_tag
|
43
34
|
elsif @scanner.scan(RE::STRING)
|
44
|
-
parse_string
|
35
|
+
parse_string
|
45
36
|
else
|
46
37
|
nil
|
47
38
|
end
|
@@ -55,43 +46,26 @@ module EimXML
|
|
55
46
|
end
|
56
47
|
protected :parse_tag
|
57
48
|
|
58
|
-
def
|
59
|
-
|
60
|
-
s = ename.to_s
|
61
|
-
@space_holder_res.each do |re|
|
62
|
-
return true if re=~s
|
63
|
-
end
|
64
|
-
false
|
65
|
-
end
|
66
|
-
|
67
|
-
def parse_empty_element(hold_space)
|
68
|
-
e = parse_tag
|
69
|
-
hold_space = space_holder?(e.name) unless hold_space
|
70
|
-
e.hold_space if hold_space
|
71
|
-
e
|
49
|
+
def parse_empty_element
|
50
|
+
parse_tag
|
72
51
|
end
|
73
52
|
protected :parse_empty_element
|
74
53
|
|
75
|
-
def parse_start_tag
|
54
|
+
def parse_start_tag
|
76
55
|
e = parse_tag
|
77
|
-
hold_space = space_holder?(e.name) unless hold_space
|
78
56
|
|
79
|
-
e.hold_space if hold_space
|
80
|
-
@scanner.scan(/\s*/) unless hold_space
|
81
57
|
until @scanner.scan(RE::END_TAG)
|
82
|
-
c = parse
|
58
|
+
c = parse
|
83
59
|
raise ParseError.new("Syntax error.") unless c
|
84
60
|
e << c
|
85
|
-
@scanner.scan(/\s*/) unless hold_space
|
86
61
|
end
|
87
62
|
raise ParseError.new("End tag mismatched.") unless @scanner[1].to_sym==e.name
|
88
63
|
e
|
89
64
|
end
|
90
65
|
protected :parse_start_tag
|
91
66
|
|
92
|
-
def parse_string
|
67
|
+
def parse_string
|
93
68
|
s = @scanner[0]
|
94
|
-
s = s.strip unless hold_space
|
95
69
|
s = s.gsub(/&(amp|quot|apos|lt|gt);/) do
|
96
70
|
case $1
|
97
71
|
when "amp"
|
@@ -104,8 +78,6 @@ module EimXML
|
|
104
78
|
"<"
|
105
79
|
when "gt"
|
106
80
|
">"
|
107
|
-
else
|
108
|
-
raise "must not happen"
|
109
81
|
end
|
110
82
|
end
|
111
83
|
PCString.new(s)
|
data/lib/eim_xml/xhtml.rb
CHANGED
@@ -1,16 +1,11 @@
|
|
1
1
|
require "eim_xml"
|
2
|
+
require "eim_xml/formatter"
|
2
3
|
|
3
4
|
module EimXML::XHTML
|
4
5
|
module DocType
|
5
6
|
XHTML_MATHML = %[<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN" "http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd">]
|
6
7
|
end
|
7
8
|
|
8
|
-
class DSL < EimXML::BaseDSL
|
9
|
-
end
|
10
|
-
|
11
|
-
class OpenDSL < EimXML::OpenDSL
|
12
|
-
end
|
13
|
-
|
14
9
|
class Base_ < EimXML::Element
|
15
10
|
end
|
16
11
|
|
@@ -20,106 +15,139 @@ module EimXML::XHTML
|
|
20
15
|
XHTML = "http://www.w3.org/1999/xhtml"
|
21
16
|
end
|
22
17
|
|
23
|
-
def initialize(attributes=
|
18
|
+
def initialize(attributes={})
|
24
19
|
super(:html, attributes)
|
25
20
|
end
|
26
21
|
|
27
|
-
def
|
28
|
-
|
29
|
-
super
|
22
|
+
def write_to(out="")
|
23
|
+
out << @prefix << "\n" if @prefix
|
24
|
+
super
|
30
25
|
end
|
31
26
|
end
|
32
27
|
|
33
28
|
class Simple_ < Base_
|
34
|
-
def initialize(attributes=
|
29
|
+
def initialize(attributes={})
|
35
30
|
super(self.class.name[/.*::(.*)/, 1].downcase.to_sym, attributes)
|
36
31
|
end
|
37
32
|
end
|
38
33
|
|
34
|
+
class PreserveSpace_ < Base_
|
35
|
+
def initialize(name={}, attributes={})
|
36
|
+
if name.is_a?(Hash)
|
37
|
+
super(self.class.name[/.*::(.*)/, 1].downcase.to_sym, name)
|
38
|
+
else
|
39
|
+
super(name, attributes)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
39
44
|
class HEAD < Simple_; end
|
40
45
|
class META < Simple_; end
|
41
46
|
class LINK < Simple_; end
|
42
|
-
class
|
43
|
-
class
|
47
|
+
class IMG < Simple_; end
|
48
|
+
class STYLE < PreserveSpace_; end
|
49
|
+
class SCRIPT < PreserveSpace_; end
|
44
50
|
class TITLE < Simple_; end
|
45
51
|
class BODY < Simple_; end
|
46
|
-
class PRE <
|
47
|
-
|
52
|
+
class PRE < PreserveSpace_; end
|
53
|
+
class FORM < Simple_
|
54
|
+
def initialize(attributes={})
|
55
|
+
if attributes
|
56
|
+
if s = attributes.delete(:session)
|
57
|
+
name = attributes.delete(:session_name) || "token"
|
58
|
+
require "digest/sha1"
|
59
|
+
token = s[name] ||= Digest::SHA1.hexdigest("#{$$}#{Time.now}#{rand}")
|
60
|
+
end
|
61
|
+
end
|
48
62
|
super
|
49
|
-
|
63
|
+
add(HIDDEN.new(:name=>name, :value=>token)) if token
|
50
64
|
end
|
51
65
|
end
|
52
|
-
class
|
53
|
-
class
|
54
|
-
class
|
55
|
-
class
|
56
|
-
class
|
57
|
-
class
|
58
|
-
class
|
59
|
-
class
|
60
|
-
class
|
61
|
-
class
|
62
|
-
class STRONG < Simple_; end
|
66
|
+
class H1 < PreserveSpace_; end
|
67
|
+
class H2 < PreserveSpace_; end
|
68
|
+
class H3 < PreserveSpace_; end
|
69
|
+
class H4 < PreserveSpace_; end
|
70
|
+
class H5 < PreserveSpace_; end
|
71
|
+
class H6 < PreserveSpace_; end
|
72
|
+
class P < PreserveSpace_; end
|
73
|
+
class A < PreserveSpace_; end
|
74
|
+
class EM < PreserveSpace_; end
|
75
|
+
class STRONG < PreserveSpace_; end
|
63
76
|
class DIV < Simple_; end
|
77
|
+
class SPAN < PreserveSpace_; end
|
64
78
|
class UL < Simple_; end
|
65
79
|
class OL < Simple_; end
|
66
|
-
class LI <
|
80
|
+
class LI < PreserveSpace_; end
|
67
81
|
class DL < Simple_; end
|
68
|
-
class DT <
|
69
|
-
class DD <
|
82
|
+
class DT < PreserveSpace_; end
|
83
|
+
class DD < PreserveSpace_; end
|
70
84
|
class TABLE < Simple_; end
|
71
|
-
class CAPTION <
|
85
|
+
class CAPTION < PreserveSpace_; end
|
72
86
|
class TR < Simple_; end
|
73
|
-
class TH <
|
74
|
-
class TD <
|
87
|
+
class TH < PreserveSpace_; end
|
88
|
+
class TD < PreserveSpace_; end
|
89
|
+
class BR < Simple_; end
|
90
|
+
class HR < Simple_; end
|
91
|
+
class SELECT < Simple_; end
|
92
|
+
class OPTION < Simple_; end
|
93
|
+
|
75
94
|
|
76
95
|
module Hn
|
77
|
-
def self.new(level, attr=
|
96
|
+
def self.new(level, attr={}, &proc)
|
78
97
|
raise ArgumentError unless 1<=level && level<=6
|
79
98
|
klass = EimXML::XHTML.const_get("H#{level}")
|
80
99
|
klass.new(attr, &proc)
|
81
100
|
end
|
82
101
|
end
|
83
102
|
|
84
|
-
class TEXTAREA <
|
85
|
-
|
86
|
-
|
103
|
+
class TEXTAREA < PreserveSpace_; end
|
104
|
+
|
105
|
+
class INPUT < Base_
|
106
|
+
def initialize(opt={})
|
107
|
+
super(:input, opt)
|
87
108
|
end
|
88
109
|
end
|
89
110
|
|
90
|
-
class
|
91
|
-
def initialize(
|
92
|
-
|
93
|
-
attr[:name]=name if name
|
94
|
-
attr[:value]=value if value
|
95
|
-
super(:input, attr.merge(opt))
|
111
|
+
class BUTTON < PreserveSpace_
|
112
|
+
def initialize(opt={})
|
113
|
+
super(:button, opt)
|
96
114
|
end
|
97
115
|
end
|
98
116
|
|
99
|
-
class
|
100
|
-
def initialize(
|
101
|
-
super(:
|
117
|
+
class SUBMIT < BUTTON
|
118
|
+
def initialize(opt={})
|
119
|
+
super(opt.merge(:type=>:submit))
|
102
120
|
end
|
103
121
|
end
|
104
122
|
|
105
|
-
class
|
123
|
+
class HIDDEN < INPUT
|
106
124
|
def initialize(opt={})
|
107
|
-
opt
|
108
|
-
super(:submit, opt.delete(:name), opt.delete(:value), opt)
|
125
|
+
super(opt.merge(:type=>:hidden))
|
109
126
|
end
|
110
127
|
end
|
111
128
|
|
112
129
|
class TEXT < INPUT
|
113
|
-
def initialize(
|
114
|
-
super(:text
|
130
|
+
def initialize(opt={})
|
131
|
+
super(opt.merge(:type=>:text))
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
class PASSWORD < INPUT
|
136
|
+
def initialize(opt={})
|
137
|
+
super(opt.merge(:type=>:password))
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class FILE < INPUT
|
142
|
+
def initialize(opt={})
|
143
|
+
super(opt.merge(:type=>:file))
|
115
144
|
end
|
116
145
|
end
|
117
146
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
OpenDSL.register v
|
147
|
+
PRESERVE_SPACES = [PreserveSpace_]
|
148
|
+
class Formatter < EimXML::Formatter
|
149
|
+
def self.write(element, opt={})
|
150
|
+
EimXML::Formatter.write(element, opt.merge(:preservers=>PRESERVE_SPACES))
|
123
151
|
end
|
124
152
|
end
|
125
153
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "eim_xml/dsl"
|
2
|
+
require "eim_xml/xhtml"
|
3
|
+
|
4
|
+
module EimXML::XHTML
|
5
|
+
class DSL < EimXML::BaseDSL
|
6
|
+
end
|
7
|
+
|
8
|
+
class OpenDSL < EimXML::OpenDSL
|
9
|
+
end
|
10
|
+
|
11
|
+
constants.each do |c|
|
12
|
+
v = const_get(c)
|
13
|
+
if v.is_a?(Class) && /_$/ !~ v.name
|
14
|
+
DSL.register v
|
15
|
+
OpenDSL.register v
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|