activesupport 3.2.22.5 → 4.0.0.beta1
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 +325 -136
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -2
- data/lib/active_support.rb +8 -21
- 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.rb +203 -171
- data/lib/active_support/cache/file_store.rb +12 -12
- 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/callbacks.rb +195 -247
- 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.rb +1 -0
- data/lib/active_support/core_ext/array.rb +0 -1
- data/lib/active_support/core_ext/array/access.rb +17 -9
- data/lib/active_support/core_ext/array/conversions.rb +113 -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 +11 -14
- data/lib/active_support/core_ext/big_decimal/conversions.rb +7 -24
- data/lib/active_support/core_ext/class/attribute.rb +12 -8
- 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.rb +6 -0
- data/lib/active_support/core_ext/date/calculations.rb +34 -188
- data/lib/active_support/core_ext/date/conversions.rb +16 -38
- data/lib/active_support/core_ext/date/infinite_comparable.rb +5 -0
- data/lib/active_support/core_ext/date/zones.rb +25 -2
- data/lib/active_support/core_ext/date_and_time/calculations.rb +232 -0
- data/lib/active_support/core_ext/date_time.rb +5 -0
- data/lib/active_support/core_ext/date_time/acts_like.rb +0 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +73 -65
- data/lib/active_support/core_ext/date_time/conversions.rb +21 -33
- data/lib/active_support/core_ext/date_time/infinite_comparable.rb +5 -0
- data/lib/active_support/core_ext/date_time/zones.rb +11 -8
- data/lib/active_support/core_ext/enumerable.rb +26 -73
- data/lib/active_support/core_ext/file.rb +0 -1
- data/lib/active_support/core_ext/file/atomic.rb +27 -11
- data/lib/active_support/core_ext/hash.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/infinite_comparable.rb +35 -0
- 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 +19 -0
- data/lib/active_support/core_ext/module.rb +1 -3
- 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 +57 -40
- 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/numeric.rb +2 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +135 -0
- data/lib/active_support/core_ext/numeric/infinite_comparable.rb +9 -0
- data/lib/active_support/core_ext/numeric/time.rb +6 -6
- data/lib/active_support/core_ext/object.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 +6 -6
- 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/proc.rb +3 -0
- data/lib/active_support/core_ext/range.rb +0 -2
- data/lib/active_support/core_ext/range/conversions.rb +0 -2
- data/lib/active_support/core_ext/range/include_range.rb +1 -1
- data/lib/active_support/core_ext/range/overlaps.rb +1 -1
- data/lib/active_support/core_ext/string.rb +2 -2
- data/lib/active_support/core_ext/string/access.rb +95 -90
- data/lib/active_support/core_ext/string/conversions.rb +29 -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/struct.rb +6 -0
- data/lib/active_support/core_ext/thread.rb +74 -0
- data/lib/active_support/core_ext/time.rb +6 -0
- data/lib/active_support/core_ext/time/calculations.rb +105 -193
- data/lib/active_support/core_ext/time/conversions.rb +27 -51
- data/lib/active_support/core_ext/time/infinite_comparable.rb +5 -0
- 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/uri.rb +13 -17
- data/lib/active_support/dependencies.rb +160 -141
- data/lib/active_support/dependencies/autoload.rb +47 -20
- data/lib/active_support/deprecation.rb +39 -14
- 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/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 +112 -37
- 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.rb +56 -36
- data/lib/active_support/log_subscriber/test_helper.rb +18 -15
- data/lib/active_support/logger.rb +57 -0
- data/lib/active_support/logger_silence.rb +24 -0
- data/lib/active_support/message_encryptor.rb +32 -29
- data/lib/active_support/message_verifier.rb +8 -14
- data/lib/active_support/multibyte.rb +5 -28
- data/lib/active_support/multibyte/chars.rb +80 -333
- data/lib/active_support/multibyte/unicode.rb +74 -64
- data/lib/active_support/notifications.rb +57 -25
- data/lib/active_support/notifications/fanout.rb +105 -18
- data/lib/active_support/notifications/instrumenter.rb +32 -13
- data/lib/active_support/number_helper.rb +636 -0
- data/lib/active_support/ordered_hash.rb +8 -190
- data/lib/active_support/ordered_options.rb +21 -23
- 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/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 +52 -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 +25 -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 +78 -43
- data/lib/active_support/values/time_zone.rb +77 -58
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/version.rb +4 -4
- data/lib/active_support/xml_mini.rb +35 -17
- data/lib/active_support/xml_mini/jdom.rb +9 -17
- data/lib/active_support/xml_mini/libxml.rb +1 -2
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -2
- data/lib/active_support/xml_mini/nokogiri.rb +1 -2
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -2
- data/lib/active_support/xml_mini/rexml.rb +6 -8
- metadata +107 -77
- 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.rb +0 -1
- data/lib/active_support/core_ext/float/rounding.rb +0 -19
- 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.rb +0 -1
- data/lib/active_support/core_ext/process/daemon.rb +0 -23
- 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/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.rb +0 -317
- 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.rb +0 -152
- 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/time/autoload.rb +0 -5
- data/lib/active_support/whiny_nil.rb +0 -24
@@ -17,8 +17,8 @@ class Array
|
|
17
17
|
# args.extract_options!
|
18
18
|
# end
|
19
19
|
#
|
20
|
-
# options(1, 2)
|
21
|
-
# options(1, 2, :
|
20
|
+
# options(1, 2) # => {}
|
21
|
+
# options(1, 2, a: :b) # => {:a=>:b}
|
22
22
|
def extract_options!
|
23
23
|
if last.is_a?(Hash) && last.extractable_options?
|
24
24
|
pop
|
@@ -1,21 +1,22 @@
|
|
1
|
-
require 'enumerator'
|
2
|
-
|
3
1
|
class Array
|
4
2
|
# Splits or iterates over the array in groups of size +number+,
|
5
3
|
# padding any remaining slots with +fill_with+ unless it is +false+.
|
6
4
|
#
|
7
|
-
# %w(1 2 3 4 5 6 7).in_groups_of(3) {|group| p group}
|
5
|
+
# %w(1 2 3 4 5 6 7 8 9 10).in_groups_of(3) {|group| p group}
|
8
6
|
# ["1", "2", "3"]
|
9
7
|
# ["4", "5", "6"]
|
10
|
-
# ["7",
|
8
|
+
# ["7", "8", "9"]
|
9
|
+
# ["10", nil, nil]
|
11
10
|
#
|
12
|
-
# %w(1 2 3).in_groups_of(2, ' ') {|group| p group}
|
11
|
+
# %w(1 2 3 4 5).in_groups_of(2, ' ') {|group| p group}
|
13
12
|
# ["1", "2"]
|
14
|
-
# ["3", "
|
13
|
+
# ["3", "4"]
|
14
|
+
# ["5", " "]
|
15
15
|
#
|
16
|
-
# %w(1 2 3).in_groups_of(2, false) {|group| p group}
|
16
|
+
# %w(1 2 3 4 5).in_groups_of(2, false) {|group| p group}
|
17
17
|
# ["1", "2"]
|
18
|
-
# ["3"]
|
18
|
+
# ["3", "4"]
|
19
|
+
# ["5"]
|
19
20
|
def in_groups_of(number, fill_with = nil)
|
20
21
|
if fill_with == false
|
21
22
|
collection = self
|
@@ -44,10 +45,10 @@ class Array
|
|
44
45
|
# ["5", "6", "7", nil]
|
45
46
|
# ["8", "9", "10", nil]
|
46
47
|
#
|
47
|
-
# %w(1 2 3 4 5 6 7).in_groups(3, ' ') {|group| p group}
|
48
|
-
# ["1", "2", "3"]
|
49
|
-
# ["
|
50
|
-
# ["
|
48
|
+
# %w(1 2 3 4 5 6 7 8 9 10).in_groups(3, ' ') {|group| p group}
|
49
|
+
# ["1", "2", "3", "4"]
|
50
|
+
# ["5", "6", "7", " "]
|
51
|
+
# ["8", "9", "10", " "]
|
51
52
|
#
|
52
53
|
# %w(1 2 3 4 5 6 7).in_groups(3, false) {|group| p group}
|
53
54
|
# ["1", "2", "3"]
|
@@ -57,7 +58,7 @@ class Array
|
|
57
58
|
# size / number gives minor group size;
|
58
59
|
# size % number gives how many objects need extra accommodation;
|
59
60
|
# each group hold either division or division + 1 items.
|
60
|
-
division = size
|
61
|
+
division = size.div number
|
61
62
|
modulo = size % number
|
62
63
|
|
63
64
|
# create a new array avoiding dup
|
@@ -66,9 +67,9 @@ class Array
|
|
66
67
|
|
67
68
|
number.times do |index|
|
68
69
|
length = division + (modulo > 0 && modulo > index ? 1 : 0)
|
69
|
-
|
70
|
-
|
71
|
-
|
70
|
+
groups << last_group = slice(start, length)
|
71
|
+
last_group << fill_with if fill_with != false &&
|
72
|
+
modulo > 0 && length == division
|
72
73
|
start += length
|
73
74
|
end
|
74
75
|
|
@@ -82,13 +83,11 @@ class Array
|
|
82
83
|
# Divides the array into one or more subarrays based on a delimiting +value+
|
83
84
|
# or the result of an optional block.
|
84
85
|
#
|
85
|
-
# [1, 2, 3, 4, 5].split(3)
|
86
|
-
# (1..10).to_a.split { |i| i % 3 == 0 }
|
87
|
-
def split(value = nil)
|
88
|
-
using_block = block_given?
|
89
|
-
|
86
|
+
# [1, 2, 3, 4, 5].split(3) # => [[1, 2], [4, 5]]
|
87
|
+
# (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]]
|
88
|
+
def split(value = nil, &block)
|
90
89
|
inject([[]]) do |results, element|
|
91
|
-
if
|
90
|
+
if block && block.call(element) || value == element
|
92
91
|
results << []
|
93
92
|
else
|
94
93
|
results.last << element
|
@@ -1,16 +1,19 @@
|
|
1
1
|
class Array
|
2
|
-
#
|
2
|
+
# *DEPRECATED*: Use +Array#uniq+ instead.
|
3
3
|
#
|
4
|
-
#
|
4
|
+
# Returns a unique array based on the criteria in the block.
|
5
5
|
#
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
# [1, 2, 3, 4].uniq_by { |i| i.odd? } # => [1, 2]
|
7
|
+
def uniq_by(&block)
|
8
|
+
ActiveSupport::Deprecation.warn 'uniq_by is deprecated. Use Array#uniq instead'
|
9
|
+
uniq(&block)
|
10
10
|
end
|
11
11
|
|
12
|
-
#
|
13
|
-
|
14
|
-
|
12
|
+
# *DEPRECATED*: Use +Array#uniq!+ instead.
|
13
|
+
#
|
14
|
+
# Same as +uniq_by+, but modifies +self+.
|
15
|
+
def uniq_by!(&block)
|
16
|
+
ActiveSupport::Deprecation.warn 'uniq_by! is deprecated. Use Array#uniq! instead'
|
17
|
+
uniq!(&block)
|
15
18
|
end
|
16
19
|
end
|
@@ -7,35 +7,32 @@ class Array
|
|
7
7
|
# * Otherwise, if the argument responds to +to_ary+ it is invoked, and its result returned.
|
8
8
|
# * Otherwise, returns an array with the argument as its single element.
|
9
9
|
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
10
|
+
# Array.wrap(nil) # => []
|
11
|
+
# Array.wrap([1, 2, 3]) # => [1, 2, 3]
|
12
|
+
# Array.wrap(0) # => [0]
|
13
13
|
#
|
14
14
|
# This method is similar in purpose to <tt>Kernel#Array</tt>, but there are some differences:
|
15
15
|
#
|
16
16
|
# * If the argument responds to +to_ary+ the method is invoked. <tt>Kernel#Array</tt>
|
17
|
-
#
|
18
|
-
#
|
17
|
+
# moves on to try +to_a+ if the returned value is +nil+, but <tt>Array.wrap</tt> returns
|
18
|
+
# such a +nil+ right away.
|
19
19
|
# * If the returned value from +to_ary+ is neither +nil+ nor an +Array+ object, <tt>Kernel#Array</tt>
|
20
|
-
#
|
20
|
+
# raises an exception, while <tt>Array.wrap</tt> does not, it just returns the value.
|
21
21
|
# * It does not call +to_a+ on the argument, though special-cases +nil+ to return an empty array.
|
22
22
|
#
|
23
23
|
# The last point is particularly worth comparing for some enumerables:
|
24
24
|
#
|
25
|
-
# Array(:
|
26
|
-
# Array.wrap(:
|
27
|
-
#
|
28
|
-
# Array("foo\nbar") # => ["foo\n", "bar"], in Ruby 1.8
|
29
|
-
# Array.wrap("foo\nbar") # => ["foo\nbar"]
|
25
|
+
# Array(foo: :bar) # => [[:foo, :bar]]
|
26
|
+
# Array.wrap(foo: :bar) # => [{:foo=>:bar}]
|
30
27
|
#
|
31
28
|
# There's also a related idiom that uses the splat operator:
|
32
29
|
#
|
33
30
|
# [*object]
|
34
31
|
#
|
35
|
-
# which returns <tt>[
|
32
|
+
# which for +nil+ returns <tt>[]</tt>, and calls to <tt>Array(object)</tt> otherwise.
|
36
33
|
#
|
37
|
-
# Thus, in this case the behavior
|
38
|
-
# <tt>Kernel#Array</tt> explained above apply to the rest of
|
34
|
+
# Thus, in this case the behavior may be different for +nil+, and the differences with
|
35
|
+
# <tt>Kernel#Array</tt> explained above apply to the rest of <tt>object</tt>s.
|
39
36
|
def self.wrap(object)
|
40
37
|
if object.nil?
|
41
38
|
[]
|
@@ -1,31 +1,9 @@
|
|
1
1
|
require 'bigdecimal'
|
2
|
-
|
3
|
-
begin
|
4
|
-
require 'psych'
|
5
|
-
rescue LoadError
|
6
|
-
end
|
7
|
-
|
8
2
|
require 'yaml'
|
9
3
|
|
10
4
|
class BigDecimal
|
11
|
-
YAML_TAG = 'tag:yaml.org,2002:float'
|
12
5
|
YAML_MAPPING = { 'Infinity' => '.Inf', '-Infinity' => '-.Inf', 'NaN' => '.NaN' }
|
13
6
|
|
14
|
-
# This emits the number without any scientific notation.
|
15
|
-
# This is better than self.to_f.to_s since it doesn't lose precision.
|
16
|
-
#
|
17
|
-
# Note that reconstituting YAML floats to native floats may lose precision.
|
18
|
-
def to_yaml(opts = {})
|
19
|
-
return super if
|
20
|
-
(defined?(YAML::ENGINE) && !YAML::ENGINE.syck?) ||
|
21
|
-
(defined?(Psych) && YAML == Psych)
|
22
|
-
|
23
|
-
YAML.quick_emit(nil, opts) do |out|
|
24
|
-
string = to_s
|
25
|
-
out.scalar(YAML_TAG, YAML_MAPPING[string] || string, :plain)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
7
|
def encode_with(coder)
|
30
8
|
string = to_s
|
31
9
|
coder.represent_scalar(nil, YAML_MAPPING[string] || string)
|
@@ -39,8 +17,13 @@ class BigDecimal
|
|
39
17
|
end
|
40
18
|
|
41
19
|
DEFAULT_STRING_FORMAT = 'F'
|
42
|
-
def to_formatted_s(
|
43
|
-
|
20
|
+
def to_formatted_s(*args)
|
21
|
+
if args[0].is_a?(Symbol)
|
22
|
+
super
|
23
|
+
else
|
24
|
+
format = args[0] || DEFAULT_STRING_FORMAT
|
25
|
+
_original_to_s(format)
|
26
|
+
end
|
44
27
|
end
|
45
28
|
alias_method :_original_to_s, :to_s
|
46
29
|
alias_method :to_s, :to_formatted_s
|
@@ -57,19 +57,25 @@ class Class
|
|
57
57
|
# object.setting # => false
|
58
58
|
# Base.setting # => true
|
59
59
|
#
|
60
|
-
# To opt out of the instance reader method, pass :
|
60
|
+
# To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
|
61
61
|
#
|
62
62
|
# object.setting # => NoMethodError
|
63
63
|
# object.setting? # => NoMethodError
|
64
64
|
#
|
65
|
-
# To opt out of the instance writer method, pass :
|
65
|
+
# To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
|
66
66
|
#
|
67
67
|
# object.setting = false # => NoMethodError
|
68
|
+
#
|
69
|
+
# To opt out of both instance methods, pass <tt>instance_accessor: false</tt>.
|
68
70
|
def class_attribute(*attrs)
|
69
71
|
options = attrs.extract_options!
|
70
|
-
|
71
|
-
|
72
|
+
# double assignment is used to avoid "assigned but unused variable" warning
|
73
|
+
instance_reader = instance_reader = options.fetch(:instance_accessor, true) && options.fetch(:instance_reader, true)
|
74
|
+
instance_writer = options.fetch(:instance_accessor, true) && options.fetch(:instance_writer, true)
|
72
75
|
|
76
|
+
# We use class_eval here rather than define_method because class_attribute
|
77
|
+
# may be used in a performance sensitive context therefore the overhead that
|
78
|
+
# define_method introduces may become significant.
|
73
79
|
attrs.each do |name|
|
74
80
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
75
81
|
def self.#{name}() nil end
|
@@ -109,9 +115,7 @@ class Class
|
|
109
115
|
end
|
110
116
|
|
111
117
|
private
|
112
|
-
|
113
|
-
|
114
|
-
ancestors.first != self
|
115
|
-
end
|
118
|
+
def singleton_class?
|
119
|
+
ancestors.first != self
|
116
120
|
end
|
117
121
|
end
|
@@ -21,17 +21,18 @@ class Class
|
|
21
21
|
# end
|
22
22
|
# # => NameError: invalid attribute name
|
23
23
|
#
|
24
|
-
# If you want to opt out the instance reader method, you can pass <tt
|
25
|
-
# or <tt
|
24
|
+
# If you want to opt out the instance reader method, you can pass <tt>instance_reader: false</tt>
|
25
|
+
# or <tt>instance_accessor: false</tt>.
|
26
26
|
#
|
27
27
|
# class Person
|
28
|
-
# cattr_reader :hair_colors, :
|
28
|
+
# cattr_reader :hair_colors, instance_reader: false
|
29
29
|
# end
|
30
30
|
#
|
31
31
|
# Person.new.hair_colors # => NoMethodError
|
32
32
|
def cattr_reader(*syms)
|
33
33
|
options = syms.extract_options!
|
34
34
|
syms.each do |sym|
|
35
|
+
raise NameError.new('invalid attribute name') unless sym =~ /^[_A-Za-z]\w*$/
|
35
36
|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
36
37
|
unless defined? @@#{sym}
|
37
38
|
@@#{sym} = nil
|
@@ -71,11 +72,11 @@ class Class
|
|
71
72
|
# end
|
72
73
|
# # => NameError: invalid attribute name
|
73
74
|
#
|
74
|
-
# If you want to opt out the instance writer method, pass <tt
|
75
|
-
# or <tt
|
75
|
+
# If you want to opt out the instance writer method, pass <tt>instance_writer: false</tt>
|
76
|
+
# or <tt>instance_accessor: false</tt>.
|
76
77
|
#
|
77
78
|
# class Person
|
78
|
-
# cattr_writer :hair_colors, :
|
79
|
+
# cattr_writer :hair_colors, instance_writer: false
|
79
80
|
# end
|
80
81
|
#
|
81
82
|
# Person.new.hair_colors = [:blonde, :red] # => NoMethodError
|
@@ -92,6 +93,7 @@ class Class
|
|
92
93
|
def cattr_writer(*syms)
|
93
94
|
options = syms.extract_options!
|
94
95
|
syms.each do |sym|
|
96
|
+
raise NameError.new('invalid attribute name') unless sym =~ /^[_A-Za-z]\w*$/
|
95
97
|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
96
98
|
unless defined? @@#{sym}
|
97
99
|
@@#{sym} = nil
|
@@ -109,7 +111,7 @@ class Class
|
|
109
111
|
end
|
110
112
|
EOS
|
111
113
|
end
|
112
|
-
|
114
|
+
send("#{sym}=", yield) if block_given?
|
113
115
|
end
|
114
116
|
end
|
115
117
|
|
@@ -133,20 +135,20 @@ class Class
|
|
133
135
|
# Male.hair_colors << :blue
|
134
136
|
# Person.hair_colors # => [:brown, :black, :blonde, :red, :blue]
|
135
137
|
#
|
136
|
-
# To opt out of the instance writer method, pass <tt
|
137
|
-
# To opt out of the instance reader method, pass <tt
|
138
|
+
# To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
|
139
|
+
# To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
|
138
140
|
#
|
139
141
|
# class Person
|
140
|
-
# cattr_accessor :hair_colors, :
|
142
|
+
# cattr_accessor :hair_colors, instance_writer: false, instance_reader: false
|
141
143
|
# end
|
142
144
|
#
|
143
145
|
# Person.new.hair_colors = [:brown] # => NoMethodError
|
144
146
|
# Person.new.hair_colors # => NoMethodError
|
145
147
|
#
|
146
|
-
# Or pass <tt
|
148
|
+
# Or pass <tt>instance_accessor: false</tt>, to opt out both instance methods.
|
147
149
|
#
|
148
150
|
# class Person
|
149
|
-
# cattr_accessor :hair_colors, :
|
151
|
+
# cattr_accessor :hair_colors, instance_accessor: false
|
150
152
|
# end
|
151
153
|
#
|
152
154
|
# Person.new.hair_colors = [:brown] # => NoMethodError
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'active_support/core_ext/object/blank'
|
2
|
-
require 'active_support/core_ext/array/extract_options'
|
3
1
|
require 'active_support/core_ext/kernel/singleton_class'
|
4
2
|
require 'active_support/core_ext/module/remove_method'
|
5
3
|
|
@@ -22,23 +20,21 @@ class Class
|
|
22
20
|
define_method("#{name}?") { !!send("#{name}") } if options[:instance_reader] != false
|
23
21
|
end
|
24
22
|
|
25
|
-
private
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
define_method(method) { object } if instance_reader
|
35
|
-
end
|
36
|
-
|
37
|
-
def _superclass_delegating_accessor(name, options = {})
|
38
|
-
singleton_class.send(:define_method, "#{name}=") do |value|
|
39
|
-
_stash_object_in_method(value, name, options[:instance_reader] != false)
|
23
|
+
private
|
24
|
+
# Take the object being set and store it in a method. This gives us automatic
|
25
|
+
# inheritance behavior, without having to store the object in an instance
|
26
|
+
# variable and look up the superclass chain manually.
|
27
|
+
def _stash_object_in_method(object, method, instance_reader = true)
|
28
|
+
singleton_class.remove_possible_method(method)
|
29
|
+
singleton_class.send(:define_method, method) { object }
|
30
|
+
remove_possible_method(method)
|
31
|
+
define_method(method) { object } if instance_reader
|
40
32
|
end
|
41
|
-
send("#{name}=", nil)
|
42
|
-
end
|
43
33
|
|
34
|
+
def _superclass_delegating_accessor(name, options = {})
|
35
|
+
singleton_class.send(:define_method, "#{name}=") do |value|
|
36
|
+
_stash_object_in_method(value, name, options[:instance_reader] != false)
|
37
|
+
end
|
38
|
+
send("#{name}=", nil)
|
39
|
+
end
|
44
40
|
end
|
@@ -1,19 +1,19 @@
|
|
1
1
|
require 'active_support/core_ext/module/anonymous'
|
2
2
|
require 'active_support/core_ext/module/reachable'
|
3
3
|
|
4
|
-
class Class
|
4
|
+
class Class
|
5
5
|
begin
|
6
6
|
ObjectSpace.each_object(Class.new) {}
|
7
7
|
|
8
|
-
def descendants
|
8
|
+
def descendants # :nodoc:
|
9
9
|
descendants = []
|
10
|
-
ObjectSpace.each_object(
|
10
|
+
ObjectSpace.each_object(singleton_class) do |k|
|
11
11
|
descendants.unshift k unless k == self
|
12
12
|
end
|
13
13
|
descendants
|
14
14
|
end
|
15
15
|
rescue StandardError # JRuby
|
16
|
-
def descendants
|
16
|
+
def descendants # :nodoc:
|
17
17
|
descendants = []
|
18
18
|
ObjectSpace.each_object(Class) do |k|
|
19
19
|
descendants.unshift k if k < self
|
@@ -25,7 +25,13 @@ class Class #:nodoc:
|
|
25
25
|
|
26
26
|
# Returns an array with the direct children of +self+.
|
27
27
|
#
|
28
|
-
# Integer.subclasses # => [
|
28
|
+
# Integer.subclasses # => [Fixnum, Bignum]
|
29
|
+
#
|
30
|
+
# class Foo; end
|
31
|
+
# class Bar < Foo; end
|
32
|
+
# class Baz < Bar; end
|
33
|
+
#
|
34
|
+
# Foo.subclasses # => [Bar]
|
29
35
|
def subclasses
|
30
36
|
subclasses, chain = [], descendants
|
31
37
|
chain.each do |k|
|
@@ -3,29 +3,35 @@ require 'active_support/duration'
|
|
3
3
|
require 'active_support/core_ext/object/acts_like'
|
4
4
|
require 'active_support/core_ext/date/zones'
|
5
5
|
require 'active_support/core_ext/time/zones'
|
6
|
+
require 'active_support/core_ext/date_and_time/calculations'
|
6
7
|
|
7
8
|
class Date
|
8
|
-
|
9
|
+
include DateAndTime::Calculations
|
9
10
|
|
10
|
-
|
11
|
-
|
11
|
+
class << self
|
12
|
+
attr_accessor :beginning_of_week_default
|
12
13
|
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
14
|
+
# Returns the week start (e.g. :monday) for the current request, if this has been set (via Date.beginning_of_week=).
|
15
|
+
# If <tt>Date.beginning_of_week</tt> has not been set for the current request, returns the week start specified in <tt>config.beginning_of_week</tt>.
|
16
|
+
# If no config.beginning_of_week was specified, returns :monday.
|
17
|
+
def beginning_of_week
|
18
|
+
Thread.current[:beginning_of_week] || beginning_of_week_default || :monday
|
19
|
+
end
|
20
|
+
|
21
|
+
# Sets <tt>Date.beginning_of_week</tt> to a week start (e.g. :monday) for current request/thread.
|
22
|
+
#
|
23
|
+
# This method accepts any of the following day symbols:
|
24
|
+
# :monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday
|
25
|
+
def beginning_of_week=(week_start)
|
26
|
+
Thread.current[:beginning_of_week] = find_beginning_of_week!(week_start)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns week start day symbol (e.g. :monday), or raises an ArgumentError for invalid day symbol.
|
30
|
+
def find_beginning_of_week!(week_start)
|
31
|
+
raise ArgumentError, "Invalid beginning of week: #{week_start}" unless ::Date::DAYS_INTO_WEEK.key?(week_start)
|
32
|
+
week_start
|
25
33
|
end
|
26
|
-
end
|
27
34
|
|
28
|
-
class << self
|
29
35
|
# Returns a new Date representing the date 1 day ago (i.e. yesterday's date).
|
30
36
|
def yesterday
|
31
37
|
::Date.current.yesterday
|
@@ -42,37 +48,22 @@ class Date
|
|
42
48
|
end
|
43
49
|
end
|
44
50
|
|
45
|
-
# Returns true if the Date object's date lies in the past. Otherwise returns false.
|
46
|
-
def past?
|
47
|
-
self < ::Date.current
|
48
|
-
end
|
49
|
-
|
50
|
-
# Returns true if the Date object's date is today.
|
51
|
-
def today?
|
52
|
-
self.to_date == ::Date.current # we need the to_date because of DateTime
|
53
|
-
end
|
54
|
-
|
55
|
-
# Returns true if the Date object's date lies in the future.
|
56
|
-
def future?
|
57
|
-
self > ::Date.current
|
58
|
-
end
|
59
|
-
|
60
51
|
# Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00)
|
61
52
|
# and then subtracts the specified number of seconds.
|
62
53
|
def ago(seconds)
|
63
|
-
|
54
|
+
in_time_zone.since(-seconds)
|
64
55
|
end
|
65
56
|
|
66
57
|
# Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00)
|
67
58
|
# and then adds the specified number of seconds
|
68
59
|
def since(seconds)
|
69
|
-
|
60
|
+
in_time_zone.since(seconds)
|
70
61
|
end
|
71
62
|
alias :in :since
|
72
63
|
|
73
64
|
# Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00)
|
74
65
|
def beginning_of_day
|
75
|
-
|
66
|
+
in_time_zone
|
76
67
|
end
|
77
68
|
alias :midnight :beginning_of_day
|
78
69
|
alias :at_midnight :beginning_of_day
|
@@ -80,8 +71,9 @@ class Date
|
|
80
71
|
|
81
72
|
# Converts Date to a Time (or DateTime if necessary) with the time portion set to the end of the day (23:59:59)
|
82
73
|
def end_of_day
|
83
|
-
|
74
|
+
in_time_zone.end_of_day
|
84
75
|
end
|
76
|
+
alias :at_end_of_day :end_of_day
|
85
77
|
|
86
78
|
def plus_with_duration(other) #:nodoc:
|
87
79
|
if ActiveSupport::Duration === other
|
@@ -116,161 +108,15 @@ class Date
|
|
116
108
|
end
|
117
109
|
|
118
110
|
# Returns a new Date where one or more of the elements have been changed according to the +options+ parameter.
|
111
|
+
# The +options+ parameter is a hash with a combination of these keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>.
|
119
112
|
#
|
120
|
-
#
|
121
|
-
#
|
122
|
-
# Date.new(2007, 5, 12).change(:day => 1) # => Date.new(2007, 5, 1)
|
123
|
-
# Date.new(2007, 5, 12).change(:year => 2005, :month => 1) # => Date.new(2005, 1, 12)
|
113
|
+
# Date.new(2007, 5, 12).change(day: 1) # => Date.new(2007, 5, 1)
|
114
|
+
# Date.new(2007, 5, 12).change(year: 2005, month: 1) # => Date.new(2005, 1, 12)
|
124
115
|
def change(options)
|
125
116
|
::Date.new(
|
126
|
-
options
|
127
|
-
options
|
128
|
-
options
|
117
|
+
options.fetch(:year, year),
|
118
|
+
options.fetch(:month, month),
|
119
|
+
options.fetch(:day, day)
|
129
120
|
)
|
130
121
|
end
|
131
|
-
|
132
|
-
# Returns a new Date/DateTime representing the time a number of specified weeks ago.
|
133
|
-
def weeks_ago(weeks)
|
134
|
-
advance(:weeks => -weeks)
|
135
|
-
end
|
136
|
-
|
137
|
-
# Returns a new Date/DateTime representing the time a number of specified months ago.
|
138
|
-
def months_ago(months)
|
139
|
-
advance(:months => -months)
|
140
|
-
end
|
141
|
-
|
142
|
-
# Returns a new Date/DateTime representing the time a number of specified months in the future.
|
143
|
-
def months_since(months)
|
144
|
-
advance(:months => months)
|
145
|
-
end
|
146
|
-
|
147
|
-
# Returns a new Date/DateTime representing the time a number of specified years ago.
|
148
|
-
def years_ago(years)
|
149
|
-
advance(:years => -years)
|
150
|
-
end
|
151
|
-
|
152
|
-
# Returns a new Date/DateTime representing the time a number of specified years in the future.
|
153
|
-
def years_since(years)
|
154
|
-
advance(:years => years)
|
155
|
-
end
|
156
|
-
|
157
|
-
# Shorthand for years_ago(1)
|
158
|
-
def prev_year
|
159
|
-
years_ago(1)
|
160
|
-
end unless method_defined?(:prev_year)
|
161
|
-
|
162
|
-
# Shorthand for years_since(1)
|
163
|
-
def next_year
|
164
|
-
years_since(1)
|
165
|
-
end unless method_defined?(:next_year)
|
166
|
-
|
167
|
-
# Shorthand for months_ago(1)
|
168
|
-
def prev_month
|
169
|
-
months_ago(1)
|
170
|
-
end unless method_defined?(:prev_month)
|
171
|
-
|
172
|
-
# Shorthand for months_since(1)
|
173
|
-
def next_month
|
174
|
-
months_since(1)
|
175
|
-
end unless method_defined?(:next_month)
|
176
|
-
|
177
|
-
# Returns number of days to start of this week. Week is assumed to start on
|
178
|
-
# +start_day+, default is +:monday+.
|
179
|
-
def days_to_week_start(start_day = :monday)
|
180
|
-
start_day_number = DAYS_INTO_WEEK[start_day]
|
181
|
-
current_day_number = wday != 0 ? wday - 1 : 6
|
182
|
-
(current_day_number - start_day_number) % 7
|
183
|
-
end
|
184
|
-
|
185
|
-
# Returns a new +Date+/+DateTime+ representing the start of this week. Week is
|
186
|
-
# assumed to start on +start_day+, default is +:monday+. +DateTime+ objects
|
187
|
-
# have their time set to 0:00.
|
188
|
-
def beginning_of_week(start_day = :monday)
|
189
|
-
days_to_start = days_to_week_start(start_day)
|
190
|
-
result = self - days_to_start
|
191
|
-
acts_like?(:time) ? result.midnight : result
|
192
|
-
end
|
193
|
-
alias :at_beginning_of_week :beginning_of_week
|
194
|
-
|
195
|
-
# Returns a new +Date+/+DateTime+ representing the start of this week. Week is
|
196
|
-
# assumed to start on a Monday. +DateTime+ objects have their time set to 0:00.
|
197
|
-
def monday
|
198
|
-
beginning_of_week
|
199
|
-
end
|
200
|
-
|
201
|
-
# Returns a new +Date+/+DateTime+ representing the end of this week. Week is
|
202
|
-
# assumed to start on +start_day+, default is +:monday+. +DateTime+ objects
|
203
|
-
# have their time set to 23:59:59.
|
204
|
-
def end_of_week(start_day = :monday)
|
205
|
-
days_to_end = 6 - days_to_week_start(start_day)
|
206
|
-
result = self + days_to_end.days
|
207
|
-
self.acts_like?(:time) ? result.end_of_day : result
|
208
|
-
end
|
209
|
-
alias :at_end_of_week :end_of_week
|
210
|
-
|
211
|
-
# Returns a new +Date+/+DateTime+ representing the end of this week. Week is
|
212
|
-
# assumed to start on a Monday. +DateTime+ objects have their time set to 23:59:59.
|
213
|
-
def sunday
|
214
|
-
end_of_week
|
215
|
-
end
|
216
|
-
|
217
|
-
# Returns a new +Date+/+DateTime+ representing the given +day+ in the previous
|
218
|
-
# week. Default is +:monday+. +DateTime+ objects have their time set to 0:00.
|
219
|
-
def prev_week(day = :monday)
|
220
|
-
result = (self - 7).beginning_of_week + DAYS_INTO_WEEK[day]
|
221
|
-
self.acts_like?(:time) ? result.change(:hour => 0) : result
|
222
|
-
end
|
223
|
-
|
224
|
-
# Returns a new Date/DateTime representing the start of the given day in next week (default is :monday).
|
225
|
-
def next_week(day = :monday)
|
226
|
-
result = (self + 7).beginning_of_week + DAYS_INTO_WEEK[day]
|
227
|
-
self.acts_like?(:time) ? result.change(:hour => 0) : result
|
228
|
-
end
|
229
|
-
|
230
|
-
# Returns a new ; DateTime objects will have time set to 0:00DateTime representing the start of the month (1st of the month; DateTime objects will have time set to 0:00)
|
231
|
-
def beginning_of_month
|
232
|
-
self.acts_like?(:time) ? change(:day => 1, :hour => 0) : change(:day => 1)
|
233
|
-
end
|
234
|
-
alias :at_beginning_of_month :beginning_of_month
|
235
|
-
|
236
|
-
# Returns a new Date/DateTime representing the end of the month (last day of the month; DateTime objects will have time set to 0:00)
|
237
|
-
def end_of_month
|
238
|
-
last_day = ::Time.days_in_month( self.month, self.year )
|
239
|
-
self.acts_like?(:time) ? change(:day => last_day, :hour => 23, :min => 59, :sec => 59) : change(:day => last_day)
|
240
|
-
end
|
241
|
-
alias :at_end_of_month :end_of_month
|
242
|
-
|
243
|
-
# Returns a new Date/DateTime representing the start of the quarter (1st of january, april, july, october; DateTime objects will have time set to 0:00)
|
244
|
-
def beginning_of_quarter
|
245
|
-
beginning_of_month.change(:month => [10, 7, 4, 1].detect { |m| m <= self.month })
|
246
|
-
end
|
247
|
-
alias :at_beginning_of_quarter :beginning_of_quarter
|
248
|
-
|
249
|
-
# Returns a new Date/DateTime representing the end of the quarter (last day of march, june, september, december; DateTime objects will have time set to 23:59:59)
|
250
|
-
def end_of_quarter
|
251
|
-
beginning_of_month.change(:month => [3, 6, 9, 12].detect { |m| m >= self.month }).end_of_month
|
252
|
-
end
|
253
|
-
alias :at_end_of_quarter :end_of_quarter
|
254
|
-
|
255
|
-
# Returns a new Date/DateTime representing the start of the year (1st of january; DateTime objects will have time set to 0:00)
|
256
|
-
def beginning_of_year
|
257
|
-
self.acts_like?(:time) ? change(:month => 1, :day => 1, :hour => 0) : change(:month => 1, :day => 1)
|
258
|
-
end
|
259
|
-
alias :at_beginning_of_year :beginning_of_year
|
260
|
-
|
261
|
-
# Returns a new Time representing the end of the year (31st of december; DateTime objects will have time set to 23:59:59)
|
262
|
-
def end_of_year
|
263
|
-
self.acts_like?(:time) ? change(:month => 12, :day => 31, :hour => 23, :min => 59, :sec => 59) : change(:month => 12, :day => 31)
|
264
|
-
end
|
265
|
-
alias :at_end_of_year :end_of_year
|
266
|
-
|
267
|
-
# Convenience method which returns a new Date/DateTime representing the time 1 day ago
|
268
|
-
def yesterday
|
269
|
-
self - 1
|
270
|
-
end
|
271
|
-
|
272
|
-
# Convenience method which returns a new Date/DateTime representing the time 1 day since the instance time
|
273
|
-
def tomorrow
|
274
|
-
self + 1
|
275
|
-
end
|
276
122
|
end
|