/
ruby_core_support.rb
176 lines (157 loc) · 5.47 KB
/
ruby_core_support.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
require 'date'
require 'rational' unless defined?(Rational)
module TZInfo
# Methods to support different versions of Ruby.
#
# @private
module RubyCoreSupport #:nodoc:
# Use Rational.new! for performance reasons in Ruby 1.8.
# This has been removed from 1.9, but Rational performs better.
if Rational.respond_to? :new!
def self.rational_new!(numerator, denominator = 1)
Rational.new!(numerator, denominator)
end
else
def self.rational_new!(numerator, denominator = 1)
Rational(numerator, denominator)
end
end
# Ruby 1.8.6 introduced new! and deprecated new0.
# Ruby 1.9.0 removed new0.
# Ruby trunk revision 31668 removed the new! method.
# Still support new0 for better performance on older versions of Ruby (new0 indicates
# that the rational has already been reduced to its lowest terms).
# Fallback to jd with conversion from ajd if new! and new0 are unavailable.
if DateTime.respond_to? :new!
def self.datetime_new!(ajd = 0, of = 0, sg = Date::ITALY)
DateTime.new!(ajd, of, sg)
end
elsif DateTime.respond_to? :new0
def self.datetime_new!(ajd = 0, of = 0, sg = Date::ITALY)
DateTime.new0(ajd, of, sg)
end
else
HALF_DAYS_IN_DAY = rational_new!(1, 2)
def self.datetime_new!(ajd = 0, of = 0, sg = Date::ITALY)
# Convert from an Astronomical Julian Day number to a civil Julian Day number.
jd = ajd + of + HALF_DAYS_IN_DAY
# Ruby trunk revision 31862 changed the behaviour of DateTime.jd so that it will no
# longer accept a fractional civil Julian Day number if further arguments are specified.
# Calculate the hours, minutes and seconds to pass to jd.
jd_i = jd.to_i
jd_i -= 1 if jd < 0
hours = (jd - jd_i) * 24
hours_i = hours.to_i
minutes = (hours - hours_i) * 60
minutes_i = minutes.to_i
seconds = (minutes - minutes_i) * 60
DateTime.jd(jd_i, hours_i, minutes_i, seconds, of, sg)
end
end
# DateTime in Ruby 1.8.6 doesn't consider times within the 60th second to be
# valid. When attempting to specify such a DateTime, subtract the fractional
# part and then add it back later
if Date.respond_to?(:valid_time?) && !Date.valid_time?(0, 0, rational_new!(59001, 1000)) # 0:0:59.001
def self.datetime_new(y=-4712, m=1, d=1, h=0, min=0, s=0, of=0, sg=Date::ITALY)
if !s.kind_of?(Integer) && s > 59
dt = DateTime.new(y, m, d, h, min, 59, of, sg)
dt + (s - 59) / 86400
else
DateTime.new(y, m, d, h, min, s, of, sg)
end
end
else
def self.datetime_new(y=-4712, m=1, d=1, h=0, min=0, s=0, of=0, sg=Date::ITALY)
DateTime.new(y, m, d, h, min, s, of, sg)
end
end
# Returns true if Time on the runtime platform supports Times defined
# by negative 32-bit timestamps, otherwise false.
begin
Time.at(-1)
Time.at(-2147483648)
def self.time_supports_negative
true
end
rescue ArgumentError
def self.time_supports_negative
false
end
end
# Returns true if Time on the runtime platform supports Times defined by
# 64-bit timestamps, otherwise false.
begin
Time.at(-2147483649)
Time.at(2147483648)
def self.time_supports_64bit
true
end
rescue RangeError
def self.time_supports_64bit
false
end
end
# Return the result of Time#nsec if it exists, otherwise return the
# result of Time#usec * 1000.
if Time.method_defined?(:nsec)
def self.time_nsec(time)
time.nsec
end
else
def self.time_nsec(time)
time.usec * 1000
end
end
# Call String#force_encoding if this version of Ruby has encoding support
# otherwise treat as a no-op.
if String.method_defined?(:force_encoding)
def self.force_encoding(str, encoding)
str.force_encoding(encoding)
end
else
def self.force_encoding(str, encoding)
str
end
end
# Wrapper for File.open that supports passing hash options for specifying
# encodings on Ruby 1.9+. The options are ignored on earlier versions of
# Ruby.
if RUBY_VERSION =~ /\A1\.[0-8]\./
def self.open_file(file_name, mode, opts, &block)
File.open(file_name, mode, &block)
end
elsif RUBY_VERSION =~ /\A1\.9\./
def self.open_file(file_name, mode, opts, &block)
File.open(file_name, mode, opts, &block)
end
else
# Evaluate method as a string because **opts isn't valid syntax prior to
# Ruby 2.0.
eval(<<-EOF
def self.open_file(file_name, mode, opts, &block)
File.open(file_name, mode, **opts, &block)
end
EOF
)
end
# Object#untaint is deprecated and becomes a no-op in Ruby >= 2.7. It has
# been removed from Ruby 3.2.
if !Object.new.respond_to?(:untaint) || RUBY_VERSION =~ /\A(\d+)\.(\d+)(?:\.|\z)/ && ($1 == '2' && $2.to_i >= 7 || $1.to_i >= 3)
# Returns the supplied `Object`
#
# @param o [Object] the `Object` to untaint.
# @return [Object] `o`.
def self.untaint(o)
o
end
else
# Untaints and returns the supplied `Object`.
#
# @param o [Object] the `Object` to untaint.
# @return [Object] `o`.
def self.untaint(o)
o.untaint
end
end
end
end