diff options
Diffstat (limited to 'vendor/rails-2.0.2/activesupport')
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, ' ') {|g| p g} + # ["1", "2"] + # ["3", " "] + # + # %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 Binary files differnew file mode 100644 index 000000000..35edb148c --- /dev/null +++ b/vendor/rails-2.0.2/activesupport/lib/active_support/values/unicode_tables.dat 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 => '&', # ampersand + 60 => '<', # left angle bracket + 62 => '>', # 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{"}, '"') # " 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 & 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 <, + # > and & 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 & Last Name' + }.stringify_keys + + expected_xml = '<person><bare-string>First & Last Name</bare-string><pre-escaped-string>First &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 & Last Name</bare-string><pre-escaped-string>First &amp; Last Name</pre-escaped-string></person>' + expected_hash = { + :bare_string => 'First & Last Name', + :pre_escaped_string => 'First & 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 & 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 |