activesupport 4.2.11.1 → 6.0.3.1
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 +399 -411
- data/MIT-LICENSE +2 -2
- data/README.rdoc +7 -7
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/all.rb +5 -3
- data/lib/active_support/array_inquirer.rb +48 -0
- data/lib/active_support/backtrace_cleaner.rb +34 -6
- data/lib/active_support/benchmarkable.rb +6 -4
- data/lib/active_support/builder.rb +3 -1
- data/lib/active_support/cache/file_store.rb +58 -53
- data/lib/active_support/cache/mem_cache_store.rb +95 -91
- data/lib/active_support/cache/memory_store.rb +39 -36
- data/lib/active_support/cache/null_store.rb +11 -7
- data/lib/active_support/cache/redis_cache_store.rb +493 -0
- data/lib/active_support/cache/strategy/local_cache.rb +75 -42
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
- data/lib/active_support/cache.rb +331 -217
- data/lib/active_support/callbacks.rb +650 -592
- data/lib/active_support/concern.rb +35 -6
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
- data/lib/active_support/concurrency/share_lock.rb +226 -0
- data/lib/active_support/configurable.rb +13 -14
- data/lib/active_support/core_ext/array/access.rb +41 -1
- data/lib/active_support/core_ext/array/conversions.rb +24 -20
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array/extract_options.rb +2 -0
- data/lib/active_support/core_ext/array/grouping.rb +11 -18
- data/lib/active_support/core_ext/array/inquiry.rb +19 -0
- data/lib/active_support/core_ext/array/prepend_and_append.rb +4 -6
- data/lib/active_support/core_ext/array/wrap.rb +7 -4
- data/lib/active_support/core_ext/array.rb +9 -6
- data/lib/active_support/core_ext/benchmark.rb +3 -1
- data/lib/active_support/core_ext/big_decimal/conversions.rb +10 -12
- data/lib/active_support/core_ext/big_decimal.rb +3 -1
- data/lib/active_support/core_ext/class/attribute.rb +45 -31
- data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
- data/lib/active_support/core_ext/class/subclasses.rb +20 -6
- data/lib/active_support/core_ext/class.rb +4 -3
- data/lib/active_support/core_ext/date/acts_like.rb +3 -1
- data/lib/active_support/core_ext/date/blank.rb +14 -0
- data/lib/active_support/core_ext/date/calculations.rb +17 -14
- data/lib/active_support/core_ext/date/conversions.rb +25 -23
- data/lib/active_support/core_ext/date/zones.rb +4 -2
- data/lib/active_support/core_ext/date.rb +6 -4
- data/lib/active_support/core_ext/date_and_time/calculations.rb +154 -65
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +4 -3
- data/lib/active_support/core_ext/date_and_time/zones.rb +12 -13
- data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
- data/lib/active_support/core_ext/date_time/blank.rb +14 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +37 -19
- data/lib/active_support/core_ext/date_time/compatibility.rb +8 -6
- data/lib/active_support/core_ext/date_time/conversions.rb +16 -13
- data/lib/active_support/core_ext/date_time.rb +7 -5
- data/lib/active_support/core_ext/digest/uuid.rb +7 -5
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +114 -22
- data/lib/active_support/core_ext/file/atomic.rb +38 -31
- data/lib/active_support/core_ext/file.rb +3 -1
- data/lib/active_support/core_ext/hash/compact.rb +4 -23
- data/lib/active_support/core_ext/hash/conversions.rb +62 -41
- data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +12 -9
- data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -3
- data/lib/active_support/core_ext/hash/keys.rb +19 -42
- data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
- data/lib/active_support/core_ext/hash/slice.rb +5 -27
- data/lib/active_support/core_ext/hash/transform_values.rb +4 -22
- data/lib/active_support/core_ext/hash.rb +10 -9
- data/lib/active_support/core_ext/integer/inflections.rb +3 -1
- data/lib/active_support/core_ext/integer/multiple.rb +3 -1
- data/lib/active_support/core_ext/integer/time.rb +11 -18
- data/lib/active_support/core_ext/integer.rb +5 -3
- data/lib/active_support/core_ext/kernel/concern.rb +5 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -84
- data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
- data/lib/active_support/core_ext/kernel.rb +5 -5
- data/lib/active_support/core_ext/load_error.rb +3 -22
- data/lib/active_support/core_ext/marshal.rb +8 -8
- data/lib/active_support/core_ext/module/aliasing.rb +6 -44
- data/lib/active_support/core_ext/module/anonymous.rb +12 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +8 -9
- data/lib/active_support/core_ext/module/attribute_accessors.rb +46 -46
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +144 -0
- data/lib/active_support/core_ext/module/concerning.rb +11 -12
- data/lib/active_support/core_ext/module/delegation.rb +133 -30
- data/lib/active_support/core_ext/module/deprecation.rb +4 -2
- data/lib/active_support/core_ext/module/introspection.rb +44 -19
- data/lib/active_support/core_ext/module/reachable.rb +5 -7
- data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
- data/lib/active_support/core_ext/module/remove_method.rb +8 -3
- data/lib/active_support/core_ext/module.rb +13 -11
- data/lib/active_support/core_ext/name_error.rb +22 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +129 -136
- data/lib/active_support/core_ext/numeric/inquiry.rb +5 -0
- data/lib/active_support/core_ext/numeric/time.rb +35 -23
- data/lib/active_support/core_ext/numeric.rb +5 -3
- data/lib/active_support/core_ext/object/acts_like.rb +12 -1
- data/lib/active_support/core_ext/object/blank.rb +27 -3
- data/lib/active_support/core_ext/object/conversions.rb +6 -4
- data/lib/active_support/core_ext/object/deep_dup.rb +13 -4
- data/lib/active_support/core_ext/object/duplicable.rb +13 -93
- data/lib/active_support/core_ext/object/inclusion.rb +5 -3
- data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
- data/lib/active_support/core_ext/object/json.rb +51 -20
- data/lib/active_support/core_ext/object/to_param.rb +3 -1
- data/lib/active_support/core_ext/object/to_query.rb +10 -5
- data/lib/active_support/core_ext/object/try.rb +81 -23
- data/lib/active_support/core_ext/object/with_options.rb +16 -3
- data/lib/active_support/core_ext/object.rb +14 -13
- data/lib/active_support/core_ext/range/compare_range.rb +76 -0
- data/lib/active_support/core_ext/range/conversions.rb +37 -15
- data/lib/active_support/core_ext/range/each.rb +18 -17
- data/lib/active_support/core_ext/range/include_range.rb +7 -21
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
- data/lib/active_support/core_ext/range/overlaps.rb +2 -0
- data/lib/active_support/core_ext/range.rb +7 -4
- data/lib/active_support/core_ext/regexp.rb +2 -0
- data/lib/active_support/core_ext/securerandom.rb +45 -0
- data/lib/active_support/core_ext/string/access.rb +16 -6
- data/lib/active_support/core_ext/string/behavior.rb +3 -1
- data/lib/active_support/core_ext/string/conversions.rb +7 -4
- data/lib/active_support/core_ext/string/exclude.rb +2 -0
- data/lib/active_support/core_ext/string/filters.rb +48 -6
- data/lib/active_support/core_ext/string/indent.rb +6 -4
- data/lib/active_support/core_ext/string/inflections.rb +66 -24
- data/lib/active_support/core_ext/string/inquiry.rb +3 -1
- data/lib/active_support/core_ext/string/multibyte.rb +16 -7
- data/lib/active_support/core_ext/string/output_safety.rb +93 -40
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -0
- data/lib/active_support/core_ext/string/strip.rb +6 -5
- data/lib/active_support/core_ext/string/zones.rb +4 -2
- data/lib/active_support/core_ext/string.rb +15 -13
- data/lib/active_support/core_ext/time/acts_like.rb +3 -1
- data/lib/active_support/core_ext/time/calculations.rb +115 -52
- data/lib/active_support/core_ext/time/compatibility.rb +4 -2
- data/lib/active_support/core_ext/time/conversions.rb +20 -13
- data/lib/active_support/core_ext/time/zones.rb +41 -7
- data/lib/active_support/core_ext/time.rb +7 -6
- data/lib/active_support/core_ext/uri.rb +6 -7
- data/lib/active_support/core_ext.rb +3 -1
- data/lib/active_support/current_attributes.rb +203 -0
- data/lib/active_support/dependencies/autoload.rb +2 -0
- data/lib/active_support/dependencies/interlock.rb +57 -0
- data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
- data/lib/active_support/dependencies.rb +208 -166
- data/lib/active_support/deprecation/behaviors.rb +44 -11
- data/lib/active_support/deprecation/constant_accessor.rb +52 -0
- data/lib/active_support/deprecation/instance_delegator.rb +17 -2
- data/lib/active_support/deprecation/method_wrappers.rb +61 -21
- data/lib/active_support/deprecation/proxy_wrappers.rb +81 -30
- data/lib/active_support/deprecation/reporting.rb +32 -12
- data/lib/active_support/deprecation.rb +12 -9
- data/lib/active_support/descendants_tracker.rb +57 -9
- data/lib/active_support/digest.rb +20 -0
- data/lib/active_support/duration/iso8601_parser.rb +123 -0
- data/lib/active_support/duration/iso8601_serializer.rb +53 -0
- data/lib/active_support/duration.rb +315 -40
- data/lib/active_support/encrypted_configuration.rb +45 -0
- data/lib/active_support/encrypted_file.rb +100 -0
- data/lib/active_support/evented_file_update_checker.rb +234 -0
- data/lib/active_support/execution_wrapper.rb +129 -0
- data/lib/active_support/executor.rb +8 -0
- data/lib/active_support/file_update_checker.rb +62 -37
- data/lib/active_support/gem_version.rb +6 -4
- data/lib/active_support/gzip.rb +7 -5
- data/lib/active_support/hash_with_indifferent_access.rb +129 -30
- data/lib/active_support/i18n.rb +9 -6
- data/lib/active_support/i18n_railtie.rb +50 -14
- data/lib/active_support/inflections.rb +13 -11
- data/lib/active_support/inflector/inflections.rb +58 -13
- data/lib/active_support/inflector/methods.rb +159 -145
- data/lib/active_support/inflector/transliterate.rb +84 -34
- data/lib/active_support/inflector.rb +7 -5
- data/lib/active_support/json/decoding.rb +32 -30
- data/lib/active_support/json/encoding.rb +17 -60
- data/lib/active_support/json.rb +4 -2
- data/lib/active_support/key_generator.rb +11 -43
- data/lib/active_support/lazy_load_hooks.rb +53 -20
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +2 -0
- data/lib/active_support/log_subscriber/test_helper.rb +14 -12
- data/lib/active_support/log_subscriber.rb +44 -19
- data/lib/active_support/logger.rb +9 -23
- data/lib/active_support/logger_silence.rb +32 -14
- data/lib/active_support/logger_thread_safe_level.rb +32 -8
- data/lib/active_support/message_encryptor.rb +166 -53
- data/lib/active_support/message_verifier.rb +149 -16
- data/lib/active_support/messages/metadata.rb +72 -0
- data/lib/active_support/messages/rotation_configuration.rb +22 -0
- data/lib/active_support/messages/rotator.rb +56 -0
- data/lib/active_support/multibyte/chars.rb +56 -63
- data/lib/active_support/multibyte/unicode.rb +56 -290
- data/lib/active_support/multibyte.rb +4 -2
- data/lib/active_support/notifications/fanout.rb +109 -22
- data/lib/active_support/notifications/instrumenter.rb +107 -16
- data/lib/active_support/notifications.rb +51 -10
- data/lib/active_support/number_helper/number_converter.rb +16 -15
- data/lib/active_support/number_helper/number_to_currency_converter.rb +14 -15
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +11 -4
- data/lib/active_support/number_helper/number_to_human_converter.rb +13 -10
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +11 -9
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +15 -5
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +25 -57
- data/lib/active_support/number_helper/rounding_helper.rb +66 -0
- data/lib/active_support/number_helper.rb +105 -68
- data/lib/active_support/option_merger.rb +24 -4
- data/lib/active_support/ordered_hash.rb +7 -5
- data/lib/active_support/ordered_options.rb +27 -5
- data/lib/active_support/parameter_filter.rb +128 -0
- data/lib/active_support/per_thread_registry.rb +9 -4
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +10 -8
- data/lib/active_support/railtie.rb +43 -9
- data/lib/active_support/reloader.rb +130 -0
- data/lib/active_support/rescuable.rb +108 -53
- data/lib/active_support/security_utils.rb +15 -11
- data/lib/active_support/string_inquirer.rb +11 -4
- data/lib/active_support/subscriber.rb +74 -30
- data/lib/active_support/tagged_logging.rb +25 -13
- data/lib/active_support/test_case.rb +107 -44
- data/lib/active_support/testing/assertions.rb +151 -20
- data/lib/active_support/testing/autorun.rb +4 -2
- data/lib/active_support/testing/constant_lookup.rb +2 -1
- data/lib/active_support/testing/declarative.rb +3 -1
- data/lib/active_support/testing/deprecation.rb +13 -10
- data/lib/active_support/testing/file_fixtures.rb +38 -0
- data/lib/active_support/testing/isolation.rb +35 -26
- data/lib/active_support/testing/method_call_assertions.rb +70 -0
- data/lib/active_support/testing/parallelization.rb +134 -0
- data/lib/active_support/testing/setup_and_teardown.rb +13 -8
- data/lib/active_support/testing/stream.rb +43 -0
- data/lib/active_support/testing/tagged_logging.rb +3 -1
- data/lib/active_support/testing/time_helpers.rb +84 -20
- data/lib/active_support/time.rb +14 -12
- data/lib/active_support/time_with_zone.rb +179 -39
- data/lib/active_support/values/time_zone.rb +203 -63
- data/lib/active_support/version.rb +3 -1
- data/lib/active_support/xml_mini/jdom.rb +116 -115
- data/lib/active_support/xml_mini/libxml.rb +16 -13
- data/lib/active_support/xml_mini/libxmlsax.rb +15 -14
- data/lib/active_support/xml_mini/nokogiri.rb +14 -12
- data/lib/active_support/xml_mini/nokogirisax.rb +14 -13
- data/lib/active_support/xml_mini/rexml.rb +11 -9
- data/lib/active_support/xml_mini.rb +38 -46
- data/lib/active_support.rb +13 -11
- metadata +84 -26
- data/lib/active_support/concurrency/latch.rb +0 -27
- data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
- data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
- data/lib/active_support/core_ext/date_time/zones.rb +0 -6
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
- data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
- data/lib/active_support/core_ext/module/method_transplanting.rb +0 -13
- data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
- data/lib/active_support/core_ext/object/itself.rb +0 -15
- data/lib/active_support/core_ext/struct.rb +0 -6
- data/lib/active_support/core_ext/thread.rb +0 -86
- data/lib/active_support/core_ext/time/marshal.rb +0 -30
- data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,49 +1,8 @@
|
|
1
|
-
|
2
|
-
# Encapsulates the common pattern of:
|
3
|
-
#
|
4
|
-
# alias_method :foo_without_feature, :foo
|
5
|
-
# alias_method :foo, :foo_with_feature
|
6
|
-
#
|
7
|
-
# With this, you simply do:
|
8
|
-
#
|
9
|
-
# alias_method_chain :foo, :feature
|
10
|
-
#
|
11
|
-
# And both aliases are set up for you.
|
12
|
-
#
|
13
|
-
# Query and bang methods (foo?, foo!) keep the same punctuation:
|
14
|
-
#
|
15
|
-
# alias_method_chain :foo?, :feature
|
16
|
-
#
|
17
|
-
# is equivalent to
|
18
|
-
#
|
19
|
-
# alias_method :foo_without_feature?, :foo?
|
20
|
-
# alias_method :foo?, :foo_with_feature?
|
21
|
-
#
|
22
|
-
# so you can safely chain foo, foo?, foo! and/or foo= with the same feature.
|
23
|
-
def alias_method_chain(target, feature)
|
24
|
-
# Strip out punctuation on predicates, bang or writer methods since
|
25
|
-
# e.g. target?_without_feature is not a valid method name.
|
26
|
-
aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
|
27
|
-
yield(aliased_target, punctuation) if block_given?
|
28
|
-
|
29
|
-
with_method = "#{aliased_target}_with_#{feature}#{punctuation}"
|
30
|
-
without_method = "#{aliased_target}_without_#{feature}#{punctuation}"
|
31
|
-
|
32
|
-
alias_method without_method, target
|
33
|
-
alias_method target, with_method
|
34
|
-
|
35
|
-
case
|
36
|
-
when public_method_defined?(without_method)
|
37
|
-
public target
|
38
|
-
when protected_method_defined?(without_method)
|
39
|
-
protected target
|
40
|
-
when private_method_defined?(without_method)
|
41
|
-
private target
|
42
|
-
end
|
43
|
-
end
|
1
|
+
# frozen_string_literal: true
|
44
2
|
|
3
|
+
class Module
|
45
4
|
# Allows you to make aliases for attributes, which includes
|
46
|
-
# getter, setter, and
|
5
|
+
# getter, setter, and a predicate.
|
47
6
|
#
|
48
7
|
# class Content < ActiveRecord::Base
|
49
8
|
# # has a title attribute
|
@@ -60,6 +19,9 @@ class Module
|
|
60
19
|
# e.subject = "Megastars"
|
61
20
|
# e.title # => "Megastars"
|
62
21
|
def alias_attribute(new_name, old_name)
|
22
|
+
# The following reader methods use an explicit `self` receiver in order to
|
23
|
+
# support aliases that start with an uppercase letter. Otherwise, they would
|
24
|
+
# be resolved as constants instead.
|
63
25
|
module_eval <<-STR, __FILE__, __LINE__ + 1
|
64
26
|
def #{new_name}; self.#{old_name}; end # def subject; self.title; end
|
65
27
|
def #{new_name}?; self.#{old_name}?; end # def subject?; self.title?; end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Module
|
2
4
|
# A module may or may not have a name.
|
3
5
|
#
|
@@ -7,12 +9,21 @@ class Module
|
|
7
9
|
# m = Module.new
|
8
10
|
# m.name # => nil
|
9
11
|
#
|
12
|
+
# +anonymous?+ method returns true if module does not have a name, false otherwise:
|
13
|
+
#
|
14
|
+
# Module.new.anonymous? # => true
|
15
|
+
#
|
16
|
+
# module M; end
|
17
|
+
# M.anonymous? # => false
|
18
|
+
#
|
10
19
|
# A module gets a name when it is first assigned to a constant. Either
|
11
20
|
# via the +module+ or +class+ keyword or by an explicit assignment:
|
12
21
|
#
|
13
22
|
# m = Module.new # creates an anonymous module
|
14
|
-
#
|
23
|
+
# m.anonymous? # => true
|
24
|
+
# M = m # m gets a name here as a side-effect
|
15
25
|
# m.name # => "M"
|
26
|
+
# m.anonymous? # => false
|
16
27
|
def anonymous?
|
17
28
|
name.nil?
|
18
29
|
end
|
@@ -1,12 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Module
|
2
4
|
# Declares an attribute reader backed by an internally-named instance variable.
|
3
5
|
def attr_internal_reader(*attrs)
|
4
|
-
attrs.each {|attr_name| attr_internal_define(attr_name, :reader)}
|
6
|
+
attrs.each { |attr_name| attr_internal_define(attr_name, :reader) }
|
5
7
|
end
|
6
8
|
|
7
9
|
# Declares an attribute writer backed by an internally-named instance variable.
|
8
10
|
def attr_internal_writer(*attrs)
|
9
|
-
attrs.each {|attr_name| attr_internal_define(attr_name, :writer)}
|
11
|
+
attrs.each { |attr_name| attr_internal_define(attr_name, :writer) }
|
10
12
|
end
|
11
13
|
|
12
14
|
# Declares an attribute reader and writer backed by an internally-named instance
|
@@ -18,7 +20,7 @@ class Module
|
|
18
20
|
alias_method :attr_internal, :attr_internal_accessor
|
19
21
|
|
20
22
|
class << self; attr_accessor :attr_internal_naming_format end
|
21
|
-
self.attr_internal_naming_format =
|
23
|
+
self.attr_internal_naming_format = "@_%s"
|
22
24
|
|
23
25
|
private
|
24
26
|
def attr_internal_ivar_name(attr)
|
@@ -26,12 +28,9 @@ class Module
|
|
26
28
|
end
|
27
29
|
|
28
30
|
def attr_internal_define(attr_name, type)
|
29
|
-
internal_name = attr_internal_ivar_name(attr_name).sub(/\A@/,
|
30
|
-
#
|
31
|
-
|
32
|
-
# use native attr_* methods as they are faster on some Ruby implementations
|
33
|
-
send("attr_#{type}", internal_name)
|
34
|
-
end
|
31
|
+
internal_name = attr_internal_ivar_name(attr_name).sub(/\A@/, "")
|
32
|
+
# use native attr_* methods as they are faster on some Ruby implementations
|
33
|
+
send("attr_#{type}", internal_name)
|
35
34
|
attr_name, internal_name = "#{attr_name}=", "#{internal_name}=" if type == :writer
|
36
35
|
alias_method attr_name, internal_name
|
37
36
|
remove_method internal_name
|
@@ -1,12 +1,13 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Extends the module object with class/module and instance accessors for
|
4
4
|
# class/module attributes, just like the native attr* accessors for instance
|
5
5
|
# attributes.
|
6
6
|
class Module
|
7
7
|
# Defines a class attribute and creates a class and instance reader methods.
|
8
|
-
# The underlying
|
9
|
-
# defined.
|
8
|
+
# The underlying class variable is set to +nil+, if it is not previously
|
9
|
+
# defined. All class and instance methods created will be public, even if
|
10
|
+
# this method is called with a private or protected access modifier.
|
10
11
|
#
|
11
12
|
# module HairColors
|
12
13
|
# mattr_reader :hair_colors
|
@@ -19,15 +20,15 @@ class Module
|
|
19
20
|
# The attribute name must be a valid method name in Ruby.
|
20
21
|
#
|
21
22
|
# module Foo
|
22
|
-
# mattr_reader :"1_Badname
|
23
|
+
# mattr_reader :"1_Badname"
|
23
24
|
# end
|
24
|
-
# # => NameError: invalid attribute name
|
25
|
+
# # => NameError: invalid attribute name: 1_Badname
|
25
26
|
#
|
26
|
-
#
|
27
|
+
# To omit the instance reader method, pass
|
27
28
|
# <tt>instance_reader: false</tt> or <tt>instance_accessor: false</tt>.
|
28
29
|
#
|
29
30
|
# module HairColors
|
30
|
-
#
|
31
|
+
# mattr_reader :hair_colors, instance_reader: false
|
31
32
|
# end
|
32
33
|
#
|
33
34
|
# class Person
|
@@ -36,24 +37,20 @@ class Module
|
|
36
37
|
#
|
37
38
|
# Person.new.hair_colors # => NoMethodError
|
38
39
|
#
|
39
|
-
#
|
40
|
-
# Also, you can pass a block to set up the attribute with a default value.
|
40
|
+
# You can set a default value for the attribute.
|
41
41
|
#
|
42
42
|
# module HairColors
|
43
|
-
#
|
44
|
-
# [:brown, :black, :blonde, :red]
|
45
|
-
# end
|
43
|
+
# mattr_reader :hair_colors, default: [:brown, :black, :blonde, :red]
|
46
44
|
# end
|
47
45
|
#
|
48
46
|
# class Person
|
49
47
|
# include HairColors
|
50
48
|
# end
|
51
49
|
#
|
52
|
-
# Person.hair_colors # => [:brown, :black, :blonde, :red]
|
53
|
-
def mattr_reader(*syms)
|
54
|
-
options = syms.extract_options!
|
50
|
+
# Person.new.hair_colors # => [:brown, :black, :blonde, :red]
|
51
|
+
def mattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil)
|
55
52
|
syms.each do |sym|
|
56
|
-
raise NameError.new("invalid attribute name: #{sym}") unless
|
53
|
+
raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym)
|
57
54
|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
58
55
|
@@#{sym} = nil unless defined? @@#{sym}
|
59
56
|
|
@@ -62,20 +59,24 @@ class Module
|
|
62
59
|
end
|
63
60
|
EOS
|
64
61
|
|
65
|
-
|
62
|
+
if instance_reader && instance_accessor
|
66
63
|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
67
64
|
def #{sym}
|
68
65
|
@@#{sym}
|
69
66
|
end
|
70
67
|
EOS
|
71
68
|
end
|
72
|
-
|
69
|
+
|
70
|
+
sym_default_value = (block_given? && default.nil?) ? yield : default
|
71
|
+
class_variable_set("@@#{sym}", sym_default_value) unless sym_default_value.nil?
|
73
72
|
end
|
74
73
|
end
|
75
74
|
alias :cattr_reader :mattr_reader
|
76
75
|
|
77
76
|
# Defines a class attribute and creates a class and instance writer methods to
|
78
|
-
# allow assignment to the attribute.
|
77
|
+
# allow assignment to the attribute. All class and instance methods created
|
78
|
+
# will be public, even if this method is called with a private or protected
|
79
|
+
# access modifier.
|
79
80
|
#
|
80
81
|
# module HairColors
|
81
82
|
# mattr_writer :hair_colors
|
@@ -90,7 +91,7 @@ class Module
|
|
90
91
|
# Person.new.hair_colors = [:blonde, :red]
|
91
92
|
# HairColors.class_variable_get("@@hair_colors") # => [:blonde, :red]
|
92
93
|
#
|
93
|
-
#
|
94
|
+
# To omit the instance writer method, pass
|
94
95
|
# <tt>instance_writer: false</tt> or <tt>instance_accessor: false</tt>.
|
95
96
|
#
|
96
97
|
# module HairColors
|
@@ -103,12 +104,10 @@ class Module
|
|
103
104
|
#
|
104
105
|
# Person.new.hair_colors = [:blonde, :red] # => NoMethodError
|
105
106
|
#
|
106
|
-
#
|
107
|
+
# You can set a default value for the attribute.
|
107
108
|
#
|
108
|
-
#
|
109
|
-
# mattr_writer :hair_colors
|
110
|
-
# [:brown, :black, :blonde, :red]
|
111
|
-
# end
|
109
|
+
# module HairColors
|
110
|
+
# mattr_writer :hair_colors, default: [:brown, :black, :blonde, :red]
|
112
111
|
# end
|
113
112
|
#
|
114
113
|
# class Person
|
@@ -116,10 +115,9 @@ class Module
|
|
116
115
|
# end
|
117
116
|
#
|
118
117
|
# Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
|
119
|
-
def mattr_writer(*syms)
|
120
|
-
options = syms.extract_options!
|
118
|
+
def mattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil)
|
121
119
|
syms.each do |sym|
|
122
|
-
raise NameError.new("invalid attribute name: #{sym}") unless
|
120
|
+
raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym)
|
123
121
|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
124
122
|
@@#{sym} = nil unless defined? @@#{sym}
|
125
123
|
|
@@ -128,19 +126,23 @@ class Module
|
|
128
126
|
end
|
129
127
|
EOS
|
130
128
|
|
131
|
-
|
129
|
+
if instance_writer && instance_accessor
|
132
130
|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
133
131
|
def #{sym}=(obj)
|
134
132
|
@@#{sym} = obj
|
135
133
|
end
|
136
134
|
EOS
|
137
135
|
end
|
138
|
-
|
136
|
+
|
137
|
+
sym_default_value = (block_given? && default.nil?) ? yield : default
|
138
|
+
send("#{sym}=", sym_default_value) unless sym_default_value.nil?
|
139
139
|
end
|
140
140
|
end
|
141
141
|
alias :cattr_writer :mattr_writer
|
142
142
|
|
143
143
|
# Defines both class and instance accessors for class attributes.
|
144
|
+
# All class and instance methods created will be public, even if
|
145
|
+
# this method is called with a private or protected access modifier.
|
144
146
|
#
|
145
147
|
# module HairColors
|
146
148
|
# mattr_accessor :hair_colors
|
@@ -150,22 +152,22 @@ class Module
|
|
150
152
|
# include HairColors
|
151
153
|
# end
|
152
154
|
#
|
153
|
-
#
|
154
|
-
#
|
155
|
+
# HairColors.hair_colors = [:brown, :black, :blonde, :red]
|
156
|
+
# HairColors.hair_colors # => [:brown, :black, :blonde, :red]
|
155
157
|
# Person.new.hair_colors # => [:brown, :black, :blonde, :red]
|
156
158
|
#
|
157
159
|
# If a subclass changes the value then that would also change the value for
|
158
160
|
# parent class. Similarly if parent class changes the value then that would
|
159
161
|
# change the value of subclasses too.
|
160
162
|
#
|
161
|
-
# class
|
163
|
+
# class Citizen < Person
|
162
164
|
# end
|
163
165
|
#
|
164
|
-
#
|
165
|
-
# Person.hair_colors # => [:brown, :black, :blonde, :red, :blue]
|
166
|
+
# Citizen.new.hair_colors << :blue
|
167
|
+
# Person.new.hair_colors # => [:brown, :black, :blonde, :red, :blue]
|
166
168
|
#
|
167
|
-
# To
|
168
|
-
# 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>.
|
169
171
|
#
|
170
172
|
# module HairColors
|
171
173
|
# mattr_accessor :hair_colors, instance_writer: false, instance_reader: false
|
@@ -178,7 +180,7 @@ class Module
|
|
178
180
|
# Person.new.hair_colors = [:brown] # => NoMethodError
|
179
181
|
# Person.new.hair_colors # => NoMethodError
|
180
182
|
#
|
181
|
-
# Or pass <tt>instance_accessor: false</tt>, to
|
183
|
+
# Or pass <tt>instance_accessor: false</tt>, to omit both instance methods.
|
182
184
|
#
|
183
185
|
# module HairColors
|
184
186
|
# mattr_accessor :hair_colors, instance_accessor: false
|
@@ -191,22 +193,20 @@ class Module
|
|
191
193
|
# Person.new.hair_colors = [:brown] # => NoMethodError
|
192
194
|
# Person.new.hair_colors # => NoMethodError
|
193
195
|
#
|
194
|
-
#
|
196
|
+
# You can set a default value for the attribute.
|
195
197
|
#
|
196
198
|
# module HairColors
|
197
|
-
# mattr_accessor :hair_colors
|
198
|
-
# [:brown, :black, :blonde, :red]
|
199
|
-
# end
|
199
|
+
# mattr_accessor :hair_colors, default: [:brown, :black, :blonde, :red]
|
200
200
|
# end
|
201
201
|
#
|
202
202
|
# class Person
|
203
203
|
# include HairColors
|
204
204
|
# end
|
205
205
|
#
|
206
|
-
# Person.class_variable_get("@@hair_colors")
|
207
|
-
def mattr_accessor(*syms, &blk)
|
208
|
-
mattr_reader(*syms, &blk)
|
209
|
-
mattr_writer(*syms,
|
206
|
+
# Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
|
207
|
+
def mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil, &blk)
|
208
|
+
mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor, default: default, &blk)
|
209
|
+
mattr_writer(*syms, instance_writer: instance_writer, instance_accessor: instance_accessor, default: default)
|
210
210
|
end
|
211
211
|
alias :cattr_accessor :mattr_accessor
|
212
212
|
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Extends the module object with class/module and instance accessors for
|
4
|
+
# class/module attributes, just like the native attr* accessors for instance
|
5
|
+
# attributes, but does so on a per-thread basis.
|
6
|
+
#
|
7
|
+
# So the values are scoped within the Thread.current space under the class name
|
8
|
+
# of the module.
|
9
|
+
class Module
|
10
|
+
# Defines a per-thread class attribute and creates class and instance reader methods.
|
11
|
+
# The underlying per-thread class variable is set to +nil+, if it is not previously defined.
|
12
|
+
#
|
13
|
+
# module Current
|
14
|
+
# thread_mattr_reader :user
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# Current.user # => nil
|
18
|
+
# Thread.current[:attr_Current_user] = "DHH"
|
19
|
+
# Current.user # => "DHH"
|
20
|
+
#
|
21
|
+
# The attribute name must be a valid method name in Ruby.
|
22
|
+
#
|
23
|
+
# module Foo
|
24
|
+
# thread_mattr_reader :"1_Badname"
|
25
|
+
# end
|
26
|
+
# # => NameError: invalid attribute name: 1_Badname
|
27
|
+
#
|
28
|
+
# To omit the instance reader method, pass
|
29
|
+
# <tt>instance_reader: false</tt> or <tt>instance_accessor: false</tt>.
|
30
|
+
#
|
31
|
+
# class Current
|
32
|
+
# thread_mattr_reader :user, instance_reader: false
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# Current.new.user # => NoMethodError
|
36
|
+
def thread_mattr_reader(*syms, instance_reader: true, instance_accessor: true) # :nodoc:
|
37
|
+
syms.each do |sym|
|
38
|
+
raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
|
39
|
+
|
40
|
+
# The following generated method concatenates `name` because we want it
|
41
|
+
# to work with inheritance via polymorphism.
|
42
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
43
|
+
def self.#{sym}
|
44
|
+
Thread.current["attr_" + name + "_#{sym}"]
|
45
|
+
end
|
46
|
+
EOS
|
47
|
+
|
48
|
+
if instance_reader && instance_accessor
|
49
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
50
|
+
def #{sym}
|
51
|
+
self.class.#{sym}
|
52
|
+
end
|
53
|
+
EOS
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
alias :thread_cattr_reader :thread_mattr_reader
|
58
|
+
|
59
|
+
# Defines a per-thread class attribute and creates a class and instance writer methods to
|
60
|
+
# allow assignment to the attribute.
|
61
|
+
#
|
62
|
+
# module Current
|
63
|
+
# thread_mattr_writer :user
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# Current.user = "DHH"
|
67
|
+
# Thread.current[:attr_Current_user] # => "DHH"
|
68
|
+
#
|
69
|
+
# To omit the instance writer method, pass
|
70
|
+
# <tt>instance_writer: false</tt> or <tt>instance_accessor: false</tt>.
|
71
|
+
#
|
72
|
+
# class Current
|
73
|
+
# thread_mattr_writer :user, instance_writer: false
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
# Current.new.user = "DHH" # => NoMethodError
|
77
|
+
def thread_mattr_writer(*syms, instance_writer: true, instance_accessor: true) # :nodoc:
|
78
|
+
syms.each do |sym|
|
79
|
+
raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
|
80
|
+
|
81
|
+
# The following generated method concatenates `name` because we want it
|
82
|
+
# to work with inheritance via polymorphism.
|
83
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
84
|
+
def self.#{sym}=(obj)
|
85
|
+
Thread.current["attr_" + name + "_#{sym}"] = obj
|
86
|
+
end
|
87
|
+
EOS
|
88
|
+
|
89
|
+
if instance_writer && instance_accessor
|
90
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
91
|
+
def #{sym}=(obj)
|
92
|
+
self.class.#{sym} = obj
|
93
|
+
end
|
94
|
+
EOS
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
alias :thread_cattr_writer :thread_mattr_writer
|
99
|
+
|
100
|
+
# Defines both class and instance accessors for class attributes.
|
101
|
+
#
|
102
|
+
# class Account
|
103
|
+
# thread_mattr_accessor :user
|
104
|
+
# end
|
105
|
+
#
|
106
|
+
# Account.user = "DHH"
|
107
|
+
# Account.user # => "DHH"
|
108
|
+
# Account.new.user # => "DHH"
|
109
|
+
#
|
110
|
+
# If a subclass changes the value, the parent class' value is not changed.
|
111
|
+
# Similarly, if the parent class changes the value, the value of subclasses
|
112
|
+
# is not changed.
|
113
|
+
#
|
114
|
+
# class Customer < Account
|
115
|
+
# end
|
116
|
+
#
|
117
|
+
# Customer.user = "Rafael"
|
118
|
+
# Customer.user # => "Rafael"
|
119
|
+
# Account.user # => "DHH"
|
120
|
+
#
|
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
|
+
#
|
124
|
+
# class Current
|
125
|
+
# thread_mattr_accessor :user, instance_writer: false, instance_reader: false
|
126
|
+
# end
|
127
|
+
#
|
128
|
+
# Current.new.user = "DHH" # => NoMethodError
|
129
|
+
# Current.new.user # => NoMethodError
|
130
|
+
#
|
131
|
+
# Or pass <tt>instance_accessor: false</tt>, to omit both instance methods.
|
132
|
+
#
|
133
|
+
# class Current
|
134
|
+
# thread_mattr_accessor :user, instance_accessor: false
|
135
|
+
# end
|
136
|
+
#
|
137
|
+
# Current.new.user = "DHH" # => NoMethodError
|
138
|
+
# Current.new.user # => NoMethodError
|
139
|
+
def thread_mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true)
|
140
|
+
thread_mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor)
|
141
|
+
thread_mattr_writer(*syms, instance_writer: instance_writer, instance_accessor: instance_accessor)
|
142
|
+
end
|
143
|
+
alias :thread_cattr_accessor :thread_mattr_accessor
|
144
|
+
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/concern"
|
2
4
|
|
3
5
|
class Module
|
4
6
|
# = Bite-sized separation of concerns
|
@@ -20,7 +22,7 @@ class Module
|
|
20
22
|
#
|
21
23
|
# == Using comments:
|
22
24
|
#
|
23
|
-
# class Todo
|
25
|
+
# class Todo < ApplicationRecord
|
24
26
|
# # Other todo implementation
|
25
27
|
# # ...
|
26
28
|
#
|
@@ -28,7 +30,6 @@ class Module
|
|
28
30
|
# has_many :events
|
29
31
|
#
|
30
32
|
# before_create :track_creation
|
31
|
-
# after_destroy :track_deletion
|
32
33
|
#
|
33
34
|
# private
|
34
35
|
# def track_creation
|
@@ -40,7 +41,7 @@ class Module
|
|
40
41
|
#
|
41
42
|
# Noisy syntax.
|
42
43
|
#
|
43
|
-
# class Todo
|
44
|
+
# class Todo < ApplicationRecord
|
44
45
|
# # Other todo implementation
|
45
46
|
# # ...
|
46
47
|
#
|
@@ -50,7 +51,6 @@ class Module
|
|
50
51
|
# included do
|
51
52
|
# has_many :events
|
52
53
|
# before_create :track_creation
|
53
|
-
# after_destroy :track_deletion
|
54
54
|
# end
|
55
55
|
#
|
56
56
|
# private
|
@@ -63,12 +63,12 @@ class Module
|
|
63
63
|
#
|
64
64
|
# == Mix-in noise exiled to its own file:
|
65
65
|
#
|
66
|
-
# Once our chunk of behavior starts pushing the scroll-to-understand
|
66
|
+
# Once our chunk of behavior starts pushing the scroll-to-understand-it
|
67
67
|
# boundary, we give in and move it to a separate file. At this size, the
|
68
|
-
# overhead
|
69
|
-
#
|
68
|
+
# increased overhead can be a reasonable tradeoff even if it reduces our
|
69
|
+
# at-a-glance perception of how things work.
|
70
70
|
#
|
71
|
-
# class Todo
|
71
|
+
# class Todo < ApplicationRecord
|
72
72
|
# # Other todo implementation
|
73
73
|
# # ...
|
74
74
|
#
|
@@ -80,7 +80,7 @@ class Module
|
|
80
80
|
# By quieting the mix-in noise, we arrive at a natural, low-ceremony way to
|
81
81
|
# separate bite-sized concerns.
|
82
82
|
#
|
83
|
-
# class Todo
|
83
|
+
# class Todo < ApplicationRecord
|
84
84
|
# # Other todo implementation
|
85
85
|
# # ...
|
86
86
|
#
|
@@ -88,7 +88,6 @@ class Module
|
|
88
88
|
# included do
|
89
89
|
# has_many :events
|
90
90
|
# before_create :track_creation
|
91
|
-
# after_destroy :track_deletion
|
92
91
|
# end
|
93
92
|
#
|
94
93
|
# private
|
@@ -99,7 +98,7 @@ class Module
|
|
99
98
|
# end
|
100
99
|
#
|
101
100
|
# Todo.ancestors
|
102
|
-
# # => Todo, Todo::EventTracking, Object
|
101
|
+
# # => [Todo, Todo::EventTracking, ApplicationRecord, Object]
|
103
102
|
#
|
104
103
|
# This small step has some wonderful ripple effects. We can
|
105
104
|
# * grok the behavior of our class in one glance,
|