aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/rails-2.0.2/activesupport
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/rails-2.0.2/activesupport')
-rw-r--r--vendor/rails-2.0.2/activesupport/CHANGELOG986
-rw-r--r--vendor/rails-2.0.2/activesupport/MIT-LICENSE20
-rw-r--r--vendor/rails-2.0.2/activesupport/README43
-rw-r--r--vendor/rails-2.0.2/activesupport/Rakefile84
-rw-r--r--vendor/rails-2.0.2/activesupport/install.rb30
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support.rb49
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/basic_object.rb5
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/buffered_logger.rb107
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/clean_logger.rb127
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext.rb4
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array.rb13
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array/access.rb28
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array/conversions.rb94
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array/extract_options.rb19
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array/grouping.rb68
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array/random_access.rb12
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/bigdecimal.rb2
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/bigdecimal/conversions.rb6
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/blank.rb50
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/cgi.rb5
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb14
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/class.rb4
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb48
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb40
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb140
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/class/removal.rb24
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date.rb10
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date/behavior.rb13
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date/calculations.rb188
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date/conversions.rb98
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date_time.rb10
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date_time/calculations.rb77
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date_time/conversions.rb74
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/duplicable.rb37
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/enumerable.rb63
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/exception.rb33
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/file.rb21
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/float.rb5
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/float/rounding.rb24
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash.rb13
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/conversions.rb242
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/diff.rb19
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/except.rb24
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb102
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/keys.rb54
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb25
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/slice.rb28
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/integer.rb7
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/integer/even_odd.rb24
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/integer/inflections.rb21
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel.rb5
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel/agnostics.rb11
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel/daemonizing.rb15
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel/debugger.rb13
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel/reporting.rb51
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel/requires.rb24
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/load_error.rb38
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/logger.rb16
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module.rb8
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/aliasing.rb70
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/attr_accessor_with_default.rb31
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/attr_internal.rb31
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb48
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/delegation.rb62
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/inclusion.rb11
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/introspection.rb35
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/loading.rb13
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/name_error.rb17
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/numeric.rb7
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/numeric/bytes.rb44
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/numeric/time.rb91
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/object.rb4
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/object/conversions.rb14
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/object/extending.rb58
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/object/instance_variables.rb22
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/object/misc.rb59
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/pathname.rb7
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/pathname/clean_within.rb14
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/proc.rb12
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/range.rb11
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/range/blockless_step.rb22
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/range/conversions.rb23
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/range/include_range.rb22
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/range/overlaps.rb12
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string.rb23
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/access.rb58
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/conversions.rb28
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/inflections.rb153
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/iterators.rb17
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/starts_ends_with.rb27
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/unicode.rb42
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/xchar.rb11
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/symbol.rb14
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/test.rb1
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/test/unit/assertions.rb62
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/time.rb19
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/time/behavior.rb13
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/time/calculations.rb224
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/time/conversions.rb94
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/dependencies.rb540
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/deprecation.rb204
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/duration.rb96
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/inflections.rb53
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/inflector.rb282
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/json.rb31
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/json/decoding.rb60
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/date.rb5
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/date_time.rb5
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/enumerable.rb12
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/false_class.rb5
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/hash.rb50
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/nil_class.rb5
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/numeric.rb5
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/object.rb6
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/regexp.rb5
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/string.rb30
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/symbol.rb5
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/time.rb5
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/true_class.rb5
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/json/encoding.rb38
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/json/variable.rb10
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/multibyte.rb9
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/multibyte/chars.rb141
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/multibyte/generators/generate_tables.rb149
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/multibyte/handlers/passthru_handler.rb9
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb564
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/multibyte/handlers/utf8_handler_proc.rb43
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/option_merger.rb25
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/ordered_options.rb49
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/test_case.rb5
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/testing.rb1
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/testing/default.rb12
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/values/time_zone.rb181
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/values/unicode_tables.datbin0 -> 656156 bytes
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/vendor.rb14
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/blankslate.rb113
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder.rb13
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/blankslate.rb20
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb250
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xchar.rb115
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb139
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb63
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb328
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb1021
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/version.rb9
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/active_support/whiny_nil.rb38
-rw-r--r--vendor/rails-2.0.2/activesupport/lib/activesupport.rb1
-rw-r--r--vendor/rails-2.0.2/activesupport/test/abstract_unit.rb20
-rw-r--r--vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/a/b.rb2
-rw-r--r--vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/a/c/d.rb2
-rw-r--r--vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/a/c/e/f.rb2
-rw-r--r--vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/application.rb1
-rw-r--r--vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/class_folder.rb3
-rw-r--r--vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/class_folder/class_folder_subclass.rb3
-rw-r--r--vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/class_folder/inline_class.rb2
-rw-r--r--vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/class_folder/nested_class.rb7
-rw-r--r--vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/conflict.rb1
-rw-r--r--vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/counting_loader.rb5
-rw-r--r--vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/cross_site_dependency.rb2
-rw-r--r--vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/e.rb2
-rw-r--r--vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/module_folder/inline_class.rb2
-rw-r--r--vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/module_folder/nested_class.rb4
-rw-r--r--vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/module_folder/nested_sibling.rb2
-rw-r--r--vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/module_with_custom_const_missing/a/b.rb1
-rw-r--r--vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/multiple_constant_file.rb2
-rw-r--r--vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/raises_name_error.rb3
-rw-r--r--vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/raises_no_method_error.rb3
-rw-r--r--vendor/rails-2.0.2/activesupport/test/buffered_logger_test.rb107
-rw-r--r--vendor/rails-2.0.2/activesupport/test/clean_logger_test.rb57
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/array_ext_test.rb250
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/blank_test.rb19
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/cgi_ext_test.rb14
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/class/attribute_accessor_test.rb31
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/class/class_inheritable_attributes_test.rb224
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/class/delegating_attributes_test.rb105
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/class_test.rb46
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/date_ext_test.rb196
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/date_time_ext_test.rb230
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/duplicable_test.rb22
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/duration_test.rb21
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/enumerable_test.rb61
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/exception_test.rb64
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/file_test.rb29
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/float_ext_test.rb25
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/hash_ext_test.rb743
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/integer_ext_test.rb37
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/kernel_test.rb43
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/load_error_tests.rb16
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/module/attr_accessor_with_default_test.rb30
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/module/attr_internal_test.rb52
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/module/attribute_accessor_test.rb33
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/module/attribute_aliasing_test.rb58
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/module_test.rb293
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/name_error_test.rb24
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/numeric_ext_test.rb147
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/object_and_class_ext_test.rb242
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/pathname_test.rb9
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/proc_test.rb11
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/range_ext_test.rb63
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/string_ext_test.rb180
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/symbol_test.rb9
-rw-r--r--vendor/rails-2.0.2/activesupport/test/core_ext/time_ext_test.rb420
-rw-r--r--vendor/rails-2.0.2/activesupport/test/dependencies/check_warnings.rb2
-rw-r--r--vendor/rails-2.0.2/activesupport/test/dependencies/conflict.rb1
-rw-r--r--vendor/rails-2.0.2/activesupport/test/dependencies/cross_site_depender.rb3
-rw-r--r--vendor/rails-2.0.2/activesupport/test/dependencies/mutual_one.rb4
-rw-r--r--vendor/rails-2.0.2/activesupport/test/dependencies/mutual_two.rb4
-rw-r--r--vendor/rails-2.0.2/activesupport/test/dependencies/raises_exception.rb3
-rw-r--r--vendor/rails-2.0.2/activesupport/test/dependencies/requires_nonexistent0.rb1
-rw-r--r--vendor/rails-2.0.2/activesupport/test/dependencies/requires_nonexistent1.rb1
-rw-r--r--vendor/rails-2.0.2/activesupport/test/dependencies/service_one.rb5
-rw-r--r--vendor/rails-2.0.2/activesupport/test/dependencies/service_two.rb2
-rw-r--r--vendor/rails-2.0.2/activesupport/test/dependencies_test.rb751
-rw-r--r--vendor/rails-2.0.2/activesupport/test/deprecation_test.rb151
-rw-r--r--vendor/rails-2.0.2/activesupport/test/inflector_test.rb248
-rw-r--r--vendor/rails-2.0.2/activesupport/test/inflector_test_cases.rb208
-rw-r--r--vendor/rails-2.0.2/activesupport/test/json/decoding_test.rb41
-rw-r--r--vendor/rails-2.0.2/activesupport/test/json/encoding_test.rb111
-rw-r--r--vendor/rails-2.0.2/activesupport/test/multibyte_chars_test.rb173
-rw-r--r--vendor/rails-2.0.2/activesupport/test/multibyte_conformance.rb141
-rw-r--r--vendor/rails-2.0.2/activesupport/test/multibyte_handler_test.rb367
-rw-r--r--vendor/rails-2.0.2/activesupport/test/option_merger_test.rb50
-rw-r--r--vendor/rails-2.0.2/activesupport/test/ordered_options_test.rb84
-rw-r--r--vendor/rails-2.0.2/activesupport/test/test_test.rb73
-rw-r--r--vendor/rails-2.0.2/activesupport/test/time_zone_test.rb98
-rw-r--r--vendor/rails-2.0.2/activesupport/test/whiny_nil_test.rb38
226 files changed, 16250 insertions, 0 deletions
diff --git a/vendor/rails-2.0.2/activesupport/CHANGELOG b/vendor/rails-2.0.2/activesupport/CHANGELOG
new file mode 100644
index 000000000..79869c6f9
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/CHANGELOG
@@ -0,0 +1,986 @@
+*SVN*
+
+* Ruby 1.9 compatibility. #1689, #10466, #10468 [Cheah Chu Yeow, Pratik Naik, Jeremy Kemper]
+
+* TimeZone#to_s uses UTC rather than GMT. #1689 [Cheah Chu Yeow]
+
+* Refactor of Hash#symbolize_keys! to use Hash#replace. Closes #10420 [ReinH]
+
+* Fix HashWithIndifferentAccess#to_options! so it doesn't clear the options hash. Closes #10419 [ReinH]
+
+
+*2.0.1* (December 7th, 2007)
+
+* Added Array#from and Array#to that behaves just from String#from and String#to [DHH]
+
+* Fix that empty collections should be treated as empty arrays regardless of whitespace for Hash#from_xml #10255 [adamj]
+
+* Time#time_with_datetime_fallback, Time#to_datetime, Date#to_datetime and String#to_datetime honor Ruby's default calendar reform setting. #10201 [Geoff Buesing]
+
+* Change Time and DateTime #end_of_month to return last second of month instead of beginning of last day of month. Closes #10200 [Geoff Buesing]
+
+* Speedup String#blank? [Jeremy Kemper, Koz]
+
+* Add documentation for Hash#diff. Closes #9306 [Tarmo Tänav]
+
+* Add new superclass_delegating_accessors. Similar to class inheritable attributes but with subtly different semantics. [Koz, Tarmo Tänav]
+
+* Change JSON to encode %w(< > &) as 4 digit hex codes to be in compliance with the JSON spec. Closes #9975 [Josh Peek, Cheah Chu Yeow, Tim Pope]
+
+* Fix JSON encoding/decoding bugs dealing with /'s. Closes #9990 [Rick, theamazingrando]
+
+* Introduce a base class for all test cases used by rails applications. ActiveSupport::TestCase [Koz]
+
+ The intention is to use this to reduce the amount of monkeypatching / overriding that
+ is done to test/unit's classes.
+
+* Document Enumerable and Hash #to_json. #9970 [Cheah Chu Yeow]
+
+* Hash#to_xml handles symbol values. #9954 [Assaf]
+
+* Hash#symbolize_keys behaves well with integer keys. #9890 [PotatoSalad]
+
+* Multibyte: String#slice supports regexp argument. #9646 [yob]
+
+* object.duplicable? returns true if object.dup is safe. False for nil, true, false, symbols, and numbers; true otherwise. #9333 [sur]
+
+* Time, Date and DateTime #advance accept :weeks option. #9866 [Geoff Buesing]
+
+* Fix Time#years_ago and #years_since from leap days. #9865 [Geoff Buesing]
+
+* Time and DateTime#advance accept :hours, :minutes, and :seconds options. #9825 [Geoff Buesing]
+
+* Fix Date#years_ago and #years_since from leap days. #9864 [Geoff Buesing]
+
+* Refactor Time and Date#months_since and #months_ago to use #advance. #9863 [Geoff Buesing]
+
+* Rebundle Builder 2.1.2 but prefer a newer RubyGem if available. [Jeremy Kemper]
+
+* Add Range#overlaps?(range), Range#include?(range), and Range#step without a block. [brandon]
+
+* Correct BufferedLogger#level? checks. #9806 [wildchild, Johan Sorensen]
+
+* String#to_xs uses Eric Wong's fast_xs extension, if available, for Builder speedup. http://bogomips.org/fast_xs/ [Jeremy Kemper]
+
+* Introduce BasicObject as Builder::BlankSlate for Ruby 1.9 forward compatibility. [Jeremy Kemper]
+
+* Unbundle Builder in favor of a gem dependency. [Jeremy Kemper]
+
+* Disambiguate Time, Date, and DateTime#to_json formatting. #9750 [Geoff Buesing, Cheah Chu Yeow]
+
+* Hash#to_json takes :only or :except options to specific or omit certain hash keys. Enumerable#to_json passes through its options to each element. #9751 [Cheah Chu Yeow]
+
+* BufferedLogger#auto_flushing = N flushes the log every N messages. Buffers with an array instead of string. Disabling auto_flushing still flushes when the buffer hits a maximum size, as a failsafe against memory-gobbling. [Jeremy Kemper]
+
+* Fixed Date#xmlschema for dates outside the range of what can be created with Time #9744 [Geoff Buesing]
+
+* Fixed that La Paz was included in -25200 and -14400 offsets when it should only be in -14400 #9735 [bermi]
+
+* Fixed JSON encoding to use quoted keys according to the JSON standard. #8762 [choonkat, Cheah Chu Yeow]
+
+* Alias Object#send to send! for Ruby 1.9 forward compatibility. [Jeremy Kemper]
+
+* Backport Object#instance_variable_defined? for Ruby < 1.8.6. [Jeremy Kemper]
+
+* BufferedLogger#add converts the message to a string. #9702, #9724 [eigentone, DrMark, tomafro]
+
+* Added ActiveSupport::BufferedLogger as a duck-typing alternative (albeit with no formatter) to the Ruby Logger, which provides a very nice speed bump (inspired by Ezra's buffered logger) [DHH]
+
+* Object#instance_exec produces fewer garbage methods. [Mauricio Fernandez]
+
+* Decode json strings as Dates/Times if they're using a YAML-compatible format. Closes #9614 [Rick]
+
+* Fixed cache_page to use the request url instead of the routing options when picking a save path. #8614 [Josh Peek]
+
+* Object.subclasses_of includes anonymous subclasses. [Jeremy Kemper]
+
+* Fixed that pluralizing an empty string should return the same empty string, not "s". #7720 [Josh Peek]
+
+* Added call to inspect on non-string classes for the logger #8533 [codahale]
+
+* Deprecation: remove deprecated :mday option from Time, Date, and DateTime#change. [Jeremy Kemper]
+
+* Fix JSON decoder with nested quotes and commas. #9579 [zdennis]
+
+* Hash#to_xml doesn't double-unescape. #8806 [Ezran]
+
+* Added Array#rand #9170 [Norbert Crombach]. Examples:
+
+ [].rand # => nil
+ ['a'].rand # => 'a'
+ [1,2,3].rand # => 1 or 2 or 3
+
+* Deprecation: removed Reloadable. [Jeremy Kemper]
+
+* Make the utf-handler return the correct value for non-matching regular expressions. Closes #9049 [manfred]
+
+* Add ljust, rjust and center to utf8-handler. Closes #9165 [manfred]
+
+* Fix Time#advance bug when trying to advance a year from leap day. Closes #8655 [gbuesing]
+
+* Add support for []= on ActiveSupport::Multibyte::Chars. Closes #9142. [ewan, manfred]
+
+* Added Array#extract_options! to encapsulate the pattern of getting an options hash out of a variable number of parameters. #8759 [Norbert Crombach]
+
+* Let alias_attribute work with attributes with initial capital letters (legacy columns etc). Closes #8596 [mpalmer]
+
+* Added Hash#except which is the inverse of Hash#slice -- return the hash except the keys that are specified [DHH]
+
+* Added support for pluralization with a different starting letter than the singular version (cow/kine) #4929 [norri_b/hasmanyjosh]
+
+* Demote Hash#to_xml to use XmlSimple#xml_in_string so it can't read files or stdin. #8453 [candlerb, Jeremy Kemper]
+
+* Backport clean_logger changes to support ruby 1.8.2 [mislav]
+
+* Added proper handling of arrays #8537 [hasmanyjosh]
+
+ Before:
+ Hash.from_xml '<images></images>'
+ # => {:images => nil}
+
+ Hash.from_xml '<images><image>foo.jpg</image></images>'
+ # => {:images => {:image => "foo.jpg"}}
+
+ Hash.from_xml '<images><image>foo.jpg</image><image>bar.jpg</image></images>'
+ # => {:images => {:image => ["foo.jpg", "bar.jpg"]}}
+
+ After:
+ Hash.from_xml '<images type="array"></images>'
+ # => {:images => []}
+
+ Hash.from_xml '<images type="array"><image>foo.jpg</image></images>'
+ # => {:images => ["foo.jpg"]}
+
+ Hash.from_xml '<images type="array"><image>foo.jpg</image><image>bar.jpg</image></images>'
+ # => {:images => ["foo.jpg", "bar.jpg"]}
+
+* Improve Time and Date test coverage. #8646 [Josh Peek]
+
+* Add Date#since, ago, beginning_of_day, and end_of_day. Date + seconds works now. #8575 [Geoff Buesing]
+
+* String#to_time overflows to DateTime. Add String#to_datetime. #8572 [Geoff Buesing]
+
+* Date.yesterday and .tomorrow. #8571 [Geoff Buesing]
+
+* Readable Date and DateTime#inspect. #8570 [Geoff Buesing]
+
+* Move common DateTime calculations to Date. #8536 [Geoff Buesing]
+
+* Added Date#change (like Time#change) [DHH]
+
+* DateTime#to_time converts to Time unless out of range. #8512 [Geoff Buesing]
+
+* Date#to_datetime, #to_s(:rfc822). #8512 [Geoff Buesing]
+
+* Time durations use since instead of + for accuracy. #8513 [Geoff Buesing]
+
+* escape <'s and >'s in JSON strings. #8371 [Rick]
+
+* Inflections: MatrixTest -> MatrixTests instead of MatricesTest. #8496 [jbwiv]
+
+* Multibyte strings respond_to the String methods they proxy so they can be duck-typed. #6549 [Tuxie]
+
+* Array#to_xml yields the builder just like Hash and ActiveRecord::Base. #8472 [seth]
+
+* Date, Time, and DateTime support formatting blocks in addition to strftime strings. Introduce :long_ordinal format, e.g. "February 21st, 2005". #8191 [Coda Hale]
+
+* Document Object#blank?. #6491 [Chris Mear]
+
+* Date, Time, and DateTime#to_json. #8399 [wycats]
+
+* Simplify API of assert_difference by passing in an expression that is evaluated before and after the passed in block. See documenation for examples of new API. [Marcel Molina Jr.]
+
+* Added assert_difference and assert_no_difference to test/unit assertions [Tobias Luetke]
+
+* Removed breakpointer and Binding.of_caller in favor of relying on ruby-debug by Kent Sibilev since the breakpointer has been broken since Ruby 1.8.4 and will not be coming back [DHH]
+
+* Added parsing of file type in Hash.xml_in so you can easily do file uploads with base64 from an API [DHH]
+
+ <person>
+ <name>David</name>
+ <avatar type="file" name="me.jpg" content_type="image/jpg">R0lGODlhkACZAPUAAM5lcfjrtMQCG=\n</avatar>
+ </person>
+
+ ...becomes:
+
+ attributes = { :person => { :name => "David", :avatar => #<StringIO> } }
+ attributes[:person][:avatar].content_type # => "image/jpg"
+ attributes[:person][:avatar].original_filename # => "me.jpg"
+ attributes[:person][:avatar].read # => binary data of the file
+
+ Which is duck-type compatible with the files that you get when doing multipart uploads through HTML.
+
+* Improved multibyte performance by relying less on exception raising #8159 [Blaine]
+
+* Use XSD-compatible type names for Hash#to_xml and make the converters extendable #8047 [Tim Pope]
+
+* Added yielding of builder in Hash#to_xml [DHH]
+
+* Hash#with_indifferent_access now also converts hashes kept in arrays to indifferent access (makes it easier to treat HTML and XML parameters the same) [DHH]
+
+* Hash#to_xml supports YAML attributes. #7502 [jonathan]
+
+* Refactor ActiveSupport::JSON to be less obtuse. Add support for JSON decoding by way of Syck with ActiveSupport::JSON.decode(json_string). Prevent hash keys that are JavaScript reserved words from being unquoted during encoding. [Sam Stephenson]
+
+* alias_method_chain preserves the original method's visibility. #7854 [Jonathan Viney]
+
+* Update Dependencies to ignore constants inherited from ancestors. Closes #6951. [Nicholas Seckar]
+
+* Array#to_query preserves its ordering. #7756 [Greg Spurrier]
+
+* Out-of-range Time calculations transparently overflow to DateTime. Introduce Time#to_datetime. #7706, #7715 [Geoff Buesing]
+
+* DateTime calculations analogous to the Date and Time extensions. #7693 [Geoff Buesing]
+
+* Give DateTime correct .to_s implementations, lets it play nice with ActiveRecord quoting. #7649 [Geoff Buesing]
+
+* Add File.atomic_write, allows you to write large files in an atomic manner, preventing users from seeing half written files. [Koz]
+
+* Allow users to provide custom formatters to Logger. [aeden]
+
+* Hash#to_query CGI-escapes its keys. [Jeremy Kemper]
+
+* Optimize Class Inheritable Attributes so that unnecessary hashes are not created. Closes #7472 [Bruce Perens]
+
+* :db format for Date#to_s [Jeremy Kemper]
+ Date.new(2007, 1, 27).to_s(:db) # => '2007-01-27'
+
+* Added :instance_writer option to #mattr_writer/accessor, #cattr_writer/accessor, and #class_inheritable_writer to skip the creation of the instance writer. [Rick]
+
+* Added Hash#to_query to turn a hash of values into a form-encoded query string [Nicholas Seckar]
+
+* Increase test coverage for subclasses_of. Closes #7335. [Roman2K, Nicholas Seckar]
+
+* Remove unused code from Duration#inspect. Closes #7180. [Rich Collins]
+
+* Added test coverage for Inflector.inflections.clear. Closes #7179. [Rich Collins]
+
+* ActiveSupport::Multibyte::Handlers::UTF8Handler should raise when a range and an integer are passed in (just like the native implementation). Closes #7176 [Rich Collins]
+
+* A couple extra tests for #classify. Closes #7273. [Josh Susser]
+
+* Better docs for Object extensions [zackchandler, Jamis Buck]
+
+* Fix that Dates couldn't be subtracted from Dates after [5940]. [Sam Stephenson]
+
+* Add Object#acts_like? and Time#acts_like_time? and Date#acts_like_date? to facilitate duck-typing. [Jamis Buck]
+
+* Make 1.months and friends accurate by introducing a Duration class. #6835 [eventualbuddha]
+
+
+*1.4.2* (March 12th, 2007)
+
+* Ruby 1.8.6 and 1.9 define private Time#to_date and #to_datetime; make them
+public for compatibility. [Jeremy Kemper]
+
+* Deprecation: warn on stderr if RAILS_DEFAULT_LOGGER isn't set yet. [Jeremy Kemper]
+
+
+*1.4.1* (February 5th, 2007)
+
+* Optimize Class Inheritable Attributes so that unnecessary hashes are not created. Closes #7472 [Bruce Perens]
+
+* Added :instance_writer option to #mattr_writer/accessor, #cattr_writer/accessor, and #class_inheritable_writer to skip the creation of the instance writer. [Rick]
+
+* Full test coverage for Inflector. #7228 [Dan Kubb]
+
+
+*1.4.0* (January 16th, 2007)
+
+* Document Inflector.ordinalize and merge docs from String inflections. #7023 [smeade]
+
+* Unbundle flexmock. [Jeremy Kemper]
+
+* Fix Dependencies.autoloaded? to ignore anonymous modules. Closes #6561. [Nicholas Seckar]
+
+* Update load once paths to prevent nested once constants from being detected and claimed by an external non-once load. [Nicholas Seckar]
+
+* Deprecation: silence warnings when reporting test errors. [Jeremy Kemper]
+
+* Hash#slice(*keys) returns a new hash with only the given keys. #slice! replaces the hash with only the given keys. Works with HashWithIndifferentAccess also. [Jeremy Kemper]
+
+* HashWithIndifferentAccess#to_hash converts to a Hash with String keys and the same default value. [Jeremy Kemper]
+
+* Fix remove_constant to correctly handle constant names of the form "::A::...". References #6720. [Nicholas Seckar]
+
+* Fixed Array#to_xml when it contains a series of hashes (each piece would get its own XML declaration) #6610 [thkarcher/cyu]
+
+* Added Time#to_s(:time) which will just return H:M, like 17:44 [DHH]
+
+* Add Module#attr_accessor_with_default to initialize value of attribute before setting it. Closes #6538. [Stuart Halloway, Marcel Molina Jr.]
+
+* Hash#to_xml handles keys with the same name as Kernel methods. #6613 [Catfish]
+
+* Added Time#end_of_day to get 23:59:59 of that day [DHH]
+
+* Don't quote hash keys in Hash#to_json if they're valid JavaScript identifiers. Disable this with ActiveSupport::JSON.unquote_hash_key_identifiers = false if you need strict JSON compliance. [Sam Stephenson]
+
+* Lazily load the Unicode Database in the UTF-8 Handler [Rick Olson]
+
+* Update dependencies to delete partially loaded constants. [Nicholas Seckar]
+
+* Fix unicode JSON regexp for Onigurama compatibility. #6494 [whitley]
+
+* update XmlSimple to 1.0.10. Closes #6532. [nicksieger]
+
+* Update dependencies to allow constants to be defined alongside their siblings. A common case for this is AR model classes with STI; user.rb might define User, Administrator and Guest for example. [Nicholas Seckar]
+
+* next_week respects DST changes. #6483, #5617, #2353, #2509, #4551 [marclove, rabiedenharn, rails@roetzel.de, jsolson@damogran.org, drbrain@segment7.net]
+
+* Expose methods added to Enumerable in the documentation, such as group_by. Closes #6170. [sergeykojin@gmail.com, Marcel Molina Jr.]
+
+* Ensure Chars#tidy_bytes only tidies broken bytes. Closes #6397 [Manfred Stienstra]
+
+* Add 'unloadable', a method used to mark any constant as requiring an unload after each request. [Nicholas Seckar]
+
+* Make core_ext/string/access.rb multibyte safe. Closes #6388 [Manfred Stienstra]
+
+* Make String#chars slicing behaviour consistent with String. Closes #6387 [Manfred Stienstra]
+
+* Pull in latest multibyte patch. Closes #6346 [Manfred Stienstra]
+
+* Add ActiveSupport::Multibyte. Provides String#chars which lets you deal with strings as a sequence of chars, not of bytes. Closes #6242 [Julian Tarkhanov, Manfred Stienstra, Thijs van der Vossen & Jan Behrens]
+
+* Fix issue with #class_inheritable_accessor saving updates to the parent class when initialized with an Array or Hash [mojombo]
+
+* Hash#to_xml supports Bignum and BigDecimal. #6313 [edibiase]
+
+* Don't undefine #class in OptionMerger [Rick]
+
+* Hash.create_from_xml has been renamed to Hash.from_xml, alias will exist until Rails 2.0 [DHH]
+
+* alias_method_chain works with accessor= methods also. #6153 [Caio Chassot]
+
+* Fix loadable_constants_for_path to handle load paths that do not end with a slash. [Nicholas Seckar]
+
+* Fix logic error in determining what was loaded by a given file. Closes #6039. [Nicholas Seckar]
+
+* Equate Kernel.const_missing with Object.const_missing. Fixes #5988. [Nicholas Seckar]
+
+* Add ApplicationController special case to Dependencies. [Nicholas Seckar]
+
+* Don't pad remaining places with in_groups_of if specified padding value is false. [Marcel Molina Jr.]
+
+* Fix cases where empty xml nodes weren't being translated to nil in Hash.create_from_xml [Rick Olso n]
+
+ <written-on type="date"></written-on> # => { :type => 'date' } # WRONG
+ <written-on type="date"></written-on> # => nil # RIGHT
+
+* Tighten rescue clauses. #5985 [james@grayproductions.net]
+
+* Inflections: don't singularize -ies plurals. [foamdino@gmail.com, Mark Van Holstyn]
+
+* Update Initializer to use load_once_paths to avoid plugin reloading. References #5852. [Nicholas Seckar]
+
+* Use Array#assoc in ActiveSupport::OrderedHash. [Mauricio Fernandez]
+
+* Greatly increased performance of String.to_json, which speeds up RJS considerably on large pages, fixes #3473 [Shugo Maeda]
+
+* Detect missing_constants calls from removed modules and fail accordingly. [Nicholas Seckar]
+
+* Stop using defined? in Dependencies.qualified_const_defined? since defined? may invoke const_missing. [Nicholas Seckar]
+
+* Dependencies can autoload directories of nested classes. [Jeremy Kemper]
+ Example:
+ invoice.rb class Invoice
+ invoice/lineitem.rb class Invoice::Lineitem
+
+* Add Deprecation.silence so that Reloadable does not scold itself. [Nicholas Seckar]
+
+* Add debugging logging to Dependencies. Currently can be enabled with Dependencies.log_activity = true; adding to Initializer and documenting is forthcoming. [Nicholas Seckar]
+
+* Replace Reloadable with improvements to the Dependencies mechanism. [Nicholas Seckar]
+
+* DateTime#to_time gives hour/minute/second resolution. #5747 [jon.evans@pobox.com]
+
+* attr_internal to support namespacing and deprecation. Like attr_* except backed by internally-named instance variable. Set attr_internal_naming_format to change the format from the default '@_%s'. [Jeremy Kemper]
+ # def foo() @foo__rofl end
+ # def foo=(v) @foo__rofl = v end
+ self.attr_internal_naming_format = '@%s__rofl'
+ attr_internal :foo
+
+* Raise fully qualified names upon name errors. #5533 [lars@pinds.com, Nicholas Seckar]
+
+* Add extention to obtain the missing constant from NameError instances. [Nicholas Seckar]
+
+* Thoroughly document inflections. #5700 [petermichaux@gmail.com]
+
+* Added Module#alias_attribute [Jamis/DHH]. Example:
+
+ class Content < ActiveRecord::Base
+ # has a title attribute
+ end
+
+ class Email < ActiveRecord::Base
+ alias_attribute :subject, :title
+ end
+
+ e = Email.find(1)
+ e.title # => "Superstars"
+ e.subject # => "Superstars"
+ e.subject? # => true
+ e.subject = "Megastars"
+ e.title # => "Megastars"
+
+* Deprecation: easier to work with warning behavior as procs; default behaviors for each environment so users needn't update env.rb; and testing pleasure with assert_deprecated, assert_not_deprecated. [Jeremy Kemper]
+ By default, test prints to $stderr, dev logs, production ignores.
+ Provide your own per-environment in e.g. config/environments/development.rb:
+ ActiveSupport::Deprecation.behavior = Proc.new { |message| raise message }
+
+* First cut of the Rails Deprecation system. [Koz]
+
+* Strip boolean XML content before checking for 'true' [Rick Olson]
+
+* Customize default BigDecimal formatting. References #5672 [dave@pragprog.com]
+
+* Correctly convert <foo nil="true"> to nil when using Hash.create_from_xml. [Rick]
+
+* Optional identity for Enumerable#sum defaults to zero. #5657 [gensym@mac.com]
+
+* HashWithIndifferentAccess shouldn't confuse false and nil. #5601 [shugo@ruby-lang.org]
+
+* Fixed HashWithIndifferentAccess#default #5586 [chris@seagul.co.uk]
+
+* More compatible Hash.create_from_xml. #5523 [nunemaker@gmail.com]
+
+* Added Enumerable#sum for calculating a sum from the elements [DHH, jonathan@daikini.com]. Examples:
+
+ [1, 2, 3].sum
+ payments.sum { |p| p.price * p.tax_rate }
+ payments.sum(&:price)
+
+ This is instead of payments.inject(0) { |sum, p| sum + p.price }
+
+* Correct and clarify Array#to_sentence docs. #5458 [brad@madriska.com]
+
+* alias_method_chain preserves method punctuation so foo, foo?, and foo! may be chained with the same feature. [Jeremy Kemper]
+ Example:
+ alias_method_chain :save!, :validation
+ is equivalent to
+ alias_method :save_without_validation!, :save!
+ alias_method :save!, :save_with_validation!
+
+* Enhance Symbol#to_proc so it works with list objects, such as multi-dimensional arrays. Closes #5295 [nov@yo.rim.or.jp]. Example:
+
+ {1 => "one", 2 => "two", 3 => "three"}.sort_by(&:first).map(&:last)
+ #=> ["one", "two", "three"]
+
+* Added Hash.create_from_xml(string) which will create a hash from a XML string and even typecast if possible [DHH]. Example:
+
+ Hash.create_from_xml <<-EOT
+ <note>
+ <title>This is a note</title>
+ <created-at type="date">2004-10-10</created-at>
+ </note>
+ EOT
+
+ ...would return:
+
+ { :note => { :title => "This is a note", :created_at => Date.new(2004, 10, 10) } }
+
+* Added Jim Weirich's excellent FlexMock class to vendor (Copyright 2003, 2004 by Jim Weirich (jim@weriichhouse.org)) -- it's not automatically required, though, so require 'flexmock' is still necessary [DHH]
+
+* Fixed that Module#alias_method_chain should work with both foo? foo! and foo at the same time #4954 [anna@wota.jp]
+
+* to_xml fixes, features, and speedup: introduce :dasherize option that converts updated_at to updated-at if true (the existing default); binary columns get encoding="base64" attribute; nil values get nil="true" attribute to distinguish empty values; add type information for float columns; allow arbitrarily deep :include; include SQL type information as the type attribute. #4989 [Blair Zajac <blair@orcaware.com>]
+
+* Add OrderedHash#values. [Sam Stephenson]
+
+* Added Array#to_s(:db) that'll produce a comma-separated list of ids [DHH]. Example:
+
+ Purchase.find(:all, :conditions => "product_id IN (#{shops.products.to_s(:db)})"
+
+* Normalize classify's argument to a String so that it plays nice with Symbols. [Marcel Molina Jr.]
+
+* Strip out leading schema name in classify. References #5139. [schoenm@earthlink.net]
+
+* Remove Enumerable#first_match since break(value) handles the use case well enough. [Nicholas Seckar]
+
+ Enumerable#first_match was like detect, but instead of returning the matching element, the yielded value returned. For example:
+
+ user_xml = adapters(:from => User, :to => Xml).first_match do |adapter|
+ adapter.adapt @user
+ end
+
+ But this is just as easily done with:
+
+ user_xml = adapters(:from => User, :to => Xml).each do
+ break adapter.adapt(@user)
+ end
+
+* Make Array#in_groups_of just return the grouped collection if a block isn't given. [Marcel Molina Jr.]
+
+* Don't destroy a HashWithIndifferentAccess if symbolize_keys! or stringify_keys! is called on it. Closes #5076. [Marcel Molina Jr., guy.naor@famundo.com]
+
+* Document Module::delegate. #5002 [pergesu@gmail.com]
+
+* Replace alias method chaining with Module#alias_method_chain. [Marcel Molina Jr.]
+
+* Strip out punctuation on predicates or bang methods being aliased with alias_method_chain since target?_without_feature is not a valid method name. Add tests for Module#alias_method_chain. [Marcel Molina Jr.]
+
+* Replace Ruby's deprecated append_features in favor of included. [Marcel Molina Jr.]
+
+* Allow default options in with_options to be overridden. Closes #4480. [murphy@cYcnus.de]
+
+* Added Module#alias_method_chain [Jamis Buck]
+
+* Updated to Builder 2.0 [DHH]
+
+* Add Array#split for dividing arrays into one or more subarrays by value or block. [Sam Stephenson]
+
+*1.3.1* (April 6th, 2006)
+
+* Clean paths inside of exception messages and traces. [Nicholas Seckar]
+
+* Add Pathname.clean_within for cleaning all the paths inside of a string. [Nicholas Seckar]
+
+* provide an empty Dependencies::LoadingModule.load which prints deprecation warnings. Lets 1.0 applications function with .13-style environment.rb.
+
+
+*1.3.0* (March 27th, 2006)
+
+* When possible, avoid incorrectly obtaining constants from parent modules. Fixes #4221. [Nicholas Seckar]
+
+* Add more tests for dependencies; refactor existing cases. [Nicholas Seckar]
+
+* Move Module#parent and Module#as_load_path into core_ext. Add Module#parent. [Nicholas Seckar]
+
+* Add CachingTools::HashCaching to simplify the creation of nested, autofilling hashes. [Nicholas Seckar]
+
+* Remove a hack intended to avoid unloading the same class twice, but which would not work anyways. [Nicholas Seckar]
+
+* Update Object.subclasses_of to locate nested classes. This affects Object.remove_subclasses_of in that nested classes will now be unloaded. [Nicholas Seckar]
+
+* Update Object.remove_subclasses_of to use Class.remove_class, reducing duplication. [Nicholas Seckar]
+
+* Added Fixnum#seconds for consistency, so you can say 5.minutes + 30.seconds instead of 5.minutes + 30 #4389 [François Beausoleil]
+
+* Added option to String#camelize to generate lower-cased camel case by passing in :lower, like "super_man".camelize(:lower) # => "superMan" [DHH]
+
+* Added Hash#diff to show the difference between two hashes [Chris McGrath]
+
+* Added Time#advance to do precise time time calculations for cases where a month being approximated to 30 days won't do #1860 [Rick Olson]
+
+* Enhance Inflector.underscore to convert '-' into '_' (as the inverse of Inflector.dasherize) [Jamis Buck]
+
+* Switched to_xml to use the xml schema format for datetimes. This allows the encoding of time zones and should improve operability. [Koz]
+
+* Added a note to the documentation for the Date related Numeric extensions to indicate that they're
+approximations and shouldn't be used for critical calculations. [Koz]
+
+* Added Hash#to_xml and Array#to_xml that makes it much easier to produce XML from basic structures [DHH]. Examples:
+
+ { :name => "David", :street_name => "Paulina", :age => 26, :moved_on => Date.new(2005, 11, 15) }.to_xml
+
+ ...returns:
+
+ <person>
+ <street-name>Paulina</street-name>
+ <name>David</name>
+ <age type="integer">26</age>
+ <moved-on type="date">2005-11-15</moved-on>
+ </person>
+
+* Moved Jim Weirich's wonderful Builder from Action Pack to Active Support (it's simply too useful to be stuck in AP) [DHH]
+
+* Fixed that Array#to_sentence will return "" on an empty array instead of ", and" #3842, #4031 [rubyonrails@beautifulpixel.com]
+
+* Add Enumerable#group_by for grouping collections based on the result of some
+ block. Useful, for example, for grouping records by date.
+
+ ex.
+
+ latest_transcripts.group_by(&:day).each do |day, transcripts|
+ p "#{day} -> #{transcripts.map(&:class) * ', '}"
+ end
+ "2006-03-01 -> Transcript"
+ "2006-02-28 -> Transcript"
+ "2006-02-27 -> Transcript, Transcript"
+ "2006-02-26 -> Transcript, Transcript"
+
+ Add Array#in_groups_of, for iterating over an array in groups of a certain
+ size.
+
+ ex.
+
+ %w(1 2 3 4 5 6 7).in_groups_of(3) {|g| p g}
+ ["1", "2", "3"]
+ ["4", "5", "6"]
+ ["7", nil, nil]
+
+ [Marcel Molina Jr., Sam Stephenson]
+
+* Added Kernel#daemonize to turn the current process into a daemon that can be killed with a TERM signal [DHH]
+
+* Add 'around' methods to Logger, to make it easy to log before and after messages for a given block as requested in #3809. [Michael Koziarski] Example:
+
+ logger.around_info("Start rendering component (#{options.inspect}): ",
+ "\n\nEnd of component rendering") { yield }
+
+* Added Time#beginning_of_quarter #3607 [cohen.jeff@gmail.com]
+
+* Fix Object.subclasses_of to only return currently defined objects [Jonathan Viney <jonathan@bluewire.net.nz>]
+
+* Fix constantize to properly handle names beginning with '::'. [Nicholas Seckar]
+
+* Make String#last return the string instead of nil when it is shorter than the limit [Scott Barron].
+
+* Added delegation support to Module that allows multiple delegations at once (unlike Forwardable in the stdlib) [DHH]. Example:
+
+ class Account < ActiveRecord::Base
+ has_one :subscription
+ delegate :free?, :paying?, :to => :subscription
+ delegate :overdue?, :to => "subscription.last_payment"
+ end
+
+ account.free? # => account.subscription.free?
+ account.overdue? # => account.subscription.last_payment.overdue?
+
+* Fix Reloadable to handle the case where a class that has been 'removed' has not yet been garbage collected. [Nicholas Seckar]
+
+* Don't allow Reloadable to be included into Modules.
+
+* Remove LoadingModule. [Nicholas Seckar]
+
+* Add documentation for Reloadable::Subclasses. [Nicholas Seckar]
+
+* Add Reloadable::Subclasses which handles the common case where a base class should not be reloaded, but its subclasses should be. [Nicholas Seckar]
+
+* Further improvements to reloading code [Nicholas Seckar, Trevor Squires]
+
+ - All classes/modules which include Reloadable can define reloadable? for fine grained control of reloading
+ - Class.remove_class uses Module#parent to access the parent module
+ - Class.remove_class expanded to handle multiple classes in a single call
+ - LoadingModule.clear! has been removed as it is no longer required
+ - Module#remove_classes_including has been removed in favor of Reloadable.reloadable_classes
+
+* Added reusable reloading support through the inclusion of the Relodable module that all subclasses of ActiveRecord::Base, ActiveRecord::Observer, ActiveController::Base, and ActionMailer::Base automatically gets. This means that these classes will be reloaded by the dispatcher when Dependencies.mechanism = :load. You can make your own models reloadable easily:
+
+ class Setting
+ include Reloadable
+ end
+
+ Reloading a class is done by removing its constant which will cause it to be loaded again on the next reference. [DHH]
+
+* Added auto-loading support for classes in modules, so Conductor::Migration will look for conductor/migration.rb and Conductor::Database::Settings will look for conductor/database/settings.rb [Nicholas Seckar]
+
+* Add Object#instance_exec, like instance_eval but passes its arguments to the block. (Active Support will not override the Ruby 1.9 implementation of this method.) [Sam Stephenson]
+
+* Add Proc#bind(object) for changing a proc or block's self by returning a Method bound to the given object. Based on why the lucky stiff's "cloaker" method. [Sam Stephenson]
+
+* Fix merge and dup for hashes with indifferent access #3404 [kenneth.miller@bitfield.net]
+
+* Fix the requires in option_merger_test to unbreak AS tests. [Sam Stephenson]
+
+* Make HashWithIndifferentAccess#update behave like Hash#update by returning the hash. #3419, #3425 [asnem@student.ethz.ch, JanPrill@blauton.de, Marcel Molina Jr.]
+
+* Add ActiveSupport::JSON and Object#to_json for converting Ruby objects to JSON strings. [Sam Stephenson]
+
+* Add Object#with_options for DRYing up multiple calls to methods having shared options. [Sam Stephenson] Example:
+
+ ActionController::Routing::Routes.draw do |map|
+ # Account routes
+ map.with_options(:controller => 'account') do |account|
+ account.home '', :action => 'dashboard'
+ account.signup 'signup', :action => 'new'
+ account.logout 'logout', :action => 'logout'
+ end
+ end
+
+* Introduce Dependencies.warnings_on_first_load setting. If true, enables warnings on first load of a require_dependency. Otherwise, loads without warnings. Disabled (set to false) by default. [Jeremy Kemper]
+
+* Active Support is warnings-safe. #1792 [Eric Hodel]
+
+* Introduce enable_warnings counterpart to silence_warnings. Turn warnings on when loading a file for the first time if Dependencies.mechanism == :load. Common mistakes such as redefined methods will print warnings to stderr. [Jeremy Kemper]
+
+* Add Symbol#to_proc, which allows for, e.g. [:foo, :bar].map(&:to_s). [Marcel Molina Jr.]
+
+* Added the following methods [Marcel Molina Jr., Sam Stephenson]:
+ * Object#copy_instance_variables_from(object) to copy instance variables from one object to another
+ * Object#extended_by to get an instance's included/extended modules
+ * Object#extend_with_included_modules_from(object) to extend an instance with the modules from another instance
+
+*1.2.5* (December 13th, 2005)
+
+* Become part of Rails 1.0
+
+* Rename Version constant to VERSION. #2802 [Marcel Molina Jr.]
+
+*1.2.3* (November 7th, 2005)
+
+* Change Inflector#constantize to use eval instead of const_get. [Nicholas Seckar]
+
+* Fix const_missing handler to ignore the trailing '.rb' on files when comparing paths. [Nicholas Seckar]
+
+* Define kernel.rb methods in "class Object" instead of "module Kernel" to work around a Windows peculiarity [Sam Stephenson]
+
+* Fix broken tests caused by incomplete loading of active support. [Nicholas Seckar]
+
+* Fix status pluralization bug so status_codes doesn't get pluralized as statuses_code. #2758 [keithm@infused.org]
+
+* Added Kernel#silence_stderr to silence stderr for the duration of the given block [Sam Stephenson]
+
+* Changed Kernel#` to print a message to stderr (like Unix) instead of raising Errno::ENOENT on Win32 [Sam Stephenson]
+
+* Changed 0.blank? to false rather than true since it violates everyone's expectation of blankness. #2518, #2705 [rails@jeffcole.net]
+
+* When loading classes using const_missing, raise a NameError if and only if the file we tried to load was not present. [Nicholas Seckar]
+
+* Added petabytes and exebytes to numeric extensions #2397 [timct@mac.com]
+
+* Added Time#end_of_month to accompany Time#beginning_of_month #2514 [Jens-Christian Fischer]
+
+
+*1.2.2* (October 26th, 2005)
+
+* Set Logger.silencer = false to disable Logger#silence. Useful for debugging fixtures.
+
+* Add title case method to String to do, e.g., 'action_web_service'.titlecase # => 'Action Web Service'. [Marcel Molina Jr.]
+
+
+*1.2.1* (October 19th, 2005)
+
+* Classify generated routing code as framework code to avoid appearing in application traces. [Nicholas Seckar]
+
+* Show all framework frames in the framework trace. [Nicholas Seckar]
+
+
+*1.2.0* (October 16th, 2005)
+
+* Update Exception extension to show the first few framework frames in an application trace. [Nicholas Seckar]
+
+* Added Exception extension to provide support for clean backtraces. [Nicholas Seckar]
+
+* Updated whiny nil to be more concise and useful. [Nicholas Seckar]
+
+* Added Enumerable#first_match [Nicholas Seckar]
+
+* Fixed that Time#change should also reset usec when also resetting minutes #2459 [ikeda@dream.big.or.jp]
+
+* Fix Logger compatibility for distributions that don't keep Ruby and its standard library in sync.
+
+* Replace '%e' from long and short time formats as Windows does not support it. #2344. [Tom Ward <tom@popdog.net>]
+
+* Added to_s(:db) to Range, so you can get "BETWEEN '2005-12-10' AND '2005-12-12'" from Date.new(2005, 12, 10)..Date.new(2005, 12, 12) (and likewise with Times)
+
+* Moved require_library_or_gem into Kernel. #1992 [Michael Schuerig <michael@schuerig.de>]
+
+* Add :rfc822 as an option for Time#to_s (to get rfc822-formatted times)
+
+* Chain the const_missing hook to any previously existing hook so rails can play nicely with rake
+
+* Clean logger is compatible with both 1.8.2 and 1.8.3 Logger. #2263 [Michael Schuerig <michael@schuerig.de>]
+
+* Added native, faster implementations of .blank? for the core types #2286 [skae]
+
+* Fixed clean logger to work with Ruby 1.8.3 Logger class #2245
+
+* Fixed memory leak with Active Record classes when Dependencies.mechanism = :load #1704 [c.r.mcgrath@gmail.com]
+
+* Fixed Inflector.underscore for use with acronyms, so HTML becomes html instead of htm_l #2173 [k@v2studio.com]
+
+* Fixed dependencies related infinite recursion bug when a controller file does not contain a controller class. Closes #1760. [rcolli2@tampabay.rr.com]
+
+* Fixed inflections for status, quiz, move #2056 [deirdre@deirdre.net]
+
+* Added Hash#reverse_merge, Hash#reverse_merge!, and Hash#reverse_update to ease the use of default options
+
+* Added Array#to_sentence that'll turn ['one', 'two', 'three'] into "one, two, and three" #2157 [m.stienstra@fngtps.com]
+
+* Added Kernel#silence_warnings to turn off warnings temporarily for the passed block
+
+* Added String#starts_with? and String#ends_with? #2118 [thijs@vandervossen.net]
+
+* Added easy extendability to the inflector through Inflector.inflections (using the Inflector::Inflections singleton class). Examples:
+
+ Inflector.inflections do |inflect|
+ inflect.plural /^(ox)$/i, '\1\2en'
+ inflect.singular /^(ox)en/i, '\1'
+
+ inflect.irregular 'octopus', 'octopi'
+
+ inflect.uncountable "equipment"
+ end
+
+* Added String#at, String#from, String#to, String#first, String#last in ActiveSupport::CoreExtensions::String::Access to ease access to individual characters and substrings in a string serving basically as human names for range access.
+
+* Make Time#last_month work when invoked on the 31st of a month.
+
+* Add Time.days_in_month, and make Time#next_month work when invoked on the 31st of a month
+
+* Fixed that Time#midnight would have a non-zero usec on some platforms #1836
+
+* Fixed inflections of "index/indices" #1766 [damn_pepe@gmail.com]
+
+* Added stripping of _id to String#humanize, so "employee_id" becomes "Employee" #1574 [Justin French]
+
+* Factor Fixnum and Bignum extensions into Integer extensions [Nicholas Seckar]
+
+* Hooked #ordinalize into Fixnum and Bignum classes. [Nicholas Seckar, danp]
+
+* Added Fixnum#ordinalize to turn 1.ordinalize to "1st", 3.ordinalize to "3rd", and 10.ordinalize to "10th" and so on #1724 [paul@cnt.org]
+
+
+*1.1.1* (11 July, 2005)
+
+* Added more efficient implementation of the development mode reset of classes #1638 [Chris McGrath]
+
+
+*1.1.0* (6 July, 2005)
+
+* Fixed conflict with Glue gem #1606 [Rick Olson]
+
+* Added new rules to the Inflector to deal with more unusual plurals mouse/louse => mice/lice, information => information, ox => oxen, virus => viri, archive => archives #1571, #1583, #1490, #1599, #1608 [foamdino@gmail.com/others]
+
+* Fixed memory leak with Object#remove_subclasses_of, which inflicted a Rails application running in development mode with a ~20KB leak per request #1289 [c.r.mcgrath@gmail.com]
+
+* Made 1.year == 365.25.days to account for leap years. This allows you to do User.find(:all, :conditions => ['birthday > ?', 50.years.ago]) without losing a lot of days. #1488 [tuxie@dekadance.se]
+
+* Added an exception if calling id on nil to WhinyNil #584 [kevin-temp@writesoon.com]
+
+* Added Fix/Bignum#multiple_of? which returns true on 14.multiple_of?(7) and false on 16.multiple_of?(7) #1464 [Thomas Fuchs]
+
+* Added even? and odd? to work with Bignums in addition to Fixnums #1464 [Thomas Fuchs]
+
+* Fixed Time#at_beginning_of_week returned the next Monday instead of the previous one when called on a Sunday #1403 [jean.helou@gmail.com]
+
+* Increased the speed of indifferent hash access by using Hash#default. #1436 [Nicholas Seckar]
+
+* Added that " " is now also blank? (using strip if available)
+
+* Fixed Dependencies so all modules are able to load missing constants #1173 [Nicholas Seckar]
+
+* Fixed the Inflector to underscore strings containing numbers, so Area51Controller becomes area51_controller #1176 [Nicholas Seckar]
+
+* Fixed that HashWithIndifferentAccess stringified all keys including symbols, ints, objects, and arrays #1162 [Nicholas Seckar]
+
+* Fixed Time#last_year to go back in time, not forward #1278 [fabien@odilat.com]
+
+* Fixed the pluralization of analysis to analyses #1295 [seattle@rootimage.msu.edu]
+
+* Fixed that Time.local(2005,12).months_since(1) would raise "ArgumentError: argument out of range" #1311 [jhahn@niveon.com]
+
+* Added silencing to the default Logger class
+
+
+*1.0.4* (19th April, 2005)
+
+* Fixed that in some circumstances controllers outside of modules may have hidden ones inside modules. For example, admin/content might have been hidden by /content. #1075 [Nicholas Seckar]
+
+* Fixed inflection of perspectives and similar words #1045 [thijs@vandervossen.net]
+
+* Added Fixnum#even? and Fixnum#odd?
+
+* Fixed problem with classes being required twice. Object#const_missing now uses require_dependency to load files. It used to use require_or_load which would cause models to be loaded twice, which was not good for validations and other class methods #971 [Nicholas Seckar]
+
+
+*1.0.3* (27th March, 2005)
+
+* Fixed Inflector.pluralize to handle capitalized words #932 [Jeremy Kemper]
+
+* Added Object#suppress which allows you to make a saner choice around with exceptions to swallow #980. Example:
+
+ suppress(ZeroDivisionError) { 1/0 }
+
+ ...instead of:
+
+ 1/0 rescue nil # BAD, EVIL, DIRTY.
+
+
+*1.0.2* (22th March, 2005)
+
+* Added Kernel#returning -- a Ruby-ized realization of the K combinator, courtesy of Mikael Brockman.
+
+ def foo
+ returning values = [] do
+ values << 'bar'
+ values << 'baz'
+ end
+ end
+
+ foo # => ['bar', 'baz']
+
+
+*1.0.1* (7th March, 2005)
+
+* Fixed Hash#indifferent_access to also deal with include? and fetch and nested hashes #726 [Nicholas Seckar]
+
+* Added Object#blank? -- see http://redhanded.hobix.com/inspect/objectBlank.html #783 [_why the lucky stiff]
+
+* Added inflection rules for "sh" words, like "wish" and "fish" #755 [phillip@pjbsoftware.com]
+
+* Fixed an exception when using Ajax based requests from Safari because Safari appends a \000 to the post body. Symbols can't have \000 in them so indifferent access would throw an exception in the constructor. Indifferent hashes now use strings internally instead. #746 [Tobias Luetke]
+
+* Added String#to_time and String#to_date for wrapping ParseDate
+
+
+*1.0.0* (24th February, 2005)
+
+* Added TimeZone as the first of a number of value objects that among others Active Record can use rich value objects using composed_of #688 [Jamis Buck]
+
+* Added Date::Conversions for getting dates in different convenient string representations and other objects
+
+* Added Time::Conversions for getting times in different convenient string representations and other objects
+
+* Added Time::Calculations to ask for things like Time.now.tomorrow, Time.now.yesterday, Time.now.months_ago(4) #580 [DP|Flurin]. Examples:
+
+ "Later today" => now.in(3.hours),
+ "Tomorrow morning" => now.tomorrow.change(:hour => 9),
+ "Tomorrow afternoon" => now.tomorrow.change(:hour => 14),
+ "In a couple of days" => now.tomorrow.tomorrow.change(:hour => 9),
+ "Next monday" => now.next_week.change(:hour => 9),
+ "In a month" => now.next_month.change(:hour => 9),
+ "In 6 months" => now.months_since(6).change(:hour => 9),
+ "In a year" => now.in(1.year).change(:hour => 9)
+
+* Upgraded to breakpoint 92 which fixes:
+
+ * overload IRB.parse_opts(), fixes #443
+ => breakpoints in tests work even when running them via rake
+ * untaint handlers, might fix an issue discussed on the Rails ML
+ * added verbose mode to breakpoint_client
+ * less noise caused by breakpoint_client by default
+ * ignored TerminateLineInput exception in signal handler
+ => quiet exit on Ctrl-C
+
+* Fixed Inflector for words like "news" and "series" that are the same in plural and singular #603 [echion], #615 [marcenuc]
+
+* Added Hash#stringify_keys and Hash#stringify_keys!
+
+* Added IndifferentAccess as a way to wrap a hash by a symbol-based store that also can be accessed by string keys
+
+* Added Inflector.constantize to turn "Admin::User" into a reference for the constant Admin::User
+
+* Added that Inflector.camelize and Inflector.underscore can deal with modules like turning "Admin::User" into "admin/user" and back
+
+* Added Inflector.humanize to turn attribute names like employee_salary into "Employee salary". Used by automated error reporting in AR.
+
+* Added availability of class inheritable attributes to the masses #477 [Jeremy Kemper]
+
+ class Foo
+ class_inheritable_reader :read_me
+ class_inheritable_writer :write_me
+ class_inheritable_accessor :read_and_write_me
+ class_inheritable_array :read_and_concat_me
+ class_inheritable_hash :read_and_update_me
+ end
+
+ # Bar gets a clone of (not a reference to) Foo's attributes.
+ class Bar < Foo
+ end
+
+ Bar.read_and_write_me == Foo.read_and_write_me
+ Bar.read_and_write_me = 'bar'
+ Bar.read_and_write_me != Foo.read_and_write_me
+
+* Added Inflections as an extension on String, so Inflector.pluralize(Inflector.classify(name)) becomes name.classify.pluralize #476 [Jeremy Kemper]
+
+* Added Byte operations to Numeric, so 5.5.megabytes + 200.kilobytes #461 [Marcel Molina]
+
+* Fixed that Dependencies.reload can't load the same file twice #420 [Kent Sibilev]
+
+* Added Fixnum#ago/until, Fixnum#since/from_now #450 [Jeremy Kemper]
+
+* Added that Inflector now accepts Symbols and Classes by calling .to_s on the word supplied
+
+* Added time unit extensions to Fixnum that'll return the period in seconds, like 2.days + 4.hours.
diff --git a/vendor/rails-2.0.2/activesupport/MIT-LICENSE b/vendor/rails-2.0.2/activesupport/MIT-LICENSE
new file mode 100644
index 000000000..dbe78035b
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2005-2007 David Heinemeier Hansson
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/README b/vendor/rails-2.0.2/activesupport/README
new file mode 100644
index 000000000..9fb9a80cb
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/README
@@ -0,0 +1,43 @@
+= Active Support -- Utility classes and standard library extensions from Rails
+
+Active Support is a collection of various utility classes and standard library extensions that were found useful
+for Rails. All these additions have hence been collected in this bundle as way to gather all that sugar that makes
+Ruby sweeter.
+
+
+== Download
+
+The latest version of Active Support can be found at
+
+* http://rubyforge.org/project/showfiles.php?group_id=182
+
+Documentation can be found at
+
+* http://as.rubyonrails.com
+
+
+== Installation
+
+The preferred method of installing Active Support is through its GEM file. You'll need to have
+RubyGems[http://rubygems.rubyforge.org/wiki/wiki.pl] installed for that, though. If you have it,
+then use:
+
+ % [sudo] gem install activesupport-1.0.0.gem
+
+
+== License
+
+Active Support is released under the MIT license.
+
+
+== Support
+
+The Active Support homepage is http://www.rubyonrails.com. You can find the Active Support
+RubyForge page at http://rubyforge.org/projects/activesupport. And as Jim from Rake says:
+
+ Feel free to submit commits or feature requests. If you send a patch,
+ remember to update the corresponding unit tests. If fact, I prefer
+ new feature to be submitted in the form of new unit tests.
+
+For other information, feel free to ask on the ruby-talk mailing list
+(which is mirrored to comp.lang.ruby) or contact mailto:david@loudthinking.com.
diff --git a/vendor/rails-2.0.2/activesupport/Rakefile b/vendor/rails-2.0.2/activesupport/Rakefile
new file mode 100644
index 000000000..fd8e59677
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/Rakefile
@@ -0,0 +1,84 @@
+require 'rake/testtask'
+require 'rake/rdoctask'
+require 'rake/gempackagetask'
+require 'rake/contrib/rubyforgepublisher'
+require File.join(File.dirname(__FILE__), 'lib', 'active_support', 'version')
+
+PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
+PKG_NAME = 'activesupport'
+PKG_VERSION = ActiveSupport::VERSION::STRING + PKG_BUILD
+PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
+
+RELEASE_NAME = "REL #{PKG_VERSION}"
+
+RUBY_FORGE_PROJECT = "activesupport"
+RUBY_FORGE_USER = "webster132"
+
+task :default => :test
+Rake::TestTask.new { |t|
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = true
+ t.warning = true
+}
+
+# Create compressed packages
+dist_dirs = [ "lib", "test"]
+
+# Genereate the RDoc documentation
+
+Rake::RDocTask.new { |rdoc|
+ rdoc.rdoc_dir = 'doc'
+ rdoc.title = "Active Support -- Utility classes and standard library extensions from Rails"
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.options << '--charset' << 'utf-8'
+ rdoc.template = "#{ENV['template']}.rb" if ENV['template']
+ rdoc.rdoc_files.include('README', 'CHANGELOG')
+ rdoc.rdoc_files.include('lib/active_support.rb')
+ rdoc.rdoc_files.include('lib/active_support/*.rb')
+ rdoc.rdoc_files.include('lib/active_support/**/*.rb')
+}
+
+spec = Gem::Specification.new do |s|
+ s.platform = Gem::Platform::RUBY
+ s.name = PKG_NAME
+ s.version = PKG_VERSION
+ s.summary = "Support and utility classes used by the Rails framework."
+ s.description = %q{Utility library which carries commonly used classes and goodies from the Rails framework}
+
+ s.files = [ "CHANGELOG", "README" ] + Dir.glob( "lib/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
+ s.require_path = 'lib'
+ s.has_rdoc = true
+
+ s.author = "David Heinemeier Hansson"
+ s.email = "david@loudthinking.com"
+ s.homepage = "http://www.rubyonrails.org"
+ s.rubyforge_project = "activesupport"
+end
+
+Rake::GemPackageTask.new(spec) do |p|
+ p.gem_spec = spec
+ p.need_tar = true
+ p.need_zip = true
+end
+
+desc "Publish the beta gem"
+task :pgem => [:package] do
+ Rake::SshFilePublisher.new("davidhh@wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
+ `ssh davidhh@wrath.rubyonrails.org './gemupdate.sh'`
+end
+
+desc "Publish the API documentation"
+task :pdoc => [:rdoc] do
+ Rake::SshDirPublisher.new("davidhh@wrath.rubyonrails.org", "public_html/as", "doc").upload
+end
+
+desc "Publish the release files to RubyForge."
+task :release => [ :package ] do
+ require 'rubyforge'
+
+ packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
+
+ rubyforge = RubyForge.new
+ rubyforge.login
+ rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages)
+end
diff --git a/vendor/rails-2.0.2/activesupport/install.rb b/vendor/rails-2.0.2/activesupport/install.rb
new file mode 100644
index 000000000..9c54d8c1a
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/install.rb
@@ -0,0 +1,30 @@
+require 'rbconfig'
+require 'find'
+require 'ftools'
+
+include Config
+
+# this was adapted from rdoc's install.rb by ways of Log4r
+
+$sitedir = CONFIG["sitelibdir"]
+unless $sitedir
+ version = CONFIG["MAJOR"] + "." + CONFIG["MINOR"]
+ $libdir = File.join(CONFIG["libdir"], "ruby", version)
+ $sitedir = $:.find {|x| x =~ /site_ruby/ }
+ if !$sitedir
+ $sitedir = File.join($libdir, "site_ruby")
+ elsif $sitedir !~ Regexp.quote(version)
+ $sitedir = File.join($sitedir, version)
+ end
+end
+
+# the actual gruntwork
+Dir.chdir("lib")
+
+Find.find("active_support", "active_support.rb") { |f|
+ if f[-3..-1] == ".rb"
+ File::install(f, File.join($sitedir, *f.split(/\//)), 0644, true)
+ else
+ File::makedirs(File.join($sitedir, *f.split(/\//)))
+ end
+}
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support.rb b/vendor/rails-2.0.2/activesupport/lib/active_support.rb
new file mode 100644
index 000000000..0b3816ec0
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support.rb
@@ -0,0 +1,49 @@
+#--
+# Copyright (c) 2005 David Heinemeier Hansson
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#++
+
+$:.unshift(File.dirname(__FILE__))
+
+require 'active_support/vendor'
+require 'active_support/basic_object'
+require 'active_support/inflector'
+
+require 'active_support/core_ext'
+
+require 'active_support/clean_logger'
+require 'active_support/buffered_logger'
+
+require 'active_support/dependencies'
+require 'active_support/deprecation'
+
+require 'active_support/ordered_options'
+require 'active_support/option_merger'
+
+require 'active_support/values/time_zone'
+require 'active_support/duration'
+
+require 'active_support/json'
+
+require 'active_support/multibyte'
+
+require 'active_support/testing'
+
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/basic_object.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/basic_object.rb
new file mode 100644
index 000000000..5e79de993
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/basic_object.rb
@@ -0,0 +1,5 @@
+# Ruby 1.9 introduces BasicObject. Use Builder's BlankSlate until then.
+unless defined? BasicObject
+ require 'blankslate'
+ BasicObject = BlankSlate
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/buffered_logger.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/buffered_logger.rb
new file mode 100644
index 000000000..c854599e6
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/buffered_logger.rb
@@ -0,0 +1,107 @@
+module ActiveSupport
+ # Inspired by the buffered logger idea by Ezra
+ class BufferedLogger
+ module Severity
+ DEBUG = 0
+ INFO = 1
+ WARN = 2
+ ERROR = 3
+ FATAL = 4
+ UNKNOWN = 5
+ end
+ include Severity
+
+ MAX_BUFFER_SIZE = 1000
+
+ # Set to false to disable the silencer
+ cattr_accessor :silencer
+ self.silencer = true
+
+ # Silences the logger for the duration of the block.
+ def silence(temporary_level = ERROR)
+ if silencer
+ begin
+ old_logger_level, self.level = level, temporary_level
+ yield self
+ ensure
+ self.level = old_logger_level
+ end
+ else
+ yield self
+ end
+ end
+
+ attr_accessor :level
+ attr_reader :auto_flushing
+ attr_reader :buffer
+
+ def initialize(log, level = DEBUG)
+ @level = level
+ @buffer = []
+ @auto_flushing = 1
+
+ if log.respond_to?(:write)
+ @log = log
+ elsif File.exist?(log)
+ @log = open(log, (File::WRONLY | File::APPEND))
+ @log.sync = true
+ else
+ @log = open(log, (File::WRONLY | File::APPEND | File::CREAT))
+ @log.sync = true
+ @log.write("# Logfile created on %s" % [Time.now.to_s])
+ end
+ end
+
+ def add(severity, message = nil, progname = nil, &block)
+ return if @level > severity
+ message = (message || (block && block.call) || progname).to_s
+ # If a newline is necessary then create a new message ending with a newline.
+ # Ensures that the original message is not mutated.
+ message = "#{message}\n" unless message[-1] == ?\n
+ @buffer << message
+ auto_flush
+ message
+ end
+
+ for severity in Severity.constants
+ class_eval <<-EOT, __FILE__, __LINE__
+ def #{severity.downcase}(message = nil, progname = nil, &block)
+ add(#{severity}, message, progname, &block)
+ end
+
+ def #{severity.downcase}?
+ #{severity} >= @level
+ end
+ EOT
+ end
+
+ # Set the auto-flush period. Set to true to flush after every log message,
+ # to an integer to flush every N messages, or to false, nil, or zero to
+ # never auto-flush. If you turn auto-flushing off, be sure to regularly
+ # flush the log yourself -- it will eat up memory until you do.
+ def auto_flushing=(period)
+ @auto_flushing =
+ case period
+ when true; 1
+ when false, nil, 0; MAX_BUFFER_SIZE
+ when Integer; period
+ else raise ArgumentError, "Unrecognized auto_flushing period: #{period.inspect}"
+ end
+ end
+
+ def flush
+ @log.write(@buffer.slice!(0..-1).to_s) unless @buffer.empty?
+ end
+
+ def close
+ flush
+ @log.close if @log.respond_to?(:close)
+ @log = nil
+ end
+
+ protected
+ def auto_flush
+ flush if @buffer.size >= @auto_flushing
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/clean_logger.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/clean_logger.rb
new file mode 100644
index 000000000..b4c27ebc9
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/clean_logger.rb
@@ -0,0 +1,127 @@
+require 'logger'
+require 'active_support/core_ext/class/attribute_accessors'
+
+# Extensions to the built in Ruby logger.
+#
+# If you want to use the default log formatter as defined in the Ruby core, then you
+# will need to set the formatter for the logger as in:
+#
+# logger.formatter = Formatter.new
+#
+# You can then specify the datetime format, for example:
+#
+# logger.datetime_format = "%Y-%m-%d"
+#
+# Note: This logger is deprecated in favor of ActiveSupport::BufferedLogger
+class Logger
+ # Set to false to disable the silencer
+ cattr_accessor :silencer
+ self.silencer = true
+
+ # Silences the logger for the duration of the block.
+ def silence(temporary_level = Logger::ERROR)
+ if silencer
+ begin
+ old_logger_level, self.level = level, temporary_level
+ yield self
+ ensure
+ self.level = old_logger_level
+ end
+ else
+ yield self
+ end
+ end
+
+ alias :old_datetime_format= :datetime_format=
+ # Logging date-time format (string passed to +strftime+). Ignored if the formatter
+ # does not respond to datetime_format=.
+ def datetime_format=(datetime_format)
+ formatter.datetime_format = datetime_format if formatter.respond_to?(:datetime_format=)
+ end
+
+ alias :old_datetime_format :datetime_format
+ # Get the logging datetime format. Returns nil if the formatter does not support
+ # datetime formatting.
+ def datetime_format
+ formatter.datetime_format if formatter.respond_to?(:datetime_format)
+ end
+
+ alias :old_formatter :formatter if method_defined?(:formatter)
+ # Get the current formatter. The default formatter is a SimpleFormatter which only
+ # displays the log message
+ def formatter
+ @formatter ||= SimpleFormatter.new
+ end
+
+ unless const_defined? :Formatter
+ class Formatter
+ Format = "%s, [%s#%d] %5s -- %s: %s\n"
+
+ attr_accessor :datetime_format
+
+ def initialize
+ @datetime_format = nil
+ end
+
+ def call(severity, time, progname, msg)
+ Format % [severity[0..0], format_datetime(time), $$, severity, progname,
+ msg2str(msg)]
+ end
+
+ private
+ def format_datetime(time)
+ if @datetime_format.nil?
+ time.strftime("%Y-%m-%dT%H:%M:%S.") << "%06d " % time.usec
+ else
+ time.strftime(@datetime_format)
+ end
+ end
+
+ def msg2str(msg)
+ case msg
+ when ::String
+ msg
+ when ::Exception
+ "#{ msg.message } (#{ msg.class })\n" <<
+ (msg.backtrace || []).join("\n")
+ else
+ msg.inspect
+ end
+ end
+ end
+ end
+
+ # Simple formatter which only displays the message.
+ class SimpleFormatter < Logger::Formatter
+ # This method is invoked when a log event occurs
+ def call(severity, timestamp, progname, msg)
+ "#{String === msg ? msg : msg.inspect}\n"
+ end
+ end
+
+ private
+ alias old_format_message format_message
+
+ # Ruby 1.8.3 transposed the msg and progname arguments to format_message.
+ # We can't test RUBY_VERSION because some distributions don't keep Ruby
+ # and its standard library in sync, leading to installations of Ruby 1.8.2
+ # with Logger from 1.8.3 and vice versa.
+ if method_defined?(:formatter=)
+ def format_message(severity, timestamp, progname, msg)
+ formatter.call(severity, timestamp, progname, msg)
+ end
+ else
+ def format_message(severity, timestamp, msg, progname)
+ formatter.call(severity, timestamp, progname, msg)
+ end
+
+ attr_writer :formatter
+ public :formatter=
+
+ alias old_format_datetime format_datetime
+ def format_datetime(datetime) datetime end
+
+ alias old_msg2str msg2str
+ def msg2str(msg) msg end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext.rb
new file mode 100644
index 000000000..4deef8c7a
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext.rb
@@ -0,0 +1,4 @@
+Dir[File.dirname(__FILE__) + "/core_ext/*.rb"].sort.each do |path|
+ filename = File.basename(path)
+ require "active_support/core_ext/#{filename}"
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array.rb
new file mode 100644
index 000000000..cc0a1ebc1
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array.rb
@@ -0,0 +1,13 @@
+require 'active_support/core_ext/array/access'
+require 'active_support/core_ext/array/conversions'
+require 'active_support/core_ext/array/extract_options'
+require 'active_support/core_ext/array/grouping'
+require 'active_support/core_ext/array/random_access'
+
+class Array #:nodoc:
+ include ActiveSupport::CoreExtensions::Array::Access
+ include ActiveSupport::CoreExtensions::Array::Conversions
+ include ActiveSupport::CoreExtensions::Array::ExtractOptions
+ include ActiveSupport::CoreExtensions::Array::Grouping
+ include ActiveSupport::CoreExtensions::Array::RandomAccess
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array/access.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array/access.rb
new file mode 100644
index 000000000..fce319d3c
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array/access.rb
@@ -0,0 +1,28 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Array #:nodoc:
+ # Makes it easier to access parts of an array.
+ module Access
+ # Returns the remaining of the array from the +position+.
+ #
+ # Examples:
+ # %w( a b c d ).from(0) # => %w( a b c d )
+ # %w( a b c d ).from(2) # => %w( c d )
+ # %w( a b c d ).from(10) # => nil
+ def from(position)
+ self[position..-1]
+ end
+
+ # Returns the beginning of the array up to the +position+.
+ #
+ # Examples:
+ # %w( a b c d ).to(0) # => %w( a )
+ # %w( a b c d ).to(2) # => %w( a b c )
+ # %w( a b c d ).to(10) # => %w( a b c d )
+ def to(position)
+ self[0..position]
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array/conversions.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array/conversions.rb
new file mode 100644
index 000000000..7574dc13c
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array/conversions.rb
@@ -0,0 +1,94 @@
+require 'builder'
+
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Array #:nodoc:
+ module Conversions
+ # Converts the array to a comma-separated sentence where the last element is joined by the connector word. Options:
+ # * <tt>:connector</tt> - The word used to join the last element in arrays with two or more elements (default: "and")
+ # * <tt>:skip_last_comma</tt> - Set to true to return "a, b and c" instead of "a, b, and c".
+ def to_sentence(options = {})
+ options.assert_valid_keys(:connector, :skip_last_comma)
+ options.reverse_merge! :connector => 'and', :skip_last_comma => false
+ options[:connector] = "#{options[:connector]} " unless options[:connector].nil? || options[:connector].strip == ''
+
+ case length
+ when 0
+ ""
+ when 1
+ self[0].to_s
+ when 2
+ "#{self[0]} #{options[:connector]}#{self[1]}"
+ else
+ "#{self[0...-1].join(', ')}#{options[:skip_last_comma] ? '' : ','} #{options[:connector]}#{self[-1]}"
+ end
+ end
+
+ # Calls to_param on all its elements and joins the result with slashes. This is used by url_for in Action Pack.
+ def to_param
+ map(&:to_param).join '/'
+ end
+
+ # Converts an array into a string suitable for use as a URL query string, using the given <tt>key</tt> as the
+ # param name.
+ #
+ # ==== Example:
+ # ['Rails', 'coding'].to_query('hobbies') => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"
+ def to_query(key)
+ collect { |value| value.to_query("#{key}[]") } * '&'
+ end
+
+ def self.included(base) #:nodoc:
+ base.class_eval do
+ alias_method :to_default_s, :to_s
+ alias_method :to_s, :to_formatted_s
+ end
+ end
+
+ def to_formatted_s(format = :default)
+ case format
+ when :db
+ if respond_to?(:empty?) && self.empty?
+ "null"
+ else
+ collect { |element| element.id }.join(",")
+ end
+ else
+ to_default_s
+ end
+ end
+
+ def to_xml(options = {})
+ raise "Not all elements respond to to_xml" unless all? { |e| e.respond_to? :to_xml }
+
+ options[:root] ||= all? { |e| e.is_a?(first.class) && first.class.to_s != "Hash" } ? first.class.to_s.underscore.pluralize : "records"
+ options[:children] ||= options[:root].singularize
+ options[:indent] ||= 2
+ options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
+
+ root = options.delete(:root).to_s
+ children = options.delete(:children)
+
+ if !options.has_key?(:dasherize) || options[:dasherize]
+ root = root.dasherize
+ end
+
+ options[:builder].instruct! unless options.delete(:skip_instruct)
+
+ opts = options.merge({ :root => children })
+
+ xml = options[:builder]
+ if empty?
+ xml.tag!(root, options[:skip_types] ? {} : {:type => "array"})
+ else
+ xml.tag!(root, options[:skip_types] ? {} : {:type => "array"}) {
+ yield xml if block_given?
+ each { |e| e.to_xml(opts.merge!({ :skip_instruct => true })) }
+ }
+ end
+ end
+
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array/extract_options.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array/extract_options.rb
new file mode 100644
index 000000000..980d36400
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array/extract_options.rb
@@ -0,0 +1,19 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Array #:nodoc:
+ module ExtractOptions
+ # Extract options from a set of arguments. Removes and returns the last element in the array if it's a hash, otherwise returns a blank hash.
+ #
+ # def options(*args)
+ # args.extract_options!
+ # end
+ #
+ # options(1, 2) # => {}
+ # options(1, 2, :a => :b) # => {:a=>:b}
+ def extract_options!
+ last.is_a?(::Hash) ? pop : {}
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array/grouping.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array/grouping.rb
new file mode 100644
index 000000000..52ed61d3d
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array/grouping.rb
@@ -0,0 +1,68 @@
+require 'enumerator'
+
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Array #:nodoc:
+ module Grouping
+ # Iterate over an array in groups of a certain size, padding any remaining
+ # slots with specified value (<tt>nil</tt> by default) unless it is
+ # <tt>false</tt>.
+ #
+ # E.g.
+ #
+ # %w(1 2 3 4 5 6 7).in_groups_of(3) {|g| p g}
+ # ["1", "2", "3"]
+ # ["4", "5", "6"]
+ # ["7", nil, nil]
+ #
+ # %w(1 2 3).in_groups_of(2, '&nbsp;') {|g| p g}
+ # ["1", "2"]
+ # ["3", "&nbsp;"]
+ #
+ # %w(1 2 3).in_groups_of(2, false) {|g| p g}
+ # ["1", "2"]
+ # ["3"]
+ def in_groups_of(number, fill_with = nil, &block)
+ if fill_with == false
+ collection = self
+ else
+ # size % number gives how many extra we have;
+ # subtracting from number gives how many to add;
+ # modulo number ensures we don't add group of just fill.
+ padding = (number - size % number) % number
+ collection = dup.concat([fill_with] * padding)
+ end
+
+ if block_given?
+ collection.each_slice(number, &block)
+ else
+ returning [] do |groups|
+ collection.each_slice(number) { |group| groups << group }
+ end
+ end
+ end
+
+ # Divide the array into one or more subarrays based on a delimiting +value+
+ # or the result of an optional block.
+ #
+ # ex.
+ #
+ # [1, 2, 3, 4, 5].split(3) # => [[1, 2], [4, 5]]
+ # (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]]
+ def split(value = nil, &block)
+ block ||= Proc.new { |e| e == value }
+
+ inject([[]]) do |results, element|
+ if block.call(element)
+ results << []
+ else
+ results.last << element
+ end
+
+ results
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array/random_access.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array/random_access.rb
new file mode 100644
index 000000000..b7ee00742
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/array/random_access.rb
@@ -0,0 +1,12 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Array #:nodoc:
+ module RandomAccess
+ # Return a random element from the array.
+ def rand
+ self[Kernel.rand(length)]
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/bigdecimal.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/bigdecimal.rb
new file mode 100644
index 000000000..b442ae965
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/bigdecimal.rb
@@ -0,0 +1,2 @@
+require 'bigdecimal'
+require 'active_support/core_ext/bigdecimal/conversions'
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/bigdecimal/conversions.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/bigdecimal/conversions.rb
new file mode 100644
index 000000000..dcdb08aea
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/bigdecimal/conversions.rb
@@ -0,0 +1,6 @@
+class BigDecimal #:nodoc:
+ alias :_original_to_s :to_s
+ def to_s(format="F")
+ _original_to_s(format)
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/blank.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/blank.rb
new file mode 100644
index 000000000..c4695816e
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/blank.rb
@@ -0,0 +1,50 @@
+class Object
+ # An object is blank if it's nil, empty, or a whitespace string.
+ # For example, "", " ", nil, [], and {} are blank.
+ #
+ # This simplifies
+ # if !address.nil? && !address.empty?
+ # to
+ # if !address.blank?
+ def blank?
+ respond_to?(:empty?) ? empty? : !self
+ end
+end
+
+class NilClass #:nodoc:
+ def blank?
+ true
+ end
+end
+
+class FalseClass #:nodoc:
+ def blank?
+ true
+ end
+end
+
+class TrueClass #:nodoc:
+ def blank?
+ false
+ end
+end
+
+class Array #:nodoc:
+ alias_method :blank?, :empty?
+end
+
+class Hash #:nodoc:
+ alias_method :blank?, :empty?
+end
+
+class String #:nodoc:
+ def blank?
+ self !~ /\S/
+ end
+end
+
+class Numeric #:nodoc:
+ def blank?
+ false
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/cgi.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/cgi.rb
new file mode 100644
index 000000000..db90e5c74
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/cgi.rb
@@ -0,0 +1,5 @@
+require 'active_support/core_ext/cgi/escape_skipping_slashes'
+
+class CGI #:nodoc:
+ extend ActiveSupport::CoreExtensions::CGI::EscapeSkippingSlashes
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb
new file mode 100644
index 000000000..a21e98fa8
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb
@@ -0,0 +1,14 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module CGI #:nodoc:
+ module EscapeSkippingSlashes #:nodoc:
+ def escape_skipping_slashes(str)
+ str = str.join('/') if str.respond_to? :join
+ str.gsub(/([^ \/a-zA-Z0-9_.-])/n) do
+ "%#{$1.unpack('H2').first.upcase}"
+ end.tr(' ', '+')
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/class.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/class.rb
new file mode 100644
index 000000000..44ad6c8c0
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/class.rb
@@ -0,0 +1,4 @@
+require 'active_support/core_ext/class/attribute_accessors'
+require 'active_support/core_ext/class/inheritable_attributes'
+require 'active_support/core_ext/class/removal'
+require 'active_support/core_ext/class/delegating_attributes'
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb
new file mode 100644
index 000000000..eee61d48c
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb
@@ -0,0 +1,48 @@
+# Extends the class object with class and instance accessors for class attributes,
+# just like the native attr* accessors for instance attributes.
+class Class # :nodoc:
+ def cattr_reader(*syms)
+ syms.flatten.each do |sym|
+ next if sym.is_a?(Hash)
+ class_eval(<<-EOS, __FILE__, __LINE__)
+ unless defined? @@#{sym}
+ @@#{sym} = nil
+ end
+
+ def self.#{sym}
+ @@#{sym}
+ end
+
+ def #{sym}
+ @@#{sym}
+ end
+ EOS
+ end
+ end
+
+ def cattr_writer(*syms)
+ options = syms.extract_options!
+ syms.flatten.each do |sym|
+ class_eval(<<-EOS, __FILE__, __LINE__)
+ unless defined? @@#{sym}
+ @@#{sym} = nil
+ end
+
+ def self.#{sym}=(obj)
+ @@#{sym} = obj
+ end
+
+ #{"
+ def #{sym}=(obj)
+ @@#{sym} = obj
+ end
+ " unless options[:instance_writer] == false }
+ EOS
+ end
+ end
+
+ def cattr_accessor(*syms)
+ cattr_reader(*syms)
+ cattr_writer(*syms)
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb
new file mode 100644
index 000000000..f5f0ef877
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb
@@ -0,0 +1,40 @@
+# These class attributes behave something like the class
+# inheritable accessors. But instead of copying the hash over at
+# the time the subclass is first defined, the accessors simply
+# delegate to their superclass unless they have been given a
+# specific value. This stops the strange situation where values
+# set after class definition don't get applied to subclasses.
+class Class
+ def superclass_delegating_reader(*names)
+ class_name_to_stop_searching_on = self.superclass.name.blank? ? "Object" : self.superclass.name
+ names.each do |name|
+ class_eval <<-EOS
+ def self.#{name}
+ if defined?(@#{name})
+ @#{name}
+ elsif superclass < #{class_name_to_stop_searching_on} && superclass.respond_to?(:#{name})
+ superclass.#{name}
+ end
+ end
+ def #{name}
+ self.class.#{name}
+ end
+ EOS
+ end
+ end
+
+ def superclass_delegating_writer(*names)
+ names.each do |name|
+ class_eval <<-EOS
+ def self.#{name}=(value)
+ @#{name} = value
+ end
+ EOS
+ end
+ end
+
+ def superclass_delegating_accessor(*names)
+ superclass_delegating_reader(*names)
+ superclass_delegating_writer(*names)
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
new file mode 100644
index 000000000..371d074d3
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
@@ -0,0 +1,140 @@
+# Retain for backward compatibility. Methods are now included in Class.
+module ClassInheritableAttributes # :nodoc:
+end
+
+# Allows attributes to be shared within an inheritance hierarchy, but where each descendant gets a copy of
+# their parents' attributes, instead of just a pointer to the same. This means that the child can add elements
+# to, for example, an array without those additions being shared with either their parent, siblings, or
+# children, which is unlike the regular class-level attributes that are shared across the entire hierarchy.
+class Class # :nodoc:
+ def class_inheritable_reader(*syms)
+ syms.each do |sym|
+ next if sym.is_a?(Hash)
+ class_eval <<-EOS
+ def self.#{sym}
+ read_inheritable_attribute(:#{sym})
+ end
+
+ def #{sym}
+ self.class.#{sym}
+ end
+ EOS
+ end
+ end
+
+ def class_inheritable_writer(*syms)
+ options = syms.extract_options!
+ syms.each do |sym|
+ class_eval <<-EOS
+ def self.#{sym}=(obj)
+ write_inheritable_attribute(:#{sym}, obj)
+ end
+
+ #{"
+ def #{sym}=(obj)
+ self.class.#{sym} = obj
+ end
+ " unless options[:instance_writer] == false }
+ EOS
+ end
+ end
+
+ def class_inheritable_array_writer(*syms)
+ options = syms.extract_options!
+ syms.each do |sym|
+ class_eval <<-EOS
+ def self.#{sym}=(obj)
+ write_inheritable_array(:#{sym}, obj)
+ end
+
+ #{"
+ def #{sym}=(obj)
+ self.class.#{sym} = obj
+ end
+ " unless options[:instance_writer] == false }
+ EOS
+ end
+ end
+
+ def class_inheritable_hash_writer(*syms)
+ options = syms.extract_options!
+ syms.each do |sym|
+ class_eval <<-EOS
+ def self.#{sym}=(obj)
+ write_inheritable_hash(:#{sym}, obj)
+ end
+
+ #{"
+ def #{sym}=(obj)
+ self.class.#{sym} = obj
+ end
+ " unless options[:instance_writer] == false }
+ EOS
+ end
+ end
+
+ def class_inheritable_accessor(*syms)
+ class_inheritable_reader(*syms)
+ class_inheritable_writer(*syms)
+ end
+
+ def class_inheritable_array(*syms)
+ class_inheritable_reader(*syms)
+ class_inheritable_array_writer(*syms)
+ end
+
+ def class_inheritable_hash(*syms)
+ class_inheritable_reader(*syms)
+ class_inheritable_hash_writer(*syms)
+ end
+
+ def inheritable_attributes
+ @inheritable_attributes ||= EMPTY_INHERITABLE_ATTRIBUTES
+ end
+
+ def write_inheritable_attribute(key, value)
+ if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
+ @inheritable_attributes = {}
+ end
+ inheritable_attributes[key] = value
+ end
+
+ def write_inheritable_array(key, elements)
+ write_inheritable_attribute(key, []) if read_inheritable_attribute(key).nil?
+ write_inheritable_attribute(key, read_inheritable_attribute(key) + elements)
+ end
+
+ def write_inheritable_hash(key, hash)
+ write_inheritable_attribute(key, {}) if read_inheritable_attribute(key).nil?
+ write_inheritable_attribute(key, read_inheritable_attribute(key).merge(hash))
+ end
+
+ def read_inheritable_attribute(key)
+ inheritable_attributes[key]
+ end
+
+ def reset_inheritable_attributes
+ @inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
+ end
+
+ private
+ # Prevent this constant from being created multiple times
+ EMPTY_INHERITABLE_ATTRIBUTES = {}.freeze unless const_defined?(:EMPTY_INHERITABLE_ATTRIBUTES)
+
+ def inherited_with_inheritable_attributes(child)
+ inherited_without_inheritable_attributes(child) if respond_to?(:inherited_without_inheritable_attributes)
+
+ if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
+ new_inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
+ else
+ new_inheritable_attributes = inheritable_attributes.inject({}) do |memo, (key, value)|
+ memo.update(key => (value.dup rescue value))
+ end
+ end
+
+ child.instance_variable_set('@inheritable_attributes', new_inheritable_attributes)
+ end
+
+ alias inherited_without_inheritable_attributes inherited
+ alias inherited inherited_with_inheritable_attributes
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/class/removal.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/class/removal.rb
new file mode 100644
index 000000000..0c70e7181
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/class/removal.rb
@@ -0,0 +1,24 @@
+class Class #:nodoc:
+ def remove_subclasses
+ Object.remove_subclasses_of(self)
+ end
+
+ def subclasses
+ Object.subclasses_of(self).map { |o| o.to_s }
+ end
+
+ def remove_class(*klasses)
+ klasses.flatten.each do |klass|
+ # Skip this class if there is nothing bound to this name
+ next unless defined?(klass.name)
+
+ basename = klass.to_s.split("::").last
+ parent = klass.parent
+
+ # Skip this class if it does not match the current one bound to this name
+ next unless parent.const_defined?(basename) && klass = parent.const_get(basename)
+
+ parent.instance_eval { remove_const basename } unless parent == klass
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date.rb
new file mode 100644
index 000000000..3f56c560b
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date.rb
@@ -0,0 +1,10 @@
+require 'date'
+require 'active_support/core_ext/date/behavior'
+require 'active_support/core_ext/date/calculations'
+require 'active_support/core_ext/date/conversions'
+
+class Date#:nodoc:
+ include ActiveSupport::CoreExtensions::Date::Behavior
+ include ActiveSupport::CoreExtensions::Date::Calculations
+ include ActiveSupport::CoreExtensions::Date::Conversions
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date/behavior.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date/behavior.rb
new file mode 100644
index 000000000..011cc17cb
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date/behavior.rb
@@ -0,0 +1,13 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Date #:nodoc:
+ module Behavior
+ # Enable more predictable duck-typing on Date-like classes. See
+ # Object#acts_like?.
+ def acts_like_date?
+ true
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date/calculations.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date/calculations.rb
new file mode 100644
index 000000000..b82f7be49
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date/calculations.rb
@@ -0,0 +1,188 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Date #:nodoc:
+ # Enables the use of time calculations within Time itself
+ module Calculations
+ def self.included(base) #:nodoc:
+ base.extend ClassMethods
+
+ base.instance_eval do
+ alias_method :plus_without_duration, :+
+ alias_method :+, :plus_with_duration
+
+ alias_method :minus_without_duration, :-
+ alias_method :-, :minus_with_duration
+ end
+ end
+
+ module ClassMethods
+ def yesterday
+ ::Date.today.yesterday
+ end
+
+ def tomorrow
+ ::Date.today.tomorrow
+ end
+ end
+
+ # Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00)
+ # and then subtracts the specified number of seconds
+ def ago(seconds)
+ to_time.since(-seconds)
+ end
+
+ # Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00)
+ # and then adds the specified number of seconds
+ def since(seconds)
+ to_time.since(seconds)
+ end
+ alias :in :since
+
+ # Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00)
+ def beginning_of_day
+ to_time
+ end
+ alias :midnight :beginning_of_day
+ alias :at_midnight :beginning_of_day
+ alias :at_beginning_of_day :beginning_of_day
+
+ # Converts Date to a Time (or DateTime if necessary) with the time portion set to the end of the day (23:59:59)
+ def end_of_day
+ to_time.end_of_day
+ end
+
+ def plus_with_duration(other) #:nodoc:
+ if ActiveSupport::Duration === other
+ other.since(self)
+ else
+ plus_without_duration(other)
+ end
+ end
+
+ def minus_with_duration(other) #:nodoc:
+ if ActiveSupport::Duration === other
+ plus_with_duration(-other)
+ else
+ minus_without_duration(other)
+ end
+ end
+
+ # Provides precise Date calculations for years, months, and days. The +options+ parameter takes a hash with
+ # any of these keys: :years, :months, :weeks, :days.
+ def advance(options)
+ d = self
+ d = d >> options.delete(:years) * 12 if options[:years]
+ d = d >> options.delete(:months) if options[:months]
+ d = d + options.delete(:weeks) * 7 if options[:weeks]
+ d = d + options.delete(:days) if options[:days]
+ d
+ end
+
+ # Returns a new Date where one or more of the elements have been changed according to the +options+ parameter.
+ #
+ # Examples:
+ #
+ # Date.new(2007, 5, 12).change(:day => 1) # => Date.new(2007, 5, 1)
+ # Date.new(2007, 5, 12).change(:year => 2005, :month => 1) # => Date.new(2005, 1, 12)
+ def change(options)
+ ::Date.new(
+ options[:year] || self.year,
+ options[:month] || self.month,
+ options[:day] || self.day
+ )
+ end
+
+ # Returns a new Date/DateTime representing the time a number of specified months ago
+ def months_ago(months)
+ advance(:months => -months)
+ end
+
+ # Returns a new Date/DateTime representing the time a number of specified months in the future
+ def months_since(months)
+ advance(:months => months)
+ end
+
+ # Returns a new Date/DateTime representing the time a number of specified years ago
+ def years_ago(years)
+ advance(:years => -years)
+ end
+
+ # Returns a new Date/DateTime representing the time a number of specified years in the future
+ def years_since(years)
+ advance(:years => years)
+ end
+
+ # Short-hand for years_ago(1)
+ def last_year
+ years_ago(1)
+ end
+
+ # Short-hand for years_since(1)
+ def next_year
+ years_since(1)
+ end
+
+ # Short-hand for months_ago(1)
+ def last_month
+ months_ago(1)
+ end
+
+ # Short-hand for months_since(1)
+ def next_month
+ months_since(1)
+ end
+
+ # Returns a new Date/DateTime representing the "start" of this week (i.e, Monday; DateTime objects will have time set to 0:00)
+ def beginning_of_week
+ days_to_monday = self.wday!=0 ? self.wday-1 : 6
+ result = self - days_to_monday
+ self.acts_like?(:time) ? result.midnight : result
+ end
+ alias :monday :beginning_of_week
+ alias :at_beginning_of_week :beginning_of_week
+
+ # Returns a new Date/DateTime representing the start of the given day in next week (default is Monday).
+ def next_week(day = :monday)
+ days_into_week = { :monday => 0, :tuesday => 1, :wednesday => 2, :thursday => 3, :friday => 4, :saturday => 5, :sunday => 6}
+ result = (self + 7).beginning_of_week + days_into_week[day]
+ self.acts_like?(:time) ? result.change(:hour => 0) : result
+ end
+
+ # Returns a new ; DateTime objects will have time set to 0:00DateTime representing the start of the month (1st of the month; DateTime objects will have time set to 0:00)
+ def beginning_of_month
+ self.acts_like?(:time) ? change(:day => 1,:hour => 0, :min => 0, :sec => 0) : change(:day => 1)
+ end
+ alias :at_beginning_of_month :beginning_of_month
+
+ # Returns a new Date/DateTime representing the end of the month (last day of the month; DateTime objects will have time set to 0:00)
+ def end_of_month
+ last_day = ::Time.days_in_month( self.month, self.year )
+ self.acts_like?(:time) ? change(:day => last_day, :hour => 23, :min => 59, :sec => 59) : change(:day => last_day)
+ end
+ alias :at_end_of_month :end_of_month
+
+ # Returns a new Date/DateTime representing the start of the quarter (1st of january, april, july, october; DateTime objects will have time set to 0:00)
+ def beginning_of_quarter
+ beginning_of_month.change(:month => [10, 7, 4, 1].detect { |m| m <= self.month })
+ end
+ alias :at_beginning_of_quarter :beginning_of_quarter
+
+ # Returns a new Date/DateTime representing the start of the year (1st of january; DateTime objects will have time set to 0:00)
+ def beginning_of_year
+ self.acts_like?(:time) ? change(:month => 1, :day => 1, :hour => 0, :min => 0, :sec => 0) : change(:month => 1, :day => 1)
+ end
+ alias :at_beginning_of_year :beginning_of_year
+
+ # Convenience method which returns a new Date/DateTime representing the time 1 day ago
+ def yesterday
+ self - 1
+ end
+
+ # Convenience method which returns a new Date/DateTime representing the time 1 day since the instance time
+ def tomorrow
+ self + 1
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date/conversions.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date/conversions.rb
new file mode 100644
index 000000000..f34d86011
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date/conversions.rb
@@ -0,0 +1,98 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Date #:nodoc:
+ # Getting dates in different convenient string representations and other objects
+ module Conversions
+ DATE_FORMATS = {
+ :short => "%e %b",
+ :long => "%B %e, %Y",
+ :db => "%Y-%m-%d",
+ :long_ordinal => lambda { |date| date.strftime("%B #{date.day.ordinalize}, %Y") }, # => "April 25th, 2007"
+ :rfc822 => "%e %b %Y"
+ }
+
+ def self.included(base) #:nodoc:
+ base.instance_eval do
+ alias_method :to_default_s, :to_s
+ alias_method :to_s, :to_formatted_s
+ alias_method :default_inspect, :inspect
+ alias_method :inspect, :readable_inspect
+
+ # Ruby 1.9 has Date#to_time which converts to localtime only.
+ remove_method :to_time if base.instance_methods.include?(:to_time)
+
+ # Ruby 1.9 has Date#xmlschema which converts to a string without the time component.
+ remove_method :xmlschema if base.instance_methods.include?(:xmlschema)
+ end
+ end
+
+ # Convert to a formatted string - see DATE_FORMATS for predefined formats.
+ # You can also add your own formats to the DATE_FORMATS constant and use them with this method.
+ #
+ # This method is also aliased as <tt>to_s</tt>.
+ #
+ # ==== Examples:
+ # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
+ #
+ # date.to_formatted_s(:db) # => "2007-11-10"
+ # date.to_s(:db) # => "2007-11-10"
+ #
+ # date.to_formatted_s(:short) # => "10 Nov"
+ # date.to_formatted_s(:long) # => "November 10, 2007"
+ # date.to_formatted_s(:long_ordinal) # => "November 10th, 2007"
+ # date.to_formatted_s(:rfc822) # => "10 Nov 2007"
+ def to_formatted_s(format = :default)
+ if formatter = DATE_FORMATS[format]
+ if formatter.respond_to?(:call)
+ formatter.call(self).to_s
+ else
+ strftime(formatter)
+ end
+ else
+ to_default_s
+ end
+ end
+
+ # Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005"
+ def readable_inspect
+ strftime("%a, %d %b %Y")
+ end
+
+ # A method to keep Time, Date and DateTime instances interchangeable on conversions.
+ # In this case, it simply returns +self+.
+ def to_date
+ self
+ end if RUBY_VERSION < '1.9'
+
+ # Converts a Date instance to a Time, where the time is set to the beginning of the day.
+ # The timezone can be either :local or :utc (default :local).
+ #
+ # ==== Examples:
+ # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
+ #
+ # date.to_time # => Sat Nov 10 00:00:00 0800 2007
+ # date.to_time(:local) # => Sat Nov 10 00:00:00 0800 2007
+ #
+ # date.to_time(:utc) # => Sat Nov 10 00:00:00 UTC 2007
+ def to_time(form = :local)
+ ::Time.send("#{form}_time", year, month, day)
+ end
+
+ # Converts a Date instance to a DateTime, where the time is set to the beginning of the day
+ # and UTC offset is set to 0.
+ #
+ # ==== Example:
+ # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
+ #
+ # date.to_datetime # => Sat, 10 Nov 2007 00:00:00 0000
+ def to_datetime
+ ::DateTime.civil(year, month, day, 0, 0, 0, 0)
+ end if RUBY_VERSION < '1.9'
+
+ def xmlschema
+ to_time.xmlschema
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date_time.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date_time.rb
new file mode 100644
index 000000000..1d711de70
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date_time.rb
@@ -0,0 +1,10 @@
+require 'date'
+require 'active_support/core_ext/time/behavior'
+require 'active_support/core_ext/date_time/calculations'
+require 'active_support/core_ext/date_time/conversions'
+
+class DateTime
+ include ActiveSupport::CoreExtensions::Time::Behavior
+ include ActiveSupport::CoreExtensions::DateTime::Calculations
+ include ActiveSupport::CoreExtensions::DateTime::Conversions
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date_time/calculations.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date_time/calculations.rb
new file mode 100644
index 000000000..2e85d1457
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date_time/calculations.rb
@@ -0,0 +1,77 @@
+require 'rational'
+
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module DateTime #:nodoc:
+ # Enables the use of time calculations within DateTime itself
+ module Calculations
+ def self.included(base) #:nodoc:
+ base.extend ClassMethods
+ end
+
+ module ClassMethods
+ # DateTimes aren't aware of DST rules, so use a consistent non-DST offset when creating a DateTime with an offset in the local zone
+ def local_offset
+ ::Time.local(2007).utc_offset.to_r / 86400
+ end
+ end
+
+ # Seconds since midnight: DateTime.now.seconds_since_midnight
+ def seconds_since_midnight
+ self.sec + (self.min * 60) + (self.hour * 3600)
+ end
+
+ # Returns a new DateTime where one or more of the elements have been changed according to the +options+ parameter. The time options
+ # (hour, minute, sec) reset cascadingly, so if only the hour is passed, then minute and sec is set to 0. If the hour and
+ # minute is passed, then sec is set to 0.
+ def change(options)
+ ::DateTime.civil(
+ options[:year] || self.year,
+ options[:month] || self.month,
+ options[:day] || self.day,
+ options[:hour] || self.hour,
+ options[:min] || (options[:hour] ? 0 : self.min),
+ options[:sec] || ((options[:hour] || options[:min]) ? 0 : self.sec),
+ options[:offset] || self.offset,
+ options[:start] || self.start
+ )
+ end
+
+ # Uses Date to provide precise Time calculations for years, months, and days. The +options+ parameter takes a hash with
+ # any of these keys: :years, :months, :weeks, :days, :hours, :minutes, :seconds.
+ def advance(options)
+ d = to_date.advance(options)
+ datetime_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
+ seconds_to_advance = (options[:seconds] || 0) + (options[:minutes] || 0) * 60 + (options[:hours] || 0) * 3600
+ seconds_to_advance == 0 ? datetime_advanced_by_date : datetime_advanced_by_date.since(seconds_to_advance)
+ end
+
+ # Returns a new DateTime representing the time a number of seconds ago
+ # Do not use this method in combination with x.months, use months_ago instead!
+ def ago(seconds)
+ self.since(-seconds)
+ end
+
+ # Returns a new DateTime representing the time a number of seconds since the instance time
+ # Do not use this method in combination with x.months, use months_since instead!
+ def since(seconds)
+ self + Rational(seconds.round, 86400)
+ end
+ alias :in :since
+
+ # Returns a new DateTime representing the start of the day (0:00)
+ def beginning_of_day
+ change(:hour => 0)
+ end
+ alias :midnight :beginning_of_day
+ alias :at_midnight :beginning_of_day
+ alias :at_beginning_of_day :beginning_of_day
+
+ # Returns a new DateTime representing the end of the day (23:59:59)
+ def end_of_day
+ change(:hour => 23, :min => 59, :sec => 59)
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date_time/conversions.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date_time/conversions.rb
new file mode 100644
index 000000000..8ea8679b4
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/date_time/conversions.rb
@@ -0,0 +1,74 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module DateTime #:nodoc:
+ # Getting datetimes in different convenient string representations and other objects
+ module Conversions
+ def self.included(base)
+ base.class_eval do
+ alias_method :to_datetime_default_s, :to_s
+ alias_method :to_s, :to_formatted_s
+ alias_method :default_inspect, :inspect
+ alias_method :inspect, :readable_inspect
+
+ # Ruby 1.9 has DateTime#to_time which internally relies on Time. We define our own #to_time which allows
+ # DateTimes outside the range of what can be created with Time.
+ remove_method :to_time if base.instance_methods.include?(:to_time)
+ end
+ end
+
+ # Convert to a formatted string - see DATE_FORMATS for predefined formats.
+ # You can also add your own formats to the DATE_FORMATS constant and use them with this method.
+ #
+ # This method is also aliased as <tt>to_s</tt>.
+ #
+ # === Examples:
+ # datetime = DateTime.civil(2007, 12, 4, 0, 0, 0, 0) # => Tue, 04 Dec 2007 00:00:00 +0000
+ #
+ # datetime.to_formatted_s(:db) # => "2007-12-04 00:00:00"
+ # datetime.to_s(:db) # => "2007-12-04 00:00:00"
+ # datetime.to_s(:number) # => "20071204000000"
+ # datetime.to_formatted_s(:short) # => "04 Dec 00:00"
+ # datetime.to_formatted_s(:long) # => "December 04, 2007 00:00"
+ # datetime.to_formatted_s(:long_ordinal) # => "December 4th, 2007 00:00"
+ # datetime.to_formatted_s(:rfc822) # => "Tue, 04 Dec 2007 00:00:00 +0000"
+ def to_formatted_s(format = :default)
+ if formatter = ::Time::DATE_FORMATS[format]
+ if formatter.respond_to?(:call)
+ formatter.call(self).to_s
+ else
+ strftime(formatter)
+ end
+ else
+ to_datetime_default_s
+ end
+ end
+
+ # Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005 14:30:00 +0000"
+ def readable_inspect
+ to_s(:rfc822)
+ end
+
+ # Converts self to a Ruby Date object; time portion is discarded
+ def to_date
+ ::Date.new(year, month, day)
+ end
+
+ # Attempts to convert self to a Ruby Time object; returns self if out of range of Ruby Time class
+ # If self has an offset other than 0, self will just be returned unaltered, since there's no clean way to map it to a Time
+ def to_time
+ self.offset == 0 ? ::Time.utc_time(year, month, day, hour, min, sec) : self
+ end
+
+ # To be able to keep Times, Dates and DateTimes interchangeable on conversions
+ def to_datetime
+ self
+ end
+
+ # Converts datetime to an appropriate format for use in XML
+ def xmlschema
+ strftime("%Y-%m-%dT%H:%M:%S%Z")
+ end if RUBY_VERSION < '1.9'
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/duplicable.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/duplicable.rb
new file mode 100644
index 000000000..adbbfd8c6
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/duplicable.rb
@@ -0,0 +1,37 @@
+class Object
+ # Can you safely .dup this object?
+ # False for nil, false, true, symbols, and numbers; true otherwise.
+ def duplicable?
+ true
+ end
+end
+
+class NilClass #:nodoc:
+ def duplicable?
+ false
+ end
+end
+
+class FalseClass #:nodoc:
+ def duplicable?
+ false
+ end
+end
+
+class TrueClass #:nodoc:
+ def duplicable?
+ false
+ end
+end
+
+class Symbol #:nodoc:
+ def duplicable?
+ false
+ end
+end
+
+class Numeric #:nodoc:
+ def duplicable?
+ false
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/enumerable.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/enumerable.rb
new file mode 100644
index 000000000..f35c8f86c
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/enumerable.rb
@@ -0,0 +1,63 @@
+module Enumerable
+ # Collect an enumerable into sets, grouped by the result of a block. Useful,
+ # for example, for grouping records by date.
+ #
+ # e.g.
+ #
+ # latest_transcripts.group_by(&:day).each do |day, transcripts|
+ # p "#{day} -> #{transcripts.map(&:class) * ', '}"
+ # end
+ # "2006-03-01 -> Transcript"
+ # "2006-02-28 -> Transcript"
+ # "2006-02-27 -> Transcript, Transcript"
+ # "2006-02-26 -> Transcript, Transcript"
+ # "2006-02-25 -> Transcript"
+ # "2006-02-24 -> Transcript, Transcript"
+ # "2006-02-23 -> Transcript"
+ def group_by
+ inject({}) do |groups, element|
+ (groups[yield(element)] ||= []) << element
+ groups
+ end
+ end if RUBY_VERSION < '1.9'
+
+ # Calculates a sum from the elements. Examples:
+ #
+ # payments.sum { |p| p.price * p.tax_rate }
+ # payments.sum(&:price)
+ #
+ # This is instead of payments.inject { |sum, p| sum + p.price }
+ #
+ # Also calculates sums without the use of a block:
+ # [5, 15, 10].sum # => 30
+ #
+ # The default identity (sum of an empty list) is zero.
+ # However, you can override this default:
+ #
+ # [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
+ #
+ def sum(identity = 0, &block)
+ return identity unless size > 0
+
+ if block_given?
+ map(&block).sum
+ else
+ inject { |sum, element| sum + element }
+ end
+ end
+
+ # Convert an enumerable to a hash. Examples:
+ #
+ # people.index_by(&:login)
+ # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
+ # people.index_by { |person| "#{person.first_name} #{person.last_name}" }
+ # => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
+ #
+ def index_by
+ inject({}) do |accum, elem|
+ accum[yield(elem)] = elem
+ accum
+ end
+ end
+
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/exception.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/exception.rb
new file mode 100644
index 000000000..14cd57706
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/exception.rb
@@ -0,0 +1,33 @@
+class Exception # :nodoc:
+ def clean_message
+ Pathname.clean_within message
+ end
+
+ TraceSubstitutions = []
+ FrameworkRegexp = /generated|vendor|dispatch|ruby|script\/\w+/
+
+ def clean_backtrace
+ backtrace.collect do |line|
+ Pathname.clean_within(TraceSubstitutions.inject(line) do |result, (regexp, sub)|
+ result.gsub regexp, sub
+ end)
+ end
+ end
+
+ def application_backtrace
+ before_application_frame = true
+
+ trace = clean_backtrace.reject do |line|
+ non_app_frame = (line =~ FrameworkRegexp)
+ before_application_frame = false unless non_app_frame
+ non_app_frame && ! before_application_frame
+ end
+
+ # If we didn't find any application frames, return an empty app trace.
+ before_application_frame ? [] : trace
+ end
+
+ def framework_backtrace
+ clean_backtrace.grep FrameworkRegexp
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/file.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/file.rb
new file mode 100644
index 000000000..cd43be37e
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/file.rb
@@ -0,0 +1,21 @@
+require 'tempfile'
+
+# Write to a file atomically. Useful for situations where you don't
+# want other processes or threads to see half-written files.
+#
+# File.atomic_write("important.file") do |file|
+# file.write("hello")
+# end
+#
+# If your temp directory is not on the same filesystem as the file you're
+# trying to write, you can provide a different temporary directory.
+#
+# File.atomic_write("/data/something.imporant", "/data/tmp") do |f|
+# file.write("hello")
+# end
+def File.atomic_write(file_name, temp_dir = Dir.tmpdir)
+ temp_file = Tempfile.new(File.basename(file_name), temp_dir)
+ yield temp_file
+ temp_file.close
+ File.rename(temp_file.path, file_name)
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/float.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/float.rb
new file mode 100644
index 000000000..86862b715
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/float.rb
@@ -0,0 +1,5 @@
+require 'active_support/core_ext/float/rounding'
+
+class Float #:nodoc:
+ include ActiveSupport::CoreExtensions::Float::Rounding
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/float/rounding.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/float/rounding.rb
new file mode 100644
index 000000000..062d46683
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/float/rounding.rb
@@ -0,0 +1,24 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Float #:nodoc:
+ module Rounding
+ def self.included(base) #:nodoc:
+ base.class_eval do
+ alias_method :round_without_precision, :round
+ alias_method :round, :round_with_precision
+ end
+ end
+
+ # Rounds the float with the specified precision.
+ #
+ # x = 1.337
+ # x.round # => 1
+ # x.round(1) # => 1.3
+ # x.round(2) # => 1.34
+ def round_with_precision(precision = nil)
+ precision.nil? ? round_without_precision : (self * (10 ** precision)).round / (10 ** precision).to_f
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash.rb
new file mode 100644
index 000000000..6cbd9dd37
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash.rb
@@ -0,0 +1,13 @@
+%w(keys indifferent_access reverse_merge conversions diff slice except).each do |ext|
+ require "active_support/core_ext/hash/#{ext}"
+end
+
+class Hash #:nodoc:
+ include ActiveSupport::CoreExtensions::Hash::Keys
+ include ActiveSupport::CoreExtensions::Hash::IndifferentAccess
+ include ActiveSupport::CoreExtensions::Hash::ReverseMerge
+ include ActiveSupport::CoreExtensions::Hash::Conversions
+ include ActiveSupport::CoreExtensions::Hash::Diff
+ include ActiveSupport::CoreExtensions::Hash::Slice
+ include ActiveSupport::CoreExtensions::Hash::Except
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/conversions.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/conversions.rb
new file mode 100644
index 000000000..8021dfa87
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/conversions.rb
@@ -0,0 +1,242 @@
+require 'date'
+require 'cgi'
+require 'base64'
+require 'builder'
+require 'xmlsimple'
+
+# Locked down XmlSimple#xml_in_string
+class XmlSimple
+ # Same as xml_in but doesn't try to smartly shoot itself in the foot.
+ def xml_in_string(string, options = nil)
+ handle_options('in', options)
+
+ @doc = parse(string)
+ result = collapse(@doc.root)
+
+ if @options['keeproot']
+ merge({}, @doc.root.name, result)
+ else
+ result
+ end
+ end
+
+ def self.xml_in_string(string, options = nil)
+ new.xml_in_string(string, options)
+ end
+end
+
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Hash #:nodoc:
+ module Conversions
+ XML_TYPE_NAMES = {
+ "Symbol" => "symbol",
+ "Fixnum" => "integer",
+ "Bignum" => "integer",
+ "BigDecimal" => "decimal",
+ "Float" => "float",
+ "Date" => "date",
+ "DateTime" => "datetime",
+ "Time" => "datetime",
+ "TrueClass" => "boolean",
+ "FalseClass" => "boolean"
+ } unless defined?(XML_TYPE_NAMES)
+
+ XML_FORMATTING = {
+ "symbol" => Proc.new { |symbol| symbol.to_s },
+ "date" => Proc.new { |date| date.to_s(:db) },
+ "datetime" => Proc.new { |time| time.xmlschema },
+ "binary" => Proc.new { |binary| Base64.encode64(binary) },
+ "yaml" => Proc.new { |yaml| yaml.to_yaml }
+ } unless defined?(XML_FORMATTING)
+
+ # TODO: use Time.xmlschema instead of Time.parse;
+ # use regexp instead of Date.parse
+ unless defined?(XML_PARSING)
+ XML_PARSING = {
+ "symbol" => Proc.new { |symbol| symbol.to_sym },
+ "date" => Proc.new { |date| ::Date.parse(date) },
+ "datetime" => Proc.new { |time| ::Time.parse(time).utc },
+ "integer" => Proc.new { |integer| integer.to_i },
+ "float" => Proc.new { |float| float.to_f },
+ "decimal" => Proc.new { |number| BigDecimal(number) },
+ "boolean" => Proc.new { |boolean| %w(1 true).include?(boolean.strip) },
+ "string" => Proc.new { |string| string.to_s },
+ "yaml" => Proc.new { |yaml| YAML::load(yaml) rescue yaml },
+ "base64Binary" => Proc.new { |bin| Base64.decode64(bin) },
+ # FIXME: Get rid of eval and institute a proper decorator here
+ "file" => Proc.new do |file, entity|
+ f = StringIO.new(Base64.decode64(file))
+ eval "def f.original_filename() '#{entity["name"]}' || 'untitled' end"
+ eval "def f.content_type() '#{entity["content_type"]}' || 'application/octet-stream' end"
+ f
+ end
+ }
+
+ XML_PARSING.update(
+ "double" => XML_PARSING["float"],
+ "dateTime" => XML_PARSING["datetime"]
+ )
+ end
+
+ def self.included(klass)
+ klass.extend(ClassMethods)
+ end
+
+ # Converts a hash into a string suitable for use as a URL query string. An optional <tt>namespace</tt> can be
+ # passed to enclose the param names (see example below).
+ #
+ # ==== Example:
+ # { :name => 'David', :nationality => 'Danish' }.to_query # => "name=David&nationality=Danish"
+ #
+ # { :name => 'David', :nationality => 'Danish' }.to_query('user') # => "user%5Bname%5D=David&user%5Bnationality%5D=Danish"
+ def to_query(namespace = nil)
+ collect do |key, value|
+ value.to_query(namespace ? "#{namespace}[#{key}]" : key)
+ end.sort * '&'
+ end
+
+ def to_xml(options = {})
+ options[:indent] ||= 2
+ options.reverse_merge!({ :builder => Builder::XmlMarkup.new(:indent => options[:indent]),
+ :root => "hash" })
+ options[:builder].instruct! unless options.delete(:skip_instruct)
+ dasherize = !options.has_key?(:dasherize) || options[:dasherize]
+ root = dasherize ? options[:root].to_s.dasherize : options[:root].to_s
+
+ options[:builder].__send__(:method_missing, root) do
+ each do |key, value|
+ case value
+ when ::Hash
+ value.to_xml(options.merge({ :root => key, :skip_instruct => true }))
+ when ::Array
+ value.to_xml(options.merge({ :root => key, :children => key.to_s.singularize, :skip_instruct => true}))
+ when ::Method, ::Proc
+ # If the Method or Proc takes two arguments, then
+ # pass the suggested child element name. This is
+ # used if the Method or Proc will be operating over
+ # multiple records and needs to create an containing
+ # element that will contain the objects being
+ # serialized.
+ if 1 == value.arity
+ value.call(options.merge({ :root => key, :skip_instruct => true }))
+ else
+ value.call(options.merge({ :root => key, :skip_instruct => true }), key.to_s.singularize)
+ end
+ else
+ if value.respond_to?(:to_xml)
+ value.to_xml(options.merge({ :root => key, :skip_instruct => true }))
+ else
+ type_name = XML_TYPE_NAMES[value.class.name]
+
+ key = dasherize ? key.to_s.dasherize : key.to_s
+
+ attributes = options[:skip_types] || value.nil? || type_name.nil? ? { } : { :type => type_name }
+ if value.nil?
+ attributes[:nil] = true
+ end
+
+ options[:builder].tag!(key,
+ XML_FORMATTING[type_name] ? XML_FORMATTING[type_name].call(value) : value,
+ attributes
+ )
+ end
+ end
+ end
+
+ yield options[:builder] if block_given?
+ end
+
+ end
+
+ module ClassMethods
+ def from_xml(xml)
+ # TODO: Refactor this into something much cleaner that doesn't rely on XmlSimple
+ typecast_xml_value(undasherize_keys(XmlSimple.xml_in_string(xml,
+ 'forcearray' => false,
+ 'forcecontent' => true,
+ 'keeproot' => true,
+ 'contentkey' => '__content__')
+ ))
+ end
+
+ private
+ def typecast_xml_value(value)
+ case value.class.to_s
+ when 'Hash'
+ if value['type'] == 'array'
+ child_key, entries = value.detect { |k,v| k != 'type' } # child_key is throwaway
+ if entries.nil? || (c = value['__content__'] && c.blank?)
+ []
+ else
+ case entries.class.to_s # something weird with classes not matching here. maybe singleton methods breaking is_a?
+ when "Array"
+ entries.collect { |v| typecast_xml_value(v) }
+ when "Hash"
+ [typecast_xml_value(entries)]
+ else
+ raise "can't typecast #{entries.inspect}"
+ end
+ end
+ elsif value.has_key?("__content__")
+ content = value["__content__"]
+ if parser = XML_PARSING[value["type"]]
+ if parser.arity == 2
+ XML_PARSING[value["type"]].call(content, value)
+ else
+ XML_PARSING[value["type"]].call(content)
+ end
+ else
+ content
+ end
+ elsif value['type'] == 'string' && value['nil'] != 'true'
+ ""
+ # blank or nil parsed values are represented by nil
+ elsif value.blank? || value['nil'] == 'true'
+ nil
+ # If the type is the only element which makes it then
+ # this still makes the value nil
+ elsif value['type'] && value.size == 1
+ nil
+ else
+ xml_value = value.inject({}) do |h,(k,v)|
+ h[k] = typecast_xml_value(v)
+ h
+ end
+
+ # Turn { :files => { :file => #<StringIO> } into { :files => #<StringIO> } so it is compatible with
+ # how multipart uploaded files from HTML appear
+ xml_value["file"].is_a?(StringIO) ? xml_value["file"] : xml_value
+ end
+ when 'Array'
+ value.map! { |i| typecast_xml_value(i) }
+ case value.length
+ when 0 then nil
+ when 1 then value.first
+ else value
+ end
+ when 'String'
+ value
+ else
+ raise "can't typecast #{value.class.name} - #{value.inspect}"
+ end
+ end
+
+ def undasherize_keys(params)
+ case params.class.to_s
+ when "Hash"
+ params.inject({}) do |h,(k,v)|
+ h[k.to_s.tr("-", "_")] = undasherize_keys(v)
+ h
+ end
+ when "Array"
+ params.map { |v| undasherize_keys(v) }
+ else
+ params
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/diff.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/diff.rb
new file mode 100644
index 000000000..6abd67882
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/diff.rb
@@ -0,0 +1,19 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Hash #:nodoc:
+ module Diff
+ # Returns a hash that represents the difference between two hashes.
+ #
+ # Examples:
+ #
+ # {1 => 2}.diff(1 => 2) # => {}
+ # {1 => 2}.diff(1 => 3) # => {1 => 2}
+ # {}.diff(1 => 2) # => {1 => 2}
+ # {1 => 2, 3 => 4}.diff(1 => 2) # => {3 => 4}
+ def diff(h2)
+ self.dup.delete_if { |k, v| h2[k] == v }.merge(h2.dup.delete_if { |k, v| self.has_key?(k) })
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/except.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/except.rb
new file mode 100644
index 000000000..8362cd880
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/except.rb
@@ -0,0 +1,24 @@
+require 'set'
+
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Hash #:nodoc:
+ # Return a hash that includes everything but the given keys. This is useful for
+ # limiting a set of parameters to everything but a few known toggles:
+ #
+ # @person.update_attributes(params[:person].except(:admin))
+ module Except
+ # Returns a new hash without the given keys.
+ def except(*keys)
+ rejected = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
+ reject { |key,| rejected.include?(key) }
+ end
+
+ # Replaces the hash without only the given keys.
+ def except!(*keys)
+ replace(except(*keys))
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb
new file mode 100644
index 000000000..fda0489e7
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb
@@ -0,0 +1,102 @@
+# This class has dubious semantics and we only have it so that
+# people can write params[:key] instead of params['key']
+
+class HashWithIndifferentAccess < Hash
+ def initialize(constructor = {})
+ if constructor.is_a?(Hash)
+ super()
+ update(constructor)
+ else
+ super(constructor)
+ end
+ end
+
+ def default(key = nil)
+ if key.is_a?(Symbol) && include?(key = key.to_s)
+ self[key]
+ else
+ super
+ end
+ end
+
+ alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
+ alias_method :regular_update, :update unless method_defined?(:regular_update)
+
+ def []=(key, value)
+ regular_writer(convert_key(key), convert_value(value))
+ end
+
+ def update(other_hash)
+ other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
+ self
+ end
+
+ alias_method :merge!, :update
+
+ def key?(key)
+ super(convert_key(key))
+ end
+
+ alias_method :include?, :key?
+ alias_method :has_key?, :key?
+ alias_method :member?, :key?
+
+ def fetch(key, *extras)
+ super(convert_key(key), *extras)
+ end
+
+ def values_at(*indices)
+ indices.collect {|key| self[convert_key(key)]}
+ end
+
+ def dup
+ HashWithIndifferentAccess.new(self)
+ end
+
+ def merge(hash)
+ self.dup.update(hash)
+ end
+
+ def delete(key)
+ super(convert_key(key))
+ end
+
+ def stringify_keys!; self end
+ def symbolize_keys!; self end
+ def to_options!; self end
+
+ # Convert to a Hash with String keys.
+ def to_hash
+ Hash.new(default).merge(self)
+ end
+
+ protected
+ def convert_key(key)
+ key.kind_of?(Symbol) ? key.to_s : key
+ end
+
+ def convert_value(value)
+ case value
+ when Hash
+ value.with_indifferent_access
+ when Array
+ value.collect { |e| e.is_a?(Hash) ? e.with_indifferent_access : e }
+ else
+ value
+ end
+ end
+end
+
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Hash #:nodoc:
+ module IndifferentAccess #:nodoc:
+ def with_indifferent_access
+ hash = HashWithIndifferentAccess.new(self)
+ hash.default = self.default
+ hash
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/keys.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/keys.rb
new file mode 100644
index 000000000..2bd4138be
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/keys.rb
@@ -0,0 +1,54 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Hash #:nodoc:
+ module Keys
+ # Return a new hash with all keys converted to strings.
+ def stringify_keys
+ inject({}) do |options, (key, value)|
+ options[key.to_s] = value
+ options
+ end
+ end
+
+ # Destructively convert all keys to strings.
+ def stringify_keys!
+ keys.each do |key|
+ unless key.class.to_s == "String" # weird hack to make the tests run when string_ext_test.rb is also running
+ self[key.to_s] = self[key]
+ delete(key)
+ end
+ end
+ self
+ end
+
+ # Return a new hash with all keys converted to symbols.
+ def symbolize_keys
+ inject({}) do |options, (key, value)|
+ options[key.to_sym || key] = value
+ options
+ end
+ end
+
+ # Destructively convert all keys to symbols.
+ def symbolize_keys!
+ self.replace(self.symbolize_keys)
+ end
+
+ alias_method :to_options, :symbolize_keys
+ alias_method :to_options!, :symbolize_keys!
+
+ # Validate all keys in a hash match *valid keys, raising ArgumentError on a mismatch.
+ # Note that keys are NOT treated indifferently, meaning if you use strings for keys but assert symbol
+ # as keys, this will fail.
+ # examples:
+ # { :name => "Rob", :years => "28" }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key(s): years"
+ # { :name => "Rob", :age => "28" }.assert_valid_keys("name", "age") # => raises "ArgumentError: Unknown key(s): years, name"
+ # { :name => "Rob", :age => "28" }.assert_valid_keys(:name, :age) # => passes, raises nothing
+ def assert_valid_keys(*valid_keys)
+ unknown_keys = keys - [valid_keys].flatten
+ raise(ArgumentError, "Unknown key(s): #{unknown_keys.join(", ")}") unless unknown_keys.empty?
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb
new file mode 100644
index 000000000..3c4908ac9
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb
@@ -0,0 +1,25 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Hash #:nodoc:
+ # Allows for reverse merging where its the keys in the calling hash that wins over those in the <tt>other_hash</tt>.
+ # This is particularly useful for initializing an incoming option hash with default values:
+ #
+ # def setup(options = {})
+ # options.reverse_merge! :size => 25, :velocity => 10
+ # end
+ #
+ # The default :size and :velocity is only set if the +options+ passed in doesn't already have those keys set.
+ module ReverseMerge
+ def reverse_merge(other_hash)
+ other_hash.merge(self)
+ end
+
+ def reverse_merge!(other_hash)
+ replace(reverse_merge(other_hash))
+ end
+
+ alias_method :reverse_update, :reverse_merge!
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/slice.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/slice.rb
new file mode 100644
index 000000000..6fe5e0533
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/hash/slice.rb
@@ -0,0 +1,28 @@
+require 'set'
+
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Hash #:nodoc:
+ # Slice a hash to include only the given keys. This is useful for
+ # limiting an options hash to valid keys before passing to a method:
+ #
+ # def search(criteria = {})
+ # assert_valid_keys(:mass, :velocity, :time)
+ # end
+ #
+ # search(options.slice(:mass, :velocity, :time))
+ module Slice
+ # Returns a new hash with only the given keys.
+ def slice(*keys)
+ allowed = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
+ reject { |key,| !allowed.include?(key) }
+ end
+
+ # Replaces the hash with only the given keys.
+ def slice!(*keys)
+ replace(slice(*keys))
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/integer.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/integer.rb
new file mode 100644
index 000000000..d1e6d76ac
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/integer.rb
@@ -0,0 +1,7 @@
+require 'active_support/core_ext/integer/even_odd'
+require 'active_support/core_ext/integer/inflections'
+
+class Integer #:nodoc:
+ include ActiveSupport::CoreExtensions::Integer::EvenOdd
+ include ActiveSupport::CoreExtensions::Integer::Inflections
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/integer/even_odd.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/integer/even_odd.rb
new file mode 100644
index 000000000..7ea4cbf2b
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/integer/even_odd.rb
@@ -0,0 +1,24 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Integer #:nodoc:
+ # For checking if a fixnum is even or odd.
+ # * 1.even? # => false
+ # * 1.odd? # => true
+ # * 2.even? # => true
+ # * 2.odd? # => false
+ module EvenOdd
+ def multiple_of?(number)
+ self % number == 0
+ end
+
+ def even?
+ multiple_of? 2
+ end if RUBY_VERSION < '1.9'
+
+ def odd?
+ !even?
+ end if RUBY_VERSION < '1.9'
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/integer/inflections.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/integer/inflections.rb
new file mode 100644
index 000000000..87b57e3ad
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/integer/inflections.rb
@@ -0,0 +1,21 @@
+require 'active_support/inflector'
+
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Integer #:nodoc:
+ module Inflections
+ # Ordinalize turns a number into an ordinal string used to denote the
+ # position in an ordered sequence such as 1st, 2nd, 3rd, 4th.
+ #
+ # Examples
+ # 1.ordinalize # => "1st"
+ # 2.ordinalize # => "2nd"
+ # 1002.ordinalize # => "1002nd"
+ # 1003.ordinalize # => "1003rd"
+ def ordinalize
+ Inflector.ordinalize(self)
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel.rb
new file mode 100644
index 000000000..1922d804b
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel.rb
@@ -0,0 +1,5 @@
+require 'active_support/core_ext/kernel/daemonizing'
+require 'active_support/core_ext/kernel/reporting'
+require 'active_support/core_ext/kernel/agnostics'
+require 'active_support/core_ext/kernel/requires'
+require 'active_support/core_ext/kernel/debugger'
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel/agnostics.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel/agnostics.rb
new file mode 100644
index 000000000..c0cb4fb42
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel/agnostics.rb
@@ -0,0 +1,11 @@
+class Object
+ # Makes backticks behave (somewhat more) similarly on all platforms.
+ # On win32 `nonexistent_command` raises Errno::ENOENT; on Unix, the
+ # spawned shell prints a message to stderr and sets $?. We emulate
+ # Unix on the former but not the latter.
+ def `(command) #:nodoc:
+ super
+ rescue Errno::ENOENT => e
+ STDERR.puts "#$0: #{e}"
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel/daemonizing.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel/daemonizing.rb
new file mode 100644
index 000000000..0e78819fd
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel/daemonizing.rb
@@ -0,0 +1,15 @@
+module Kernel
+ # Turns the current script into a daemon process that detaches from the console.
+ # It can be shut down with a TERM signal.
+ def daemonize
+ exit if fork # Parent exits, child continues.
+ Process.setsid # Become session leader.
+ exit if fork # Zap session leader. See [1].
+ Dir.chdir "/" # Release old working directory.
+ File.umask 0000 # Ensure sensible umask. Adjust as needed.
+ STDIN.reopen "/dev/null" # Free file descriptors and
+ STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
+ STDERR.reopen STDOUT # STDOUT/ERR should better go to a logfile.
+ trap("TERM") { exit }
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel/debugger.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel/debugger.rb
new file mode 100644
index 000000000..c74d6cf88
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel/debugger.rb
@@ -0,0 +1,13 @@
+module Kernel
+ unless respond_to?(:debugger)
+ # Starts a debugging session if ruby-debug has been loaded (call script/server --debugger to do load it).
+ def debugger
+ RAILS_DEFAULT_LOGGER.info "\n***** Debugger requested, but was not available: Start server with --debugger to enable *****\n"
+ end
+ end
+
+ def breakpoint
+ RAILS_DEFAULT_LOGGER.info "\n***** The 'breakpoint' command has been renamed 'debugger' -- please change *****\n"
+ debugger
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel/reporting.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel/reporting.rb
new file mode 100644
index 000000000..a5cec5024
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel/reporting.rb
@@ -0,0 +1,51 @@
+module Kernel
+ # Sets $VERBOSE to nil for the duration of the block and back to its original value afterwards.
+ #
+ # silence_warnings do
+ # value = noisy_call # no warning voiced
+ # end
+ #
+ # noisy_call # warning voiced
+ def silence_warnings
+ old_verbose, $VERBOSE = $VERBOSE, nil
+ yield
+ ensure
+ $VERBOSE = old_verbose
+ end
+
+ # Sets $VERBOSE to true for the duration of the block and back to its original value afterwards.
+ def enable_warnings
+ old_verbose, $VERBOSE = $VERBOSE, true
+ yield
+ ensure
+ $VERBOSE = old_verbose
+ end
+
+ # For compatibility
+ def silence_stderr #:nodoc:
+ silence_stream(STDERR) { yield }
+ end
+
+ # Silences any stream for the duration of the block.
+ #
+ # silence_stream(STDOUT) do
+ # puts 'This will never be seen'
+ # end
+ #
+ # puts 'But this will'
+ def silence_stream(stream)
+ old_stream = stream.dup
+ stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null')
+ stream.sync = true
+ yield
+ ensure
+ stream.reopen(old_stream)
+ end
+
+ def suppress(*exception_classes)
+ begin yield
+ rescue Exception => e
+ raise unless exception_classes.any? { |cls| e.kind_of?(cls) }
+ end
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel/requires.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel/requires.rb
new file mode 100644
index 000000000..323fea49f
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/kernel/requires.rb
@@ -0,0 +1,24 @@
+module Kernel
+ # Require a library with fallback to RubyGems. Warnings during library
+ # loading are silenced to increase signal/noise for application warnings.
+ def require_library_or_gem(library_name)
+ silence_warnings do
+ begin
+ require library_name
+ rescue LoadError => cannot_require
+ # 1. Requiring the module is unsuccessful, maybe it's a gem and nobody required rubygems yet. Try.
+ begin
+ require 'rubygems'
+ rescue LoadError => rubygems_not_installed
+ raise cannot_require
+ end
+ # 2. Rubygems is installed and loaded. Try to load the library again
+ begin
+ require library_name
+ rescue LoadError => gem_not_installed
+ raise cannot_require
+ end
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/load_error.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/load_error.rb
new file mode 100644
index 000000000..6165e9544
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/load_error.rb
@@ -0,0 +1,38 @@
+class MissingSourceFile < LoadError #:nodoc:
+ attr_reader :path
+ def initialize(message, path)
+ super(message)
+ @path = path
+ end
+
+ def is_missing?(path)
+ path.gsub(/\.rb$/, '') == self.path.gsub(/\.rb$/, '')
+ end
+
+ def self.from_message(message)
+ REGEXPS.each do |regexp, capture|
+ match = regexp.match(message)
+ return MissingSourceFile.new(message, match[capture]) unless match.nil?
+ end
+ nil
+ end
+
+ REGEXPS = [
+ [/^no such file to load -- (.+)$/i, 1],
+ [/^Missing \w+ (file\s*)?([^\s]+.rb)$/i, 2],
+ [/^Missing API definition file in (.+)$/i, 1]
+ ] unless defined?(REGEXPS)
+end
+
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module LoadErrorExtensions #:nodoc:
+ module LoadErrorClassMethods #:nodoc:
+ def new(*args)
+ (self == LoadError && MissingSourceFile.from_message(args.first)) || super
+ end
+ end
+ ::LoadError.extend(LoadErrorClassMethods)
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/logger.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/logger.rb
new file mode 100644
index 000000000..9c1fd274a
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/logger.rb
@@ -0,0 +1,16 @@
+# Adds the 'around_level' method to Logger.
+
+class Logger
+ def self.define_around_helper(level)
+ module_eval <<-end_eval
+ def around_#{level}(before_message, after_message, &block)
+ self.#{level}(before_message)
+ return_value = block.call(self)
+ self.#{level}(after_message)
+ return return_value
+ end
+ end_eval
+ end
+ [:debug, :info, :error, :fatal].each {|level| define_around_helper(level) }
+
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module.rb
new file mode 100644
index 000000000..da8d5b376
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module.rb
@@ -0,0 +1,8 @@
+require 'active_support/core_ext/module/inclusion'
+require 'active_support/core_ext/module/attribute_accessors'
+require 'active_support/core_ext/module/attr_internal'
+require 'active_support/core_ext/module/attr_accessor_with_default'
+require 'active_support/core_ext/module/delegation'
+require 'active_support/core_ext/module/introspection'
+require 'active_support/core_ext/module/loading'
+require 'active_support/core_ext/module/aliasing'
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/aliasing.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/aliasing.rb
new file mode 100644
index 000000000..1894e3b0a
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/aliasing.rb
@@ -0,0 +1,70 @@
+class Module
+ # Encapsulates the common pattern of:
+ #
+ # alias_method :foo_without_feature, :foo
+ # alias_method :foo, :foo_with_feature
+ #
+ # With this, you simply do:
+ #
+ # alias_method_chain :foo, :feature
+ #
+ # And both aliases are set up for you.
+ #
+ # Query and bang methods (foo?, foo!) keep the same punctuation:
+ #
+ # alias_method_chain :foo?, :feature
+ #
+ # is equivalent to
+ #
+ # alias_method :foo_without_feature?, :foo?
+ # alias_method :foo?, :foo_with_feature?
+ #
+ # so you can safely chain foo, foo?, and foo! with the same feature.
+ def alias_method_chain(target, feature)
+ # Strip out punctuation on predicates or bang methods since
+ # e.g. target?_without_feature is not a valid method name.
+ aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
+ yield(aliased_target, punctuation) if block_given?
+
+ with_method, without_method = "#{aliased_target}_with_#{feature}#{punctuation}", "#{aliased_target}_without_#{feature}#{punctuation}"
+
+ alias_method without_method, target
+ alias_method target, with_method
+
+ case
+ when public_method_defined?(without_method)
+ public target
+ when protected_method_defined?(without_method)
+ protected target
+ when private_method_defined?(without_method)
+ private target
+ end
+ end
+
+ # Allows you to make aliases for attributes, which includes
+ # getter, setter, and query methods.
+ #
+ # Example:
+ #
+ # class Content < ActiveRecord::Base
+ # # has a title attribute
+ # end
+ #
+ # class Email < Content
+ # alias_attribute :subject, :title
+ # end
+ #
+ # e = Email.find(1)
+ # e.title # => "Superstars"
+ # e.subject # => "Superstars"
+ # e.subject? # => true
+ # e.subject = "Megastars"
+ # e.title # => "Megastars"
+ def alias_attribute(new_name, old_name)
+ module_eval <<-STR, __FILE__, __LINE__+1
+ def #{new_name}; self.#{old_name}; end
+ def #{new_name}?; self.#{old_name}?; end
+ def #{new_name}=(v); self.#{old_name} = v; end
+ STR
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/attr_accessor_with_default.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/attr_accessor_with_default.rb
new file mode 100644
index 000000000..683789d85
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/attr_accessor_with_default.rb
@@ -0,0 +1,31 @@
+class Module
+ # Declare an attribute accessor with an initial default return value.
+ #
+ # To give attribute <tt>:age</tt> the initial value <tt>25</tt>:
+ #
+ # class Person
+ # attr_accessor_with_default :age, 25
+ # end
+ #
+ # some_person.age
+ # => 25
+ # some_person.age = 26
+ # some_person.age
+ # => 26
+ #
+ # To give attribute <tt>:element_name</tt> a dynamic default value, evaluated
+ # in scope of self:
+ #
+ # attr_accessor_with_default(:element_name) { name.underscore }
+ #
+ def attr_accessor_with_default(sym, default = nil, &block)
+ raise 'Default value or block required' unless !default.nil? || block
+ define_method(sym, block_given? ? block : Proc.new { default })
+ module_eval(<<-EVAL, __FILE__, __LINE__)
+ def #{sym}=(value)
+ class << self; attr_reader :#{sym} end
+ @#{sym} = value
+ end
+ EVAL
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/attr_internal.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/attr_internal.rb
new file mode 100644
index 000000000..7f2fb9641
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/attr_internal.rb
@@ -0,0 +1,31 @@
+class Module
+ # Declare an attribute reader backed by an internally-named instance variable.
+ def attr_internal_reader(*attrs)
+ attrs.each do |attr|
+ module_eval "def #{attr}() #{attr_internal_ivar_name(attr)} end"
+ end
+ end
+
+ # Declare an attribute writer backed by an internally-named instance variable.
+ def attr_internal_writer(*attrs)
+ attrs.each do |attr|
+ module_eval "def #{attr}=(v) #{attr_internal_ivar_name(attr)} = v end"
+ end
+ end
+
+ # Declare attributes backed by 'internal' instance variables names.
+ def attr_internal_accessor(*attrs)
+ attr_internal_reader(*attrs)
+ attr_internal_writer(*attrs)
+ end
+
+ alias_method :attr_internal, :attr_internal_accessor
+
+ private
+ mattr_accessor :attr_internal_naming_format
+ self.attr_internal_naming_format = '@_%s'
+
+ def attr_internal_ivar_name(attr)
+ attr_internal_naming_format % attr
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
new file mode 100644
index 000000000..58ff36324
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
@@ -0,0 +1,48 @@
+# Extends the module object with module and instance accessors for class attributes,
+# just like the native attr* accessors for instance attributes.
+class Module # :nodoc:
+ def mattr_reader(*syms)
+ syms.each do |sym|
+ next if sym.is_a?(Hash)
+ class_eval(<<-EOS, __FILE__, __LINE__)
+ unless defined? @@#{sym}
+ @@#{sym} = nil
+ end
+
+ def self.#{sym}
+ @@#{sym}
+ end
+
+ def #{sym}
+ @@#{sym}
+ end
+ EOS
+ end
+ end
+
+ def mattr_writer(*syms)
+ options = syms.extract_options!
+ syms.each do |sym|
+ class_eval(<<-EOS, __FILE__, __LINE__)
+ unless defined? @@#{sym}
+ @@#{sym} = nil
+ end
+
+ def self.#{sym}=(obj)
+ @@#{sym} = obj
+ end
+
+ #{"
+ def #{sym}=(obj)
+ @@#{sym} = obj
+ end
+ " unless options[:instance_writer] == false }
+ EOS
+ end
+ end
+
+ def mattr_accessor(*syms)
+ mattr_reader(*syms)
+ mattr_writer(*syms)
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/delegation.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/delegation.rb
new file mode 100644
index 000000000..f6647eaed
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/delegation.rb
@@ -0,0 +1,62 @@
+class Module
+ # Provides a delegate class method to easily expose contained objects' methods
+ # as your own. Pass one or more methods (specified as symbols or strings)
+ # and the name of the target object as the final :to option (also a symbol
+ # or string). At least one method and the :to option are required.
+ #
+ # Delegation is particularly useful with Active Record associations:
+ #
+ # class Greeter < ActiveRecord::Base
+ # def hello() "hello" end
+ # def goodbye() "goodbye" end
+ # end
+ #
+ # class Foo < ActiveRecord::Base
+ # belongs_to :greeter
+ # delegate :hello, :to => :greeter
+ # end
+ #
+ # Foo.new.hello # => "hello"
+ # Foo.new.goodbye # => NoMethodError: undefined method `goodbye' for #<Foo:0x1af30c>
+ #
+ # Multiple delegates to the same target are allowed:
+ # class Foo < ActiveRecord::Base
+ # belongs_to :greeter
+ # delegate :hello, :goodbye, :to => :greeter
+ # end
+ #
+ # Foo.new.goodbye # => "goodbye"
+ #
+ # Methods can be delegated to instance variables, class variables, or constants
+ # by providing the variable as a symbol:
+ # class Foo
+ # CONSTANT_ARRAY = [0,1,2,3]
+ # @@class_array = [4,5,6,7]
+ #
+ # def initialize
+ # @instance_array = [8,9,10,11]
+ # end
+ # delegate :sum, :to => :CONSTANT_ARRAY
+ # delegate :min, :to => :@@class_array
+ # delegate :max, :to => :@instance_array
+ # end
+ #
+ # Foo.new.sum # => 6
+ # Foo.new.min # => 4
+ # Foo.new.max # => 11
+ #
+ def delegate(*methods)
+ options = methods.pop
+ unless options.is_a?(Hash) && to = options[:to]
+ raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, :to => :greeter)."
+ end
+
+ methods.each do |method|
+ module_eval(<<-EOS, "(__DELEGATION__)", 1)
+ def #{method}(*args, &block)
+ #{to}.__send__(#{method.inspect}, *args, &block)
+ end
+ EOS
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/inclusion.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/inclusion.rb
new file mode 100644
index 000000000..efc00d6f2
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/inclusion.rb
@@ -0,0 +1,11 @@
+class Module
+ def included_in_classes
+ classes = []
+ ObjectSpace.each_object(Class) { |k| classes << k if k.included_modules.include?(self) }
+
+ classes.reverse.inject([]) do |unique_classes, klass|
+ unique_classes << klass unless unique_classes.collect { |k| k.to_s }.include?(klass.to_s)
+ unique_classes
+ end
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/introspection.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/introspection.rb
new file mode 100644
index 000000000..36481927a
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/introspection.rb
@@ -0,0 +1,35 @@
+class Module
+ # Return the module which contains this one; if this is a root module, such as
+ # +::MyModule+, then Object is returned.
+ def parent
+ parent_name = name.split('::')[0..-2] * '::'
+ parent_name.empty? ? Object : parent_name.constantize
+ end
+
+ # Return all the parents of this module, ordered from nested outwards. The
+ # receiver is not contained within the result.
+ def parents
+ parents = []
+ parts = name.split('::')[0..-2]
+ until parts.empty?
+ parents << (parts * '::').constantize
+ parts.pop
+ end
+ parents << Object unless parents.include? Object
+ parents
+ end
+
+ # Return the constants that have been defined locally by this object and not
+ # in an ancestor. This method may miss some constants if their definition in
+ # the ancestor is identical to their definition in the receiver.
+ def local_constants
+ inherited = {}
+ ancestors.each do |anc|
+ next if anc == self
+ anc.constants.each { |const| inherited[const] = anc.const_get(const) }
+ end
+ constants.select do |const|
+ ! inherited.key?(const) || inherited[const].object_id != const_get(const).object_id
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/loading.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/loading.rb
new file mode 100644
index 000000000..36c0c6140
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/module/loading.rb
@@ -0,0 +1,13 @@
+class Module
+ def as_load_path
+ if self == Object || self == Kernel
+ ''
+ elsif is_a? Class
+ parent == self ? '' : parent.as_load_path
+ else
+ name.split('::').collect do |word|
+ word.underscore
+ end * '/'
+ end
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/name_error.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/name_error.rb
new file mode 100644
index 000000000..49176c12d
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/name_error.rb
@@ -0,0 +1,17 @@
+# Add a +missing_name+ method to NameError instances.
+class NameError #:nodoc:
+ # Add a method to obtain the missing name from a NameError.
+ def missing_name
+ $1 if /((::)?([A-Z]\w*)(::[A-Z]\w*)*)$/ =~ message
+ end
+
+ # Was this exception raised because the given name was missing?
+ def missing_name?(name)
+ if name.is_a? Symbol
+ last_name = (missing_name || '').split('::').last
+ last_name == name.to_s
+ else
+ missing_name == name.to_s
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/numeric.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/numeric.rb
new file mode 100644
index 000000000..59da205b3
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/numeric.rb
@@ -0,0 +1,7 @@
+require 'active_support/core_ext/numeric/time'
+require 'active_support/core_ext/numeric/bytes'
+
+class Numeric #:nodoc:
+ include ActiveSupport::CoreExtensions::Numeric::Time
+ include ActiveSupport::CoreExtensions::Numeric::Bytes
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/numeric/bytes.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/numeric/bytes.rb
new file mode 100644
index 000000000..56477673a
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/numeric/bytes.rb
@@ -0,0 +1,44 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Numeric #:nodoc:
+ # Enables the use of byte calculations and declarations, like 45.bytes + 2.6.megabytes
+ module Bytes
+ def bytes
+ self
+ end
+ alias :byte :bytes
+
+ def kilobytes
+ self * 1024
+ end
+ alias :kilobyte :kilobytes
+
+ def megabytes
+ self * 1024.kilobytes
+ end
+ alias :megabyte :megabytes
+
+ def gigabytes
+ self * 1024.megabytes
+ end
+ alias :gigabyte :gigabytes
+
+ def terabytes
+ self * 1024.gigabytes
+ end
+ alias :terabyte :terabytes
+
+ def petabytes
+ self * 1024.terabytes
+ end
+ alias :petabyte :petabytes
+
+ def exabytes
+ self * 1024.petabytes
+ end
+ alias :exabyte :exabytes
+
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/numeric/time.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/numeric/time.rb
new file mode 100644
index 000000000..aac698f7a
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/numeric/time.rb
@@ -0,0 +1,91 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Numeric #:nodoc:
+ # Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years.
+ #
+ # These methods use Time#advance for precise date calculations when using from_now, ago, etc.
+ # as well as adding or subtracting their results from a Time object. For example:
+ #
+ # # equivalent to Time.now.advance(:months => 1)
+ # 1.month.from_now
+ #
+ # # equivalent to Time.now.advance(:years => 2)
+ # 2.years.from_now
+ #
+ # # equivalent to Time.now.advance(:months => 4, :years => 5)
+ # (4.months + 5.years).from_now
+ #
+ # While these methods provide precise calculation when used as in the examples above, care
+ # should be taken to note that this is not true if the result of `months', `years', etc is
+ # converted before use:
+ #
+ # # equivalent to 30.days.to_i.from_now
+ # 1.month.to_i.from_now
+ #
+ # # equivalent to 365.25.days.to_f.from_now
+ # 1.year.to_f.from_now
+ #
+ # In such cases, Ruby's core
+ # Date[http://stdlib.rubyonrails.org/libdoc/date/rdoc/index.html] and
+ # Time[http://stdlib.rubyonrails.org/libdoc/time/rdoc/index.html] should be used for precision
+ # date and time arithmetic
+ module Time
+ def seconds
+ ActiveSupport::Duration.new(self, [[:seconds, self]])
+ end
+ alias :second :seconds
+
+ def minutes
+ ActiveSupport::Duration.new(self * 60, [[:seconds, self * 60]])
+ end
+ alias :minute :minutes
+
+ def hours
+ ActiveSupport::Duration.new(self * 3600, [[:seconds, self * 3600]])
+ end
+ alias :hour :hours
+
+ def days
+ ActiveSupport::Duration.new(self * 24.hours, [[:days, self]])
+ end
+ alias :day :days
+
+ def weeks
+ ActiveSupport::Duration.new(self * 7.days, [[:days, self * 7]])
+ end
+ alias :week :weeks
+
+ def fortnights
+ ActiveSupport::Duration.new(self * 2.weeks, [[:days, self * 14]])
+ end
+ alias :fortnight :fortnights
+
+ def months
+ ActiveSupport::Duration.new(self * 30.days, [[:months, self]])
+ end
+ alias :month :months
+
+ def years
+ ActiveSupport::Duration.new(self * 365.25.days, [[:years, self]])
+ end
+ alias :year :years
+
+ # Reads best without arguments: 10.minutes.ago
+ def ago(time = ::Time.now)
+ time - self
+ end
+
+ # Reads best with argument: 10.minutes.until(time)
+ alias :until :ago
+
+ # Reads best with argument: 10.minutes.since(time)
+ def since(time = ::Time.now)
+ time + self
+ end
+
+ # Reads best without arguments: 10.minutes.from_now
+ alias :from_now :since
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/object.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/object.rb
new file mode 100644
index 000000000..bbc7d8167
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/object.rb
@@ -0,0 +1,4 @@
+require 'active_support/core_ext/object/conversions'
+require 'active_support/core_ext/object/extending'
+require 'active_support/core_ext/object/instance_variables'
+require 'active_support/core_ext/object/misc'
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/object/conversions.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/object/conversions.rb
new file mode 100644
index 000000000..ad752f0fc
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/object/conversions.rb
@@ -0,0 +1,14 @@
+class Object
+ # Alias of <tt>to_s</tt>.
+ def to_param
+ to_s
+ end
+
+ # Converts an object into a string suitable for use as a URL query string, using the given <tt>key</tt> as the
+ # param name.
+ #
+ # Note: This method is defined as a default implementation for all Objects for Hash#to_query to work.
+ def to_query(key)
+ "#{CGI.escape(key.to_s)}=#{CGI.escape(to_param.to_s)}"
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/object/extending.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/object/extending.rb
new file mode 100644
index 000000000..43a2be916
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/object/extending.rb
@@ -0,0 +1,58 @@
+class Object
+ def remove_subclasses_of(*superclasses) #:nodoc:
+ Class.remove_class(*subclasses_of(*superclasses))
+ end
+
+ def subclasses_of(*superclasses) #:nodoc:
+ subclasses = []
+
+ # Exclude this class unless it's a subclass of our supers and is defined.
+ # We check defined? in case we find a removed class that has yet to be
+ # garbage collected. This also fails for anonymous classes -- please
+ # submit a patch if you have a workaround.
+ ObjectSpace.each_object(Class) do |k|
+ if superclasses.any? { |superclass| k < superclass } &&
+ (k.name.blank? || eval("defined?(::#{k}) && ::#{k}.object_id == k.object_id"))
+ subclasses << k
+ end
+ end
+
+ subclasses
+ end
+
+ def extended_by #:nodoc:
+ ancestors = class << self; ancestors end
+ ancestors.select { |mod| mod.class == Module } - [ Object, Kernel ]
+ end
+
+ def extend_with_included_modules_from(object) #:nodoc:
+ object.extended_by.each { |mod| extend mod }
+ end
+
+ unless defined? instance_exec # 1.9
+ module InstanceExecMethods #:nodoc:
+ end
+ include InstanceExecMethods
+
+ # Evaluate the block with the given arguments within the context of
+ # this object, so self is set to the method receiver.
+ #
+ # From Mauricio's http://eigenclass.org/hiki/bounded+space+instance_exec
+ def instance_exec(*args, &block)
+ begin
+ old_critical, Thread.critical = Thread.critical, true
+ n = 0
+ n += 1 while respond_to?(method_name = "__instance_exec#{n}")
+ InstanceExecMethods.module_eval { define_method(method_name, &block) }
+ ensure
+ Thread.critical = old_critical
+ end
+
+ begin
+ send(method_name, *args)
+ ensure
+ InstanceExecMethods.module_eval { remove_method(method_name) } rescue nil
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/object/instance_variables.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/object/instance_variables.rb
new file mode 100644
index 000000000..e07eb76c1
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/object/instance_variables.rb
@@ -0,0 +1,22 @@
+class Object
+ # Available in 1.8.6 and later.
+ unless respond_to?(:instance_variable_defined?)
+ def instance_variable_defined?(variable)
+ instance_variables.include?(variable.to_s)
+ end
+ end
+
+ def instance_values #:nodoc:
+ instance_variables.inject({}) do |values, name|
+ values[name.to_s[1..-1]] = instance_variable_get(name)
+ values
+ end
+ end
+
+ def copy_instance_variables_from(object, exclude = []) #:nodoc:
+ exclude += object.protected_instance_variables if object.respond_to? :protected_instance_variables
+
+ vars = object.instance_variables.map(&:to_s) - exclude.map(&:to_s)
+ vars.each { |name| instance_variable_set(name, object.instance_variable_get(name)) }
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/object/misc.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/object/misc.rb
new file mode 100644
index 000000000..a3637d7a8
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/object/misc.rb
@@ -0,0 +1,59 @@
+class Object
+ unless respond_to?(:send!)
+ # Anticipating Ruby 1.9 neutering send
+ alias send! send
+ end
+
+ # A Ruby-ized realization of the K combinator, courtesy of Mikael Brockman.
+ #
+ # def foo
+ # returning values = [] do
+ # values << 'bar'
+ # values << 'baz'
+ # end
+ # end
+ #
+ # foo # => ['bar', 'baz']
+ #
+ # def foo
+ # returning [] do |values|
+ # values << 'bar'
+ # values << 'baz'
+ # end
+ # end
+ #
+ # foo # => ['bar', 'baz']
+ #
+ def returning(value)
+ yield(value)
+ value
+ end
+
+ # An elegant way to refactor out common options
+ #
+ # with_options :order => 'created_at', :class_name => 'Comment' do |post|
+ # post.has_many :comments, :conditions => ['approved = ?', true], :dependent => :delete_all
+ # post.has_many :unapproved_comments, :conditions => ['approved = ?', false]
+ # post.has_many :all_comments
+ # end
+ #
+ # Can also be used with an explicit receiver:
+ #
+ # map.with_options :controller => "people" do |people|
+ # people.connect "/people", :action => "index"
+ # people.connect "/people/:id", :action => "show"
+ # end
+ #
+ def with_options(options)
+ yield ActiveSupport::OptionMerger.new(self, options)
+ end
+
+ # A duck-type assistant method. For example, ActiveSupport extends Date
+ # to define an acts_like_date? method, and extends Time to define
+ # acts_like_time?. As a result, we can do "x.acts_like?(:time)" and
+ # "x.acts_like?(:date)" to do duck-type-safe comparisons, since classes that
+ # we want to act like Time simply need to define an acts_like_time? method.
+ def acts_like?(duck)
+ respond_to? "acts_like_#{duck}?"
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/pathname.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/pathname.rb
new file mode 100644
index 000000000..4c5318ee6
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/pathname.rb
@@ -0,0 +1,7 @@
+require 'pathname'
+require 'active_support/core_ext/pathname/clean_within'
+
+class Pathname#:nodoc:
+ extend ActiveSupport::CoreExtensions::Pathname::CleanWithin
+end
+
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/pathname/clean_within.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/pathname/clean_within.rb
new file mode 100644
index 000000000..ae03e1bc5
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/pathname/clean_within.rb
@@ -0,0 +1,14 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Pathname #:nodoc:
+ module CleanWithin
+ # Clean the paths contained in the provided string.
+ def clean_within(string)
+ string.gsub(%r{[\w. ]+(/[\w. ]+)+(\.rb)?(\b|$)}) do |path|
+ new(path).cleanpath
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/proc.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/proc.rb
new file mode 100644
index 000000000..2ca23f62e
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/proc.rb
@@ -0,0 +1,12 @@
+class Proc #:nodoc:
+ def bind(object)
+ block, time = self, Time.now
+ (class << object; self end).class_eval do
+ method_name = "__bind_#{time.to_i}_#{time.usec}"
+ define_method(method_name, &block)
+ method = instance_method(method_name)
+ remove_method(method_name)
+ method
+ end.bind(object)
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/range.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/range.rb
new file mode 100644
index 000000000..0d2b169e3
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/range.rb
@@ -0,0 +1,11 @@
+require 'active_support/core_ext/range/conversions'
+require 'active_support/core_ext/range/overlaps'
+require 'active_support/core_ext/range/include_range'
+require 'active_support/core_ext/range/blockless_step'
+
+class Range #:nodoc:
+ include ActiveSupport::CoreExtensions::Range::Conversions
+ include ActiveSupport::CoreExtensions::Range::Overlaps
+ include ActiveSupport::CoreExtensions::Range::IncludeRange
+ include ActiveSupport::CoreExtensions::Range::BlocklessStep
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/range/blockless_step.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/range/blockless_step.rb
new file mode 100644
index 000000000..bc69263ab
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/range/blockless_step.rb
@@ -0,0 +1,22 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Range #:nodoc:
+ # Return an array when step is called without a block.
+ module BlocklessStep
+ def self.included(base) #:nodoc:
+ base.alias_method_chain :step, :blockless
+ end
+
+ def step_with_blockless(value, &block)
+ if block_given?
+ step_without_blockless(value, &block)
+ else
+ returning [] do |array|
+ step_without_blockless(value) { |step| array << step }
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/range/conversions.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/range/conversions.rb
new file mode 100644
index 000000000..3d12605f4
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/range/conversions.rb
@@ -0,0 +1,23 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Range #:nodoc:
+ # Getting ranges in different convenient string representations and other objects
+ module Conversions
+ RANGE_FORMATS = {
+ :db => Proc.new { |start, stop| "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'" }
+ }
+
+ def self.included(base) #:nodoc:
+ base.class_eval do
+ alias_method :to_default_s, :to_s
+ alias_method :to_s, :to_formatted_s
+ end
+ end
+
+ def to_formatted_s(format = :default)
+ RANGE_FORMATS[format] ? RANGE_FORMATS[format].call(first, last) : to_default_s
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/range/include_range.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/range/include_range.rb
new file mode 100644
index 000000000..cd53cf154
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/range/include_range.rb
@@ -0,0 +1,22 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Range #:nodoc:
+ # Check if a Range includes another Range.
+ module IncludeRange
+ def self.included(base) #:nodoc:
+ base.alias_method_chain :include?, :range
+ end
+
+ def include_with_range?(value)
+ if value.is_a?(::Range)
+ operator = exclude_end? ? :< : :<=
+ end_value = value.exclude_end? ? last.succ : last
+ include?(value.first) && (value.last <=> end_value).send(operator, 0)
+ else
+ include_without_range?(value)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/range/overlaps.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/range/overlaps.rb
new file mode 100644
index 000000000..80ed1bba9
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/range/overlaps.rb
@@ -0,0 +1,12 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Range #:nodoc:
+ # Check if Ranges overlap.
+ module Overlaps
+ def overlaps?(other)
+ include?(other.first) || other.include?(first)
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string.rb
new file mode 100644
index 000000000..5497b6f6f
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string.rb
@@ -0,0 +1,23 @@
+require 'active_support/core_ext/string/inflections'
+require 'active_support/core_ext/string/conversions'
+require 'active_support/core_ext/string/access'
+require 'active_support/core_ext/string/starts_ends_with'
+require 'active_support/core_ext/string/iterators' unless 'test'.respond_to?(:each_char)
+require 'active_support/core_ext/string/unicode'
+require 'active_support/core_ext/string/xchar'
+
+class String #:nodoc:
+ include ActiveSupport::CoreExtensions::String::Access
+ include ActiveSupport::CoreExtensions::String::Conversions
+ include ActiveSupport::CoreExtensions::String::Inflections
+ if RUBY_VERSION < '1.9'
+ include ActiveSupport::CoreExtensions::String::StartsEndsWith
+ else
+ alias starts_with? start_with?
+ alias ends_with? end_with?
+ end
+ if defined? ActiveSupport::CoreExtensions::String::Iterators
+ include ActiveSupport::CoreExtensions::String::Iterators
+ end
+ include ActiveSupport::CoreExtensions::String::Unicode
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/access.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/access.rb
new file mode 100644
index 000000000..d70d889f0
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/access.rb
@@ -0,0 +1,58 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module String #:nodoc:
+ # Makes it easier to access parts of a string, such as specific characters and substrings.
+ module Access
+ # Returns the character at the +position+ treating the string as an array (where 0 is the first character).
+ #
+ # Examples:
+ # "hello".at(0) # => "h"
+ # "hello".at(4) # => "o"
+ # "hello".at(10) # => nil
+ def at(position)
+ chars[position, 1].to_s
+ end
+
+ # Returns the remaining of the string from the +position+ treating the string as an array (where 0 is the first character).
+ #
+ # Examples:
+ # "hello".from(0) # => "hello"
+ # "hello".from(2) # => "llo"
+ # "hello".from(10) # => nil
+ def from(position)
+ chars[position..-1].to_s
+ end
+
+ # Returns the beginning of the string up to the +position+ treating the string as an array (where 0 is the first character).
+ #
+ # Examples:
+ # "hello".to(0) # => "h"
+ # "hello".to(2) # => "hel"
+ # "hello".to(10) # => "hello"
+ def to(position)
+ chars[0..position].to_s
+ end
+
+ # Returns the first character of the string or the first +limit+ characters.
+ #
+ # Examples:
+ # "hello".first # => "h"
+ # "hello".first(2) # => "he"
+ # "hello".first(10) # => "hello"
+ def first(limit = 1)
+ chars[0..(limit - 1)].to_s
+ end
+
+ # Returns the last character of the string or the last +limit+ characters.
+ #
+ # Examples:
+ # "hello".last # => "o"
+ # "hello".last(2) # => "lo"
+ # "hello".last(10) # => "hello"
+ def last(limit = 1)
+ (chars[(-limit)..-1] || self).to_s
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/conversions.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/conversions.rb
new file mode 100644
index 000000000..663ea8747
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/conversions.rb
@@ -0,0 +1,28 @@
+require 'parsedate'
+
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module String #:nodoc:
+ # Converting strings to other objects
+ module Conversions
+ # 'a'.ord == 'a'[0] for Ruby 1.9 forward compatibility.
+ def ord
+ self[0]
+ end if RUBY_VERSION < '1.9'
+
+ # Form can be either :utc (default) or :local.
+ def to_time(form = :utc)
+ ::Time.send("#{form}_time", *ParseDate.parsedate(self)[0..5].map {|arg| arg || 0})
+ end
+
+ def to_date
+ ::Date.new(*ParseDate.parsedate(self)[0..2])
+ end
+
+ def to_datetime
+ ::DateTime.civil(*ParseDate.parsedate(self)[0..5].map {|arg| arg || 0} << 0)
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/inflections.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/inflections.rb
new file mode 100644
index 000000000..dec6c9f01
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/inflections.rb
@@ -0,0 +1,153 @@
+require 'active_support/inflector'
+
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module String #:nodoc:
+ # String inflections define new methods on the String class to transform names for different purposes.
+ # For instance, you can figure out the name of a database from the name of a class.
+ # "ScaleScore".tableize => "scale_scores"
+ module Inflections
+ # Returns the plural form of the word in the string.
+ #
+ # Examples
+ # "post".pluralize #=> "posts"
+ # "octopus".pluralize #=> "octopi"
+ # "sheep".pluralize #=> "sheep"
+ # "words".pluralize #=> "words"
+ # "the blue mailman".pluralize #=> "the blue mailmen"
+ # "CamelOctopus".pluralize #=> "CamelOctopi"
+ def pluralize
+ Inflector.pluralize(self)
+ end
+
+ # The reverse of pluralize, returns the singular form of a word in a string.
+ #
+ # Examples
+ # "posts".singularize #=> "post"
+ # "octopi".singularize #=> "octopus"
+ # "sheep".singluarize #=> "sheep"
+ # "word".singluarize #=> "word"
+ # "the blue mailmen".singularize #=> "the blue mailman"
+ # "CamelOctopi".singularize #=> "CamelOctopus"
+ def singularize
+ Inflector.singularize(self)
+ end
+
+ # By default, camelize converts strings to UpperCamelCase. If the argument to camelize
+ # is set to ":lower" then camelize produces lowerCamelCase.
+ #
+ # camelize will also convert '/' to '::' which is useful for converting paths to namespaces
+ #
+ # Examples
+ # "active_record".camelize #=> "ActiveRecord"
+ # "active_record".camelize(:lower) #=> "activeRecord"
+ # "active_record/errors".camelize #=> "ActiveRecord::Errors"
+ # "active_record/errors".camelize(:lower) #=> "activeRecord::Errors"
+ def camelize(first_letter = :upper)
+ case first_letter
+ when :upper then Inflector.camelize(self, true)
+ when :lower then Inflector.camelize(self, false)
+ end
+ end
+ alias_method :camelcase, :camelize
+
+ # Capitalizes all the words and replaces some characters in the string to create
+ # a nicer looking title. Titleize is meant for creating pretty output. It is not
+ # used in the Rails internals.
+ #
+ # titleize is also aliased as as titlecase
+ #
+ # Examples
+ # "man from the boondocks".titleize #=> "Man From The Boondocks"
+ # "x-men: the last stand".titleize #=> "X Men: The Last Stand"
+ def titleize
+ Inflector.titleize(self)
+ end
+ alias_method :titlecase, :titleize
+
+ # The reverse of +camelize+. Makes an underscored form from the expression in the string.
+ #
+ # Changes '::' to '/' to convert namespaces to paths.
+ #
+ # Examples
+ # "ActiveRecord".underscore #=> "active_record"
+ # "ActiveRecord::Errors".underscore #=> active_record/errors
+ def underscore
+ Inflector.underscore(self)
+ end
+
+ # Replaces underscores with dashes in the string.
+ #
+ # Example
+ # "puni_puni" #=> "puni-puni"
+ def dasherize
+ Inflector.dasherize(self)
+ end
+
+ # Removes the module part from the expression in the string
+ #
+ # Examples
+ # "ActiveRecord::CoreExtensions::String::Inflections".demodulize #=> "Inflections"
+ # "Inflections".demodulize #=> "Inflections"
+ def demodulize
+ Inflector.demodulize(self)
+ end
+
+ # Create the name of a table like Rails does for models to table names. This method
+ # uses the pluralize method on the last word in the string.
+ #
+ # Examples
+ # "RawScaledScorer".tableize #=> "raw_scaled_scorers"
+ # "egg_and_ham".tableize #=> "egg_and_hams"
+ # "fancyCategory".tableize #=> "fancy_categories"
+ def tableize
+ Inflector.tableize(self)
+ end
+
+ # Create a class name from a table name like Rails does for table names to models.
+ # Note that this returns a string and not a Class. (To convert to an actual class
+ # follow classify with constantize.)
+ #
+ # Examples
+ # "egg_and_hams".classify #=> "EggAndHam"
+ # "post".classify #=> "Post"
+ def classify
+ Inflector.classify(self)
+ end
+
+ # Capitalizes the first word and turns underscores into spaces and strips _id.
+ # Like titleize, this is meant for creating pretty output.
+ #
+ # Examples
+ # "employee_salary" #=> "Employee salary"
+ # "author_id" #=> "Author"
+ def humanize
+ Inflector.humanize(self)
+ end
+
+ # Creates a foreign key name from a class name.
+ # +separate_class_name_and_id_with_underscore+ sets whether
+ # the method should put '_' between the name and 'id'.
+ #
+ # Examples
+ # "Message".foreign_key #=> "message_id"
+ # "Message".foreign_key(false) #=> "messageid"
+ # "Admin::Post".foreign_key #=> "post_id"
+ def foreign_key(separate_class_name_and_id_with_underscore = true)
+ Inflector.foreign_key(self, separate_class_name_and_id_with_underscore)
+ end
+
+ # Constantize tries to find a declared constant with the name specified
+ # in the string. It raises a NameError when the name is not in CamelCase
+ # or is not initialized.
+ #
+ # Examples
+ # "Module".constantize #=> Module
+ # "Class".constantize #=> Class
+ def constantize
+ Inflector.constantize(self)
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/iterators.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/iterators.rb
new file mode 100644
index 000000000..73114d9d5
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/iterators.rb
@@ -0,0 +1,17 @@
+require 'strscan'
+
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module String #:nodoc:
+ # Custom string iterators
+ module Iterators
+ # Yields a single-character string for each character in the string.
+ # When $KCODE = 'UTF8', multi-byte characters are yielded appropriately.
+ def each_char
+ scanner, char = StringScanner.new(self), /./mu
+ loop { yield(scanner.scan(char) || break) }
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/starts_ends_with.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/starts_ends_with.rb
new file mode 100644
index 000000000..396066979
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/starts_ends_with.rb
@@ -0,0 +1,27 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module String #:nodoc:
+ # Additional string tests.
+ module StartsEndsWith
+ def self.included(base)
+ base.class_eval do
+ alias_method :start_with?, :starts_with?
+ alias_method :end_with?, :ends_with?
+ end
+ end
+
+ # Does the string start with the specified +prefix+?
+ def starts_with?(prefix)
+ prefix = prefix.to_s
+ self[0, prefix.length] == prefix
+ end
+
+ # Does the string end with the specified +suffix+?
+ def ends_with?(suffix)
+ suffix = suffix.to_s
+ self[-suffix.length, suffix.length] == suffix
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/unicode.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/unicode.rb
new file mode 100644
index 000000000..dd19fe542
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/unicode.rb
@@ -0,0 +1,42 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module String #:nodoc:
+ # Define methods for handling unicode data.
+ module Unicode
+ # +chars+ is a Unicode safe proxy for string methods. It creates and returns an instance of the
+ # ActiveSupport::Multibyte::Chars class which encapsulates the original string. A Unicode safe version of all
+ # the String methods are defined on this proxy class. Undefined methods are forwarded to String, so all of the
+ # string overrides can also be called through the +chars+ proxy.
+ #
+ # name = 'Claus Müller'
+ # name.reverse #=> "rell??M sualC"
+ # name.length #=> 13
+ #
+ # name.chars.reverse.to_s #=> "rellüM sualC"
+ # name.chars.length #=> 12
+ #
+ #
+ # All the methods on the chars proxy which normally return a string will return a Chars object. This allows
+ # method chaining on the result of any of these methods.
+ #
+ # name.chars.reverse.length #=> 12
+ #
+ # The Char object tries to be as interchangeable with String objects as possible: sorting and comparing between
+ # String and Char work like expected. The bang! methods change the internal string representation in the Chars
+ # object. Interoperability problems can be resolved easily with a +to_s+ call.
+ #
+ # For more information about the methods defined on the Chars proxy see ActiveSupport::Multibyte::Chars and
+ # ActiveSupport::Multibyte::Handlers::UTF8Handler
+ def chars
+ ActiveSupport::Multibyte::Chars.new(self)
+ end
+
+ # Returns true if the string has UTF-8 semantics (a String used for purely byte resources is unlikely to have
+ # them), returns false otherwise.
+ def is_utf8?
+ ActiveSupport::Multibyte::Handlers::UTF8Handler.consumes?(self)
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/xchar.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/xchar.rb
new file mode 100644
index 000000000..df186e42d
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/string/xchar.rb
@@ -0,0 +1,11 @@
+begin
+ # See http://bogomips.org/fast_xs/ by Eric Wong
+ require 'fast_xs'
+
+ class String
+ alias_method :original_xs, :to_xs if method_defined?(:to_xs)
+ alias_method :to_xs, :fast_xs
+ end
+rescue LoadError
+ # fast_xs extension unavailable.
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/symbol.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/symbol.rb
new file mode 100644
index 000000000..54f541ad9
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/symbol.rb
@@ -0,0 +1,14 @@
+unless :test.respond_to?(:to_proc)
+ class Symbol
+ # Turns the symbol into a simple proc, which is especially useful for enumerations. Examples:
+ #
+ # # The same as people.collect { |p| p.name }
+ # people.collect(&:name)
+ #
+ # # The same as people.select { |p| p.manager? }.collect { |p| p.salary }
+ # people.select(&:manager?).collect(&:salary)
+ def to_proc
+ Proc.new { |*args| args.shift.__send__(self, *args) }
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/test.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/test.rb
new file mode 100644
index 000000000..c0b19bdc5
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/test.rb
@@ -0,0 +1 @@
+require 'active_support/core_ext/test/unit/assertions'
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/test/unit/assertions.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/test/unit/assertions.rb
new file mode 100644
index 000000000..2ae4b7d6d
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/test/unit/assertions.rb
@@ -0,0 +1,62 @@
+module Test #:nodoc:
+ module Unit #:nodoc:
+ # FIXME: no Proc#binding in Ruby 2, must change this API
+ module Assertions #:nodoc:
+ # Test numeric difference between the return value of an expression as a result of what is evaluated
+ # in the yielded block.
+ #
+ # assert_difference 'Article.count' do
+ # post :create, :article => {...}
+ # end
+ #
+ # An arbitrary expression is passed in and evaluated.
+ #
+ # assert_difference 'assigns(:article).comments(:reload).size' do
+ # post :create, :comment => {...}
+ # end
+ #
+ # An arbitrary positive or negative difference can be specified. The default is +1.
+ #
+ # assert_difference 'Article.count', -1 do
+ # post :delete, :id => ...
+ # end
+ #
+ # An array of expressions can also be passed in and evaluated.
+ #
+ # assert_difference [ 'Article.count', 'Post.count' ], +2 do
+ # post :create, :article => {...}
+ # end
+ #
+ # A error message can be specified.
+ #
+ # assert_difference 'Article.count', -1, "An Article should be destroyed" do
+ # post :delete, :id => ...
+ # end
+ def assert_difference(expressions, difference = 1, message = nil, &block)
+ expression_evaluations = Array(expressions).collect{ |expression| lambda { eval(expression, block.send!(:binding)) } }
+
+ original_values = expression_evaluations.inject([]) { |memo, expression| memo << expression.call }
+ yield
+ expression_evaluations.each_with_index do |expression, i|
+ assert_equal original_values[i] + difference, expression.call, message
+ end
+ end
+
+ # Assertion that the numeric result of evaluating an expression is not changed before and after
+ # invoking the passed in block.
+ #
+ # assert_no_difference 'Article.count' do
+ # post :create, :article => invalid_attributes
+ # end
+ #
+ # A error message can be specified.
+ #
+ # assert_no_difference 'Article.count', "An Article should not be destroyed" do
+ # post :create, :article => invalid_attributes
+ # end
+ def assert_no_difference(expressions, message = nil, &block)
+ assert_difference expressions, 0, message, &block
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/time.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/time.rb
new file mode 100644
index 000000000..d87c4ec65
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/time.rb
@@ -0,0 +1,19 @@
+require 'date'
+require 'time'
+
+# Ruby 1.8-cvs and 1.9 define private Time#to_date
+class Time
+ %w(to_date to_datetime).each do |method|
+ public method if private_instance_methods.include?(method)
+ end
+end
+
+require 'active_support/core_ext/time/behavior'
+require 'active_support/core_ext/time/calculations'
+require 'active_support/core_ext/time/conversions'
+
+class Time#:nodoc:
+ include ActiveSupport::CoreExtensions::Time::Behavior
+ include ActiveSupport::CoreExtensions::Time::Calculations
+ include ActiveSupport::CoreExtensions::Time::Conversions
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/time/behavior.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/time/behavior.rb
new file mode 100644
index 000000000..a5c0baacd
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/time/behavior.rb
@@ -0,0 +1,13 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Time #:nodoc:
+ module Behavior
+ # Enable more predictable duck-typing on Time-like classes. See
+ # Object#acts_like?.
+ def acts_like_time?
+ true
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/time/calculations.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/time/calculations.rb
new file mode 100644
index 000000000..7181bac3f
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -0,0 +1,224 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Time #:nodoc:
+ # Enables the use of time calculations within Time itself
+ module Calculations
+ def self.included(base) #:nodoc:
+ base.extend ClassMethods
+
+ base.class_eval do
+ alias_method :plus_without_duration, :+
+ alias_method :+, :plus_with_duration
+ alias_method :minus_without_duration, :-
+ alias_method :-, :minus_with_duration
+ end
+ end
+
+ module ClassMethods
+ # Return the number of days in the given month. If a year is given,
+ # February will return the correct number of days for leap years.
+ # Otherwise, this method will always report February as having 28
+ # days.
+ def days_in_month(month, year=nil)
+ if month == 2
+ !year.nil? && (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)) ? 29 : 28
+ elsif month <= 7
+ month % 2 == 0 ? 30 : 31
+ else
+ month % 2 == 0 ? 31 : 30
+ end
+ end
+
+ # Returns a new Time if requested year can be accommodated by Ruby's Time class
+ # (i.e., if year is within either 1970..2038 or 1902..2038, depending on system architecture);
+ # otherwise returns a DateTime
+ def time_with_datetime_fallback(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0, usec=0)
+ ::Time.send(utc_or_local, year, month, day, hour, min, sec, usec)
+ rescue
+ offset = utc_or_local.to_sym == :local ? ::DateTime.local_offset : 0
+ ::DateTime.civil(year, month, day, hour, min, sec, offset)
+ end
+
+ # wraps class method time_with_datetime_fallback with utc_or_local == :utc
+ def utc_time(*args)
+ time_with_datetime_fallback(:utc, *args)
+ end
+
+ # wraps class method time_with_datetime_fallback with utc_or_local == :local
+ def local_time(*args)
+ time_with_datetime_fallback(:local, *args)
+ end
+ end
+
+ # Seconds since midnight: Time.now.seconds_since_midnight
+ def seconds_since_midnight
+ self.to_i - self.change(:hour => 0).to_i + (self.usec/1.0e+6)
+ end
+
+ # Returns a new Time where one or more of the elements have been changed according to the +options+ parameter. The time options
+ # (hour, minute, sec, usec) reset cascadingly, so if only the hour is passed, then minute, sec, and usec is set to 0. If the hour and
+ # minute is passed, then sec and usec is set to 0.
+ def change(options)
+ ::Time.send(
+ self.utc? ? :utc_time : :local_time,
+ options[:year] || self.year,
+ options[:month] || self.month,
+ options[:day] || self.day,
+ options[:hour] || self.hour,
+ options[:min] || (options[:hour] ? 0 : self.min),
+ options[:sec] || ((options[:hour] || options[:min]) ? 0 : self.sec),
+ options[:usec] || ((options[:hour] || options[:min] || options[:sec]) ? 0 : self.usec)
+ )
+ end
+
+ # Uses Date to provide precise Time calculations for years, months, and days. The +options+ parameter takes a hash with
+ # any of these keys: :years, :months, :weeks, :days, :hours, :minutes, :seconds.
+ def advance(options)
+ d = to_date.advance(options)
+ time_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
+ seconds_to_advance = (options[:seconds] || 0) + (options[:minutes] || 0) * 60 + (options[:hours] || 0) * 3600
+ seconds_to_advance == 0 ? time_advanced_by_date : time_advanced_by_date.since(seconds_to_advance)
+ end
+
+ # Returns a new Time representing the time a number of seconds ago, this is basically a wrapper around the Numeric extension
+ # Do not use this method in combination with x.months, use months_ago instead!
+ def ago(seconds)
+ self.since(-seconds)
+ end
+
+ # Returns a new Time representing the time a number of seconds since the instance time, this is basically a wrapper around
+ # the Numeric extension. Do not use this method in combination with x.months, use months_since instead!
+ def since(seconds)
+ initial_dst = self.dst? ? 1 : 0
+ f = seconds.since(self)
+ final_dst = f.dst? ? 1 : 0
+ (seconds.abs >= 86400 && initial_dst != final_dst) ? f + (initial_dst - final_dst).hours : f
+ rescue
+ self.to_datetime.since(seconds)
+ end
+ alias :in :since
+
+ # Returns a new Time representing the time a number of specified months ago
+ def months_ago(months)
+ advance(:months => -months)
+ end
+
+ # Returns a new Time representing the time a number of specified months in the future
+ def months_since(months)
+ advance(:months => months)
+ end
+
+ # Returns a new Time representing the time a number of specified years ago
+ def years_ago(years)
+ advance(:years => -years)
+ end
+
+ # Returns a new Time representing the time a number of specified years in the future
+ def years_since(years)
+ advance(:years => years)
+ end
+
+ # Short-hand for years_ago(1)
+ def last_year
+ years_ago(1)
+ end
+
+ # Short-hand for years_since(1)
+ def next_year
+ years_since(1)
+ end
+
+
+ # Short-hand for months_ago(1)
+ def last_month
+ months_ago(1)
+ end
+
+ # Short-hand for months_since(1)
+ def next_month
+ months_since(1)
+ end
+
+ # Returns a new Time representing the "start" of this week (Monday, 0:00)
+ def beginning_of_week
+ days_to_monday = self.wday!=0 ? self.wday-1 : 6
+ (self - days_to_monday.days).midnight
+ end
+ alias :monday :beginning_of_week
+ alias :at_beginning_of_week :beginning_of_week
+
+ # Returns a new Time representing the start of the given day in next week (default is Monday).
+ def next_week(day = :monday)
+ days_into_week = { :monday => 0, :tuesday => 1, :wednesday => 2, :thursday => 3, :friday => 4, :saturday => 5, :sunday => 6}
+ since(1.week).beginning_of_week.since(days_into_week[day].day).change(:hour => 0)
+ end
+
+ # Returns a new Time representing the start of the day (0:00)
+ def beginning_of_day
+ (self - self.seconds_since_midnight).change(:usec => 0)
+ end
+ alias :midnight :beginning_of_day
+ alias :at_midnight :beginning_of_day
+ alias :at_beginning_of_day :beginning_of_day
+
+ # Returns a new Time representing the end of the day (23:59:59)
+ def end_of_day
+ change(:hour => 23, :min => 59, :sec => 59)
+ end
+
+ # Returns a new Time representing the start of the month (1st of the month, 0:00)
+ def beginning_of_month
+ #self - ((self.mday-1).days + self.seconds_since_midnight)
+ change(:day => 1,:hour => 0, :min => 0, :sec => 0, :usec => 0)
+ end
+ alias :at_beginning_of_month :beginning_of_month
+
+ # Returns a new Time representing the end of the month (last day of the month, 0:00)
+ def end_of_month
+ #self - ((self.mday-1).days + self.seconds_since_midnight)
+ last_day = ::Time.days_in_month( self.month, self.year )
+ change(:day => last_day, :hour => 23, :min => 59, :sec => 59, :usec => 0)
+ end
+ alias :at_end_of_month :end_of_month
+
+ # Returns a new Time representing the start of the quarter (1st of january, april, july, october, 0:00)
+ def beginning_of_quarter
+ beginning_of_month.change(:month => [10, 7, 4, 1].detect { |m| m <= self.month })
+ end
+ alias :at_beginning_of_quarter :beginning_of_quarter
+
+ # Returns a new Time representing the start of the year (1st of january, 0:00)
+ def beginning_of_year
+ change(:month => 1,:day => 1,:hour => 0, :min => 0, :sec => 0, :usec => 0)
+ end
+ alias :at_beginning_of_year :beginning_of_year
+
+ # Convenience method which returns a new Time representing the time 1 day ago
+ def yesterday
+ self.ago(1.day)
+ end
+
+ # Convenience method which returns a new Time representing the time 1 day since the instance time
+ def tomorrow
+ self.since(1.day)
+ end
+
+ def plus_with_duration(other) #:nodoc:
+ if ActiveSupport::Duration === other
+ other.since(self)
+ else
+ plus_without_duration(other)
+ end
+ end
+
+ def minus_with_duration(other) #:nodoc:
+ if ActiveSupport::Duration === other
+ other.until(self)
+ else
+ minus_without_duration(other)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/time/conversions.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/time/conversions.rb
new file mode 100644
index 000000000..0ce90669d
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/core_ext/time/conversions.rb
@@ -0,0 +1,94 @@
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Time #:nodoc:
+ # Getting times in different convenient string representations and other objects
+ module Conversions
+ DATE_FORMATS = {
+ :db => "%Y-%m-%d %H:%M:%S",
+ :time => "%H:%M",
+ :short => "%d %b %H:%M",
+ :long => "%B %d, %Y %H:%M",
+ :long_ordinal => lambda { |time| time.strftime("%B #{time.day.ordinalize}, %Y %H:%M") },
+ :rfc822 => "%a, %d %b %Y %H:%M:%S %z"
+ }
+
+ def self.included(base)
+ base.class_eval do
+ alias_method :to_default_s, :to_s
+ alias_method :to_s, :to_formatted_s
+ end
+ end
+
+ # Convert to a formatted string - see DATE_FORMATS for predefined formats.
+ # You can also add your own formats to the DATE_FORMATS constant and use them with this method.
+ #
+ # This method is also aliased as <tt>to_s</tt>.
+ #
+ # ==== Examples:
+ # time = Time.now # => Thu Jan 18 06:10:17 CST 2007
+ #
+ # time.to_formatted_s(:time) # => "06:10:17"
+ # time.to_s(:time) # => "06:10:17"
+ #
+ # time.to_formatted_s(:db) # => "2007-01-18 06:10:17"
+ # time.to_formatted_s(:short) # => "18 Jan 06:10"
+ # time.to_formatted_s(:long) # => "January 18, 2007 06:10"
+ # time.to_formatted_s(:long_ordinal) # => "January 18th, 2007 06:10"
+ # time.to_formatted_s(:rfc822) # => "Thu, 18 Jan 2007 06:10:17 -0600"
+ def to_formatted_s(format = :default)
+ if formatter = DATE_FORMATS[format]
+ if formatter.respond_to?(:call)
+ formatter.call(self).to_s
+ else
+ strftime(formatter)
+ end
+ else
+ to_default_s
+ end
+ end
+
+ # Convert a Time object to a Date, dropping hour, minute, and second precision.
+ #
+ # ==== Examples
+ # my_time = Time.now
+ # # => Mon Nov 12 22:59:51 -0500 2007
+ #
+ # my_time.to_date
+ # #=> Mon, 12 Nov 2007
+ #
+ # your_time = Time.parse("1/13/2009 1:13:03 P.M.")
+ # # => Tue Jan 13 13:13:03 -0500 2009
+ #
+ # your_time.to_date
+ # # => Tue, 13 Jan 2009
+ def to_date
+ ::Date.new(year, month, day)
+ end
+
+ # A method to keep Time, Date and DateTime instances interchangeable on conversions.
+ # In this case, it simply returns +self+.
+ def to_time
+ self
+ end
+
+ # Converts a Time instance to a Ruby DateTime instance, preserving UTC offset.
+ #
+ # ==== Examples
+ # my_time = Time.now
+ # # => Mon Nov 12 23:04:21 -0500 2007
+ #
+ # my_time.to_datetime
+ # # => Mon, 12 Nov 2007 23:04:21 -0500
+ #
+ # your_time = Time.parse("1/13/2009 1:13:03 P.M.")
+ # # => Tue Jan 13 13:13:03 -0500 2009
+ #
+ # your_time.to_datetime
+ # # => Tue, 13 Jan 2009 13:13:03 -0500
+ def to_datetime
+ ::DateTime.civil(year, month, day, hour, min, sec, Rational(utc_offset, 86400))
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/dependencies.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/dependencies.rb
new file mode 100644
index 000000000..6a5cfbf2e
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/dependencies.rb
@@ -0,0 +1,540 @@
+require 'set'
+require 'active_support/core_ext/module/attribute_accessors'
+require 'active_support/core_ext/load_error'
+require 'active_support/core_ext/kernel'
+
+module Dependencies #:nodoc:
+ extend self
+
+ # Should we turn on Ruby warnings on the first load of dependent files?
+ mattr_accessor :warnings_on_first_load
+ self.warnings_on_first_load = false
+
+ # All files ever loaded.
+ mattr_accessor :history
+ self.history = Set.new
+
+ # All files currently loaded.
+ mattr_accessor :loaded
+ self.loaded = Set.new
+
+ # Should we load files or require them?
+ mattr_accessor :mechanism
+ self.mechanism = :load
+
+ # The set of directories from which we may automatically load files. Files
+ # under these directories will be reloaded on each request in development mode,
+ # unless the directory also appears in load_once_paths.
+ mattr_accessor :load_paths
+ self.load_paths = []
+
+ # The set of directories from which automatically loaded constants are loaded
+ # only once. All directories in this set must also be present in +load_paths+.
+ mattr_accessor :load_once_paths
+ self.load_once_paths = []
+
+ # An array of qualified constant names that have been loaded. Adding a name to
+ # this array will cause it to be unloaded the next time Dependencies are cleared.
+ mattr_accessor :autoloaded_constants
+ self.autoloaded_constants = []
+
+ # An array of constant names that need to be unloaded on every request. Used
+ # to allow arbitrary constants to be marked for unloading.
+ mattr_accessor :explicitly_unloadable_constants
+ self.explicitly_unloadable_constants = []
+
+ # Set to true to enable logging of const_missing and file loads
+ mattr_accessor :log_activity
+ self.log_activity = false
+
+ # An internal stack used to record which constants are loaded by any block.
+ mattr_accessor :constant_watch_stack
+ self.constant_watch_stack = []
+
+ def load?
+ mechanism == :load
+ end
+
+ def depend_on(file_name, swallow_load_errors = false)
+ path = search_for_file(file_name)
+ require_or_load(path || file_name)
+ rescue LoadError
+ raise unless swallow_load_errors
+ end
+
+ def associate_with(file_name)
+ depend_on(file_name, true)
+ end
+
+ def clear
+ log_call
+ loaded.clear
+ remove_unloadable_constants!
+ end
+
+ def require_or_load(file_name, const_path = nil)
+ log_call file_name, const_path
+ file_name = $1 if file_name =~ /^(.*)\.rb$/
+ expanded = File.expand_path(file_name)
+ return if loaded.include?(expanded)
+
+ # Record that we've seen this file *before* loading it to avoid an
+ # infinite loop with mutual dependencies.
+ loaded << expanded
+
+ if load?
+ log "loading #{file_name}"
+ begin
+ # Enable warnings iff this file has not been loaded before and
+ # warnings_on_first_load is set.
+ load_args = ["#{file_name}.rb"]
+ load_args << const_path unless const_path.nil?
+
+ if !warnings_on_first_load or history.include?(expanded)
+ result = load_file(*load_args)
+ else
+ enable_warnings { result = load_file(*load_args) }
+ end
+ rescue Exception
+ loaded.delete expanded
+ raise
+ end
+ else
+ log "requiring #{file_name}"
+ result = require file_name
+ end
+
+ # Record history *after* loading so first load gets warnings.
+ history << expanded
+ return result
+ end
+
+ # Is the provided constant path defined?
+ def qualified_const_defined?(path)
+ raise NameError, "#{path.inspect} is not a valid constant name!" unless
+ /^(::)?([A-Z]\w*)(::[A-Z]\w*)*$/ =~ path
+
+ names = path.to_s.split('::')
+ names.shift if names.first.empty?
+
+ # We can't use defined? because it will invoke const_missing for the parent
+ # of the name we are checking.
+ names.inject(Object) do |mod, name|
+ return false unless mod.const_defined? name
+ mod.const_get name
+ end
+ return true
+ end
+
+ # Given +path+, a filesystem path to a ruby file, return an array of constant
+ # paths which would cause Dependencies to attempt to load this file.
+ #
+ def loadable_constants_for_path(path, bases = load_paths)
+ path = $1 if path =~ /\A(.*)\.rb\Z/
+ expanded_path = File.expand_path(path)
+
+ bases.collect do |root|
+ expanded_root = File.expand_path(root)
+ next unless %r{\A#{Regexp.escape(expanded_root)}(/|\\)} =~ expanded_path
+
+ nesting = expanded_path[(expanded_root.size)..-1]
+ nesting = nesting[1..-1] if nesting && nesting[0] == ?/
+ next if nesting.blank?
+
+ [
+ nesting.camelize,
+ # Special case: application.rb might define ApplicationControlller.
+ ('ApplicationController' if nesting == 'application')
+ ]
+ end.flatten.compact.uniq
+ end
+
+ # Search for a file in load_paths matching the provided suffix.
+ def search_for_file(path_suffix)
+ path_suffix = path_suffix + '.rb' unless path_suffix.ends_with? '.rb'
+ load_paths.each do |root|
+ path = File.join(root, path_suffix)
+ return path if File.file? path
+ end
+ nil # Gee, I sure wish we had first_match ;-)
+ end
+
+ # Does the provided path_suffix correspond to an autoloadable module?
+ # Instead of returning a boolean, the autoload base for this module is returned.
+ def autoloadable_module?(path_suffix)
+ load_paths.each do |load_path|
+ return load_path if File.directory? File.join(load_path, path_suffix)
+ end
+ nil
+ end
+
+ def load_once_path?(path)
+ load_once_paths.any? { |base| path.starts_with? base }
+ end
+
+ # Attempt to autoload the provided module name by searching for a directory
+ # matching the expect path suffix. If found, the module is created and assigned
+ # to +into+'s constants with the name +const_name+. Provided that the directory
+ # was loaded from a reloadable base path, it is added to the set of constants
+ # that are to be unloaded.
+ def autoload_module!(into, const_name, qualified_name, path_suffix)
+ return nil unless base_path = autoloadable_module?(path_suffix)
+ mod = Module.new
+ into.const_set const_name, mod
+ autoloaded_constants << qualified_name unless load_once_paths.include?(base_path)
+ return mod
+ end
+
+ # Load the file at the provided path. +const_paths+ is a set of qualified
+ # constant names. When loading the file, Dependencies will watch for the
+ # addition of these constants. Each that is defined will be marked as
+ # autoloaded, and will be removed when Dependencies.clear is next called.
+ #
+ # If the second parameter is left off, then Dependencies will construct a set
+ # of names that the file at +path+ may define. See
+ # +loadable_constants_for_path+ for more details.
+ def load_file(path, const_paths = loadable_constants_for_path(path))
+ log_call path, const_paths
+ const_paths = [const_paths].compact unless const_paths.is_a? Array
+ parent_paths = const_paths.collect { |const_path| /(.*)::[^:]+\Z/ =~ const_path ? $1 : :Object }
+
+ result = nil
+ newly_defined_paths = new_constants_in(*parent_paths) do
+ result = load_without_new_constant_marking path
+ end
+
+ autoloaded_constants.concat newly_defined_paths unless load_once_path?(path)
+ autoloaded_constants.uniq!
+ log "loading #{path} defined #{newly_defined_paths * ', '}" unless newly_defined_paths.empty?
+ return result
+ end
+
+ # Return the constant path for the provided parent and constant name.
+ def qualified_name_for(mod, name)
+ mod_name = to_constant_name mod
+ (%w(Object Kernel).include? mod_name) ? name.to_s : "#{mod_name}::#{name}"
+ end
+
+ # Load the constant named +const_name+ which is missing from +from_mod+. If
+ # it is not possible to load the constant into from_mod, try its parent module
+ # using const_missing.
+ def load_missing_constant(from_mod, const_name)
+ log_call from_mod, const_name
+ if from_mod == Kernel
+ if ::Object.const_defined?(const_name)
+ log "Returning Object::#{const_name} for Kernel::#{const_name}"
+ return ::Object.const_get(const_name)
+ else
+ log "Substituting Object for Kernel"
+ from_mod = Object
+ end
+ end
+
+ # If we have an anonymous module, all we can do is attempt to load from Object.
+ from_mod = Object if from_mod.name.blank?
+
+ unless qualified_const_defined?(from_mod.name) && from_mod.name.constantize.object_id == from_mod.object_id
+ raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!"
+ end
+
+ raise ArgumentError, "#{from_mod} is not missing constant #{const_name}!" if from_mod.const_defined?(const_name)
+
+ qualified_name = qualified_name_for from_mod, const_name
+ path_suffix = qualified_name.underscore
+ name_error = NameError.new("uninitialized constant #{qualified_name}")
+
+ file_path = search_for_file(path_suffix)
+ if file_path && ! loaded.include?(File.expand_path(file_path)) # We found a matching file to load
+ require_or_load file_path
+ raise LoadError, "Expected #{file_path} to define #{qualified_name}" unless from_mod.const_defined?(const_name)
+ return from_mod.const_get(const_name)
+ elsif mod = autoload_module!(from_mod, const_name, qualified_name, path_suffix)
+ return mod
+ elsif (parent = from_mod.parent) && parent != from_mod &&
+ ! from_mod.parents.any? { |p| p.const_defined?(const_name) }
+ # If our parents do not have a constant named +const_name+ then we are free
+ # to attempt to load upwards. If they do have such a constant, then this
+ # const_missing must be due to from_mod::const_name, which should not
+ # return constants from from_mod's parents.
+ begin
+ return parent.const_missing(const_name)
+ rescue NameError => e
+ raise unless e.missing_name? qualified_name_for(parent, const_name)
+ raise name_error
+ end
+ else
+ raise name_error
+ end
+ end
+
+ # Remove the constants that have been autoloaded, and those that have been
+ # marked for unloading.
+ def remove_unloadable_constants!
+ autoloaded_constants.each { |const| remove_constant const }
+ autoloaded_constants.clear
+ explicitly_unloadable_constants.each { |const| remove_constant const }
+ end
+
+ # Determine if the given constant has been automatically loaded.
+ def autoloaded?(desc)
+ # No name => anonymous module.
+ return false if desc.is_a?(Module) && desc.name.blank?
+ name = to_constant_name desc
+ return false unless qualified_const_defined? name
+ return autoloaded_constants.include?(name)
+ end
+
+ # Will the provided constant descriptor be unloaded?
+ def will_unload?(const_desc)
+ autoloaded?(desc) ||
+ explicitly_unloadable_constants.include?(to_constant_name(const_desc))
+ end
+
+ # Mark the provided constant name for unloading. This constant will be
+ # unloaded on each request, not just the next one.
+ def mark_for_unload(const_desc)
+ name = to_constant_name const_desc
+ if explicitly_unloadable_constants.include? name
+ return false
+ else
+ explicitly_unloadable_constants << name
+ return true
+ end
+ end
+
+ # Run the provided block and detect the new constants that were loaded during
+ # its execution. Constants may only be regarded as 'new' once -- so if the
+ # block calls +new_constants_in+ again, then the constants defined within the
+ # inner call will not be reported in this one.
+ #
+ # If the provided block does not run to completion, and instead raises an
+ # exception, any new constants are regarded as being only partially defined
+ # and will be removed immediately.
+ def new_constants_in(*descs)
+ log_call(*descs)
+
+ # Build the watch frames. Each frame is a tuple of
+ # [module_name_as_string, constants_defined_elsewhere]
+ watch_frames = descs.collect do |desc|
+ if desc.is_a? Module
+ mod_name = desc.name
+ initial_constants = desc.local_constants
+ elsif desc.is_a?(String) || desc.is_a?(Symbol)
+ mod_name = desc.to_s
+
+ # Handle the case where the module has yet to be defined.
+ initial_constants = if qualified_const_defined?(mod_name)
+ mod_name.constantize.local_constants
+ else
+ []
+ end
+ else
+ raise Argument, "#{desc.inspect} does not describe a module!"
+ end
+
+ [mod_name, initial_constants]
+ end
+
+ constant_watch_stack.concat watch_frames
+
+ aborting = true
+ begin
+ yield # Now yield to the code that is to define new constants.
+ aborting = false
+ ensure
+ # Find the new constants.
+ new_constants = watch_frames.collect do |mod_name, prior_constants|
+ # Module still doesn't exist? Treat it as if it has no constants.
+ next [] unless qualified_const_defined?(mod_name)
+
+ mod = mod_name.constantize
+ next [] unless mod.is_a? Module
+ new_constants = mod.local_constants - prior_constants
+
+ # Make sure no other frames takes credit for these constants.
+ constant_watch_stack.each do |frame_name, constants|
+ constants.concat new_constants if frame_name == mod_name
+ end
+
+ new_constants.collect do |suffix|
+ mod_name == "Object" ? suffix : "#{mod_name}::#{suffix}"
+ end
+ end.flatten
+
+ log "New constants: #{new_constants * ', '}"
+
+ if aborting
+ log "Error during loading, removing partially loaded constants "
+ new_constants.each { |name| remove_constant name }
+ new_constants.clear
+ end
+ end
+
+ return new_constants
+ ensure
+ # Remove the stack frames that we added.
+ if defined?(watch_frames) && ! watch_frames.empty?
+ frame_ids = watch_frames.collect(&:object_id)
+ constant_watch_stack.delete_if do |watch_frame|
+ frame_ids.include? watch_frame.object_id
+ end
+ end
+ end
+
+ class LoadingModule #:nodoc:
+ # Old style environment.rb referenced this method directly. Please note, it doesn't
+ # actually *do* anything any more.
+ def self.root(*args)
+ if defined?(RAILS_DEFAULT_LOGGER)
+ RAILS_DEFAULT_LOGGER.warn "Your environment.rb uses the old syntax, it may not continue to work in future releases."
+ RAILS_DEFAULT_LOGGER.warn "For upgrade instructions please see: http://manuals.rubyonrails.com/read/book/19"
+ end
+ end
+ end
+
+ # Convert the provided const desc to a qualified constant name (as a string).
+ # A module, class, symbol, or string may be provided.
+ def to_constant_name(desc) #:nodoc:
+ name = case desc
+ when String then desc.starts_with?('::') ? desc[2..-1] : desc
+ when Symbol then desc.to_s
+ when Module
+ raise ArgumentError, "Anonymous modules have no name to be referenced by" if desc.name.blank?
+ desc.name
+ else raise TypeError, "Not a valid constant descriptor: #{desc.inspect}"
+ end
+ end
+
+ def remove_constant(const) #:nodoc:
+ return false unless qualified_const_defined? const
+
+ const = $1 if /\A::(.*)\Z/ =~ const.to_s
+ names = const.to_s.split('::')
+ if names.size == 1 # It's under Object
+ parent = Object
+ else
+ parent = (names[0..-2] * '::').constantize
+ end
+
+ log "removing constant #{const}"
+ parent.instance_eval { remove_const names.last }
+ return true
+ end
+
+protected
+ def log_call(*args)
+ arg_str = args.collect(&:inspect) * ', '
+ /in `([a-z_\?\!]+)'/ =~ caller(1).first
+ selector = $1 || '<unknown>'
+ log "called #{selector}(#{arg_str})"
+ end
+
+ def log(msg)
+ if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER && log_activity
+ RAILS_DEFAULT_LOGGER.debug "Dependencies: #{msg}"
+ end
+ end
+
+end
+
+Object.instance_eval do
+ define_method(:require_or_load) { |file_name| Dependencies.require_or_load(file_name) } unless Object.respond_to?(:require_or_load)
+ define_method(:require_dependency) { |file_name| Dependencies.depend_on(file_name) } unless Object.respond_to?(:require_dependency)
+ define_method(:require_association) { |file_name| Dependencies.associate_with(file_name) } unless Object.respond_to?(:require_association)
+end
+
+class Module #:nodoc:
+ # Rename the original handler so we can chain it to the new one
+ alias :rails_original_const_missing :const_missing
+
+ # Use const_missing to autoload associations so we don't have to
+ # require_association when using single-table inheritance.
+ def const_missing(class_id)
+ Dependencies.load_missing_constant self, class_id
+ end
+
+ def unloadable(const_desc = self)
+ super(const_desc)
+ end
+
+end
+
+class Class
+ def const_missing(const_name)
+ if [Object, Kernel].include?(self) || parent == self
+ super
+ else
+ begin
+ begin
+ Dependencies.load_missing_constant self, const_name
+ rescue NameError
+ parent.send :const_missing, const_name
+ end
+ rescue NameError => e
+ # Make sure that the name we are missing is the one that caused the error
+ parent_qualified_name = Dependencies.qualified_name_for parent, const_name
+ raise unless e.missing_name? parent_qualified_name
+ qualified_name = Dependencies.qualified_name_for self, const_name
+ raise NameError.new("uninitialized constant #{qualified_name}").copy_blame!(e)
+ end
+ end
+ end
+end
+
+class Object
+
+ alias_method :load_without_new_constant_marking, :load
+
+ def load(file, *extras) #:nodoc:
+ Dependencies.new_constants_in(Object) { super(file, *extras) }
+ rescue Exception => exception # errors from loading file
+ exception.blame_file! file
+ raise
+ end
+
+ def require(file, *extras) #:nodoc:
+ Dependencies.new_constants_in(Object) { super(file, *extras) }
+ rescue Exception => exception # errors from required file
+ exception.blame_file! file
+ raise
+ end
+
+ # Mark the given constant as unloadable. Unloadable constants are removed each
+ # time dependencies are cleared.
+ #
+ # Note that marking a constant for unloading need only be done once. Setup
+ # or init scripts may list each unloadable constant that may need unloading;
+ # each constant will be removed for every subsequent clear, as opposed to for
+ # the first clear.
+ #
+ # The provided constant descriptor may be a (non-anonymous) module or class,
+ # or a qualified constant name as a string or symbol.
+ #
+ # Returns true if the constant was not previously marked for unloading, false
+ # otherwise.
+ def unloadable(const_desc)
+ Dependencies.mark_for_unload const_desc
+ end
+
+end
+
+# Add file-blaming to exceptions
+class Exception #:nodoc:
+ def blame_file!(file)
+ (@blamed_files ||= []).unshift file
+ end
+
+ def blamed_files
+ @blamed_files ||= []
+ end
+
+ def describe_blame
+ return nil if blamed_files.empty?
+ "This error occurred while loading the following files:\n #{blamed_files.join "\n "}"
+ end
+
+ def copy_blame!(exc)
+ @blamed_files = exc.blamed_files.clone
+ self
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/deprecation.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/deprecation.rb
new file mode 100644
index 000000000..c9f1884da
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/deprecation.rb
@@ -0,0 +1,204 @@
+require 'yaml'
+
+module ActiveSupport
+ module Deprecation #:nodoc:
+ mattr_accessor :debug
+ self.debug = false
+
+ # Choose the default warn behavior according to RAILS_ENV.
+ # Ignore deprecation warnings in production.
+ DEFAULT_BEHAVIORS = {
+ 'test' => Proc.new { |message, callstack|
+ $stderr.puts(message)
+ $stderr.puts callstack.join("\n ") if debug
+ },
+ 'development' => Proc.new { |message, callstack|
+ logger = defined?(::RAILS_DEFAULT_LOGGER) ? ::RAILS_DEFAULT_LOGGER : Logger.new($stderr)
+ logger.warn message
+ logger.debug callstack.join("\n ") if debug
+ }
+ }
+
+ class << self
+ def warn(message = nil, callstack = caller)
+ behavior.call(deprecation_message(callstack, message), callstack) if behavior && !silenced?
+ end
+
+ def default_behavior
+ if defined?(RAILS_ENV)
+ DEFAULT_BEHAVIORS[RAILS_ENV.to_s]
+ else
+ DEFAULT_BEHAVIORS['test']
+ end
+ end
+
+ # Have deprecations been silenced?
+ def silenced?
+ @silenced = false unless defined?(@silenced)
+ @silenced
+ end
+
+ # Silence deprecation warnings within the block.
+ def silence
+ old_silenced, @silenced = @silenced, true
+ yield
+ ensure
+ @silenced = old_silenced
+ end
+
+ attr_writer :silenced
+
+
+ private
+ def deprecation_message(callstack, message = nil)
+ message ||= "You are using deprecated behavior which will be removed from Rails 2.0."
+ "DEPRECATION WARNING: #{message} See http://www.rubyonrails.org/deprecation for details. #{deprecation_caller_message(callstack)}"
+ end
+
+ def deprecation_caller_message(callstack)
+ file, line, method = extract_callstack(callstack)
+ if file
+ if line && method
+ "(called from #{method} at #{file}:#{line})"
+ else
+ "(called from #{file}:#{line})"
+ end
+ end
+ end
+
+ def extract_callstack(callstack)
+ if md = callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/)
+ md.captures
+ else
+ callstack.first
+ end
+ end
+ end
+
+ # Behavior is a block that takes a message argument.
+ mattr_accessor :behavior
+ self.behavior = default_behavior
+
+ # Warnings are not silenced by default.
+ self.silenced = false
+
+ module ClassMethods #:nodoc:
+ # Declare that a method has been deprecated.
+ def deprecate(*method_names)
+ options = method_names.extract_options!
+ method_names = method_names + options.keys
+ method_names.each do |method_name|
+ alias_method_chain(method_name, :deprecation) do |target, punctuation|
+ class_eval(<<-EOS, __FILE__, __LINE__)
+ def #{target}_with_deprecation#{punctuation}(*args, &block)
+ ::ActiveSupport::Deprecation.warn(self.class.deprecated_method_warning(:#{method_name}, #{options[method_name].inspect}), caller)
+ #{target}_without_deprecation#{punctuation}(*args, &block)
+ end
+ EOS
+ end
+ end
+ end
+
+ def deprecated_method_warning(method_name, message=nil)
+ warning = "#{method_name} is deprecated and will be removed from Rails #{deprecation_horizon}"
+ case message
+ when Symbol then "#{warning} (use #{message} instead)"
+ when String then "#{warning} (#{message})"
+ else warning
+ end
+ end
+
+ def deprecation_horizon
+ '2.0'
+ end
+ end
+
+ module Assertions #:nodoc:
+ def assert_deprecated(match = nil, &block)
+ result, warnings = collect_deprecations(&block)
+ assert !warnings.empty?, "Expected a deprecation warning within the block but received none"
+ if match
+ match = Regexp.new(Regexp.escape(match)) unless match.is_a?(Regexp)
+ assert warnings.any? { |w| w =~ match }, "No deprecation warning matched #{match}: #{warnings.join(', ')}"
+ end
+ result
+ end
+
+ def assert_not_deprecated(&block)
+ result, deprecations = collect_deprecations(&block)
+ assert deprecations.empty?, "Expected no deprecation warning within the block but received #{deprecations.size}: \n #{deprecations * "\n "}"
+ result
+ end
+
+ private
+ def collect_deprecations
+ old_behavior = ActiveSupport::Deprecation.behavior
+ deprecations = []
+ ActiveSupport::Deprecation.behavior = Proc.new do |message, callstack|
+ deprecations << message
+ end
+ result = yield
+ [result, deprecations]
+ ensure
+ ActiveSupport::Deprecation.behavior = old_behavior
+ end
+ end
+
+ # Stand-in for @request, @attributes, @params, etc which emits deprecation
+ # warnings on any method call (except #inspect).
+ class DeprecatedInstanceVariableProxy #:nodoc:
+ silence_warnings do
+ instance_methods.each { |m| undef_method m unless m =~ /^__/ }
+ end
+
+ def initialize(instance, method, var = "@#{method}")
+ @instance, @method, @var = instance, method, var
+ end
+
+ # Don't give a deprecation warning on inspect since test/unit and error
+ # logs rely on it for diagnostics.
+ def inspect
+ target.inspect
+ end
+
+ private
+ def method_missing(called, *args, &block)
+ warn caller, called, args
+ target.__send__(called, *args, &block)
+ end
+
+ def target
+ @instance.__send__(@method)
+ end
+
+ def warn(callstack, called, args)
+ ActiveSupport::Deprecation.warn("#{@var} is deprecated! Call #{@method}.#{called} instead of #{@var}.#{called}. Args: #{args.inspect}", callstack)
+ end
+ end
+ end
+end
+
+class Module
+ include ActiveSupport::Deprecation::ClassMethods
+end
+
+require 'test/unit/error'
+
+module Test
+ module Unit
+ class TestCase
+ include ActiveSupport::Deprecation::Assertions
+ end
+
+ class Error # :nodoc:
+ # Silence warnings when reporting test errors.
+ def message_with_silenced_deprecation
+ ActiveSupport::Deprecation.silence do
+ message_without_silenced_deprecation
+ end
+ end
+
+ alias_method_chain :message, :silenced_deprecation
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/duration.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/duration.rb
new file mode 100644
index 000000000..82b38e79b
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/duration.rb
@@ -0,0 +1,96 @@
+module ActiveSupport
+ # Provides accurate date and time measurements using Date#advance and
+ # Time#advance, respectively. It mainly supports the methods on Numeric,
+ # such as in this example:
+ #
+ # 1.month.ago # equivalent to Time.now.advance(:months => -1)
+ class Duration < BasicObject
+ attr_accessor :value, :parts
+
+ def initialize(value, parts) #:nodoc:
+ @value, @parts = value, parts
+ end
+
+ # Adds another Duration or a Numeric to this Duration. Numeric values
+ # are treated as seconds.
+ def +(other)
+ if Duration === other
+ Duration.new(value + other.value, @parts + other.parts)
+ else
+ Duration.new(value + other, @parts + [[:seconds, other]])
+ end
+ end
+
+ # Subtracts another Duration or a Numeric from this Duration. Numeric
+ # values are treated as seconds.
+ def -(other)
+ self + (-other)
+ end
+
+ def -@ #:nodoc:
+ Duration.new(-value, parts.map { |type,number| [type, -number] })
+ end
+
+ def is_a?(klass) #:nodoc:
+ klass == Duration || super
+ end
+
+ # Returns true if <tt>other</tt> is also a Duration instance with the
+ # same <tt>value</tt>, or if <tt>other == value</tt>.
+ def ==(other)
+ if Duration === other
+ other.value == value
+ else
+ other == value
+ end
+ end
+
+ def self.===(other) #:nodoc:
+ other.is_a?(Duration) rescue super
+ end
+
+ # Calculates a new Time or Date that is as far in the future
+ # as this Duration represents.
+ def since(time = ::Time.now)
+ sum(1, time)
+ end
+ alias :from_now :since
+
+ # Calculates a new Time or Date that is as far in the past
+ # as this Duration represents.
+ def ago(time = ::Time.now)
+ sum(-1, time)
+ end
+ alias :until :ago
+
+ def inspect #:nodoc:
+ consolidated = parts.inject(::Hash.new(0)) { |h,part| h[part.first] += part.last; h }
+ [:years, :months, :days, :minutes, :seconds].map do |length|
+ n = consolidated[length]
+ "#{n} #{n == 1 ? length.to_s.singularize : length.to_s}" if n.nonzero?
+ end.compact.to_sentence
+ end
+
+ protected
+
+ def sum(sign, time = ::Time.now) #:nodoc:
+ parts.inject(time) do |t,(type,number)|
+ if t.acts_like?(:time) || t.acts_like?(:date)
+ if type == :seconds
+ t.since(sign * number)
+ else
+ t.advance(type => sign * number)
+ end
+ else
+ raise ArgumentError, "expected a time or date, got #{time.inspect}"
+ end
+ end
+ end
+
+ private
+
+ def method_missing(method, *args, &block) #:nodoc:
+ value.send(method, *args)
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/inflections.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/inflections.rb
new file mode 100644
index 000000000..967722c2b
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/inflections.rb
@@ -0,0 +1,53 @@
+Inflector.inflections do |inflect|
+ inflect.plural(/$/, 's')
+ inflect.plural(/s$/i, 's')
+ inflect.plural(/(ax|test)is$/i, '\1es')
+ inflect.plural(/(octop|vir)us$/i, '\1i')
+ inflect.plural(/(alias|status)$/i, '\1es')
+ inflect.plural(/(bu)s$/i, '\1ses')
+ inflect.plural(/(buffal|tomat)o$/i, '\1oes')
+ inflect.plural(/([ti])um$/i, '\1a')
+ inflect.plural(/sis$/i, 'ses')
+ inflect.plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
+ inflect.plural(/(hive)$/i, '\1s')
+ inflect.plural(/([^aeiouy]|qu)y$/i, '\1ies')
+ inflect.plural(/(x|ch|ss|sh)$/i, '\1es')
+ inflect.plural(/(matr|vert|ind)(?:ix|ex)$/i, '\1ices')
+ inflect.plural(/([m|l])ouse$/i, '\1ice')
+ inflect.plural(/^(ox)$/i, '\1en')
+ inflect.plural(/(quiz)$/i, '\1zes')
+
+ inflect.singular(/s$/i, '')
+ inflect.singular(/(n)ews$/i, '\1ews')
+ inflect.singular(/([ti])a$/i, '\1um')
+ inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, '\1\2sis')
+ inflect.singular(/(^analy)ses$/i, '\1sis')
+ inflect.singular(/([^f])ves$/i, '\1fe')
+ inflect.singular(/(hive)s$/i, '\1')
+ inflect.singular(/(tive)s$/i, '\1')
+ inflect.singular(/([lr])ves$/i, '\1f')
+ inflect.singular(/([^aeiouy]|qu)ies$/i, '\1y')
+ inflect.singular(/(s)eries$/i, '\1eries')
+ inflect.singular(/(m)ovies$/i, '\1ovie')
+ inflect.singular(/(x|ch|ss|sh)es$/i, '\1')
+ inflect.singular(/([m|l])ice$/i, '\1ouse')
+ inflect.singular(/(bus)es$/i, '\1')
+ inflect.singular(/(o)es$/i, '\1')
+ inflect.singular(/(shoe)s$/i, '\1')
+ inflect.singular(/(cris|ax|test)es$/i, '\1is')
+ inflect.singular(/(octop|vir)i$/i, '\1us')
+ inflect.singular(/(alias|status)es$/i, '\1')
+ inflect.singular(/^(ox)en/i, '\1')
+ inflect.singular(/(vert|ind)ices$/i, '\1ex')
+ inflect.singular(/(matr)ices$/i, '\1ix')
+ inflect.singular(/(quiz)zes$/i, '\1')
+
+ inflect.irregular('person', 'people')
+ inflect.irregular('man', 'men')
+ inflect.irregular('child', 'children')
+ inflect.irregular('sex', 'sexes')
+ inflect.irregular('move', 'moves')
+ inflect.irregular('cow', 'kine')
+
+ inflect.uncountable(%w(equipment information rice money species series fish sheep))
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/inflector.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/inflector.rb
new file mode 100644
index 000000000..baa342f66
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/inflector.rb
@@ -0,0 +1,282 @@
+require 'singleton'
+
+# The Inflector transforms words from singular to plural, class names to table names, modularized class names to ones without,
+# and class names to foreign keys. The default inflections for pluralization, singularization, and uncountable words are kept
+# in inflections.rb.
+module Inflector
+ # A singleton instance of this class is yielded by Inflector.inflections, which can then be used to specify additional
+ # inflection rules. Examples:
+ #
+ # Inflector.inflections do |inflect|
+ # inflect.plural /^(ox)$/i, '\1\2en'
+ # inflect.singular /^(ox)en/i, '\1'
+ #
+ # inflect.irregular 'octopus', 'octopi'
+ #
+ # inflect.uncountable "equipment"
+ # end
+ #
+ # New rules are added at the top. So in the example above, the irregular rule for octopus will now be the first of the
+ # pluralization and singularization rules that is runs. This guarantees that your rules run before any of the rules that may
+ # already have been loaded.
+ class Inflections
+ include Singleton
+
+ attr_reader :plurals, :singulars, :uncountables
+
+ def initialize
+ @plurals, @singulars, @uncountables = [], [], []
+ end
+
+ # Specifies a new pluralization rule and its replacement. The rule can either be a string or a regular expression.
+ # The replacement should always be a string that may include references to the matched data from the rule.
+ def plural(rule, replacement)
+ @plurals.insert(0, [rule, replacement])
+ end
+
+ # Specifies a new singularization rule and its replacement. The rule can either be a string or a regular expression.
+ # The replacement should always be a string that may include references to the matched data from the rule.
+ def singular(rule, replacement)
+ @singulars.insert(0, [rule, replacement])
+ end
+
+ # Specifies a new irregular that applies to both pluralization and singularization at the same time. This can only be used
+ # for strings, not regular expressions. You simply pass the irregular in singular and plural form.
+ #
+ # Examples:
+ # irregular 'octopus', 'octopi'
+ # irregular 'person', 'people'
+ def irregular(singular, plural)
+ if singular[0,1].upcase == plural[0,1].upcase
+ plural(Regexp.new("(#{singular[0,1]})#{singular[1..-1]}$", "i"), '\1' + plural[1..-1])
+ singular(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + singular[1..-1])
+ else
+ plural(Regexp.new("#{singular[0,1].upcase}(?i)#{singular[1..-1]}$"), plural[0,1].upcase + plural[1..-1])
+ plural(Regexp.new("#{singular[0,1].downcase}(?i)#{singular[1..-1]}$"), plural[0,1].downcase + plural[1..-1])
+ singular(Regexp.new("#{plural[0,1].upcase}(?i)#{plural[1..-1]}$"), singular[0,1].upcase + singular[1..-1])
+ singular(Regexp.new("#{plural[0,1].downcase}(?i)#{plural[1..-1]}$"), singular[0,1].downcase + singular[1..-1])
+ end
+ end
+
+ # Add uncountable words that shouldn't be attempted inflected.
+ #
+ # Examples:
+ # uncountable "money"
+ # uncountable "money", "information"
+ # uncountable %w( money information rice )
+ def uncountable(*words)
+ (@uncountables << words).flatten!
+ end
+
+ # Clears the loaded inflections within a given scope (default is :all). Give the scope as a symbol of the inflection type,
+ # the options are: :plurals, :singulars, :uncountables
+ #
+ # Examples:
+ # clear :all
+ # clear :plurals
+ def clear(scope = :all)
+ case scope
+ when :all
+ @plurals, @singulars, @uncountables = [], [], []
+ else
+ instance_variable_set "@#{scope}", []
+ end
+ end
+ end
+
+ extend self
+
+ def inflections
+ if block_given?
+ yield Inflections.instance
+ else
+ Inflections.instance
+ end
+ end
+
+ # Returns the plural form of the word in the string.
+ #
+ # Examples
+ # "post".pluralize #=> "posts"
+ # "octopus".pluralize #=> "octopi"
+ # "sheep".pluralize #=> "sheep"
+ # "words".pluralize #=> "words"
+ # "the blue mailman".pluralize #=> "the blue mailmen"
+ # "CamelOctopus".pluralize #=> "CamelOctopi"
+ def pluralize(word)
+ result = word.to_s.dup
+
+ if word.empty? || inflections.uncountables.include?(result.downcase)
+ result
+ else
+ inflections.plurals.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
+ result
+ end
+ end
+
+ # The reverse of pluralize, returns the singular form of a word in a string.
+ #
+ # Examples
+ # "posts".singularize #=> "post"
+ # "octopi".singularize #=> "octopus"
+ # "sheep".singluarize #=> "sheep"
+ # "word".singluarize #=> "word"
+ # "the blue mailmen".singularize #=> "the blue mailman"
+ # "CamelOctopi".singularize #=> "CamelOctopus"
+ def singularize(word)
+ result = word.to_s.dup
+
+ if inflections.uncountables.include?(result.downcase)
+ result
+ else
+ inflections.singulars.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
+ result
+ end
+ end
+
+ # By default, camelize converts strings to UpperCamelCase. If the argument to camelize
+ # is set to ":lower" then camelize produces lowerCamelCase.
+ #
+ # camelize will also convert '/' to '::' which is useful for converting paths to namespaces
+ #
+ # Examples
+ # "active_record".camelize #=> "ActiveRecord"
+ # "active_record".camelize(:lower) #=> "activeRecord"
+ # "active_record/errors".camelize #=> "ActiveRecord::Errors"
+ # "active_record/errors".camelize(:lower) #=> "activeRecord::Errors"
+ def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
+ if first_letter_in_uppercase
+ lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
+ else
+ lower_case_and_underscored_word.first + camelize(lower_case_and_underscored_word)[1..-1]
+ end
+ end
+
+ # Capitalizes all the words and replaces some characters in the string to create
+ # a nicer looking title. Titleize is meant for creating pretty output. It is not
+ # used in the Rails internals.
+ #
+ # titleize is also aliased as as titlecase
+ #
+ # Examples
+ # "man from the boondocks".titleize #=> "Man From The Boondocks"
+ # "x-men: the last stand".titleize #=> "X Men: The Last Stand"
+ def titleize(word)
+ humanize(underscore(word)).gsub(/\b([a-z])/) { $1.capitalize }
+ end
+
+ # The reverse of +camelize+. Makes an underscored form from the expression in the string.
+ #
+ # Changes '::' to '/' to convert namespaces to paths.
+ #
+ # Examples
+ # "ActiveRecord".underscore #=> "active_record"
+ # "ActiveRecord::Errors".underscore #=> active_record/errors
+ def underscore(camel_cased_word)
+ camel_cased_word.to_s.gsub(/::/, '/').
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
+ tr("-", "_").
+ downcase
+ end
+
+ # Replaces underscores with dashes in the string.
+ #
+ # Example
+ # "puni_puni" #=> "puni-puni"
+ def dasherize(underscored_word)
+ underscored_word.gsub(/_/, '-')
+ end
+
+ # Capitalizes the first word and turns underscores into spaces and strips _id.
+ # Like titleize, this is meant for creating pretty output.
+ #
+ # Examples
+ # "employee_salary" #=> "Employee salary"
+ # "author_id" #=> "Author"
+ def humanize(lower_case_and_underscored_word)
+ lower_case_and_underscored_word.to_s.gsub(/_id$/, "").gsub(/_/, " ").capitalize
+ end
+
+ # Removes the module part from the expression in the string
+ #
+ # Examples
+ # "ActiveRecord::CoreExtensions::String::Inflections".demodulize #=> "Inflections"
+ # "Inflections".demodulize #=> "Inflections"
+ def demodulize(class_name_in_module)
+ class_name_in_module.to_s.gsub(/^.*::/, '')
+ end
+
+ # Create the name of a table like Rails does for models to table names. This method
+ # uses the pluralize method on the last word in the string.
+ #
+ # Examples
+ # "RawScaledScorer".tableize #=> "raw_scaled_scorers"
+ # "egg_and_ham".tableize #=> "egg_and_hams"
+ # "fancyCategory".tableize #=> "fancy_categories"
+ def tableize(class_name)
+ pluralize(underscore(class_name))
+ end
+
+ # Create a class name from a table name like Rails does for table names to models.
+ # Note that this returns a string and not a Class. (To convert to an actual class
+ # follow classify with constantize.)
+ #
+ # Examples
+ # "egg_and_hams".classify #=> "EggAndHam"
+ # "post".classify #=> "Post"
+ def classify(table_name)
+ # strip out any leading schema name
+ camelize(singularize(table_name.to_s.sub(/.*\./, '')))
+ end
+
+ # Creates a foreign key name from a class name.
+ # +separate_class_name_and_id_with_underscore+ sets whether
+ # the method should put '_' between the name and 'id'.
+ #
+ # Examples
+ # "Message".foreign_key #=> "message_id"
+ # "Message".foreign_key(false) #=> "messageid"
+ # "Admin::Post".foreign_key #=> "post_id"
+ def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
+ underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
+ end
+
+ # Constantize tries to find a declared constant with the name specified
+ # in the string. It raises a NameError when the name is not in CamelCase
+ # or is not initialized.
+ #
+ # Examples
+ # "Module".constantize #=> Module
+ # "Class".constantize #=> Class
+ def constantize(camel_cased_word)
+ unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ camel_cased_word
+ raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!"
+ end
+
+ Object.module_eval("::#{$1}", __FILE__, __LINE__)
+ end
+
+ # Ordinalize turns a number into an ordinal string used to denote the
+ # position in an ordered sequence such as 1st, 2nd, 3rd, 4th.
+ #
+ # Examples
+ # ordinalize(1) # => "1st"
+ # ordinalize(2) # => "2nd"
+ # ordinalize(1002) # => "1002nd"
+ # ordinalize(1003) # => "1003rd"
+ def ordinalize(number)
+ if (11..13).include?(number.to_i % 100)
+ "#{number}th"
+ else
+ case number.to_i % 10
+ when 1; "#{number}st"
+ when 2; "#{number}nd"
+ when 3; "#{number}rd"
+ else "#{number}th"
+ end
+ end
+ end
+end
+
+require File.dirname(__FILE__) + '/inflections'
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/json.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/json.rb
new file mode 100644
index 000000000..6c828293e
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/json.rb
@@ -0,0 +1,31 @@
+require 'active_support/json/encoding'
+require 'active_support/json/decoding'
+
+module ActiveSupport
+ module JSON
+ RESERVED_WORDS = %w(
+ abstract delete goto private transient
+ boolean do if protected try
+ break double implements public typeof
+ byte else import return var
+ case enum in short void
+ catch export instanceof static volatile
+ char extends int super while
+ class final interface switch with
+ const finally long synchronized
+ continue float native this
+ debugger for new throw
+ default function package throws
+ ) #:nodoc:
+
+ class << self
+ def valid_identifier?(key) #:nodoc:
+ key.to_s =~ /^[[:alpha:]_$][[:alnum:]_$]*$/ && !reserved_word?(key)
+ end
+
+ def reserved_word?(key) #:nodoc:
+ RESERVED_WORDS.include?(key.to_s)
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/json/decoding.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/json/decoding.rb
new file mode 100644
index 000000000..f24aa9e57
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/json/decoding.rb
@@ -0,0 +1,60 @@
+require 'yaml'
+require 'strscan'
+
+module ActiveSupport
+ module JSON
+ class ParseError < StandardError
+ end
+
+ class << self
+ # Converts a JSON string into a Ruby object.
+ def decode(json)
+ YAML.load(convert_json_to_yaml(json))
+ rescue ArgumentError => e
+ raise ParseError, "Invalid JSON string"
+ end
+
+ protected
+ # matches YAML-formatted dates
+ DATE_REGEX = /^\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[ \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?)?$/
+
+ # Ensure that ":" and "," are always followed by a space
+ def convert_json_to_yaml(json) #:nodoc:
+ scanner, quoting, marks, pos, times = StringScanner.new(json), false, [], nil, []
+ while scanner.scan_until(/(\\['"]|['":,\\]|\\.)/)
+ case char = scanner[1]
+ when '"', "'"
+ if !quoting
+ quoting = char
+ pos = scanner.pos
+ elsif quoting == char
+ if json[pos..scanner.pos-2] =~ DATE_REGEX
+ # found a date, track the exact positions of the quotes so we can remove them later.
+ # oh, and increment them for each current mark, each one is an extra padded space that bumps
+ # the position in the final yaml output
+ total_marks = marks.size
+ times << pos+total_marks << scanner.pos+total_marks
+ end
+ quoting = false
+ end
+ when ":",","
+ marks << scanner.pos - 1 unless quoting
+ end
+ end
+
+ if marks.empty?
+ json.gsub(/\\\//, '/')
+ else
+ # FIXME: multiple slow enumerations
+ output = ([0] + marks.map(&:succ)).
+ zip(marks + [json.length]).
+ map { |left, right| json[left..right] }.
+ join(" ")
+ times.each { |i| output[i-1] = ' ' }
+ output.gsub!(/\\\//, '/')
+ output
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/date.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/date.rb
new file mode 100644
index 000000000..853d9b868
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/date.rb
@@ -0,0 +1,5 @@
+class Date
+ def to_json(options = nil) #:nodoc:
+ %("#{strftime("%Y/%m/%d")}")
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/date_time.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/date_time.rb
new file mode 100644
index 000000000..f0b043441
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/date_time.rb
@@ -0,0 +1,5 @@
+class DateTime
+ def to_json(options = nil) #:nodoc:
+ %("#{strftime("%Y/%m/%d %H:%M:%S %z")}")
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/enumerable.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/enumerable.rb
new file mode 100644
index 000000000..720fd88f9
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/enumerable.rb
@@ -0,0 +1,12 @@
+module Enumerable
+ # Returns a JSON string representing the enumerable. Any +options+
+ # given will be passed on to its elements. For example:
+ #
+ # users = User.find(:all)
+ # users.to_json(:only => :name)
+ #
+ # will pass the <tt>:only => :name</tt> option to each user.
+ def to_json(options = {}) #:nodoc:
+ "[#{map { |value| ActiveSupport::JSON.encode(value, options) } * ', '}]"
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/false_class.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/false_class.rb
new file mode 100644
index 000000000..bf0844334
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/false_class.rb
@@ -0,0 +1,5 @@
+class FalseClass
+ def to_json(options = nil) #:nodoc:
+ 'false'
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/hash.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/hash.rb
new file mode 100644
index 000000000..774803d64
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/hash.rb
@@ -0,0 +1,50 @@
+class Hash
+ # Returns a JSON string representing the hash.
+ #
+ # Without any +options+, the returned JSON string will include all
+ # the hash keys. For example:
+ #
+ # { :name => "Konata Izumi", 'age' => 16, 1 => 2 }.to_json
+ #
+ # {"name": "Konata Izumi", 1: 2, "age": 16}
+ #
+ # The keys in the JSON string are unordered due to the nature of hashes.
+ #
+ # The <tt>:only</tt> and <tt>:except</tt> options can be used to limit the
+ # attributes included, and will accept 1 or more hash keys to include/exclude.
+ #
+ # { :name => "Konata Izumi", 'age' => 16, 1 => 2 }.to_json(:only => [:name, 'age'])
+ #
+ # {"name": "Konata Izumi", "age": 16}
+ #
+ # { :name => "Konata Izumi", 'age' => 16, 1 => 2 }.to_json(:except => 1)
+ #
+ # {"name": "Konata Izumi", "age": 16}
+ #
+ # The +options+ also filter down to any hash values. This is particularly
+ # useful for converting hashes containing ActiveRecord objects or any object
+ # that responds to options in their <tt>to_json</tt> method. For example:
+ #
+ # users = User.find(:all)
+ # { :users => users, :count => users.size }.to_json(:include => :posts)
+ #
+ # would pass the <tt>:include => :posts</tt> option to <tt>users</tt>,
+ # allowing the posts association in the User model to be converted to JSON
+ # as well.
+ def to_json(options = {}) #:nodoc:
+ hash_keys = self.keys
+
+ if options[:except]
+ hash_keys = hash_keys - Array(options[:except])
+ elsif options[:only]
+ hash_keys = hash_keys & Array(options[:only])
+ end
+
+ returning result = '{' do
+ result << hash_keys.map do |key|
+ "#{ActiveSupport::JSON.encode(key)}: #{ActiveSupport::JSON.encode(self[key], options)}"
+ end * ', '
+ result << '}'
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/nil_class.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/nil_class.rb
new file mode 100644
index 000000000..4763471ac
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/nil_class.rb
@@ -0,0 +1,5 @@
+class NilClass
+ def to_json(options = nil) #:nodoc:
+ 'null'
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/numeric.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/numeric.rb
new file mode 100644
index 000000000..38713fb36
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/numeric.rb
@@ -0,0 +1,5 @@
+class Numeric
+ def to_json(options = nil) #:nodoc:
+ to_s
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/object.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/object.rb
new file mode 100644
index 000000000..6da0d1d1c
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/object.rb
@@ -0,0 +1,6 @@
+class Object
+ # Dumps object in JSON (JavaScript Object Notation). See www.json.org for more info.
+ def to_json(options = {})
+ ActiveSupport::JSON.encode(instance_values, options)
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/regexp.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/regexp.rb
new file mode 100644
index 000000000..b6116b70b
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/regexp.rb
@@ -0,0 +1,5 @@
+class Regexp
+ def to_json(options = nil) #:nodoc:
+ inspect
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/string.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/string.rb
new file mode 100644
index 000000000..28f119066
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/string.rb
@@ -0,0 +1,30 @@
+module ActiveSupport
+ module JSON
+ module Encoding
+ ESCAPED_CHARS = {
+ "\010" => '\b',
+ "\f" => '\f',
+ "\n" => '\n',
+ "\r" => '\r',
+ "\t" => '\t',
+ '"' => '\"',
+ '\\' => '\\\\',
+ '>' => '\u003E',
+ '<' => '\u003C',
+ '&' => '\u0026'
+ }
+ end
+ end
+end
+
+class String
+ def to_json(options = nil) #:nodoc:
+ '"' + gsub(/[\010\f\n\r\t"\\><&]/) { |s|
+ ActiveSupport::JSON::Encoding::ESCAPED_CHARS[s]
+ }.gsub(/([\xC0-\xDF][\x80-\xBF]|
+ [\xE0-\xEF][\x80-\xBF]{2}|
+ [\xF0-\xF7][\x80-\xBF]{3})+/nx) { |s|
+ s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/, '\\\\u\&')
+ } + '"'
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/symbol.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/symbol.rb
new file mode 100644
index 000000000..485112f97
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/symbol.rb
@@ -0,0 +1,5 @@
+class Symbol
+ def to_json(options = {}) #:nodoc:
+ ActiveSupport::JSON.encode(to_s, options)
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/time.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/time.rb
new file mode 100644
index 000000000..8eb9ff132
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/time.rb
@@ -0,0 +1,5 @@
+class Time
+ def to_json(options = nil) #:nodoc:
+ to_datetime.to_json(options)
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/true_class.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/true_class.rb
new file mode 100644
index 000000000..037d812b3
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoders/true_class.rb
@@ -0,0 +1,5 @@
+class TrueClass
+ def to_json(options = nil) #:nodoc:
+ 'true'
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoding.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoding.rb
new file mode 100644
index 000000000..adfbfd5f7
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/json/encoding.rb
@@ -0,0 +1,38 @@
+require 'active_support/json/variable'
+
+require 'active_support/json/encoders/object' # Require explicitly for rdoc.
+Dir["#{File.dirname(__FILE__)}/encoders/**/*.rb"].each do |file|
+ basename = File.basename(file, '.rb')
+ unless basename == 'object'
+ require "active_support/json/encoders/#{basename}"
+ end
+end
+
+module ActiveSupport
+ module JSON
+ class CircularReferenceError < StandardError
+ end
+
+ class << self
+ REFERENCE_STACK_VARIABLE = :json_reference_stack #:nodoc:
+
+ # Converts a Ruby object into a JSON string.
+ def encode(value, options = {})
+ raise_on_circular_reference(value) do
+ value.send(:to_json, options)
+ end
+ end
+
+ protected
+ def raise_on_circular_reference(value) #:nodoc:
+ stack = Thread.current[REFERENCE_STACK_VARIABLE] ||= []
+ raise CircularReferenceError, 'object references itself' if
+ stack.include? value
+ stack << value
+ yield
+ ensure
+ stack.pop
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/json/variable.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/json/variable.rb
new file mode 100644
index 000000000..7fd23b0a9
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/json/variable.rb
@@ -0,0 +1,10 @@
+module ActiveSupport
+ module JSON
+ # A string that returns itself as its JSON-encoded form.
+ class Variable < String
+ def to_json(options=nil)
+ self
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/multibyte.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/multibyte.rb
new file mode 100644
index 000000000..27c0d180a
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/multibyte.rb
@@ -0,0 +1,9 @@
+module ActiveSupport
+ module Multibyte #:nodoc:
+ DEFAULT_NORMALIZATION_FORM = :kc
+ NORMALIZATIONS_FORMS = [:c, :kc, :d, :kd]
+ UNICODE_VERSION = '5.0.0'
+ end
+end
+
+require 'active_support/multibyte/chars'
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/multibyte/chars.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/multibyte/chars.rb
new file mode 100644
index 000000000..b30214d94
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/multibyte/chars.rb
@@ -0,0 +1,141 @@
+require 'active_support/multibyte/handlers/utf8_handler'
+require 'active_support/multibyte/handlers/passthru_handler'
+
+# Encapsulates all the functionality related to the Chars proxy.
+module ActiveSupport::Multibyte #:nodoc:
+ # Chars enables you to work transparently with multibyte encodings in the Ruby String class without having extensive
+ # knowledge about the encoding. A Chars object accepts a string upon initialization and proxies String methods in an
+ # encoding safe manner. All the normal String methods are also implemented on the proxy.
+ #
+ # String methods are proxied through the Chars object, and can be accessed through the +chars+ method. Methods
+ # which would normally return a String object now return a Chars object so methods can be chained.
+ #
+ # "The Perfect String ".chars.downcase.strip.normalize #=> "the perfect string"
+ #
+ # Chars objects are perfectly interchangeable with String objects as long as no explicit class checks are made.
+ # If certain methods do explicitly check the class, call +to_s+ before you pass chars objects to them.
+ #
+ # bad.explicit_checking_method "T".chars.downcase.to_s
+ #
+ # The actual operations on the string are delegated to handlers. Theoretically handlers can be implemented for
+ # any encoding, but the default handler handles UTF-8. This handler is set during initialization, if you want to
+ # use you own handler, you can set it on the Chars class. Look at the UTF8Handler source for an example how to
+ # implement your own handler. If you your own handler to work on anything but UTF-8 you probably also
+ # want to override Chars#handler.
+ #
+ # ActiveSupport::Multibyte::Chars.handler = MyHandler
+ #
+ # Note that a few methods are defined on Chars instead of the handler because they are defined on Object or Kernel
+ # and method_missing can't catch them.
+ class Chars
+
+ attr_reader :string # The contained string
+ alias_method :to_s, :string
+
+ include Comparable
+
+ # The magic method to make String and Chars comparable
+ def to_str
+ # Using any other ways of overriding the String itself will lead you all the way from infinite loops to
+ # core dumps. Don't go there.
+ @string
+ end
+
+ # Make duck-typing with String possible
+ def respond_to?(method)
+ super || @string.respond_to?(method) || handler.respond_to?(method) ||
+ (method.to_s =~ /(.*)!/ && handler.respond_to?($1)) || false
+ end
+
+ # Create a new Chars instance.
+ def initialize(str)
+ @string = str.respond_to?(:string) ? str.string : str
+ end
+
+ # Returns -1, 0 or +1 depending on whether the Chars object is to be sorted before, equal or after the
+ # object on the right side of the operation. It accepts any object that implements +to_s+. See String.<=>
+ # for more details.
+ def <=>(other); @string <=> other.to_s; end
+
+ # Works just like String#split, with the exception that the items in the resulting list are Chars
+ # instances instead of String. This makes chaining methods easier.
+ def split(*args)
+ @string.split(*args).map { |i| i.chars }
+ end
+
+ # Gsub works exactly the same as gsub on a normal string.
+ def gsub(*a, &b); @string.gsub(*a, &b).chars; end
+
+ # Like String.=~ only it returns the character offset (in codepoints) instead of the byte offset.
+ def =~(other)
+ handler.translate_offset(@string, @string =~ other)
+ end
+
+ # Try to forward all undefined methods to the handler, when a method is not defined on the handler, send it to
+ # the contained string. Method_missing is also responsible for making the bang! methods destructive.
+ def method_missing(m, *a, &b)
+ begin
+ # Simulate methods with a ! at the end because we can't touch the enclosed string from the handlers.
+ if m.to_s =~ /^(.*)\!$/ && handler.respond_to?($1)
+ result = handler.send($1, @string, *a, &b)
+ if result == @string
+ result = nil
+ else
+ @string.replace result
+ end
+ elsif handler.respond_to?(m)
+ result = handler.send(m, @string, *a, &b)
+ else
+ result = @string.send(m, *a, &b)
+ end
+ rescue Handlers::EncodingError
+ @string.replace handler.tidy_bytes(@string)
+ retry
+ end
+
+ if result.kind_of?(String)
+ result.chars
+ else
+ result
+ end
+ end
+
+ # Set the handler class for the Char objects.
+ def self.handler=(klass)
+ @@handler = klass
+ end
+
+ # Returns the proper handler for the contained string depending on $KCODE and the encoding of the string. This
+ # method is used internally to always redirect messages to the proper classes depending on the context.
+ def handler
+ if utf8_pragma?
+ @@handler
+ else
+ ActiveSupport::Multibyte::Handlers::PassthruHandler
+ end
+ end
+
+ private
+
+ # +utf8_pragma+ checks if it can send this string to the handlers. It makes sure @string isn't nil and $KCODE is
+ # set to 'UTF8'.
+ if RUBY_VERSION < '1.9'
+ def utf8_pragma?
+ !@string.nil? && ($KCODE == 'UTF8')
+ end
+ else
+ def utf8_pragma?
+ !@string.nil? && (Encoding.default_external == Encoding::UTF_8)
+ end
+ end
+ end
+end
+
+# When we can load the utf8proc library, override normalization with the faster methods
+begin
+ require 'utf8proc_native'
+ require 'active_support/multibyte/handlers/utf8_handler_proc'
+ ActiveSupport::Multibyte::Chars.handler = ActiveSupport::Multibyte::Handlers::UTF8HandlerProc
+rescue LoadError
+ ActiveSupport::Multibyte::Chars.handler = ActiveSupport::Multibyte::Handlers::UTF8Handler
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/multibyte/generators/generate_tables.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/multibyte/generators/generate_tables.rb
new file mode 100644
index 000000000..7f807585c
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/multibyte/generators/generate_tables.rb
@@ -0,0 +1,149 @@
+#!/usr/bin/env ruby
+begin
+ require File.dirname(__FILE__) + '/../../../active_support'
+rescue IOError
+end
+require 'open-uri'
+require 'tmpdir'
+
+module ActiveSupport::Multibyte::Handlers #:nodoc:
+ class UnicodeDatabase #:nodoc:
+ def self.load
+ [Hash.new(Codepoint.new),[],{},{}]
+ end
+ end
+
+ class UnicodeTableGenerator #:nodoc:
+ BASE_URI = "http://www.unicode.org/Public/#{ActiveSupport::Multibyte::UNICODE_VERSION}/ucd/"
+ SOURCES = {
+ :codepoints => BASE_URI + 'UnicodeData.txt',
+ :composition_exclusion => BASE_URI + 'CompositionExclusions.txt',
+ :grapheme_break_property => BASE_URI + 'auxiliary/GraphemeBreakProperty.txt',
+ :cp1252 => 'http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT'
+ }
+
+ def initialize
+ @ucd = UnicodeDatabase.new
+
+ default = Codepoint.new
+ default.combining_class = 0
+ default.uppercase_mapping = 0
+ default.lowercase_mapping = 0
+ @ucd.codepoints = Hash.new(default)
+
+ @ucd.composition_exclusion = []
+ @ucd.composition_map = {}
+ @ucd.boundary = {}
+ @ucd.cp1252 = {}
+ end
+
+ def parse_codepoints(line)
+ codepoint = Codepoint.new
+ raise "Could not parse input." unless line =~ /^
+ ([0-9A-F]+); # code
+ ([^;]+); # name
+ ([A-Z]+); # general category
+ ([0-9]+); # canonical combining class
+ ([A-Z]+); # bidi class
+ (<([A-Z]*)>)? # decomposition type
+ ((\ ?[0-9A-F]+)*); # decompomposition mapping
+ ([0-9]*); # decimal digit
+ ([0-9]*); # digit
+ ([^;]*); # numeric
+ ([YN]*); # bidi mirrored
+ ([^;]*); # unicode 1.0 name
+ ([^;]*); # iso comment
+ ([0-9A-F]*); # simple uppercase mapping
+ ([0-9A-F]*); # simple lowercase mapping
+ ([0-9A-F]*)$/ix # simple titlecase mapping
+ codepoint.code = $1.hex
+ #codepoint.name = $2
+ #codepoint.category = $3
+ codepoint.combining_class = Integer($4)
+ #codepoint.bidi_class = $5
+ codepoint.decomp_type = $7
+ codepoint.decomp_mapping = ($8=='') ? nil : $8.split.collect { |element| element.hex }
+ #codepoint.bidi_mirrored = ($13=='Y') ? true : false
+ codepoint.uppercase_mapping = ($16=='') ? 0 : $16.hex
+ codepoint.lowercase_mapping = ($17=='') ? 0 : $17.hex
+ #codepoint.titlecase_mapping = ($18=='') ? nil : $18.hex
+ @ucd.codepoints[codepoint.code] = codepoint
+ end
+
+ def parse_grapheme_break_property(line)
+ if line =~ /^([0-9A-F\.]+)\s*;\s*([\w]+)\s*#/
+ type = $2.downcase.intern
+ @ucd.boundary[type] ||= []
+ if $1.include? '..'
+ parts = $1.split '..'
+ @ucd.boundary[type] << (parts[0].hex..parts[1].hex)
+ else
+ @ucd.boundary[type] << $1.hex
+ end
+ end
+ end
+
+ def parse_composition_exclusion(line)
+ if line =~ /^([0-9A-F]+)/i
+ @ucd.composition_exclusion << $1.hex
+ end
+ end
+
+ def parse_cp1252(line)
+ if line =~ /^([0-9A-Fx]+)\s([0-9A-Fx]+)/i
+ @ucd.cp1252[$1.hex] = $2.hex
+ end
+ end
+
+ def create_composition_map
+ @ucd.codepoints.each do |_, cp|
+ if !cp.nil? and cp.combining_class == 0 and cp.decomp_type.nil? and !cp.decomp_mapping.nil? and cp.decomp_mapping.length == 2 and @ucd[cp.decomp_mapping[0]].combining_class == 0 and !@ucd.composition_exclusion.include?(cp.code)
+ @ucd.composition_map[cp.decomp_mapping[0]] ||= {}
+ @ucd.composition_map[cp.decomp_mapping[0]][cp.decomp_mapping[1]] = cp.code
+ end
+ end
+ end
+
+ def normalize_boundary_map
+ @ucd.boundary.each do |k,v|
+ if [:lf, :cr].include? k
+ @ucd.boundary[k] = v[0]
+ end
+ end
+ end
+
+ def parse
+ SOURCES.each do |type, url|
+ filename = File.join(Dir.tmpdir, "#{url.split('/').last}")
+ unless File.exist?(filename)
+ $stderr.puts "Downloading #{url.split('/').last}"
+ File.open(filename, 'wb') do |target|
+ open(url) do |source|
+ source.each_line { |line| target.write line }
+ end
+ end
+ end
+ File.open(filename) do |file|
+ file.each_line { |line| send "parse_#{type}".intern, line }
+ end
+ end
+ create_composition_map
+ normalize_boundary_map
+ end
+
+ def dump_to(filename)
+ File.open(filename, 'wb') do |f|
+ f.write Marshal.dump([@ucd.codepoints, @ucd.composition_exclusion, @ucd.composition_map, @ucd.boundary, @ucd.cp1252])
+ end
+ end
+ end
+end
+
+if __FILE__ == $0
+ filename = ActiveSupport::Multibyte::Handlers::UnicodeDatabase.filename
+ generator = ActiveSupport::Multibyte::Handlers::UnicodeTableGenerator.new
+ generator.parse
+ print "Writing to: #{filename}"
+ generator.dump_to filename
+ puts " (#{File.size(filename)} bytes)"
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/multibyte/handlers/passthru_handler.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/multibyte/handlers/passthru_handler.rb
new file mode 100644
index 000000000..916215c2c
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/multibyte/handlers/passthru_handler.rb
@@ -0,0 +1,9 @@
+# Chars uses this handler when $KCODE is not set to 'UTF8'. Because this handler doesn't define any methods all call
+# will be forwarded to String.
+class ActiveSupport::Multibyte::Handlers::PassthruHandler #:nodoc:
+
+ # Return the original byteoffset
+ def self.translate_offset(string, byte_offset) #:nodoc:
+ byte_offset
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb
new file mode 100644
index 000000000..66fe47a60
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb
@@ -0,0 +1,564 @@
+# Contains all the handlers and helper classes
+module ActiveSupport::Multibyte::Handlers #:nodoc:
+ class EncodingError < ArgumentError #:nodoc:
+ end
+
+ class Codepoint #:nodoc:
+ attr_accessor :code, :combining_class, :decomp_type, :decomp_mapping, :uppercase_mapping, :lowercase_mapping
+ end
+
+ class UnicodeDatabase #:nodoc:
+ attr_writer :codepoints, :composition_exclusion, :composition_map, :boundary, :cp1252
+
+ # self-expiring methods that lazily load the Unicode database and then return the value.
+ [:codepoints, :composition_exclusion, :composition_map, :boundary, :cp1252].each do |attr_name|
+ class_eval(<<-EOS, __FILE__, __LINE__)
+ def #{attr_name}
+ load
+ @#{attr_name}
+ end
+ EOS
+ end
+
+ # Shortcut to ucd.codepoints[]
+ def [](index); codepoints[index]; end
+
+ # Returns the directory in which the data files are stored
+ def self.dirname
+ File.dirname(__FILE__) + '/../../values/'
+ end
+
+ # Returns the filename for the data file for this version
+ def self.filename
+ File.expand_path File.join(dirname, "unicode_tables.dat")
+ end
+
+ # Loads the unicode database and returns all the internal objects of UnicodeDatabase
+ # Once the values have been loaded, define attr_reader methods for the instance variables.
+ def load
+ begin
+ @codepoints, @composition_exclusion, @composition_map, @boundary, @cp1252 = File.open(self.class.filename, 'rb') { |f| Marshal.load f.read }
+ rescue Exception => e
+ raise IOError.new("Couldn't load the unicode tables for UTF8Handler (#{e.message}), handler is unusable")
+ end
+ @codepoints ||= Hash.new(Codepoint.new)
+ @composition_exclusion ||= []
+ @composition_map ||= {}
+ @boundary ||= {}
+ @cp1252 ||= {}
+
+ # Redefine the === method so we can write shorter rules for grapheme cluster breaks
+ @boundary.each do |k,_|
+ @boundary[k].instance_eval do
+ def ===(other)
+ detect { |i| i === other } ? true : false
+ end
+ end if @boundary[k].kind_of?(Array)
+ end
+
+ # define attr_reader methods for the instance variables
+ class << self
+ attr_reader :codepoints, :composition_exclusion, :composition_map, :boundary, :cp1252
+ end
+ end
+ end
+
+ # UTF8Handler implements Unicode aware operations for strings, these operations will be used by the Chars
+ # proxy when $KCODE is set to 'UTF8'.
+ class UTF8Handler
+ # Hangul character boundaries and properties
+ HANGUL_SBASE = 0xAC00
+ HANGUL_LBASE = 0x1100
+ HANGUL_VBASE = 0x1161
+ HANGUL_TBASE = 0x11A7
+ HANGUL_LCOUNT = 19
+ HANGUL_VCOUNT = 21
+ HANGUL_TCOUNT = 28
+ HANGUL_NCOUNT = HANGUL_VCOUNT * HANGUL_TCOUNT
+ HANGUL_SCOUNT = 11172
+ HANGUL_SLAST = HANGUL_SBASE + HANGUL_SCOUNT
+ HANGUL_JAMO_FIRST = 0x1100
+ HANGUL_JAMO_LAST = 0x11FF
+
+ # All the unicode whitespace
+ UNICODE_WHITESPACE = [
+ (0x0009..0x000D).to_a, # White_Space # Cc [5] <control-0009>..<control-000D>
+ 0x0020, # White_Space # Zs SPACE
+ 0x0085, # White_Space # Cc <control-0085>
+ 0x00A0, # White_Space # Zs NO-BREAK SPACE
+ 0x1680, # White_Space # Zs OGHAM SPACE MARK
+ 0x180E, # White_Space # Zs MONGOLIAN VOWEL SEPARATOR
+ (0x2000..0x200A).to_a, # White_Space # Zs [11] EN QUAD..HAIR SPACE
+ 0x2028, # White_Space # Zl LINE SEPARATOR
+ 0x2029, # White_Space # Zp PARAGRAPH SEPARATOR
+ 0x202F, # White_Space # Zs NARROW NO-BREAK SPACE
+ 0x205F, # White_Space # Zs MEDIUM MATHEMATICAL SPACE
+ 0x3000, # White_Space # Zs IDEOGRAPHIC SPACE
+ ].flatten.freeze
+
+ # BOM (byte order mark) can also be seen as whitespace, it's a non-rendering character used to distinguish
+ # between little and big endian. This is not an issue in utf-8, so it must be ignored.
+ UNICODE_LEADERS_AND_TRAILERS = UNICODE_WHITESPACE + [65279] # ZERO-WIDTH NO-BREAK SPACE aka BOM
+
+ # Borrowed from the Kconv library by Shinji KONO - (also as seen on the W3C site)
+ UTF8_PAT = /\A(?:
+ [\x00-\x7f] |
+ [\xc2-\xdf] [\x80-\xbf] |
+ \xe0 [\xa0-\xbf] [\x80-\xbf] |
+ [\xe1-\xef] [\x80-\xbf] [\x80-\xbf] |
+ \xf0 [\x90-\xbf] [\x80-\xbf] [\x80-\xbf] |
+ [\xf1-\xf3] [\x80-\xbf] [\x80-\xbf] [\x80-\xbf] |
+ \xf4 [\x80-\x8f] [\x80-\xbf] [\x80-\xbf]
+ )*\z/xn
+
+ # Returns a regular expression pattern that matches the passed Unicode codepoints
+ def self.codepoints_to_pattern(array_of_codepoints) #:nodoc:
+ array_of_codepoints.collect{ |e| [e].pack 'U*' }.join('|')
+ end
+ UNICODE_TRAILERS_PAT = /(#{codepoints_to_pattern(UNICODE_LEADERS_AND_TRAILERS)})+\Z/
+ UNICODE_LEADERS_PAT = /\A(#{codepoints_to_pattern(UNICODE_LEADERS_AND_TRAILERS)})+/
+
+ class << self
+
+ # ///
+ # /// BEGIN String method overrides
+ # ///
+
+ # Inserts the passed string at specified codepoint offsets
+ def insert(str, offset, fragment)
+ str.replace(
+ u_unpack(str).insert(
+ offset,
+ u_unpack(fragment)
+ ).flatten.pack('U*')
+ )
+ end
+
+ # Returns the position of the passed argument in the string, counting in codepoints
+ def index(str, *args)
+ bidx = str.index(*args)
+ bidx ? (u_unpack(str.slice(0...bidx)).size) : nil
+ end
+
+ # Works just like the indexed replace method on string, except instead of byte offsets you specify
+ # character offsets.
+ #
+ # Example:
+ #
+ # s = "Müller"
+ # s.chars[2] = "e" # Replace character with offset 2
+ # s
+ # #=> "Müeler"
+ #
+ # s = "Müller"
+ # s.chars[1, 2] = "ö" # Replace 2 characters at character offset 1
+ # s
+ # #=> "Möler"
+ def []=(str, *args)
+ replace_by = args.pop
+ # Indexed replace with regular expressions already works
+ return str[*args] = replace_by if args.first.is_a?(Regexp)
+ result = u_unpack(str)
+ if args[0].is_a?(Fixnum)
+ raise IndexError, "index #{args[0]} out of string" if args[0] >= result.length
+ min = args[0]
+ max = args[1].nil? ? min : (min + args[1] - 1)
+ range = Range.new(min, max)
+ replace_by = [replace_by].pack('U') if replace_by.is_a?(Fixnum)
+ elsif args.first.is_a?(Range)
+ raise RangeError, "#{args[0]} out of range" if args[0].min >= result.length
+ range = args[0]
+ else
+ needle = args[0].to_s
+ min = index(str, needle)
+ max = min + length(needle) - 1
+ range = Range.new(min, max)
+ end
+ result[range] = u_unpack(replace_by)
+ str.replace(result.pack('U*'))
+ end
+
+ # Works just like String#rjust, only integer specifies characters instead of bytes.
+ #
+ # Example:
+ #
+ # "¾ cup".chars.rjust(8).to_s
+ # #=> " ¾ cup"
+ #
+ # "¾ cup".chars.rjust(8, " ").to_s # Use non-breaking whitespace
+ # #=> "   ¾ cup"
+ def rjust(str, integer, padstr=' ')
+ justify(str, integer, :right, padstr)
+ end
+
+ # Works just like String#ljust, only integer specifies characters instead of bytes.
+ #
+ # Example:
+ #
+ # "¾ cup".chars.rjust(8).to_s
+ # #=> "¾ cup "
+ #
+ # "¾ cup".chars.rjust(8, " ").to_s # Use non-breaking whitespace
+ # #=> "¾ cup   "
+ def ljust(str, integer, padstr=' ')
+ justify(str, integer, :left, padstr)
+ end
+
+ # Works just like String#center, only integer specifies characters instead of bytes.
+ #
+ # Example:
+ #
+ # "¾ cup".chars.center(8).to_s
+ # #=> " ¾ cup "
+ #
+ # "¾ cup".chars.center(8, " ").to_s # Use non-breaking whitespace
+ # #=> " ¾ cup  "
+ def center(str, integer, padstr=' ')
+ justify(str, integer, :center, padstr)
+ end
+
+ # Does Unicode-aware rstrip
+ def rstrip(str)
+ str.gsub(UNICODE_TRAILERS_PAT, '')
+ end
+
+ # Does Unicode-aware lstrip
+ def lstrip(str)
+ str.gsub(UNICODE_LEADERS_PAT, '')
+ end
+
+ # Removed leading and trailing whitespace
+ def strip(str)
+ str.gsub(UNICODE_LEADERS_PAT, '').gsub(UNICODE_TRAILERS_PAT, '')
+ end
+
+ # Returns the number of codepoints in the string
+ def size(str)
+ u_unpack(str).size
+ end
+ alias_method :length, :size
+
+ # Reverses codepoints in the string.
+ def reverse(str)
+ u_unpack(str).reverse.pack('U*')
+ end
+
+ # Implements Unicode-aware slice with codepoints. Slicing on one point returns the codepoints for that
+ # character.
+ def slice(str, *args)
+ if args.size > 2
+ raise ArgumentError, "wrong number of arguments (#{args.size} for 1)" # Do as if we were native
+ elsif (args.size == 2 && !(args.first.is_a?(Numeric) || args.first.is_a?(Regexp)))
+ raise TypeError, "cannot convert #{args.first.class} into Integer" # Do as if we were native
+ elsif (args.size == 2 && !args[1].is_a?(Numeric))
+ raise TypeError, "cannot convert #{args[1].class} into Integer" # Do as if we were native
+ elsif args[0].kind_of? Range
+ cps = u_unpack(str).slice(*args)
+ cps.nil? ? nil : cps.pack('U*')
+ elsif args[0].kind_of? Regexp
+ str.slice(*args)
+ elsif args.size == 1 && args[0].kind_of?(Numeric)
+ u_unpack(str)[args[0]]
+ else
+ u_unpack(str).slice(*args).pack('U*')
+ end
+ end
+ alias_method :[], :slice
+
+ # Convert characters in the string to uppercase
+ def upcase(str); to_case :uppercase_mapping, str; end
+
+ # Convert characters in the string to lowercase
+ def downcase(str); to_case :lowercase_mapping, str; end
+
+ # Returns a copy of +str+ with the first character converted to uppercase and the remainder to lowercase
+ def capitalize(str)
+ upcase(slice(str, 0..0)) + downcase(slice(str, 1..-1) || '')
+ end
+
+ # ///
+ # /// Extra String methods for unicode operations
+ # ///
+
+ # Returns the KC normalization of the string by default. NFKC is considered the best normalization form for
+ # passing strings to databases and validations.
+ #
+ # * <tt>str</tt> - The string to perform normalization on.
+ # * <tt>form</tt> - The form you want to normalize in. Should be one of the following: :c, :kc, :d or :kd.
+ def normalize(str, form=ActiveSupport::Multibyte::DEFAULT_NORMALIZATION_FORM)
+ # See http://www.unicode.org/reports/tr15, Table 1
+ codepoints = u_unpack(str)
+ case form
+ when :d
+ reorder_characters(decompose_codepoints(:canonical, codepoints))
+ when :c
+ compose_codepoints reorder_characters(decompose_codepoints(:canonical, codepoints))
+ when :kd
+ reorder_characters(decompose_codepoints(:compatability, codepoints))
+ when :kc
+ compose_codepoints reorder_characters(decompose_codepoints(:compatability, codepoints))
+ else
+ raise ArgumentError, "#{form} is not a valid normalization variant", caller
+ end.pack('U*')
+ end
+
+ # Perform decomposition on the characters in the string
+ def decompose(str)
+ decompose_codepoints(:canonical, u_unpack(str)).pack('U*')
+ end
+
+ # Perform composition on the characters in the string
+ def compose(str)
+ compose_codepoints u_unpack(str).pack('U*')
+ end
+
+ # ///
+ # /// BEGIN Helper methods for unicode operation
+ # ///
+
+ # Used to translate an offset from bytes to characters, for instance one received from a regular expression match
+ def translate_offset(str, byte_offset)
+ return nil if byte_offset.nil?
+ return 0 if str == ''
+ chunk = str[0..byte_offset]
+ begin
+ begin
+ chunk.unpack('U*').length - 1
+ rescue ArgumentError => e
+ chunk = str[0..(byte_offset+=1)]
+ # Stop retrying at the end of the string
+ raise e unless byte_offset < chunk.length
+ # We damaged a character, retry
+ retry
+ end
+ # Catch the ArgumentError so we can throw our own
+ rescue ArgumentError
+ raise EncodingError.new('malformed UTF-8 character')
+ end
+ end
+
+ # Checks if the string is valid UTF8.
+ def consumes?(str)
+ # Unpack is a little bit faster than regular expressions
+ begin
+ str.unpack('U*')
+ true
+ rescue ArgumentError
+ false
+ end
+ end
+
+ # Returns the number of grapheme clusters in the string. This method is very likely to be moved or renamed
+ # in future versions.
+ def g_length(str)
+ g_unpack(str).length
+ end
+
+ # Replaces all the non-utf-8 bytes by their iso-8859-1 or cp1252 equivalent resulting in a valid utf-8 string
+ def tidy_bytes(str)
+ str.split(//u).map do |c|
+ if !UTF8_PAT.match(c)
+ n = c.unpack('C')[0]
+ n < 128 ? n.chr :
+ n < 160 ? [UCD.cp1252[n] || n].pack('U') :
+ n < 192 ? "\xC2" + n.chr : "\xC3" + (n-64).chr
+ else
+ c
+ end
+ end.join
+ end
+
+ protected
+
+ # Detect whether the codepoint is in a certain character class. Primarily used by the
+ # grapheme cluster support.
+ def in_char_class?(codepoint, classes)
+ classes.detect { |c| UCD.boundary[c] === codepoint } ? true : false
+ end
+
+ # Unpack the string at codepoints boundaries
+ def u_unpack(str)
+ begin
+ str.unpack 'U*'
+ rescue ArgumentError
+ raise EncodingError.new('malformed UTF-8 character')
+ end
+ end
+
+ # Unpack the string at grapheme boundaries instead of codepoint boundaries
+ def g_unpack(str)
+ codepoints = u_unpack(str)
+ unpacked = []
+ pos = 0
+ marker = 0
+ eoc = codepoints.length
+ while(pos < eoc)
+ pos += 1
+ previous = codepoints[pos-1]
+ current = codepoints[pos]
+ if (
+ # CR X LF
+ one = ( previous == UCD.boundary[:cr] and current == UCD.boundary[:lf] ) or
+ # L X (L|V|LV|LVT)
+ two = ( UCD.boundary[:l] === previous and in_char_class?(current, [:l,:v,:lv,:lvt]) ) or
+ # (LV|V) X (V|T)
+ three = ( in_char_class?(previous, [:lv,:v]) and in_char_class?(current, [:v,:t]) ) or
+ # (LVT|T) X (T)
+ four = ( in_char_class?(previous, [:lvt,:t]) and UCD.boundary[:t] === current ) or
+ # X Extend
+ five = (UCD.boundary[:extend] === current)
+ )
+ else
+ unpacked << codepoints[marker..pos-1]
+ marker = pos
+ end
+ end
+ unpacked
+ end
+
+ # Reverse operation of g_unpack
+ def g_pack(unpacked)
+ unpacked.flatten
+ end
+
+ # Justifies a string in a certain way. Valid values for <tt>way</tt> are <tt>:right</tt>, <tt>:left</tt> and
+ # <tt>:center</tt>. Is primarily used as a helper method by <tt>rjust</tt>, <tt>ljust</tt> and <tt>center</tt>.
+ def justify(str, integer, way, padstr=' ')
+ raise ArgumentError, "zero width padding" if padstr.length == 0
+ padsize = integer - size(str)
+ padsize = padsize > 0 ? padsize : 0
+ case way
+ when :right
+ str.dup.insert(0, padding(padsize, padstr))
+ when :left
+ str.dup.insert(-1, padding(padsize, padstr))
+ when :center
+ lpad = padding((padsize / 2.0).floor, padstr)
+ rpad = padding((padsize / 2.0).ceil, padstr)
+ str.dup.insert(0, lpad).insert(-1, rpad)
+ end
+ end
+
+ # Generates a padding string of a certain size.
+ def padding(padsize, padstr=' ')
+ if padsize != 0
+ slice(padstr * ((padsize / size(padstr)) + 1), 0, padsize)
+ else
+ ''
+ end
+ end
+
+ # Convert characters to a different case
+ def to_case(way, str)
+ u_unpack(str).map do |codepoint|
+ cp = UCD[codepoint]
+ unless cp.nil?
+ ncp = cp.send(way)
+ ncp > 0 ? ncp : codepoint
+ else
+ codepoint
+ end
+ end.pack('U*')
+ end
+
+ # Re-order codepoints so the string becomes canonical
+ def reorder_characters(codepoints)
+ length = codepoints.length- 1
+ pos = 0
+ while pos < length do
+ cp1, cp2 = UCD[codepoints[pos]], UCD[codepoints[pos+1]]
+ if (cp1.combining_class > cp2.combining_class) && (cp2.combining_class > 0)
+ codepoints[pos..pos+1] = cp2.code, cp1.code
+ pos += (pos > 0 ? -1 : 1)
+ else
+ pos += 1
+ end
+ end
+ codepoints
+ end
+
+ # Decompose composed characters to the decomposed form
+ def decompose_codepoints(type, codepoints)
+ codepoints.inject([]) do |decomposed, cp|
+ # if it's a hangul syllable starter character
+ if HANGUL_SBASE <= cp and cp < HANGUL_SLAST
+ sindex = cp - HANGUL_SBASE
+ ncp = [] # new codepoints
+ ncp << HANGUL_LBASE + sindex / HANGUL_NCOUNT
+ ncp << HANGUL_VBASE + (sindex % HANGUL_NCOUNT) / HANGUL_TCOUNT
+ tindex = sindex % HANGUL_TCOUNT
+ ncp << (HANGUL_TBASE + tindex) unless tindex == 0
+ decomposed.concat ncp
+ # if the codepoint is decomposable in with the current decomposition type
+ elsif (ncp = UCD[cp].decomp_mapping) and (!UCD[cp].decomp_type || type == :compatability)
+ decomposed.concat decompose_codepoints(type, ncp.dup)
+ else
+ decomposed << cp
+ end
+ end
+ end
+
+ # Compose decomposed characters to the composed form
+ def compose_codepoints(codepoints)
+ pos = 0
+ eoa = codepoints.length - 1
+ starter_pos = 0
+ starter_char = codepoints[0]
+ previous_combining_class = -1
+ while pos < eoa
+ pos += 1
+ lindex = starter_char - HANGUL_LBASE
+ # -- Hangul
+ if 0 <= lindex and lindex < HANGUL_LCOUNT
+ vindex = codepoints[starter_pos+1] - HANGUL_VBASE rescue vindex = -1
+ if 0 <= vindex and vindex < HANGUL_VCOUNT
+ tindex = codepoints[starter_pos+2] - HANGUL_TBASE rescue tindex = -1
+ if 0 <= tindex and tindex < HANGUL_TCOUNT
+ j = starter_pos + 2
+ eoa -= 2
+ else
+ tindex = 0
+ j = starter_pos + 1
+ eoa -= 1
+ end
+ codepoints[starter_pos..j] = (lindex * HANGUL_VCOUNT + vindex) * HANGUL_TCOUNT + tindex + HANGUL_SBASE
+ end
+ starter_pos += 1
+ starter_char = codepoints[starter_pos]
+ # -- Other characters
+ else
+ current_char = codepoints[pos]
+ current = UCD[current_char]
+ if current.combining_class > previous_combining_class
+ if ref = UCD.composition_map[starter_char]
+ composition = ref[current_char]
+ else
+ composition = nil
+ end
+ unless composition.nil?
+ codepoints[starter_pos] = composition
+ starter_char = composition
+ codepoints.delete_at pos
+ eoa -= 1
+ pos -= 1
+ previous_combining_class = -1
+ else
+ previous_combining_class = current.combining_class
+ end
+ else
+ previous_combining_class = current.combining_class
+ end
+ if current.combining_class == 0
+ starter_pos = pos
+ starter_char = codepoints[pos]
+ end
+ end
+ end
+ codepoints
+ end
+
+ # UniCode Database
+ UCD = UnicodeDatabase.new
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/multibyte/handlers/utf8_handler_proc.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/multibyte/handlers/utf8_handler_proc.rb
new file mode 100644
index 000000000..f10eecc62
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/multibyte/handlers/utf8_handler_proc.rb
@@ -0,0 +1,43 @@
+# Methods in this handler call functions in the utf8proc ruby extension. These are significantly faster than the
+# pure ruby versions. Chars automatically uses this handler when it can load the utf8proc extension. For
+# documentation on handler methods see UTF8Handler.
+class ActiveSupport::Multibyte::Handlers::UTF8HandlerProc < ActiveSupport::Multibyte::Handlers::UTF8Handler #:nodoc:
+ class << self
+ def normalize(str, form=ActiveSupport::Multibyte::DEFAULT_NORMALIZATION_FORM) #:nodoc:
+ codepoints = str.unpack('U*')
+ case form
+ when :d
+ utf8map(str, :stable)
+ when :c
+ utf8map(str, :stable, :compose)
+ when :kd
+ utf8map(str, :stable, :compat)
+ when :kc
+ utf8map(str, :stable, :compose, :compat)
+ else
+ raise ArgumentError, "#{form} is not a valid normalization variant", caller
+ end
+ end
+
+ def decompose(str) #:nodoc:
+ utf8map(str, :stable)
+ end
+
+ def downcase(str) #:nodoc:c
+ utf8map(str, :casefold)
+ end
+
+ protected
+
+ def utf8map(str, *option_array) #:nodoc:
+ options = 0
+ option_array.each do |option|
+ flag = Utf8Proc::Options[option]
+ raise ArgumentError, "Unknown argument given to utf8map." unless
+ flag
+ options |= flag
+ end
+ return Utf8Proc::utf8map(str, options)
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/option_merger.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/option_merger.rb
new file mode 100644
index 000000000..1a4ff9db9
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/option_merger.rb
@@ -0,0 +1,25 @@
+module ActiveSupport
+ class OptionMerger #:nodoc:
+ instance_methods.each do |method|
+ undef_method(method) if method !~ /^(__|instance_eval|class|object_id)/
+ end
+
+ def initialize(context, options)
+ @context, @options = context, options
+ end
+
+ private
+ def method_missing(method, *arguments, &block)
+ merge_argument_options! arguments
+ @context.send!(method, *arguments, &block)
+ end
+
+ def merge_argument_options!(arguments)
+ arguments << if arguments.last.respond_to? :to_hash
+ @options.merge(arguments.pop)
+ else
+ @options.dup
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/ordered_options.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/ordered_options.rb
new file mode 100644
index 000000000..1542a2479
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/ordered_options.rb
@@ -0,0 +1,49 @@
+# OrderedHash is namespaced to prevent conflicts with other implementations
+module ActiveSupport
+ # Hash is ordered in Ruby 1.9!
+ if RUBY_VERSION >= '1.9'
+ OrderedHash = ::Hash
+ else
+ class OrderedHash < Array #:nodoc:
+ def []=(key, value)
+ if pair = assoc(key)
+ pair.pop
+ pair << value
+ else
+ self << [key, value]
+ end
+ end
+
+ def [](key)
+ pair = assoc(key)
+ pair ? pair.last : nil
+ end
+
+ def keys
+ collect { |key, value| key }
+ end
+
+ def values
+ collect { |key, value| value }
+ end
+ end
+ end
+end
+
+class OrderedOptions < ActiveSupport::OrderedHash #:nodoc:
+ def []=(key, value)
+ super(key.to_sym, value)
+ end
+
+ def [](key)
+ super(key.to_sym)
+ end
+
+ def method_missing(name, *args)
+ if name.to_s =~ /(.*)=$/
+ self[$1.to_sym] = args.first
+ else
+ self[name]
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/test_case.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/test_case.rb
new file mode 100644
index 000000000..be8f8b17f
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/test_case.rb
@@ -0,0 +1,5 @@
+module ActiveSupport
+ class TestCase < Test::Unit::TestCase
+ include ActiveSupport::Testing::Default
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/testing.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/testing.rb
new file mode 100644
index 000000000..1bf30cbbd
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/testing.rb
@@ -0,0 +1 @@
+require 'active_support/testing/default' \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/testing/default.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/testing/default.rb
new file mode 100644
index 000000000..d97a610c7
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/testing/default.rb
@@ -0,0 +1,12 @@
+module ActiveSupport
+ module Testing
+ module Default
+ def run(*args)
+ #method_name appears to be a symbol on 1.8.4 and a string on 1.8.6
+ return if @method_name.to_s == "default_test"
+ super
+ end
+ end
+ end
+end
+
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/values/time_zone.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/values/time_zone.rb
new file mode 100644
index 000000000..b7df68fe3
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/values/time_zone.rb
@@ -0,0 +1,181 @@
+# A value object representing a time zone. A time zone is simply a named
+# offset (in seconds) from GMT. Note that two time zone objects are only
+# equivalent if they have both the same offset, and the same name.
+#
+# A TimeZone instance may be used to convert a Time value to the corresponding
+# time zone.
+#
+# The class also includes #all, which returns a list of all TimeZone objects.
+class TimeZone
+ include Comparable
+
+ attr_reader :name, :utc_offset
+
+ # Create a new TimeZone object with the given name and offset. The offset is
+ # the number of seconds that this time zone is offset from UTC (GMT). Seconds
+ # were chosen as the offset unit because that is the unit that Ruby uses
+ # to represent time zone offsets (see Time#utc_offset).
+ def initialize(name, utc_offset)
+ @name = name
+ @utc_offset = utc_offset
+ end
+
+ # Returns the offset of this time zone as a formatted string, of the
+ # format "+HH:MM". If the offset is zero, this returns the empty
+ # string. If +colon+ is false, a colon will not be inserted into the
+ # result.
+ def formatted_offset( colon=true )
+ return "" if utc_offset == 0
+ sign = (utc_offset < 0 ? -1 : 1)
+ hours = utc_offset.abs / 3600
+ minutes = (utc_offset.abs % 3600) / 60
+ "%+03d%s%02d" % [ hours * sign, colon ? ":" : "", minutes ]
+ end
+
+ # Compute and return the current time, in the time zone represented by
+ # +self+.
+ def now
+ adjust(Time.now)
+ end
+
+ # Return the current date in this time zone.
+ def today
+ now.to_date
+ end
+
+ # Adjust the given time to the time zone represented by +self+.
+ def adjust(time)
+ time = time.to_time unless time.is_a?(::Time)
+ time + utc_offset - time.utc_offset
+ end
+
+ # Reinterprets the given time value as a time in the current time
+ # zone, and then adjusts it to return the corresponding time in the
+ # local time zone.
+ def unadjust(time)
+ time = time.to_time unless time.is_a?(::Time)
+ time = time.localtime
+ time - utc_offset - time.utc_offset
+ end
+
+ # Compare this time zone to the parameter. The two are comapred first on
+ # their offsets, and then by name.
+ def <=>(zone)
+ result = (utc_offset <=> zone.utc_offset)
+ result = (name <=> zone.name) if result == 0
+ result
+ end
+
+ # Returns a textual representation of this time zone.
+ def to_s
+ "(UTC#{formatted_offset}) #{name}"
+ end
+
+ @@zones = nil
+
+ class << self
+ # Create a new TimeZone instance with the given name and offset.
+ def create(name, offset)
+ zone = allocate
+ zone.send!(:initialize, name, offset)
+ zone
+ end
+
+ # Return a TimeZone instance with the given name, or +nil+ if no
+ # such TimeZone instance exists. (This exists to support the use of
+ # this class with the #composed_of macro.)
+ def new(name)
+ self[name]
+ end
+
+ # Return an array of all TimeZone objects. There are multiple TimeZone
+ # objects per time zone, in many cases, to make it easier for users to
+ # find their own time zone.
+ def all
+ unless @@zones
+ @@zones = []
+ [[-43_200, "International Date Line West" ],
+ [-39_600, "Midway Island", "Samoa" ],
+ [-36_000, "Hawaii" ],
+ [-32_400, "Alaska" ],
+ [-28_800, "Pacific Time (US & Canada)", "Tijuana" ],
+ [-25_200, "Mountain Time (US & Canada)", "Chihuahua", "Mazatlan",
+ "Arizona" ],
+ [-21_600, "Central Time (US & Canada)", "Saskatchewan", "Guadalajara",
+ "Mexico City", "Monterrey", "Central America" ],
+ [-18_000, "Eastern Time (US & Canada)", "Indiana (East)", "Bogota",
+ "Lima", "Quito" ],
+ [-14_400, "Atlantic Time (Canada)", "Caracas", "La Paz", "Santiago" ],
+ [-12_600, "Newfoundland" ],
+ [-10_800, "Brasilia", "Buenos Aires", "Georgetown", "Greenland" ],
+ [ -7_200, "Mid-Atlantic" ],
+ [ -3_600, "Azores", "Cape Verde Is." ],
+ [ 0, "Dublin", "Edinburgh", "Lisbon", "London", "Casablanca",
+ "Monrovia" ],
+ [ 3_600, "Belgrade", "Bratislava", "Budapest", "Ljubljana", "Prague",
+ "Sarajevo", "Skopje", "Warsaw", "Zagreb", "Brussels",
+ "Copenhagen", "Madrid", "Paris", "Amsterdam", "Berlin",
+ "Bern", "Rome", "Stockholm", "Vienna",
+ "West Central Africa" ],
+ [ 7_200, "Bucharest", "Cairo", "Helsinki", "Kyev", "Riga", "Sofia",
+ "Tallinn", "Vilnius", "Athens", "Istanbul", "Minsk",
+ "Jerusalem", "Harare", "Pretoria" ],
+ [ 10_800, "Moscow", "St. Petersburg", "Volgograd", "Kuwait", "Riyadh",
+ "Nairobi", "Baghdad" ],
+ [ 12_600, "Tehran" ],
+ [ 14_400, "Abu Dhabi", "Muscat", "Baku", "Tbilisi", "Yerevan" ],
+ [ 16_200, "Kabul" ],
+ [ 18_000, "Ekaterinburg", "Islamabad", "Karachi", "Tashkent" ],
+ [ 19_800, "Chennai", "Kolkata", "Mumbai", "New Delhi" ],
+ [ 20_700, "Kathmandu" ],
+ [ 21_600, "Astana", "Dhaka", "Sri Jayawardenepura", "Almaty",
+ "Novosibirsk" ],
+ [ 23_400, "Rangoon" ],
+ [ 25_200, "Bangkok", "Hanoi", "Jakarta", "Krasnoyarsk" ],
+ [ 28_800, "Beijing", "Chongqing", "Hong Kong", "Urumqi",
+ "Kuala Lumpur", "Singapore", "Taipei", "Perth", "Irkutsk",
+ "Ulaan Bataar" ],
+ [ 32_400, "Seoul", "Osaka", "Sapporo", "Tokyo", "Yakutsk" ],
+ [ 34_200, "Darwin", "Adelaide" ],
+ [ 36_000, "Canberra", "Melbourne", "Sydney", "Brisbane", "Hobart",
+ "Vladivostok", "Guam", "Port Moresby" ],
+ [ 39_600, "Magadan", "Solomon Is.", "New Caledonia" ],
+ [ 43_200, "Fiji", "Kamchatka", "Marshall Is.", "Auckland",
+ "Wellington" ],
+ [ 46_800, "Nuku'alofa" ]].
+ each do |offset, *places|
+ places.each { |place| @@zones << create(place, offset).freeze }
+ end
+ @@zones.sort!
+ end
+ @@zones
+ end
+
+ # Locate a specific time zone object. If the argument is a string, it
+ # is interpreted to mean the name of the timezone to locate. If it is a
+ # numeric value it is either the hour offset, or the second offset, of the
+ # timezone to find. (The first one with that offset will be returned.)
+ # Returns +nil+ if no such time zone is known to the system.
+ def [](arg)
+ case arg
+ when String
+ all.find { |z| z.name == arg }
+ when Numeric
+ arg *= 3600 if arg.abs <= 13
+ all.find { |z| z.utc_offset == arg.to_i }
+ else
+ raise ArgumentError, "invalid argument to TimeZone[]: #{arg.inspect}"
+ end
+ end
+
+ # A regular expression that matches the names of all time zones in
+ # the USA.
+ US_ZONES = /US|Arizona|Indiana|Hawaii|Alaska/ unless defined?(US_ZONES)
+
+ # A convenience method for returning a collection of TimeZone objects
+ # for time zones in the USA.
+ def us_zones
+ all.find_all { |z| z.name =~ US_ZONES }
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/values/unicode_tables.dat b/vendor/rails-2.0.2/activesupport/lib/active_support/values/unicode_tables.dat
new file mode 100644
index 000000000..35edb148c
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/values/unicode_tables.dat
Binary files differ
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/vendor.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/vendor.rb
new file mode 100644
index 000000000..75c18062c
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/vendor.rb
@@ -0,0 +1,14 @@
+# Prefer gems to the bundled libs.
+require 'rubygems'
+
+begin
+ gem 'builder', '~> 2.1.2'
+rescue Gem::LoadError
+ $:.unshift "#{File.dirname(__FILE__)}/vendor/builder-2.1.2"
+end
+
+begin
+ gem 'xml-simple', '~> 1.0.11'
+rescue Gem::LoadError
+ $:.unshift "#{File.dirname(__FILE__)}/vendor/xml-simple-1.0.11"
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/blankslate.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/blankslate.rb
new file mode 100644
index 000000000..da6034d9c
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/blankslate.rb
@@ -0,0 +1,113 @@
+#!/usr/bin/env ruby
+#--
+# Copyright 2004, 2006 by Jim Weirich (jim@weirichhouse.org).
+# All rights reserved.
+
+# Permission is granted for use, copying, modification, distribution,
+# and distribution of modified versions of this work as long as the
+# above copyright notice is included.
+#++
+
+######################################################################
+# BlankSlate provides an abstract base class with no predefined
+# methods (except for <tt>\_\_send__</tt> and <tt>\_\_id__</tt>).
+# BlankSlate is useful as a base class when writing classes that
+# depend upon <tt>method_missing</tt> (e.g. dynamic proxies).
+#
+class BlankSlate
+ class << self
+
+ # Hide the method named +name+ in the BlankSlate class. Don't
+ # hide +instance_eval+ or any method beginning with "__".
+ def hide(name)
+ if instance_methods.include?(name.to_s) and
+ name !~ /^(__|instance_eval)/
+ @hidden_methods ||= {}
+ @hidden_methods[name.to_sym] = instance_method(name)
+ undef_method name
+ end
+ end
+
+ def find_hidden_method(name)
+ @hidden_methods ||= {}
+ @hidden_methods[name] || superclass.find_hidden_method(name)
+ end
+
+ # Redefine a previously hidden method so that it may be called on a blank
+ # slate object.
+ def reveal(name)
+ bound_method = nil
+ unbound_method = find_hidden_method(name)
+ fail "Don't know how to reveal method '#{name}'" unless unbound_method
+ define_method(name) do |*args|
+ bound_method ||= unbound_method.bind(self)
+ bound_method.call(*args)
+ end
+ end
+ end
+
+ instance_methods.each { |m| hide(m) }
+end
+
+######################################################################
+# Since Ruby is very dynamic, methods added to the ancestors of
+# BlankSlate <em>after BlankSlate is defined</em> will show up in the
+# list of available BlankSlate methods. We handle this by defining a
+# hook in the Object and Kernel classes that will hide any method
+# defined after BlankSlate has been loaded.
+#
+module Kernel
+ class << self
+ alias_method :blank_slate_method_added, :method_added
+
+ # Detect method additions to Kernel and remove them in the
+ # BlankSlate class.
+ def method_added(name)
+ result = blank_slate_method_added(name)
+ return result if self != Kernel
+ BlankSlate.hide(name)
+ result
+ end
+ end
+end
+
+######################################################################
+# Same as above, except in Object.
+#
+class Object
+ class << self
+ alias_method :blank_slate_method_added, :method_added
+
+ # Detect method additions to Object and remove them in the
+ # BlankSlate class.
+ def method_added(name)
+ result = blank_slate_method_added(name)
+ return result if self != Object
+ BlankSlate.hide(name)
+ result
+ end
+
+ def find_hidden_method(name)
+ nil
+ end
+ end
+end
+
+######################################################################
+# Also, modules included into Object need to be scanned and have their
+# instance methods removed from blank slate. In theory, modules
+# included into Kernel would have to be removed as well, but a
+# "feature" of Ruby prevents late includes into modules from being
+# exposed in the first place.
+#
+class Module
+ alias blankslate_original_append_features append_features
+ def append_features(mod)
+ result = blankslate_original_append_features(mod)
+ return result if mod != Object
+ instance_methods.each do |name|
+ BlankSlate.hide(name)
+ end
+ result
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder.rb
new file mode 100644
index 000000000..971927766
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder.rb
@@ -0,0 +1,13 @@
+#!/usr/bin/env ruby
+
+#--
+# Copyright 2004 by Jim Weirich (jim@weirichhouse.org).
+# All rights reserved.
+
+# Permission is granted for use, copying, modification, distribution,
+# and distribution of modified versions of this work as long as the
+# above copyright notice is included.
+#++
+
+require 'builder/xmlmarkup'
+require 'builder/xmlevents'
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/blankslate.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/blankslate.rb
new file mode 100644
index 000000000..2935b6f1d
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/blankslate.rb
@@ -0,0 +1,20 @@
+#!/usr/bin/env ruby
+#--
+# Copyright 2004, 2006 by Jim Weirich (jim@weirichhouse.org).
+# All rights reserved.
+
+# Permission is granted for use, copying, modification, distribution,
+# and distribution of modified versions of this work as long as the
+# above copyright notice is included.
+#++
+
+require 'blankslate'
+
+######################################################################
+# BlankSlate has been promoted to a top level name and is now
+# available as a standalone gem. We make the name available in the
+# Builder namespace for compatibility.
+#
+module Builder
+ BlankSlate = ::BlankSlate
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb
new file mode 100644
index 000000000..e086a1b13
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb
@@ -0,0 +1,250 @@
+#!/usr/bin/env ruby
+#--
+# Copyright 2004, 2005 by Jim Weirich (jim@weirichhouse.org).
+# Copyright 2005 by Scott Barron (scott@elitists.net).
+# All rights reserved.
+#
+# Permission is granted for use, copying, modification, distribution,
+# and distribution of modified versions of this work as long as the
+# above copyright notice is included.
+#
+# Much of this is taken from Jim's work in xmlbase.rb and xmlmarkup.rb.
+# Documentation has also been copied and pasted and modified to reflect
+# that we're building CSS here instead of XML. Jim is conducting the
+# orchestra here and I'm just off in the corner playing a flute.
+#++
+
+# Provide a flexible and easy to use Builder for creating Cascading
+# Style Sheets (CSS).
+
+
+require 'builder/blankslate'
+
+module Builder
+
+ # Create a Cascading Style Sheet (CSS) using Ruby.
+ #
+ # Example usage:
+ #
+ # css = Builder::CSS.new
+ #
+ # text_color = '#7F7F7F'
+ # preferred_fonts = 'Helvetica, Arial, sans_serif'
+ #
+ # css.comment! 'This is our stylesheet'
+ # css.body {
+ # background_color '#FAFAFA'
+ # font_size 'small'
+ # font_family preferred_fonts
+ # color text_color
+ # }
+ #
+ # css.id!('navbar') {
+ # width '500px'
+ # }
+ #
+ # css.class!('navitem') {
+ # color 'red'
+ # }
+ #
+ # css.a :hover {
+ # text_decoration 'underline'
+ # }
+ #
+ # css.div(:id => 'menu') {
+ # background 'green'
+ # }
+ #
+ # css.div(:class => 'foo') {
+ # background 'red'
+ # }
+ #
+ # This will yield the following stylesheet:
+ #
+ # /* This is our stylesheet */
+ # body {
+ # background_color: #FAFAFA;
+ # font_size: small;
+ # font_family: Helvetica, Arial, sans_serif;
+ # color: #7F7F7F;
+ # }
+ #
+ # #navbar {
+ # width: 500px;
+ # }
+ #
+ # .navitem {
+ # color: red;
+ # }
+ #
+ # a:hover {
+ # text_decoration: underline;
+ # }
+ #
+ # div#menu {
+ # background: green;
+ # }
+ #
+ # div.foo {
+ # background: red;
+ # }
+ #
+ class CSS < BlankSlate
+
+ # Create a CSS builder.
+ #
+ # out:: Object receiving the markup.1 +out+ must respond to
+ # <tt><<</tt>.
+ # indent:: Number of spaces used for indentation (0 implies no
+ # indentation and no line breaks).
+ #
+ def initialize(indent=2)
+ @indent = indent
+ @target = []
+ @parts = []
+ @library = {}
+ end
+
+ def +(part)
+ _join_with_op! '+'
+ self
+ end
+
+ def >>(part)
+ _join_with_op! ''
+ self
+ end
+
+ def >(part)
+ _join_with_op! '>'
+ self
+ end
+
+ def |(part)
+ _join_with_op! ','
+ self
+ end
+
+ # Return the target of the builder
+ def target!
+ @target * ''
+ end
+
+ # Create a comment string in the output.
+ def comment!(comment_text)
+ @target << "/* #{comment_text} */\n"
+ end
+
+ def id!(arg, &block)
+ _start_container('#'+arg.to_s, nil, block_given?)
+ _css_block(block) if block
+ _unify_block
+ self
+ end
+
+ def class!(arg, &block)
+ _start_container('.'+arg.to_s, nil, block_given?)
+ _css_block(block) if block
+ _unify_block
+ self
+ end
+
+ def store!(sym, &block)
+ @library[sym] = block.to_proc
+ end
+
+ def group!(*args, &block)
+ args.each do |arg|
+ if arg.is_a?(Symbol)
+ instance_eval(&@library[arg])
+ else
+ instance_eval(&arg)
+ end
+ _text ', ' unless arg == args.last
+ end
+ if block
+ _css_block(block)
+ _unify_block
+ end
+ end
+
+ def method_missing(sym, *args, &block)
+ sym = "#{sym}:#{args.shift}" if args.first.kind_of?(Symbol)
+ if block
+ _start_container(sym, args.first)
+ _css_block(block)
+ _unify_block
+ elsif @in_block
+ _indent
+ _css_line(sym, *args)
+ _newline
+ return self
+ else
+ _start_container(sym, args.first, false)
+ _unify_block
+ end
+ self
+ end
+
+ # "Cargo culted" from Jim who also "cargo culted" it. See xmlbase.rb.
+ def nil?
+ false
+ end
+
+ private
+ def _unify_block
+ @target << @parts * ''
+ @parts = []
+ end
+
+ def _join_with_op!(op)
+ rhs, lhs = @target.pop, @target.pop
+ @target << "#{lhs} #{op} #{rhs}"
+ end
+
+ def _text(text)
+ @parts << text
+ end
+
+ def _css_block(block)
+ _newline
+ _nested_structures(block)
+ _end_container
+ _end_block
+ end
+
+ def _end_block
+ _newline
+ _newline
+ end
+
+ def _newline
+ _text "\n"
+ end
+
+ def _indent
+ _text ' ' * @indent
+ end
+
+ def _nested_structures(block)
+ @in_block = true
+ self.instance_eval(&block)
+ @in_block = false
+ end
+
+ def _start_container(sym, atts = {}, with_bracket = true)
+ selector = sym.to_s
+ selector << ".#{atts[:class]}" if atts && atts[:class]
+ selector << '#' + "#{atts[:id]}" if atts && atts[:id]
+ @parts << "#{selector}#{with_bracket ? ' {' : ''}"
+ end
+
+ def _end_container
+ @parts << "}"
+ end
+
+ def _css_line(sym, *args)
+ _text("#{sym.to_s.gsub('_','-')}: #{args * ' '};")
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xchar.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xchar.rb
new file mode 100644
index 000000000..8bdbd0589
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xchar.rb
@@ -0,0 +1,115 @@
+#!/usr/bin/env ruby
+
+# The XChar library is provided courtesy of Sam Ruby (See
+# http://intertwingly.net/stories/2005/09/28/xchar.rb)
+
+# --------------------------------------------------------------------
+
+# If the Builder::XChar module is not currently defined, fail on any
+# name clashes in standard library classes.
+
+module Builder
+ def self.check_for_name_collision(klass, method_name, defined_constant=nil)
+ if klass.instance_methods.include?(method_name.to_s)
+ fail RuntimeError,
+ "Name Collision: Method '#{method_name}' is already defined in #{klass}"
+ end
+ end
+end
+
+if ! defined?(Builder::XChar)
+ Builder.check_for_name_collision(String, "to_xs")
+ Builder.check_for_name_collision(Fixnum, "xchr")
+end
+
+######################################################################
+module Builder
+
+ ####################################################################
+ # XML Character converter, from Sam Ruby:
+ # (see http://intertwingly.net/stories/2005/09/28/xchar.rb).
+ #
+ module XChar # :nodoc:
+
+ # See
+ # http://intertwingly.net/stories/2004/04/14/i18n.html#CleaningWindows
+ # for details.
+ CP1252 = { # :nodoc:
+ 128 => 8364, # euro sign
+ 130 => 8218, # single low-9 quotation mark
+ 131 => 402, # latin small letter f with hook
+ 132 => 8222, # double low-9 quotation mark
+ 133 => 8230, # horizontal ellipsis
+ 134 => 8224, # dagger
+ 135 => 8225, # double dagger
+ 136 => 710, # modifier letter circumflex accent
+ 137 => 8240, # per mille sign
+ 138 => 352, # latin capital letter s with caron
+ 139 => 8249, # single left-pointing angle quotation mark
+ 140 => 338, # latin capital ligature oe
+ 142 => 381, # latin capital letter z with caron
+ 145 => 8216, # left single quotation mark
+ 146 => 8217, # right single quotation mark
+ 147 => 8220, # left double quotation mark
+ 148 => 8221, # right double quotation mark
+ 149 => 8226, # bullet
+ 150 => 8211, # en dash
+ 151 => 8212, # em dash
+ 152 => 732, # small tilde
+ 153 => 8482, # trade mark sign
+ 154 => 353, # latin small letter s with caron
+ 155 => 8250, # single right-pointing angle quotation mark
+ 156 => 339, # latin small ligature oe
+ 158 => 382, # latin small letter z with caron
+ 159 => 376, # latin capital letter y with diaeresis
+ }
+
+ # See http://www.w3.org/TR/REC-xml/#dt-chardata for details.
+ PREDEFINED = {
+ 38 => '&amp;', # ampersand
+ 60 => '&lt;', # left angle bracket
+ 62 => '&gt;', # right angle bracket
+ }
+
+ # See http://www.w3.org/TR/REC-xml/#charsets for details.
+ VALID = [
+ 0x9, 0xA, 0xD,
+ (0x20..0xD7FF),
+ (0xE000..0xFFFD),
+ (0x10000..0x10FFFF)
+ ]
+ end
+
+end
+
+
+######################################################################
+# Enhance the Fixnum class with a XML escaped character conversion.
+#
+class Fixnum
+ XChar = Builder::XChar if ! defined?(XChar)
+
+ # XML escaped version of chr
+ def xchr
+ n = XChar::CP1252[self] || self
+ case n when *XChar::VALID
+ XChar::PREDEFINED[n] or (n<128 ? n.chr : "&##{n};")
+ else
+ '*'
+ end
+ end
+end
+
+
+######################################################################
+# Enhance the String class with a XML escaped character version of
+# to_s.
+#
+class String
+ # XML escaped version of to_s
+ def to_xs
+ unpack('U*').map {|n| n.xchr}.join # ASCII, UTF-8
+ rescue
+ unpack('C*').map {|n| n.xchr}.join # ISO-8859-1, WIN-1252
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb
new file mode 100644
index 000000000..ace4b56d5
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb
@@ -0,0 +1,139 @@
+#!/usr/bin/env ruby
+
+require 'builder/blankslate'
+
+module Builder
+
+ # Generic error for builder
+ class IllegalBlockError < RuntimeError; end
+
+ # XmlBase is a base class for building XML builders. See
+ # Builder::XmlMarkup and Builder::XmlEvents for examples.
+ class XmlBase < BlankSlate
+
+ # Create an XML markup builder.
+ #
+ # out:: Object receiving the markup. +out+ must respond to
+ # <tt><<</tt>.
+ # indent:: Number of spaces used for indentation (0 implies no
+ # indentation and no line breaks).
+ # initial:: Level of initial indentation.
+ #
+ def initialize(indent=0, initial=0)
+ @indent = indent
+ @level = initial
+ end
+
+ # Create a tag named +sym+. Other than the first argument which
+ # is the tag name, the arguments are the same as the tags
+ # implemented via <tt>method_missing</tt>.
+ def tag!(sym, *args, &block)
+ method_missing(sym.to_sym, *args, &block)
+ end
+
+ # Create XML markup based on the name of the method. This method
+ # is never invoked directly, but is called for each markup method
+ # in the markup block.
+ def method_missing(sym, *args, &block)
+ text = nil
+ attrs = nil
+ sym = "#{sym}:#{args.shift}" if args.first.kind_of?(Symbol)
+ args.each do |arg|
+ case arg
+ when Hash
+ attrs ||= {}
+ attrs.merge!(arg)
+ else
+ text ||= ''
+ text << arg.to_s
+ end
+ end
+ if block
+ unless text.nil?
+ raise ArgumentError, "XmlMarkup cannot mix a text argument with a block"
+ end
+ _indent
+ _start_tag(sym, attrs)
+ _newline
+ _nested_structures(block)
+ _indent
+ _end_tag(sym)
+ _newline
+ elsif text.nil?
+ _indent
+ _start_tag(sym, attrs, true)
+ _newline
+ else
+ _indent
+ _start_tag(sym, attrs)
+ text! text
+ _end_tag(sym)
+ _newline
+ end
+ @target
+ end
+
+ # Append text to the output target. Escape any markup. May be
+ # used within the markup brackets as:
+ #
+ # builder.p { |b| b.br; b.text! "HI" } #=> <p><br/>HI</p>
+ def text!(text)
+ _text(_escape(text))
+ end
+
+ # Append text to the output target without escaping any markup.
+ # May be used within the markup brackets as:
+ #
+ # builder.p { |x| x << "<br/>HI" } #=> <p><br/>HI</p>
+ #
+ # This is useful when using non-builder enabled software that
+ # generates strings. Just insert the string directly into the
+ # builder without changing the inserted markup.
+ #
+ # It is also useful for stacking builder objects. Builders only
+ # use <tt><<</tt> to append to the target, so by supporting this
+ # method/operation builders can use other builders as their
+ # targets.
+ def <<(text)
+ _text(text)
+ end
+
+ # For some reason, nil? is sent to the XmlMarkup object. If nil?
+ # is not defined and method_missing is invoked, some strange kind
+ # of recursion happens. Since nil? won't ever be an XML tag, it
+ # is pretty safe to define it here. (Note: this is an example of
+ # cargo cult programming,
+ # cf. http://fishbowl.pastiche.org/2004/10/13/cargo_cult_programming).
+ def nil?
+ false
+ end
+
+ private
+
+ require 'builder/xchar'
+ def _escape(text)
+ text.to_xs
+ end
+
+ def _escape_quote(text)
+ _escape(text).gsub(%r{"}, '&quot;') # " WART
+ end
+
+ def _newline
+ return if @indent == 0
+ text! "\n"
+ end
+
+ def _indent
+ return if @indent == 0 || @level == 0
+ text!(" " * (@level * @indent))
+ end
+
+ def _nested_structures(block)
+ @level += 1
+ block.call(self)
+ ensure
+ @level -= 1
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb
new file mode 100644
index 000000000..91fcd21e1
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb
@@ -0,0 +1,63 @@
+#!/usr/bin/env ruby
+
+#--
+# Copyright 2004 by Jim Weirich (jim@weirichhouse.org).
+# All rights reserved.
+
+# Permission is granted for use, copying, modification, distribution,
+# and distribution of modified versions of this work as long as the
+# above copyright notice is included.
+#++
+
+require 'builder/xmlmarkup'
+
+module Builder
+
+ # Create a series of SAX-like XML events (e.g. start_tag, end_tag)
+ # from the markup code. XmlEvent objects are used in a way similar
+ # to XmlMarkup objects, except that a series of events are generated
+ # and passed to a handler rather than generating character-based
+ # markup.
+ #
+ # Usage:
+ # xe = Builder::XmlEvents.new(hander)
+ # xe.title("HI") # Sends start_tag/end_tag/text messages to the handler.
+ #
+ # Indentation may also be selected by providing value for the
+ # indentation size and initial indentation level.
+ #
+ # xe = Builder::XmlEvents.new(handler, indent_size, initial_indent_level)
+ #
+ # == XML Event Handler
+ #
+ # The handler object must expect the following events.
+ #
+ # [<tt>start_tag(tag, attrs)</tt>]
+ # Announces that a new tag has been found. +tag+ is the name of
+ # the tag and +attrs+ is a hash of attributes for the tag.
+ #
+ # [<tt>end_tag(tag)</tt>]
+ # Announces that an end tag for +tag+ has been found.
+ #
+ # [<tt>text(text)</tt>]
+ # Announces that a string of characters (+text+) has been found.
+ # A series of characters may be broken up into more than one
+ # +text+ call, so the client cannot assume that a single
+ # callback contains all the text data.
+ #
+ class XmlEvents < XmlMarkup
+ def text!(text)
+ @target.text(text)
+ end
+
+ def _start_tag(sym, attrs, end_too=false)
+ @target.start_tag(sym, attrs)
+ _end_tag(sym) if end_too
+ end
+
+ def _end_tag(sym)
+ @target.end_tag(sym)
+ end
+ end
+
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb
new file mode 100644
index 000000000..ec59dddc3
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb
@@ -0,0 +1,328 @@
+#!/usr/bin/env ruby
+#--
+# Copyright 2004, 2005 by Jim Weirich (jim@weirichhouse.org).
+# All rights reserved.
+
+# Permission is granted for use, copying, modification, distribution,
+# and distribution of modified versions of this work as long as the
+# above copyright notice is included.
+#++
+
+# Provide a flexible and easy to use Builder for creating XML markup.
+# See XmlBuilder for usage details.
+
+require 'builder/xmlbase'
+
+module Builder
+
+ # Create XML markup easily. All (well, almost all) methods sent to
+ # an XmlMarkup object will be translated to the equivalent XML
+ # markup. Any method with a block will be treated as an XML markup
+ # tag with nested markup in the block.
+ #
+ # Examples will demonstrate this easier than words. In the
+ # following, +xm+ is an +XmlMarkup+ object.
+ #
+ # xm.em("emphasized") # => <em>emphasized</em>
+ # xm.em { xmm.b("emp & bold") } # => <em><b>emph &amp; bold</b></em>
+ # xm.a("A Link", "href"=>"http://onestepback.org")
+ # # => <a href="http://onestepback.org">A Link</a>
+ # xm.div { br } # => <div><br/></div>
+ # xm.target("name"=>"compile", "option"=>"fast")
+ # # => <target option="fast" name="compile"\>
+ # # NOTE: order of attributes is not specified.
+ #
+ # xm.instruct! # <?xml version="1.0" encoding="UTF-8"?>
+ # xm.html { # <html>
+ # xm.head { # <head>
+ # xm.title("History") # <title>History</title>
+ # } # </head>
+ # xm.body { # <body>
+ # xm.comment! "HI" # <! -- HI -->
+ # xm.h1("Header") # <h1>Header</h1>
+ # xm.p("paragraph") # <p>paragraph</p>
+ # } # </body>
+ # } # </html>
+ #
+ # == Notes:
+ #
+ # * The order that attributes are inserted in markup tags is
+ # undefined.
+ #
+ # * Sometimes you wish to insert text without enclosing tags. Use
+ # the <tt>text!</tt> method to accomplish this.
+ #
+ # Example:
+ #
+ # xm.div { # <div>
+ # xm.text! "line"; xm.br # line<br/>
+ # xm.text! "another line"; xmbr # another line<br/>
+ # } # </div>
+ #
+ # * The special XML characters <, >, and & are converted to &lt;,
+ # &gt; and &amp; automatically. Use the <tt><<</tt> operation to
+ # insert text without modification.
+ #
+ # * Sometimes tags use special characters not allowed in ruby
+ # identifiers. Use the <tt>tag!</tt> method to handle these
+ # cases.
+ #
+ # Example:
+ #
+ # xml.tag!("SOAP:Envelope") { ... }
+ #
+ # will produce ...
+ #
+ # <SOAP:Envelope> ... </SOAP:Envelope>"
+ #
+ # <tt>tag!</tt> will also take text and attribute arguments (after
+ # the tag name) like normal markup methods. (But see the next
+ # bullet item for a better way to handle XML namespaces).
+ #
+ # * Direct support for XML namespaces is now available. If the
+ # first argument to a tag call is a symbol, it will be joined to
+ # the tag to produce a namespace:tag combination. It is easier to
+ # show this than describe it.
+ #
+ # xml.SOAP :Envelope do ... end
+ #
+ # Just put a space before the colon in a namespace to produce the
+ # right form for builder (e.g. "<tt>SOAP:Envelope</tt>" =>
+ # "<tt>xml.SOAP :Envelope</tt>")
+ #
+ # * XmlMarkup builds the markup in any object (called a _target_)
+ # that accepts the <tt><<</tt> method. If no target is given,
+ # then XmlMarkup defaults to a string target.
+ #
+ # Examples:
+ #
+ # xm = Builder::XmlMarkup.new
+ # result = xm.title("yada")
+ # # result is a string containing the markup.
+ #
+ # buffer = ""
+ # xm = Builder::XmlMarkup.new(buffer)
+ # # The markup is appended to buffer (using <<)
+ #
+ # xm = Builder::XmlMarkup.new(STDOUT)
+ # # The markup is written to STDOUT (using <<)
+ #
+ # xm = Builder::XmlMarkup.new
+ # x2 = Builder::XmlMarkup.new(:target=>xm)
+ # # Markup written to +x2+ will be send to +xm+.
+ #
+ # * Indentation is enabled by providing the number of spaces to
+ # indent for each level as a second argument to XmlBuilder.new.
+ # Initial indentation may be specified using a third parameter.
+ #
+ # Example:
+ #
+ # xm = Builder.new(:indent=>2)
+ # # xm will produce nicely formatted and indented XML.
+ #
+ # xm = Builder.new(:indent=>2, :margin=>4)
+ # # xm will produce nicely formatted and indented XML with 2
+ # # spaces per indent and an over all indentation level of 4.
+ #
+ # builder = Builder::XmlMarkup.new(:target=>$stdout, :indent=>2)
+ # builder.name { |b| b.first("Jim"); b.last("Weirich) }
+ # # prints:
+ # # <name>
+ # # <first>Jim</first>
+ # # <last>Weirich</last>
+ # # </name>
+ #
+ # * The instance_eval implementation which forces self to refer to
+ # the message receiver as self is now obsolete. We now use normal
+ # block calls to execute the markup block. This means that all
+ # markup methods must now be explicitly send to the xml builder.
+ # For instance, instead of
+ #
+ # xml.div { strong("text") }
+ #
+ # you need to write:
+ #
+ # xml.div { xml.strong("text") }
+ #
+ # Although more verbose, the subtle change in semantics within the
+ # block was found to be prone to error. To make this change a
+ # little less cumbersome, the markup block now gets the markup
+ # object sent as an argument, allowing you to use a shorter alias
+ # within the block.
+ #
+ # For example:
+ #
+ # xml_builder = Builder::XmlMarkup.new
+ # xml_builder.div { |xml|
+ # xml.stong("text")
+ # }
+ #
+ class XmlMarkup < XmlBase
+
+ # Create an XML markup builder. Parameters are specified by an
+ # option hash.
+ #
+ # :target=><em>target_object</em>::
+ # Object receiving the markup. +out+ must respond to the
+ # <tt><<</tt> operator. The default is a plain string target.
+ #
+ # :indent=><em>indentation</em>::
+ # Number of spaces used for indentation. The default is no
+ # indentation and no line breaks.
+ #
+ # :margin=><em>initial_indentation_level</em>::
+ # Amount of initial indentation (specified in levels, not
+ # spaces).
+ #
+ # :escape_attrs=><b>OBSOLETE</em>::
+ # The :escape_attrs option is no longer supported by builder
+ # (and will be quietly ignored). String attribute values are
+ # now automatically escaped. If you need unescaped attribute
+ # values (perhaps you are using entities in the attribute
+ # values), then give the value as a Symbol. This allows much
+ # finer control over escaping attribute values.
+ #
+ def initialize(options={})
+ indent = options[:indent] || 0
+ margin = options[:margin] || 0
+ super(indent, margin)
+ @target = options[:target] || ""
+ end
+
+ # Return the target of the builder.
+ def target!
+ @target
+ end
+
+ def comment!(comment_text)
+ _ensure_no_block block_given?
+ _special("<!-- ", " -->", comment_text, nil)
+ end
+
+ # Insert an XML declaration into the XML markup.
+ #
+ # For example:
+ #
+ # xml.declare! :ELEMENT, :blah, "yada"
+ # # => <!ELEMENT blah "yada">
+ def declare!(inst, *args, &block)
+ _indent
+ @target << "<!#{inst}"
+ args.each do |arg|
+ case arg
+ when String
+ @target << %{ "#{arg}"} # " WART
+ when Symbol
+ @target << " #{arg}"
+ end
+ end
+ if block_given?
+ @target << " ["
+ _newline
+ _nested_structures(block)
+ @target << "]"
+ end
+ @target << ">"
+ _newline
+ end
+
+ # Insert a processing instruction into the XML markup. E.g.
+ #
+ # For example:
+ #
+ # xml.instruct!
+ # #=> <?xml version="1.0" encoding="UTF-8"?>
+ # xml.instruct! :aaa, :bbb=>"ccc"
+ # #=> <?aaa bbb="ccc"?>
+ #
+ def instruct!(directive_tag=:xml, attrs={})
+ _ensure_no_block block_given?
+ if directive_tag == :xml
+ a = { :version=>"1.0", :encoding=>"UTF-8" }
+ attrs = a.merge attrs
+ end
+ _special(
+ "<?#{directive_tag}",
+ "?>",
+ nil,
+ attrs,
+ [:version, :encoding, :standalone])
+ end
+
+ # Insert a CDATA section into the XML markup.
+ #
+ # For example:
+ #
+ # xml.cdata!("text to be included in cdata")
+ # #=> <![CDATA[text to be included in cdata]]>
+ #
+ def cdata!(text)
+ _ensure_no_block block_given?
+ _special("<![CDATA[", "]]>", text, nil)
+ end
+
+ private
+
+ # NOTE: All private methods of a builder object are prefixed when
+ # a "_" character to avoid possible conflict with XML tag names.
+
+ # Insert text directly in to the builder's target.
+ def _text(text)
+ @target << text
+ end
+
+ # Insert special instruction.
+ def _special(open, close, data=nil, attrs=nil, order=[])
+ _indent
+ @target << open
+ @target << data if data
+ _insert_attributes(attrs, order) if attrs
+ @target << close
+ _newline
+ end
+
+ # Start an XML tag. If <tt>end_too</tt> is true, then the start
+ # tag is also the end tag (e.g. <br/>
+ def _start_tag(sym, attrs, end_too=false)
+ @target << "<#{sym}"
+ _insert_attributes(attrs)
+ @target << "/" if end_too
+ @target << ">"
+ end
+
+ # Insert an ending tag.
+ def _end_tag(sym)
+ @target << "</#{sym}>"
+ end
+
+ # Insert the attributes (given in the hash).
+ def _insert_attributes(attrs, order=[])
+ return if attrs.nil?
+ order.each do |k|
+ v = attrs[k]
+ @target << %{ #{k}="#{_attr_value(v)}"} if v # " WART
+ end
+ attrs.each do |k, v|
+ @target << %{ #{k}="#{_attr_value(v)}"} unless order.member?(k) # " WART
+ end
+ end
+
+ def _attr_value(value)
+ case value
+ when Symbol
+ value.to_s
+ else
+ _escape_quote(value.to_s)
+ end
+ end
+
+ def _ensure_no_block(got_block)
+ if got_block
+ fail IllegalBlockError,
+ "Blocks are not allowed on XML instructions"
+ end
+ end
+
+ end
+
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb
new file mode 100644
index 000000000..0de24c0ef
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb
@@ -0,0 +1,1021 @@
+# = XmlSimple
+#
+# Author:: Maik Schmidt <contact@maik-schmidt.de>
+# Copyright:: Copyright (c) 2003-2006 Maik Schmidt
+# License:: Distributes under the same terms as Ruby.
+#
+require 'rexml/document'
+require 'stringio'
+
+# Easy API to maintain XML (especially configuration files).
+class XmlSimple
+ include REXML
+
+ @@VERSION = '1.0.11'
+
+ # A simple cache for XML documents that were already transformed
+ # by xml_in.
+ class Cache
+ # Creates and initializes a new Cache object.
+ def initialize
+ @mem_share_cache = {}
+ @mem_copy_cache = {}
+ end
+
+ # Saves a data structure into a file.
+ #
+ # data::
+ # Data structure to be saved.
+ # filename::
+ # Name of the file belonging to the data structure.
+ def save_storable(data, filename)
+ cache_file = get_cache_filename(filename)
+ File.open(cache_file, "w+") { |f| Marshal.dump(data, f) }
+ end
+
+ # Restores a data structure from a file. If restoring the data
+ # structure failed for any reason, nil will be returned.
+ #
+ # filename::
+ # Name of the file belonging to the data structure.
+ def restore_storable(filename)
+ cache_file = get_cache_filename(filename)
+ return nil unless File::exist?(cache_file)
+ return nil unless File::mtime(cache_file).to_i > File::mtime(filename).to_i
+ data = nil
+ File.open(cache_file) { |f| data = Marshal.load(f) }
+ data
+ end
+
+ # Saves a data structure in a shared memory cache.
+ #
+ # data::
+ # Data structure to be saved.
+ # filename::
+ # Name of the file belonging to the data structure.
+ def save_mem_share(data, filename)
+ @mem_share_cache[filename] = [Time::now.to_i, data]
+ end
+
+ # Restores a data structure from a shared memory cache. You
+ # should consider these elements as "read only". If restoring
+ # the data structure failed for any reason, nil will be
+ # returned.
+ #
+ # filename::
+ # Name of the file belonging to the data structure.
+ def restore_mem_share(filename)
+ get_from_memory_cache(filename, @mem_share_cache)
+ end
+
+ # Copies a data structure to a memory cache.
+ #
+ # data::
+ # Data structure to be copied.
+ # filename::
+ # Name of the file belonging to the data structure.
+ def save_mem_copy(data, filename)
+ @mem_share_cache[filename] = [Time::now.to_i, Marshal.dump(data)]
+ end
+
+ # Restores a data structure from a memory cache. If restoring
+ # the data structure failed for any reason, nil will be
+ # returned.
+ #
+ # filename::
+ # Name of the file belonging to the data structure.
+ def restore_mem_copy(filename)
+ data = get_from_memory_cache(filename, @mem_share_cache)
+ data = Marshal.load(data) unless data.nil?
+ data
+ end
+
+ private
+
+ # Returns the "cache filename" belonging to a filename, i.e.
+ # the extension '.xml' in the original filename will be replaced
+ # by '.stor'. If filename does not have this extension, '.stor'
+ # will be appended.
+ #
+ # filename::
+ # Filename to get "cache filename" for.
+ def get_cache_filename(filename)
+ filename.sub(/(\.xml)?$/, '.stor')
+ end
+
+ # Returns a cache entry from a memory cache belonging to a
+ # certain filename. If no entry could be found for any reason,
+ # nil will be returned.
+ #
+ # filename::
+ # Name of the file the cache entry belongs to.
+ # cache::
+ # Memory cache to get entry from.
+ def get_from_memory_cache(filename, cache)
+ return nil unless cache[filename]
+ return nil unless cache[filename][0] > File::mtime(filename).to_i
+ return cache[filename][1]
+ end
+ end
+
+ # Create a "global" cache.
+ @@cache = Cache.new
+
+ # Creates and intializes a new XmlSimple object.
+ #
+ # defaults::
+ # Default values for options.
+ def initialize(defaults = nil)
+ unless defaults.nil? || defaults.instance_of?(Hash)
+ raise ArgumentError, "Options have to be a Hash."
+ end
+ @default_options = normalize_option_names(defaults, (KNOWN_OPTIONS['in'] + KNOWN_OPTIONS['out']).uniq)
+ @options = Hash.new
+ @_var_values = nil
+ end
+
+ # Converts an XML document in the same way as the Perl module XML::Simple.
+ #
+ # string::
+ # XML source. Could be one of the following:
+ #
+ # - nil: Tries to load and parse '<scriptname>.xml'.
+ # - filename: Tries to load and parse filename.
+ # - IO object: Reads from object until EOF is detected and parses result.
+ # - XML string: Parses string.
+ #
+ # options::
+ # Options to be used.
+ def xml_in(string = nil, options = nil)
+ handle_options('in', options)
+
+ # If no XML string or filename was supplied look for scriptname.xml.
+ if string.nil?
+ string = File::basename($0)
+ string.sub!(/\.[^.]+$/, '')
+ string += '.xml'
+
+ directory = File::dirname($0)
+ @options['searchpath'].unshift(directory) unless directory.nil?
+ end
+
+ if string.instance_of?(String)
+ if string =~ /<.*?>/m
+ @doc = parse(string)
+ elsif string == '-'
+ @doc = parse($stdin.readlines.to_s)
+ else
+ filename = find_xml_file(string, @options['searchpath'])
+
+ if @options.has_key?('cache')
+ @options['cache'].each { |scheme|
+ case(scheme)
+ when 'storable'
+ content = @@cache.restore_storable(filename)
+ when 'mem_share'
+ content = @@cache.restore_mem_share(filename)
+ when 'mem_copy'
+ content = @@cache.restore_mem_copy(filename)
+ else
+ raise ArgumentError, "Unsupported caching scheme: <#{scheme}>."
+ end
+ return content if content
+ }
+ end
+
+ @doc = load_xml_file(filename)
+ end
+ elsif string.kind_of?(IO) || string.kind_of?(StringIO)
+ @doc = parse(string.readlines.to_s)
+ else
+ raise ArgumentError, "Could not parse object of type: <#{string.type}>."
+ end
+
+ result = collapse(@doc.root)
+ result = @options['keeproot'] ? merge({}, @doc.root.name, result) : result
+ put_into_cache(result, filename)
+ result
+ end
+
+ # This is the functional version of the instance method xml_in.
+ def XmlSimple.xml_in(string = nil, options = nil)
+ xml_simple = XmlSimple.new
+ xml_simple.xml_in(string, options)
+ end
+
+ # Converts a data structure into an XML document.
+ #
+ # ref::
+ # Reference to data structure to be converted into XML.
+ # options::
+ # Options to be used.
+ def xml_out(ref, options = nil)
+ handle_options('out', options)
+ if ref.instance_of?(Array)
+ ref = { @options['anonymoustag'] => ref }
+ end
+
+ if @options['keeproot']
+ keys = ref.keys
+ if keys.size == 1
+ ref = ref[keys[0]]
+ @options['rootname'] = keys[0]
+ end
+ elsif @options['rootname'] == ''
+ if ref.instance_of?(Hash)
+ refsave = ref
+ ref = {}
+ refsave.each { |key, value|
+ if !scalar(value)
+ ref[key] = value
+ else
+ ref[key] = [ value.to_s ]
+ end
+ }
+ end
+ end
+
+ @ancestors = []
+ xml = value_to_xml(ref, @options['rootname'], '')
+ @ancestors = nil
+
+ if @options['xmldeclaration']
+ xml = @options['xmldeclaration'] + "\n" + xml
+ end
+
+ if @options.has_key?('outputfile')
+ if @options['outputfile'].kind_of?(IO)
+ return @options['outputfile'].write(xml)
+ else
+ File.open(@options['outputfile'], "w") { |file| file.write(xml) }
+ end
+ end
+ xml
+ end
+
+ # This is the functional version of the instance method xml_out.
+ def XmlSimple.xml_out(hash, options = nil)
+ xml_simple = XmlSimple.new
+ xml_simple.xml_out(hash, options)
+ end
+
+ private
+
+ # Declare options that are valid for xml_in and xml_out.
+ KNOWN_OPTIONS = {
+ 'in' => %w(
+ keyattr keeproot forcecontent contentkey noattr
+ searchpath forcearray suppressempty anonymoustag
+ cache grouptags normalisespace normalizespace
+ variables varattr keytosymbol
+ ),
+ 'out' => %w(
+ keyattr keeproot contentkey noattr rootname
+ xmldeclaration outputfile noescape suppressempty
+ anonymoustag indent grouptags noindent
+ )
+ }
+
+ # Define some reasonable defaults.
+ DEF_KEY_ATTRIBUTES = []
+ DEF_ROOT_NAME = 'opt'
+ DEF_CONTENT_KEY = 'content'
+ DEF_XML_DECLARATION = "<?xml version='1.0' standalone='yes'?>"
+ DEF_ANONYMOUS_TAG = 'anon'
+ DEF_FORCE_ARRAY = true
+ DEF_INDENTATION = ' '
+ DEF_KEY_TO_SYMBOL = false
+
+ # Normalizes option names in a hash, i.e., turns all
+ # characters to lower case and removes all underscores.
+ # Additionally, this method checks, if an unknown option
+ # was used and raises an according exception.
+ #
+ # options::
+ # Hash to be normalized.
+ # known_options::
+ # List of known options.
+ def normalize_option_names(options, known_options)
+ return nil if options.nil?
+ result = Hash.new
+ options.each { |key, value|
+ lkey = key.downcase
+ lkey.gsub!(/_/, '')
+ if !known_options.member?(lkey)
+ raise ArgumentError, "Unrecognised option: #{lkey}."
+ end
+ result[lkey] = value
+ }
+ result
+ end
+
+ # Merges a set of options with the default options.
+ #
+ # direction::
+ # 'in': If options should be handled for xml_in.
+ # 'out': If options should be handled for xml_out.
+ # options::
+ # Options to be merged with the default options.
+ def handle_options(direction, options)
+ @options = options || Hash.new
+
+ raise ArgumentError, "Options must be a Hash!" unless @options.instance_of?(Hash)
+
+ unless KNOWN_OPTIONS.has_key?(direction)
+ raise ArgumentError, "Unknown direction: <#{direction}>."
+ end
+
+ known_options = KNOWN_OPTIONS[direction]
+ @options = normalize_option_names(@options, known_options)
+
+ unless @default_options.nil?
+ known_options.each { |option|
+ unless @options.has_key?(option)
+ if @default_options.has_key?(option)
+ @options[option] = @default_options[option]
+ end
+ end
+ }
+ end
+
+ unless @options.has_key?('noattr')
+ @options['noattr'] = false
+ end
+
+ if @options.has_key?('rootname')
+ @options['rootname'] = '' if @options['rootname'].nil?
+ else
+ @options['rootname'] = DEF_ROOT_NAME
+ end
+
+ if @options.has_key?('xmldeclaration') && @options['xmldeclaration'] == true
+ @options['xmldeclaration'] = DEF_XML_DECLARATION
+ end
+
+ @options['keytosymbol'] = DEF_KEY_TO_SYMBOL unless @options.has_key?('keytosymbol')
+
+ if @options.has_key?('contentkey')
+ if @options['contentkey'] =~ /^-(.*)$/
+ @options['contentkey'] = $1
+ @options['collapseagain'] = true
+ end
+ else
+ @options['contentkey'] = DEF_CONTENT_KEY
+ end
+
+ unless @options.has_key?('normalisespace')
+ @options['normalisespace'] = @options['normalizespace']
+ end
+ @options['normalisespace'] = 0 if @options['normalisespace'].nil?
+
+ if @options.has_key?('searchpath')
+ unless @options['searchpath'].instance_of?(Array)
+ @options['searchpath'] = [ @options['searchpath'] ]
+ end
+ else
+ @options['searchpath'] = []
+ end
+
+ if @options.has_key?('cache') && scalar(@options['cache'])
+ @options['cache'] = [ @options['cache'] ]
+ end
+
+ @options['anonymoustag'] = DEF_ANONYMOUS_TAG unless @options.has_key?('anonymoustag')
+
+ if !@options.has_key?('indent') || @options['indent'].nil?
+ @options['indent'] = DEF_INDENTATION
+ end
+
+ @options['indent'] = '' if @options.has_key?('noindent')
+
+ # Special cleanup for 'keyattr' which could be an array or
+ # a hash or left to default to array.
+ if @options.has_key?('keyattr')
+ if !scalar(@options['keyattr'])
+ # Convert keyattr => { elem => '+attr' }
+ # to keyattr => { elem => ['attr', '+'] }
+ if @options['keyattr'].instance_of?(Hash)
+ @options['keyattr'].each { |key, value|
+ if value =~ /^([-+])?(.*)$/
+ @options['keyattr'][key] = [$2, $1 ? $1 : '']
+ end
+ }
+ elsif !@options['keyattr'].instance_of?(Array)
+ raise ArgumentError, "'keyattr' must be String, Hash, or Array!"
+ end
+ else
+ @options['keyattr'] = [ @options['keyattr'] ]
+ end
+ else
+ @options['keyattr'] = DEF_KEY_ATTRIBUTES
+ end
+
+ if @options.has_key?('forcearray')
+ if @options['forcearray'].instance_of?(Regexp)
+ @options['forcearray'] = [ @options['forcearray'] ]
+ end
+
+ if @options['forcearray'].instance_of?(Array)
+ force_list = @options['forcearray']
+ unless force_list.empty?
+ @options['forcearray'] = {}
+ force_list.each { |tag|
+ if tag.instance_of?(Regexp)
+ unless @options['forcearray']['_regex'].instance_of?(Array)
+ @options['forcearray']['_regex'] = []
+ end
+ @options['forcearray']['_regex'] << tag
+ else
+ @options['forcearray'][tag] = true
+ end
+ }
+ else
+ @options['forcearray'] = false
+ end
+ else
+ @options['forcearray'] = @options['forcearray'] ? true : false
+ end
+ else
+ @options['forcearray'] = DEF_FORCE_ARRAY
+ end
+
+ if @options.has_key?('grouptags') && !@options['grouptags'].instance_of?(Hash)
+ raise ArgumentError, "Illegal value for 'GroupTags' option - expected a Hash."
+ end
+
+ if @options.has_key?('variables') && !@options['variables'].instance_of?(Hash)
+ raise ArgumentError, "Illegal value for 'Variables' option - expected a Hash."
+ end
+
+ if @options.has_key?('variables')
+ @_var_values = @options['variables']
+ elsif @options.has_key?('varattr')
+ @_var_values = {}
+ end
+ end
+
+ # Actually converts an XML document element into a data structure.
+ #
+ # element::
+ # The document element to be collapsed.
+ def collapse(element)
+ result = @options['noattr'] ? {} : get_attributes(element)
+
+ if @options['normalisespace'] == 2
+ result.each { |k, v| result[k] = normalise_space(v) }
+ end
+
+ if element.has_elements?
+ element.each_element { |child|
+ value = collapse(child)
+ if empty(value) && (element.attributes.empty? || @options['noattr'])
+ next if @options.has_key?('suppressempty') && @options['suppressempty'] == true
+ end
+ result = merge(result, child.name, value)
+ }
+ if has_mixed_content?(element)
+ # normalisespace?
+ content = element.texts.map { |x| x.to_s }
+ content = content[0] if content.size == 1
+ result[@options['contentkey']] = content
+ end
+ elsif element.has_text? # i.e. it has only text.
+ return collapse_text_node(result, element)
+ end
+
+ # Turn Arrays into Hashes if key fields present.
+ count = fold_arrays(result)
+
+ # Disintermediate grouped tags.
+ if @options.has_key?('grouptags')
+ result.each { |key, value|
+ next unless (value.instance_of?(Hash) && (value.size == 1))
+ child_key, child_value = value.to_a[0]
+ if @options['grouptags'][key] == child_key
+ result[key] = child_value
+ end
+ }
+ end
+
+ # Fold Hases containing a single anonymous Array up into just the Array.
+ if count == 1
+ anonymoustag = @options['anonymoustag']
+ if result.has_key?(anonymoustag) && result[anonymoustag].instance_of?(Array)
+ return result[anonymoustag]
+ end
+ end
+
+ if result.empty? && @options.has_key?('suppressempty')
+ return @options['suppressempty'] == '' ? '' : nil
+ end
+
+ result
+ end
+
+ # Collapses a text node and merges it with an existing Hash, if
+ # possible.
+ # Thanks to Curtis Schofield for reporting a subtle bug.
+ #
+ # hash::
+ # Hash to merge text node value with, if possible.
+ # element::
+ # Text node to be collapsed.
+ def collapse_text_node(hash, element)
+ value = node_to_text(element)
+ if empty(value) && !element.has_attributes?
+ return {}
+ end
+
+ if element.has_attributes? && !@options['noattr']
+ return merge(hash, @options['contentkey'], value)
+ else
+ if @options['forcecontent']
+ return merge(hash, @options['contentkey'], value)
+ else
+ return value
+ end
+ end
+ end
+
+ # Folds all arrays in a Hash.
+ #
+ # hash::
+ # Hash to be folded.
+ def fold_arrays(hash)
+ fold_amount = 0
+ keyattr = @options['keyattr']
+ if (keyattr.instance_of?(Array) || keyattr.instance_of?(Hash))
+ hash.each { |key, value|
+ if value.instance_of?(Array)
+ if keyattr.instance_of?(Array)
+ hash[key] = fold_array(value)
+ else
+ hash[key] = fold_array_by_name(key, value)
+ end
+ fold_amount += 1
+ end
+ }
+ end
+ fold_amount
+ end
+
+ # Folds an Array to a Hash, if possible. Folding happens
+ # according to the content of keyattr, which has to be
+ # an array.
+ #
+ # array::
+ # Array to be folded.
+ def fold_array(array)
+ hash = Hash.new
+ array.each { |x|
+ return array unless x.instance_of?(Hash)
+ key_matched = false
+ @options['keyattr'].each { |key|
+ if x.has_key?(key)
+ key_matched = true
+ value = x[key]
+ return array if value.instance_of?(Hash) || value.instance_of?(Array)
+ value = normalise_space(value) if @options['normalisespace'] == 1
+ x.delete(key)
+ hash[value] = x
+ break
+ end
+ }
+ return array unless key_matched
+ }
+ hash = collapse_content(hash) if @options['collapseagain']
+ hash
+ end
+
+ # Folds an Array to a Hash, if possible. Folding happens
+ # according to the content of keyattr, which has to be
+ # a Hash.
+ #
+ # name::
+ # Name of the attribute to be folded upon.
+ # array::
+ # Array to be folded.
+ def fold_array_by_name(name, array)
+ return array unless @options['keyattr'].has_key?(name)
+ key, flag = @options['keyattr'][name]
+
+ hash = Hash.new
+ array.each { |x|
+ if x.instance_of?(Hash) && x.has_key?(key)
+ value = x[key]
+ return array if value.instance_of?(Hash) || value.instance_of?(Array)
+ value = normalise_space(value) if @options['normalisespace'] == 1
+ hash[value] = x
+ hash[value]["-#{key}"] = hash[value][key] if flag == '-'
+ hash[value].delete(key) unless flag == '+'
+ else
+ $stderr.puts("Warning: <#{name}> element has no '#{key}' attribute.")
+ return array
+ end
+ }
+ hash = collapse_content(hash) if @options['collapseagain']
+ hash
+ end
+
+ # Tries to collapse a Hash even more ;-)
+ #
+ # hash::
+ # Hash to be collapsed again.
+ def collapse_content(hash)
+ content_key = @options['contentkey']
+ hash.each_value { |value|
+ return hash unless value.instance_of?(Hash) && value.size == 1 && value.has_key?(content_key)
+ hash.each_key { |key| hash[key] = hash[key][content_key] }
+ }
+ hash
+ end
+
+ # Adds a new key/value pair to an existing Hash. If the key to be added
+ # does already exist and the existing value associated with key is not
+ # an Array, it will be converted into an Array. Then the new value is
+ # appended to that Array.
+ #
+ # hash::
+ # Hash to add key/value pair to.
+ # key::
+ # Key to be added.
+ # value::
+ # Value to be associated with key.
+ def merge(hash, key, value)
+ if value.instance_of?(String)
+ value = normalise_space(value) if @options['normalisespace'] == 2
+
+ # do variable substitutions
+ unless @_var_values.nil? || @_var_values.empty?
+ value.gsub!(/\$\{(\w+)\}/) { |x| get_var($1) }
+ end
+
+ # look for variable definitions
+ if @options.has_key?('varattr')
+ varattr = @options['varattr']
+ if hash.has_key?(varattr)
+ set_var(hash[varattr], value)
+ end
+ end
+ end
+
+ #patch for converting keys to symbols
+ if @options.has_key?('keytosymbol')
+ if @options['keytosymbol'] == true
+ key = key.to_s.downcase.to_sym
+ end
+ end
+
+ if hash.has_key?(key)
+ if hash[key].instance_of?(Array)
+ hash[key] << value
+ else
+ hash[key] = [ hash[key], value ]
+ end
+ elsif value.instance_of?(Array) # Handle anonymous arrays.
+ hash[key] = [ value ]
+ else
+ if force_array?(key)
+ hash[key] = [ value ]
+ else
+ hash[key] = value
+ end
+ end
+ hash
+ end
+
+ # Checks, if the 'forcearray' option has to be used for
+ # a certain key.
+ def force_array?(key)
+ return false if key == @options['contentkey']
+ return true if @options['forcearray'] == true
+ forcearray = @options['forcearray']
+ if forcearray.instance_of?(Hash)
+ return true if forcearray.has_key?(key)
+ return false unless forcearray.has_key?('_regex')
+ forcearray['_regex'].each { |x| return true if key =~ x }
+ end
+ return false
+ end
+
+ # Converts the attributes array of a document node into a Hash.
+ # Returns an empty Hash, if node has no attributes.
+ #
+ # node::
+ # Document node to extract attributes from.
+ def get_attributes(node)
+ attributes = {}
+ node.attributes.each { |n,v| attributes[n] = v }
+ attributes
+ end
+
+ # Determines, if a document element has mixed content.
+ #
+ # element::
+ # Document element to be checked.
+ def has_mixed_content?(element)
+ if element.has_text? && element.has_elements?
+ return true if element.texts.join('') !~ /^\s*$/s
+ end
+ false
+ end
+
+ # Called when a variable definition is encountered in the XML.
+ # A variable definition looks like
+ # <element attrname="name">value</element>
+ # where attrname matches the varattr setting.
+ def set_var(name, value)
+ @_var_values[name] = value
+ end
+
+ # Called during variable substitution to get the value for the
+ # named variable.
+ def get_var(name)
+ if @_var_values.has_key?(name)
+ return @_var_values[name]
+ else
+ return "${#{name}}"
+ end
+ end
+
+ # Recurses through a data structure building up and returning an
+ # XML representation of that structure as a string.
+ #
+ # ref::
+ # Reference to the data structure to be encoded.
+ # name::
+ # The XML tag name to be used for this item.
+ # indent::
+ # A string of spaces for use as the current indent level.
+ def value_to_xml(ref, name, indent)
+ named = !name.nil? && name != ''
+ nl = @options.has_key?('noindent') ? '' : "\n"
+
+ if !scalar(ref)
+ if @ancestors.member?(ref)
+ raise ArgumentError, "Circular data structures not supported!"
+ end
+ @ancestors << ref
+ else
+ if named
+ return [indent, '<', name, '>', @options['noescape'] ? ref.to_s : escape_value(ref.to_s), '</', name, '>', nl].join('')
+ else
+ return ref.to_s + nl
+ end
+ end
+
+ # Unfold hash to array if possible.
+ if ref.instance_of?(Hash) && !ref.empty? && !@options['keyattr'].empty? && indent != ''
+ ref = hash_to_array(name, ref)
+ end
+
+ result = []
+ if ref.instance_of?(Hash)
+ # Reintermediate grouped values if applicable.
+ if @options.has_key?('grouptags')
+ ref.each { |key, value|
+ if @options['grouptags'].has_key?(key)
+ ref[key] = { @options['grouptags'][key] => value }
+ end
+ }
+ end
+
+ nested = []
+ text_content = nil
+ if named
+ result << indent << '<' << name
+ end
+
+ if !ref.empty?
+ ref.each { |key, value|
+ next if !key.nil? && key[0, 1] == '-'
+ if value.nil?
+ unless @options.has_key?('suppressempty') && @options['suppressempty'].nil?
+ raise ArgumentError, "Use of uninitialized value!"
+ end
+ value = {}
+ end
+
+ if !scalar(value) || @options['noattr']
+ nested << value_to_xml(value, key, indent + @options['indent'])
+ else
+ value = value.to_s
+ value = escape_value(value) unless @options['noescape']
+ if key == @options['contentkey']
+ text_content = value
+ else
+ result << ' ' << key << '="' << value << '"'
+ end
+ end
+ }
+ else
+ text_content = ''
+ end
+
+ if !nested.empty? || !text_content.nil?
+ if named
+ result << '>'
+ if !text_content.nil?
+ result << text_content
+ nested[0].sub!(/^\s+/, '') if !nested.empty?
+ else
+ result << nl
+ end
+ if !nested.empty?
+ result << nested << indent
+ end
+ result << '</' << name << '>' << nl
+ else
+ result << nested
+ end
+ else
+ result << ' />' << nl
+ end
+ elsif ref.instance_of?(Array)
+ ref.each { |value|
+ if scalar(value)
+ result << indent << '<' << name << '>'
+ result << (@options['noescape'] ? value.to_s : escape_value(value.to_s))
+ result << '</' << name << '>' << nl
+ elsif value.instance_of?(Hash)
+ result << value_to_xml(value, name, indent)
+ else
+ result << indent << '<' << name << '>' << nl
+ result << value_to_xml(value, @options['anonymoustag'], indent + @options['indent'])
+ result << indent << '</' << name << '>' << nl
+ end
+ }
+ else
+ # Probably, this is obsolete.
+ raise ArgumentError, "Can't encode a value of type: #{ref.type}."
+ end
+ @ancestors.pop if !scalar(ref)
+ result.join('')
+ end
+
+ # Checks, if a certain value is a "scalar" value. Whatever
+ # that will be in Ruby ... ;-)
+ #
+ # value::
+ # Value to be checked.
+ def scalar(value)
+ return false if value.instance_of?(Hash) || value.instance_of?(Array)
+ return true
+ end
+
+ # Attempts to unfold a hash of hashes into an array of hashes. Returns
+ # a reference to th array on success or the original hash, if unfolding
+ # is not possible.
+ #
+ # parent::
+ #
+ # hashref::
+ # Reference to the hash to be unfolded.
+ def hash_to_array(parent, hashref)
+ arrayref = []
+ hashref.each { |key, value|
+ return hashref unless value.instance_of?(Hash)
+
+ if @options['keyattr'].instance_of?(Hash)
+ return hashref unless @options['keyattr'].has_key?(parent)
+ arrayref << { @options['keyattr'][parent][0] => key }.update(value)
+ else
+ arrayref << { @options['keyattr'][0] => key }.update(value)
+ end
+ }
+ arrayref
+ end
+
+ # Replaces XML markup characters by their external entities.
+ #
+ # data::
+ # The string to be escaped.
+ def escape_value(data)
+ Text::normalize(data)
+ end
+
+ # Removes leading and trailing whitespace and sequences of
+ # whitespaces from a string.
+ #
+ # text::
+ # String to be normalised.
+ def normalise_space(text)
+ text.strip.gsub(/\s\s+/, ' ')
+ end
+
+ # Checks, if an object is nil, an empty String or an empty Hash.
+ # Thanks to Norbert Gawor for a bugfix.
+ #
+ # value::
+ # Value to be checked for emptyness.
+ def empty(value)
+ case value
+ when Hash
+ return value.empty?
+ when String
+ return value !~ /\S/m
+ else
+ return value.nil?
+ end
+ end
+
+ # Converts a document node into a String.
+ # If the node could not be converted into a String
+ # for any reason, default will be returned.
+ #
+ # node::
+ # Document node to be converted.
+ # default::
+ # Value to be returned, if node could not be converted.
+ def node_to_text(node, default = nil)
+ if node.instance_of?(REXML::Element)
+ node.texts.map { |t| t.value }.join('')
+ elsif node.instance_of?(REXML::Attribute)
+ node.value.nil? ? default : node.value.strip
+ elsif node.instance_of?(REXML::Text)
+ node.value.strip
+ else
+ default
+ end
+ end
+
+ # Parses an XML string and returns the according document.
+ #
+ # xml_string::
+ # XML string to be parsed.
+ #
+ # The following exception may be raised:
+ #
+ # REXML::ParseException::
+ # If the specified file is not wellformed.
+ def parse(xml_string)
+ Document.new(xml_string)
+ end
+
+ # Searches in a list of paths for a certain file. Returns
+ # the full path to the file, if it could be found. Otherwise,
+ # an exception will be raised.
+ #
+ # filename::
+ # Name of the file to search for.
+ # searchpath::
+ # List of paths to search in.
+ def find_xml_file(file, searchpath)
+ filename = File::basename(file)
+
+ if filename != file
+ return file if File::file?(file)
+ else
+ searchpath.each { |path|
+ full_path = File::join(path, filename)
+ return full_path if File::file?(full_path)
+ }
+ end
+
+ if searchpath.empty?
+ return file if File::file?(file)
+ raise ArgumentError, "File does not exist: #{file}."
+ end
+ raise ArgumentError, "Could not find <#{filename}> in <#{searchpath.join(':')}>"
+ end
+
+ # Loads and parses an XML configuration file.
+ #
+ # filename::
+ # Name of the configuration file to be loaded.
+ #
+ # The following exceptions may be raised:
+ #
+ # Errno::ENOENT::
+ # If the specified file does not exist.
+ # REXML::ParseException::
+ # If the specified file is not wellformed.
+ def load_xml_file(filename)
+ parse(File.readlines(filename).to_s)
+ end
+
+ # Caches the data belonging to a certain file.
+ #
+ # data::
+ # Data to be cached.
+ # filename::
+ # Name of file the data was read from.
+ def put_into_cache(data, filename)
+ if @options.has_key?('cache')
+ @options['cache'].each { |scheme|
+ case(scheme)
+ when 'storable'
+ @@cache.save_storable(data, filename)
+ when 'mem_share'
+ @@cache.save_mem_share(data, filename)
+ when 'mem_copy'
+ @@cache.save_mem_copy(data, filename)
+ else
+ raise ArgumentError, "Unsupported caching scheme: <#{scheme}>."
+ end
+ }
+ end
+ end
+end
+
+# vim:sw=2
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/version.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/version.rb
new file mode 100644
index 000000000..83fbaec62
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/version.rb
@@ -0,0 +1,9 @@
+module ActiveSupport
+ module VERSION #:nodoc:
+ MAJOR = 2
+ MINOR = 0
+ TINY = 2
+
+ STRING = [MAJOR, MINOR, TINY].join('.')
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/lib/active_support/whiny_nil.rb b/vendor/rails-2.0.2/activesupport/lib/active_support/whiny_nil.rb
new file mode 100644
index 000000000..f614b41fc
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/active_support/whiny_nil.rb
@@ -0,0 +1,38 @@
+# Extensions to nil which allow for more helpful error messages for
+# people who are new to rails.
+#
+# The aim is to ensure that when users pass nil to methods where that isn't
+# appropriate, instead of NoMethodError and the name of some method used
+# by the framework users will see a message explaining what type of object
+# was expected.
+
+class NilClass
+ WHINERS = [::Array]
+ WHINERS << ::ActiveRecord::Base if defined? ::ActiveRecord
+
+ @@method_class_map = Hash.new
+
+ WHINERS.each do |klass|
+ methods = klass.public_instance_methods - public_instance_methods
+ class_name = klass.name
+ methods.each { |method| @@method_class_map[method.to_sym] = class_name }
+ end
+
+ def id
+ raise RuntimeError, "Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id", caller
+ end
+
+ private
+ def method_missing(method, *args, &block)
+ raise_nil_warning_for @@method_class_map[method], method, caller
+ end
+
+ def raise_nil_warning_for(class_name = nil, selector = nil, with_caller = nil)
+ message = "You have a nil object when you didn't expect it!"
+ message << "\nYou might have expected an instance of #{class_name}." if class_name
+ message << "\nThe error occurred while evaluating nil.#{selector}" if selector
+
+ raise NoMethodError, message, with_caller || caller
+ end
+end
+
diff --git a/vendor/rails-2.0.2/activesupport/lib/activesupport.rb b/vendor/rails-2.0.2/activesupport/lib/activesupport.rb
new file mode 100644
index 000000000..69f36f793
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/lib/activesupport.rb
@@ -0,0 +1 @@
+require 'active_support'
diff --git a/vendor/rails-2.0.2/activesupport/test/abstract_unit.rb b/vendor/rails-2.0.2/activesupport/test/abstract_unit.rb
new file mode 100644
index 000000000..2cfa245bc
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/abstract_unit.rb
@@ -0,0 +1,20 @@
+require 'test/unit'
+
+$:.unshift "#{File.dirname(__FILE__)}/../lib"
+$:.unshift File.dirname(__FILE__)
+require 'active_support'
+
+# Wrap tests that use Mocha and skip if unavailable.
+unless defined? uses_mocha
+ def uses_mocha(test_name)
+ require 'rubygems'
+ gem 'mocha', '>= 0.5.5'
+ require 'mocha'
+ yield
+ rescue LoadError
+ $stderr.puts "Skipping #{test_name} tests. `gem install mocha` and try again."
+ end
+end
+
+# Show backtraces for deprecated behavior for quicker cleanup.
+ActiveSupport::Deprecation.debug = true
diff --git a/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/a/b.rb b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/a/b.rb
new file mode 100644
index 000000000..9c9e6454c
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/a/b.rb
@@ -0,0 +1,2 @@
+class A::B
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/a/c/d.rb b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/a/c/d.rb
new file mode 100644
index 000000000..0f40d6fbc
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/a/c/d.rb
@@ -0,0 +1,2 @@
+class A::C::D
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/a/c/e/f.rb b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/a/c/e/f.rb
new file mode 100644
index 000000000..57dba5a30
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/a/c/e/f.rb
@@ -0,0 +1,2 @@
+class A::C::E::F
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/application.rb b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/application.rb
new file mode 100644
index 000000000..d7d3096dc
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/application.rb
@@ -0,0 +1 @@
+ApplicationController = 10
diff --git a/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/class_folder.rb b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/class_folder.rb
new file mode 100644
index 000000000..ad2b27be6
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/class_folder.rb
@@ -0,0 +1,3 @@
+class ClassFolder
+ ConstantInClassFolder = 'indeed'
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/class_folder/class_folder_subclass.rb b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/class_folder/class_folder_subclass.rb
new file mode 100644
index 000000000..ef66ddaac
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/class_folder/class_folder_subclass.rb
@@ -0,0 +1,3 @@
+class ClassFolder::ClassFolderSubclass < ClassFolder
+ ConstantInClassFolder
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/class_folder/inline_class.rb b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/class_folder/inline_class.rb
new file mode 100644
index 000000000..8235e9072
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/class_folder/inline_class.rb
@@ -0,0 +1,2 @@
+class ClassFolder::InlineClass
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/class_folder/nested_class.rb b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/class_folder/nested_class.rb
new file mode 100644
index 000000000..77ea230d2
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/class_folder/nested_class.rb
@@ -0,0 +1,7 @@
+class ClassFolder
+ class NestedClass
+ end
+
+ class SiblingClass
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/conflict.rb b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/conflict.rb
new file mode 100644
index 000000000..4ac620190
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/conflict.rb
@@ -0,0 +1 @@
+Conflict = 2 \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/counting_loader.rb b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/counting_loader.rb
new file mode 100644
index 000000000..4225c4412
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/counting_loader.rb
@@ -0,0 +1,5 @@
+$counting_loaded_times ||= 0
+$counting_loaded_times += 1
+
+module CountingLoader
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/cross_site_dependency.rb b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/cross_site_dependency.rb
new file mode 100644
index 000000000..21ee554e9
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/cross_site_dependency.rb
@@ -0,0 +1,2 @@
+class CrossSiteDependency
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/e.rb b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/e.rb
new file mode 100644
index 000000000..2f59e4fb7
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/e.rb
@@ -0,0 +1,2 @@
+class E
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/module_folder/inline_class.rb b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/module_folder/inline_class.rb
new file mode 100644
index 000000000..ca8343704
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/module_folder/inline_class.rb
@@ -0,0 +1,2 @@
+class ModuleFolder::InlineClass
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/module_folder/nested_class.rb b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/module_folder/nested_class.rb
new file mode 100644
index 000000000..fc4076bd0
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/module_folder/nested_class.rb
@@ -0,0 +1,4 @@
+module ModuleFolder
+ class NestedClass
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/module_folder/nested_sibling.rb b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/module_folder/nested_sibling.rb
new file mode 100644
index 000000000..80244b8ba
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/module_folder/nested_sibling.rb
@@ -0,0 +1,2 @@
+class ModuleFolder::NestedSibling
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/module_with_custom_const_missing/a/b.rb b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/module_with_custom_const_missing/a/b.rb
new file mode 100644
index 000000000..d12d02f3a
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/module_with_custom_const_missing/a/b.rb
@@ -0,0 +1 @@
+ModuleWithCustomConstMissing::A::B = "10" \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/multiple_constant_file.rb b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/multiple_constant_file.rb
new file mode 100644
index 000000000..a9ff4eb89
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/multiple_constant_file.rb
@@ -0,0 +1,2 @@
+MultipleConstantFile = 10
+SiblingConstant = MultipleConstantFile * 2
diff --git a/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/raises_name_error.rb b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/raises_name_error.rb
new file mode 100644
index 000000000..a49960abf
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/raises_name_error.rb
@@ -0,0 +1,3 @@
+class RaisesNameError
+ FooBarBaz
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/raises_no_method_error.rb b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/raises_no_method_error.rb
new file mode 100644
index 000000000..e1b8fce24
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/autoloading_fixtures/raises_no_method_error.rb
@@ -0,0 +1,3 @@
+class RaisesNoMethodError
+ self.foobar_method_doesnt_exist
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/buffered_logger_test.rb b/vendor/rails-2.0.2/activesupport/test/buffered_logger_test.rb
new file mode 100644
index 000000000..5ce197eba
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/buffered_logger_test.rb
@@ -0,0 +1,107 @@
+require File.dirname(__FILE__) + '/abstract_unit'
+require 'stringio'
+
+class BufferedLoggerTest < Test::Unit::TestCase
+ def setup
+ @message = "A debug message"
+ @integer_message = 12345
+ @output = StringIO.new
+ @logger = ActiveSupport::BufferedLogger.new(@output)
+ end
+
+ def test_should_log_debugging_message_when_debugging
+ @logger.level = Logger::DEBUG
+ @logger.add(Logger::DEBUG, @message)
+ assert @output.string.include?(@message)
+ end
+
+ def test_should_not_log_debug_messages_when_log_level_is_info
+ @logger.level = Logger::INFO
+ @logger.add(Logger::DEBUG, @message)
+ assert ! @output.string.include?(@message)
+ end
+
+ def test_should_add_message_passed_as_block_when_using_add
+ @logger.level = Logger::INFO
+ @logger.add(Logger::INFO) {@message}
+ assert @output.string.include?(@message)
+ end
+
+ def test_should_add_message_passed_as_block_when_using_shortcut
+ @logger.level = Logger::INFO
+ @logger.info {@message}
+ assert @output.string.include?(@message)
+ end
+
+ def test_should_convert_message_to_string
+ @logger.level = Logger::INFO
+ @logger.info @integer_message
+ assert @output.string.include?(@integer_message.to_s)
+ end
+
+ def test_should_convert_message_to_string_when_passed_in_block
+ @logger.level = Logger::INFO
+ @logger.info {@integer_message}
+ assert @output.string.include?(@integer_message.to_s)
+ end
+
+ def test_should_not_evaluate_block_if_message_wont_be_logged
+ @logger.level = Logger::INFO
+ evaluated = false
+ @logger.add(Logger::DEBUG) {evaluated = true}
+ assert evaluated == false
+ end
+
+ def test_should_not_mutate_message
+ message_copy = @message.dup
+ @logger.info @message
+ assert_equal message_copy, @message
+ end
+
+
+ [false, nil, 0].each do |disable|
+ define_method "test_disabling_auto_flush_with_#{disable.inspect}_should_buffer_until_explicit_flush" do
+ @logger.auto_flushing = disable
+
+ 4.times do
+ @logger.info 'wait for it..'
+ assert @output.string.empty?, @output.string
+ end
+
+ @logger.flush
+ assert !@output.string.empty?, @logger.buffer.size
+ end
+
+ define_method "test_disabling_auto_flush_with_#{disable.inspect}_should_flush_at_max_buffer_size_as_failsafe" do
+ @logger.auto_flushing = disable
+ assert_equal ActiveSupport::BufferedLogger::MAX_BUFFER_SIZE, @logger.auto_flushing
+
+ (ActiveSupport::BufferedLogger::MAX_BUFFER_SIZE - 1).times do
+ @logger.info 'wait for it..'
+ assert @output.string.empty?, @output.string
+ end
+
+ @logger.info 'there it is.'
+ assert !@output.string.empty?, @logger.buffer.size
+ end
+ end
+
+ def test_should_know_if_its_loglevel_is_below_a_given_level
+ ActiveSupport::BufferedLogger::Severity.constants.each do |level|
+ @logger.level = ActiveSupport::BufferedLogger::Severity.const_get(level) - 1
+ assert @logger.send("#{level.downcase}?"), "didn't know if it was #{level.downcase}? or below"
+ end
+ end
+
+ def test_should_auto_flush_every_n_messages
+ @logger.auto_flushing = 5
+
+ 4.times do
+ @logger.info 'wait for it..'
+ assert @output.string.empty?, @output.string
+ end
+
+ @logger.info 'there it is.'
+ assert !@output.string.empty?, @output.string
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/clean_logger_test.rb b/vendor/rails-2.0.2/activesupport/test/clean_logger_test.rb
new file mode 100644
index 000000000..5c9c8f914
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/clean_logger_test.rb
@@ -0,0 +1,57 @@
+require File.dirname(__FILE__) + '/abstract_unit'
+require 'stringio'
+
+class CleanLoggerTest < Test::Unit::TestCase
+ def setup
+ @out = StringIO.new
+ @logger = Logger.new(@out)
+ end
+
+ def test_format_message
+ @logger.error 'error'
+ assert_equal "error\n", @out.string
+ end
+
+ def test_silence
+ # Without yielding self.
+ @logger.silence do
+ @logger.debug 'debug'
+ @logger.info 'info'
+ @logger.warn 'warn'
+ @logger.error 'error'
+ @logger.fatal 'fatal'
+ end
+
+ # Yielding self.
+ @logger.silence do |logger|
+ logger.debug 'debug'
+ logger.info 'info'
+ logger.warn 'warn'
+ logger.error 'error'
+ logger.fatal 'fatal'
+ end
+
+ # Silencer off.
+ Logger.silencer = false
+ @logger.silence do |logger|
+ logger.warn 'unsilenced'
+ end
+ Logger.silencer = true
+
+ assert_equal "error\nfatal\nerror\nfatal\nunsilenced\n", @out.string
+ end
+
+ def test_datetime_format
+ @logger.formatter = Logger::Formatter.new
+ @logger.datetime_format = "%Y-%m-%d"
+ @logger.debug 'debug'
+ assert_equal "%Y-%m-%d", @logger.datetime_format
+ assert_match(/D, \[\d\d\d\d-\d\d-\d\d#\d+\] DEBUG -- : debug/, @out.string)
+ end
+
+ def test_nonstring_formatting
+ an_object = [1, 2, 3, 4, 5]
+ @logger.debug an_object
+ assert_equal("#{an_object.inspect}\n", @out.string)
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/array_ext_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/array_ext_test.rb
new file mode 100644
index 000000000..840a4c81d
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/array_ext_test.rb
@@ -0,0 +1,250 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+require 'bigdecimal'
+
+class ArrayExtAccessTests < Test::Unit::TestCase
+ def test_from
+ assert_equal %w( a b c d ), %w( a b c d ).from(0)
+ assert_equal %w( c d ), %w( a b c d ).from(2)
+ assert_nil %w( a b c d ).from(10)
+ end
+
+ def test_to
+ assert_equal %w( a ), %w( a b c d ).to(0)
+ assert_equal %w( a b c ), %w( a b c d ).to(2)
+ assert_equal %w( a b c d ), %w( a b c d ).to(10)
+ end
+end
+
+class ArrayExtToParamTests < Test::Unit::TestCase
+ class ToParam < String
+ def to_param
+ "#{self}1"
+ end
+ end
+
+ def test_string_array
+ assert_equal '', %w().to_param
+ assert_equal 'hello/world', %w(hello world).to_param
+ assert_equal 'hello/10', %w(hello 10).to_param
+ end
+
+ def test_number_array
+ assert_equal '10/20', [10, 20].to_param
+ end
+
+ def test_to_param_array
+ assert_equal 'custom1/param1', [ToParam.new('custom'), ToParam.new('param')].to_param
+ end
+end
+
+class ArrayExtToSentenceTests < Test::Unit::TestCase
+ def test_plain_array_to_sentence
+ assert_equal "", [].to_sentence
+ assert_equal "one", ['one'].to_sentence
+ assert_equal "one and two", ['one', 'two'].to_sentence
+ assert_equal "one, two, and three", ['one', 'two', 'three'].to_sentence
+ end
+
+ def test_to_sentence_with_connector
+ assert_equal "one, two, and also three", ['one', 'two', 'three'].to_sentence(:connector => 'and also')
+ assert_equal "one, two, three", ['one', 'two', 'three'].to_sentence(:connector => '')
+ assert_equal "one, two, three", ['one', 'two', 'three'].to_sentence(:connector => nil)
+ assert_equal "one, two, three", ['one', 'two', 'three'].to_sentence(:connector => ' ')
+ assert_equal "one, two, and three", ['one', 'two', 'three'].to_sentence(:connector => 'and ')
+ end
+
+ def test_to_sentence_with_skip_last_comma
+ assert_equal "one, two, and three", ['one', 'two', 'three'].to_sentence(:skip_last_comma => false)
+ end
+
+ def test_two_elements
+ assert_equal "one and two", ['one', 'two'].to_sentence
+ assert_equal "one two", ['one', 'two'].to_sentence(:connector => '')
+ end
+
+ def test_one_element
+ assert_equal "one", ['one'].to_sentence
+ end
+
+ def test_one_non_string_element
+ assert_equal '1', [1].to_sentence
+ end
+end
+
+class ArrayExtToSTests < Test::Unit::TestCase
+ def test_to_s_db
+ collection = [
+ Class.new { def id() 1 end }.new,
+ Class.new { def id() 2 end }.new,
+ Class.new { def id() 3 end }.new
+ ]
+
+ assert_equal "null", [].to_s(:db)
+ assert_equal "1,2,3", collection.to_s(:db)
+ end
+end
+
+class ArrayExtGroupingTests < Test::Unit::TestCase
+ def test_group_by_with_perfect_fit
+ groups = []
+ ('a'..'i').to_a.in_groups_of(3) do |group|
+ groups << group
+ end
+
+ assert_equal [%w(a b c), %w(d e f), %w(g h i)], groups
+ assert_equal [%w(a b c), %w(d e f), %w(g h i)], ('a'..'i').to_a.in_groups_of(3)
+ end
+
+ def test_group_by_with_padding
+ groups = []
+ ('a'..'g').to_a.in_groups_of(3) do |group|
+ groups << group
+ end
+
+ assert_equal [%w(a b c), %w(d e f), ['g', nil, nil]], groups
+ end
+
+ def test_group_by_pads_with_specified_values
+ groups = []
+
+ ('a'..'g').to_a.in_groups_of(3, 'foo') do |group|
+ groups << group
+ end
+
+ assert_equal [%w(a b c), %w(d e f), ['g', 'foo', 'foo']], groups
+ end
+
+ def test_group_without_padding
+ groups = []
+
+ ('a'..'g').to_a.in_groups_of(3, false) do |group|
+ groups << group
+ end
+
+ assert_equal [%w(a b c), %w(d e f), ['g']], groups
+ end
+end
+
+class ArraySplitTests < Test::Unit::TestCase
+ def test_split_with_empty_array
+ assert_equal [[]], [].split(0)
+ end
+
+ def test_split_with_argument
+ assert_equal [[1, 2], [4, 5]], [1, 2, 3, 4, 5].split(3)
+ assert_equal [[1, 2, 3, 4, 5]], [1, 2, 3, 4, 5].split(0)
+ end
+
+ def test_split_with_block
+ assert_equal [[1, 2], [4, 5], [7, 8], [10]], (1..10).to_a.split { |i| i % 3 == 0 }
+ end
+
+ def test_split_with_edge_values
+ assert_equal [[], [2, 3, 4, 5]], [1, 2, 3, 4, 5].split(1)
+ assert_equal [[1, 2, 3, 4], []], [1, 2, 3, 4, 5].split(5)
+ assert_equal [[], [2, 3, 4], []], [1, 2, 3, 4, 5].split { |i| i == 1 || i == 5 }
+ end
+end
+
+class ArrayToXmlTests < Test::Unit::TestCase
+ def test_to_xml
+ xml = [
+ { :name => "David", :age => 26, :age_in_millis => 820497600000 },
+ { :name => "Jason", :age => 31, :age_in_millis => BigDecimal.new('1.0') }
+ ].to_xml(:skip_instruct => true, :indent => 0)
+
+ assert_equal '<records type="array"><record>', xml.first(30)
+ assert xml.include?(%(<age type="integer">26</age>)), xml
+ assert xml.include?(%(<age-in-millis type="integer">820497600000</age-in-millis>)), xml
+ assert xml.include?(%(<name>David</name>)), xml
+ assert xml.include?(%(<age type="integer">31</age>)), xml
+ assert xml.include?(%(<age-in-millis type="decimal">1.0</age-in-millis>)), xml
+ assert xml.include?(%(<name>Jason</name>)), xml
+ end
+
+ def test_to_xml_with_dedicated_name
+ xml = [
+ { :name => "David", :age => 26, :age_in_millis => 820497600000 }, { :name => "Jason", :age => 31 }
+ ].to_xml(:skip_instruct => true, :indent => 0, :root => "people")
+
+ assert_equal '<people type="array"><person>', xml.first(29)
+ end
+
+ def test_to_xml_with_options
+ xml = [
+ { :name => "David", :street_address => "Paulina" }, { :name => "Jason", :street_address => "Evergreen" }
+ ].to_xml(:skip_instruct => true, :skip_types => true, :indent => 0)
+
+ assert_equal "<records><record>", xml.first(17)
+ assert xml.include?(%(<street-address>Paulina</street-address>))
+ assert xml.include?(%(<name>David</name>))
+ assert xml.include?(%(<street-address>Evergreen</street-address>))
+ assert xml.include?(%(<name>Jason</name>))
+ end
+
+ def test_to_xml_with_dasherize_false
+ xml = [
+ { :name => "David", :street_address => "Paulina" }, { :name => "Jason", :street_address => "Evergreen" }
+ ].to_xml(:skip_instruct => true, :skip_types => true, :indent => 0, :dasherize => false)
+
+ assert_equal "<records><record>", xml.first(17)
+ assert xml.include?(%(<street_address>Paulina</street_address>))
+ assert xml.include?(%(<street_address>Evergreen</street_address>))
+ end
+
+ def test_to_xml_with_dasherize_true
+ xml = [
+ { :name => "David", :street_address => "Paulina" }, { :name => "Jason", :street_address => "Evergreen" }
+ ].to_xml(:skip_instruct => true, :skip_types => true, :indent => 0, :dasherize => true)
+
+ assert_equal "<records><record>", xml.first(17)
+ assert xml.include?(%(<street-address>Paulina</street-address>))
+ assert xml.include?(%(<street-address>Evergreen</street-address>))
+ end
+
+ def test_to_with_instruct
+ xml = [
+ { :name => "David", :age => 26, :age_in_millis => 820497600000 },
+ { :name => "Jason", :age => 31, :age_in_millis => BigDecimal.new('1.0') }
+ ].to_xml(:skip_instruct => false, :indent => 0)
+
+ assert_match(/^<\?xml [^>]*/, xml)
+ assert_equal 0, xml.rindex(/<\?xml /)
+ end
+
+ def test_to_xml_with_block
+ xml = [
+ { :name => "David", :age => 26, :age_in_millis => 820497600000 },
+ { :name => "Jason", :age => 31, :age_in_millis => BigDecimal.new('1.0') }
+ ].to_xml(:skip_instruct => true, :indent => 0) do |builder|
+ builder.count 2
+ end
+
+ assert xml.include?(%(<count>2</count>)), xml
+ end
+end
+
+class ArrayExtractOptionsTests < Test::Unit::TestCase
+ def test_extract_options
+ assert_equal({}, [].extract_options!)
+ assert_equal({}, [1].extract_options!)
+ assert_equal({:a=>:b}, [{:a=>:b}].extract_options!)
+ assert_equal({:a=>:b}, [1, {:a=>:b}].extract_options!)
+ end
+end
+
+uses_mocha "ArrayExtRandomTests" do
+
+class ArrayExtRandomTests < Test::Unit::TestCase
+ def test_random_element_from_array
+ assert_nil [].rand
+
+ Kernel.expects(:rand).with(1).returns(0)
+ assert_equal 'x', ['x'].rand
+
+ Kernel.expects(:rand).with(3).returns(1)
+ assert_equal 2, [1, 2, 3].rand
+ end
+end
+
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/blank_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/blank_test.rb
new file mode 100644
index 000000000..27b9813ac
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/blank_test.rb
@@ -0,0 +1,19 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class EmptyTrue
+ def empty?() true; end
+end
+
+class EmptyFalse
+ def empty?() false; end
+end
+
+class BlankTest < Test::Unit::TestCase
+ BLANK = [ EmptyTrue.new, nil, false, '', ' ', " \n\t \r ", [], {} ]
+ NOT = [ EmptyFalse.new, Object.new, true, 0, 1, 'a', [nil], { nil => 0 } ]
+
+ def test_blank
+ BLANK.each { |v| assert v.blank?, "#{v.inspect} should be blank" }
+ NOT.each { |v| assert !v.blank?, "#{v.inspect} should not be blank" }
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/cgi_ext_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/cgi_ext_test.rb
new file mode 100644
index 000000000..229715c28
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/cgi_ext_test.rb
@@ -0,0 +1,14 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class EscapeSkippingSlashesTest < Test::Unit::TestCase
+ def test_array
+ assert_equal 'hello/world', CGI.escape_skipping_slashes(%w(hello world))
+ assert_equal 'hello+world/how/are/you', CGI.escape_skipping_slashes(['hello world', 'how', 'are', 'you'])
+ end
+
+ def test_typical
+ assert_equal 'hi', CGI.escape_skipping_slashes('hi')
+ assert_equal 'hi/world', CGI.escape_skipping_slashes('hi/world')
+ assert_equal 'hi/world+you+funky+thing', CGI.escape_skipping_slashes('hi/world you funky thing')
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/class/attribute_accessor_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/class/attribute_accessor_test.rb
new file mode 100644
index 000000000..8104c9ce8
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/class/attribute_accessor_test.rb
@@ -0,0 +1,31 @@
+require File.dirname(__FILE__) + '/../../abstract_unit'
+
+class ClassAttributeAccessorTest < Test::Unit::TestCase
+ def setup
+ @class = Class.new do
+ cattr_accessor :foo
+ cattr_accessor :bar, :instance_writer => false
+ end
+ @object = @class.new
+ end
+
+ def test_should_use_mattr_default
+ assert_nil @class.foo
+ assert_nil @object.foo
+ end
+
+ def test_should_set_mattr_value
+ @class.foo = :test
+ assert_equal :test, @object.foo
+
+ @object.foo = :test2
+ assert_equal :test2, @class.foo
+ end
+
+ def test_should_not_create_instance_writer
+ assert @class.respond_to?(:foo)
+ assert @class.respond_to?(:foo=)
+ assert @object.respond_to?(:bar)
+ assert !@object.respond_to?(:bar=)
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/class/class_inheritable_attributes_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/class/class_inheritable_attributes_test.rb
new file mode 100644
index 000000000..c0bb7acb3
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/class/class_inheritable_attributes_test.rb
@@ -0,0 +1,224 @@
+require File.dirname(__FILE__) + '/../../abstract_unit'
+
+class ClassInheritableAttributesTest < Test::Unit::TestCase
+ def setup
+ @klass = Class.new
+ end
+
+ def test_reader_declaration
+ assert_nothing_raised do
+ @klass.class_inheritable_reader :a
+ assert_respond_to @klass, :a
+ assert_respond_to @klass.new, :a
+ end
+ end
+
+ def test_writer_declaration
+ assert_nothing_raised do
+ @klass.class_inheritable_writer :a
+ assert_respond_to @klass, :a=
+ assert_respond_to @klass.new, :a=
+ end
+ end
+
+ def test_writer_declaration_without_instance_writer
+ assert_nothing_raised do
+ @klass.class_inheritable_writer :a, :instance_writer => false
+ assert_respond_to @klass, :a=
+ assert !@klass.new.respond_to?(:a=)
+ end
+ end
+
+ def test_accessor_declaration
+ assert_nothing_raised do
+ @klass.class_inheritable_accessor :a
+ assert_respond_to @klass, :a
+ assert_respond_to @klass.new, :a
+ assert_respond_to @klass, :a=
+ assert_respond_to @klass.new, :a=
+ end
+ end
+
+ def test_accessor_declaration_without_instance_writer
+ assert_nothing_raised do
+ @klass.class_inheritable_accessor :a, :instance_writer => false
+ assert_respond_to @klass, :a
+ assert_respond_to @klass.new, :a
+ assert_respond_to @klass, :a=
+ assert !@klass.new.respond_to?(:a=)
+ end
+ end
+
+ def test_array_declaration
+ assert_nothing_raised do
+ @klass.class_inheritable_array :a
+ assert_respond_to @klass, :a
+ assert_respond_to @klass.new, :a
+ assert_respond_to @klass, :a=
+ assert_respond_to @klass.new, :a=
+ end
+ end
+
+ def test_array_declaration_without_instance_writer
+ assert_nothing_raised do
+ @klass.class_inheritable_array :a, :instance_writer => false
+ assert_respond_to @klass, :a
+ assert_respond_to @klass.new, :a
+ assert_respond_to @klass, :a=
+ assert !@klass.new.respond_to?(:a=)
+ end
+ end
+
+ def test_hash_declaration
+ assert_nothing_raised do
+ @klass.class_inheritable_hash :a
+ assert_respond_to @klass, :a
+ assert_respond_to @klass.new, :a
+ assert_respond_to @klass, :a=
+ assert_respond_to @klass.new, :a=
+ end
+ end
+
+ def test_hash_declaration_without_instance_writer
+ assert_nothing_raised do
+ @klass.class_inheritable_hash :a, :instance_writer => false
+ assert_respond_to @klass, :a
+ assert_respond_to @klass.new, :a
+ assert_respond_to @klass, :a=
+ assert !@klass.new.respond_to?(:a=)
+ end
+ end
+
+ def test_reader
+ @klass.class_inheritable_reader :a
+ assert_nil @klass.a
+ assert_nil @klass.new.a
+
+ @klass.send(:write_inheritable_attribute, :a, 'a')
+
+ assert_equal 'a', @klass.a
+ assert_equal 'a', @klass.new.a
+ assert_equal @klass.a, @klass.new.a
+ assert_equal @klass.a.object_id, @klass.new.a.object_id
+ end
+
+ def test_writer
+ @klass.class_inheritable_reader :a
+ @klass.class_inheritable_writer :a
+
+ assert_nil @klass.a
+ assert_nil @klass.new.a
+
+ @klass.a = 'a'
+ assert_equal 'a', @klass.a
+ @klass.new.a = 'A'
+ assert_equal 'A', @klass.a
+ end
+
+ def test_array
+ @klass.class_inheritable_array :a
+
+ assert_nil @klass.a
+ assert_nil @klass.new.a
+
+ @klass.a = %w(a b c)
+ assert_equal %w(a b c), @klass.a
+ assert_equal %w(a b c), @klass.new.a
+
+ @klass.new.a = %w(A B C)
+ assert_equal %w(a b c A B C), @klass.a
+ assert_equal %w(a b c A B C), @klass.new.a
+ end
+
+ def test_hash
+ @klass.class_inheritable_hash :a
+
+ assert_nil @klass.a
+ assert_nil @klass.new.a
+
+ @klass.a = { :a => 'a' }
+ assert_equal({ :a => 'a' }, @klass.a)
+ assert_equal({ :a => 'a' }, @klass.new.a)
+
+ @klass.new.a = { :b => 'b' }
+ assert_equal({ :a => 'a', :b => 'b' }, @klass.a)
+ assert_equal({ :a => 'a', :b => 'b' }, @klass.new.a)
+ end
+
+ def test_inheritance
+ @klass.class_inheritable_accessor :a
+ @klass.a = 'a'
+
+ @sub = eval("class FlogMe < @klass; end; FlogMe")
+
+ @klass.class_inheritable_accessor :b
+
+ assert_respond_to @sub, :a
+ assert_respond_to @sub, :b
+ assert_equal @klass.a, @sub.a
+ assert_equal @klass.b, @sub.b
+ assert_equal 'a', @sub.a
+ assert_nil @sub.b
+
+ @klass.b = 'b'
+ assert_not_equal @klass.b, @sub.b
+ assert_equal 'b', @klass.b
+ assert_nil @sub.b
+
+ @sub.a = 'A'
+ assert_not_equal @klass.a, @sub.a
+ assert_equal 'a', @klass.a
+ assert_equal 'A', @sub.a
+
+ @sub.b = 'B'
+ assert_not_equal @klass.b, @sub.b
+ assert_equal 'b', @klass.b
+ assert_equal 'B', @sub.b
+ end
+
+ def test_array_inheritance
+ @klass.class_inheritable_accessor :a
+ @klass.a = []
+
+ @sub = eval("class SubbyArray < @klass; end; SubbyArray")
+
+ assert_equal [], @klass.a
+ assert_equal [], @sub.a
+
+ @sub.a << :first
+
+ assert_equal [:first], @sub.a
+ assert_equal [], @klass.a
+ end
+
+ def test_array_inheritance_
+ @klass.class_inheritable_accessor :a
+ @klass.a = {}
+
+ @sub = eval("class SubbyHash < @klass; end; SubbyHash")
+
+ assert_equal Hash.new, @klass.a
+ assert_equal Hash.new, @sub.a
+
+ @sub.a[:first] = :first
+
+ assert_equal 1, @sub.a.keys.size
+ assert_equal 0, @klass.a.keys.size
+ end
+
+ def test_reset_inheritable_attributes
+ @klass.class_inheritable_accessor :a
+ @klass.a = 'a'
+
+ @sub = eval("class Inheriting < @klass; end; Inheriting")
+
+ assert_equal 'a', @klass.a
+ assert_equal 'a', @sub.a
+
+ @klass.reset_inheritable_attributes
+ @sub = eval("class NotInheriting < @klass; end; NotInheriting")
+
+ assert_equal nil, @klass.a
+ assert_equal nil, @sub.a
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/class/delegating_attributes_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/class/delegating_attributes_test.rb
new file mode 100644
index 000000000..f5b14364c
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/class/delegating_attributes_test.rb
@@ -0,0 +1,105 @@
+require File.dirname(__FILE__) + '/../../abstract_unit'
+
+module DelegatingFixtures
+ class Parent
+ end
+
+ class Child < Parent
+ superclass_delegating_accessor :some_attribute
+ end
+
+ class Mokopuna < Child
+ end
+end
+
+class DelegatingAttributesTest < Test::Unit::TestCase
+ include DelegatingFixtures
+ attr_reader :single_class
+
+ def setup
+ @single_class = Class.new(Object)
+ end
+
+ def test_simple_reader_declaration
+ single_class.superclass_delegating_reader :only_reader
+ # The class and instance should have an accessor, but there
+ # should be no mutator
+ assert single_class.respond_to?(:only_reader)
+ assert single_class.public_instance_methods.map(&:to_s).include?("only_reader")
+ assert !single_class.respond_to?(:only_reader=)
+ end
+
+ def test_simple_writer_declaration
+ single_class.superclass_delegating_writer :only_writer
+ # The class should have a mutator, the instances shouldn't
+ # neither should have an accessor
+ assert single_class.respond_to?(:only_writer=)
+ assert !single_class.public_instance_methods.include?("only_writer=")
+ assert !single_class.public_instance_methods.include?("only_writer")
+ assert !single_class.respond_to?(:only_writer)
+ end
+
+ def test_simple_accessor_declaration
+ single_class.superclass_delegating_accessor :both
+ # Class should have accessor and mutator
+ # the instance should have an accessor only
+ assert single_class.respond_to?(:both)
+ assert single_class.respond_to?(:both=)
+ assert single_class.public_instance_methods.map(&:to_s).include?("both")
+ assert !single_class.public_instance_methods.map(&:to_s).include?("both=")
+ end
+
+ def test_working_with_simple_attributes
+ single_class.superclass_delegating_accessor :both
+ single_class.both= "HMMM"
+ assert_equal "HMMM", single_class.both
+ assert_equal "HMMM", single_class.new.both
+ end
+
+ def test_working_with_accessors
+ single_class.superclass_delegating_reader :only_reader
+ single_class.instance_variable_set("@only_reader", "reading only")
+ assert_equal "reading only", single_class.only_reader
+ assert_equal "reading only", single_class.new.only_reader
+ end
+
+ def test_working_with_simple_mutators
+ single_class.superclass_delegating_writer :only_writer
+ single_class.only_writer="written"
+ assert_equal "written", single_class.instance_variable_get("@only_writer")
+ end
+
+ def test_child_class_delegates_to_parent_but_can_be_overridden
+ parent = Class.new
+ parent.superclass_delegating_accessor :both
+ child = Class.new(parent)
+ parent.both= "1"
+ assert_equal "1", child.both
+
+ child.both="2"
+ assert_equal "1", parent.both
+ assert_equal "2", child.both
+
+ parent.both="3"
+ assert_equal "3", parent.both
+ assert_equal "2", child.both
+ end
+
+ def test_delegation_stops_at_the_right_level
+ assert_nil Mokopuna.some_attribute
+ assert_nil Child.some_attribute
+ Child.some_attribute="1"
+ assert_equal "1", Mokopuna.some_attribute
+ ensure
+ Child.some_attribute=nil
+ end
+
+ def test_delegation_stops_for_nil
+ Mokopuna.some_attribute = nil
+ Child.some_attribute="1"
+
+ assert_equal "1", Child.some_attribute
+ assert_nil Mokopuna.some_attribute
+ end
+
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/class_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/class_test.rb
new file mode 100644
index 000000000..e1b38a1e0
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/class_test.rb
@@ -0,0 +1,46 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class A
+end
+
+module X
+ class B
+ end
+end
+
+module Y
+ module Z
+ class C
+ end
+ end
+end
+
+class ClassTest < Test::Unit::TestCase
+ def test_removing_class_in_root_namespace
+ assert A.is_a?(Class)
+ Class.remove_class(A)
+ assert_raises(NameError) { A.is_a?(Class) }
+ end
+
+ def test_removing_class_in_one_level_namespace
+ assert X::B.is_a?(Class)
+ Class.remove_class(X::B)
+ assert_raises(NameError) { X::B.is_a?(Class) }
+ end
+
+ def test_removing_class_in_two_level_namespace
+ assert Y::Z::C.is_a?(Class)
+ Class.remove_class(Y::Z::C)
+ assert_raises(NameError) { Y::Z::C.is_a?(Class) }
+ end
+
+ def test_retrieving_subclasses
+ @parent = eval("class D; end; D")
+ @sub = eval("class E < D; end; E")
+ @subofsub = eval("class F < E; end; F")
+ assert @parent.subclasses.all? { |i| [@sub.to_s, @subofsub.to_s].include?(i) }
+ assert_equal 2, @parent.subclasses.size
+ assert_equal [@subofsub.to_s], @sub.subclasses
+ assert_equal [], @subofsub.subclasses
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/date_ext_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/date_ext_test.rb
new file mode 100644
index 000000000..0023d48c1
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/date_ext_test.rb
@@ -0,0 +1,196 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class DateExtCalculationsTest < Test::Unit::TestCase
+ def test_to_s
+ date = Date.new(2005, 2, 21)
+ assert_equal "2005-02-21", date.to_s
+ assert_equal "21 Feb", date.to_s(:short)
+ assert_equal "February 21, 2005", date.to_s(:long)
+ assert_equal "February 21st, 2005", date.to_s(:long_ordinal)
+ assert_equal "2005-02-21", date.to_s(:db)
+ assert_equal "21 Feb 2005", date.to_s(:rfc822)
+ end
+
+ def test_readable_inspect
+ assert_equal "Mon, 21 Feb 2005", Date.new(2005, 2, 21).readable_inspect
+ assert_equal Date.new(2005, 2, 21).readable_inspect, Date.new(2005, 2, 21).inspect
+ end
+
+ def test_to_time
+ assert_equal Time.local(2005, 2, 21), Date.new(2005, 2, 21).to_time
+ assert_equal Time.local_time(2039, 2, 21), Date.new(2039, 2, 21).to_time
+ end
+
+ def test_to_datetime
+ assert_equal DateTime.civil(2005, 2, 21), Date.new(2005, 2, 21).to_datetime
+ assert_equal 0, Date.new(2005, 2, 21).to_datetime.offset # use UTC offset
+ assert_equal ::Date::ITALY, Date.new(2005, 2, 21).to_datetime.start # use Ruby's default start value
+ end
+
+ def test_to_date
+ assert_equal Date.new(2005, 2, 21), Date.new(2005, 2, 21).to_date
+ end
+
+ def test_change
+ assert_equal Date.new(2005, 2, 21), Date.new(2005, 2, 11).change(:day => 21)
+ assert_equal Date.new(2007, 5, 11), Date.new(2005, 2, 11).change(:year => 2007, :month => 5)
+ assert_equal Date.new(2006,2,22), Date.new(2005,2,22).change(:year => 2006)
+ assert_equal Date.new(2005,6,22), Date.new(2005,2,22).change(:month => 6)
+ end
+
+ def test_beginning_of_week
+ assert_equal Date.new(2005,1,31), Date.new(2005,2,4).beginning_of_week
+ assert_equal Date.new(2005,11,28), Date.new(2005,11,28).beginning_of_week #monday
+ assert_equal Date.new(2005,11,28), Date.new(2005,11,29).beginning_of_week #tuesday
+ assert_equal Date.new(2005,11,28), Date.new(2005,11,30).beginning_of_week #wednesday
+ assert_equal Date.new(2005,11,28), Date.new(2005,12,01).beginning_of_week #thursday
+ assert_equal Date.new(2005,11,28), Date.new(2005,12,02).beginning_of_week #friday
+ assert_equal Date.new(2005,11,28), Date.new(2005,12,03).beginning_of_week #saturday
+ assert_equal Date.new(2005,11,28), Date.new(2005,12,04).beginning_of_week #sunday
+ end
+
+ def test_beginning_of_month
+ assert_equal Date.new(2005,2,1), Date.new(2005,2,22).beginning_of_month
+ end
+
+ def test_beginning_of_quarter
+ assert_equal Date.new(2005,1,1), Date.new(2005,2,15).beginning_of_quarter
+ assert_equal Date.new(2005,1,1), Date.new(2005,1,1).beginning_of_quarter
+ assert_equal Date.new(2005,10,1), Date.new(2005,12,31).beginning_of_quarter
+ assert_equal Date.new(2005,4,1), Date.new(2005,6,30).beginning_of_quarter
+ end
+
+ def test_end_of_month
+ assert_equal Date.new(2005,3,31), Date.new(2005,3,20).end_of_month
+ assert_equal Date.new(2005,2,28), Date.new(2005,2,20).end_of_month
+ assert_equal Date.new(2005,4,30), Date.new(2005,4,20).end_of_month
+
+ end
+
+ def test_beginning_of_year
+ assert_equal Date.new(2005,1,1).to_s, Date.new(2005,2,22).beginning_of_year.to_s
+ end
+
+ def test_months_ago
+ assert_equal Date.new(2005,5,5), Date.new(2005,6,5).months_ago(1)
+ assert_equal Date.new(2004,11,5), Date.new(2005,6,5).months_ago(7)
+ assert_equal Date.new(2004,12,5), Date.new(2005,6,5).months_ago(6)
+ assert_equal Date.new(2004,6,5), Date.new(2005,6,5).months_ago(12)
+ assert_equal Date.new(2003,6,5), Date.new(2005,6,5).months_ago(24)
+ end
+
+ def test_months_since
+ assert_equal Date.new(2005,7,5), Date.new(2005,6,5).months_since(1)
+ assert_equal Date.new(2006,1,5), Date.new(2005,12,5).months_since(1)
+ assert_equal Date.new(2005,12,5), Date.new(2005,6,5).months_since(6)
+ assert_equal Date.new(2006,6,5), Date.new(2005,12,5).months_since(6)
+ assert_equal Date.new(2006,1,5), Date.new(2005,6,5).months_since(7)
+ assert_equal Date.new(2006,6,5), Date.new(2005,6,5).months_since(12)
+ assert_equal Date.new(2007,6,5), Date.new(2005,6,5).months_since(24)
+ assert_equal Date.new(2005,4,30), Date.new(2005,3,31).months_since(1)
+ assert_equal Date.new(2005,2,28), Date.new(2005,1,29).months_since(1)
+ assert_equal Date.new(2005,2,28), Date.new(2005,1,30).months_since(1)
+ assert_equal Date.new(2005,2,28), Date.new(2005,1,31).months_since(1)
+ end
+
+ def test_years_ago
+ assert_equal Date.new(2004,6,5), Date.new(2005,6,5).years_ago(1)
+ assert_equal Date.new(1998,6,5), Date.new(2005,6,5).years_ago(7)
+ assert_equal Date.new(2003,2,28), Date.new(2004,2,29).years_ago(1) # 1 year ago from leap day
+ end
+
+ def test_years_since
+ assert_equal Date.new(2006,6,5), Date.new(2005,6,5).years_since(1)
+ assert_equal Date.new(2012,6,5), Date.new(2005,6,5).years_since(7)
+ assert_equal Date.new(2182,6,5), Date.new(2005,6,5).years_since(177)
+ assert_equal Date.new(2005,2,28), Date.new(2004,2,29).years_since(1) # 1 year since leap day
+ end
+
+ def test_last_year
+ assert_equal Date.new(2004,6,5), Date.new(2005,6,5).last_year
+ end
+
+ def test_next_year
+ assert_equal Date.new(2006,6,5), Date.new(2005,6,5).next_year
+ end
+
+ def test_yesterday
+ assert_equal Date.new(2005,2,21), Date.new(2005,2,22).yesterday
+ assert_equal Date.new(2005,2,28), Date.new(2005,3,2).yesterday.yesterday
+ end
+
+ def test_tomorrow
+ assert_equal Date.new(2005,2,23), Date.new(2005,2,22).tomorrow
+ assert_equal Date.new(2005,3,2), Date.new(2005,2,28).tomorrow.tomorrow
+ end
+
+ def test_advance
+ assert_equal Date.new(2006,2,28), Date.new(2005,2,28).advance(:years => 1)
+ assert_equal Date.new(2005,6,28), Date.new(2005,2,28).advance(:months => 4)
+ assert_equal Date.new(2005,3,21), Date.new(2005,2,28).advance(:weeks => 3)
+ assert_equal Date.new(2005,3,5), Date.new(2005,2,28).advance(:days => 5)
+ assert_equal Date.new(2012,9,28), Date.new(2005,2,28).advance(:years => 7, :months => 7)
+ assert_equal Date.new(2013,10,3), Date.new(2005,2,28).advance(:years => 7, :months => 19, :days => 5)
+ assert_equal Date.new(2013,10,17), Date.new(2005,2,28).advance(:years => 7, :months => 19, :weeks => 2, :days => 5)
+ assert_equal Date.new(2005,2,28), Date.new(2004,2,29).advance(:years => 1) #leap day plus one year
+ end
+
+ def test_next_week
+ assert_equal Date.new(2005,2,28), Date.new(2005,2,22).next_week
+ assert_equal Date.new(2005,3,4), Date.new(2005,2,22).next_week(:friday)
+ assert_equal Date.new(2006,10,30), Date.new(2006,10,23).next_week
+ assert_equal Date.new(2006,11,1), Date.new(2006,10,23).next_week(:wednesday)
+ end
+
+ def test_next_month_on_31st
+ assert_equal Date.new(2005, 9, 30), Date.new(2005, 8, 31).next_month
+ end
+
+ def test_last_month_on_31st
+ assert_equal Date.new(2004, 2, 29), Date.new(2004, 3, 31).last_month
+ end
+
+ def test_yesterday_constructor
+ assert_equal Date.today - 1, Date.yesterday
+ end
+
+ def test_tomorrow_constructor
+ assert_equal Date.today + 1, Date.tomorrow
+ end
+
+ def test_since
+ assert_equal Time.local(2005,2,21,0,0,45), Date.new(2005,2,21).since(45)
+ end
+
+ def test_ago
+ assert_equal Time.local(2005,2,20,23,59,15), Date.new(2005,2,21).ago(45)
+ end
+
+ def test_beginning_of_day
+ assert_equal Time.local(2005,2,21,0,0,0), Date.new(2005,2,21).beginning_of_day
+ end
+
+ def test_end_of_day
+ assert_equal Time.local(2005,2,21,23,59,59), Date.new(2005,2,21).end_of_day
+ end
+
+ def test_xmlschema
+ with_timezone 'US/Eastern' do
+ assert_match(/^1980-02-28T00:00:00-05:?00$/, Date.new(1980, 2, 28).xmlschema)
+ assert_match(/^1980-06-28T00:00:00-04:?00$/, Date.new(1980, 6, 28).xmlschema)
+ # these tests are only of interest on platforms where older dates #to_time fail over to DateTime
+ if ::DateTime === Date.new(1880, 6, 28).to_time
+ assert_match(/^1880-02-28T00:00:00-05:?00$/, Date.new(1880, 2, 28).xmlschema)
+ assert_match(/^1880-06-28T00:00:00-05:?00$/, Date.new(1880, 6, 28).xmlschema) # DateTimes aren't aware of DST rules
+ end
+ end
+ end
+
+ protected
+ def with_timezone(new_tz = 'US/Eastern')
+ old_tz, ENV['TZ'] = ENV['TZ'], new_tz
+ yield
+ ensure
+ old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/date_time_ext_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/date_time_ext_test.rb
new file mode 100644
index 000000000..57697871f
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/date_time_ext_test.rb
@@ -0,0 +1,230 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class DateTimeExtCalculationsTest < Test::Unit::TestCase
+ def test_to_s
+ datetime = DateTime.new(2005, 2, 21, 14, 30, 0, 0)
+ assert_match(/^2005-02-21T14:30:00(Z|\+00:00)$/, datetime.to_s)
+ assert_equal "2005-02-21 14:30:00", datetime.to_s(:db)
+ assert_equal "14:30", datetime.to_s(:time)
+ assert_equal "21 Feb 14:30", datetime.to_s(:short)
+ assert_equal "February 21, 2005 14:30", datetime.to_s(:long)
+ assert_equal "Mon, 21 Feb 2005 14:30:00 +0000", datetime.to_s(:rfc822)
+ assert_equal "February 21st, 2005 14:30", datetime.to_s(:long_ordinal)
+ end
+
+ def test_readable_inspect
+ datetime = DateTime.new(2005, 2, 21, 14, 30, 0)
+ assert_equal "Mon, 21 Feb 2005 14:30:00 +0000", datetime.readable_inspect
+ assert_equal datetime.readable_inspect, datetime.inspect
+ end
+
+ def test_custom_date_format
+ Time::DATE_FORMATS[:custom] = '%Y%m%d%H%M%S'
+ assert_equal '20050221143000', DateTime.new(2005, 2, 21, 14, 30, 0).to_s(:custom)
+ Time::DATE_FORMATS.delete(:custom)
+ end
+
+ def test_to_date
+ assert_equal Date.new(2005, 2, 21), DateTime.new(2005, 2, 21).to_date
+ end
+
+ def test_to_datetime
+ assert_equal DateTime.new(2005, 2, 21), DateTime.new(2005, 2, 21).to_datetime
+ end
+
+ def test_to_time
+ assert_equal Time.utc(2005, 2, 21, 10, 11, 12), DateTime.new(2005, 2, 21, 10, 11, 12, 0, 0).to_time
+ assert_equal Time.utc_time(2039, 2, 21, 10, 11, 12), DateTime.new(2039, 2, 21, 10, 11, 12, 0, 0).to_time
+ # DateTimes with offsets other than 0 are returned unaltered
+ assert_equal DateTime.new(2005, 2, 21, 10, 11, 12, Rational(-5, 24)), DateTime.new(2005, 2, 21, 10, 11, 12, Rational(-5, 24)).to_time
+ end
+
+ def test_seconds_since_midnight
+ assert_equal 1,DateTime.civil(2005,1,1,0,0,1).seconds_since_midnight
+ assert_equal 60,DateTime.civil(2005,1,1,0,1,0).seconds_since_midnight
+ assert_equal 3660,DateTime.civil(2005,1,1,1,1,0).seconds_since_midnight
+ assert_equal 86399,DateTime.civil(2005,1,1,23,59,59).seconds_since_midnight
+ end
+
+ def test_beginning_of_week
+ assert_equal DateTime.civil(2005,1,31), DateTime.civil(2005,2,4,10,10,10).beginning_of_week
+ assert_equal DateTime.civil(2005,11,28), DateTime.civil(2005,11,28,0,0,0).beginning_of_week #monday
+ assert_equal DateTime.civil(2005,11,28), DateTime.civil(2005,11,29,0,0,0).beginning_of_week #tuesday
+ assert_equal DateTime.civil(2005,11,28), DateTime.civil(2005,11,30,0,0,0).beginning_of_week #wednesday
+ assert_equal DateTime.civil(2005,11,28), DateTime.civil(2005,12,01,0,0,0).beginning_of_week #thursday
+ assert_equal DateTime.civil(2005,11,28), DateTime.civil(2005,12,02,0,0,0).beginning_of_week #friday
+ assert_equal DateTime.civil(2005,11,28), DateTime.civil(2005,12,03,0,0,0).beginning_of_week #saturday
+ assert_equal DateTime.civil(2005,11,28), DateTime.civil(2005,12,04,0,0,0).beginning_of_week #sunday
+ end
+
+ def test_beginning_of_day
+ assert_equal DateTime.civil(2005,2,4,0,0,0), DateTime.civil(2005,2,4,10,10,10).beginning_of_day
+ end
+
+ def test_end_of_day
+ assert_equal DateTime.civil(2005,2,4,23,59,59), DateTime.civil(2005,2,4,10,10,10).end_of_day
+ end
+
+ def test_beginning_of_month
+ assert_equal DateTime.civil(2005,2,1,0,0,0), DateTime.civil(2005,2,22,10,10,10).beginning_of_month
+ end
+
+ def test_beginning_of_quarter
+ assert_equal DateTime.civil(2005,1,1,0,0,0), DateTime.civil(2005,2,15,10,10,10).beginning_of_quarter
+ assert_equal DateTime.civil(2005,1,1,0,0,0), DateTime.civil(2005,1,1,0,0,0).beginning_of_quarter
+ assert_equal DateTime.civil(2005,10,1,0,0,0), DateTime.civil(2005,12,31,10,10,10).beginning_of_quarter
+ assert_equal DateTime.civil(2005,4,1,0,0,0), DateTime.civil(2005,6,30,23,59,59).beginning_of_quarter
+ end
+
+ def test_end_of_month
+ assert_equal DateTime.civil(2005,3,31,23,59,59), DateTime.civil(2005,3,20,10,10,10).end_of_month
+ assert_equal DateTime.civil(2005,2,28,23,59,59), DateTime.civil(2005,2,20,10,10,10).end_of_month
+ assert_equal DateTime.civil(2005,4,30,23,59,59), DateTime.civil(2005,4,20,10,10,10).end_of_month
+ end
+
+ def test_beginning_of_year
+ assert_equal DateTime.civil(2005,1,1,0,0,0), DateTime.civil(2005,2,22,10,10,10).beginning_of_year
+ end
+
+ def test_months_ago
+ assert_equal DateTime.civil(2005,5,5,10), DateTime.civil(2005,6,5,10,0,0).months_ago(1)
+ assert_equal DateTime.civil(2004,11,5,10), DateTime.civil(2005,6,5,10,0,0).months_ago(7)
+ assert_equal DateTime.civil(2004,12,5,10), DateTime.civil(2005,6,5,10,0,0).months_ago(6)
+ assert_equal DateTime.civil(2004,6,5,10), DateTime.civil(2005,6,5,10,0,0).months_ago(12)
+ assert_equal DateTime.civil(2003,6,5,10), DateTime.civil(2005,6,5,10,0,0).months_ago(24)
+ end
+
+ def test_months_since
+ assert_equal DateTime.civil(2005,7,5,10), DateTime.civil(2005,6,5,10,0,0).months_since(1)
+ assert_equal DateTime.civil(2006,1,5,10), DateTime.civil(2005,12,5,10,0,0).months_since(1)
+ assert_equal DateTime.civil(2005,12,5,10), DateTime.civil(2005,6,5,10,0,0).months_since(6)
+ assert_equal DateTime.civil(2006,6,5,10), DateTime.civil(2005,12,5,10,0,0).months_since(6)
+ assert_equal DateTime.civil(2006,1,5,10), DateTime.civil(2005,6,5,10,0,0).months_since(7)
+ assert_equal DateTime.civil(2006,6,5,10), DateTime.civil(2005,6,5,10,0,0).months_since(12)
+ assert_equal DateTime.civil(2007,6,5,10), DateTime.civil(2005,6,5,10,0,0).months_since(24)
+ assert_equal DateTime.civil(2005,4,30,10), DateTime.civil(2005,3,31,10,0,0).months_since(1)
+ assert_equal DateTime.civil(2005,2,28,10), DateTime.civil(2005,1,29,10,0,0).months_since(1)
+ assert_equal DateTime.civil(2005,2,28,10), DateTime.civil(2005,1,30,10,0,0).months_since(1)
+ assert_equal DateTime.civil(2005,2,28,10), DateTime.civil(2005,1,31,10,0,0).months_since(1)
+ end
+
+ def test_years_ago
+ assert_equal DateTime.civil(2004,6,5,10), DateTime.civil(2005,6,5,10,0,0).years_ago(1)
+ assert_equal DateTime.civil(1998,6,5,10), DateTime.civil(2005,6,5,10,0,0).years_ago(7)
+ assert_equal DateTime.civil(2003,2,28,10), DateTime.civil(2004,2,29,10,0,0).years_ago(1) # 1 year ago from leap day
+ end
+
+ def test_years_since
+ assert_equal DateTime.civil(2006,6,5,10), DateTime.civil(2005,6,5,10,0,0).years_since(1)
+ assert_equal DateTime.civil(2012,6,5,10), DateTime.civil(2005,6,5,10,0,0).years_since(7)
+ assert_equal DateTime.civil(2182,6,5,10), DateTime.civil(2005,6,5,10,0,0).years_since(177)
+ assert_equal DateTime.civil(2005,2,28,10), DateTime.civil(2004,2,29,10,0,0).years_since(1) # 1 year since leap day
+ end
+
+ def test_last_year
+ assert_equal DateTime.civil(2004,6,5,10), DateTime.civil(2005,6,5,10,0,0).last_year
+ end
+
+ def test_next_year
+ assert_equal DateTime.civil(2006,6,5,10), DateTime.civil(2005,6,5,10,0,0).next_year
+ end
+
+ def test_ago
+ assert_equal DateTime.civil(2005,2,22,10,10,9), DateTime.civil(2005,2,22,10,10,10).ago(1)
+ assert_equal DateTime.civil(2005,2,22,9,10,10), DateTime.civil(2005,2,22,10,10,10).ago(3600)
+ assert_equal DateTime.civil(2005,2,20,10,10,10), DateTime.civil(2005,2,22,10,10,10).ago(86400*2)
+ assert_equal DateTime.civil(2005,2,20,9,9,45), DateTime.civil(2005,2,22,10,10,10).ago(86400*2 + 3600 + 25)
+ end
+
+ def test_since
+ assert_equal DateTime.civil(2005,2,22,10,10,11), DateTime.civil(2005,2,22,10,10,10).since(1)
+ assert_equal DateTime.civil(2005,2,22,11,10,10), DateTime.civil(2005,2,22,10,10,10).since(3600)
+ assert_equal DateTime.civil(2005,2,24,10,10,10), DateTime.civil(2005,2,22,10,10,10).since(86400*2)
+ assert_equal DateTime.civil(2005,2,24,11,10,35), DateTime.civil(2005,2,22,10,10,10).since(86400*2 + 3600 + 25)
+ assert_equal DateTime.civil(2005,2,22,10,10,11), DateTime.civil(2005,2,22,10,10,10).since(1.333)
+ assert_equal DateTime.civil(2005,2,22,10,10,12), DateTime.civil(2005,2,22,10,10,10).since(1.667)
+ end
+
+ def test_yesterday
+ assert_equal DateTime.civil(2005,2,21,10,10,10), DateTime.civil(2005,2,22,10,10,10).yesterday
+ assert_equal DateTime.civil(2005,2,28,10,10,10), DateTime.civil(2005,3,2,10,10,10).yesterday.yesterday
+ end
+
+ def test_tomorrow
+ assert_equal DateTime.civil(2005,2,23,10,10,10), DateTime.civil(2005,2,22,10,10,10).tomorrow
+ assert_equal DateTime.civil(2005,3,2,10,10,10), DateTime.civil(2005,2,28,10,10,10).tomorrow.tomorrow
+ end
+
+ def test_change
+ assert_equal DateTime.civil(2006,2,22,15,15,10), DateTime.civil(2005,2,22,15,15,10).change(:year => 2006)
+ assert_equal DateTime.civil(2005,6,22,15,15,10), DateTime.civil(2005,2,22,15,15,10).change(:month => 6)
+ assert_equal DateTime.civil(2012,9,22,15,15,10), DateTime.civil(2005,2,22,15,15,10).change(:year => 2012, :month => 9)
+ assert_equal DateTime.civil(2005,2,22,16), DateTime.civil(2005,2,22,15,15,10).change(:hour => 16)
+ assert_equal DateTime.civil(2005,2,22,16,45), DateTime.civil(2005,2,22,15,15,10).change(:hour => 16, :min => 45)
+ assert_equal DateTime.civil(2005,2,22,15,45), DateTime.civil(2005,2,22,15,15,10).change(:min => 45)
+ end
+
+ def test_advance
+ assert_equal DateTime.civil(2006,2,28,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:years => 1)
+ assert_equal DateTime.civil(2005,6,28,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:months => 4)
+ assert_equal DateTime.civil(2005,3,21,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:weeks => 3)
+ assert_equal DateTime.civil(2005,3,5,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:days => 5)
+ assert_equal DateTime.civil(2012,9,28,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:years => 7, :months => 7)
+ assert_equal DateTime.civil(2013,10,3,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :days => 5)
+ assert_equal DateTime.civil(2013,10,17,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :weeks => 2, :days => 5)
+ assert_equal DateTime.civil(2001,12,27,15,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:years => -3, :months => -2, :days => -1)
+ assert_equal DateTime.civil(2005,2,28,15,15,10), DateTime.civil(2004,2,29,15,15,10).advance(:years => 1) #leap day plus one year
+ assert_equal DateTime.civil(2005,2,28,20,15,10), DateTime.civil(2005,2,28,15,15,10).advance(:hours => 5)
+ assert_equal DateTime.civil(2005,2,28,15,22,10), DateTime.civil(2005,2,28,15,15,10).advance(:minutes => 7)
+ assert_equal DateTime.civil(2005,2,28,15,15,19), DateTime.civil(2005,2,28,15,15,10).advance(:seconds => 9)
+ assert_equal DateTime.civil(2005,2,28,20,22,19), DateTime.civil(2005,2,28,15,15,10).advance(:hours => 5, :minutes => 7, :seconds => 9)
+ assert_equal DateTime.civil(2005,2,28,10,8,1), DateTime.civil(2005,2,28,15,15,10).advance(:hours => -5, :minutes => -7, :seconds => -9)
+ assert_equal DateTime.civil(2013,10,17,20,22,19), DateTime.civil(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :weeks => 2, :days => 5, :hours => 5, :minutes => 7, :seconds => 9)
+
+ end
+
+ def test_next_week
+ assert_equal DateTime.civil(2005,2,28), DateTime.civil(2005,2,22,15,15,10).next_week
+ assert_equal DateTime.civil(2005,3,4), DateTime.civil(2005,2,22,15,15,10).next_week(:friday)
+ assert_equal DateTime.civil(2006,10,30), DateTime.civil(2006,10,23,0,0,0).next_week
+ assert_equal DateTime.civil(2006,11,1), DateTime.civil(2006,10,23,0,0,0).next_week(:wednesday)
+ end
+
+ def test_next_month_on_31st
+ assert_equal DateTime.civil(2005, 9, 30), DateTime.civil(2005, 8, 31).next_month
+ end
+
+ def test_last_month_on_31st
+ assert_equal DateTime.civil(2004, 2, 29), DateTime.civil(2004, 3, 31).last_month
+ end
+
+ def test_xmlschema
+ assert_match(/^1880-02-28T15:15:10\+00:?00$/, DateTime.civil(1880, 2, 28, 15, 15, 10).xmlschema)
+ assert_match(/^1980-02-28T15:15:10\+00:?00$/, DateTime.civil(1980, 2, 28, 15, 15, 10).xmlschema)
+ assert_match(/^2080-02-28T15:15:10\+00:?00$/, DateTime.civil(2080, 2, 28, 15, 15, 10).xmlschema)
+ assert_match(/^1880-02-28T15:15:10-06:?00$/, DateTime.civil(1880, 2, 28, 15, 15, 10, -0.25).xmlschema)
+ assert_match(/^1980-02-28T15:15:10-06:?00$/, DateTime.civil(1980, 2, 28, 15, 15, 10, -0.25).xmlschema)
+ assert_match(/^2080-02-28T15:15:10-06:?00$/, DateTime.civil(2080, 2, 28, 15, 15, 10, -0.25).xmlschema)
+ end
+
+ def test_acts_like_time
+ assert DateTime.new.acts_like_time?
+ end
+
+ def test_local_offset
+ with_timezone 'US/Eastern' do
+ assert_equal Rational(-5, 24), DateTime.local_offset
+ end
+ with_timezone 'US/Central' do
+ assert_equal Rational(-6, 24), DateTime.local_offset
+ end
+ end
+
+ protected
+ def with_timezone(new_tz = 'US/Eastern')
+ old_tz, ENV['TZ'] = ENV['TZ'], new_tz
+ yield
+ ensure
+ old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/duplicable_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/duplicable_test.rb
new file mode 100644
index 000000000..5e34184a4
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/duplicable_test.rb
@@ -0,0 +1,22 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class DuplicableTest < Test::Unit::TestCase
+ NO = [nil, false, true, :symbol, 1, 2.3, BigDecimal.new('4.56')]
+ YES = ['1', Object.new, /foo/, [], {}, Time.now]
+
+ def test_duplicable
+ NO.each do |v|
+ assert !v.duplicable?
+ begin
+ v.dup
+ fail
+ rescue Exception
+ end
+ end
+
+ YES.each do |v|
+ assert v.duplicable?
+ assert_nothing_raised { v.dup }
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/duration_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/duration_test.rb
new file mode 100644
index 000000000..125232bd4
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/duration_test.rb
@@ -0,0 +1,21 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class DurationTest < Test::Unit::TestCase
+ def test_inspect
+ assert_equal '1 month', 1.month.inspect
+ assert_equal '1 month and 1 day', (1.month + 1.day).inspect
+ assert_equal '6 months and -2 days', (6.months - 2.days).inspect
+ assert_equal '10 seconds', 10.seconds.inspect
+ assert_equal '10 years, 2 months, and 1 day', (10.years + 2.months + 1.day).inspect
+ assert_equal '7 days', 1.week.inspect
+ assert_equal '14 days', 1.fortnight.inspect
+ end
+
+ def test_minus_with_duration_does_not_break_subtraction_of_date_from_date
+ assert_nothing_raised { Date.today - Date.today }
+ end
+
+ def test_plus_with_time
+ assert_equal 1 + 1.second, 1.second + 1, "Duration + Numeric should == Numeric + Duration"
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/enumerable_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/enumerable_test.rb
new file mode 100644
index 000000000..af183dace
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/enumerable_test.rb
@@ -0,0 +1,61 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+Payment = Struct.new(:price)
+class SummablePayment < Payment
+ def +(p) self.class.new(price + p.price) end
+end
+
+class EnumerableTests < Test::Unit::TestCase
+ def test_group_by
+ names = %w(marcel sam david jeremy)
+ klass = Struct.new(:name)
+ objects = (1..50).inject([]) do |people,|
+ p = klass.new
+ p.name = names.sort_by { rand }.first
+ people << p
+ end
+
+ objects.group_by {|object| object.name}.each do |name, group|
+ assert group.all? {|person| person.name == name}
+ end
+ end
+
+ def test_sums
+ assert_equal 30, [5, 15, 10].sum
+ assert_equal 30, [5, 15, 10].sum { |i| i }
+
+ assert_equal 'abc', %w(a b c).sum
+ assert_equal 'abc', %w(a b c).sum { |i| i }
+
+ payments = [ Payment.new(5), Payment.new(15), Payment.new(10) ]
+ assert_equal 30, payments.sum(&:price)
+ assert_equal 60, payments.sum { |p| p.price * 2 }
+
+ payments = [ SummablePayment.new(5), SummablePayment.new(15) ]
+ assert_equal SummablePayment.new(20), payments.sum
+ assert_equal SummablePayment.new(20), payments.sum { |p| p }
+ end
+
+ def test_nil_sums
+ expected_raise = TypeError
+
+ assert_raise(expected_raise) { [5, 15, nil].sum }
+
+ payments = [ Payment.new(5), Payment.new(15), Payment.new(10), Payment.new(nil) ]
+ assert_raise(expected_raise) { payments.sum(&:price) }
+
+ assert_equal 60, payments.sum { |p| p.price.to_i * 2 }
+ end
+
+ def test_empty_sums
+ assert_equal 0, [].sum
+ assert_equal 0, [].sum { |i| i }
+ assert_equal Payment.new(0), [].sum(Payment.new(0))
+ end
+
+ def test_index_by
+ payments = [ Payment.new(5), Payment.new(15), Payment.new(10) ]
+ assert_equal({ 5 => payments[0], 15 => payments[1], 10 => payments[2] },
+ payments.index_by { |p| p.price })
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/exception_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/exception_test.rb
new file mode 100644
index 000000000..b1ea564a0
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/exception_test.rb
@@ -0,0 +1,64 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class ExceptionExtTests < Test::Unit::TestCase
+
+ def get_exception(cls = RuntimeError, msg = nil, trace = nil)
+ begin raise cls, msg, (trace || caller)
+ rescue Exception => e # passed Exception
+ return e
+ end
+ end
+
+ def setup
+ Exception::TraceSubstitutions.clear
+ end
+
+ def test_clean_backtrace
+ Exception::TraceSubstitutions << [/\s*hidden.*/, '']
+ e = get_exception RuntimeError, 'RAWR', ['bhal.rb', 'rawh hid den stuff is not here', 'almost all']
+ assert_kind_of Exception, e
+ assert_equal ['bhal.rb', 'rawh hid den stuff is not here', 'almost all'], e.clean_backtrace
+ end
+
+ def test_app_backtrace
+ Exception::TraceSubstitutions << [/\s*hidden.*/, '']
+ e = get_exception RuntimeError, 'RAWR', ['bhal.rb', ' vendor/file.rb some stuff', 'almost all']
+ assert_kind_of Exception, e
+ assert_equal ['bhal.rb', 'almost all'], e.application_backtrace
+ end
+
+ def test_app_backtrace_with_before
+ Exception::TraceSubstitutions << [/\s*hidden.*/, '']
+ e = get_exception RuntimeError, 'RAWR', ['vendor/file.rb some stuff', 'bhal.rb', ' vendor/file.rb some stuff', 'almost all']
+ assert_kind_of Exception, e
+ assert_equal ['vendor/file.rb some stuff', 'bhal.rb', 'almost all'], e.application_backtrace
+ end
+
+ def test_framework_backtrace_with_before
+ Exception::TraceSubstitutions << [/\s*hidden.*/, '']
+ e = get_exception RuntimeError, 'RAWR', ['vendor/file.rb some stuff', 'bhal.rb', ' vendor/file.rb some stuff', 'almost all']
+ assert_kind_of Exception, e
+ assert_equal ['vendor/file.rb some stuff', ' vendor/file.rb some stuff'], e.framework_backtrace
+ end
+
+ def test_backtrace_should_clean_paths
+ Exception::TraceSubstitutions << [/\s*hidden.*/, '']
+ e = get_exception RuntimeError, 'RAWR', ['a/b/c/../d/../../../bhal.rb', 'rawh hid den stuff is not here', 'almost all']
+ assert_kind_of Exception, e
+ assert_equal ['bhal.rb', 'rawh hid den stuff is not here', 'almost all'], e.clean_backtrace
+ end
+
+ def test_clean_message_should_clean_paths
+ Exception::TraceSubstitutions << [/\s*hidden.*/, '']
+ e = get_exception RuntimeError, "I dislike a/z/x/../../b/y/../c", ['a/b/c/../d/../../../bhal.rb', 'rawh hid den stuff is not here', 'almost all']
+ assert_kind_of Exception, e
+ assert_equal "I dislike a/b/c", e.clean_message
+ end
+
+ def test_app_trace_should_be_empty_when_no_app_frames
+ Exception::TraceSubstitutions << [/\s*hidden.*/, '']
+ e = get_exception RuntimeError, 'RAWR', ['vendor/file.rb some stuff', 'generated/bhal.rb', ' vendor/file.rb some stuff', 'generated/almost all']
+ assert_kind_of Exception, e
+ assert_equal [], e.application_backtrace
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/file_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/file_test.rb
new file mode 100644
index 000000000..110253887
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/file_test.rb
@@ -0,0 +1,29 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class AtomicWriteTest < Test::Unit::TestCase
+
+ def test_atomic_write_without_errors
+ contents = "Atomic Text"
+ File.atomic_write(file_name, Dir.pwd) do |file|
+ file.write(contents)
+ assert !File.exist?(file_name)
+ end
+ assert File.exist?(file_name)
+ assert_equal contents, File.read(file_name)
+ ensure
+ File.unlink(file_name) rescue nil
+ end
+
+ def test_atomic_write_doesnt_write_when_block_raises
+ File.atomic_write(file_name) do |file|
+ file.write("testing")
+ raise "something bad"
+ end
+ rescue
+ assert !File.exist?(file_name)
+ end
+
+ def file_name
+ "atomic.file"
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/float_ext_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/float_ext_test.rb
new file mode 100644
index 000000000..b74add519
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/float_ext_test.rb
@@ -0,0 +1,25 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class FloatExtRoundingTests < Test::Unit::TestCase
+ def test_round_for_positive_number
+ assert_equal 1, 1.4.round
+ assert_equal 2, 1.6.round
+ assert_equal 2, 1.6.round(0)
+ assert_equal 1.4, 1.4.round(1)
+ assert_equal 1.4, 1.4.round(3)
+ assert_equal 1.5, 1.45.round(1)
+ assert_equal 1.45, 1.445.round(2)
+ end
+
+ def test_round_for_negative_number
+ assert_equal( -1, -1.4.round )
+ assert_equal( -2, -1.6.round )
+ assert_equal( -1.4, -1.4.round(1) )
+ assert_equal( -1.5, -1.45.round(1) )
+ end
+
+ def test_round_with_negative_precision
+ assert_equal 123460.0, 123456.0.round(-1)
+ assert_equal 123500.0, 123456.0.round(-2)
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/hash_ext_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/hash_ext_test.rb
new file mode 100644
index 000000000..4d01faa5d
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/hash_ext_test.rb
@@ -0,0 +1,743 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class HashExtTest < Test::Unit::TestCase
+ def setup
+ @strings = { 'a' => 1, 'b' => 2 }
+ @symbols = { :a => 1, :b => 2 }
+ @mixed = { :a => 1, 'b' => 2 }
+ @fixnums = { 0 => 1, 1 => 2 }
+ end
+
+ def test_methods
+ h = {}
+ assert_respond_to h, :symbolize_keys
+ assert_respond_to h, :symbolize_keys!
+ assert_respond_to h, :stringify_keys
+ assert_respond_to h, :stringify_keys!
+ assert_respond_to h, :to_options
+ assert_respond_to h, :to_options!
+ end
+
+ def test_symbolize_keys
+ assert_equal @symbols, @symbols.symbolize_keys
+ assert_equal @symbols, @strings.symbolize_keys
+ assert_equal @symbols, @mixed.symbolize_keys
+
+ assert_raises(NoMethodError) { { [] => 1 }.symbolize_keys }
+ end
+
+ def test_symbolize_keys!
+ assert_equal @symbols, @symbols.dup.symbolize_keys!
+ assert_equal @symbols, @strings.dup.symbolize_keys!
+ assert_equal @symbols, @mixed.dup.symbolize_keys!
+
+ assert_raises(NoMethodError) { { [] => 1 }.symbolize_keys }
+ end
+
+ def test_symbolize_keys_preserves_fixnum_keys
+ assert_equal @fixnums, @fixnums.symbolize_keys
+ assert_equal @fixnums, @fixnums.dup.symbolize_keys!
+ end
+
+ def test_stringify_keys
+ assert_equal @strings, @symbols.stringify_keys
+ assert_equal @strings, @strings.stringify_keys
+ assert_equal @strings, @mixed.stringify_keys
+ end
+
+ def test_stringify_keys!
+ assert_equal @strings, @symbols.dup.stringify_keys!
+ assert_equal @strings, @strings.dup.stringify_keys!
+ assert_equal @strings, @mixed.dup.stringify_keys!
+ end
+
+ def test_indifferent_assorted
+ @strings = @strings.with_indifferent_access
+ @symbols = @symbols.with_indifferent_access
+ @mixed = @mixed.with_indifferent_access
+
+ assert_equal 'a', @strings.send!(:convert_key, :a)
+
+ assert_equal 1, @strings.fetch('a')
+ assert_equal 1, @strings.fetch(:a.to_s)
+ assert_equal 1, @strings.fetch(:a)
+
+ hashes = { :@strings => @strings, :@symbols => @symbols, :@mixed => @mixed }
+ method_map = { :'[]' => 1, :fetch => 1, :values_at => [1],
+ :has_key? => true, :include? => true, :key? => true,
+ :member? => true }
+
+ hashes.each do |name, hash|
+ method_map.sort_by { |m| m.to_s }.each do |meth, expected|
+ assert_equal(expected, hash.send!(meth, 'a'),
+ "Calling #{name}.#{meth} 'a'")
+ assert_equal(expected, hash.send!(meth, :a),
+ "Calling #{name}.#{meth} :a")
+ end
+ end
+
+ assert_equal [1, 2], @strings.values_at('a', 'b')
+ assert_equal [1, 2], @strings.values_at(:a, :b)
+ assert_equal [1, 2], @symbols.values_at('a', 'b')
+ assert_equal [1, 2], @symbols.values_at(:a, :b)
+ assert_equal [1, 2], @mixed.values_at('a', 'b')
+ assert_equal [1, 2], @mixed.values_at(:a, :b)
+ end
+
+ def test_indifferent_reading
+ hash = HashWithIndifferentAccess.new
+ hash["a"] = 1
+ hash["b"] = true
+ hash["c"] = false
+ hash["d"] = nil
+
+ assert_equal 1, hash[:a]
+ assert_equal true, hash[:b]
+ assert_equal false, hash[:c]
+ assert_equal nil, hash[:d]
+ assert_equal nil, hash[:e]
+ end
+
+ def test_indifferent_reading_with_nonnil_default
+ hash = HashWithIndifferentAccess.new(1)
+ hash["a"] = 1
+ hash["b"] = true
+ hash["c"] = false
+ hash["d"] = nil
+
+ assert_equal 1, hash[:a]
+ assert_equal true, hash[:b]
+ assert_equal false, hash[:c]
+ assert_equal nil, hash[:d]
+ assert_equal 1, hash[:e]
+ end
+
+ def test_indifferent_writing
+ hash = HashWithIndifferentAccess.new
+ hash[:a] = 1
+ hash['b'] = 2
+ hash[3] = 3
+
+ assert_equal hash['a'], 1
+ assert_equal hash['b'], 2
+ assert_equal hash[:a], 1
+ assert_equal hash[:b], 2
+ assert_equal hash[3], 3
+ end
+
+ def test_indifferent_update
+ hash = HashWithIndifferentAccess.new
+ hash[:a] = 'a'
+ hash['b'] = 'b'
+
+ updated_with_strings = hash.update(@strings)
+ updated_with_symbols = hash.update(@symbols)
+ updated_with_mixed = hash.update(@mixed)
+
+ assert_equal updated_with_strings[:a], 1
+ assert_equal updated_with_strings['a'], 1
+ assert_equal updated_with_strings['b'], 2
+
+ assert_equal updated_with_symbols[:a], 1
+ assert_equal updated_with_symbols['b'], 2
+ assert_equal updated_with_symbols[:b], 2
+
+ assert_equal updated_with_mixed[:a], 1
+ assert_equal updated_with_mixed['b'], 2
+
+ assert [updated_with_strings, updated_with_symbols, updated_with_mixed].all? { |h| h.keys.size == 2 }
+ end
+
+ def test_indifferent_merging
+ hash = HashWithIndifferentAccess.new
+ hash[:a] = 'failure'
+ hash['b'] = 'failure'
+
+ other = { 'a' => 1, :b => 2 }
+
+ merged = hash.merge(other)
+
+ assert_equal HashWithIndifferentAccess, merged.class
+ assert_equal 1, merged[:a]
+ assert_equal 2, merged['b']
+
+ hash.update(other)
+
+ assert_equal 1, hash[:a]
+ assert_equal 2, hash['b']
+ end
+
+ def test_indifferent_deleting
+ get_hash = proc{ { :a => 'foo' }.with_indifferent_access }
+ hash = get_hash.call
+ assert_equal hash.delete(:a), 'foo'
+ assert_equal hash.delete(:a), nil
+ hash = get_hash.call
+ assert_equal hash.delete('a'), 'foo'
+ assert_equal hash.delete('a'), nil
+ end
+
+ def test_indifferent_to_hash
+ # Should convert to a Hash with String keys.
+ assert_equal @strings, @mixed.with_indifferent_access.to_hash
+
+ # Should preserve the default value.
+ mixed_with_default = @mixed.dup
+ mixed_with_default.default = '1234'
+ roundtrip = mixed_with_default.with_indifferent_access.to_hash
+ assert_equal @strings, roundtrip
+ assert_equal '1234', roundtrip.default
+ end
+
+ def test_indifferent_hash_with_array_of_hashes
+ hash = { "urls" => { "url" => [ { "address" => "1" }, { "address" => "2" } ] }}.with_indifferent_access
+ assert_equal "1", hash[:urls][:url].first[:address]
+ end
+
+ def test_stringify_and_symbolize_keys_on_indifferent_preserves_hash
+ h = HashWithIndifferentAccess.new
+ h[:first] = 1
+ h.stringify_keys!
+ assert_equal 1, h['first']
+ h = HashWithIndifferentAccess.new
+ h['first'] = 1
+ h.symbolize_keys!
+ assert_equal 1, h[:first]
+ end
+
+ def test_to_options_on_indifferent_preserves_hash
+ h = HashWithIndifferentAccess.new
+ h['first'] = 1
+ h.to_options!
+ assert_equal 1, h['first']
+ end
+
+
+ def test_indifferent_subhashes
+ h = {'user' => {'id' => 5}}.with_indifferent_access
+ ['user', :user].each {|user| [:id, 'id'].each {|id| assert_equal 5, h[user][id], "h[#{user.inspect}][#{id.inspect}] should be 5"}}
+
+ h = {:user => {:id => 5}}.with_indifferent_access
+ ['user', :user].each {|user| [:id, 'id'].each {|id| assert_equal 5, h[user][id], "h[#{user.inspect}][#{id.inspect}] should be 5"}}
+ end
+
+ def test_assert_valid_keys
+ assert_nothing_raised do
+ { :failure => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny ])
+ { :failure => "stuff", :funny => "business" }.assert_valid_keys(:failure, :funny)
+ end
+
+ assert_raises(ArgumentError, "Unknown key(s): failore") do
+ { :failore => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny ])
+ { :failore => "stuff", :funny => "business" }.assert_valid_keys(:failure, :funny)
+ end
+ end
+
+ def test_assorted_keys_not_stringified
+ original = {Object.new => 2, 1 => 2, [] => true}
+ indiff = original.with_indifferent_access
+ assert(!indiff.keys.any? {|k| k.kind_of? String}, "A key was converted to a string!")
+ end
+
+ def test_reverse_merge
+ defaults = { :a => "x", :b => "y", :c => 10 }.freeze
+ options = { :a => 1, :b => 2 }
+ expected = { :a => 1, :b => 2, :c => 10 }
+
+ # Should merge defaults into options, creating a new hash.
+ assert_equal expected, options.reverse_merge(defaults)
+ assert_not_equal expected, options
+
+ # Should merge! defaults into options, replacing options.
+ merged = options.dup
+ assert_equal expected, merged.reverse_merge!(defaults)
+ assert_equal expected, merged
+
+ # Should be an alias for reverse_merge!
+ merged = options.dup
+ assert_equal expected, merged.reverse_update(defaults)
+ assert_equal expected, merged
+ end
+
+ def test_diff
+ assert_equal({ :a => 2 }, { :a => 2, :b => 5 }.diff({ :a => 1, :b => 5 }))
+ end
+
+ def test_slice
+ original = { :a => 'x', :b => 'y', :c => 10 }
+ expected = { :a => 'x', :b => 'y' }
+
+ # Should return a new hash with only the given keys.
+ assert_equal expected, original.slice(:a, :b)
+ assert_not_equal expected, original
+
+ # Should replace the hash with only the given keys.
+ assert_equal expected, original.slice!(:a, :b)
+ assert_equal expected, original
+ end
+
+ def test_indifferent_slice
+ original = { :a => 'x', :b => 'y', :c => 10 }.with_indifferent_access
+ expected = { :a => 'x', :b => 'y' }.with_indifferent_access
+
+ [['a', 'b'], [:a, :b]].each do |keys|
+ # Should return a new hash with only the given keys.
+ assert_equal expected, original.slice(*keys), keys.inspect
+ assert_not_equal expected, original
+
+ # Should replace the hash with only the given keys.
+ copy = original.dup
+ assert_equal expected, copy.slice!(*keys)
+ assert_equal expected, copy
+ end
+ end
+
+ def test_except
+ original = { :a => 'x', :b => 'y', :c => 10 }
+ expected = { :a => 'x', :b => 'y' }
+
+ # Should return a new hash with only the given keys.
+ assert_equal expected, original.except(:c)
+ assert_not_equal expected, original
+
+ # Should replace the hash with only the given keys.
+ assert_equal expected, original.except!(:c)
+ assert_equal expected, original
+ end
+end
+
+class IWriteMyOwnXML
+ def to_xml(options = {})
+ options[:indent] ||= 2
+ xml = options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
+ xml.instruct! unless options[:skip_instruct]
+ xml.level_one do
+ xml.tag!(:second_level, 'content')
+ end
+ end
+end
+
+class HashToXmlTest < Test::Unit::TestCase
+ def setup
+ @xml_options = { :root => :person, :skip_instruct => true, :indent => 0 }
+ end
+
+ def test_one_level
+ xml = { :name => "David", :street => "Paulina" }.to_xml(@xml_options)
+ assert_equal "<person>", xml.first(8)
+ assert xml.include?(%(<street>Paulina</street>))
+ assert xml.include?(%(<name>David</name>))
+ end
+
+ def test_one_level_dasherize_false
+ xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:dasherize => false))
+ assert_equal "<person>", xml.first(8)
+ assert xml.include?(%(<street_name>Paulina</street_name>))
+ assert xml.include?(%(<name>David</name>))
+ end
+
+ def test_one_level_dasherize_true
+ xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:dasherize => true))
+ assert_equal "<person>", xml.first(8)
+ assert xml.include?(%(<street-name>Paulina</street-name>))
+ assert xml.include?(%(<name>David</name>))
+ end
+
+ def test_one_level_with_types
+ xml = { :name => "David", :street => "Paulina", :age => 26, :age_in_millis => 820497600000, :moved_on => Date.new(2005, 11, 15), :resident => :yes }.to_xml(@xml_options)
+ assert_equal "<person>", xml.first(8)
+ assert xml.include?(%(<street>Paulina</street>))
+ assert xml.include?(%(<name>David</name>))
+ assert xml.include?(%(<age type="integer">26</age>))
+ assert xml.include?(%(<age-in-millis type="integer">820497600000</age-in-millis>))
+ assert xml.include?(%(<moved-on type="date">2005-11-15</moved-on>))
+ assert xml.include?(%(<resident type="symbol">yes</resident>))
+ end
+
+ def test_one_level_with_nils
+ xml = { :name => "David", :street => "Paulina", :age => nil }.to_xml(@xml_options)
+ assert_equal "<person>", xml.first(8)
+ assert xml.include?(%(<street>Paulina</street>))
+ assert xml.include?(%(<name>David</name>))
+ assert xml.include?(%(<age nil="true"></age>))
+ end
+
+ def test_one_level_with_skipping_types
+ xml = { :name => "David", :street => "Paulina", :age => nil }.to_xml(@xml_options.merge(:skip_types => true))
+ assert_equal "<person>", xml.first(8)
+ assert xml.include?(%(<street>Paulina</street>))
+ assert xml.include?(%(<name>David</name>))
+ assert xml.include?(%(<age nil="true"></age>))
+ end
+
+ def test_one_level_with_yielding
+ xml = { :name => "David", :street => "Paulina" }.to_xml(@xml_options) do |x|
+ x.creator("Rails")
+ end
+
+ assert_equal "<person>", xml.first(8)
+ assert xml.include?(%(<street>Paulina</street>))
+ assert xml.include?(%(<name>David</name>))
+ assert xml.include?(%(<creator>Rails</creator>))
+ end
+
+ def test_two_levels
+ xml = { :name => "David", :address => { :street => "Paulina" } }.to_xml(@xml_options)
+ assert_equal "<person>", xml.first(8)
+ assert xml.include?(%(<address><street>Paulina</street></address>))
+ assert xml.include?(%(<name>David</name>))
+ end
+
+ def test_two_levels_with_second_level_overriding_to_xml
+ xml = { :name => "David", :address => { :street => "Paulina" }, :child => IWriteMyOwnXML.new }.to_xml(@xml_options)
+ assert_equal "<person>", xml.first(8)
+ assert xml.include?(%(<address><street>Paulina</street></address>))
+ assert xml.include?(%(<level_one><second_level>content</second_level></level_one>))
+ end
+
+ def test_two_levels_with_array
+ xml = { :name => "David", :addresses => [{ :street => "Paulina" }, { :street => "Evergreen" }] }.to_xml(@xml_options)
+ assert_equal "<person>", xml.first(8)
+ assert xml.include?(%(<addresses type="array"><address>))
+ assert xml.include?(%(<address><street>Paulina</street></address>))
+ assert xml.include?(%(<address><street>Evergreen</street></address>))
+ assert xml.include?(%(<name>David</name>))
+ end
+
+ def test_three_levels_with_array
+ xml = { :name => "David", :addresses => [{ :streets => [ { :name => "Paulina" }, { :name => "Paulina" } ] } ] }.to_xml(@xml_options)
+ assert xml.include?(%(<addresses type="array"><address><streets type="array"><street><name>))
+ end
+
+ def test_single_record_from_xml
+ topic_xml = <<-EOT
+ <topic>
+ <title>The First Topic</title>
+ <author-name>David</author-name>
+ <id type="integer">1</id>
+ <approved type="boolean"> true </approved>
+ <replies-count type="integer">0</replies-count>
+ <replies-close-in type="integer">2592000000</replies-close-in>
+ <written-on type="date">2003-07-16</written-on>
+ <viewed-at type="datetime">2003-07-16T09:28:00+0000</viewed-at>
+ <content type="yaml">--- \n1: should be an integer\n:message: Have a nice day\narray: \n- should-have-dashes: true\n should_have_underscores: true\n</content>
+ <author-email-address>david@loudthinking.com</author-email-address>
+ <parent-id></parent-id>
+ <ad-revenue type="decimal">1.5</ad-revenue>
+ <optimum-viewing-angle type="float">135</optimum-viewing-angle>
+ <resident type="symbol">yes</resident>
+ </topic>
+ EOT
+
+ expected_topic_hash = {
+ :title => "The First Topic",
+ :author_name => "David",
+ :id => 1,
+ :approved => true,
+ :replies_count => 0,
+ :replies_close_in => 2592000000,
+ :written_on => Date.new(2003, 7, 16),
+ :viewed_at => Time.utc(2003, 7, 16, 9, 28),
+ :content => { :message => "Have a nice day", 1 => "should be an integer", "array" => [{ "should-have-dashes" => true, "should_have_underscores" => true }] },
+ :author_email_address => "david@loudthinking.com",
+ :parent_id => nil,
+ :ad_revenue => BigDecimal("1.50"),
+ :optimum_viewing_angle => 135.0,
+ :resident => :yes
+ }.stringify_keys
+
+ assert_equal expected_topic_hash, Hash.from_xml(topic_xml)["topic"]
+ end
+
+ def test_single_record_from_xml_with_nil_values
+ topic_xml = <<-EOT
+ <topic>
+ <title></title>
+ <id type="integer"></id>
+ <approved type="boolean"></approved>
+ <written-on type="date"></written-on>
+ <viewed-at type="datetime"></viewed-at>
+ <content type="yaml"></content>
+ <parent-id></parent-id>
+ </topic>
+ EOT
+
+ expected_topic_hash = {
+ :title => nil,
+ :id => nil,
+ :approved => nil,
+ :written_on => nil,
+ :viewed_at => nil,
+ :content => nil,
+ :parent_id => nil
+ }.stringify_keys
+
+ assert_equal expected_topic_hash, Hash.from_xml(topic_xml)["topic"]
+ end
+
+ def test_multiple_records_from_xml
+ topics_xml = <<-EOT
+ <topics type="array">
+ <topic>
+ <title>The First Topic</title>
+ <author-name>David</author-name>
+ <id type="integer">1</id>
+ <approved type="boolean">false</approved>
+ <replies-count type="integer">0</replies-count>
+ <replies-close-in type="integer">2592000000</replies-close-in>
+ <written-on type="date">2003-07-16</written-on>
+ <viewed-at type="datetime">2003-07-16T09:28:00+0000</viewed-at>
+ <content>Have a nice day</content>
+ <author-email-address>david@loudthinking.com</author-email-address>
+ <parent-id nil="true"></parent-id>
+ </topic>
+ <topic>
+ <title>The Second Topic</title>
+ <author-name>Jason</author-name>
+ <id type="integer">1</id>
+ <approved type="boolean">false</approved>
+ <replies-count type="integer">0</replies-count>
+ <replies-close-in type="integer">2592000000</replies-close-in>
+ <written-on type="date">2003-07-16</written-on>
+ <viewed-at type="datetime">2003-07-16T09:28:00+0000</viewed-at>
+ <content>Have a nice day</content>
+ <author-email-address>david@loudthinking.com</author-email-address>
+ <parent-id></parent-id>
+ </topic>
+ </topics>
+ EOT
+
+ expected_topic_hash = {
+ :title => "The First Topic",
+ :author_name => "David",
+ :id => 1,
+ :approved => false,
+ :replies_count => 0,
+ :replies_close_in => 2592000000,
+ :written_on => Date.new(2003, 7, 16),
+ :viewed_at => Time.utc(2003, 7, 16, 9, 28),
+ :content => "Have a nice day",
+ :author_email_address => "david@loudthinking.com",
+ :parent_id => nil
+ }.stringify_keys
+
+ assert_equal expected_topic_hash, Hash.from_xml(topics_xml)["topics"].first
+ end
+
+ def test_single_record_from_xml_with_attributes_other_than_type
+ topic_xml = <<-EOT
+ <rsp stat="ok">
+ <photos page="1" pages="1" perpage="100" total="16">
+ <photo id="175756086" owner="55569174@N00" secret="0279bf37a1" server="76" title="Colored Pencil PhotoBooth Fun" ispublic="1" isfriend="0" isfamily="0"/>
+ </photos>
+ </rsp>
+ EOT
+
+ expected_topic_hash = {
+ :id => "175756086",
+ :owner => "55569174@N00",
+ :secret => "0279bf37a1",
+ :server => "76",
+ :title => "Colored Pencil PhotoBooth Fun",
+ :ispublic => "1",
+ :isfriend => "0",
+ :isfamily => "0",
+ }.stringify_keys
+
+ assert_equal expected_topic_hash, Hash.from_xml(topic_xml)["rsp"]["photos"]["photo"]
+ end
+
+ def test_empty_array_from_xml
+ blog_xml = <<-XML
+ <blog>
+ <posts type="array"></posts>
+ </blog>
+ XML
+ expected_blog_hash = {"blog" => {"posts" => []}}
+ assert_equal expected_blog_hash, Hash.from_xml(blog_xml)
+ end
+
+ def test_empty_array_with_whitespace_from_xml
+ blog_xml = <<-XML
+ <blog>
+ <posts type="array">
+ </posts>
+ </blog>
+ XML
+ expected_blog_hash = {"blog" => {"posts" => []}}
+ assert_equal expected_blog_hash, Hash.from_xml(blog_xml)
+ end
+
+ def test_array_with_one_entry_from_xml
+ blog_xml = <<-XML
+ <blog>
+ <posts type="array">
+ <post>a post</post>
+ </posts>
+ </blog>
+ XML
+ expected_blog_hash = {"blog" => {"posts" => ["a post"]}}
+ assert_equal expected_blog_hash, Hash.from_xml(blog_xml)
+ end
+
+ def test_array_with_multiple_entries_from_xml
+ blog_xml = <<-XML
+ <blog>
+ <posts type="array">
+ <post>a post</post>
+ <post>another post</post>
+ </posts>
+ </blog>
+ XML
+ expected_blog_hash = {"blog" => {"posts" => ["a post", "another post"]}}
+ assert_equal expected_blog_hash, Hash.from_xml(blog_xml)
+ end
+
+ def test_xsd_like_types_from_xml
+ bacon_xml = <<-EOT
+ <bacon>
+ <weight type="double">0.5</weight>
+ <price type="decimal">12.50</price>
+ <chunky type="boolean"> 1 </chunky>
+ <expires-at type="dateTime">2007-12-25T12:34:56+0000</expires-at>
+ <notes type="string"></notes>
+ <illustration type="base64Binary">YmFiZS5wbmc=</illustration>
+ </bacon>
+ EOT
+
+ expected_bacon_hash = {
+ :weight => 0.5,
+ :chunky => true,
+ :price => BigDecimal("12.50"),
+ :expires_at => Time.utc(2007,12,25,12,34,56),
+ :notes => "",
+ :illustration => "babe.png"
+ }.stringify_keys
+
+ assert_equal expected_bacon_hash, Hash.from_xml(bacon_xml)["bacon"]
+ end
+
+ def test_type_trickles_through_when_unknown
+ product_xml = <<-EOT
+ <product>
+ <weight type="double">0.5</weight>
+ <image type="ProductImage"><filename>image.gif</filename></image>
+
+ </product>
+ EOT
+
+ expected_product_hash = {
+ :weight => 0.5,
+ :image => {'type' => 'ProductImage', 'filename' => 'image.gif' },
+ }.stringify_keys
+
+ assert_equal expected_product_hash, Hash.from_xml(product_xml)["product"]
+ end
+
+ def test_should_use_default_value_for_unknown_key
+ hash_wia = HashWithIndifferentAccess.new(3)
+ assert_equal 3, hash_wia[:new_key]
+ end
+
+ def test_should_use_default_value_if_no_key_is_supplied
+ hash_wia = HashWithIndifferentAccess.new(3)
+ assert_equal 3, hash_wia.default
+ end
+
+ def test_should_nil_if_no_default_value_is_supplied
+ hash_wia = HashWithIndifferentAccess.new
+ assert_nil hash_wia.default
+ end
+
+ def test_should_copy_the_default_value_when_converting_to_hash_with_indifferent_access
+ hash = Hash.new(3)
+ hash_wia = hash.with_indifferent_access
+ assert_equal 3, hash_wia.default
+ end
+
+ # The XML builder seems to fail miserably when trying to tag something
+ # with the same name as a Kernel method (throw, test, loop, select ...)
+ def test_kernel_method_names_to_xml
+ hash = { :throw => { :ball => 'red' } }
+ expected = '<person><throw><ball>red</ball></throw></person>'
+
+ assert_nothing_raised do
+ assert_equal expected, hash.to_xml(@xml_options)
+ end
+ end
+
+ def test_empty_string_works_for_typecast_xml_value
+ assert_nothing_raised do
+ Hash.send!(:typecast_xml_value, "")
+ end
+ end
+
+ def test_escaping_to_xml
+ hash = {
+ :bare_string => 'First & Last Name',
+ :pre_escaped_string => 'First &amp; Last Name'
+ }.stringify_keys
+
+ expected_xml = '<person><bare-string>First &amp; Last Name</bare-string><pre-escaped-string>First &amp;amp; Last Name</pre-escaped-string></person>'
+ assert_equal expected_xml, hash.to_xml(@xml_options)
+ end
+
+ def test_unescaping_from_xml
+ xml_string = '<person><bare-string>First &amp; Last Name</bare-string><pre-escaped-string>First &amp;amp; Last Name</pre-escaped-string></person>'
+ expected_hash = {
+ :bare_string => 'First & Last Name',
+ :pre_escaped_string => 'First &amp; Last Name'
+ }.stringify_keys
+ assert_equal expected_hash, Hash.from_xml(xml_string)['person']
+ end
+
+ def test_roundtrip_to_xml_from_xml
+ hash = {
+ :bare_string => 'First & Last Name',
+ :pre_escaped_string => 'First &amp; Last Name'
+ }.stringify_keys
+
+ assert_equal hash, Hash.from_xml(hash.to_xml(@xml_options))['person']
+ end
+end
+
+class QueryTest < Test::Unit::TestCase
+ def test_simple_conversion
+ assert_query_equal 'a=10', :a => 10
+ end
+
+ def test_cgi_escaping
+ assert_query_equal 'a%3Ab=c+d', 'a:b' => 'c d'
+ end
+
+ def test_nil_parameter_value
+ empty = Object.new
+ def empty.to_param; nil end
+ assert_query_equal 'a=', 'a' => empty
+ end
+
+ def test_nested_conversion
+ assert_query_equal 'person%5Blogin%5D=seckar&person%5Bname%5D=Nicholas',
+ :person => {:name => 'Nicholas', :login => 'seckar'}
+ end
+
+ def test_multiple_nested
+ assert_query_equal 'account%5Bperson%5D%5Bid%5D=20&person%5Bid%5D=10',
+ :person => {:id => 10}, :account => {:person => {:id => 20}}
+ end
+
+ def test_array_values
+ assert_query_equal 'person%5Bid%5D%5B%5D=10&person%5Bid%5D%5B%5D=20',
+ :person => {:id => [10, 20]}
+ end
+
+ def test_array_values_are_not_sorted
+ assert_query_equal 'person%5Bid%5D%5B%5D=20&person%5Bid%5D%5B%5D=10',
+ :person => {:id => [20, 10]}
+ end
+
+ private
+ def assert_query_equal(expected, actual, message = nil)
+ assert_equal expected.split('&'), actual.to_query.split('&')
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/integer_ext_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/integer_ext_test.rb
new file mode 100644
index 000000000..6d6b79686
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/integer_ext_test.rb
@@ -0,0 +1,37 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class IntegerExtTest < Test::Unit::TestCase
+ def test_even
+ assert [ -2, 0, 2, 4 ].all? { |i| i.even? }
+ assert ![ -1, 1, 3 ].all? { |i| i.even? }
+
+ assert 22953686867719691230002707821868552601124472329079.odd?
+ assert !22953686867719691230002707821868552601124472329079.even?
+ assert 22953686867719691230002707821868552601124472329080.even?
+ assert !22953686867719691230002707821868552601124472329080.odd?
+ end
+
+ def test_odd
+ assert ![ -2, 0, 2, 4 ].all? { |i| i.odd? }
+ assert [ -1, 1, 3 ].all? { |i| i.odd? }
+ assert 1000000000000000000000000000000000000000000000000000000001.odd?
+ end
+
+ def test_multiple_of
+ [ -7, 0, 7, 14 ].each { |i| assert i.multiple_of?(7) }
+ [ -7, 7, 14 ].each { |i| assert ! i.multiple_of?(6) }
+ # test with a prime
+ assert !22953686867719691230002707821868552601124472329079.multiple_of?(2)
+ assert !22953686867719691230002707821868552601124472329079.multiple_of?(3)
+ assert !22953686867719691230002707821868552601124472329079.multiple_of?(5)
+ assert !22953686867719691230002707821868552601124472329079.multiple_of?(7)
+ end
+
+ def test_ordinalize
+ # These tests are mostly just to ensure that the ordinalize method exists
+ # It's results are tested comprehensively in the inflector test cases.
+ assert_equal '1st', 1.ordinalize
+ assert_equal '8th', 8.ordinalize
+ 1000000000000000000000000000000000000000000000000000000000000000000000.ordinalize
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/kernel_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/kernel_test.rb
new file mode 100644
index 000000000..92d904706
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/kernel_test.rb
@@ -0,0 +1,43 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class KernelTest < Test::Unit::TestCase
+ def test_silence_warnings
+ silence_warnings { assert_nil $VERBOSE }
+ assert_equal 1234, silence_warnings { 1234 }
+ end
+
+ def test_silence_warnings_verbose_invariant
+ old_verbose = $VERBOSE
+ silence_warnings { raise }
+ flunk
+ rescue
+ assert_equal old_verbose, $VERBOSE
+ end
+
+
+ def test_enable_warnings
+ enable_warnings { assert_equal true, $VERBOSE }
+ assert_equal 1234, enable_warnings { 1234 }
+ end
+
+ def test_enable_warnings_verbose_invariant
+ old_verbose = $VERBOSE
+ enable_warnings { raise }
+ flunk
+ rescue
+ assert_equal old_verbose, $VERBOSE
+ end
+
+
+ def test_silence_stderr
+ old_stderr_position = STDERR.tell
+ silence_stderr { STDERR.puts 'hello world' }
+ assert_equal old_stderr_position, STDERR.tell
+ rescue Errno::ESPIPE
+ # Skip if we can't STDERR.tell
+ end
+
+ def test_silence_stderr_with_return_value
+ assert_equal 1, silence_stderr { 1 }
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/load_error_tests.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/load_error_tests.rb
new file mode 100644
index 000000000..34c5cb4cd
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/load_error_tests.rb
@@ -0,0 +1,16 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class TestMissingSourceFile < Test::Unit::TestCase
+ def test_with_require
+ assert_raises(MissingSourceFile) { require 'no_this_file_don\'t_exist' }
+ end
+ def test_with_load
+ assert_raises(MissingSourceFile) { load 'nor_does_this_one' }
+ end
+ def test_path
+ begin load 'nor/this/one.rb'
+ rescue MissingSourceFile => e
+ assert_equal 'nor/this/one.rb', e.path
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/module/attr_accessor_with_default_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/module/attr_accessor_with_default_test.rb
new file mode 100644
index 000000000..71039c0ef
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/module/attr_accessor_with_default_test.rb
@@ -0,0 +1,30 @@
+require File.dirname(__FILE__) + '/../../abstract_unit'
+
+class AttrAccessorWithDefaultTest < Test::Unit::TestCase
+ def setup
+ @target = Class.new do
+ def helper
+ 'helper'
+ end
+ end
+ @instance = @target.new
+ end
+
+ def test_default_arg
+ @target.attr_accessor_with_default :foo, :bar
+ assert_equal(:bar, @instance.foo)
+ @instance.foo = nil
+ assert_nil(@instance.foo)
+ end
+
+ def test_default_proc
+ @target.attr_accessor_with_default(:foo) {helper.upcase}
+ assert_equal('HELPER', @instance.foo)
+ @instance.foo = nil
+ assert_nil(@instance.foo)
+ end
+
+ def test_invalid_args
+ assert_raise(RuntimeError) {@target.attr_accessor_with_default :foo}
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/module/attr_internal_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/module/attr_internal_test.rb
new file mode 100644
index 000000000..1bf831e49
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/module/attr_internal_test.rb
@@ -0,0 +1,52 @@
+require File.dirname(__FILE__) + '/../../abstract_unit'
+
+class AttrInternalTest < Test::Unit::TestCase
+ def setup
+ @target = Class.new
+ @instance = @target.new
+ end
+
+ def test_reader
+ assert_nothing_raised { @target.attr_internal_reader :foo }
+
+ assert !@instance.instance_variable_defined?('@_foo')
+ assert_raise(NoMethodError) { @instance.foo = 1 }
+
+ @instance.instance_variable_set('@_foo', 1)
+ assert_nothing_raised { assert_equal 1, @instance.foo }
+ end
+
+ def test_writer
+ assert_nothing_raised { @target.attr_internal_writer :foo }
+
+ assert !@instance.instance_variable_defined?('@_foo')
+ assert_nothing_raised { assert_equal 1, @instance.foo = 1 }
+
+ assert_equal 1, @instance.instance_variable_get('@_foo')
+ assert_raise(NoMethodError) { @instance.foo }
+ end
+
+ def test_accessor
+ assert_nothing_raised { @target.attr_internal :foo }
+
+ assert !@instance.instance_variable_defined?('@_foo')
+ assert_nothing_raised { assert_equal 1, @instance.foo = 1 }
+
+ assert_equal 1, @instance.instance_variable_get('@_foo')
+ assert_nothing_raised { assert_equal 1, @instance.foo }
+ end
+
+ def test_naming_format
+ assert_equal '@_%s', @target.attr_internal_naming_format
+ assert_nothing_raised { @target.attr_internal_naming_format = '@abc%sdef' }
+ @target.attr_internal :foo
+
+ assert !@instance.instance_variable_defined?('@_foo')
+ assert !@instance.instance_variable_defined?('@abcfoodef')
+ assert_nothing_raised { @instance.foo = 1 }
+ assert !@instance.instance_variable_defined?('@_foo')
+ assert @instance.instance_variable_defined?('@abcfoodef')
+ ensure
+ @target.attr_internal_naming_format = '@_%s'
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/module/attribute_accessor_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/module/attribute_accessor_test.rb
new file mode 100644
index 000000000..7296cc5f8
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/module/attribute_accessor_test.rb
@@ -0,0 +1,33 @@
+require File.dirname(__FILE__) + '/../../abstract_unit'
+
+class ModuleAttributeAccessorTest < Test::Unit::TestCase
+ def setup
+ m = @module = Module.new do
+ mattr_accessor :foo
+ mattr_accessor :bar, :instance_writer => false
+ end
+ @class = Class.new
+ @class.instance_eval { include m }
+ @object = @class.new
+ end
+
+ def test_should_use_mattr_default
+ assert_nil @module.foo
+ assert_nil @object.foo
+ end
+
+ def test_should_set_mattr_value
+ @module.foo = :test
+ assert_equal :test, @object.foo
+
+ @object.foo = :test2
+ assert_equal :test2, @module.foo
+ end
+
+ def test_should_not_create_instance_writer
+ assert @module.respond_to?(:foo)
+ assert @module.respond_to?(:foo=)
+ assert @object.respond_to?(:bar)
+ assert !@object.respond_to?(:bar=)
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/module/attribute_aliasing_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/module/attribute_aliasing_test.rb
new file mode 100644
index 000000000..bd2387951
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/module/attribute_aliasing_test.rb
@@ -0,0 +1,58 @@
+require File.dirname(__FILE__) + '/../../abstract_unit'
+
+module AttributeAliasing
+ class Content
+ attr_accessor :title, :Data
+
+ def initialize
+ @title, @Data = nil, nil
+ end
+
+ def title?
+ !title.nil?
+ end
+
+ def Data?
+ !self.Data.nil?
+ end
+ end
+
+ class Email < Content
+ alias_attribute :subject, :title
+ alias_attribute :body, :Data
+ end
+end
+
+class AttributeAliasingTest < Test::Unit::TestCase
+ def test_attribute_alias
+ e = AttributeAliasing::Email.new
+
+ assert !e.subject?
+
+ e.title = "Upgrade computer"
+ assert_equal "Upgrade computer", e.subject
+ assert e.subject?
+
+ e.subject = "We got a long way to go"
+ assert_equal "We got a long way to go", e.title
+ assert e.title?
+ end
+
+ def test_aliasing_to_uppercase_attributes
+ # Although it's very un-Ruby, some people's AR-mapped tables have
+ # upper-case attributes, and when people want to alias those names
+ # to more sensible ones, everything goes *foof*.
+ e = AttributeAliasing::Email.new
+
+ assert !e.body?
+ assert !e.Data?
+
+ e.body = "No, really, this is not a joke."
+ assert_equal "No, really, this is not a joke.", e.Data
+ assert e.Data?
+
+ e.Data = "Uppercased methods are teh suck"
+ assert_equal "Uppercased methods are teh suck", e.body
+ assert e.body?
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/module_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/module_test.rb
new file mode 100644
index 000000000..fd1f99b31
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/module_test.rb
@@ -0,0 +1,293 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+module One
+ Constant1 = "Hello World"
+ Constant2 = "What's up?"
+end
+
+class Ab
+ include One
+ Constant1 = "Hello World" # Will have different object id than One::Constant1
+ Constant3 = "Goodbye World"
+end
+
+module Xy
+ class Bc
+ include One
+ end
+end
+
+module Yz
+ module Zy
+ class Cd
+ include One
+ end
+ end
+end
+
+class De
+end
+
+Somewhere = Struct.new(:street, :city)
+
+Someone = Struct.new(:name, :place) do
+ delegate :street, :city, :to => :place
+ delegate :state, :to => :@place
+ delegate :upcase, :to => "place.city"
+end
+
+class Name
+ delegate :upcase, :to => :@full_name
+
+ def initialize(first, last)
+ @full_name = "#{first} #{last}"
+ end
+end
+
+$nowhere = <<-EOF
+class Name
+ delegate :nowhere
+end
+EOF
+
+$noplace = <<-EOF
+class Name
+ delegate :noplace, :tos => :hollywood
+end
+EOF
+
+class ModuleTest < Test::Unit::TestCase
+ def test_included_in_classes
+ assert One.included_in_classes.include?(Ab)
+ assert One.included_in_classes.include?(Xy::Bc)
+ assert One.included_in_classes.include?(Yz::Zy::Cd)
+ assert !One.included_in_classes.include?(De)
+ end
+
+ def test_delegation_to_methods
+ david = Someone.new("David", Somewhere.new("Paulina", "Chicago"))
+ assert_equal "Paulina", david.street
+ assert_equal "Chicago", david.city
+ end
+
+ def test_delegation_down_hierarchy
+ david = Someone.new("David", Somewhere.new("Paulina", "Chicago"))
+ assert_equal "CHICAGO", david.upcase
+ end
+
+ def test_delegation_to_instance_variable
+ david = Name.new("David", "Hansson")
+ assert_equal "DAVID HANSSON", david.upcase
+ end
+
+ def test_missing_delegation_target
+ assert_raises(ArgumentError) { eval($nowhere) }
+ assert_raises(ArgumentError) { eval($noplace) }
+ end
+
+ def test_parent
+ assert_equal Yz::Zy, Yz::Zy::Cd.parent
+ assert_equal Yz, Yz::Zy.parent
+ assert_equal Object, Yz.parent
+ end
+
+ def test_parents
+ assert_equal [Yz::Zy, Yz, Object], Yz::Zy::Cd.parents
+ assert_equal [Yz, Object], Yz::Zy.parents
+ end
+
+ def test_local_constants
+ assert_equal %w(Constant1 Constant3), Ab.local_constants.sort.map(&:to_s)
+ end
+
+ def test_as_load_path
+ assert_equal 'yz/zy', Yz::Zy.as_load_path
+ assert_equal 'yz', Yz.as_load_path
+ end
+end
+
+module BarMethodAliaser
+ def self.included(foo_class)
+ foo_class.class_eval do
+ include BarMethods
+ alias_method_chain :bar, :baz
+ end
+ end
+end
+
+module BarMethods
+ def bar_with_baz
+ bar_without_baz << '_with_baz'
+ end
+
+ def quux_with_baz!
+ quux_without_baz! << '_with_baz'
+ end
+
+ def quux_with_baz?
+ false
+ end
+
+ def quux_with_baz=(v)
+ send(:quux_without_baz=, v) << '_with_baz'
+ end
+
+ def duck_with_orange
+ duck_without_orange << '_with_orange'
+ end
+end
+
+class MethodAliasingTest < Test::Unit::TestCase
+ def setup
+ Object.const_set :FooClassWithBarMethod, Class.new { def bar() 'bar' end }
+ @instance = FooClassWithBarMethod.new
+ end
+
+ def teardown
+ Object.instance_eval { remove_const :FooClassWithBarMethod }
+ end
+
+ def test_alias_method_chain
+ assert @instance.respond_to?(:bar)
+ feature_aliases = [:bar_with_baz, :bar_without_baz]
+
+ feature_aliases.each do |method|
+ assert !@instance.respond_to?(method)
+ end
+
+ assert_equal 'bar', @instance.bar
+
+ FooClassWithBarMethod.class_eval { include BarMethodAliaser }
+
+ feature_aliases.each do |method|
+ assert @instance.respond_to?(method)
+ end
+
+ assert_equal 'bar_with_baz', @instance.bar
+ assert_equal 'bar', @instance.bar_without_baz
+ end
+
+ def test_alias_method_chain_with_punctuation_method
+ FooClassWithBarMethod.class_eval do
+ def quux!; 'quux' end
+ end
+
+ assert !@instance.respond_to?(:quux_with_baz!)
+ FooClassWithBarMethod.class_eval do
+ include BarMethodAliaser
+ alias_method_chain :quux!, :baz
+ end
+ assert @instance.respond_to?(:quux_with_baz!)
+
+ assert_equal 'quux_with_baz', @instance.quux!
+ assert_equal 'quux', @instance.quux_without_baz!
+ end
+
+ def test_alias_method_chain_with_same_names_between_predicates_and_bang_methods
+ FooClassWithBarMethod.class_eval do
+ def quux!; 'quux!' end
+ def quux?; true end
+ def quux=(v); 'quux=' end
+ end
+
+ assert !@instance.respond_to?(:quux_with_baz!)
+ assert !@instance.respond_to?(:quux_with_baz?)
+ assert !@instance.respond_to?(:quux_with_baz=)
+
+ FooClassWithBarMethod.class_eval { include BarMethodAliaser }
+ assert @instance.respond_to?(:quux_with_baz!)
+ assert @instance.respond_to?(:quux_with_baz?)
+ assert @instance.respond_to?(:quux_with_baz=)
+
+
+ FooClassWithBarMethod.alias_method_chain :quux!, :baz
+ assert_equal 'quux!_with_baz', @instance.quux!
+ assert_equal 'quux!', @instance.quux_without_baz!
+
+ FooClassWithBarMethod.alias_method_chain :quux?, :baz
+ assert_equal false, @instance.quux?
+ assert_equal true, @instance.quux_without_baz?
+
+ FooClassWithBarMethod.alias_method_chain :quux=, :baz
+ assert_equal 'quux=_with_baz', @instance.send(:quux=, 1234)
+ assert_equal 'quux=', @instance.send(:quux_without_baz=, 1234)
+ end
+
+ def test_alias_method_chain_with_feature_punctuation
+ FooClassWithBarMethod.class_eval do
+ def quux; 'quux' end
+ def quux?; 'quux?' end
+ include BarMethodAliaser
+ alias_method_chain :quux, :baz!
+ end
+
+ assert_nothing_raised do
+ assert_equal 'quux_with_baz', @instance.quux_with_baz!
+ end
+
+ assert_raise(NameError) do
+ FooClassWithBarMethod.alias_method_chain :quux?, :baz!
+ end
+ end
+
+ def test_alias_method_chain_yields_target_and_punctuation
+ args = nil
+
+ FooClassWithBarMethod.class_eval do
+ def quux?; end
+ include BarMethods
+
+ FooClassWithBarMethod.alias_method_chain :quux?, :baz do |target, punctuation|
+ args = [target, punctuation]
+ end
+ end
+
+ assert_not_nil args
+ assert_equal 'quux', args[0]
+ assert_equal '?', args[1]
+ end
+
+ def test_alias_method_chain_preserves_private_method_status
+ FooClassWithBarMethod.class_eval do
+ def duck; 'duck' end
+ include BarMethodAliaser
+ private :duck
+ alias_method_chain :duck, :orange
+ end
+
+ assert_raises NoMethodError do
+ @instance.duck
+ end
+
+ assert_equal 'duck_with_orange', @instance.instance_eval { duck }
+ assert FooClassWithBarMethod.private_method_defined?(:duck)
+ end
+
+ def test_alias_method_chain_preserves_protected_method_status
+ FooClassWithBarMethod.class_eval do
+ def duck; 'duck' end
+ include BarMethodAliaser
+ protected :duck
+ alias_method_chain :duck, :orange
+ end
+
+ assert_raises NoMethodError do
+ @instance.duck
+ end
+
+ assert_equal 'duck_with_orange', @instance.instance_eval { duck }
+ assert FooClassWithBarMethod.protected_method_defined?(:duck)
+ end
+
+ def test_alias_method_chain_preserves_public_method_status
+ FooClassWithBarMethod.class_eval do
+ def duck; 'duck' end
+ include BarMethodAliaser
+ public :duck
+ alias_method_chain :duck, :orange
+ end
+
+ assert_equal 'duck_with_orange', @instance.duck
+ assert FooClassWithBarMethod.public_method_defined?(:duck)
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/name_error_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/name_error_test.rb
new file mode 100644
index 000000000..d03887530
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/name_error_test.rb
@@ -0,0 +1,24 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class NameErrorTest < Test::Unit::TestCase
+ def test_name_error_should_set_missing_name
+ begin
+ SomeNameThatNobodyWillUse____Really ? 1 : 0
+ flunk "?!?!"
+ rescue NameError => exc
+ assert_equal "NameErrorTest::SomeNameThatNobodyWillUse____Really", exc.missing_name
+ assert exc.missing_name?(:SomeNameThatNobodyWillUse____Really)
+ assert exc.missing_name?("NameErrorTest::SomeNameThatNobodyWillUse____Really")
+ end
+ end
+
+ def test_missing_method_should_ignore_missing_name
+ begin
+ some_method_that_does_not_exist
+ flunk "?!?!"
+ rescue NameError => exc
+ assert_equal nil, exc.missing_name
+ assert ! exc.missing_name?(:Foo)
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/numeric_ext_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/numeric_ext_test.rb
new file mode 100644
index 000000000..a773339b2
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/numeric_ext_test.rb
@@ -0,0 +1,147 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class NumericExtTimeAndDateTimeTest < Test::Unit::TestCase
+ def setup
+ @now = Time.now
+ @dtnow = DateTime.now
+ @seconds = {
+ 1.minute => 60,
+ 10.minutes => 600,
+ 1.hour + 15.minutes => 4500,
+ 2.days + 4.hours + 30.minutes => 189000,
+ 5.years + 1.month + 1.fortnight => 161589600
+ }
+ end
+
+ def test_units
+ @seconds.each do |actual, expected|
+ assert_equal expected, actual
+ end
+ end
+
+ def test_intervals
+ @seconds.values.each do |seconds|
+ assert_equal seconds.since(@now), @now + seconds
+ assert_equal seconds.until(@now), @now - seconds
+ end
+ end
+
+ # Test intervals based from Time.now
+ def test_now
+ @seconds.values.each do |seconds|
+ now = Time.now
+ assert seconds.ago >= now - seconds
+ now = Time.now
+ assert seconds.from_now >= now + seconds
+ end
+ end
+
+ def test_irregular_durations
+ assert_equal @now.advance(:days => 3000), 3000.days.since(@now)
+ assert_equal @now.advance(:months => 1), 1.month.since(@now)
+ assert_equal @now.advance(:months => -1), 1.month.until(@now)
+ assert_equal @now.advance(:years => 20), 20.years.since(@now)
+ assert_equal @dtnow.advance(:days => 3000), 3000.days.since(@dtnow)
+ assert_equal @dtnow.advance(:months => 1), 1.month.since(@dtnow)
+ assert_equal @dtnow.advance(:months => -1), 1.month.until(@dtnow)
+ assert_equal @dtnow.advance(:years => 20), 20.years.since(@dtnow)
+ end
+
+ def test_duration_addition
+ assert_equal @now.advance(:days => 1).advance(:months => 1), (1.day + 1.month).since(@now)
+ assert_equal @now.advance(:days => 7), (1.week + 5.seconds - 5.seconds).since(@now)
+ assert_equal @now.advance(:years => 2), (4.years - 2.years).since(@now)
+ assert_equal @dtnow.advance(:days => 1).advance(:months => 1), (1.day + 1.month).since(@dtnow)
+ assert_equal @dtnow.advance(:days => 7), (1.week + 5.seconds - 5.seconds).since(@dtnow)
+ assert_equal @dtnow.advance(:years => 2), (4.years - 2.years).since(@dtnow)
+ end
+
+ def test_time_plus_duration
+ assert_equal @now + 8, @now + 8.seconds
+ assert_equal @now + 22.9, @now + 22.9.seconds
+ assert_equal @now.advance(:days => 15), @now + 15.days
+ assert_equal @now.advance(:months => 1), @now + 1.month
+ assert_equal @dtnow.since(8), @dtnow + 8.seconds
+ assert_equal @dtnow.since(22.9), @dtnow + 22.9.seconds
+ assert_equal @dtnow.advance(:days => 15), @dtnow + 15.days
+ assert_equal @dtnow.advance(:months => 1), @dtnow + 1.month
+ end
+
+ def test_chaining_duration_operations
+ assert_equal @now.advance(:days => 2).advance(:months => -3), @now + 2.days - 3.months
+ assert_equal @now.advance(:days => 1).advance(:months => 2), @now + 1.day + 2.months
+ assert_equal @dtnow.advance(:days => 2).advance(:months => -3), @dtnow + 2.days - 3.months
+ assert_equal @dtnow.advance(:days => 1).advance(:months => 2), @dtnow + 1.day + 2.months
+ end
+
+ def test_duration_after_convertion_is_no_longer_accurate
+ assert_equal 30.days.to_i.since(@now), 1.month.to_i.since(@now)
+ assert_equal 365.25.days.to_f.since(@now), 1.year.to_f.since(@now)
+ assert_equal 30.days.to_i.since(@dtnow), 1.month.to_i.since(@dtnow)
+ assert_equal 365.25.days.to_f.since(@dtnow), 1.year.to_f.since(@dtnow)
+ end
+
+ def test_add_one_year_to_leap_day
+ assert_equal Time.utc(2005,2,28,15,15,10), Time.utc(2004,2,29,15,15,10) + 1.year
+ assert_equal DateTime.civil(2005,2,28,15,15,10), DateTime.civil(2004,2,29,15,15,10) + 1.year
+ end
+end
+
+class NumericExtDateTest < Test::Unit::TestCase
+ def setup
+ @today = Date.today
+ end
+
+ def test_date_plus_duration
+ assert_equal @today + 1, @today + 1.day
+ assert_equal @today >> 1, @today + 1.month
+ assert_equal @today.to_time.since(1), @today + 1.second
+ assert_equal @today.to_time.since(60), @today + 1.minute
+ assert_equal @today.to_time.since(60*60), @today + 1.hour
+ end
+
+ def test_chaining_duration_operations
+ assert_equal @today.advance(:days => 2).advance(:months => -3), @today + 2.days - 3.months
+ assert_equal @today.advance(:days => 1).advance(:months => 2), @today + 1.day + 2.months
+ end
+
+ def test_add_one_year_to_leap_day
+ assert_equal Date.new(2005,2,28), Date.new(2004,2,29) + 1.year
+ end
+end
+
+class NumericExtSizeTest < Test::Unit::TestCase
+ def test_unit_in_terms_of_another
+ relationships = {
+ 1024.bytes => 1.kilobyte,
+ 1024.kilobytes => 1.megabyte,
+ 3584.0.kilobytes => 3.5.megabytes,
+ 3584.0.megabytes => 3.5.gigabytes,
+ 1.kilobyte ** 4 => 1.terabyte,
+ 1024.kilobytes + 2.megabytes => 3.megabytes,
+ 2.gigabytes / 4 => 512.megabytes,
+ 256.megabytes * 20 + 5.gigabytes => 10.gigabytes,
+ 1.kilobyte ** 5 => 1.petabyte,
+ 1.kilobyte ** 6 => 1.exabyte
+ }
+
+ relationships.each do |left, right|
+ assert_equal right, left
+ end
+ end
+
+ def test_units_as_bytes_independently
+ assert_equal 3145728, 3.megabytes
+ assert_equal 3145728, 3.megabyte
+ assert_equal 3072, 3.kilobytes
+ assert_equal 3072, 3.kilobyte
+ assert_equal 3221225472, 3.gigabytes
+ assert_equal 3221225472, 3.gigabyte
+ assert_equal 3298534883328, 3.terabytes
+ assert_equal 3298534883328, 3.terabyte
+ assert_equal 3377699720527872, 3.petabytes
+ assert_equal 3377699720527872, 3.petabyte
+ assert_equal 3458764513820540928, 3.exabytes
+ assert_equal 3458764513820540928, 3.exabyte
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/object_and_class_ext_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/object_and_class_ext_test.rb
new file mode 100644
index 000000000..f885d94be
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/object_and_class_ext_test.rb
@@ -0,0 +1,242 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class ClassA; end
+class ClassB < ClassA; end
+class ClassC < ClassB; end
+class ClassD < ClassA; end
+
+class ClassI; end
+class ClassJ < ClassI; end
+
+class ClassK
+end
+module Nested
+ class << self
+ def on_const_missing(&callback)
+ @on_const_missing = callback
+ end
+ private
+ def const_missing(mod_id)
+ @on_const_missing[mod_id] if @on_const_missing
+ super
+ end
+ end
+ class ClassL < ClassK
+ end
+end
+
+module Bar
+ def bar; end
+end
+
+module Baz
+ def baz; end
+end
+
+class Foo
+ include Bar
+end
+
+class ClassExtTest < Test::Unit::TestCase
+ def test_methods
+ assert defined?(ClassB)
+ assert defined?(ClassC)
+ assert defined?(ClassD)
+
+ ClassA.remove_subclasses
+
+ assert !defined?(ClassB)
+ assert !defined?(ClassC)
+ assert !defined?(ClassD)
+ end
+
+ def test_subclasses_of
+ cj = ClassJ
+ assert_equal [ClassJ], Object.subclasses_of(ClassI)
+ ClassI.remove_subclasses
+ assert_equal [], Object.subclasses_of(ClassI)
+ ensure
+ Object.const_set :ClassJ, cj
+ end
+
+ def test_subclasses_of_should_find_nested_classes
+ assert Object.subclasses_of(ClassK).include?(Nested::ClassL)
+ end
+
+ def test_subclasses_of_should_not_return_removed_classes
+ # First create the removed class
+ old_class = Nested.class_eval { remove_const :ClassL }
+ new_class = Class.new(ClassK)
+ Nested.const_set :ClassL, new_class
+ assert_equal "Nested::ClassL", new_class.name # Sanity check
+
+ subclasses = Object.subclasses_of(ClassK)
+ assert subclasses.include?(new_class)
+ assert ! subclasses.include?(old_class)
+ ensure
+ Nested.const_set :ClassL, old_class unless defined?(Nested::ClassL)
+ end
+
+ def test_subclasses_of_should_not_trigger_const_missing
+ const_missing = false
+ Nested.on_const_missing { const_missing = true }
+
+ subclasses = Object.subclasses_of ClassK
+ assert !const_missing
+ assert_equal [ Nested::ClassL ], subclasses
+
+ removed = Nested.class_eval { remove_const :ClassL } # keep it in memory
+ subclasses = Object.subclasses_of ClassK
+ assert !const_missing
+ assert subclasses.empty?
+ ensure
+ Nested.const_set :ClassL, removed unless defined?(Nested::ClassL)
+ end
+
+ def test_subclasses_of_with_multiple_roots
+ classes = Object.subclasses_of(ClassI, ClassK)
+ assert_equal %w(ClassJ Nested::ClassL), classes.collect(&:to_s).sort
+ end
+
+ def test_subclasses_of_doesnt_find_anonymous_classes
+ assert_equal [], Object.subclasses_of(Foo)
+ bar = Class.new(Foo)
+ assert_nothing_raised do
+ assert_equal [bar], Object.subclasses_of(Foo)
+ end
+ end
+end
+
+class ObjectTests < Test::Unit::TestCase
+ def test_send_bang_aliases_send_before_19
+ assert_respond_to 'a', :send!
+ assert_equal 1, 'a'.send!(:size)
+ end
+
+ def test_suppress_re_raises
+ assert_raises(LoadError) { suppress(ArgumentError) {raise LoadError} }
+ end
+ def test_suppress_supresses
+ suppress(ArgumentError) { raise ArgumentError }
+ suppress(LoadError) { raise LoadError }
+ suppress(LoadError, ArgumentError) { raise LoadError }
+ suppress(LoadError, ArgumentError) { raise ArgumentError }
+ end
+
+ def test_extended_by
+ foo = Foo.new
+ assert foo.extended_by.include?(Bar)
+ foo.extend(Baz)
+ assert(([Bar, Baz] - foo.extended_by).empty?, "Expected Bar, Baz in #{foo.extended_by.inspect}")
+ end
+
+ def test_extend_with_included_modules_from
+ foo, object = Foo.new, Object.new
+ assert !object.respond_to?(:bar)
+ assert !object.respond_to?(:baz)
+
+ object.extend_with_included_modules_from(foo)
+ assert object.respond_to?(:bar)
+ assert !object.respond_to?(:baz)
+
+ foo.extend(Baz)
+ object.extend_with_included_modules_from(foo)
+ assert object.respond_to?(:bar)
+ assert object.respond_to?(:baz)
+ end
+
+ class DuckTime
+ def acts_like_time?
+ true
+ end
+ end
+
+ def test_duck_typing
+ object = Object.new
+ time = Time.now
+ date = Date.today
+ dt = DateTime.new
+ duck = DuckTime.new
+
+ assert !object.acts_like?(:time)
+ assert !object.acts_like?(:date)
+
+ assert time.acts_like?(:time)
+ assert !time.acts_like?(:date)
+
+ assert !date.acts_like?(:time)
+ assert date.acts_like?(:date)
+
+ assert dt.acts_like?(:time)
+ assert dt.acts_like?(:date)
+
+ assert duck.acts_like?(:time)
+ assert !duck.acts_like?(:date)
+ end
+end
+
+class ObjectInstanceVariableTest < Test::Unit::TestCase
+ def setup
+ @source, @dest = Object.new, Object.new
+ @source.instance_variable_set(:@bar, 'bar')
+ @source.instance_variable_set(:@baz, 'baz')
+ end
+
+ def test_instance_variable_defined
+ assert @source.instance_variable_defined?('@bar')
+ assert @source.instance_variable_defined?(:@bar)
+ assert !@source.instance_variable_defined?(:@foo)
+ assert !@source.instance_variable_defined?('@foo')
+ end
+
+ def test_copy_instance_variables_from_without_explicit_excludes
+ assert_equal [], @dest.instance_variables
+ @dest.copy_instance_variables_from(@source)
+
+ assert_equal %w(@bar @baz), @dest.instance_variables.sort.map(&:to_s)
+ %w(@bar @baz).each do |name|
+ assert_equal @source.instance_variable_get(name).object_id,
+ @dest.instance_variable_get(name).object_id
+ end
+ end
+
+ def test_copy_instance_variables_from_with_explicit_excludes
+ @dest.copy_instance_variables_from(@source, ['@baz'])
+ assert !@dest.instance_variable_defined?('@baz')
+ assert_equal 'bar', @dest.instance_variable_get('@bar')
+ end
+
+ def test_copy_instance_variables_automatically_excludes_protected_instance_variables
+ @source.instance_variable_set(:@quux, 'quux')
+ class << @source
+ def protected_instance_variables
+ ['@bar', :@quux]
+ end
+ end
+
+ @dest.copy_instance_variables_from(@source)
+ assert !@dest.instance_variable_defined?('@bar')
+ assert !@dest.instance_variable_defined?('@quux')
+ assert_equal 'baz', @dest.instance_variable_get('@baz')
+ end
+
+ def test_instance_values
+ object = Object.new
+ object.instance_variable_set :@a, 1
+ object.instance_variable_set :@b, 2
+ assert_equal({'a' => 1, 'b' => 2}, object.instance_values)
+ end
+
+ def test_instance_exec_passes_arguments_to_block
+ assert_equal %w(hello goodbye), 'hello'.instance_exec('goodbye') { |v| [self, v] }
+ end
+
+ def test_instance_exec_with_frozen_obj
+ assert_equal %w(olleh goodbye), 'hello'.freeze.instance_exec('goodbye') { |v| [reverse, v] }
+ end
+
+ def test_instance_exec_nested
+ assert_equal %w(goodbye olleh bar), 'hello'.instance_exec('goodbye') { |arg|
+ [arg] + instance_exec('bar') { |v| [reverse, v] } }
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/pathname_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/pathname_test.rb
new file mode 100644
index 000000000..2933e2d61
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/pathname_test.rb
@@ -0,0 +1,9 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class TestPathname < Test::Unit::TestCase
+ def test_clean_within
+ assert_equal "Hi", Pathname.clean_within("Hi")
+ assert_equal "Hi", Pathname.clean_within("Hi/a/b/../..")
+ assert_equal "Hello\nWorld", Pathname.clean_within("Hello/a/b/../..\na/b/../../World/c/..")
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/proc_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/proc_test.rb
new file mode 100644
index 000000000..f63cd82d2
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/proc_test.rb
@@ -0,0 +1,11 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class ProcTests < Test::Unit::TestCase
+ def test_bind_returns_method_with_changed_self
+ block = Proc.new { self }
+ assert_equal self, block.call
+ bound_block = block.bind("hello")
+ assert_not_equal block, bound_block
+ assert_equal "hello", bound_block.call
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/range_ext_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/range_ext_test.rb
new file mode 100644
index 000000000..acb6baf43
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/range_ext_test.rb
@@ -0,0 +1,63 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class RangeTest < Test::Unit::TestCase
+ def test_to_s_from_dates
+ date_range = Date.new(2005, 12, 10)..Date.new(2005, 12, 12)
+ assert_equal "BETWEEN '2005-12-10' AND '2005-12-12'", date_range.to_s(:db)
+ end
+
+ def test_to_s_from_times
+ date_range = Time.utc(2005, 12, 10, 15, 30)..Time.utc(2005, 12, 10, 17, 30)
+ assert_equal "BETWEEN '2005-12-10 15:30:00' AND '2005-12-10 17:30:00'", date_range.to_s(:db)
+ end
+
+ def test_overlaps_last_inclusive
+ assert((1..5).overlaps?(5..10))
+ end
+
+ def test_overlaps_last_exclusive
+ assert !(1...5).overlaps?(5..10)
+ end
+
+ def test_overlaps_first_inclusive
+ assert((5..10).overlaps?(1..5))
+ end
+
+ def test_overlaps_first_exclusive
+ assert !(5..10).overlaps?(1...5)
+ end
+
+ def test_should_include_identical_inclusive
+ assert((1..10).include?(1..10))
+ end
+
+ def test_should_include_identical_exclusive
+ assert((1...10).include?(1...10))
+ end
+
+ def test_should_include_other_with_exlusive_end
+ assert((1..10).include?(1...10))
+ end
+
+ def test_exclusive_end_should_not_include_identical_with_inclusive_end
+ assert !(1...10).include?(1..10)
+ end
+
+ def test_should_not_include_overlapping_first
+ assert !(2..8).include?(1..3)
+ end
+
+ def test_should_not_include_overlapping_last
+ assert !(2..8).include?(5..9)
+ end
+
+ def test_blockless_step
+ assert_equal [1,3,5,7,9], (1..10).step(2)
+ end
+
+ def test_original_step
+ array = []
+ (1..10).step(2) {|i| array << i }
+ assert_equal [1,3,5,7,9], array
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/string_ext_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/string_ext_test.rb
new file mode 100644
index 000000000..427e7dfc5
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/string_ext_test.rb
@@ -0,0 +1,180 @@
+require 'date'
+require File.dirname(__FILE__) + '/../abstract_unit'
+require 'inflector_test_cases'
+
+class StringInflectionsTest < Test::Unit::TestCase
+ include InflectorTestCases
+
+ def test_pluralize
+ SingularToPlural.each do |singular, plural|
+ assert_equal(plural, singular.pluralize)
+ end
+
+ assert_equal("plurals", "plurals".pluralize)
+ end
+
+ def test_singularize
+ SingularToPlural.each do |singular, plural|
+ assert_equal(singular, plural.singularize)
+ end
+ end
+
+ def test_titleize
+ MixtureToTitleCase.each do |before, titleized|
+ assert_equal(titleized, before.titleize)
+ end
+ end
+
+ def test_camelize
+ CamelToUnderscore.each do |camel, underscore|
+ assert_equal(camel, underscore.camelize)
+ end
+ end
+
+ def test_underscore
+ CamelToUnderscore.each do |camel, underscore|
+ assert_equal(underscore, camel.underscore)
+ end
+
+ assert_equal "html_tidy", "HTMLTidy".underscore
+ assert_equal "html_tidy_generator", "HTMLTidyGenerator".underscore
+ end
+
+ def test_underscore_to_lower_camel
+ UnderscoreToLowerCamel.each do |underscored, lower_camel|
+ assert_equal(lower_camel, underscored.camelize(:lower))
+ end
+ end
+
+ def test_demodulize
+ assert_equal "Account", "MyApplication::Billing::Account".demodulize
+ end
+
+ def test_foreign_key
+ ClassNameToForeignKeyWithUnderscore.each do |klass, foreign_key|
+ assert_equal(foreign_key, klass.foreign_key)
+ end
+
+ ClassNameToForeignKeyWithoutUnderscore.each do |klass, foreign_key|
+ assert_equal(foreign_key, klass.foreign_key(false))
+ end
+ end
+
+ def test_tableize
+ ClassNameToTableName.each do |class_name, table_name|
+ assert_equal(table_name, class_name.tableize)
+ end
+ end
+
+ def test_classify
+ ClassNameToTableName.each do |class_name, table_name|
+ assert_equal(class_name, table_name.classify)
+ end
+ end
+
+ def test_humanize
+ UnderscoreToHuman.each do |underscore, human|
+ assert_equal(human, underscore.humanize)
+ end
+ end
+
+ def test_ord
+ assert_equal 97, 'a'.ord
+ assert_equal 97, 'abc'.ord
+ end
+
+ def test_string_to_time
+ assert_equal Time.utc(2005, 2, 27, 23, 50), "2005-02-27 23:50".to_time
+ assert_equal Time.local(2005, 2, 27, 23, 50), "2005-02-27 23:50".to_time(:local)
+ assert_equal DateTime.civil(2039, 2, 27, 23, 50), "2039-02-27 23:50".to_time
+ assert_equal Time.local_time(2039, 2, 27, 23, 50), "2039-02-27 23:50".to_time(:local)
+ end
+
+ def test_string_to_datetime
+ assert_equal DateTime.civil(2039, 2, 27, 23, 50), "2039-02-27 23:50".to_datetime
+ assert_equal 0, "2039-02-27 23:50".to_datetime.offset # use UTC offset
+ assert_equal ::Date::ITALY, "2039-02-27 23:50".to_datetime.start # use Ruby's default start value
+ end
+
+ def test_string_to_date
+ assert_equal Date.new(2005, 2, 27), "2005-02-27".to_date
+ end
+
+ def test_access
+ s = "hello"
+ assert_equal "h", s.at(0)
+
+ assert_equal "llo", s.from(2)
+ assert_equal "hel", s.to(2)
+
+ assert_equal "h", s.first
+ assert_equal "he", s.first(2)
+
+ assert_equal "o", s.last
+ assert_equal "llo", s.last(3)
+ assert_equal "hello", s.last(10)
+
+ assert_equal 'x', 'x'.first
+ assert_equal 'x', 'x'.first(4)
+
+ assert_equal 'x', 'x'.last
+ assert_equal 'x', 'x'.last(4)
+ end
+
+ def test_access_returns_a_real_string
+ hash = {}
+ hash["h"] = true
+ hash["hello123".at(0)] = true
+ assert_equal %w(h), hash.keys
+
+ hash = {}
+ hash["llo"] = true
+ hash["hello".from(2)] = true
+ assert_equal %w(llo), hash.keys
+
+ hash = {}
+ hash["hel"] = true
+ hash["hello".to(2)] = true
+ assert_equal %w(hel), hash.keys
+
+ hash = {}
+ hash["hello"] = true
+ hash["123hello".last(5)] = true
+ assert_equal %w(hello), hash.keys
+
+ hash = {}
+ hash["hello"] = true
+ hash["hello123".first(5)] = true
+ assert_equal %w(hello), hash.keys
+ end
+
+ def test_starts_ends_with_alias
+ s = "hello"
+ assert s.starts_with?('h')
+ assert s.starts_with?('hel')
+ assert !s.starts_with?('el')
+
+ assert s.start_with?('h')
+ assert s.start_with?('hel')
+ assert !s.start_with?('el')
+
+ assert s.ends_with?('o')
+ assert s.ends_with?('lo')
+ assert !s.ends_with?('el')
+
+ assert s.end_with?('o')
+ assert s.end_with?('lo')
+ assert !s.end_with?('el')
+ end
+
+ # FIXME: Ruby 1.9
+ def test_each_char_with_utf8_string_when_kcode_is_utf8
+ old_kcode, $KCODE = $KCODE, 'UTF8'
+ '€2.99'.each_char do |char|
+ assert_not_equal 1, char.length
+ break
+ end
+ ensure
+ $KCODE = old_kcode
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/symbol_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/symbol_test.rb
new file mode 100644
index 000000000..943133496
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/symbol_test.rb
@@ -0,0 +1,9 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class SymbolTests < Test::Unit::TestCase
+ def test_to_proc
+ assert_equal %w(one two three), [:one, :two, :three].map(&:to_s)
+ assert_equal(%w(one two three),
+ {1 => "one", 2 => "two", 3 => "three"}.sort_by(&:first).map(&:last))
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/core_ext/time_ext_test.rb b/vendor/rails-2.0.2/activesupport/test/core_ext/time_ext_test.rb
new file mode 100644
index 000000000..c0bd12d2a
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/core_ext/time_ext_test.rb
@@ -0,0 +1,420 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class TimeExtCalculationsTest < Test::Unit::TestCase
+ def test_seconds_since_midnight
+ assert_equal 1,Time.local(2005,1,1,0,0,1).seconds_since_midnight
+ assert_equal 60,Time.local(2005,1,1,0,1,0).seconds_since_midnight
+ assert_equal 3660,Time.local(2005,1,1,1,1,0).seconds_since_midnight
+ assert_equal 86399,Time.local(2005,1,1,23,59,59).seconds_since_midnight
+ assert_equal 60.00001,Time.local(2005,1,1,0,1,0,10).seconds_since_midnight
+ end
+
+ def test_seconds_since_midnight_at_daylight_savings_time_start
+ with_timezone 'US/Eastern' do
+ # dt: US: 2005 April 3rd 2:00am ST => April 3rd 3:00am DT
+ assert_equal 2*3600-1, Time.local(2005,4,3,1,59,59).seconds_since_midnight, 'just before DST start'
+ assert_equal 2*3600+1, Time.local(2005,4,3,3, 0, 1).seconds_since_midnight, 'just after DST start'
+ end
+
+ with_timezone 'NZ' do
+ # dt: New Zealand: 2006 October 1st 2:00am ST => October 1st 3:00am DT
+ assert_equal 2*3600-1, Time.local(2006,10,1,1,59,59).seconds_since_midnight, 'just before DST start'
+ assert_equal 2*3600+1, Time.local(2006,10,1,3, 0, 1).seconds_since_midnight, 'just after DST start'
+ end
+ end
+
+ def test_seconds_since_midnight_at_daylight_savings_time_end
+ with_timezone 'US/Eastern' do
+ # st: US: 2005 October 30th 2:00am DT => October 30th 1:00am ST
+ # avoid setting a time between 1:00 and 2:00 since that requires specifying whether DST is active
+ assert_equal 1*3600-1, Time.local(2005,10,30,0,59,59).seconds_since_midnight, 'just before DST end'
+ assert_equal 3*3600+1, Time.local(2005,10,30,2, 0, 1).seconds_since_midnight, 'just after DST end'
+
+ # now set a time between 1:00 and 2:00 by specifying whether DST is active
+ # uses: Time.local( sec, min, hour, day, month, year, wday, yday, isdst, tz )
+ assert_equal 1*3600+30*60, Time.local(0,30,1,30,10,2005,0,0,true,ENV['TZ']).seconds_since_midnight, 'before DST end'
+ assert_equal 2*3600+30*60, Time.local(0,30,1,30,10,2005,0,0,false,ENV['TZ']).seconds_since_midnight, 'after DST end'
+ end
+
+ with_timezone 'NZ' do
+ # st: New Zealand: 2006 March 19th 3:00am DT => March 19th 2:00am ST
+ # avoid setting a time between 2:00 and 3:00 since that requires specifying whether DST is active
+ assert_equal 2*3600-1, Time.local(2006,3,19,1,59,59).seconds_since_midnight, 'just before DST end'
+ assert_equal 4*3600+1, Time.local(2006,3,19,3, 0, 1).seconds_since_midnight, 'just after DST end'
+
+ # now set a time between 2:00 and 3:00 by specifying whether DST is active
+ # uses: Time.local( sec, min, hour, day, month, year, wday, yday, isdst, tz )
+ assert_equal 2*3600+30*60, Time.local(0,30,2,19,3,2006,0,0,true, ENV['TZ']).seconds_since_midnight, 'before DST end'
+ assert_equal 3*3600+30*60, Time.local(0,30,2,19,3,2006,0,0,false,ENV['TZ']).seconds_since_midnight, 'after DST end'
+ end
+ end
+
+ def test_beginning_of_week
+ assert_equal Time.local(2005,1,31), Time.local(2005,2,4,10,10,10).beginning_of_week
+ assert_equal Time.local(2005,11,28), Time.local(2005,11,28,0,0,0).beginning_of_week #monday
+ assert_equal Time.local(2005,11,28), Time.local(2005,11,29,0,0,0).beginning_of_week #tuesday
+ assert_equal Time.local(2005,11,28), Time.local(2005,11,30,0,0,0).beginning_of_week #wednesday
+ assert_equal Time.local(2005,11,28), Time.local(2005,12,01,0,0,0).beginning_of_week #thursday
+ assert_equal Time.local(2005,11,28), Time.local(2005,12,02,0,0,0).beginning_of_week #friday
+ assert_equal Time.local(2005,11,28), Time.local(2005,12,03,0,0,0).beginning_of_week #saturday
+ assert_equal Time.local(2005,11,28), Time.local(2005,12,04,0,0,0).beginning_of_week #sunday
+ end
+
+ def test_beginning_of_day
+ assert_equal Time.local(2005,2,4,0,0,0), Time.local(2005,2,4,10,10,10).beginning_of_day
+ with_timezone 'US/Eastern' do
+ assert_equal Time.local(2006,4,2,0,0,0), Time.local(2006,4,2,10,10,10).beginning_of_day, 'start DST'
+ assert_equal Time.local(2006,10,29,0,0,0), Time.local(2006,10,29,10,10,10).beginning_of_day, 'ends DST'
+ end
+ with_timezone 'NZ' do
+ assert_equal Time.local(2006,3,19,0,0,0), Time.local(2006,3,19,10,10,10).beginning_of_day, 'ends DST'
+ assert_equal Time.local(2006,10,1,0,0,0), Time.local(2006,10,1,10,10,10).beginning_of_day, 'start DST'
+ end
+ end
+
+ def test_beginning_of_month
+ assert_equal Time.local(2005,2,1,0,0,0), Time.local(2005,2,22,10,10,10).beginning_of_month
+ end
+
+ def test_beginning_of_quarter
+ assert_equal Time.local(2005,1,1,0,0,0), Time.local(2005,2,15,10,10,10).beginning_of_quarter
+ assert_equal Time.local(2005,1,1,0,0,0), Time.local(2005,1,1,0,0,0).beginning_of_quarter
+ assert_equal Time.local(2005,10,1,0,0,0), Time.local(2005,12,31,10,10,10).beginning_of_quarter
+ assert_equal Time.local(2005,4,1,0,0,0), Time.local(2005,6,30,23,59,59).beginning_of_quarter
+ end
+
+ def test_end_of_month
+ assert_equal Time.local(2005,3,31,23,59,59), Time.local(2005,3,20,10,10,10).end_of_month
+ assert_equal Time.local(2005,2,28,23,59,59), Time.local(2005,2,20,10,10,10).end_of_month
+ assert_equal Time.local(2005,4,30,23,59,59), Time.local(2005,4,20,10,10,10).end_of_month
+ end
+
+ def test_beginning_of_year
+ assert_equal Time.local(2005,1,1,0,0,0), Time.local(2005,2,22,10,10,10).beginning_of_year
+ end
+
+ def test_months_ago
+ assert_equal Time.local(2005,5,5,10), Time.local(2005,6,5,10,0,0).months_ago(1)
+ assert_equal Time.local(2004,11,5,10), Time.local(2005,6,5,10,0,0).months_ago(7)
+ assert_equal Time.local(2004,12,5,10), Time.local(2005,6,5,10,0,0).months_ago(6)
+ assert_equal Time.local(2004,6,5,10), Time.local(2005,6,5,10,0,0).months_ago(12)
+ assert_equal Time.local(2003,6,5,10), Time.local(2005,6,5,10,0,0).months_ago(24)
+ end
+
+ def test_months_since
+ assert_equal Time.local(2005,7,5,10), Time.local(2005,6,5,10,0,0).months_since(1)
+ assert_equal Time.local(2006,1,5,10), Time.local(2005,12,5,10,0,0).months_since(1)
+ assert_equal Time.local(2005,12,5,10), Time.local(2005,6,5,10,0,0).months_since(6)
+ assert_equal Time.local(2006,6,5,10), Time.local(2005,12,5,10,0,0).months_since(6)
+ assert_equal Time.local(2006,1,5,10), Time.local(2005,6,5,10,0,0).months_since(7)
+ assert_equal Time.local(2006,6,5,10), Time.local(2005,6,5,10,0,0).months_since(12)
+ assert_equal Time.local(2007,6,5,10), Time.local(2005,6,5,10,0,0).months_since(24)
+ assert_equal Time.local(2005,4,30,10), Time.local(2005,3,31,10,0,0).months_since(1)
+ assert_equal Time.local(2005,2,28,10), Time.local(2005,1,29,10,0,0).months_since(1)
+ assert_equal Time.local(2005,2,28,10), Time.local(2005,1,30,10,0,0).months_since(1)
+ assert_equal Time.local(2005,2,28,10), Time.local(2005,1,31,10,0,0).months_since(1)
+ end
+
+ def test_years_ago
+ assert_equal Time.local(2004,6,5,10), Time.local(2005,6,5,10,0,0).years_ago(1)
+ assert_equal Time.local(1998,6,5,10), Time.local(2005,6,5,10,0,0).years_ago(7)
+ assert_equal Time.local(2003,2,28,10), Time.local(2004,2,29,10,0,0).years_ago(1) # 1 year ago from leap day
+ end
+
+ def test_years_since
+ assert_equal Time.local(2006,6,5,10), Time.local(2005,6,5,10,0,0).years_since(1)
+ assert_equal Time.local(2012,6,5,10), Time.local(2005,6,5,10,0,0).years_since(7)
+ assert_equal Time.local(2005,2,28,10), Time.local(2004,2,29,10,0,0).years_since(1) # 1 year since leap day
+ # Failure because of size limitations of numeric?
+ # assert_equal Time.local(2182,6,5,10), Time.local(2005,6,5,10,0,0).years_since(177)
+ end
+
+ def test_last_year
+ assert_equal Time.local(2004,6,5,10), Time.local(2005,6,5,10,0,0).last_year
+ end
+
+ def test_next_year
+ assert_equal Time.local(2006,6,5,10), Time.local(2005,6,5,10,0,0).next_year
+ end
+
+ def test_ago
+ assert_equal Time.local(2005,2,22,10,10,9), Time.local(2005,2,22,10,10,10).ago(1)
+ assert_equal Time.local(2005,2,22,9,10,10), Time.local(2005,2,22,10,10,10).ago(3600)
+ assert_equal Time.local(2005,2,20,10,10,10), Time.local(2005,2,22,10,10,10).ago(86400*2)
+ assert_equal Time.local(2005,2,20,9,9,45), Time.local(2005,2,22,10,10,10).ago(86400*2 + 3600 + 25)
+ end
+
+ def test_daylight_savings_time_crossings_backward_start
+ with_timezone 'US/Eastern' do
+ # dt: US: 2005 April 3rd 4:18am
+ assert_equal Time.local(2005,4,2,4,18,0), Time.local(2005,4,3,4,18,0).ago(86400), 'dt-1.day=>st'
+ assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(86400), 'st-1.day=>st'
+ end
+ with_timezone 'NZ' do
+ # dt: New Zealand: 2006 October 1st 4:18am
+ assert_equal Time.local(2006,9,30,4,18,0), Time.local(2006,10,1,4,18,0).ago(86400), 'dt-1.day=>st'
+ assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(86400), 'st-1.day=>st'
+ end
+ end
+
+ def test_daylight_savings_time_crossings_backward_end
+ with_timezone 'US/Eastern' do
+ # st: US: 2005 October 30th 4:03am
+ assert_equal Time.local(2005,10,29,4,3), Time.local(2005,10,30,4,3,0).ago(86400), 'st-1.day=>dt'
+ assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(86400), 'dt-1.day=>dt'
+ end
+ with_timezone 'NZ' do
+ # st: New Zealand: 2006 March 19th 4:03am
+ assert_equal Time.local(2006,3,18,4,3), Time.local(2006,3,19,4,3,0).ago(86400), 'st-1.day=>dt'
+ assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(86400), 'dt-1.day=>dt'
+ end
+ end
+
+ def test_since
+ assert_equal Time.local(2005,2,22,10,10,11), Time.local(2005,2,22,10,10,10).since(1)
+ assert_equal Time.local(2005,2,22,11,10,10), Time.local(2005,2,22,10,10,10).since(3600)
+ assert_equal Time.local(2005,2,24,10,10,10), Time.local(2005,2,22,10,10,10).since(86400*2)
+ assert_equal Time.local(2005,2,24,11,10,35), Time.local(2005,2,22,10,10,10).since(86400*2 + 3600 + 25)
+ # when out of range of Time, returns a DateTime
+ assert_equal DateTime.civil(2038,1,20,11,59,59), Time.utc(2038,1,18,11,59,59).since(86400*2)
+ end
+
+ def test_daylight_savings_time_crossings_forward_start
+ with_timezone 'US/Eastern' do
+ # st: US: 2005 April 2nd 7:27pm
+ assert_equal Time.local(2005,4,3,19,27,0), Time.local(2005,4,2,19,27,0).since(86400), 'st+1.day=>dt'
+ assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(86400), 'dt+1.day=>dt'
+ end
+ with_timezone 'NZ' do
+ # st: New Zealand: 2006 September 30th 7:27pm
+ assert_equal Time.local(2006,10,1,19,27,0), Time.local(2006,9,30,19,27,0).since(86400), 'st+1.day=>dt'
+ assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(86400), 'dt+1.day=>dt'
+ end
+ end
+
+ def test_daylight_savings_time_crossings_forward_end
+ with_timezone 'US/Eastern' do
+ # dt: US: 2005 October 30th 12:45am
+ assert_equal Time.local(2005,10,31,0,45,0), Time.local(2005,10,30,0,45,0).since(86400), 'dt+1.day=>st'
+ assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(86400), 'st+1.day=>st'
+ end
+ with_timezone 'NZ' do
+ # dt: New Zealand: 2006 March 19th 1:45am
+ assert_equal Time.local(2006,3,20,1,45,0), Time.local(2006,3,19,1,45,0).since(86400), 'dt+1.day=>st'
+ assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(86400), 'st+1.day=>st'
+ end
+ end
+
+ def test_yesterday
+ assert_equal Time.local(2005,2,21,10,10,10), Time.local(2005,2,22,10,10,10).yesterday
+ assert_equal Time.local(2005,2,28,10,10,10), Time.local(2005,3,2,10,10,10).yesterday.yesterday
+ end
+
+ def test_tomorrow
+ assert_equal Time.local(2005,2,23,10,10,10), Time.local(2005,2,22,10,10,10).tomorrow
+ assert_equal Time.local(2005,3,2,10,10,10), Time.local(2005,2,28,10,10,10).tomorrow.tomorrow
+ end
+
+ def test_change
+ assert_equal Time.local(2006,2,22,15,15,10), Time.local(2005,2,22,15,15,10).change(:year => 2006)
+ assert_equal Time.local(2005,6,22,15,15,10), Time.local(2005,2,22,15,15,10).change(:month => 6)
+ assert_equal Time.local(2012,9,22,15,15,10), Time.local(2005,2,22,15,15,10).change(:year => 2012, :month => 9)
+ assert_equal Time.local(2005,2,22,16), Time.local(2005,2,22,15,15,10).change(:hour => 16)
+ assert_equal Time.local(2005,2,22,16,45), Time.local(2005,2,22,15,15,10).change(:hour => 16, :min => 45)
+ assert_equal Time.local(2005,2,22,15,45), Time.local(2005,2,22,15,15,10).change(:min => 45)
+
+ assert_equal Time.local(2005,1,2, 5, 0, 0, 0), Time.local(2005,1,2,11,22,33,44).change(:hour => 5)
+ assert_equal Time.local(2005,1,2,11, 6, 0, 0), Time.local(2005,1,2,11,22,33,44).change(:min => 6)
+ assert_equal Time.local(2005,1,2,11,22, 7, 0), Time.local(2005,1,2,11,22,33,44).change(:sec => 7)
+ assert_equal Time.local(2005,1,2,11,22,33, 8), Time.local(2005,1,2,11,22,33,44).change(:usec => 8)
+ end
+
+ def test_utc_change
+ assert_equal Time.utc(2006,2,22,15,15,10), Time.utc(2005,2,22,15,15,10).change(:year => 2006)
+ assert_equal Time.utc(2005,6,22,15,15,10), Time.utc(2005,2,22,15,15,10).change(:month => 6)
+ assert_equal Time.utc(2012,9,22,15,15,10), Time.utc(2005,2,22,15,15,10).change(:year => 2012, :month => 9)
+ assert_equal Time.utc(2005,2,22,16), Time.utc(2005,2,22,15,15,10).change(:hour => 16)
+ assert_equal Time.utc(2005,2,22,16,45), Time.utc(2005,2,22,15,15,10).change(:hour => 16, :min => 45)
+ assert_equal Time.utc(2005,2,22,15,45), Time.utc(2005,2,22,15,15,10).change(:min => 45)
+ end
+
+ def test_advance
+ assert_equal Time.local(2006,2,28,15,15,10), Time.local(2005,2,28,15,15,10).advance(:years => 1)
+ assert_equal Time.local(2005,6,28,15,15,10), Time.local(2005,2,28,15,15,10).advance(:months => 4)
+ assert_equal Time.local(2005,3,21,15,15,10), Time.local(2005,2,28,15,15,10).advance(:weeks => 3)
+ assert_equal Time.local(2005,3,5,15,15,10), Time.local(2005,2,28,15,15,10).advance(:days => 5)
+ assert_equal Time.local(2012,9,28,15,15,10), Time.local(2005,2,28,15,15,10).advance(:years => 7, :months => 7)
+ assert_equal Time.local(2013,10,3,15,15,10), Time.local(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :days => 5)
+ assert_equal Time.local(2013,10,17,15,15,10), Time.local(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :weeks => 2, :days => 5)
+ assert_equal Time.local(2001,12,27,15,15,10), Time.local(2005,2,28,15,15,10).advance(:years => -3, :months => -2, :days => -1)
+ assert_equal Time.local(2005,2,28,15,15,10), Time.local(2004,2,29,15,15,10).advance(:years => 1) #leap day plus one year
+ assert_equal Time.local(2005,2,28,20,15,10), Time.local(2005,2,28,15,15,10).advance(:hours => 5)
+ assert_equal Time.local(2005,2,28,15,22,10), Time.local(2005,2,28,15,15,10).advance(:minutes => 7)
+ assert_equal Time.local(2005,2,28,15,15,19), Time.local(2005,2,28,15,15,10).advance(:seconds => 9)
+ assert_equal Time.local(2005,2,28,20,22,19), Time.local(2005,2,28,15,15,10).advance(:hours => 5, :minutes => 7, :seconds => 9)
+ assert_equal Time.local(2005,2,28,10,8,1), Time.local(2005,2,28,15,15,10).advance(:hours => -5, :minutes => -7, :seconds => -9)
+ assert_equal Time.local(2013,10,17,20,22,19), Time.local(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :weeks => 2, :days => 5, :hours => 5, :minutes => 7, :seconds => 9)
+ end
+
+ def test_utc_advance
+ assert_equal Time.utc(2006,2,22,15,15,10), Time.utc(2005,2,22,15,15,10).advance(:years => 1)
+ assert_equal Time.utc(2005,6,22,15,15,10), Time.utc(2005,2,22,15,15,10).advance(:months => 4)
+ assert_equal Time.utc(2005,3,21,15,15,10), Time.utc(2005,2,28,15,15,10).advance(:weeks => 3)
+ assert_equal Time.utc(2005,3,5,15,15,10), Time.utc(2005,2,28,15,15,10).advance(:days => 5)
+ assert_equal Time.utc(2012,9,22,15,15,10), Time.utc(2005,2,22,15,15,10).advance(:years => 7, :months => 7)
+ assert_equal Time.utc(2013,10,3,15,15,10), Time.utc(2005,2,22,15,15,10).advance(:years => 7, :months => 19, :days => 11)
+ assert_equal Time.utc(2013,10,17,15,15,10), Time.utc(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :weeks => 2, :days => 5)
+ assert_equal Time.utc(2001,12,27,15,15,10), Time.utc(2005,2,28,15,15,10).advance(:years => -3, :months => -2, :days => -1)
+ assert_equal Time.utc(2005,2,28,15,15,10), Time.utc(2004,2,29,15,15,10).advance(:years => 1) #leap day plus one year
+ assert_equal Time.utc(2005,2,28,20,15,10), Time.utc(2005,2,28,15,15,10).advance(:hours => 5)
+ assert_equal Time.utc(2005,2,28,15,22,10), Time.utc(2005,2,28,15,15,10).advance(:minutes => 7)
+ assert_equal Time.utc(2005,2,28,15,15,19), Time.utc(2005,2,28,15,15,10).advance(:seconds => 9)
+ assert_equal Time.utc(2005,2,28,20,22,19), Time.utc(2005,2,28,15,15,10).advance(:hours => 5, :minutes => 7, :seconds => 9)
+ assert_equal Time.utc(2005,2,28,10,8,1), Time.utc(2005,2,28,15,15,10).advance(:hours => -5, :minutes => -7, :seconds => -9)
+ assert_equal Time.utc(2013,10,17,20,22,19), Time.utc(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :weeks => 2, :days => 5, :hours => 5, :minutes => 7, :seconds => 9)
+ end
+
+ def test_next_week
+ with_timezone 'US/Eastern' do
+ assert_equal Time.local(2005,2,28), Time.local(2005,2,22,15,15,10).next_week
+ assert_equal Time.local(2005,2,29), Time.local(2005,2,22,15,15,10).next_week(:tuesday)
+ assert_equal Time.local(2005,3,4), Time.local(2005,2,22,15,15,10).next_week(:friday)
+ assert_equal Time.local(2006,10,30), Time.local(2006,10,23,0,0,0).next_week
+ assert_equal Time.local(2006,11,1), Time.local(2006,10,23,0,0,0).next_week(:wednesday)
+ end
+ end
+
+ def test_next_week_near_daylight_start
+ with_timezone 'US/Eastern' do
+ assert_equal Time.local(2006,4,3), Time.local(2006,4,2,23,1,0).next_week, 'just crossed standard => daylight'
+ end
+ with_timezone 'NZ' do
+ assert_equal Time.local(2006,10,2), Time.local(2006,10,1,23,1,0).next_week, 'just crossed standard => daylight'
+ end
+ end
+
+ def test_next_week_near_daylight_end
+ with_timezone 'US/Eastern' do
+ assert_equal Time.local(2006,10,30), Time.local(2006,10,29,23,1,0).next_week, 'just crossed daylight => standard'
+ end
+ with_timezone 'NZ' do
+ assert_equal Time.local(2006,3,20), Time.local(2006,3,19,23,1,0).next_week, 'just crossed daylight => standard'
+ end
+ end
+
+ def test_to_s
+ time = Time.utc(2005, 2, 21, 17, 44, 30)
+ assert_equal time.to_default_s, time.to_s
+ assert_equal time.to_default_s, time.to_s(:doesnt_exist)
+ assert_equal "2005-02-21 17:44:30", time.to_s(:db)
+ assert_equal "21 Feb 17:44", time.to_s(:short)
+ assert_equal "17:44", time.to_s(:time)
+ assert_equal "February 21, 2005 17:44", time.to_s(:long)
+ assert_equal "February 21st, 2005 17:44", time.to_s(:long_ordinal)
+ with_timezone "UTC" do
+ assert_equal "Mon, 21 Feb 2005 17:44:30 +0000", time.to_s(:rfc822)
+ end
+ end
+
+ def test_custom_date_format
+ Time::DATE_FORMATS[:custom] = '%Y%m%d%H%M%S'
+ assert_equal '20050221143000', Time.local(2005, 2, 21, 14, 30, 0).to_s(:custom)
+ Time::DATE_FORMATS.delete(:custom)
+ end
+
+ def test_to_date
+ assert_equal Date.new(2005, 2, 21), Time.local(2005, 2, 21, 17, 44, 30).to_date
+ end
+
+ def test_to_datetime
+ assert_equal Time.utc(2005, 2, 21, 17, 44, 30).to_datetime, DateTime.civil(2005, 2, 21, 17, 44, 30, 0, 0)
+ with_timezone 'US/Eastern' do
+ assert_equal Time.local(2005, 2, 21, 17, 44, 30).to_datetime, DateTime.civil(2005, 2, 21, 17, 44, 30, Rational(Time.local(2005, 2, 21, 17, 44, 30).utc_offset, 86400), 0)
+ end
+ with_timezone 'NZ' do
+ assert_equal Time.local(2005, 2, 21, 17, 44, 30).to_datetime, DateTime.civil(2005, 2, 21, 17, 44, 30, Rational(Time.local(2005, 2, 21, 17, 44, 30).utc_offset, 86400), 0)
+ end
+ assert_equal ::Date::ITALY, Time.utc(2005, 2, 21, 17, 44, 30).to_datetime.start # use Ruby's default start value
+ end
+
+ def test_to_time
+ assert_equal Time.local(2005, 2, 21, 17, 44, 30), Time.local(2005, 2, 21, 17, 44, 30).to_time
+ end
+
+ # NOTE: this test seems to fail (changeset 1958) only on certain platforms,
+ # like OSX, and FreeBSD 5.4.
+ def test_fp_inaccuracy_ticket_1836
+ midnight = Time.local(2005, 2, 21, 0, 0, 0)
+ assert_equal midnight.midnight, (midnight + 1.hour + 0.000001).midnight
+ end
+
+ def test_days_in_month
+ assert_equal 31, Time.days_in_month(1, 2005)
+
+ assert_equal 28, Time.days_in_month(2, 2005)
+ assert_equal 29, Time.days_in_month(2, 2004)
+ assert_equal 29, Time.days_in_month(2, 2000)
+ assert_equal 28, Time.days_in_month(2, 1900)
+
+ assert_equal 31, Time.days_in_month(3, 2005)
+ assert_equal 30, Time.days_in_month(4, 2005)
+ assert_equal 31, Time.days_in_month(5, 2005)
+ assert_equal 30, Time.days_in_month(6, 2005)
+ assert_equal 31, Time.days_in_month(7, 2005)
+ assert_equal 31, Time.days_in_month(8, 2005)
+ assert_equal 30, Time.days_in_month(9, 2005)
+ assert_equal 31, Time.days_in_month(10, 2005)
+ assert_equal 30, Time.days_in_month(11, 2005)
+ assert_equal 31, Time.days_in_month(12, 2005)
+ end
+
+ def test_time_with_datetime_fallback
+ assert_equal Time.time_with_datetime_fallback(:utc, 2005, 2, 21, 17, 44, 30), Time.utc(2005, 2, 21, 17, 44, 30)
+ assert_equal Time.time_with_datetime_fallback(:local, 2005, 2, 21, 17, 44, 30), Time.local(2005, 2, 21, 17, 44, 30)
+ assert_equal Time.time_with_datetime_fallback(:utc, 2039, 2, 21, 17, 44, 30), DateTime.civil(2039, 2, 21, 17, 44, 30, 0, 0)
+ assert_equal Time.time_with_datetime_fallback(:local, 2039, 2, 21, 17, 44, 30), DateTime.civil(2039, 2, 21, 17, 44, 30, DateTime.now.offset, 0)
+ assert_equal Time.time_with_datetime_fallback(:utc, 1900, 2, 21, 17, 44, 30), DateTime.civil(1900, 2, 21, 17, 44, 30, 0, 0)
+ assert_equal Time.time_with_datetime_fallback(:local, 1900, 2, 21, 17, 44, 30), DateTime.civil(1900, 2, 21, 17, 44, 30, DateTime.now.offset, 0)
+ assert_equal Time.time_with_datetime_fallback(:utc, 2005), Time.utc(2005)
+ assert_equal Time.time_with_datetime_fallback(:utc, 2039), DateTime.civil(2039, 1, 1, 0, 0, 0, 0, 0)
+ assert_equal Time.time_with_datetime_fallback(:utc, 2005, 2, 21, 17, 44, 30, 1), Time.utc(2005, 2, 21, 17, 44, 30, 1) #with usec
+ assert_equal Time.time_with_datetime_fallback(:utc, 2039, 2, 21, 17, 44, 30, 1), DateTime.civil(2039, 2, 21, 17, 44, 30, 0, 0)
+ assert_equal ::Date::ITALY, Time.time_with_datetime_fallback(:utc, 2039, 2, 21, 17, 44, 30, 1).start # use Ruby's default start value
+ end
+
+ def test_utc_time
+ assert_equal Time.utc_time(2005, 2, 21, 17, 44, 30), Time.utc(2005, 2, 21, 17, 44, 30)
+ assert_equal Time.utc_time(2039, 2, 21, 17, 44, 30), DateTime.civil(2039, 2, 21, 17, 44, 30, 0, 0)
+ assert_equal Time.utc_time(1901, 2, 21, 17, 44, 30), DateTime.civil(1901, 2, 21, 17, 44, 30, 0, 0)
+ end
+
+ def test_local_time
+ assert_equal Time.local_time(2005, 2, 21, 17, 44, 30), Time.local(2005, 2, 21, 17, 44, 30)
+ assert_equal Time.local_time(2039, 2, 21, 17, 44, 30), DateTime.civil(2039, 2, 21, 17, 44, 30, DateTime.local_offset, 0)
+ assert_equal Time.local_time(1901, 2, 21, 17, 44, 30), DateTime.civil(1901, 2, 21, 17, 44, 30, DateTime.local_offset, 0)
+ end
+
+ def test_next_month_on_31st
+ assert_equal Time.local(2005, 9, 30), Time.local(2005, 8, 31).next_month
+ end
+
+ def test_last_month_on_31st
+ assert_equal Time.local(2004, 2, 29), Time.local(2004, 3, 31).last_month
+ end
+
+ def test_xmlschema_is_available
+ assert_nothing_raised { Time.now.xmlschema }
+ end
+
+ def test_acts_like_time
+ assert Time.new.acts_like_time?
+ end
+
+ protected
+ def with_timezone(new_tz = 'US/Eastern')
+ old_tz, ENV['TZ'] = ENV['TZ'], new_tz
+ yield
+ ensure
+ old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/dependencies/check_warnings.rb b/vendor/rails-2.0.2/activesupport/test/dependencies/check_warnings.rb
new file mode 100644
index 000000000..03c3dca1d
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/dependencies/check_warnings.rb
@@ -0,0 +1,2 @@
+$check_warnings_load_count += 1
+$checked_verbose = $VERBOSE
diff --git a/vendor/rails-2.0.2/activesupport/test/dependencies/conflict.rb b/vendor/rails-2.0.2/activesupport/test/dependencies/conflict.rb
new file mode 100644
index 000000000..e888b7b54
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/dependencies/conflict.rb
@@ -0,0 +1 @@
+Conflict = 1 \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/test/dependencies/cross_site_depender.rb b/vendor/rails-2.0.2/activesupport/test/dependencies/cross_site_depender.rb
new file mode 100644
index 000000000..a31015fc5
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/dependencies/cross_site_depender.rb
@@ -0,0 +1,3 @@
+class CrossSiteDepender
+ CrossSiteDependency
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/test/dependencies/mutual_one.rb b/vendor/rails-2.0.2/activesupport/test/dependencies/mutual_one.rb
new file mode 100644
index 000000000..576eb3171
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/dependencies/mutual_one.rb
@@ -0,0 +1,4 @@
+$mutual_dependencies_count += 1
+require_dependency 'mutual_two'
+require_dependency 'mutual_two.rb'
+require_dependency 'mutual_two'
diff --git a/vendor/rails-2.0.2/activesupport/test/dependencies/mutual_two.rb b/vendor/rails-2.0.2/activesupport/test/dependencies/mutual_two.rb
new file mode 100644
index 000000000..fdbc2dcd8
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/dependencies/mutual_two.rb
@@ -0,0 +1,4 @@
+$mutual_dependencies_count += 1
+require_dependency 'mutual_one.rb'
+require_dependency 'mutual_one'
+require_dependency 'mutual_one.rb'
diff --git a/vendor/rails-2.0.2/activesupport/test/dependencies/raises_exception.rb b/vendor/rails-2.0.2/activesupport/test/dependencies/raises_exception.rb
new file mode 100644
index 000000000..dd745ac20
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/dependencies/raises_exception.rb
@@ -0,0 +1,3 @@
+$raises_exception_load_count += 1
+raise Exception, 'Loading me failed, so do not add to loaded or history.'
+$raises_exception_load_count += 1
diff --git a/vendor/rails-2.0.2/activesupport/test/dependencies/requires_nonexistent0.rb b/vendor/rails-2.0.2/activesupport/test/dependencies/requires_nonexistent0.rb
new file mode 100644
index 000000000..7e24b3916
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/dependencies/requires_nonexistent0.rb
@@ -0,0 +1 @@
+require 'RMagickDontExistDude'
diff --git a/vendor/rails-2.0.2/activesupport/test/dependencies/requires_nonexistent1.rb b/vendor/rails-2.0.2/activesupport/test/dependencies/requires_nonexistent1.rb
new file mode 100644
index 000000000..41e666816
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/dependencies/requires_nonexistent1.rb
@@ -0,0 +1 @@
+require_dependency 'requires_nonexistent0'
diff --git a/vendor/rails-2.0.2/activesupport/test/dependencies/service_one.rb b/vendor/rails-2.0.2/activesupport/test/dependencies/service_one.rb
new file mode 100644
index 000000000..f43bfea23
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/dependencies/service_one.rb
@@ -0,0 +1,5 @@
+$loaded_service_one ||= 0
+$loaded_service_one += 1
+
+class ServiceOne
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/test/dependencies/service_two.rb b/vendor/rails-2.0.2/activesupport/test/dependencies/service_two.rb
new file mode 100644
index 000000000..5205a78bb
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/dependencies/service_two.rb
@@ -0,0 +1,2 @@
+class ServiceTwo
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/test/dependencies_test.rb b/vendor/rails-2.0.2/activesupport/test/dependencies_test.rb
new file mode 100644
index 000000000..76f8453c3
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/dependencies_test.rb
@@ -0,0 +1,751 @@
+require File.dirname(__FILE__) + '/abstract_unit'
+require 'pp'
+
+module ModuleWithMissing
+ mattr_accessor :missing_count
+ def self.const_missing(name)
+ self.missing_count += 1
+ name
+ end
+end
+
+module ModuleWithConstant
+ InheritedConstant = "Hello"
+end
+
+class DependenciesTest < Test::Unit::TestCase
+ def teardown
+ Dependencies.clear
+ end
+
+ def with_loading(*from)
+ old_mechanism, Dependencies.mechanism = Dependencies.mechanism, :load
+ dir = File.dirname(__FILE__)
+ prior_load_paths = Dependencies.load_paths
+ Dependencies.load_paths = from.collect { |f| "#{dir}/#{f}" }
+ yield
+ ensure
+ Dependencies.load_paths = prior_load_paths
+ Dependencies.mechanism = old_mechanism
+ Dependencies.explicitly_unloadable_constants = []
+ end
+
+ def test_tracking_loaded_files
+ require_dependency(File.dirname(__FILE__) + "/dependencies/service_one")
+ require_dependency(File.dirname(__FILE__) + "/dependencies/service_two")
+ assert_equal 2, Dependencies.loaded.size
+ end
+
+ def test_tracking_identical_loaded_files
+ require_dependency(File.dirname(__FILE__) + "/dependencies/service_one")
+ require_dependency(File.dirname(__FILE__) + "/dependencies/service_one")
+ assert_equal 1, Dependencies.loaded.size
+ end
+
+ def test_missing_dependency_raises_missing_source_file
+ assert_raises(MissingSourceFile) { require_dependency("missing_service") }
+ end
+
+ def test_missing_association_raises_nothing
+ assert_nothing_raised { require_association("missing_model") }
+ end
+
+ def test_dependency_which_raises_exception_isnt_added_to_loaded_set
+ with_loading do
+ filename = "#{File.dirname(__FILE__)}/dependencies/raises_exception"
+ $raises_exception_load_count = 0
+
+ 5.times do |count|
+ begin
+ require_dependency filename
+ flunk 'should have loaded dependencies/raises_exception which raises an exception'
+ rescue Exception => e
+ assert_equal 'Loading me failed, so do not add to loaded or history.', e.message
+ end
+ assert_equal count + 1, $raises_exception_load_count
+
+ assert !Dependencies.loaded.include?(filename)
+ assert !Dependencies.history.include?(filename)
+ end
+ end
+ end
+
+ def test_warnings_should_be_enabled_on_first_load
+ with_loading 'dependencies' do
+ old_warnings, Dependencies.warnings_on_first_load = Dependencies.warnings_on_first_load, true
+
+ filename = "check_warnings"
+ expanded = File.expand_path("test/dependencies/#{filename}")
+ $check_warnings_load_count = 0
+
+ assert !Dependencies.loaded.include?(expanded)
+ assert !Dependencies.history.include?(expanded)
+
+ silence_warnings { require_dependency filename }
+ assert_equal 1, $check_warnings_load_count
+ assert_equal true, $checked_verbose, 'On first load warnings should be enabled.'
+
+ assert Dependencies.loaded.include?(expanded)
+ Dependencies.clear
+ assert !Dependencies.loaded.include?(expanded)
+ assert Dependencies.history.include?(expanded)
+
+ silence_warnings { require_dependency filename }
+ assert_equal 2, $check_warnings_load_count
+ assert_equal nil, $checked_verbose, 'After first load warnings should be left alone.'
+
+ assert Dependencies.loaded.include?(expanded)
+ Dependencies.clear
+ assert !Dependencies.loaded.include?(expanded)
+ assert Dependencies.history.include?(expanded)
+
+ enable_warnings { require_dependency filename }
+ assert_equal 3, $check_warnings_load_count
+ assert_equal true, $checked_verbose, 'After first load warnings should be left alone.'
+
+ assert Dependencies.loaded.include?(expanded)
+ end
+ end
+
+ def test_mutual_dependencies_dont_infinite_loop
+ with_loading 'dependencies' do
+ $mutual_dependencies_count = 0
+ assert_nothing_raised { require_dependency 'mutual_one' }
+ assert_equal 2, $mutual_dependencies_count
+
+ Dependencies.clear
+
+ $mutual_dependencies_count = 0
+ assert_nothing_raised { require_dependency 'mutual_two' }
+ assert_equal 2, $mutual_dependencies_count
+ end
+ end
+
+ def test_as_load_path
+ assert_equal '', DependenciesTest.as_load_path
+ end
+
+ def test_module_loading
+ with_loading 'autoloading_fixtures' do
+ assert_kind_of Module, A
+ assert_kind_of Class, A::B
+ assert_kind_of Class, A::C::D
+ assert_kind_of Class, A::C::E::F
+ end
+ end
+
+ def test_non_existing_const_raises_name_error
+ with_loading 'autoloading_fixtures' do
+ assert_raises(NameError) { DoesNotExist }
+ assert_raises(NameError) { NoModule::DoesNotExist }
+ assert_raises(NameError) { A::DoesNotExist }
+ assert_raises(NameError) { A::B::DoesNotExist }
+ end
+ end
+
+ def test_directories_manifest_as_modules_unless_const_defined
+ with_loading 'autoloading_fixtures' do
+ assert_kind_of Module, ModuleFolder
+ Object.send! :remove_const, :ModuleFolder
+ end
+ end
+
+ def test_module_with_nested_class
+ with_loading 'autoloading_fixtures' do
+ assert_kind_of Class, ModuleFolder::NestedClass
+ Object.send! :remove_const, :ModuleFolder
+ end
+ end
+
+ def test_module_with_nested_inline_class
+ with_loading 'autoloading_fixtures' do
+ assert_kind_of Class, ModuleFolder::InlineClass
+ Object.send! :remove_const, :ModuleFolder
+ end
+ end
+
+ def test_directories_may_manifest_as_nested_classes
+ with_loading 'autoloading_fixtures' do
+ assert_kind_of Class, ClassFolder
+ Object.send! :remove_const, :ClassFolder
+ end
+ end
+
+ def test_class_with_nested_class
+ with_loading 'autoloading_fixtures' do
+ assert_kind_of Class, ClassFolder::NestedClass
+ Object.send! :remove_const, :ClassFolder
+ end
+ end
+
+ def test_class_with_nested_inline_class
+ with_loading 'autoloading_fixtures' do
+ assert_kind_of Class, ClassFolder::InlineClass
+ Object.send! :remove_const, :ClassFolder
+ end
+ end
+
+ def test_class_with_nested_inline_subclass_of_parent
+ with_loading 'autoloading_fixtures' do
+ assert_kind_of Class, ClassFolder::ClassFolderSubclass
+ assert_kind_of Class, ClassFolder
+ assert_equal 'indeed', ClassFolder::ClassFolderSubclass::ConstantInClassFolder
+ Object.send! :remove_const, :ClassFolder
+ end
+ end
+
+ def test_nested_class_can_access_sibling
+ with_loading 'autoloading_fixtures' do
+ sibling = ModuleFolder::NestedClass.class_eval "NestedSibling"
+ assert defined?(ModuleFolder::NestedSibling)
+ assert_equal ModuleFolder::NestedSibling, sibling
+ Object.send! :remove_const, :ModuleFolder
+ end
+ end
+
+ def failing_test_access_thru_and_upwards_fails
+ with_loading 'autoloading_fixtures' do
+ assert ! defined?(ModuleFolder)
+ assert_raises(NameError) { ModuleFolder::Object }
+ assert_raises(NameError) { ModuleFolder::NestedClass::Object }
+ Object.send! :remove_const, :ModuleFolder
+ end
+ end
+
+ def test_non_existing_const_raises_name_error_with_fully_qualified_name
+ with_loading 'autoloading_fixtures' do
+ begin
+ A::DoesNotExist.nil?
+ flunk "No raise!!"
+ rescue NameError => e
+ assert_equal "uninitialized constant A::DoesNotExist", e.message
+ end
+ begin
+ A::B::DoesNotExist.nil?
+ flunk "No raise!!"
+ rescue NameError => e
+ assert_equal "uninitialized constant A::B::DoesNotExist", e.message
+ end
+ end
+ end
+
+ def test_smart_name_error_strings
+ begin
+ Object.module_eval "ImaginaryObject"
+ flunk "No raise!!"
+ rescue NameError => e
+ assert e.message.include?("uninitialized constant ImaginaryObject")
+ end
+ end
+
+ def test_loadable_constants_for_path_should_handle_empty_autoloads
+ assert_equal [], Dependencies.loadable_constants_for_path('hello')
+ end
+
+ def test_loadable_constants_for_path_should_handle_relative_paths
+ fake_root = 'dependencies'
+ relative_root = File.dirname(__FILE__) + '/dependencies'
+ ['', '/'].each do |suffix|
+ with_loading fake_root + suffix do
+ assert_equal ["A::B"], Dependencies.loadable_constants_for_path(relative_root + '/a/b')
+ end
+ end
+ end
+
+ def test_loadable_constants_for_path_should_provide_all_results
+ fake_root = '/usr/apps/backpack'
+ with_loading fake_root, fake_root + '/lib' do
+ root = Dependencies.load_paths.first
+ assert_equal ["Lib::A::B", "A::B"], Dependencies.loadable_constants_for_path(root + '/lib/a/b')
+ end
+ end
+
+ def test_loadable_constants_for_path_should_uniq_results
+ fake_root = '/usr/apps/backpack/lib'
+ with_loading fake_root, fake_root + '/' do
+ root = Dependencies.load_paths.first
+ assert_equal ["A::B"], Dependencies.loadable_constants_for_path(root + '/a/b')
+ end
+ end
+
+ def test_loadable_constants_with_load_path_without_trailing_slash
+ path = File.dirname(__FILE__) + '/autoloading_fixtures/class_folder/inline_class.rb'
+ with_loading 'autoloading_fixtures/class/' do
+ assert_equal [], Dependencies.loadable_constants_for_path(path)
+ end
+ end
+
+ def test_qualified_const_defined
+ assert Dependencies.qualified_const_defined?("Object")
+ assert Dependencies.qualified_const_defined?("::Object")
+ assert Dependencies.qualified_const_defined?("::Object::Kernel")
+ assert Dependencies.qualified_const_defined?("::Object::Dependencies")
+ assert Dependencies.qualified_const_defined?("::Test::Unit::TestCase")
+ end
+
+ def test_qualified_const_defined_should_not_call_method_missing
+ ModuleWithMissing.missing_count = 0
+ assert ! Dependencies.qualified_const_defined?("ModuleWithMissing::A")
+ assert_equal 0, ModuleWithMissing.missing_count
+ assert ! Dependencies.qualified_const_defined?("ModuleWithMissing::A::B")
+ assert_equal 0, ModuleWithMissing.missing_count
+ end
+
+ def test_autoloaded?
+ with_loading 'autoloading_fixtures' do
+ assert ! Dependencies.autoloaded?("ModuleFolder")
+ assert ! Dependencies.autoloaded?("ModuleFolder::NestedClass")
+
+ assert Dependencies.autoloaded?(ModuleFolder)
+
+ assert Dependencies.autoloaded?("ModuleFolder")
+ assert ! Dependencies.autoloaded?("ModuleFolder::NestedClass")
+
+ assert Dependencies.autoloaded?(ModuleFolder::NestedClass)
+
+ assert Dependencies.autoloaded?("ModuleFolder")
+ assert Dependencies.autoloaded?("ModuleFolder::NestedClass")
+
+ assert Dependencies.autoloaded?("::ModuleFolder")
+ assert Dependencies.autoloaded?(:ModuleFolder)
+
+ # Anonymous modules aren't autoloaded.
+ assert !Dependencies.autoloaded?(Module.new)
+
+ nil_name = Module.new
+ def nil_name.name() nil end
+ assert !Dependencies.autoloaded?(nil_name)
+
+ Object.class_eval { remove_const :ModuleFolder }
+ end
+ end
+
+ def test_qualified_name_for
+ assert_equal "A", Dependencies.qualified_name_for(Object, :A)
+ assert_equal "A", Dependencies.qualified_name_for(:Object, :A)
+ assert_equal "A", Dependencies.qualified_name_for("Object", :A)
+ assert_equal "A", Dependencies.qualified_name_for("::Object", :A)
+ assert_equal "A", Dependencies.qualified_name_for("::Kernel", :A)
+
+ assert_equal "Dependencies::A", Dependencies.qualified_name_for(:Dependencies, :A)
+ assert_equal "Dependencies::A", Dependencies.qualified_name_for(Dependencies, :A)
+ end
+
+ def test_file_search
+ with_loading 'dependencies' do
+ root = Dependencies.load_paths.first
+ assert_equal nil, Dependencies.search_for_file('service_three')
+ assert_equal nil, Dependencies.search_for_file('service_three.rb')
+ assert_equal root + '/service_one.rb', Dependencies.search_for_file('service_one')
+ assert_equal root + '/service_one.rb', Dependencies.search_for_file('service_one.rb')
+ end
+ end
+
+ def test_file_search_uses_first_in_load_path
+ with_loading 'dependencies', 'autoloading_fixtures' do
+ deps, autoload = Dependencies.load_paths
+ assert_match %r/dependencies/, deps
+ assert_match %r/autoloading_fixtures/, autoload
+
+ assert_equal deps + '/conflict.rb', Dependencies.search_for_file('conflict')
+ end
+ with_loading 'autoloading_fixtures', 'dependencies' do
+ autoload, deps = Dependencies.load_paths
+ assert_match %r/dependencies/, deps
+ assert_match %r/autoloading_fixtures/, autoload
+
+ assert_equal autoload + '/conflict.rb', Dependencies.search_for_file('conflict')
+ end
+
+ end
+
+ def test_custom_const_missing_should_work
+ Object.module_eval <<-end_eval
+ module ModuleWithCustomConstMissing
+ def self.const_missing(name)
+ const_set name, name.to_s.hash
+ end
+
+ module A
+ end
+ end
+ end_eval
+
+ with_loading 'autoloading_fixtures' do
+ assert_kind_of Integer, ::ModuleWithCustomConstMissing::B
+ assert_kind_of Module, ::ModuleWithCustomConstMissing::A
+ assert_kind_of String, ::ModuleWithCustomConstMissing::A::B
+ end
+ end
+
+ def test_const_missing_should_not_double_load
+ $counting_loaded_times = 0
+ with_loading 'autoloading_fixtures' do
+ require_dependency '././counting_loader'
+ assert_equal 1, $counting_loaded_times
+ assert_raises(ArgumentError) { Dependencies.load_missing_constant Object, :CountingLoader }
+ assert_equal 1, $counting_loaded_times
+ end
+ end
+
+ def test_const_missing_within_anonymous_module
+ $counting_loaded_times = 0
+ m = Module.new
+ m.module_eval "def a() CountingLoader; end"
+ extend m
+ kls = nil
+ with_loading 'autoloading_fixtures' do
+ kls = nil
+ assert_nothing_raised { kls = a }
+ assert_equal "CountingLoader", kls.name
+ assert_equal 1, $counting_loaded_times
+
+ assert_nothing_raised { kls = a }
+ assert_equal 1, $counting_loaded_times
+ end
+ end
+
+ def test_removal_from_tree_should_be_detected
+ with_loading 'dependencies' do
+ root = Dependencies.load_paths.first
+ c = ServiceOne
+ Dependencies.clear
+ assert ! defined?(ServiceOne)
+ begin
+ Dependencies.load_missing_constant(c, :FakeMissing)
+ flunk "Expected exception"
+ rescue ArgumentError => e
+ assert_match %r{ServiceOne has been removed from the module tree}i, e.message
+ end
+ end
+ end
+
+ def test_nested_load_error_isnt_rescued
+ with_loading 'dependencies' do
+ assert_raises(MissingSourceFile) do
+ RequiresNonexistent1
+ end
+ end
+ end
+
+ def test_load_once_paths_do_not_add_to_autoloaded_constants
+ with_loading 'autoloading_fixtures' do
+ Dependencies.load_once_paths = Dependencies.load_paths.dup
+
+ assert ! Dependencies.autoloaded?("ModuleFolder")
+ assert ! Dependencies.autoloaded?("ModuleFolder::NestedClass")
+ assert ! Dependencies.autoloaded?(ModuleFolder)
+
+ 1 if ModuleFolder::NestedClass # 1 if to avoid warning
+ assert ! Dependencies.autoloaded?(ModuleFolder::NestedClass)
+ end
+ ensure
+ Object.class_eval { remove_const :ModuleFolder }
+ Dependencies.load_once_paths = []
+ end
+
+ def test_application_should_special_case_application_controller
+ with_loading 'autoloading_fixtures' do
+ require_dependency 'application'
+ assert_equal 10, ApplicationController
+ assert Dependencies.autoloaded?(:ApplicationController)
+ end
+ end
+
+ def test_const_missing_on_kernel_should_fallback_to_object
+ with_loading 'autoloading_fixtures' do
+ kls = Kernel::E
+ assert_equal "E", kls.name
+ assert_equal kls.object_id, Kernel::E.object_id
+ end
+ end
+
+ def test_preexisting_constants_are_not_marked_as_autoloaded
+ with_loading 'autoloading_fixtures' do
+ require_dependency 'e'
+ assert Dependencies.autoloaded?(:E)
+ Dependencies.clear
+ end
+
+ Object.const_set :E, Class.new
+ with_loading 'autoloading_fixtures' do
+ require_dependency 'e'
+ assert ! Dependencies.autoloaded?(:E), "E shouldn't be marked autoloaded!"
+ Dependencies.clear
+ end
+
+ ensure
+ Object.class_eval { remove_const :E }
+ end
+
+ def test_unloadable
+ with_loading 'autoloading_fixtures' do
+ Object.const_set :M, Module.new
+ M.unloadable
+
+ Dependencies.clear
+ assert ! defined?(M)
+
+ Object.const_set :M, Module.new
+ Dependencies.clear
+ assert ! defined?(M), "Dependencies should unload unloadable constants each time"
+ end
+ end
+
+ def test_unloadable_should_fail_with_anonymous_modules
+ with_loading 'autoloading_fixtures' do
+ m = Module.new
+ assert_raises(ArgumentError) { m.unloadable }
+ end
+ end
+
+ def test_unloadable_should_return_change_flag
+ with_loading 'autoloading_fixtures' do
+ Object.const_set :M, Module.new
+ assert_equal true, M.unloadable
+ assert_equal false, M.unloadable
+ end
+ end
+
+ def test_new_contants_in_without_constants
+ assert_equal [], (Dependencies.new_constants_in(Object) { })
+ assert Dependencies.constant_watch_stack.empty?
+ end
+
+ def test_new_constants_in_with_a_single_constant
+ assert_equal ["Hello"], Dependencies.new_constants_in(Object) {
+ Object.const_set :Hello, 10
+ }.map(&:to_s)
+ assert Dependencies.constant_watch_stack.empty?
+ ensure
+ Object.class_eval { remove_const :Hello }
+ end
+
+ def test_new_constants_in_with_nesting
+ outer = Dependencies.new_constants_in(Object) do
+ Object.const_set :OuterBefore, 10
+
+ assert_equal ["Inner"], Dependencies.new_constants_in(Object) {
+ Object.const_set :Inner, 20
+ }.map(&:to_s)
+
+ Object.const_set :OuterAfter, 30
+ end
+
+ assert_equal ["OuterAfter", "OuterBefore"], outer.sort.map(&:to_s)
+ assert Dependencies.constant_watch_stack.empty?
+ ensure
+ %w(OuterBefore Inner OuterAfter).each do |name|
+ Object.class_eval { remove_const name if const_defined?(name) }
+ end
+ end
+
+ def test_new_constants_in_module
+ Object.const_set :M, Module.new
+
+ outer = Dependencies.new_constants_in(M) do
+ M.const_set :OuterBefore, 10
+
+ inner = Dependencies.new_constants_in(M) do
+ M.const_set :Inner, 20
+ end
+ assert_equal ["M::Inner"], inner
+
+ M.const_set :OuterAfter, 30
+ end
+ assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort
+ assert Dependencies.constant_watch_stack.empty?
+ ensure
+ Object.class_eval { remove_const :M }
+ end
+
+ def test_new_constants_in_module_using_name
+ outer = Dependencies.new_constants_in(:M) do
+ Object.const_set :M, Module.new
+ M.const_set :OuterBefore, 10
+
+ inner = Dependencies.new_constants_in(:M) do
+ M.const_set :Inner, 20
+ end
+ assert_equal ["M::Inner"], inner
+
+ M.const_set :OuterAfter, 30
+ end
+ assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort
+ assert Dependencies.constant_watch_stack.empty?
+ ensure
+ Object.class_eval { remove_const :M }
+ end
+
+ def test_new_constants_in_with_inherited_constants
+ m = Dependencies.new_constants_in(:Object) do
+ Object.class_eval { include ModuleWithConstant }
+ end
+ assert_equal [], m
+ end
+
+ def test_file_with_multiple_constants_and_require_dependency
+ with_loading 'autoloading_fixtures' do
+ assert ! defined?(MultipleConstantFile)
+ assert ! defined?(SiblingConstant)
+
+ require_dependency 'multiple_constant_file'
+ assert defined?(MultipleConstantFile)
+ assert defined?(SiblingConstant)
+ assert Dependencies.autoloaded?(:MultipleConstantFile)
+ assert Dependencies.autoloaded?(:SiblingConstant)
+
+ Dependencies.clear
+
+ assert ! defined?(MultipleConstantFile)
+ assert ! defined?(SiblingConstant)
+ end
+ end
+
+ def test_file_with_multiple_constants_and_auto_loading
+ with_loading 'autoloading_fixtures' do
+ assert ! defined?(MultipleConstantFile)
+ assert ! defined?(SiblingConstant)
+
+ assert_equal 10, MultipleConstantFile
+
+ assert defined?(MultipleConstantFile)
+ assert defined?(SiblingConstant)
+ assert Dependencies.autoloaded?(:MultipleConstantFile)
+ assert Dependencies.autoloaded?(:SiblingConstant)
+
+ Dependencies.clear
+
+ assert ! defined?(MultipleConstantFile)
+ assert ! defined?(SiblingConstant)
+ end
+ end
+
+ def test_nested_file_with_multiple_constants_and_require_dependency
+ with_loading 'autoloading_fixtures' do
+ assert ! defined?(ClassFolder::NestedClass)
+ assert ! defined?(ClassFolder::SiblingClass)
+
+ require_dependency 'class_folder/nested_class'
+
+ assert defined?(ClassFolder::NestedClass)
+ assert defined?(ClassFolder::SiblingClass)
+ assert Dependencies.autoloaded?("ClassFolder::NestedClass")
+ assert Dependencies.autoloaded?("ClassFolder::SiblingClass")
+
+ Dependencies.clear
+
+ assert ! defined?(ClassFolder::NestedClass)
+ assert ! defined?(ClassFolder::SiblingClass)
+ end
+ end
+
+ def test_nested_file_with_multiple_constants_and_auto_loading
+ with_loading 'autoloading_fixtures' do
+ assert ! defined?(ClassFolder::NestedClass)
+ assert ! defined?(ClassFolder::SiblingClass)
+
+ assert_kind_of Class, ClassFolder::NestedClass
+
+ assert defined?(ClassFolder::NestedClass)
+ assert defined?(ClassFolder::SiblingClass)
+ assert Dependencies.autoloaded?("ClassFolder::NestedClass")
+ assert Dependencies.autoloaded?("ClassFolder::SiblingClass")
+
+ Dependencies.clear
+
+ assert ! defined?(ClassFolder::NestedClass)
+ assert ! defined?(ClassFolder::SiblingClass)
+ end
+ end
+
+ def test_autoload_doesnt_shadow_no_method_error_with_relative_constant
+ with_loading 'autoloading_fixtures' do
+ assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it hasn't been referenced yet!"
+ 2.times do
+ assert_raise(NoMethodError) { RaisesNoMethodError }
+ assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it should have failed!"
+ end
+ end
+
+ ensure
+ Object.class_eval { remove_const :RaisesNoMethodError if const_defined?(:RaisesNoMethodError) }
+ end
+
+ def test_autoload_doesnt_shadow_no_method_error_with_absolute_constant
+ with_loading 'autoloading_fixtures' do
+ assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it hasn't been referenced yet!"
+ 2.times do
+ assert_raise(NoMethodError) { ::RaisesNoMethodError }
+ assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it should have failed!"
+ end
+ end
+
+ ensure
+ Object.class_eval { remove_const :RaisesNoMethodError if const_defined?(:RaisesNoMethodError) }
+ end
+
+ def test_autoload_doesnt_shadow_name_error
+ with_loading 'autoloading_fixtures' do
+ assert !defined?(::RaisesNameError), "::RaisesNameError is defined but it hasn't been referenced yet!"
+ 2.times do
+ begin
+ ::RaisesNameError.object_id
+ flunk 'should have raised NameError when autoloaded file referenced FooBarBaz'
+ rescue NameError => e
+ assert_equal 'uninitialized constant RaisesNameError::FooBarBaz', e.message
+ end
+ assert !defined?(::RaisesNameError), "::RaisesNameError is defined but it should have failed!"
+ end
+
+ assert !defined?(RaisesNameError)
+ 2.times do
+ assert_raise(NameError) { RaisesNameError }
+ assert !defined?(::RaisesNameError), "::RaisesNameError is defined but it should have failed!"
+ end
+ end
+
+ ensure
+ Object.class_eval { remove_const :RaisesNoMethodError if const_defined?(:RaisesNoMethodError) }
+ end
+
+ def test_remove_constant_handles_double_colon_at_start
+ Object.const_set 'DeleteMe', Module.new
+ DeleteMe.const_set 'OrMe', Module.new
+ Dependencies.remove_constant "::DeleteMe::OrMe"
+ assert ! defined?(DeleteMe::OrMe)
+ assert defined?(DeleteMe)
+ Dependencies.remove_constant "::DeleteMe"
+ assert ! defined?(DeleteMe)
+ end
+
+ def test_load_once_constants_should_not_be_unloaded
+ with_loading 'autoloading_fixtures' do
+ Dependencies.load_once_paths = Dependencies.load_paths
+ ::A.to_s
+ assert defined?(A)
+ Dependencies.clear
+ assert defined?(A)
+ end
+ ensure
+ Dependencies.load_once_paths = []
+ Object.class_eval { remove_const :A if const_defined?(:A) }
+ end
+
+ def test_load_once_paths_should_behave_when_recursively_loading
+ with_loading 'dependencies', 'autoloading_fixtures' do
+ Dependencies.load_once_paths = [Dependencies.load_paths.last]
+ assert !defined?(CrossSiteDependency)
+ assert_nothing_raised { CrossSiteDepender.nil? }
+ assert defined?(CrossSiteDependency)
+ assert !Dependencies.autoloaded?(CrossSiteDependency),
+ "CrossSiteDependency shouldn't be marked as autoloaded!"
+ Dependencies.clear
+ assert defined?(CrossSiteDependency),
+ "CrossSiteDependency shouldn't have been unloaded!"
+ end
+ ensure
+ Dependencies.load_once_paths = []
+ end
+
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/deprecation_test.rb b/vendor/rails-2.0.2/activesupport/test/deprecation_test.rb
new file mode 100644
index 000000000..9eb9e9253
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/deprecation_test.rb
@@ -0,0 +1,151 @@
+require File.dirname(__FILE__) + '/abstract_unit'
+
+class Deprecatee
+ def initialize
+ @request = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(self, :request)
+ @_request = 'there we go'
+ end
+ def request; @_request end
+ def old_request; @request end
+
+ def partially(foo = nil)
+ ActiveSupport::Deprecation.warn('calling with foo=nil is out', caller) if foo.nil?
+ end
+
+ def not() 2 end
+ def none() 1 end
+ def one(a) a end
+ def multi(a,b,c) [a,b,c] end
+ deprecate :none, :one, :multi
+
+ def a; end
+ def b; end
+ def c; end
+ def d; end
+ def e; end
+ deprecate :a, :b, :c => :e, :d => "you now need to do something extra for this one"
+end
+
+
+class DeprecationTest < Test::Unit::TestCase
+ def setup
+ # Track the last warning.
+ @old_behavior = ActiveSupport::Deprecation.behavior
+ @last_message = nil
+ ActiveSupport::Deprecation.behavior = Proc.new { |message| @last_message = message }
+
+ @dtc = Deprecatee.new
+ end
+
+ def teardown
+ ActiveSupport::Deprecation.behavior = @old_behavior
+ end
+
+ def test_inline_deprecation_warning
+ assert_deprecated(/foo=nil/) do
+ @dtc.partially
+ end
+ end
+
+ def test_undeprecated
+ assert_not_deprecated do
+ assert_equal 2, @dtc.not
+ end
+ end
+
+ def test_deprecate_class_method
+ assert_deprecated(/none is deprecated.*test_deprecate_class_method at/) do
+ assert_equal 1, @dtc.none
+ end
+
+ assert_deprecated(/one is deprecated/) do
+ assert_equal 1, @dtc.one(1)
+ end
+
+ assert_deprecated(/multi is deprecated/) do
+ assert_equal [1,2,3], @dtc.multi(1,2,3)
+ end
+ end
+
+ def test_nil_behavior_is_ignored
+ ActiveSupport::Deprecation.behavior = nil
+ assert_deprecated(/foo=nil/) { @dtc.partially }
+ end
+
+ def test_deprecated_instance_variable_proxy
+ assert_not_deprecated { @dtc.request.size }
+
+ assert_deprecated('@request.size') { assert_equal @dtc.request.size, @dtc.old_request.size }
+ assert_deprecated('@request.to_s') { assert_equal @dtc.request.to_s, @dtc.old_request.to_s }
+ end
+
+ def test_deprecated_instance_variable_proxy_shouldnt_warn_on_inspect
+ assert_not_deprecated { assert_equal @dtc.request.inspect, @dtc.old_request.inspect }
+ end
+
+ def test_assert_deprecation_without_match
+ assert_deprecated do
+ @dtc.partially
+ end
+ end
+
+ def test_assert_deprecated_matches_any_warning
+ assert_deprecated 'abc' do
+ ActiveSupport::Deprecation.warn 'abc'
+ ActiveSupport::Deprecation.warn 'def'
+ end
+ rescue Test::Unit::AssertionFailedError
+ flunk 'assert_deprecated should match any warning in block, not just the last one'
+ end
+
+ def test_assert_not_deprecated_returns_result_of_block
+ assert_equal 123, assert_not_deprecated { 123 }
+ end
+
+ def test_assert_deprecated_returns_result_of_block
+ result = assert_deprecated('abc') do
+ ActiveSupport::Deprecation.warn 'abc'
+ 123
+ end
+ assert_equal 123, result
+ end
+
+ def test_silence
+ ActiveSupport::Deprecation.silence do
+ assert_not_deprecated { @dtc.partially }
+ end
+
+ ActiveSupport::Deprecation.silenced = true
+ assert_not_deprecated { @dtc.partially }
+ ActiveSupport::Deprecation.silenced = false
+ end
+
+ def test_deprecation_without_explanation
+ assert_deprecated { @dtc.a }
+ assert_deprecated { @dtc.b }
+ end
+
+ def test_deprecation_with_alternate_method
+ assert_deprecated(/use e instead/) { @dtc.c }
+ end
+
+ def test_deprecation_with_explicit_message
+ assert_deprecated(/you now need to do something extra for this one/) { @dtc.d }
+ end
+
+ def test_assertion_failed_error_doesnt_spout_deprecation_warnings
+ error_class = Class.new(StandardError) do
+ def message
+ ActiveSupport::Deprecation.warn 'warning in error message'
+ super
+ end
+ end
+
+ raise error_class.new('hmm')
+
+ rescue => e
+ error = Test::Unit::Error.new('testing ur doodz', e)
+ assert_not_deprecated { error.message }
+ assert_nil @last_message
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/inflector_test.rb b/vendor/rails-2.0.2/activesupport/test/inflector_test.rb
new file mode 100644
index 000000000..b0155d36b
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/inflector_test.rb
@@ -0,0 +1,248 @@
+require File.dirname(__FILE__) + '/abstract_unit'
+require 'inflector_test_cases'
+
+module Ace
+ module Base
+ class Case
+ end
+ end
+end
+
+class InflectorTest < Test::Unit::TestCase
+ include InflectorTestCases
+
+ def test_pluralize_plurals
+ assert_equal "plurals", Inflector.pluralize("plurals")
+ assert_equal "Plurals", Inflector.pluralize("Plurals")
+ end
+
+ def test_pluralize_empty_string
+ assert_equal "", Inflector.pluralize("")
+ end
+
+ SingularToPlural.each do |singular, plural|
+ define_method "test_pluralize_#{singular}" do
+ assert_equal(plural, Inflector.pluralize(singular))
+ assert_equal(plural.capitalize, Inflector.pluralize(singular.capitalize))
+ end
+ end
+
+ SingularToPlural.each do |singular, plural|
+ define_method "test_singularize_#{plural}" do
+ assert_equal(singular, Inflector.singularize(plural))
+ assert_equal(singular.capitalize, Inflector.singularize(plural.capitalize))
+ end
+ end
+
+ MixtureToTitleCase.each do |before, titleized|
+ define_method "test_titleize_#{before}" do
+ assert_equal(titleized, Inflector.titleize(before))
+ end
+ end
+
+ def test_camelize
+ CamelToUnderscore.each do |camel, underscore|
+ assert_equal(camel, Inflector.camelize(underscore))
+ end
+ end
+
+ def test_underscore
+ CamelToUnderscore.each do |camel, underscore|
+ assert_equal(underscore, Inflector.underscore(camel))
+ end
+ CamelToUnderscoreWithoutReverse.each do |camel, underscore|
+ assert_equal(underscore, Inflector.underscore(camel))
+ end
+ end
+
+ def test_camelize_with_module
+ CamelWithModuleToUnderscoreWithSlash.each do |camel, underscore|
+ assert_equal(camel, Inflector.camelize(underscore))
+ end
+ end
+
+ def test_underscore_with_slashes
+ CamelWithModuleToUnderscoreWithSlash.each do |camel, underscore|
+ assert_equal(underscore, Inflector.underscore(camel))
+ end
+ end
+
+ def test_demodulize
+ assert_equal "Account", Inflector.demodulize("MyApplication::Billing::Account")
+ end
+
+ def test_foreign_key
+ ClassNameToForeignKeyWithUnderscore.each do |klass, foreign_key|
+ assert_equal(foreign_key, Inflector.foreign_key(klass))
+ end
+
+ ClassNameToForeignKeyWithoutUnderscore.each do |klass, foreign_key|
+ assert_equal(foreign_key, Inflector.foreign_key(klass, false))
+ end
+ end
+
+ def test_tableize
+ ClassNameToTableName.each do |class_name, table_name|
+ assert_equal(table_name, Inflector.tableize(class_name))
+ end
+ end
+
+ def test_classify
+ ClassNameToTableName.each do |class_name, table_name|
+ assert_equal(class_name, Inflector.classify(table_name))
+ assert_equal(class_name, Inflector.classify("table_prefix." + table_name))
+ end
+ end
+
+ def test_classify_with_symbol
+ assert_nothing_raised do
+ assert_equal 'FooBar', Inflector.classify(:foo_bars)
+ end
+ end
+
+ def test_classify_with_leading_schema_name
+ assert_equal 'FooBar', Inflector.classify('schema.foo_bar')
+ end
+
+ def test_humanize
+ UnderscoreToHuman.each do |underscore, human|
+ assert_equal(human, Inflector.humanize(underscore))
+ end
+ end
+
+ def test_constantize
+ assert_nothing_raised { assert_equal Ace::Base::Case, Inflector.constantize("Ace::Base::Case") }
+ assert_nothing_raised { assert_equal Ace::Base::Case, Inflector.constantize("::Ace::Base::Case") }
+ assert_nothing_raised { assert_equal InflectorTest, Inflector.constantize("InflectorTest") }
+ assert_nothing_raised { assert_equal InflectorTest, Inflector.constantize("::InflectorTest") }
+ assert_raises(NameError) { Inflector.constantize("UnknownClass") }
+ assert_raises(NameError) { Inflector.constantize("An invalid string") }
+ assert_raises(NameError) { Inflector.constantize("InvalidClass\n") }
+ end
+
+ if RUBY_VERSION < '1.9.0'
+ def test_constantize_does_lexical_lookup
+ assert_raises(NameError) { Inflector.constantize("Ace::Base::InflectorTest") }
+ end
+ else
+ def test_constantize_does_dynamic_lookup
+ assert_equal self.class, Inflector.constantize("Ace::Base::InflectorTest")
+ end
+ end
+
+ def test_ordinal
+ OrdinalNumbers.each do |number, ordinalized|
+ assert_equal(ordinalized, Inflector.ordinalize(number))
+ end
+ end
+
+ def test_dasherize
+ UnderscoresToDashes.each do |underscored, dasherized|
+ assert_equal(dasherized, Inflector.dasherize(underscored))
+ end
+ end
+
+ def test_underscore_as_reverse_of_dasherize
+ UnderscoresToDashes.each do |underscored, dasherized|
+ assert_equal(underscored, Inflector.underscore(Inflector.dasherize(underscored)))
+ end
+ end
+
+ def test_underscore_to_lower_camel
+ UnderscoreToLowerCamel.each do |underscored, lower_camel|
+ assert_equal(lower_camel, Inflector.camelize(underscored, false))
+ end
+ end
+
+ %w{plurals singulars uncountables}.each do |inflection_type|
+ class_eval "
+ def test_clear_#{inflection_type}
+ cached_values = Inflector.inflections.#{inflection_type}
+ Inflector.inflections.clear :#{inflection_type}
+ assert Inflector.inflections.#{inflection_type}.empty?, \"#{inflection_type} inflections should be empty after clear :#{inflection_type}\"
+ Inflector.inflections.instance_variable_set :@#{inflection_type}, cached_values
+ end
+ "
+ end
+
+ def test_clear_all
+ cached_values = Inflector.inflections.plurals, Inflector.inflections.singulars, Inflector.inflections.uncountables
+ Inflector.inflections.clear :all
+ assert Inflector.inflections.plurals.empty?
+ assert Inflector.inflections.singulars.empty?
+ assert Inflector.inflections.uncountables.empty?
+ Inflector.inflections.instance_variable_set :@plurals, cached_values[0]
+ Inflector.inflections.instance_variable_set :@singulars, cached_values[1]
+ Inflector.inflections.instance_variable_set :@uncountables, cached_values[2]
+ end
+
+ def test_clear_with_default
+ cached_values = Inflector.inflections.plurals, Inflector.inflections.singulars, Inflector.inflections.uncountables
+ Inflector.inflections.clear
+ assert Inflector.inflections.plurals.empty?
+ assert Inflector.inflections.singulars.empty?
+ assert Inflector.inflections.uncountables.empty?
+ Inflector.inflections.instance_variable_set :@plurals, cached_values[0]
+ Inflector.inflections.instance_variable_set :@singulars, cached_values[1]
+ Inflector.inflections.instance_variable_set :@uncountables, cached_values[2]
+ end
+
+ Irregularities.each do |irregularity|
+ singular, plural = *irregularity
+ Inflector.inflections do |inflect|
+ define_method("test_irregularity_between_#{singular}_and_#{plural}") do
+ inflect.irregular(singular, plural)
+ assert_equal singular, Inflector.singularize(plural)
+ assert_equal plural, Inflector.pluralize(singular)
+ end
+ end
+ end
+
+ [ :all, [] ].each do |scope|
+ Inflector.inflections do |inflect|
+ define_method("test_clear_inflections_with_#{scope.kind_of?(Array) ? "no_arguments" : scope}") do
+ # save all the inflections
+ singulars, plurals, uncountables = inflect.singulars, inflect.plurals, inflect.uncountables
+
+ # clear all the inflections
+ inflect.clear(*scope)
+
+ assert_equal [], inflect.singulars
+ assert_equal [], inflect.plurals
+ assert_equal [], inflect.uncountables
+
+ # restore all the inflections
+ singulars.reverse.each { |singular| inflect.singular(*singular) }
+ plurals.reverse.each { |plural| inflect.plural(*plural) }
+ inflect.uncountable(uncountables)
+
+ assert_equal singulars, inflect.singulars
+ assert_equal plurals, inflect.plurals
+ assert_equal uncountables, inflect.uncountables
+ end
+ end
+ end
+
+ { :singulars => :singular, :plurals => :plural, :uncountables => :uncountable }.each do |scope, method|
+ Inflector.inflections do |inflect|
+ define_method("test_clear_inflections_with_#{scope}") do
+ # save the inflections
+ values = inflect.send(scope)
+
+ # clear the inflections
+ inflect.clear(scope)
+
+ assert_equal [], inflect.send(scope)
+
+ # restore the inflections
+ if scope == :uncountables
+ inflect.send(method, values)
+ else
+ values.reverse.each { |value| inflect.send(method, *value) }
+ end
+
+ assert_equal values, inflect.send(scope)
+ end
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/inflector_test_cases.rb b/vendor/rails-2.0.2/activesupport/test/inflector_test_cases.rb
new file mode 100644
index 000000000..83fd4c8e5
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/inflector_test_cases.rb
@@ -0,0 +1,208 @@
+module InflectorTestCases
+ SingularToPlural = {
+ "search" => "searches",
+ "switch" => "switches",
+ "fix" => "fixes",
+ "box" => "boxes",
+ "process" => "processes",
+ "address" => "addresses",
+ "case" => "cases",
+ "stack" => "stacks",
+ "wish" => "wishes",
+ "fish" => "fish",
+
+ "category" => "categories",
+ "query" => "queries",
+ "ability" => "abilities",
+ "agency" => "agencies",
+ "movie" => "movies",
+
+ "archive" => "archives",
+
+ "index" => "indices",
+
+ "wife" => "wives",
+ "safe" => "saves",
+ "half" => "halves",
+
+ "move" => "moves",
+
+ "salesperson" => "salespeople",
+ "person" => "people",
+
+ "spokesman" => "spokesmen",
+ "man" => "men",
+ "woman" => "women",
+
+ "basis" => "bases",
+ "diagnosis" => "diagnoses",
+ "diagnosis_a" => "diagnosis_as",
+
+ "datum" => "data",
+ "medium" => "media",
+ "analysis" => "analyses",
+
+ "node_child" => "node_children",
+ "child" => "children",
+
+ "experience" => "experiences",
+ "day" => "days",
+
+ "comment" => "comments",
+ "foobar" => "foobars",
+ "newsletter" => "newsletters",
+
+ "old_news" => "old_news",
+ "news" => "news",
+
+ "series" => "series",
+ "species" => "species",
+
+ "quiz" => "quizzes",
+
+ "perspective" => "perspectives",
+
+ "ox" => "oxen",
+ "photo" => "photos",
+ "buffalo" => "buffaloes",
+ "tomato" => "tomatoes",
+ "dwarf" => "dwarves",
+ "elf" => "elves",
+ "information" => "information",
+ "equipment" => "equipment",
+ "bus" => "buses",
+ "status" => "statuses",
+ "status_code" => "status_codes",
+ "mouse" => "mice",
+
+ "louse" => "lice",
+ "house" => "houses",
+ "octopus" => "octopi",
+ "virus" => "viri",
+ "alias" => "aliases",
+ "portfolio" => "portfolios",
+
+ "vertex" => "vertices",
+ "matrix" => "matrices",
+ "matrix_fu" => "matrix_fus",
+
+ "axis" => "axes",
+ "testis" => "testes",
+ "crisis" => "crises",
+
+ "rice" => "rice",
+ "shoe" => "shoes",
+
+ "horse" => "horses",
+ "prize" => "prizes",
+ "edge" => "edges",
+
+ "cow" => "kine"
+ }
+
+ CamelToUnderscore = {
+ "Product" => "product",
+ "SpecialGuest" => "special_guest",
+ "ApplicationController" => "application_controller",
+ "Area51Controller" => "area51_controller"
+ }
+
+ UnderscoreToLowerCamel = {
+ "product" => "product",
+ "special_guest" => "specialGuest",
+ "application_controller" => "applicationController",
+ "area51_controller" => "area51Controller"
+ }
+
+ CamelToUnderscoreWithoutReverse = {
+ "HTMLTidy" => "html_tidy",
+ "HTMLTidyGenerator" => "html_tidy_generator",
+ "FreeBSD" => "free_bsd",
+ "HTML" => "html",
+ }
+
+ CamelWithModuleToUnderscoreWithSlash = {
+ "Admin::Product" => "admin/product",
+ "Users::Commission::Department" => "users/commission/department",
+ "UsersSection::CommissionDepartment" => "users_section/commission_department",
+ }
+
+ ClassNameToForeignKeyWithUnderscore = {
+ "Person" => "person_id",
+ "MyApplication::Billing::Account" => "account_id"
+ }
+
+ ClassNameToForeignKeyWithoutUnderscore = {
+ "Person" => "personid",
+ "MyApplication::Billing::Account" => "accountid"
+ }
+
+ ClassNameToTableName = {
+ "PrimarySpokesman" => "primary_spokesmen",
+ "NodeChild" => "node_children"
+ }
+
+ UnderscoreToHuman = {
+ "employee_salary" => "Employee salary",
+ "employee_id" => "Employee",
+ "underground" => "Underground"
+ }
+
+ MixtureToTitleCase = {
+ 'active_record' => 'Active Record',
+ 'ActiveRecord' => 'Active Record',
+ 'action web service' => 'Action Web Service',
+ 'Action Web Service' => 'Action Web Service',
+ 'Action web service' => 'Action Web Service',
+ 'actionwebservice' => 'Actionwebservice',
+ 'Actionwebservice' => 'Actionwebservice'
+ }
+
+ OrdinalNumbers = {
+ "0" => "0th",
+ "1" => "1st",
+ "2" => "2nd",
+ "3" => "3rd",
+ "4" => "4th",
+ "5" => "5th",
+ "6" => "6th",
+ "7" => "7th",
+ "8" => "8th",
+ "9" => "9th",
+ "10" => "10th",
+ "11" => "11th",
+ "12" => "12th",
+ "13" => "13th",
+ "14" => "14th",
+ "20" => "20th",
+ "21" => "21st",
+ "22" => "22nd",
+ "23" => "23rd",
+ "24" => "24th",
+ "100" => "100th",
+ "101" => "101st",
+ "102" => "102nd",
+ "103" => "103rd",
+ "104" => "104th",
+ "110" => "110th",
+ "111" => "111th",
+ "112" => "112th",
+ "113" => "113th",
+ "1000" => "1000th",
+ "1001" => "1001st"
+ }
+
+ UnderscoresToDashes = {
+ "street" => "street",
+ "street_address" => "street-address",
+ "person_street_address" => "person-street-address"
+ }
+
+ Irregularities = {
+ 'person' => 'people',
+ 'man' => 'men',
+ 'child' => 'children',
+ 'sex' => 'sexes',
+ 'move' => 'moves',
+ }
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/json/decoding_test.rb b/vendor/rails-2.0.2/activesupport/test/json/decoding_test.rb
new file mode 100644
index 000000000..93560fb5a
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/json/decoding_test.rb
@@ -0,0 +1,41 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class TestJSONDecoding < Test::Unit::TestCase
+ TESTS = {
+ %q({"returnTo":{"\/categories":"\/"}}) => {"returnTo" => {"/categories" => "/"}},
+ %q({returnTo:{"\/categories":"\/"}}) => {"returnTo" => {"/categories" => "/"}},
+ %q({"return\\"To\\":":{"\/categories":"\/"}}) => {"return\"To\":" => {"/categories" => "/"}},
+ %q({"returnTo":{"\/categories":1}}) => {"returnTo" => {"/categories" => 1}},
+ %({"returnTo":[1,"a"]}) => {"returnTo" => [1, "a"]},
+ %({"returnTo":[1,"\\"a\\",", "b"]}) => {"returnTo" => [1, "\"a\",", "b"]},
+ %({a: "'", "b": "5,000"}) => {"a" => "'", "b" => "5,000"},
+ %({a: "a's, b's and c's", "b": "5,000"}) => {"a" => "a's, b's and c's", "b" => "5,000"},
+ %({a: "2007-01-01"}) => {'a' => Date.new(2007, 1, 1)},
+ %({a: "2007-01-01 01:12:34 Z"}) => {'a' => Time.utc(2007, 1, 1, 1, 12, 34)},
+ # no time zone
+ %({a: "2007-01-01 01:12:34"}) => {'a' => "2007-01-01 01:12:34"},
+ # needs to be *exact*
+ %({a: " 2007-01-01 01:12:34 Z "}) => {'a' => " 2007-01-01 01:12:34 Z "},
+ %([]) => [],
+ %({}) => {},
+ %(1) => 1,
+ %("") => "",
+ %("\\"") => "\"",
+ %(null) => nil,
+ %(true) => true,
+ %(false) => false,
+ %q("http:\/\/test.host\/posts\/1") => "http://test.host/posts/1"
+ }
+
+ TESTS.each do |json, expected|
+ define_method :"test_json_decoding_#{json}" do
+ assert_nothing_raised do
+ assert_equal expected, ActiveSupport::JSON.decode(json)
+ end
+ end
+ end
+
+ def test_failed_json_decoding
+ assert_raises(ActiveSupport::JSON::ParseError) { ActiveSupport::JSON.decode(%({: 1})) }
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/json/encoding_test.rb b/vendor/rails-2.0.2/activesupport/test/json/encoding_test.rb
new file mode 100644
index 000000000..4e4fe5703
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/json/encoding_test.rb
@@ -0,0 +1,111 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class TestJSONEncoding < Test::Unit::TestCase
+ class Foo
+ def initialize(a, b)
+ @a, @b = a, b
+ end
+ end
+
+ TrueTests = [[ true, %(true) ]]
+ FalseTests = [[ false, %(false) ]]
+ NilTests = [[ nil, %(null) ]]
+ NumericTests = [[ 1, %(1) ],
+ [ 2.5, %(2.5) ]]
+
+ StringTests = [[ 'this is the <string>', %("this is the \\u003Cstring\\u003E")],
+ [ 'a "string" with quotes & an ampersand', %("a \\"string\\" with quotes \\u0026 an ampersand") ],
+ [ 'http://test.host/posts/1', %("http://test.host/posts/1")]]
+
+ ArrayTests = [[ ['a', 'b', 'c'], %([\"a\", \"b\", \"c\"]) ],
+ [ [1, 'a', :b, nil, false], %([1, \"a\", \"b\", null, false]) ]]
+
+ SymbolTests = [[ :a, %("a") ],
+ [ :this, %("this") ],
+ [ :"a b", %("a b") ]]
+
+ ObjectTests = [[ Foo.new(1, 2), %({\"a\": 1, \"b\": 2}) ]]
+
+ VariableTests = [[ ActiveSupport::JSON::Variable.new('foo'), 'foo'],
+ [ ActiveSupport::JSON::Variable.new('alert("foo")'), 'alert("foo")']]
+ RegexpTests = [[ /^a/, '/^a/' ], [/^\w{1,2}[a-z]+/ix, '/^\\w{1,2}[a-z]+/ix']]
+
+ DateTests = [[ Date.new(2005,2,1), %("2005/02/01") ]]
+ TimeTests = [[ Time.utc(2005,2,1,15,15,10), %("2005/02/01 15:15:10 +0000") ]]
+ DateTimeTests = [[ DateTime.civil(2005,2,1,15,15,10), %("2005/02/01 15:15:10 +0000") ]]
+
+ constants.grep(/Tests$/).each do |class_tests|
+ define_method("test_#{class_tests[0..-6].downcase}") do
+ self.class.const_get(class_tests).each do |pair|
+ assert_equal pair.last, pair.first.to_json
+ end
+ end
+ end
+
+ def test_hash_encoding
+ assert_equal %({\"a\": \"b\"}), { :a => :b }.to_json
+ assert_equal %({\"a\": 1}), { 'a' => 1 }.to_json
+ assert_equal %({\"a\": [1, 2]}), { 'a' => [1,2] }.to_json
+ assert_equal %({1: 2}), { 1 => 2 }.to_json
+
+ sorted_json = '{' + {:a => :b, :c => :d}.to_json[1..-2].split(', ').sort.join(', ') + '}'
+ assert_equal %({\"a\": \"b\", \"c\": \"d\"}), sorted_json
+ end
+
+ def test_utf8_string_encoded_properly_when_kcode_is_utf8
+ with_kcode 'UTF8' do
+ assert_equal '"\\u20ac2.99"', '€2.99'.to_json
+ assert_equal '"\\u270e\\u263a"', '✎☺'.to_json
+ end
+ end
+
+ def test_exception_raised_when_encoding_circular_reference
+ a = [1]
+ a << a
+ assert_raises(ActiveSupport::JSON::CircularReferenceError) { a.to_json }
+ end
+
+ def test_hash_key_identifiers_are_always_quoted
+ values = {0 => 0, 1 => 1, :_ => :_, "$" => "$", "a" => "a", :A => :A, :A0 => :A0, "A0B" => "A0B"}
+ assert_equal %w( "$" "A" "A0" "A0B" "_" "a" 0 1 ), object_keys(values.to_json)
+ end
+
+ def test_hash_should_allow_key_filtering_with_only
+ assert_equal %({"a": 1}), { 'a' => 1, :b => 2, :c => 3 }.to_json(:only => 'a')
+ end
+
+ def test_hash_should_allow_key_filtering_with_except
+ assert_equal %({"b": 2}), { 'foo' => 'bar', :b => 2, :c => 3 }.to_json(:except => ['foo', :c])
+ end
+
+ protected
+ def with_kcode(code)
+ if RUBY_VERSION < '1.9'
+ begin
+ old_kcode, $KCODE = $KCODE, 'UTF8'
+ yield
+ ensure
+ $KCODE = old_kcode
+ end
+ else
+ yield
+ end
+ end
+
+ def object_keys(json_object)
+ json_object[1..-2].scan(/([^{}:,\s]+):/).flatten.sort
+ end
+end
+
+uses_mocha 'JsonOptionsTests' do
+ class JsonOptionsTests < Test::Unit::TestCase
+ def test_enumerable_should_passthrough_options_to_elements
+ json_options = { :include => :posts }
+ ActiveSupport::JSON.expects(:encode).with(1, json_options)
+ ActiveSupport::JSON.expects(:encode).with(2, json_options)
+ ActiveSupport::JSON.expects(:encode).with('foo', json_options)
+
+ [1, 2, 'foo'].to_json(json_options)
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/multibyte_chars_test.rb b/vendor/rails-2.0.2/activesupport/test/multibyte_chars_test.rb
new file mode 100644
index 000000000..6e87ea885
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/multibyte_chars_test.rb
@@ -0,0 +1,173 @@
+require File.dirname(__FILE__) + '/abstract_unit'
+
+$KCODE = 'UTF8'
+
+class CharsTest < Test::Unit::TestCase
+
+ def setup
+ @s = {
+ :utf8 => "Abcd Блå ffi блa 埋",
+ :ascii => "asci ias c iia s",
+ :bytes => "\270\236\010\210\245"
+ }
+ end
+
+ def test_sanity
+ @s.each do |t, s|
+ assert s.respond_to?(:chars), "All string should have the chars method (#{t})"
+ assert s.respond_to?(:to_s), "All string should have the to_s method (#{t})"
+ assert_kind_of ActiveSupport::Multibyte::Chars, s.chars, "#chars should return an instance of Chars (#{t})"
+ end
+ end
+
+ def test_comparability
+ @s.each do |t, s|
+ assert_equal s, s.chars.to_s, "Chars#to_s should return enclosed string unchanged"
+ end
+ assert_nothing_raised do
+ assert_equal "a", "a", "Normal string comparisons should be unaffected"
+ assert_not_equal "a", "b", "Normal string comparisons should be unaffected"
+ assert_not_equal "a".chars, "b".chars, "Chars objects should be comparable"
+ assert_equal "a".chars, "A".downcase.chars, "Chars objects should be comparable to each other"
+ assert_equal "a".chars, "A".downcase, "Chars objects should be comparable to strings coming from elsewhere"
+ end
+
+ assert !@s[:utf8].eql?(@s[:utf8].chars), "Strict comparison is not supported"
+ assert_equal @s[:utf8], @s[:utf8].chars, "Chars should be compared by their enclosed string"
+
+ other_string = @s[:utf8].dup
+ assert_equal other_string, @s[:utf8].chars, "Chars should be compared by their enclosed string"
+ assert_equal other_string.chars, @s[:utf8].chars, "Chars should be compared by their enclosed string"
+
+ strings = ['builder'.chars, 'armor'.chars, 'zebra'.chars]
+ strings.sort!
+ assert_equal ['armor', 'builder', 'zebra'], strings, "Chars should be sortable based on their enclosed string"
+
+ # This leads to a StackLevelTooDeep exception if the comparison is not wired properly
+ assert_raise(NameError) do
+ Chars
+ end
+ end
+
+ def test_utf8?
+ assert @s[:utf8].is_utf8?, "UTF-8 strings are UTF-8"
+ assert @s[:ascii].is_utf8?, "All ASCII strings are also valid UTF-8"
+ assert !@s[:bytes].is_utf8?, "This bytestring isn't UTF-8"
+ end
+
+ # The test for the following methods are defined here because they can only be defined on the Chars class for
+ # various reasons
+
+ def test_gsub
+ assert_equal 'éxa', 'éda'.chars.gsub(/d/, 'x')
+ with_kcode('none') do
+ assert_equal 'éxa', 'éda'.chars.gsub(/d/, 'x')
+ end
+ end
+
+ def test_split
+ word = "efficient"
+ chars = ["e", "ffi", "c", "i", "e", "n", "t"]
+ assert_equal chars, word.split(//)
+ assert_equal chars, word.chars.split(//)
+ assert_kind_of ActiveSupport::Multibyte::Chars, word.chars.split(//).first, "Split should return Chars instances"
+ end
+
+ def test_regexp
+ with_kcode('none') do
+ assert_equal 12, (@s[:utf8].chars =~ /ffi/),
+ "Regex matching should be bypassed to String"
+ end
+ with_kcode('UTF8') do
+ assert_equal 9, (@s[:utf8].chars =~ /ffi/),
+ "Regex matching should be unicode aware"
+ assert_nil((''.chars =~ /\d+/),
+ "Non-matching regular expressions should return nil")
+ end
+ end
+
+ def test_pragma
+ with_kcode('UTF8') do
+ assert " ".chars.send(:utf8_pragma?), "UTF8 pragma should be on because KCODE is UTF8"
+ end
+ with_kcode('none') do
+ assert !" ".chars.send(:utf8_pragma?), "UTF8 pragma should be off"
+ end
+ end
+
+ def test_handler_setting
+ handler = ''.chars.handler
+
+ ActiveSupport::Multibyte::Chars.handler = :first
+ assert_equal :first, ''.chars.handler
+ ActiveSupport::Multibyte::Chars.handler = :second
+ assert_equal :second, ''.chars.handler
+ assert_raise(NoMethodError) do
+ ''.chars.handler.split
+ end
+
+ ActiveSupport::Multibyte::Chars.handler = handler
+ end
+
+ def test_method_chaining
+ assert_kind_of ActiveSupport::Multibyte::Chars, ''.chars.downcase
+ assert_kind_of ActiveSupport::Multibyte::Chars, ''.chars.strip, "Strip should return a Chars object"
+ assert_kind_of ActiveSupport::Multibyte::Chars, ''.chars.downcase.strip, "The Chars object should be " +
+ "forwarded down the call path for chaining"
+ assert_equal 'foo', " FOO ".chars.normalize.downcase.strip, "The Chars that results from the " +
+ " operations should be comparable to the string value of the result"
+ end
+
+ def test_passthrough_on_kcode
+ # The easiest way to check if the passthrough is in place is through #size
+ with_kcode('none') do
+ assert_equal 26, @s[:utf8].chars.size
+ end
+ with_kcode('UTF8') do
+ assert_equal 17, @s[:utf8].chars.size
+ end
+ end
+
+ def test_destructiveness
+ # Note that we're testing the destructiveness here and not the correct behaviour of the methods
+ str = 'ac'
+ str.chars.insert(1, 'b')
+ assert_equal 'abc', str, 'Insert should be destructive for a string'
+
+ str = 'ac'
+ str.chars.reverse!
+ assert_equal 'ca', str, 'reverse! should be destructive for a string'
+ end
+
+ def test_resilience
+ assert_nothing_raised do
+ assert_equal 5, @s[:bytes].chars.size, "The sequence contains five interpretable bytes"
+ end
+ reversed = [0xb8, 0x17e, 0x8, 0x2c6, 0xa5].reverse.pack('U*')
+ assert_nothing_raised do
+ assert_equal reversed, @s[:bytes].chars.reverse.to_s, "Reversing the string should only yield interpretable bytes"
+ end
+ assert_nothing_raised do
+ @s[:bytes].chars.reverse!
+ assert_equal reversed, @s[:bytes].to_s, "Reversing the string should only yield interpretable bytes"
+ end
+ end
+
+ def test_duck_typing
+ assert_equal true, 'test'.chars.respond_to?(:strip)
+ assert_equal true, 'test'.chars.respond_to?(:normalize)
+ assert_equal true, 'test'.chars.respond_to?(:normalize!)
+ assert_equal false, 'test'.chars.respond_to?(:a_method_that_doesnt_exist)
+ end
+
+ protected
+
+ def with_kcode(kcode)
+ old_kcode, $KCODE = $KCODE, kcode
+ begin
+ yield
+ ensure
+ $KCODE = old_kcode
+ end
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/multibyte_conformance.rb b/vendor/rails-2.0.2/activesupport/test/multibyte_conformance.rb
new file mode 100644
index 000000000..dede3e561
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/multibyte_conformance.rb
@@ -0,0 +1,141 @@
+require File.dirname(__FILE__) + '/abstract_unit'
+require 'open-uri'
+
+$KCODE = 'UTF8'
+UNIDATA_URL = "http://www.unicode.org/Public/#{ActiveSupport::Multibyte::UNICODE_VERSION}/ucd"
+UNIDATA_FILE = '/NormalizationTest.txt'
+CACHE_DIR = File.dirname(__FILE__) + '/cache'
+
+class Downloader
+ def self.download(from, to)
+ unless File.exist?(to)
+ $stderr.puts "Downloading #{from} to #{to}"
+ unless File.exist?(File.dirname(to))
+ system "mkdir -p #{File.dirname(to)}"
+ end
+ open(from) do |source|
+ File.open(to, 'w') do |target|
+ source.each_line do |l|
+ target.write l
+ end
+ end
+ end
+ end
+ end
+end
+
+class String
+ # Unicode Inspect returns the codepoints of the string in hex
+ def ui
+ "#{self} " + ("[%s]" % unpack("U*").map{|cp| cp.to_s(16) }.join(' '))
+ end unless ''.respond_to?(:ui)
+end
+
+Dir.mkdir(CACHE_DIR) unless File.exist?(CACHE_DIR)
+Downloader.download(UNIDATA_URL + UNIDATA_FILE, CACHE_DIR + UNIDATA_FILE)
+
+module ConformanceTest
+ def test_normalizations_C
+ each_line_of_norm_tests do |*cols|
+ col1, col2, col3, col4, col5, comment = *cols
+
+ # CONFORMANCE:
+ # 1. The following invariants must be true for all conformant implementations
+ #
+ # NFC
+ # c2 == NFC(c1) == NFC(c2) == NFC(c3)
+ assert_equal col2.ui, @handler.normalize(col1, :c).ui, "Form C - Col 2 has to be NFC(1) - #{comment}"
+ assert_equal col2.ui, @handler.normalize(col2, :c).ui, "Form C - Col 2 has to be NFC(2) - #{comment}"
+ assert_equal col2.ui, @handler.normalize(col3, :c).ui, "Form C - Col 2 has to be NFC(3) - #{comment}"
+ #
+ # c4 == NFC(c4) == NFC(c5)
+ assert_equal col4.ui, @handler.normalize(col4, :c).ui, "Form C - Col 4 has to be C(4) - #{comment}"
+ assert_equal col4.ui, @handler.normalize(col5, :c).ui, "Form C - Col 4 has to be C(5) - #{comment}"
+ end
+ end
+
+ def test_normalizations_D
+ each_line_of_norm_tests do |*cols|
+ col1, col2, col3, col4, col5, comment = *cols
+ #
+ # NFD
+ # c3 == NFD(c1) == NFD(c2) == NFD(c3)
+ assert_equal col3.ui, @handler.normalize(col1, :d).ui, "Form D - Col 3 has to be NFD(1) - #{comment}"
+ assert_equal col3.ui, @handler.normalize(col2, :d).ui, "Form D - Col 3 has to be NFD(2) - #{comment}"
+ assert_equal col3.ui, @handler.normalize(col3, :d).ui, "Form D - Col 3 has to be NFD(3) - #{comment}"
+ # c5 == NFD(c4) == NFD(c5)
+ assert_equal col5.ui, @handler.normalize(col4, :d).ui, "Form D - Col 5 has to be NFD(4) - #{comment}"
+ assert_equal col5.ui, @handler.normalize(col5, :d).ui, "Form D - Col 5 has to be NFD(5) - #{comment}"
+ end
+ end
+
+ def test_normalizations_KC
+ each_line_of_norm_tests do | *cols |
+ col1, col2, col3, col4, col5, comment = *cols
+ #
+ # NFKC
+ # c4 == NFKC(c1) == NFKC(c2) == NFKC(c3) == NFKC(c4) == NFKC(c5)
+ assert_equal col4.ui, @handler.normalize(col1, :kc).ui, "Form D - Col 4 has to be NFKC(1) - #{comment}"
+ assert_equal col4.ui, @handler.normalize(col2, :kc).ui, "Form D - Col 4 has to be NFKC(2) - #{comment}"
+ assert_equal col4.ui, @handler.normalize(col3, :kc).ui, "Form D - Col 4 has to be NFKC(3) - #{comment}"
+ assert_equal col4.ui, @handler.normalize(col4, :kc).ui, "Form D - Col 4 has to be NFKC(4) - #{comment}"
+ assert_equal col4.ui, @handler.normalize(col5, :kc).ui, "Form D - Col 4 has to be NFKC(5) - #{comment}"
+ end
+ end
+
+ def test_normalizations_KD
+ each_line_of_norm_tests do | *cols |
+ col1, col2, col3, col4, col5, comment = *cols
+ #
+ # NFKD
+ # c5 == NFKD(c1) == NFKD(c2) == NFKD(c3) == NFKD(c4) == NFKD(c5)
+ assert_equal col5.ui, @handler.normalize(col1, :kd).ui, "Form KD - Col 5 has to be NFKD(1) - #{comment}"
+ assert_equal col5.ui, @handler.normalize(col2, :kd).ui, "Form KD - Col 5 has to be NFKD(2) - #{comment}"
+ assert_equal col5.ui, @handler.normalize(col3, :kd).ui, "Form KD - Col 5 has to be NFKD(3) - #{comment}"
+ assert_equal col5.ui, @handler.normalize(col4, :kd).ui, "Form KD - Col 5 has to be NFKD(4) - #{comment}"
+ assert_equal col5.ui, @handler.normalize(col5, :kd).ui, "Form KD - Col 5 has to be NFKD(5) - #{comment}"
+ end
+ end
+
+ protected
+ def each_line_of_norm_tests(&block)
+ lines = 0
+ max_test_lines = 0 # Don't limit below 38, because that's the header of the testfile
+ File.open(File.dirname(__FILE__) + '/cache' + UNIDATA_FILE, 'r') do | f |
+ until f.eof? || (max_test_lines > 38 and lines > max_test_lines)
+ lines += 1
+ line = f.gets.chomp!
+ next if (line.empty? || line =~ /^\#/)
+
+ cols, comment = line.split("#")
+ cols = cols.split(";").map{|e| e.strip}.reject{|e| e.empty? }
+ next unless cols.length == 5
+
+ # codepoints are in hex in the test suite, pack wants them as integers
+ cols.map!{|c| c.split.map{|codepoint| codepoint.to_i(16)}.pack("U*") }
+ cols << comment
+
+ yield(*cols)
+ end
+ end
+ end
+end
+
+begin
+ require_library_or_gem('utf8proc_native')
+ require 'active_record/multibyte/handlers/utf8_handler_proc'
+ class ConformanceTestProc < Test::Unit::TestCase
+ include ConformanceTest
+ def setup
+ @handler = ::ActiveSupport::Multibyte::Handlers::UTF8HandlerProc
+ end
+ end
+rescue LoadError
+end
+
+class ConformanceTestPure < Test::Unit::TestCase
+ include ConformanceTest
+ def setup
+ @handler = ::ActiveSupport::Multibyte::Handlers::UTF8Handler
+ end
+end \ No newline at end of file
diff --git a/vendor/rails-2.0.2/activesupport/test/multibyte_handler_test.rb b/vendor/rails-2.0.2/activesupport/test/multibyte_handler_test.rb
new file mode 100644
index 000000000..3384a1a0d
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/multibyte_handler_test.rb
@@ -0,0 +1,367 @@
+require File.dirname(__FILE__) + '/abstract_unit'
+
+$KCODE = 'UTF8'
+
+class String
+ # Unicode Inspect returns the codepoints of the string in hex
+ def ui
+ "#{self} " + ("[%s]" % unpack("U*").map{|cp| cp.to_s(16) }.join(' '))
+ end unless ''.respond_to?(:ui)
+end
+
+module UTF8HandlingTest
+
+ def common_setup
+ # This is an ASCII string with some russian strings and a ligature. It's nicely calibrated, because
+ # slicing it at some specific bytes will kill your characters if you use standard Ruby routines.
+ # It has both capital and standard letters, so that we can test case conversions easily.
+ # It has 26 characters and 28 when the ligature gets split during normalization.
+ @string = "Abcd Блå ffi бла бла бла бла"
+ @string_kd = "Abcd Блå ffi бла бла бла бла"
+ @string_kc = "Abcd Блå ffi бла бла бла бла"
+ @string_c = "Abcd Блå ffi бла бла бла бла"
+ @string_d = "Abcd Блå ffi бла бла бла бла"
+ @bytestring = "\270\236\010\210\245" # Not UTF-8
+
+ # Characters from the character classes as described in UAX #29
+ @character_from_class = {
+ :l => 0x1100, :v => 0x1160, :t => 0x11A8, :lv => 0xAC00, :lvt => 0xAC01, :cr => 0x000D, :lf => 0x000A,
+ :extend => 0x094D, :n => 0x64
+ }
+ end
+
+ def test_utf8_recognition
+ assert ActiveSupport::Multibyte::Handlers::UTF8Handler.consumes?(@string),
+ "Should recognize as a valid UTF-8 string"
+ assert !ActiveSupport::Multibyte::Handlers::UTF8Handler.consumes?(@bytestring), "This is bytestring, not UTF-8"
+ end
+
+ def test_simple_normalization
+ # Normalization of DEVANAGARI LETTER QA breaks when composition exclusion isn't used correctly
+ assert_equal [0x915, 0x93c].pack('U*').ui, [0x915, 0x93c].pack('U*').chars.normalize(:c).to_s.ui
+
+ null_byte_str = "Test\0test"
+
+ assert_equal '', @handler.normalize(''), "Empty string should not break things"
+ assert_equal null_byte_str.ui, @handler.normalize(null_byte_str, :kc).ui, "Null byte should remain"
+ assert_equal null_byte_str.ui, @handler.normalize(null_byte_str, :c).ui, "Null byte should remain"
+ assert_equal null_byte_str.ui, @handler.normalize(null_byte_str, :d).ui, "Null byte should remain"
+ assert_equal null_byte_str.ui, @handler.normalize(null_byte_str, :kd).ui, "Null byte should remain"
+ assert_equal null_byte_str.ui, @handler.decompose(null_byte_str).ui, "Null byte should remain"
+ assert_equal null_byte_str.ui, @handler.compose(null_byte_str).ui, "Null byte should remain"
+
+ comp_str = [
+ 44, # LATIN CAPITAL LETTER D
+ 307, # COMBINING DOT ABOVE
+ 328, # COMBINING OGONEK
+ 323 # COMBINING DOT BELOW
+ ].pack("U*")
+ norm_str_KC = [44,105,106,328,323].pack("U*")
+ norm_str_C = [44,307,328,323].pack("U*")
+ norm_str_D = [44,307,110,780,78,769].pack("U*")
+ norm_str_KD = [44,105,106,110,780,78,769].pack("U*")
+
+ assert_equal norm_str_KC.ui, @handler.normalize(comp_str, :kc).ui, "Should normalize KC"
+ assert_equal norm_str_C.ui, @handler.normalize(comp_str, :c).ui, "Should normalize C"
+ assert_equal norm_str_D.ui, @handler.normalize(comp_str, :d).ui, "Should normalize D"
+ assert_equal norm_str_KD.ui, @handler.normalize(comp_str, :kd).ui, "Should normalize KD"
+
+ assert_raise(ActiveSupport::Multibyte::Handlers::EncodingError) { @handler.normalize(@bytestring) }
+ end
+
+ # Test for the Public Review Issue #29, bad explanation of composition might lead to a
+ # bad implementation: http://www.unicode.org/review/pr-29.html
+ def test_normalization_C_pri_29
+ [
+ [0x0B47, 0x0300, 0x0B3E],
+ [0x1100, 0x0300, 0x1161]
+ ].map { |c| c.pack('U*') }.each do |c|
+ assert_equal c.ui, @handler.normalize(c, :c).ui, "Composition is implemented incorrectly"
+ end
+ end
+
+ def test_casefolding
+ simple_str = "abCdef"
+ simple_str_upcase = "ABCDEF"
+ simple_str_downcase = "abcdef"
+
+ assert_equal '', @handler.downcase(@handler.upcase('')), "Empty string should not break things"
+ assert_equal simple_str_upcase, @handler.upcase(simple_str), "should upcase properly"
+ assert_equal simple_str_downcase, @handler.downcase(simple_str), "should downcase properly"
+ assert_equal simple_str_downcase, @handler.downcase(@handler.upcase(simple_str_downcase)), "upcase and downcase should be mirrors"
+
+ rus_str = "аБвгд\0f"
+ rus_str_upcase = "АБВГД\0F"
+ rus_str_downcase = "абвгд\0f"
+ assert_equal rus_str_upcase, @handler.upcase(rus_str), "should upcase properly honoring null-byte"
+ assert_equal rus_str_downcase, @handler.downcase(rus_str), "should downcase properly honoring null-byte"
+
+ jap_str = "の埋め込み化対応はほぼ完成"
+ assert_equal jap_str, @handler.upcase(jap_str), "Japanse has no upcase, should remain unchanged"
+ assert_equal jap_str, @handler.downcase(jap_str), "Japanse has no downcase, should remain unchanged"
+
+ assert_raise(ActiveSupport::Multibyte::Handlers::EncodingError) { @handler.upcase(@bytestring) }
+ end
+
+ def test_capitalize
+ { 'аБвг аБвг' => 'Абвг абвг',
+ 'аБвг АБВГ' => 'Абвг абвг',
+ 'АБВГ АБВГ' => 'Абвг абвг',
+ '' => '' }.each do |f,t|
+ assert_equal t, @handler.capitalize(f), "Capitalize should work as expected"
+ end
+ assert_raise(ActiveSupport::Multibyte::Handlers::EncodingError) { @handler.capitalize(@bytestring) }
+ end
+
+ def test_translate_offset
+ str = "Блaå" # [2, 2, 1, 2] bytes
+ assert_equal 0, @handler.translate_offset('', 0), "Offset for an empty string makes no sense, return 0"
+ assert_equal 0, @handler.translate_offset(str, 0), "First character, first byte"
+ assert_equal 0, @handler.translate_offset(str, 1), "First character, second byte"
+ assert_equal 1, @handler.translate_offset(str, 2), "Second character, third byte"
+ assert_equal 1, @handler.translate_offset(str, 3), "Second character, fourth byte"
+ assert_equal 2, @handler.translate_offset(str, 4), "Third character, fifth byte"
+ assert_equal 3, @handler.translate_offset(str, 5), "Fourth character, sixth byte"
+ assert_equal 3, @handler.translate_offset(str, 6), "Fourth character, seventh byte"
+ assert_raise(ActiveSupport::Multibyte::Handlers::EncodingError) { @handler.translate_offset(@bytestring, 3) }
+ end
+
+ def test_insert
+ assert_equal '', @handler.insert('', 0, ''), "Empty string should not break things"
+ assert_equal "Abcd Блå ffiБУМ бла бла бла бла", @handler.insert(@string, 10, "БУМ"),
+ "Text should be inserted at right codepoints"
+ assert_equal "Abcd Блå ffiБУМ бла бла бла бла", @string, "Insert should be destructive"
+ assert_raise(ActiveSupport::Multibyte::Handlers::EncodingError) do
+ @handler.insert(@bytestring, 2, "\210")
+ end
+ end
+
+ def test_reverse
+ str = "wБлåa \n"
+ rev = "\n aåлБw"
+ assert_equal '', @handler.reverse(''), "Empty string shouldn't change"
+ assert_equal rev.ui, @handler.reverse(str).ui, "Should reverse properly"
+ assert_raise(ActiveSupport::Multibyte::Handlers::EncodingError) { @handler.reverse(@bytestring) }
+ end
+
+ def test_size
+ assert_equal 0, @handler.size(''), "Empty string has size 0"
+ assert_equal 26, @handler.size(@string), "String length should be 26"
+ assert_equal 26, @handler.length(@string), "String length method should be properly aliased"
+ assert_raise(ActiveSupport::Multibyte::Handlers::EncodingError) { @handler.size(@bytestring) }
+ end
+
+ def test_slice
+ assert_equal 0x41, @handler.slice(@string, 0), "Singular characters should return codepoints"
+ assert_equal 0xE5, @handler.slice(@string, 7), "Singular characters should return codepoints"
+ assert_equal nil, @handler.slice('', -1..1), "Broken range should return nil"
+ assert_equal '', @handler.slice('', 0..10), "Empty string should not break things"
+ assert_equal "d Блå ffi", @handler.slice(@string, 3..9), "Unicode characters have to be returned"
+ assert_equal "d Блå ffi", @handler.slice(@string, 3, 7), "Unicode characters have to be returned"
+ assert_equal "A", @handler.slice(@string, 0, 1), "Slicing from an offset should return characters"
+ assert_equal " Блå ffi ", @handler.slice(@string, 4..10), "Unicode characters have to be returned"
+ assert_equal "ffi бла", @handler.slice(@string, /ffi бла/u), "Slicing on Regexps should be supported"
+ assert_equal "ffi бла", @handler.slice(@string, /ffi \w\wа/u), "Slicing on Regexps should be supported"
+ assert_equal nil, @handler.slice(@string, /unknown/u), "Slicing on Regexps with no match should return nil"
+ assert_equal "ffi бла", @handler.slice(@string, /(ffi бла)/u,1), "Slicing on Regexps with a match group should be supported"
+ assert_equal nil, @handler.slice(@string, /(ffi)/u,2), "Slicing with a Regexp and asking for an invalid match group should return nil"
+ assert_equal "", @handler.slice(@string, 7..6), "Range is empty, should return an empty string"
+ assert_raise(ActiveSupport::Multibyte::Handlers::EncodingError) { @handler.slice(@bytestring, 2..3) }
+ assert_raise(TypeError, "With 2 args, should raise TypeError for non-Numeric or Regexp first argument") { @handler.slice(@string, 2..3, 1) }
+ assert_raise(TypeError, "With 2 args, should raise TypeError for non-Numeric or Regexp second argument") { @handler.slice(@string, 1, 2..3) }
+ assert_raise(ArgumentError, "Should raise ArgumentError when there are more than 2 args") { @handler.slice(@string, 1, 1, 1) }
+ end
+
+ def test_grapheme_cluster_length
+ assert_equal 0, @handler.g_length(''), "String should count 0 grapheme clusters"
+ assert_equal 2, @handler.g_length([0x0924, 0x094D, 0x0930].pack('U*')), "String should count 2 grapheme clusters"
+ assert_equal 1, @handler.g_length(string_from_classes(%w(cr lf))), "Don't cut between CR and LF"
+ assert_equal 1, @handler.g_length(string_from_classes(%w(l l))), "Don't cut between L"
+ assert_equal 1, @handler.g_length(string_from_classes(%w(l v))), "Don't cut between L and V"
+ assert_equal 1, @handler.g_length(string_from_classes(%w(l lv))), "Don't cut between L and LV"
+ assert_equal 1, @handler.g_length(string_from_classes(%w(l lvt))), "Don't cut between L and LVT"
+ assert_equal 1, @handler.g_length(string_from_classes(%w(lv v))), "Don't cut between LV and V"
+ assert_equal 1, @handler.g_length(string_from_classes(%w(lv t))), "Don't cut between LV and T"
+ assert_equal 1, @handler.g_length(string_from_classes(%w(v v))), "Don't cut between V and V"
+ assert_equal 1, @handler.g_length(string_from_classes(%w(v t))), "Don't cut between V and T"
+ assert_equal 1, @handler.g_length(string_from_classes(%w(lvt t))), "Don't cut between LVT and T"
+ assert_equal 1, @handler.g_length(string_from_classes(%w(t t))), "Don't cut between T and T"
+ assert_equal 1, @handler.g_length(string_from_classes(%w(n extend))), "Don't cut before Extend"
+ assert_equal 2, @handler.g_length(string_from_classes(%w(n n))), "Cut between normal characters"
+ assert_equal 3, @handler.g_length(string_from_classes(%w(n cr lf n))), "Don't cut between CR and LF"
+ assert_equal 2, @handler.g_length(string_from_classes(%w(n l v t))), "Don't cut between L, V and T"
+ assert_raise(ActiveSupport::Multibyte::Handlers::EncodingError) { @handler.g_length(@bytestring) }
+ end
+
+ def test_index
+ s = "Καλημέρα κόσμε!"
+ assert_equal 0, @handler.index('', ''), "The empty string is always found at the beginning of the string"
+ assert_equal 0, @handler.index('haystack', ''), "The empty string is always found at the beginning of the string"
+ assert_equal 0, @handler.index(s, 'Κ'), "Greek K is at 0"
+ assert_equal 1, @handler.index(s, 'α'), "Greek Alpha is at 1"
+
+ assert_equal nil, @handler.index(@bytestring, 'a')
+ assert_raise(ActiveSupport::Multibyte::Handlers::EncodingError) { @handler.index(@bytestring, "\010") }
+ end
+
+ def test_indexed_insert
+ s = "Καλη!"
+ @handler[s, 2] = "a"
+ assert_equal "Καaη!", s
+ @handler[s, 2] = "ηη"
+ assert_equal "Καηηη!", s
+ assert_raises(IndexError) { @handler[s, 10] = 'a' }
+ assert_equal "Καηηη!", s
+ @handler[s, 2] = 32
+ assert_equal "Κα ηη!", s
+ @handler[s, 3, 2] = "λλλ"
+ assert_equal "Κα λλλ!", s
+ @handler[s, 1, 0] = "λ"
+ assert_equal "Κλα λλλ!", s
+ assert_raises(IndexError) { @handler[s, 10, 4] = 'a' }
+ assert_equal "Κλα λλλ!", s
+ @handler[s, 4..6] = "ηη"
+ assert_equal "Κλα ηη!", s
+ assert_raises(RangeError) { @handler[s, 10..12] = 'a' }
+ assert_equal "Κλα ηη!", s
+ @handler[s, /ηη/] = "λλλ"
+ assert_equal "Κλα λλλ!", s
+ assert_raises(IndexError) { @handler[s, /ii/] = 'a' }
+ assert_equal "Κλα λλλ!", s
+ @handler[s, /(λλ)(.)/, 2] = "α"
+ assert_equal "Κλα λλα!", s
+ assert_raises(IndexError) { @handler[s, /()/, 10] = 'a' }
+ assert_equal "Κλα λλα!", s
+ @handler[s, "α"] = "η"
+ assert_equal "Κλη λλα!", s
+ @handler[s, "λλ"] = "ααα"
+ assert_equal "Κλη αααα!", s
+ end
+
+ def test_rjust
+ s = "Καη"
+ assert_raises(ArgumentError) { @handler.rjust(s, 10, '') }
+ assert_raises(ArgumentError) { @handler.rjust(s) }
+ assert_equal "Καη", @handler.rjust(s, -3)
+ assert_equal "Καη", @handler.rjust(s, 0)
+ assert_equal "Καη", @handler.rjust(s, 3)
+ assert_equal " Καη", @handler.rjust(s, 5)
+ assert_equal " Καη", @handler.rjust(s, 7)
+ assert_equal "----Καη", @handler.rjust(s, 7, '-')
+ assert_equal "ααααΚαη", @handler.rjust(s, 7, 'α')
+ assert_equal "abaΚαη", @handler.rjust(s, 6, 'ab')
+ assert_equal "αηαΚαη", @handler.rjust(s, 6, 'αη')
+ end
+
+ def test_ljust
+ s = "Καη"
+ assert_raises(ArgumentError) { @handler.ljust(s, 10, '') }
+ assert_raises(ArgumentError) { @handler.ljust(s) }
+ assert_equal "Καη", @handler.ljust(s, -3)
+ assert_equal "Καη", @handler.ljust(s, 0)
+ assert_equal "Καη", @handler.ljust(s, 3)
+ assert_equal "Καη ", @handler.ljust(s, 5)
+ assert_equal "Καη ", @handler.ljust(s, 7)
+ assert_equal "Καη----", @handler.ljust(s, 7, '-')
+ assert_equal "Καηαααα", @handler.ljust(s, 7, 'α')
+ assert_equal "Καηaba", @handler.ljust(s, 6, 'ab')
+ assert_equal "Καηαηα", @handler.ljust(s, 6, 'αη')
+ end
+
+ def test_center
+ s = "Καη"
+ assert_raises(ArgumentError) { @handler.center(s, 10, '') }
+ assert_raises(ArgumentError) { @handler.center(s) }
+ assert_equal "Καη", @handler.center(s, -3)
+ assert_equal "Καη", @handler.center(s, 0)
+ assert_equal "Καη", @handler.center(s, 3)
+ assert_equal "Καη ", @handler.center(s, 4)
+ assert_equal " Καη ", @handler.center(s, 5)
+ assert_equal " Καη ", @handler.center(s, 6)
+ assert_equal "--Καη--", @handler.center(s, 7, '-')
+ assert_equal "--Καη---", @handler.center(s, 8, '-')
+ assert_equal "ααΚαηαα", @handler.center(s, 7, 'α')
+ assert_equal "ααΚαηααα", @handler.center(s, 8, 'α')
+ assert_equal "aΚαηab", @handler.center(s, 6, 'ab')
+ assert_equal "abΚαηab", @handler.center(s, 7, 'ab')
+ assert_equal "ababΚαηabab", @handler.center(s, 11, 'ab')
+ assert_equal "αΚαηαη", @handler.center(s, 6, 'αη')
+ assert_equal "αηΚαηαη", @handler.center(s, 7, 'αη')
+ end
+
+ def test_strip
+ # A unicode aware version of strip should strip all 26 types of whitespace. This includes the NO BREAK SPACE
+ # aka BOM (byte order mark). The byte order mark has no place in UTF-8 because it's used to detect LE and BE.
+ b = "\n" + [
+ 32, # SPACE
+ 8195, # EM SPACE
+ 8199, # FIGURE SPACE,
+ 8201, # THIN SPACE
+ 8202, # HAIR SPACE
+ 65279, # NO BREAK SPACE (ZW)
+ ].pack('U*')
+ m = "word блин\n\n\n word"
+ e = [
+ 65279, # NO BREAK SPACE (ZW)
+ 8201, # THIN SPACE
+ 8199, # FIGURE SPACE,
+ 32, # SPACE
+ ].pack('U*')
+ string = b+m+e
+
+ assert_equal '', @handler.strip(''), "Empty string should stay empty"
+ assert_equal m+e, @handler.lstrip(string), "Whitespace should be gone on the left"
+ assert_equal b+m, @handler.rstrip(string), "Whitespace should be gone on the right"
+ assert_equal m, @handler.strip(string), "Whitespace should be stripped on both sides"
+
+ bs = "\n #{@bytestring} \n\n"
+ assert_equal @bytestring, @handler.strip(bs), "Invalid unicode strings should still strip"
+ end
+
+ def test_tidy_bytes
+ result = [0xb8, 0x17e, 0x8, 0x2c6, 0xa5].pack('U*')
+ assert_equal result, @handler.tidy_bytes(@bytestring)
+ assert_equal "a#{result}a", @handler.tidy_bytes('a' + @bytestring + 'a'),
+ 'tidy_bytes should leave surrounding characters intact'
+ assert_equal "é#{result}é", @handler.tidy_bytes('é' + @bytestring + 'é'),
+ 'tidy_bytes should leave surrounding characters intact'
+ assert_nothing_raised { @handler.tidy_bytes(@bytestring).unpack('U*') }
+
+ assert_equal "\xC3\xA7", @handler.tidy_bytes("\xE7") # iso_8859_1: small c cedilla
+ assert_equal "\xC2\xA9", @handler.tidy_bytes("\xA9") # iso_8859_1: copyright symbol
+ assert_equal "\xE2\x80\x9C", @handler.tidy_bytes("\x93") # win_1252: left smart quote
+ assert_equal "\xE2\x82\xAC", @handler.tidy_bytes("\x80") # win_1252: euro
+ assert_equal "\x00", @handler.tidy_bytes("\x00") # null char
+ assert_equal [0xfffd].pack('U'), @handler.tidy_bytes("\xef\xbf\xbd") # invalid char
+ end
+
+ protected
+
+ def string_from_classes(classes)
+ classes.collect do |k|
+ @character_from_class[k.intern]
+ end.pack('U*')
+ end
+end
+
+
+begin
+ require_library_or_gem('utf8proc_native')
+ require 'active_record/multibyte/handlers/utf8_handler_proc'
+ class UTF8HandlingTestProc < Test::Unit::TestCase
+ include UTF8HandlingTest
+ def setup
+ common_setup
+ @handler = ::ActiveSupport::Multibyte::Handlers::UTF8HandlerProc
+ end
+ end
+rescue LoadError
+end
+
+class UTF8HandlingTestPure < Test::Unit::TestCase
+ include UTF8HandlingTest
+ def setup
+ common_setup
+ @handler = ::ActiveSupport::Multibyte::Handlers::UTF8Handler
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/option_merger_test.rb b/vendor/rails-2.0.2/activesupport/test/option_merger_test.rb
new file mode 100644
index 000000000..0cddfe8c2
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/option_merger_test.rb
@@ -0,0 +1,50 @@
+require File.dirname(__FILE__) + '/abstract_unit'
+
+class OptionMergerTest < Test::Unit::TestCase
+ def setup
+ @options = {:hello => 'world'}
+ end
+
+ def test_method_with_options_merges_options_when_options_are_present
+ local_options = {:cool => true}
+
+ with_options(@options) do |o|
+ assert_equal local_options, method_with_options(local_options)
+ assert_equal @options.merge(local_options),
+ o.method_with_options(local_options)
+ end
+ end
+
+ def test_method_with_options_appends_options_when_options_are_missing
+ with_options(@options) do |o|
+ assert_equal Hash.new, method_with_options
+ assert_equal @options, o.method_with_options
+ end
+ end
+
+ def test_method_with_options_allows_to_overwrite_options
+ local_options = {:hello => 'moon'}
+ assert_equal @options.keys, local_options.keys
+
+ with_options(@options) do |o|
+ assert_equal local_options, method_with_options(local_options)
+ assert_equal @options.merge(local_options),
+ o.method_with_options(local_options)
+ assert_equal local_options, o.method_with_options(local_options)
+ end
+ with_options(local_options) do |o|
+ assert_equal local_options.merge(@options),
+ o.method_with_options(@options)
+ end
+ end
+
+ # Needed when counting objects with the ObjectSpace
+ def test_option_merger_class_method
+ assert_equal ActiveSupport::OptionMerger, ActiveSupport::OptionMerger.new('', '').class
+ end
+
+ private
+ def method_with_options(options = {})
+ options
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/ordered_options_test.rb b/vendor/rails-2.0.2/activesupport/test/ordered_options_test.rb
new file mode 100644
index 000000000..bf7339ac5
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/ordered_options_test.rb
@@ -0,0 +1,84 @@
+require File.dirname(__FILE__) + '/abstract_unit'
+
+class OrderedHashTest < Test::Unit::TestCase
+ def setup
+ @keys = %w( blue green red pink orange )
+ @values = %w( 000099 009900 aa0000 cc0066 cc6633 )
+ @ordered_hash = ActiveSupport::OrderedHash.new
+
+ @keys.each_with_index do |key, index|
+ @ordered_hash[key] = @values[index]
+ end
+ end
+
+ def test_order
+ assert_equal @keys, @ordered_hash.keys
+ assert_equal @values, @ordered_hash.values
+ end
+
+ def test_access
+ assert @keys.zip(@values).all? { |k, v| @ordered_hash[k] == v }
+ end
+
+ def test_assignment
+ key, value = 'purple', '5422a8'
+
+ @ordered_hash[key] = value
+ assert_equal @keys.length + 1, @ordered_hash.length
+ assert_equal key, @ordered_hash.keys.last
+ assert_equal value, @ordered_hash.values.last
+ assert_equal value, @ordered_hash[key]
+ end
+end
+
+class OrderedOptionsTest < Test::Unit::TestCase
+ def test_usage
+ a = OrderedOptions.new
+
+ assert_nil a[:not_set]
+
+ a[:allow_concurreny] = true
+ assert_equal 1, a.size
+ assert a[:allow_concurreny]
+
+ a[:allow_concurreny] = false
+ assert_equal 1, a.size
+ assert !a[:allow_concurreny]
+
+ a["else_where"] = 56
+ assert_equal 2, a.size
+ assert_equal 56, a[:else_where]
+ end
+
+ def test_looping
+ a = OrderedOptions.new
+
+ a[:allow_concurreny] = true
+ a["else_where"] = 56
+
+ test = [[:allow_concurreny, true], [:else_where, 56]]
+
+ a.each_with_index do |(key, value), index|
+ assert_equal test[index].first, key
+ assert_equal test[index].last, value
+ end
+ end
+
+ def test_method_access
+ a = OrderedOptions.new
+
+ assert_nil a.not_set
+
+ a.allow_concurreny = true
+ assert_equal 1, a.size
+ assert a.allow_concurreny
+
+ a.allow_concurreny = false
+ assert_equal 1, a.size
+ assert !a.allow_concurreny
+
+ a.else_where = 56
+ assert_equal 2, a.size
+ assert_equal 56, a.else_where
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/test_test.rb b/vendor/rails-2.0.2/activesupport/test/test_test.rb
new file mode 100644
index 000000000..eecbd31f9
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/test_test.rb
@@ -0,0 +1,73 @@
+require File.dirname(__FILE__) + '/abstract_unit'
+require 'active_support/test_case'
+class AssertDifferenceTest < Test::Unit::TestCase
+ def setup
+ @object = Class.new do
+ attr_accessor :num
+ def increment
+ self.num += 1
+ end
+
+ def decrement
+ self.num -= 1
+ end
+ end.new
+ @object.num = 0
+ end
+
+ if lambda { }.respond_to?(:binding)
+ def test_assert_no_difference
+ assert_no_difference '@object.num' do
+ # ...
+ end
+ end
+
+ def test_assert_difference
+ assert_difference '@object.num', +1 do
+ @object.increment
+ end
+ end
+
+ def test_assert_difference_with_implicit_difference
+ assert_difference '@object.num' do
+ @object.increment
+ end
+ end
+
+ def test_arbitrary_expression
+ assert_difference '@object.num + 1', +2 do
+ @object.increment
+ @object.increment
+ end
+ end
+
+ def test_negative_differences
+ assert_difference '@object.num', -1 do
+ @object.decrement
+ end
+ end
+
+ def test_expression_is_evaluated_in_the_appropriate_scope
+ local_scope = 'foo'
+ silence_warnings do
+ assert_difference('local_scope; @object.num') { @object.increment }
+ end
+ end
+
+ def test_array_of_expressions
+ assert_difference [ '@object.num', '@object.num + 1' ], +1 do
+ @object.increment
+ end
+ end
+ else
+ def default_test; end
+ end
+end
+
+# These should always pass
+class NotTestingThingsTest < Test::Unit::TestCase
+ include ActiveSupport::Testing::Default
+end
+
+class AlsoDoingNothingTest < ActiveSupport::TestCase
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/time_zone_test.rb b/vendor/rails-2.0.2/activesupport/test/time_zone_test.rb
new file mode 100644
index 000000000..c2a3e1c53
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/time_zone_test.rb
@@ -0,0 +1,98 @@
+require File.dirname(__FILE__) + '/abstract_unit'
+
+class TimeZoneTest < Test::Unit::TestCase
+ class MockTime
+ def self.now
+ Time.utc( 2004, 7, 25, 14, 49, 00 )
+ end
+
+ def self.local(*args)
+ Time.utc(*args)
+ end
+ end
+
+ TimeZone::Time = MockTime
+
+ def test_formatted_offset_positive
+ zone = TimeZone.create( "Test", 4200 )
+ assert_equal "+01:10", zone.formatted_offset
+ end
+
+ def test_formatted_offset_negative
+ zone = TimeZone.create( "Test", -4200 )
+ assert_equal "-01:10", zone.formatted_offset
+ end
+
+ def test_now
+ zone = TimeZone.create( "Test", 4200 )
+ assert_equal Time.local(2004,7,25,15,59,00).to_a[0,6], zone.now.to_a[0,6]
+ end
+
+ def test_today
+ zone = TimeZone.create( "Test", 43200 )
+ assert_equal Date.new(2004,7,26), zone.today
+ end
+
+ def test_adjust_negative
+ zone = TimeZone.create( "Test", -4200 ) # 4200s == 70 mins
+ assert_equal Time.utc(2004,7,24,23,55,0), zone.adjust(Time.utc(2004,7,25,1,5,0))
+ end
+
+ def test_adjust_positive
+ zone = TimeZone.create( "Test", 4200 )
+ assert_equal Time.utc(2004,7,26,1,5,0), zone.adjust(Time.utc(2004,7,25,23,55,0))
+ end
+
+ def test_unadjust
+ zone = TimeZone.create( "Test", 4200 )
+ expect = Time.utc(2004,7,24,23,55,0).to_a[0,6]
+ actual = zone.unadjust(Time.utc(2004,7,25,1,5,0)).to_a[0,6]
+ assert_equal expect, actual
+ end
+
+ def test_zone_compare
+ zone1 = TimeZone.create( "Test1", 4200 )
+ zone2 = TimeZone.create( "Test1", 5600 )
+ assert zone1 < zone2
+ assert zone2 > zone1
+
+ zone1 = TimeZone.create( "Able", 10000 )
+ zone2 = TimeZone.create( "Zone", 10000 )
+ assert zone1 < zone2
+ assert zone2 > zone1
+
+ zone1 = TimeZone.create( "Able", 10000 )
+ assert zone1 == zone1
+ end
+
+ def test_to_s
+ zone = TimeZone.create( "Test", 4200 )
+ assert_equal "(UTC+01:10) Test", zone.to_s
+ end
+
+ def test_all_sorted
+ all = TimeZone.all
+ 1.upto( all.length-1 ) do |i|
+ assert all[i-1] < all[i]
+ end
+ end
+
+ def test_index
+ assert_nil TimeZone["bogus"]
+ assert_not_nil TimeZone["Central Time (US & Canada)"]
+ assert_not_nil TimeZone[8]
+ assert_raises(ArgumentError) { TimeZone[false] }
+ end
+
+ def test_new
+ a = TimeZone.new("Berlin")
+ b = TimeZone.new("Berlin")
+ assert_same a, b
+ assert_nil TimeZone.new("bogus")
+ end
+
+ def test_us_zones
+ assert TimeZone.us_zones.include?(TimeZone["Hawaii"])
+ assert !TimeZone.us_zones.include?(TimeZone["Kuala Lumpur"])
+ end
+end
diff --git a/vendor/rails-2.0.2/activesupport/test/whiny_nil_test.rb b/vendor/rails-2.0.2/activesupport/test/whiny_nil_test.rb
new file mode 100644
index 000000000..4483134be
--- /dev/null
+++ b/vendor/rails-2.0.2/activesupport/test/whiny_nil_test.rb
@@ -0,0 +1,38 @@
+# Stub to enable testing without Active Record
+module ActiveRecord
+ class Base
+ def save!
+ end
+ end
+end
+
+require File.dirname(__FILE__) + '/abstract_unit'
+require 'active_support/whiny_nil'
+
+class WhinyNilTest < Test::Unit::TestCase
+ def test_unchanged
+ nil.method_thats_not_in_whiners
+ rescue NoMethodError => nme
+ assert_match(/nil.method_thats_not_in_whiners/, nme.message)
+ end
+
+ def test_active_record
+ nil.save!
+ rescue NoMethodError => nme
+ assert(!(nme.message =~ /nil:NilClass/))
+ assert_match(/nil\.save!/, nme.message)
+ end
+
+ def test_array
+ nil.each
+ rescue NoMethodError => nme
+ assert(!(nme.message =~ /nil:NilClass/))
+ assert_match(/nil\.each/, nme.message)
+ end
+
+ def test_id
+ nil.id
+ rescue RuntimeError => nme
+ assert(!(nme.message =~ /nil:NilClass/))
+ end
+end