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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5cfc64bf0a2a0fc7d5dfa7eddf824a91de78019e
4
- data.tar.gz: 68539178080588cf391bd98619dd994f2e55fd6a
3
+ metadata.gz: e9a620bcdd50c48d3b01ee43b5df3227820036c2
4
+ data.tar.gz: f0702e3d79fbfb2365bdfeec0c2cb5fa6c4f539e
5
5
  SHA512:
6
- metadata.gz: f176dc33c32a6293ff8d3df5e04ac7e48b9fd6edf275b1fe0260c56b18e5baa24366f9335bad203367d1f2aee5413be9dd17e92be4f4bccb1190f92428ac8bbc
7
- data.tar.gz: cc453d524c27917c4ad689023e4622090edc17c3a08b4ecb42383a93c7c0516422fcb958ad29333e04d859a48efe88939c26db1125491fc47aaba925cf6f7ec0
6
+ metadata.gz: 16aa187942b52c19196771bb213650351148fff1e2ba675247ec65829ca4ca812ce824bfe9fbbc44ae88ff0b9b4dd66c068aafb48a6d440a45dc435c96016e64
7
+ data.tar.gz: 14fa01c704c3db5e73613871f94d57bae6b999d3b2d33eba2bd86761910993abe778b586738ca5165880380b8bbeee97434106e940a0e7e36efc99b2786df49c
@@ -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
- type = :NewText
74
- nodes.insert(index, obj)
75
- report(type, nodes.size-1)
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 nodes.last.count_observers < 1 && @observer_peers
80
- nodes.last.add_observer(@observer_peers.first.first)
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, nodes.size - 1)
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.concat(current.nodes) if current.respond_to?(:nodes)
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
@@ -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 NoMethodError
77
- # handling Constant look up to dynamically extend or add to element
78
- if lowercase?(sym)
79
- if (const = look_up_const) and const.is_a?(Module)
80
- extend const
81
- result = method(sym).call(*args)
82
- return(result) unless block_given?
83
- yield(result)
84
- elsif block_given?
85
- new_method = proc(&block)
86
- self.const_set(sym, new_method)
87
- return new_method.call *args
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
- raise NoMethodError, "undefined method `#{sym.to_s}' for #{description}"
90
- end # if (const = look_up_const) ... elsif block_given? ... else ...
91
- else
92
- results = filter(sym, args)
93
- return results unless block_given?
94
- results.keep_if do |node| yield(node) end
95
- end # if lowercase? ... else ...
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
- word = mod_names.shift
128
- k = word.constantize
129
- if maudule.const_defined?(k, true) or Module.const_defined?(simple_class, true)
130
- const = maudule.const_get(k)
131
- if const.is_a?(Module)
132
- maudule = const
133
- end
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 _index [Fixnum] index of child
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 currenlty being scanned
125
+ # @return [Fixnum] index of child currently being scanned
126
126
  def child_index
127
- i = object.parent.nodes.size-child_stack.size-1
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
- attr_reader :subject, :index
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 = if g.is_a?(GrammarClass)
41
- g
42
- else
43
- @grammar_path = g if File.exists?(g)
44
- Grammar.import(g)
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.capitalize unless word == '_' end.join.gsub('-', '_')
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 match
23
- when '_' then '-'
24
- else "_#{match.downcase}"
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.downcase
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.0
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-17 00:00:00.000000000 Z
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/ruby-dita/duxml
92
+ homepage: http://www.github.com/Ludocracy/duxml
93
93
  licenses:
94
94
  - MIT
95
95
  metadata: {}