meteor 0.9.13 → 0.9.14
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.
- checksums.yaml +4 -4
- data/ChangeLog +4 -0
- data/Gemfile.lock +3 -3
- data/demo/html.rb +49 -39
- data/demo/html4.rb +40 -33
- data/demo/ml/sample.xml +36 -38
- data/demo/ml/sample_html.html +7 -2
- data/demo/ml/sample_html4.html +9 -2
- data/demo/ml/sample_xhtml.html +7 -2
- data/demo/ml/sample_xhtml4.html +10 -3
- data/demo/xhtml.rb +41 -30
- data/demo/xhtml4.rb +35 -26
- data/demo/xml.rb +25 -20
- data/lib/meteor/attribute_map.rb +8 -6
- data/lib/meteor/core/kernel.rb +288 -260
- data/lib/meteor/core/util/pattern_cache.rb +16 -15
- data/lib/meteor/element.rb +65 -63
- data/lib/meteor/exception/no_such_element_exception.rb +15 -15
- data/lib/meteor/ml/html/parser_impl.rb +58 -33
- data/lib/meteor/ml/html4/parser_impl.rb +118 -90
- data/lib/meteor/ml/xhtml/parser_impl.rb +33 -29
- data/lib/meteor/ml/xhtml4/parser_impl.rb +98 -90
- data/lib/meteor/ml/xml/parser_impl.rb +35 -25
- data/lib/meteor/parser_factory.rb +125 -125
- data/lib/meteor.rb +2 -2
- metadata +2 -2
|
@@ -28,22 +28,23 @@ module Meteor
|
|
|
28
28
|
#
|
|
29
29
|
def self.get(*args)
|
|
30
30
|
case args.length
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
else
|
|
36
|
-
@@regex_cache[args[0].to_sym] = Regexp.new(args[0], Regexp::MULTILINE)
|
|
37
|
-
end
|
|
38
|
-
when TWO
|
|
39
|
-
# get_2(args[0], args[1])
|
|
40
|
-
if @@regex_cache[args[0].to_sym]
|
|
41
|
-
@@regex_cache[args[0].to_sym]
|
|
42
|
-
else
|
|
43
|
-
@@regex_cache[args[0].to_sym] = Regexp.new(args[0], args[1])
|
|
44
|
-
end
|
|
31
|
+
when ONE
|
|
32
|
+
# get_1(args[0])
|
|
33
|
+
if @@regex_cache[args[0].to_sym]
|
|
34
|
+
@@regex_cache[args[0].to_sym]
|
|
45
35
|
else
|
|
46
|
-
|
|
36
|
+
@@regex_cache[args[0].to_sym] = Regexp.new(args[0], Regexp::MULTILINE)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
when TWO
|
|
40
|
+
# get_2(args[0], args[1])
|
|
41
|
+
if @@regex_cache[args[0].to_sym]
|
|
42
|
+
@@regex_cache[args[0].to_sym]
|
|
43
|
+
else
|
|
44
|
+
@@regex_cache[args[0].to_sym] = Regexp.new(args[0], args[1])
|
|
45
|
+
end
|
|
46
|
+
else
|
|
47
|
+
raise ArgumentError
|
|
47
48
|
end
|
|
48
49
|
end
|
|
49
50
|
|
data/lib/meteor/element.rb
CHANGED
|
@@ -68,31 +68,32 @@ module Meteor
|
|
|
68
68
|
#
|
|
69
69
|
def initialize(*args)
|
|
70
70
|
case args.length
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
else
|
|
77
|
-
raise ArgumentError
|
|
78
|
-
end
|
|
79
|
-
when Meteor::TWO
|
|
80
|
-
@name = args[0].name
|
|
81
|
-
@attributes = String.new(args[0].attributes)
|
|
82
|
-
@mixed_content = String.new(args[0].mixed_content)
|
|
83
|
-
# @pattern = String.new(args[0].pattern)
|
|
84
|
-
@pattern = args[0].pattern
|
|
85
|
-
@document = String.new(args[0].document)
|
|
86
|
-
@empty = args[0].empty
|
|
87
|
-
@cx = args[0].cx
|
|
88
|
-
@mono = args[0].mono
|
|
89
|
-
@parser = args[1]
|
|
90
|
-
# @usable = false
|
|
91
|
-
@origin = args[0]
|
|
92
|
-
args[0].copy = self
|
|
93
|
-
when Meteor::ZERO
|
|
71
|
+
when Meteor::ONE
|
|
72
|
+
if args[0].kind_of?(String)
|
|
73
|
+
initialize_s(args[0])
|
|
74
|
+
elsif args[0].kind_of?(Meteor::Element)
|
|
75
|
+
initialize_e(args[0])
|
|
94
76
|
else
|
|
95
77
|
raise ArgumentError
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
when Meteor::TWO
|
|
81
|
+
@name = args[0].name
|
|
82
|
+
@attributes = String.new(args[0].attributes)
|
|
83
|
+
@mixed_content = String.new(args[0].mixed_content)
|
|
84
|
+
# @pattern = String.new(args[0].pattern)
|
|
85
|
+
@pattern = args[0].pattern
|
|
86
|
+
@document = String.new(args[0].document)
|
|
87
|
+
@empty = args[0].empty
|
|
88
|
+
@cx = args[0].cx
|
|
89
|
+
@mono = args[0].mono
|
|
90
|
+
@parser = args[1]
|
|
91
|
+
# @usable = false
|
|
92
|
+
@origin = args[0]
|
|
93
|
+
args[0].copy = self
|
|
94
|
+
when Meteor::ZERO
|
|
95
|
+
else
|
|
96
|
+
raise ArgumentError
|
|
96
97
|
end
|
|
97
98
|
end
|
|
98
99
|
|
|
@@ -145,21 +146,21 @@ module Meteor
|
|
|
145
146
|
#
|
|
146
147
|
def self.new!(*args)
|
|
147
148
|
case args.length
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
else
|
|
157
|
-
@obj = self.new(args[0], args[1])
|
|
158
|
-
args[1].element_hook = @obj
|
|
159
|
-
@obj
|
|
160
|
-
end
|
|
149
|
+
when Meteor::TWO
|
|
150
|
+
@obj = args[1].element_hook
|
|
151
|
+
if @obj
|
|
152
|
+
@obj.attributes = String.new(args[0].attributes)
|
|
153
|
+
@obj.mixed_content = String.new(args[0].mixed_content)
|
|
154
|
+
# @obj.pattern = String.new(args[0].pattern)
|
|
155
|
+
@obj.document = String.new(args[0].document)
|
|
156
|
+
@obj
|
|
161
157
|
else
|
|
162
|
-
|
|
158
|
+
@obj = self.new(args[0], args[1])
|
|
159
|
+
args[1].element_hook = @obj
|
|
160
|
+
@obj
|
|
161
|
+
end
|
|
162
|
+
else
|
|
163
|
+
raise ArgumentError
|
|
163
164
|
end
|
|
164
165
|
end
|
|
165
166
|
|
|
@@ -200,32 +201,33 @@ module Meteor
|
|
|
200
201
|
if @document_sync
|
|
201
202
|
@document_sync = false
|
|
202
203
|
case @parser.doc_type
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
204
|
+
when Parser::HTML, Parser::HTML4
|
|
205
|
+
if @cx
|
|
206
|
+
# @pattern_cc = String.new('') << '<!-- @' << elm.name << ' ' << elm.attributes << '-->' << elm.mixed_content << '<!-- /@' << elm.name << ' -->'
|
|
207
|
+
@document = "<!-- @#{@name} #{@attributes} -->#{@mixed_content}<!-- /@#{@name} -->"
|
|
208
|
+
else
|
|
209
|
+
if @empty
|
|
210
|
+
# @pattern_cc = String.new('') << "<" << elm.name << elm.attributes << '>' << elm.mixed_content << '</' << elm.name << '>'
|
|
211
|
+
@document = "<#{@name}#{@attributes}>#{@mixed_content}</#{@name}>"
|
|
207
212
|
else
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
@document = "<#{@name}#{@attributes}>#{@mixed_content}</#{@name}>"
|
|
211
|
-
else
|
|
212
|
-
@document = String.new('') << "<" << @name << @attributes << '>'
|
|
213
|
-
# @document = "<#{@name}#{@attributes}>"
|
|
214
|
-
end
|
|
213
|
+
@document = String.new("") << "<" << @name << @attributes << ">"
|
|
214
|
+
# @document = "<#{@name}#{@attributes}>"
|
|
215
215
|
end
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
when Parser::XHTML, Parser::XHTML4, Parser::XML
|
|
219
|
+
if @cx
|
|
220
|
+
# @pattern_cc = String.new('') << '<!-- @' << elm.name << ' ' << elm.attributes << '-->' << elm.mixed_content << '<!-- /@' << elm.name << ' -->'
|
|
221
|
+
@document = "<!-- @#{@name} #{@attributes} -->#{@mixed_content}<!-- /@#{@name} -->"
|
|
222
|
+
else
|
|
223
|
+
if @empty
|
|
224
|
+
# @pattern_cc = String.new('') << "<" << elm.name << elm.attributes << '>' << elm.mixed_content << '</' << elm.name << '>'
|
|
225
|
+
@document = "<#{@name}#{@attributes}>#{@mixed_content}</#{@name}>"
|
|
220
226
|
else
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
@document = "<#{@name}#{@attributes}>#{@mixed_content}</#{@name}>"
|
|
224
|
-
else
|
|
225
|
-
@document = String.new('') << "<" << @name << @attributes << '/>'
|
|
226
|
-
# @document = "<#{@name}#{@attributes}/>"
|
|
227
|
-
end
|
|
227
|
+
@document = String.new("") << "<" << @name << @attributes << "/>"
|
|
228
|
+
# @document = "<#{@name}#{@attributes}/>"
|
|
228
229
|
end
|
|
230
|
+
end
|
|
229
231
|
end
|
|
230
232
|
else
|
|
231
233
|
@document
|
|
@@ -281,7 +283,7 @@ module Meteor
|
|
|
281
283
|
# @param [Meteor::Element] elm element(要素)
|
|
282
284
|
# @return [Meteor::Element] element(要素)
|
|
283
285
|
#
|
|
284
|
-
def element(elm = nil, attrs = nil
|
|
286
|
+
def element(elm = nil, attrs = nil, *args)
|
|
285
287
|
# case args.length
|
|
286
288
|
# when ZERO
|
|
287
289
|
if !elm && !attrs
|
|
@@ -383,8 +385,8 @@ module Meteor
|
|
|
383
385
|
# @param [String,Symbol] attr_name attribute name (属性名)
|
|
384
386
|
# @return [String] attribute value (属性値)
|
|
385
387
|
#
|
|
386
|
-
def attr(attrs
|
|
387
|
-
@parser.attr(self, attrs
|
|
388
|
+
def attr(attrs, *args)
|
|
389
|
+
@parser.attr(self, attrs, *args)
|
|
388
390
|
end
|
|
389
391
|
|
|
390
392
|
#
|
|
@@ -393,7 +395,7 @@ module Meteor
|
|
|
393
395
|
# @return [Meteor::Element] element (要素)
|
|
394
396
|
#
|
|
395
397
|
def attr=(attr)
|
|
396
|
-
@parser.attr(self,attr)
|
|
398
|
+
@parser.attr(self, attr)
|
|
397
399
|
end
|
|
398
400
|
|
|
399
401
|
#
|
|
@@ -37,45 +37,45 @@ module Meteor
|
|
|
37
37
|
#
|
|
38
38
|
def initialize(*args)
|
|
39
39
|
case args.length
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
40
|
+
when ONE
|
|
41
|
+
initialize_1(args[0])
|
|
42
|
+
when TWO
|
|
43
|
+
initialize_2(args[0], args[1])
|
|
44
|
+
when THREE
|
|
45
|
+
initialize_3(args[0], args[1], args[2])
|
|
46
|
+
when FOUR
|
|
47
|
+
initialize_4(args[0], args[1], args[2], args[3])
|
|
48
|
+
when FIVE
|
|
49
|
+
initialize_5(args[0], args[1], args[2], args[3], args[4])
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
def initialize_1(name)
|
|
54
|
-
self.message="element not found : #{name}"
|
|
54
|
+
self.message = "element not found : #{name}"
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
private :initialize_1
|
|
58
58
|
|
|
59
59
|
def initialize_2(attr_name, attr_value)
|
|
60
|
-
self.message="element not found : [#{attr_name}=#{attr_value}]"
|
|
60
|
+
self.message = "element not found : [#{attr_name}=#{attr_value}]"
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
private :initialize_2
|
|
64
64
|
|
|
65
65
|
def initialize_3(name, attr_name, attr_value)
|
|
66
|
-
self.message="element not found : #{name}[#{attr_name}=#{attr_value}]"
|
|
66
|
+
self.message = "element not found : #{name}[#{attr_name}=#{attr_value}]"
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
private :initialize_3
|
|
70
70
|
|
|
71
71
|
def initialize_4(attr_name1, attr_value1, attr_name2, attr_value2)
|
|
72
|
-
self.message="element not found : [#{attr_name1}=#{attr_value1}][#{attr_name2}=#{attr_value2}]"
|
|
72
|
+
self.message = "element not found : [#{attr_name1}=#{attr_value1}][#{attr_name2}=#{attr_value2}]"
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
private :initialize_4
|
|
76
76
|
|
|
77
77
|
def initialize_5(name, attr_name1, attr_value1, attr_name2, attr_value2)
|
|
78
|
-
self.message="element not found : #{name}[#{attr_name1}=#{attr_value1}][#{attr_name2}=#{attr_value2}]"
|
|
78
|
+
self.message = "element not found : #{name}[#{attr_name1}=#{attr_value1}][#{attr_name2}=#{attr_value2}]"
|
|
79
79
|
end
|
|
80
80
|
|
|
81
81
|
private :initialize_5
|
|
@@ -8,19 +8,42 @@ module Meteor
|
|
|
8
8
|
# HTML parser (HTMLパーサ)
|
|
9
9
|
#
|
|
10
10
|
class ParserImpl < Meteor::Ml::Html4::ParserImpl
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
#[Array] void elements (空要素)
|
|
12
|
+
MATCH_TAG = ["br", "hr", "img", "input", "meta", "base", "embed", "command", "keygen"]
|
|
13
|
+
|
|
14
|
+
#[Array] non-nestable elements (入れ子にできない要素)
|
|
15
|
+
MATCH_TAG_SNG = [
|
|
16
|
+
"texarea",
|
|
17
|
+
"select",
|
|
18
|
+
"option",
|
|
19
|
+
"form",
|
|
20
|
+
"fieldset",
|
|
21
|
+
"figure",
|
|
22
|
+
"figcaption",
|
|
23
|
+
"video",
|
|
24
|
+
"audio",
|
|
25
|
+
"progress",
|
|
26
|
+
"meter",
|
|
27
|
+
"time",
|
|
28
|
+
"ruby",
|
|
29
|
+
"rt",
|
|
30
|
+
"rp",
|
|
31
|
+
"datalist",
|
|
32
|
+
"output"
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
#[Array] boolean attributes (論理値で指定する属性)
|
|
36
|
+
ATTR_LOGIC = ["disabled", "readonly", "checked", "selected", "multiple", "required"]
|
|
37
|
+
|
|
38
|
+
#[Array] elements with the disabled attribute (disabled属性のある要素)
|
|
39
|
+
DISABLE_ELEMENT = ["input", "textarea", "select", "optgroup", "fieldset"]
|
|
40
|
+
|
|
41
|
+
#[Array] elements with the required attribute (required属性のある要素)
|
|
42
|
+
REQUIRE_ELEMENT = ["input", "textarea"]
|
|
43
|
+
|
|
44
|
+
REQUIRED_M = "\\srequired\\s|\\srequired$|\\sREQUIRED\\s|\\sREQUIRED$"
|
|
22
45
|
# REQUIRED_M = [' required ',' required',' REQUIRED ',' REQUIRED']
|
|
23
|
-
REQUIRED_R =
|
|
46
|
+
REQUIRED_R = "required\\s|required$|REQUIRED\\s|REQUIRED$"
|
|
24
47
|
|
|
25
48
|
@@pattern_required_m = Regexp.new(REQUIRED_M)
|
|
26
49
|
@@pattern_required_r = Regexp.new(REQUIRED_R)
|
|
@@ -38,12 +61,12 @@ module Meteor
|
|
|
38
61
|
@@attr_logic = ATTR_LOGIC
|
|
39
62
|
@doc_type = Parser::HTML
|
|
40
63
|
case args.length
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
64
|
+
when ZERO
|
|
65
|
+
# initialize_0
|
|
66
|
+
when ONE
|
|
67
|
+
initialize_1(args[0])
|
|
68
|
+
else
|
|
69
|
+
raise ArgumentError
|
|
47
70
|
end
|
|
48
71
|
end
|
|
49
72
|
|
|
@@ -75,10 +98,10 @@ module Meteor
|
|
|
75
98
|
def analyze_content_type
|
|
76
99
|
@error_check = false
|
|
77
100
|
|
|
78
|
-
element_3(
|
|
101
|
+
element_3("meta", "charset", "[a-zA-Z-]+", false)
|
|
79
102
|
|
|
80
103
|
if !@elm_
|
|
81
|
-
element_3(
|
|
104
|
+
element_3("meta", "charset", "[a-zA-Z-]+", false)
|
|
82
105
|
end
|
|
83
106
|
|
|
84
107
|
@error_check = true
|
|
@@ -92,23 +115,24 @@ module Meteor
|
|
|
92
115
|
@root.charset = "utf-8"
|
|
93
116
|
end
|
|
94
117
|
|
|
95
|
-
@root.content_type =
|
|
118
|
+
@root.content_type = "text/html"
|
|
96
119
|
end
|
|
97
120
|
|
|
98
121
|
private :analyze_content_type
|
|
99
122
|
|
|
100
123
|
def edit_attrs_(elm, attr_name, attr_value)
|
|
101
|
-
if is_match(
|
|
124
|
+
if is_match("selected", attr_name) && is_match("option", elm.name)
|
|
102
125
|
edit_attrs_5(elm, attr_name, attr_value, @@pattern_selected_m, @@pattern_selected_r)
|
|
103
|
-
elsif is_match(
|
|
126
|
+
elsif is_match("multiple", attr_name) && is_match("select", elm.name)
|
|
104
127
|
edit_attrs_5(elm, attr_name, attr_value, @@pattern_multiple_m, @@pattern_multiple_r)
|
|
105
|
-
elsif is_match(
|
|
128
|
+
elsif is_match("disabled", attr_name) && is_match(DISABLE_ELEMENT, elm.name)
|
|
106
129
|
edit_attrs_5(elm, attr_name, attr_value, @@pattern_disabled_m, @@pattern_disabled_r)
|
|
107
|
-
elsif is_match(
|
|
130
|
+
elsif is_match("checked", attr_name) && is_match("input", elm.name) && is_match("radio", get_type(elm))
|
|
108
131
|
edit_attrs_5(elm, attr_name, attr_value, @@pattern_checked_m, @@pattern_checked_r)
|
|
109
|
-
elsif is_match(
|
|
132
|
+
elsif is_match("readonly", attr_name) &&
|
|
133
|
+
(is_match("textarea", elm.name) || (is_match("input", elm.name) && is_match(READONLY_TYPE, get_type(elm))))
|
|
110
134
|
edit_attrs_5(elm, attr_name, attr_value, @@pattern_readonly_m, @@pattern_readonly_r)
|
|
111
|
-
elsif is_match(
|
|
135
|
+
elsif is_match("required", attr_name) && is_match(REQUIRE_ELEMENT, elm.name)
|
|
112
136
|
edit_attrs_5(elm, attr_name, attr_value, @@pattern_required_m, @@pattern_required_r)
|
|
113
137
|
else
|
|
114
138
|
super(elm, attr_name, attr_value)
|
|
@@ -118,17 +142,18 @@ module Meteor
|
|
|
118
142
|
private :edit_attrs_
|
|
119
143
|
|
|
120
144
|
def get_attr_value_(elm, attr_name)
|
|
121
|
-
if is_match(
|
|
145
|
+
if is_match("selected", attr_name) && is_match("option", elm.name)
|
|
122
146
|
get_attr_value_r(elm, @@pattern_selected_m)
|
|
123
|
-
elsif is_match(
|
|
147
|
+
elsif is_match("multiple", attr_name) && is_match("select", elm.name)
|
|
124
148
|
get_attr_value_r(elm, @@pattern_multiple_m)
|
|
125
|
-
elsif is_match(
|
|
149
|
+
elsif is_match("disabled", attr_name) && is_match(DISABLE_ELEMENT, elm.name)
|
|
126
150
|
get_attr_value_r(elm, @@pattern_disabled_m)
|
|
127
|
-
elsif is_match(
|
|
151
|
+
elsif is_match("checked", attr_name) && is_match("input", elm.name) && is_match("radio", get_type(elm))
|
|
128
152
|
get_attr_value_r(elm, @@pattern_checked_m)
|
|
129
|
-
elsif is_match(
|
|
153
|
+
elsif is_match("readonly", attr_name) &&
|
|
154
|
+
(is_match("textarea", elm.name) || (is_match("input", elm.name) && is_match(READONLY_TYPE, get_type(elm))))
|
|
130
155
|
get_attr_value_r(elm, @@pattern_readonly_m)
|
|
131
|
-
elsif is_match(
|
|
156
|
+
elsif is_match("required", attr_name) && is_match(REQUIRE_ELEMENT, elm.name)
|
|
132
157
|
get_attr_value_r(elm, @@pattern_required_m)
|
|
133
158
|
else
|
|
134
159
|
super(elm, attr_name)
|