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 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: {}