duxml 0.7.2 → 0.8.0
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/bin/validate_xml +13 -1
- data/lib/duxml/doc/element.rb +31 -7
- data/lib/duxml/doc/lazy_ox.rb +152 -152
- data/lib/duxml/doc/node_set.rb +38 -38
- data/lib/duxml/doc.rb +67 -7
- data/lib/duxml/meta/grammar/pattern.rb +14 -0
- data/lib/duxml/meta/grammar/spreadsheet.rb +34 -34
- data/lib/duxml/meta/grammar.rb +3 -3
- data/lib/duxml/meta/history.rb +10 -9
- data/lib/duxml/meta.rb +20 -9
- data/lib/duxml/reportable.rb +28 -26
- data/lib/duxml/saxer.rb +4 -3
- data/lib/duxml.rb +42 -63
- metadata +3 -4
- data/xml/dita_grammar.xml +0 -2133
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5cfc64bf0a2a0fc7d5dfa7eddf824a91de78019e
|
4
|
+
data.tar.gz: 68539178080588cf391bd98619dd994f2e55fd6a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f176dc33c32a6293ff8d3df5e04ac7e48b9fd6edf275b1fe0260c56b18e5baa24366f9335bad203367d1f2aee5413be9dd17e92be4f4bccb1190f92428ac8bbc
|
7
|
+
data.tar.gz: cc453d524c27917c4ad689023e4622090edc17c3a08b4ecb42383a93c7c0516422fcb958ad29333e04d859a48efe88939c26db1125491fc47aaba925cf6f7ec0
|
data/bin/validate_xml
CHANGED
@@ -16,4 +16,16 @@ puts "loaded grammar file: #{DITA_GRAMMAR_FILE}"
|
|
16
16
|
validate
|
17
17
|
puts "validation complete"
|
18
18
|
log log_file
|
19
|
-
puts "logged errors to #{log_file}"
|
19
|
+
puts "logged errors to #{log_file}"
|
20
|
+
|
21
|
+
|
22
|
+
if conditions
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
def conditions
|
28
|
+
asdf and b and c
|
29
|
+
end
|
30
|
+
|
31
|
+
File
|
data/lib/duxml/doc/element.rb
CHANGED
@@ -25,7 +25,7 @@ module Duxml
|
|
25
25
|
# in Ruby mode, args are some combination of new attributes/values and/or child nodes (text or XML) with which to initialize this node
|
26
26
|
#
|
27
27
|
# @param name [String] name of element, in both Ruby and file modes
|
28
|
-
# @param
|
28
|
+
# @param _line_or_content [Fixnum, Array, Hash] line number of element file mode; if Array, new child nodes; if Hash, attributes; can be nil
|
29
29
|
# @param _col_or_children [Fixnum, Array] column position in file mode; if Array, new child nodes; can be nil
|
30
30
|
def initialize(name, _line_or_content=nil, _col_or_children=nil)
|
31
31
|
super name
|
@@ -51,18 +51,31 @@ module Duxml
|
|
51
51
|
# @see Ox::Element#<<
|
52
52
|
# this override reports changes to history; NewText for Strings, Add for elements
|
53
53
|
#
|
54
|
-
# @param obj [Element] element or string to add to this Element
|
54
|
+
# @param obj [Element, Array] element or string to add to this Element; can insert arrays which are always inserted in order
|
55
55
|
# @return [Element] self
|
56
56
|
def <<(obj)
|
57
|
+
add(obj)
|
58
|
+
end
|
59
|
+
|
60
|
+
# @see #<<
|
61
|
+
# this version of the method allows insertions between existing elements
|
62
|
+
#
|
63
|
+
# @param obj [Element, Array] element or string to add to this Element; can insert arrays which are always inserted in order
|
64
|
+
# @param index [Fixnum] index at which to insert new node; inserts at end of element by default; when inserting arrays, index is incremented for each item to avoid reversing array order
|
65
|
+
# @return [Element] self
|
66
|
+
def add(obj, index=-1)
|
57
67
|
case
|
58
68
|
when obj.is_a?(Array), obj.is_a?(NodeSet)
|
59
|
-
obj.
|
69
|
+
obj.each_with_index do |e, i|
|
70
|
+
add(e, index == -1 ? index : index+i)
|
71
|
+
end
|
60
72
|
when obj.is_a?(String)
|
61
73
|
type = :NewText
|
62
|
-
|
74
|
+
nodes.insert(index, obj)
|
75
|
+
report(type, nodes.size-1)
|
63
76
|
else
|
64
77
|
type = :Add
|
65
|
-
|
78
|
+
nodes.insert(index, obj)
|
66
79
|
if nodes.last.count_observers < 1 && @observer_peers
|
67
80
|
nodes.last.add_observer(@observer_peers.first.first)
|
68
81
|
end
|
@@ -71,10 +84,21 @@ module Duxml
|
|
71
84
|
self
|
72
85
|
end
|
73
86
|
|
74
|
-
# @param
|
75
|
-
# @
|
87
|
+
# @param index_or_attr [String, Symbol, Fixnum] string or symbol of attribute or index of child node
|
88
|
+
# @return [Element, String] string if attribute value or text node; Element if XML node
|
89
|
+
def [](index_or_attr)
|
90
|
+
index_or_attr.is_a?(Fixnum) ? nodes[index_or_attr] : super(index_or_attr)
|
91
|
+
end
|
92
|
+
|
93
|
+
# @param attr_sym [String, Symbol, Fixnum] name of attribute or index of child to replace
|
94
|
+
# @param val [String] new attribute value or replacement child node
|
76
95
|
# @return [Element] self
|
77
96
|
def []=(attr_sym, val)
|
97
|
+
if attr_sym.is_a?(Fixnum)
|
98
|
+
remove nodes[attr_sym]
|
99
|
+
add(val, attr_sym)
|
100
|
+
return self
|
101
|
+
end
|
78
102
|
attr = attr_sym.to_s
|
79
103
|
raise "argument to [] must be a Symbol or a String." unless attr.is_a?(Symbol) or attr.is_a?(String)
|
80
104
|
args = [attr]
|
data/lib/duxml/doc/lazy_ox.rb
CHANGED
@@ -1,153 +1,153 @@
|
|
1
|
-
# Copyright (c) 2016 Freescale Semiconductor Inc.
|
2
|
-
|
3
|
-
require File.expand_path(File.dirname(__FILE__) + '/../ruby_ext/string')
|
4
|
-
|
5
|
-
|
6
|
-
module Duxml
|
7
|
-
module LazyOx
|
8
|
-
# welcome to Lazy-Ox - where any method that doesn't exist, you can create on the fly and assign its methods to
|
9
|
-
# a corresponding Duxml::Element. see Regexp.nmtoken and String#nmtokenize and String#constantize to see how a given symbol
|
10
|
-
# can be converted into XML element names and vice versa. it can also use Class names as method calls to return children by type
|
11
|
-
#
|
12
|
-
# this method uses Ox::Element's :method_missing but adds an additional rescue block that:
|
13
|
-
# matches namespaced Ruby module to this Element's name and extends this node with module's methods
|
14
|
-
# then method matching symbol is called again with given arguments, yielding result to block if given, returning result if not
|
15
|
-
# e.g.
|
16
|
-
# module Duxml
|
17
|
-
# module Throwable
|
18
|
-
# def throw
|
19
|
-
# puts 'throwing!!'
|
20
|
-
# end
|
21
|
-
# end
|
22
|
-
# end
|
23
|
-
#
|
24
|
-
# Element.new('throwable').throw => 'throwing!!'
|
25
|
-
#
|
26
|
-
# if symbol name matches a class then method yields to block or returns as array child nodes that matches class
|
27
|
-
# you can further refine search results by adding the symbol of the child instance variable, including name, by which to filter
|
28
|
-
# if block given, returns first child for which block evaluates to true
|
29
|
-
#
|
30
|
-
# e.g.
|
31
|
-
# class Child; end
|
32
|
-
#
|
33
|
-
# n = Element.new('node')
|
34
|
-
# n << 'text'
|
35
|
-
# n << Element.new('child')
|
36
|
-
# n << Element.new('child')
|
37
|
-
# n.Element # returns Array of Element nodes
|
38
|
-
# => [#<Duxml::Element:0x0002 @value="child" ...>,
|
39
|
-
# #<Duxml::Element:0x0003 @value="child" ...>]
|
40
|
-
#
|
41
|
-
# n.Element.each do |child| child << 'some text' end # adding some text
|
42
|
-
# => ['text',
|
43
|
-
# #<Duxml::Element:0x0002 @value="child" ... @nodes=['some text']>,
|
44
|
-
# #<Duxml::Element 0x0003 @value="child" ... @nodes=['some text']>]
|
45
|
-
#
|
46
|
-
# n.Element do |child| child.nodes.first == 'some text' end # returns all children for which block is true
|
47
|
-
# => [#<Duxml::Element:0x0002 @value="child" ... @nodes=['some text']>]
|
48
|
-
#
|
49
|
-
# %w(bar mar).each_with_index do |x, i| next if i.zero?; n.Child[:foo] = x end # adding some attributes
|
50
|
-
# => ['text',
|
51
|
-
# #<Duxml::Element:0x0002 @value="child" @attributes={foo: 'bar'} ...>,
|
52
|
-
# #<Duxml::Element:0x0003 @value="child" @attributes={foo: 'mar'} ...>]
|
53
|
-
#
|
54
|
-
# n.Element(:foo) # returns array of Child nodes with attribute :foo
|
55
|
-
# => [#<Duxml::Element:0x0002 @value="child" @attributes={foo: 'bar'} ...>,
|
56
|
-
# #<Duxml::Element:0x0003 @value="child" @attributes={foo: 'mar'} ...>]
|
57
|
-
#
|
58
|
-
# n.Element(foo: 'bar') # returns array of Child nodes with attribute :foo equal to 'bar'
|
59
|
-
# => [#<Duxml::Element:0xfff @value="child" @attributes={foo: 'bar'} ...>]
|
60
|
-
#
|
61
|
-
#
|
62
|
-
# if element name has no matching Class or Module in namespace,
|
63
|
-
# if symbol is lower case, it is made into a method, given &block as definition, then called with *args
|
64
|
-
# e.g. n.change_color('blue') do |new_color| => #<Duxml::Element:0xfff @value="node" @attributes={color: 'blue'} @nodes=[]>
|
65
|
-
# @color = new_color
|
66
|
-
# self
|
67
|
-
# end
|
68
|
-
# n.color => 'blue'
|
69
|
-
# n.change_color('mauve').color => 'mauve'
|
70
|
-
#
|
71
|
-
# @param sym [Symbol] method, class or module
|
72
|
-
# @param *args [*several_variants] either arguments to method or initializing values for instance of given class
|
73
|
-
# @param &block [block] if yielding result, yields to given block; if defining new method, block defines its contents
|
74
|
-
def method_missing(sym, *args, &block)
|
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
|
88
|
-
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 ...
|
96
|
-
end # def method_missing(sym, *args, &block)
|
97
|
-
|
98
|
-
private
|
99
|
-
|
100
|
-
# @param sym [Symbol] indicates which element type is being filtered for
|
101
|
-
# @param args [several_variants] arguments for filtering element children that matched 'sym'
|
102
|
-
# @return [[Element]] Elements of type 'sym' that match criteria 'args'
|
103
|
-
def filter(sym, args)
|
104
|
-
class_nodes = nodes.select do |node|
|
105
|
-
node.name == sym.to_s.nmtokenize or simple_class(node) == sym.to_s
|
106
|
-
end
|
107
|
-
class_nodes.keep_if do |node|
|
108
|
-
if args.empty?
|
109
|
-
true
|
110
|
-
else
|
111
|
-
args.any? do |arg|
|
112
|
-
if arg.is_a?(Hash)
|
113
|
-
node[arg.first.first] == arg.first.last
|
114
|
-
else
|
115
|
-
!node[arg].nil?
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end # if args.empty? ... else ...
|
119
|
-
end # class_nodes.keep_if do |node|
|
120
|
-
end # def filter(args)
|
121
|
-
|
122
|
-
# @param maudule [Module] module context in which to look for duck-called method's module
|
123
|
-
# @return [Module, Class] requested module or class
|
124
|
-
def look_up_const(maudule = Duxml)
|
125
|
-
mod_names = name.split(':')
|
126
|
-
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)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
nil
|
139
|
-
end
|
140
|
-
|
141
|
-
# @param sym [Symbol] symbol for a constant
|
142
|
-
# @return [Boolean] is symbol lowercase?
|
143
|
-
def lowercase?(sym)
|
144
|
-
sym.to_s[0].match(/[A-Z]/).nil?
|
145
|
-
end
|
146
|
-
|
147
|
-
# @param obj [Object] usually Element
|
148
|
-
# @return [String] name of final Class or Module of self
|
149
|
-
def simple_class(obj=self)
|
150
|
-
obj.class.to_s.split('::').last
|
151
|
-
end
|
152
|
-
end # module LazyOx
|
1
|
+
# Copyright (c) 2016 Freescale Semiconductor Inc.
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../ruby_ext/string')
|
4
|
+
|
5
|
+
|
6
|
+
module Duxml
|
7
|
+
module LazyOx
|
8
|
+
# welcome to Lazy-Ox - where any method that doesn't exist, you can create on the fly and assign its methods to
|
9
|
+
# a corresponding Duxml::Element. see Regexp.nmtoken and String#nmtokenize and String#constantize to see how a given symbol
|
10
|
+
# can be converted into XML element names and vice versa. it can also use Class names as method calls to return children by type
|
11
|
+
#
|
12
|
+
# this method uses Ox::Element's :method_missing but adds an additional rescue block that:
|
13
|
+
# matches namespaced Ruby module to this Element's name and extends this node with module's methods
|
14
|
+
# then method matching symbol is called again with given arguments, yielding result to block if given, returning result if not
|
15
|
+
# e.g.
|
16
|
+
# module Duxml
|
17
|
+
# module Throwable
|
18
|
+
# def throw
|
19
|
+
# puts 'throwing!!'
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# Element.new('throwable').throw => 'throwing!!'
|
25
|
+
#
|
26
|
+
# if symbol name matches a class then method yields to block or returns as array child nodes that matches class
|
27
|
+
# you can further refine search results by adding the symbol of the child instance variable, including name, by which to filter
|
28
|
+
# if block given, returns first child for which block evaluates to true
|
29
|
+
#
|
30
|
+
# e.g.
|
31
|
+
# class Child; end
|
32
|
+
#
|
33
|
+
# n = Element.new('node')
|
34
|
+
# n << 'text'
|
35
|
+
# n << Element.new('child')
|
36
|
+
# n << Element.new('child')
|
37
|
+
# n.Element # returns Array of Element nodes
|
38
|
+
# => [#<Duxml::Element:0x0002 @value="child" ...>,
|
39
|
+
# #<Duxml::Element:0x0003 @value="child" ...>]
|
40
|
+
#
|
41
|
+
# n.Element.each do |child| child << 'some text' end # adding some text
|
42
|
+
# => ['text',
|
43
|
+
# #<Duxml::Element:0x0002 @value="child" ... @nodes=['some text']>,
|
44
|
+
# #<Duxml::Element 0x0003 @value="child" ... @nodes=['some text']>]
|
45
|
+
#
|
46
|
+
# n.Element do |child| child.nodes.first == 'some text' end # returns all children for which block is true
|
47
|
+
# => [#<Duxml::Element:0x0002 @value="child" ... @nodes=['some text']>]
|
48
|
+
#
|
49
|
+
# %w(bar mar).each_with_index do |x, i| next if i.zero?; n.Child[:foo] = x end # adding some attributes
|
50
|
+
# => ['text',
|
51
|
+
# #<Duxml::Element:0x0002 @value="child" @attributes={foo: 'bar'} ...>,
|
52
|
+
# #<Duxml::Element:0x0003 @value="child" @attributes={foo: 'mar'} ...>]
|
53
|
+
#
|
54
|
+
# n.Element(:foo) # returns array of Child nodes with attribute :foo
|
55
|
+
# => [#<Duxml::Element:0x0002 @value="child" @attributes={foo: 'bar'} ...>,
|
56
|
+
# #<Duxml::Element:0x0003 @value="child" @attributes={foo: 'mar'} ...>]
|
57
|
+
#
|
58
|
+
# n.Element(foo: 'bar') # returns array of Child nodes with attribute :foo equal to 'bar'
|
59
|
+
# => [#<Duxml::Element:0xfff @value="child" @attributes={foo: 'bar'} ...>]
|
60
|
+
#
|
61
|
+
#
|
62
|
+
# if element name has no matching Class or Module in namespace,
|
63
|
+
# if symbol is lower case, it is made into a method, given &block as definition, then called with *args
|
64
|
+
# e.g. n.change_color('blue') do |new_color| => #<Duxml::Element:0xfff @value="node" @attributes={color: 'blue'} @nodes=[]>
|
65
|
+
# @color = new_color
|
66
|
+
# self
|
67
|
+
# end
|
68
|
+
# n.color => 'blue'
|
69
|
+
# n.change_color('mauve').color => 'mauve'
|
70
|
+
#
|
71
|
+
# @param sym [Symbol] method, class or module
|
72
|
+
# @param *args [*several_variants] either arguments to method or initializing values for instance of given class
|
73
|
+
# @param &block [block] if yielding result, yields to given block; if defining new method, block defines its contents
|
74
|
+
def method_missing(sym, *args, &block)
|
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
|
88
|
+
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 ...
|
96
|
+
end # def method_missing(sym, *args, &block)
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
# @param sym [Symbol] indicates which element type is being filtered for
|
101
|
+
# @param args [several_variants] arguments for filtering element children that matched 'sym'
|
102
|
+
# @return [[Element]] Elements of type 'sym' that match criteria 'args'
|
103
|
+
def filter(sym, args)
|
104
|
+
class_nodes = nodes.select do |node|
|
105
|
+
node.name == sym.to_s.nmtokenize or simple_class(node) == sym.to_s
|
106
|
+
end
|
107
|
+
class_nodes.keep_if do |node|
|
108
|
+
if args.empty?
|
109
|
+
true
|
110
|
+
else
|
111
|
+
args.any? do |arg|
|
112
|
+
if arg.is_a?(Hash)
|
113
|
+
node[arg.first.first] == arg.first.last
|
114
|
+
else
|
115
|
+
!node[arg].nil?
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end # if args.empty? ... else ...
|
119
|
+
end # class_nodes.keep_if do |node|
|
120
|
+
end # def filter(args)
|
121
|
+
|
122
|
+
# @param maudule [Module] module context in which to look for duck-called method's module
|
123
|
+
# @return [Module, Class] requested module or class
|
124
|
+
def look_up_const(maudule = Duxml)
|
125
|
+
mod_names = name.split(':')
|
126
|
+
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)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
nil
|
139
|
+
end
|
140
|
+
|
141
|
+
# @param sym [Symbol] symbol for a constant
|
142
|
+
# @return [Boolean] is symbol lowercase?
|
143
|
+
def lowercase?(sym)
|
144
|
+
sym.to_s[0].match(/[A-Z]/).nil?
|
145
|
+
end
|
146
|
+
|
147
|
+
# @param obj [Object] usually Element
|
148
|
+
# @return [String] name of final Class or Module of self
|
149
|
+
def simple_class(obj=self)
|
150
|
+
obj.class.to_s.split('::').last
|
151
|
+
end
|
152
|
+
end # module LazyOx
|
153
153
|
end # module Duxml
|
data/lib/duxml/doc/node_set.rb
CHANGED
@@ -1,39 +1,39 @@
|
|
1
|
-
# Copyright (c) 2016 Freescale Semiconductor Inc.
|
2
|
-
|
3
|
-
require 'observer'
|
4
|
-
|
5
|
-
module Duxml
|
6
|
-
# subclass of Array that is Observable by History
|
7
|
-
# used to track changes in String nodes of XML Element
|
8
|
-
class NodeSet < Array
|
9
|
-
include Observable
|
10
|
-
|
11
|
-
@parent
|
12
|
-
|
13
|
-
attr_reader :parent
|
14
|
-
|
15
|
-
# @param _parent [Element] Element that is parent to this NodeSet's elements
|
16
|
-
# @param ary [[String, Element]] child nodes with which to initialize this NodeSet
|
17
|
-
def initialize(_parent, ary=[])
|
18
|
-
super ary
|
19
|
-
@parent = _parent
|
20
|
-
end
|
21
|
-
|
22
|
-
# @return [HistoryClass] object that observes this NodeSet for changes
|
23
|
-
def history
|
24
|
-
@observer_peers.first.first if @observer_peers and @observer_peers.first.any?
|
25
|
-
end
|
26
|
-
|
27
|
-
# @param index [Fixnum] index of array where old String is to be replaced
|
28
|
-
# @param str [String] replacing String
|
29
|
-
# @return [self] reports old String and index to history
|
30
|
-
def []=(index, str)
|
31
|
-
raise Exception if count_observers < 1
|
32
|
-
old_str = self[index]
|
33
|
-
super(index, str)
|
34
|
-
changed
|
35
|
-
notify_observers(:ChangeText, parent, index, old_str)
|
36
|
-
self
|
37
|
-
end
|
38
|
-
end # class NodeSet < Array
|
1
|
+
# Copyright (c) 2016 Freescale Semiconductor Inc.
|
2
|
+
|
3
|
+
require 'observer'
|
4
|
+
|
5
|
+
module Duxml
|
6
|
+
# subclass of Array that is Observable by History
|
7
|
+
# used to track changes in String nodes of XML Element
|
8
|
+
class NodeSet < Array
|
9
|
+
include Observable
|
10
|
+
|
11
|
+
@parent
|
12
|
+
|
13
|
+
attr_reader :parent
|
14
|
+
|
15
|
+
# @param _parent [Element] Element that is parent to this NodeSet's elements
|
16
|
+
# @param ary [[String, Element]] child nodes with which to initialize this NodeSet
|
17
|
+
def initialize(_parent, ary=[])
|
18
|
+
super ary
|
19
|
+
@parent = _parent
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [HistoryClass] object that observes this NodeSet for changes
|
23
|
+
def history
|
24
|
+
@observer_peers.first.first if @observer_peers and @observer_peers.first.any?
|
25
|
+
end
|
26
|
+
|
27
|
+
# @param index [Fixnum] index of array where old String is to be replaced
|
28
|
+
# @param str [String] replacing String
|
29
|
+
# @return [self] reports old String and index to history
|
30
|
+
def []=(index, str)
|
31
|
+
raise Exception if count_observers < 1
|
32
|
+
old_str = self[index]
|
33
|
+
super(index, str)
|
34
|
+
changed
|
35
|
+
notify_observers(:ChangeText, parent, index, old_str)
|
36
|
+
self
|
37
|
+
end
|
38
|
+
end # class NodeSet < Array
|
39
39
|
end # module Duxml
|
data/lib/duxml/doc.rb
CHANGED
@@ -1,26 +1,86 @@
|
|
1
1
|
# Copyright (c) 2016 Freescale Semiconductor Inc.
|
2
2
|
|
3
3
|
require File.expand_path(File.dirname(__FILE__) + '/doc/element')
|
4
|
+
require File.expand_path(File.dirname(__FILE__) + '/meta')
|
4
5
|
|
5
6
|
module Duxml
|
6
7
|
class Doc < ::Ox::Document
|
7
8
|
include ElementGuts
|
9
|
+
|
10
|
+
# path of file where this Doc is saved to
|
11
|
+
@path
|
12
|
+
|
13
|
+
# meta data for this Doc; contains reference to grammar if it exists and history
|
14
|
+
@meta
|
15
|
+
|
16
|
+
attr_reader :meta, :path
|
17
|
+
|
8
18
|
def initialize(prolog={})
|
9
19
|
super(prolog)
|
10
20
|
self[:version] ||= '1.0'
|
21
|
+
@meta = MetaClass.new
|
11
22
|
@nodes = NodeSet.new(self)
|
12
|
-
|
23
|
+
add_observer meta.history
|
13
24
|
end
|
14
25
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
26
|
+
# @param _path [String] assigns file path to document, creating it if it does not already exist along with metadata file
|
27
|
+
def path=(_path)
|
28
|
+
@path = _path
|
29
|
+
set_meta _path unless path
|
30
|
+
unless File.exists?(path)
|
31
|
+
write_to(path)
|
32
|
+
end
|
20
33
|
end
|
21
34
|
|
35
|
+
# @return [String] summary of XML document as Ruby object and description of root element
|
22
36
|
def to_s
|
23
37
|
"#<#{self.class.to_s} @object_id='#{object_id}' @root='#{root.nil? ? '' : root.description}'>"
|
24
38
|
end
|
39
|
+
|
40
|
+
# @param path_or_obj [String, MetaClass] metadata object itself or path of metadata for this file; if none given, saves existing metadata to file using @path
|
41
|
+
# @return [Doc] self
|
42
|
+
def set_meta(path_or_obj=nil)
|
43
|
+
@meta = case path_or_obj
|
44
|
+
when MetaClass, Element then path_or_obj
|
45
|
+
when String && File.exists?(path_or_obj)
|
46
|
+
Ox.parse_obj(path_or_obj)
|
47
|
+
else
|
48
|
+
File.write(Meta.meta_path(path), Ox.dump(meta)) if path
|
49
|
+
meta
|
50
|
+
end
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
# shortcut method @see Meta#grammar
|
55
|
+
def grammar
|
56
|
+
meta.grammar
|
57
|
+
end
|
58
|
+
|
59
|
+
# shortcut method @see Meta#grammar=
|
60
|
+
def grammar=(grammar_or_file)
|
61
|
+
meta.grammar = grammar_or_file
|
62
|
+
end
|
63
|
+
|
64
|
+
# shortcut method @see Meta#history
|
65
|
+
def history
|
66
|
+
meta.history
|
67
|
+
end
|
68
|
+
|
69
|
+
# @return [String] one word description of what this object is: 'document'
|
70
|
+
def description
|
71
|
+
'document'
|
72
|
+
end
|
73
|
+
|
74
|
+
# @param path [String] document's file path
|
75
|
+
# @return [Doc] returns self after writing contents to file
|
76
|
+
def write_to(path)
|
77
|
+
s = attributes.collect do |k, v| %( #{k}="#{v}") end.join
|
78
|
+
File.write(path, %(<?xml #{s}?>\n) + root.to_s)
|
79
|
+
x = meta.xml
|
80
|
+
File.write(Meta.meta_path(path), meta.xml.to_s)
|
81
|
+
self
|
82
|
+
end
|
25
83
|
end # class Document < Element
|
26
|
-
end
|
84
|
+
end
|
85
|
+
|
86
|
+
Hash
|
@@ -31,6 +31,20 @@ module Duxml
|
|
31
31
|
module Pattern
|
32
32
|
include Duxml
|
33
33
|
|
34
|
+
def xml
|
35
|
+
p = Element.new(simple_name)
|
36
|
+
instance_variables.each do |sym|
|
37
|
+
val = instance_variable_get(sym)
|
38
|
+
if val.respond_to?(:nodes)
|
39
|
+
d = Element.new(sym.to_s) << val
|
40
|
+
p << d
|
41
|
+
else
|
42
|
+
p[sym.to_s[1..-1].to_sym] = val.to_s unless sym == :@observer_peers
|
43
|
+
end
|
44
|
+
end
|
45
|
+
p
|
46
|
+
end
|
47
|
+
|
34
48
|
# @return [String] nmtoken name of this pattern without namespace prefix e.g. ChildPattern.new(parent, child).name => 'child_pattern'
|
35
49
|
def simple_name
|
36
50
|
name.split(':').last
|