duxml 0.8.0 → 0.8.4
Sign up to get free protection for your applications and to get access to all the features.
- 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: {}
|