activesupport 4.2.11.1 → 5.2.8.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 +441 -399
- data/MIT-LICENSE +2 -2
- data/README.rdoc +4 -5
- data/lib/active_support/all.rb +5 -3
- data/lib/active_support/array_inquirer.rb +48 -0
- data/lib/active_support/backtrace_cleaner.rb +7 -5
- data/lib/active_support/benchmarkable.rb +6 -4
- data/lib/active_support/builder.rb +3 -1
- data/lib/active_support/cache/file_store.rb +41 -35
- data/lib/active_support/cache/mem_cache_store.rb +91 -91
- data/lib/active_support/cache/memory_store.rb +27 -30
- data/lib/active_support/cache/null_store.rb +7 -8
- data/lib/active_support/cache/redis_cache_store.rb +466 -0
- data/lib/active_support/cache/strategy/local_cache.rb +67 -34
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
- data/lib/active_support/cache.rb +287 -196
- data/lib/active_support/callbacks.rb +640 -590
- data/lib/active_support/concern.rb +11 -5
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
- data/lib/active_support/concurrency/share_lock.rb +227 -0
- data/lib/active_support/configurable.rb +8 -5
- data/lib/active_support/core_ext/array/access.rb +29 -1
- data/lib/active_support/core_ext/array/conversions.rb +22 -18
- 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 +5 -3
- 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 +41 -22
- 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 +11 -9
- 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 +170 -58
- 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 -12
- 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 +36 -18
- data/lib/active_support/core_ext/date_time/compatibility.rb +8 -6
- data/lib/active_support/core_ext/date_time/conversions.rb +16 -12
- 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 +101 -33
- 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 +14 -9
- 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/except.rb +11 -8
- data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -3
- data/lib/active_support/core_ext/hash/keys.rb +33 -27
- data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
- data/lib/active_support/core_ext/hash/slice.rb +8 -8
- data/lib/active_support/core_ext/hash/transform_values.rb +14 -5
- data/lib/active_support/core_ext/hash.rb +11 -9
- data/lib/active_support/core_ext/integer/inflections.rb +3 -1
- data/lib/active_support/core_ext/integer/multiple.rb +2 -0
- 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/agnostics.rb +2 -0
- 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 +6 -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 +43 -40
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +150 -0
- data/lib/active_support/core_ext/module/concerning.rb +11 -12
- data/lib/active_support/core_ext/module/delegation.rb +99 -29
- data/lib/active_support/core_ext/module/deprecation.rb +4 -2
- data/lib/active_support/core_ext/module/introspection.rb +9 -9
- data/lib/active_support/core_ext/module/reachable.rb +5 -2
- data/lib/active_support/core_ext/module/redefine_method.rb +49 -0
- data/lib/active_support/core_ext/module/remove_method.rb +8 -3
- data/lib/active_support/core_ext/module.rb +14 -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 +78 -81
- data/lib/active_support/core_ext/numeric/inquiry.rb +28 -0
- data/lib/active_support/core_ext/numeric/time.rb +35 -23
- data/lib/active_support/core_ext/numeric.rb +6 -3
- data/lib/active_support/core_ext/object/acts_like.rb +12 -1
- data/lib/active_support/core_ext/object/blank.rb +27 -2
- 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 +41 -14
- 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 +49 -19
- 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 +69 -21
- 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 +61 -0
- data/lib/active_support/core_ext/range/conversions.rb +27 -7
- data/lib/active_support/core_ext/range/each.rb +19 -17
- data/lib/active_support/core_ext/range/include_range.rb +2 -22
- 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 +6 -0
- data/lib/active_support/core_ext/securerandom.rb +25 -0
- data/lib/active_support/core_ext/string/access.rb +8 -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 +6 -5
- data/lib/active_support/core_ext/string/indent.rb +6 -4
- data/lib/active_support/core_ext/string/inflections.rb +61 -24
- data/lib/active_support/core_ext/string/inquiry.rb +3 -1
- data/lib/active_support/core_ext/string/multibyte.rb +15 -7
- data/lib/active_support/core_ext/string/output_safety.rb +62 -38
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -0
- data/lib/active_support/core_ext/string/strip.rb +4 -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 +85 -51
- 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 -8
- data/lib/active_support/core_ext.rb +3 -1
- data/lib/active_support/current_attributes.rb +195 -0
- data/lib/active_support/dependencies/autoload.rb +2 -0
- data/lib/active_support/dependencies/interlock.rb +57 -0
- data/lib/active_support/dependencies.rb +152 -161
- 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 +66 -20
- data/lib/active_support/deprecation/proxy_wrappers.rb +56 -28
- data/lib/active_support/deprecation/reporting.rb +32 -12
- data/lib/active_support/deprecation.rb +12 -9
- data/lib/active_support/descendants_tracker.rb +2 -0
- data/lib/active_support/digest.rb +20 -0
- data/lib/active_support/duration/iso8601_parser.rb +125 -0
- data/lib/active_support/duration/iso8601_serializer.rb +55 -0
- data/lib/active_support/duration.rb +314 -38
- data/lib/active_support/encrypted_configuration.rb +49 -0
- data/lib/active_support/encrypted_file.rb +99 -0
- data/lib/active_support/evented_file_update_checker.rb +205 -0
- data/lib/active_support/execution_wrapper.rb +131 -0
- data/lib/active_support/executor.rb +8 -0
- data/lib/active_support/file_update_checker.rb +63 -37
- data/lib/active_support/gem_version.rb +5 -3
- data/lib/active_support/gzip.rb +7 -5
- data/lib/active_support/hash_with_indifferent_access.rb +123 -28
- data/lib/active_support/i18n.rb +8 -6
- data/lib/active_support/i18n_railtie.rb +37 -13
- data/lib/active_support/inflections.rb +13 -11
- data/lib/active_support/inflector/inflections.rb +61 -12
- data/lib/active_support/inflector/methods.rb +163 -136
- data/lib/active_support/inflector/transliterate.rb +48 -27
- data/lib/active_support/inflector.rb +7 -5
- data/lib/active_support/json/decoding.rb +16 -13
- data/lib/active_support/json/encoding.rb +11 -58
- data/lib/active_support/json.rb +4 -2
- data/lib/active_support/key_generator.rb +25 -25
- data/lib/active_support/lazy_load_hooks.rb +50 -20
- 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 +13 -10
- data/lib/active_support/logger.rb +8 -7
- data/lib/active_support/logger_silence.rb +6 -4
- data/lib/active_support/logger_thread_safe_level.rb +7 -5
- data/lib/active_support/message_encryptor.rb +168 -53
- data/lib/active_support/message_verifier.rb +150 -17
- data/lib/active_support/messages/metadata.rb +71 -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 +36 -23
- data/lib/active_support/multibyte/unicode.rb +100 -96
- data/lib/active_support/multibyte.rb +4 -2
- data/lib/active_support/notifications/fanout.rb +11 -9
- data/lib/active_support/notifications/instrumenter.rb +27 -7
- data/lib/active_support/notifications.rb +11 -7
- data/lib/active_support/number_helper/number_converter.rb +13 -11
- data/lib/active_support/number_helper/number_to_currency_converter.rb +9 -9
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +9 -3
- data/lib/active_support/number_helper/number_to_human_converter.rb +11 -9
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +9 -8
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +13 -4
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +23 -56
- data/lib/active_support/number_helper/rounding_helper.rb +66 -0
- data/lib/active_support/number_helper.rb +94 -68
- data/lib/active_support/option_merger.rb +3 -1
- data/lib/active_support/ordered_hash.rb +6 -4
- data/lib/active_support/ordered_options.rb +23 -5
- 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 +16 -8
- data/lib/active_support/railtie.rb +43 -9
- data/lib/active_support/reloader.rb +131 -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 -3
- data/lib/active_support/subscriber.rb +21 -16
- data/lib/active_support/tagged_logging.rb +14 -11
- data/lib/active_support/test_case.rb +19 -47
- data/lib/active_support/testing/assertions.rb +137 -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 +14 -10
- data/lib/active_support/testing/file_fixtures.rb +36 -0
- data/lib/active_support/testing/isolation.rb +34 -25
- data/lib/active_support/testing/method_call_assertions.rb +43 -0
- data/lib/active_support/testing/setup_and_teardown.rb +13 -8
- data/lib/active_support/testing/stream.rb +44 -0
- data/lib/active_support/testing/tagged_logging.rb +3 -1
- data/lib/active_support/testing/time_helpers.rb +81 -15
- data/lib/active_support/time.rb +14 -12
- data/lib/active_support/time_with_zone.rb +169 -39
- data/lib/active_support/values/time_zone.rb +196 -61
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/version.rb +3 -1
- data/lib/active_support/xml_mini/jdom.rb +116 -114
- 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 +37 -37
- data/lib/active_support.rb +12 -11
- metadata +57 -27
- 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/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
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pathname"
|
4
|
+
require "active_support/message_encryptor"
|
5
|
+
|
6
|
+
module ActiveSupport
|
7
|
+
class EncryptedFile
|
8
|
+
class MissingContentError < RuntimeError
|
9
|
+
def initialize(content_path)
|
10
|
+
super "Missing encrypted content file in #{content_path}."
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class MissingKeyError < RuntimeError
|
15
|
+
def initialize(key_path:, env_key:)
|
16
|
+
super \
|
17
|
+
"Missing encryption key to decrypt file with. " +
|
18
|
+
"Ask your team for your master key and write it to #{key_path} or put it in the ENV['#{env_key}']."
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
CIPHER = "aes-128-gcm"
|
23
|
+
|
24
|
+
def self.generate_key
|
25
|
+
SecureRandom.hex(ActiveSupport::MessageEncryptor.key_len(CIPHER))
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
attr_reader :content_path, :key_path, :env_key, :raise_if_missing_key
|
30
|
+
|
31
|
+
def initialize(content_path:, key_path:, env_key:, raise_if_missing_key:)
|
32
|
+
@content_path, @key_path = Pathname.new(content_path), Pathname.new(key_path)
|
33
|
+
@env_key, @raise_if_missing_key = env_key, raise_if_missing_key
|
34
|
+
end
|
35
|
+
|
36
|
+
def key
|
37
|
+
read_env_key || read_key_file || handle_missing_key
|
38
|
+
end
|
39
|
+
|
40
|
+
def read
|
41
|
+
if !key.nil? && content_path.exist?
|
42
|
+
decrypt content_path.binread
|
43
|
+
else
|
44
|
+
raise MissingContentError, content_path
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def write(contents)
|
49
|
+
IO.binwrite "#{content_path}.tmp", encrypt(contents)
|
50
|
+
FileUtils.mv "#{content_path}.tmp", content_path
|
51
|
+
end
|
52
|
+
|
53
|
+
def change(&block)
|
54
|
+
writing read, &block
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
private
|
59
|
+
def writing(contents)
|
60
|
+
tmp_file = "#{Process.pid}.#{content_path.basename.to_s.chomp('.enc')}"
|
61
|
+
tmp_path = Pathname.new File.join(Dir.tmpdir, tmp_file)
|
62
|
+
tmp_path.binwrite contents
|
63
|
+
|
64
|
+
yield tmp_path
|
65
|
+
|
66
|
+
updated_contents = tmp_path.binread
|
67
|
+
|
68
|
+
write(updated_contents) if updated_contents != contents
|
69
|
+
ensure
|
70
|
+
FileUtils.rm(tmp_path) if tmp_path.exist?
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
def encrypt(contents)
|
75
|
+
encryptor.encrypt_and_sign contents
|
76
|
+
end
|
77
|
+
|
78
|
+
def decrypt(contents)
|
79
|
+
encryptor.decrypt_and_verify contents
|
80
|
+
end
|
81
|
+
|
82
|
+
def encryptor
|
83
|
+
@encryptor ||= ActiveSupport::MessageEncryptor.new([ key ].pack("H*"), cipher: CIPHER)
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
def read_env_key
|
88
|
+
ENV[env_key]
|
89
|
+
end
|
90
|
+
|
91
|
+
def read_key_file
|
92
|
+
key_path.binread.strip if key_path.exist?
|
93
|
+
end
|
94
|
+
|
95
|
+
def handle_missing_key
|
96
|
+
raise MissingKeyError, key_path: key_path, env_key: env_key if raise_if_missing_key
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "set"
|
4
|
+
require "pathname"
|
5
|
+
require "concurrent/atomic/atomic_boolean"
|
6
|
+
|
7
|
+
module ActiveSupport
|
8
|
+
# Allows you to "listen" to changes in a file system.
|
9
|
+
# The evented file updater does not hit disk when checking for updates
|
10
|
+
# instead it uses platform specific file system events to trigger a change
|
11
|
+
# in state.
|
12
|
+
#
|
13
|
+
# The file checker takes an array of files to watch or a hash specifying directories
|
14
|
+
# and file extensions to watch. It also takes a block that is called when
|
15
|
+
# EventedFileUpdateChecker#execute is run or when EventedFileUpdateChecker#execute_if_updated
|
16
|
+
# is run and there have been changes to the file system.
|
17
|
+
#
|
18
|
+
# Note: Forking will cause the first call to `updated?` to return `true`.
|
19
|
+
#
|
20
|
+
# Example:
|
21
|
+
#
|
22
|
+
# checker = ActiveSupport::EventedFileUpdateChecker.new(["/tmp/foo"]) { puts "changed" }
|
23
|
+
# checker.updated?
|
24
|
+
# # => false
|
25
|
+
# checker.execute_if_updated
|
26
|
+
# # => nil
|
27
|
+
#
|
28
|
+
# FileUtils.touch("/tmp/foo")
|
29
|
+
#
|
30
|
+
# checker.updated?
|
31
|
+
# # => true
|
32
|
+
# checker.execute_if_updated
|
33
|
+
# # => "changed"
|
34
|
+
#
|
35
|
+
class EventedFileUpdateChecker #:nodoc: all
|
36
|
+
def initialize(files, dirs = {}, &block)
|
37
|
+
unless block
|
38
|
+
raise ArgumentError, "A block is required to initialize an EventedFileUpdateChecker"
|
39
|
+
end
|
40
|
+
|
41
|
+
@ph = PathHelper.new
|
42
|
+
@files = files.map { |f| @ph.xpath(f) }.to_set
|
43
|
+
|
44
|
+
@dirs = {}
|
45
|
+
dirs.each do |dir, exts|
|
46
|
+
@dirs[@ph.xpath(dir)] = Array(exts).map { |ext| @ph.normalize_extension(ext) }
|
47
|
+
end
|
48
|
+
|
49
|
+
@block = block
|
50
|
+
@updated = Concurrent::AtomicBoolean.new(false)
|
51
|
+
@lcsp = @ph.longest_common_subpath(@dirs.keys)
|
52
|
+
@pid = Process.pid
|
53
|
+
@boot_mutex = Mutex.new
|
54
|
+
|
55
|
+
if (@dtw = directories_to_watch).any?
|
56
|
+
# Loading listen triggers warnings. These are originated by a legit
|
57
|
+
# usage of attr_* macros for private attributes, but adds a lot of noise
|
58
|
+
# to our test suite. Thus, we lazy load it and disable warnings locally.
|
59
|
+
silence_warnings do
|
60
|
+
begin
|
61
|
+
require "listen"
|
62
|
+
rescue LoadError => e
|
63
|
+
raise LoadError, "Could not load the 'listen' gem. Add `gem 'listen'` to the development group of your Gemfile", e.backtrace
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
boot!
|
68
|
+
end
|
69
|
+
|
70
|
+
def updated?
|
71
|
+
@boot_mutex.synchronize do
|
72
|
+
if @pid != Process.pid
|
73
|
+
boot!
|
74
|
+
@pid = Process.pid
|
75
|
+
@updated.make_true
|
76
|
+
end
|
77
|
+
end
|
78
|
+
@updated.true?
|
79
|
+
end
|
80
|
+
|
81
|
+
def execute
|
82
|
+
@updated.make_false
|
83
|
+
@block.call
|
84
|
+
end
|
85
|
+
|
86
|
+
def execute_if_updated
|
87
|
+
if updated?
|
88
|
+
yield if block_given?
|
89
|
+
execute
|
90
|
+
true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
def boot!
|
96
|
+
Listen.to(*@dtw, &method(:changed)).start
|
97
|
+
end
|
98
|
+
|
99
|
+
def changed(modified, added, removed)
|
100
|
+
unless updated?
|
101
|
+
@updated.make_true if (modified + added + removed).any? { |f| watching?(f) }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def watching?(file)
|
106
|
+
file = @ph.xpath(file)
|
107
|
+
|
108
|
+
if @files.member?(file)
|
109
|
+
true
|
110
|
+
elsif file.directory?
|
111
|
+
false
|
112
|
+
else
|
113
|
+
ext = @ph.normalize_extension(file.extname)
|
114
|
+
|
115
|
+
file.dirname.ascend do |dir|
|
116
|
+
if @dirs.fetch(dir, []).include?(ext)
|
117
|
+
break true
|
118
|
+
elsif dir == @lcsp || dir.root?
|
119
|
+
break false
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def directories_to_watch
|
126
|
+
dtw = (@files + @dirs.keys).map { |f| @ph.existing_parent(f) }
|
127
|
+
dtw.compact!
|
128
|
+
dtw.uniq!
|
129
|
+
|
130
|
+
normalized_gem_paths = Gem.path.map { |path| File.join path, "" }
|
131
|
+
dtw = dtw.reject do |path|
|
132
|
+
normalized_gem_paths.any? { |gem_path| path.to_s.start_with?(gem_path) }
|
133
|
+
end
|
134
|
+
|
135
|
+
@ph.filter_out_descendants(dtw)
|
136
|
+
end
|
137
|
+
|
138
|
+
class PathHelper
|
139
|
+
def xpath(path)
|
140
|
+
Pathname.new(path).expand_path
|
141
|
+
end
|
142
|
+
|
143
|
+
def normalize_extension(ext)
|
144
|
+
ext.to_s.sub(/\A\./, "")
|
145
|
+
end
|
146
|
+
|
147
|
+
# Given a collection of Pathname objects returns the longest subpath
|
148
|
+
# common to all of them, or +nil+ if there is none.
|
149
|
+
def longest_common_subpath(paths)
|
150
|
+
return if paths.empty?
|
151
|
+
|
152
|
+
lcsp = Pathname.new(paths[0])
|
153
|
+
|
154
|
+
paths[1..-1].each do |path|
|
155
|
+
until ascendant_of?(lcsp, path)
|
156
|
+
if lcsp.root?
|
157
|
+
# If we get here a root directory is not an ascendant of path.
|
158
|
+
# This may happen if there are paths in different drives on
|
159
|
+
# Windows.
|
160
|
+
return
|
161
|
+
else
|
162
|
+
lcsp = lcsp.parent
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
lcsp
|
168
|
+
end
|
169
|
+
|
170
|
+
# Returns the deepest existing ascendant, which could be the argument itself.
|
171
|
+
def existing_parent(dir)
|
172
|
+
dir.ascend do |ascendant|
|
173
|
+
break ascendant if ascendant.directory?
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
# Filters out directories which are descendants of others in the collection (stable).
|
178
|
+
def filter_out_descendants(dirs)
|
179
|
+
return dirs if dirs.length < 2
|
180
|
+
|
181
|
+
dirs_sorted_by_nparts = dirs.sort_by { |dir| dir.each_filename.to_a.length }
|
182
|
+
descendants = []
|
183
|
+
|
184
|
+
until dirs_sorted_by_nparts.empty?
|
185
|
+
dir = dirs_sorted_by_nparts.shift
|
186
|
+
|
187
|
+
dirs_sorted_by_nparts.reject! do |possible_descendant|
|
188
|
+
ascendant_of?(dir, possible_descendant) && descendants << possible_descendant
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# Array#- preserves order.
|
193
|
+
dirs - descendants
|
194
|
+
end
|
195
|
+
|
196
|
+
private
|
197
|
+
|
198
|
+
def ascendant_of?(base, other)
|
199
|
+
base != other && other.ascend do |ascendant|
|
200
|
+
break true if base == ascendant
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/callbacks"
|
4
|
+
|
5
|
+
module ActiveSupport
|
6
|
+
class ExecutionWrapper
|
7
|
+
include ActiveSupport::Callbacks
|
8
|
+
|
9
|
+
Null = Object.new # :nodoc:
|
10
|
+
def Null.complete! # :nodoc:
|
11
|
+
end
|
12
|
+
|
13
|
+
define_callbacks :run
|
14
|
+
define_callbacks :complete
|
15
|
+
|
16
|
+
def self.to_run(*args, &block)
|
17
|
+
set_callback(:run, *args, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.to_complete(*args, &block)
|
21
|
+
set_callback(:complete, *args, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
RunHook = Struct.new(:hook) do # :nodoc:
|
25
|
+
def before(target)
|
26
|
+
hook_state = target.send(:hook_state)
|
27
|
+
hook_state[hook] = hook.run
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
CompleteHook = Struct.new(:hook) do # :nodoc:
|
32
|
+
def before(target)
|
33
|
+
hook_state = target.send(:hook_state)
|
34
|
+
if hook_state.key?(hook)
|
35
|
+
hook.complete hook_state[hook]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
alias after before
|
39
|
+
end
|
40
|
+
|
41
|
+
# Register an object to be invoked during both the +run+ and
|
42
|
+
# +complete+ steps.
|
43
|
+
#
|
44
|
+
# +hook.complete+ will be passed the value returned from +hook.run+,
|
45
|
+
# and will only be invoked if +run+ has previously been called.
|
46
|
+
# (Mostly, this means it won't be invoked if an exception occurs in
|
47
|
+
# a preceding +to_run+ block; all ordinary +to_complete+ blocks are
|
48
|
+
# invoked in that situation.)
|
49
|
+
def self.register_hook(hook, outer: false)
|
50
|
+
if outer
|
51
|
+
to_run RunHook.new(hook), prepend: true
|
52
|
+
to_complete :after, CompleteHook.new(hook)
|
53
|
+
else
|
54
|
+
to_run RunHook.new(hook)
|
55
|
+
to_complete CompleteHook.new(hook)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Run this execution.
|
60
|
+
#
|
61
|
+
# Returns an instance, whose +complete!+ method *must* be invoked
|
62
|
+
# after the work has been performed.
|
63
|
+
#
|
64
|
+
# Where possible, prefer +wrap+.
|
65
|
+
def self.run!(reset: false)
|
66
|
+
if reset
|
67
|
+
lost_instance = active.delete(Thread.current)
|
68
|
+
lost_instance.complete! unless lost_instance.nil?
|
69
|
+
else
|
70
|
+
return Null if active?
|
71
|
+
end
|
72
|
+
|
73
|
+
new.tap do |instance|
|
74
|
+
success = nil
|
75
|
+
begin
|
76
|
+
instance.run!
|
77
|
+
success = true
|
78
|
+
ensure
|
79
|
+
instance.complete! unless success
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Perform the work in the supplied block as an execution.
|
85
|
+
def self.wrap
|
86
|
+
return yield if active?
|
87
|
+
|
88
|
+
instance = run!
|
89
|
+
begin
|
90
|
+
yield
|
91
|
+
ensure
|
92
|
+
instance.complete!
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class << self # :nodoc:
|
97
|
+
attr_accessor :active
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.inherited(other) # :nodoc:
|
101
|
+
super
|
102
|
+
other.active = Concurrent::Hash.new
|
103
|
+
end
|
104
|
+
|
105
|
+
self.active = Concurrent::Hash.new
|
106
|
+
|
107
|
+
def self.active? # :nodoc:
|
108
|
+
@active.key?(Thread.current)
|
109
|
+
end
|
110
|
+
|
111
|
+
def run! # :nodoc:
|
112
|
+
self.class.active[Thread.current] = self
|
113
|
+
run_callbacks(:run)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Complete this in-flight execution. This method *must* be called
|
117
|
+
# exactly once on the result of any call to +run!+.
|
118
|
+
#
|
119
|
+
# Where possible, prefer +wrap+.
|
120
|
+
def complete!
|
121
|
+
run_callbacks(:complete)
|
122
|
+
ensure
|
123
|
+
self.class.active.delete Thread.current
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
def hook_state
|
128
|
+
@_hook_state ||= {}
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -1,3 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/time/calculations"
|
4
|
+
|
1
5
|
module ActiveSupport
|
2
6
|
# FileUpdateChecker specifies the API used by Rails to watch files
|
3
7
|
# and control reloading. The API depends on four methods:
|
@@ -23,7 +27,7 @@ module ActiveSupport
|
|
23
27
|
# I18n.reload!
|
24
28
|
# end
|
25
29
|
#
|
26
|
-
#
|
30
|
+
# ActiveSupport::Reloader.to_prepare do
|
27
31
|
# i18n_reloader.execute_if_updated
|
28
32
|
# end
|
29
33
|
class FileUpdateChecker
|
@@ -35,7 +39,11 @@ module ActiveSupport
|
|
35
39
|
# This method must also receive a block that will be called once a path
|
36
40
|
# changes. The array of files and list of directories cannot be changed
|
37
41
|
# after FileUpdateChecker has been initialized.
|
38
|
-
def initialize(files, dirs={}, &block)
|
42
|
+
def initialize(files, dirs = {}, &block)
|
43
|
+
unless block
|
44
|
+
raise ArgumentError, "A block is required to initialize a FileUpdateChecker"
|
45
|
+
end
|
46
|
+
|
39
47
|
@files = files.freeze
|
40
48
|
@glob = compile_glob(dirs)
|
41
49
|
@block = block
|
@@ -81,6 +89,7 @@ module ActiveSupport
|
|
81
89
|
# Execute the block given if updated.
|
82
90
|
def execute_if_updated
|
83
91
|
if updated?
|
92
|
+
yield if block_given?
|
84
93
|
execute
|
85
94
|
true
|
86
95
|
else
|
@@ -90,48 +99,65 @@ module ActiveSupport
|
|
90
99
|
|
91
100
|
private
|
92
101
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
102
|
+
def watched
|
103
|
+
@watched || begin
|
104
|
+
all = @files.select { |f| File.exist?(f) }
|
105
|
+
all.concat(Dir[@glob]) if @glob
|
106
|
+
all
|
107
|
+
end
|
98
108
|
end
|
99
|
-
end
|
100
109
|
|
101
|
-
|
102
|
-
|
103
|
-
|
110
|
+
def updated_at(paths)
|
111
|
+
@updated_at || max_mtime(paths) || Time.at(0)
|
112
|
+
end
|
104
113
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
114
|
+
# This method returns the maximum mtime of the files in +paths+, or +nil+
|
115
|
+
# if the array is empty.
|
116
|
+
#
|
117
|
+
# Files with a mtime in the future are ignored. Such abnormal situation
|
118
|
+
# can happen for example if the user changes the clock by hand. It is
|
119
|
+
# healthy to consider this edge case because with mtimes in the future
|
120
|
+
# reloading is not triggered.
|
121
|
+
def max_mtime(paths)
|
122
|
+
time_now = Time.now
|
123
|
+
max_mtime = nil
|
124
|
+
|
125
|
+
# Time comparisons are performed with #compare_without_coercion because
|
126
|
+
# AS redefines these operators in a way that is much slower and does not
|
127
|
+
# bring any benefit in this particular code.
|
128
|
+
#
|
129
|
+
# Read t1.compare_without_coercion(t2) < 0 as t1 < t2.
|
130
|
+
paths.each do |path|
|
131
|
+
mtime = File.mtime(path)
|
116
132
|
|
117
|
-
|
118
|
-
hash.freeze # Freeze so changes aren't accidentally pushed
|
119
|
-
return if hash.empty?
|
133
|
+
next if time_now.compare_without_coercion(mtime) < 0
|
120
134
|
|
121
|
-
|
122
|
-
|
135
|
+
if max_mtime.nil? || max_mtime.compare_without_coercion(mtime) < 0
|
136
|
+
max_mtime = mtime
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
max_mtime
|
123
141
|
end
|
124
|
-
"{#{globs.join(",")}}"
|
125
|
-
end
|
126
142
|
|
127
|
-
|
128
|
-
|
129
|
-
|
143
|
+
def compile_glob(hash)
|
144
|
+
hash.freeze # Freeze so changes aren't accidentally pushed
|
145
|
+
return if hash.empty?
|
130
146
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
147
|
+
globs = hash.map do |key, value|
|
148
|
+
"#{escape(key)}/**/*#{compile_ext(value)}"
|
149
|
+
end
|
150
|
+
"{#{globs.join(",")}}"
|
151
|
+
end
|
152
|
+
|
153
|
+
def escape(key)
|
154
|
+
key.gsub(",", '\,')
|
155
|
+
end
|
156
|
+
|
157
|
+
def compile_ext(array)
|
158
|
+
array = Array(array)
|
159
|
+
return if array.empty?
|
160
|
+
".{#{array.join(",")}}"
|
161
|
+
end
|
136
162
|
end
|
137
163
|
end
|
@@ -1,13 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveSupport
|
2
|
-
# Returns the version of the currently loaded Active Support as a <tt>Gem::Version</tt
|
4
|
+
# Returns the version of the currently loaded Active Support as a <tt>Gem::Version</tt>.
|
3
5
|
def self.gem_version
|
4
6
|
Gem::Version.new VERSION::STRING
|
5
7
|
end
|
6
8
|
|
7
9
|
module VERSION
|
8
|
-
MAJOR =
|
10
|
+
MAJOR = 5
|
9
11
|
MINOR = 2
|
10
|
-
TINY =
|
12
|
+
TINY = 8
|
11
13
|
PRE = "1"
|
12
14
|
|
13
15
|
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
data/lib/active_support/gzip.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "zlib"
|
4
|
+
require "stringio"
|
3
5
|
|
4
6
|
module ActiveSupport
|
5
7
|
# A convenient wrapper for the zlib standard library that allows
|
@@ -9,7 +11,7 @@ module ActiveSupport
|
|
9
11
|
# # => "\x1F\x8B\b\x00o\x8D\xCDO\x00\x03K\xCE\xCF-(J-.V\xC8MU\x04\x00R>n\x83\f\x00\x00\x00"
|
10
12
|
#
|
11
13
|
# ActiveSupport::Gzip.decompress(gzip)
|
12
|
-
# # => "compress me!"
|
14
|
+
# # => "compress me!"
|
13
15
|
module Gzip
|
14
16
|
class Stream < StringIO
|
15
17
|
def initialize(*)
|
@@ -21,11 +23,11 @@ module ActiveSupport
|
|
21
23
|
|
22
24
|
# Decompresses a gzipped string.
|
23
25
|
def self.decompress(source)
|
24
|
-
Zlib::GzipReader.
|
26
|
+
Zlib::GzipReader.wrap(StringIO.new(source), &:read)
|
25
27
|
end
|
26
28
|
|
27
29
|
# Compresses a string using gzip.
|
28
|
-
def self.compress(source, level=Zlib::DEFAULT_COMPRESSION, strategy=Zlib::DEFAULT_STRATEGY)
|
30
|
+
def self.compress(source, level = Zlib::DEFAULT_COMPRESSION, strategy = Zlib::DEFAULT_STRATEGY)
|
29
31
|
output = Stream.new
|
30
32
|
gz = Zlib::GzipWriter.new(output, level, strategy)
|
31
33
|
gz.write(source)
|