activesupport 6.0.0.beta2 → 6.0.2.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +287 -3
- data/README.rdoc +2 -1
- data/lib/active_support.rb +1 -0
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/backtrace_cleaner.rb +5 -1
- data/lib/active_support/cache.rb +5 -5
- data/lib/active_support/cache/memory_store.rb +2 -0
- data/lib/active_support/cache/redis_cache_store.rb +9 -6
- data/lib/active_support/concern.rb +24 -1
- data/lib/active_support/configurable.rb +3 -3
- data/lib/active_support/core_ext/array/access.rb +18 -6
- data/lib/active_support/core_ext/class/attribute.rb +10 -15
- data/lib/active_support/core_ext/date_and_time/calculations.rb +0 -30
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +24 -4
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +2 -2
- data/lib/active_support/core_ext/hash/except.rb +1 -1
- data/lib/active_support/core_ext/module/attribute_accessors.rb +5 -5
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +5 -5
- data/lib/active_support/core_ext/module/delegation.rb +6 -0
- data/lib/active_support/core_ext/object/duplicable.rb +7 -117
- data/lib/active_support/core_ext/range/compare_range.rb +27 -12
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +2 -2
- data/lib/active_support/core_ext/string/filters.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +7 -2
- data/lib/active_support/core_ext/string/output_safety.rb +51 -4
- data/lib/active_support/core_ext/time/calculations.rb +31 -2
- data/lib/active_support/dependencies.rb +41 -5
- data/lib/active_support/dependencies/zeitwerk_integration.rb +44 -21
- data/lib/active_support/deprecation/method_wrappers.rb +7 -18
- data/lib/active_support/deprecation/proxy_wrappers.rb +24 -3
- data/lib/active_support/descendants_tracker.rb +52 -6
- data/lib/active_support/duration.rb +2 -3
- data/lib/active_support/evented_file_update_checker.rb +14 -2
- data/lib/active_support/gem_version.rb +2 -2
- data/lib/active_support/hash_with_indifferent_access.rb +6 -3
- data/lib/active_support/i18n_railtie.rb +6 -1
- data/lib/active_support/inflector/transliterate.rb +43 -14
- data/lib/active_support/logger_thread_safe_level.rb +2 -1
- data/lib/active_support/notifications/fanout.rb +2 -2
- data/lib/active_support/notifications/instrumenter.rb +12 -11
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +1 -1
- data/lib/active_support/parameter_filter.rb +6 -1
- data/lib/active_support/security_utils.rb +1 -1
- data/lib/active_support/subscriber.rb +55 -6
- data/lib/active_support/testing/parallelization.rb +21 -2
- metadata +13 -14
@@ -152,12 +152,14 @@ module ActiveSupport
|
|
152
152
|
|
153
153
|
# Creates a new Redis cache store.
|
154
154
|
#
|
155
|
-
# Handles
|
156
|
-
#
|
155
|
+
# Handles four options: :redis block, :redis instance, single :url
|
156
|
+
# string, and multiple :url strings.
|
157
157
|
#
|
158
|
-
#
|
159
|
-
# :
|
160
|
-
# :
|
158
|
+
# Option Class Result
|
159
|
+
# :redis Proc -> options[:redis].call
|
160
|
+
# :redis Object -> options[:redis]
|
161
|
+
# :url String -> Redis.new(url: …)
|
162
|
+
# :url Array -> Redis::Distributed.new([{ url: … }, { url: … }, …])
|
161
163
|
#
|
162
164
|
# No namespace is set by default. Provide one if the Redis cache
|
163
165
|
# server is shared with other apps: <tt>namespace: 'myapp-cache'</tt>.
|
@@ -361,6 +363,7 @@ module ActiveSupport
|
|
361
363
|
def read_multi_mget(*names)
|
362
364
|
options = names.extract_options!
|
363
365
|
options = merged_options(options)
|
366
|
+
return {} if names == []
|
364
367
|
|
365
368
|
keys = names.map { |name| normalize_key(name, options) }
|
366
369
|
|
@@ -468,7 +471,7 @@ module ActiveSupport
|
|
468
471
|
|
469
472
|
def failsafe(method, returning: nil)
|
470
473
|
yield
|
471
|
-
rescue ::Redis::
|
474
|
+
rescue ::Redis::BaseError => e
|
472
475
|
handle_exception exception: e, method: method, returning: returning
|
473
476
|
returning
|
474
477
|
end
|
@@ -110,7 +110,7 @@ module ActiveSupport
|
|
110
110
|
base.instance_variable_set(:@_dependencies, [])
|
111
111
|
end
|
112
112
|
|
113
|
-
def append_features(base)
|
113
|
+
def append_features(base) #:nodoc:
|
114
114
|
if base.instance_variable_defined?(:@_dependencies)
|
115
115
|
base.instance_variable_get(:@_dependencies) << self
|
116
116
|
false
|
@@ -123,6 +123,9 @@ module ActiveSupport
|
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
126
|
+
# Evaluate given block in context of base class,
|
127
|
+
# so that you can write class macros here.
|
128
|
+
# When you define more than one +included+ block, it raises an exception.
|
126
129
|
def included(base = nil, &block)
|
127
130
|
if base.nil?
|
128
131
|
if instance_variable_defined?(:@_included_block)
|
@@ -137,6 +140,26 @@ module ActiveSupport
|
|
137
140
|
end
|
138
141
|
end
|
139
142
|
|
143
|
+
# Define class methods from given block.
|
144
|
+
# You can define private class methods as well.
|
145
|
+
#
|
146
|
+
# module Example
|
147
|
+
# extend ActiveSupport::Concern
|
148
|
+
#
|
149
|
+
# class_methods do
|
150
|
+
# def foo; puts 'foo'; end
|
151
|
+
#
|
152
|
+
# private
|
153
|
+
# def bar; puts 'bar'; end
|
154
|
+
# end
|
155
|
+
# end
|
156
|
+
#
|
157
|
+
# class Buzz
|
158
|
+
# include Example
|
159
|
+
# end
|
160
|
+
#
|
161
|
+
# Buzz.foo # => "foo"
|
162
|
+
# Buzz.bar # => private method 'bar' called for Buzz:Class(NoMethodError)
|
140
163
|
def class_methods(&class_methods_module_definition)
|
141
164
|
mod = const_defined?(:ClassMethods, false) ?
|
142
165
|
const_get(:ClassMethods) :
|
@@ -67,8 +67,8 @@ module ActiveSupport
|
|
67
67
|
# end
|
68
68
|
# # => NameError: invalid config attribute name
|
69
69
|
#
|
70
|
-
# To
|
71
|
-
# To
|
70
|
+
# To omit the instance writer method, pass <tt>instance_writer: false</tt>.
|
71
|
+
# To omit the instance reader method, pass <tt>instance_reader: false</tt>.
|
72
72
|
#
|
73
73
|
# class User
|
74
74
|
# include ActiveSupport::Configurable
|
@@ -81,7 +81,7 @@ module ActiveSupport
|
|
81
81
|
# User.new.allowed_access = true # => NoMethodError
|
82
82
|
# User.new.allowed_access # => NoMethodError
|
83
83
|
#
|
84
|
-
# Or pass <tt>instance_accessor: false</tt>, to
|
84
|
+
# Or pass <tt>instance_accessor: false</tt>, to omit both instance methods.
|
85
85
|
#
|
86
86
|
# class User
|
87
87
|
# include ActiveSupport::Configurable
|
@@ -29,16 +29,28 @@ class Array
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
# Returns a
|
32
|
+
# Returns a new array that includes the passed elements.
|
33
33
|
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
|
34
|
+
# [ 1, 2, 3 ].including(4, 5) # => [ 1, 2, 3, 4, 5 ]
|
35
|
+
# [ [ 0, 1 ] ].including([ [ 1, 0 ] ]) # => [ [ 0, 1 ], [ 1, 0 ] ]
|
36
|
+
def including(*elements)
|
37
|
+
self + elements.flatten(1)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns a copy of the Array excluding the specified elements.
|
41
|
+
#
|
42
|
+
# ["David", "Rafael", "Aaron", "Todd"].excluding("Aaron", "Todd") # => ["David", "Rafael"]
|
43
|
+
# [ [ 0, 1 ], [ 1, 0 ] ].excluding([ [ 1, 0 ] ]) # => [ [ 0, 1 ] ]
|
37
44
|
#
|
38
|
-
# Note: This is an optimization of <tt>Enumerable#
|
45
|
+
# Note: This is an optimization of <tt>Enumerable#excluding</tt> that uses <tt>Array#-</tt>
|
39
46
|
# instead of <tt>Array#reject</tt> for performance reasons.
|
47
|
+
def excluding(*elements)
|
48
|
+
self - elements.flatten(1)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Alias for #excluding.
|
40
52
|
def without(*elements)
|
41
|
-
|
53
|
+
excluding(*elements)
|
42
54
|
end
|
43
55
|
|
44
56
|
# Equal to <tt>self[1]</tt>.
|
@@ -84,16 +84,17 @@ class Class
|
|
84
84
|
# To set a default value for the attribute, pass <tt>default:</tt>, like so:
|
85
85
|
#
|
86
86
|
# class_attribute :settings, default: {}
|
87
|
-
def class_attribute(
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
87
|
+
def class_attribute(
|
88
|
+
*attrs,
|
89
|
+
instance_accessor: true,
|
90
|
+
instance_reader: instance_accessor,
|
91
|
+
instance_writer: instance_accessor,
|
92
|
+
instance_predicate: true,
|
93
|
+
default: nil
|
94
|
+
)
|
94
95
|
attrs.each do |name|
|
95
96
|
singleton_class.silence_redefinition_of_method(name)
|
96
|
-
define_singleton_method(name) {
|
97
|
+
define_singleton_method(name) { default }
|
97
98
|
|
98
99
|
singleton_class.silence_redefinition_of_method("#{name}?")
|
99
100
|
define_singleton_method("#{name}?") { !!public_send(name) } if instance_predicate
|
@@ -102,9 +103,7 @@ class Class
|
|
102
103
|
|
103
104
|
singleton_class.silence_redefinition_of_method("#{name}=")
|
104
105
|
define_singleton_method("#{name}=") do |val|
|
105
|
-
|
106
|
-
redefine_method(name) { val }
|
107
|
-
end
|
106
|
+
redefine_singleton_method(name) { val }
|
108
107
|
|
109
108
|
if singleton_class?
|
110
109
|
class_eval do
|
@@ -137,10 +136,6 @@ class Class
|
|
137
136
|
instance_variable_set ivar, val
|
138
137
|
end
|
139
138
|
end
|
140
|
-
|
141
|
-
unless default_value.nil?
|
142
|
-
self.send("#{name}=", default_value)
|
143
|
-
end
|
144
139
|
end
|
145
140
|
end
|
146
141
|
end
|
@@ -20,21 +20,11 @@ module DateAndTime
|
|
20
20
|
advance(days: -1)
|
21
21
|
end
|
22
22
|
|
23
|
-
# Returns a new date/time the specified number of days ago.
|
24
|
-
def prev_day(days = 1)
|
25
|
-
advance(days: -days)
|
26
|
-
end
|
27
|
-
|
28
23
|
# Returns a new date/time representing tomorrow.
|
29
24
|
def tomorrow
|
30
25
|
advance(days: 1)
|
31
26
|
end
|
32
27
|
|
33
|
-
# Returns a new date/time the specified number of days in the future.
|
34
|
-
def next_day(days = 1)
|
35
|
-
advance(days: days)
|
36
|
-
end
|
37
|
-
|
38
28
|
# Returns true if the date/time is today.
|
39
29
|
def today?
|
40
30
|
to_date == ::Date.current
|
@@ -198,21 +188,11 @@ module DateAndTime
|
|
198
188
|
end
|
199
189
|
end
|
200
190
|
|
201
|
-
# Returns a new date/time the specified number of months in the future.
|
202
|
-
def next_month(months = 1)
|
203
|
-
advance(months: months)
|
204
|
-
end
|
205
|
-
|
206
191
|
# Short-hand for months_since(3)
|
207
192
|
def next_quarter
|
208
193
|
months_since(3)
|
209
194
|
end
|
210
195
|
|
211
|
-
# Returns a new date/time the specified number of years in the future.
|
212
|
-
def next_year(years = 1)
|
213
|
-
advance(years: years)
|
214
|
-
end
|
215
|
-
|
216
196
|
# Returns a new date/time representing the given day in the previous week.
|
217
197
|
# Week is assumed to start on +start_day+, default is
|
218
198
|
# +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
|
@@ -233,11 +213,6 @@ module DateAndTime
|
|
233
213
|
end
|
234
214
|
alias_method :last_weekday, :prev_weekday
|
235
215
|
|
236
|
-
# Returns a new date/time the specified number of months ago.
|
237
|
-
def prev_month(months = 1)
|
238
|
-
advance(months: -months)
|
239
|
-
end
|
240
|
-
|
241
216
|
# Short-hand for months_ago(1).
|
242
217
|
def last_month
|
243
218
|
months_ago(1)
|
@@ -249,11 +224,6 @@ module DateAndTime
|
|
249
224
|
end
|
250
225
|
alias_method :last_quarter, :prev_quarter
|
251
226
|
|
252
|
-
# Returns a new date/time the specified number of years ago.
|
253
|
-
def prev_year(years = 1)
|
254
|
-
advance(years: -years)
|
255
|
-
end
|
256
|
-
|
257
227
|
# Short-hand for years_ago(1).
|
258
228
|
def last_year
|
259
229
|
years_ago(1)
|
@@ -97,23 +97,43 @@ module Enumerable
|
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
100
|
+
# Returns a new array that includes the passed elements.
|
101
|
+
#
|
102
|
+
# [ 1, 2, 3 ].including(4, 5)
|
103
|
+
# # => [ 1, 2, 3, 4, 5 ]
|
104
|
+
#
|
105
|
+
# ["David", "Rafael"].including %w[ Aaron Todd ]
|
106
|
+
# # => ["David", "Rafael", "Aaron", "Todd"]
|
107
|
+
def including(*elements)
|
108
|
+
to_a.including(*elements)
|
109
|
+
end
|
110
|
+
|
100
111
|
# The negative of the <tt>Enumerable#include?</tt>. Returns +true+ if the
|
101
112
|
# collection does not include the object.
|
102
113
|
def exclude?(object)
|
103
114
|
!include?(object)
|
104
115
|
end
|
105
116
|
|
106
|
-
# Returns a copy of the enumerable
|
117
|
+
# Returns a copy of the enumerable excluding the specified elements.
|
118
|
+
#
|
119
|
+
# ["David", "Rafael", "Aaron", "Todd"].excluding "Aaron", "Todd"
|
120
|
+
# # => ["David", "Rafael"]
|
107
121
|
#
|
108
|
-
# ["David", "Rafael", "Aaron", "Todd"].
|
122
|
+
# ["David", "Rafael", "Aaron", "Todd"].excluding %w[ Aaron Todd ]
|
109
123
|
# # => ["David", "Rafael"]
|
110
124
|
#
|
111
|
-
# {foo: 1, bar: 2, baz: 3}.
|
125
|
+
# {foo: 1, bar: 2, baz: 3}.excluding :bar
|
112
126
|
# # => {foo: 1, baz: 3}
|
113
|
-
def
|
127
|
+
def excluding(*elements)
|
128
|
+
elements.flatten!(1)
|
114
129
|
reject { |element| elements.include?(element) }
|
115
130
|
end
|
116
131
|
|
132
|
+
# Alias for #excluding.
|
133
|
+
def without(*elements)
|
134
|
+
excluding(*elements)
|
135
|
+
end
|
136
|
+
|
117
137
|
# Convert an enumerable to an array based on the given key.
|
118
138
|
#
|
119
139
|
# [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name)
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Hash
|
4
|
-
# Returns a new hash with all
|
5
|
-
# This includes the
|
4
|
+
# Returns a new hash with all values converted by the block operation.
|
5
|
+
# This includes the values from the root hash and from all
|
6
6
|
# nested hashes and arrays.
|
7
7
|
#
|
8
8
|
# hash = { person: { name: 'Rob', age: '28' } }
|
@@ -10,7 +10,7 @@ class Hash
|
|
10
10
|
# This is useful for limiting a set of parameters to everything but a few known toggles:
|
11
11
|
# @person.update(params[:person].except(:admin))
|
12
12
|
def except(*keys)
|
13
|
-
|
13
|
+
slice(*self.keys - keys)
|
14
14
|
end
|
15
15
|
|
16
16
|
# Removes the given keys from hash and returns it.
|
@@ -24,7 +24,7 @@ class Module
|
|
24
24
|
# end
|
25
25
|
# # => NameError: invalid attribute name: 1_Badname
|
26
26
|
#
|
27
|
-
#
|
27
|
+
# To omit the instance reader method, pass
|
28
28
|
# <tt>instance_reader: false</tt> or <tt>instance_accessor: false</tt>.
|
29
29
|
#
|
30
30
|
# module HairColors
|
@@ -91,7 +91,7 @@ class Module
|
|
91
91
|
# Person.new.hair_colors = [:blonde, :red]
|
92
92
|
# HairColors.class_variable_get("@@hair_colors") # => [:blonde, :red]
|
93
93
|
#
|
94
|
-
#
|
94
|
+
# To omit the instance writer method, pass
|
95
95
|
# <tt>instance_writer: false</tt> or <tt>instance_accessor: false</tt>.
|
96
96
|
#
|
97
97
|
# module HairColors
|
@@ -166,8 +166,8 @@ class Module
|
|
166
166
|
# Citizen.new.hair_colors << :blue
|
167
167
|
# Person.new.hair_colors # => [:brown, :black, :blonde, :red, :blue]
|
168
168
|
#
|
169
|
-
# To
|
170
|
-
# To
|
169
|
+
# To omit the instance writer method, pass <tt>instance_writer: false</tt>.
|
170
|
+
# To omit the instance reader method, pass <tt>instance_reader: false</tt>.
|
171
171
|
#
|
172
172
|
# module HairColors
|
173
173
|
# mattr_accessor :hair_colors, instance_writer: false, instance_reader: false
|
@@ -180,7 +180,7 @@ class Module
|
|
180
180
|
# Person.new.hair_colors = [:brown] # => NoMethodError
|
181
181
|
# Person.new.hair_colors # => NoMethodError
|
182
182
|
#
|
183
|
-
# Or pass <tt>instance_accessor: false</tt>, to
|
183
|
+
# Or pass <tt>instance_accessor: false</tt>, to omit both instance methods.
|
184
184
|
#
|
185
185
|
# module HairColors
|
186
186
|
# mattr_accessor :hair_colors, instance_accessor: false
|
@@ -25,7 +25,7 @@ class Module
|
|
25
25
|
# end
|
26
26
|
# # => NameError: invalid attribute name: 1_Badname
|
27
27
|
#
|
28
|
-
#
|
28
|
+
# To omit the instance reader method, pass
|
29
29
|
# <tt>instance_reader: false</tt> or <tt>instance_accessor: false</tt>.
|
30
30
|
#
|
31
31
|
# class Current
|
@@ -66,7 +66,7 @@ class Module
|
|
66
66
|
# Current.user = "DHH"
|
67
67
|
# Thread.current[:attr_Current_user] # => "DHH"
|
68
68
|
#
|
69
|
-
#
|
69
|
+
# To omit the instance writer method, pass
|
70
70
|
# <tt>instance_writer: false</tt> or <tt>instance_accessor: false</tt>.
|
71
71
|
#
|
72
72
|
# class Current
|
@@ -118,8 +118,8 @@ class Module
|
|
118
118
|
# Customer.user # => "Rafael"
|
119
119
|
# Account.user # => "DHH"
|
120
120
|
#
|
121
|
-
# To
|
122
|
-
# To
|
121
|
+
# To omit the instance writer method, pass <tt>instance_writer: false</tt>.
|
122
|
+
# To omit the instance reader method, pass <tt>instance_reader: false</tt>.
|
123
123
|
#
|
124
124
|
# class Current
|
125
125
|
# thread_mattr_accessor :user, instance_writer: false, instance_reader: false
|
@@ -128,7 +128,7 @@ class Module
|
|
128
128
|
# Current.new.user = "DHH" # => NoMethodError
|
129
129
|
# Current.new.user # => NoMethodError
|
130
130
|
#
|
131
|
-
# Or pass <tt>instance_accessor: false</tt>, to
|
131
|
+
# Or pass <tt>instance_accessor: false</tt>, to omit both instance methods.
|
132
132
|
#
|
133
133
|
# class Current
|
134
134
|
# thread_mattr_accessor :user, instance_accessor: false
|
@@ -275,6 +275,11 @@ class Module
|
|
275
275
|
#
|
276
276
|
# The delegated method must be public on the target, otherwise it will
|
277
277
|
# raise +NoMethodError+.
|
278
|
+
#
|
279
|
+
# The <tt>marshal_dump</tt> and <tt>_dump</tt> methods are exempt from
|
280
|
+
# delegation due to possible interference when calling
|
281
|
+
# <tt>Marshal.dump(object)</tt>, should the delegation target method
|
282
|
+
# of <tt>object</tt> add or remove instance variables.
|
278
283
|
def delegate_missing_to(target)
|
279
284
|
target = target.to_s
|
280
285
|
target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target)
|
@@ -284,6 +289,7 @@ class Module
|
|
284
289
|
# It may look like an oversight, but we deliberately do not pass
|
285
290
|
# +include_private+, because they do not get delegated.
|
286
291
|
|
292
|
+
return false if name == :marshal_dump || name == :_dump
|
287
293
|
#{target}.respond_to?(name) || super
|
288
294
|
end
|
289
295
|
|
@@ -28,96 +28,6 @@ class Object
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
class NilClass
|
32
|
-
begin
|
33
|
-
nil.dup
|
34
|
-
rescue TypeError
|
35
|
-
|
36
|
-
# +nil+ is not duplicable:
|
37
|
-
#
|
38
|
-
# nil.duplicable? # => false
|
39
|
-
# nil.dup # => TypeError: can't dup NilClass
|
40
|
-
def duplicable?
|
41
|
-
false
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
class FalseClass
|
47
|
-
begin
|
48
|
-
false.dup
|
49
|
-
rescue TypeError
|
50
|
-
|
51
|
-
# +false+ is not duplicable:
|
52
|
-
#
|
53
|
-
# false.duplicable? # => false
|
54
|
-
# false.dup # => TypeError: can't dup FalseClass
|
55
|
-
def duplicable?
|
56
|
-
false
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
class TrueClass
|
62
|
-
begin
|
63
|
-
true.dup
|
64
|
-
rescue TypeError
|
65
|
-
|
66
|
-
# +true+ is not duplicable:
|
67
|
-
#
|
68
|
-
# true.duplicable? # => false
|
69
|
-
# true.dup # => TypeError: can't dup TrueClass
|
70
|
-
def duplicable?
|
71
|
-
false
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
class Symbol
|
77
|
-
begin
|
78
|
-
:symbol.dup
|
79
|
-
|
80
|
-
# Some symbols couldn't be duped in Ruby 2.4.0 only, due to a bug.
|
81
|
-
# This feature check catches any regression.
|
82
|
-
"symbol_from_string".to_sym.dup
|
83
|
-
rescue TypeError
|
84
|
-
|
85
|
-
# Symbols are not duplicable:
|
86
|
-
#
|
87
|
-
# :my_symbol.duplicable? # => false
|
88
|
-
# :my_symbol.dup # => TypeError: can't dup Symbol
|
89
|
-
def duplicable?
|
90
|
-
false
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
class Numeric
|
96
|
-
begin
|
97
|
-
1.dup
|
98
|
-
rescue TypeError
|
99
|
-
|
100
|
-
# Numbers are not duplicable:
|
101
|
-
#
|
102
|
-
# 3.duplicable? # => false
|
103
|
-
# 3.dup # => TypeError: can't dup Integer
|
104
|
-
def duplicable?
|
105
|
-
false
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
require "bigdecimal"
|
111
|
-
class BigDecimal
|
112
|
-
# BigDecimals are duplicable:
|
113
|
-
#
|
114
|
-
# BigDecimal("1.2").duplicable? # => true
|
115
|
-
# BigDecimal("1.2").dup # => #<BigDecimal:...,'0.12E1',18(18)>
|
116
|
-
def duplicable?
|
117
|
-
true
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
31
|
class Method
|
122
32
|
# Methods are not duplicable:
|
123
33
|
#
|
@@ -128,32 +38,12 @@ class Method
|
|
128
38
|
end
|
129
39
|
end
|
130
40
|
|
131
|
-
class
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
# Complex(1).duplicable? # => false
|
139
|
-
# Complex(1).dup # => TypeError: can't copy Complex
|
140
|
-
def duplicable?
|
141
|
-
false
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
class Rational
|
147
|
-
begin
|
148
|
-
Rational(1).dup
|
149
|
-
rescue TypeError
|
150
|
-
|
151
|
-
# Rationals are not duplicable:
|
152
|
-
#
|
153
|
-
# Rational(1).duplicable? # => false
|
154
|
-
# Rational(1).dup # => TypeError: can't copy Rational
|
155
|
-
def duplicable?
|
156
|
-
false
|
157
|
-
end
|
41
|
+
class UnboundMethod
|
42
|
+
# Unbound methods are not duplicable:
|
43
|
+
#
|
44
|
+
# method(:puts).unbind.duplicable? # => false
|
45
|
+
# method(:puts).unbind.dup # => TypeError: allocator undefined for UnboundMethod
|
46
|
+
def duplicable?
|
47
|
+
false
|
158
48
|
end
|
159
49
|
end
|