diff --git a/iseq.c b/iseq.c index 93e58db2e65287..f2db484f59f03e 100644 --- a/iseq.c +++ b/iseq.c @@ -3002,6 +3002,10 @@ rb_iseq_disasm_recursive(const rb_iseq_t *iseq, VALUE indent) n += rb_iseq_disasm_insn(str, code, n, iseq, child); } + if (body->mandatory_only_iseq) { + rb_ary_push(child, (VALUE)body->mandatory_only_iseq); + } + for (l = 0; l < RARRAY_LEN(child); l++) { VALUE isv = rb_ary_entry(child, l); if (done_iseq && st_is_member(done_iseq, (st_data_t)isv)) continue; diff --git a/lib/time.rb b/lib/time.rb index e6aab3fa5d444b..1c66088d33ac21 100644 --- a/lib/time.rb +++ b/lib/time.rb @@ -369,6 +369,9 @@ def make_time(date, year, yday, mon, day, hour, min, sec, sec_fraction, zone, no # If the extracted time zone abbreviation does not match any of them, # it is ignored and the given time is regarded as a local time. # + # A +zone+ argument can be provided to specify the zone for the given + # +date+, if the +date+ does not include a time zone or offset. + # # ArgumentError is raised if Date._parse cannot extract information from # +date+ or if the Time class cannot represent specified date. # @@ -382,12 +385,12 @@ def make_time(date, year, yday, mon, day, hour, min, sec, sec_fraction, zone, no # # You must require 'time' to use this method. # - def parse(date, now=self.now) + def parse(date, now=self.now, zone: nil) comp = !block_given? d = Date._parse(date, comp) year = d[:year] year = yield(year) if year && !comp - make_time(date, year, d[:yday], d[:mon], d[:mday], d[:hour], d[:min], d[:sec], d[:sec_fraction], d[:zone], now) + make_time(date, year, d[:yday], d[:mon], d[:mday], d[:hour], d[:min], d[:sec], d[:sec_fraction], d[:zone] || zone, now) end # @@ -624,39 +627,84 @@ def httpdate(date) # You must require 'time' to use this method. # def xmlschema(time) - if /\A\s* + pattern = /\A\s* (-?\d+)-(\d\d)-(\d\d) T (\d\d):(\d\d):(\d\d) (\.\d+)? (Z|[+-]\d\d(?::?\d\d)?)? - \s*\z/ix =~ time - year = $1.to_i - mon = $2.to_i - day = $3.to_i - hour = $4.to_i - min = $5.to_i - sec = $6.to_i - usec = 0 - if $7 - usec = Rational($7) * 1000000 + \s*\z/ix + _xmlschema(pattern, time) + end + alias iso8601 xmlschema + + # + # Parses +time+ as a dateTime defined by RFC3339 and converts it to + # a Time object. + # + # ArgumentError is raised if +time+ is not compliant with the format or if + # the Time class cannot represent the specified time. + # + # See #xmlschema for more information on this format. + # + # require 'time' + # + # Time.rfc3339("2011-10-05T22:26:12-04:00") + # #=> 2011-10-05 22:26:12-04:00 + # + # You must require 'time' to use this method. + # + def rfc3339(time) + pattern = /\A\s* + (-?\d{4})-(\d\d)-(\d\d) + [T\s] + (\d\d):(\d\d):(\d\d) + (\.\d+)? + (Z|[+-]\d\d(?::?\d\d)?)? + \s*\z/ix + _xmlschema(pattern, time) + end + + private + + if RUBY_VERSION >= "3.2" + def _xmlschema(pattern, time) + if pattern.match?(time) + new(time) + else + raise ArgumentError.new("invalid xmlschema format: #{time.inspect}") end - if $8 - zone = $8 - off = zone_offset(zone) - year, mon, day, hour, min, sec = - apply_offset(year, mon, day, hour, min, sec, off) - t = self.utc(year, mon, day, hour, min, sec, usec) - force_zone!(t, zone, off) - t + end + else + def _xmlschema(pattern, time) + if pattern =~ time + year = $1.to_i + mon = $2.to_i + day = $3.to_i + hour = $4.to_i + min = $5.to_i + sec = $6.to_i + usec = 0 + if $7 + usec = Rational($7) * 1000000 + end + if $8 + zone = $8 + off = zone_offset(zone) + year, mon, day, hour, min, sec = + apply_offset(year, mon, day, hour, min, sec, off) + t = self.utc(year, mon, day, hour, min, sec, usec) + force_zone!(t, zone, off) + t + else + self.local(year, mon, day, hour, min, sec, usec) + end else - self.local(year, mon, day, hour, min, sec, usec) + raise ArgumentError.new("invalid xmlschema format: #{time.inspect}") end - else - raise ArgumentError.new("invalid xmlschema format: #{time.inspect}") end end - alias iso8601 xmlschema + end # class << self # @@ -731,4 +779,5 @@ def xmlschema(fraction_digits=0) end end alias iso8601 xmlschema unless method_defined?(:iso8601) + alias rfc3339 xmlschema end diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb index 30931587f8b6e4..0a06d01b08a1d4 100644 --- a/test/ruby/test_iseq.rb +++ b/test/ruby/test_iseq.rb @@ -524,6 +524,12 @@ def test_anon_block_param_in_disasm assert_equal [:&], param_names end + def test_disasm_mandatory_only_overloaded + disasm = RubyVM::InstructionSequence.disasm(Time.method(:at)) + assert_include disasm, "" + assert_include disasm, "" + end + def strip_lineno(source) source.gsub(/^.*?: /, "") end diff --git a/test/test_time.rb b/test/test_time.rb index 55964d02fc1e78..a4df0b9ef4d9a1 100644 --- a/test/test_time.rb +++ b/test/test_time.rb @@ -370,6 +370,15 @@ def test_parse_offset_hour_minute_second assert_equal(t, Time.parse("1200-02-15 BC 14:13:20-00:00:00")) end + def test_parse_custom_offset + t = Time.at(-100000000000).utc + assert_equal(t, Time.parse("1200-02-15 BC 14:13:20", zone: "UTC")) + assert_equal(t, Time.parse("1200-02-15 BC 15:13:20", zone: "+01:00").utc) + + assert_equal(t, Time.parse("1200-02-15 BC 15:13:20+01:00", zone: "UTC").utc) + assert_equal(t, Time.parse("1200-02-15 BC 15:13:20+01:00", zone: "+02:00").utc) + end + def test_parse_leap_second t = Time.utc(1998,12,31,23,59,59) assert_equal(t, Time.parse("Thu Dec 31 23:59:59 UTC 1998")) @@ -574,6 +583,7 @@ def test_huge_precision test = $1 define_method(test) {__send__(sub, :xmlschema)} define_method(test.sub(/xmlschema/, 'iso8601')) {__send__(sub, :iso8601)} + define_method(test.sub(/xmlschema/, 'rfc3339')) {__send__(sub, :rfc3339)} end def test_parse_with_various_object