saxon-rb 0.4.0-java → 0.7.2-java
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/.circleci/config.yml +429 -42
- data/.ruby-version +1 -1
- data/.yardopts +1 -0
- data/Gemfile +2 -2
- data/README.md +358 -10
- data/Rakefile +237 -7
- data/docs/templates/plugin.rb +73 -0
- data/lib/net/sf/saxon/Saxon-HE/{9.9.1-5/Saxon-HE-9.9.1-5.jar → 9.9.1-6/Saxon-HE-9.9.1-6.jar} +0 -0
- data/lib/saxon-rb.rb +0 -0
- data/lib/{saxon_jars.rb → saxon-rb_jars.rb} +2 -2
- data/lib/saxon.rb +13 -0
- data/lib/saxon/axis_iterator.rb +8 -1
- data/lib/saxon/configuration.rb +16 -13
- data/lib/saxon/document_builder.rb +216 -5
- data/lib/saxon/feature_flags.rb +11 -0
- data/lib/saxon/feature_flags/errors.rb +8 -0
- data/lib/saxon/feature_flags/helpers.rb +15 -0
- data/lib/saxon/feature_flags/version.rb +100 -0
- data/lib/saxon/item_type.rb +129 -89
- data/lib/saxon/item_type/lexical_string_conversion.rb +214 -59
- data/lib/saxon/item_type/value_to_ruby.rb +25 -0
- data/lib/saxon/loader.rb +6 -1
- data/lib/saxon/nokogiri.rb +78 -0
- data/lib/saxon/occurrence_indicator.rb +32 -3
- data/lib/saxon/processor.rb +50 -5
- data/lib/saxon/qname.rb +37 -2
- data/lib/saxon/s9api.rb +5 -0
- data/lib/saxon/sequence_type.rb +131 -0
- data/lib/saxon/serializer.rb +3 -137
- data/lib/saxon/serializer/destination.rb +80 -0
- data/lib/saxon/serializer/object.rb +93 -0
- data/lib/saxon/serializer/output_properties.rb +83 -0
- data/lib/saxon/source.rb +207 -71
- data/lib/saxon/version.rb +7 -1
- data/lib/saxon/version/library.rb +89 -0
- data/lib/saxon/xdm.rb +7 -0
- data/lib/saxon/xdm/array.rb +16 -0
- data/lib/saxon/xdm/atomic_value.rb +10 -2
- data/lib/saxon/xdm/empty_sequence.rb +13 -0
- data/lib/saxon/xdm/external_object.rb +1 -0
- data/lib/saxon/xdm/function_item.rb +1 -0
- data/lib/saxon/xdm/item.rb +7 -0
- data/lib/saxon/xdm/map.rb +38 -0
- data/lib/saxon/xdm/node.rb +50 -1
- data/lib/saxon/xdm/sequence_like.rb +15 -0
- data/lib/saxon/xdm/value.rb +21 -5
- data/lib/saxon/xpath.rb +9 -0
- data/lib/saxon/xpath/compiler.rb +37 -2
- data/lib/saxon/xpath/executable.rb +53 -28
- data/lib/saxon/xpath/static_context.rb +25 -40
- data/lib/saxon/xpath/variable_declaration.rb +16 -49
- data/lib/saxon/xslt.rb +12 -0
- data/lib/saxon/xslt/compiler.rb +75 -6
- data/lib/saxon/xslt/evaluation_context.rb +30 -4
- data/lib/saxon/xslt/executable.rb +206 -29
- data/lib/saxon/xslt/invocation.rb +97 -0
- data/saxon-rb.gemspec +3 -3
- metadata +22 -10
- data/saxon.gemspec +0 -30
@@ -0,0 +1,83 @@
|
|
1
|
+
module Saxon
|
2
|
+
module Serializer
|
3
|
+
# Manage access to the serialization properties of this serializer, with
|
4
|
+
# hash-like access.
|
5
|
+
#
|
6
|
+
# Properties can be set explicitly through this API, or via XSLT or XQuery
|
7
|
+
# serialization options like +<xsl:output>+.
|
8
|
+
#
|
9
|
+
# Properties set explicitly here will override properties set through the
|
10
|
+
# document by +<xsl:output>+.
|
11
|
+
module OutputProperties
|
12
|
+
# @return [Saxon::Serializer::OutputProperties] hash-like access to the Output Properties
|
13
|
+
def output_property
|
14
|
+
@output_property ||= OutputProperties::Accessor.new(s9_serializer)
|
15
|
+
end
|
16
|
+
|
17
|
+
# @api private
|
18
|
+
#
|
19
|
+
# The private wrapper class that manages getting and setting output
|
20
|
+
# properties on a Serializer in an idiomatic Ruby-like way.
|
21
|
+
class Accessor
|
22
|
+
# @api private
|
23
|
+
# Provides mapping between symbols and the underlying Saxon property
|
24
|
+
# instances
|
25
|
+
def self.output_properties
|
26
|
+
@output_properties ||= Hash[
|
27
|
+
Saxon::S9API::Serializer::Property.values.map { |property|
|
28
|
+
qname = property.getQName
|
29
|
+
key = [
|
30
|
+
qname.getPrefix,
|
31
|
+
qname.getLocalName.tr('-', '_')
|
32
|
+
].reject { |str| str == '' }.join('_').to_sym
|
33
|
+
[key, property]
|
34
|
+
}
|
35
|
+
]
|
36
|
+
end
|
37
|
+
|
38
|
+
attr_reader :s9_serializer
|
39
|
+
|
40
|
+
# @api private
|
41
|
+
def initialize(s9_serializer)
|
42
|
+
@s9_serializer = s9_serializer
|
43
|
+
end
|
44
|
+
|
45
|
+
# @param [Symbol, Saxon::S9API::Serializer::Property] property The property to fetch
|
46
|
+
def [](property)
|
47
|
+
s9_serializer.getOutputProperty(resolved_property(property))
|
48
|
+
end
|
49
|
+
|
50
|
+
# @param [Symbol, Saxon::S9API::Serializer::Property] property The property to set
|
51
|
+
# @param [String] value The string value of the property
|
52
|
+
def []=(property, value)
|
53
|
+
s9_serializer.setOutputProperty(resolved_property(property), value)
|
54
|
+
end
|
55
|
+
|
56
|
+
# @overload fetch(property)
|
57
|
+
# @param [Symbol, Saxon::S9API::Serializer::Property] property The property to fetch
|
58
|
+
# @overload fetch(property, default)
|
59
|
+
# @param property [Symbol, Saxon::S9API::Serializer::Property] The property to fetch
|
60
|
+
# @param default [Object] The value to return if the property is unset
|
61
|
+
def fetch(property, default = nil)
|
62
|
+
explicit_value = self[property]
|
63
|
+
if explicit_value.nil? && !default.nil?
|
64
|
+
default
|
65
|
+
else
|
66
|
+
explicit_value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def resolved_property(property_key)
|
73
|
+
case property_key
|
74
|
+
when Symbol
|
75
|
+
self.class.output_properties.fetch(property_key)
|
76
|
+
else
|
77
|
+
property_key
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/saxon/source.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'java'
|
2
2
|
require 'saxon/jaxp'
|
3
3
|
require 'uri'
|
4
|
+
require 'open-uri'
|
4
5
|
require 'pathname'
|
5
6
|
|
6
7
|
module Saxon
|
@@ -8,10 +9,13 @@ module Saxon
|
|
8
9
|
# the XML bytestream in. Provides some extra methods to make handling closing
|
9
10
|
# the source and its inputstream after consumption more idiomatic
|
10
11
|
class Source
|
12
|
+
# Helper methods for getting Java-useful representations of source document
|
13
|
+
# strings and files
|
11
14
|
module Helpers
|
12
15
|
# Given a File, or IO object which will return either #path or
|
13
16
|
# #base_uri, return the #base_uri, if present, or the #path, if present, or
|
14
17
|
# nil
|
18
|
+
#
|
15
19
|
# @param [File, IO] io A File or IO
|
16
20
|
# object representing the input XML file or data, or a String containing
|
17
21
|
# the XML
|
@@ -23,30 +27,92 @@ module Saxon
|
|
23
27
|
io.path if io.respond_to?(:path)
|
24
28
|
end
|
25
29
|
|
26
|
-
# Given a File or IO return a Java InputStream
|
27
|
-
#
|
28
|
-
#
|
30
|
+
# Given a File or IO return a Java InputStream, or an InputStreamReader if
|
31
|
+
# the Encoding is explicitly specified (rather than inferred from the
|
32
|
+
# <?xml charset="..."?>) declaration in the source.
|
33
|
+
#
|
34
|
+
# @param io [File, IO, org.jruby.util.IOInputStream, java.io.InputStream]
|
35
|
+
# input to be converted to an input stream
|
36
|
+
# @param encoding [Encoding, String] the character encoding to be used to
|
37
|
+
# for the stream, overriding the XML parser.
|
29
38
|
# @return [java.io.InputStream] the wrapped input
|
30
|
-
def self.inputstream(io)
|
31
|
-
case io
|
39
|
+
def self.inputstream(io, encoding = nil)
|
40
|
+
stream = case io
|
32
41
|
when org.jruby.util.IOInputStream, java.io.InputStream
|
33
42
|
io
|
34
43
|
else
|
35
44
|
io.to_inputstream if io.respond_to?(:read)
|
36
45
|
end
|
46
|
+
|
47
|
+
return stream if encoding.nil?
|
48
|
+
java.io.InputStreamReader.new(stream, ruby_encoding_to_charset(encoding))
|
37
49
|
end
|
38
50
|
|
39
51
|
# Given a path return a Java File object
|
40
|
-
#
|
52
|
+
#
|
53
|
+
# @param path [String, Pathname] the path to the file
|
41
54
|
# @return [java.io.File] the Java File object
|
42
55
|
def self.file(path)
|
43
56
|
java.io.File.new(path.to_s)
|
44
57
|
end
|
58
|
+
|
59
|
+
# Given a file path and encoding, return a Java InputStreamReader object
|
60
|
+
# for the file.
|
61
|
+
#
|
62
|
+
# @param path [String, Pathname] the path to the file
|
63
|
+
# @param encoding [String, Encoding] the file's character encoding
|
64
|
+
# @return [java.io.InputStreamReader] a Java InputStreamReader object
|
65
|
+
# wrapping a FileInputStream for the file
|
66
|
+
def self.file_reader(path, encoding)
|
67
|
+
java.io.InputStreamReader.new(java.io.FileInputStream.new(file(path)), ruby_encoding_to_charset(encoding))
|
68
|
+
end
|
69
|
+
|
70
|
+
# Return a File or Reader object for a file, depending on whether the
|
71
|
+
# encoding must be explicitly specified or not.
|
72
|
+
#
|
73
|
+
# @param path [String, Pathname] the path to the file
|
74
|
+
# @param encoding [String, Encoding] the file's character encoding
|
75
|
+
# @return [java.io.Reader] a Java Reader object
|
76
|
+
def self.file_or_reader(path, encoding = nil)
|
77
|
+
encoding.nil? ? file(path) : file_reader(path, encoding)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Return a Reader object for the String with an explicitly set encoding.
|
81
|
+
# If the encoding is +ASCII_8BIT+ then a binary-mode StreamReader is
|
82
|
+
# returned, rather than a character Reader
|
83
|
+
#
|
84
|
+
# @param string [String] the string
|
85
|
+
# @param encoding [String, Encoding] the string's character encoding
|
86
|
+
# @return [java.io.InputStream, java.io.Reader] a Java InputStream or Reader object
|
87
|
+
def self.string_reader(string, encoding)
|
88
|
+
inputstream = StringIO.new(string).to_inputstream
|
89
|
+
encoding = ruby_encoding(encoding)
|
90
|
+
return inputstream if encoding == ::Encoding::ASCII_8BIT
|
91
|
+
java.io.InputStreamReader.new(inputstream, ruby_encoding_to_charset(encoding))
|
92
|
+
end
|
93
|
+
|
94
|
+
# Figure out the equivalent Java +Charset+ for a Ruby {Encoding}.
|
95
|
+
#
|
96
|
+
# @param encoding [String, Encoding] the encoding to find a +Charset+ for
|
97
|
+
def self.ruby_encoding_to_charset(encoding)
|
98
|
+
ruby_encoding(encoding).to_java.getEncoding.getCharset
|
99
|
+
end
|
100
|
+
|
101
|
+
# Given a String with an {Encoding} name or an {Encoding} instance, return
|
102
|
+
# an {Encoding} instance
|
103
|
+
#
|
104
|
+
# @param encoding [String, Encoding] the encoding or encoding name
|
105
|
+
# @return [Encoding] the encoding
|
106
|
+
def self.ruby_encoding(encoding)
|
107
|
+
encoding.nil? ? nil : ::Encoding.find(encoding)
|
108
|
+
end
|
45
109
|
end
|
46
110
|
|
111
|
+
# Lambda that checks if the given path exists and is a file
|
47
112
|
PathChecker = ->(path) {
|
48
113
|
File.file?(path)
|
49
114
|
}
|
115
|
+
# Lambda that checks if the given string is a valid URI
|
50
116
|
URIChecker = ->(uri) {
|
51
117
|
begin
|
52
118
|
URI.parse(uri)
|
@@ -56,75 +122,144 @@ module Saxon
|
|
56
122
|
end
|
57
123
|
}
|
58
124
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
125
|
+
class << self
|
126
|
+
# Generate a Saxon::Source given an IO-like
|
127
|
+
#
|
128
|
+
# @param [IO, File] io The IO-like containing XML to be parsed
|
129
|
+
# @param [Hash] opts
|
130
|
+
# @option opts [String] :base_uri The Base URI for the Source - an
|
131
|
+
# absolute URI or relative path that will be used to resolve relative
|
132
|
+
# URLs in the XML. Setting this will override any path or URI derived
|
133
|
+
# from the IO-like.
|
134
|
+
# @option opts [String, Encoding] :encoding The encoding of the source.
|
135
|
+
# Note that specifying this will force the parser to ignore the charset
|
136
|
+
# if it's set in the XML declaration of the source. Only really useful
|
137
|
+
# if there's a discrepancy between the source's declared and actual
|
138
|
+
# encoding. Defaults to the <?xml charset="..."?> declaration in the
|
139
|
+
# source.
|
140
|
+
# @return [Saxon::Source] the Saxon::Source wrapping the input
|
141
|
+
def from_io(io, opts = {})
|
142
|
+
base_uri = opts.fetch(:base_uri) { Helpers.base_uri(io) }
|
143
|
+
encoding = opts.fetch(:encoding, nil)
|
144
|
+
inputstream = Helpers.inputstream(io, encoding)
|
145
|
+
from_inputstream_or_reader(inputstream, base_uri)
|
146
|
+
end
|
74
147
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
148
|
+
# Generate a Saxon::Source given a path to a file
|
149
|
+
#
|
150
|
+
# @param [String, Pathname] path The path to the XML file to be parsed
|
151
|
+
# @param [Hash] opts
|
152
|
+
# @option opts [String] :base_uri The Base URI for the Source - an
|
153
|
+
# absolute URI or relative path that will be used to resolve relative
|
154
|
+
# URLs in the XML. Setting this will override the file path.
|
155
|
+
# @option opts [String, Encoding] :encoding The encoding of the source.
|
156
|
+
# Note that specifying this will force the parser to ignore the charset
|
157
|
+
# if it's set in the XML declaration of the source. Only really useful
|
158
|
+
# if there's a discrepancy between the source's declared and actual
|
159
|
+
# encoding. Defaults to the <?xml charset="..."?> declaration in the
|
160
|
+
# source.
|
161
|
+
# @return [Saxon::Source] the Saxon::Source wrapping the input
|
162
|
+
def from_path(path, opts = {})
|
163
|
+
encoding = opts.fetch(:encoding, nil)
|
164
|
+
return from_inputstream_or_reader(Helpers.file(path), opts[:base_uri]) if encoding.nil?
|
165
|
+
reader = Helpers.file_reader(path, encoding)
|
166
|
+
base_uri = opts.fetch(:base_uri) { File.expand_path(path) }
|
167
|
+
from_inputstream_or_reader(reader, base_uri)
|
168
|
+
end
|
88
169
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
170
|
+
# Generate a Saxon::Source given a URI
|
171
|
+
#
|
172
|
+
# @param [String, URI] uri The URI to the XML file to be parsed
|
173
|
+
# @param [Hash] opts
|
174
|
+
# @option opts [String] :base_uri The Base URI for the Source - an
|
175
|
+
# absolute URI or relative path that will be used to resolve relative
|
176
|
+
# URLs in the XML. Setting this will override the given URI.
|
177
|
+
# @option opts [String, Encoding] :encoding The encoding of the source.
|
178
|
+
# Note that specifying this will force the parser to ignore the charset
|
179
|
+
# if it's set in the XML declaration of the source. Only really useful
|
180
|
+
# if there's a discrepancy between the source's declared and actual
|
181
|
+
# encoding. Defaults to the <?xml charset="..."?> declaration in the
|
182
|
+
# source.
|
183
|
+
# @return [Saxon::Source] the Saxon::Source wrapping the input
|
184
|
+
def from_uri(uri, opts = {})
|
185
|
+
encoding = opts.fetch(:encoding, nil)
|
186
|
+
return from_io(open(uri), encoding: encoding) if encoding
|
187
|
+
from_inputstream_or_reader(uri.to_s, opts[:base_uri])
|
188
|
+
end
|
102
189
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
190
|
+
# Generate a Saxon::Source given a string containing XML
|
191
|
+
#
|
192
|
+
# @param [String] string The string containing XML to be parsed
|
193
|
+
# @param [Hash] opts
|
194
|
+
# @option opts [String] :base_uri The Base URI for the Source - an
|
195
|
+
# absolute URI or relative path that will be used to resolve relative
|
196
|
+
# URLs in the XML. This will be nil unless set.
|
197
|
+
# @option opts [String, Encoding] :encoding The encoding of the source.
|
198
|
+
# Note that specifying this will force the parser to ignore the charset
|
199
|
+
# if it's set in the XML declaration of the source. Only really useful
|
200
|
+
# if there's a discrepancy between the encoding of the string and the
|
201
|
+
# encoding of the source. Defaults to the encoding of the string, unless
|
202
|
+
# that is ASCII-8BIT, in which case the parser will use the
|
203
|
+
# <?xml charset="..."?> declaration in the source to pick the encoding.
|
204
|
+
# @return [Saxon::Source] the Saxon::Source wrapping the input
|
205
|
+
def from_string(string, opts = {})
|
206
|
+
encoding = opts.fetch(:encoding) { string.encoding }
|
207
|
+
reader = Helpers.string_reader(string, encoding)
|
208
|
+
from_inputstream_or_reader(reader, opts[:base_uri])
|
209
|
+
end
|
210
|
+
|
211
|
+
# Generate a Saxon::Source from one of the several inputs allowed.
|
212
|
+
#
|
213
|
+
# If possible the character encoding of the input source will be left to
|
214
|
+
# the XML parser to discover (from the <tt><?xml charset="..."?></tt> XML
|
215
|
+
# declaration).
|
216
|
+
#
|
217
|
+
# The Base URI for the source (its absolute path, or URI) can be set by
|
218
|
+
# passing in the +:base_uri+ option. This is the same thing as an XML
|
219
|
+
# document's 'System ID' - Base URI is the term most widely used in Ruby
|
220
|
+
# libraries for this, so that's what's used here.
|
221
|
+
#
|
222
|
+
# If the source's character encoding can't be correctly discovered by the
|
223
|
+
# parser from the XML declaration (<tt><?xml version="..."
|
224
|
+
# charset="..."?></tt> at the top of the document), then it can be passed
|
225
|
+
# as the +:encoding+ option.
|
226
|
+
#
|
227
|
+
# If an existing {Source} is passed in, simply return it.
|
228
|
+
#
|
229
|
+
# @param [Saxon::Source, IO, File, String, Pathname, URI] input The XML to be parsed
|
230
|
+
# @param [Hash] opts
|
231
|
+
# @option opts [String] :base_uri The Base URI for the Source - an
|
232
|
+
# absolute URI or relative path that will be used to resolve relative
|
233
|
+
# URLs in the XML. Setting this will override any path or URI derived
|
234
|
+
# from an IO, URI, or Path.
|
235
|
+
# @option opts [String, Encoding] :encoding The encoding of the source.
|
236
|
+
# Note that specifying this will force the parser to ignore the charset
|
237
|
+
# if it's set in the XML declaration of the source. Only really useful
|
238
|
+
# if there's a discrepancy between the source's declared and actual
|
239
|
+
# encoding. Defaults to the <?xml charset="..."?> declaration in the
|
240
|
+
# source.
|
241
|
+
# @return [Saxon::Source] the Saxon::Source wrapping the input
|
242
|
+
def create(input, opts = {})
|
243
|
+
case input
|
244
|
+
when Saxon::Source
|
245
|
+
input
|
246
|
+
when IO, File, java.io.InputStream, StringIO
|
247
|
+
from_io(input, opts)
|
248
|
+
when Pathname, PathChecker
|
249
|
+
from_path(input, opts)
|
250
|
+
when URIChecker
|
251
|
+
from_uri(input, opts)
|
252
|
+
else
|
253
|
+
from_string(input, opts)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
private
|
117
258
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
when Pathname, PathChecker
|
123
|
-
from_path(io_path_uri_or_string, opts)
|
124
|
-
when URIChecker
|
125
|
-
from_uri(io_path_uri_or_string, opts)
|
126
|
-
else
|
127
|
-
from_string(io_path_uri_or_string, opts)
|
259
|
+
def from_inputstream_or_reader(inputstream_or_reader, base_uri = nil)
|
260
|
+
stream_source = Saxon::JAXP::StreamSource.new(inputstream_or_reader)
|
261
|
+
stream_source.setSystemId(base_uri) if base_uri
|
262
|
+
new(stream_source, inputstream_or_reader)
|
128
263
|
end
|
129
264
|
end
|
130
265
|
|
@@ -183,5 +318,6 @@ module Saxon
|
|
183
318
|
end
|
184
319
|
end
|
185
320
|
|
321
|
+
# Error raised when trying to consume an already-consumed, and closed, Source
|
186
322
|
class SourceClosedError < Exception; end
|
187
323
|
end
|
data/lib/saxon/version.rb
CHANGED
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'saxon/s9api'
|
2
|
+
|
3
|
+
module Saxon
|
4
|
+
module Version
|
5
|
+
# The version of the underlying Saxon library, which we need to discover at
|
6
|
+
# runtime based on what version is on the Classpath
|
7
|
+
class Library
|
8
|
+
# The loaded version of the Saxon Java library
|
9
|
+
#
|
10
|
+
# @return [Saxon::Version::Library] the version of the loaded library
|
11
|
+
def self.loaded_version
|
12
|
+
Saxon::Loader.load!
|
13
|
+
|
14
|
+
sv = Java::net.sf.saxon.Version
|
15
|
+
new(sv.getProductVersion, sv.getStructuredVersionNumber, sv.softwareEdition)
|
16
|
+
end
|
17
|
+
|
18
|
+
include Comparable
|
19
|
+
|
20
|
+
# @return [String] the version string (e.g. '9.9.1.6', '10.0')
|
21
|
+
attr_reader :version
|
22
|
+
# @return [String] the version components (e.g. <tt>[9, 9, 1, 6]</tt>, <tt>[10, 0]</tt>)
|
23
|
+
attr_reader :components
|
24
|
+
# @return [Symbol] the edition (+:he+, +:pe+, or +:ee+)
|
25
|
+
attr_reader :edition
|
26
|
+
|
27
|
+
# @param version [String] the version string
|
28
|
+
# @param components [Array<Integer>] the version components separated
|
29
|
+
# @param edition [String, Symbol] the name of the Saxon edition (e.g. +:he+, +'HE'+)
|
30
|
+
def initialize(version, components, edition)
|
31
|
+
@version = version.dup.freeze
|
32
|
+
@components = components.dup.freeze
|
33
|
+
@edition = edition.downcase.to_sym
|
34
|
+
end
|
35
|
+
|
36
|
+
# Comparison against another instance
|
37
|
+
#
|
38
|
+
# @param other [Saxon::Version::Library] the other version to compare against
|
39
|
+
# @return [Integer] -1 for less, 1 for greater, 0 for equal
|
40
|
+
def <=>(other)
|
41
|
+
return false unless other.is_a?(self.class)
|
42
|
+
|
43
|
+
n_components = [self.components.length, other.components.length].max
|
44
|
+
(0..(n_components - 1)).reduce(0, &comparator(other))
|
45
|
+
end
|
46
|
+
|
47
|
+
# Pessimistic comparison à la rubygems +~>+: do I satisfy the other
|
48
|
+
# version if considered as a pessimistic version constraint
|
49
|
+
#
|
50
|
+
# @param pessimistic_version [Saxon::Version::Library] the version to
|
51
|
+
# compare pessimistically
|
52
|
+
# @return [Boolean] do I satisfy the constraint?
|
53
|
+
def pessimistic_compare(pessimistic_version)
|
54
|
+
pessimistic_components = pessimistic_version.components
|
55
|
+
pessimistic_components = pessimistic_components + [0] if pessimistic_components.length == 1
|
56
|
+
locked = pessimistic_components[0..-2]
|
57
|
+
locked = locked.zip(components[0..locked.length])
|
58
|
+
variable = [pessimistic_components[-1], components[locked.length]]
|
59
|
+
|
60
|
+
locked_ok = locked.all? { |check, mine|
|
61
|
+
check == mine
|
62
|
+
}
|
63
|
+
|
64
|
+
return false unless locked_ok
|
65
|
+
|
66
|
+
check, mine = variable
|
67
|
+
mine >= check
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [String] the version string
|
71
|
+
def to_s
|
72
|
+
version
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def comparator(other)
|
78
|
+
->(cmp, i) {
|
79
|
+
return cmp unless cmp == 0
|
80
|
+
|
81
|
+
mine = self.components[i].nil? ? 0 : self.components[i]
|
82
|
+
theirs = other.components[i].nil? ? 0 : other.components[i]
|
83
|
+
|
84
|
+
mine <=> theirs
|
85
|
+
}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|