activesupport 7.0.4 → 7.1.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (187) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +996 -232
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -6
  5. data/lib/active_support/actionable_error.rb +3 -1
  6. data/lib/active_support/array_inquirer.rb +2 -0
  7. data/lib/active_support/backtrace_cleaner.rb +25 -5
  8. data/lib/active_support/benchmarkable.rb +1 -0
  9. data/lib/active_support/broadcast_logger.rb +250 -0
  10. data/lib/active_support/builder.rb +1 -1
  11. data/lib/active_support/cache/coder.rb +153 -0
  12. data/lib/active_support/cache/entry.rb +134 -0
  13. data/lib/active_support/cache/file_store.rb +37 -10
  14. data/lib/active_support/cache/mem_cache_store.rb +100 -76
  15. data/lib/active_support/cache/memory_store.rb +78 -24
  16. data/lib/active_support/cache/null_store.rb +6 -0
  17. data/lib/active_support/cache/redis_cache_store.rb +153 -141
  18. data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
  19. data/lib/active_support/cache/strategy/local_cache.rb +29 -14
  20. data/lib/active_support/cache.rb +331 -252
  21. data/lib/active_support/callbacks.rb +44 -21
  22. data/lib/active_support/concern.rb +4 -2
  23. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +42 -3
  24. data/lib/active_support/concurrency/null_lock.rb +13 -0
  25. data/lib/active_support/configurable.rb +10 -0
  26. data/lib/active_support/core_ext/array/conversions.rb +2 -1
  27. data/lib/active_support/core_ext/array.rb +0 -1
  28. data/lib/active_support/core_ext/class/subclasses.rb +13 -10
  29. data/lib/active_support/core_ext/date/calculations.rb +15 -0
  30. data/lib/active_support/core_ext/date/conversions.rb +2 -1
  31. data/lib/active_support/core_ext/date.rb +0 -1
  32. data/lib/active_support/core_ext/date_and_time/calculations.rb +10 -0
  33. data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
  34. data/lib/active_support/core_ext/date_time/conversions.rb +6 -2
  35. data/lib/active_support/core_ext/date_time.rb +0 -1
  36. data/lib/active_support/core_ext/digest/uuid.rb +1 -10
  37. data/lib/active_support/core_ext/enumerable.rb +8 -75
  38. data/lib/active_support/core_ext/erb/util.rb +196 -0
  39. data/lib/active_support/core_ext/hash/conversions.rb +1 -1
  40. data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
  41. data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
  42. data/lib/active_support/core_ext/hash/keys.rb +3 -3
  43. data/lib/active_support/core_ext/integer/inflections.rb +12 -12
  44. data/lib/active_support/core_ext/module/attribute_accessors.rb +6 -0
  45. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +34 -16
  46. data/lib/active_support/core_ext/module/concerning.rb +6 -6
  47. data/lib/active_support/core_ext/module/delegation.rb +40 -11
  48. data/lib/active_support/core_ext/module/deprecation.rb +15 -12
  49. data/lib/active_support/core_ext/module/introspection.rb +0 -1
  50. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  51. data/lib/active_support/core_ext/numeric/conversions.rb +2 -0
  52. data/lib/active_support/core_ext/numeric.rb +0 -1
  53. data/lib/active_support/core_ext/object/deep_dup.rb +16 -0
  54. data/lib/active_support/core_ext/object/duplicable.rb +5 -5
  55. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  56. data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
  57. data/lib/active_support/core_ext/object/json.rb +11 -3
  58. data/lib/active_support/core_ext/object/to_query.rb +0 -2
  59. data/lib/active_support/core_ext/object/with.rb +44 -0
  60. data/lib/active_support/core_ext/object/with_options.rb +9 -9
  61. data/lib/active_support/core_ext/object.rb +1 -0
  62. data/lib/active_support/core_ext/pathname/blank.rb +16 -0
  63. data/lib/active_support/core_ext/pathname/existence.rb +2 -0
  64. data/lib/active_support/core_ext/pathname.rb +1 -0
  65. data/lib/active_support/core_ext/range/conversions.rb +28 -7
  66. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  67. data/lib/active_support/core_ext/range.rb +1 -2
  68. data/lib/active_support/core_ext/securerandom.rb +24 -12
  69. data/lib/active_support/core_ext/string/filters.rb +20 -14
  70. data/lib/active_support/core_ext/string/indent.rb +1 -1
  71. data/lib/active_support/core_ext/string/inflections.rb +16 -9
  72. data/lib/active_support/core_ext/string/output_safety.rb +42 -174
  73. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  74. data/lib/active_support/core_ext/time/calculations.rb +22 -2
  75. data/lib/active_support/core_ext/time/conversions.rb +2 -2
  76. data/lib/active_support/core_ext/time/zones.rb +7 -8
  77. data/lib/active_support/core_ext/time.rb +0 -1
  78. data/lib/active_support/current_attributes.rb +15 -6
  79. data/lib/active_support/deep_mergeable.rb +53 -0
  80. data/lib/active_support/dependencies/autoload.rb +17 -12
  81. data/lib/active_support/deprecation/behaviors.rb +65 -42
  82. data/lib/active_support/deprecation/constant_accessor.rb +5 -4
  83. data/lib/active_support/deprecation/deprecators.rb +104 -0
  84. data/lib/active_support/deprecation/disallowed.rb +6 -8
  85. data/lib/active_support/deprecation/instance_delegator.rb +31 -4
  86. data/lib/active_support/deprecation/method_wrappers.rb +6 -23
  87. data/lib/active_support/deprecation/proxy_wrappers.rb +37 -22
  88. data/lib/active_support/deprecation/reporting.rb +42 -25
  89. data/lib/active_support/deprecation.rb +32 -5
  90. data/lib/active_support/deprecator.rb +7 -0
  91. data/lib/active_support/descendants_tracker.rb +104 -132
  92. data/lib/active_support/duration/iso8601_serializer.rb +0 -2
  93. data/lib/active_support/duration.rb +2 -1
  94. data/lib/active_support/encrypted_configuration.rb +63 -11
  95. data/lib/active_support/encrypted_file.rb +16 -12
  96. data/lib/active_support/environment_inquirer.rb +22 -2
  97. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  98. data/lib/active_support/error_reporter.rb +121 -35
  99. data/lib/active_support/evented_file_update_checker.rb +17 -2
  100. data/lib/active_support/execution_wrapper.rb +4 -4
  101. data/lib/active_support/file_update_checker.rb +4 -2
  102. data/lib/active_support/fork_tracker.rb +10 -2
  103. data/lib/active_support/gem_version.rb +4 -4
  104. data/lib/active_support/gzip.rb +2 -0
  105. data/lib/active_support/hash_with_indifferent_access.rb +35 -17
  106. data/lib/active_support/html_safe_translation.rb +12 -2
  107. data/lib/active_support/i18n.rb +1 -1
  108. data/lib/active_support/i18n_railtie.rb +20 -13
  109. data/lib/active_support/inflector/inflections.rb +2 -0
  110. data/lib/active_support/inflector/methods.rb +28 -18
  111. data/lib/active_support/inflector/transliterate.rb +3 -1
  112. data/lib/active_support/isolated_execution_state.rb +26 -22
  113. data/lib/active_support/json/decoding.rb +2 -1
  114. data/lib/active_support/json/encoding.rb +25 -43
  115. data/lib/active_support/key_generator.rb +9 -1
  116. data/lib/active_support/lazy_load_hooks.rb +7 -5
  117. data/lib/active_support/locale/en.yml +2 -0
  118. data/lib/active_support/log_subscriber.rb +84 -33
  119. data/lib/active_support/logger.rb +9 -60
  120. data/lib/active_support/logger_thread_safe_level.rb +10 -24
  121. data/lib/active_support/message_encryptor.rb +197 -53
  122. data/lib/active_support/message_encryptors.rb +141 -0
  123. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  124. data/lib/active_support/message_pack/extensions.rb +292 -0
  125. data/lib/active_support/message_pack/serializer.rb +63 -0
  126. data/lib/active_support/message_pack.rb +50 -0
  127. data/lib/active_support/message_verifier.rb +212 -93
  128. data/lib/active_support/message_verifiers.rb +135 -0
  129. data/lib/active_support/messages/codec.rb +65 -0
  130. data/lib/active_support/messages/metadata.rb +111 -45
  131. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  132. data/lib/active_support/messages/rotator.rb +34 -32
  133. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  134. data/lib/active_support/multibyte/chars.rb +2 -0
  135. data/lib/active_support/multibyte/unicode.rb +9 -37
  136. data/lib/active_support/notifications/fanout.rb +245 -81
  137. data/lib/active_support/notifications/instrumenter.rb +77 -20
  138. data/lib/active_support/notifications.rb +3 -3
  139. data/lib/active_support/number_helper/number_converter.rb +14 -5
  140. data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -6
  141. data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -3
  142. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
  143. data/lib/active_support/number_helper.rb +379 -317
  144. data/lib/active_support/ordered_hash.rb +3 -3
  145. data/lib/active_support/ordered_options.rb +14 -0
  146. data/lib/active_support/parameter_filter.rb +103 -84
  147. data/lib/active_support/proxy_object.rb +2 -0
  148. data/lib/active_support/railtie.rb +33 -21
  149. data/lib/active_support/reloader.rb +12 -4
  150. data/lib/active_support/rescuable.rb +2 -0
  151. data/lib/active_support/secure_compare_rotator.rb +16 -9
  152. data/lib/active_support/string_inquirer.rb +3 -1
  153. data/lib/active_support/subscriber.rb +9 -27
  154. data/lib/active_support/syntax_error_proxy.rb +70 -0
  155. data/lib/active_support/tagged_logging.rb +60 -24
  156. data/lib/active_support/test_case.rb +153 -6
  157. data/lib/active_support/testing/assertions.rb +26 -10
  158. data/lib/active_support/testing/autorun.rb +0 -2
  159. data/lib/active_support/testing/constant_stubbing.rb +32 -0
  160. data/lib/active_support/testing/deprecation.rb +25 -25
  161. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  162. data/lib/active_support/testing/isolation.rb +29 -28
  163. data/lib/active_support/testing/method_call_assertions.rb +21 -8
  164. data/lib/active_support/testing/parallelize_executor.rb +8 -3
  165. data/lib/active_support/testing/stream.rb +1 -1
  166. data/lib/active_support/testing/strict_warnings.rb +39 -0
  167. data/lib/active_support/testing/time_helpers.rb +37 -15
  168. data/lib/active_support/time_with_zone.rb +8 -37
  169. data/lib/active_support/values/time_zone.rb +9 -7
  170. data/lib/active_support/version.rb +1 -1
  171. data/lib/active_support/xml_mini/jdom.rb +3 -10
  172. data/lib/active_support/xml_mini/nokogiri.rb +1 -1
  173. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  174. data/lib/active_support/xml_mini/rexml.rb +1 -1
  175. data/lib/active_support/xml_mini.rb +2 -2
  176. data/lib/active_support.rb +14 -3
  177. metadata +103 -16
  178. data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
  179. data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -26
  180. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -22
  181. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
  182. data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -26
  183. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -7
  184. data/lib/active_support/core_ext/range/overlaps.rb +0 -10
  185. data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -22
  186. data/lib/active_support/core_ext/uri.rb +0 -5
  187. data/lib/active_support/per_thread_registry.rb +0 -65
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/messages/rotation_coordinator"
4
+
5
+ module ActiveSupport
6
+ class MessageEncryptors < Messages::RotationCoordinator
7
+ ##
8
+ # :attr_accessor: transitional
9
+ #
10
+ # If true, the first two rotation option sets are swapped when building
11
+ # message encryptors. For example, with the following configuration, message
12
+ # encryptors will encrypt messages using <tt>serializer: Marshal, url_safe: true</tt>,
13
+ # and will able to decrypt messages that were encrypted using any of the
14
+ # three option sets:
15
+ #
16
+ # encryptors = ActiveSupport::MessageEncryptors.new { ... }
17
+ # encryptors.rotate(serializer: JSON, url_safe: true)
18
+ # encryptors.rotate(serializer: Marshal, url_safe: true)
19
+ # encryptors.rotate(serializer: Marshal, url_safe: false)
20
+ # encryptors.transitional = true
21
+ #
22
+ # This can be useful when performing a rolling deploy of an application,
23
+ # wherein servers that have not yet been updated must still be able to
24
+ # decrypt messages from updated servers. In such a scenario, first perform a
25
+ # rolling deploy with the new rotation (e.g. <tt>serializer: JSON, url_safe: true</tt>)
26
+ # as the first rotation and <tt>transitional = true</tt>. Then, after all
27
+ # servers have been updated, perform a second rolling deploy with
28
+ # <tt>transitional = false</tt>.
29
+
30
+ ##
31
+ # :method: initialize
32
+ # :call-seq: initialize(&secret_generator)
33
+ #
34
+ # Initializes a new instance. +secret_generator+ must accept a salt and a
35
+ # +secret_length+ kwarg, and return a suitable secret (string) or secrets
36
+ # (array of strings). +secret_generator+ may also accept other arbitrary
37
+ # kwargs. If #rotate is called with any options matching those kwargs, those
38
+ # options will be passed to +secret_generator+ instead of to the message
39
+ # encryptor.
40
+ #
41
+ # encryptors = ActiveSupport::MessageEncryptors.new do |salt, secret_length:, base:|
42
+ # MySecretGenerator.new(base).generate(salt, secret_length)
43
+ # end
44
+ #
45
+ # encryptors.rotate(base: "...")
46
+
47
+ ##
48
+ # :method: []
49
+ # :call-seq: [](salt)
50
+ #
51
+ # Returns a MessageEncryptor configured with a secret derived from the
52
+ # given +salt+, and options from #rotate. MessageEncryptor instances will
53
+ # be memoized, so the same +salt+ will return the same instance.
54
+
55
+ ##
56
+ # :method: []=
57
+ # :call-seq: []=(salt, encryptor)
58
+ #
59
+ # Overrides a MessageEncryptor instance associated with a given +salt+.
60
+
61
+ ##
62
+ # :method: rotate
63
+ # :call-seq:
64
+ # rotate(**options)
65
+ # rotate(&block)
66
+ #
67
+ # Adds +options+ to the list of option sets. Messages will be encrypted
68
+ # using the first set in the list. When decrypting, however, each set will
69
+ # be tried, in order, until one succeeds.
70
+ #
71
+ # Notably, the +:secret_generator+ option can specify a different secret
72
+ # generator than the one initially specified. The secret generator must
73
+ # respond to +call+, accept a salt and a +secret_length+ kwarg, and return
74
+ # a suitable secret (string) or secrets (array of strings). The secret
75
+ # generator may also accept other arbitrary kwargs.
76
+ #
77
+ # If any options match the kwargs of the operative secret generator, those
78
+ # options will be passed to the secret generator instead of to the message
79
+ # encryptor.
80
+ #
81
+ # For fine-grained per-salt rotations, a block form is supported. The block
82
+ # will receive the salt, and should return an appropriate options Hash. The
83
+ # block may also return +nil+ to indicate that the rotation does not apply
84
+ # to the given salt. For example:
85
+ #
86
+ # encryptors = ActiveSupport::MessageEncryptors.new { ... }
87
+ #
88
+ # encryptors.rotate do |salt|
89
+ # case salt
90
+ # when :foo
91
+ # { serializer: JSON, url_safe: true }
92
+ # when :bar
93
+ # { serializer: Marshal, url_safe: true }
94
+ # end
95
+ # end
96
+ #
97
+ # encryptors.rotate(serializer: Marshal, url_safe: false)
98
+ #
99
+ # # Uses `serializer: JSON, url_safe: true`.
100
+ # # Falls back to `serializer: Marshal, url_safe: false`.
101
+ # encryptors[:foo]
102
+ #
103
+ # # Uses `serializer: Marshal, url_safe: true`.
104
+ # # Falls back to `serializer: Marshal, url_safe: false`.
105
+ # encryptors[:bar]
106
+ #
107
+ # # Uses `serializer: Marshal, url_safe: false`.
108
+ # encryptors[:baz]
109
+
110
+ ##
111
+ # :method: rotate_defaults
112
+ # :call-seq: rotate_defaults
113
+ #
114
+ # Invokes #rotate with the default options.
115
+
116
+ ##
117
+ # :method: clear_rotations
118
+ # :call-seq: clear_rotations
119
+ #
120
+ # Clears the list of option sets.
121
+
122
+ ##
123
+ # :method: on_rotation
124
+ # :call-seq: on_rotation(&callback)
125
+ #
126
+ # Sets a callback to invoke when a message is decrypted using an option set
127
+ # other than the first.
128
+ #
129
+ # For example, this callback could log each time it is called, and thus
130
+ # indicate whether old option sets are still in use or can be removed from
131
+ # rotation.
132
+
133
+ ##
134
+ private
135
+ def build(salt, secret_generator:, secret_generator_options:, **options)
136
+ secret_length = MessageEncryptor.key_len(*options[:cipher])
137
+ secret = secret_generator.call(salt, secret_length: secret_length, **secret_generator_options)
138
+ MessageEncryptor.new(*Array(secret), **options)
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "serializer"
4
+
5
+ module ActiveSupport
6
+ module MessagePack
7
+ module CacheSerializer
8
+ include Serializer
9
+ extend self
10
+
11
+ def load(dumped)
12
+ super
13
+ rescue ActiveSupport::MessagePack::MissingClassError
14
+ # Treat missing class as cache miss => return nil
15
+ end
16
+
17
+ private
18
+ def install_unregistered_type_handler
19
+ Extensions.install_unregistered_type_fallback(message_pack_factory)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,292 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bigdecimal"
4
+ require "date"
5
+ require "ipaddr"
6
+ require "pathname"
7
+ require "uri/generic"
8
+ require "msgpack/bigint"
9
+ require "active_support/hash_with_indifferent_access"
10
+ require "active_support/time"
11
+
12
+ module ActiveSupport
13
+ module MessagePack
14
+ class UnserializableObjectError < StandardError; end
15
+ class MissingClassError < StandardError; end # :nodoc:
16
+
17
+ module Extensions # :nodoc:
18
+ extend self
19
+
20
+ def install(registry)
21
+ registry.register_type 0, Symbol,
22
+ packer: :to_msgpack_ext,
23
+ unpacker: :from_msgpack_ext,
24
+ optimized_symbols_parsing: true
25
+
26
+ registry.register_type 1, Integer,
27
+ packer: ::MessagePack::Bigint.method(:to_msgpack_ext),
28
+ unpacker: ::MessagePack::Bigint.method(:from_msgpack_ext),
29
+ oversized_integer_extension: true
30
+
31
+ registry.register_type 2, BigDecimal,
32
+ packer: :_dump,
33
+ unpacker: :_load
34
+
35
+ registry.register_type 3, Rational,
36
+ packer: method(:write_rational),
37
+ unpacker: method(:read_rational),
38
+ recursive: true
39
+
40
+ registry.register_type 4, Complex,
41
+ packer: method(:write_complex),
42
+ unpacker: method(:read_complex),
43
+ recursive: true
44
+
45
+ registry.register_type 5, DateTime,
46
+ packer: method(:write_datetime),
47
+ unpacker: method(:read_datetime),
48
+ recursive: true
49
+
50
+ registry.register_type 6, Date,
51
+ packer: method(:write_date),
52
+ unpacker: method(:read_date),
53
+ recursive: true
54
+
55
+ registry.register_type 7, Time,
56
+ packer: method(:write_time),
57
+ unpacker: method(:read_time),
58
+ recursive: true
59
+
60
+ registry.register_type 8, ActiveSupport::TimeWithZone,
61
+ packer: method(:write_time_with_zone),
62
+ unpacker: method(:read_time_with_zone),
63
+ recursive: true
64
+
65
+ registry.register_type 9, ActiveSupport::TimeZone,
66
+ packer: method(:dump_time_zone),
67
+ unpacker: method(:load_time_zone)
68
+
69
+ registry.register_type 10, ActiveSupport::Duration,
70
+ packer: method(:write_duration),
71
+ unpacker: method(:read_duration),
72
+ recursive: true
73
+
74
+ registry.register_type 11, Range,
75
+ packer: method(:write_range),
76
+ unpacker: method(:read_range),
77
+ recursive: true
78
+
79
+ registry.register_type 12, Set,
80
+ packer: method(:write_set),
81
+ unpacker: method(:read_set),
82
+ recursive: true
83
+
84
+ registry.register_type 13, URI::Generic,
85
+ packer: :to_s,
86
+ unpacker: URI.method(:parse)
87
+
88
+ registry.register_type 14, IPAddr,
89
+ packer: :to_s,
90
+ unpacker: :new
91
+
92
+ registry.register_type 15, Pathname,
93
+ packer: :to_s,
94
+ unpacker: :new
95
+
96
+ registry.register_type 16, Regexp,
97
+ packer: :to_s,
98
+ unpacker: :new
99
+
100
+ registry.register_type 17, ActiveSupport::HashWithIndifferentAccess,
101
+ packer: method(:write_hash_with_indifferent_access),
102
+ unpacker: method(:read_hash_with_indifferent_access),
103
+ recursive: true
104
+ end
105
+
106
+ def install_unregistered_type_error(registry)
107
+ registry.register_type 127, Object,
108
+ packer: method(:raise_unserializable),
109
+ unpacker: method(:raise_invalid_format)
110
+ end
111
+
112
+ def install_unregistered_type_fallback(registry)
113
+ registry.register_type 127, Object,
114
+ packer: method(:write_object),
115
+ unpacker: method(:read_object),
116
+ recursive: true
117
+ end
118
+
119
+ def write_rational(rational, packer)
120
+ packer.write(rational.numerator)
121
+ packer.write(rational.denominator) unless rational.numerator.zero?
122
+ end
123
+
124
+ def read_rational(unpacker)
125
+ numerator = unpacker.read
126
+ Rational(numerator, numerator.zero? ? 1 : unpacker.read)
127
+ end
128
+
129
+ def write_complex(complex, packer)
130
+ packer.write(complex.real)
131
+ packer.write(complex.imaginary)
132
+ end
133
+
134
+ def read_complex(unpacker)
135
+ Complex(unpacker.read, unpacker.read)
136
+ end
137
+
138
+ def write_datetime(datetime, packer)
139
+ packer.write(datetime.jd)
140
+ packer.write(datetime.hour)
141
+ packer.write(datetime.min)
142
+ packer.write(datetime.sec)
143
+ write_rational(datetime.sec_fraction, packer)
144
+ write_rational(datetime.offset, packer)
145
+ end
146
+
147
+ def read_datetime(unpacker)
148
+ DateTime.jd(unpacker.read, unpacker.read, unpacker.read, unpacker.read + read_rational(unpacker), read_rational(unpacker))
149
+ end
150
+
151
+ def write_date(date, packer)
152
+ packer.write(date.jd)
153
+ end
154
+
155
+ def read_date(unpacker)
156
+ Date.jd(unpacker.read)
157
+ end
158
+
159
+ def write_time(time, packer)
160
+ packer.write(time.tv_sec)
161
+ packer.write(time.tv_nsec)
162
+ packer.write(time.utc_offset)
163
+ end
164
+
165
+ def read_time(unpacker)
166
+ Time.at_without_coercion(unpacker.read, unpacker.read, :nanosecond, in: unpacker.read)
167
+ end
168
+
169
+ def write_time_with_zone(twz, packer)
170
+ write_time(twz.utc, packer)
171
+ write_time_zone(twz.time_zone, packer)
172
+ end
173
+
174
+ def read_time_with_zone(unpacker)
175
+ ActiveSupport::TimeWithZone.new(read_time(unpacker), read_time_zone(unpacker))
176
+ end
177
+
178
+ def dump_time_zone(time_zone)
179
+ time_zone.name
180
+ end
181
+
182
+ def load_time_zone(name)
183
+ ActiveSupport::TimeZone[name]
184
+ end
185
+
186
+ def write_time_zone(time_zone, packer)
187
+ packer.write(dump_time_zone(time_zone))
188
+ end
189
+
190
+ def read_time_zone(unpacker)
191
+ load_time_zone(unpacker.read)
192
+ end
193
+
194
+ def write_duration(duration, packer)
195
+ packer.write(duration.value)
196
+ packer.write(duration._parts.values_at(*ActiveSupport::Duration::PARTS))
197
+ end
198
+
199
+ def read_duration(unpacker)
200
+ value = unpacker.read
201
+ parts = ActiveSupport::Duration::PARTS.zip(unpacker.read).to_h
202
+ parts.compact!
203
+ ActiveSupport::Duration.new(value, parts)
204
+ end
205
+
206
+ def write_range(range, packer)
207
+ packer.write(range.begin)
208
+ packer.write(range.end)
209
+ packer.write(range.exclude_end?)
210
+ end
211
+
212
+ def read_range(unpacker)
213
+ Range.new(unpacker.read, unpacker.read, unpacker.read)
214
+ end
215
+
216
+ def write_set(set, packer)
217
+ packer.write(set.to_a)
218
+ end
219
+
220
+ def read_set(unpacker)
221
+ Set.new(unpacker.read)
222
+ end
223
+
224
+ def write_hash_with_indifferent_access(hwia, packer)
225
+ packer.write(hwia.to_h)
226
+ end
227
+
228
+ def read_hash_with_indifferent_access(unpacker)
229
+ ActiveSupport::HashWithIndifferentAccess.new(unpacker.read)
230
+ end
231
+
232
+ def raise_unserializable(object, *)
233
+ raise UnserializableObjectError, "Unsupported type #{object.class} for object #{object.inspect}"
234
+ end
235
+
236
+ def raise_invalid_format(*)
237
+ raise "Invalid format"
238
+ end
239
+
240
+ def dump_class(klass)
241
+ raise UnserializableObjectError, "Cannot serialize anonymous class" unless klass.name
242
+ klass.name
243
+ end
244
+
245
+ def load_class(name)
246
+ Object.const_get(name)
247
+ rescue NameError => error
248
+ if error.name.to_s == name
249
+ raise MissingClassError, "Missing class: #{name}"
250
+ else
251
+ raise
252
+ end
253
+ end
254
+
255
+ def write_class(klass, packer)
256
+ packer.write(dump_class(klass))
257
+ end
258
+
259
+ def read_class(unpacker)
260
+ load_class(unpacker.read)
261
+ end
262
+
263
+ LOAD_WITH_MSGPACK_EXT = 0
264
+ LOAD_WITH_JSON_CREATE = 1
265
+
266
+ def write_object(object, packer)
267
+ if object.class.respond_to?(:from_msgpack_ext)
268
+ packer.write(LOAD_WITH_MSGPACK_EXT)
269
+ write_class(object.class, packer)
270
+ packer.write(object.to_msgpack_ext)
271
+ elsif object.class.respond_to?(:json_create)
272
+ packer.write(LOAD_WITH_JSON_CREATE)
273
+ write_class(object.class, packer)
274
+ packer.write(object.as_json)
275
+ else
276
+ raise_unserializable(object)
277
+ end
278
+ end
279
+
280
+ def read_object(unpacker)
281
+ case unpacker.read
282
+ when LOAD_WITH_MSGPACK_EXT
283
+ read_class(unpacker).from_msgpack_ext(unpacker.read)
284
+ when LOAD_WITH_JSON_CREATE
285
+ read_class(unpacker).json_create(unpacker.read)
286
+ else
287
+ raise_invalid_format
288
+ end
289
+ end
290
+ end
291
+ end
292
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "extensions"
4
+
5
+ module ActiveSupport
6
+ module MessagePack
7
+ module Serializer # :nodoc:
8
+ SIGNATURE = "\xCC\x80".b.freeze # == 128.to_msgpack
9
+ SIGNATURE_INT = 128
10
+
11
+ def dump(object)
12
+ message_pack_pool.packer do |packer|
13
+ packer.write(SIGNATURE_INT)
14
+ packer.write(object)
15
+ packer.full_pack
16
+ end
17
+ end
18
+
19
+ def load(dumped)
20
+ message_pack_pool.unpacker do |unpacker|
21
+ unpacker.feed_reference(dumped)
22
+ raise "Invalid serialization format" unless unpacker.read == SIGNATURE_INT
23
+ unpacker.full_unpack
24
+ end
25
+ end
26
+
27
+ def signature?(dumped)
28
+ dumped.getbyte(0) == SIGNATURE.getbyte(0) && dumped.getbyte(1) == SIGNATURE.getbyte(1)
29
+ end
30
+
31
+ def message_pack_factory
32
+ @message_pack_factory ||= ::MessagePack::Factory.new
33
+ end
34
+
35
+ def message_pack_factory=(factory)
36
+ @message_pack_pool = nil
37
+ @message_pack_factory = factory
38
+ end
39
+
40
+ delegate :register_type, to: :message_pack_factory
41
+
42
+ def warmup
43
+ message_pack_pool # eagerly compute
44
+ end
45
+
46
+ private
47
+ def message_pack_pool
48
+ @message_pack_pool ||= begin
49
+ unless message_pack_factory.frozen?
50
+ Extensions.install(message_pack_factory)
51
+ install_unregistered_type_handler
52
+ message_pack_factory.freeze
53
+ end
54
+ message_pack_factory.pool(ENV.fetch("RAILS_MAX_THREADS", 5).to_i)
55
+ end
56
+ end
57
+
58
+ def install_unregistered_type_handler
59
+ Extensions.install_unregistered_type_error(message_pack_factory)
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ gem "msgpack", ">= 1.7.0"
5
+ require "msgpack"
6
+ rescue LoadError => error
7
+ warn "ActiveSupport::MessagePack requires the msgpack gem, version 1.7.0 or later. " \
8
+ "Please add it to your Gemfile: `gem \"msgpack\", \">= 1.7.0\"`"
9
+ raise error
10
+ end
11
+
12
+ require_relative "message_pack/cache_serializer"
13
+ require_relative "message_pack/serializer"
14
+
15
+ module ActiveSupport
16
+ module MessagePack
17
+ extend Serializer
18
+
19
+ ##
20
+ # :singleton-method: dump
21
+ # :call-seq: dump(object)
22
+ #
23
+ # Dumps an object. Raises ActiveSupport::MessagePack::UnserializableObjectError
24
+ # if the object type is not supported.
25
+ #
26
+ #--
27
+ # Implemented by Serializer#dump.
28
+
29
+ ##
30
+ # :singleton-method: load
31
+ # :call-seq: load(dumped)
32
+ #
33
+ # Loads an object dump created by ::dump.
34
+ #
35
+ #--
36
+ # Implemented by Serializer#load.
37
+
38
+ ##
39
+ # :singleton-method: signature?
40
+ # :call-seq: signature?(dumped)
41
+ #
42
+ # Returns true if the given dump begins with an +ActiveSupport::MessagePack+
43
+ # signature.
44
+ #
45
+ #--
46
+ # Implemented by Serializer#signature?.
47
+
48
+ ActiveSupport.run_load_hooks(:message_pack, self)
49
+ end
50
+ end