activesupport 1.2.4 → 8.1.2
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 +7 -0
- data/CHANGELOG.md +505 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +40 -0
- data/lib/active_support/actionable_error.rb +50 -0
- data/lib/active_support/all.rb +5 -0
- data/lib/active_support/array_inquirer.rb +50 -0
- data/lib/active_support/backtrace_cleaner.rb +234 -0
- data/lib/active_support/benchmark.rb +21 -0
- data/lib/active_support/benchmarkable.rb +53 -0
- data/lib/active_support/broadcast_logger.rb +238 -0
- data/lib/active_support/builder.rb +8 -0
- data/lib/active_support/cache/coder.rb +153 -0
- data/lib/active_support/cache/entry.rb +134 -0
- data/lib/active_support/cache/file_store.rb +244 -0
- data/lib/active_support/cache/mem_cache_store.rb +288 -0
- data/lib/active_support/cache/memory_store.rb +264 -0
- data/lib/active_support/cache/null_store.rb +62 -0
- data/lib/active_support/cache/redis_cache_store.rb +498 -0
- data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
- data/lib/active_support/cache/strategy/local_cache.rb +246 -0
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
- data/lib/active_support/cache.rb +1170 -0
- data/lib/active_support/callbacks.rb +960 -0
- data/lib/active_support/class_attribute.rb +33 -0
- data/lib/active_support/code_generator.rb +79 -0
- data/lib/active_support/concern.rb +217 -0
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
- data/lib/active_support/concurrency/null_lock.rb +13 -0
- data/lib/active_support/concurrency/share_lock.rb +225 -0
- data/lib/active_support/concurrency/thread_monitor.rb +55 -0
- data/lib/active_support/configurable.rb +193 -0
- data/lib/active_support/configuration_file.rb +60 -0
- data/lib/active_support/continuous_integration.rb +145 -0
- data/lib/active_support/core_ext/array/access.rb +100 -0
- data/lib/active_support/core_ext/array/conversions.rb +209 -26
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array/extract_options.rb +31 -0
- data/lib/active_support/core_ext/array/grouping.rb +109 -0
- data/lib/active_support/core_ext/array/inquiry.rb +19 -0
- data/lib/active_support/core_ext/array/wrap.rb +48 -0
- data/lib/active_support/core_ext/array.rb +8 -4
- data/lib/active_support/core_ext/benchmark.rb +6 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
- data/lib/active_support/core_ext/big_decimal.rb +3 -0
- data/lib/active_support/core_ext/class/attribute.rb +137 -0
- data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
- data/lib/active_support/core_ext/class/subclasses.rb +24 -0
- data/lib/active_support/core_ext/class.rb +4 -0
- data/lib/active_support/core_ext/date/acts_like.rb +10 -0
- data/lib/active_support/core_ext/date/blank.rb +18 -0
- data/lib/active_support/core_ext/date/calculations.rb +161 -0
- data/lib/active_support/core_ext/date/conversions.rb +95 -28
- data/lib/active_support/core_ext/date/zones.rb +8 -0
- data/lib/active_support/core_ext/date.rb +6 -5
- data/lib/active_support/core_ext/date_and_time/calculations.rb +374 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +23 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
- data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
- data/lib/active_support/core_ext/date_time/blank.rb +18 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +215 -0
- data/lib/active_support/core_ext/date_time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +108 -0
- data/lib/active_support/core_ext/date_time.rb +7 -0
- data/lib/active_support/core_ext/digest/uuid.rb +76 -0
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +277 -7
- data/lib/active_support/core_ext/erb/util.rb +201 -0
- data/lib/active_support/core_ext/file/atomic.rb +72 -0
- data/lib/active_support/core_ext/file.rb +3 -0
- data/lib/active_support/core_ext/hash/conversions.rb +262 -0
- data/lib/active_support/core_ext/hash/deep_merge.rb +43 -0
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +12 -0
- data/lib/active_support/core_ext/hash/indifferent_access.rb +19 -55
- data/lib/active_support/core_ext/hash/keys.rb +134 -44
- data/lib/active_support/core_ext/hash/reverse_merge.rb +22 -22
- data/lib/active_support/core_ext/hash/slice.rb +27 -0
- data/lib/active_support/core_ext/hash.rb +9 -8
- data/lib/active_support/core_ext/integer/inflections.rb +29 -13
- data/lib/active_support/core_ext/integer/multiple.rb +12 -0
- data/lib/active_support/core_ext/integer/time.rb +22 -0
- data/lib/active_support/core_ext/integer.rb +4 -6
- data/lib/active_support/core_ext/kernel/concern.rb +14 -0
- data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
- data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
- data/lib/active_support/core_ext/kernel.rb +4 -78
- data/lib/active_support/core_ext/load_error.rb +6 -35
- data/lib/active_support/core_ext/module/aliasing.rb +31 -0
- data/lib/active_support/core_ext/module/anonymous.rb +30 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +48 -0
- data/lib/active_support/core_ext/module/attribute_accessors.rb +214 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +175 -0
- data/lib/active_support/core_ext/module/concerning.rb +140 -0
- data/lib/active_support/core_ext/module/delegation.rb +225 -0
- data/lib/active_support/core_ext/module/deprecation.rb +25 -0
- data/lib/active_support/core_ext/module/introspection.rb +65 -0
- data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
- data/lib/active_support/core_ext/module/remove_method.rb +17 -0
- data/lib/active_support/core_ext/module.rb +13 -0
- data/lib/active_support/core_ext/name_error.rb +59 -0
- data/lib/active_support/core_ext/numeric/bytes.rb +73 -42
- data/lib/active_support/core_ext/numeric/conversions.rb +145 -0
- data/lib/active_support/core_ext/numeric/time.rb +64 -57
- data/lib/active_support/core_ext/numeric.rb +4 -6
- data/lib/active_support/core_ext/object/acts_like.rb +45 -0
- data/lib/active_support/core_ext/object/blank.rb +199 -0
- data/lib/active_support/core_ext/object/conversions.rb +6 -0
- data/lib/active_support/core_ext/object/deep_dup.rb +71 -0
- data/lib/active_support/core_ext/object/duplicable.rb +69 -0
- data/lib/active_support/core_ext/object/inclusion.rb +37 -0
- data/lib/active_support/core_ext/object/instance_variables.rb +32 -0
- data/lib/active_support/core_ext/object/json.rb +267 -0
- data/lib/active_support/core_ext/object/to_param.rb +3 -0
- data/lib/active_support/core_ext/object/to_query.rb +93 -0
- data/lib/active_support/core_ext/object/try.rb +158 -0
- data/lib/active_support/core_ext/object/with.rb +46 -0
- data/lib/active_support/core_ext/object/with_options.rb +101 -0
- data/lib/active_support/core_ext/object.rb +17 -0
- data/lib/active_support/core_ext/pathname/blank.rb +20 -0
- data/lib/active_support/core_ext/pathname/existence.rb +23 -0
- data/lib/active_support/core_ext/pathname.rb +4 -0
- data/lib/active_support/core_ext/range/compare_range.rb +57 -0
- data/lib/active_support/core_ext/range/conversions.rb +58 -17
- data/lib/active_support/core_ext/range/overlap.rb +40 -0
- data/lib/active_support/core_ext/range/sole.rb +17 -0
- data/lib/active_support/core_ext/range.rb +5 -4
- data/lib/active_support/core_ext/regexp.rb +14 -0
- data/lib/active_support/core_ext/securerandom.rb +57 -0
- data/lib/active_support/core_ext/string/access.rb +93 -56
- data/lib/active_support/core_ext/string/behavior.rb +8 -0
- data/lib/active_support/core_ext/string/conversions.rb +57 -16
- data/lib/active_support/core_ext/string/exclude.rb +13 -0
- data/lib/active_support/core_ext/string/filters.rb +151 -0
- data/lib/active_support/core_ext/string/indent.rb +45 -0
- data/lib/active_support/core_ext/string/inflections.rb +297 -54
- data/lib/active_support/core_ext/string/inquiry.rb +16 -0
- data/lib/active_support/core_ext/string/multibyte.rb +67 -0
- data/lib/active_support/core_ext/string/output_safety.rb +235 -0
- data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -18
- data/lib/active_support/core_ext/string/strip.rb +27 -0
- data/lib/active_support/core_ext/string/zones.rb +16 -0
- data/lib/active_support/core_ext/string.rb +14 -10
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/thread/backtrace/location.rb +7 -0
- data/lib/active_support/core_ext/time/acts_like.rb +10 -0
- data/lib/active_support/core_ext/time/calculations.rb +358 -153
- data/lib/active_support/core_ext/time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/time/conversions.rb +69 -30
- data/lib/active_support/core_ext/time/zones.rb +97 -0
- data/lib/active_support/core_ext/time.rb +6 -6
- data/lib/active_support/core_ext.rb +5 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +243 -0
- data/lib/active_support/deep_mergeable.rb +53 -0
- data/lib/active_support/delegation.rb +183 -0
- data/lib/active_support/dependencies/autoload.rb +72 -0
- data/lib/active_support/dependencies/interlock.rb +55 -0
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +84 -222
- data/lib/active_support/deprecation/behaviors.rb +148 -0
- data/lib/active_support/deprecation/constant_accessor.rb +74 -0
- data/lib/active_support/deprecation/deprecators.rb +104 -0
- data/lib/active_support/deprecation/disallowed.rb +54 -0
- data/lib/active_support/deprecation/method_wrappers.rb +68 -0
- data/lib/active_support/deprecation/proxy_wrappers.rb +189 -0
- data/lib/active_support/deprecation/reporting.rb +162 -0
- data/lib/active_support/deprecation.rb +81 -0
- data/lib/active_support/deprecator.rb +7 -0
- data/lib/active_support/descendants_tracker.rb +112 -0
- data/lib/active_support/digest.rb +22 -0
- data/lib/active_support/duration/iso8601_parser.rb +123 -0
- data/lib/active_support/duration/iso8601_serializer.rb +64 -0
- data/lib/active_support/duration.rb +524 -0
- data/lib/active_support/editor.rb +70 -0
- data/lib/active_support/encrypted_configuration.rb +126 -0
- data/lib/active_support/encrypted_file.rb +133 -0
- data/lib/active_support/environment_inquirer.rb +40 -0
- data/lib/active_support/error_reporter/test_helper.rb +15 -0
- data/lib/active_support/error_reporter.rb +318 -0
- data/lib/active_support/event_reporter/test_helper.rb +32 -0
- data/lib/active_support/event_reporter.rb +592 -0
- data/lib/active_support/evented_file_update_checker.rb +185 -0
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +110 -0
- data/lib/active_support/execution_wrapper.rb +150 -0
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/executor.rb +8 -0
- data/lib/active_support/file_update_checker.rb +166 -0
- data/lib/active_support/fork_tracker.rb +43 -0
- data/lib/active_support/gem_version.rb +17 -0
- data/lib/active_support/gzip.rb +41 -0
- data/lib/active_support/hash_with_indifferent_access.rb +464 -0
- data/lib/active_support/html_safe_translation.rb +56 -0
- data/lib/active_support/i18n.rb +17 -0
- data/lib/active_support/i18n_railtie.rb +140 -0
- data/lib/active_support/inflections.rb +68 -49
- data/lib/active_support/inflector/inflections.rb +290 -0
- data/lib/active_support/inflector/methods.rb +387 -0
- data/lib/active_support/inflector/transliterate.rb +147 -0
- data/lib/active_support/inflector.rb +7 -164
- data/lib/active_support/isolated_execution_state.rb +76 -0
- data/lib/active_support/json/decoding.rb +78 -0
- data/lib/active_support/json/encoding.rb +256 -0
- data/lib/active_support/json.rb +4 -0
- data/lib/active_support/key_generator.rb +66 -0
- data/lib/active_support/lazy_load_hooks.rb +107 -0
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +141 -0
- data/lib/active_support/log_subscriber/test_helper.rb +106 -0
- data/lib/active_support/log_subscriber.rb +188 -0
- data/lib/active_support/logger.rb +55 -0
- data/lib/active_support/logger_silence.rb +21 -0
- data/lib/active_support/logger_thread_safe_level.rb +50 -0
- data/lib/active_support/message_encryptor.rb +374 -0
- data/lib/active_support/message_encryptors.rb +193 -0
- data/lib/active_support/message_pack/cache_serializer.rb +23 -0
- data/lib/active_support/message_pack/extensions.rb +310 -0
- data/lib/active_support/message_pack/serializer.rb +63 -0
- data/lib/active_support/message_pack.rb +50 -0
- data/lib/active_support/message_verifier.rb +377 -0
- data/lib/active_support/message_verifiers.rb +189 -0
- data/lib/active_support/messages/codec.rb +65 -0
- data/lib/active_support/messages/metadata.rb +146 -0
- data/lib/active_support/messages/rotation_configuration.rb +23 -0
- data/lib/active_support/messages/rotation_coordinator.rb +102 -0
- data/lib/active_support/messages/rotator.rb +69 -0
- data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
- data/lib/active_support/multibyte/chars.rb +188 -0
- data/lib/active_support/multibyte/unicode.rb +42 -0
- data/lib/active_support/multibyte.rb +27 -0
- data/lib/active_support/notifications/fanout.rb +467 -0
- data/lib/active_support/notifications/instrumenter.rb +240 -0
- data/lib/active_support/notifications.rb +281 -0
- data/lib/active_support/number_helper/number_converter.rb +190 -0
- data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +30 -0
- data/lib/active_support/number_helper/number_to_human_converter.rb +69 -0
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +60 -0
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
- data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +59 -0
- data/lib/active_support/number_helper/rounding_helper.rb +46 -0
- data/lib/active_support/number_helper.rb +479 -0
- data/lib/active_support/option_merger.rb +38 -0
- data/lib/active_support/ordered_hash.rb +50 -0
- data/lib/active_support/ordered_options.rb +141 -25
- data/lib/active_support/parameter_filter.rb +157 -0
- data/lib/active_support/rails.rb +26 -0
- data/lib/active_support/railtie.rb +180 -0
- data/lib/active_support/reloader.rb +138 -0
- data/lib/active_support/rescuable.rb +176 -0
- data/lib/active_support/secure_compare_rotator.rb +58 -0
- data/lib/active_support/security_utils.rb +38 -0
- data/lib/active_support/string_inquirer.rb +35 -0
- data/lib/active_support/structured_event_subscriber.rb +99 -0
- data/lib/active_support/subscriber.rb +141 -0
- data/lib/active_support/syntax_error_proxy.rb +67 -0
- data/lib/active_support/tagged_logging.rb +157 -0
- data/lib/active_support/test_case.rb +365 -0
- data/lib/active_support/testing/assertions.rb +369 -0
- data/lib/active_support/testing/autorun.rb +10 -0
- data/lib/active_support/testing/constant_lookup.rb +51 -0
- data/lib/active_support/testing/constant_stubbing.rb +54 -0
- data/lib/active_support/testing/declarative.rb +28 -0
- data/lib/active_support/testing/deprecation.rb +82 -0
- data/lib/active_support/testing/error_reporter_assertions.rb +124 -0
- data/lib/active_support/testing/event_reporter_assertions.rb +227 -0
- data/lib/active_support/testing/file_fixtures.rb +38 -0
- data/lib/active_support/testing/isolation.rb +121 -0
- data/lib/active_support/testing/method_call_assertions.rb +69 -0
- data/lib/active_support/testing/notification_assertions.rb +92 -0
- data/lib/active_support/testing/parallelization/server.rb +98 -0
- data/lib/active_support/testing/parallelization/worker.rb +107 -0
- data/lib/active_support/testing/parallelization.rb +79 -0
- data/lib/active_support/testing/parallelize_executor.rb +81 -0
- data/lib/active_support/testing/setup_and_teardown.rb +57 -0
- data/lib/active_support/testing/stream.rb +41 -0
- data/lib/active_support/testing/tagged_logging.rb +27 -0
- data/lib/active_support/testing/tests_without_assertions.rb +19 -0
- data/lib/active_support/testing/time_helpers.rb +273 -0
- data/lib/active_support/time.rb +20 -0
- data/lib/active_support/time_with_zone.rb +613 -0
- data/lib/active_support/values/time_zone.rb +599 -158
- data/lib/active_support/version.rb +7 -6
- data/lib/active_support/xml_mini/jdom.rb +175 -0
- data/lib/active_support/xml_mini/libxml.rb +80 -0
- data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
- data/lib/active_support/xml_mini/nokogiri.rb +83 -0
- data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
- data/lib/active_support/xml_mini/rexml.rb +137 -0
- data/lib/active_support/xml_mini.rb +212 -0
- data/lib/active_support.rb +122 -10
- metadata +524 -93
- data/CHANGELOG +0 -283
- data/lib/active_support/binding_of_caller.rb +0 -84
- data/lib/active_support/breakpoint.rb +0 -523
- data/lib/active_support/class_attribute_accessors.rb +0 -57
- data/lib/active_support/class_inheritable_attributes.rb +0 -117
- data/lib/active_support/clean_logger.rb +0 -36
- data/lib/active_support/core_ext/blank.rb +0 -38
- data/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +0 -14
- data/lib/active_support/core_ext/cgi.rb +0 -5
- data/lib/active_support/core_ext/exception.rb +0 -29
- data/lib/active_support/core_ext/integer/even_odd.rb +0 -24
- data/lib/active_support/core_ext/object_and_class.rb +0 -44
- data/lib/active_support/module_attribute_accessors.rb +0 -57
- data/lib/active_support/whiny_nil.rb +0 -38
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/option_merger"
|
|
4
|
+
|
|
5
|
+
class Object
|
|
6
|
+
# An elegant way to factor duplication out of options passed to a series of
|
|
7
|
+
# method calls. Each method called in the block, with the block variable as
|
|
8
|
+
# the receiver, will have its options merged with the default +options+
|
|
9
|
+
# <tt>Hash</tt> or <tt>Hash</tt>-like object provided. Each method called on
|
|
10
|
+
# the block variable must take an options hash as its final argument.
|
|
11
|
+
#
|
|
12
|
+
# Without <tt>with_options</tt>, this code contains duplication:
|
|
13
|
+
#
|
|
14
|
+
# class Account < ActiveRecord::Base
|
|
15
|
+
# has_many :customers, dependent: :destroy
|
|
16
|
+
# has_many :products, dependent: :destroy
|
|
17
|
+
# has_many :invoices, dependent: :destroy
|
|
18
|
+
# has_many :expenses, dependent: :destroy
|
|
19
|
+
# end
|
|
20
|
+
#
|
|
21
|
+
# Using <tt>with_options</tt>, we can remove the duplication:
|
|
22
|
+
#
|
|
23
|
+
# class Account < ActiveRecord::Base
|
|
24
|
+
# with_options dependent: :destroy do |assoc|
|
|
25
|
+
# assoc.has_many :customers
|
|
26
|
+
# assoc.has_many :products
|
|
27
|
+
# assoc.has_many :invoices
|
|
28
|
+
# assoc.has_many :expenses
|
|
29
|
+
# end
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
32
|
+
# It can also be used with an explicit receiver:
|
|
33
|
+
#
|
|
34
|
+
# I18n.with_options locale: user.locale, scope: 'newsletter' do |i18n|
|
|
35
|
+
# subject i18n.t :subject
|
|
36
|
+
# body i18n.t :body, user_name: user.name
|
|
37
|
+
# end
|
|
38
|
+
#
|
|
39
|
+
# When you don't pass an explicit receiver, it executes the whole block
|
|
40
|
+
# in merging options context:
|
|
41
|
+
#
|
|
42
|
+
# class Account < ActiveRecord::Base
|
|
43
|
+
# with_options dependent: :destroy do
|
|
44
|
+
# has_many :customers
|
|
45
|
+
# has_many :products
|
|
46
|
+
# has_many :invoices
|
|
47
|
+
# has_many :expenses
|
|
48
|
+
# end
|
|
49
|
+
# end
|
|
50
|
+
#
|
|
51
|
+
# <tt>with_options</tt> can also be nested since the call is forwarded to its receiver.
|
|
52
|
+
#
|
|
53
|
+
# NOTE: Each nesting level will merge inherited defaults in addition to their own.
|
|
54
|
+
#
|
|
55
|
+
# class Post < ActiveRecord::Base
|
|
56
|
+
# with_options if: :persisted?, length: { minimum: 50 } do
|
|
57
|
+
# validates :content, if: -> { content.present? }
|
|
58
|
+
# end
|
|
59
|
+
# end
|
|
60
|
+
#
|
|
61
|
+
# The code is equivalent to:
|
|
62
|
+
#
|
|
63
|
+
# validates :content, length: { minimum: 50 }, if: -> { content.present? }
|
|
64
|
+
#
|
|
65
|
+
# Hence the inherited default for +if+ key is ignored.
|
|
66
|
+
#
|
|
67
|
+
# NOTE: You cannot call class methods implicitly inside of +with_options+.
|
|
68
|
+
# You can access these methods using the class name instead:
|
|
69
|
+
#
|
|
70
|
+
# class Phone < ActiveRecord::Base
|
|
71
|
+
# enum :phone_number_type, { home: 0, office: 1, mobile: 2 }
|
|
72
|
+
#
|
|
73
|
+
# with_options presence: true do
|
|
74
|
+
# validates :phone_number_type, inclusion: { in: Phone.phone_number_types.keys }
|
|
75
|
+
# end
|
|
76
|
+
# end
|
|
77
|
+
#
|
|
78
|
+
# When the block argument is omitted, the decorated Object instance is returned:
|
|
79
|
+
#
|
|
80
|
+
# module MyStyledHelpers
|
|
81
|
+
# def styled
|
|
82
|
+
# with_options style: "color: red;"
|
|
83
|
+
# end
|
|
84
|
+
# end
|
|
85
|
+
#
|
|
86
|
+
# styled.link_to "I'm red", "/"
|
|
87
|
+
# # => <a href="/" style="color: red;">I'm red</a>
|
|
88
|
+
#
|
|
89
|
+
# styled.button_tag "I'm red too!"
|
|
90
|
+
# # => <button style="color: red;">I'm red too!</button>
|
|
91
|
+
#
|
|
92
|
+
def with_options(options, &block)
|
|
93
|
+
option_merger = ActiveSupport::OptionMerger.new(self, options)
|
|
94
|
+
|
|
95
|
+
if block
|
|
96
|
+
block.arity.zero? ? option_merger.instance_eval(&block) : block.call(option_merger)
|
|
97
|
+
else
|
|
98
|
+
option_merger
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "object/acts_like"
|
|
4
|
+
require_relative "object/blank"
|
|
5
|
+
require_relative "object/duplicable"
|
|
6
|
+
require_relative "object/deep_dup"
|
|
7
|
+
require_relative "object/try"
|
|
8
|
+
require_relative "object/inclusion"
|
|
9
|
+
|
|
10
|
+
require_relative "object/conversions"
|
|
11
|
+
require_relative "object/instance_variables"
|
|
12
|
+
|
|
13
|
+
require_relative "object/json"
|
|
14
|
+
require_relative "object/to_param"
|
|
15
|
+
require_relative "object/to_query"
|
|
16
|
+
require_relative "object/with"
|
|
17
|
+
require_relative "object/with_options"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "pathname"
|
|
4
|
+
|
|
5
|
+
class Pathname
|
|
6
|
+
# An Pathname is blank if it's empty:
|
|
7
|
+
#
|
|
8
|
+
# Pathname.new("").blank? # => true
|
|
9
|
+
# Pathname.new(" ").blank? # => false
|
|
10
|
+
# Pathname.new("test").blank? # => false
|
|
11
|
+
#
|
|
12
|
+
# @return [true, false]
|
|
13
|
+
def blank?
|
|
14
|
+
to_s.empty?
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def present? # :nodoc:
|
|
18
|
+
!to_s.empty?
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "pathname"
|
|
4
|
+
|
|
5
|
+
class Pathname
|
|
6
|
+
# Returns the receiver if the named file exists otherwise returns +nil+.
|
|
7
|
+
# <tt>pathname.existence</tt> is equivalent to
|
|
8
|
+
#
|
|
9
|
+
# pathname.exist? ? pathname : nil
|
|
10
|
+
#
|
|
11
|
+
# For example, something like
|
|
12
|
+
#
|
|
13
|
+
# content = pathname.read if pathname.exist?
|
|
14
|
+
#
|
|
15
|
+
# becomes
|
|
16
|
+
#
|
|
17
|
+
# content = pathname.existence&.read
|
|
18
|
+
#
|
|
19
|
+
# @return [Pathname]
|
|
20
|
+
def existence
|
|
21
|
+
self if exist?
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveSupport
|
|
4
|
+
module CompareWithRange
|
|
5
|
+
# Extends the default Range#=== to support range comparisons.
|
|
6
|
+
# (1..5) === (1..5) # => true
|
|
7
|
+
# (1..5) === (2..3) # => true
|
|
8
|
+
# (1..5) === (1...6) # => true
|
|
9
|
+
# (1..5) === (2..6) # => false
|
|
10
|
+
#
|
|
11
|
+
# The native Range#=== behavior is untouched.
|
|
12
|
+
# ('a'..'f') === ('c') # => true
|
|
13
|
+
# (5..9) === (11) # => false
|
|
14
|
+
#
|
|
15
|
+
# The given range must be fully bounded, with both start and end.
|
|
16
|
+
def ===(value)
|
|
17
|
+
if value.is_a?(::Range)
|
|
18
|
+
is_backwards_op = value.exclude_end? ? :>= : :>
|
|
19
|
+
return false if value.begin && value.end && value.begin.public_send(is_backwards_op, value.end)
|
|
20
|
+
# 1...10 includes 1..9 but it does not include 1..10.
|
|
21
|
+
# 1..10 includes 1...11 but it does not include 1...12.
|
|
22
|
+
operator = exclude_end? && !value.exclude_end? ? :< : :<=
|
|
23
|
+
value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
|
|
24
|
+
super(value.first) && (self.end.nil? || value_max.public_send(operator, last))
|
|
25
|
+
else
|
|
26
|
+
super
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Extends the default Range#include? to support range comparisons.
|
|
31
|
+
# (1..5).include?(1..5) # => true
|
|
32
|
+
# (1..5).include?(2..3) # => true
|
|
33
|
+
# (1..5).include?(1...6) # => true
|
|
34
|
+
# (1..5).include?(2..6) # => false
|
|
35
|
+
#
|
|
36
|
+
# The native Range#include? behavior is untouched.
|
|
37
|
+
# ('a'..'f').include?('c') # => true
|
|
38
|
+
# (5..9).include?(11) # => false
|
|
39
|
+
#
|
|
40
|
+
# The given range must be fully bounded, with both start and end.
|
|
41
|
+
def include?(value)
|
|
42
|
+
if value.is_a?(::Range)
|
|
43
|
+
is_backwards_op = value.exclude_end? ? :>= : :>
|
|
44
|
+
return false if value.begin && value.end && value.begin.public_send(is_backwards_op, value.end)
|
|
45
|
+
# 1...10 includes 1..9 but it does not include 1..10.
|
|
46
|
+
# 1..10 includes 1...11 but it does not include 1...12.
|
|
47
|
+
operator = exclude_end? && !value.exclude_end? ? :< : :<=
|
|
48
|
+
value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
|
|
49
|
+
super(value.first) && (self.end.nil? || value_max.public_send(operator, last))
|
|
50
|
+
else
|
|
51
|
+
super
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
Range.prepend(ActiveSupport::CompareWithRange)
|
|
@@ -1,21 +1,62 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveSupport
|
|
4
|
+
# = \Range With Format
|
|
5
|
+
module RangeWithFormat
|
|
6
|
+
RANGE_FORMATS = {
|
|
7
|
+
db: -> (start, stop) do
|
|
8
|
+
if start && stop
|
|
9
|
+
case start
|
|
10
|
+
when String then "BETWEEN '#{start}' AND '#{stop}'"
|
|
11
|
+
else
|
|
12
|
+
"BETWEEN '#{start.to_fs(:db)}' AND '#{stop.to_fs(:db)}'"
|
|
13
|
+
end
|
|
14
|
+
elsif start
|
|
15
|
+
case start
|
|
16
|
+
when String then ">= '#{start}'"
|
|
17
|
+
else
|
|
18
|
+
">= '#{start.to_fs(:db)}'"
|
|
19
|
+
end
|
|
20
|
+
elsif stop
|
|
21
|
+
case stop
|
|
22
|
+
when String then "<= '#{stop}'"
|
|
23
|
+
else
|
|
24
|
+
"<= '#{stop.to_fs(:db)}'"
|
|
25
|
+
end
|
|
17
26
|
end
|
|
18
27
|
end
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# Convert range to a formatted string. See RANGE_FORMATS for predefined formats.
|
|
31
|
+
#
|
|
32
|
+
# This method is aliased to <tt>to_formatted_s</tt>.
|
|
33
|
+
#
|
|
34
|
+
# range = (1..100) # => 1..100
|
|
35
|
+
#
|
|
36
|
+
# range.to_s # => "1..100"
|
|
37
|
+
# range.to_fs(:db) # => "BETWEEN '1' AND '100'"
|
|
38
|
+
#
|
|
39
|
+
# range = (1..) # => 1..
|
|
40
|
+
# range.to_fs(:db) # => ">= '1'"
|
|
41
|
+
#
|
|
42
|
+
# range = (..100) # => ..100
|
|
43
|
+
# range.to_fs(:db) # => "<= '100'"
|
|
44
|
+
#
|
|
45
|
+
# == Adding your own range formats to to_fs
|
|
46
|
+
# You can add your own formats to the Range::RANGE_FORMATS hash.
|
|
47
|
+
# Use the format name as the hash key and a Proc instance.
|
|
48
|
+
#
|
|
49
|
+
# # config/initializers/range_formats.rb
|
|
50
|
+
# Range::RANGE_FORMATS[:short] = ->(start, stop) { "Between #{start.to_fs(:db)} and #{stop.to_fs(:db)}" }
|
|
51
|
+
def to_fs(format = :default)
|
|
52
|
+
if formatter = RANGE_FORMATS[format]
|
|
53
|
+
formatter.call(self.begin, self.end)
|
|
54
|
+
else
|
|
55
|
+
to_s
|
|
56
|
+
end
|
|
19
57
|
end
|
|
58
|
+
alias_method :to_formatted_s, :to_fs
|
|
20
59
|
end
|
|
21
|
-
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
Range.prepend(ActiveSupport::RangeWithFormat)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Range
|
|
4
|
+
unless Range.method_defined?(:overlap?) # Ruby 3.3+
|
|
5
|
+
# Compare two ranges and see if they overlap each other
|
|
6
|
+
# (1..5).overlap?(4..6) # => true
|
|
7
|
+
# (1..5).overlap?(7..9) # => false
|
|
8
|
+
def overlap?(other)
|
|
9
|
+
raise TypeError unless other.is_a? Range
|
|
10
|
+
|
|
11
|
+
self_begin = self.begin
|
|
12
|
+
other_end = other.end
|
|
13
|
+
other_excl = other.exclude_end?
|
|
14
|
+
|
|
15
|
+
return false if _empty_range?(self_begin, other_end, other_excl)
|
|
16
|
+
|
|
17
|
+
other_begin = other.begin
|
|
18
|
+
self_end = self.end
|
|
19
|
+
self_excl = self.exclude_end?
|
|
20
|
+
|
|
21
|
+
return false if _empty_range?(other_begin, self_end, self_excl)
|
|
22
|
+
return true if self_begin == other_begin
|
|
23
|
+
|
|
24
|
+
return false if _empty_range?(self_begin, self_end, self_excl)
|
|
25
|
+
return false if _empty_range?(other_begin, other_end, other_excl)
|
|
26
|
+
|
|
27
|
+
true
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
def _empty_range?(b, e, excl)
|
|
32
|
+
return false if b.nil? || e.nil?
|
|
33
|
+
|
|
34
|
+
comp = b <=> e
|
|
35
|
+
comp.nil? || comp > 0 || (comp == 0 && excl)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
alias :overlaps? :overlap?
|
|
40
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Range
|
|
4
|
+
# Returns the sole item in the range. If there are no items, or more
|
|
5
|
+
# than one item, raises Enumerable::SoleItemExpectedError.
|
|
6
|
+
#
|
|
7
|
+
# (1..1).sole # => 1
|
|
8
|
+
# (2..1).sole # => Enumerable::SoleItemExpectedError: no item found
|
|
9
|
+
# (..1).sole # => Enumerable::SoleItemExpectedError: infinite range cannot represent a sole item
|
|
10
|
+
def sole
|
|
11
|
+
if self.begin.nil? || self.end.nil?
|
|
12
|
+
raise ActiveSupport::EnumerableCoreExt::SoleItemExpectedError, "infinite range '#{inspect}' cannot represent a sole item"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
super
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
require_relative "range/conversions"
|
|
4
|
+
require_relative "range/compare_range"
|
|
5
|
+
require_relative "range/overlap"
|
|
6
|
+
require_relative "range/sole"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Regexp
|
|
4
|
+
# Returns +true+ if the regexp has the multiline flag set.
|
|
5
|
+
#
|
|
6
|
+
# (/./).multiline? # => false
|
|
7
|
+
# (/./m).multiline? # => true
|
|
8
|
+
#
|
|
9
|
+
# Regexp.new(".").multiline? # => false
|
|
10
|
+
# Regexp.new(".", Regexp::MULTILINE).multiline? # => true
|
|
11
|
+
def multiline?
|
|
12
|
+
options & MULTILINE == MULTILINE
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "securerandom"
|
|
4
|
+
|
|
5
|
+
module SecureRandom
|
|
6
|
+
BASE58_ALPHABET = ("0".."9").to_a + ("A".."Z").to_a + ("a".."z").to_a - ["0", "O", "I", "l"]
|
|
7
|
+
BASE36_ALPHABET = ("0".."9").to_a + ("a".."z").to_a
|
|
8
|
+
|
|
9
|
+
# SecureRandom.base58 generates a random base58 string.
|
|
10
|
+
#
|
|
11
|
+
# The argument _n_ specifies the length of the random string to be generated.
|
|
12
|
+
#
|
|
13
|
+
# If _n_ is not specified or is +nil+, 16 is assumed. It may be larger in the future.
|
|
14
|
+
#
|
|
15
|
+
# The result may contain alphanumeric characters except 0, O, I, and l.
|
|
16
|
+
#
|
|
17
|
+
# p SecureRandom.base58 # => "4kUgL2pdQMSCQtjE"
|
|
18
|
+
# p SecureRandom.base58(24) # => "77TMHrHJFvFDwodq8w7Ev2m7"
|
|
19
|
+
if SecureRandom.method(:alphanumeric).parameters.size == 2 # Remove check when Ruby 3.3 is the minimum supported version
|
|
20
|
+
def self.base58(n = 16)
|
|
21
|
+
alphanumeric(n, chars: BASE58_ALPHABET)
|
|
22
|
+
end
|
|
23
|
+
else
|
|
24
|
+
def self.base58(n = 16)
|
|
25
|
+
SecureRandom.random_bytes(n).unpack("C*").map do |byte|
|
|
26
|
+
idx = byte % 64
|
|
27
|
+
idx = SecureRandom.random_number(58) if idx >= 58
|
|
28
|
+
BASE58_ALPHABET[idx]
|
|
29
|
+
end.join
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# SecureRandom.base36 generates a random base36 string in lowercase.
|
|
34
|
+
#
|
|
35
|
+
# The argument _n_ specifies the length of the random string to be generated.
|
|
36
|
+
#
|
|
37
|
+
# If _n_ is not specified or is +nil+, 16 is assumed. It may be larger in the future.
|
|
38
|
+
# This method can be used over +base58+ if a deterministic case key is necessary.
|
|
39
|
+
#
|
|
40
|
+
# The result will contain alphanumeric characters in lowercase.
|
|
41
|
+
#
|
|
42
|
+
# p SecureRandom.base36 # => "4kugl2pdqmscqtje"
|
|
43
|
+
# p SecureRandom.base36(24) # => "77tmhrhjfvfdwodq8w7ev2m7"
|
|
44
|
+
if SecureRandom.method(:alphanumeric).parameters.size == 2 # Remove check when Ruby 3.3 is the minimum supported version
|
|
45
|
+
def self.base36(n = 16)
|
|
46
|
+
alphanumeric(n, chars: BASE36_ALPHABET)
|
|
47
|
+
end
|
|
48
|
+
else
|
|
49
|
+
def self.base36(n = 16)
|
|
50
|
+
SecureRandom.random_bytes(n).unpack("C*").map do |byte|
|
|
51
|
+
idx = byte % 64
|
|
52
|
+
idx = SecureRandom.random_number(36) if idx >= 36
|
|
53
|
+
BASE36_ALPHABET[idx]
|
|
54
|
+
end.join
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -1,58 +1,95 @@
|
|
|
1
|
-
|
|
2
|
-
module CoreExtensions #:nodoc:
|
|
3
|
-
module String #:nodoc:
|
|
4
|
-
# Makes it easier to access parts of a string, such as specific characters and substrings.
|
|
5
|
-
module Access
|
|
6
|
-
# Returns the character at the +position+ treating the string as an array (where 0 is the first character).
|
|
7
|
-
#
|
|
8
|
-
# Examples:
|
|
9
|
-
# "hello".at(0) # => "h"
|
|
10
|
-
# "hello".at(4) # => "o"
|
|
11
|
-
# "hello".at(10) # => nil
|
|
12
|
-
def at(position)
|
|
13
|
-
self[position, 1]
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# Returns the remaining of the string from the +position+ treating the string as an array (where 0 is the first character).
|
|
17
|
-
#
|
|
18
|
-
# Examples:
|
|
19
|
-
# "hello".from(0) # => "hello"
|
|
20
|
-
# "hello".from(2) # => "llo"
|
|
21
|
-
# "hello".from(10) # => nil
|
|
22
|
-
def from(position)
|
|
23
|
-
self[position..-1]
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# Returns the beginning of the string up to the +position+ treating the string as an array (where 0 is the first character).
|
|
27
|
-
#
|
|
28
|
-
# Examples:
|
|
29
|
-
# "hello".to(0) # => "h"
|
|
30
|
-
# "hello".to(2) # => "hel"
|
|
31
|
-
# "hello".to(10) # => "hello"
|
|
32
|
-
def to(position)
|
|
33
|
-
self[0..position]
|
|
34
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
35
2
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
3
|
+
class String
|
|
4
|
+
# If you pass a single integer, returns a substring of one character at that
|
|
5
|
+
# position. The first character of the string is at position 0, the next at
|
|
6
|
+
# position 1, and so on. If a range is supplied, a substring containing
|
|
7
|
+
# characters at offsets given by the range is returned. In both cases, if an
|
|
8
|
+
# offset is negative, it is counted from the end of the string. Returns +nil+
|
|
9
|
+
# if the initial offset falls outside the string. Returns an empty string if
|
|
10
|
+
# the beginning of the range is greater than the end of the string.
|
|
11
|
+
#
|
|
12
|
+
# str = "hello"
|
|
13
|
+
# str.at(0) # => "h"
|
|
14
|
+
# str.at(1..3) # => "ell"
|
|
15
|
+
# str.at(-2) # => "l"
|
|
16
|
+
# str.at(-2..-1) # => "lo"
|
|
17
|
+
# str.at(5) # => nil
|
|
18
|
+
# str.at(5..-1) # => ""
|
|
19
|
+
#
|
|
20
|
+
# If a Regexp is given, the matching portion of the string is returned.
|
|
21
|
+
# If a String is given, that given string is returned if it occurs in
|
|
22
|
+
# the string. In both cases, +nil+ is returned if there is no match.
|
|
23
|
+
#
|
|
24
|
+
# str = "hello"
|
|
25
|
+
# str.at(/lo/) # => "lo"
|
|
26
|
+
# str.at(/ol/) # => nil
|
|
27
|
+
# str.at("lo") # => "lo"
|
|
28
|
+
# str.at("ol") # => nil
|
|
29
|
+
def at(position)
|
|
30
|
+
self[position]
|
|
57
31
|
end
|
|
58
|
-
|
|
32
|
+
|
|
33
|
+
# Returns a substring from the given position to the end of the string.
|
|
34
|
+
# If the position is negative, it is counted from the end of the string.
|
|
35
|
+
#
|
|
36
|
+
# str = "hello"
|
|
37
|
+
# str.from(0) # => "hello"
|
|
38
|
+
# str.from(3) # => "lo"
|
|
39
|
+
# str.from(-2) # => "lo"
|
|
40
|
+
#
|
|
41
|
+
# You can mix it with +to+ method and do fun things like:
|
|
42
|
+
#
|
|
43
|
+
# str = "hello"
|
|
44
|
+
# str.from(0).to(-1) # => "hello"
|
|
45
|
+
# str.from(1).to(-2) # => "ell"
|
|
46
|
+
def from(position)
|
|
47
|
+
self[position, length]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Returns a substring from the beginning of the string to the given position.
|
|
51
|
+
# If the position is negative, it is counted from the end of the string.
|
|
52
|
+
#
|
|
53
|
+
# str = "hello"
|
|
54
|
+
# str.to(0) # => "h"
|
|
55
|
+
# str.to(3) # => "hell"
|
|
56
|
+
# str.to(-2) # => "hell"
|
|
57
|
+
#
|
|
58
|
+
# You can mix it with +from+ method and do fun things like:
|
|
59
|
+
#
|
|
60
|
+
# str = "hello"
|
|
61
|
+
# str.from(0).to(-1) # => "hello"
|
|
62
|
+
# str.from(1).to(-2) # => "ell"
|
|
63
|
+
def to(position)
|
|
64
|
+
position += size if position < 0
|
|
65
|
+
self[0, position + 1] || +""
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Returns the first character. If a limit is supplied, returns a substring
|
|
69
|
+
# from the beginning of the string until it reaches the limit value. If the
|
|
70
|
+
# given limit is greater than or equal to the string length, returns a copy of self.
|
|
71
|
+
#
|
|
72
|
+
# str = "hello"
|
|
73
|
+
# str.first # => "h"
|
|
74
|
+
# str.first(1) # => "h"
|
|
75
|
+
# str.first(2) # => "he"
|
|
76
|
+
# str.first(0) # => ""
|
|
77
|
+
# str.first(6) # => "hello"
|
|
78
|
+
def first(limit = 1)
|
|
79
|
+
self[0, limit] || raise(ArgumentError, "negative limit")
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Returns the last character of the string. If a limit is supplied, returns a substring
|
|
83
|
+
# from the end of the string until it reaches the limit value (counting backwards). If
|
|
84
|
+
# the given limit is greater than or equal to the string length, returns a copy of self.
|
|
85
|
+
#
|
|
86
|
+
# str = "hello"
|
|
87
|
+
# str.last # => "o"
|
|
88
|
+
# str.last(1) # => "o"
|
|
89
|
+
# str.last(2) # => "lo"
|
|
90
|
+
# str.last(0) # => ""
|
|
91
|
+
# str.last(6) # => "hello"
|
|
92
|
+
def last(limit = 1)
|
|
93
|
+
self[[length - limit, 0].max, limit] || raise(ArgumentError, "negative limit")
|
|
94
|
+
end
|
|
95
|
+
end
|