activesupport 3.2.22.5 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +364 -135
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -4
- data/lib/active_support/backtrace_cleaner.rb +33 -25
- data/lib/active_support/basic_object.rb +7 -17
- data/lib/active_support/benchmarkable.rb +19 -15
- data/lib/active_support/buffered_logger.rb +9 -113
- data/lib/active_support/cache/file_store.rb +14 -14
- data/lib/active_support/cache/mem_cache_store.rb +24 -30
- data/lib/active_support/cache/memory_store.rb +2 -0
- data/lib/active_support/cache/strategy/local_cache.rb +48 -37
- data/lib/active_support/cache.rb +228 -183
- data/lib/active_support/callbacks.rb +201 -253
- data/lib/active_support/concern.rb +16 -23
- data/lib/active_support/concurrency/latch.rb +27 -0
- data/lib/active_support/configurable.rb +69 -12
- data/lib/active_support/core_ext/array/access.rb +17 -9
- data/lib/active_support/core_ext/array/conversions.rb +115 -55
- data/lib/active_support/core_ext/array/extract_options.rb +2 -2
- data/lib/active_support/core_ext/array/grouping.rb +21 -22
- data/lib/active_support/core_ext/array/uniq_by.rb +12 -9
- data/lib/active_support/core_ext/array/wrap.rb +13 -16
- data/lib/active_support/core_ext/array.rb +0 -1
- data/lib/active_support/core_ext/benchmark.rb +7 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -24
- data/lib/active_support/core_ext/class/attribute.rb +40 -32
- data/lib/active_support/core_ext/class/attribute_accessors.rb +14 -12
- data/lib/active_support/core_ext/class/delegating_attributes.rb +15 -19
- data/lib/active_support/core_ext/class/subclasses.rb +11 -5
- data/lib/active_support/core_ext/date/calculations.rb +44 -187
- data/lib/active_support/core_ext/date/conversions.rb +16 -38
- data/lib/active_support/core_ext/date/zones.rb +25 -2
- data/lib/active_support/core_ext/date.rb +5 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +232 -0
- data/lib/active_support/core_ext/date_time/acts_like.rb +0 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +77 -62
- data/lib/active_support/core_ext/date_time/conversions.rb +21 -33
- data/lib/active_support/core_ext/date_time/zones.rb +11 -8
- data/lib/active_support/core_ext/date_time.rb +4 -0
- data/lib/active_support/core_ext/enumerable.rb +26 -73
- data/lib/active_support/core_ext/file/atomic.rb +27 -11
- data/lib/active_support/core_ext/file.rb +0 -1
- data/lib/active_support/core_ext/hash/conversions.rb +145 -79
- data/lib/active_support/core_ext/hash/deep_merge.rb +14 -8
- data/lib/active_support/core_ext/hash/diff.rb +5 -4
- data/lib/active_support/core_ext/hash/except.rb +1 -9
- data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -5
- data/lib/active_support/core_ext/hash/keys.rb +108 -24
- data/lib/active_support/core_ext/hash/reverse_merge.rb +2 -3
- data/lib/active_support/core_ext/hash/slice.rb +12 -12
- data/lib/active_support/core_ext/hash.rb +0 -1
- data/lib/active_support/core_ext/integer/inflections.rb +13 -1
- data/lib/active_support/core_ext/integer/time.rb +17 -12
- data/lib/active_support/core_ext/kernel/debugger.rb +2 -2
- data/lib/active_support/core_ext/kernel/reporting.rb +36 -22
- data/lib/active_support/core_ext/kernel/singleton_class.rb +0 -7
- data/lib/active_support/core_ext/load_error.rb +7 -5
- data/lib/active_support/core_ext/logger.rb +7 -23
- data/lib/active_support/core_ext/marshal.rb +21 -0
- data/lib/active_support/core_ext/module/aliasing.rb +8 -9
- data/lib/active_support/core_ext/module/anonymous.rb +2 -7
- data/lib/active_support/core_ext/module/attr_internal.rb +0 -1
- data/lib/active_support/core_ext/module/attribute_accessors.rb +12 -10
- data/lib/active_support/core_ext/module/delegation.rb +92 -49
- data/lib/active_support/core_ext/module/deprecation.rb +19 -3
- data/lib/active_support/core_ext/module/introspection.rb +17 -27
- data/lib/active_support/core_ext/module/qualified_const.rb +8 -20
- data/lib/active_support/core_ext/module/remove_method.rb +1 -5
- data/lib/active_support/core_ext/module.rb +1 -3
- data/lib/active_support/core_ext/numeric/conversions.rb +135 -0
- data/lib/active_support/core_ext/numeric/time.rb +6 -6
- data/lib/active_support/core_ext/numeric.rb +1 -0
- data/lib/active_support/core_ext/object/acts_like.rb +4 -4
- data/lib/active_support/core_ext/object/blank.rb +7 -23
- data/lib/active_support/core_ext/object/deep_dup.rb +46 -0
- data/lib/active_support/core_ext/object/duplicable.rb +1 -30
- data/lib/active_support/core_ext/object/inclusion.rb +8 -7
- data/lib/active_support/core_ext/object/instance_variables.rb +7 -12
- data/lib/active_support/core_ext/object/to_json.rb +8 -0
- data/lib/active_support/core_ext/object/to_param.rb +5 -2
- data/lib/active_support/core_ext/object/try.rb +46 -25
- data/lib/active_support/core_ext/object/with_options.rb +7 -8
- data/lib/active_support/core_ext/object.rb +1 -0
- data/lib/active_support/core_ext/proc.rb +3 -0
- data/lib/active_support/core_ext/range/conversions.rb +0 -2
- data/lib/active_support/core_ext/range/include_range.rb +3 -1
- data/lib/active_support/core_ext/range/overlaps.rb +1 -1
- data/lib/active_support/core_ext/range.rb +0 -2
- data/lib/active_support/core_ext/string/access.rb +95 -90
- data/lib/active_support/core_ext/string/conversions.rb +27 -38
- data/lib/active_support/core_ext/string/encoding.rb +6 -9
- data/lib/active_support/core_ext/string/filters.rb +24 -18
- data/lib/active_support/core_ext/string/indent.rb +43 -0
- data/lib/active_support/core_ext/string/inflections.rb +70 -60
- data/lib/active_support/core_ext/string/inquiry.rb +2 -2
- data/lib/active_support/core_ext/string/multibyte.rb +41 -64
- data/lib/active_support/core_ext/string/output_safety.rb +59 -51
- data/lib/active_support/core_ext/string/zones.rb +13 -0
- data/lib/active_support/core_ext/string.rb +2 -3
- data/lib/active_support/core_ext/struct.rb +6 -0
- data/lib/active_support/core_ext/thread.rb +74 -0
- data/lib/active_support/core_ext/time/calculations.rb +108 -184
- data/lib/active_support/core_ext/time/conversions.rb +27 -51
- data/lib/active_support/core_ext/time/marshal.rb +0 -27
- data/lib/active_support/core_ext/time/zones.rb +27 -17
- data/lib/active_support/core_ext/time.rb +5 -0
- data/lib/active_support/core_ext/uri.rb +13 -17
- data/lib/active_support/core_ext.rb +3 -2
- data/lib/active_support/dependencies/autoload.rb +47 -20
- data/lib/active_support/dependencies.rb +160 -141
- data/lib/active_support/deprecation/behaviors.rb +44 -30
- data/lib/active_support/deprecation/instance_delegator.rb +24 -0
- data/lib/active_support/deprecation/method_wrappers.rb +33 -18
- data/lib/active_support/deprecation/proxy_wrappers.rb +58 -13
- data/lib/active_support/deprecation/reporting.rb +40 -11
- data/lib/active_support/deprecation.rb +39 -14
- data/lib/active_support/descendants_tracker.rb +34 -19
- data/lib/active_support/duration.rb +6 -8
- data/lib/active_support/file_update_checker.rb +63 -47
- data/lib/active_support/gzip.rb +11 -5
- data/lib/active_support/hash_with_indifferent_access.rb +127 -42
- data/lib/active_support/i18n.rb +4 -0
- data/lib/active_support/i18n_railtie.rb +5 -22
- data/lib/active_support/inflections.rb +14 -12
- data/lib/active_support/inflector/inflections.rb +108 -71
- data/lib/active_support/inflector/methods.rb +181 -160
- data/lib/active_support/inflector/transliterate.rb +16 -17
- data/lib/active_support/json/decoding.rb +18 -17
- data/lib/active_support/json/encoding.rb +93 -39
- data/lib/active_support/json/variable.rb +10 -1
- data/lib/active_support/key_generator.rb +75 -0
- data/lib/active_support/lazy_load_hooks.rb +21 -19
- data/lib/active_support/locale/en.yml +100 -3
- data/lib/active_support/log_subscriber/test_helper.rb +18 -15
- data/lib/active_support/log_subscriber.rb +35 -52
- data/lib/active_support/logger.rb +57 -0
- data/lib/active_support/logger_silence.rb +24 -0
- data/lib/active_support/message_encryptor.rb +38 -35
- data/lib/active_support/message_verifier.rb +9 -15
- data/lib/active_support/multibyte/chars.rb +80 -333
- data/lib/active_support/multibyte/unicode.rb +74 -64
- data/lib/active_support/multibyte.rb +5 -28
- data/lib/active_support/notifications/fanout.rb +112 -18
- data/lib/active_support/notifications/instrumenter.rb +33 -14
- data/lib/active_support/notifications.rb +79 -26
- data/lib/active_support/number_helper.rb +637 -0
- data/lib/active_support/ordered_hash.rb +8 -190
- data/lib/active_support/ordered_options.rb +21 -23
- data/lib/active_support/per_thread_registry.rb +52 -0
- data/lib/active_support/proxy_object.rb +13 -0
- data/lib/active_support/rails.rb +27 -0
- data/lib/active_support/railtie.rb +12 -32
- data/lib/active_support/rescuable.rb +9 -4
- data/lib/active_support/string_inquirer.rb +13 -8
- data/lib/active_support/subscriber.rb +93 -0
- data/lib/active_support/tagged_logging.rb +51 -73
- data/lib/active_support/test_case.rb +46 -17
- data/lib/active_support/testing/assertions.rb +56 -26
- data/lib/active_support/testing/autorun.rb +5 -0
- data/lib/active_support/testing/constant_lookup.rb +54 -0
- data/lib/active_support/testing/declarative.rb +1 -1
- data/lib/active_support/testing/deprecation.rb +0 -19
- data/lib/active_support/testing/isolation.rb +29 -58
- data/lib/active_support/testing/pending.rb +5 -43
- data/lib/active_support/testing/setup_and_teardown.rb +6 -92
- data/lib/active_support/testing/tagged_logging.rb +25 -0
- data/lib/active_support/time.rb +6 -21
- data/lib/active_support/time_with_zone.rb +80 -43
- data/lib/active_support/values/time_zone.rb +81 -60
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/version.rb +7 -6
- data/lib/active_support/xml_mini/jdom.rb +9 -11
- data/lib/active_support/xml_mini/libxml.rb +1 -2
- data/lib/active_support/xml_mini/libxmlsax.rb +2 -3
- data/lib/active_support/xml_mini/nokogiri.rb +1 -2
- data/lib/active_support/xml_mini/nokogirisax.rb +2 -3
- data/lib/active_support/xml_mini/rexml.rb +6 -8
- data/lib/active_support/xml_mini.rb +35 -17
- data/lib/active_support.rb +8 -21
- metadata +104 -72
- data/lib/active_support/base64.rb +0 -54
- data/lib/active_support/core_ext/array/random_access.rb +0 -30
- data/lib/active_support/core_ext/date/freeze.rb +0 -33
- data/lib/active_support/core_ext/exception.rb +0 -3
- data/lib/active_support/core_ext/file/path.rb +0 -5
- data/lib/active_support/core_ext/float/rounding.rb +0 -19
- data/lib/active_support/core_ext/float.rb +0 -1
- data/lib/active_support/core_ext/hash/deep_dup.rb +0 -18
- data/lib/active_support/core_ext/io.rb +0 -15
- data/lib/active_support/core_ext/module/method_names.rb +0 -14
- data/lib/active_support/core_ext/module/synchronization.rb +0 -45
- data/lib/active_support/core_ext/process/daemon.rb +0 -23
- data/lib/active_support/core_ext/process.rb +0 -1
- data/lib/active_support/core_ext/range/blockless_step.rb +0 -29
- data/lib/active_support/core_ext/range/cover.rb +0 -3
- data/lib/active_support/core_ext/rexml.rb +0 -46
- data/lib/active_support/core_ext/string/interpolation.rb +0 -2
- data/lib/active_support/core_ext/string/xchar.rb +0 -18
- data/lib/active_support/core_ext/time/publicize_conversion_methods.rb +0 -10
- data/lib/active_support/memoizable.rb +0 -116
- data/lib/active_support/multibyte/exceptions.rb +0 -8
- data/lib/active_support/multibyte/utils.rb +0 -60
- data/lib/active_support/ruby/shim.rb +0 -22
- data/lib/active_support/security_utils.rb +0 -27
- data/lib/active_support/testing/mochaing.rb +0 -7
- data/lib/active_support/testing/performance/jruby.rb +0 -115
- data/lib/active_support/testing/performance/rubinius.rb +0 -113
- data/lib/active_support/testing/performance/ruby/mri.rb +0 -57
- data/lib/active_support/testing/performance/ruby/yarv.rb +0 -57
- data/lib/active_support/testing/performance/ruby.rb +0 -152
- data/lib/active_support/testing/performance.rb +0 -317
- data/lib/active_support/time/autoload.rb +0 -5
- data/lib/active_support/whiny_nil.rb +0 -24
|
@@ -1,26 +1,21 @@
|
|
|
1
|
-
require "active_support/core_ext/array/wrap"
|
|
2
|
-
require "active_support/core_ext/array/extract_options"
|
|
3
|
-
|
|
4
1
|
module ActiveSupport
|
|
5
|
-
#
|
|
2
|
+
# FileUpdateChecker specifies the API used by Rails to watch files
|
|
6
3
|
# and control reloading. The API depends on four methods:
|
|
7
4
|
#
|
|
8
5
|
# * +initialize+ which expects two parameters and one block as
|
|
9
|
-
# described below
|
|
6
|
+
# described below.
|
|
10
7
|
#
|
|
11
8
|
# * +updated?+ which returns a boolean if there were updates in
|
|
12
|
-
# the filesystem or not
|
|
9
|
+
# the filesystem or not.
|
|
13
10
|
#
|
|
14
11
|
# * +execute+ which executes the given block on initialization
|
|
15
|
-
# and updates the
|
|
12
|
+
# and updates the latest watched files and timestamp.
|
|
16
13
|
#
|
|
17
|
-
# * +execute_if_updated+ which just executes the block if it was updated
|
|
14
|
+
# * +execute_if_updated+ which just executes the block if it was updated.
|
|
18
15
|
#
|
|
19
16
|
# After initialization, a call to +execute_if_updated+ must execute
|
|
20
17
|
# the block only if there was really a change in the filesystem.
|
|
21
18
|
#
|
|
22
|
-
# == Examples
|
|
23
|
-
#
|
|
24
19
|
# This class is used by Rails to reload the I18n framework whenever
|
|
25
20
|
# they are changed upon a new request.
|
|
26
21
|
#
|
|
@@ -31,52 +26,55 @@ module ActiveSupport
|
|
|
31
26
|
# ActionDispatch::Reloader.to_prepare do
|
|
32
27
|
# i18n_reloader.execute_if_updated
|
|
33
28
|
# end
|
|
34
|
-
#
|
|
35
29
|
class FileUpdateChecker
|
|
36
30
|
# It accepts two parameters on initialization. The first is an array
|
|
37
31
|
# of files and the second is an optional hash of directories. The hash must
|
|
38
32
|
# have directories as keys and the value is an array of extensions to be
|
|
39
33
|
# watched under that directory.
|
|
40
34
|
#
|
|
41
|
-
# This method must also receive a block that will be called once a path
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
# This particular implementation checks for added and updated files,
|
|
46
|
-
# but not removed files. Directories lookup are compiled to a glob for
|
|
47
|
-
# performance. Therefore, while someone can add new files to the +files+
|
|
48
|
-
# array after initialization (and parts of Rails do depend on this feature),
|
|
49
|
-
# adding new directories after initialization is not allowed.
|
|
50
|
-
#
|
|
51
|
-
# Notice that other objects that implements FileUpdateChecker API may
|
|
52
|
-
# not even allow new files to be added after initialization. If this
|
|
53
|
-
# is the case, we recommend freezing the +files+ after initialization to
|
|
54
|
-
# avoid changes that won't make effect.
|
|
35
|
+
# This method must also receive a block that will be called once a path
|
|
36
|
+
# changes. The array of files and list of directories cannot be changed
|
|
37
|
+
# after FileUpdateChecker has been initialized.
|
|
55
38
|
def initialize(files, dirs={}, &block)
|
|
56
|
-
@files = files
|
|
39
|
+
@files = files.freeze
|
|
57
40
|
@glob = compile_glob(dirs)
|
|
58
41
|
@block = block
|
|
42
|
+
|
|
43
|
+
@watched = nil
|
|
59
44
|
@updated_at = nil
|
|
60
|
-
|
|
45
|
+
|
|
46
|
+
@last_watched = watched
|
|
47
|
+
@last_update_at = updated_at(@last_watched)
|
|
61
48
|
end
|
|
62
49
|
|
|
63
|
-
# Check if any of the entries were updated. If so, the
|
|
64
|
-
#
|
|
50
|
+
# Check if any of the entries were updated. If so, the watched and/or
|
|
51
|
+
# updated_at values are cached until the block is executed via +execute+
|
|
52
|
+
# or +execute_if_updated+.
|
|
65
53
|
def updated?
|
|
66
|
-
|
|
67
|
-
if @
|
|
68
|
-
@
|
|
54
|
+
current_watched = watched
|
|
55
|
+
if @last_watched.size != current_watched.size
|
|
56
|
+
@watched = current_watched
|
|
69
57
|
true
|
|
70
58
|
else
|
|
71
|
-
|
|
59
|
+
current_updated_at = updated_at(current_watched)
|
|
60
|
+
if @last_update_at < current_updated_at
|
|
61
|
+
@watched = current_watched
|
|
62
|
+
@updated_at = current_updated_at
|
|
63
|
+
true
|
|
64
|
+
else
|
|
65
|
+
false
|
|
66
|
+
end
|
|
72
67
|
end
|
|
73
68
|
end
|
|
74
69
|
|
|
75
|
-
# Executes the given block and updates the
|
|
70
|
+
# Executes the given block and updates the latest watched files and
|
|
71
|
+
# timestamp.
|
|
76
72
|
def execute
|
|
77
|
-
@
|
|
73
|
+
@last_watched = watched
|
|
74
|
+
@last_update_at = updated_at(@last_watched)
|
|
78
75
|
@block.call
|
|
79
76
|
ensure
|
|
77
|
+
@watched = nil
|
|
80
78
|
@updated_at = nil
|
|
81
79
|
end
|
|
82
80
|
|
|
@@ -92,28 +90,46 @@ module ActiveSupport
|
|
|
92
90
|
|
|
93
91
|
private
|
|
94
92
|
|
|
95
|
-
def
|
|
96
|
-
@
|
|
97
|
-
all =
|
|
98
|
-
all.concat
|
|
99
|
-
all
|
|
100
|
-
all.map { |path| File.mtime(path) }.max || Time.at(0)
|
|
93
|
+
def watched
|
|
94
|
+
@watched || begin
|
|
95
|
+
all = @files.select { |f| File.exists?(f) }
|
|
96
|
+
all.concat(Dir[@glob]) if @glob
|
|
97
|
+
all
|
|
101
98
|
end
|
|
102
99
|
end
|
|
103
100
|
|
|
104
|
-
def
|
|
101
|
+
def updated_at(paths)
|
|
102
|
+
@updated_at || max_mtime(paths) || Time.at(0)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# This method returns the maximum mtime of the files in +paths+, or +nil+
|
|
106
|
+
# if the array is empty.
|
|
107
|
+
#
|
|
108
|
+
# Files with a mtime in the future are ignored. Such abnormal situation
|
|
109
|
+
# can happen for example if the user changes the clock by hand. It is
|
|
110
|
+
# healthy to consider this edge case because with mtimes in the future
|
|
111
|
+
# reloading is not triggered.
|
|
112
|
+
def max_mtime(paths)
|
|
113
|
+
time_now = Time.now
|
|
114
|
+
paths.map {|path| File.mtime(path)}.reject {|mtime| time_now < mtime}.max
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def compile_glob(hash)
|
|
105
118
|
hash.freeze # Freeze so changes aren't accidently pushed
|
|
106
119
|
return if hash.empty?
|
|
107
120
|
|
|
108
|
-
globs =
|
|
109
|
-
|
|
110
|
-
globs << "#{key}/**/*#{compile_ext(value)}"
|
|
121
|
+
globs = hash.map do |key, value|
|
|
122
|
+
"#{escape(key)}/**/*#{compile_ext(value)}"
|
|
111
123
|
end
|
|
112
124
|
"{#{globs.join(",")}}"
|
|
113
125
|
end
|
|
114
126
|
|
|
115
|
-
def
|
|
116
|
-
|
|
127
|
+
def escape(key)
|
|
128
|
+
key.gsub(',','\,')
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def compile_ext(array)
|
|
132
|
+
array = Array(array)
|
|
117
133
|
return if array.empty?
|
|
118
134
|
".{#{array.join(",")}}"
|
|
119
135
|
end
|
data/lib/active_support/gzip.rb
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
require 'zlib'
|
|
2
2
|
require 'stringio'
|
|
3
|
-
require 'active_support/core_ext/string/encoding'
|
|
4
3
|
|
|
5
4
|
module ActiveSupport
|
|
6
|
-
# A convenient wrapper for the zlib standard library that allows
|
|
5
|
+
# A convenient wrapper for the zlib standard library that allows
|
|
6
|
+
# compression/decompression of strings with gzip.
|
|
7
|
+
#
|
|
8
|
+
# gzip = ActiveSupport::Gzip.compress('compress me!')
|
|
9
|
+
# # => "\x1F\x8B\b\x00o\x8D\xCDO\x00\x03K\xCE\xCF-(J-.V\xC8MU\x04\x00R>n\x83\f\x00\x00\x00"
|
|
10
|
+
#
|
|
11
|
+
# ActiveSupport::Gzip.decompress(gzip)
|
|
12
|
+
# # => "compress me!"
|
|
7
13
|
module Gzip
|
|
8
14
|
class Stream < StringIO
|
|
9
15
|
def initialize(*)
|
|
10
16
|
super
|
|
11
|
-
set_encoding "BINARY"
|
|
17
|
+
set_encoding "BINARY"
|
|
12
18
|
end
|
|
13
19
|
def close; rewind; end
|
|
14
20
|
end
|
|
@@ -19,9 +25,9 @@ module ActiveSupport
|
|
|
19
25
|
end
|
|
20
26
|
|
|
21
27
|
# Compresses a string using gzip.
|
|
22
|
-
def self.compress(source)
|
|
28
|
+
def self.compress(source, level=Zlib::DEFAULT_COMPRESSION, strategy=Zlib::DEFAULT_STRATEGY)
|
|
23
29
|
output = Stream.new
|
|
24
|
-
gz = Zlib::GzipWriter.new(output)
|
|
30
|
+
gz = Zlib::GzipWriter.new(output, level, strategy)
|
|
25
31
|
gz.write(source)
|
|
26
32
|
gz.close
|
|
27
33
|
output.string
|
|
@@ -1,13 +1,47 @@
|
|
|
1
1
|
require 'active_support/core_ext/hash/keys'
|
|
2
2
|
|
|
3
|
-
# This class has dubious semantics and we only have it so that
|
|
4
|
-
# people can write <tt>params[:key]</tt> instead of <tt>params['key']</tt>
|
|
5
|
-
# and they get the same value for both keys.
|
|
6
|
-
|
|
7
3
|
module ActiveSupport
|
|
4
|
+
# Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered
|
|
5
|
+
# to be the same.
|
|
6
|
+
#
|
|
7
|
+
# rgb = ActiveSupport::HashWithIndifferentAccess.new
|
|
8
|
+
#
|
|
9
|
+
# rgb[:black] = '#000000'
|
|
10
|
+
# rgb[:black] # => '#000000'
|
|
11
|
+
# rgb['black'] # => '#000000'
|
|
12
|
+
#
|
|
13
|
+
# rgb['white'] = '#FFFFFF'
|
|
14
|
+
# rgb[:white] # => '#FFFFFF'
|
|
15
|
+
# rgb['white'] # => '#FFFFFF'
|
|
16
|
+
#
|
|
17
|
+
# Internally symbols are mapped to strings when used as keys in the entire
|
|
18
|
+
# writing interface (calling <tt>[]=</tt>, <tt>merge</tt>, etc). This
|
|
19
|
+
# mapping belongs to the public interface. For example, given:
|
|
20
|
+
#
|
|
21
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1)
|
|
22
|
+
#
|
|
23
|
+
# You are guaranteed that the key is returned as a string:
|
|
24
|
+
#
|
|
25
|
+
# hash.keys # => ["a"]
|
|
26
|
+
#
|
|
27
|
+
# Technically other types of keys are accepted:
|
|
28
|
+
#
|
|
29
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1)
|
|
30
|
+
# hash[0] = 0
|
|
31
|
+
# hash # => {"a"=>1, 0=>0}
|
|
32
|
+
#
|
|
33
|
+
# but this class is intended for use cases where strings or symbols are the
|
|
34
|
+
# expected keys and it is convenient to understand both as the same. For
|
|
35
|
+
# example the +params+ hash in Ruby on Rails.
|
|
36
|
+
#
|
|
37
|
+
# Note that core extensions define <tt>Hash#with_indifferent_access</tt>:
|
|
38
|
+
#
|
|
39
|
+
# rgb = { black: '#000000', white: '#FFFFFF' }.with_indifferent_access
|
|
40
|
+
#
|
|
41
|
+
# which may be handy.
|
|
8
42
|
class HashWithIndifferentAccess < Hash
|
|
9
|
-
|
|
10
|
-
#
|
|
43
|
+
# Returns +true+ so that <tt>Array#extract_options!</tt> finds members of
|
|
44
|
+
# this class.
|
|
11
45
|
def extractable_options?
|
|
12
46
|
true
|
|
13
47
|
end
|
|
@@ -43,35 +77,60 @@ module ActiveSupport
|
|
|
43
77
|
end
|
|
44
78
|
end
|
|
45
79
|
|
|
80
|
+
def self.[](*args)
|
|
81
|
+
new.merge!(Hash[*args])
|
|
82
|
+
end
|
|
83
|
+
|
|
46
84
|
alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
|
|
47
85
|
alias_method :regular_update, :update unless method_defined?(:regular_update)
|
|
48
86
|
|
|
49
87
|
# Assigns a new value to the hash:
|
|
50
88
|
#
|
|
51
|
-
# hash = HashWithIndifferentAccess.new
|
|
52
|
-
# hash[:key] =
|
|
89
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new
|
|
90
|
+
# hash[:key] = 'value'
|
|
53
91
|
#
|
|
92
|
+
# This value can be later fetched using either +:key+ or +'key'+.
|
|
54
93
|
def []=(key, value)
|
|
55
|
-
regular_writer(convert_key(key), convert_value(value))
|
|
94
|
+
regular_writer(convert_key(key), convert_value(value, for: :assignment))
|
|
56
95
|
end
|
|
57
96
|
|
|
58
97
|
alias_method :store, :[]=
|
|
59
98
|
|
|
60
|
-
# Updates the
|
|
99
|
+
# Updates the receiver in-place, merging in the hash passed as argument:
|
|
61
100
|
#
|
|
62
|
-
# hash_1 = HashWithIndifferentAccess.new
|
|
63
|
-
# hash_1[:key] =
|
|
101
|
+
# hash_1 = ActiveSupport::HashWithIndifferentAccess.new
|
|
102
|
+
# hash_1[:key] = 'value'
|
|
64
103
|
#
|
|
65
|
-
# hash_2 = HashWithIndifferentAccess.new
|
|
66
|
-
# hash_2[:key] =
|
|
104
|
+
# hash_2 = ActiveSupport::HashWithIndifferentAccess.new
|
|
105
|
+
# hash_2[:key] = 'New Value!'
|
|
67
106
|
#
|
|
68
107
|
# hash_1.update(hash_2) # => {"key"=>"New Value!"}
|
|
69
108
|
#
|
|
109
|
+
# The argument can be either an
|
|
110
|
+
# <tt>ActiveSupport::HashWithIndifferentAccess</tt> or a regular +Hash+.
|
|
111
|
+
# In either case the merge respects the semantics of indifferent access.
|
|
112
|
+
#
|
|
113
|
+
# If the argument is a regular hash with keys +:key+ and +"key"+ only one
|
|
114
|
+
# of the values end up in the receiver, but which one is unspecified.
|
|
115
|
+
#
|
|
116
|
+
# When given a block, the value for duplicated keys will be determined
|
|
117
|
+
# by the result of invoking the block with the duplicated key, the value
|
|
118
|
+
# in the receiver, and the value in +other_hash+. The rules for duplicated
|
|
119
|
+
# keys follow the semantics of indifferent access:
|
|
120
|
+
#
|
|
121
|
+
# hash_1[:key] = 10
|
|
122
|
+
# hash_2['key'] = 12
|
|
123
|
+
# hash_1.update(hash_2) { |key, old, new| old + new } # => {"key"=>22}
|
|
70
124
|
def update(other_hash)
|
|
71
125
|
if other_hash.is_a? HashWithIndifferentAccess
|
|
72
126
|
super(other_hash)
|
|
73
127
|
else
|
|
74
|
-
other_hash.each_pair
|
|
128
|
+
other_hash.each_pair do |key, value|
|
|
129
|
+
if block_given? && key?(key)
|
|
130
|
+
value = yield(convert_key(key), self[key], value)
|
|
131
|
+
end
|
|
132
|
+
regular_writer(convert_key(key), convert_value(value))
|
|
133
|
+
end
|
|
75
134
|
self
|
|
76
135
|
end
|
|
77
136
|
end
|
|
@@ -80,11 +139,10 @@ module ActiveSupport
|
|
|
80
139
|
|
|
81
140
|
# Checks the hash for a key matching the argument passed in:
|
|
82
141
|
#
|
|
83
|
-
# hash = HashWithIndifferentAccess.new
|
|
84
|
-
# hash[
|
|
85
|
-
# hash.key?
|
|
86
|
-
# hash.key?
|
|
87
|
-
#
|
|
142
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new
|
|
143
|
+
# hash['key'] = 'value'
|
|
144
|
+
# hash.key?(:key) # => true
|
|
145
|
+
# hash.key?('key') # => true
|
|
88
146
|
def key?(key)
|
|
89
147
|
super(convert_key(key))
|
|
90
148
|
end
|
|
@@ -96,25 +154,23 @@ module ActiveSupport
|
|
|
96
154
|
# Same as <tt>Hash#fetch</tt> where the key passed as argument can be
|
|
97
155
|
# either a string or a symbol:
|
|
98
156
|
#
|
|
99
|
-
# counters = HashWithIndifferentAccess.new
|
|
157
|
+
# counters = ActiveSupport::HashWithIndifferentAccess.new
|
|
100
158
|
# counters[:foo] = 1
|
|
101
159
|
#
|
|
102
|
-
# counters.fetch(
|
|
160
|
+
# counters.fetch('foo') # => 1
|
|
103
161
|
# counters.fetch(:bar, 0) # => 0
|
|
104
162
|
# counters.fetch(:bar) {|key| 0} # => 0
|
|
105
163
|
# counters.fetch(:zoo) # => KeyError: key not found: "zoo"
|
|
106
|
-
#
|
|
107
164
|
def fetch(key, *extras)
|
|
108
165
|
super(convert_key(key), *extras)
|
|
109
166
|
end
|
|
110
167
|
|
|
111
168
|
# Returns an array of the values at the specified indices:
|
|
112
169
|
#
|
|
113
|
-
# hash = HashWithIndifferentAccess.new
|
|
114
|
-
# hash[:a] =
|
|
115
|
-
# hash[:b] =
|
|
116
|
-
# hash.values_at(
|
|
117
|
-
#
|
|
170
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new
|
|
171
|
+
# hash[:a] = 'x'
|
|
172
|
+
# hash[:b] = 'y'
|
|
173
|
+
# hash.values_at('a', 'b') # => ["x", "y"]
|
|
118
174
|
def values_at(*indices)
|
|
119
175
|
indices.collect {|key| self[convert_key(key)]}
|
|
120
176
|
end
|
|
@@ -126,36 +182,58 @@ module ActiveSupport
|
|
|
126
182
|
end
|
|
127
183
|
end
|
|
128
184
|
|
|
129
|
-
#
|
|
130
|
-
#
|
|
131
|
-
|
|
132
|
-
|
|
185
|
+
# This method has the same semantics of +update+, except it does not
|
|
186
|
+
# modify the receiver but rather returns a new hash with indifferent
|
|
187
|
+
# access with the result of the merge.
|
|
188
|
+
def merge(hash, &block)
|
|
189
|
+
self.dup.update(hash, &block)
|
|
133
190
|
end
|
|
134
191
|
|
|
135
|
-
#
|
|
136
|
-
#
|
|
192
|
+
# Like +merge+ but the other way around: Merges the receiver into the
|
|
193
|
+
# argument and returns a new hash with indifferent access as result:
|
|
194
|
+
#
|
|
195
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new
|
|
196
|
+
# hash['a'] = nil
|
|
197
|
+
# hash.reverse_merge(a: 0, b: 1) # => {"a"=>nil, "b"=>1}
|
|
137
198
|
def reverse_merge(other_hash)
|
|
138
|
-
super
|
|
199
|
+
super(self.class.new_from_hash_copying_default(other_hash))
|
|
139
200
|
end
|
|
140
201
|
|
|
202
|
+
# Same semantics as +reverse_merge+ but modifies the receiver in-place.
|
|
141
203
|
def reverse_merge!(other_hash)
|
|
142
204
|
replace(reverse_merge( other_hash ))
|
|
143
205
|
end
|
|
144
206
|
|
|
145
|
-
#
|
|
207
|
+
# Replaces the contents of this hash with other_hash.
|
|
208
|
+
#
|
|
209
|
+
# h = { "a" => 100, "b" => 200 }
|
|
210
|
+
# h.replace({ "c" => 300, "d" => 400 }) #=> {"c"=>300, "d"=>400}
|
|
211
|
+
def replace(other_hash)
|
|
212
|
+
super(self.class.new_from_hash_copying_default(other_hash))
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# Removes the specified key from the hash.
|
|
146
216
|
def delete(key)
|
|
147
217
|
super(convert_key(key))
|
|
148
218
|
end
|
|
149
219
|
|
|
150
220
|
def stringify_keys!; self end
|
|
221
|
+
def deep_stringify_keys!; self end
|
|
151
222
|
def stringify_keys; dup end
|
|
223
|
+
def deep_stringify_keys; dup end
|
|
152
224
|
undef :symbolize_keys!
|
|
153
|
-
|
|
225
|
+
undef :deep_symbolize_keys!
|
|
226
|
+
def symbolize_keys; to_hash.symbolize_keys! end
|
|
227
|
+
def deep_symbolize_keys; to_hash.deep_symbolize_keys end
|
|
154
228
|
def to_options!; self end
|
|
155
229
|
|
|
156
|
-
# Convert to a
|
|
230
|
+
# Convert to a regular hash with string keys.
|
|
157
231
|
def to_hash
|
|
158
|
-
|
|
232
|
+
_new_hash= {}
|
|
233
|
+
each do |key, value|
|
|
234
|
+
_new_hash[convert_key(key)] = convert_value(value, for: :to_hash)
|
|
235
|
+
end
|
|
236
|
+
Hash.new(default).merge!(_new_hash)
|
|
159
237
|
end
|
|
160
238
|
|
|
161
239
|
protected
|
|
@@ -163,11 +241,18 @@ module ActiveSupport
|
|
|
163
241
|
key.kind_of?(Symbol) ? key.to_s : key
|
|
164
242
|
end
|
|
165
243
|
|
|
166
|
-
def convert_value(value)
|
|
244
|
+
def convert_value(value, options = {})
|
|
167
245
|
if value.is_a? Hash
|
|
168
|
-
|
|
246
|
+
if options[:for] == :to_hash
|
|
247
|
+
value.to_hash
|
|
248
|
+
else
|
|
249
|
+
value.nested_under_indifferent_access
|
|
250
|
+
end
|
|
169
251
|
elsif value.is_a?(Array)
|
|
170
|
-
|
|
252
|
+
unless options[:for] == :assignment
|
|
253
|
+
value = value.dup
|
|
254
|
+
end
|
|
255
|
+
value.map! { |e| convert_value(e, options) }
|
|
171
256
|
else
|
|
172
257
|
value
|
|
173
258
|
end
|
data/lib/active_support/i18n.rb
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
begin
|
|
2
|
+
require 'active_support/core_ext/hash/deep_merge'
|
|
3
|
+
require 'active_support/core_ext/hash/except'
|
|
4
|
+
require 'active_support/core_ext/hash/slice'
|
|
2
5
|
require 'i18n'
|
|
3
6
|
require 'active_support/lazy_load_hooks'
|
|
4
7
|
rescue LoadError => e
|
|
@@ -6,4 +9,5 @@ rescue LoadError => e
|
|
|
6
9
|
raise e
|
|
7
10
|
end
|
|
8
11
|
|
|
12
|
+
ActiveSupport.run_load_hooks(:i18n)
|
|
9
13
|
I18n.load_path << "#{File.dirname(__FILE__)}/locale/en.yml"
|
|
@@ -9,25 +9,6 @@ module I18n
|
|
|
9
9
|
config.i18n.load_path = []
|
|
10
10
|
config.i18n.fallbacks = ActiveSupport::OrderedOptions.new
|
|
11
11
|
|
|
12
|
-
def self.reloader
|
|
13
|
-
@reloader ||= ActiveSupport::FileUpdateChecker.new(reloader_paths){ I18n.reload! }
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def self.reloader_paths
|
|
17
|
-
@reloader_paths ||= []
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
# Add <tt>I18n::Railtie.reloader</tt> to ActionDispatch callbacks. Since, at this
|
|
21
|
-
# point, no path was added to the reloader, I18n.reload! is not triggered
|
|
22
|
-
# on to_prepare callbacks. This will only happen on the config.after_initialize
|
|
23
|
-
# callback below.
|
|
24
|
-
initializer "i18n.callbacks" do |app|
|
|
25
|
-
app.reloaders << I18n::Railtie.reloader
|
|
26
|
-
ActionDispatch::Reloader.to_prepare do
|
|
27
|
-
I18n::Railtie.reloader.execute_if_updated
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
12
|
# Set the i18n configuration after initialization since a lot of
|
|
32
13
|
# configuration is still usually done in application initializers.
|
|
33
14
|
config.after_initialize do |app|
|
|
@@ -35,7 +16,7 @@ module I18n
|
|
|
35
16
|
end
|
|
36
17
|
|
|
37
18
|
# Trigger i18n config before any eager loading has happened
|
|
38
|
-
# so it's ready if any classes require it when eager loaded
|
|
19
|
+
# so it's ready if any classes require it when eager loaded.
|
|
39
20
|
config.before_eager_load do |app|
|
|
40
21
|
I18n::Railtie.initialize_i18n(app)
|
|
41
22
|
end
|
|
@@ -44,7 +25,7 @@ module I18n
|
|
|
44
25
|
|
|
45
26
|
@i18n_inited = false
|
|
46
27
|
|
|
47
|
-
# Setup i18n configuration
|
|
28
|
+
# Setup i18n configuration.
|
|
48
29
|
def self.initialize_i18n(app)
|
|
49
30
|
return if @i18n_inited
|
|
50
31
|
|
|
@@ -63,7 +44,9 @@ module I18n
|
|
|
63
44
|
|
|
64
45
|
init_fallbacks(fallbacks) if fallbacks && validate_fallbacks(fallbacks)
|
|
65
46
|
|
|
66
|
-
|
|
47
|
+
reloader = ActiveSupport::FileUpdateChecker.new(I18n.load_path.dup){ I18n.reload! }
|
|
48
|
+
app.reloaders << reloader
|
|
49
|
+
ActionDispatch::Reloader.to_prepare { reloader.execute_if_updated }
|
|
67
50
|
reloader.execute
|
|
68
51
|
|
|
69
52
|
@i18n_inited = true
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
require 'active_support/inflector/inflections'
|
|
2
2
|
|
|
3
3
|
module ActiveSupport
|
|
4
|
-
Inflector.inflections do |inflect|
|
|
4
|
+
Inflector.inflections(:en) do |inflect|
|
|
5
5
|
inflect.plural(/$/, 's')
|
|
6
6
|
inflect.plural(/s$/i, 's')
|
|
7
|
-
inflect.plural(
|
|
7
|
+
inflect.plural(/^(ax|test)is$/i, '\1es')
|
|
8
8
|
inflect.plural(/(octop|vir)us$/i, '\1i')
|
|
9
9
|
inflect.plural(/(octop|vir)i$/i, '\1i')
|
|
10
10
|
inflect.plural(/(alias|status)$/i, '\1es')
|
|
@@ -18,17 +18,18 @@ module ActiveSupport
|
|
|
18
18
|
inflect.plural(/([^aeiouy]|qu)y$/i, '\1ies')
|
|
19
19
|
inflect.plural(/(x|ch|ss|sh)$/i, '\1es')
|
|
20
20
|
inflect.plural(/(matr|vert|ind)(?:ix|ex)$/i, '\1ices')
|
|
21
|
-
inflect.plural(
|
|
22
|
-
inflect.plural(
|
|
21
|
+
inflect.plural(/^(m|l)ouse$/i, '\1ice')
|
|
22
|
+
inflect.plural(/^(m|l)ice$/i, '\1ice')
|
|
23
23
|
inflect.plural(/^(ox)$/i, '\1en')
|
|
24
24
|
inflect.plural(/^(oxen)$/i, '\1')
|
|
25
25
|
inflect.plural(/(quiz)$/i, '\1zes')
|
|
26
26
|
|
|
27
27
|
inflect.singular(/s$/i, '')
|
|
28
|
+
inflect.singular(/(ss)$/i, '\1')
|
|
28
29
|
inflect.singular(/(n)ews$/i, '\1ews')
|
|
29
30
|
inflect.singular(/([ti])a$/i, '\1um')
|
|
30
|
-
inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, '\
|
|
31
|
-
inflect.singular(/(^analy)ses$/i, '\1sis')
|
|
31
|
+
inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '\1sis')
|
|
32
|
+
inflect.singular(/(^analy)(sis|ses)$/i, '\1sis')
|
|
32
33
|
inflect.singular(/([^f])ves$/i, '\1fe')
|
|
33
34
|
inflect.singular(/(hive)s$/i, '\1')
|
|
34
35
|
inflect.singular(/(tive)s$/i, '\1')
|
|
@@ -37,13 +38,14 @@ module ActiveSupport
|
|
|
37
38
|
inflect.singular(/(s)eries$/i, '\1eries')
|
|
38
39
|
inflect.singular(/(m)ovies$/i, '\1ovie')
|
|
39
40
|
inflect.singular(/(x|ch|ss|sh)es$/i, '\1')
|
|
40
|
-
inflect.singular(
|
|
41
|
-
inflect.singular(/(bus)es
|
|
41
|
+
inflect.singular(/^(m|l)ice$/i, '\1ouse')
|
|
42
|
+
inflect.singular(/(bus)(es)?$/i, '\1')
|
|
42
43
|
inflect.singular(/(o)es$/i, '\1')
|
|
43
44
|
inflect.singular(/(shoe)s$/i, '\1')
|
|
44
|
-
inflect.singular(/(cris|
|
|
45
|
-
inflect.singular(
|
|
46
|
-
inflect.singular(/(
|
|
45
|
+
inflect.singular(/(cris|test)(is|es)$/i, '\1is')
|
|
46
|
+
inflect.singular(/^(a)x[ie]s$/i, '\1xis')
|
|
47
|
+
inflect.singular(/(octop|vir)(us|i)$/i, '\1us')
|
|
48
|
+
inflect.singular(/(alias|status)(es)?$/i, '\1')
|
|
47
49
|
inflect.singular(/^(ox)en/i, '\1')
|
|
48
50
|
inflect.singular(/(vert|ind)ices$/i, '\1ex')
|
|
49
51
|
inflect.singular(/(matr)ices$/i, '\1ix')
|
|
@@ -58,6 +60,6 @@ module ActiveSupport
|
|
|
58
60
|
inflect.irregular('cow', 'kine')
|
|
59
61
|
inflect.irregular('zombie', 'zombies')
|
|
60
62
|
|
|
61
|
-
inflect.uncountable(%w(equipment information rice money species series fish sheep jeans))
|
|
63
|
+
inflect.uncountable(%w(equipment information rice money species series fish sheep jeans police))
|
|
62
64
|
end
|
|
63
65
|
end
|