soap4r-ng 2.0.6 → 2.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ee42117a6f0c89fd3dbf5a3fb81a4953dcb4ab6a6a0b7b17d701fd4a1df5692
4
- data.tar.gz: 9c1cd45b938b7763bf30fd62670bf2119054129f44b2cb86f9c421e7ba8e7861
3
+ metadata.gz: 1ec08ba5accd7ec65e6304c09557a8da24d1c084f1d8da5a670cc43f170215d4
4
+ data.tar.gz: 511a26a5a90fedd8d1bca578b39bd3273f11bba64a41647e569107bdcad33461
5
5
  SHA512:
6
- metadata.gz: c967b100a580ee46c0b4825579f4c195a292f22764ecb18789c447d12572f30de45c051d4a5ad7a2dc9bab72d73520e63c5ca23877998b706bb6a8797c267aff
7
- data.tar.gz: cc8c9af693fff6f4c3e88e66cc4ed489f05e9b98e8edee3f2a7c1568f956b552be1dadb2738ded70e14a273ffff1054927f79b49997f4052fcb6872a8ad3c443
6
+ metadata.gz: ad85078c39eed227b20ca73050e2c36cc272fa037b7afea634da3ecee9214f1941ce7c7a26a377f365a1303cfd7e986124ae317ecd85e2b5cb942ec4c7d8b215
7
+ data.tar.gz: 5f13e6fadeb0b16cad896050c67e6f9455b9c1684fb7f78a3009c1ea1508e8c0fe572884040ff83f02b4bece9644e5caf2bd15ae02908d5af63632eb7d52c088
data/lib/soap/baseData.rb CHANGED
@@ -542,7 +542,7 @@ public
542
542
  end
543
543
 
544
544
  def to_s
545
- str = ''
545
+ str = String.new
546
546
  self.each do |key, data|
547
547
  str << "#{key}: #{data}\n"
548
548
  end
@@ -1080,7 +1080,11 @@ private
1080
1080
  "#{typename}[" << ',' * (rank - 1) << ']'
1081
1081
  end
1082
1082
 
1083
- TypeParseRegexp = Regexp.new('^(.+)\[([\d,]*)\]$', Regexp::NOENCODING)
1083
+ # Regexp::NOENCODING doesn't exist pre-1.9 (part of Ruby's M17N overhaul);
1084
+ # 0 (no special options) is the equivalent on 1.8.7, which has no
1085
+ # per-string encoding concept for this flag to apply to in the first place.
1086
+ TypeParseRegexp = Regexp.new('^(.+)\[([\d,]*)\]$',
1087
+ defined?(Regexp::NOENCODING) ? Regexp::NOENCODING : 0)
1084
1088
 
1085
1089
  def self.parse_type(string)
1086
1090
  TypeParseRegexp =~ string
@@ -20,7 +20,7 @@ class ASPDotNetHandler < Handler
20
20
 
21
21
  def initialize(charset = nil)
22
22
  super(charset)
23
- @textbuf = ''
23
+ @textbuf = String.new
24
24
  @decode_typemap = nil
25
25
  end
26
26
 
@@ -108,7 +108,7 @@ class ASPDotNetHandler < Handler
108
108
  end
109
109
 
110
110
  def decode_tag(ns, elename, attrs, parent)
111
- @textbuf = ''
111
+ @textbuf = String.new
112
112
  o = SOAPUnknown.new(self, elename)
113
113
  o.parent = parent
114
114
  o
@@ -128,7 +128,7 @@ class ASPDotNetHandler < Handler
128
128
  end
129
129
 
130
130
  decode_textbuf(o)
131
- @textbuf = ''
131
+ @textbuf = String.new
132
132
  end
133
133
 
134
134
  def decode_text(ns, text)
@@ -51,7 +51,7 @@ public
51
51
  end
52
52
 
53
53
  def generate(obj, io = nil)
54
- @buf = io || ''
54
+ @buf = io || String.new
55
55
  @indent = ''
56
56
  @encode_char_regexp = get_encode_char_regexp()
57
57
 
@@ -273,9 +273,9 @@ private
273
273
  ENCODE_CHAR_REGEXP[XSD::Charset.encoding] ||= begin
274
274
  if RUBY_VERSION.to_f <= 1.8
275
275
  Regexp.new("[#{EncodeMap.keys.join}]", nil, XSD::Charset.encoding)
276
- elsif RUBY_VERSION.to_f < 3.3
277
- Regexp.new("[#{EncodeMap.keys.join}]", nil, nil) # RubyJedi: compatible with Ruby 1.8.6 and above
278
276
  else
277
+ # the deprecated 3-arg form's kcode argument was already nil here
278
+ # (a no-op since Ruby 1.9), so there's nothing lost by dropping it.
279
279
  Regexp.new("[#{EncodeMap.keys.join}]")
280
280
  end
281
281
  end
@@ -12,6 +12,42 @@ FIXNUM_PRESENT = FixnumShim.name == 'Fixnum'
12
12
  BignumShim = (10**20).class
13
13
  BIGNUM_PRESENT = BignumShim.name == 'Bignum'
14
14
 
15
+ if RUBY_VERSION.to_f >= 3.4 && defined?(Warning) && Warning.respond_to?(:warn)
16
+ # Ruby 3.4+'s chilled-string deprecation notice fires every time
17
+ # addextend2soap (below) opens a string's singleton class to check for a
18
+ # prior #extend, even when it turns out not to be extended -- unavoidable
19
+ # without breaking test/soap/marshal/marshaltestlib.rb#test_extend_string's
20
+ # real, tested round-trip behavior (see the NOTE on addextend2soap).
21
+ # Installed once, permanently, rather than swapped in/out per call: this
22
+ # method can run concurrently from multiple WEBrick request threads, and a
23
+ # temporary swap-and-restore around each call would race between threads.
24
+ # Matched on both the message text AND this file's own path, so no other
25
+ # chilled-string warning -- from elsewhere in this library, a dependency
26
+ # like simplecov, or the embedding application -- is ever affected.
27
+ #
28
+ # The override itself is built via class_eval on a *string* rather than
29
+ # literal keyword-argument syntax (`category:`) in this file: this file
30
+ # must parse cleanly on every supported Ruby back to 1.8.7, and Ruby
31
+ # parses an entire file up front regardless of the RUBY_VERSION guard
32
+ # above being a runtime check -- literal keyword-arg syntax here would be
33
+ # a SyntaxError on any pre-2.0 Ruby long before that guard ever runs
34
+ # (confirmed: broke the whole file, and everything requiring it, on
35
+ # 1.8.7). A string is just inert data to the parser; it's only parsed as
36
+ # code, by class_eval, once we're already inside the version-gated branch.
37
+ class << Warning
38
+ alias_method :__soap4r_encodedregistry_original_warn, :warn
39
+ end
40
+ Warning.singleton_class.class_eval(<<-'RUBY', __FILE__, __LINE__ + 1)
41
+ def warn(message, category: nil)
42
+ if message.include?("literal string will be frozen in the future") &&
43
+ message.include?("soap/mapping/encodedregistry.rb")
44
+ return
45
+ end
46
+ __soap4r_encodedregistry_original_warn(message, category: category)
47
+ end
48
+ RUBY
49
+ end
50
+
15
51
  require 'soap/baseData'
16
52
  require 'soap/mapping/mapping'
17
53
  require 'soap/mapping/typeMap'
@@ -421,6 +457,14 @@ private
421
457
  return if [Symbol, Integer, Float].any?{ |c| obj.is_a?(c) }
422
458
  return if FIXNUM_PRESENT && obj.is_a?(FixnumShim)
423
459
  return if BIGNUM_PRESENT && obj.is_a?(BignumShim)
460
+ # NOTE: test/soap/marshal/marshaltestlib.rb#test_extend_string
461
+ # deliberately extends a String value with a module and expects that
462
+ # extension to round-trip through SOAP marshal -- so plain (non-frozen)
463
+ # strings can't be skipped outright here, even though opening a
464
+ # singleton class on one (below) trips Ruby 3.4+'s chilled-string
465
+ # warning for any ordinary string literal that happens to pass through
466
+ # unextended. Not cleanly fixable without breaking that real behavior;
467
+ # left as a known, harmless, forward-looking warning.
424
468
  return if obj.is_a?(String) && obj.frozen?
425
469
  list = (class << obj; self; end).ancestors - obj.class.ancestors
426
470
  list = list.reject{|c| c.class == Class } ## As of Ruby 2.1 Singleton Classes are now included in the ancestry. Need to filter those out here.
@@ -357,10 +357,12 @@ private
357
357
  # much memory for each singleton Object. just instance_eval instead of it.
358
358
  def define_xmlattr_accessor(obj, qname)
359
359
  # untaint depends GenSupport.safemethodname
360
- name = Mapping.safemethodname('xmlattr_' + qname.name).untaint
360
+ name = Mapping.safemethodname('xmlattr_' + qname.name)
361
+ name.untaint if RUBY_VERSION < '2.7'
361
362
  unless obj.respond_to?(name)
362
363
  # untaint depends QName#dump
363
- qnamedump = qname.dump.untaint
364
+ qnamedump = qname.dump
365
+ qnamedump.untaint if RUBY_VERSION < '2.7'
364
366
  obj.instance_eval <<-EOS
365
367
  def #{name}
366
368
  @__xmlattr[#{qnamedump}]
@@ -108,7 +108,7 @@ module Mapping
108
108
  e.set_backtrace(nil)
109
109
  raise e # ruby sets current caller as local backtrace of e => e2.
110
110
  rescue Exception => e
111
- e.set_backtrace(remote_backtrace + e.backtrace[1..-1])
111
+ e.set_backtrace((remote_backtrace || []) + ((e.backtrace || [])[1..-1] || []))
112
112
  raise
113
113
  end
114
114
  else
@@ -167,7 +167,7 @@ module Mapping
167
167
  #
168
168
  def self.name2elename(name)
169
169
  name.to_s.gsub(/([^a-zA-Z0-9:_\-]+)/n) {
170
- '.' << $1.unpack('H2' * $1.size).join('.')
170
+ '.' + $1.unpack('H2' * $1.size).join('.')
171
171
  }.gsub(/::/n, '..')
172
172
  end
173
173
 
@@ -333,7 +333,8 @@ module Mapping
333
333
  else
334
334
  values.each do |attr_name, value|
335
335
  # untaint depends GenSupport.safevarname
336
- name = Mapping.safevarname(attr_name).untaint
336
+ name = Mapping.safevarname(attr_name)
337
+ name.untaint if RUBY_VERSION < '2.7'
337
338
  setter = name + "="
338
339
  if obj.respond_to?(setter)
339
340
  obj.__send__(setter, value)
@@ -107,9 +107,11 @@ private
107
107
  # much memory for each singleton Object. just instance_eval instead of it.
108
108
  def __define_attr_accessor(qname)
109
109
  # untaint depends GenSupport.safemethodname
110
- name = Mapping.safemethodname(qname.name).untaint
110
+ name = Mapping.safemethodname(qname.name)
111
+ name.untaint if RUBY_VERSION < '2.7'
111
112
  # untaint depends on QName#dump
112
- qnamedump = qname.dump.untaint
113
+ qnamedump = qname.dump
114
+ qnamedump.untaint if RUBY_VERSION < '2.7'
113
115
  singleton = false
114
116
  unless self.respond_to?(name)
115
117
  singleton = true
@@ -8,7 +8,12 @@
8
8
 
9
9
  old_verbose, $VERBOSE = $VERBOSE, nil # silence warnings
10
10
  DATA_PRESENT = defined?(Data)
11
- DataShim = Kernel.const_get('Data') if DATA_PRESENT
11
+ # DataShim must always be a defined class, since it's referenced unconditionally
12
+ # in a `case/when` below. Ruby's old C-extension Data class was removed in 3.1,
13
+ # then Ruby 3.2 introduced an unrelated Data.define -- so DATA_PRESENT is false
14
+ # only on the 3.1.x line. Fall back to an anonymous class nothing will ever be
15
+ # an instance of, so the `when` comparison is always valid but never matches.
16
+ DataShim = DATA_PRESENT ? Kernel.const_get('Data') : Class.new
12
17
  $VERBOSE = old_verbose
13
18
 
14
19
  module SOAP
@@ -225,7 +225,7 @@ class MIMEMessage
225
225
  end
226
226
 
227
227
  def content_str
228
- str = ''
228
+ str = String.new
229
229
  @parts.each do |prt|
230
230
  str << "--" + boundary + "\r\n"
231
231
  str << prt.to_s + "\r\n"
@@ -42,7 +42,7 @@ class HTTPServer < Logger::Application
42
42
  @soaplet = ::SOAP::RPC::SOAPlet.new(@router)
43
43
  on_init
44
44
 
45
- @server = WEBrick::HTTPServer.new(@webrick_config)
45
+ @server = new_webrick_server(@webrick_config)
46
46
  @server.mount('/soaprouter', @soaplet)
47
47
  if wsdldir = config[:WSDLDocumentDirectory]
48
48
  @server.mount('/wsdl', WEBrick::HTTPServlet::FileHandler, wsdldir)
@@ -137,6 +137,35 @@ class HTTPServer < Logger::Application
137
137
 
138
138
  private
139
139
 
140
+ # A short retry-on-EADDRINUSE, matching test/testutil.rb's existing
141
+ # TestUtil.webrick_server helper, applied here so it covers every caller
142
+ # (not just tests that happen to go through that helper). Note: the mass
143
+ # EADDRINUSE cascade seen across the test suite (most test files share a
144
+ # single fixed port) turned out to be caused by a genuinely orphaned
145
+ # server -- test/soap/header/test_authheader_cgi.rb's teardown could
146
+ # raise before reaching teardown_server, permanently leaking that test's
147
+ # listener for the rest of the run -- not by transient TIME_WAIT. This
148
+ # retry is still worth keeping as a real defensive measure, just don't
149
+ # rely on it alone to mask a genuine leak elsewhere.
150
+ def new_webrick_server(config)
151
+ try = 0
152
+ begin
153
+ WEBrick::HTTPServer.new(config)
154
+ rescue Errno::EADDRINUSE => e
155
+ sleep 1
156
+ # See test/testutil.rb's webrick_server for the full history and why
157
+ # this was pulled back down from 120 to 20 -- the real leak (Thread#kill
158
+ # racing WEBrick's own async shutdown cleanup in test teardown) is
159
+ # fixed now, so this only needs to cover transient scheduling delay,
160
+ # not a real leak. A large budget here actively hurts: sslsvr.rb (test
161
+ # SSL support script) calls into this same path, and its parent process
162
+ # blocks on a timeout-less read waiting for it to report a PID --
163
+ # confirmed a stuck retry here manifests as a multi-minute *silent
164
+ # hang* in CI (run 28892185757), not just a slow test.
165
+ ((try += 1) < 20) ? retry : raise(e)
166
+ end
167
+ end
168
+
140
169
  def attrproxy
141
170
  @router
142
171
  end
data/lib/soap/version.rb CHANGED
@@ -2,8 +2,8 @@
2
2
  module SOAP
3
3
  module VERSION #:nodoc:
4
4
  MAJOR = 2
5
- MINOR = 0
6
- TINY = 6
5
+ MINOR = 1
6
+ TINY = 0
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
 
9
9
  FORK = "SOAP4R-NG"
data/lib/wsdl/parser.rb CHANGED
@@ -62,7 +62,7 @@ public
62
62
  def parse(string_or_readable)
63
63
  @parsestack = []
64
64
  @lastnode = nil
65
- @textbuf = ''
65
+ @textbuf = String.new
66
66
  @parser.do_parse(string_or_readable)
67
67
  @lastnode
68
68
  end
@@ -43,7 +43,7 @@ class ClassDefCreator
43
43
  end
44
44
 
45
45
  def dump(type = nil)
46
- result = "require 'xsd/qname'\n"
46
+ result = "require 'xsd/qname'\n".dup
47
47
  # cannot use @modulepath because of multiple classes
48
48
  if @modulepath
49
49
  result << "\n"
@@ -130,7 +130,7 @@ private
130
130
  def dump_inout_type(param, element_definitions)
131
131
  if param
132
132
  message = param.find_message
133
- params = ""
133
+ params = String.new
134
134
  message.parts.each do |part|
135
135
  name = safevarname(part.name)
136
136
  if part.type
@@ -158,7 +158,7 @@ private
158
158
 
159
159
  def dump_inputparam(input)
160
160
  message = input.find_message
161
- params = ""
161
+ params = String.new
162
162
  message.parts.each do |part|
163
163
  params << ", " unless params.empty?
164
164
  params << safevarname(part.name)
@@ -31,7 +31,7 @@ class ClientSkeltonCreator
31
31
  unless services
32
32
  raise RuntimeError.new("service not defined: #{service_name}")
33
33
  end
34
- result = ""
34
+ result = String.new
35
35
  if @modulepath
36
36
  result << "\n"
37
37
  modulepath = @modulepath.respond_to?(:lines) ? @modulepath.lines : @modulepath # RubyJedi: compatible with Ruby 1.8.6 and above
@@ -57,7 +57,7 @@ private
57
57
  assigned_method = collect_assigned_method(@definitions, porttype.name, @modulepath)
58
58
  drv_name = mapped_class_basename(porttype.name, @modulepath)
59
59
 
60
- result = ""
60
+ result = String.new
61
61
  result << <<__EOD__
62
62
  endpoint_url = ARGV.shift
63
63
  obj = #{ drv_name }.new(endpoint_url)
@@ -32,7 +32,7 @@ class DriverCreator
32
32
  end
33
33
 
34
34
  def dump(porttype = nil)
35
- result = "require 'soap/rpc/driver'\n\n"
35
+ result = String.new("require 'soap/rpc/driver'\n\n")
36
36
  if @modulepath
37
37
  modulepath = @modulepath.respond_to?(:lines) ? @modulepath.lines : @modulepath # RubyJedi: compatible with Ruby 1.8.6 and above
38
38
  modulepath.each do |name|
@@ -34,7 +34,7 @@ class EncodedMappingRegistryCreator
34
34
 
35
35
  def dump(varname)
36
36
  @varname = varname
37
- result = ''
37
+ result = String.new
38
38
  str = dump_complextype
39
39
  unless str.empty?
40
40
  result << "\n" unless result.empty?
@@ -36,7 +36,7 @@ class LiteralMappingRegistryCreator
36
36
 
37
37
  def dump(varname)
38
38
  @varname = varname
39
- result = ''
39
+ result = String.new
40
40
  str = dump_complextype
41
41
  unless str.empty?
42
42
  result << "\n" unless result.empty?
@@ -37,7 +37,7 @@ class MethodDefCreator
37
37
  end
38
38
 
39
39
  def dump(name)
40
- methoddef = ""
40
+ methoddef = String.new
41
41
  porttype = @definitions.porttype(name)
42
42
  binding = porttype.find_binding
43
43
  if binding
@@ -94,7 +94,7 @@ private
94
94
  if paramstr.empty?
95
95
  paramstr = '[]'
96
96
  else
97
- paramstr = "[ " << paramstr.split(/\r?\n/).join("\n ") << " ]"
97
+ paramstr = "[ " + paramstr.split(/\r?\n/).join("\n ") + " ]"
98
98
  end
99
99
  definitions = <<__EOD__
100
100
  #{ndq(mdef.soapaction)},
@@ -29,7 +29,7 @@ class ServantSkeltonCreator
29
29
  end
30
30
 
31
31
  def dump(porttype = nil)
32
- result = ""
32
+ result = String.new
33
33
  if @modulepath
34
34
  result << "\n"
35
35
  modulepath = @modulepath.respond_to?(:lines) ? @modulepath.lines : @modulepath # RubyJedi: compatible with Ruby 1.8.6 and above
@@ -60,7 +60,7 @@ public
60
60
  def parse(string_or_readable)
61
61
  @parsestack = []
62
62
  @lastnode = nil
63
- @textbuf = ''
63
+ @textbuf = String.new
64
64
  @parser.do_parse(string_or_readable)
65
65
  @lastnode
66
66
  end
data/lib/xsd/charset.rb CHANGED
@@ -128,20 +128,27 @@ public
128
128
  end
129
129
  end
130
130
 
131
+ # Regexp::NOENCODING doesn't exist pre-1.9 (part of Ruby's M17N overhaul);
132
+ # these regexes match raw byte patterns regardless of string encoding, so
133
+ # on 1.8.7 -- which has no per-string encoding concept at all -- byte
134
+ # matching is just the default behavior and 0 (no special options) is the
135
+ # equivalent.
136
+ NOENCODING_OPT = defined?(Regexp::NOENCODING) ? Regexp::NOENCODING : 0
137
+
131
138
  # us_ascii = '[\x00-\x7F]'
132
139
  us_ascii = '[\x9\xa\xd\x20-\x7F]' # XML 1.0 restricted.
133
- USASCIIRegexp = Regexp.new("\\A#{us_ascii}*\\z", Regexp::NOENCODING)
140
+ USASCIIRegexp = Regexp.new("\\A#{us_ascii}*\\z", NOENCODING_OPT)
134
141
 
135
142
  twobytes_euc = '(?:[\x8E\xA1-\xFE][\xA1-\xFE])'
136
143
  threebytes_euc = '(?:\x8F[\xA1-\xFE][\xA1-\xFE])'
137
144
  character_euc = "(?:#{us_ascii}|#{twobytes_euc}|#{threebytes_euc})"
138
- EUCRegexp = Regexp.new("\\A#{character_euc}*\\z", Regexp::NOENCODING)
145
+ EUCRegexp = Regexp.new("\\A#{character_euc}*\\z", NOENCODING_OPT)
139
146
 
140
147
  # onebyte_sjis = '[\x00-\x7F\xA1-\xDF]'
141
148
  onebyte_sjis = '[\x9\xa\xd\x20-\x7F\xA1-\xDF]' # XML 1.0 restricted.
142
149
  twobytes_sjis = '(?:[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'
143
150
  character_sjis = "(?:#{onebyte_sjis}|#{twobytes_sjis})"
144
- SJISRegexp = Regexp.new("\\A#{character_sjis}*\\z", Regexp::NOENCODING)
151
+ SJISRegexp = Regexp.new("\\A#{character_sjis}*\\z", NOENCODING_OPT)
145
152
 
146
153
  # 0xxxxxxx
147
154
  # 110yyyyy 10xxxxxx
@@ -152,7 +159,7 @@ public
152
159
  fourbytes_utf8 = '(?:[\xF0-\xF7][\x80-\xBF][\x80-\xBF][\x80-\xBF])'
153
160
  character_utf8 =
154
161
  "(?:#{us_ascii}|#{twobytes_utf8}|#{threebytes_utf8}|#{fourbytes_utf8})"
155
- UTF8Regexp = Regexp.new("\\A#{character_utf8}*\\z", Regexp::NOENCODING)
162
+ UTF8Regexp = Regexp.new("\\A#{character_utf8}*\\z", NOENCODING_OPT)
156
163
 
157
164
  def Charset.is_us_ascii(str)
158
165
  USASCIIRegexp =~ str
@@ -42,7 +42,7 @@ class ClassDef < ModuleDef
42
42
  end
43
43
 
44
44
  def dump
45
- buf = ""
45
+ buf = String.new
46
46
  unless @requirepath.empty?
47
47
  buf << dump_requirepath
48
48
  end
@@ -110,7 +110,7 @@ private
110
110
  end
111
111
 
112
112
  def dump_attributes
113
- str = ""
113
+ str = String.new
114
114
  @attrdef.each do |attrname, writable, varname|
115
115
  varname ||= attrname
116
116
  if attrname == varname
@@ -39,7 +39,7 @@ class MethodDef
39
39
  end
40
40
 
41
41
  def dump
42
- buf = ""
42
+ buf = String.new
43
43
  buf << dump_comment if @comment
44
44
  buf << dump_method_def
45
45
  buf << dump_definition if @definition and !@definition.empty?
@@ -67,7 +67,7 @@ class ModuleDef
67
67
  end
68
68
 
69
69
  def dump
70
- buf = ""
70
+ buf = String.new
71
71
  unless @requirepath.empty?
72
72
  buf << dump_requirepath
73
73
  end
@@ -141,7 +141,7 @@ private
141
141
  @methoddef.each do |visibility, method|
142
142
  (methods[visibility] ||= []) << method
143
143
  end
144
- str = ""
144
+ str = String.new
145
145
  [:public, :protected, :private].each do |visibility|
146
146
  if methods[visibility]
147
147
  str << "\n" unless str.empty?
data/lib/xsd/datatypes.rb CHANGED
@@ -256,7 +256,7 @@ private
256
256
  def screen_data(d)
257
257
  if d.is_a?(String)
258
258
  # Integer("00012") => 10 in Ruby.
259
- d.sub!(/^([+\-]?)0*(?=\d)/, "\\1")
259
+ d = d.sub(/^([+\-]?)0*(?=\d)/, "\\1")
260
260
  end
261
261
  screen_data_str(d)
262
262
  end
@@ -480,14 +480,14 @@ private
480
480
  end
481
481
 
482
482
  def _to_s
483
- str = ''
483
+ str = String.new
484
484
  str << @sign if @sign
485
485
  str << 'P'
486
- l = ''
486
+ l = String.new
487
487
  l << "#{ @year }Y" if @year.nonzero?
488
488
  l << "#{ @month }M" if @month.nonzero?
489
489
  l << "#{ @day }D" if @day.nonzero?
490
- r = ''
490
+ r = String.new
491
491
  r << "#{ @hour }H" if @hour.nonzero?
492
492
  r << "#{ @min }M" if @min.nonzero?
493
493
  r << "#{ @sec }S" if @sec.nonzero?
@@ -568,7 +568,7 @@ module XSDDateTimeImpl
568
568
  if diffmin.zero?
569
569
  'Z'
570
570
  else
571
- ((diffmin < 0) ? '-' : '+') << format('%02d:%02d',
571
+ ((diffmin < 0) ? '-' : '+') + format('%02d:%02d',
572
572
  (diffmin.abs / 60.0).to_i, (diffmin.abs % 60.0).to_i)
573
573
  end
574
574
  end
@@ -629,8 +629,18 @@ private
629
629
  zonestr = $8
630
630
  data = DateTime.civil(year, mon, mday, hour, min, sec, tz2of(zonestr))
631
631
  if secfrac
632
- diffday = secfrac.to_i.to_r / (10 ** secfrac.size) / DayInSec
633
- data += diffday
632
+ if RUBY_VERSION.to_f >= 1.9
633
+ diffday = secfrac.to_i.to_r / (10 ** secfrac.size) / DayInSec
634
+ data += diffday
635
+ else
636
+ # DateTime#+ produces wildly wrong results for certain Rational
637
+ # values on Ruby 1.8.7's date library (confirmed directly: e.g.
638
+ # adding Rational(1, 86400000) sends the date to 4763 BC). Baking
639
+ # the fraction into DateTime.civil's own seconds argument instead
640
+ # of adding it afterwards avoids the buggy code path entirely.
641
+ fracval = secfrac.to_i.to_r / (10 ** secfrac.size)
642
+ data = DateTime.civil(year, mon, mday, hour, min, sec + fracval, tz2of(zonestr))
643
+ end
634
644
  # FYI: new! and jd_to_rjd are not necessary to use if you don't have
635
645
  # exceptional reason.
636
646
  end
@@ -683,8 +693,18 @@ private
683
693
  zonestr = $5
684
694
  data = DateTime.civil(1, 1, 1, hour, min, sec, tz2of(zonestr))
685
695
  if secfrac
686
- diffday = secfrac.to_i.to_r / (10 ** secfrac.size) / DayInSec
687
- data += diffday
696
+ if RUBY_VERSION.to_f >= 1.9
697
+ diffday = secfrac.to_i.to_r / (10 ** secfrac.size) / DayInSec
698
+ data += diffday
699
+ else
700
+ # DateTime#+ produces wildly wrong results for certain Rational
701
+ # values on Ruby 1.8.7's date library (confirmed directly: e.g.
702
+ # adding Rational(1, 86400000) sends the date to 4763 BC). Baking
703
+ # the fraction into DateTime.civil's own seconds argument instead
704
+ # of adding it afterwards avoids the buggy code path entirely.
705
+ fracval = secfrac.to_i.to_r / (10 ** secfrac.size)
706
+ data = DateTime.civil(1, 1, 1, hour, min, sec + fracval, tz2of(zonestr))
707
+ end
688
708
  end
689
709
  [data, secfrac]
690
710
  end
data/lib/xsd/mapping.rb CHANGED
@@ -20,12 +20,12 @@ module XSD
20
20
  module Mapping
21
21
  MappingRegistry = SOAP::Mapping::LiteralRegistry.new
22
22
 
23
- def self.obj2xml(obj, elename = nil, io = nil)
24
- Mapper.new(MappingRegistry).obj2xml(obj, elename, io)
23
+ def self.obj2xml(obj, elename = nil, io = nil, options = {})
24
+ Mapper.new(MappingRegistry).obj2xml(obj, elename, io, options)
25
25
  end
26
26
 
27
- def self.xml2obj(stream, klass = nil)
28
- Mapper.new(MappingRegistry).xml2obj(stream, klass)
27
+ def self.xml2obj(stream, klass = nil, options = {})
28
+ Mapper.new(MappingRegistry).xml2obj(stream, klass, options)
29
29
  end
30
30
 
31
31
  class Mapper
@@ -39,8 +39,8 @@ module Mapping
39
39
  @registry = registry
40
40
  end
41
41
 
42
- def obj2xml(obj, elename = nil, io = nil)
43
- opt = MAPPING_OPT.dup
42
+ def obj2xml(obj, elename = nil, io = nil, options = {})
43
+ opt = MAPPING_OPT.dup.merge(options)
44
44
  unless elename
45
45
  if definition = @registry.elename_schema_definition_from_class(obj.class)
46
46
  elename = definition.elename
@@ -57,8 +57,9 @@ module Mapping
57
57
  generator.generate(soap, io)
58
58
  end
59
59
 
60
- def xml2obj(stream, klass = nil)
61
- parser = SOAP::Parser.new(MAPPING_OPT)
60
+ def xml2obj(stream, klass = nil, options = {})
61
+ opt = MAPPING_OPT.dup.merge(options)
62
+ parser = SOAP::Parser.new(opt)
62
63
  soap = parser.parse(stream)
63
64
  SOAP::Mapping.soap2obj(soap, @registry, klass)
64
65
  end
data/lib/xsd/qname.rb CHANGED
@@ -33,6 +33,7 @@ class QName
33
33
  end
34
34
 
35
35
  def match(rhs)
36
+ return false unless rhs.is_a?(XSD::QName)
36
37
  if rhs.namespace and (rhs.namespace != @namespace)
37
38
  return false
38
39
  end
@@ -43,7 +44,7 @@ class QName
43
44
  end
44
45
 
45
46
  def ==(rhs)
46
- !rhs.nil? and @namespace == rhs.namespace and @name == rhs.name
47
+ rhs.is_a?(XSD::QName) and @namespace == rhs.namespace and @name == rhs.name
47
48
  end
48
49
 
49
50
  def ===(rhs)
@@ -6,15 +6,6 @@
6
6
  # redistribute it and/or modify it under the same terms of Ruby's license;
7
7
  # either the dual license version in 2003, or any later version.
8
8
 
9
- ### WIP, 2015-June-13:
10
- ###
11
- ### LibXML drops namespaces on Elements *AND* Attributes, which makes it impossible
12
- ### to correctly associate Namespaces on Namespace-Declared Element Attributes when
13
- ### more than one namespace exists.
14
- ###
15
- ### This issue is evident when you run test/soap/test_cookie.rb
16
- ###
17
-
18
9
  require 'libxml'
19
10
 
20
11
  module XSD
@@ -22,113 +13,69 @@ module XMLParser
22
13
 
23
14
 
24
15
  class LibXMLParser < XSD::XMLParser::Parser
25
- include ::LibXML::XML::SaxParser::Callbacks
26
-
16
+ # Parses via XML::Reader rather than the SaxParser callbacks used before.
17
+ # libxml-ruby's SAX2 callback (on_start_element_ns) never surfaces an
18
+ # attribute's own namespace prefix to Ruby: the C extension
19
+ # (ruby_xml_sax2_handler.c's start_element_ns_callback) only reads an
20
+ # attribute's local name and value, discarding the prefix/URI slots that
21
+ # libxml2 itself provides per attribute. That made it impossible to
22
+ # recognize namespace-qualified attributes such as xsi:type, xsi:nil, and
23
+ # xml:lang, which SOAP4R's demarshaller depends on to pick the right Ruby
24
+ # type -- values silently fell back to an untyped SOAP::Mapping::Object,
25
+ # or stayed raw strings instead of being cast to Integer/nil/etc. This gap
26
+ # is still present as of libxml-ruby 6.0.0 (2026); it isn't a matter of
27
+ # being on an old release.
28
+ #
29
+ # XML::Reader's per-attribute #name *does* return the full "prefix:local"
30
+ # form (confirmed against libxml-ruby 2.8.0, the version pinned for Ruby
31
+ # 1.9.3, through the current 3.x/6.x releases) -- matching exactly what
32
+ # REXML's tag_start and Ox's attr callbacks already hand back, so this
33
+ # mirrors their convention rather than trying to resolve namespace URIs
34
+ # itself.
27
35
  def do_parse(string_or_readable)
28
- $stderr.puts "XSD::XMLParser::LibXMLParser.do_parse" if $DEBUG
29
- # string = string_or_readable.respond_to?(:read) ? string_or_readable.read : string_or_readable
30
-
36
+ $stderr.puts "XSD::XMLParser::LibXMLParser.do_parse" if $DEBUG
31
37
  @charset = 'utf-8'
32
- string = StringIO.new(string_or_readable)
33
- parser = LibXML::XML::SaxParser.io(string)
34
- parser.callbacks = self
35
- parser.parse
36
- end
37
-
38
- ENTITY_REF_MAP = {
39
- 'lt' => '<',
40
- 'gt' => '>',
41
- 'amp' => '&',
42
- 'quot' => '"',
43
- 'apos' => '\''
44
- }
45
-
46
- #def on_internal_subset(name, external_id, system_id)
47
- # nil
48
- #end
49
-
50
- #def on_is_standalone()
51
- # nil
52
- #end
53
-
54
- #def on_has_internal_subset()
55
- # nil
56
- #end
57
-
58
- #def on_has_external_subset()
59
- # nil
60
- #end
61
-
62
- #def on_start_document()
63
- # nil
64
- #end
65
-
66
- #def on_end_document()
67
- # nil
68
- #end
69
-
70
- def on_start_element_ns (name, attr_hash, prefix, uri, namespaces)
71
- prefixed_ns = attr_hash.merge(Hash[namespaces.map{|k,v| ["xmlns:#{k}",v]}])
72
- if prefix.nil?
73
- start_element(name, prefixed_ns)
74
- else
75
- start_element("#{prefix}:#{name}", prefixed_ns)
38
+ string = string_or_readable.respond_to?(:read) ? string_or_readable.read : string_or_readable
39
+ reader = ::LibXML::XML::Reader.string(string)
40
+ while reader.read
41
+ case reader.node_type
42
+ when ::LibXML::XML::Reader::TYPE_ELEMENT
43
+ name = reader.name
44
+ attrs = read_attributes(reader)
45
+ empty = reader.empty_element?
46
+ start_element(name, attrs)
47
+ end_element(name) if empty
48
+ when ::LibXML::XML::Reader::TYPE_END_ELEMENT
49
+ end_element(reader.name)
50
+ when ::LibXML::XML::Reader::TYPE_TEXT,
51
+ ::LibXML::XML::Reader::TYPE_CDATA,
52
+ ::LibXML::XML::Reader::TYPE_SIGNIFICANT_WHITESPACE
53
+ characters(reader.value)
54
+ end
76
55
  end
56
+ rescue ::LibXML::XML::Error => e
57
+ raise ParseError.new(e.message)
77
58
  end
78
59
 
79
- def on_end_element_ns (name, prefix, uri)
80
- if prefix.nil?
81
- end_element(name)
82
- else
83
- end_element("#{prefix}:#{name}")
84
- end
85
- end
86
-
87
- def on_start_element (name, attr_hash)
88
- # start_element(name, attr_hash)
89
- end
90
-
91
- def on_end_element(name)
92
- # end_element(name)
93
- end
94
-
95
- def on_reference(name)
96
- characters(ENTITY_REF_MAP[name])
97
- end
98
-
99
- def on_characters(chars)
100
- characters(chars)
101
- end
102
-
103
- #def on_processing_instruction(target, data)
104
- # nil
105
- #end
106
-
107
- #def on_comment(msg)
108
- # nil
109
- #end
110
-
111
- def on_parser_warning(msg)
112
- warn(msg)
113
- end
114
-
115
- def on_parser_error(msg)
116
- raise ParseError.new(msg)
117
- end
118
-
119
- def on_parser_fatal_error(msg)
120
- raise ParseError.new(msg)
121
- end
122
-
123
- def on_cdata_block(cdata)
124
- characters(cdata)
125
- end
60
+ add_factory(self)
126
61
 
127
- def on_external_subset(name, external_id, system_id)
128
- nil
62
+ private
63
+
64
+ # Attribute names come back in literal "prefix:local" form already (see
65
+ # do_parse comment above), including xmlns:* declarations -- which are
66
+ # themselves just attributes as far as the reader is concerned, so no
67
+ # separate namespace-merging step is needed.
68
+ def read_attributes(reader)
69
+ attrs = {}
70
+ return attrs unless reader.has_attributes?
71
+ if reader.move_to_first_attribute == 1
72
+ begin
73
+ attrs[reader.name] = reader.value
74
+ end while reader.move_to_next_attribute == 1
75
+ reader.move_to_element
76
+ end
77
+ attrs
129
78
  end
130
-
131
- add_factory(self)
132
79
  end
133
80
 
134
81
 
metadata CHANGED
@@ -1,16 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: soap4r-ng
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.6
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Laurence A. Lee, Hiroshi NAKAMURA
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-08-03 00:00:00.000000000 Z
12
- dependencies: []
13
- description: Soap4R NextGen (as maintained by RubyJedi) for Ruby 1.8 thru 2.1 and
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: httpclient
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: logger-application
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ description: Soap4R NextGen (as maintained by RubyJedi) for Ruby 1.8.7 thru 4.0 and
14
41
  beyond
15
42
  email: rubyjedi@gmail.com, nahi@ruby-lang.org
16
43
  executables:
@@ -185,7 +212,6 @@ homepage: http://rubyjedi.github.io/soap4r/
185
212
  licenses:
186
213
  - Ruby
187
214
  metadata: {}
188
- post_install_message:
189
215
  rdoc_options: []
190
216
  require_paths:
191
217
  - lib
@@ -201,9 +227,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
201
227
  version: '0'
202
228
  requirements:
203
229
  - none
204
- rubygems_version: 3.5.11
205
- signing_key:
230
+ rubygems_version: 3.6.9
206
231
  specification_version: 4
207
- summary: Soap4R-ng - Soap4R (as maintained by RubyJedi) for Ruby 1.8 thru 2.1 and
232
+ summary: Soap4R-ng - Soap4R (as maintained by RubyJedi) for Ruby 1.8.7 thru 4.0 and
208
233
  beyond
209
234
  test_files: []