activesupport 2.3.18 → 3.0.0.beta
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.
- data/CHANGELOG +30 -53
- data/lib/active_support.rb +43 -31
- data/lib/active_support/all.rb +3 -7
- data/lib/active_support/backtrace_cleaner.rb +24 -8
- data/lib/active_support/base64.rb +9 -0
- data/lib/active_support/benchmarkable.rb +60 -0
- data/lib/active_support/buffered_logger.rb +12 -9
- data/lib/active_support/cache.rb +75 -55
- data/lib/active_support/cache/compressed_mem_cache_store.rb +2 -0
- data/lib/active_support/cache/file_store.rb +35 -17
- data/lib/active_support/cache/mem_cache_store.rb +29 -20
- data/lib/active_support/cache/memory_store.rb +18 -17
- data/lib/active_support/cache/strategy/local_cache.rb +9 -1
- data/lib/active_support/callbacks.rb +490 -169
- data/lib/active_support/concern.rb +29 -0
- data/lib/active_support/configurable.rb +35 -0
- data/lib/active_support/core_ext.rb +2 -7
- data/lib/active_support/core_ext/array.rb +2 -10
- data/lib/active_support/core_ext/array/access.rb +39 -46
- data/lib/active_support/core_ext/array/conversions.rb +146 -182
- data/lib/active_support/core_ext/array/extract_options.rb +12 -18
- data/lib/active_support/core_ext/array/grouping.rb +87 -93
- data/lib/active_support/core_ext/array/random_access.rb +4 -40
- data/lib/active_support/core_ext/array/uniq_by.rb +17 -0
- data/lib/active_support/core_ext/array/wrap.rb +22 -0
- data/lib/active_support/core_ext/big_decimal.rb +1 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +27 -0
- data/lib/active_support/core_ext/cgi.rb +0 -4
- data/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +16 -20
- data/lib/active_support/core_ext/class.rb +0 -2
- data/lib/active_support/core_ext/class/attribute.rb +8 -39
- data/lib/active_support/core_ext/class/attribute_accessors.rb +31 -35
- data/lib/active_support/core_ext/class/delegating_attributes.rb +34 -40
- data/lib/active_support/core_ext/class/inheritable_attributes.rb +100 -16
- data/lib/active_support/core_ext/date/acts_like.rb +8 -0
- data/lib/active_support/core_ext/date/calculations.rb +218 -238
- data/lib/active_support/core_ext/date/conversions.rb +87 -96
- data/lib/active_support/core_ext/date/freeze.rb +31 -0
- data/lib/active_support/core_ext/date_time/acts_like.rb +13 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +97 -110
- data/lib/active_support/core_ext/date_time/conversions.rb +83 -95
- data/lib/active_support/core_ext/date_time/zones.rb +17 -0
- data/lib/active_support/core_ext/enumerable.rb +14 -15
- data/lib/active_support/core_ext/exception.rb +1 -43
- data/lib/active_support/core_ext/file.rb +0 -4
- data/lib/active_support/core_ext/file/atomic.rb +34 -41
- data/lib/active_support/core_ext/float.rb +0 -6
- data/lib/active_support/core_ext/float/rounding.rb +15 -20
- data/lib/active_support/core_ext/hash.rb +8 -14
- data/lib/active_support/core_ext/hash/conversions.rb +236 -236
- data/lib/active_support/core_ext/hash/deep_merge.rb +12 -19
- data/lib/active_support/core_ext/hash/diff.rb +11 -17
- data/lib/active_support/core_ext/hash/except.rb +21 -22
- data/lib/active_support/core_ext/hash/indifferent_access.rb +8 -137
- data/lib/active_support/core_ext/hash/keys.rb +38 -45
- data/lib/active_support/core_ext/hash/reverse_merge.rb +25 -32
- data/lib/active_support/core_ext/hash/slice.rb +35 -37
- data/lib/active_support/core_ext/integer.rb +1 -7
- data/lib/active_support/core_ext/integer/inflections.rb +10 -16
- data/lib/active_support/core_ext/integer/multiple.rb +6 -0
- data/lib/active_support/core_ext/integer/time.rb +36 -42
- data/lib/active_support/core_ext/kernel/reporting.rb +9 -7
- data/lib/active_support/core_ext/kernel/requires.rb +3 -1
- data/lib/active_support/core_ext/load_error.rb +16 -33
- data/lib/active_support/core_ext/logger.rb +3 -2
- data/lib/active_support/core_ext/module.rb +3 -16
- data/lib/active_support/core_ext/module/aliasing.rb +64 -68
- data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +1 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +4 -4
- data/lib/active_support/core_ext/module/attribute_accessors.rb +36 -41
- data/lib/active_support/core_ext/module/delegation.rb +1 -1
- data/lib/active_support/core_ext/module/deprecation.rb +9 -0
- data/lib/active_support/core_ext/module/introspection.rb +77 -79
- data/lib/active_support/core_ext/module/loading.rb +2 -0
- data/lib/active_support/core_ext/module/synchronization.rb +4 -1
- data/lib/active_support/core_ext/name_error.rb +3 -4
- data/lib/active_support/core_ext/numeric.rb +1 -8
- data/lib/active_support/core_ext/numeric/bytes.rb +35 -41
- data/lib/active_support/core_ext/numeric/time.rb +70 -74
- data/lib/active_support/core_ext/object.rb +4 -2
- data/lib/active_support/core_ext/object/acts_like.rb +10 -0
- data/lib/active_support/core_ext/object/conversions.rb +4 -15
- data/lib/active_support/core_ext/object/duplicable.rb +65 -0
- data/lib/active_support/core_ext/object/instance_variables.rb +0 -7
- data/lib/active_support/core_ext/object/metaclass.rb +5 -6
- data/lib/active_support/core_ext/object/misc.rb +2 -93
- data/lib/active_support/core_ext/object/returning.rb +42 -0
- data/lib/active_support/core_ext/object/to_param.rb +49 -0
- data/lib/active_support/core_ext/object/to_query.rb +27 -0
- data/lib/active_support/core_ext/{try.rb → object/try.rb} +4 -4
- data/lib/active_support/core_ext/object/with_options.rb +24 -0
- data/lib/active_support/core_ext/proc.rb +6 -4
- data/lib/active_support/core_ext/process/daemon.rb +17 -19
- data/lib/active_support/core_ext/range.rb +2 -9
- data/lib/active_support/core_ext/range/blockless_step.rb +24 -27
- data/lib/active_support/core_ext/range/conversions.rb +17 -23
- data/lib/active_support/core_ext/range/include_range.rb +18 -27
- data/lib/active_support/core_ext/range/overlaps.rb +6 -13
- data/lib/active_support/core_ext/regexp.rb +5 -0
- data/lib/active_support/core_ext/rexml.rb +12 -7
- data/lib/active_support/core_ext/string.rb +6 -19
- data/lib/active_support/core_ext/string/access.rb +88 -95
- data/lib/active_support/core_ext/string/behavior.rb +6 -12
- data/lib/active_support/core_ext/string/conversions.rb +19 -21
- data/lib/active_support/core_ext/string/exclude.rb +6 -0
- data/lib/active_support/core_ext/string/filters.rb +17 -23
- data/lib/active_support/core_ext/string/inflections.rb +146 -153
- data/lib/active_support/{vendor/i18n-0.4.1/i18n/core_ext/string/interpolate.rb → core_ext/string/interpolation.rb} +8 -15
- data/lib/active_support/core_ext/string/multibyte.rb +68 -74
- data/lib/active_support/core_ext/string/output_safety.rb +21 -17
- data/lib/active_support/core_ext/string/starts_ends_with.rb +3 -32
- data/lib/active_support/core_ext/string/xchar.rb +10 -3
- data/lib/active_support/core_ext/time/acts_like.rb +8 -0
- data/lib/active_support/core_ext/time/calculations.rb +276 -308
- data/lib/active_support/core_ext/time/conversions.rb +78 -84
- data/lib/active_support/core_ext/time/marshal_with_utc_flag.rb +22 -0
- data/lib/active_support/core_ext/time/publicize_conversion_methods.rb +10 -0
- data/lib/active_support/core_ext/time/zones.rb +73 -81
- data/lib/active_support/core_ext/uri.rb +2 -1
- data/lib/active_support/dependencies.rb +38 -48
- data/lib/active_support/dependencies/autoload.rb +49 -0
- data/lib/active_support/deprecation.rb +9 -195
- data/lib/active_support/deprecation/behaviors.rb +38 -0
- data/lib/active_support/deprecation/method_wrappers.rb +29 -0
- data/lib/active_support/deprecation/proxy_wrappers.rb +74 -0
- data/lib/active_support/deprecation/reporting.rb +55 -0
- data/lib/active_support/duration.rb +6 -2
- data/lib/active_support/hash_with_indifferent_access.rb +137 -0
- data/lib/active_support/i18n.rb +2 -0
- data/lib/active_support/inflections.rb +1 -1
- data/lib/active_support/inflector.rb +4 -406
- data/lib/active_support/inflector/inflections.rb +211 -0
- data/lib/active_support/inflector/methods.rb +139 -0
- data/lib/active_support/inflector/transliterate.rb +61 -0
- data/lib/active_support/json/backends/jsongem.rb +16 -10
- data/lib/active_support/json/backends/yaml.rb +72 -2
- data/lib/active_support/json/decoding.rb +2 -16
- data/lib/active_support/json/encoding.rb +153 -33
- data/lib/active_support/json/variable.rb +4 -3
- data/lib/active_support/locale/en.yml +1 -4
- data/lib/active_support/memoizable.rb +7 -6
- data/lib/active_support/message_encryptor.rb +1 -0
- data/lib/active_support/message_verifier.rb +12 -29
- data/lib/active_support/multibyte.rb +9 -4
- data/lib/active_support/multibyte/chars.rb +25 -17
- data/lib/active_support/multibyte/unicode_database.rb +5 -5
- data/lib/active_support/multibyte/utils.rb +1 -1
- data/lib/active_support/notifications.rb +77 -0
- data/lib/active_support/notifications/fanout.rb +69 -0
- data/lib/active_support/notifications/instrumenter.rb +50 -0
- data/lib/active_support/option_merger.rb +2 -0
- data/lib/active_support/ordered_hash.rb +33 -37
- data/lib/active_support/ordered_options.rb +3 -1
- data/lib/active_support/railtie.rb +64 -0
- data/lib/active_support/rescuable.rb +11 -6
- data/lib/active_support/ruby/shim.rb +19 -0
- data/lib/active_support/test_case.rb +8 -1
- data/lib/active_support/testing/assertions.rb +2 -14
- data/lib/active_support/testing/declarative.rb +31 -12
- data/lib/active_support/testing/deprecation.rb +8 -10
- data/lib/active_support/testing/isolation.rb +153 -0
- data/lib/active_support/testing/pending.rb +48 -0
- data/lib/active_support/testing/performance.rb +342 -339
- data/lib/active_support/testing/setup_and_teardown.rb +48 -31
- data/lib/active_support/time.rb +34 -0
- data/lib/active_support/time/autoload.rb +5 -0
- data/lib/active_support/time_with_zone.rb +18 -12
- data/lib/active_support/values/time_zone.rb +97 -93
- data/lib/active_support/version.rb +3 -3
- data/lib/active_support/whiny_nil.rb +1 -4
- data/lib/active_support/xml_mini.rb +2 -0
- data/lib/active_support/xml_mini/jdom.rb +13 -7
- data/lib/active_support/xml_mini/libxml.rb +19 -12
- data/lib/active_support/xml_mini/libxmlsax.rb +19 -9
- data/lib/active_support/xml_mini/nokogiri.rb +18 -12
- data/lib/active_support/xml_mini/nokogirisax.rb +15 -6
- data/lib/active_support/xml_mini/rexml.rb +24 -9
- metadata +94 -244
- data/lib/active_support/cache/drb_store.rb +0 -14
- data/lib/active_support/core_ext/array/wrapper.rb +0 -24
- data/lib/active_support/core_ext/base64.rb +0 -4
- data/lib/active_support/core_ext/base64/encoding.rb +0 -16
- data/lib/active_support/core_ext/bigdecimal.rb +0 -6
- data/lib/active_support/core_ext/bigdecimal/conversions.rb +0 -37
- data/lib/active_support/core_ext/blank.rb +0 -2
- data/lib/active_support/core_ext/class/removal.rb +0 -50
- data/lib/active_support/core_ext/date.rb +0 -10
- data/lib/active_support/core_ext/date/behavior.rb +0 -42
- data/lib/active_support/core_ext/date_time.rb +0 -12
- data/lib/active_support/core_ext/duplicable.rb +0 -43
- data/lib/active_support/core_ext/float/time.rb +0 -27
- data/lib/active_support/core_ext/integer/even_odd.rb +0 -29
- data/lib/active_support/core_ext/kernel/singleton_class.rb +0 -13
- data/lib/active_support/core_ext/module/model_naming.rb +0 -25
- data/lib/active_support/core_ext/module/remove_method.rb +0 -6
- data/lib/active_support/core_ext/numeric/conversions.rb +0 -19
- data/lib/active_support/core_ext/object/extending.rb +0 -80
- data/lib/active_support/core_ext/object/singleton_class.rb +0 -13
- data/lib/active_support/core_ext/pathname.rb +0 -7
- data/lib/active_support/core_ext/pathname/clean_within.rb +0 -14
- data/lib/active_support/core_ext/string/bytesize.rb +0 -5
- data/lib/active_support/core_ext/string/iterators.rb +0 -23
- data/lib/active_support/core_ext/symbol.rb +0 -14
- data/lib/active_support/core_ext/time.rb +0 -46
- data/lib/active_support/core_ext/time/behavior.rb +0 -13
- data/lib/active_support/json/backends/okjson.rb +0 -644
- data/lib/active_support/json/backends/yajl.rb +0 -40
- data/lib/active_support/json/encoders/date.rb +0 -22
- data/lib/active_support/json/encoders/date_time.rb +0 -22
- data/lib/active_support/json/encoders/enumerable.rb +0 -17
- data/lib/active_support/json/encoders/false_class.rb +0 -7
- data/lib/active_support/json/encoders/hash.rb +0 -56
- data/lib/active_support/json/encoders/nil_class.rb +0 -7
- data/lib/active_support/json/encoders/numeric.rb +0 -21
- data/lib/active_support/json/encoders/object.rb +0 -10
- data/lib/active_support/json/encoders/regexp.rb +0 -9
- data/lib/active_support/json/encoders/string.rb +0 -9
- data/lib/active_support/json/encoders/symbol.rb +0 -5
- data/lib/active_support/json/encoders/time.rb +0 -22
- data/lib/active_support/json/encoders/true_class.rb +0 -7
- data/lib/active_support/vendor.rb +0 -36
- data/lib/active_support/vendor/builder-2.1.2/blankslate.rb +0 -113
- data/lib/active_support/vendor/builder-2.1.2/builder.rb +0 -13
- data/lib/active_support/vendor/builder-2.1.2/builder/blankslate.rb +0 -20
- data/lib/active_support/vendor/builder-2.1.2/builder/css.rb +0 -250
- data/lib/active_support/vendor/builder-2.1.2/builder/xchar.rb +0 -115
- data/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb +0 -139
- data/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb +0 -63
- data/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb +0 -328
- data/lib/active_support/vendor/i18n-0.4.1/i18n.rb +0 -322
- data/lib/active_support/vendor/i18n-0.4.1/i18n/backend.rb +0 -20
- data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/active_record.rb +0 -61
- data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/active_record/missing.rb +0 -65
- data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/active_record/store_procs.rb +0 -38
- data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/active_record/translation.rb +0 -93
- data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/base.rb +0 -237
- data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/cache.rb +0 -77
- data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/cascade.rb +0 -57
- data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/chain.rb +0 -77
- data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/cldr.rb +0 -100
- data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/fallbacks.rb +0 -69
- data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/flatten.rb +0 -113
- data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/gettext.rb +0 -75
- data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/interpolation_compiler.rb +0 -123
- data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/key_value.rb +0 -102
- data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/memoize.rb +0 -48
- data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/metadata.rb +0 -65
- data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/pluralization.rb +0 -57
- data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/simple.rb +0 -87
- data/lib/active_support/vendor/i18n-0.4.1/i18n/backend/transliterator.rb +0 -98
- data/lib/active_support/vendor/i18n-0.4.1/i18n/config.rb +0 -84
- data/lib/active_support/vendor/i18n-0.4.1/i18n/core_ext/hash.rb +0 -29
- data/lib/active_support/vendor/i18n-0.4.1/i18n/exceptions.rb +0 -61
- data/lib/active_support/vendor/i18n-0.4.1/i18n/gettext.rb +0 -27
- data/lib/active_support/vendor/i18n-0.4.1/i18n/gettext/helpers.rb +0 -65
- data/lib/active_support/vendor/i18n-0.4.1/i18n/gettext/po_parser.rb +0 -329
- data/lib/active_support/vendor/i18n-0.4.1/i18n/locale.rb +0 -6
- data/lib/active_support/vendor/i18n-0.4.1/i18n/locale/fallbacks.rb +0 -98
- data/lib/active_support/vendor/i18n-0.4.1/i18n/locale/tag.rb +0 -28
- data/lib/active_support/vendor/i18n-0.4.1/i18n/locale/tag/parents.rb +0 -24
- data/lib/active_support/vendor/i18n-0.4.1/i18n/locale/tag/rfc4646.rb +0 -76
- data/lib/active_support/vendor/i18n-0.4.1/i18n/locale/tag/simple.rb +0 -41
- data/lib/active_support/vendor/i18n-0.4.1/i18n/version.rb +0 -3
- data/lib/active_support/vendor/memcache-client-1.7.4/memcache.rb +0 -1107
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo.rb +0 -33
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/data_timezone.rb +0 -47
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/data_timezone_info.rb +0 -228
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Africa/Algiers.rb +0 -55
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Africa/Cairo.rb +0 -219
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Africa/Casablanca.rb +0 -40
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Africa/Harare.rb +0 -18
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Africa/Johannesburg.rb +0 -25
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Africa/Monrovia.rb +0 -22
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Africa/Nairobi.rb +0 -23
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Argentina/Buenos_Aires.rb +0 -166
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Argentina/San_Juan.rb +0 -86
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Bogota.rb +0 -23
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Caracas.rb +0 -23
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Chicago.rb +0 -283
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Chihuahua.rb +0 -136
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Denver.rb +0 -204
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Godthab.rb +0 -161
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Guatemala.rb +0 -27
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Halifax.rb +0 -274
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Indiana/Indianapolis.rb +0 -149
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Juneau.rb +0 -194
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/La_Paz.rb +0 -22
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Lima.rb +0 -35
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Los_Angeles.rb +0 -232
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Mazatlan.rb +0 -139
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Mexico_City.rb +0 -144
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Monterrey.rb +0 -131
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/New_York.rb +0 -282
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Phoenix.rb +0 -30
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Regina.rb +0 -74
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Santiago.rb +0 -205
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Sao_Paulo.rb +0 -171
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/St_Johns.rb +0 -288
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/America/Tijuana.rb +0 -196
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Almaty.rb +0 -67
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Baghdad.rb +0 -73
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Baku.rb +0 -161
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Bangkok.rb +0 -20
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Chongqing.rb +0 -33
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Colombo.rb +0 -30
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Dhaka.rb +0 -27
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Hong_Kong.rb +0 -87
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Irkutsk.rb +0 -165
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Jakarta.rb +0 -30
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Jerusalem.rb +0 -163
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Kabul.rb +0 -20
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Kamchatka.rb +0 -163
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Karachi.rb +0 -30
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Katmandu.rb +0 -20
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Kolkata.rb +0 -25
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Krasnoyarsk.rb +0 -163
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Kuala_Lumpur.rb +0 -31
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Kuwait.rb +0 -18
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Magadan.rb +0 -163
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Muscat.rb +0 -18
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Novosibirsk.rb +0 -164
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Rangoon.rb +0 -24
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Riyadh.rb +0 -18
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Seoul.rb +0 -34
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Shanghai.rb +0 -35
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Singapore.rb +0 -33
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Taipei.rb +0 -59
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Tashkent.rb +0 -47
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Tbilisi.rb +0 -78
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Tehran.rb +0 -121
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Tokyo.rb +0 -30
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Ulaanbaatar.rb +0 -65
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Urumqi.rb +0 -33
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Vladivostok.rb +0 -164
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Yakutsk.rb +0 -163
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Yekaterinburg.rb +0 -165
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Asia/Yerevan.rb +0 -165
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Atlantic/Azores.rb +0 -270
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Atlantic/Cape_Verde.rb +0 -23
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Atlantic/South_Georgia.rb +0 -18
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Australia/Adelaide.rb +0 -187
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Australia/Brisbane.rb +0 -35
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Australia/Darwin.rb +0 -29
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Australia/Hobart.rb +0 -193
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Australia/Melbourne.rb +0 -185
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Australia/Perth.rb +0 -37
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Australia/Sydney.rb +0 -185
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Etc/UTC.rb +0 -16
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Amsterdam.rb +0 -228
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Athens.rb +0 -185
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Belgrade.rb +0 -163
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Berlin.rb +0 -188
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Bratislava.rb +0 -13
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Brussels.rb +0 -232
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Bucharest.rb +0 -181
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Budapest.rb +0 -197
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Copenhagen.rb +0 -179
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Dublin.rb +0 -276
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Helsinki.rb +0 -163
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Istanbul.rb +0 -218
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Kiev.rb +0 -168
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Lisbon.rb +0 -268
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Ljubljana.rb +0 -13
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/London.rb +0 -288
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Madrid.rb +0 -211
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Minsk.rb +0 -170
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Moscow.rb +0 -181
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Paris.rb +0 -232
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Prague.rb +0 -187
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Riga.rb +0 -176
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Rome.rb +0 -215
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Sarajevo.rb +0 -13
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Skopje.rb +0 -13
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Sofia.rb +0 -173
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Stockholm.rb +0 -165
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Tallinn.rb +0 -172
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Vienna.rb +0 -183
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Vilnius.rb +0 -170
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Warsaw.rb +0 -212
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Europe/Zagreb.rb +0 -13
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Auckland.rb +0 -202
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Fiji.rb +0 -23
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Guam.rb +0 -22
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Honolulu.rb +0 -28
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Majuro.rb +0 -20
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Midway.rb +0 -25
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Noumea.rb +0 -25
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Pago_Pago.rb +0 -26
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Port_Moresby.rb +0 -20
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions/Pacific/Tongatapu.rb +0 -27
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/info_timezone.rb +0 -52
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/linked_timezone.rb +0 -51
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/linked_timezone_info.rb +0 -44
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/offset_rationals.rb +0 -98
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/ruby_core_support.rb +0 -56
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/time_or_datetime.rb +0 -292
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone.rb +0 -508
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone_definition.rb +0 -56
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone_info.rb +0 -40
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone_offset_info.rb +0 -94
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone_period.rb +0 -198
- data/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone_transition_info.rb +0 -129
- data/lib/activesupport.rb +0 -2
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/core_ext/file/atomic'
|
2
|
+
|
1
3
|
module ActiveSupport
|
2
4
|
module Cache
|
3
5
|
# A cache store implementation which stores everything on the filesystem.
|
@@ -8,43 +10,59 @@ module ActiveSupport
|
|
8
10
|
@cache_path = cache_path
|
9
11
|
end
|
10
12
|
|
13
|
+
# Reads a value from the cache.
|
14
|
+
#
|
15
|
+
# Possible options:
|
16
|
+
# - +:expires_in+ - the number of seconds that this value may stay in
|
17
|
+
# the cache.
|
11
18
|
def read(name, options = nil)
|
12
|
-
super
|
13
|
-
|
19
|
+
super do
|
20
|
+
file_name = real_file_path(name)
|
21
|
+
expires = expires_in(options)
|
22
|
+
|
23
|
+
if File.exist?(file_name) && (expires <= 0 || Time.now - File.mtime(file_name) < expires)
|
24
|
+
File.open(file_name, 'rb') { |f| Marshal.load(f) }
|
25
|
+
end
|
26
|
+
end
|
14
27
|
end
|
15
28
|
|
29
|
+
# Writes a value to the cache.
|
16
30
|
def write(name, value, options = nil)
|
17
|
-
super
|
18
|
-
|
19
|
-
|
20
|
-
|
31
|
+
super do
|
32
|
+
ensure_cache_path(File.dirname(real_file_path(name)))
|
33
|
+
File.atomic_write(real_file_path(name), cache_path) { |f| Marshal.dump(value, f) }
|
34
|
+
value
|
35
|
+
end
|
21
36
|
rescue => e
|
22
37
|
logger.error "Couldn't create cache directory: #{name} (#{e.message})" if logger
|
23
38
|
end
|
24
39
|
|
25
40
|
def delete(name, options = nil)
|
26
|
-
super
|
27
|
-
|
41
|
+
super do
|
42
|
+
File.delete(real_file_path(name))
|
43
|
+
end
|
28
44
|
rescue SystemCallError => e
|
29
45
|
# If there's no cache, then there's nothing to complain about
|
30
46
|
end
|
31
47
|
|
32
48
|
def delete_matched(matcher, options = nil)
|
33
|
-
super
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
49
|
+
super do
|
50
|
+
search_dir(@cache_path) do |f|
|
51
|
+
if f =~ matcher
|
52
|
+
begin
|
53
|
+
File.delete(f)
|
54
|
+
rescue SystemCallError => e
|
55
|
+
# If there's no cache, then there's nothing to complain about
|
56
|
+
end
|
40
57
|
end
|
41
58
|
end
|
42
59
|
end
|
43
60
|
end
|
44
61
|
|
45
62
|
def exist?(name, options = nil)
|
46
|
-
super
|
47
|
-
|
63
|
+
super do
|
64
|
+
File.exist?(real_file_path(name))
|
65
|
+
end
|
48
66
|
end
|
49
67
|
|
50
68
|
private
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'memcache'
|
2
|
+
require 'active_support/core_ext/array/extract_options'
|
2
3
|
|
3
4
|
module ActiveSupport
|
4
5
|
module Cache
|
@@ -12,7 +13,7 @@ module ActiveSupport
|
|
12
13
|
# and MemCacheStore will load balance between all available servers. If a
|
13
14
|
# server goes down, then MemCacheStore will ignore it until it goes back
|
14
15
|
# online.
|
15
|
-
# - Time-based expiry support. See #write and the
|
16
|
+
# - Time-based expiry support. See #write and the <tt>:expires_in</tt> option.
|
16
17
|
# - Per-request in memory cache for all communication with the MemCache server(s).
|
17
18
|
class MemCacheStore < Store
|
18
19
|
module Response # :nodoc:
|
@@ -59,8 +60,9 @@ module ActiveSupport
|
|
59
60
|
end
|
60
61
|
|
61
62
|
def read(key, options = nil) # :nodoc:
|
62
|
-
super
|
63
|
-
|
63
|
+
super do
|
64
|
+
@data.get(key, raw?(options))
|
65
|
+
end
|
64
66
|
rescue MemCache::MemCacheError => e
|
65
67
|
logger.error("MemCacheError (#{e}): #{e.message}")
|
66
68
|
nil
|
@@ -69,27 +71,29 @@ module ActiveSupport
|
|
69
71
|
# Writes a value to the cache.
|
70
72
|
#
|
71
73
|
# Possible options:
|
72
|
-
# -
|
74
|
+
# - <tt>:unless_exist</tt> - set to true if you don't want to update the cache
|
73
75
|
# if the key is already set.
|
74
|
-
# -
|
76
|
+
# - <tt>:expires_in</tt> - the number of seconds that this value may stay in
|
75
77
|
# the cache. See ActiveSupport::Cache::Store#write for an example.
|
76
78
|
def write(key, value, options = nil)
|
77
|
-
super
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
79
|
+
super do
|
80
|
+
method = options && options[:unless_exist] ? :add : :set
|
81
|
+
# memcache-client will break the connection if you send it an integer
|
82
|
+
# in raw mode, so we convert it to a string to be sure it continues working.
|
83
|
+
value = value.to_s if raw?(options)
|
84
|
+
response = @data.send(method, key, value, expires_in(options), raw?(options))
|
85
|
+
response == Response::STORED
|
86
|
+
end
|
84
87
|
rescue MemCache::MemCacheError => e
|
85
88
|
logger.error("MemCacheError (#{e}): #{e.message}")
|
86
89
|
false
|
87
90
|
end
|
88
91
|
|
89
92
|
def delete(key, options = nil) # :nodoc:
|
90
|
-
super
|
91
|
-
|
92
|
-
|
93
|
+
super do
|
94
|
+
response = @data.delete(key, expires_in(options))
|
95
|
+
response == Response::DELETED
|
96
|
+
end
|
93
97
|
rescue MemCache::MemCacheError => e
|
94
98
|
logger.error("MemCacheError (#{e}): #{e.message}")
|
95
99
|
false
|
@@ -99,21 +103,26 @@ module ActiveSupport
|
|
99
103
|
# Doesn't call super, cause exist? in memcache is in fact a read
|
100
104
|
# But who cares? Reading is very fast anyway
|
101
105
|
# Local cache is checked first, if it doesn't know then memcache itself is read from
|
102
|
-
|
106
|
+
super do
|
107
|
+
!read(key, options).nil?
|
108
|
+
end
|
103
109
|
end
|
104
110
|
|
105
111
|
def increment(key, amount = 1) # :nodoc:
|
106
|
-
|
112
|
+
response = instrument(:increment, key, :amount => amount) do
|
113
|
+
@data.incr(key, amount)
|
114
|
+
end
|
107
115
|
|
108
|
-
response = @data.incr(key, amount)
|
109
116
|
response == Response::NOT_FOUND ? nil : response
|
110
117
|
rescue MemCache::MemCacheError
|
111
118
|
nil
|
112
119
|
end
|
113
120
|
|
114
121
|
def decrement(key, amount = 1) # :nodoc:
|
115
|
-
|
116
|
-
|
122
|
+
response = instrument(:decrement, key, :amount => amount) do
|
123
|
+
@data.decr(key, amount)
|
124
|
+
end
|
125
|
+
|
117
126
|
response == Response::NOT_FOUND ? nil : response
|
118
127
|
rescue MemCache::MemCacheError
|
119
128
|
nil
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/core_ext/object/duplicable'
|
2
|
+
|
1
3
|
module ActiveSupport
|
2
4
|
module Cache
|
3
5
|
# A cache store implementation which stores everything into memory in the
|
@@ -19,35 +21,34 @@ module ActiveSupport
|
|
19
21
|
@data = {}
|
20
22
|
end
|
21
23
|
|
22
|
-
def read_multi(*names)
|
23
|
-
results = {}
|
24
|
-
names.each { |n| results[n] = read(n) }
|
25
|
-
results
|
26
|
-
end
|
27
|
-
|
28
24
|
def read(name, options = nil)
|
29
|
-
super
|
30
|
-
|
25
|
+
super do
|
26
|
+
@data[name]
|
27
|
+
end
|
31
28
|
end
|
32
29
|
|
33
30
|
def write(name, value, options = nil)
|
34
|
-
super
|
35
|
-
|
31
|
+
super do
|
32
|
+
@data[name] = (value.duplicable? ? value.dup : value).freeze
|
33
|
+
end
|
36
34
|
end
|
37
35
|
|
38
36
|
def delete(name, options = nil)
|
39
|
-
super
|
40
|
-
|
37
|
+
super do
|
38
|
+
@data.delete(name)
|
39
|
+
end
|
41
40
|
end
|
42
41
|
|
43
42
|
def delete_matched(matcher, options = nil)
|
44
|
-
super
|
45
|
-
|
43
|
+
super do
|
44
|
+
@data.delete_if { |k,v| k =~ matcher }
|
45
|
+
end
|
46
46
|
end
|
47
47
|
|
48
|
-
def exist?(name,
|
49
|
-
super
|
50
|
-
|
48
|
+
def exist?(name,options = nil)
|
49
|
+
super do
|
50
|
+
@data.has_key?(name)
|
51
|
+
end
|
51
52
|
end
|
52
53
|
|
53
54
|
def clear
|
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'active_support/core_ext/object/duplicable'
|
2
|
+
require 'active_support/core_ext/string/inflections'
|
3
|
+
|
1
4
|
module ActiveSupport
|
2
5
|
module Cache
|
3
6
|
module Strategy
|
@@ -15,7 +18,7 @@ module ActiveSupport
|
|
15
18
|
def middleware
|
16
19
|
@middleware ||= begin
|
17
20
|
klass = Class.new
|
18
|
-
klass.class_eval(<<-EOS, __FILE__, __LINE__
|
21
|
+
klass.class_eval(<<-EOS, __FILE__, __LINE__)
|
19
22
|
def initialize(app)
|
20
23
|
@app = app
|
21
24
|
end
|
@@ -27,6 +30,11 @@ module ActiveSupport
|
|
27
30
|
Thread.current[:#{thread_local_key}] = nil
|
28
31
|
end
|
29
32
|
EOS
|
33
|
+
|
34
|
+
def klass.to_s
|
35
|
+
"ActiveSupport::Cache::Strategy::LocalCache"
|
36
|
+
end
|
37
|
+
|
30
38
|
klass
|
31
39
|
end
|
32
40
|
end
|
@@ -1,3 +1,8 @@
|
|
1
|
+
require 'active_support/core_ext/array/wrap'
|
2
|
+
require 'active_support/core_ext/class/inheritable_attributes'
|
3
|
+
require 'active_support/core_ext/kernel/reporting'
|
4
|
+
require 'active_support/core_ext/object/metaclass'
|
5
|
+
|
1
6
|
module ActiveSupport
|
2
7
|
# Callbacks are hooks into the lifecycle of an object that allow you to trigger logic
|
3
8
|
# before or after an alteration of the object state.
|
@@ -8,23 +13,23 @@ module ActiveSupport
|
|
8
13
|
# class Storage
|
9
14
|
# include ActiveSupport::Callbacks
|
10
15
|
#
|
11
|
-
# define_callbacks :
|
16
|
+
# define_callbacks :save
|
12
17
|
# end
|
13
18
|
#
|
14
19
|
# class ConfigStorage < Storage
|
15
|
-
#
|
20
|
+
# set_callback :save, :before, :saving_message
|
16
21
|
# def saving_message
|
17
22
|
# puts "saving..."
|
18
23
|
# end
|
19
24
|
#
|
20
|
-
#
|
25
|
+
# set_callback :save, :after do |object|
|
21
26
|
# puts "saved"
|
22
27
|
# end
|
23
28
|
#
|
24
29
|
# def save
|
25
|
-
# run_callbacks
|
26
|
-
#
|
27
|
-
#
|
30
|
+
# run_callbacks :save do
|
31
|
+
# puts "- save"
|
32
|
+
# end
|
28
33
|
# end
|
29
34
|
# end
|
30
35
|
#
|
@@ -42,28 +47,28 @@ module ActiveSupport
|
|
42
47
|
# class Storage
|
43
48
|
# include ActiveSupport::Callbacks
|
44
49
|
#
|
45
|
-
# define_callbacks :
|
50
|
+
# define_callbacks :save
|
46
51
|
#
|
47
|
-
#
|
52
|
+
# set_callback :save, :before, :prepare
|
48
53
|
# def prepare
|
49
54
|
# puts "preparing save"
|
50
55
|
# end
|
51
56
|
# end
|
52
57
|
#
|
53
58
|
# class ConfigStorage < Storage
|
54
|
-
#
|
59
|
+
# set_callback :save, :before, :saving_message
|
55
60
|
# def saving_message
|
56
61
|
# puts "saving..."
|
57
62
|
# end
|
58
63
|
#
|
59
|
-
#
|
64
|
+
# set_callback :save, :after do |object|
|
60
65
|
# puts "saved"
|
61
66
|
# end
|
62
67
|
#
|
63
68
|
# def save
|
64
|
-
# run_callbacks
|
65
|
-
#
|
66
|
-
#
|
69
|
+
# run_callbacks :save do
|
70
|
+
# puts "- save"
|
71
|
+
# end
|
67
72
|
# end
|
68
73
|
# end
|
69
74
|
#
|
@@ -75,205 +80,521 @@ module ActiveSupport
|
|
75
80
|
# saving...
|
76
81
|
# - save
|
77
82
|
# saved
|
83
|
+
#
|
78
84
|
module Callbacks
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
85
|
+
extend Concern
|
86
|
+
|
87
|
+
def run_callbacks(kind, *args, &block)
|
88
|
+
send("_run_#{kind}_callbacks", *args, &block)
|
89
|
+
end
|
90
|
+
|
91
|
+
class Callback
|
92
|
+
@@_callback_sequence = 0
|
93
|
+
|
94
|
+
attr_accessor :chain, :filter, :kind, :options, :per_key, :klass, :raw_filter
|
95
|
+
|
96
|
+
def initialize(chain, filter, kind, options, klass)
|
97
|
+
@chain, @kind, @klass = chain, kind, klass
|
98
|
+
normalize_options!(options)
|
99
|
+
|
100
|
+
@per_key = options.delete(:per_key)
|
101
|
+
@raw_filter, @options = filter, options
|
102
|
+
@filter = _compile_filter(filter)
|
103
|
+
@compiled_options = _compile_options(options)
|
104
|
+
@callback_id = next_id
|
105
|
+
|
106
|
+
_compile_per_key_options
|
84
107
|
end
|
85
108
|
|
86
|
-
def
|
87
|
-
|
109
|
+
def clone(chain, klass)
|
110
|
+
obj = super()
|
111
|
+
obj.chain = chain
|
112
|
+
obj.klass = klass
|
113
|
+
obj.per_key = @per_key.dup
|
114
|
+
obj.options = @options.dup
|
115
|
+
obj.per_key[:if] = @per_key[:if].dup
|
116
|
+
obj.per_key[:unless] = @per_key[:unless].dup
|
117
|
+
obj.options[:if] = @options[:if].dup
|
118
|
+
obj.options[:unless] = @options[:unless].dup
|
119
|
+
obj
|
120
|
+
end
|
88
121
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
122
|
+
def normalize_options!(options)
|
123
|
+
options[:if] = Array.wrap(options[:if])
|
124
|
+
options[:unless] = Array.wrap(options[:unless])
|
125
|
+
|
126
|
+
options[:per_key] ||= {}
|
127
|
+
options[:per_key][:if] = Array.wrap(options[:per_key][:if])
|
128
|
+
options[:per_key][:unless] = Array.wrap(options[:per_key][:unless])
|
129
|
+
end
|
130
|
+
|
131
|
+
def name
|
132
|
+
chain.name
|
133
|
+
end
|
134
|
+
|
135
|
+
def next_id
|
136
|
+
@@_callback_sequence += 1
|
137
|
+
end
|
138
|
+
|
139
|
+
def matches?(_kind, _filter)
|
140
|
+
@kind == _kind && @filter == _filter
|
141
|
+
end
|
142
|
+
|
143
|
+
def _update_filter(filter_options, new_options)
|
144
|
+
filter_options[:if].push(new_options[:unless]) if new_options.key?(:unless)
|
145
|
+
filter_options[:unless].push(new_options[:if]) if new_options.key?(:if)
|
146
|
+
end
|
147
|
+
|
148
|
+
def recompile!(_options, _per_key)
|
149
|
+
_update_filter(self.options, _options)
|
150
|
+
_update_filter(self.per_key, _per_key)
|
151
|
+
|
152
|
+
@callback_id = next_id
|
153
|
+
@filter = _compile_filter(@raw_filter)
|
154
|
+
@compiled_options = _compile_options(@options)
|
155
|
+
_compile_per_key_options
|
156
|
+
end
|
157
|
+
|
158
|
+
def _compile_per_key_options
|
159
|
+
key_options = _compile_options(@per_key)
|
160
|
+
|
161
|
+
@klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
|
162
|
+
def _one_time_conditions_valid_#{@callback_id}?
|
163
|
+
true #{key_options[0]}
|
95
164
|
end
|
96
|
-
|
165
|
+
RUBY_EVAL
|
97
166
|
end
|
98
167
|
|
99
|
-
#
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
168
|
+
# This will supply contents for before and around filters, and no
|
169
|
+
# contents for after filters (for the forward pass).
|
170
|
+
def start(key=nil, object=nil)
|
171
|
+
return if key && !object.send("_one_time_conditions_valid_#{@callback_id}?")
|
172
|
+
|
173
|
+
# options[0] is the compiled form of supplied conditions
|
174
|
+
# options[1] is the "end" for the conditional
|
175
|
+
#
|
176
|
+
if @kind == :before || @kind == :around
|
177
|
+
if @kind == :before
|
178
|
+
# if condition # before_save :filter_name, :if => :condition
|
179
|
+
# filter_name
|
180
|
+
# end
|
181
|
+
filter = <<-RUBY_EVAL
|
182
|
+
unless halted
|
183
|
+
result = #{@filter}
|
184
|
+
halted = (#{chain.config[:terminator]})
|
185
|
+
end
|
186
|
+
RUBY_EVAL
|
187
|
+
|
188
|
+
[@compiled_options[0], filter, @compiled_options[1]].compact.join("\n")
|
189
|
+
else
|
190
|
+
# Compile around filters with conditions into proxy methods
|
191
|
+
# that contain the conditions.
|
192
|
+
#
|
193
|
+
# For `around_save :filter_name, :if => :condition':
|
194
|
+
#
|
195
|
+
# def _conditional_callback_save_17
|
196
|
+
# if condition
|
197
|
+
# filter_name do
|
198
|
+
# yield self
|
199
|
+
# end
|
200
|
+
# else
|
201
|
+
# yield self
|
202
|
+
# end
|
203
|
+
# end
|
204
|
+
#
|
205
|
+
name = "_conditional_callback_#{@kind}_#{next_id}"
|
206
|
+
txt, line = <<-RUBY_EVAL, __LINE__ + 1
|
207
|
+
def #{name}(halted)
|
208
|
+
#{@compiled_options[0] || "if true"} && !halted
|
209
|
+
#{@filter} do
|
210
|
+
yield self
|
211
|
+
end
|
212
|
+
else
|
213
|
+
yield self
|
214
|
+
end
|
215
|
+
end
|
216
|
+
RUBY_EVAL
|
217
|
+
@klass.class_eval(txt, __FILE__, line)
|
218
|
+
"#{name}(halted) do"
|
219
|
+
end
|
105
220
|
end
|
106
|
-
self
|
107
221
|
end
|
108
222
|
|
109
|
-
|
110
|
-
|
111
|
-
end
|
223
|
+
# This will supply contents for around and after filters, but not
|
224
|
+
# before filters (for the backward pass).
|
225
|
+
def end(key=nil, object=nil)
|
226
|
+
return if key && !object.send("_one_time_conditions_valid_#{@callback_id}?")
|
112
227
|
|
113
|
-
|
114
|
-
|
228
|
+
if @kind == :around || @kind == :after
|
229
|
+
# if condition # after_save :filter_name, :if => :condition
|
230
|
+
# filter_name
|
231
|
+
# end
|
232
|
+
if @kind == :after
|
233
|
+
[@compiled_options[0], @filter, @compiled_options[1]].compact.join("\n")
|
234
|
+
else
|
235
|
+
"end"
|
236
|
+
end
|
237
|
+
end
|
115
238
|
end
|
116
239
|
|
117
240
|
private
|
118
|
-
def self.extract_options(*methods, &block)
|
119
|
-
methods.flatten!
|
120
|
-
options = methods.extract_options!
|
121
|
-
methods << block if block_given?
|
122
|
-
return methods, options
|
123
|
-
end
|
124
241
|
|
125
|
-
|
126
|
-
|
242
|
+
# Options support the same options as filters themselves (and support
|
243
|
+
# symbols, string, procs, and objects), so compile a conditional
|
244
|
+
# expression based on the options
|
245
|
+
def _compile_options(options)
|
246
|
+
return [] if options[:if].empty? && options[:unless].empty?
|
247
|
+
|
248
|
+
conditions = []
|
249
|
+
|
250
|
+
unless options[:if].empty?
|
251
|
+
conditions << Array.wrap(_compile_filter(options[:if]))
|
127
252
|
end
|
128
|
-
end
|
129
253
|
|
130
|
-
|
131
|
-
|
254
|
+
unless options[:unless].empty?
|
255
|
+
conditions << Array.wrap(_compile_filter(options[:unless])).map {|f| "!#{f}"}
|
256
|
+
end
|
132
257
|
|
133
|
-
|
134
|
-
@kind = kind
|
135
|
-
@method = method
|
136
|
-
@identifier = options[:identifier]
|
137
|
-
@options = options
|
258
|
+
["if #{conditions.flatten.join(" && ")}", "end"]
|
138
259
|
end
|
139
260
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
261
|
+
# Filters support:
|
262
|
+
#
|
263
|
+
# Arrays:: Used in conditions. This is used to specify
|
264
|
+
# multiple conditions. Used internally to
|
265
|
+
# merge conditions from skip_* filters
|
266
|
+
# Symbols:: A method to call
|
267
|
+
# Strings:: Some content to evaluate
|
268
|
+
# Procs:: A proc to call with the object
|
269
|
+
# Objects:: An object with a before_foo method on it to call
|
270
|
+
#
|
271
|
+
# All of these objects are compiled into methods and handled
|
272
|
+
# the same after this point:
|
273
|
+
#
|
274
|
+
# Arrays:: Merged together into a single filter
|
275
|
+
# Symbols:: Already methods
|
276
|
+
# Strings:: class_eval'ed into methods
|
277
|
+
# Procs:: define_method'ed into methods
|
278
|
+
# Objects::
|
279
|
+
# a method is created that calls the before_foo method
|
280
|
+
# on the object.
|
281
|
+
#
|
282
|
+
def _compile_filter(filter)
|
283
|
+
method_name = "_callback_#{@kind}_#{next_id}"
|
284
|
+
case filter
|
285
|
+
when Array
|
286
|
+
filter.map {|f| _compile_filter(f)}
|
287
|
+
when Symbol
|
288
|
+
filter
|
289
|
+
when String
|
290
|
+
"(#{filter})"
|
291
|
+
when Proc
|
292
|
+
@klass.send(:define_method, method_name, &filter)
|
293
|
+
return method_name if filter.arity <= 0
|
294
|
+
|
295
|
+
method_name << (filter.arity == 1 ? "(self)" : " self, Proc.new ")
|
144
296
|
else
|
145
|
-
(
|
297
|
+
@klass.send(:define_method, "#{method_name}_object") { filter }
|
298
|
+
|
299
|
+
_normalize_legacy_filter(kind, filter)
|
300
|
+
scopes = Array.wrap(chain.config[:scope])
|
301
|
+
method_to_call = scopes.map{ |s| s.is_a?(Symbol) ? send(s) : s }.join("_")
|
302
|
+
|
303
|
+
@klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
|
304
|
+
def #{method_name}(&blk)
|
305
|
+
#{method_name}_object.send(:#{method_to_call}, self, &blk)
|
306
|
+
end
|
307
|
+
RUBY_EVAL
|
308
|
+
|
309
|
+
method_name
|
146
310
|
end
|
147
311
|
end
|
148
312
|
|
149
|
-
def
|
150
|
-
|
313
|
+
def _normalize_legacy_filter(kind, filter)
|
314
|
+
if !filter.respond_to?(kind) && filter.respond_to?(:filter)
|
315
|
+
filter.metaclass.class_eval(
|
316
|
+
"def #{kind}(context, &block) filter(context, &block) end",
|
317
|
+
__FILE__, __LINE__ - 1)
|
318
|
+
elsif filter.respond_to?(:before) && filter.respond_to?(:after) && kind == :around
|
319
|
+
def filter.around(context)
|
320
|
+
should_continue = before(context)
|
321
|
+
yield if should_continue
|
322
|
+
after(context)
|
323
|
+
end
|
324
|
+
end
|
151
325
|
end
|
326
|
+
end
|
327
|
+
|
328
|
+
# An Array with a compile method
|
329
|
+
class CallbackChain < Array
|
330
|
+
attr_reader :name, :config
|
152
331
|
|
153
|
-
def
|
154
|
-
|
332
|
+
def initialize(name, config)
|
333
|
+
@name = name
|
334
|
+
@config = {
|
335
|
+
:terminator => "false",
|
336
|
+
:rescuable => false,
|
337
|
+
:scope => [ :kind ]
|
338
|
+
}.merge(config)
|
155
339
|
end
|
156
340
|
|
157
|
-
def
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
341
|
+
def compile(key=nil, object=nil)
|
342
|
+
method = []
|
343
|
+
method << "value = nil"
|
344
|
+
method << "halted = false"
|
345
|
+
|
346
|
+
each do |callback|
|
347
|
+
method << callback.start(key, object)
|
348
|
+
end
|
349
|
+
|
350
|
+
if config[:rescuable]
|
351
|
+
method << "rescued_error = nil"
|
352
|
+
method << "begin"
|
353
|
+
end
|
354
|
+
|
355
|
+
method << "value = yield if block_given? && !halted"
|
356
|
+
|
357
|
+
if config[:rescuable]
|
358
|
+
method << "rescue Exception => e"
|
359
|
+
method << "rescued_error = e"
|
360
|
+
method << "end"
|
361
|
+
end
|
362
|
+
|
363
|
+
reverse_each do |callback|
|
364
|
+
method << callback.end(key, object)
|
162
365
|
end
|
163
|
-
end
|
164
366
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
raise ArgumentError,
|
169
|
-
"Cannot yield from a Proc type filter. The Proc must take two " +
|
170
|
-
"arguments and execute #call on the second argument."
|
367
|
+
method << "raise rescued_error if rescued_error" if config[:rescuable]
|
368
|
+
method << "halted ? false : (block_given? ? value : true)"
|
369
|
+
method.compact.join("\n")
|
171
370
|
end
|
371
|
+
end
|
172
372
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
373
|
+
module ClassMethods
|
374
|
+
# Make the run_callbacks :save method. The generated method takes
|
375
|
+
# a block that it'll yield to. It'll call the before and around filters
|
376
|
+
# in order, yield the block, and then run the after filters.
|
377
|
+
#
|
378
|
+
# run_callbacks :save do
|
379
|
+
# save
|
380
|
+
# end
|
381
|
+
#
|
382
|
+
# The run_callbacks :save method can optionally take a key, which
|
383
|
+
# will be used to compile an optimized callback method for each
|
384
|
+
# key. See #define_callbacks for more information.
|
385
|
+
#
|
386
|
+
def __define_runner(symbol) #:nodoc:
|
387
|
+
send("_update_#{symbol}_superclass_callbacks")
|
388
|
+
body = send("_#{symbol}_callbacks").compile(nil)
|
389
|
+
|
390
|
+
body, line = <<-RUBY_EVAL, __LINE__
|
391
|
+
def _run_#{symbol}_callbacks(key = nil, &blk)
|
392
|
+
if self.class.send("_update_#{symbol}_superclass_callbacks")
|
393
|
+
self.class.__define_runner(#{symbol.inspect})
|
394
|
+
return _run_#{symbol}_callbacks(key, &blk)
|
395
|
+
end
|
396
|
+
|
397
|
+
if key
|
398
|
+
name = "_run__\#{self.class.name.hash.abs}__#{symbol}__\#{key.hash.abs}__callbacks"
|
399
|
+
|
400
|
+
unless respond_to?(name)
|
401
|
+
self.class.__create_keyed_callback(name, :#{symbol}, self, &blk)
|
190
402
|
end
|
403
|
+
|
404
|
+
send(name, &blk)
|
405
|
+
else
|
406
|
+
#{body}
|
407
|
+
end
|
191
408
|
end
|
409
|
+
private :_run_#{symbol}_callbacks
|
410
|
+
RUBY_EVAL
|
411
|
+
|
412
|
+
silence_warnings do
|
413
|
+
undef_method "_run_#{symbol}_callbacks" if method_defined?("_run_#{symbol}_callbacks")
|
414
|
+
class_eval body, __FILE__, line
|
192
415
|
end
|
416
|
+
end
|
193
417
|
|
194
|
-
|
195
|
-
|
196
|
-
|
418
|
+
# This is called the first time a callback is called with a particular
|
419
|
+
# key. It creates a new callback method for the key, calculating
|
420
|
+
# which callbacks can be omitted because of per_key conditions.
|
421
|
+
#
|
422
|
+
def __create_keyed_callback(name, kind, object, &blk) #:nodoc:
|
423
|
+
@_keyed_callbacks ||= {}
|
424
|
+
@_keyed_callbacks[name] ||= begin
|
425
|
+
str = send("_#{kind}_callbacks").compile(name, object)
|
426
|
+
class_eval "def #{name}() #{str} end", __FILE__, __LINE__
|
427
|
+
true
|
197
428
|
end
|
198
|
-
|
429
|
+
end
|
199
430
|
|
200
|
-
|
201
|
-
|
202
|
-
|
431
|
+
# This is used internally to append, prepend and skip callbacks to the
|
432
|
+
# CallbackChain.
|
433
|
+
#
|
434
|
+
def __update_callbacks(name, filters = [], block = nil) #:nodoc:
|
435
|
+
send("_update_#{name}_superclass_callbacks")
|
203
436
|
|
204
|
-
|
437
|
+
type = [:before, :after, :around].include?(filters.first) ? filters.shift : :before
|
438
|
+
options = filters.last.is_a?(Hash) ? filters.pop : {}
|
439
|
+
filters.unshift(block) if block
|
440
|
+
|
441
|
+
chain = send("_#{name}_callbacks")
|
442
|
+
yield chain, type, filters, options if block_given?
|
443
|
+
|
444
|
+
__define_runner(name)
|
445
|
+
end
|
446
|
+
|
447
|
+
# Set callbacks for a previously defined callback.
|
448
|
+
#
|
449
|
+
# Syntax:
|
450
|
+
# set_callback :save, :before, :before_meth
|
451
|
+
# set_callback :save, :after, :after_meth, :if => :condition
|
452
|
+
# set_callback :save, :around, lambda { |r| stuff; yield; stuff }
|
453
|
+
#
|
454
|
+
# Use skip_callback to skip any defined one.
|
455
|
+
#
|
456
|
+
# When creating or skipping callbacks, you can specify conditions that
|
457
|
+
# are always the same for a given key. For instance, in ActionPack,
|
458
|
+
# we convert :only and :except conditions into per-key conditions.
|
459
|
+
#
|
460
|
+
# before_filter :authenticate, :except => "index"
|
461
|
+
# becomes
|
462
|
+
# dispatch_callback :before, :authenticate, :per_key => {:unless => proc {|c| c.action_name == "index"}}
|
463
|
+
#
|
464
|
+
# Per-Key conditions are evaluated only once per use of a given key.
|
465
|
+
# In the case of the above example, you would do:
|
466
|
+
#
|
467
|
+
# run_callbacks(:dispatch, action_name) { ... dispatch stuff ... }
|
468
|
+
#
|
469
|
+
# In that case, each action_name would get its own compiled callback
|
470
|
+
# method that took into consideration the per_key conditions. This
|
471
|
+
# is a speed improvement for ActionPack.
|
472
|
+
#
|
473
|
+
def set_callback(name, *filter_list, &block)
|
474
|
+
__update_callbacks(name, filter_list, block) do |chain, type, filters, options|
|
475
|
+
filters.map! do |filter|
|
476
|
+
removed = chain.delete_if {|c| c.matches?(type, filter) }
|
477
|
+
send("_removed_#{name}_callbacks").push(*removed)
|
478
|
+
Callback.new(chain, filter, type, options.dup, self)
|
479
|
+
end
|
480
|
+
|
481
|
+
options[:prepend] ? chain.unshift(*filters) : chain.push(*filters)
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
485
|
+
# Skip a previously defined callback for a given type.
|
486
|
+
#
|
487
|
+
def skip_callback(name, *filter_list, &block)
|
488
|
+
__update_callbacks(name, filter_list, block) do |chain, type, filters, options|
|
489
|
+
filters.each do |filter|
|
490
|
+
filter = chain.find {|c| c.matches?(type, filter) }
|
491
|
+
|
492
|
+
if filter && options.any?
|
493
|
+
new_filter = filter.clone(chain, self)
|
494
|
+
chain.insert(chain.index(filter), new_filter)
|
495
|
+
new_filter.recompile!(options, options[:per_key] || {})
|
496
|
+
end
|
497
|
+
|
498
|
+
chain.delete(filter)
|
499
|
+
send("_removed_#{name}_callbacks") << filter
|
500
|
+
end
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
# Reset callbacks for a given type.
|
505
|
+
#
|
506
|
+
def reset_callbacks(symbol)
|
507
|
+
callbacks = send("_#{symbol}_callbacks")
|
508
|
+
callbacks.clear
|
509
|
+
send("_removed_#{symbol}_callbacks").concat(callbacks)
|
510
|
+
__define_runner(symbol)
|
511
|
+
end
|
512
|
+
|
513
|
+
# Define callbacks types.
|
514
|
+
#
|
515
|
+
# ==== Example
|
516
|
+
#
|
517
|
+
# define_callbacks :validate
|
518
|
+
#
|
519
|
+
# ==== Options
|
520
|
+
#
|
521
|
+
# * <tt>:terminator</tt> - Indicates when a before filter is considered
|
522
|
+
# to be halted.
|
523
|
+
#
|
524
|
+
# define_callbacks :validate, :terminator => "result == false"
|
525
|
+
#
|
526
|
+
# In the example above, if any before validate callbacks returns false,
|
527
|
+
# other callbacks are not executed. Defaults to "false".
|
528
|
+
#
|
529
|
+
# * <tt>:rescuable</tt> - By default, after filters are not executed if
|
530
|
+
# the given block or an before_filter raises an error. Supply :rescuable => true
|
531
|
+
# to change this behavior.
|
532
|
+
#
|
533
|
+
# * <tt>:scope</tt> - Show which methods should be executed when a class
|
534
|
+
# is given as callback:
|
535
|
+
#
|
536
|
+
# define_callbacks :filters, :scope => [ :kind ]
|
537
|
+
#
|
538
|
+
# When a class is given:
|
539
|
+
#
|
540
|
+
# before_filter MyFilter
|
541
|
+
#
|
542
|
+
# It will call the type of the filter in the given class, which in this
|
543
|
+
# case, is "before".
|
544
|
+
#
|
545
|
+
# If, for instance, you supply the given scope:
|
546
|
+
#
|
547
|
+
# define_callbacks :validate, :scope => [ :kind, :name ]
|
548
|
+
#
|
549
|
+
# It will call "#{kind}_#{name}" in the given class. So "before_validate"
|
550
|
+
# will be called in the class below:
|
551
|
+
#
|
552
|
+
# before_validate MyValidation
|
553
|
+
#
|
554
|
+
# Defaults to :kind.
|
555
|
+
#
|
205
556
|
def define_callbacks(*callbacks)
|
557
|
+
config = callbacks.last.is_a?(Hash) ? callbacks.pop : {}
|
206
558
|
callbacks.each do |callback|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
if superclass.respond_to?(
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
559
|
+
extlib_inheritable_reader("_#{callback}_callbacks") do
|
560
|
+
CallbackChain.new(callback, config)
|
561
|
+
end
|
562
|
+
|
563
|
+
extlib_inheritable_reader("_removed_#{callback}_callbacks") do
|
564
|
+
[]
|
565
|
+
end
|
566
|
+
|
567
|
+
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
568
|
+
def self._#{callback}_superclass_callbacks
|
569
|
+
if superclass.respond_to?(:_#{callback}_callbacks)
|
570
|
+
superclass._#{callback}_callbacks + superclass._#{callback}_superclass_callbacks
|
571
|
+
else
|
572
|
+
[]
|
573
|
+
end
|
574
|
+
end
|
575
|
+
|
576
|
+
def self._update_#{callback}_superclass_callbacks
|
577
|
+
changed, index = false, 0
|
578
|
+
|
579
|
+
callbacks = (_#{callback}_superclass_callbacks -
|
580
|
+
_#{callback}_callbacks) - _removed_#{callback}_callbacks
|
581
|
+
|
582
|
+
callbacks.each do |callback|
|
583
|
+
if new_index = _#{callback}_callbacks.index(callback)
|
584
|
+
index = new_index + 1
|
585
|
+
else
|
586
|
+
changed = true
|
587
|
+
_#{callback}_callbacks.insert(index, callback)
|
588
|
+
index = index + 1
|
589
|
+
end
|
590
|
+
end
|
591
|
+
changed
|
592
|
+
end
|
593
|
+
METHOD
|
594
|
+
|
595
|
+
__define_runner(callback)
|
227
596
|
end
|
228
597
|
end
|
229
598
|
end
|
230
|
-
|
231
|
-
# Runs all the callbacks defined for the given options.
|
232
|
-
#
|
233
|
-
# If a block is given it will be called after each callback receiving as arguments:
|
234
|
-
#
|
235
|
-
# * the result from the callback
|
236
|
-
# * the object which has the callback
|
237
|
-
#
|
238
|
-
# If the result from the block evaluates to false, the callback chain is stopped.
|
239
|
-
#
|
240
|
-
# Example:
|
241
|
-
# class Storage
|
242
|
-
# include ActiveSupport::Callbacks
|
243
|
-
#
|
244
|
-
# define_callbacks :before_save, :after_save
|
245
|
-
# end
|
246
|
-
#
|
247
|
-
# class ConfigStorage < Storage
|
248
|
-
# before_save :pass
|
249
|
-
# before_save :pass
|
250
|
-
# before_save :stop
|
251
|
-
# before_save :pass
|
252
|
-
#
|
253
|
-
# def pass
|
254
|
-
# puts "pass"
|
255
|
-
# end
|
256
|
-
#
|
257
|
-
# def stop
|
258
|
-
# puts "stop"
|
259
|
-
# return false
|
260
|
-
# end
|
261
|
-
#
|
262
|
-
# def save
|
263
|
-
# result = run_callbacks(:before_save) { |result, object| result == false }
|
264
|
-
# puts "- save" if result
|
265
|
-
# end
|
266
|
-
# end
|
267
|
-
#
|
268
|
-
# config = ConfigStorage.new
|
269
|
-
# config.save
|
270
|
-
#
|
271
|
-
# Output:
|
272
|
-
# pass
|
273
|
-
# pass
|
274
|
-
# stop
|
275
|
-
def run_callbacks(kind, options = {}, &block)
|
276
|
-
self.class.send("#{kind}_callback_chain").run(self, options, &block)
|
277
|
-
end
|
278
599
|
end
|
279
600
|
end
|