xqsr3 0.12.2 → 0.13.3
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/xqsr3/command_line_utilities/map_option_string.rb +6 -4
- data/lib/xqsr3/containers/frequency_map.rb +5 -2
- data/lib/xqsr3/containers/multi_map.rb +5 -2
- data/lib/xqsr3/conversion/bool_parser.rb +2 -4
- data/lib/xqsr3/diagnostics/exception_utilities.rb +4 -1
- data/lib/xqsr3/hash_utilities/deep_transform.rb +1 -2
- data/lib/xqsr3/io/writelines.rb +5 -2
- data/lib/xqsr3/quality/parameter_checking.rb +105 -8
- data/lib/xqsr3/version.rb +2 -2
- data/lib/xqsr3/xml/utilities/compare.rb +466 -0
- data/test/unit/extensions/string/tc_ends_with.rb +1 -2
- data/test/unit/extensions/string/tc_starts_with.rb +0 -1
- data/test/unit/quality/tc_parameter_checking.rb +20 -1
- data/test/unit/xml/ts_all.rb +12 -0
- data/test/unit/xml/utilities/tc_compare.rb +131 -0
- data/test/unit/xml/utilities/ts_all.rb +12 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a62fcdc4c1aa7176aa20acf04a477f9ce9e32dde
|
4
|
+
data.tar.gz: 9e3085307d16b630cbe34d5e7d243b4f3ec18622
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 947e35e638cbd5ce7bdef5811d8c3f9de6923f697aff9212f371fda83b049b4032dd7f789f7183720c53714967c13e5ce62501071dbc11c93bb85a06adea8e41
|
7
|
+
data.tar.gz: b458cea2b2fb99ceb8a42b5262f6556fa926aecb2c2489212ede046d503d82a60acc1fb735049bf5e4eff8815aee6caab20dc23f71abae962f560bb12b4b4f3c
|
@@ -2,17 +2,17 @@
|
|
2
2
|
# ######################################################################## #
|
3
3
|
# File: lib/xqsr3/command_line_utilities/map_option_string.rb
|
4
4
|
#
|
5
|
-
# Purpose: Definition of the
|
6
|
-
# module
|
5
|
+
# Purpose: Definition of the
|
6
|
+
# ::Xqsr3::CommandLineUtilities::MapOptionString module
|
7
7
|
#
|
8
8
|
# Created: 15th April 2016
|
9
|
-
# Updated:
|
9
|
+
# Updated: 2nd August 2017
|
10
10
|
#
|
11
11
|
# Home: http://github.com/synesissoftware/xqsr3
|
12
12
|
#
|
13
13
|
# Author: Matthew Wilson
|
14
14
|
#
|
15
|
-
# Copyright (c) 2016, Matthew Wilson and Synesis Software
|
15
|
+
# Copyright (c) 2016-2017, Matthew Wilson and Synesis Software
|
16
16
|
# All rights reserved.
|
17
17
|
#
|
18
18
|
# Redistribution and use in source and binary forms, with or without
|
@@ -45,6 +45,8 @@
|
|
45
45
|
# ######################################################################## #
|
46
46
|
|
47
47
|
|
48
|
+
# ##########################################################
|
49
|
+
# ::Xqsr3::CommandLineUtilities::MapOptionString
|
48
50
|
|
49
51
|
require 'xqsr3/string_utilities/to_symbol'
|
50
52
|
|
@@ -5,13 +5,13 @@
|
|
5
5
|
# Purpose: FrequencyMap container
|
6
6
|
#
|
7
7
|
# Created: 28th January 2005
|
8
|
-
# Updated:
|
8
|
+
# Updated: 30th July 2017
|
9
9
|
#
|
10
10
|
# Home: http://github.com/synesissoftware/xqsr3
|
11
11
|
#
|
12
12
|
# Author: Matthew Wilson
|
13
13
|
#
|
14
|
-
# Copyright (c) 2005-
|
14
|
+
# Copyright (c) 2005-2017, Matthew Wilson and Synesis Software
|
15
15
|
# All rights reserved.
|
16
16
|
#
|
17
17
|
# Redistribution and use in source and binary forms, with or without
|
@@ -44,6 +44,9 @@
|
|
44
44
|
# ######################################################################## #
|
45
45
|
|
46
46
|
|
47
|
+
# ##########################################################
|
48
|
+
# ::Xqsr3::Containers::FrequencyMap
|
49
|
+
|
47
50
|
=begin
|
48
51
|
=end
|
49
52
|
|
@@ -5,13 +5,13 @@
|
|
5
5
|
# Purpose: multimap container
|
6
6
|
#
|
7
7
|
# Created: 21st March 2007
|
8
|
-
# Updated:
|
8
|
+
# Updated: 30th July 2017
|
9
9
|
#
|
10
10
|
# Home: http://github.com/synesissoftware/xqsr3
|
11
11
|
#
|
12
12
|
# Author: Matthew Wilson
|
13
13
|
#
|
14
|
-
# Copyright (c) 2007-
|
14
|
+
# Copyright (c) 2007-2017, Matthew Wilson and Synesis Software
|
15
15
|
# All rights reserved.
|
16
16
|
#
|
17
17
|
# Redistribution and use in source and binary forms, with or without
|
@@ -44,6 +44,9 @@
|
|
44
44
|
# ######################################################################## #
|
45
45
|
|
46
46
|
|
47
|
+
# ##########################################################
|
48
|
+
# ::Xqsr3::Containers::MultiMap
|
49
|
+
|
47
50
|
=begin
|
48
51
|
=end
|
49
52
|
|
@@ -6,7 +6,7 @@
|
|
6
6
|
# module
|
7
7
|
#
|
8
8
|
# Created: 3rd June 2017
|
9
|
-
# Updated:
|
9
|
+
# Updated: 28th July 2017
|
10
10
|
#
|
11
11
|
# Home: http://github.com/synesissoftware/xqsr3
|
12
12
|
#
|
@@ -46,7 +46,7 @@
|
|
46
46
|
|
47
47
|
|
48
48
|
# ##########################################################
|
49
|
-
# ::Xqsr3::Conversion::
|
49
|
+
# ::Xqsr3::Conversion::BoolParser
|
50
50
|
|
51
51
|
=begin
|
52
52
|
=end
|
@@ -116,5 +116,3 @@ end # module Xqsr3
|
|
116
116
|
|
117
117
|
# ############################## end of file ############################# #
|
118
118
|
|
119
|
-
|
120
|
-
|
@@ -5,7 +5,7 @@
|
|
5
5
|
# Purpose: Definition of the ExceptionUtilities module
|
6
6
|
#
|
7
7
|
# Created: 12th February 2015
|
8
|
-
# Updated:
|
8
|
+
# Updated: 2nd August 2017
|
9
9
|
#
|
10
10
|
# Home: http://github.com/synesissoftware/xqsr3
|
11
11
|
#
|
@@ -44,6 +44,9 @@
|
|
44
44
|
# ######################################################################## #
|
45
45
|
|
46
46
|
|
47
|
+
# ##########################################################
|
48
|
+
# ::Xqsr3::Diagnostics::ExceptionUtilities
|
49
|
+
|
47
50
|
=begin
|
48
51
|
=end
|
49
52
|
|
@@ -6,7 +6,7 @@
|
|
6
6
|
# module
|
7
7
|
#
|
8
8
|
# Created: 3rd June 2017
|
9
|
-
# Updated:
|
9
|
+
# Updated: 28th July 2017
|
10
10
|
#
|
11
11
|
# Home: http://github.com/synesissoftware/xqsr3
|
12
12
|
#
|
@@ -152,4 +152,3 @@ end # module Xqsr3
|
|
152
152
|
|
153
153
|
# ############################## end of file ############################# #
|
154
154
|
|
155
|
-
|
data/lib/xqsr3/io/writelines.rb
CHANGED
@@ -5,13 +5,13 @@
|
|
5
5
|
# Purpose: Adds a writelines() method to the IO module
|
6
6
|
#
|
7
7
|
# Created: 13th April 2007
|
8
|
-
# Updated:
|
8
|
+
# Updated: 2nd August 2017
|
9
9
|
#
|
10
10
|
# Home: http://github.com/synesissoftware/xqsr3
|
11
11
|
#
|
12
12
|
# Author: Matthew Wilson
|
13
13
|
#
|
14
|
-
# Copyright (c) 2007-
|
14
|
+
# Copyright (c) 2007-2017, Matthew Wilson and Synesis Software
|
15
15
|
# All rights reserved.
|
16
16
|
#
|
17
17
|
# Redistribution and use in source and binary forms, with or without
|
@@ -44,6 +44,9 @@
|
|
44
44
|
# ######################################################################## #
|
45
45
|
|
46
46
|
|
47
|
+
# ##########################################################
|
48
|
+
# ::Xqsr3::IO
|
49
|
+
|
47
50
|
require 'xqsr3/quality/parameter_checking'
|
48
51
|
|
49
52
|
=begin
|
@@ -5,7 +5,7 @@
|
|
5
5
|
# Purpose: Definition of the ParameterChecking module
|
6
6
|
#
|
7
7
|
# Created: 12th February 2015
|
8
|
-
# Updated:
|
8
|
+
# Updated: 1st November 2017
|
9
9
|
#
|
10
10
|
# Home: http://github.com/synesissoftware/xqsr3
|
11
11
|
#
|
@@ -44,6 +44,9 @@
|
|
44
44
|
# ######################################################################## #
|
45
45
|
|
46
46
|
|
47
|
+
# ##########################################################
|
48
|
+
# ::Xqsr3::Quality::ParameterChecking
|
49
|
+
|
47
50
|
=begin
|
48
51
|
=end
|
49
52
|
|
@@ -69,8 +72,32 @@ module ParameterChecking
|
|
69
72
|
end
|
70
73
|
end
|
71
74
|
end # module Util_
|
72
|
-
|
73
75
|
public
|
76
|
+
|
77
|
+
def self.included base
|
78
|
+
|
79
|
+
base.extend self
|
80
|
+
|
81
|
+
base.class_eval do
|
82
|
+
|
83
|
+
public
|
84
|
+
def self.check_parameter value, name, options = {}, &block
|
85
|
+
|
86
|
+
Util_.check_parameter value, name, options, &block
|
87
|
+
end
|
88
|
+
|
89
|
+
# @see check_parameter
|
90
|
+
#
|
91
|
+
# @note This is obsolete, and will be removed in a future
|
92
|
+
# version. Please use +check_parameter+ instead
|
93
|
+
public
|
94
|
+
def self.check_param value, name, options = {}, &block
|
95
|
+
|
96
|
+
Util_.check_parameter value, name, options, &block
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
74
101
|
# Check a given parameter (value=+value+, name=+name+) for type and value
|
75
102
|
#
|
76
103
|
# @param +value+ the parameter whose value and type is to be checked
|
@@ -83,6 +110,8 @@ module ParameterChecking
|
|
83
110
|
# must be derived from). One of these types may be an array
|
84
111
|
# of types, in which case +value+ may be an array that must
|
85
112
|
# consist wholly of those types
|
113
|
+
# @option +:type+ a single type parameter, used only if +:types+ is not
|
114
|
+
# specified
|
86
115
|
# @option +:values+ an array of values one of which +value+ must be
|
87
116
|
# @option +:responds_to+ an array of symbols specifying all messages to
|
88
117
|
# which the parameter will respond
|
@@ -96,8 +125,70 @@ module ParameterChecking
|
|
96
125
|
# exception, which suppresses internal message preparation
|
97
126
|
# @option +:treat_as_option+ if true, the value will be treated as an
|
98
127
|
# option when reporting check failure
|
128
|
+
#
|
129
|
+
# This method is private, because it should only be used within methods
|
130
|
+
private
|
99
131
|
def check_parameter value, name, options = {}, &block
|
100
132
|
|
133
|
+
Util_.check_parameter value, name, options, &block
|
134
|
+
end
|
135
|
+
|
136
|
+
# @see check_parameter
|
137
|
+
#
|
138
|
+
# @note This is obsolete, and will be removed in a future version.
|
139
|
+
# Please use +check_parameter+ instead
|
140
|
+
private
|
141
|
+
def check_param value, name, options = {}, &block
|
142
|
+
|
143
|
+
Util_.check_parameter value, name, options, &block
|
144
|
+
end
|
145
|
+
|
146
|
+
# Check a given parameter (value=+value+, name=+name+) for type and value
|
147
|
+
#
|
148
|
+
# @param +value+ the parameter whose value and type is to be checked
|
149
|
+
# @param +name+ the name of the parameter to be checked
|
150
|
+
# @param +options+ options
|
151
|
+
#
|
152
|
+
# @option +:allow_nil+ the +value+ must not be +nil+ unless this option
|
153
|
+
# is true
|
154
|
+
# @option +:types+ an array of types one of which +value+ must be (or
|
155
|
+
# must be derived from). One of these types may be an array
|
156
|
+
# of types, in which case +value+ may be an array that must
|
157
|
+
# consist wholly of those types
|
158
|
+
# @option +:type+ a single type parameter, used only if +:types+ is not
|
159
|
+
# specified
|
160
|
+
# @option +:values+ an array of values one of which +value+ must be
|
161
|
+
# @option +:responds_to+ an array of symbols specifying all messages to
|
162
|
+
# which the parameter will respond
|
163
|
+
# @option +:reject_empty+ requires value to respond to +empty?+
|
164
|
+
# message and to do so with false, unless +nil+
|
165
|
+
# @option +:require_empty+ requires value to respond to +empty?+
|
166
|
+
# message and to do so with true, unless +nil+
|
167
|
+
# @option +:nothrow+ causes failure to be indicated by a +nil+ return
|
168
|
+
# rather than a thrown exception
|
169
|
+
# @option +:message+ specifies a message to be used in any thrown
|
170
|
+
# exception, which suppresses internal message preparation
|
171
|
+
# @option +:treat_as_option+ if true, the value will be treated as an
|
172
|
+
# option when reporting check failure
|
173
|
+
public
|
174
|
+
def self.check_parameter value, name, options = {}, &block
|
175
|
+
|
176
|
+
Util_.check_parameter value, name, options, &block
|
177
|
+
end
|
178
|
+
|
179
|
+
# @see check_parameter
|
180
|
+
#
|
181
|
+
# @note This is obsolete, and will be removed in a future version.
|
182
|
+
# Please use +check_parameter+ instead
|
183
|
+
public
|
184
|
+
def self.check_param value, name, options = {}, &block
|
185
|
+
|
186
|
+
Util_.check_parameter value, name, options, &block
|
187
|
+
end
|
188
|
+
|
189
|
+
private
|
190
|
+
def Util_.check_parameter value, name, options, &block
|
191
|
+
|
101
192
|
failed_check = false
|
102
193
|
options ||= {}
|
103
194
|
message = options[:message]
|
@@ -140,6 +231,10 @@ module ParameterChecking
|
|
140
231
|
# types
|
141
232
|
|
142
233
|
types = options[:types] || []
|
234
|
+
if options.has_key? :type
|
235
|
+
|
236
|
+
types << options[:type] if types.empty?
|
237
|
+
end
|
143
238
|
types = [value.class] if types.empty?
|
144
239
|
|
145
240
|
warn "#{self}::check_parameter: options[:types] of type #{types.class} - should be #{::Array}" unless types.is_a?(Array)
|
@@ -311,13 +406,19 @@ module ParameterChecking
|
|
311
406
|
|
312
407
|
if value and block
|
313
408
|
|
314
|
-
warn "#{self}::check_parameter: block arity must be 1" unless block.arity
|
409
|
+
warn "#{self}::check_parameter: block arity must be 1 or 2" unless (1..2).include? block.arity
|
315
410
|
|
316
411
|
r = nil
|
317
412
|
|
318
413
|
begin
|
319
414
|
|
320
|
-
|
415
|
+
if 1 == block.arity
|
416
|
+
|
417
|
+
r = block.call(value)
|
418
|
+
else
|
419
|
+
|
420
|
+
r = block.call(value, options)
|
421
|
+
end
|
321
422
|
|
322
423
|
rescue StandardError => x
|
323
424
|
|
@@ -392,10 +493,6 @@ module ParameterChecking
|
|
392
493
|
failed_check ? nil : return_value
|
393
494
|
end
|
394
495
|
|
395
|
-
alias check_param check_parameter
|
396
|
-
|
397
|
-
module_function :check_parameter
|
398
|
-
|
399
496
|
end # module ParameterChecking
|
400
497
|
|
401
498
|
end # module Quality
|
data/lib/xqsr3/version.rb
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
# Purpose: Version for Xqsr3 library
|
6
6
|
#
|
7
7
|
# Created: 3rd April 2016
|
8
|
-
# Updated:
|
8
|
+
# Updated: 1st November 2017
|
9
9
|
#
|
10
10
|
# Home: http://github.com/synesissoftware/xqsr3
|
11
11
|
#
|
@@ -50,7 +50,7 @@
|
|
50
50
|
module Xqsr3
|
51
51
|
|
52
52
|
# Current version of the Xqsr3 library
|
53
|
-
VERSION = '0.
|
53
|
+
VERSION = '0.13.3'
|
54
54
|
|
55
55
|
private
|
56
56
|
VERSION_PARTS_ = VERSION.split(/[.]/).collect { |n| n.to_i } # :nodoc:
|
@@ -0,0 +1,466 @@
|
|
1
|
+
|
2
|
+
# ######################################################################## #
|
3
|
+
# File: lib/xqsr3/xml/_utilities/compare.rb
|
4
|
+
#
|
5
|
+
# Purpose: Definition of the ::Xqsr3::XML::Utilities::Compare
|
6
|
+
# module
|
7
|
+
#
|
8
|
+
# Created: 30th July 2017
|
9
|
+
# Updated: 1st November 2017
|
10
|
+
#
|
11
|
+
# Home: http://github.com/synesissoftware/xqsr3
|
12
|
+
#
|
13
|
+
# Author: Matthew Wilson
|
14
|
+
#
|
15
|
+
# Copyright (c) 2017, Matthew Wilson and Synesis Software
|
16
|
+
# All rights reserved.
|
17
|
+
#
|
18
|
+
# Redistribution and use in source and binary forms, with or without
|
19
|
+
# modification, are permitted provided that the following conditions are
|
20
|
+
# met:
|
21
|
+
#
|
22
|
+
# * Redistributions of source code must retain the above copyright notice,
|
23
|
+
# this list of conditions and the following disclaimer.
|
24
|
+
#
|
25
|
+
# * Redistributions in binary form must reproduce the above copyright
|
26
|
+
# notice, this list of conditions and the following disclaimer in the
|
27
|
+
# documentation and/or other materials provided with the distribution.
|
28
|
+
#
|
29
|
+
# * Neither the names of the copyright holder nor the names of its
|
30
|
+
# contributors may be used to endorse or promote products derived from
|
31
|
+
# this software without specific prior written permission.
|
32
|
+
#
|
33
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
34
|
+
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
35
|
+
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
36
|
+
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
37
|
+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
38
|
+
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
39
|
+
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
40
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
41
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
42
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
43
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
44
|
+
#
|
45
|
+
# ######################################################################## #
|
46
|
+
|
47
|
+
|
48
|
+
# ##########################################################
|
49
|
+
# ::Xqsr3::XML::Utilities::Compare
|
50
|
+
|
51
|
+
=begin
|
52
|
+
=end
|
53
|
+
|
54
|
+
require 'xqsr3/quality/parameter_checking'
|
55
|
+
|
56
|
+
require 'nokogiri'
|
57
|
+
|
58
|
+
module Xqsr3
|
59
|
+
module XML
|
60
|
+
module Utilities
|
61
|
+
|
62
|
+
module Compare
|
63
|
+
|
64
|
+
# Class that represents the result of an XML comparison
|
65
|
+
#
|
66
|
+
# NOTE: Sadly, we cannot create instances of +FalseClass+/+TrueClass+,
|
67
|
+
# to which we could then add a +reason+ attribute, so instead we must
|
68
|
+
# have a results class
|
69
|
+
class Result
|
70
|
+
|
71
|
+
include ::Xqsr3::Quality::ParameterChecking
|
72
|
+
|
73
|
+
protected :check_parameter
|
74
|
+
|
75
|
+
#
|
76
|
+
# Options:
|
77
|
+
#
|
78
|
+
# +:different_attributes+
|
79
|
+
# +:different_attribute_count+
|
80
|
+
# +:different_attribute_order+
|
81
|
+
# +:different_child_node_count+
|
82
|
+
# +:different_child_node_order+
|
83
|
+
# +:different_child_nodes+
|
84
|
+
# +:different_node_names+
|
85
|
+
# +:different_node_contents+
|
86
|
+
# +:parameter_is_empty+
|
87
|
+
# +:parameter_is_nil+
|
88
|
+
# +:+
|
89
|
+
|
90
|
+
def initialize status, reason, **options
|
91
|
+
|
92
|
+
check_parameter status, 'status', types: [ ::FalseClass, ::TrueClass ]
|
93
|
+
check_parameter reason, 'reason', type: ::Symbol, allow_nil: true
|
94
|
+
|
95
|
+
@status = status
|
96
|
+
@reason = reason
|
97
|
+
|
98
|
+
@lhs_node = options[:lhs_node]
|
99
|
+
@rhs_node = options[:rhs_node]
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.return status, reason, **options
|
103
|
+
|
104
|
+
return self.new status, reason, **options
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.same reason = nil, **options
|
108
|
+
|
109
|
+
return self.new true, reason, **options
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.different reason, **options
|
113
|
+
|
114
|
+
return self.new false, reason, **options
|
115
|
+
end
|
116
|
+
|
117
|
+
attr_reader :status
|
118
|
+
attr_reader :reason
|
119
|
+
|
120
|
+
def different?
|
121
|
+
|
122
|
+
!status
|
123
|
+
end
|
124
|
+
|
125
|
+
def same?
|
126
|
+
|
127
|
+
status
|
128
|
+
end
|
129
|
+
|
130
|
+
def details
|
131
|
+
|
132
|
+
r = reason.to_s.gsub /_/, ' '
|
133
|
+
|
134
|
+
qualifying = ''
|
135
|
+
|
136
|
+
if @lhs_node
|
137
|
+
|
138
|
+
qualifying += '; ' unless qualifying.empty?
|
139
|
+
qualifying += "lhs-node=#{@lhs_node}"
|
140
|
+
end
|
141
|
+
|
142
|
+
if @rhs_node
|
143
|
+
|
144
|
+
qualifying += '; ' unless qualifying.empty?
|
145
|
+
qualifying += "rhs-node=#{@rhs_node}"
|
146
|
+
end
|
147
|
+
|
148
|
+
r = "#{r}: #{qualifying}" unless qualifying.empty?
|
149
|
+
|
150
|
+
r
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
module Internal_Compare_
|
155
|
+
|
156
|
+
extend ::Xqsr3::Quality::ParameterChecking
|
157
|
+
|
158
|
+
DEFAULT_OPTIONS = {
|
159
|
+
|
160
|
+
debug: false,
|
161
|
+
# element_order: false,
|
162
|
+
equate_nil_and_empty: false,
|
163
|
+
ignore_attributes: false,
|
164
|
+
ignore_attribute_order: true,
|
165
|
+
ignore_child_node_order: true,
|
166
|
+
normalise_whitespace: true,
|
167
|
+
# normalize_whitespace: true,
|
168
|
+
validate_params: true,
|
169
|
+
}
|
170
|
+
|
171
|
+
ORDER_OPTIONS_SYMBOLS = [
|
172
|
+
|
173
|
+
:element_order,
|
174
|
+
:ignore_attribute_order,
|
175
|
+
:ignore_child_node_order,
|
176
|
+
]
|
177
|
+
|
178
|
+
WHITESPACE_OPTIONS_SYMBOLS = [
|
179
|
+
|
180
|
+
:normalise_whitespace,
|
181
|
+
:normalize_whitespace,
|
182
|
+
]
|
183
|
+
|
184
|
+
def self.derive_options_ given_options
|
185
|
+
|
186
|
+
default_options = DEFAULT_OPTIONS
|
187
|
+
derived_options = {}.merge given_options
|
188
|
+
|
189
|
+
|
190
|
+
# sort whitespace
|
191
|
+
|
192
|
+
if WHITESPACE_OPTIONS_SYMBOLS.any? { |sym| given_options.has_key? sym }
|
193
|
+
|
194
|
+
default_options = default_options.reject { |k, v| WHITESPACE_OPTIONS_SYMBOLS.include? k }
|
195
|
+
end
|
196
|
+
|
197
|
+
if given_options.has_key? :normalise_whitespace
|
198
|
+
|
199
|
+
derived_options.delete :normalize_whitespace
|
200
|
+
elsif given_options.has_key? :normalize_whitespace
|
201
|
+
|
202
|
+
derived_options[:normalise_whitespace] = given_options[:normalize_whitespace]
|
203
|
+
|
204
|
+
derived_options.delete :normalize_whitespace
|
205
|
+
end
|
206
|
+
|
207
|
+
|
208
|
+
# sort element-order
|
209
|
+
|
210
|
+
if ORDER_OPTIONS_SYMBOLS.any? { |sym| given_options.has_key? sym }
|
211
|
+
|
212
|
+
default_options = default_options.reject { |k, v| ORDER_OPTIONS_SYMBOLS.include? k }
|
213
|
+
end
|
214
|
+
|
215
|
+
if given_options.has_key? :element_order
|
216
|
+
|
217
|
+
element_order = given_options[:element_order]
|
218
|
+
|
219
|
+
derived_options[:ignore_attribute_order] = !element_order
|
220
|
+
derived_options[:ignore_child_node_order] = !element_order
|
221
|
+
end
|
222
|
+
|
223
|
+
derived_options[:ignore_attribute_order] = given_options[:ignore_attribute_order] if given_options.has_key? :ignore_attribute_order
|
224
|
+
derived_options[:ignore_child_node_order] = given_options[:ignore_child_node_order] if given_options.has_key? :ignore_child_node_order
|
225
|
+
|
226
|
+
default_options.merge derived_options
|
227
|
+
end
|
228
|
+
|
229
|
+
def self.one_line_ s
|
230
|
+
|
231
|
+
s = s.to_s.gsub(/\s+/, ' ')
|
232
|
+
end
|
233
|
+
|
234
|
+
#
|
235
|
+
# +:debug+
|
236
|
+
# +:element_order+
|
237
|
+
# +:equate_nil_and_empty+
|
238
|
+
# +:ignore_attributes+
|
239
|
+
# +:ignore_attribute_order+
|
240
|
+
# +:normalise_whitespace+
|
241
|
+
# +:normalize_whitespace+
|
242
|
+
# +:validate_params+
|
243
|
+
#
|
244
|
+
|
245
|
+
def self.xml_compare_ lhs, rhs, options
|
246
|
+
|
247
|
+
$stderr.puts "#{self}#{__method__}(lhs (#{lhs.class})=#{self.one_line_ lhs}, rhs (#{rhs.class})=#{self.one_line_ rhs}, options (#{options.class})=#{options})" if $DEBUG
|
248
|
+
|
249
|
+
# validate parameter(s)
|
250
|
+
|
251
|
+
check_parameter options, 'options', type: ::Hash if $DEBUG
|
252
|
+
|
253
|
+
validate_params = $DEBUG || options[:debug] || options[:validate_params]
|
254
|
+
|
255
|
+
check_parameter lhs, 'lhs', types: [ ::String, ::Nokogiri::XML::Node ], allow_nil: true if validate_params
|
256
|
+
check_parameter rhs, 'rhs', types: [ ::String, ::Nokogiri::XML::Node ], allow_nil: true if validate_params
|
257
|
+
|
258
|
+
options = self.derive_options_ options
|
259
|
+
|
260
|
+
# deal with nil(s)
|
261
|
+
|
262
|
+
return Result.same if lhs.nil? && rhs.nil?
|
263
|
+
|
264
|
+
if lhs.nil?
|
265
|
+
|
266
|
+
return Result.same if options[:equate_nil_and_empty] && ::String === rhs && rhs.empty?
|
267
|
+
|
268
|
+
return Result.different :parameter_is_nil
|
269
|
+
end
|
270
|
+
|
271
|
+
if rhs.nil?
|
272
|
+
|
273
|
+
return Result.same if options[:equate_nil_and_empty] && ::String === lhs && lhs.empty?
|
274
|
+
|
275
|
+
return Result.different :parameter_is_nil
|
276
|
+
end
|
277
|
+
|
278
|
+
|
279
|
+
# deal with string(s)
|
280
|
+
|
281
|
+
lhs = Nokogiri::XML(lhs) if ::String === lhs
|
282
|
+
rhs = Nokogiri::XML(rhs) if ::String === rhs
|
283
|
+
|
284
|
+
|
285
|
+
self.xml_compare_nodes_ lhs, rhs, options
|
286
|
+
end
|
287
|
+
|
288
|
+
def self.xml_compare_nodes_ lhs, rhs, options
|
289
|
+
|
290
|
+
$stderr.puts "#{self}#{__method__}(lhs (#{lhs.class})=#{self.one_line_ lhs}, rhs (#{rhs.class})=#{self.one_line_ rhs}, options (#{options.class})=#{options})" if $DEBUG
|
291
|
+
|
292
|
+
|
293
|
+
# Compare:
|
294
|
+
#
|
295
|
+
# - name
|
296
|
+
# - attributes
|
297
|
+
# - content
|
298
|
+
# - children
|
299
|
+
# -
|
300
|
+
|
301
|
+
|
302
|
+
# ##########################
|
303
|
+
# name
|
304
|
+
|
305
|
+
lhs_name = lhs.name
|
306
|
+
rhs_name = rhs.name
|
307
|
+
|
308
|
+
return Result.different :different_node_names, lhs_node: lhs, rhs_node: rhs if lhs_name != rhs_name
|
309
|
+
|
310
|
+
|
311
|
+
# ##########################
|
312
|
+
# attributes
|
313
|
+
|
314
|
+
unless options[:ignore_attributes]
|
315
|
+
|
316
|
+
lhs_attributes = lhs.attribute_nodes
|
317
|
+
rhs_attributes = rhs.attribute_nodes
|
318
|
+
|
319
|
+
return Result.different :different_attribute_count, lhs_node: lhs, rhs_node: rhs if lhs_attributes.count != rhs_attributes.count
|
320
|
+
|
321
|
+
|
322
|
+
lhs_attr_list = lhs_attributes.map { |attr| [ attr.name, attr.content ] }
|
323
|
+
rhs_attr_list = rhs_attributes.map { |attr| [ attr.name, attr.content ] }
|
324
|
+
|
325
|
+
if lhs_attr_list != rhs_attr_list
|
326
|
+
|
327
|
+
# do the sort first
|
328
|
+
|
329
|
+
lhs_attr_list.sort! { |l, r| l[0] <=> r[0] }
|
330
|
+
rhs_attr_list.sort! { |l, r| l[0] <=> r[0] }
|
331
|
+
|
332
|
+
# Now there are four possibiliies:
|
333
|
+
#
|
334
|
+
# 1. Different attributes
|
335
|
+
# 2. Different attribute order
|
336
|
+
# 3. Same (when reordered)
|
337
|
+
|
338
|
+
if lhs_attr_list == rhs_attr_list
|
339
|
+
|
340
|
+
if options[:ignore_attribute_order]
|
341
|
+
|
342
|
+
# 3
|
343
|
+
else
|
344
|
+
|
345
|
+
# 2
|
346
|
+
|
347
|
+
return Result.different :different_attribute_order, lhs_node: lhs, rhs_node: rhs
|
348
|
+
end
|
349
|
+
else
|
350
|
+
|
351
|
+
return Result.different :different_attributes, lhs_node: lhs, rhs_node: rhs
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
# ##########################
|
357
|
+
# content
|
358
|
+
|
359
|
+
normalise_ws = options[:normalise_whitespace]
|
360
|
+
|
361
|
+
lhs_content = normalise_ws ? lhs.content.gsub(/\s+/, ' ').strip : lhs.content
|
362
|
+
rhs_content = normalise_ws ? rhs.content.gsub(/\s+/, ' ').strip : rhs.content
|
363
|
+
|
364
|
+
return Result.different :different_node_contents, lhs_node: lhs, rhs_node: rhs if lhs_content != rhs_content
|
365
|
+
|
366
|
+
|
367
|
+
# ##########################
|
368
|
+
# children (preparation)
|
369
|
+
|
370
|
+
lhs_children = lhs.children.to_a
|
371
|
+
rhs_children = rhs.children.to_a
|
372
|
+
|
373
|
+
lhs_children.reject! { |child| child.text? && child.content.strip.empty? }
|
374
|
+
rhs_children.reject! { |child| child.text? && child.content.strip.empty? }
|
375
|
+
|
376
|
+
|
377
|
+
# ##########################
|
378
|
+
# children - count
|
379
|
+
|
380
|
+
lhs_children_count = lhs_children.count
|
381
|
+
rhs_children_count = rhs_children.count
|
382
|
+
|
383
|
+
return Result.different :different_child_node_count, lhs_node: lhs, rhs_node: rhs if lhs_children_count != rhs_children_count
|
384
|
+
|
385
|
+
|
386
|
+
# ##########################
|
387
|
+
# children - names
|
388
|
+
|
389
|
+
lhs_children_names = lhs_children.map { |ch| ch.name }
|
390
|
+
rhs_children_names = rhs_children.map { |ch| ch.name }
|
391
|
+
|
392
|
+
if lhs_children_names != rhs_children_names
|
393
|
+
|
394
|
+
# At this point, the lists of names of child elements are
|
395
|
+
# different. This may be because there are different
|
396
|
+
# elements or because they are in a different order. Either
|
397
|
+
# way, in order to provide detailed reasons for
|
398
|
+
# inequivalency, we must do an order-independent comparison
|
399
|
+
|
400
|
+
children_sorted_lhs = lhs_children.sort { |x, y| x.name <=> y.name }
|
401
|
+
children_sorted_rhs = rhs_children.sort { |x, y| x.name <=> y.name }
|
402
|
+
|
403
|
+
ch_names_sorted_lhs = children_sorted_lhs.map { |ch| ch.name }
|
404
|
+
ch_names_sorted_rhs = children_sorted_rhs.map { |ch| ch.name }
|
405
|
+
|
406
|
+
ignore_order = options[:ignore_child_node_order]
|
407
|
+
|
408
|
+
if ignore_order
|
409
|
+
|
410
|
+
return Result.different :different_child_nodes, lhs_node: lhs, rhs_node: rhs if ch_names_sorted_lhs != ch_names_sorted_rhs
|
411
|
+
|
412
|
+
# Since they are the same (when reordered), we need to
|
413
|
+
# adopt the ordered sequences so that the comparison of
|
414
|
+
# the children are meaningful
|
415
|
+
|
416
|
+
lhs_children = children_sorted_lhs
|
417
|
+
rhs_children = children_sorted_rhs
|
418
|
+
else
|
419
|
+
|
420
|
+
# failed, so need to determine whether it's due to
|
421
|
+
# different nodes or different order
|
422
|
+
|
423
|
+
if ch_names_sorted_lhs == ch_names_sorted_rhs
|
424
|
+
|
425
|
+
return Result.different :different_child_node_order, lhs_node: lhs, rhs_node: rhs
|
426
|
+
else
|
427
|
+
|
428
|
+
return Result.different :different_child_nodes, lhs_node: lhs, rhs_node: rhs
|
429
|
+
end
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
(0 ... lhs_children.count).each do |index|
|
434
|
+
|
435
|
+
ch_lhs = lhs_children[index]
|
436
|
+
ch_rhs = rhs_children[index]
|
437
|
+
|
438
|
+
r = self.xml_compare_nodes_ ch_lhs, ch_rhs, options
|
439
|
+
|
440
|
+
return r unless r.status
|
441
|
+
end
|
442
|
+
|
443
|
+
return Result.same
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
def self.xml_compare lhs, rhs, **options
|
448
|
+
|
449
|
+
$stderr.puts "#{self}#{__method__}(lhs (#{lhs.class})=#{Internal_Compare_.one_line_ lhs}, rhs (#{rhs.class})=#{Internal_Compare_.one_line_ rhs}, options (#{options.class})=#{options})" if $DEBUG
|
450
|
+
|
451
|
+
Internal_Compare_.xml_compare_ lhs, rhs, options
|
452
|
+
end
|
453
|
+
|
454
|
+
def xml_compare lhs, rhs, **options
|
455
|
+
|
456
|
+
$stderr.puts "#{self}#{__method__}(lhs (#{lhs.class})=#{Internal_Compare_.one_line_ lhs}, rhs (#{rhs.class})=#{Internal_Compare_.one_line_ rhs}, options (#{options.class})=#{options})" if $DEBUG
|
457
|
+
|
458
|
+
Internal_Compare_.xml_compare_ lhs, rhs, options
|
459
|
+
end
|
460
|
+
|
461
|
+
end # module Compare
|
462
|
+
|
463
|
+
end # module Utilities
|
464
|
+
end # module XML
|
465
|
+
end # module Xqsr3
|
466
|
+
|
@@ -58,8 +58,7 @@ class Test_String_ends_with < Test::Unit::TestCase
|
|
58
58
|
prefixes = %w{ a c def }
|
59
59
|
|
60
60
|
assert_not ''.ends_with?(*prefixes)
|
61
|
-
assert_nil ''.ends_with?(*prefixes)
|
62
|
-
assert ''.ends_with?(*prefixes), ''
|
61
|
+
assert_nil ''.ends_with?(*prefixes), 'empty string does not yield nil with given non-empty prefix(es)'
|
63
62
|
assert 'abc'.ends_with?(*prefixes)
|
64
63
|
assert_not 'd'.ends_with?(*prefixes)
|
65
64
|
assert_nil 'd'.ends_with?(*prefixes)
|
@@ -59,7 +59,6 @@ class Test_String_starts_with < Test::Unit::TestCase
|
|
59
59
|
|
60
60
|
assert_not ''.starts_with?(*prefixes)
|
61
61
|
assert_nil ''.starts_with?(*prefixes)
|
62
|
-
assert ''.starts_with?(*prefixes), ''
|
63
62
|
assert 'abc'.starts_with?(*prefixes)
|
64
63
|
assert_not 'd'.starts_with?(*prefixes)
|
65
64
|
assert_nil 'd'.starts_with?(*prefixes)
|
@@ -12,7 +12,7 @@ class Test_parameter_checks_as_separate_module < Test::Unit::TestCase
|
|
12
12
|
end
|
13
13
|
include TestConstants
|
14
14
|
|
15
|
-
|
15
|
+
include ::Xqsr3::Quality::ParameterChecking
|
16
16
|
|
17
17
|
|
18
18
|
# test 1
|
@@ -239,5 +239,24 @@ end
|
|
239
239
|
check_responds_to Hash.new, [ :this_is_not_a_Hash_method ]
|
240
240
|
end
|
241
241
|
end
|
242
|
+
|
243
|
+
|
244
|
+
|
245
|
+
# test type:
|
246
|
+
|
247
|
+
def check_method_type a, type
|
248
|
+
|
249
|
+
self.class.check_parameter a, 'a', type: type
|
250
|
+
end
|
251
|
+
|
252
|
+
def test_type
|
253
|
+
|
254
|
+
check_method_type '', ::String
|
255
|
+
|
256
|
+
assert_raise TypeError do
|
257
|
+
|
258
|
+
check_method_type :sym, ::String
|
259
|
+
end
|
260
|
+
end
|
242
261
|
end
|
243
262
|
|
@@ -0,0 +1,12 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# executes all other tests
|
4
|
+
|
5
|
+
this_dir = File.expand_path(File.dirname(__FILE__))
|
6
|
+
|
7
|
+
# all tc_*rb in current directory
|
8
|
+
Dir[File.join(this_dir, 'tc_*rb')].each { |file| require file }
|
9
|
+
|
10
|
+
# all ts_*rb in immediate sub-directories
|
11
|
+
Dir[File.join(this_dir, '*', 'ts_*rb')].each { |file| require file }
|
12
|
+
|
@@ -0,0 +1,131 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), '../../../../lib')
|
4
|
+
|
5
|
+
require 'xqsr3/xml/utilities/compare'
|
6
|
+
|
7
|
+
require 'xqsr3/extensions/test/unit'
|
8
|
+
require 'test/unit'
|
9
|
+
|
10
|
+
class Test_Xqsr3_XML_Utilities_Compare < Test::Unit::TestCase
|
11
|
+
|
12
|
+
include ::Xqsr3::XML::Utilities::Compare
|
13
|
+
|
14
|
+
def test_compare_nil
|
15
|
+
|
16
|
+
assert xml_compare(nil, nil).same?
|
17
|
+
|
18
|
+
assert_false xml_compare('', nil).same?
|
19
|
+
assert_false xml_compare(nil, '').same?
|
20
|
+
|
21
|
+
assert xml_compare('', nil, equate_nil_and_empty: true).same?
|
22
|
+
assert xml_compare(nil, '', equate_nil_and_empty: true).same?
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_compare_empty
|
26
|
+
|
27
|
+
assert xml_compare('', '').same?
|
28
|
+
|
29
|
+
assert_false xml_compare('<abc/>', '').same?
|
30
|
+
assert_false xml_compare('', '<abc/>').same?
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_compare_one_level_1
|
34
|
+
|
35
|
+
assert xml_compare('<abc/>', '<abc/>').same?
|
36
|
+
assert xml_compare('<abc/>', '<abc></abc>').same?
|
37
|
+
assert_false xml_compare('<abc/>', '<def/>').same?
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_compare_two_level_1
|
41
|
+
|
42
|
+
assert xml_compare('<parent><child1></child1></parent>', '<parent><child1></child1></parent>').same?
|
43
|
+
assert xml_compare('<parent><child1/></parent>', '<parent><child1></child1></parent>').same?
|
44
|
+
|
45
|
+
r = xml_compare('<parent><child1/></parent>', '<parent><child2/></parent>')
|
46
|
+
|
47
|
+
assert_false r.same?
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_compare_attributes_1
|
51
|
+
|
52
|
+
lhs = <<END_OF_lhs
|
53
|
+
<node name="John Smith" age="21" />
|
54
|
+
END_OF_lhs
|
55
|
+
|
56
|
+
rhs_same = <<END_OF_lhs
|
57
|
+
<node age="21" name="John Smith" />
|
58
|
+
END_OF_lhs
|
59
|
+
|
60
|
+
rhs_diff = <<END_OF_lhs
|
61
|
+
<node name="John Smith" age="22" />
|
62
|
+
END_OF_lhs
|
63
|
+
|
64
|
+
r = xml_compare lhs, rhs_same, ignore_attribute_order: false
|
65
|
+
|
66
|
+
assert r.different?, r.details
|
67
|
+
assert_equal :different_attribute_order, r.reason
|
68
|
+
|
69
|
+
r = xml_compare lhs, rhs_same, ignore_attribute_order: true
|
70
|
+
|
71
|
+
assert r.same?
|
72
|
+
|
73
|
+
r = xml_compare lhs, rhs_same, element_order: false
|
74
|
+
|
75
|
+
assert r.same?
|
76
|
+
|
77
|
+
r = xml_compare lhs, rhs_diff
|
78
|
+
|
79
|
+
assert r.different?
|
80
|
+
assert_equal :different_attributes, r.reason
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_compare_two_level_2
|
84
|
+
|
85
|
+
lhs = <<END_OF_lhs
|
86
|
+
<parent>
|
87
|
+
<child1/>
|
88
|
+
</parent>
|
89
|
+
END_OF_lhs
|
90
|
+
rhs = <<END_OF_rhs
|
91
|
+
<parent>
|
92
|
+
<child1>
|
93
|
+
</child1>
|
94
|
+
</parent>
|
95
|
+
END_OF_rhs
|
96
|
+
|
97
|
+
r = xml_compare lhs, rhs, normalize_whitespace: false
|
98
|
+
|
99
|
+
assert r.different?, "#{r.details}"
|
100
|
+
assert_equal :different_node_contents, r.reason
|
101
|
+
|
102
|
+
r = xml_compare(lhs, rhs, normalize_whitespace: true)
|
103
|
+
|
104
|
+
assert r.same?, "#{r.details}"
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_compare_two_level_3
|
108
|
+
|
109
|
+
lhs = <<END_OF_lhs
|
110
|
+
<parent>
|
111
|
+
<child1/>
|
112
|
+
<child2>
|
113
|
+
<grandchild2a/>
|
114
|
+
</child2>
|
115
|
+
</parent>
|
116
|
+
END_OF_lhs
|
117
|
+
rhs = <<END_OF_rhs
|
118
|
+
<parent>
|
119
|
+
<child2><grandchild2a/></child2>
|
120
|
+
<child1>
|
121
|
+
</child1>
|
122
|
+
</parent>
|
123
|
+
END_OF_rhs
|
124
|
+
|
125
|
+
r = xml_compare lhs, rhs, normalize_whitespace: true
|
126
|
+
|
127
|
+
assert r.same?, "#{r.details}"
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# executes all other tests
|
4
|
+
|
5
|
+
this_dir = File.expand_path(File.dirname(__FILE__))
|
6
|
+
|
7
|
+
# all tc_*rb in current directory
|
8
|
+
Dir[File.join(this_dir, 'tc_*rb')].each { |file| require file }
|
9
|
+
|
10
|
+
# all ts_*rb in immediate sub-directories
|
11
|
+
Dir[File.join(this_dir, '*', 'ts_*rb')].each { |file| require file }
|
12
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xqsr3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.13.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Wilson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-11-15 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |
|
14
14
|
eXtensions by fine Quantum for Standard Ruby and 3rd-party libraries is a
|
@@ -57,6 +57,7 @@ files:
|
|
57
57
|
- lib/xqsr3/string_utilities/starts_with.rb
|
58
58
|
- lib/xqsr3/string_utilities/to_symbol.rb
|
59
59
|
- lib/xqsr3/version.rb
|
60
|
+
- lib/xqsr3/xml/utilities/compare.rb
|
60
61
|
- test/unit/command_line_utilities/tc_map_option_string.rb
|
61
62
|
- test/unit/command_line_utilities/ts_all.rb
|
62
63
|
- test/unit/containers/tc_frequency_map.rb
|
@@ -89,6 +90,9 @@ files:
|
|
89
90
|
- test/unit/quality/ts_all.rb
|
90
91
|
- test/unit/tc_version.rb
|
91
92
|
- test/unit/ts_all.rb
|
93
|
+
- test/unit/xml/ts_all.rb
|
94
|
+
- test/unit/xml/utilities/tc_compare.rb
|
95
|
+
- test/unit/xml/utilities/ts_all.rb
|
92
96
|
homepage: http://github.com/synesissoftware/xqsr3
|
93
97
|
licenses:
|
94
98
|
- 3-clause BSD
|