duxml 0.8.0 → 0.8.4
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/lib/duxml/doc/element.rb +58 -10
- data/lib/duxml/doc/lazy_ox.rb +36 -28
- data/lib/duxml/meta/grammar/pattern/child_pattern.rb +7 -19
- data/lib/duxml/meta/grammar/pattern/text_pattern.rb +3 -2
- data/lib/duxml/meta/grammar/pattern_maker.rb +3 -3
- data/lib/duxml/meta/grammar/rule/children_rule.rb +2 -3
- data/lib/duxml/meta/history/add.rb +5 -10
- data/lib/duxml/meta/history/new_text.rb +3 -3
- data/lib/duxml/meta.rb +16 -5
- data/lib/duxml/ruby_ext/string.rb +15 -7
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e9a620bcdd50c48d3b01ee43b5df3227820036c2
|
4
|
+
data.tar.gz: f0702e3d79fbfb2365bdfeec0c2cb5fa6c4f539e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16aa187942b52c19196771bb213650351148fff1e2ba675247ec65829ca4ca812ce824bfe9fbbc44ae88ff0b9b4dd66c068aafb48a6d440a45dc435c96016e64
|
7
|
+
data.tar.gz: 14fa01c704c3db5e73613871f94d57bae6b999d3b2d33eba2bd86761910993abe778b586738ca5165880380b8bbeee97434106e940a0e7e36efc99b2786df49c
|
data/lib/duxml/doc/element.rb
CHANGED
@@ -70,17 +70,20 @@ module Duxml
|
|
70
70
|
add(e, index == -1 ? index : index+i)
|
71
71
|
end
|
72
72
|
when obj.is_a?(String)
|
73
|
-
|
74
|
-
|
75
|
-
|
73
|
+
if obj[0] == '<' and obj[-1] == '>' and (s = Ox.parse(obj))
|
74
|
+
add dclone s
|
75
|
+
else
|
76
|
+
type = :NewText
|
77
|
+
nodes.insert(index, obj)
|
78
|
+
end
|
76
79
|
else
|
77
80
|
type = :Add
|
78
81
|
nodes.insert(index, obj)
|
79
|
-
if
|
80
|
-
|
82
|
+
if obj.count_observers < 1 && @observer_peers
|
83
|
+
obj.add_observer(@observer_peers.first.first)
|
81
84
|
end
|
82
85
|
end
|
83
|
-
report(type,
|
86
|
+
report(type, obj, index)
|
84
87
|
self
|
85
88
|
end
|
86
89
|
|
@@ -150,19 +153,19 @@ module Duxml
|
|
150
153
|
# pre-order traverse through this node and all of its descendants
|
151
154
|
#
|
152
155
|
# @param &block [block] code to execute for each yielded node
|
153
|
-
def traverse(&block)
|
156
|
+
def traverse(node=nil, &block)
|
154
157
|
return self.to_enum unless block_given?
|
155
|
-
node_stack = [self]
|
158
|
+
node_stack = [node || self]
|
156
159
|
|
157
160
|
until node_stack.empty?
|
158
161
|
current = node_stack.shift
|
159
162
|
if current
|
160
163
|
yield current
|
161
|
-
node_stack = node_stack.
|
164
|
+
node_stack = node_stack.insert(0, *current.nodes) if current.respond_to?(:nodes)
|
162
165
|
end
|
163
166
|
end
|
164
167
|
|
165
|
-
self if block_given?
|
168
|
+
node || self if block_given?
|
166
169
|
end
|
167
170
|
|
168
171
|
# traverse through just the children of this node
|
@@ -177,5 +180,50 @@ module Duxml
|
|
177
180
|
return nil unless (i = name.index(':'))
|
178
181
|
name[0..i-1]
|
179
182
|
end
|
183
|
+
|
184
|
+
|
185
|
+
# @param source [Element] if not explicitly provided, creates deep clone of this element; source can be any XML element (not only Duxml) that responds to traverse with pre-order traversal
|
186
|
+
# @return [Element] deep clone of source, including its attributes and recursively cloned children
|
187
|
+
def dclone(source = self)
|
188
|
+
input_stack = []
|
189
|
+
output_stack = []
|
190
|
+
traverse(source) do |node|
|
191
|
+
if node.is_a?(String)
|
192
|
+
output_stack.last << node
|
193
|
+
next
|
194
|
+
end
|
195
|
+
copy = Element.new(node.name, node.attributes)
|
196
|
+
if output_stack.empty?
|
197
|
+
output_stack << copy
|
198
|
+
input_stack << node
|
199
|
+
else
|
200
|
+
|
201
|
+
if input_stack.last.nodes.none? do |n| n === node end
|
202
|
+
input_stack.pop
|
203
|
+
output_stack.pop
|
204
|
+
end
|
205
|
+
|
206
|
+
output_stack.last << copy
|
207
|
+
if node.nodes.any?
|
208
|
+
output_stack << copy
|
209
|
+
input_stack << node
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
end
|
214
|
+
output_stack.pop
|
215
|
+
end
|
216
|
+
|
217
|
+
# @return [Element] shallow clone of this element, with all attributes and children only if none are Elements
|
218
|
+
def sclone
|
219
|
+
stub = Element.new(name, attributes)
|
220
|
+
stub << nodes if text?
|
221
|
+
stub
|
222
|
+
end
|
223
|
+
|
224
|
+
# @return [true, false] true if all child nodes are text only; false if any child nodes are XML
|
225
|
+
def text?
|
226
|
+
nodes.all? do |node| node.is_a?(String) end
|
227
|
+
end
|
180
228
|
end # class Element < Node
|
181
229
|
end # module Ox
|
data/lib/duxml/doc/lazy_ox.rb
CHANGED
@@ -73,26 +73,30 @@ module Duxml
|
|
73
73
|
# @param &block [block] if yielding result, yields to given block; if defining new method, block defines its contents
|
74
74
|
def method_missing(sym, *args, &block)
|
75
75
|
super(sym, *args, &block)
|
76
|
-
rescue
|
77
|
-
|
78
|
-
|
79
|
-
if
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
76
|
+
rescue Exception => orig_error
|
77
|
+
begin
|
78
|
+
# handling Constant look up to dynamically extend or add to element
|
79
|
+
if lowercase?(sym)
|
80
|
+
if (const = look_up_const) and const.is_a?(Module)
|
81
|
+
extend const
|
82
|
+
result = method(sym).call(*args)
|
83
|
+
return(result) unless block_given?
|
84
|
+
yield(result)
|
85
|
+
elsif block_given?
|
86
|
+
new_method = proc(&block)
|
87
|
+
self.const_set(sym, new_method)
|
88
|
+
return new_method.call *args
|
89
|
+
else
|
90
|
+
raise orig_error
|
91
|
+
end # if (const = look_up_const) ... elsif block_given? ... else ...
|
88
92
|
else
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
end
|
93
|
+
results = filter(sym, args)
|
94
|
+
return results unless block_given?
|
95
|
+
results.keep_if do |node| yield(node) end
|
96
|
+
end # if lowercase? ... else ...
|
97
|
+
rescue Exception
|
98
|
+
raise orig_error
|
99
|
+
end
|
96
100
|
end # def method_missing(sym, *args, &block)
|
97
101
|
|
98
102
|
private
|
@@ -124,16 +128,20 @@ module Duxml
|
|
124
128
|
def look_up_const(maudule = Duxml)
|
125
129
|
mod_names = name.split(':')
|
126
130
|
until mod_names.empty?
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
return const if mod_names.empty? and [Module, Class].include?(const.class)
|
131
|
+
k = mod_names.shift.constantize
|
132
|
+
case
|
133
|
+
when maudule.const_defined?(k, true)
|
134
|
+
when Module.const_defined?(simple_class, true)
|
135
|
+
k = simple_class
|
136
|
+
else
|
137
|
+
return nil
|
136
138
|
end
|
139
|
+
const = maudule.const_get(k)
|
140
|
+
if const.is_a?(Module)
|
141
|
+
maudule = const
|
142
|
+
end
|
143
|
+
|
144
|
+
return const if mod_names.empty? and [Module, Class].include?(const.class)
|
137
145
|
end
|
138
146
|
nil
|
139
147
|
end
|
@@ -10,14 +10,14 @@ module Duxml
|
|
10
10
|
include ChildPattern
|
11
11
|
|
12
12
|
# @param _subject [Duxml::Element] parent element
|
13
|
-
# @param
|
14
|
-
def initialize(_subject, _index)
|
15
|
-
@index = _index
|
13
|
+
# @param _child [Fixnum] child node
|
14
|
+
def initialize(_subject, _child, _index)
|
15
|
+
@child, @index = _child, _index
|
16
16
|
super _subject
|
17
17
|
end
|
18
18
|
|
19
19
|
alias_method :parent, :subject
|
20
|
-
attr_reader :index
|
20
|
+
attr_reader :child, :index
|
21
21
|
end # class ChildPatternClass
|
22
22
|
|
23
23
|
# null child patterns represent and parent child relationship where the child
|
@@ -27,16 +27,11 @@ module Duxml
|
|
27
27
|
|
28
28
|
# @param _subject [Element] parent element
|
29
29
|
# @param _missing_child [String] nmtoken for missing child element
|
30
|
-
def initialize(_subject, _missing_child)
|
31
|
-
@missing_child = _missing_child
|
30
|
+
def initialize(_subject, _missing_child, _index=-1)
|
31
|
+
@missing_child, @index = _missing_child, _index
|
32
32
|
super _subject
|
33
33
|
end
|
34
34
|
|
35
|
-
# @return [-1] class must respond to #index; only NullChildPatternClass is allowed to have a negative index
|
36
|
-
def index
|
37
|
-
-1
|
38
|
-
end
|
39
|
-
|
40
35
|
def relationship
|
41
36
|
'missing child'
|
42
37
|
end
|
@@ -46,19 +41,12 @@ module Duxml
|
|
46
41
|
"#{subject.description} #{relationship} <#{child}>"
|
47
42
|
end
|
48
43
|
|
49
|
-
attr_reader :missing_child
|
44
|
+
attr_reader :missing_child, :index
|
50
45
|
alias_method :child, :missing_child
|
51
46
|
alias_method :parent, :subject
|
52
47
|
end
|
53
48
|
|
54
49
|
module ChildPattern
|
55
|
-
# @return [Element] child element
|
56
|
-
def child
|
57
|
-
subject.nodes[index]
|
58
|
-
end
|
59
|
-
|
60
|
-
alias_method :object, :child
|
61
|
-
|
62
50
|
# @return [String] describes relationship between parent and child
|
63
51
|
def relationship
|
64
52
|
"#{(index+1).ordinal_name} #{super}"
|
@@ -10,12 +10,13 @@ module Duxml
|
|
10
10
|
|
11
11
|
# @param _subject [Ox::Element] parent of text node
|
12
12
|
# @param _index [Fixnum] index of text node
|
13
|
-
def initialize(_subject, _index)
|
13
|
+
def initialize(_subject, _str, _index)
|
14
14
|
@index = _index
|
15
|
+
@string = _str
|
15
16
|
super _subject
|
16
17
|
end
|
17
18
|
|
18
|
-
attr_reader :subject, :index
|
19
|
+
attr_reader :subject, :index, :str
|
19
20
|
end
|
20
21
|
|
21
22
|
module TextPattern
|
@@ -44,7 +44,7 @@ module Duxml
|
|
44
44
|
if node.name == child_rule.subject
|
45
45
|
return child_rule.required_children.collect do |required_child_type|
|
46
46
|
unless node.nodes.any? do |n| n.name == required_child_type end
|
47
|
-
NullChildPatternClass.new(node, required_child_type)
|
47
|
+
NullChildPatternClass.new(node, required_child_type, -1)
|
48
48
|
end
|
49
49
|
end.compact
|
50
50
|
end
|
@@ -59,9 +59,9 @@ module Duxml
|
|
59
59
|
node.nodes.collect do |child|
|
60
60
|
i += 1
|
61
61
|
if child.is_a?(String)
|
62
|
-
TextPatternClass.new(node, i)
|
62
|
+
TextPatternClass.new(node, child, i)
|
63
63
|
else
|
64
|
-
ChildPatternClass.new(node, i)
|
64
|
+
ChildPatternClass.new(node, child, i)
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end # def get_child_patterns
|
@@ -122,10 +122,9 @@ module Duxml
|
|
122
122
|
child_index == object.index
|
123
123
|
end
|
124
124
|
|
125
|
-
# @return [Fixnum] index of child
|
125
|
+
# @return [Fixnum] index of child currently being scanned
|
126
126
|
def child_index
|
127
|
-
|
128
|
-
i
|
127
|
+
object.parent.nodes.size-child_stack.size-1
|
129
128
|
end
|
130
129
|
|
131
130
|
# @return [Element] previous element to the one being scanned
|
@@ -9,28 +9,23 @@ module Duxml
|
|
9
9
|
class AddClass < ChangeClass
|
10
10
|
include Add
|
11
11
|
|
12
|
-
def initialize(_subject, _index)
|
12
|
+
def initialize(_subject, _child, _index)
|
13
13
|
super _subject
|
14
|
-
@index = _index
|
14
|
+
@child, @index = _child, _index
|
15
15
|
end
|
16
16
|
|
17
|
+
attr_reader :subject, :child, :index
|
17
18
|
alias_method :parent, :subject
|
18
|
-
|
19
|
+
alias_method :object, :child
|
19
20
|
end
|
20
21
|
|
21
22
|
module Add
|
22
23
|
def description
|
23
|
-
%(#{super} #{child.description} added to #{parent.description}.)
|
24
|
+
%(#{super} #{child.description} added to #{parent.description} at index #{index == -1 ? '0' : index.to_s}.)
|
24
25
|
end
|
25
26
|
|
26
27
|
def parent
|
27
28
|
subject
|
28
29
|
end
|
29
|
-
|
30
|
-
def child
|
31
|
-
subject.nodes[index]
|
32
|
-
end
|
33
|
-
|
34
|
-
alias_method :object, :child
|
35
30
|
end # class Add
|
36
31
|
end # module Duxml
|
@@ -11,12 +11,12 @@ module Duxml
|
|
11
11
|
|
12
12
|
# @param _subject [Duxml::Element] doc that has gained new text
|
13
13
|
# @param _index [Fixnum] index of new text node
|
14
|
-
def initialize(_subject, _index)
|
14
|
+
def initialize(_subject, _str, _index)
|
15
15
|
super _subject
|
16
|
-
@index = _index
|
16
|
+
@index, @str = _index, _str
|
17
17
|
end
|
18
18
|
|
19
|
-
attr_reader :index
|
19
|
+
attr_reader :index, :str
|
20
20
|
end
|
21
21
|
|
22
22
|
module NewText
|
data/lib/duxml/meta.rb
CHANGED
@@ -37,11 +37,22 @@ module Duxml
|
|
37
37
|
# @param g [String, GrammarClass] either a grammar object or path to one
|
38
38
|
# @return [GrammarClass] grammar object
|
39
39
|
def grammar=(g)
|
40
|
-
@grammar =
|
41
|
-
g
|
42
|
-
|
43
|
-
|
44
|
-
|
40
|
+
@grammar = case g
|
41
|
+
when GrammarClass then g
|
42
|
+
when String
|
43
|
+
if File.exists?(g)
|
44
|
+
@grammar_path = g
|
45
|
+
Grammar.import(g)
|
46
|
+
else
|
47
|
+
maudule, meth = *g.split('.')
|
48
|
+
if Module.const_defined?(maudule.to_sym)
|
49
|
+
Module.const_get(maudule.to_sym).send(meth.to_sym)
|
50
|
+
else
|
51
|
+
raise ArgumentError, "#{g.to_s} is not a valid module/grammar symbol"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
else
|
55
|
+
raise ArgumentError, "#{g.to_s} is not a valid Grammar or path to one"
|
45
56
|
end
|
46
57
|
history.delete_observers if history.respond_to?(:delete_observers)
|
47
58
|
history.add_observer(grammar, :qualify)
|
@@ -5,25 +5,33 @@ class String
|
|
5
5
|
# @return [String] converts string into Ruby constant. self must be String with no whitespaces and match Regexp.nmtoken
|
6
6
|
# 'foo-bar'.constantize => 'Foo_bar'
|
7
7
|
# 'foo_bar'.constantize => 'FooBar'
|
8
|
+
# 'fooBar'.constantize => 'FooBar'
|
8
9
|
def constantize
|
9
10
|
return self if Regexp.constant.match(self)
|
10
11
|
raise Exception unless Regexp.nmtoken.match(self)
|
11
|
-
s = split('_').collect do |word| word.
|
12
|
+
s = split('_').collect do |word| word[0] = word[0].upcase; word unless word == '_' end.join.gsub('-', '_')
|
12
13
|
raise Exception unless s.match(Regexp.constant)
|
13
14
|
s
|
14
15
|
end
|
15
16
|
|
17
|
+
# @param sym [Symbol] optional setting for what type of nmtoken desired: either :snakeCase or :under_score
|
16
18
|
# @return [String] does reverse of #constantize e.g.
|
17
19
|
# 'Foo_b'.nmtokenize => 'foo-bar'
|
18
20
|
# 'FooBar'.nmtokenize => 'foo_bar'
|
19
|
-
def nmtokenize
|
21
|
+
def nmtokenize(sym = :under_score)
|
20
22
|
split('::').collect do |word|
|
21
|
-
word.gsub(/(?!^)[A-Z_]/) do |match|
|
22
|
-
case
|
23
|
-
when '_' then '-'
|
24
|
-
|
23
|
+
s = word.gsub(/(?!^)[A-Z_]/) do |match|
|
24
|
+
case
|
25
|
+
when match == '_' then '-'
|
26
|
+
when sym == :snakeCase
|
27
|
+
match
|
28
|
+
when sym == :under_score
|
29
|
+
"_#{match.downcase}"
|
30
|
+
else
|
25
31
|
end
|
26
|
-
end
|
32
|
+
end
|
33
|
+
s[0] = s[0].downcase
|
34
|
+
s
|
27
35
|
end.join(':')
|
28
36
|
end
|
29
37
|
end # class String
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: duxml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Kong
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-08-
|
11
|
+
date: 2016-08-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ox
|
@@ -89,7 +89,7 @@ files:
|
|
89
89
|
- lib/duxml/saxer.rb
|
90
90
|
- lib/duxml.rb
|
91
91
|
- bin/validate_xml
|
92
|
-
homepage: http://www.github.com/
|
92
|
+
homepage: http://www.github.com/Ludocracy/duxml
|
93
93
|
licenses:
|
94
94
|
- MIT
|
95
95
|
metadata: {}
|