From 5a3fd46d42f05a241b3178af60d38fe5e0cebee6 Mon Sep 17 00:00:00 2001 From: Rodrigo Kochenburger Date: Tue, 13 May 2008 22:08:31 -0300 Subject: Fixing test for named_scope through a has_many :through The test that checks if a has_many :through association has access to named_scope had a typo and didn't have the proper fixtures loaded. [#190 state:resolved] --- activerecord/test/cases/named_scope_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb index 30c074c9d8..9730f93579 100644 --- a/activerecord/test/cases/named_scope_test.rb +++ b/activerecord/test/cases/named_scope_test.rb @@ -6,7 +6,7 @@ require 'models/reply' require 'models/author' class NamedScopeTest < ActiveRecord::TestCase - fixtures :posts, :authors, :topics + fixtures :posts, :authors, :topics, :comments def test_implements_enumerable assert !Topic.find(:all).empty? @@ -95,7 +95,7 @@ class NamedScopeTest < ActiveRecord::TestCase end def test_has_many_through_associations_have_access_to_named_scopes - assert_not_equal Comment.containing_the_letter_e, authors(:david).posts + assert_not_equal Comment.containing_the_letter_e, authors(:david).comments assert !Comment.containing_the_letter_e.empty? assert_equal authors(:david).comments & Comment.containing_the_letter_e, authors(:david).comments.containing_the_letter_e -- cgit v1.2.3 From 3baf810482303126c75daa7915e200030d1755e0 Mon Sep 17 00:00:00 2001 From: Jake Howerton Date: Fri, 16 May 2008 01:29:55 -0400 Subject: Add rdoc task to activemodel. [#156 state:resolved] Signed-off-by: Pratik Naik --- activemodel/Rakefile | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/activemodel/Rakefile b/activemodel/Rakefile index cb9a61773f..87e9b547f3 100644 --- a/activemodel/Rakefile +++ b/activemodel/Rakefile @@ -1,4 +1,16 @@ #!/usr/bin/env ruby $LOAD_PATH << File.join(File.dirname(__FILE__), 'vendor', 'rspec', 'lib') require 'rake' -require 'spec/rake/spectask' \ No newline at end of file +require 'spec/rake/spectask' +require 'rake/rdoctask' + +# Generate the RDoc documentation +Rake::RDocTask.new { |rdoc| + rdoc.rdoc_dir = 'doc' + rdoc.title = "Active Model" + rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object' + rdoc.options << '--charset' << 'utf-8' + rdoc.template = "#{ENV['template']}.rb" if ENV['template'] + rdoc.rdoc_files.include('README', 'CHANGES') + rdoc.rdoc_files.include('lib/**/*.rb') +} \ No newline at end of file -- cgit v1.2.3 From a01a0178be297b0eb62909819a15a01c6b69a841 Mon Sep 17 00:00:00 2001 From: miloops Date: Wed, 14 May 2008 09:22:39 +0000 Subject: Change migration generator USAGE to explain the timestamped migrations behaviour --- .../lib/rails_generator/generators/components/migration/USAGE | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/railties/lib/rails_generator/generators/components/migration/USAGE b/railties/lib/rails_generator/generators/components/migration/USAGE index 3e914a5d7b..b83c657963 100644 --- a/railties/lib/rails_generator/generators/components/migration/USAGE +++ b/railties/lib/rails_generator/generators/components/migration/USAGE @@ -2,7 +2,7 @@ Description: Stubs out a new database migration. Pass the migration name, either CamelCased or under_scored, and an optional list of attribute pairs as arguments. - A migration class is generated in db/migrate prefixed by the latest migration number. + A migration class is generated in db/migrate prefixed by a timestamp of the current date and time. You can name your migration in either of these formats to generate add/remove column lines from supplied attributes: AddColumnsToTable or RemoveColumnsFromTable @@ -10,12 +10,12 @@ Description: Example: `./script/generate migration AddSslFlag` - With 4 existing migrations, this creates the AddSslFlag migration in - db/migrate/005_add_ssl_flag.rb + If the current date is May 14, 2008 and the current time 09:09:12, this creates the AddSslFlag migration + db/migrate/20080514090912_add_ssl_flag.rb `./script/generate migration AddTitleBodyToPost title:string body:text published:boolean` - This will create the AddTitleBodyToPost in db/migrate/005_add_title_body_to_post.rb with + This will create the AddTitleBodyToPost in db/migrate/20080514090912_add_title_body_to_post.rb with this in the Up migration: add_column :posts, :title, :string -- cgit v1.2.3 From 150717344aa5c6d8f46fc67de39d6947553ac286 Mon Sep 17 00:00:00 2001 From: Eugene Pimenov Date: Thu, 1 May 2008 09:37:10 +0400 Subject: auto_link helper fails to recognize links separated by space. [#72 state:resolved] Signed-off-by: Pratik Naik --- actionpack/lib/action_view/helpers/text_helper.rb | 2 +- actionpack/test/template/text_helper_test.rb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 9d220c546a..55d2a68327 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -454,7 +454,7 @@ module ActionView ( # leading text <\w+.*?>| # leading HTML tag, or [^=!:'"/]| # leading punctuation, or - ^ # beginning of line + | # nothing ) ( (?:https?://)| # protocol spec, or diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb index 06e1fd1929..337697bf5c 100644 --- a/actionpack/test/template/text_helper_test.rb +++ b/actionpack/test/template/text_helper_test.rb @@ -262,6 +262,7 @@ class TextHelperTest < ActionView::TestCase assert_equal email2_result, auto_link(email2_raw) assert_equal '', auto_link(nil) assert_equal '', auto_link('') + assert_equal "#{link_result} #{link_result} #{link_result}", auto_link("#{link_raw} #{link_raw} #{link_raw}") end def test_auto_link_at_eol -- cgit v1.2.3 From 77f873acf2f1fb4533dfca6b26b965a115ebbc54 Mon Sep 17 00:00:00 2001 From: Kyle Hargraves Date: Fri, 16 May 2008 06:51:39 -0500 Subject: dbconsole should not require a username for postgresql. [#207 state:resolved] Signed-off-by: Pratik Naik --- railties/lib/commands/dbconsole.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/railties/lib/commands/dbconsole.rb b/railties/lib/commands/dbconsole.rb index 3e5010c688..b81997aa59 100644 --- a/railties/lib/commands/dbconsole.rb +++ b/railties/lib/commands/dbconsole.rb @@ -40,10 +40,11 @@ when "mysql" exec(find_cmd('mysql5', 'mysql'), *args) when "postgresql" + ENV['PGUSER'] = config["username"] if config["username"] ENV['PGHOST'] = config["host"] if config["host"] ENV['PGPORT'] = config["port"].to_s if config["port"] ENV['PGPASSWORD'] = config["password"].to_s if config["password"] - exec(find_cmd('psql'), '-U', config["username"], config["database"]) + exec(find_cmd('psql'), config["database"]) when "sqlite" exec(find_cmd('sqlite'), config["database"]) -- cgit v1.2.3 From 6ea5e4208f724b50e774e6a1af027336c3ee3de1 Mon Sep 17 00:00:00 2001 From: Chris O'Sullivan Date: Fri, 16 May 2008 16:09:11 +0100 Subject: Added docs about source_type for has_one association --- activerecord/lib/active_record/associations.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index c17e35f5e0..95caf68692 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -753,6 +753,8 @@ module ActiveRecord # * :source - Specifies the source association name used by has_one :through queries. Only use it if the name cannot be # inferred from the association. has_one :favorite, :through => :favorites will look for a # :favorite on Favorite, unless a :source is given. + # * :source_type - Specifies type of the source association used by has_one :through queries where the source + # association is a polymorphic +belongs_to+. # * :readonly - If true, the associated object is readonly through the association. # # Option examples: -- cgit v1.2.3 From 345f030c5b6c0a28ddde56c80a1112b00d345c79 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Tue, 13 May 2008 22:04:20 +0200 Subject: Ensure routing generator works with non-string keys. [#172 state:resolved] Make sure that (with recent correction to globbed parameter escaping) non-string values can still be passed route generation helpers for globbed route segments. For example, foo_path([1, 2, 3]) should still work for a route like map.foo "*globbed" by implicitely calling to_s on the Fixnums. Signed-off-by: Pratik Naik --- actionpack/lib/action_controller/routing/segments.rb | 2 +- actionpack/test/controller/routing_test.rb | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_controller/routing/segments.rb b/actionpack/lib/action_controller/routing/segments.rb index b142d18b47..864e068004 100644 --- a/actionpack/lib/action_controller/routing/segments.rb +++ b/actionpack/lib/action_controller/routing/segments.rb @@ -249,7 +249,7 @@ module ActionController end def extract_value - "#{local_name} = hash[:#{key}] && hash[:#{key}].collect { |path_component| URI.escape(path_component, ActionController::Routing::Segment::UNSAFE_PCHAR) }.to_param #{"|| #{default.inspect}" if default}" + "#{local_name} = hash[:#{key}] && hash[:#{key}].collect { |path_component| URI.escape(path_component.to_param, ActionController::Routing::Segment::UNSAFE_PCHAR) }.to_param #{"|| #{default.inspect}" if default}" end def default diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index b28f7bcdff..5e5503fd52 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -50,6 +50,13 @@ class UriReservedCharactersRoutingTest < Test::Unit::TestCase :additional => ["add#{@segment}itional-1", "add#{@segment}itional-2"] } assert_equal options, @set.recognize_path("/controller/act#{@escaped}ion/var#{@escaped}iable/add#{@escaped}itional-1/add#{@escaped}itional-2") end + + def test_route_generation_allows_passing_non_string_values_to_generated_helper + assert_equal "/controller/action/variable/1/2", @set.generate(:controller => "controller", + :action => "action", + :variable => "variable", + :additional => [1, 2]) + end end class LegacyRouteSetTests < Test::Unit::TestCase -- cgit v1.2.3 From 70e4bcf5cb039bea073851faed2df9f465e6f2f8 Mon Sep 17 00:00:00 2001 From: Chris Kampmeier Date: Fri, 16 May 2008 12:09:46 -0700 Subject: Fix a couple spelling errors in docs --- actionpack/lib/action_controller/mime_responds.rb | 2 +- railties/configs/initializers/new_rails_defaults.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_controller/mime_responds.rb b/actionpack/lib/action_controller/mime_responds.rb index a17782cafc..1dbd8b9e6f 100644 --- a/actionpack/lib/action_controller/mime_responds.rb +++ b/actionpack/lib/action_controller/mime_responds.rb @@ -92,7 +92,7 @@ module ActionController #:nodoc: # with the remaining data. # # Note that you can define your own XML parameter parser which would allow you to describe multiple entities - # in a single request (i.e., by wrapping them all in a single root note), but if you just go with the flow + # in a single request (i.e., by wrapping them all in a single root node), but if you just go with the flow # and accept Rails' defaults, life will be much easier. # # If you need to use a MIME type which isn't supported by default, you can register your own handlers in diff --git a/railties/configs/initializers/new_rails_defaults.rb b/railties/configs/initializers/new_rails_defaults.rb index b8f0e2cac2..1a718608ae 100644 --- a/railties/configs/initializers/new_rails_defaults.rb +++ b/railties/configs/initializers/new_rails_defaults.rb @@ -1,4 +1,4 @@ -# These settins change the behavior of Rails 2 apps and will be defaults +# These settings change the behavior of Rails 2 apps and will be defaults # for Rails 3. You can remove this initializer when Rails 3 is released. # Only save the attributes that have changed since the record was loaded. -- cgit v1.2.3 From 0fc3381aa5359f31b36057d7bfba2e0eb6a3c064 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Fri, 16 May 2008 23:44:51 +0200 Subject: revised docs of form_for This revision encourages the modern resource-oriented form_for usage. In addition corrects some markup and other details. --- actionpack/lib/action_view/helpers/form_helper.rb | 84 +++++++++++++++-------- 1 file changed, 56 insertions(+), 28 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index b8600fe445..6d97038da9 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -73,30 +73,54 @@ module ActionView # There are also methods for helping to build form tags in link:classes/ActionView/Helpers/FormOptionsHelper.html, # link:classes/ActionView/Helpers/DateHelper.html, and link:classes/ActionView/Helpers/ActiveRecordHelper.html module FormHelper - # Creates a form and a scope around a specific model object that is used as a base for questioning about - # values for the fields. + # Creates a form and a scope around a specific model object that is used as + # a base for questioning about values for the fields. # - # <% form_for :person, @person, :url => { :action => "update" } do |f| %> - # <%= f.error_messages %> - # First name: <%= f.text_field :first_name %> - # Last name : <%= f.text_field :last_name %> - # Biography : <%= f.text_area :biography %> - # Admin? : <%= f.check_box :admin %> + # Rails provides succint resource-oriented form generation with +form_for+ + # like this: + # + # <% form_for @offer do |f| %> + # <%= f.label :version, 'Version' %>: + # <%= f.text_field :version %>
+ # <%= f.label :author, 'Author' %>: + # <%= f.text_field :author %>
# <% end %> # - # Worth noting is that the form_for tag is called in a ERb evaluation block, not an ERb output block. So that's <% %>, - # not <%= %>. Also worth noting is that form_for yields a form_builder object, in this example as f, which emulates - # the API for the stand-alone FormHelper methods, but without the object name. So instead of text_field :person, :name, - # you get away with f.text_field :name. Notice that you can even do <%= f.error_messages %> to display the - # error messsages of the model object in question. + # There, +form_for+ is able to generate the rest of RESTful parameters + # based on introspection on the record, but to understand what it does we + # need to dig first into the alternative generic usage it is based upon. + # + # === Generic form_for # - # Even further, the form_for method allows you to more easily escape the instance variable convention. So while the stand-alone - # approach would require text_field :person, :name, :object => person - # to work with local variables instead of instance ones, the form_for calls remain the same. You simply declare once with - # :person, person and all subsequent field calls save :person and :object => person. + # The generic way to call +form_for+ requires a few arguments: # - # Also note that form_for doesn't create an exclusive scope. It's still possible to use both the stand-alone FormHelper methods - # and methods from FormTagHelper. For example: + # <% form_for :person, @person, :url => { :action => "update" } do |f| %> + # <%= f.error_messages %> + # First name: <%= f.text_field :first_name %>
+ # Last name : <%= f.text_field :last_name %>
+ # Biography : <%= f.text_area :biography %>
+ # Admin? : <%= f.check_box :admin %>
+ # <% end %> + # + # Worth noting is that the +form_for+ tag is called in a ERb evaluation block, + # not an ERb output block. So that's <% %>, not <%= %>. Also + # worth noting is that +form_for+ yields a form builder object, in this + # example as +f+, which emulates the API for the stand-alone FormHelper + # methods, but without the object name. So instead of text_field :person, :name, + # you get away with f.text_field :name. Notice that you can even do + # <%= f.error_messages %> to display the error messsages of the model + # object in question. + # + # Even further, the +form_for+ method allows you to more easily escape the + # instance variable convention. So while the stand-alone approach would require + # text_field :person, :name, :object => person to work with local + # variables instead of instance ones, the +form_for+ calls remain the same. + # You simply declare once with :person, person and all subsequent + # field calls save :person and :object => person. + # + # Also note that +form_for+ doesn't create an exclusive scope. It's still + # possible to use both the stand-alone FormHelper methods and methods from + # FormTagHelper. For example: # # <% form_for :person, @person, :url => { :action => "update" } do |f| %> # First name: <%= f.text_field :first_name %> @@ -105,22 +129,26 @@ module ActionView # Admin? : <%= check_box_tag "person[admin]", @person.company.admin? %> # <% end %> # - # Note: This also works for the methods in FormOptionHelper and DateHelper that are designed to work with an object as base, - # like FormOptionHelper#collection_select and DateHelper#datetime_select. + # This also works for the methods in FormOptionHelper and DateHelper that are + # designed to work with an object as base, like FormOptionHelper#collection_select + # and DateHelper#datetime_select. # - # HTML attributes for the form tag can be given as :html => {...}. For example: + # HTML attributes for the form tag can be given as :html => {...}. + # For example: # # <% form_for :person, @person, :html => {:id => 'person_form'} do |f| %> # ... # <% end %> # - # The above form will then have the id attribute with the value person_form, which you can then - # style with CSS or manipulate with JavaScript. + # The above form will then have the +id+ attribute with the value "person_form", + # which you can then style with CSS or manipulate with JavaScript. # # === Relying on record identification # - # In addition to manually configuring the form_for call, you can also rely on record identification, which will use - # the conventions and named routes of that approach. Examples: + # As we said above, in addition to manually configuring the +form_for+ call, + # you can rely on record identification, which will use the conventions and + # named routes of that approach. This is the preferred way to use +form_for+ + # nowadays: # # <% form_for(@post) do |f| %> # ... @@ -140,7 +168,7 @@ module ActionView # # This will expand to be the same as: # - # <% form_for :post, @post, :url => posts_path, :html => { :class => "new_post", :id => "new_post" } do |f| %> + # <% form_for :post, Post.new, :url => posts_path, :html => { :class => "new_post", :id => "new_post" } do |f| %> # ... # <% end %> # @@ -150,7 +178,7 @@ module ActionView # ... # <% end %> # - # And for namespaced routes, like admin_post_url: + # And for namespaced routes, like +admin_post_url+: # # <% form_for([:admin, @post]) do |f| %> # ... -- cgit v1.2.3 From 46f30f902fb5e705683dea19ec22179c61e5f208 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Fri, 16 May 2008 23:01:32 +0100 Subject: Merge documentation changes from docrails. commit 0fc3381aa5359f31b36057d7bfba2e0eb6a3c064 Author: Xavier Noria Date: Fri May 16 23:44:51 2008 +0200 Conventions. Formatting. Revising docs all over the rails. This revision encourages the modern resource-oriented form_for usage. In addition corrects some markup and other details. commit 70e4bcf5cb039bea073851faed2df9f465e6f2f8 Author: Chris Kampmeier Date: Fri May 16 12:09:46 2008 -0700 Fix a couple spelling errors in docs commit 6ea5e4208f724b50e774e6a1af027336c3ee3de1 Author: Chris O'Sullivan Date: Fri May 16 16:09:11 2008 +0100 Added docs about source_type for has_one association commit a01a0178be297b0eb62909819a15a01c6b69a841 Author: miloops Date: Wed May 14 09:22:39 2008 +0000 Change migration generator USAGE to explain the timestamped migrations behaviour commit 4e2bc02163aa646ab1304b1b5bec98a7af8927f5 Author: Xavier Noria Date: Fri May 16 00:43:03 2008 +0200 minor revision in url_for docs Made explicit that RESTful and controller/action styles are not interchangeable, and revised some markup. commit d6ecce66f4e125531875006eea8022b73fe135b5 Author: Michael Hartl Date: Thu May 15 10:46:40 2008 -0700 Expanded and updated the link_to documentation commit b8c46c86f0b785f6afc3c58eeb1b347543f5901e Author: Cody Fauser Date: Wed May 14 09:10:02 2008 -0400 Improve and cleanup ActionMailer documentation commit 9546ee299952c86329c4854f9b3776382c0575ff Author: Yehuda Katz Date: Mon May 12 23:41:43 2008 -0700 Add documentation for Inflector.inflections commit cbd5db8f5165f013069b02414f9bf762d88f619f Author: Manik Juneja Date: Mon May 12 23:43:31 2008 +0530 minor changes in railties/README. Added dbconsole introduction commit 130a280ddee1f96ccf378b52c17ee742b5e54f4a Author: Gaurav Sharma Date: Mon May 12 18:00:19 2008 +0530 adding documentation for cached_attributes commit 164c9586480f0a02522ea15ec7fb42c6a783a74d Author: TomK32 Date: Mon May 12 10:59:33 2008 +0200 proper heading for "Example:" commit 35634feb474cc55fbc95edeffe98cec241d45f23 Author: Matt Boehlig Date: Sun May 11 16:46:07 2008 -0500 Cleanup whitespace and change_table documentation commit 80bba28a1a56a0cafeb0fc94659905e88129bc31 Author: Xavier Noria Date: Sun May 11 02:54:02 2008 +0200 documented the source annotation extractor commit e6823bb1650d9b0fea58bd2d355f388961a408b3 Author: Mike Mondragon Date: Fri May 9 13:49:56 2008 -0700 Added additional information about processing email with ActionMailer and the strategy one might want to employ to do so. commit e6afd8b2736364322b673bbdcca3e9b38b6d3da0 Author: Xavier Noria Date: Thu May 8 23:49:36 2008 +0200 corrected and completed docs of increment/decrement/toggle in AR::Base commit 2fead68b3192332eee27945ed95a94a64ca73f70 Author: Austin Putman Date: Wed May 7 19:35:46 2008 -0700 Documented class methods on ActionController::Routing. These are dangerous, and mostly used for testing. commit f5b84182dbc39bea79c8ee319c688d00fa99f9d1 Author: Teflon Ted Date: Wed May 7 16:08:49 2008 -0400 Added explanation about errant inflections not being patched in the future in order to avoid breaking legacy applications. commit 370f4f51722cec49ace17093d29e9ce9e8f15cfb Author: Sunny Ripert Date: Wed May 7 14:00:59 2008 +0200 Applied list conventions in AR::Base commit 5bd18429f09d44e75191bec42a6db04bd33f3030 Author: Sunny Ripert Date: Wed May 7 13:53:35 2008 +0200 Renamed Options list to Attributes list whenever they weren't option hashes in AR::Base commit 2fa628e34b25166afb49e3afeea87e770ab84256 Author: Xavier Noria Date: Wed May 7 11:52:33 2008 +0200 revised details in Exceptions section of AR::Base docs commit d912bd5672316454457ae83f6e9dda5197beeb6f Author: Yaroslav Markin Date: Wed May 7 13:50:28 2008 +0400 Add a filter_parameter_logging usage hint to generated ApplicationController. This may help to remind the developer to filter sensitive information from application logs. Closes #11578 commit f81d771f0657ae8375b84a77a059812cce5d6fd9 Author: Jack Danger Canty Date: Tue May 6 23:35:05 2008 -0700 doc: ActiveRecord::Reflection::AssociationReflection#through_reflection Added documentation demonstrating the use of #through_reflection for finding intervening reflection objects for HasManyThrough and HasOneThrough. commit ae6b46f00b5b8b2939c6b37ce3329c83de7e71db Author: Cheah Chu Yeow Date: Wed May 7 13:47:41 2008 +0800 Document AttributeAssignmentError and MultiparameterAssignmentErrors. commit 8f463550b597db2156b67733f31aed13487fbc3a Author: John Barnette Date: Tue May 6 22:46:44 2008 -0700 Killing/fixing a bunch of outdated language in the AR README. commit 284a930a93fbee16e25d06392779dbf2f03e9e12 Author: Jonathan Dance Date: Tue May 6 14:58:26 2008 -0400 improvements to the page caching docs commit 9482da621390c874da7c921c8bd6230caae7035a Author: Sunny Ripert Date: Mon May 5 18:13:40 2008 +0200 validates_numericality_of() "integer" option really is "only_integer" commit e9afd6790a8f530528f6597a7f59bb283be754f6 Author: Sunny Ripert Date: Mon May 5 12:11:59 2008 +0200 Harmonized hash notation in AR::Base commit 67ebf14a91ffd970b582be4ff2991d691a9cf3e1 Author: Sunny Ripert Date: Mon May 5 12:06:19 2008 +0200 Turned options into rdoc-lists in AR::Base commit 0ec7c0a41d889d4e5382b9dff72f1aaba89bf297 Author: Marshall Huss Date: Sun May 4 23:21:33 2008 -0400 Added information of how to set element_name in the case the user has a name confliction with an existing model Signed-off-by: Pratik Naik --- actionmailer/README | 24 +++--- actionmailer/lib/action_mailer/base.rb | 46 ++++++----- actionpack/lib/action_controller/mime_responds.rb | 2 +- actionpack/lib/action_view/helpers/form_helper.rb | 84 +++++++++++++------- actionpack/lib/action_view/helpers/url_helper.rb | 63 ++++++++++++++- activerecord/CHANGELOG | 2 +- activerecord/lib/active_record/associations.rb | 2 + .../lib/active_record/attribute_methods.rb | 40 ++++++---- .../abstract/schema_definitions.rb | 90 +++++++++++----------- .../abstract/schema_statements.rb | 20 ++--- .../core_ext/module/attr_internal.rb | 6 +- .../active_support/core_ext/range/conversions.rb | 5 +- activesupport/lib/active_support/inflector.rb | 7 ++ railties/README | 16 +++- .../configs/initializers/new_rails_defaults.rb | 2 +- .../generators/components/migration/USAGE | 8 +- railties/lib/source_annotation_extractor.rb | 40 ++++++++++ 17 files changed, 307 insertions(+), 150 deletions(-) diff --git a/actionmailer/README b/actionmailer/README index 67e8266e92..0e16ea6ec6 100755 --- a/actionmailer/README +++ b/actionmailer/README @@ -19,8 +19,7 @@ are all set up this way. An example of such a method: recipients recipient subject "[Signed up] Welcome #{recipient}" from "system@loudthinking.com" - - body(:recipient => recipient) + body :recipient => recipient end The body of the email is created by using an Action View template (regular @@ -78,21 +77,26 @@ Example: end end -This Mailman can be the target for Postfix. In Rails, you would use the runner like this: +This Mailman can be the target for Postfix or other MTAs. In Rails, you would use the runner in the +trivial case like this: ./script/runner 'Mailman.receive(STDIN.read)' +However, invoking Rails in the runner for each mail to be received is very resource intensive. A single +instance of Rails should be run within a daemon if it is going to be utilized to process more than just +a limited number of email. + == Configuration The Base class has the full list of configuration options. Here's an example: -ActionMailer::Base.smtp_settings = { - :address=>'smtp.yourserver.com', # default: localhost - :port=>'25', # default: 25 - :user_name=>'user', - :password=>'pass', - :authentication=>:plain # :plain, :login or :cram_md5 -} + ActionMailer::Base.smtp_settings = { + :address => 'smtp.yourserver.com', # default: localhost + :port => '25', # default: 25 + :user_name => 'user', + :password => 'pass', + :authentication => :plain # :plain, :login or :cram_md5 + } == Dependencies diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index aafa26e79e..7ed133d099 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -35,7 +35,7 @@ module ActionMailer #:nodoc: # * subject - The subject of your email. Sets the Subject: header. # * from - Who the email you are sending is from. Sets the From: header. # * cc - Takes one or more email addresses. These addresses will receive a carbon copy of your email. Sets the Cc: header. - # * bcc - Takes one or more email address. These addresses will receive a blind carbon copy of your email. Sets the Bcc header. + # * bcc - Takes one or more email address. These addresses will receive a blind carbon copy of your email. Sets the Bcc: header. # * sent_on - The date on which the message was sent. If not set, the header wil be set by the delivery agent. # * content_type - Specify the content type of the message. Defaults to text/plain. # * headers - Specify additional headers to be set for the message, e.g. headers 'X-Mail-Count' => 107370. @@ -127,11 +127,11 @@ module ActionMailer #:nodoc: # # class MyMailer < ActionMailer::Base # def signup_notification(recipient) - # recipients recipient.email_address_with_name - # subject "New account information" - # body "account" => recipient - # from "system@example.com" - # content_type "text/html" # Here's where the magic happens + # recipients recipient.email_address_with_name + # subject "New account information" + # from "system@example.com" + # body :account => recipient + # content_type "text/html" # end # end # @@ -145,6 +145,7 @@ module ActionMailer #:nodoc: # recipients recipient.email_address_with_name # subject "New account information" # from "system@example.com" + # content_type "multipart/alternative" # # part :content_type => "text/html", # :body => render_message("signup-as-html", :account => recipient) @@ -167,9 +168,14 @@ module ActionMailer #:nodoc: # * signup_notification.text.x-yaml.erb # # Each would be rendered and added as a separate part to the message, - # with the corresponding content type. The same body hash is passed to - # each template. + # with the corresponding content type. The content type for the entire + # message is automatically set to multipart/alternative, which indicates + # that the email contains multiple different representations of the same email + # body. The same body hash is passed to each template. # + # Implicit template rendering is not performed if any attachments or parts have been added to the email. + # This means that you'll have to manually add each part to the email and set the content type of the email + # to multipart/alternative. # # = Attachments # @@ -209,12 +215,12 @@ module ActionMailer #:nodoc: # * :domain - If you need to specify a HELO domain, you can do it here. # * :user_name - If your mail server requires authentication, set the username in this setting. # * :password - If your mail server requires authentication, set the password in this setting. - # * :authentication - If your mail server requires authentication, you need to specify the authentication type here. - # This is a symbol and one of :plain, :login, :cram_md5 + # * :authentication - If your mail server requires authentication, you need to specify the authentication type here. + # This is a symbol and one of :plain, :login, :cram_md5. # - # * sendmail_settings - Allows you to override options for the :sendmail delivery method - # * :location - The location of the sendmail executable, defaults to "/usr/sbin/sendmail" - # * :arguments - The command line arguments + # * sendmail_settings - Allows you to override options for the :sendmail delivery method. + # * :location - The location of the sendmail executable. Defaults to /usr/sbin/sendmail. + # * :arguments - The command line arguments. Defaults to -i -t. # # * raise_delivery_errors - Whether or not errors should be raised if the email fails to be delivered. # @@ -226,17 +232,17 @@ module ActionMailer #:nodoc: # * deliveries - Keeps an array of all the emails sent out through the Action Mailer with delivery_method :test. Most useful # for unit and functional testing. # - # * default_charset - The default charset used for the body and to encode the subject. Defaults to UTF-8. You can also - # pick a different charset from inside a method with @charset. + # * default_charset - The default charset used for the body and to encode the subject. Defaults to UTF-8. You can also + # pick a different charset from inside a method with +charset+. # * default_content_type - The default content type used for the main part of the message. Defaults to "text/plain". You - # can also pick a different content type from inside a method with @content_type. - # * default_mime_version - The default mime version used for the message. Defaults to "1.0". You - # can also pick a different value from inside a method with @mime_version. + # can also pick a different content type from inside a method with +content_type+. + # * default_mime_version - The default mime version used for the message. Defaults to 1.0. You + # can also pick a different value from inside a method with +mime_version+. # * default_implicit_parts_order - When a message is built implicitly (i.e. multiple parts are assembled from templates # which specify the content type in their filenames) this variable controls how the parts are ordered. Defaults to - # ["text/html", "text/enriched", "text/plain"]. Items that appear first in the array have higher priority in the mail client + # ["text/html", "text/enriched", "text/plain"]. Items that appear first in the array have higher priority in the mail client # and appear last in the mime encoded message. You can also pick a different order from inside a method with - # @implicit_parts_order. + # +implicit_parts_order+. class Base include AdvAttrAccessor, PartContainer include ActionController::UrlWriter if Object.const_defined?(:ActionController) diff --git a/actionpack/lib/action_controller/mime_responds.rb b/actionpack/lib/action_controller/mime_responds.rb index a17782cafc..1dbd8b9e6f 100644 --- a/actionpack/lib/action_controller/mime_responds.rb +++ b/actionpack/lib/action_controller/mime_responds.rb @@ -92,7 +92,7 @@ module ActionController #:nodoc: # with the remaining data. # # Note that you can define your own XML parameter parser which would allow you to describe multiple entities - # in a single request (i.e., by wrapping them all in a single root note), but if you just go with the flow + # in a single request (i.e., by wrapping them all in a single root node), but if you just go with the flow # and accept Rails' defaults, life will be much easier. # # If you need to use a MIME type which isn't supported by default, you can register your own handlers in diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index b8600fe445..6d97038da9 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -73,30 +73,54 @@ module ActionView # There are also methods for helping to build form tags in link:classes/ActionView/Helpers/FormOptionsHelper.html, # link:classes/ActionView/Helpers/DateHelper.html, and link:classes/ActionView/Helpers/ActiveRecordHelper.html module FormHelper - # Creates a form and a scope around a specific model object that is used as a base for questioning about - # values for the fields. + # Creates a form and a scope around a specific model object that is used as + # a base for questioning about values for the fields. # - # <% form_for :person, @person, :url => { :action => "update" } do |f| %> - # <%= f.error_messages %> - # First name: <%= f.text_field :first_name %> - # Last name : <%= f.text_field :last_name %> - # Biography : <%= f.text_area :biography %> - # Admin? : <%= f.check_box :admin %> + # Rails provides succint resource-oriented form generation with +form_for+ + # like this: + # + # <% form_for @offer do |f| %> + # <%= f.label :version, 'Version' %>: + # <%= f.text_field :version %>
+ # <%= f.label :author, 'Author' %>: + # <%= f.text_field :author %>
# <% end %> # - # Worth noting is that the form_for tag is called in a ERb evaluation block, not an ERb output block. So that's <% %>, - # not <%= %>. Also worth noting is that form_for yields a form_builder object, in this example as f, which emulates - # the API for the stand-alone FormHelper methods, but without the object name. So instead of text_field :person, :name, - # you get away with f.text_field :name. Notice that you can even do <%= f.error_messages %> to display the - # error messsages of the model object in question. + # There, +form_for+ is able to generate the rest of RESTful parameters + # based on introspection on the record, but to understand what it does we + # need to dig first into the alternative generic usage it is based upon. + # + # === Generic form_for # - # Even further, the form_for method allows you to more easily escape the instance variable convention. So while the stand-alone - # approach would require text_field :person, :name, :object => person - # to work with local variables instead of instance ones, the form_for calls remain the same. You simply declare once with - # :person, person and all subsequent field calls save :person and :object => person. + # The generic way to call +form_for+ requires a few arguments: # - # Also note that form_for doesn't create an exclusive scope. It's still possible to use both the stand-alone FormHelper methods - # and methods from FormTagHelper. For example: + # <% form_for :person, @person, :url => { :action => "update" } do |f| %> + # <%= f.error_messages %> + # First name: <%= f.text_field :first_name %>
+ # Last name : <%= f.text_field :last_name %>
+ # Biography : <%= f.text_area :biography %>
+ # Admin? : <%= f.check_box :admin %>
+ # <% end %> + # + # Worth noting is that the +form_for+ tag is called in a ERb evaluation block, + # not an ERb output block. So that's <% %>, not <%= %>. Also + # worth noting is that +form_for+ yields a form builder object, in this + # example as +f+, which emulates the API for the stand-alone FormHelper + # methods, but without the object name. So instead of text_field :person, :name, + # you get away with f.text_field :name. Notice that you can even do + # <%= f.error_messages %> to display the error messsages of the model + # object in question. + # + # Even further, the +form_for+ method allows you to more easily escape the + # instance variable convention. So while the stand-alone approach would require + # text_field :person, :name, :object => person to work with local + # variables instead of instance ones, the +form_for+ calls remain the same. + # You simply declare once with :person, person and all subsequent + # field calls save :person and :object => person. + # + # Also note that +form_for+ doesn't create an exclusive scope. It's still + # possible to use both the stand-alone FormHelper methods and methods from + # FormTagHelper. For example: # # <% form_for :person, @person, :url => { :action => "update" } do |f| %> # First name: <%= f.text_field :first_name %> @@ -105,22 +129,26 @@ module ActionView # Admin? : <%= check_box_tag "person[admin]", @person.company.admin? %> # <% end %> # - # Note: This also works for the methods in FormOptionHelper and DateHelper that are designed to work with an object as base, - # like FormOptionHelper#collection_select and DateHelper#datetime_select. + # This also works for the methods in FormOptionHelper and DateHelper that are + # designed to work with an object as base, like FormOptionHelper#collection_select + # and DateHelper#datetime_select. # - # HTML attributes for the form tag can be given as :html => {...}. For example: + # HTML attributes for the form tag can be given as :html => {...}. + # For example: # # <% form_for :person, @person, :html => {:id => 'person_form'} do |f| %> # ... # <% end %> # - # The above form will then have the id attribute with the value person_form, which you can then - # style with CSS or manipulate with JavaScript. + # The above form will then have the +id+ attribute with the value "person_form", + # which you can then style with CSS or manipulate with JavaScript. # # === Relying on record identification # - # In addition to manually configuring the form_for call, you can also rely on record identification, which will use - # the conventions and named routes of that approach. Examples: + # As we said above, in addition to manually configuring the +form_for+ call, + # you can rely on record identification, which will use the conventions and + # named routes of that approach. This is the preferred way to use +form_for+ + # nowadays: # # <% form_for(@post) do |f| %> # ... @@ -140,7 +168,7 @@ module ActionView # # This will expand to be the same as: # - # <% form_for :post, @post, :url => posts_path, :html => { :class => "new_post", :id => "new_post" } do |f| %> + # <% form_for :post, Post.new, :url => posts_path, :html => { :class => "new_post", :id => "new_post" } do |f| %> # ... # <% end %> # @@ -150,7 +178,7 @@ module ActionView # ... # <% end %> # - # And for namespaced routes, like admin_post_url: + # And for namespaced routes, like +admin_post_url+: # # <% form_for([:admin, @post]) do |f| %> # ... diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index 375ebfcdc5..38c8d18cb0 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -120,17 +120,72 @@ module ActionView # exception. # # ==== Examples + # Because it relies on +url_for+, +link_to+ supports both older-style controller/action/id arguments + # and newer RESTful routes. Current Rails style favors RESTful routes whenever possible, so base + # your application on resources and use + # + # link_to "Profile", profile_path(@profile) + # # => Profile + # + # or the even pithier + # + # link_to "Profile", @profile + # # => Profile + # + # in place of the older more verbose, non-resource-oriented + # + # link_to "Profile", :controller => "profiles", :action => "show", :id => @profile + # # => Profile + # + # Similarly, + # + # link_to "Profiles", profiles_path + # # => Profiles + # + # is better than + # + # link_to "Profiles", :controller => "profiles" + # # => Profiles + # + # Classes and ids for CSS are easy to produce: + # + # link_to "Articles", articles_path, :id => "news", :class => "article" + # # => Articles + # + # Be careful when using the older argument style, as an extra literal hash is needed: + # + # link_to "Articles", { :controller => "articles" }, :id => "news", :class => "article" + # # => Articles + # + # Leaving the hash off gives the wrong link: + # + # link_to "WRONG!", :controller => "articles", :id => "news", :class => "article" + # # => WRONG! + # + # +link_to+ can also produce links with anchors or query strings: + # + # link_to "Comment wall", profile_path(@profile, :anchor => "wall") + # # => Comment wall + # + # link_to "Ruby on Rails search", :controller => "searches", :query => "ruby on rails" + # # => Ruby on Rails search + # + # link_to "Nonsense search", searches_path(:foo => "bar", :baz => "quux") + # # => Nonsense search + # + # The three options specfic to +link_to+ (:confirm, :popup, and :method) are used as follows: + # # link_to "Visit Other Site", "http://www.rubyonrails.org/", :confirm => "Are you sure?" # # => Visit Other Site # # link_to "Help", { :action => "help" }, :popup => true # # => Help # - # link_to "View Image", { :action => "view" }, :popup => ['new_window_name', 'height=300,width=600'] - # # => View Image + # link_to "View Image", @image, :popup => ['new_window_name', 'height=300,width=600'] + # # => View Image # - # link_to "Delete Image", { :action => "delete", :id => @image.id }, :confirm => "Are you sure?", :method => :delete - # # => "Are you sure?", :method => :delete + # # => Delete Image diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 9b936863ba..cd526a52a7 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -12,7 +12,7 @@ change_table :videos do |t| t.timestamps # adds created_at, updated_at - t.belongs_to :goat # add goat_id integer + t.belongs_to :goat # adds goat_id integer t.string :name, :email, :limit => 20 # adds name and email both with a 20 char limit t.remove :name, :email # removes the name and email columns end diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index c17e35f5e0..95caf68692 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -753,6 +753,8 @@ module ActiveRecord # * :source - Specifies the source association name used by has_one :through queries. Only use it if the name cannot be # inferred from the association. has_one :favorite, :through => :favorites will look for a # :favorite on Favorite, unless a :source is given. + # * :source_type - Specifies type of the source association used by has_one :through queries where the source + # association is a polymorphic +belongs_to+. # * :readonly - If true, the associated object is readonly through the association. # # Option examples: diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 2db27226f2..c2604894a8 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -16,16 +16,20 @@ module ActiveRecord # Declare and check for suffixed attribute methods. module ClassMethods - # Declare a method available for all attributes with the given suffix. - # Uses method_missing and respond_to? to rewrite the method + # Declares a method available for all attributes with the given suffix. + # Uses +method_missing+ and respond_to? to rewrite the method + # # #{attr}#{suffix}(*args, &block) + # # to + # # attribute#{suffix}(#{attr}, *args, &block) # - # An attribute#{suffix} instance method must exist and accept at least - # the attr argument. + # An attribute#{suffix} instance method must exist and accept at least + # the +attr+ argument. # # For example: + # # class Person < ActiveRecord::Base # attribute_method_suffix '_changed?' # @@ -60,8 +64,8 @@ module ActiveRecord !generated_methods.empty? end - # generates all the attribute related methods for columns in the database - # accessors, mutators and query methods + # Generates all the attribute related methods for columns in the database + # accessors, mutators and query methods. def define_attribute_methods return if generated_methods? columns_hash.each do |name, column| @@ -89,8 +93,9 @@ module ActiveRecord end end - # Check to see if the method is defined in the model or any of its subclasses that also derive from ActiveRecord. - # Raise DangerousAttributeError if the method is defined by ActiveRecord though. + # Checks whether the method is defined in the model or any of its subclasses + # that also derive from ActiveRecord. Raises DangerousAttributeError if the + # method is defined by Active Record though. def instance_method_already_implemented?(method_name) method_name = method_name.to_s return true if method_name =~ /^id(=$|\?$|$)/ @@ -104,17 +109,19 @@ module ActiveRecord # +cache_attributes+ allows you to declare which converted attribute values should # be cached. Usually caching only pays off for attributes with expensive conversion - # methods, like date columns (e.g. created_at, updated_at). + # methods, like time related columns (e.g. +created_at+, +updated_at+). def cache_attributes(*attribute_names) attribute_names.each {|attr| cached_attributes << attr.to_s} end - # returns the attributes where + # Returns the attributes which are cached. By default time related columns + # with datatype :datetime, :timestamp, :time, :date are cached. def cached_attributes @cached_attributes ||= columns.select{|c| attribute_types_cached_by_default.include?(c.type)}.map(&:name).to_set end + # Returns +true+ if the provided attribute is being cached. def cache_attribute?(attr_name) cached_attributes.include?(attr_name) end @@ -210,14 +217,14 @@ module ActiveRecord end # ClassMethods - # Allows access to the object attributes, which are held in the @attributes hash, as though they + # Allows access to the object attributes, which are held in the @attributes hash, as though they # were first-class methods. So a Person class with a name attribute can use Person#name and # Person#name= and never directly use the attributes hash -- except for multiple assigns with # ActiveRecord#attributes=. A Milestone class can also ask Milestone#completed? to test that - # the completed attribute is not nil or 0. + # the completed attribute is not +nil+ or 0. # # It's also possible to instantiate related objects, so a Client class belonging to the clients - # table with a master_id foreign key can instantiate master through Client#master. + # table with a +master_id+ foreign key can instantiate master through Client#master. def method_missing(method_id, *args, &block) method_name = method_id.to_s @@ -288,7 +295,7 @@ module ActiveRecord # Updates the attribute identified by attr_name with the specified +value+. Empty strings for fixnum and float - # columns are turned into nil. + # columns are turned into +nil+. def write_attribute(attr_name, value) attr_name = attr_name.to_s @attributes_cache.delete(attr_name) @@ -319,8 +326,9 @@ module ActiveRecord end end - # A Person object with a name attribute can ask person.respond_to?("name"), person.respond_to?("name="), and - # person.respond_to?("name?") which will all return true. + # A Person object with a name attribute can ask person.respond_to?("name"), + # person.respond_to?("name="), and person.respond_to?("name?") + # which will all return +true+. alias :respond_to_without_attributes? :respond_to? def respond_to?(method, include_priv = false) method_name = method.to_s diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index d73ffc3da6..fdb18b234c 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -18,11 +18,11 @@ module ActiveRecord # # +name+ is the column's name, as in supplier_id int(11). # +default+ is the type-casted default value, such as sales_stage varchar(20) default 'new'. - # +sql_type+ is only used to extract the column's length, if necessary. For example, company_name varchar(60). + # +sql_type+ is only used to extract the column's length, if necessary. For example, company_name varchar(60). # +null+ determines if this column allows +NULL+ values. def initialize(name, default, sql_type = nil, null = true) @name, @sql_type, @null = name, sql_type, null - @limit, @precision, @scale = extract_limit(sql_type), extract_precision(sql_type), extract_scale(sql_type) + @limit, @precision, @scale = extract_limit(sql_type), extract_precision(sql_type), extract_scale(sql_type) @type = simplified_type(sql_type) @default = extract_default(default) @@ -172,7 +172,7 @@ module ActiveRecord def new_time(year, mon, mday, hour, min, sec, microsec) # Treat 0000-00-00 00:00:00 as nil. return nil if year.nil? || year == 0 - + Time.time_with_datetime_fallback(Base.default_timezone, year, mon, mday, hour, min, sec, microsec) rescue nil end @@ -250,11 +250,11 @@ module ActiveRecord end class ColumnDefinition < Struct.new(:base, :name, :type, :limit, :precision, :scale, :default, :null) #:nodoc: - + def sql_type base.type_to_sql(type.to_sym, limit, precision, scale) rescue type end - + def to_sql column_sql = "#{base.quote_column_name(name)} #{sql_type}" add_column_options!(column_sql, :null => null, :default => default) unless type.to_sym == :primary_key @@ -309,39 +309,39 @@ module ActiveRecord # * :default - # The column's default value. Use nil for NULL. # * :null - - # Allows or disallows +NULL+ values in the column. This option could + # Allows or disallows +NULL+ values in the column. This option could # have been named :null_allowed. # * :precision - - # Specifies the precision for a :decimal column. + # Specifies the precision for a :decimal column. # * :scale - - # Specifies the scale for a :decimal column. + # Specifies the scale for a :decimal column. # # Please be aware of different RDBMS implementations behavior with # :decimal columns: # * The SQL standard says the default scale should be 0, :scale <= # :precision, and makes no comments about the requirements of # :precision. - # * MySQL: :precision [1..63], :scale [0..30]. + # * MySQL: :precision [1..63], :scale [0..30]. # Default is (10,0). - # * PostgreSQL: :precision [1..infinity], + # * PostgreSQL: :precision [1..infinity], # :scale [0..infinity]. No default. - # * SQLite2: Any :precision and :scale may be used. + # * SQLite2: Any :precision and :scale may be used. # Internal storage as strings. No default. # * SQLite3: No restrictions on :precision and :scale, # but the maximum supported :precision is 16. No default. - # * Oracle: :precision [1..38], :scale [-84..127]. + # * Oracle: :precision [1..38], :scale [-84..127]. # Default is (38,0). - # * DB2: :precision [1..63], :scale [0..62]. + # * DB2: :precision [1..63], :scale [0..62]. # Default unknown. - # * Firebird: :precision [1..18], :scale [0..18]. + # * Firebird: :precision [1..18], :scale [0..18]. # Default (9,0). Internal types NUMERIC and DECIMAL have different # storage rules, decimal being better. - # * FrontBase?: :precision [1..38], :scale [0..38]. + # * FrontBase?: :precision [1..38], :scale [0..38]. # Default (38,0). WARNING Max :precision/:scale for # NUMERIC is 19, and DECIMAL is 38. - # * SqlServer?: :precision [1..38], :scale [0..38]. + # * SqlServer?: :precision [1..38], :scale [0..38]. # Default (38,0). - # * Sybase: :precision [1..38], :scale [0..38]. + # * Sybase: :precision [1..38], :scale [0..38]. # Default (38,0). # * OpenBase?: Documentation unclear. Claims storage in double. # @@ -394,7 +394,7 @@ module ActiveRecord # t.timestamps # end # - # There's a short-hand method for each of the type values declared at the top. And then there's + # There's a short-hand method for each of the type values declared at the top. And then there's # TableDefinition#timestamps that'll add created_at and updated_at as datetimes. # # TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type @@ -434,13 +434,13 @@ module ActiveRecord def #{column_type}(*args) options = args.extract_options! column_names = args - + column_names.each { |name| column(name, '#{column_type}', options) } end EOV end - - # Appends :datetime columns :created_at and + + # Appends :datetime columns :created_at and # :updated_at to the table. def timestamps column(:created_at, :datetime) @@ -458,7 +458,7 @@ module ActiveRecord alias :belongs_to :references # Returns a String whose contents are the column definitions - # concatenated together. This string can then be prepended and appended to + # concatenated together. This string can then be prepended and appended to # to generate the final SQL to create the table. def to_sql @columns * ', ' @@ -510,15 +510,15 @@ module ActiveRecord # Adds a new column to the named table. # See TableDefinition#column for details of the options you can use. - # ===== Examples - # ====== Creating a simple columns + # ===== Example + # ====== Creating a simple column # t.column(:name, :string) def column(column_name, type, options = {}) @base.add_column(@table_name, column_name, type, options) end - # Adds a new index to the table. +column_name+ can be a single Symbol, or - # an Array of Symbols. See SchemaStatements#add_index + # Adds a new index to the table. +column_name+ can be a single Symbol, or + # an Array of Symbols. See SchemaStatements#add_index # # ===== Examples # ====== Creating a simple index @@ -531,8 +531,8 @@ module ActiveRecord @base.add_index(@table_name, column_name, options) end - # Adds timestamps (created_at and updated_at) columns to the table. See SchemaStatements#timestamps - # ===== Examples + # Adds timestamps (created_at and updated_at) columns to the table. See SchemaStatements#add_timestamps + # ===== Example # t.timestamps def timestamps @base.add_timestamps(@table_name) @@ -547,7 +547,7 @@ module ActiveRecord @base.change_column(@table_name, column_name, type, options) end - # Sets a new default value for a column. See + # Sets a new default value for a column. See SchemaStatements#change_column_default # ===== Examples # t.change_default(:qualification, 'new') # t.change_default(:authorized, 1) @@ -559,27 +559,27 @@ module ActiveRecord # ===== Examples # t.remove(:qualification) # t.remove(:qualification, :experience) - # t.removes(:qualification, :experience) def remove(*column_names) @base.remove_column(@table_name, column_names) end - # Remove the given index from the table. + # Removes the given index from the table. # - # Remove the suppliers_name_index in the suppliers table. + # ===== Examples + # ====== Remove the suppliers_name_index in the suppliers table # t.remove_index :name - # Remove the index named accounts_branch_id_index in the accounts table. + # ====== Remove the index named accounts_branch_id_index in the accounts table # t.remove_index :column => :branch_id - # Remove the index named accounts_branch_id_party_id_index in the accounts table. + # ====== Remove the index named accounts_branch_id_party_id_index in the accounts table # t.remove_index :column => [:branch_id, :party_id] - # Remove the index named by_branch_party in the accounts table. + # ====== Remove the index named by_branch_party in the accounts table # t.remove_index :name => :by_branch_party def remove_index(options = {}) @base.remove_index(@table_name, options) end # Removes the timestamp columns (created_at and updated_at) from the table. - # ===== Examples + # ===== Example # t.remove_timestamps def remove_timestamps @base.remove_timestamps(@table_name) @@ -592,12 +592,11 @@ module ActiveRecord @base.rename_column(@table_name, column_name, new_column_name) end - # Adds a reference. Optionally adds a +type+ column. reference, - # references and belongs_to are all acceptable - # ===== Example + # Adds a reference. Optionally adds a +type+ column. + # references and belongs_to are acceptable. + # ===== Examples # t.references(:goat) # t.references(:goat, :polymorphic => true) - # t.references(:goat) # t.belongs_to(:goat) def references(*args) options = args.extract_options! @@ -609,12 +608,11 @@ module ActiveRecord end alias :belongs_to :references - # Adds a reference. Optionally removes a +type+ column. remove_reference, - # remove_references and remove_belongs_to are all acceptable - # ===== Example - # t.remove_reference(:goat) - # t.remove_reference(:goat, :polymorphic => true) + # Removes a reference. Optionally removes a +type+ column. + # remove_references and remove_belongs_to are acceptable. + # ===== Examples # t.remove_references(:goat) + # t.remove_references(:goat, :polymorphic => true) # t.remove_belongs_to(:goat) def remove_references(*args) options = args.extract_options! @@ -627,7 +625,7 @@ module ActiveRecord alias :remove_belongs_to :remove_references # Adds a column or columns of a specified type - # ===== Example + # ===== Examples # t.string(:goat) # t.string(:goat, :sheep) %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type| diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 1594be40e2..ac24e920fe 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -13,7 +13,7 @@ module ActiveRecord 255 end - # Truncates a table alias according to the limits of the current adapter. + # Truncates a table alias according to the limits of the current adapter. def table_alias_for(table_name) table_name[0..table_alias_length-1].gsub(/\./, '_') end @@ -152,7 +152,7 @@ module ActiveRecord # t.remove :company # end # - # ====== Remove a column + # ====== Remove several columns # change_table(:suppliers) do |t| # t.remove :company_id # t.remove :width, :height @@ -168,7 +168,7 @@ module ActiveRecord def change_table(table_name) yield Table.new(table_name, self) end - + # Renames a table. # ===== Example # rename_table('octopuses', 'octopi') @@ -199,7 +199,7 @@ module ActiveRecord end end alias :remove_columns :remove_column - + # Changes the column's definition according to the new options. # See TableDefinition#column for details of the options you can use. # ===== Examples @@ -389,7 +389,7 @@ module ActiveRecord def distinct(columns, order_by) "DISTINCT #{columns}" end - + # ORDER BY clause for the passed order option. # PostgreSQL overrides this due to its stricter standards compliance. def add_order_by_for_association_limiting!(sql, options) @@ -401,17 +401,17 @@ module ActiveRecord # add_timestamps(:suppliers) def add_timestamps(table_name) add_column table_name, :created_at, :datetime - add_column table_name, :updated_at, :datetime + add_column table_name, :updated_at, :datetime end - + # Removes the timestamp columns (created_at and updated_at) from the table definition. # ===== Examples # remove_timestamps(:suppliers) def remove_timestamps(table_name) - remove_column table_name, :updated_at - remove_column table_name, :created_at + remove_column table_name, :updated_at + remove_column table_name, :created_at end - + protected def options_include_default?(options) options.include?(:default) && !(options[:null] == false && options[:default].nil?) diff --git a/activesupport/lib/active_support/core_ext/module/attr_internal.rb b/activesupport/lib/active_support/core_ext/module/attr_internal.rb index e0be31090c..b66c0d7500 100644 --- a/activesupport/lib/active_support/core_ext/module/attr_internal.rb +++ b/activesupport/lib/active_support/core_ext/module/attr_internal.rb @@ -1,19 +1,19 @@ class Module - # Declare an attribute reader backed by an internally-named instance variable. + # Declares 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. + # Declares 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 an attribute reader and writer backed by an internally-named instance + # Declares an attribute reader and writer backed by an internally-named instance # variable. def attr_internal_accessor(*attrs) attr_internal_reader(*attrs) diff --git a/activesupport/lib/active_support/core_ext/range/conversions.rb b/activesupport/lib/active_support/core_ext/range/conversions.rb index 8d757646d3..932bdedad3 100644 --- a/activesupport/lib/active_support/core_ext/range/conversions.rb +++ b/activesupport/lib/active_support/core_ext/range/conversions.rb @@ -15,10 +15,9 @@ module ActiveSupport #:nodoc: end # Gives a human readable format of the range. # - # Example: + # ==== Example: # - # >> [1..100].to_formatted_s - # => "1..100" + # [1..100].to_formatted_s # => "1..100" def to_formatted_s(format = :default) RANGE_FORMATS[format] ? RANGE_FORMATS[format].call(first, last) : to_default_s end diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb index 68fbf3da35..0fd44324bb 100644 --- a/activesupport/lib/active_support/inflector.rb +++ b/activesupport/lib/active_support/inflector.rb @@ -92,6 +92,13 @@ module Inflector extend self + # Yields a singleton instance of Inflector::Inflections so you can specify additional + # inflector rules. + # + # Example: + # Inflector.inflections do |inflect| + # inflect.uncountable "rails" + # end def inflections if block_given? yield Inflections.instance diff --git a/railties/README b/railties/README index b5f4eee4b7..2af0fb1133 100644 --- a/railties/README +++ b/railties/README @@ -145,7 +145,9 @@ and also on programming in general. Debugger support is available through the debugger command when you start your Mongrel or Webrick server with --debugger. This means that you can break out of execution at any point -in the code, investigate and change the model, AND then resume execution! Example: +in the code, investigate and change the model, AND then resume execution! +You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug' +Example: class WeblogController < ActionController::Base def index @@ -183,6 +185,13 @@ Passing an argument will specify a different environment, like script/consol To reload your controllers and models after launching the console run reload! +== dbconsole + +You can go to the command line of your database directly through script/dbconsole. +You would be connected to the database with the credentials defined in database.yml. +Starting the script without arguments will connect you to the development database. Passing an +argument will connect you to a different database, like script/dbconsole production. +Currently works for mysql, postgresql and sqlite. == Description of Contents @@ -200,13 +209,13 @@ app/models app/views Holds the template files for the view that should be named like - weblogs/index.erb for the WeblogsController#index action. All views use eRuby + weblogs/index.html.erb for the WeblogsController#index action. All views use eRuby syntax. app/views/layouts Holds the template files for layouts to be used with views. This models the common header/footer method of wrapping views. In your views, define a layout using the - layout :default and create a file named default.erb. Inside default.erb, + layout :default and create a file named default.html.erb. Inside default.html.erb, call <% yield %> to render the view using this layout. app/helpers @@ -243,4 +252,5 @@ test vendor External libraries that the application depends on. Also includes the plugins subdirectory. + If the app has frozen rails, those gems also go here, under vendor/rails/. This directory is in the load path. diff --git a/railties/configs/initializers/new_rails_defaults.rb b/railties/configs/initializers/new_rails_defaults.rb index b8f0e2cac2..1a718608ae 100644 --- a/railties/configs/initializers/new_rails_defaults.rb +++ b/railties/configs/initializers/new_rails_defaults.rb @@ -1,4 +1,4 @@ -# These settins change the behavior of Rails 2 apps and will be defaults +# These settings change the behavior of Rails 2 apps and will be defaults # for Rails 3. You can remove this initializer when Rails 3 is released. # Only save the attributes that have changed since the record was loaded. diff --git a/railties/lib/rails_generator/generators/components/migration/USAGE b/railties/lib/rails_generator/generators/components/migration/USAGE index 3e914a5d7b..b83c657963 100644 --- a/railties/lib/rails_generator/generators/components/migration/USAGE +++ b/railties/lib/rails_generator/generators/components/migration/USAGE @@ -2,7 +2,7 @@ Description: Stubs out a new database migration. Pass the migration name, either CamelCased or under_scored, and an optional list of attribute pairs as arguments. - A migration class is generated in db/migrate prefixed by the latest migration number. + A migration class is generated in db/migrate prefixed by a timestamp of the current date and time. You can name your migration in either of these formats to generate add/remove column lines from supplied attributes: AddColumnsToTable or RemoveColumnsFromTable @@ -10,12 +10,12 @@ Description: Example: `./script/generate migration AddSslFlag` - With 4 existing migrations, this creates the AddSslFlag migration in - db/migrate/005_add_ssl_flag.rb + If the current date is May 14, 2008 and the current time 09:09:12, this creates the AddSslFlag migration + db/migrate/20080514090912_add_ssl_flag.rb `./script/generate migration AddTitleBodyToPost title:string body:text published:boolean` - This will create the AddTitleBodyToPost in db/migrate/005_add_title_body_to_post.rb with + This will create the AddTitleBodyToPost in db/migrate/20080514090912_add_title_body_to_post.rb with this in the Up migration: add_column :posts, :title, :string diff --git a/railties/lib/source_annotation_extractor.rb b/railties/lib/source_annotation_extractor.rb index 8844226536..591fd6f6bd 100644 --- a/railties/lib/source_annotation_extractor.rb +++ b/railties/lib/source_annotation_extractor.rb @@ -1,5 +1,26 @@ +# Implements the logic behind the rake tasks for annotations like +# +# rake notes +# rake notes:optimize +# +# and friends. See rake -T notes and railties/lib/tasks/annotations.rake. +# +# Annotation objects are triplets :line, :tag, :text that +# represent the line where the annotation lives, its tag, and its text. Note +# the filename is not stored. +# +# Annotations are looked for in comments and modulus whitespace they have to +# start with the tag optionally followed by a colon. Everything up to the end +# of the line (or closing ERb comment tag) is considered to be their text. class SourceAnnotationExtractor class Annotation < Struct.new(:line, :tag, :text) + + # Returns a representation of the annotation that looks like this: + # + # [126] [TODO] This algorithm is simple and clearly correct, make it faster. + # + # If +options+ has a flag :tag the tag is shown as in the example above. + # Otherwise the string contains just line and text. def to_s(options={}) s = "[%3d] " % line s << "[#{tag}] " if options[:tag] @@ -7,6 +28,12 @@ class SourceAnnotationExtractor end end + # Prints all annotations with tag +tag+ under the root directories +app+, +lib+, + # and +test+ (recursively). Only filenames with extension +.builder+, +.rb+, + # +.rxml+, +.rjs+, +.rhtml+, or +.erb+ are taken into account. The +options+ + # hash is passed to each annotation's +to_s+. + # + # This class method is the single entry point for the rake tasks. def self.enumerate(tag, options={}) extractor = new(tag) extractor.display(extractor.find, options) @@ -18,10 +45,18 @@ class SourceAnnotationExtractor @tag = tag end + # Returns a hash that maps filenames under +dirs+ (recursively) to arrays + # with their annotations. Only files with annotations are included, and only + # those with extension +.builder+, +.rb+, +.rxml+, +.rjs+, +.rhtml+, and +.erb+ + # are taken into account. def find(dirs=%w(app lib test)) dirs.inject({}) { |h, dir| h.update(find_in(dir)) } end + # Returns a hash that maps filenames under +dir+ (recursively) to arrays + # with their annotations. Only files with annotations are included, and only + # those with extension +.builder+, +.rb+, +.rxml+, +.rjs+, +.rhtml+, and +.erb+ + # are taken into account. def find_in(dir) results = {} @@ -40,6 +75,9 @@ class SourceAnnotationExtractor results end + # If +file+ is the filename of a file that contains annotations this method returns + # a hash with a single entry that maps +file+ to an array of its annotations. + # Otherwise it returns an empty hash. def extract_annotations_from(file, pattern) lineno = 0 result = File.readlines(file).inject([]) do |list, line| @@ -50,6 +88,8 @@ class SourceAnnotationExtractor result.empty? ? {} : { file => result } end + # Prints the mapping from filenames to annotations in +results+ ordered by filename. + # The +options+ hash is passed to each annotation's +to_s+. def display(results, options={}) results.keys.sort.each do |file| puts "#{file}:" -- cgit v1.2.3 From 72ed17df44e194674ec9a83a5504db53e3426a8e Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Sat, 17 May 2008 12:35:55 +1200 Subject: ignore pkg too --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index d19b982f85..e57310cdc8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,9 @@ actionpack/doc actionmailer/doc activesupport/doc railties/doc +activeresource/pkg +activerecord/pkg +actionpack/pkg +actionmailer/pkg +activesupport/pkg +railties/pkg -- cgit v1.2.3 From 2183c220ada046993274ccdc6f1f86e9e8a3a5c6 Mon Sep 17 00:00:00 2001 From: Steven Soroka Date: Fri, 16 May 2008 17:41:59 -0500 Subject: Make sure clone_structure can load the results of dump_schema_information SchemaStatements#dump_schema_information joins inserts with a single \n, but is later split on \n\n, and fails when trying to execute all the inserts as a single sql statement. Signed-off-by: Michael Koziarski [#201 state:resolved] --- .../lib/active_record/connection_adapters/abstract/schema_statements.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index ac24e920fe..b57d0a3ef7 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -302,7 +302,7 @@ module ActiveRecord def dump_schema_information #:nodoc: sm_table = ActiveRecord::Migrator.schema_migrations_table_name migrated = select_values("SELECT version FROM #{sm_table}") - migrated.map { |v| "INSERT INTO #{sm_table} (version) VALUES ('#{v}');" }.join("\n") + migrated.map { |v| "INSERT INTO #{sm_table} (version) VALUES ('#{v}');" }.join("\n\n") end # Should not be called normally, but this operation is non-destructive. -- cgit v1.2.3 From e535c037e3bb8e78d873b9330900dce37071d735 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sat, 17 May 2008 12:37:39 +0200 Subject: major revision of form_for documentation --- actionpack/lib/action_view/helpers/form_helper.rb | 89 ++++++++++++++--------- 1 file changed, 54 insertions(+), 35 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 6d97038da9..88c2d7ba9d 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -86,15 +86,15 @@ module ActionView # <%= f.text_field :author %>
# <% end %> # - # There, +form_for+ is able to generate the rest of RESTful parameters + # There, +form_for+ is able to generate the rest of RESTful form parameters # based on introspection on the record, but to understand what it does we # need to dig first into the alternative generic usage it is based upon. # # === Generic form_for # - # The generic way to call +form_for+ requires a few arguments: + # The generic way to call +form_for+ yields a form builder around a model: # - # <% form_for :person, @person, :url => { :action => "update" } do |f| %> + # <% form_for :person, :url => { :action => "update" } do |f| %> # <%= f.error_messages %> # First name: <%= f.text_field :first_name %>
# Last name : <%= f.text_field :last_name %>
@@ -102,21 +102,48 @@ module ActionView # Admin? : <%= f.check_box :admin %>
# <% end %> # + # There, the first argument is a symbol or string with the name of the + # object the form is about, and also the name of the instance variable the + # object is stored in. + # + # The form builder acts as a regular form helper that somehow carries the + # model. Thus, the idea is that + # + # <%= f.text_field :first_name %> + # + # gets expanded to + # + # <%= text_field :person, :first_name %> + # + # If the instance variable is not @person you can pass the actual + # record as the second argument: + # + # <% form_for :person, person, :url => { :action => "update" } do |f| %> + # ... + # <% end %> + # + # In that case you can think + # + # <%= f.text_field :first_name %> + # + # gets expanded to + # + # <%= text_field :person, :first_name, :object => person %> + # + # You can even display error messages of the wrapped model this way: + # + # <%= f.error_messages %> + # + # In any of its variants, the rightmost argument to +form_for+ is an + # optional hash of options: + # + # * :url - The URL the form is submit to. It takes the same fields + # you pass to`+url_for+ or +link_to+. In particular you may pass here a + # named route directly as well. Defaults to the current action. + # * :html - Optional HTML attributes for the form tag. + # # Worth noting is that the +form_for+ tag is called in a ERb evaluation block, - # not an ERb output block. So that's <% %>, not <%= %>. Also - # worth noting is that +form_for+ yields a form builder object, in this - # example as +f+, which emulates the API for the stand-alone FormHelper - # methods, but without the object name. So instead of text_field :person, :name, - # you get away with f.text_field :name. Notice that you can even do - # <%= f.error_messages %> to display the error messsages of the model - # object in question. - # - # Even further, the +form_for+ method allows you to more easily escape the - # instance variable convention. So while the stand-alone approach would require - # text_field :person, :name, :object => person to work with local - # variables instead of instance ones, the +form_for+ calls remain the same. - # You simply declare once with :person, person and all subsequent - # field calls save :person and :object => person. + # not an ERb output block. So that's <% %>, not <%= %>. # # Also note that +form_for+ doesn't create an exclusive scope. It's still # possible to use both the stand-alone FormHelper methods and methods from @@ -133,40 +160,32 @@ module ActionView # designed to work with an object as base, like FormOptionHelper#collection_select # and DateHelper#datetime_select. # - # HTML attributes for the form tag can be given as :html => {...}. - # For example: - # - # <% form_for :person, @person, :html => {:id => 'person_form'} do |f| %> - # ... - # <% end %> - # - # The above form will then have the +id+ attribute with the value "person_form", - # which you can then style with CSS or manipulate with JavaScript. - # - # === Relying on record identification + # === Resource-oriented style # # As we said above, in addition to manually configuring the +form_for+ call, - # you can rely on record identification, which will use the conventions and - # named routes of that approach. This is the preferred way to use +form_for+ - # nowadays: + # you can rely on automated resource identification, which will use the conventions + # and named routes of that approach. This is the preferred way to use +form_for+ + # nowadays. + # + # For example, if @post is an existing record you want to edit # - # <% form_for(@post) do |f| %> + # <% form_for @post do |f| %> # ... # <% end %> # - # This will expand to be the same as: + # is equivalent to something like: # # <% form_for :post, @post, :url => post_path(@post), :html => { :method => :put, :class => "edit_post", :id => "edit_post_45" } do |f| %> # ... # <% end %> # - # And for new records: + # And for new records # # <% form_for(Post.new) do |f| %> # ... # <% end %> # - # This will expand to be the same as: + # expands to be the same as # # <% form_for :post, Post.new, :url => posts_path, :html => { :class => "new_post", :id => "new_post" } do |f| %> # ... -- cgit v1.2.3 From 82a1b93c6a5f0ee866a270f66c8b051175c9793b Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sat, 17 May 2008 12:44:48 +0200 Subject: small touches to the form_for docs revision --- actionpack/lib/action_view/helpers/form_helper.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 88c2d7ba9d..940f1c9b5d 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -137,8 +137,8 @@ module ActionView # In any of its variants, the rightmost argument to +form_for+ is an # optional hash of options: # - # * :url - The URL the form is submit to. It takes the same fields - # you pass to`+url_for+ or +link_to+. In particular you may pass here a + # * :url - The URL the form is submitted to. It takes the same fields + # you pass to +url_for+ or +link_to+. In particular you may pass here a # named route directly as well. Defaults to the current action. # * :html - Optional HTML attributes for the form tag. # @@ -185,7 +185,7 @@ module ActionView # ... # <% end %> # - # expands to be the same as + # expands to # # <% form_for :post, Post.new, :url => posts_path, :html => { :class => "new_post", :id => "new_post" } do |f| %> # ... -- cgit v1.2.3 From 2463e38efd3cbcc10e7b0a93ad9c2d2224340668 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 17 May 2008 12:22:15 +0100 Subject: Deprecate ActionView::Base.cache_template_extensions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit deprecates unused ActionView::Base.cache_template_extensions option and adds a deprecation warning for those having it in env specific config files. Thanks to José Valim for pointing this out. --- actionpack/lib/action_view/base.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 4840b2526d..f398756550 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -168,12 +168,12 @@ module ActionView #:nodoc: # Specify whether file modification times should be checked to see if a template needs recompilation @@cache_template_loading = false cattr_accessor :cache_template_loading - - # Specify whether file extension lookup should be cached, and whether template base path lookup should be cached. - # Should be +false+ for development environments. Defaults to +true+. - @@cache_template_extensions = true - cattr_accessor :cache_template_extensions + def self.cache_template_extensions=(*args) + ActiveSupport::Deprecation.warn("config.action_view.cache_template_extensions option has been deprecated and has no affect. " << + "Please remove it from your config files.", caller) + end + # Specify whether RJS responses should be wrapped in a try/catch block # that alert()s the caught exception (and then re-raises it). @@debug_rjs = false -- cgit v1.2.3 From a49ebf6d7909c344d2fe570cb82c97fa271db03e Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sat, 17 May 2008 17:33:44 +0200 Subject: revised documentation of attr_(protected|accessible) Revised wording and coherence between both docs, avoided the term "hacker" to refer to a malicious user, revised markup and structure. --- activerecord/lib/active_record/base.rb | 38 ++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 5351f55200..00083a50fd 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -860,9 +860,15 @@ module ActiveRecord #:nodoc: end - # Attributes named in this macro are protected from mass-assignment, such as new(attributes) and - # attributes=(attributes). Their assignment will simply be ignored. Instead, you can use the direct writer - # methods to do assignment. This is meant to protect sensitive attributes from being overwritten by URL/form hackers. Example: + # Attributes named in this macro are protected from mass-assignment, + # such as new(attributes), + # update_attributes(attributes), or + # attributes=(attributes). + # + # Mass-assignment to these attributes will simply be ignored, to assign + # to them you can use direct writer methods. This is meant to protect + # sensitive attributes from being overwritten by malicious users + # tampering with URLs or forms. # # class Customer < ActiveRecord::Base # attr_protected :credit_rating @@ -876,7 +882,8 @@ module ActiveRecord #:nodoc: # customer.credit_rating = "Average" # customer.credit_rating # => "Average" # - # To start from an all-closed default and enable attributes as needed, have a look at attr_accessible. + # To start from an all-closed default and enable attributes as needed, + # have a look at +attr_accessible+. def attr_protected(*attributes) write_inheritable_attribute("attr_protected", Set.new(attributes.map(&:to_s)) + (protected_attributes || [])) end @@ -886,19 +893,18 @@ module ActiveRecord #:nodoc: read_inheritable_attribute("attr_protected") end - # Similar to the attr_protected macro, this protects attributes of your model from mass-assignment, - # such as new(attributes) and attributes=(attributes) - # however, it does it in the opposite way. This locks all attributes and only allows access to the - # attributes specified. Assignment to attributes not in this list will be ignored and need to be set - # using the direct writer methods instead. This is meant to protect sensitive attributes from being - # overwritten by URL/form hackers. If you'd rather start from an all-open default and restrict - # attributes as needed, have a look at attr_protected. - # - # ==== Attributes + # Specifies a white list of model attributes that can be set via + # mass-assignment, such as new(attributes), + # update_attributes(attributes), or + # attributes=(attributes) # - # * *attributes A comma separated list of symbols that represent columns _not_ to be protected - # - # ==== Examples + # This is the opposite of the +attr_protected+ macro: Mass-assignment + # will only set attributes in this list, to assign to the rest of + # attributes you can use direct writer methods. This is meant to protect + # sensitive attributes from being overwritten by malicious users + # tampering with URLs or forms. If you'd rather start from an all-open + # default and restrict attributes as needed, have a look at + # +attr_protected+. # # class Customer < ActiveRecord::Base # attr_accessible :name, :nickname -- cgit v1.2.3 From 0f333449bd47737a7260d7b9770a2bc50a373abb Mon Sep 17 00:00:00 2001 From: gbuesing Date: Sun, 18 May 2008 10:25:29 -0500 Subject: time_zone_select docs: explain priority zones option. Add example showing a custom set of priority zones. --- actionpack/lib/action_view/helpers/form_options_helper.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index bf65fe5574..6f3818659e 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -146,6 +146,12 @@ module ActionView # to TimeZone. This may be used by users to specify a different time # zone model object. (See #time_zone_options_for_select for more # information.) + # + # You can also supply an array of TimeZone objects + # as +priority_zones+, so that they will be listed above the rest of the + # (long) list. (You can use TimeZone.us_zones as a convenience for + # obtaining a list of the US time zones.) + # # Finally, this method supports a :default option, which selects # a default TimeZone if the object's time zone is nil. # @@ -156,6 +162,8 @@ module ActionView # # time_zone_select( "user", 'time_zone', TimeZone.us_zones, :default => "Pacific Time (US & Canada)") # + # time_zone_select( "user", 'time_zone', [ TimeZone['Alaska'], TimeZone['Hawaii'] ]) + # # time_zone_select( "user", "time_zone", TZInfo::Timezone.all.sort, :model => TZInfo::Timezone) def time_zone_select(object, method, priority_zones = nil, options = {}, html_options = {}) InstanceTag.new(object, method, self, nil, options.delete(:object)).to_time_zone_select_tag(priority_zones, options, html_options) -- cgit v1.2.3 From be85868987675a158fd4111393b9161296431728 Mon Sep 17 00:00:00 2001 From: gbuesing Date: Sun, 18 May 2008 10:48:11 -0500 Subject: Time#to_json: don't convert to utc before encoding. References #175 --- activesupport/CHANGELOG | 2 ++ activesupport/lib/active_support/json/encoders/time.rb | 2 +- activesupport/test/json/encoding_test.rb | 16 ++++++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index e8821060f9..dabb6a0c6f 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,3 +1,5 @@ +* Time#to_json: don't convert to utc before encoding. References #175 [Geoff Buesing] + *2.1.0 RC1 (May 11th, 2008)* * Remove unused JSON::RESERVED_WORDS, JSON.valid_identifier? and JSON.reserved_word? methods. Resolves #164. [Cheah Chu Yeow] diff --git a/activesupport/lib/active_support/json/encoders/time.rb b/activesupport/lib/active_support/json/encoders/time.rb index 3660d87c82..57ed3c9e31 100644 --- a/activesupport/lib/active_support/json/encoders/time.rb +++ b/activesupport/lib/active_support/json/encoders/time.rb @@ -6,7 +6,7 @@ class Time # # => 2005/02/01 15:15:10 +0000" def to_json(options = nil) if ActiveSupport.use_standard_json_time_format - utc.xmlschema.inspect + xmlschema.inspect else %("#{strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)}") end diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb index 7bc8eaf06c..38bb8f3e79 100644 --- a/activesupport/test/json/encoding_test.rb +++ b/activesupport/test/json/encoding_test.rb @@ -90,6 +90,15 @@ class TestJSONEncoding < Test::Unit::TestCase 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 + + def test_time_to_json_includes_local_offset + ActiveSupport.use_standard_json_time_format = true + with_env_tz 'US/Eastern' do + assert_equal %("2005-02-01T15:15:10-05:00"), Time.local(2005,2,1,15,15,10).to_json + end + ensure + ActiveSupport.use_standard_json_time_format = false + end protected def with_kcode(code) @@ -108,6 +117,13 @@ class TestJSONEncoding < Test::Unit::TestCase def object_keys(json_object) json_object[1..-2].scan(/([^{}:,\s]+):/).flatten.sort end + + def with_env_tz(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 uses_mocha 'JsonOptionsTests' do -- cgit v1.2.3 From e30a263bf1744d0b55d073c7d1087d0d64181d2c Mon Sep 17 00:00:00 2001 From: gbuesing Date: Sun, 18 May 2008 10:59:24 -0500 Subject: InstanceTag#default_time_from_options overflows to DateTime --- actionpack/CHANGELOG | 2 ++ actionpack/lib/action_view/helpers/date_helper.rb | 2 +- actionpack/test/template/date_helper_test.rb | 6 ++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 4a24d2f8b9..5c4bfbf3c9 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,3 +1,5 @@ +* InstanceTag#default_time_from_options overflows to DateTime [Geoff Buesing] + *2.1.0 RC1 (May 11th, 2008)* * Fixed that forgery protection can be used without session tracking (Peter Jones) [#139] diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb index 8a9c8044ae..7ed6272898 100755 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionpack/lib/action_view/helpers/date_helper.rb @@ -689,7 +689,7 @@ module ActionView default[key] ||= time.send(key) end - Time.utc(default[:year], default[:month], default[:day], default[:hour], default[:min], default[:sec]) + Time.utc_time(default[:year], default[:month], default[:day], default[:hour], default[:min], default[:sec]) end end end diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb index ae83c7bf47..0a7b19ba96 100755 --- a/actionpack/test/template/date_helper_test.rb +++ b/actionpack/test/template/date_helper_test.rb @@ -1722,6 +1722,12 @@ class DateHelperTest < ActionView::TestCase assert_equal 2, dummy_instance_tag.send!(:default_time_from_options, :hour => 2).hour end end + + def test_instance_tag_default_time_from_options_handles_far_future_date + dummy_instance_tag = ActionView::Helpers::InstanceTag.new(1,2,3) + time = dummy_instance_tag.send!(:default_time_from_options, :year => 2050, :month => 2, :day => 10, :hour => 15, :min => 30, :sec => 45) + assert_equal 2050, time.year + end end protected -- cgit v1.2.3 From cde9c09a524a21214ea9cd0f9ee4489e4d185af2 Mon Sep 17 00:00:00 2001 From: gbuesing Date: Sun, 18 May 2008 11:15:29 -0500 Subject: TimeWithZone #+ and #- : ensure overflow to DateTime with Numeric arg --- activesupport/CHANGELOG | 2 ++ activesupport/lib/active_support/time_with_zone.rb | 4 ++-- activesupport/test/core_ext/time_with_zone_test.rb | 7 +++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index dabb6a0c6f..7f2c3e971a 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,3 +1,5 @@ +* TimeWithZone #+ and #- : ensure overflow to DateTime with Numeric arg [Geoff Buesing] + * Time#to_json: don't convert to utc before encoding. References #175 [Geoff Buesing] *2.1.0 RC1 (May 11th, 2008)* diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index 48606dbcff..15145a2575 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -135,7 +135,7 @@ module ActiveSupport # If wrapped #time is a DateTime, use DateTime#since instead of #+ # Otherwise, just pass on to #method_missing def +(other) - result = utc.acts_like?(:date) ? utc.since(other) : utc + other + result = utc.acts_like?(:date) ? utc.since(other) : utc + other rescue utc.since(other) result.in_time_zone(time_zone) end @@ -146,7 +146,7 @@ module ActiveSupport if other.acts_like?(:time) utc - other else - result = utc.acts_like?(:date) ? utc.ago(other) : utc - other + result = utc.acts_like?(:date) ? utc.ago(other) : utc - other rescue utc.ago(other) result.in_time_zone(time_zone) end end diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb index 70c393dd46..c373bca88d 100644 --- a/activesupport/test/core_ext/time_with_zone_test.rb +++ b/activesupport/test/core_ext/time_with_zone_test.rb @@ -170,6 +170,13 @@ class TimeWithZoneTest < Test::Unit::TestCase assert_equal DateTime.civil(1999, 12, 31, 19, 0 ,5), (twz + 5).time end end + + def test_plus_when_crossing_time_class_limit + silence_warnings do # silence warnings raised by tzinfo gem + twz = ActiveSupport::TimeWithZone.new(Time.utc(2038, 1, 19), @time_zone) + assert_equal [0, 0, 19, 19, 1, 2038], (twz + 86_400).to_a[0,6] + end + end def test_plus_with_duration silence_warnings do # silence warnings raised by tzinfo gem -- cgit v1.2.3 From cee9297c9bd43ca8975dc7ca9b707a6aa94c275d Mon Sep 17 00:00:00 2001 From: gbuesing Date: Sun, 18 May 2008 11:48:33 -0500 Subject: Hash.from_xml: datetime xml types overflow to Ruby DateTime class when out of range of Time. Adding tests for utc offsets --- activesupport/CHANGELOG | 2 ++ .../active_support/core_ext/hash/conversions.rb | 2 +- activesupport/test/core_ext/hash_ext_test.rb | 38 ++++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 7f2c3e971a..6250f33998 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,3 +1,5 @@ +* Hash.from_xml: datetime xml types overflow to Ruby DateTime class when out of range of Time. Adding tests for utc offsets [Geoff Buesing] + * TimeWithZone #+ and #- : ensure overflow to DateTime with Numeric arg [Geoff Buesing] * Time#to_json: don't convert to utc before encoding. References #175 [Geoff Buesing] diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb index 3d6a8d8588..a023118885 100644 --- a/activesupport/lib/active_support/core_ext/hash/conversions.rb +++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb @@ -70,7 +70,7 @@ module ActiveSupport #:nodoc: XML_PARSING = { "symbol" => Proc.new { |symbol| symbol.to_sym }, "date" => Proc.new { |date| ::Date.parse(date) }, - "datetime" => Proc.new { |time| ::Time.parse(time).utc }, + "datetime" => Proc.new { |time| ::Time.parse(time).utc rescue ::DateTime.parse(time).utc }, "integer" => Proc.new { |integer| integer.to_i }, "float" => Proc.new { |float| float.to_f }, "decimal" => Proc.new { |number| BigDecimal(number) }, diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index 706e218abc..69028a123f 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -733,6 +733,44 @@ class HashToXmlTest < Test::Unit::TestCase assert_equal hash, Hash.from_xml(hash.to_xml(@xml_options))['person'] end + + def test_datetime_xml_type_with_utc_time + alert_xml = <<-XML + + 2008-02-10T15:30:45Z + + XML + alert_at = Hash.from_xml(alert_xml)['alert']['alert_at'] + assert alert_at.utc? + assert_equal Time.utc(2008, 2, 10, 15, 30, 45), alert_at + end + + def test_datetime_xml_type_with_non_utc_time + alert_xml = <<-XML + + 2008-02-10T10:30:45-05:00 + + XML + alert_at = Hash.from_xml(alert_xml)['alert']['alert_at'] + assert alert_at.utc? + assert_equal Time.utc(2008, 2, 10, 15, 30, 45), alert_at + end + + def test_datetime_xml_type_with_far_future_date + alert_xml = <<-XML + + 2050-02-10T15:30:45Z + + XML + alert_at = Hash.from_xml(alert_xml)['alert']['alert_at'] + assert alert_at.utc? + assert_equal 2050, alert_at.year + assert_equal 2, alert_at.month + assert_equal 10, alert_at.day + assert_equal 15, alert_at.hour + assert_equal 30, alert_at.min + assert_equal 45, alert_at.sec + end end class QueryTest < Test::Unit::TestCase -- cgit v1.2.3 From c1c1d6c2ea72424dfae0b5ee1991d904dcf0f252 Mon Sep 17 00:00:00 2001 From: gbuesing Date: Sun, 18 May 2008 14:13:47 -0500 Subject: Adding documentation for time zone features --- .../lib/active_record/attribute_methods.rb | 4 +++ .../lib/active_support/core_ext/time/zones.rb | 27 ++++++++++++++------ activesupport/lib/active_support/time_with_zone.rb | 29 +++++++++++++++++++++- .../lib/active_support/values/time_zone.rb | 21 ++++++++++++++++ 4 files changed, 72 insertions(+), 9 deletions(-) diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index c2604894a8..d753778d52 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -162,6 +162,8 @@ module ActiveRecord evaluate_attribute_method attr_name, "def #{attr_name}; unserialize_attribute('#{attr_name}'); end" end + # Defined for all datetime and timestamp attributes when time_zone_aware_attributes are enabled. + # This enhanced read method automatically converts the UTC time stored in the database to the time zone stored in Time.zone def define_read_method_for_time_zone_conversion(attr_name) method_body = <<-EOV def #{attr_name}(reload = false) @@ -183,6 +185,8 @@ module ActiveRecord evaluate_attribute_method attr_name, "def #{attr_name}=(new_value);write_attribute('#{attr_name}', new_value);end", "#{attr_name}=" end + # Defined for all datetime and timestamp attributes when time_zone_aware_attributes are enabled. + # This enhanced write method will automatically convert the time passed to it to the zone stored in Time.zone. def define_write_method_for_time_zone_conversion(attr_name) method_body = <<-EOV def #{attr_name}=(time) diff --git a/activesupport/lib/active_support/core_ext/time/zones.rb b/activesupport/lib/active_support/core_ext/time/zones.rb index 3ffc71407c..cf28d0fa95 100644 --- a/activesupport/lib/active_support/core_ext/time/zones.rb +++ b/activesupport/lib/active_support/core_ext/time/zones.rb @@ -1,9 +1,7 @@ module ActiveSupport #:nodoc: module CoreExtensions #:nodoc: module Time #:nodoc: - # Methods for creating TimeWithZone objects from Time instances module Zones - def self.included(base) #:nodoc: base.extend(ClassMethods) if base == ::Time # i.e., don't include class methods in DateTime end @@ -11,18 +9,31 @@ module ActiveSupport #:nodoc: module ClassMethods attr_accessor :zone_default + # Returns the TimeZone for the current request, if this has been set (via Time.zone=). + # If Time.zone has not been set for the current request, returns the TimeZone specified in config.time_zone def zone Thread.current[:time_zone] || zone_default end - # Sets a global default time zone, separate from the system time zone in ENV['TZ']. - # Accepts either a Rails TimeZone object, a string that identifies a - # Rails TimeZone object (e.g., "Central Time (US & Canada)"), or a TZInfo::Timezone object. + # Sets Time.zone to a TimeZone object for the current request/thread. + # + # This method accepts any of the following: + # + # * a Rails TimeZone object + # * an identifier for a Rails TimeZone object (e.g., "Eastern Time (US & Canada)", -5.hours) + # * a TZInfo::Timezone object + # * an identifier for a TZInfo::Timezone object (e.g., "America/New_York") + # + # Here's an example of how you might set Time.zone on a per request basis -- current_user.time_zone + # just needs to return a string identifying the user's preferred TimeZone: # - # Any Time or DateTime object can use this default time zone, via in_time_zone. + # class ApplicationController < ActionController::Base + # before_filter :set_time_zone # - # Time.zone = 'Hawaii' # => 'Hawaii' - # Time.utc(2000).in_time_zone # => Fri, 31 Dec 1999 14:00:00 HST -10:00 + # def set_time_zone + # Time.zone = current_user.time_zone + # end + # end def zone=(time_zone) Thread.current[:time_zone] = get_zone(time_zone) end diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index 15145a2575..64c935717d 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -1,7 +1,34 @@ require 'tzinfo' module ActiveSupport # A Time-like class that can represent a time in any time zone. Necessary because standard Ruby Time instances are - # limited to UTC and the system's ENV['TZ'] zone + # limited to UTC and the system's ENV['TZ'] zone. + # + # You shouldn't ever need to create a TimeWithZone instance directly via .new -- instead, Rails provides the methods + # #local, #parse, #at and #now on TimeZone instances, and #in_time_zone on Time and DateTime instances, for a more + # user-friendly syntax. Examples: + # + # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)' + # Time.zone.local(2007, 2, 10, 15, 30, 45) # => Sat, 10 Feb 2007 15:30:45 EST -05:00 + # Time.zone.parse('2007-02-01 15:30:45') # => Sat, 10 Feb 2007 15:30:45 EST -05:00 + # Time.zone.at(1170361845) # => Sat, 10 Feb 2007 15:30:45 EST -05:00 + # Time.zone.now # => Sun, 18 May 2008 13:07:55 EDT -04:00 + # Time.utc(2007, 2, 10, 20, 30, 45).in_time_zone # => Sat, 10 Feb 2007 15:30:45 EST -05:00 + # + # See TimeZone and ActiveSupport::CoreExtensions::Time::Zones for further documentation for these methods. + # + # TimeWithZone instances implement the same API as Ruby Time instances, so that Time and TimeWithZone instances are interchangable. Examples: + # + # t = Time.zone.now # => Sun, 18 May 2008 13:27:25 EDT -04:00 + # t.hour # => 13 + # t.dst? # => true + # t.utc_offset # => -14400 + # t.zone # => "EDT" + # t.to_s(:rfc822) # => "Sun, 18 May 2008 13:27:25 -0400" + # t + 1.day # => Mon, 19 May 2008 13:27:25 EDT -04:00 + # t.beginning_of_year # => Tue, 01 Jan 2008 00:00:00 EST -05:00 + # t > Time.utc(1999) # => true + # t.is_a?(Time) # => true + # t.is_a?(ActiveSupport::TimeWithZone) # => true class TimeWithZone include Comparable attr_reader :time_zone diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index f522b64108..5340b5ed28 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -1,3 +1,24 @@ +# The TimeZone class serves as a wrapper around TZInfo::Timezone instances. It allows us to do the following: +# +# * limit the set of zones provided by TZInfo to a meaningful subset of 142 zones +# * retrieve and display zones with a friendlier name (e.g., "Eastern Time (US & Canada)" instead of "America/New_York") +# * lazily load TZInfo::Timezone instances only when they're needed +# * create ActiveSupport::TimeWithZone instances via TimeZone #local, #parse, #at and #now methods +# +# If you set config.time_zone in the Rails Initializer, you can access this TimeZone object via Time.zone: +# +# # environment.rb: +# Rails::Initializer.run do |config| +# config.time_zone = "Eastern Time (US & Canada)" +# end +# +# Time.zone # => # +# Time.zone.name # => "Eastern Time (US & Canada)" +# Time.zone.now # => Sun, 18 May 2008 14:30:44 EDT -04:00 +# +# The version of TZInfo bundled with ActiveSupport only includes the definitions necessary to support the zones +# defined by the TimeZone class. If you need to use zones that aren't defined by TimeZone, you'll need to install the TZInfo gem +# (if a recent version of the gem is installed locally, this will be used instead of the bundled version.) class TimeZone unless const_defined?(:MAPPING) # Keys are Rails TimeZone names, values are TZInfo identifiers -- cgit v1.2.3 From c9c4f7bababda23f33693bdca35d1bb37fdfcd15 Mon Sep 17 00:00:00 2001 From: Frederick Cheung Date: Sun, 18 May 2008 20:02:37 +0100 Subject: Update documentation on :include. --- activerecord/lib/active_record/associations.rb | 116 ++++++++++++++----------- activerecord/lib/active_record/base.rb | 2 +- 2 files changed, 64 insertions(+), 54 deletions(-) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 95caf68692..902deeb35c 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -441,9 +441,9 @@ module ActiveRecord # # == Eager loading of associations # - # Eager loading is a way to find objects of a certain class and a number of named associations along with it in a single SQL call. This is + # Eager loading is a way to find objects of a certain class and a number of named associations. This is # one of the easiest ways of to prevent the dreaded 1+N problem in which fetching 100 posts that each need to display their author - # triggers 101 database queries. Through the use of eager loading, the 101 queries can be reduced to 1. Example: + # triggers 101 database queries. Through the use of eager loading, the 101 queries can be reduced to 2. Example: # # class Post < ActiveRecord::Base # belongs_to :author @@ -462,14 +462,15 @@ module ActiveRecord # # for post in Post.find(:all, :include => :author) # - # This references the name of the +belongs_to+ association that also used the :author symbol, so the find will now weave in a join something - # like this: LEFT OUTER JOIN authors ON authors.id = posts.author_id. Doing so will cut down the number of queries from 201 to 101. + # This references the name of the +belongs_to+ association that also used the :author symbol. After loading the posts, find + # will collect the +author_id+ from each one and load all the referenced authors with one query. Doing so will cut down the number of queries from 201 to 102. # # We can improve upon the situation further by referencing both associations in the finder with: # # for post in Post.find(:all, :include => [ :author, :comments ]) # - # That'll add another join along the lines of: LEFT OUTER JOIN comments ON comments.post_id = posts.id. And we'll be down to 1 query. + # This will load all comments with a single query. This reduces the total number of queries to 3. More generally the number of queries + # will be 1 plus the number of associations named (except if some of the associations are polymorphic belongs_to - see below). # # To include a deep hierarchy of associations, use a hash: # @@ -482,36 +483,46 @@ module ActiveRecord # the number of queries. The database still needs to send all the data to Active Record and it still needs to be processed. So it's no # catch-all for performance problems, but it's a great way to cut down on the number of queries in a situation as the one described above. # - # Since the eager loading pulls from multiple tables, you'll have to disambiguate any column references in both conditions and orders. So - # :order => "posts.id DESC" will work while :order => "id DESC" will not. Because eager loading generates the +SELECT+ statement too, the - # :select option is ignored. + # Since only one table is loaded at a time, conditions or orders cannot reference tables other than the main one. If this is the case + # Active Record falls back to the previously used LEFT OUTER JOIN based strategy. For example + # + # Post.find(:all, :include => [ :author, :comments ], :conditions => ['comments.approved = ?', true]) # - # You can use eager loading on multiple associations from the same table, but you cannot use those associations in orders and conditions - # as there is currently not any way to disambiguate them. Eager loading will not pull additional attributes on join tables, so "rich - # associations" with +has_and_belongs_to_many+ are not a good fit for eager loading. + # will result in a single sql query with joins along the lines of: LEFT OUTER JOIN comments ON comments.post_id = posts.id and + # LEFT OUTER JOIN authors ON authors.id = posts.author_id. Note that using conditions like this can have unintended consequences. + # In the above example posts with no approved comments are not returned at all, because the conditions apply to the sql statement as a whole + # and not just to the association. You must disambiguate column references for this fallback to happen, for example + # :order => "author.name DESC" will work but :order => "name DESC" will not. + # + # If you do want eagerload only some members of an association it is usually more natural to :include an association + # which has conditions defined on it: + # + # class Post < ActiveRecord::Base + # has_many :approved_comments, :class_name => 'Comment', :conditions => ['approved = ?', true] + # end + # + # Post.find(:all, :include => :approved_comments) + # + # will load posts and eager load the approved_comments association, which contains only those comments that have been approved. # # When eager loaded, conditions are interpolated in the context of the model class, not the model instance. Conditions are lazily interpolated # before the actual model exists. # - # Eager loading is not supported with polymorphic associations up to (and including) - # version 2.0.2. Given + # Eager loading is supported with polymorphic associations. # # class Address < ActiveRecord::Base # belongs_to :addressable, :polymorphic => true # end # - # a call that tries to eager load the addressable model - # - # Address.find(:all, :include => :addressable) # INVALID - # - # will raise ActiveRecord::EagerLoadPolymorphicError. The reason is that the parent model's type - # is a column value so its corresponding table name cannot be put in the +FROM+/+JOIN+ clauses of that early query. + # A call that tries to eager load the addressable model # - # In versions greater than 2.0.2 eager loading in polymorphic associations is supported - # thanks to a change in the overall preloading strategy. + # Address.find(:all, :include => :addressable) # - # It does work the other way around though: if the User model is addressable you can eager load - # their addresses with :include just fine, every piece needed to construct the query is known beforehand. + # will execute one query to load the addresses and load the addressables with one query per addressable type. + # For example if all the addressables are either of class Person or Company then a total of 3 queries will be executed. The list of + # addressable types to load is determined on the back of the addresses loaded. This is not supported if ActiveRecord has to fallback + # to the previous implementation of eager loading and will raise ActiveRecord::EagerLoadPolymorphicError. The reason is that the parent + # model's type is a column value so its corresponding table name cannot be put in the +FROM+/+JOIN+ clauses of that query. # # == Table Aliasing # @@ -519,44 +530,44 @@ module ActiveRecord # the standard table name is used. The second time, the table is aliased as #{reflection_name}_#{parent_table_name}. Indexes are appended # for any more successive uses of the table name. # - # Post.find :all, :include => :comments - # # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... - # Post.find :all, :include => :special_comments # STI - # # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... AND comments.type = 'SpecialComment' - # Post.find :all, :include => [:comments, :special_comments] # special_comments is the reflection name, posts is the parent table name - # # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... LEFT OUTER JOIN comments special_comments_posts + # Post.find :all, :joins => :comments + # # => SELECT ... FROM posts INNER JOIN comments ON ... + # Post.find :all, :joins => :special_comments # STI + # # => SELECT ... FROM posts INNER JOIN comments ON ... AND comments.type = 'SpecialComment' + # Post.find :all, :joins => [:comments, :special_comments] # special_comments is the reflection name, posts is the parent table name + # # => SELECT ... FROM posts INNER JOIN comments ON ... INNER JOIN comments special_comments_posts # # Acts as tree example: # - # TreeMixin.find :all, :include => :children - # # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ... - # TreeMixin.find :all, :include => {:children => :parent} # using cascading eager includes - # # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ... - # LEFT OUTER JOIN parents_mixins ... - # TreeMixin.find :all, :include => {:children => {:parent => :children}} - # # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ... - # LEFT OUTER JOIN parents_mixins ... - # LEFT OUTER JOIN mixins childrens_mixins_2 + # TreeMixin.find :all, :joins => :children + # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ... + # TreeMixin.find :all, :joins => {:children => :parent} + # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ... + # INNER JOIN parents_mixins ... + # TreeMixin.find :all, :joins => {:children => {:parent => :children}} + # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ... + # INNER JOIN parents_mixins ... + # INNER JOIN mixins childrens_mixins_2 # # Has and Belongs to Many join tables use the same idea, but add a _join suffix: # - # Post.find :all, :include => :categories - # # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ... - # Post.find :all, :include => {:categories => :posts} - # # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ... - # LEFT OUTER JOIN categories_posts posts_categories_join LEFT OUTER JOIN posts posts_categories - # Post.find :all, :include => {:categories => {:posts => :categories}} - # # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ... - # LEFT OUTER JOIN categories_posts posts_categories_join LEFT OUTER JOIN posts posts_categories - # LEFT OUTER JOIN categories_posts categories_posts_join LEFT OUTER JOIN categories categories_posts + # Post.find :all, :joins => :categories + # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ... + # Post.find :all, :joins => {:categories => :posts} + # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ... + # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories + # Post.find :all, :joins => {:categories => {:posts => :categories}} + # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ... + # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories + # INNER JOIN categories_posts categories_posts_join INNER JOIN categories categories_posts_2 # # If you wish to specify your own custom joins using a :joins option, those table names will take precedence over the eager associations: # - # Post.find :all, :include => :comments, :joins => "inner join comments ..." - # # => SELECT ... FROM posts LEFT OUTER JOIN comments_posts ON ... INNER JOIN comments ... - # Post.find :all, :include => [:comments, :special_comments], :joins => "inner join comments ..." - # # => SELECT ... FROM posts LEFT OUTER JOIN comments comments_posts ON ... - # LEFT OUTER JOIN comments special_comments_posts ... + # Post.find :all, :joins => :comments, :joins => "inner join comments ..." + # # => SELECT ... FROM posts INNER JOIN comments_posts ON ... INNER JOIN comments ... + # Post.find :all, :joins => [:comments, :special_comments], :joins => "inner join comments ..." + # # => SELECT ... FROM posts INNER JOIN comments comments_posts ON ... + # INNER JOIN comments special_comments_posts ... # INNER JOIN comments ... # # Table aliases are automatically truncated according to the maximum length of table identifiers according to the specific database. @@ -840,7 +851,6 @@ module ActiveRecord # this results in a counter with +NULL+ value, which will never increment. # Note: Specifying a counter cache will add it to that model's list of readonly attributes using +attr_readonly+. # * :include - Specify second-order associations that should be eager loaded when this object is loaded. - # Not allowed if the association is polymorphic. # * :polymorphic - Specify this association is a polymorphic association by passing +true+. # Note: If you've enabled the counter cache, then you may want to add the counter cache attribute # to the +attr_readonly+ list in the associated classes (e.g. class Post; attr_readonly :comments_count; end). diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 00083a50fd..c51743af16 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -465,7 +465,7 @@ module ActiveRecord #:nodoc: # or named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s). # If the value is a string, then the records will be returned read-only since they will have attributes that do not correspond to the table's columns. # Pass :readonly => false to override. - # * :include: Names associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer + # * :include: Names associations that should be loaded alongside. The symbols named refer # to already defined associations. See eager loading under Associations. # * :select: By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join but not # include the joined columns. -- cgit v1.2.3 From a50e747971a37dbce95e24253063113d252744e7 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 18 May 2008 21:44:15 +0200 Subject: minor details in associations.rb --- activerecord/lib/active_record/associations.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 902deeb35c..ce3d273a42 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -452,7 +452,7 @@ module ActiveRecord # # Consider the following loop using the class above: # - # for post in Post.find(:all) + # for post in Post.all # puts "Post: " + post.title # puts "Written by: " + post.author.name # puts "Last comment on: " + post.comments.first.created_on @@ -470,7 +470,7 @@ module ActiveRecord # for post in Post.find(:all, :include => [ :author, :comments ]) # # This will load all comments with a single query. This reduces the total number of queries to 3. More generally the number of queries - # will be 1 plus the number of associations named (except if some of the associations are polymorphic belongs_to - see below). + # will be 1 plus the number of associations named (except if some of the associations are polymorphic +belongs_to+ - see below). # # To include a deep hierarchy of associations, use a hash: # @@ -488,13 +488,13 @@ module ActiveRecord # # Post.find(:all, :include => [ :author, :comments ], :conditions => ['comments.approved = ?', true]) # - # will result in a single sql query with joins along the lines of: LEFT OUTER JOIN comments ON comments.post_id = posts.id and + # will result in a single SQL query with joins along the lines of: LEFT OUTER JOIN comments ON comments.post_id = posts.id and # LEFT OUTER JOIN authors ON authors.id = posts.author_id. Note that using conditions like this can have unintended consequences. - # In the above example posts with no approved comments are not returned at all, because the conditions apply to the sql statement as a whole + # In the above example posts with no approved comments are not returned at all, because the conditions apply to the SQL statement as a whole # and not just to the association. You must disambiguate column references for this fallback to happen, for example # :order => "author.name DESC" will work but :order => "name DESC" will not. # - # If you do want eagerload only some members of an association it is usually more natural to :include an association + # If you do want eagerload only some members of an association it is usually more natural to :include an association # which has conditions defined on it: # # class Post < ActiveRecord::Base @@ -503,7 +503,7 @@ module ActiveRecord # # Post.find(:all, :include => :approved_comments) # - # will load posts and eager load the approved_comments association, which contains only those comments that have been approved. + # will load posts and eager load the +approved_comments+ association, which contains only those comments that have been approved. # # When eager loaded, conditions are interpolated in the context of the model class, not the model instance. Conditions are lazily interpolated # before the actual model exists. -- cgit v1.2.3 From 14bd01b9a9cdd4ec5c9abf8ae595cca880aa6faf Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 18 May 2008 21:51:54 +0200 Subject: revised description list convention in AR's find docs, and markup here and there --- activerecord/lib/active_record/base.rb | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index c51743af16..c78eb1984a 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -456,23 +456,23 @@ module ActiveRecord #:nodoc: # # All approaches accept an options hash as their last parameter. The options are: # - # * :conditions: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro. - # * :order: An SQL fragment like "created_at DESC, name". - # * :group: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause. - # * :limit: An integer determining the limit on the number of rows that should be returned. - # * :offset: An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4. - # * :joins: Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed) - # or named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s). + # * :conditions - An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro. + # * :order - An SQL fragment like "created_at DESC, name". + # * :group - An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause. + # * :limit - An integer determining the limit on the number of rows that should be returned. + # * :offset - An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4. + # * :joins - Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed) + # or named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s). # If the value is a string, then the records will be returned read-only since they will have attributes that do not correspond to the table's columns. # Pass :readonly => false to override. - # * :include: Names associations that should be loaded alongside. The symbols named refer + # * :include - Names associations that should be loaded alongside. The symbols named refer # to already defined associations. See eager loading under Associations. - # * :select: By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join but not + # * :select - By default, this is "*" as in "SELECT * FROM", but can be changed if you, for example, want to do a join but not # include the joined columns. - # * :from: By default, this is the table name of the class, but can be changed to an alternate table name (or even the name + # * :from - By default, this is the table name of the class, but can be changed to an alternate table name (or even the name # of a database view). - # * :readonly: Mark the returned records read-only so they cannot be saved or updated. - # * :lock: An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE". + # * :readonly - Mark the returned records read-only so they cannot be saved or updated. + # * :lock - An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE". # :lock => true gives connection's default exclusive lock, usually "FOR UPDATE". # # Examples for find by id: @@ -504,11 +504,12 @@ module ActiveRecord #:nodoc: # Person.find(:all, :include => [ :account, :friends ]) # Person.find(:all, :group => "category") # - # Example for find with a lock. Imagine two concurrent transactions: - # each will read person.visits == 2, add 1 to it, and save, resulting - # in two saves of person.visits = 3. By locking the row, the second + # Example for find with a lock: Imagine two concurrent transactions: + # each will read person.visits == 2, add 1 to it, and save, resulting + # in two saves of person.visits = 3. By locking the row, the second # transaction has to wait until the first is finished; we get the - # expected person.visits == 4. + # expected person.visits == 4. + # # Person.transaction do # person = Person.find(1, :lock => true) # person.visits += 1 -- cgit v1.2.3 From bd57507e7fcbe4c388022f4258c3198d1d614f2b Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 18 May 2008 22:02:07 +0200 Subject: added mention to Model.(first|last|all) in AR's find, and assorted tweaks --- activerecord/lib/active_record/base.rb | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index c78eb1984a..decc6b9b74 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -446,13 +446,17 @@ module ActiveRecord #:nodoc: class << self # Class methods # Find operates with four different retrieval approaches: # - # * Find by id: This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]). + # * Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]). # If no record can be found for all of the listed ids, then RecordNotFound will be raised. - # * Find first: This will return the first record matched by the options used. These options can either be specific - # conditions or merely an order. If no record can be matched, nil is returned. - # * Find last: This will return the last record matched by the options used. These options can either be specific - # conditions or merely an order. If no record can be matched, nil is returned. - # * Find all: This will return all the records matched by the options used. If no records are found, an empty array is returned. + # * Find first - This will return the first record matched by the options used. These options can either be specific + # conditions or merely an order. If no record can be matched, +nil+ is returned. Use + # Model.find(:first, *args) or its shortcut Model.first(*args). + # * Find last - This will return the last record matched by the options used. These options can either be specific + # conditions or merely an order. If no record can be matched, nil is returned. Use + # Model.find(:last, *args) or its shortcut Model.last(*args). + # * Find all - This will return all the records matched by the options used. + # If no records are found, an empty array is returned. Use + # Model.find(:all, *args) or its shortcut Model.all(*args). # # All approaches accept an options hash as their last parameter. The options are: # -- cgit v1.2.3 From c40c17c9864b3225573b682320179fd519184cf0 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 18 May 2008 22:04:41 +0200 Subject: fixed-width font for nil --- activerecord/lib/active_record/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index decc6b9b74..2bb855488f 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -452,7 +452,7 @@ module ActiveRecord #:nodoc: # conditions or merely an order. If no record can be matched, +nil+ is returned. Use # Model.find(:first, *args) or its shortcut Model.first(*args). # * Find last - This will return the last record matched by the options used. These options can either be specific - # conditions or merely an order. If no record can be matched, nil is returned. Use + # conditions or merely an order. If no record can be matched, +nil+ is returned. Use # Model.find(:last, *args) or its shortcut Model.last(*args). # * Find all - This will return all the records matched by the options used. # If no records are found, an empty array is returned. Use -- cgit v1.2.3 From aa4a7a298967f89a5812870962f8c858411eb7ab Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 18 May 2008 22:11:15 +0200 Subject: gsub("sql", "SQL") --- .../associations/has_many_through_association.rb | 2 +- activerecord/lib/active_record/base.rb | 17 ++++++++--------- .../connection_adapters/postgresql_adapter.rb | 2 +- railties/configs/databases/oracle.yml | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index f683669615..ebcf462f2e 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -34,7 +34,7 @@ module ActiveRecord def count(*args) column_name, options = @reflection.klass.send(:construct_count_options_from_args, *args) if @reflection.options[:uniq] - # This is needed because 'SELECT count(DISTINCT *)..' is not valid sql statement. + # This is needed because 'SELECT count(DISTINCT *)..' is not valid SQL statement. column_name = "#{@reflection.quoted_table_name}.#{@reflection.klass.primary_key}" if column_name == :all options.merge!(:distinct => true) end diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 2bb855488f..ccb35bd1ba 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -550,8 +550,7 @@ module ActiveRecord #:nodoc: find(:all, *args) end - # - # Executes a custom sql query against your database and returns all the results. The results will + # Executes a custom SQL query against your database and returns all the results. The results will # be returned as an array with columns requested encapsulated as attributes of the model you call # this method from. If you call +Product.find_by_sql+ then the results will be returned in a Product # object with the attributes you specified in the SQL query. @@ -560,13 +559,13 @@ module ActiveRecord #:nodoc: # SELECT will be attributes of the model, whether or not they are columns of the corresponding # table. # - # The +sql+ parameter is a full sql query as a string. It will be called as is, there will be + # The +sql+ parameter is a full SQL query as a string. It will be called as is, there will be # no database agnostic conversions performed. This should be a last resort because using, for example, # MySQL specific terms will lock you to using that particular database engine or require you to # change your call if you switch engines # # ==== Examples - # # A simple sql query spanning multiple tables + # # A simple SQL query spanning multiple tables # Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id" # > [#"Ruby Meetup", "first_name"=>"Quentin"}>, ...] # @@ -1919,7 +1918,7 @@ module ActiveRecord #:nodoc: klass.base_class.name end - # Accepts an array, hash, or string of sql conditions and sanitizes + # Accepts an array, hash, or string of SQL conditions and sanitizes # them into a valid SQL fragment for a WHERE clause. # ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'" # { :name => "foo'bar", :group_id => 4 } returns "name='foo''bar' and group_id='4'" @@ -1935,7 +1934,7 @@ module ActiveRecord #:nodoc: end alias_method :sanitize_sql, :sanitize_sql_for_conditions - # Accepts an array, hash, or string of sql conditions and sanitizes + # Accepts an array, hash, or string of SQL conditions and sanitizes # them into a valid SQL fragment for a SET clause. # { :name => nil, :group_id => 4 } returns "name = NULL , group_id='4'" def sanitize_sql_for_assignment(assignments) @@ -1951,7 +1950,7 @@ module ActiveRecord #:nodoc: mapping.first.is_a?(Array) ? mapping : [mapping] end - # Accepts a hash of sql conditions and replaces those attributes + # Accepts a hash of SQL conditions and replaces those attributes # that correspond to a +composed_of+ relationship with their expanded # aggregate attribute values. # Given: @@ -2024,7 +2023,7 @@ module ActiveRecord #:nodoc: end # Accepts an array of conditions. The array has each value - # sanitized and interpolated into the sql statement. + # sanitized and interpolated into the SQL statement. # ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'" def sanitize_sql_array(ary) statement, *values = ary @@ -2575,7 +2574,7 @@ module ActiveRecord #:nodoc: self.class.connection.quote(value, column) end - # Interpolate custom sql string in instance context. + # Interpolate custom SQL string in instance context. # Optional record argument is meant for custom insert_sql. def interpolate_sql(sql, record = nil) instance_eval("%@#{sql.gsub('@', '\@')}@") diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 2ec2d80af4..7dbfbb41f6 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -776,7 +776,7 @@ module ActiveRecord # Returns an ORDER BY clause for the passed order option. # # PostgreSQL does not allow arbitrary ordering when using DISTINCT ON, so we work around this - # by wrapping the sql as a sub-select and ordering in that query. + # by wrapping the +sql+ string as a sub-select and ordering in that query. def add_order_by_for_association_limiting!(sql, options) #:nodoc: return sql if options[:order].blank? diff --git a/railties/configs/databases/oracle.yml b/railties/configs/databases/oracle.yml index c86cbdbaba..822d998543 100644 --- a/railties/configs/databases/oracle.yml +++ b/railties/configs/databases/oracle.yml @@ -4,7 +4,7 @@ # http://rubyforge.org/projects/ruby-oci8/ # # Specify your database using any valid connection syntax, such as a -# tnsnames.ora service name, or a sql connect url string of the form: +# tnsnames.ora service name, or a SQL connect url string of the form: # # //host:[port][/service name] # -- cgit v1.2.3 From 17d1319c480e58e28641b243da50ae5e5eab89dc Mon Sep 17 00:00:00 2001 From: Frederick Cheung Date: Sat, 17 May 2008 19:12:36 +0100 Subject: Ensure observe_field encodes value parameter. [#216 state:resolved] Signed-off-by: Pratik Naik --- actionpack/lib/action_view/helpers/prototype_helper.rb | 2 +- actionpack/test/template/prototype_helper_test.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index 1a0e660d52..04bf5f2a30 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -1068,7 +1068,7 @@ module ActionView def build_observer(klass, name, options = {}) if options[:with] && (options[:with] !~ /[\{=(.]/) - options[:with] = "'#{options[:with]}=' + value" + options[:with] = "'#{options[:with]}=' + encodeURIComponent(value)" else options[:with] ||= 'value' unless options[:function] end diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb index 9a1079b297..5e00eadb8d 100644 --- a/actionpack/test/template/prototype_helper_test.rb +++ b/actionpack/test/template/prototype_helper_test.rb @@ -219,9 +219,9 @@ class PrototypeHelperTest < PrototypeHelperBaseTest end def test_observe_field_using_with_option - expected = %() + expected = %() assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id') - assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + value") + assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + encodeURIComponent(value)") end def test_observe_field_using_json_in_with_option -- cgit v1.2.3 From 99860b72aebe0348f41e82d4710343498d89a84b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 16 May 2008 19:10:30 +0200 Subject: Add fragment_exist? and exist? methods to cache stores. [#203 state:resolved] Signed-off-by: Pratik Naik --- .../lib/action_controller/caching/fragments.rb | 13 ++++++- actionpack/test/controller/caching_test.rb | 42 +++++++++++----------- activesupport/lib/active_support/cache.rb | 8 +++-- .../lib/active_support/cache/file_store.rb | 7 +++- .../lib/active_support/cache/mem_cache_store.rb | 8 ++++- .../lib/active_support/cache/memory_store.rb | 7 +++- 6 files changed, 59 insertions(+), 26 deletions(-) diff --git a/actionpack/lib/action_controller/caching/fragments.rb b/actionpack/lib/action_controller/caching/fragments.rb index e4d8678a07..e4f5de44ab 100644 --- a/actionpack/lib/action_controller/caching/fragments.rb +++ b/actionpack/lib/action_controller/caching/fragments.rb @@ -98,6 +98,17 @@ module ActionController #:nodoc: end end + # Check if a cached fragment from the location signified by key exists (see expire_fragment for acceptable formats) + def fragment_exist?(key, options = nil) + return unless cache_configured? + + key = fragment_cache_key(key) + + self.class.benchmark "Cached fragment exists?: #{key}" do + cache_store.exist?(key, options) + end + end + # Name can take one of three forms: # * String: This would normally take the form of a path like "pages/45/notes" # * Hash: Is treated as an implicit call to url_for, like { :controller => "pages", :action => "notes", :id => 45 } @@ -124,4 +135,4 @@ module ActionController #:nodoc: end end end -end \ No newline at end of file +end diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index 4aacb4a78a..f9b6b87bc6 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -232,7 +232,7 @@ class ActionCacheTest < Test::Unit::TestCase get :index cached_time = content_to_cache assert_equal cached_time, @response.body - assert_cache_exists 'hostname.com/action_caching_test' + assert fragment_exist?('hostname.com/action_caching_test') reset! get :index @@ -243,7 +243,7 @@ class ActionCacheTest < Test::Unit::TestCase get :destroy cached_time = content_to_cache assert_equal cached_time, @response.body - assert_cache_does_not_exist 'hostname.com/action_caching_test/destroy' + assert !fragment_exist?('hostname.com/action_caching_test/destroy') reset! get :destroy @@ -254,7 +254,7 @@ class ActionCacheTest < Test::Unit::TestCase get :with_layout cached_time = content_to_cache assert_not_equal cached_time, @response.body - assert_cache_exists 'hostname.com/action_caching_test/with_layout' + assert fragment_exist?('hostname.com/action_caching_test/with_layout') reset! get :with_layout @@ -266,14 +266,14 @@ class ActionCacheTest < Test::Unit::TestCase def test_action_cache_conditional_options @request.env['HTTP_ACCEPT'] = 'application/json' get :index - assert_cache_does_not_exist 'hostname.com/action_caching_test' + assert !fragment_exist?('hostname.com/action_caching_test') end def test_action_cache_with_custom_cache_path get :show cached_time = content_to_cache assert_equal cached_time, @response.body - assert_cache_exists 'test.host/custom/show' + assert fragment_exist?('test.host/custom/show') reset! get :show @@ -282,11 +282,11 @@ class ActionCacheTest < Test::Unit::TestCase def test_action_cache_with_custom_cache_path_in_block get :edit - assert_cache_exists 'test.host/edit' + assert fragment_exist?('test.host/edit') reset! get :edit, :id => 1 - assert_cache_exists 'test.host/1;edit' + assert fragment_exist?('test.host/1;edit') end def test_cache_expiration @@ -395,18 +395,8 @@ class ActionCacheTest < Test::Unit::TestCase @request.host = 'hostname.com' end - def assert_cache_exists(path) - full_path = cache_path(path) - assert File.exist?(full_path), "#{full_path.inspect} does not exist." - end - - def assert_cache_does_not_exist(path) - full_path = cache_path(path) - assert !File.exist?(full_path), "#{full_path.inspect} should not exist." - end - - def cache_path(path) - File.join(FILE_STORE_PATH, 'views', path + '.cache') + def fragment_exist?(path) + @controller.fragment_exist?(path) end def read_fragment(path) @@ -450,6 +440,19 @@ class FragmentCachingTest < Test::Unit::TestCase assert_nil @controller.read_fragment('name') end + def test_fragment_exist__with_caching_enabled + @store.write('views/name', 'value') + assert @controller.fragment_exist?('name') + assert !@controller.fragment_exist?('other_name') + end + + def test_fragment_exist__with_caching_disabled + ActionController::Base.perform_caching = false + @store.write('views/name', 'value') + assert !@controller.fragment_exist?('name') + assert !@controller.fragment_exist?('other_name') + end + def test_write_fragment__with_caching_enabled assert_nil @store.read('views/name') assert_equal 'value', @controller.write_fragment('name', 'value') @@ -494,7 +497,6 @@ class FragmentCachingTest < Test::Unit::TestCase assert_equal 'generated till now -> ', buffer end - def test_fragment_for @store.write('views/expensive', 'fragment content') fragment_computed = false diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index b3c9c23d9f..2f1143e610 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -87,8 +87,12 @@ module ActiveSupport def delete_matched(matcher, options = nil) log("delete matched", matcher.inspect, options) - end - + end + + def exist?(key, options = nil) + log("exist?", key, options) + end + def increment(key, amount = 1) log("incrementing", key, amount) if num = read(key) diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb index 16a2509ce2..5b771b1da0 100644 --- a/activesupport/lib/active_support/cache/file_store.rb +++ b/activesupport/lib/active_support/cache/file_store.rb @@ -40,13 +40,18 @@ module ActiveSupport end end + def exist?(name, options = nil) + super + File.exist?(real_file_path(name)) + end + private def real_file_path(name) '%s/%s.cache' % [@cache_path, name.gsub('?', '.').gsub(':', '.')] end def ensure_cache_path(path) - FileUtils.makedirs(path) unless File.exists?(path) + FileUtils.makedirs(path) unless File.exist?(path) end def search_dir(dir, &callback) diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb index bfe7e2ccf3..b3769b812f 100644 --- a/activesupport/lib/active_support/cache/mem_cache_store.rb +++ b/activesupport/lib/active_support/cache/mem_cache_store.rb @@ -48,7 +48,13 @@ module ActiveSupport rescue MemCache::MemCacheError => e logger.error("MemCacheError (#{e}): #{e.message}") false - end + end + + def exist?(key, options = nil) + # Doesn't call super, cause exist? in memcache is in fact a read + # But who cares? Reading is very fast anyway + !read(key, options).nil? + end def increment(key, amount = 1) log("incrementing", key, amount) diff --git a/activesupport/lib/active_support/cache/memory_store.rb b/activesupport/lib/active_support/cache/memory_store.rb index 4872e025cd..6f114273e4 100644 --- a/activesupport/lib/active_support/cache/memory_store.rb +++ b/activesupport/lib/active_support/cache/memory_store.rb @@ -24,7 +24,12 @@ module ActiveSupport super @data.delete_if { |k,v| k =~ matcher } end - + + def exist?(name,options = nil) + super + @data.has_key?(name) + end + def clear @data.clear end -- cgit v1.2.3 From e6f5079a48094eeba3dab9dca52b16b58ddc3634 Mon Sep 17 00:00:00 2001 From: Chris Hapgood Date: Fri, 16 May 2008 11:27:09 -0400 Subject: Test for assert_response for failure response without an exception. [#141 state:resolved] Signed-off-by: Pratik Naik --- actionpack/test/controller/action_pack_assertions_test.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index 1db057580b..f152b1d19c 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -131,6 +131,10 @@ class AssertResponseWithUnexpectedErrorController < ActionController::Base def index raise 'FAIL' end + + def show + render :text => "Boom", :status => 500 + end end module Admin @@ -483,6 +487,16 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase rescue Test::Unit::AssertionFailedError => e assert e.message.include?('FAIL') end + + def test_assert_response_failure_response_with_no_exception + @controller = AssertResponseWithUnexpectedErrorController.new + get :show + assert_response :success + flunk 'Expected non-success response' + rescue Test::Unit::AssertionFailedError + rescue + flunk "assert_response failed to handle failure response with missing, but optional, exception." + end end class ActionPackHeaderTest < Test::Unit::TestCase -- cgit v1.2.3 From ce63b2e5df22f4d80a90bc5b117c55044917d175 Mon Sep 17 00:00:00 2001 From: Cody Fauser Date: Mon, 19 May 2008 11:01:09 -0400 Subject: Markup inline code in ActiveRecord::Base docs --- activerecord/lib/active_record/base.rb | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index ccb35bd1ba..6f9d5e53f5 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -200,7 +200,7 @@ module ActiveRecord #:nodoc: # # All column values are automatically available through basic accessors on the Active Record object, but sometimes you # want to specialize this behavior. This can be done by overwriting the default accessors (using the same - # name as the attribute) and calling read_attribute(attr_name) and write_attribute(attr_name, value) to actually change things. + # name as the attribute) and calling read_attribute(attr_name) and write_attribute(attr_name, value) to actually change things. # Example: # # class Song < ActiveRecord::Base @@ -215,8 +215,8 @@ module ActiveRecord #:nodoc: # end # end # - # You can alternatively use self[:attribute]=(value) and self[:attribute] instead of write_attribute(:attribute, value) and - # read_attribute(:attribute) as a shorter form. + # You can alternatively use self[:attribute]=(value) and self[:attribute] instead of write_attribute(:attribute, value) and + # read_attribute(:attribute) as a shorter form. # # == Attribute query methods # @@ -236,7 +236,7 @@ module ActiveRecord #:nodoc: # # Sometimes you want to be able to read the raw attribute data without having the column-determined typecast run its course first. # That can be done by using the _before_type_cast accessors that all attributes have. For example, if your Account model - # has a balance attribute, you can call account.balance_before_type_cast or account.id_before_type_cast. + # has a balance attribute, you can call account.balance_before_type_cast or account.id_before_type_cast. # # This is especially useful in validation situations where the user might supply a string for an integer field and you want to display # the original string back in an error message. Accessing the attribute normally would typecast the string to 0, which isn't what you @@ -245,8 +245,8 @@ module ActiveRecord #:nodoc: # == Dynamic attribute-based finders # # Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects by simple queries without turning to SQL. They work by - # appending the name of an attribute to find_by_ or find_all_by_, so you get finders like Person.find_by_user_name, - # Person.find_all_by_last_name, Payment.find_by_transaction_id. So instead of writing + # appending the name of an attribute to find_by_ or find_all_by_, so you get finders like Person.find_by_user_name, + # Person.find_all_by_last_name, and Payment.find_by_transaction_id. So instead of writing # Person.find(:first, :conditions => ["user_name = ?", user_name]), you just do Person.find_by_user_name(user_name). # And instead of writing Person.find(:all, :conditions => ["last_name = ?", last_name]), you just do Person.find_all_by_last_name(last_name). # @@ -255,8 +255,8 @@ module ActiveRecord #:nodoc: # Person.find(:first, :conditions => ["user_name = ? AND password = ?", user_name, password]), you just do # Person.find_by_user_name_and_password(user_name, password). # - # It's even possible to use all the additional parameters to find. For example, the full interface for Payment.find_all_by_amount - # is actually Payment.find_all_by_amount(amount, options). And the full interface to Person.find_by_user_name is + # It's even possible to use all the additional parameters to find. For example, the full interface for Payment.find_all_by_amount + # is actually Payment.find_all_by_amount(amount, options). And the full interface to Person.find_by_user_name is # actually Person.find_by_user_name(user_name, options). So you could call Payment.find_all_by_amount(50, :order => "created_on"). # # The same dynamic finder style can be used to create the object if it doesn't already exist. This dynamic finder is called with @@ -316,8 +316,8 @@ module ActiveRecord #:nodoc: # class Client < Company; end # class PriorityClient < Client; end # - # When you do Firm.create(:name => "37signals"), this record will be saved in the companies table with type = "Firm". You can then - # fetch this row again using Company.find(:first, "name = '37signals'") and it will return a Firm object. + # When you do Firm.create(:name => "37signals"), this record will be saved in the companies table with type = "Firm". You can then + # fetch this row again using Company.find(:first, "name = '37signals'") and it will return a Firm object. # # If you don't have a type column defined in your table, single-table inheritance won't be triggered. In that case, it'll work just # like normal subclasses with no special magic for differentiating between them or reloading the right type with find. @@ -329,8 +329,8 @@ module ActiveRecord #:nodoc: # # Connections are usually created through ActiveRecord::Base.establish_connection and retrieved by ActiveRecord::Base.connection. # All classes inheriting from ActiveRecord::Base will use this connection. But you can also set a class-specific connection. - # For example, if Course is an ActiveRecord::Base, but resides in a different database, you can just say Course.establish_connection - # and Course *and all its subclasses* will use this connection instead. + # For example, if Course is an ActiveRecord::Base, but resides in a different database, you can just say Course.establish_connection + # and Course and all of its subclasses will use this connection instead. # # This feature is implemented by keeping a connection pool in ActiveRecord::Base that is a Hash indexed by the class. If a connection is # requested, the retrieve_connection method will go up the class-hierarchy until a connection is found in the connection pool. -- cgit v1.2.3 From 0b580047fecaa474aaae4c618e67420fbe545781 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 19 May 2008 19:25:44 +0200 Subject: gsub("http", "HTTP") --- actionpack/lib/action_controller/base.rb | 12 ++++++------ actionpack/lib/action_controller/filters.rb | 2 +- actionpack/lib/action_controller/test_process.rb | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index ea55fe42ce..f89afa15fa 100755 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -118,10 +118,10 @@ module ActionController #:nodoc: # # Requests are processed by the Action Controller framework by extracting the value of the "action" key in the request parameters. # This value should hold the name of the action to be performed. Once the action has been identified, the remaining - # request parameters, the session (if one is available), and the full request with all the http headers are made available to + # request parameters, the session (if one is available), and the full request with all the HTTP headers are made available to # the action through instance variables. Then the action is performed. # - # The full request object is available with the request accessor and is primarily used to query for http headers. These queries + # The full request object is available with the request accessor and is primarily used to query for HTTP headers. These queries # are made by accessing the environment hash, like this: # # def server_ip @@ -291,10 +291,10 @@ module ActionController #:nodoc: cattr_accessor :allow_concurrency # Modern REST web services often need to submit complex data to the web application. - # The param_parsers hash lets you register handlers which will process the http body and add parameters to the - # params hash. These handlers are invoked for post and put requests. + # The @@param_parsers hash lets you register handlers which will process the HTTP body and add parameters to the + # params hash. These handlers are invoked for POST and PUT requests. # - # By default application/xml is enabled. A XmlSimple class with the same param name as the root will be instantiated + # By default application/xml is enabled. A XmlSimple class with the same param name as the root will be instantiated # in the params. This allows XML requests to mask themselves as regular form submissions, so you can have one # action serve both regular forms and web service requests. # @@ -307,7 +307,7 @@ module ActionController #:nodoc: # # Note: Up until release 1.1 of Rails, Action Controller would default to using XmlSimple configured to discard the # root node for such requests. The new default is to keep the root, such that "David" results - # in params[:r][:name] for "David" instead of params[:name]. To get the old behavior, you can + # in params[:r][:name] for "David" instead of params[:name]. To get the old behavior, you can # re-register XmlSimple as application/xml handler ike this: # # ActionController::Base.param_parsers[Mime::XML] = diff --git a/actionpack/lib/action_controller/filters.rb b/actionpack/lib/action_controller/filters.rb index 6d0c83eb40..5aa34ceb19 100644 --- a/actionpack/lib/action_controller/filters.rb +++ b/actionpack/lib/action_controller/filters.rb @@ -215,7 +215,7 @@ module ActionController #:nodoc: # # before_filter and around_filter may halt the request # before a controller action is run. This is useful, for example, to deny - # access to unauthenticated users or to redirect from http to https. + # access to unauthenticated users or to redirect from HTTP to HTTPS. # Simply call render or redirect. After filters will not be executed if the filter # chain is halted. # diff --git a/actionpack/lib/action_controller/test_process.rb b/actionpack/lib/action_controller/test_process.rb index dcb6cdf4ca..eeb49a7021 100644 --- a/actionpack/lib/action_controller/test_process.rb +++ b/actionpack/lib/action_controller/test_process.rb @@ -357,7 +357,7 @@ module ActionController #:nodoc: module TestProcess def self.included(base) - # execute the request simulating a specific http method and set/volley the response + # execute the request simulating a specific HTTP method and set/volley the response %w( get post put delete head ).each do |method| base.class_eval <<-EOV, __FILE__, __LINE__ def #{method}(action, parameters = nil, session = nil, flash = nil) -- cgit v1.2.3 From 43d0200d94b7d66cee9ef3d20c376e03f30b1b60 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 19 May 2008 19:28:33 +0200 Subject: gsub("xml", "XML") --- actionpack/lib/action_controller/mime_type.rb | 2 +- activesupport/lib/active_support/core_ext/hash/conversions.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_controller/mime_type.rb b/actionpack/lib/action_controller/mime_type.rb index f43e2ba06d..1d6c8e704b 100644 --- a/actionpack/lib/action_controller/mime_type.rb +++ b/actionpack/lib/action_controller/mime_type.rb @@ -104,7 +104,7 @@ module Mime list[text_xml].name = Mime::XML.to_s end - # Look for more specific xml-based types and sort them ahead of app/xml + # Look for more specific XML-based types and sort them ahead of app/xml if app_xml idx = app_xml diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb index 3d6a8d8588..f0f54a92fe 100644 --- a/activesupport/lib/active_support/core_ext/hash/conversions.rb +++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb @@ -212,7 +212,7 @@ module ActiveSupport #:nodoc: nil # If the type is the only element which makes it then # this still makes the value nil, except if type is - # a xml node(where type['value'] is a Hash) + # a XML node(where type['value'] is a Hash) elsif value['type'] && value.size == 1 && !value['type'].is_a?(::Hash) nil else -- cgit v1.2.3 From abc42927052969aa878b6f5f83d821f5771fc8c1 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 19 May 2008 19:34:07 +0200 Subject: gsub("yaml", "YAML") --- .../abstract/connection_specification.rb | 2 +- activesupport/lib/active_support/json/decoding.rb | 2 +- .../about_yml_plugins/bad_about_yml/about.yml | 2 +- railties/test/generators/generator_test_helper.rb | 60 +++++++++++----------- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb index 34627dfaf9..2a8807fb78 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb @@ -193,7 +193,7 @@ module ActiveRecord # :database => "path/to/dbfile" # ) # - # Also accepts keys as strings (for parsing from yaml for example): + # Also accepts keys as strings (for parsing from YAML for example): # # ActiveRecord::Base.establish_connection( # "adapter" => "sqlite", diff --git a/activesupport/lib/active_support/json/decoding.rb b/activesupport/lib/active_support/json/decoding.rb index c58001f49f..fdb219dbf7 100644 --- a/activesupport/lib/active_support/json/decoding.rb +++ b/activesupport/lib/active_support/json/decoding.rb @@ -31,7 +31,7 @@ module ActiveSupport 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 + # the position in the final YAML output total_marks = marks.size times << pos+total_marks << scanner.pos+total_marks end diff --git a/railties/test/fixtures/about_yml_plugins/bad_about_yml/about.yml b/railties/test/fixtures/about_yml_plugins/bad_about_yml/about.yml index 79d5721a53..fe80872a16 100644 --- a/railties/test/fixtures/about_yml_plugins/bad_about_yml/about.yml +++ b/railties/test/fixtures/about_yml_plugins/bad_about_yml/about.yml @@ -1 +1 @@ -# an empty yaml file - any content in here seems to get parsed as a string \ No newline at end of file +# an empty YAML file - any content in here seems to get parsed as a string \ No newline at end of file diff --git a/railties/test/generators/generator_test_helper.rb b/railties/test/generators/generator_test_helper.rb index c99df6e2d3..41ddeb7d71 100644 --- a/railties/test/generators/generator_test_helper.rb +++ b/railties/test/generators/generator_test_helper.rb @@ -86,19 +86,19 @@ class GeneratorTestCase < Test::Unit::TestCase # don't complain, test/unit end - # Instantiates the Generator + # Instantiates the Generator. def build_generator(name, params) Rails::Generator::Base.instance(name, params) end - # Runs the create command (like the command line does) + # Runs the +create+ command (like the command line does). def run_generator(name, params) silence_generator do build_generator(name, params).command(:create).invoke! end end - # Silences the logger temporarily and returns the output as a String + # Silences the logger temporarily and returns the output as a String. def silence_generator logger_original = Rails::Generator::Base.logger myout = StringIO.new @@ -108,7 +108,7 @@ class GeneratorTestCase < Test::Unit::TestCase myout.string end - # asserts that the given controller was generated. + # Asserts that the given controller was generated. # It takes a name or symbol without the _controller part and an optional super class. # The contents of the class source file is passed to a block. def assert_generated_controller_for(name, parent = "ApplicationController") @@ -117,44 +117,44 @@ class GeneratorTestCase < Test::Unit::TestCase end end - # asserts that the given model was generated. + # Asserts that the given model was generated. # It takes a name or symbol and an optional super class. - # the contents of the class source file is passed to a block. + # The contents of the class source file is passed to a block. def assert_generated_model_for(name, parent = "ActiveRecord::Base") assert_generated_class "app/models/#{name.to_s.underscore}", parent do |body| yield body if block_given? end end - # asserts that the given helper was generated. - # It takes a name or symbol without the _helper part - # the contents of the module source file is passed to a block. + # Asserts that the given helper was generated. + # It takes a name or symbol without the _helper part. + # The contents of the module source file is passed to a block. def assert_generated_helper_for(name) assert_generated_module "app/helpers/#{name.to_s.underscore}_helper" do |body| yield body if block_given? end end - # asserts that the given functional test was generated. + # Asserts that the given functional test was generated. # It takes a name or symbol without the _controller_test part and an optional super class. - # the contents of the class source file is passed to a block. + # The contents of the class source file is passed to a block. def assert_generated_functional_test_for(name, parent = "ActionController::TestCase") assert_generated_class "test/functional/#{name.to_s.underscore}_controller_test",parent do |body| yield body if block_given? end end - # asserts that the given unit test was generated. + # Asserts that the given unit test was generated. # It takes a name or symbol without the _test part and an optional super class. - # the contents of the class source file is passed to a block. + # The contents of the class source file is passed to a block. def assert_generated_unit_test_for(name, parent = "ActiveSupport::TestCase") assert_generated_class "test/unit/#{name.to_s.underscore}_test", parent do |body| yield body if block_given? end end - # asserts that the given file was generated. - # the contents of the file is passed to a block. + # Asserts that the given file was generated. + # The contents of the file is passed to a block. def assert_generated_file(path) assert_file_exists(path) File.open("#{RAILS_ROOT}/#{path}") do |f| @@ -168,9 +168,9 @@ class GeneratorTestCase < Test::Unit::TestCase "The file '#{RAILS_ROOT}/#{path}' should exist" end - # asserts that the given class source file was generated. + # Asserts that the given class source file was generated. # It takes a path without the .rb part and an optional super class. - # the contents of the class source file is passed to a block. + # The contents of the class source file is passed to a block. def assert_generated_class(path, parent = nil) # FIXME: Sucky way to detect namespaced classes if path.split('/').size > 3 @@ -187,9 +187,9 @@ class GeneratorTestCase < Test::Unit::TestCase end end - # asserts that the given module source file was generated. + # Asserts that the given module source file was generated. # It takes a path without the .rb part. - # the contents of the class source file is passed to a block. + # The contents of the class source file is passed to a block. def assert_generated_module(path) # FIXME: Sucky way to detect namespaced modules if path.split('/').size > 3 @@ -206,18 +206,18 @@ class GeneratorTestCase < Test::Unit::TestCase end end - # asserts that the given css stylesheet file was generated. + # Asserts that the given css stylesheet file was generated. # It takes a path without the .css part. - # the contents of the stylesheet source file is passed to a block. + # The contents of the stylesheet source file is passed to a block. def assert_generated_stylesheet(path) assert_generated_file("public/stylesheets/#{path}.css") do |body| yield body if block_given? end end - # asserts that the given yaml file was generated. + # Asserts that the given YAML file was generated. # It takes a path without the .yml part. - # the parsed yaml tree is passed to a block. + # The parsed YAML tree is passed to a block. def assert_generated_yaml(path) assert_generated_file("#{path}.yml") do |body| yaml = YAML.load(body) @@ -226,18 +226,18 @@ class GeneratorTestCase < Test::Unit::TestCase end end - # asserts that the given fixtures yaml file was generated. + # Asserts that the given fixtures yaml file was generated. # It takes a fixture name without the .yml part. - # the parsed yaml tree is passed to a block. + # The parsed YAML tree is passed to a block. def assert_generated_fixtures_for(name) assert_generated_yaml "test/fixtures/#{name.to_s.underscore}" do |yaml| yield yaml if block_given? end end - # asserts that the given views were generated. + # Asserts that the given views were generated. # It takes a controller name and a list of views (including extensions). - # The body of each view is passed to a block + # The body of each view is passed to a block. def assert_generated_views_for(name, *actions) actions.each do |action| assert_generated_file("app/views/#{name.to_s.underscore}/#{action}") do |body| @@ -262,7 +262,7 @@ class GeneratorTestCase < Test::Unit::TestCase assert !File.exist?(migration_file), "should not create migration #{migration_file}" end - # asserts that the given resource was added to the routes. + # Asserts that the given resource was added to the routes. def assert_added_route_for(name) assert_generated_file("config/routes.rb") do |body| assert_match /map.resources :#{name.to_s.underscore}/, body, @@ -270,7 +270,7 @@ class GeneratorTestCase < Test::Unit::TestCase end end - # asserts that the given methods are defined in the body. + # Asserts that the given methods are defined in the body. # This does assume standard rails code conventions with regards to the source code. # The body of each individual method is passed to a block. def assert_has_method(body, *methods) @@ -280,7 +280,7 @@ class GeneratorTestCase < Test::Unit::TestCase end end - # asserts that the given column is defined in the migration + # Asserts that the given column is defined in the migration. def assert_generated_column(body, name, type) assert_match /t\.#{type.to_s} :#{name.to_s}/, body, "should have column #{name.to_s} defined" end -- cgit v1.2.3 From 2b6bec5cdd84c4ba65cbe99ae48697d977ae9491 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 19 May 2008 11:16:21 -0700 Subject: Workaround missing Test::Unit::TestCase::PASSTHROUGH_EXCEPTIONS in Ruby < 1.8.6. [#224 state:resolved] --- .../lib/active_support/testing/setup_and_teardown.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb index b2a937edd0..ed8e34510a 100644 --- a/activesupport/lib/active_support/testing/setup_and_teardown.rb +++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb @@ -1,6 +1,14 @@ module ActiveSupport module Testing module SetupAndTeardown + # For compatibility with Ruby < 1.8.6 + PASSTHROUGH_EXCEPTIONS = + if defined?(Test::Unit::TestCase::PASSTHROUGH_EXCEPTIONS) + Test::Unit::TestCase::PASSTHROUGH_EXCEPTIONS + else + [NoMemoryError, SignalException, Interrupt, SystemExit] + end + def self.included(base) base.send :include, ActiveSupport::Callbacks base.define_callbacks :setup, :teardown @@ -25,7 +33,7 @@ module ActiveSupport __send__(@method_name) rescue Test::Unit::AssertionFailedError => e add_failure(e.message, e.backtrace) - rescue *Test::Unit::TestCase::PASSTHROUGH_EXCEPTIONS + rescue *PASSTHROUGH_EXCEPTIONS raise rescue Exception add_error($!) @@ -35,7 +43,7 @@ module ActiveSupport run_callbacks :teardown, :enumerator => :reverse_each rescue Test::Unit::AssertionFailedError => e add_failure(e.message, e.backtrace) - rescue *Test::Unit::TestCase::PASSTHROUGH_EXCEPTIONS + rescue *PASSTHROUGH_EXCEPTIONS raise rescue Exception add_error($!) -- cgit v1.2.3 From 411c675947db097ec25fe3684f82f424c19a39c6 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 19 May 2008 20:34:38 +0200 Subject: #method vs +method+ in Action Mailer --- actionmailer/lib/action_mailer/base.rb | 6 +++--- actionmailer/lib/action_mailer/helpers.rb | 2 +- actionmailer/lib/action_mailer/part.rb | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 7ed133d099..7ab6e37503 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -383,8 +383,8 @@ module ActionMailer #:nodoc: # Receives a raw email, parses it into an email object, decodes it, # instantiates a new mailer, and passes the email object to the mailer - # object's #receive method. If you want your mailer to be able to - # process incoming messages, you'll need to implement a #receive + # object's +receive+ method. If you want your mailer to be able to + # process incoming messages, you'll need to implement a +receive+ # method that accepts the email object as a parameter: # # class MyMailer < ActionMailer::Base @@ -490,7 +490,7 @@ module ActionMailer #:nodoc: end # Delivers a TMail::Mail object. By default, it delivers the cached mail - # object (from the #create! method). If no cached mail object exists, and + # object (from the create! method). If no cached mail object exists, and # no alternate has been given as the parameter, this will fail. def deliver!(mail = @mail) raise "no mail object available for delivery!" unless mail diff --git a/actionmailer/lib/action_mailer/helpers.rb b/actionmailer/lib/action_mailer/helpers.rb index 3e5ed9e9d7..9c5fcc6afb 100644 --- a/actionmailer/lib/action_mailer/helpers.rb +++ b/actionmailer/lib/action_mailer/helpers.rb @@ -34,7 +34,7 @@ module ActionMailer # helper FooHelper # includes FooHelper in the template class. # helper { def foo() "#{bar} is the very best" end } - # evaluates the block in the template class, adding method #foo. + # evaluates the block in the template class, adding method +foo+. # helper(:three, BlindHelper) { def mice() 'mice' end } # does all three. def helper(*args, &block) diff --git a/actionmailer/lib/action_mailer/part.rb b/actionmailer/lib/action_mailer/part.rb index de1b1689f7..2dabf15f08 100644 --- a/actionmailer/lib/action_mailer/part.rb +++ b/actionmailer/lib/action_mailer/part.rb @@ -5,7 +5,7 @@ require 'action_mailer/utils' module ActionMailer # Represents a subpart of an email message. It shares many similar # attributes of ActionMailer::Base. Although you can create parts manually - # and add them to the #parts list of the mailer, it is easier + # and add them to the +parts+ list of the mailer, it is easier # to use the helper methods in ActionMailer::PartContainer. class Part include ActionMailer::AdvAttrAccessor @@ -13,7 +13,7 @@ module ActionMailer # Represents the body of the part, as a string. This should not be a # Hash (like ActionMailer::Base), but if you want a template to be rendered - # into the body of a subpart you can do it with the mailer's #render method + # into the body of a subpart you can do it with the mailer's +render+ method # and assign the result here. adv_attr_accessor :body -- cgit v1.2.3 From 5ff769afc96717ae87c9fbe977b81b7da47cf5c5 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 19 May 2008 20:50:22 +0200 Subject: #method vs +method+ in Action Controller --- .../assertions/routing_assertions.rb | 6 ++-- .../assertions/selector_assertions.rb | 20 ++++++------ .../action_controller/assertions/tag_assertions.rb | 6 ++-- actionpack/lib/action_controller/filters.rb | 38 +++++++++++----------- actionpack/lib/action_controller/integration.rb | 16 ++++----- actionpack/lib/action_controller/resources.rb | 6 ++-- .../lib/action_controller/routing/builder.rb | 6 ++-- 7 files changed, 49 insertions(+), 49 deletions(-) diff --git a/actionpack/lib/action_controller/assertions/routing_assertions.rb b/actionpack/lib/action_controller/assertions/routing_assertions.rb index 2acd003243..491b72d586 100644 --- a/actionpack/lib/action_controller/assertions/routing_assertions.rb +++ b/actionpack/lib/action_controller/assertions/routing_assertions.rb @@ -59,7 +59,7 @@ module ActionController end end - # Asserts that the provided options can be used to generate the provided path. This is the inverse of #assert_recognizes. + # Asserts that the provided options can be used to generate the provided path. This is the inverse of +assert_recognizes+. # The +extras+ parameter is used to tell the request the names and values of additional request parameters that would be in # a query string. The +message+ parameter allows you to specify a custom error message for assertion failures. # @@ -96,8 +96,8 @@ module ActionController end # Asserts that path and options match both ways; in other words, it verifies that path generates - # options and then that options generates path. This essentially combines #assert_recognizes - # and #assert_generates into one step. + # options and then that options generates path. This essentially combines +assert_recognizes+ + # and +assert_generates+ into one step. # # The +extras+ hash allows you to specify options that would normally be provided as a query string to the action. The # +message+ parameter allows you to specify a custom error message to display upon failure. diff --git a/actionpack/lib/action_controller/assertions/selector_assertions.rb b/actionpack/lib/action_controller/assertions/selector_assertions.rb index 9ef093acfc..871fb23c1e 100644 --- a/actionpack/lib/action_controller/assertions/selector_assertions.rb +++ b/actionpack/lib/action_controller/assertions/selector_assertions.rb @@ -12,12 +12,12 @@ module ActionController NO_STRIP = %w{pre script style textarea} end - # Adds the #assert_select method for use in Rails functional + # Adds the +assert_select+ method for use in Rails functional # test cases, which can be used to make assertions on the response HTML of a controller - # action. You can also call #assert_select within another #assert_select to + # action. You can also call +assert_select+ within another +assert_select+ to # make assertions on elements selected by the enclosing assertion. # - # Use #css_select to select elements without making an assertions, either + # Use +css_select+ to select elements without making an assertions, either # from the response HTML or elements selected by the enclosing assertion. # # In addition to HTML responses, you can make the following assertions: @@ -114,8 +114,8 @@ module ActionController # starting from (and including) that element and all its children in # depth-first order. # - # If no element if specified, calling #assert_select will select from the - # response HTML. Calling #assert_select inside an #assert_select block will + # If no element if specified, calling +assert_select+ will select from the + # response HTML. Calling #assert_select inside an +assert_select+ block will # run the assertion for each element selected by the enclosing assertion. # # ==== Example @@ -356,16 +356,16 @@ module ActionController # # === Using blocks # - # Without a block, #assert_select_rjs merely asserts that the response + # Without a block, +assert_select_rjs+ merely asserts that the response # contains one or more RJS statements that replace or update content. # - # With a block, #assert_select_rjs also selects all elements used in + # With a block, +assert_select_rjs+ also selects all elements used in # these statements and passes them to the block. Nested assertions are # supported. # - # Calling #assert_select_rjs with no arguments and using nested asserts + # Calling +assert_select_rjs+ with no arguments and using nested asserts # asserts that the HTML content is returned by one or more RJS statements. - # Using #assert_select directly makes the same assertion on the content, + # Using +assert_select+ directly makes the same assertion on the content, # but without distinguishing whether the content is returned in an HTML # or JavaScript. # @@ -601,7 +601,7 @@ module ActionController RJS_PATTERN_UNICODE_ESCAPED_CHAR = /\\u([0-9a-zA-Z]{4})/ end - # #assert_select and #css_select call this to obtain the content in the HTML + # +assert_select+ and +css_select+ call this to obtain the content in the HTML # page, or from all the RJS statements, depending on the type of response. def response_from_page_or_rjs() content_type = @response.content_type diff --git a/actionpack/lib/action_controller/assertions/tag_assertions.rb b/actionpack/lib/action_controller/assertions/tag_assertions.rb index 4ac489520a..90ba3668fb 100644 --- a/actionpack/lib/action_controller/assertions/tag_assertions.rb +++ b/actionpack/lib/action_controller/assertions/tag_assertions.rb @@ -91,7 +91,7 @@ module ActionController # :descendant => { :tag => "span", # :child => /hello world/ } # - # Please note: #assert_tag and #assert_no_tag only work + # Please note: +assert_tag+ and +assert_no_tag+ only work # with well-formed XHTML. They recognize a few tags as implicitly self-closing # (like br and hr and such) but will not work correctly with tags # that allow optional closing tags (p, li, td). You must explicitly @@ -104,8 +104,8 @@ module ActionController end end - # Identical to #assert_tag, but asserts that a matching tag does _not_ - # exist. (See #assert_tag for a full discussion of the syntax.) + # Identical to +assert_tag+, but asserts that a matching tag does _not_ + # exist. (See +assert_tag+ for a full discussion of the syntax.) # # === Examples # # Assert that there is not a "div" containing a "p" diff --git a/actionpack/lib/action_controller/filters.rb b/actionpack/lib/action_controller/filters.rb index 5aa34ceb19..60d92d9b98 100644 --- a/actionpack/lib/action_controller/filters.rb +++ b/actionpack/lib/action_controller/filters.rb @@ -100,10 +100,10 @@ module ActionController #:nodoc: # # Around filters wrap an action, executing code both before and after. # They may be declared as method references, blocks, or objects responding - # to #filter or to both #before and #after. + # to +filter+ or to both +before+ and +after+. # - # To use a method as an around_filter, pass a symbol naming the Ruby method. - # Yield (or block.call) within the method to run the action. + # To use a method as an +around_filter+, pass a symbol naming the Ruby method. + # Yield (or block.call) within the method to run the action. # # around_filter :catch_exceptions # @@ -115,9 +115,9 @@ module ActionController #:nodoc: # raise # end # - # To use a block as an around_filter, pass a block taking as args both + # To use a block as an +around_filter+, pass a block taking as args both # the controller and the action block. You can't call yield directly from - # an around_filter block; explicitly call the action block instead: + # an +around_filter+ block; explicitly call the action block instead: # # around_filter do |controller, action| # logger.debug "before #{controller.action_name}" @@ -125,7 +125,7 @@ module ActionController #:nodoc: # logger.debug "after #{controller.action_name}" # end # - # To use a filter object with around_filter, pass an object responding + # To use a filter object with +around_filter+, pass an object responding # to :filter or both :before and :after. With a # filter method, yield to the block as above: # @@ -137,7 +137,7 @@ module ActionController #:nodoc: # end # end # - # With before and after methods: + # With +before+ and +after+ methods: # # around_filter Authorizer.new # @@ -154,9 +154,9 @@ module ActionController #:nodoc: # end # end # - # If the filter has before and after methods, the before method will be - # called before the action. If before renders or redirects, the filter chain is - # halted and after will not be run. See Filter Chain Halting below for + # If the filter has +before+ and +after+ methods, the +before+ method will be + # called before the action. If +before+ renders or redirects, the filter chain is + # halted and +after+ will not be run. See Filter Chain Halting below for # an example. # # == Filter chain skipping @@ -241,10 +241,10 @@ module ActionController #:nodoc: # . / # #after (actual filter code is run, unless the around filter does not yield) # - # If #around returns before yielding, #after will still not be run. The #before - # filter and controller action will not be run. If #before renders or redirects, - # the second half of #around and will still run but #after and the - # action will not. If #around fails to yield, #after will not be run. + # If +around+ returns before yielding, +after+ will still not be run. The +before+ + # filter and controller action will not be run. If +before+ renders or redirects, + # the second half of +around+ and will still run but +after+ and the + # action will not. If +around+ fails to yield, +after+ will not be run. class FilterChain < ActiveSupport::Callbacks::CallbackChain #:nodoc: def append_filter_to_chain(filters, filter_type, &block) @@ -471,7 +471,7 @@ module ActionController #:nodoc: # Shorthand for append_after_filter since it's the most common. alias :after_filter :append_after_filter - # If you append_around_filter A.new, B.new, the filter chain looks like + # If you append_around_filter A.new, B.new, the filter chain looks like # # B#before # A#before @@ -479,13 +479,13 @@ module ActionController #:nodoc: # A#after # B#after # - # With around filters which yield to the action block, #before and #after + # With around filters which yield to the action block, +before+ and +after+ # are the code before and after the yield. def append_around_filter(*filters, &block) filter_chain.append_filter_to_chain(filters, :around, &block) end - # If you prepend_around_filter A.new, B.new, the filter chain looks like: + # If you prepend_around_filter A.new, B.new, the filter chain looks like: # # A#before # B#before @@ -493,13 +493,13 @@ module ActionController #:nodoc: # B#after # A#after # - # With around filters which yield to the action block, #before and #after + # With around filters which yield to the action block, +before+ and +after+ # are the code before and after the yield. def prepend_around_filter(*filters, &block) filter_chain.prepend_filter_to_chain(filters, :around, &block) end - # Shorthand for append_around_filter since it's the most common. + # Shorthand for +append_around_filter+ since it's the most common. alias :around_filter :append_around_filter # Removes the specified filters from the +before+ filter chain. Note that this only works for skipping method-reference diff --git a/actionpack/lib/action_controller/integration.rb b/actionpack/lib/action_controller/integration.rb index a4bbee9c54..3b1d2b5641 100644 --- a/actionpack/lib/action_controller/integration.rb +++ b/actionpack/lib/action_controller/integration.rb @@ -136,25 +136,25 @@ module ActionController end # Performs a GET request, following any subsequent redirect. - # See #request_via_redirect() for more information. + # See +request_via_redirect+ for more information. def get_via_redirect(path, parameters = nil, headers = nil) request_via_redirect(:get, path, parameters, headers) end # Performs a POST request, following any subsequent redirect. - # See #request_via_redirect() for more information. + # See +request_via_redirect+ for more information. def post_via_redirect(path, parameters = nil, headers = nil) request_via_redirect(:post, path, parameters, headers) end # Performs a PUT request, following any subsequent redirect. - # See #request_via_redirect() for more information. + # See +request_via_redirect+ for more information. def put_via_redirect(path, parameters = nil, headers = nil) request_via_redirect(:put, path, parameters, headers) end # Performs a DELETE request, following any subsequent redirect. - # See #request_via_redirect() for more information. + # See +request_via_redirect+ for more information. def delete_via_redirect(path, parameters = nil, headers = nil) request_via_redirect(:delete, path, parameters, headers) end @@ -166,12 +166,12 @@ module ActionController # Performs a GET request with the given parameters. The parameters may # be +nil+, a Hash, or a string that is appropriately encoded - # (application/x-www-form-urlencoded or multipart/form-data). The headers - # should be a hash. The keys will automatically be upcased, with the + # (application/x-www-form-urlencoded or multipart/form-data). + # The headers should be a hash. The keys will automatically be upcased, with the # prefix 'HTTP_' added if needed. # - # You can also perform POST, PUT, DELETE, and HEAD requests with #post, - # #put, #delete, and #head. + # You can also perform POST, PUT, DELETE, and HEAD requests with +post+, + # +put+, +delete+, and +head+. def get(path, parameters = nil, headers = nil) process :get, path, parameters, headers end diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/resources.rb index 26f75780c1..9fb1f9fa39 100644 --- a/actionpack/lib/action_controller/resources.rb +++ b/actionpack/lib/action_controller/resources.rb @@ -191,7 +191,7 @@ module ActionController # end # end # - # Along with the routes themselves, #resources generates named routes for use in + # Along with the routes themselves, +resources+ generates named routes for use in # controllers and views. map.resources :messages produces the following named routes and helpers: # # Named Route Helpers @@ -208,7 +208,7 @@ module ActionController # edit_message edit_message_url(id), hash_for_edit_message_url(id), # edit_message_path(id), hash_for_edit_message_path(id) # - # You can use these helpers instead of #url_for or methods that take #url_for parameters. For example: + # You can use these helpers instead of +url_for+ or methods that take +url_for+ parameters. For example: # # redirect_to :controller => 'messages', :action => 'index' # # and @@ -406,7 +406,7 @@ module ActionController # end # end # - # Along with the routes themselves, #resource generates named routes for + # Along with the routes themselves, +resource+ generates named routes for # use in controllers and views. map.resource :account produces # these named routes and helpers: # diff --git a/actionpack/lib/action_controller/routing/builder.rb b/actionpack/lib/action_controller/routing/builder.rb index b1a98d1a51..4740113ed0 100644 --- a/actionpack/lib/action_controller/routing/builder.rb +++ b/actionpack/lib/action_controller/routing/builder.rb @@ -23,9 +23,9 @@ module ActionController # Accepts a "route path" (a string defining a route), and returns the array # of segments that corresponds to it. Note that the segment array is only # partially initialized--the defaults and requirements, for instance, need - # to be set separately, via the #assign_route_options method, and the - # #optional? method for each segment will not be reliable until after - # #assign_route_options is called, as well. + # to be set separately, via the +assign_route_options+ method, and the + # optional? method for each segment will not be reliable until after + # +assign_route_options+ is called, as well. def segments_for_route_path(path) rest, segments = path, [] -- cgit v1.2.3 From 67603693b5933d825fb17036394fe913e6edde8e Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 19 May 2008 21:00:29 +0200 Subject: #method vs +method+ in Action View --- .../lib/action_view/helpers/form_options_helper.rb | 34 ++++++++++------------ .../lib/action_view/helpers/prototype_helper.rb | 8 ++--- .../lib/action_view/helpers/sanitize_helper.rb | 31 ++++++++++---------- actionpack/lib/action_view/template.rb | 4 +-- 4 files changed, 38 insertions(+), 39 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index bf65fe5574..460d47fb0f 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -144,10 +144,10 @@ module ActionView # In addition to the :include_blank option documented above, # this method also supports a :model option, which defaults # to TimeZone. This may be used by users to specify a different time - # zone model object. (See #time_zone_options_for_select for more + # zone model object. (See +time_zone_options_for_select+ for more # information.) # Finally, this method supports a :default option, which selects - # a default TimeZone if the object's time zone is nil. + # a default TimeZone if the object's time zone is +nil+. # # Examples: # time_zone_select( "user", "time_zone", nil, :include_blank => true) @@ -209,24 +209,22 @@ module ActionView options_for_select(options, selected) end - # Returns a string of tags, like #options_from_collection_for_select, but + # Returns a string of tags, like options_from_collection_for_select, but # groups them by tags based on the object relationships of the arguments. # # Parameters: - # +collection+:: An array of objects representing the tags - # +group_method+:: The name of a method which, when called on a member of +collection+, returns an - # array of child objects representing the tags - # +group_label_method+:: The name of a method which, when called on a member of +collection+, returns a - # string to be used as the +label+ attribute for its tag - # +option_key_method+:: The name of a method which, when called on a child object of a member of - # +collection+, returns a value to be used as the +value+ attribute for its - # tag - # +option_value_method+:: The name of a method which, when called on a child object of a member of - # +collection+, returns a value to be used as the contents of its - # tag - # +selected_key+:: A value equal to the +value+ attribute for one of the tags, - # which will have the +selected+ attribute set. Corresponds to the return value - # of one of the calls to +option_key_method+. If +nil+, no selection is made. + # * +collection+ - An array of objects representing the tags. + # * +group_method+ - The name of a method which, when called on a member of +collection+, returns an + # array of child objects representing the tags. + # * group_label_method+ - The name of a method which, when called on a member of +collection+, returns a + # string to be used as the +label+ attribute for its tag. + # * +option_key_method+ - The name of a method which, when called on a child object of a member of + # +collection+, returns a value to be used as the +value+ attribute for its tag. + # * +option_value_method+ - The name of a method which, when called on a child object of a member of + # +collection+, returns a value to be used as the contents of its tag. + # * +selected_key+ - A value equal to the +value+ attribute for one of the tags, + # which will have the +selected+ attribute set. Corresponds to the return value of one of the calls + # to +option_key_method+. If +nil+, no selection is made. # # Example object structure for use with this method: # class Continent < ActiveRecord::Base @@ -293,7 +291,7 @@ module ActionView # # By default, +model+ is the TimeZone constant (which can be obtained # in ActiveRecord as a value object). The only requirement is that the - # +model+ parameter be an object that responds to #all, and returns + # +model+ parameter be an object that responds to +all+, and returns # an array of objects that represent time zones. # # NOTE: Only the option tags are returned, you have to wrap this call in diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index 1a0e660d52..c79f791c57 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -595,8 +595,8 @@ module ActionView # JavaScript sent with a Content-type of "text/javascript". # # Create new instances with PrototypeHelper#update_page or with - # ActionController::Base#render, then call #insert_html, #replace_html, - # #remove, #show, #hide, #visual_effect, or any other of the built-in + # ActionController::Base#render, then call +insert_html+, +replace_html+, + # +remove+, +show+, +hide+, +visual_effect+, or any other of the built-in # methods on the yielded generator in any order you like to modify the # content and appearance of the current page. # @@ -687,7 +687,7 @@ module ActionView end end - # Returns an object whose #to_json evaluates to +code+. Use this to pass a literal JavaScript + # Returns an object whose to_json evaluates to +code+. Use this to pass a literal JavaScript # expression as an argument to another JavaScriptGenerator method. def literal(code) ActiveSupport::JSON::Variable.new(code.to_s) @@ -1173,7 +1173,7 @@ module ActionView super(generator) end - # The JSON Encoder calls this to check for the #to_json method + # The JSON Encoder calls this to check for the +to_json+ method # Since it's a blank slate object, I suppose it responds to anything. def respond_to?(method) true diff --git a/actionpack/lib/action_view/helpers/sanitize_helper.rb b/actionpack/lib/action_view/helpers/sanitize_helper.rb index 6c0a7ec25c..968a974b35 100644 --- a/actionpack/lib/action_view/helpers/sanitize_helper.rb +++ b/actionpack/lib/action_view/helpers/sanitize_helper.rb @@ -57,7 +57,7 @@ module ActionView self.class.white_list_sanitizer.sanitize(html, options) end - # Sanitizes a block of css code. Used by #sanitize when it comes across a style attribute + # Sanitizes a block of CSS code. Used by +sanitize+ when it comes across a style attribute. def sanitize_css(style) self.class.white_list_sanitizer.sanitize_css(style) end @@ -111,8 +111,8 @@ module ActionView end end - # Gets the HTML::FullSanitizer instance used by strip_tags. Replace with - # any object that responds to #sanitize + # Gets the HTML::FullSanitizer instance used by +strip_tags+. Replace with + # any object that responds to +sanitize+. # # Rails::Initializer.run do |config| # config.action_view.full_sanitizer = MySpecialSanitizer.new @@ -122,8 +122,8 @@ module ActionView @full_sanitizer ||= HTML::FullSanitizer.new end - # Gets the HTML::LinkSanitizer instance used by strip_links. Replace with - # any object that responds to #sanitize + # Gets the HTML::LinkSanitizer instance used by +strip_links+. Replace with + # any object that responds to +sanitize+. # # Rails::Initializer.run do |config| # config.action_view.link_sanitizer = MySpecialSanitizer.new @@ -133,8 +133,8 @@ module ActionView @link_sanitizer ||= HTML::LinkSanitizer.new end - # Gets the HTML::WhiteListSanitizer instance used by sanitize and sanitize_css. - # Replace with any object that responds to #sanitize + # Gets the HTML::WhiteListSanitizer instance used by sanitize and +sanitize_css+. + # Replace with any object that responds to +sanitize+. # # Rails::Initializer.run do |config| # config.action_view.white_list_sanitizer = MySpecialSanitizer.new @@ -144,7 +144,7 @@ module ActionView @white_list_sanitizer ||= HTML::WhiteListSanitizer.new end - # Adds valid HTML attributes that the #sanitize helper checks for URIs. + # Adds valid HTML attributes that the +sanitize+ helper checks for URIs. # # Rails::Initializer.run do |config| # config.action_view.sanitized_uri_attributes = 'lowsrc', 'target' @@ -154,7 +154,7 @@ module ActionView HTML::WhiteListSanitizer.uri_attributes.merge(attributes) end - # Adds to the Set of 'bad' tags for the #sanitize helper. + # Adds to the Set of 'bad' tags for the +sanitize+ helper. # # Rails::Initializer.run do |config| # config.action_view.sanitized_bad_tags = 'embed', 'object' @@ -163,7 +163,8 @@ module ActionView def sanitized_bad_tags=(attributes) HTML::WhiteListSanitizer.bad_tags.merge(attributes) end - # Adds to the Set of allowed tags for the #sanitize helper. + + # Adds to the Set of allowed tags for the +sanitize+ helper. # # Rails::Initializer.run do |config| # config.action_view.sanitized_allowed_tags = 'table', 'tr', 'td' @@ -173,7 +174,7 @@ module ActionView HTML::WhiteListSanitizer.allowed_tags.merge(attributes) end - # Adds to the Set of allowed html attributes for the #sanitize helper. + # Adds to the Set of allowed HTML attributes for the +sanitize+ helper. # # Rails::Initializer.run do |config| # config.action_view.sanitized_allowed_attributes = 'onclick', 'longdesc' @@ -183,7 +184,7 @@ module ActionView HTML::WhiteListSanitizer.allowed_attributes.merge(attributes) end - # Adds to the Set of allowed css properties for the #sanitize and #sanitize_css heleprs. + # Adds to the Set of allowed CSS properties for the #sanitize and +sanitize_css+ heleprs. # # Rails::Initializer.run do |config| # config.action_view.sanitized_allowed_css_properties = 'expression' @@ -193,7 +194,7 @@ module ActionView HTML::WhiteListSanitizer.allowed_css_properties.merge(attributes) end - # Adds to the Set of allowed css keywords for the #sanitize and #sanitize_css helpers. + # Adds to the Set of allowed css keywords for the +sanitize+ and +sanitize_css+ helpers. # # Rails::Initializer.run do |config| # config.action_view.sanitized_allowed_css_keywords = 'expression' @@ -203,7 +204,7 @@ module ActionView HTML::WhiteListSanitizer.allowed_css_keywords.merge(attributes) end - # Adds to the Set of allowed shorthand css properties for the #sanitize and #sanitize_css helpers. + # Adds to the Set of allowed shorthand CSS properties for the +sanitize+ and +sanitize_css+ helpers. # # Rails::Initializer.run do |config| # config.action_view.sanitized_shorthand_css_properties = 'expression' @@ -213,7 +214,7 @@ module ActionView HTML::WhiteListSanitizer.shorthand_css_properties.merge(attributes) end - # Adds to the Set of allowed protocols for the #sanitize helper. + # Adds to the Set of allowed protocols for the +sanitize+ helper. # # Rails::Initializer.run do |config| # config.action_view.sanitized_allowed_protocols = 'ssh', 'feed' diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index 2cda3d94b5..369526188f 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -93,9 +93,9 @@ module ActionView #:nodoc: # Register a class that knows how to handle template files with the given # extension. This can be used to implement new template types. # The constructor for the class must take the ActiveView::Base instance - # as a parameter, and the class must implement a #render method that + # as a parameter, and the class must implement a +render+ method that # takes the contents of the template to render as well as the Hash of - # local assigns available to the template. The #render method ought to + # local assigns available to the template. The +render+ method ought to # return the rendered template as a string. def self.register_template_handler(extension, klass) @@template_handlers[extension.to_sym] = klass -- cgit v1.2.3 From 78596747bae784196da7a184a33ef5d1b2a94107 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 19 May 2008 21:31:18 +0200 Subject: #method vs +method+ in Active Record --- activerecord/lib/active_record/aggregations.rb | 2 +- activerecord/lib/active_record/base.rb | 6 +++--- activerecord/lib/active_record/calculations.rb | 8 ++++---- activerecord/lib/active_record/callbacks.rb | 2 +- .../connection_adapters/abstract/database_statements.rb | 4 ++-- .../connection_adapters/abstract/schema_definitions.rb | 4 ++-- .../connection_adapters/abstract/schema_statements.rb | 2 +- activerecord/lib/active_record/locking/optimistic.rb | 14 +++++++------- activerecord/lib/active_record/migration.rb | 2 +- activerecord/lib/active_record/observer.rb | 2 +- activerecord/lib/active_record/schema.rb | 4 ++-- .../lib/active_record/serializers/xml_serializer.rb | 6 +++--- activerecord/lib/active_record/validations.rb | 4 ++-- 13 files changed, 30 insertions(+), 30 deletions(-) diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index 61446cde36..a8c8c7f3dc 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -99,7 +99,7 @@ module ActiveRecord # relational unique identifiers (such as primary keys). Normal ActiveRecord::Base classes are entity objects. # # It's also important to treat the value objects as immutable. Don't allow the +Money+ object to have its amount changed after - # creation. Create a new +Money+ object with the new value instead. This is exemplified by the Money#exchanged_to method that + # creation. Create a new Money object with the new value instead. This is exemplified by the Money#exchanged_to method that # returns a new value object instead of changing its own values. Active Record won't persist value objects that have been # changed through means other than the writer method. # diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 6f9d5e53f5..35f18e9fa0 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1277,7 +1277,7 @@ module ActiveRecord #:nodoc: class_of_active_record_descendant(self) end - # Set this to true if this is an abstract class (see #abstract_class?). + # Set this to true if this is an abstract class (see abstract_class?). attr_accessor :abstract_class # Returns whether this class is a base AR class. If A is a base class and @@ -1724,8 +1724,8 @@ module ActiveRecord #:nodoc: end - # Defines an "attribute" method (like #inheritance_column or - # #table_name). A new (class) method will be created with the + # Defines an "attribute" method (like +inheritance_column+ or + # +table_name+). A new (class) method will be created with the # given name. If a value is specified, the new method will # return that value (as a string). Otherwise, the given block # will be used to compute the value of the method. diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb index 3c5caefe3b..fec9bee38f 100644 --- a/activerecord/lib/active_record/calculations.rb +++ b/activerecord/lib/active_record/calculations.rb @@ -46,28 +46,28 @@ module ActiveRecord calculate(:count, *construct_count_options_from_args(*args)) end - # Calculates the average value on a given column. The value is returned as a float. See #calculate for examples with options. + # Calculates the average value on a given column. The value is returned as a float. See +calculate+ for examples with options. # # Person.average('age') def average(column_name, options = {}) calculate(:avg, column_name, options) end - # Calculates the minimum value on a given column. The value is returned with the same data type of the column. See #calculate for examples with options. + # Calculates the minimum value on a given column. The value is returned with the same data type of the column. See +calculate+ for examples with options. # # Person.minimum('age') def minimum(column_name, options = {}) calculate(:min, column_name, options) end - # Calculates the maximum value on a given column. The value is returned with the same data type of the column. See #calculate for examples with options. + # Calculates the maximum value on a given column. The value is returned with the same data type of the column. See +calculate+ for examples with options. # # Person.maximum('age') def maximum(column_name, options = {}) calculate(:max, column_name, options) end - # Calculates the sum of values on a given column. The value is returned with the same data type of the column. See #calculate for examples with options. + # Calculates the sum of values on a given column. The value is returned with the same data type of the column. See +calculate+ for examples with options. # # Person.sum('age') def sum(column_name, options = {}) diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb index a469af682b..41ec5c5e61 100755 --- a/activerecord/lib/active_record/callbacks.rb +++ b/activerecord/lib/active_record/callbacks.rb @@ -161,7 +161,7 @@ module ActiveRecord # == before_validation* returning statements # # If the returning value of a +before_validation+ callback can be evaluated to +false+, the process will be aborted and Base#save will return +false+. - # If Base#save! is called it will raise a +RecordNotSaved+ exception. + # If Base#save! is called it will raise a RecordNotSaved exception. # Nothing will be appended to the errors object. # # == Canceling callbacks diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index 589acd3945..16d405d3bd 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -29,7 +29,7 @@ module ActiveRecord end # Returns an array of arrays containing the field values. - # Order is the same as that returned by #columns. + # Order is the same as that returned by +columns+. def select_rows(sql, name = nil) raise NotImplementedError, "select_rows is an abstract method" end @@ -93,7 +93,7 @@ module ActiveRecord # done if the transaction block raises an exception or returns false. def rollback_db_transaction() end - # Alias for #add_limit_offset!. + # Alias for add_limit_offset!. def add_limit!(sql, options) add_limit_offset!(sql, options) if options end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index fdb18b234c..18f1175f5f 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -270,7 +270,7 @@ module ActiveRecord end # Represents a SQL table in an abstract way. - # Columns are stored as a ColumnDefinition in the #columns attribute. + # Columns are stored as a ColumnDefinition in the +columns+ attribute. class TableDefinition attr_accessor :columns @@ -395,7 +395,7 @@ module ActiveRecord # end # # There's a short-hand method for each of the type values declared at the top. And then there's - # TableDefinition#timestamps that'll add created_at and updated_at as datetimes. + # TableDefinition#timestamps that'll add created_at and +updated_at+ as datetimes. # # TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type # column if the :polymorphic option is supplied. If :polymorphic is a hash of options, these will be diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index ac24e920fe..01e128f02f 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -32,7 +32,7 @@ module ActiveRecord def columns(table_name, name = nil) end # Creates a new table - # There are two ways to work with #create_table. You can use the block + # There are two ways to work with +create_table+. You can use the block # form or the regular form, like this: # # === Block form diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index 65f88cfdc7..c66034d18b 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -107,20 +107,20 @@ module ActiveRecord end # Is optimistic locking enabled for this table? Returns true if the - # #lock_optimistically flag is set to true (which it is, by default) - # and the table includes the #locking_column column (defaults to - # lock_version). + # +lock_optimistically+ flag is set to true (which it is, by default) + # and the table includes the +locking_column+ column (defaults to + # +lock_version+). def locking_enabled? lock_optimistically && columns_hash[locking_column] end - # Set the column to use for optimistic locking. Defaults to lock_version. + # Set the column to use for optimistic locking. Defaults to +lock_version+. def set_locking_column(value = nil, &block) define_attr_method :locking_column, value, &block value end - # The version column used for optimistic locking. Defaults to lock_version. + # The version column used for optimistic locking. Defaults to +lock_version+. def locking_column reset_locking_column end @@ -130,12 +130,12 @@ module ActiveRecord connection.quote_column_name(locking_column) end - # Reset the column used for optimistic locking back to the lock_version default. + # Reset the column used for optimistic locking back to the +lock_version+ default. def reset_locking_column set_locking_column DEFAULT_LOCKING_COLUMN end - # make sure the lock version column gets updated when counters are + # Make sure the lock version column gets updated when counters are # updated. def update_counters_with_lock(id, counters) counters = counters.merge(locking_column => 1) if locking_enabled? diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 5cc9f4e197..df512a996a 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -208,7 +208,7 @@ module ActiveRecord # # You can quiet them down by setting ActiveRecord::Migration.verbose = false. # - # You can also insert your own messages and benchmarks by using the #say_with_time + # You can also insert your own messages and benchmarks by using the +say_with_time+ # method: # # def self.up diff --git a/activerecord/lib/active_record/observer.rb b/activerecord/lib/active_record/observer.rb index 2b0728fc25..45e4d5b704 100644 --- a/activerecord/lib/active_record/observer.rb +++ b/activerecord/lib/active_record/observer.rb @@ -19,7 +19,7 @@ module ActiveRecord # # Same as above, just using explicit class references # ActiveRecord::Base.observers = Cacher, GarbageCollector # - # Note: Setting this does not instantiate the observers yet. #instantiate_observers is + # Note: Setting this does not instantiate the observers yet. +instantiate_observers+ is # called during startup, and before each development request. def observers=(*observers) @observers = observers.flatten diff --git a/activerecord/lib/active_record/schema.rb b/activerecord/lib/active_record/schema.rb index d6b254fcf9..8a32cf1ca2 100644 --- a/activerecord/lib/active_record/schema.rb +++ b/activerecord/lib/active_record/schema.rb @@ -30,8 +30,8 @@ module ActiveRecord # Eval the given block. All methods available to the current connection # adapter are available within the block, so you can easily use the - # database definition DSL to build up your schema (#create_table, - # #add_index, etc.). + # database definition DSL to build up your schema (+create_table+, + # +add_index+, etc.). # # The +info+ hash is optional, and if given is used to define metadata # about the current schema (currently, only the schema's version): diff --git a/activerecord/lib/active_record/serializers/xml_serializer.rb b/activerecord/lib/active_record/serializers/xml_serializer.rb index 2d0887ecf0..d171b742f5 100644 --- a/activerecord/lib/active_record/serializers/xml_serializer.rb +++ b/activerecord/lib/active_record/serializers/xml_serializer.rb @@ -273,14 +273,14 @@ module ActiveRecord #:nodoc: end # There is a significant speed improvement if the value - # does not need to be escaped, as #tag! escapes all values + # does not need to be escaped, as tag! escapes all values # to ensure that valid XML is generated. For known binary # values, it is at least an order of magnitude faster to # Base64 encode binary values and directly put them in the # output XML than to pass the original value or the Base64 - # encoded value to the #tag! method. It definitely makes + # encoded value to the tag! method. It definitely makes # no sense to Base64 encode the value and then give it to - # #tag!, since that just adds additional overhead. + # tag!, since that just adds additional overhead. def needs_encoding? ![ :binary, :date, :datetime, :boolean, :float, :integer ].include?(type) end diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index b3a75121ed..0e150bddb2 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -301,7 +301,7 @@ module ActiveRecord :odd => 'odd?', :even => 'even?' }.freeze # Adds a validation method or block to the class. This is useful when - # overriding the #validate instance method becomes too unwieldly and + # overriding the +validate+ instance method becomes too unwieldly and # you're looking for more descriptive declaration of your validations. # # This can be done with a symbol pointing to a method: @@ -326,7 +326,7 @@ module ActiveRecord # end # end # - # This usage applies to #validate_on_create and #validate_on_update as well. + # This usage applies to +validate_on_create+ and +validate_on_update+ as well. # Validates each attribute against a block. # -- cgit v1.2.3 From 1855fd29e00c2eeaf77ef34bb2b8de502eaf3655 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 19 May 2008 21:32:26 +0200 Subject: Class#method in regular font --- activeresource/lib/active_resource/validations.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activeresource/lib/active_resource/validations.rb b/activeresource/lib/active_resource/validations.rb index 57d2ae559d..b955db6ec1 100644 --- a/activeresource/lib/active_resource/validations.rb +++ b/activeresource/lib/active_resource/validations.rb @@ -217,7 +217,7 @@ module ActiveResource end # Module to allow validation of ActiveResource objects, which creates an Errors instance for every resource. - # Methods are implemented by overriding +Base#validate+ or its variants Each of these methods can inspect + # Methods are implemented by overriding Base#validate or its variants Each of these methods can inspect # the state of the object, which usually means ensuring that a number of attributes have a certain value # (such as not empty, within a given range, matching a certain regular expression and so on). # -- cgit v1.2.3 From 69597df908334df5ed0c55794d28f17865d448b8 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 19 May 2008 21:37:08 +0200 Subject: #method vs +method+ in Active Support --- activesupport/lib/active_support/deprecation.rb | 4 ++-- activesupport/lib/active_support/time_with_zone.rb | 6 +++--- activesupport/lib/active_support/values/time_zone.rb | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/activesupport/lib/active_support/deprecation.rb b/activesupport/lib/active_support/deprecation.rb index 6aa379b550..758aef5445 100644 --- a/activesupport/lib/active_support/deprecation.rb +++ b/activesupport/lib/active_support/deprecation.rb @@ -144,8 +144,8 @@ module ActiveSupport end end - # Stand-in for @request, @attributes, @params, etc which emits deprecation - # warnings on any method call (except #inspect). + # 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 =~ /^__/ } diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index 48606dbcff..fbdc680235 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -62,7 +62,7 @@ module ActiveSupport utc? && alternate_utc_string || utc_offset.to_utc_offset_s(colon) end - # Time uses #zone to display the time zone abbreviation, so we're duck-typing it + # Time uses +zone+ to display the time zone abbreviation, so we're duck-typing it. def zone period.zone_identifier.to_s end @@ -132,8 +132,8 @@ module ActiveSupport utc == other end - # If wrapped #time is a DateTime, use DateTime#since instead of #+ - # Otherwise, just pass on to #method_missing + # If wrapped #time is a DateTime, use DateTime#since instead of +. + # Otherwise, just pass on to +method_missing+. def +(other) result = utc.acts_like?(:date) ? utc.since(other) : utc + other result.in_time_zone(time_zone) diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index f522b64108..323429d126 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -335,7 +335,7 @@ class TimeZone # 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.) + # this class with the +composed_of+ macro.) def new(name) self[name] end -- cgit v1.2.3 From b5c8433a6f7f869bfcd2001f8c3c4660716e873b Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 19 May 2008 12:57:08 -0700 Subject: Ruby 1.9 compat: qualify module name within module_evaled block --- actionpack/test/controller/helper_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb index 6dc77a4aaf..83e3b085e7 100644 --- a/actionpack/test/controller/helper_test.rb +++ b/actionpack/test/controller/helper_test.rb @@ -85,7 +85,7 @@ class HelperTest < Test::Unit::TestCase def test_helper_block_include assert_equal expected_helper_methods, missing_methods assert_nothing_raised { - @controller_class.helper { include TestHelper } + @controller_class.helper { include HelperTest::TestHelper } } assert [], missing_methods end -- cgit v1.2.3 From 55b995ba6bafdddd01dc8fe6591aaada6e03197f Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 19 May 2008 22:04:43 +0200 Subject: gsub("css", "CSS") and assorted improvements --- .../lib/action_view/helpers/asset_tag_helper.rb | 24 +++++++++++----------- .../lib/action_view/helpers/sanitize_helper.rb | 2 +- railties/test/generators/generator_test_helper.rb | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index dfc7e2b3ed..e5a95a961c 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -11,8 +11,8 @@ module ActionView # === Using asset hosts # By default, Rails links to these assets on the current host in the public # folder, but you can direct Rails to link to assets from a dedicated assets server by - # setting ActionController::Base.asset_host in your environment.rb. For example, - # let's say your asset host is assets.example.com. + # setting ActionController::Base.asset_host in your config/environment.rb. For example, + # let's say your asset host is assets.example.com. # # ActionController::Base.asset_host = "assets.example.com" # image_tag("rails.png") @@ -22,8 +22,8 @@ module ActionView # # This is useful since browsers typically open at most two connections to a single host, # which means your assets often wait in single file for their turn to load. You can - # alleviate this by using a %d wildcard in asset_host (for example, "assets%d.example.com") - # to automatically distribute asset requests among four hosts (e.g., assets0.example.com through assets3.example.com) + # alleviate this by using a %d wildcard in asset_host (for example, "assets%d.example.com") + # to automatically distribute asset requests among four hosts (e.g., "assets0.example.com" through "assets3.example.com") # so browsers will open eight connections rather than two. # # image_tag("rails.png") @@ -293,9 +293,9 @@ module ActionView end # Computes the path to a stylesheet asset in the public stylesheets directory. - # If the +source+ filename has no extension, .css will be appended. + # If the +source+ filename has no extension, .css will be appended. # Full paths from the document root will be passed through. - # Used internally by stylesheet_link_tag to build the stylesheet path. + # Used internally by +stylesheet_link_tag+ to build the stylesheet path. # # ==== Examples # stylesheet_path "style" # => /stylesheets/style.css @@ -309,7 +309,7 @@ module ActionView alias_method :path_to_stylesheet, :stylesheet_path # aliased to avoid conflicts with a stylesheet_path named route # Returns a stylesheet link tag for the sources specified as arguments. If - # you don't specify an extension, .css will be appended automatically. + # you don't specify an extension, .css will be appended automatically. # You can modify the link attributes by passing a hash as the last argument. # # ==== Examples @@ -379,7 +379,7 @@ module ActionView # Computes the path to an image asset in the public images directory. # Full paths from the document root will be passed through. - # Used internally by image_tag to build the image path. + # Used internally by +image_tag+ to build the image path. # # ==== Examples # image_path("edit") # => /images/edit @@ -454,8 +454,8 @@ module ActionView end end - # Add the .ext if not present. Return full URLs otherwise untouched. - # Prefix with /dir/ if lacking a leading /. Account for relative URL + # Add the the extension +ext+ if not present. Return full URLs otherwise untouched. + # Prefix with /dir/ if lacking a leading +/+. Account for relative URL # roots. Rewrite the asset path for cache-busting asset ids. Include # asset host, if configured, with the correct request protocol. def compute_public_path(source, dir, ext = nil, include_host = true) @@ -502,9 +502,9 @@ module ActionView end end - # Pick an asset host for this source. Returns nil if no host is set, + # Pick an asset host for this source. Returns +nil+ if no host is set, # the host if no wildcard is set, the host interpolated with the - # numbers 0-3 if it contains %d (the number is the source hash mod 4), + # numbers 0-3 if it contains %d (the number is the source hash mod 4), # or the value returned from invoking the proc if it's a proc. def compute_asset_host(source) if host = ActionController::Base.asset_host diff --git a/actionpack/lib/action_view/helpers/sanitize_helper.rb b/actionpack/lib/action_view/helpers/sanitize_helper.rb index 968a974b35..b0dacfe964 100644 --- a/actionpack/lib/action_view/helpers/sanitize_helper.rb +++ b/actionpack/lib/action_view/helpers/sanitize_helper.rb @@ -194,7 +194,7 @@ module ActionView HTML::WhiteListSanitizer.allowed_css_properties.merge(attributes) end - # Adds to the Set of allowed css keywords for the +sanitize+ and +sanitize_css+ helpers. + # Adds to the Set of allowed CSS keywords for the +sanitize+ and +sanitize_css+ helpers. # # Rails::Initializer.run do |config| # config.action_view.sanitized_allowed_css_keywords = 'expression' diff --git a/railties/test/generators/generator_test_helper.rb b/railties/test/generators/generator_test_helper.rb index 41ddeb7d71..05dca3400e 100644 --- a/railties/test/generators/generator_test_helper.rb +++ b/railties/test/generators/generator_test_helper.rb @@ -206,7 +206,7 @@ class GeneratorTestCase < Test::Unit::TestCase end end - # Asserts that the given css stylesheet file was generated. + # Asserts that the given CSS stylesheet file was generated. # It takes a path without the .css part. # The contents of the stylesheet source file is passed to a block. def assert_generated_stylesheet(path) -- cgit v1.2.3 From ecba27c9701698a70eb7a7af1a995bb1d089949c Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 19 May 2008 22:11:04 +0200 Subject: revised markup in fixtures.rb --- activerecord/lib/active_record/fixtures.rb | 31 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index ac06cdbe43..796ee13d3d 100755 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -33,8 +33,8 @@ end # # Unlike single-file fixtures, YAML fixtures are stored in a single file per model, which are placed in the directory appointed # by ActiveSupport::TestCase.fixture_path=(path) (this is automatically configured for Rails, so you can just -# put your files in /test/fixtures/). The fixture file ends with the .yml file extension (Rails example: -# "/test/fixtures/web_sites.yml"). The format of a YAML fixture file looks like this: +# put your files in /test/fixtures/). The fixture file ends with the .yml file extension (Rails example: +# /test/fixtures/web_sites.yml). The format of a YAML fixture file looks like this: # # rubyonrails: # id: 1 @@ -67,7 +67,8 @@ end # = CSV fixtures # # Fixtures can also be kept in the Comma Separated Value format. Akin to YAML fixtures, CSV fixtures are stored -# in a single file, but instead end with the .csv file extension (Rails example: "/test/fixtures/web_sites.csv") +# in a single file, but instead end with the .csv file extension +# (Rails example: /test/fixtures/web_sites.csv). # # The format of this type of fixture file is much more compact than the others, but also a little harder to read by us # humans. The first line of the CSV file is a comma-separated list of field names. The rest of the file is then comprised @@ -93,11 +94,11 @@ end # This type of fixture was the original format for Active Record that has since been deprecated in favor of the YAML and CSV formats. # Fixtures for this format are created by placing text files in a sub-directory (with the name of the model) to the directory # appointed by ActiveSupport::TestCase.fixture_path=(path) (this is automatically configured for Rails, so you can just -# put your files in /test/fixtures// -- like /test/fixtures/web_sites/ for the WebSite -# model). +# put your files in /test/fixtures// -- +# like /test/fixtures/web_sites/ for the WebSite model). # # Each text file placed in this directory represents a "record". Usually these types of fixtures are named without -# extensions, but if you are on a Windows machine, you might consider adding .txt as the extension. Here's what the +# extensions, but if you are on a Windows machine, you might consider adding .txt as the extension. Here's what the # above example might look like: # # web_sites/google @@ -138,20 +139,20 @@ end # # In addition to being available in the database, the fixtures are also loaded into a hash stored in an instance variable # of the test case. It is named after the symbol... so, in our example, there would be a hash available called -# @web_sites. This is where the "fixture name" comes into play. +# @web_sites. This is where the "fixture name" comes into play. # -# On top of that, each record is automatically "found" (using Model.find(id)) and placed in the instance variable of its name. -# So for the YAML fixtures, we'd get @rubyonrails and @google, which could be interrogated using regular Active Record semantics: +# On top of that, each record is automatically "found" (using Model.find(id)) and placed in the instance variable of its name. +# So for the YAML fixtures, we'd get @rubyonrails and @google, which could be interrogated using regular Active Record semantics: # # # test if the object created from the fixture data has the same attributes as the data itself # def test_find # assert_equal @web_sites["rubyonrails"]["name"], @rubyonrails.name # end # -# As seen above, the data hash created from the YAML fixtures would have @web_sites["rubyonrails"]["url"] return -# "http://www.rubyonrails.org" and @web_sites["google"]["name"] would return "Google". The same fixtures, but loaded -# from a CSV fixture file, would be accessible via @web_sites["web_site_1"]["name"] == "Ruby on Rails" and have the individual -# fixtures available as instance variables @web_site_1 and @web_site_2. +# As seen above, the data hash created from the YAML fixtures would have @web_sites["rubyonrails"]["url"] return +# "http://www.rubyonrails.org" and @web_sites["google"]["name"] would return "Google". The same fixtures, but loaded +# from a CSV fixture file, would be accessible via @web_sites["web_site_1"]["name"] == "Ruby on Rails" and have the individual +# fixtures available as instance variables @web_site_1 and @web_site_2. # # If you do not wish to use instantiated fixtures (usually for performance reasons) there are two options. # @@ -184,7 +185,7 @@ end # # This will create 1000 very simple YAML fixtures. # -# Using ERb, you can also inject dynamic values into your fixtures with inserts like <%= Date.today.strftime("%Y-%m-%d") %>. +# Using ERb, you can also inject dynamic values into your fixtures with inserts like <%= Date.today.strftime("%Y-%m-%d") %>. # This is however a feature to be used with some caution. The point of fixtures are that they're stable units of predictable # sample data. If you feel that you need to inject dynamic values, then perhaps you should reexamine whether your application # is properly testable. Hence, dynamic values in fixtures are to be considered a code smell. @@ -307,7 +308,7 @@ end # Pow! All is made clear. ActiveRecord reflects on the fixture's model class, # finds all the +belongs_to+ associations, and allows you to specify # a target *label* for the *association* (monkey: george) rather than -# a target *id* for the *FK* (monkey_id: 1). +# a target *id* for the *FK* (monkey_id: 1). # # ==== Polymorphic belongs_to # -- cgit v1.2.3 From b43309328a4a4c1f6fda6db40a4a86a3c8d643fc Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 19 May 2008 16:01:42 -0700 Subject: Ruby 1.9 compat: ensure binary encoding for post body parsing --- .../lib/action_controller/cgi_ext/stdinput.rb | 1 + actionpack/lib/action_controller/cgi_process.rb | 1 + actionpack/lib/action_controller/integration.rb | 4 ++++ actionpack/lib/action_controller/request.rb | 28 +++++++++++++--------- actionpack/lib/action_controller/test_process.rb | 3 ++- actionpack/test/controller/test_test.rb | 20 ++++++++++++---- 6 files changed, 40 insertions(+), 17 deletions(-) diff --git a/actionpack/lib/action_controller/cgi_ext/stdinput.rb b/actionpack/lib/action_controller/cgi_ext/stdinput.rb index b0ca63ef2f..5e9b6784af 100644 --- a/actionpack/lib/action_controller/cgi_ext/stdinput.rb +++ b/actionpack/lib/action_controller/cgi_ext/stdinput.rb @@ -16,6 +16,7 @@ module ActionController def initialize_with_stdinput(type = nil, stdinput = $stdin) @stdinput = stdinput + @stdinput.set_encoding(Encoding::BINARY) if @stdinput.respond_to?(:set_encoding) initialize_without_stdinput(type || 'query') end end diff --git a/actionpack/lib/action_controller/cgi_process.rb b/actionpack/lib/action_controller/cgi_process.rb index b529db8af4..7e58c98bf2 100644 --- a/actionpack/lib/action_controller/cgi_process.rb +++ b/actionpack/lib/action_controller/cgi_process.rb @@ -65,6 +65,7 @@ module ActionController #:nodoc: # variable is already set, wrap it in a StringIO. def body if raw_post = env['RAW_POST_DATA'] + raw_post.force_encoding(Encoding::BINARY) if raw_post.respond_to?(:force_encoding) StringIO.new(raw_post) else @cgi.stdinput diff --git a/actionpack/lib/action_controller/integration.rb b/actionpack/lib/action_controller/integration.rb index a4bbee9c54..f0fc1945a9 100644 --- a/actionpack/lib/action_controller/integration.rb +++ b/actionpack/lib/action_controller/integration.rb @@ -228,6 +228,8 @@ module ActionController super + stdinput.set_encoding(Encoding::BINARY) if stdinput.respond_to?(:set_encoding) + stdinput.force_encoding(Encoding::BINARY) if stdinput.respond_to?(:force_encoding) @stdinput = stdinput.is_a?(IO) ? stdinput : StringIO.new(stdinput || '') end end @@ -382,6 +384,8 @@ module ActionController multipart_requestify(params).map do |key, value| if value.respond_to?(:original_filename) File.open(value.path) do |f| + f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding) + <<-EOF --#{boundary}\r Content-Disposition: form-data; name="#{key}"; filename="#{CGI.escape(value.original_filename)}"\r diff --git a/actionpack/lib/action_controller/request.rb b/actionpack/lib/action_controller/request.rb index d5ecbd9d29..a35b904194 100755 --- a/actionpack/lib/action_controller/request.rb +++ b/actionpack/lib/action_controller/request.rb @@ -466,8 +466,8 @@ EOM parser.result end - def parse_multipart_form_parameters(body, boundary, content_length, env) - parse_request_parameters(read_multipart(body, boundary, content_length, env)) + def parse_multipart_form_parameters(body, boundary, body_size, env) + parse_request_parameters(read_multipart(body, boundary, body_size, env)) end def extract_multipart_boundary(content_type_with_parameters) @@ -519,7 +519,7 @@ EOM EOL = "\015\012" - def read_multipart(body, boundary, content_length, env) + def read_multipart(body, boundary, body_size, env) params = Hash.new([]) boundary = "--" + boundary quoted_boundary = Regexp.quote(boundary) @@ -529,8 +529,14 @@ EOM # start multipart/form-data body.binmode if defined? body.binmode + case body + when File + body.set_encoding(Encoding::BINARY) if body.respond_to?(:set_encoding) + when StringIO + body.string.force_encoding(Encoding::BINARY) if body.string.respond_to?(:force_encoding) + end boundary_size = boundary.size + EOL.size - content_length -= boundary_size + body_size -= boundary_size status = body.read(boundary_size) if nil == status raise EOFError, "no content body" @@ -541,7 +547,7 @@ EOM loop do head = nil content = - if 10240 < content_length + if 10240 < body_size UploadedTempfile.new("CGI") else UploadedStringIO.new @@ -563,24 +569,24 @@ EOM buf[0 ... (buf.size - (EOL + boundary + EOL).size)] = "" end - c = if bufsize < content_length + c = if bufsize < body_size body.read(bufsize) else - body.read(content_length) + body.read(body_size) end if c.nil? || c.empty? raise EOFError, "bad content body" end buf.concat(c) - content_length -= c.size + body_size -= c.size end buf = buf.sub(/\A((?:.|\n)*?)(?:[\r\n]{1,2})?#{quoted_boundary}([\r\n]{1,2}|--)/n) do content.print $1 if "--" == $2 - content_length = -1 + body_size = -1 end - boundary_end = $2.dup + boundary_end = $2.dup "" end @@ -607,7 +613,7 @@ EOM else params[name] = [content] end - break if content_length == -1 + break if body_size == -1 end raise EOFError, "bad boundary end of body part" unless boundary_end=~/--/ diff --git a/actionpack/lib/action_controller/test_process.rb b/actionpack/lib/action_controller/test_process.rb index dcb6cdf4ca..f03ed5b2a7 100644 --- a/actionpack/lib/action_controller/test_process.rb +++ b/actionpack/lib/action_controller/test_process.rb @@ -49,7 +49,7 @@ module ActionController #:nodoc: # Either the RAW_POST_DATA environment variable or the URL-encoded request # parameters. def raw_post - env['RAW_POST_DATA'] ||= url_encoded_request_parameters + env['RAW_POST_DATA'] ||= returning(url_encoded_request_parameters) { |b| b.force_encoding(Encoding::BINARY) if b.respond_to?(:force_encoding) } end def port=(number) @@ -340,6 +340,7 @@ module ActionController #:nodoc: @content_type = content_type @original_filename = path.sub(/^.*#{File::SEPARATOR}([^#{File::SEPARATOR}]+)$/) { $1 } @tempfile = Tempfile.new(@original_filename) + @tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding) @tempfile.binmode if binary FileUtils.copy_file(path, @tempfile.path) end diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb index ba6c7f4299..38898a1f75 100644 --- a/actionpack/test/controller/test_test.rb +++ b/actionpack/test/controller/test_test.rb @@ -511,16 +511,26 @@ XML FILES_DIR = File.dirname(__FILE__) + '/../fixtures/multipart' + if RUBY_VERSION < '1.9' + READ_BINARY = 'rb' + READ_PLAIN = 'r' + else + READ_BINARY = 'rb:binary' + READ_PLAIN = 'r:binary' + end + def test_test_uploaded_file filename = 'mona_lisa.jpg' path = "#{FILES_DIR}/#{filename}" content_type = 'image/png' + expected = File.read(path) + expected.force_encoding(Encoding::BINARY) if expected.respond_to?(:force_encoding) file = ActionController::TestUploadedFile.new(path, content_type) assert_equal filename, file.original_filename assert_equal content_type, file.content_type assert_equal file.path, file.local_path - assert_equal File.read(path), file.read + assert_equal expected, file.read end def test_test_uploaded_file_with_binary @@ -529,10 +539,10 @@ XML content_type = 'image/png' binary_uploaded_file = ActionController::TestUploadedFile.new(path, content_type, :binary) - assert_equal File.open(path, 'rb').read, binary_uploaded_file.read + assert_equal File.open(path, READ_BINARY).read, binary_uploaded_file.read plain_uploaded_file = ActionController::TestUploadedFile.new(path, content_type) - assert_equal File.open(path, 'r').read, plain_uploaded_file.read + assert_equal File.open(path, READ_PLAIN).read, plain_uploaded_file.read end def test_fixture_file_upload_with_binary @@ -541,10 +551,10 @@ XML content_type = 'image/jpg' binary_file_upload = fixture_file_upload(path, content_type, :binary) - assert_equal File.open(path, 'rb').read, binary_file_upload.read + assert_equal File.open(path, READ_BINARY).read, binary_file_upload.read plain_file_upload = fixture_file_upload(path, content_type) - assert_equal File.open(path, 'r').read, plain_file_upload.read + assert_equal File.open(path, READ_PLAIN).read, plain_file_upload.read end def test_fixture_file_upload -- cgit v1.2.3 From 762295e0ae9d67450403596412bb8489893378d9 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 19 May 2008 19:04:28 -0700 Subject: Bundle tmail 1.2.3 --- actionmailer/lib/action_mailer/vendor.rb | 4 +- .../lib/action_mailer/vendor/tmail-1.2.2/tmail.rb | 5 - .../vendor/tmail-1.2.2/tmail/address.rb | 426 ------ .../vendor/tmail-1.2.2/tmail/attachments.rb | 46 - .../vendor/tmail-1.2.2/tmail/base64.rb | 46 - .../vendor/tmail-1.2.2/tmail/compat.rb | 41 - .../vendor/tmail-1.2.2/tmail/config.rb | 67 - .../vendor/tmail-1.2.2/tmail/core_extensions.rb | 63 - .../vendor/tmail-1.2.2/tmail/encode.rb | 561 -------- .../vendor/tmail-1.2.2/tmail/header.rb | 960 ------------- .../vendor/tmail-1.2.2/tmail/index.rb | 9 - .../vendor/tmail-1.2.2/tmail/interface.rb | 1125 --------------- .../vendor/tmail-1.2.2/tmail/loader.rb | 3 - .../action_mailer/vendor/tmail-1.2.2/tmail/mail.rb | 578 -------- .../vendor/tmail-1.2.2/tmail/mailbox.rb | 495 ------- .../action_mailer/vendor/tmail-1.2.2/tmail/main.rb | 6 - .../action_mailer/vendor/tmail-1.2.2/tmail/mbox.rb | 3 - .../action_mailer/vendor/tmail-1.2.2/tmail/net.rb | 248 ---- .../vendor/tmail-1.2.2/tmail/obsolete.rb | 132 -- .../vendor/tmail-1.2.2/tmail/parser.rb | 1476 -------------------- .../action_mailer/vendor/tmail-1.2.2/tmail/port.rb | 379 ----- .../vendor/tmail-1.2.2/tmail/quoting.rb | 118 -- .../vendor/tmail-1.2.2/tmail/require_arch.rb | 58 - .../vendor/tmail-1.2.2/tmail/scanner.rb | 49 - .../vendor/tmail-1.2.2/tmail/scanner_r.rb | 261 ---- .../vendor/tmail-1.2.2/tmail/stringio.rb | 280 ---- .../vendor/tmail-1.2.2/tmail/utils.rb | 337 ----- .../vendor/tmail-1.2.2/tmail/version.rb | 39 - .../lib/action_mailer/vendor/tmail-1.2.3/tmail.rb | 5 + .../vendor/tmail-1.2.3/tmail/address.rb | 426 ++++++ .../vendor/tmail-1.2.3/tmail/attachments.rb | 46 + .../vendor/tmail-1.2.3/tmail/base64.rb | 46 + .../vendor/tmail-1.2.3/tmail/compat.rb | 41 + .../vendor/tmail-1.2.3/tmail/config.rb | 67 + .../vendor/tmail-1.2.3/tmail/core_extensions.rb | 63 + .../vendor/tmail-1.2.3/tmail/encode.rb | 581 ++++++++ .../vendor/tmail-1.2.3/tmail/header.rb | 960 +++++++++++++ .../vendor/tmail-1.2.3/tmail/index.rb | 9 + .../vendor/tmail-1.2.3/tmail/interface.rb | 1130 +++++++++++++++ .../vendor/tmail-1.2.3/tmail/loader.rb | 3 + .../action_mailer/vendor/tmail-1.2.3/tmail/mail.rb | 578 ++++++++ .../vendor/tmail-1.2.3/tmail/mailbox.rb | 495 +++++++ .../action_mailer/vendor/tmail-1.2.3/tmail/main.rb | 6 + .../action_mailer/vendor/tmail-1.2.3/tmail/mbox.rb | 3 + .../action_mailer/vendor/tmail-1.2.3/tmail/net.rb | 248 ++++ .../vendor/tmail-1.2.3/tmail/obsolete.rb | 132 ++ .../vendor/tmail-1.2.3/tmail/parser.rb | 1476 ++++++++++++++++++++ .../action_mailer/vendor/tmail-1.2.3/tmail/port.rb | 379 +++++ .../vendor/tmail-1.2.3/tmail/quoting.rb | 118 ++ .../vendor/tmail-1.2.3/tmail/require_arch.rb | 58 + .../vendor/tmail-1.2.3/tmail/scanner.rb | 49 + .../vendor/tmail-1.2.3/tmail/scanner_r.rb | 261 ++++ .../vendor/tmail-1.2.3/tmail/stringio.rb | 280 ++++ .../vendor/tmail-1.2.3/tmail/utils.rb | 337 +++++ .../vendor/tmail-1.2.3/tmail/version.rb | 39 + 55 files changed, 7838 insertions(+), 7813 deletions(-) delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/address.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/attachments.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/base64.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/compat.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/config.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/core_extensions.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/encode.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/header.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/index.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/interface.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/loader.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mail.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mailbox.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/main.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mbox.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/net.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/obsolete.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/parser.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/port.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/quoting.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/require_arch.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner_r.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/stringio.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/utils.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/version.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/address.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/attachments.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/base64.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/compat.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/config.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/core_extensions.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/encode.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/header.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/index.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/interface.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/loader.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mailbox.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/main.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mbox.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/net.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/obsolete.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/parser.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/port.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/quoting.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/require_arch.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner_r.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/stringio.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/utils.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/version.rb diff --git a/actionmailer/lib/action_mailer/vendor.rb b/actionmailer/lib/action_mailer/vendor.rb index 56a2858be5..7a20e9bd6e 100644 --- a/actionmailer/lib/action_mailer/vendor.rb +++ b/actionmailer/lib/action_mailer/vendor.rb @@ -2,9 +2,9 @@ require 'rubygems' begin - gem 'tmail', '~> 1.2.2' + gem 'tmail', '~> 1.2.3' rescue Gem::LoadError - $:.unshift "#{File.dirname(__FILE__)}/vendor/tmail-1.2.2" + $:.unshift "#{File.dirname(__FILE__)}/vendor/tmail-1.2.3" end begin diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail.rb deleted file mode 100644 index 18003659a6..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'tmail/version' -require 'tmail/mail' -require 'tmail/mailbox' -require 'tmail/core_extensions' -require 'tmail/net' diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/address.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/address.rb deleted file mode 100644 index fa8e5bcd8c..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/address.rb +++ /dev/null @@ -1,426 +0,0 @@ -=begin rdoc - -= Address handling class - -=end -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# 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. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -require 'tmail/encode' -require 'tmail/parser' - - -module TMail - - # = Class Address - # - # Provides a complete handling library for email addresses. Can parse a string of an - # address directly or take in preformatted addresses themseleves. Allows you to add - # and remove phrases from the front of the address and provides a compare function for - # email addresses. - # - # == Parsing and Handling a Valid Address: - # - # Just pass the email address in as a string to Address.parse: - # - # email = TMail::Address.parse('Mikel Lindsaar ) - # #=> # - # email.address - # #=> "mikel@lindsaar.net" - # email.local - # #=> "mikel" - # email.domain - # #=> "lindsaar.net" - # email.name # Aliased as phrase as well - # #=> "Mikel Lindsaar" - # - # == Detecting an Invalid Address - # - # If you want to check the syntactical validity of an email address, just pass it to - # Address.parse and catch any SyntaxError: - # - # begin - # TMail::Mail.parse("mikel 2@@@@@ me .com") - # rescue TMail::SyntaxError - # puts("Invalid Email Address Detected") - # else - # puts("Address is valid") - # end - # #=> "Invalid Email Address Detected" - class Address - - include TextUtils #:nodoc: - - # Sometimes you need to parse an address, TMail can do it for you and provide you with - # a fairly robust method of detecting a valid address. - # - # Takes in a string, returns a TMail::Address object. - # - # Raises a TMail::SyntaxError on invalid email format - def Address.parse( str ) - Parser.parse :ADDRESS, special_quote_address(str) - end - - def Address.special_quote_address(str) #:nodoc: - # Takes a string which is an address and adds quotation marks to special - # edge case methods that the RACC parser can not handle. - # - # Right now just handles two edge cases: - # - # Full stop as the last character of the display name: - # Mikel L. - # Returns: - # "Mikel L." - # - # Unquoted @ symbol in the display name: - # mikel@me.com - # Returns: - # "mikel@me.com" - # - # Any other address not matching these patterns just gets returned as is. - case - # This handles the missing "" in an older version of Apple Mail.app - # around the display name when the display name contains a '@' - # like 'mikel@me.com ' - # Just quotes it to: '"mikel@me.com" ' - when str =~ /\A([^"].+@.+[^"])\s(<.*?>)\Z/ - return "\"#{$1}\" #{$2}" - # This handles cases where 'Mikel A. ' which is a trailing - # full stop before the address section. Just quotes it to - # '"Mikel A. " - when str =~ /\A(.*?\.)\s(<.*?>)\Z/ - return "\"#{$1}\" #{$2}" - else - str - end - end - - def address_group? #:nodoc: - false - end - - # Address.new(local, domain) - # - # Accepts: - # - # * local - Left of the at symbol - # - # * domain - Array of the domain split at the periods. - # - # For example: - # - # Address.new("mikel", ["lindsaar", "net"]) - # #=> "#" - def initialize( local, domain ) - if domain - domain.each do |s| - raise SyntaxError, 'empty word in domain' if s.empty? - end - end - - # This is to catch an unquoted "@" symbol in the local part of the - # address. Handles addresses like <"@"@me.com> and makes sure they - # stay like <"@"@me.com> (previously were becomming <@@me.com>) - if local && (local.join == '@' || local.join =~ /\A[^"].*?@.*?[^"]\Z/) - @local = "\"#{local.join}\"" - else - @local = local - end - - @domain = domain - @name = nil - @routes = [] - end - - # Provides the name or 'phrase' of the email address. - # - # For Example: - # - # email = TMail::Address.parse("Mikel Lindsaar ") - # email.name - # #=> "Mikel Lindsaar" - def name - @name - end - - # Setter method for the name or phrase of the email - # - # For Example: - # - # email = TMail::Address.parse("mikel@lindsaar.net") - # email.name - # #=> nil - # email.name = "Mikel Lindsaar" - # email.to_s - # #=> "Mikel Lindsaar " - def name=( str ) - @name = str - @name = nil if str and str.empty? - end - - #:stopdoc: - alias phrase name - alias phrase= name= - #:startdoc: - - # This is still here from RFC 822, and is now obsolete per RFC2822 Section 4. - # - # "When interpreting addresses, the route portion SHOULD be ignored." - # - # It is still here, so you can access it. - # - # Routes return the route portion at the front of the email address, if any. - # - # For Example: - # email = TMail::Address.parse( "<@sa,@another:Mikel@me.com>") - # => # - # email.to_s - # => "<@sa,@another:Mikel@me.com>" - # email.routes - # => ["sa", "another"] - def routes - @routes - end - - def inspect #:nodoc: - "#<#{self.class} #{address()}>" - end - - # Returns the local part of the email address - # - # For Example: - # - # email = TMail::Address.parse("mikel@lindsaar.net") - # email.local - # #=> "mikel" - def local - return nil unless @local - return '""' if @local.size == 1 and @local[0].empty? - # Check to see if it is an array before trying to map it - if @local.respond_to?(:map) - @local.map {|i| quote_atom(i) }.join('.') - else - quote_atom(@local) - end - end - - # Returns the domain part of the email address - # - # For Example: - # - # email = TMail::Address.parse("mikel@lindsaar.net") - # email.local - # #=> "lindsaar.net" - def domain - return nil unless @domain - join_domain(@domain) - end - - # Returns the full specific address itself - # - # For Example: - # - # email = TMail::Address.parse("mikel@lindsaar.net") - # email.address - # #=> "mikel@lindsaar.net" - def spec - s = self.local - d = self.domain - if s and d - s + '@' + d - else - s - end - end - - alias address spec - - # Provides == function to the email. Only checks the actual address - # and ignores the name/phrase component - # - # For Example - # - # addr1 = TMail::Address.parse("My Address ") - # #=> "#" - # addr2 = TMail::Address.parse("Another ") - # #=> "#" - # addr1 == addr2 - # #=> true - def ==( other ) - other.respond_to? :spec and self.spec == other.spec - end - - alias eql? == - - # Provides a unique hash value for this record against the local and domain - # parts, ignores the name/phrase value - # - # email = TMail::Address.parse("mikel@lindsaar.net") - # email.hash - # #=> 18767598 - def hash - @local.hash ^ @domain.hash - end - - # Duplicates a TMail::Address object returning the duplicate - # - # addr1 = TMail::Address.parse("mikel@lindsaar.net") - # addr2 = addr1.dup - # addr1.id == addr2.id - # #=> false - def dup - obj = self.class.new(@local.dup, @domain.dup) - obj.name = @name.dup if @name - obj.routes.replace @routes - obj - end - - include StrategyInterface #:nodoc: - - def accept( strategy, dummy1 = nil, dummy2 = nil ) #:nodoc: - unless @local - strategy.meta '<>' # empty return-path - return - end - - spec_p = (not @name and @routes.empty?) - if @name - strategy.phrase @name - strategy.space - end - tmp = spec_p ? '' : '<' - unless @routes.empty? - tmp << @routes.map {|i| '@' + i }.join(',') << ':' - end - tmp << self.spec - tmp << '>' unless spec_p - strategy.meta tmp - strategy.lwsp '' - end - - end - - - class AddressGroup - - include Enumerable - - def address_group? - true - end - - def initialize( name, addrs ) - @name = name - @addresses = addrs - end - - attr_reader :name - - def ==( other ) - other.respond_to? :to_a and @addresses == other.to_a - end - - alias eql? == - - def hash - map {|i| i.hash }.hash - end - - def []( idx ) - @addresses[idx] - end - - def size - @addresses.size - end - - def empty? - @addresses.empty? - end - - def each( &block ) - @addresses.each(&block) - end - - def to_a - @addresses.dup - end - - alias to_ary to_a - - def include?( a ) - @addresses.include? a - end - - def flatten - set = [] - @addresses.each do |a| - if a.respond_to? :flatten - set.concat a.flatten - else - set.push a - end - end - set - end - - def each_address( &block ) - flatten.each(&block) - end - - def add( a ) - @addresses.push a - end - - alias push add - - def delete( a ) - @addresses.delete a - end - - include StrategyInterface - - def accept( strategy, dummy1 = nil, dummy2 = nil ) - strategy.phrase @name - strategy.meta ':' - strategy.space - first = true - each do |mbox| - if first - first = false - else - strategy.meta ',' - end - strategy.space - mbox.accept strategy - end - strategy.meta ';' - strategy.lwsp '' - end - - end - -end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/attachments.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/attachments.rb deleted file mode 100644 index 5dc5efae5e..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/attachments.rb +++ /dev/null @@ -1,46 +0,0 @@ -=begin rdoc - -= Attachment handling file - -=end - -require 'stringio' - -module TMail - class Attachment < StringIO - attr_accessor :original_filename, :content_type - end - - class Mail - def has_attachments? - multipart? && parts.any? { |part| attachment?(part) } - end - - def attachment?(part) - part.disposition_is_attachment? || part.content_type_is_text? - end - - def attachments - if multipart? - parts.collect { |part| - if part.multipart? - part.attachments - elsif attachment?(part) - content = part.body # unquoted automatically by TMail#body - file_name = (part['content-location'] && - part['content-location'].body) || - part.sub_header("content-type", "name") || - part.sub_header("content-disposition", "filename") - - next if file_name.blank? || content.blank? - - attachment = Attachment.new(content) - attachment.original_filename = file_name.strip - attachment.content_type = part.content_type - attachment - end - }.flatten.compact - end - end - end -end diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/base64.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/base64.rb deleted file mode 100644 index e294c62960..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/base64.rb +++ /dev/null @@ -1,46 +0,0 @@ -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# 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. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ -#:stopdoc: -module TMail - module Base64 - - module_function - - def folding_encode( str, eol = "\n", limit = 60 ) - [str].pack('m') - end - - def encode( str ) - [str].pack('m').tr( "\r\n", '' ) - end - - def decode( str, strict = false ) - str.unpack('m').first - end - - end -end -#:startdoc: diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/compat.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/compat.rb deleted file mode 100644 index 1275df79a6..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/compat.rb +++ /dev/null @@ -1,41 +0,0 @@ -#:stopdoc: -unless Enumerable.method_defined?(:map) - module Enumerable #:nodoc: - alias map collect - end -end - -unless Enumerable.method_defined?(:select) - module Enumerable #:nodoc: - alias select find_all - end -end - -unless Enumerable.method_defined?(:reject) - module Enumerable #:nodoc: - def reject - result = [] - each do |i| - result.push i unless yield(i) - end - result - end - end -end - -unless Enumerable.method_defined?(:sort_by) - module Enumerable #:nodoc: - def sort_by - map {|i| [yield(i), i] }.sort.map {|val, i| i } - end - end -end - -unless File.respond_to?(:read) - def File.read(fname) #:nodoc: - File.open(fname) {|f| - return f.read - } - end -end -#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/config.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/config.rb deleted file mode 100644 index 3a876dcdbd..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/config.rb +++ /dev/null @@ -1,67 +0,0 @@ -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# 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. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ -#:stopdoc: -module TMail - - class Config - - def initialize( strict ) - @strict_parse = strict - @strict_base64decode = strict - end - - def strict_parse? - @strict_parse - end - - attr_writer :strict_parse - - def strict_base64decode? - @strict_base64decode - end - - attr_writer :strict_base64decode - - def new_body_port( mail ) - StringPort.new - end - - alias new_preamble_port new_body_port - alias new_part_port new_body_port - - end - - DEFAULT_CONFIG = Config.new(false) - DEFAULT_STRICT_CONFIG = Config.new(true) - - def Config.to_config( arg ) - return DEFAULT_STRICT_CONFIG if arg == true - return DEFAULT_CONFIG if arg == false - arg or DEFAULT_CONFIG - end - -end -#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/core_extensions.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/core_extensions.rb deleted file mode 100644 index da62c33bbf..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/core_extensions.rb +++ /dev/null @@ -1,63 +0,0 @@ -#:stopdoc: -unless Object.respond_to?(:blank?) - class Object - # Check first to see if we are in a Rails environment, no need to - # define these methods if we are - - # 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? - if respond_to?(:empty?) && respond_to?(:strip) - empty? or strip.empty? - elsif respond_to?(:empty?) - empty? - else - !self - end - end - end - - class NilClass - def blank? - true - end - end - - class FalseClass - def blank? - true - end - end - - class TrueClass - def blank? - false - end - end - - class Array - alias_method :blank?, :empty? - end - - class Hash - alias_method :blank?, :empty? - end - - class String - def blank? - empty? || strip.empty? - end - end - - class Numeric - def blank? - false - end - end -end -#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/encode.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/encode.rb deleted file mode 100644 index 63bccce4fc..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/encode.rb +++ /dev/null @@ -1,561 +0,0 @@ -#-- -# = COPYRIGHT: -# -# Copyright (c) 1998-2003 Minero Aoki -# -# 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. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ -#:stopdoc: -require 'nkf' -require 'tmail/base64' -require 'tmail/stringio' -require 'tmail/utils' -#:startdoc: - - -module TMail - - #:stopdoc: - class << self - attr_accessor :KCODE - end - self.KCODE = 'NONE' - - module StrategyInterface - - def create_dest( obj ) - case obj - when nil - StringOutput.new - when String - StringOutput.new(obj) - when IO, StringOutput - obj - else - raise TypeError, 'cannot handle this type of object for dest' - end - end - module_function :create_dest - - #:startdoc: - # Returns the TMail object encoded and ready to be sent via SMTP etc. - # You should call this before you are packaging up your email to - # correctly escape all the values that need escaping in the email, line - # wrap the email etc. - # - # It is also a good idea to call this before you marshal or serialize - # a TMail object. - # - # For Example: - # - # email = TMail::Load(my_email_file) - # email_to_send = email.encoded - def encoded( eol = "\r\n", charset = 'j', dest = nil ) - accept_strategy Encoder, eol, charset, dest - end - - # Returns the TMail object decoded and ready to be used by you, your - # program etc. - # - # You should call this before you are packaging up your email to - # correctly escape all the values that need escaping in the email, line - # wrap the email etc. - # - # For Example: - # - # email = TMail::Load(my_email_file) - # email_to_send = email.encoded - def decoded( eol = "\n", charset = 'e', dest = nil ) - # Turn the E-Mail into a string and return it with all - # encoded characters decoded. alias for to_s - accept_strategy Decoder, eol, charset, dest - end - - alias to_s decoded - - def accept_strategy( klass, eol, charset, dest = nil ) #:nodoc: - dest ||= '' - accept klass.new( create_dest(dest), charset, eol ) - dest - end - - end - - #:stopdoc: - - ### - ### MIME B encoding decoder - ### - - class Decoder - - include TextUtils - - encoded = '=\?(?:iso-2022-jp|euc-jp|shift_jis)\?[QB]\?[a-z0-9+/=]+\?=' - ENCODED_WORDS = /#{encoded}(?:\s+#{encoded})*/i - - OUTPUT_ENCODING = { - 'EUC' => 'e', - 'SJIS' => 's', - } - - def self.decode( str, encoding = nil ) - encoding ||= (OUTPUT_ENCODING[TMail.KCODE] || 'j') - opt = '-mS' + encoding - str.gsub(ENCODED_WORDS) {|s| NKF.nkf(opt, s) } - end - - def initialize( dest, encoding = nil, eol = "\n" ) - @f = StrategyInterface.create_dest(dest) - @encoding = (/\A[ejs]/ === encoding) ? encoding[0,1] : nil - @eol = eol - end - - def decode( str ) - self.class.decode(str, @encoding) - end - private :decode - - def terminate - end - - def header_line( str ) - @f << decode(str) - end - - def header_name( nm ) - @f << nm << ': ' - end - - def header_body( str ) - @f << decode(str) - end - - def space - @f << ' ' - end - - alias spc space - - def lwsp( str ) - @f << str - end - - def meta( str ) - @f << str - end - - def text( str ) - @f << decode(str) - end - - def phrase( str ) - @f << quote_phrase(decode(str)) - end - - def kv_pair( k, v ) - v = dquote(v) unless token_safe?(v) - @f << k << '=' << v - end - - def puts( str = nil ) - @f << str if str - @f << @eol - end - - def write( str ) - @f << str - end - - end - - - ### - ### MIME B-encoding encoder - ### - - # - # FIXME: This class can handle only (euc-jp/shift_jis -> iso-2022-jp). - # - class Encoder - - include TextUtils - - BENCODE_DEBUG = false unless defined?(BENCODE_DEBUG) - - def Encoder.encode( str ) - e = new() - e.header_body str - e.terminate - e.dest.string - end - - SPACER = "\t" - MAX_LINE_LEN = 78 - RFC_2822_MAX_LENGTH = 998 - - OPTIONS = { - 'EUC' => '-Ej -m0', - 'SJIS' => '-Sj -m0', - 'UTF8' => nil, # FIXME - 'NONE' => nil - } - - def initialize( dest = nil, encoding = nil, eol = "\r\n", limit = nil ) - @f = StrategyInterface.create_dest(dest) - @opt = OPTIONS[TMail.KCODE] - @eol = eol - @folded = false - @preserve_quotes = true - reset - end - - def preserve_quotes=( bool ) - @preserve_quotes - end - - def preserve_quotes - @preserve_quotes - end - - def normalize_encoding( str ) - if @opt - then NKF.nkf(@opt, str) - else str - end - end - - def reset - @text = '' - @lwsp = '' - @curlen = 0 - end - - def terminate - add_lwsp '' - reset - end - - def dest - @f - end - - def puts( str = nil ) - @f << str if str - @f << @eol - end - - def write( str ) - @f << str - end - - # - # add - # - - def header_line( line ) - scanadd line - end - - def header_name( name ) - add_text name.split(/-/).map {|i| i.capitalize }.join('-') - add_text ':' - add_lwsp ' ' - end - - def header_body( str ) - scanadd normalize_encoding(str) - end - - def space - add_lwsp ' ' - end - - alias spc space - - def lwsp( str ) - add_lwsp str.sub(/[\r\n]+[^\r\n]*\z/, '') - end - - def meta( str ) - add_text str - end - - def text( str ) - scanadd normalize_encoding(str) - end - - def phrase( str ) - str = normalize_encoding(str) - if CONTROL_CHAR === str - scanadd str - else - add_text quote_phrase(str) - end - end - - # FIXME: implement line folding - # - def kv_pair( k, v ) - return if v.nil? - v = normalize_encoding(v) - if token_safe?(v) - add_text k + '=' + v - elsif not CONTROL_CHAR === v - add_text k + '=' + quote_token(v) - else - # apply RFC2231 encoding - kv = k + '*=' + "iso-2022-jp'ja'" + encode_value(v) - add_text kv - end - end - - def encode_value( str ) - str.gsub(TOKEN_UNSAFE) {|s| '%%%02x' % s[0] } - end - - private - - def scanadd( str, force = false ) - types = '' - strs = [] - - until str.empty? - if m = /\A[^\e\t\r\n ]+/.match(str) - types << (force ? 'j' : 'a') - strs.push m[0] - - elsif m = /\A[\t\r\n ]+/.match(str) - types << 's' - strs.push m[0] - - elsif m = /\A\e../.match(str) - esc = m[0] - str = m.post_match - if esc != "\e(B" and m = /\A[^\e]+/.match(str) - types << 'j' - strs.push m[0] - end - - else - raise 'TMail FATAL: encoder scan fail' - end - (str = m.post_match) unless m.nil? - end - - do_encode types, strs - end - - def do_encode( types, strs ) - # - # result : (A|E)(S(A|E))* - # E : W(SW)* - # W : (J|A)+ but must contain J # (J|A)*J(J|A)* - # A : <> - # J : <> - # S : <> - # - # An encoding unit is `E'. - # Input (parameter `types') is (J|A)(J|A|S)*(J|A) - # - if BENCODE_DEBUG - puts - puts '-- do_encode ------------' - puts types.split(//).join(' ') - p strs - end - - e = /[ja]*j[ja]*(?:s[ja]*j[ja]*)*/ - - while m = e.match(types) - pre = m.pre_match - concat_A_S pre, strs[0, pre.size] unless pre.empty? - concat_E m[0], strs[m.begin(0) ... m.end(0)] - types = m.post_match - strs.slice! 0, m.end(0) - end - concat_A_S types, strs - end - - def concat_A_S( types, strs ) - if RUBY_VERSION < '1.9' - a = ?a; s = ?s - else - a = 'a'.ord; s = 's'.ord - end - i = 0 - types.each_byte do |t| - case t - when a then add_text strs[i] - when s then add_lwsp strs[i] - else - raise "TMail FATAL: unknown flag: #{t.chr}" - end - i += 1 - end - end - - METHOD_ID = { - ?j => :extract_J, - ?e => :extract_E, - ?a => :extract_A, - ?s => :extract_S - } - - def concat_E( types, strs ) - if BENCODE_DEBUG - puts '---- concat_E' - puts "types=#{types.split(//).join(' ')}" - puts "strs =#{strs.inspect}" - end - - flush() unless @text.empty? - - chunk = '' - strs.each_with_index do |s,i| - mid = METHOD_ID[types[i]] - until s.empty? - unless c = __send__(mid, chunk.size, s) - add_with_encode chunk unless chunk.empty? - flush - chunk = '' - fold - c = __send__(mid, 0, s) - raise 'TMail FATAL: extract fail' unless c - end - chunk << c - end - end - add_with_encode chunk unless chunk.empty? - end - - def extract_J( chunksize, str ) - size = max_bytes(chunksize, str.size) - 6 - size = (size % 2 == 0) ? (size) : (size - 1) - return nil if size <= 0 - "\e$B#{str.slice!(0, size)}\e(B" - end - - def extract_A( chunksize, str ) - size = max_bytes(chunksize, str.size) - return nil if size <= 0 - str.slice!(0, size) - end - - alias extract_S extract_A - - def max_bytes( chunksize, ssize ) - (restsize() - '=?iso-2022-jp?B??='.size) / 4 * 3 - chunksize - end - - # - # free length buffer - # - - def add_text( str ) - @text << str - # puts '---- text -------------------------------------' - # puts "+ #{str.inspect}" - # puts "txt >>>#{@text.inspect}<<<" - end - - def add_with_encode( str ) - @text << "=?iso-2022-jp?B?#{Base64.encode(str)}?=" - end - - def add_lwsp( lwsp ) - # puts '---- lwsp -------------------------------------' - # puts "+ #{lwsp.inspect}" - fold if restsize() <= 0 - flush(@folded) - @lwsp = lwsp - end - - def flush(folded = false) - # puts '---- flush ----' - # puts "spc >>>#{@lwsp.inspect}<<<" - # puts "txt >>>#{@text.inspect}<<<" - @f << @lwsp << @text - if folded - @curlen = 0 - else - @curlen += (@lwsp.size + @text.size) - end - @text = '' - @lwsp = '' - end - - def fold - # puts '---- fold ----' - unless @f.string =~ /^.*?:$/ - @f << @eol - @lwsp = SPACER - else - fold_header - @folded = true - end - @curlen = 0 - end - - def fold_header - # Called because line is too long - so we need to wrap. - # First look for whitespace in the text - # if it has text, fold there - # check the remaining text, if too long, fold again - # if it doesn't, then don't fold unless the line goes beyond 998 chars - - # Check the text to see if there is whitespace, or if not - @wrapped_text = [] - until @text.blank? - fold_the_string - end - @text = @wrapped_text.join("#{@eol}#{SPACER}") - end - - def fold_the_string - whitespace_location = @text =~ /\s/ || @text.length - # Is the location of the whitespace shorter than the RCF_2822_MAX_LENGTH? - # if there is no whitespace in the string, then this - unless mazsize(whitespace_location) <= 0 - @text.strip! - @wrapped_text << @text.slice!(0...whitespace_location) - # If it is not less, we have to wrap it destructively - else - slice_point = RFC_2822_MAX_LENGTH - @curlen - @lwsp.length - @text.strip! - @wrapped_text << @text.slice!(0...slice_point) - end - end - - def restsize - MAX_LINE_LEN - (@curlen + @lwsp.size + @text.size) - end - - def mazsize(whitespace_location) - # Per RFC2822, the maximum length of a line is 998 chars - RFC_2822_MAX_LENGTH - (@curlen + @lwsp.size + whitespace_location) - end - - end - #:startdoc: -end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/header.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/header.rb deleted file mode 100644 index 9153dcd7c6..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/header.rb +++ /dev/null @@ -1,960 +0,0 @@ -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# 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. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -require 'tmail/encode' -require 'tmail/address' -require 'tmail/parser' -require 'tmail/config' -require 'tmail/utils' - -#:startdoc: -module TMail - - # Provides methods to handle and manipulate headers in the email - class HeaderField - - include TextUtils - - class << self - - alias newobj new - - def new( name, body, conf = DEFAULT_CONFIG ) - klass = FNAME_TO_CLASS[name.downcase] || UnstructuredHeader - klass.newobj body, conf - end - - # Returns a HeaderField object matching the header you specify in the "name" param. - # Requires an initialized TMail::Port to be passed in. - # - # The method searches the header of the Port you pass into it to find a match on - # the header line you pass. Once a match is found, it will unwrap the matching line - # as needed to return an initialized HeaderField object. - # - # If you want to get the Envelope sender of the email object, pass in "EnvelopeSender", - # if you want the From address of the email itself, pass in 'From'. - # - # This is because a mailbox doesn't have the : after the From that designates the - # beginning of the envelope sender (which can be different to the from address of - # the emial) - # - # Other fields can be passed as normal, "Reply-To", "Received" etc. - # - # Note: Change of behaviour in 1.2.1 => returns nil if it does not find the specified - # header field, otherwise returns an instantiated object of the correct header class - # - # For example: - # port = TMail::FilePort.new("/test/fixtures/raw_email_simple") - # h = TMail::HeaderField.new_from_port(port, "From") - # h.addrs.to_s #=> "Mikel Lindsaar " - # h = TMail::HeaderField.new_from_port(port, "EvelopeSender") - # h.addrs.to_s #=> "mike@anotherplace.com.au" - # h = TMail::HeaderField.new_from_port(port, "SomeWeirdHeaderField") - # h #=> nil - def new_from_port( port, name, conf = DEFAULT_CONFIG ) - if name == "EnvelopeSender" - name = "From" - re = Regexp.new('\A(From) ', 'i') - else - re = Regexp.new('\A(' + Regexp.quote(name) + '):', 'i') - end - str = nil - port.ropen {|f| - f.each do |line| - if m = re.match(line) then str = m.post_match.strip - elsif str and /\A[\t ]/ === line then str << ' ' << line.strip - elsif /\A-*\s*\z/ === line then break - elsif str then break - end - end - } - new(name, str, Config.to_config(conf)) if str - end - - def internal_new( name, conf ) - FNAME_TO_CLASS[name].newobj('', conf, true) - end - - end # class << self - - def initialize( body, conf, intern = false ) - @body = body - @config = conf - - @illegal = false - @parsed = false - - if intern - @parsed = true - parse_init - end - end - - def inspect - "#<#{self.class} #{@body.inspect}>" - end - - def illegal? - @illegal - end - - def empty? - ensure_parsed - return true if @illegal - isempty? - end - - private - - def ensure_parsed - return if @parsed - @parsed = true - parse - end - - # defabstract parse - # end - - def clear_parse_status - @parsed = false - @illegal = false - end - - public - - def body - ensure_parsed - v = Decoder.new(s = '') - do_accept v - v.terminate - s - end - - def body=( str ) - @body = str - clear_parse_status - end - - include StrategyInterface - - def accept( strategy ) - ensure_parsed - do_accept strategy - strategy.terminate - end - - # abstract do_accept - - end - - - class UnstructuredHeader < HeaderField - - def body - ensure_parsed - @body - end - - def body=( arg ) - ensure_parsed - @body = arg - end - - private - - def parse_init - end - - def parse - @body = Decoder.decode(@body.gsub(/\n|\r\n|\r/, '')) - end - - def isempty? - not @body - end - - def do_accept( strategy ) - strategy.text @body - end - - end - - - class StructuredHeader < HeaderField - - def comments - ensure_parsed - if @comments[0] - [Decoder.decode(@comments[0])] - else - @comments - end - end - - private - - def parse - save = nil - - begin - parse_init - do_parse - rescue SyntaxError - if not save and mime_encoded? @body - save = @body - @body = Decoder.decode(save) - retry - elsif save - @body = save - end - - @illegal = true - raise if @config.strict_parse? - end - end - - def parse_init - @comments = [] - init - end - - def do_parse - quote_boundary - obj = Parser.parse(self.class::PARSE_TYPE, @body, @comments) - set obj if obj - end - - end - - - class DateTimeHeader < StructuredHeader - - PARSE_TYPE = :DATETIME - - def date - ensure_parsed - @date - end - - def date=( arg ) - ensure_parsed - @date = arg - end - - private - - def init - @date = nil - end - - def set( t ) - @date = t - end - - def isempty? - not @date - end - - def do_accept( strategy ) - strategy.meta time2str(@date) - end - - end - - - class AddressHeader < StructuredHeader - - PARSE_TYPE = :MADDRESS - - def addrs - ensure_parsed - @addrs - end - - private - - def init - @addrs = [] - end - - def set( a ) - @addrs = a - end - - def isempty? - @addrs.empty? - end - - def do_accept( strategy ) - first = true - @addrs.each do |a| - if first - first = false - else - strategy.meta ',' - strategy.space - end - a.accept strategy - end - - @comments.each do |c| - strategy.space - strategy.meta '(' - strategy.text c - strategy.meta ')' - end - end - - end - - - class ReturnPathHeader < AddressHeader - - PARSE_TYPE = :RETPATH - - def addr - addrs()[0] - end - - def spec - a = addr() or return nil - a.spec - end - - def routes - a = addr() or return nil - a.routes - end - - private - - def do_accept( strategy ) - a = addr() - - strategy.meta '<' - unless a.routes.empty? - strategy.meta a.routes.map {|i| '@' + i }.join(',') - strategy.meta ':' - end - spec = a.spec - strategy.meta spec if spec - strategy.meta '>' - end - - end - - - class SingleAddressHeader < AddressHeader - - def addr - addrs()[0] - end - - private - - def do_accept( strategy ) - a = addr() - a.accept strategy - @comments.each do |c| - strategy.space - strategy.meta '(' - strategy.text c - strategy.meta ')' - end - end - - end - - - class MessageIdHeader < StructuredHeader - - def id - ensure_parsed - @id - end - - def id=( arg ) - ensure_parsed - @id = arg - end - - private - - def init - @id = nil - end - - def isempty? - not @id - end - - def do_parse - @id = @body.slice(MESSAGE_ID) or - raise SyntaxError, "wrong Message-ID format: #{@body}" - end - - def do_accept( strategy ) - strategy.meta @id - end - - end - - - class ReferencesHeader < StructuredHeader - - def refs - ensure_parsed - @refs - end - - def each_id - self.refs.each do |i| - yield i if MESSAGE_ID === i - end - end - - def ids - ensure_parsed - @ids - end - - def each_phrase - self.refs.each do |i| - yield i unless MESSAGE_ID === i - end - end - - def phrases - ret = [] - each_phrase {|i| ret.push i } - ret - end - - private - - def init - @refs = [] - @ids = [] - end - - def isempty? - @ids.empty? - end - - def do_parse - str = @body - while m = MESSAGE_ID.match(str) - pre = m.pre_match.strip - @refs.push pre unless pre.empty? - @refs.push s = m[0] - @ids.push s - str = m.post_match - end - str = str.strip - @refs.push str unless str.empty? - end - - def do_accept( strategy ) - first = true - @ids.each do |i| - if first - first = false - else - strategy.space - end - strategy.meta i - end - end - - end - - - class ReceivedHeader < StructuredHeader - - PARSE_TYPE = :RECEIVED - - def from - ensure_parsed - @from - end - - def from=( arg ) - ensure_parsed - @from = arg - end - - def by - ensure_parsed - @by - end - - def by=( arg ) - ensure_parsed - @by = arg - end - - def via - ensure_parsed - @via - end - - def via=( arg ) - ensure_parsed - @via = arg - end - - def with - ensure_parsed - @with - end - - def id - ensure_parsed - @id - end - - def id=( arg ) - ensure_parsed - @id = arg - end - - def _for - ensure_parsed - @_for - end - - def _for=( arg ) - ensure_parsed - @_for = arg - end - - def date - ensure_parsed - @date - end - - def date=( arg ) - ensure_parsed - @date = arg - end - - private - - def init - @from = @by = @via = @with = @id = @_for = nil - @with = [] - @date = nil - end - - def set( args ) - @from, @by, @via, @with, @id, @_for, @date = *args - end - - def isempty? - @with.empty? and not (@from or @by or @via or @id or @_for or @date) - end - - def do_accept( strategy ) - list = [] - list.push 'from ' + @from if @from - list.push 'by ' + @by if @by - list.push 'via ' + @via if @via - @with.each do |i| - list.push 'with ' + i - end - list.push 'id ' + @id if @id - list.push 'for <' + @_for + '>' if @_for - - first = true - list.each do |i| - strategy.space unless first - strategy.meta i - first = false - end - if @date - strategy.meta ';' - strategy.space - strategy.meta time2str(@date) - end - end - - end - - - class KeywordsHeader < StructuredHeader - - PARSE_TYPE = :KEYWORDS - - def keys - ensure_parsed - @keys - end - - private - - def init - @keys = [] - end - - def set( a ) - @keys = a - end - - def isempty? - @keys.empty? - end - - def do_accept( strategy ) - first = true - @keys.each do |i| - if first - first = false - else - strategy.meta ',' - end - strategy.meta i - end - end - - end - - - class EncryptedHeader < StructuredHeader - - PARSE_TYPE = :ENCRYPTED - - def encrypter - ensure_parsed - @encrypter - end - - def encrypter=( arg ) - ensure_parsed - @encrypter = arg - end - - def keyword - ensure_parsed - @keyword - end - - def keyword=( arg ) - ensure_parsed - @keyword = arg - end - - private - - def init - @encrypter = nil - @keyword = nil - end - - def set( args ) - @encrypter, @keyword = args - end - - def isempty? - not (@encrypter or @keyword) - end - - def do_accept( strategy ) - if @key - strategy.meta @encrypter + ',' - strategy.space - strategy.meta @keyword - else - strategy.meta @encrypter - end - end - - end - - - class MimeVersionHeader < StructuredHeader - - PARSE_TYPE = :MIMEVERSION - - def major - ensure_parsed - @major - end - - def major=( arg ) - ensure_parsed - @major = arg - end - - def minor - ensure_parsed - @minor - end - - def minor=( arg ) - ensure_parsed - @minor = arg - end - - def version - sprintf('%d.%d', major, minor) - end - - private - - def init - @major = nil - @minor = nil - end - - def set( args ) - @major, @minor = *args - end - - def isempty? - not (@major or @minor) - end - - def do_accept( strategy ) - strategy.meta sprintf('%d.%d', @major, @minor) - end - - end - - - class ContentTypeHeader < StructuredHeader - - PARSE_TYPE = :CTYPE - - def main_type - ensure_parsed - @main - end - - def main_type=( arg ) - ensure_parsed - @main = arg.downcase - end - - def sub_type - ensure_parsed - @sub - end - - def sub_type=( arg ) - ensure_parsed - @sub = arg.downcase - end - - def content_type - ensure_parsed - @sub ? sprintf('%s/%s', @main, @sub) : @main - end - - def params - ensure_parsed - unless @params.blank? - @params.each do |k, v| - @params[k] = unquote(v) - end - end - @params - end - - def []( key ) - ensure_parsed - @params and unquote(@params[key]) - end - - def []=( key, val ) - ensure_parsed - (@params ||= {})[key] = val - end - - private - - def init - @main = @sub = @params = nil - end - - def set( args ) - @main, @sub, @params = *args - end - - def isempty? - not (@main or @sub) - end - - def do_accept( strategy ) - if @sub - strategy.meta sprintf('%s/%s', @main, @sub) - else - strategy.meta @main - end - @params.each do |k,v| - if v - strategy.meta ';' - strategy.space - strategy.kv_pair k, v - end - end - end - - end - - - class ContentTransferEncodingHeader < StructuredHeader - - PARSE_TYPE = :CENCODING - - def encoding - ensure_parsed - @encoding - end - - def encoding=( arg ) - ensure_parsed - @encoding = arg - end - - private - - def init - @encoding = nil - end - - def set( s ) - @encoding = s - end - - def isempty? - not @encoding - end - - def do_accept( strategy ) - strategy.meta @encoding.capitalize - end - - end - - - class ContentDispositionHeader < StructuredHeader - - PARSE_TYPE = :CDISPOSITION - - def disposition - ensure_parsed - @disposition - end - - def disposition=( str ) - ensure_parsed - @disposition = str.downcase - end - - def params - ensure_parsed - unless @params.blank? - @params.each do |k, v| - @params[k] = unquote(v) - end - end - @params - end - - def []( key ) - ensure_parsed - @params and unquote(@params[key]) - end - - def []=( key, val ) - ensure_parsed - (@params ||= {})[key] = val - end - - private - - def init - @disposition = @params = nil - end - - def set( args ) - @disposition, @params = *args - end - - def isempty? - not @disposition and (not @params or @params.empty?) - end - - def do_accept( strategy ) - strategy.meta @disposition - @params.each do |k,v| - strategy.meta ';' - strategy.space - strategy.kv_pair k, unquote(v) - end - end - - end - - - class HeaderField # redefine - - FNAME_TO_CLASS = { - 'date' => DateTimeHeader, - 'resent-date' => DateTimeHeader, - 'to' => AddressHeader, - 'cc' => AddressHeader, - 'bcc' => AddressHeader, - 'from' => AddressHeader, - 'reply-to' => AddressHeader, - 'resent-to' => AddressHeader, - 'resent-cc' => AddressHeader, - 'resent-bcc' => AddressHeader, - 'resent-from' => AddressHeader, - 'resent-reply-to' => AddressHeader, - 'sender' => SingleAddressHeader, - 'resent-sender' => SingleAddressHeader, - 'return-path' => ReturnPathHeader, - 'message-id' => MessageIdHeader, - 'resent-message-id' => MessageIdHeader, - 'in-reply-to' => ReferencesHeader, - 'received' => ReceivedHeader, - 'references' => ReferencesHeader, - 'keywords' => KeywordsHeader, - 'encrypted' => EncryptedHeader, - 'mime-version' => MimeVersionHeader, - 'content-type' => ContentTypeHeader, - 'content-transfer-encoding' => ContentTransferEncodingHeader, - 'content-disposition' => ContentDispositionHeader, - 'content-id' => MessageIdHeader, - 'subject' => UnstructuredHeader, - 'comments' => UnstructuredHeader, - 'content-description' => UnstructuredHeader - } - - end - -end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/index.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/index.rb deleted file mode 100644 index 554e2fd696..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/index.rb +++ /dev/null @@ -1,9 +0,0 @@ -#:stopdoc: -# This is here for Rolls. -# Rolls uses this instead of lib/tmail.rb. - -require 'tmail/version' -require 'tmail/mail' -require 'tmail/mailbox' -require 'tmail/core_extensions' -#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/interface.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/interface.rb deleted file mode 100644 index 206653bd5d..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/interface.rb +++ /dev/null @@ -1,1125 +0,0 @@ -=begin rdoc - -= interface.rb Provides an interface to the TMail object - -=end -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# 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. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -# TMail::Mail objects get accessed primarily through the methods in this file. -# -# - -require 'tmail/utils' - -module TMail - - class Mail - - # Allows you to query the mail object with a string to get the contents - # of the field you want. - # - # Returns a string of the exact contnts of the field - # - # mail.from = "mikel " - # mail.header_string("From") #=> "mikel " - def header_string( name, default = nil ) - h = @header[name.downcase] or return default - h.to_s - end - - #:stopdoc: - #-- - #== Attributes - - include TextUtils - - def set_string_array_attr( key, strs ) - strs.flatten! - if strs.empty? - @header.delete key.downcase - else - store key, strs.join(', ') - end - strs - end - private :set_string_array_attr - - def set_string_attr( key, str ) - if str - store key, str - else - @header.delete key.downcase - end - str - end - private :set_string_attr - - def set_addrfield( name, arg ) - if arg - h = HeaderField.internal_new(name, @config) - h.addrs.replace [arg].flatten - @header[name] = h - else - @header.delete name - end - arg - end - private :set_addrfield - - def addrs2specs( addrs ) - return nil unless addrs - list = addrs.map {|addr| - if addr.address_group? - then addr.map {|a| a.spec } - else addr.spec - end - }.flatten - return nil if list.empty? - list - end - private :addrs2specs - - #:startdoc: - - #== Date and Time methods - - # Returns the date of the email message as per the "date" header value or returns - # nil by default (if no date field exists). - # - # You can also pass whatever default you want into this method and it will return - # that instead of nil if there is no date already set. - def date( default = nil ) - if h = @header['date'] - h.date - else - default - end - end - - # Destructively sets the date of the mail object with the passed Time instance, - # returns a Time instance set to the date/time of the mail - # - # Example: - # - # now = Time.now - # mail.date = now - # mail.date #=> Sat Nov 03 18:47:50 +1100 2007 - # mail.date.class #=> Time - def date=( time ) - if time - store 'Date', time2str(time) - else - @header.delete 'date' - end - time - end - - # Returns the time of the mail message formatted to your taste using a - # strftime format string. If no date set returns nil by default or whatever value - # you pass as the second optional parameter. - # - # time = Time.now # (on Nov 16 2007) - # mail.date = time - # mail.strftime("%D") #=> "11/16/07" - def strftime( fmt, default = nil ) - if t = date - t.strftime(fmt) - else - default - end - end - - #== Destination methods - - # Return a TMail::Addresses instance for each entry in the "To:" field of the mail object header. - # - # If the "To:" field does not exist, will return nil by default or the value you - # pass as the optional parameter. - # - # Example: - # - # mail = TMail::Mail.new - # mail.to_addrs #=> nil - # mail.to_addrs([]) #=> [] - # mail.to = "Mikel , another Mikel " - # mail.to_addrs #=> [#, #] - def to_addrs( default = nil ) - if h = @header['to'] - h.addrs - else - default - end - end - - # Return a TMail::Addresses instance for each entry in the "Cc:" field of the mail object header. - # - # If the "Cc:" field does not exist, will return nil by default or the value you - # pass as the optional parameter. - # - # Example: - # - # mail = TMail::Mail.new - # mail.cc_addrs #=> nil - # mail.cc_addrs([]) #=> [] - # mail.cc = "Mikel , another Mikel " - # mail.cc_addrs #=> [#, #] - def cc_addrs( default = nil ) - if h = @header['cc'] - h.addrs - else - default - end - end - - # Return a TMail::Addresses instance for each entry in the "Bcc:" field of the mail object header. - # - # If the "Bcc:" field does not exist, will return nil by default or the value you - # pass as the optional parameter. - # - # Example: - # - # mail = TMail::Mail.new - # mail.bcc_addrs #=> nil - # mail.bcc_addrs([]) #=> [] - # mail.bcc = "Mikel , another Mikel " - # mail.bcc_addrs #=> [#, #] - def bcc_addrs( default = nil ) - if h = @header['bcc'] - h.addrs - else - default - end - end - - # Destructively set the to field of the "To:" header to equal the passed in string. - # - # TMail will parse your contents and turn each valid email address into a TMail::Address - # object before assigning it to the mail message. - # - # Example: - # - # mail = TMail::Mail.new - # mail.to = "Mikel , another Mikel " - # mail.to_addrs #=> [#, #] - def to_addrs=( arg ) - set_addrfield 'to', arg - end - - # Destructively set the to field of the "Cc:" header to equal the passed in string. - # - # TMail will parse your contents and turn each valid email address into a TMail::Address - # object before assigning it to the mail message. - # - # Example: - # - # mail = TMail::Mail.new - # mail.cc = "Mikel , another Mikel " - # mail.cc_addrs #=> [#, #] - def cc_addrs=( arg ) - set_addrfield 'cc', arg - end - - # Destructively set the to field of the "Bcc:" header to equal the passed in string. - # - # TMail will parse your contents and turn each valid email address into a TMail::Address - # object before assigning it to the mail message. - # - # Example: - # - # mail = TMail::Mail.new - # mail.bcc = "Mikel , another Mikel " - # mail.bcc_addrs #=> [#, #] - def bcc_addrs=( arg ) - set_addrfield 'bcc', arg - end - - # Returns who the email is to as an Array of email addresses as opposed to an Array of - # TMail::Address objects which is what Mail#to_addrs returns - # - # Example: - # - # mail = TMail::Mail.new - # mail.to = "Mikel , another Mikel " - # mail.to #=> ["mikel@me.org", "mikel@you.org"] - def to( default = nil ) - addrs2specs(to_addrs(nil)) || default - end - - # Returns who the email cc'd as an Array of email addresses as opposed to an Array of - # TMail::Address objects which is what Mail#to_addrs returns - # - # Example: - # - # mail = TMail::Mail.new - # mail.cc = "Mikel , another Mikel " - # mail.cc #=> ["mikel@me.org", "mikel@you.org"] - def cc( default = nil ) - addrs2specs(cc_addrs(nil)) || default - end - - # Returns who the email bcc'd as an Array of email addresses as opposed to an Array of - # TMail::Address objects which is what Mail#to_addrs returns - # - # Example: - # - # mail = TMail::Mail.new - # mail.bcc = "Mikel , another Mikel " - # mail.bcc #=> ["mikel@me.org", "mikel@you.org"] - def bcc( default = nil ) - addrs2specs(bcc_addrs(nil)) || default - end - - # Destructively sets the "To:" field to the passed array of strings (which should be valid - # email addresses) - # - # Example: - # - # mail = TMail::Mail.new - # mail.to = ["mikel@abc.com", "Mikel "] - # mail.to #=> ["mikel@abc.org", "mikel@xyz.org"] - # mail['to'].to_s #=> "mikel@abc.com, Mikel " - def to=( *strs ) - set_string_array_attr 'To', strs - end - - # Destructively sets the "Cc:" field to the passed array of strings (which should be valid - # email addresses) - # - # Example: - # - # mail = TMail::Mail.new - # mail.cc = ["mikel@abc.com", "Mikel "] - # mail.cc #=> ["mikel@abc.org", "mikel@xyz.org"] - # mail['cc'].to_s #=> "mikel@abc.com, Mikel " - def cc=( *strs ) - set_string_array_attr 'Cc', strs - end - - # Destructively sets the "Bcc:" field to the passed array of strings (which should be valid - # email addresses) - # - # Example: - # - # mail = TMail::Mail.new - # mail.bcc = ["mikel@abc.com", "Mikel "] - # mail.bcc #=> ["mikel@abc.org", "mikel@xyz.org"] - # mail['bcc'].to_s #=> "mikel@abc.com, Mikel " - def bcc=( *strs ) - set_string_array_attr 'Bcc', strs - end - - #== Originator methods - - # Return a TMail::Addresses instance for each entry in the "From:" field of the mail object header. - # - # If the "From:" field does not exist, will return nil by default or the value you - # pass as the optional parameter. - # - # Example: - # - # mail = TMail::Mail.new - # mail.from_addrs #=> nil - # mail.from_addrs([]) #=> [] - # mail.from = "Mikel , another Mikel " - # mail.from_addrs #=> [#, #] - def from_addrs( default = nil ) - if h = @header['from'] - h.addrs - else - default - end - end - - # Destructively set the to value of the "From:" header to equal the passed in string. - # - # TMail will parse your contents and turn each valid email address into a TMail::Address - # object before assigning it to the mail message. - # - # Example: - # - # mail = TMail::Mail.new - # mail.from_addrs = "Mikel , another Mikel " - # mail.from_addrs #=> [#, #] - def from_addrs=( arg ) - set_addrfield 'from', arg - end - - # Returns who the email is from as an Array of email address strings instead to an Array of - # TMail::Address objects which is what Mail#from_addrs returns - # - # Example: - # - # mail = TMail::Mail.new - # mail.from = "Mikel , another Mikel " - # mail.from #=> ["mikel@me.org", "mikel@you.org"] - def from( default = nil ) - addrs2specs(from_addrs(nil)) || default - end - - # Destructively sets the "From:" field to the passed array of strings (which should be valid - # email addresses) - # - # Example: - # - # mail = TMail::Mail.new - # mail.from = ["mikel@abc.com", "Mikel "] - # mail.from #=> ["mikel@abc.org", "mikel@xyz.org"] - # mail['from'].to_s #=> "mikel@abc.com, Mikel " - def from=( *strs ) - set_string_array_attr 'From', strs - end - - # Returns the "friendly" human readable part of the address - # - # Example: - # - # mail = TMail::Mail.new - # mail.from = "Mikel Lindsaar " - # mail.friendly_from #=> "Mikel Lindsaar" - def friendly_from( default = nil ) - h = @header['from'] - a, = h.addrs - return default unless a - return a.phrase if a.phrase - return h.comments.join(' ') unless h.comments.empty? - a.spec - end - - # Return a TMail::Addresses instance for each entry in the "Reply-To:" field of the mail object header. - # - # If the "Reply-To:" field does not exist, will return nil by default or the value you - # pass as the optional parameter. - # - # Example: - # - # mail = TMail::Mail.new - # mail.reply_to_addrs #=> nil - # mail.reply_to_addrs([]) #=> [] - # mail.reply_to = "Mikel , another Mikel " - # mail.reply_to_addrs #=> [#, #] - def reply_to_addrs( default = nil ) - if h = @header['reply-to'] - h.addrs.blank? ? default : h.addrs - else - default - end - end - - # Destructively set the to value of the "Reply-To:" header to equal the passed in argument. - # - # TMail will parse your contents and turn each valid email address into a TMail::Address - # object before assigning it to the mail message. - # - # Example: - # - # mail = TMail::Mail.new - # mail.reply_to_addrs = "Mikel , another Mikel " - # mail.reply_to_addrs #=> [#, #] - def reply_to_addrs=( arg ) - set_addrfield 'reply-to', arg - end - - # Returns who the email is from as an Array of email address strings instead to an Array of - # TMail::Address objects which is what Mail#reply_to_addrs returns - # - # Example: - # - # mail = TMail::Mail.new - # mail.reply_to = "Mikel , another Mikel " - # mail.reply_to #=> ["mikel@me.org", "mikel@you.org"] - def reply_to( default = nil ) - addrs2specs(reply_to_addrs(nil)) || default - end - - # Destructively sets the "Reply-To:" field to the passed array of strings (which should be valid - # email addresses) - # - # Example: - # - # mail = TMail::Mail.new - # mail.reply_to = ["mikel@abc.com", "Mikel "] - # mail.reply_to #=> ["mikel@abc.org", "mikel@xyz.org"] - # mail['reply_to'].to_s #=> "mikel@abc.com, Mikel " - def reply_to=( *strs ) - set_string_array_attr 'Reply-To', strs - end - - # Return a TMail::Addresses instance of the "Sender:" field of the mail object header. - # - # If the "Sender:" field does not exist, will return nil by default or the value you - # pass as the optional parameter. - # - # Example: - # - # mail = TMail::Mail.new - # mail.sender #=> nil - # mail.sender([]) #=> [] - # mail.sender = "Mikel " - # mail.reply_to_addrs #=> [#] - def sender_addr( default = nil ) - f = @header['sender'] or return default - f.addr or return default - end - - # Destructively set the to value of the "Sender:" header to equal the passed in argument. - # - # TMail will parse your contents and turn each valid email address into a TMail::Address - # object before assigning it to the mail message. - # - # Example: - # - # mail = TMail::Mail.new - # mail.sender_addrs = "Mikel , another Mikel " - # mail.sender_addrs #=> [#, #] - def sender_addr=( addr ) - if addr - h = HeaderField.internal_new('sender', @config) - h.addr = addr - @header['sender'] = h - else - @header.delete 'sender' - end - addr - end - - # Returns who the sender of this mail is as string instead to an Array of - # TMail::Address objects which is what Mail#sender_addr returns - # - # Example: - # - # mail = TMail::Mail.new - # mail.sender = "Mikel " - # mail.sender #=> "mikel@me.org" - def sender( default = nil ) - f = @header['sender'] or return default - a = f.addr or return default - a.spec - end - - # Destructively sets the "Sender:" field to the passed string (which should be a valid - # email address) - # - # Example: - # - # mail = TMail::Mail.new - # mail.sender = "mikel@abc.com" - # mail.sender #=> "mikel@abc.org" - # mail['sender'].to_s #=> "mikel@abc.com" - def sender=( str ) - set_string_attr 'Sender', str - end - - #== Subject methods - - # Returns the subject of the mail instance. - # - # If the subject field does not exist, returns nil by default or you can pass in as - # the parameter for what you want the default value to be. - # - # Example: - # - # mail = TMail::Mail.new - # mail.subject #=> nil - # mail.subject("") #=> "" - # mail.subject = "Hello" - # mail.subject #=> "Hello" - def subject( default = nil ) - if h = @header['subject'] - h.body - else - default - end - end - alias quoted_subject subject - - # Destructively sets the passed string as the subject of the mail message. - # - # Example - # - # mail = TMail::Mail.new - # mail.subject #=> "This subject" - # mail.subject = "Another subject" - # mail.subject #=> "Another subject" - def subject=( str ) - set_string_attr 'Subject', str - end - - #== Message Identity & Threading Methods - - # Returns the message ID for this mail object instance. - # - # If the message_id field does not exist, returns nil by default or you can pass in as - # the parameter for what you want the default value to be. - # - # Example: - # - # mail = TMail::Mail.new - # mail.message_id #=> nil - # mail.message_id(TMail.new_message_id) #=> "<47404c5326d9c_2ad4fbb80161@baci.local.tmail>" - # mail.message_id = TMail.new_message_id - # mail.message_id #=> "<47404c5326d9c_2ad4fbb80161@baci.local.tmail>" - def message_id( default = nil ) - if h = @header['message-id'] - h.id || default - else - default - end - end - - # Destructively sets the message ID of the mail object instance to the passed in string - # - # Example: - # - # mail = TMail::Mail.new - # mail.message_id = "this_is_my_badly_formatted_message_id" - # mail.message_id #=> "this_is_my_badly_formatted_message_id" - def message_id=( str ) - set_string_attr 'Message-Id', str - end - - # Returns the "In-Reply-To:" field contents as an array of this mail instance if it exists - # - # If the in_reply_to field does not exist, returns nil by default or you can pass in as - # the parameter for what you want the default value to be. - # - # Example: - # - # mail = TMail::Mail.new - # mail.in_reply_to #=> nil - # mail.in_reply_to([]) #=> [] - # TMail::Mail.load("../test/fixtures/raw_email_reply") - # mail.in_reply_to #=> ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] - def in_reply_to( default = nil ) - if h = @header['in-reply-to'] - h.ids - else - default - end - end - - # Destructively sets the value of the "In-Reply-To:" field of an email. - # - # Accepts an array of a single string of a message id - # - # Example: - # - # mail = TMail::Mail.new - # mail.in_reply_to = ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] - # mail.in_reply_to #=> ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] - def in_reply_to=( *idstrs ) - set_string_array_attr 'In-Reply-To', idstrs - end - - # Returns the references of this email (prior messages relating to this message) - # as an array of message ID strings. Useful when you are trying to thread an - # email. - # - # If the references field does not exist, returns nil by default or you can pass in as - # the parameter for what you want the default value to be. - # - # Example: - # - # mail = TMail::Mail.new - # mail.references #=> nil - # mail.references([]) #=> [] - # mail = TMail::Mail.load("../test/fixtures/raw_email_reply") - # mail.references #=> ["<473FF3B8.9020707@xxx.org>", "<348F04F142D69C21-291E56D292BC@xxxx.net>"] - def references( default = nil ) - if h = @header['references'] - h.refs - else - default - end - end - - # Destructively sets the value of the "References:" field of an email. - # - # Accepts an array of strings of message IDs - # - # Example: - # - # mail = TMail::Mail.new - # mail.references = ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] - # mail.references #=> ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] - def references=( *strs ) - set_string_array_attr 'References', strs - end - - #== MIME header methods - - # Returns the listed MIME version of this email from the "Mime-Version:" header field - # - # If the mime_version field does not exist, returns nil by default or you can pass in as - # the parameter for what you want the default value to be. - # - # Example: - # - # mail = TMail::Mail.new - # mail.mime_version #=> nil - # mail.mime_version([]) #=> [] - # mail = TMail::Mail.load("../test/fixtures/raw_email") - # mail.mime_version #=> "1.0" - def mime_version( default = nil ) - if h = @header['mime-version'] - h.version || default - else - default - end - end - - def mime_version=( m, opt = nil ) - if opt - if h = @header['mime-version'] - h.major = m - h.minor = opt - else - store 'Mime-Version', "#{m}.#{opt}" - end - else - store 'Mime-Version', m - end - m - end - - # Returns the current "Content-Type" of the mail instance. - # - # If the content_type field does not exist, returns nil by default or you can pass in as - # the parameter for what you want the default value to be. - # - # Example: - # - # mail = TMail::Mail.new - # mail.content_type #=> nil - # mail.content_type([]) #=> [] - # mail = TMail::Mail.load("../test/fixtures/raw_email") - # mail.content_type #=> "text/plain" - def content_type( default = nil ) - if h = @header['content-type'] - h.content_type || default - else - default - end - end - - # Returns the current main type of the "Content-Type" of the mail instance. - # - # If the content_type field does not exist, returns nil by default or you can pass in as - # the parameter for what you want the default value to be. - # - # Example: - # - # mail = TMail::Mail.new - # mail.main_type #=> nil - # mail.main_type([]) #=> [] - # mail = TMail::Mail.load("../test/fixtures/raw_email") - # mail.main_type #=> "text" - def main_type( default = nil ) - if h = @header['content-type'] - h.main_type || default - else - default - end - end - - # Returns the current sub type of the "Content-Type" of the mail instance. - # - # If the content_type field does not exist, returns nil by default or you can pass in as - # the parameter for what you want the default value to be. - # - # Example: - # - # mail = TMail::Mail.new - # mail.sub_type #=> nil - # mail.sub_type([]) #=> [] - # mail = TMail::Mail.load("../test/fixtures/raw_email") - # mail.sub_type #=> "plain" - def sub_type( default = nil ) - if h = @header['content-type'] - h.sub_type || default - else - default - end - end - - # Destructively sets the "Content-Type:" header field of this mail object - # - # Allows you to set the main type, sub type as well as parameters to the field. - # The main type and sub type need to be a string. - # - # The optional params hash can be passed with keys as symbols and values as a string, - # or strings as keys and values. - # - # Example: - # - # mail = TMail::Mail.new - # mail.set_content_type("text", "plain") - # mail.to_s #=> "Content-Type: text/plain\n\n" - # - # mail.set_content_type("text", "plain", {:charset => "EUC-KR", :format => "flowed"}) - # mail.to_s #=> "Content-Type: text/plain; charset=EUC-KR; format=flowed\n\n" - # - # mail.set_content_type("text", "plain", {"charset" => "EUC-KR", "format" => "flowed"}) - # mail.to_s #=> "Content-Type: text/plain; charset=EUC-KR; format=flowed\n\n" - def set_content_type( str, sub = nil, param = nil ) - if sub - main, sub = str, sub - else - main, sub = str.split(%r, 2) - raise ArgumentError, "sub type missing: #{str.inspect}" unless sub - end - if h = @header['content-type'] - h.main_type = main - h.sub_type = sub - h.params.clear - else - store 'Content-Type', "#{main}/#{sub}" - end - @header['content-type'].params.replace param if param - str - end - - alias content_type= set_content_type - - # Returns the named type parameter as a string, from the "Content-Type:" header. - # - # Example: - # - # mail = TMail::Mail.new - # mail.type_param("charset") #=> nil - # mail.type_param("charset", []) #=> [] - # mail.set_content_type("text", "plain", {:charset => "EUC-KR", :format => "flowed"}) - # mail.type_param("charset") #=> "EUC-KR" - # mail.type_param("format") #=> "flowed" - def type_param( name, default = nil ) - if h = @header['content-type'] - h[name] || default - else - default - end - end - - # Returns the character set of the email. Returns nil if no encoding set or returns - # whatever default you pass as a parameter - note passing the parameter does NOT change - # the mail object in any way. - # - # Example: - # - # mail = TMail::Mail.load("path_to/utf8_email") - # mail.charset #=> "UTF-8" - # - # mail = TMail::Mail.new - # mail.charset #=> nil - # mail.charset("US-ASCII") #=> "US-ASCII" - def charset( default = nil ) - if h = @header['content-type'] - h['charset'] or default - else - default - end - end - - # Destructively sets the character set used by this mail object to the passed string, you - # should note though that this does nothing to the mail body, just changes the header - # value, you will need to transliterate the body as well to match whatever you put - # in this header value if you are changing character sets. - # - # Example: - # - # mail = TMail::Mail.new - # mail.charset #=> nil - # mail.charset = "UTF-8" - # mail.charset #=> "UTF-8" - def charset=( str ) - if str - if h = @header[ 'content-type' ] - h['charset'] = str - else - store 'Content-Type', "text/plain; charset=#{str}" - end - end - str - end - - # Returns the transfer encoding of the email. Returns nil if no encoding set or returns - # whatever default you pass as a parameter - note passing the parameter does NOT change - # the mail object in any way. - # - # Example: - # - # mail = TMail::Mail.load("path_to/base64_encoded_email") - # mail.transfer_encoding #=> "base64" - # - # mail = TMail::Mail.new - # mail.transfer_encoding #=> nil - # mail.transfer_encoding("base64") #=> "base64" - def transfer_encoding( default = nil ) - if h = @header['content-transfer-encoding'] - h.encoding || default - else - default - end - end - - # Destructively sets the transfer encoding of the mail object to the passed string, you - # should note though that this does nothing to the mail body, just changes the header - # value, you will need to encode or decode the body as well to match whatever you put - # in this header value. - # - # Example: - # - # mail = TMail::Mail.new - # mail.transfer_encoding #=> nil - # mail.transfer_encoding = "base64" - # mail.transfer_encoding #=> "base64" - def transfer_encoding=( str ) - set_string_attr 'Content-Transfer-Encoding', str - end - - alias encoding transfer_encoding - alias encoding= transfer_encoding= - alias content_transfer_encoding transfer_encoding - alias content_transfer_encoding= transfer_encoding= - - # Returns the content-disposition of the mail object, returns nil or the passed - # default value if given - # - # Example: - # - # mail = TMail::Mail.load("path_to/raw_mail_with_attachment") - # mail.disposition #=> "attachment" - # - # mail = TMail::Mail.load("path_to/plain_simple_email") - # mail.disposition #=> nil - # mail.disposition(false) #=> false - def disposition( default = nil ) - if h = @header['content-disposition'] - h.disposition || default - else - default - end - end - - alias content_disposition disposition - - # Allows you to set the content-disposition of the mail object. Accepts a type - # and a hash of parameters. - # - # Example: - # - # mail.set_disposition("attachment", {:filename => "test.rb"}) - # mail.disposition #=> "attachment" - # mail['content-disposition'].to_s #=> "attachment; filename=test.rb" - def set_disposition( str, params = nil ) - if h = @header['content-disposition'] - h.disposition = str - h.params.clear - else - store('Content-Disposition', str) - h = @header['content-disposition'] - end - h.params.replace params if params - end - - alias disposition= set_disposition - alias set_content_disposition set_disposition - alias content_disposition= set_disposition - - # Returns the value of a parameter in an existing content-disposition header - # - # Example: - # - # mail.set_disposition("attachment", {:filename => "test.rb"}) - # mail['content-disposition'].to_s #=> "attachment; filename=test.rb" - # mail.disposition_param("filename") #=> "test.rb" - # mail.disposition_param("missing_param_key") #=> nil - # mail.disposition_param("missing_param_key", false) #=> false - # mail.disposition_param("missing_param_key", "Nothing to see here") #=> "Nothing to see here" - def disposition_param( name, default = nil ) - if h = @header['content-disposition'] - h[name] || default - else - default - end - end - - # Convert the Mail object's body into a Base64 encoded email - # returning the modified Mail object - def base64_encode! - store 'Content-Transfer-Encoding', 'Base64' - self.body = base64_encode - end - - # Return the result of encoding the TMail::Mail object body - # without altering the current body - def base64_encode - Base64.folding_encode(self.body) - end - - # Convert the Mail object's body into a Base64 decoded email - # returning the modified Mail object - def base64_decode! - if /base64/i === self.transfer_encoding('') - store 'Content-Transfer-Encoding', '8bit' - self.body = base64_decode - end - end - - # Returns the result of decoding the TMail::Mail object body - # without altering the current body - def base64_decode - Base64.decode(self.body, @config.strict_base64decode?) - end - - # Returns an array of each destination in the email message including to: cc: or bcc: - # - # Example: - # - # mail.to = "Mikel " - # mail.cc = "Trans " - # mail.bcc = "bob " - # mail.destinations #=> ["mikel@lindsaar.net", "t@t.com", "bob@me.com"] - def destinations( default = nil ) - ret = [] - %w( to cc bcc ).each do |nm| - if h = @header[nm] - h.addrs.each {|i| ret.push i.address } - end - end - ret.empty? ? default : ret - end - - # Yields a block of destination, yielding each as a string. - # (from the destinations example) - # mail.each_destination { |d| puts "#{d.class}: #{d}" } - # String: mikel@lindsaar.net - # String: t@t.com - # String: bob@me.com - def each_destination( &block ) - destinations([]).each do |i| - if Address === i - yield i - else - i.each(&block) - end - end - end - - alias each_dest each_destination - - # Returns an array of reply to addresses that the Mail object has, - # or if the Mail message has no reply-to, returns an array of the - # Mail objects from addresses. Else returns the default which can - # either be passed as a parameter or defaults to nil - # - # Example: - # mail.from = "Mikel " - # mail.reply_to = nil - # mail.reply_addresses #=> [""] - # - def reply_addresses( default = nil ) - reply_to_addrs(nil) or from_addrs(nil) or default - end - - # Returns the "sender" field as an array -> useful to find out who to - # send an error email to. - def error_reply_addresses( default = nil ) - if s = sender(nil) - [s] - else - from_addrs(default) - end - end - - # Returns true if the Mail object is a multipart message - def multipart? - main_type('').downcase == 'multipart' - end - - # Creates a new email in reply to self. Sets the In-Reply-To and - # References headers for you automagically. - # - # Example: - # mail = TMail::Mail.load("my_email") - # reply_email = mail.create_reply - # reply_email.class #=> TMail::Mail - # reply_email.references #=> [""] - # reply_email.in_reply_to #=> [""] - def create_reply - setup_reply create_empty_mail() - end - - # Creates a new email in reply to self. Sets the In-Reply-To and - # References headers for you automagically. - # - # Example: - # mail = TMail::Mail.load("my_email") - # forward_email = mail.create_forward - # forward_email.class #=> TMail::Mail - # forward_email.content_type #=> "multipart/mixed" - # forward_email.body #=> "Attachment: (unnamed)" - # forward_email.encoded #=> Returns the original email as a MIME attachment - def create_forward - setup_forward create_empty_mail() - end - - #:stopdoc: - private - - def create_empty_mail - self.class.new(StringPort.new(''), @config) - end - - def setup_reply( mail ) - if tmp = reply_addresses(nil) - mail.to_addrs = tmp - end - - mid = message_id(nil) - tmp = references(nil) || [] - tmp.push mid if mid - mail.in_reply_to = [mid] if mid - mail.references = tmp unless tmp.empty? - mail.subject = 'Re: ' + subject('').sub(/\A(?:\[[^\]]+\])?(?:\s*Re:)*\s*/i, '') - mail.mime_version = '1.0' - mail - end - - def setup_forward( mail ) - m = Mail.new(StringPort.new('')) - m.body = decoded - m.set_content_type 'message', 'rfc822' - m.encoding = encoding('7bit') - mail.parts.push m - # call encoded to reparse the message - mail.encoded - mail - end - - #:startdoc: - end # class Mail - -end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/loader.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/loader.rb deleted file mode 100644 index 6c0e251102..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/loader.rb +++ /dev/null @@ -1,3 +0,0 @@ -#:stopdoc: -require 'tmail/mailbox' -#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mail.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mail.rb deleted file mode 100644 index fef6b01c39..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mail.rb +++ /dev/null @@ -1,578 +0,0 @@ -=begin rdoc - -= Mail class - -=end -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# 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. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - - - -require 'tmail/interface' -require 'tmail/encode' -require 'tmail/header' -require 'tmail/port' -require 'tmail/config' -require 'tmail/utils' -require 'tmail/attachments' -require 'tmail/quoting' -require 'socket' - -module TMail - - # == Mail Class - # - # Accessing a TMail object done via the TMail::Mail class. As email can be fairly complex - # creatures, you will find a large amount of accessor and setter methods in this class! - # - # Most of the below methods handle the header, in fact, what TMail does best is handle the - # header of the email object. There are only a few methods that deal directly with the body - # of the email, such as base64_encode and base64_decode. - # - # === Using TMail inside your code - # - # The usual way is to install the gem (see the {README}[link:/README] on how to do this) and - # then put at the top of your class: - # - # require 'tmail' - # - # You can then create a new TMail object in your code with: - # - # @email = TMail::Mail.new - # - # Or if you have an email as a string, you can initialize a new TMail::Mail object and get it - # to parse that string for you like so: - # - # @email = TMail::Mail.parse(email_text) - # - # You can also read a single email off the disk, for example: - # - # @email = TMail::Mail.load('filename.txt') - # - # Also, you can read a mailbox (usual unix mbox format) and end up with an array of TMail - # objects by doing something like this: - # - # # Note, we pass true as the last variable to open the mailbox read only - # mailbox = TMail::UNIXMbox.new("mailbox", nil, true) - # @emails = [] - # mailbox.each_port { |m| @emails << TMail::Mail.new(m) } - # - class Mail - - class << self - - # Opens an email that has been saved out as a file by itself. - # - # This function will read a file non-destructively and then parse - # the contents and return a TMail::Mail object. - # - # Does not handle multiple email mailboxes (like a unix mbox) for that - # use the TMail::UNIXMbox class. - # - # Example: - # mail = TMail::Mail.load('filename') - # - def load( fname ) - new(FilePort.new(fname)) - end - - alias load_from load - alias loadfrom load - - # Parses an email from the supplied string and returns a TMail::Mail - # object. - # - # Example: - # require 'rubygems'; require 'tmail' - # email_string =< # bodyport=nil> - # mail.body - # #=> "Hello there Mikel!\n\n" - def parse( str ) - new(StringPort.new(str)) - end - - end - - def initialize( port = nil, conf = DEFAULT_CONFIG ) #:nodoc: - @port = port || StringPort.new - @config = Config.to_config(conf) - - @header = {} - @body_port = nil - @body_parsed = false - @epilogue = '' - @parts = [] - - @port.ropen {|f| - parse_header f - parse_body f unless @port.reproducible? - } - end - - # Provides access to the port this email is using to hold it's data - # - # Example: - # mail = TMail::Mail.parse(email_string) - # mail.port - # #=> # - attr_reader :port - - def inspect - "\#<#{self.class} port=#{@port.inspect} bodyport=#{@body_port.inspect}>" - end - - # - # to_s interfaces - # - - public - - include StrategyInterface - - def write_back( eol = "\n", charset = 'e' ) - parse_body - @port.wopen {|stream| encoded eol, charset, stream } - end - - def accept( strategy ) - with_multipart_encoding(strategy) { - ordered_each do |name, field| - next if field.empty? - strategy.header_name canonical(name) - field.accept strategy - strategy.puts - end - strategy.puts - body_port().ropen {|r| - strategy.write r.read - } - } - end - - private - - def canonical( name ) - name.split(/-/).map {|s| s.capitalize }.join('-') - end - - def with_multipart_encoding( strategy ) - if parts().empty? # DO NOT USE @parts - yield - - else - bound = ::TMail.new_boundary - if @header.key? 'content-type' - @header['content-type'].params['boundary'] = bound - else - store 'Content-Type', % - end - - yield - - parts().each do |tm| - strategy.puts - strategy.puts '--' + bound - tm.accept strategy - end - strategy.puts - strategy.puts '--' + bound + '--' - strategy.write epilogue() - end - end - - ### - ### header - ### - - public - - ALLOW_MULTIPLE = { - 'received' => true, - 'resent-date' => true, - 'resent-from' => true, - 'resent-sender' => true, - 'resent-to' => true, - 'resent-cc' => true, - 'resent-bcc' => true, - 'resent-message-id' => true, - 'comments' => true, - 'keywords' => true - } - USE_ARRAY = ALLOW_MULTIPLE - - def header - @header.dup - end - - # Returns a TMail::AddressHeader object of the field you are querying. - # Examples: - # @mail['from'] #=> # - # @mail['to'] #=> # - # - # You can get the string value of this by passing "to_s" to the query: - # Example: - # @mail['to'].to_s #=> "mikel@test.com.au" - def []( key ) - @header[key.downcase] - end - - def sub_header(key, param) - (hdr = self[key]) ? hdr[param] : nil - end - - alias fetch [] - - # Allows you to set or delete TMail header objects at will. - # Eamples: - # @mail = TMail::Mail.new - # @mail['to'].to_s # => 'mikel@test.com.au' - # @mail['to'] = 'mikel@elsewhere.org' - # @mail['to'].to_s # => 'mikel@elsewhere.org' - # @mail.encoded # => "To: mikel@elsewhere.org\r\n\r\n" - # @mail['to'] = nil - # @mail['to'].to_s # => nil - # @mail.encoded # => "\r\n" - # - # Note: setting mail[] = nil actualy deletes the header field in question from the object, - # it does not just set the value of the hash to nil - def []=( key, val ) - dkey = key.downcase - - if val.nil? - @header.delete dkey - return nil - end - - case val - when String - header = new_hf(key, val) - when HeaderField - ; - when Array - ALLOW_MULTIPLE.include? dkey or - raise ArgumentError, "#{key}: Header must not be multiple" - @header[dkey] = val - return val - else - header = new_hf(key, val.to_s) - end - if ALLOW_MULTIPLE.include? dkey - (@header[dkey] ||= []).push header - else - @header[dkey] = header - end - - val - end - - alias store []= - - # Allows you to loop through each header in the TMail::Mail object in a block - # Example: - # @mail['to'] = 'mikel@elsewhere.org' - # @mail['from'] = 'me@me.com' - # @mail.each_header { |k,v| puts "#{k} = #{v}" } - # # => from = me@me.com - # # => to = mikel@elsewhere.org - def each_header - @header.each do |key, val| - [val].flatten.each {|v| yield key, v } - end - end - - alias each_pair each_header - - def each_header_name( &block ) - @header.each_key(&block) - end - - alias each_key each_header_name - - def each_field( &block ) - @header.values.flatten.each(&block) - end - - alias each_value each_field - - FIELD_ORDER = %w( - return-path received - resent-date resent-from resent-sender resent-to - resent-cc resent-bcc resent-message-id - date from sender reply-to to cc bcc - message-id in-reply-to references - subject comments keywords - mime-version content-type content-transfer-encoding - content-disposition content-description - ) - - def ordered_each - list = @header.keys - FIELD_ORDER.each do |name| - if list.delete(name) - [@header[name]].flatten.each {|v| yield name, v } - end - end - list.each do |name| - [@header[name]].flatten.each {|v| yield name, v } - end - end - - def clear - @header.clear - end - - def delete( key ) - @header.delete key.downcase - end - - def delete_if - @header.delete_if do |key,val| - if Array === val - val.delete_if {|v| yield key, v } - val.empty? - else - yield key, val - end - end - end - - def keys - @header.keys - end - - def key?( key ) - @header.key? key.downcase - end - - def values_at( *args ) - args.map {|k| @header[k.downcase] }.flatten - end - - alias indexes values_at - alias indices values_at - - private - - def parse_header( f ) - name = field = nil - unixfrom = nil - - while line = f.gets - case line - when /\A[ \t]/ # continue from prev line - raise SyntaxError, 'mail is began by space' unless field - field << ' ' << line.strip - - when /\A([^\: \t]+):\s*/ # new header line - add_hf name, field if field - name = $1 - field = $' #.strip - - when /\A\-*\s*\z/ # end of header - add_hf name, field if field - name = field = nil - break - - when /\AFrom (\S+)/ - unixfrom = $1 - - when /^charset=.*/ - - else - raise SyntaxError, "wrong mail header: '#{line.inspect}'" - end - end - add_hf name, field if name - - if unixfrom - add_hf 'Return-Path', "<#{unixfrom}>" unless @header['return-path'] - end - end - - def add_hf( name, field ) - key = name.downcase - field = new_hf(name, field) - - if ALLOW_MULTIPLE.include? key - (@header[key] ||= []).push field - else - @header[key] = field - end - end - - def new_hf( name, field ) - HeaderField.new(name, field, @config) - end - - ### - ### body - ### - - public - - def body_port - parse_body - @body_port - end - - def each( &block ) - body_port().ropen {|f| f.each(&block) } - end - - def quoted_body - body_port.ropen {|f| return f.read } - end - - def quoted_body= str - body_port.wopen { |f| f.write str } - str - end - - def body=( str ) - # Sets the body of the email to a new (encoded) string. - # - # We also reparses the email if the body is ever reassigned, this is a performance hit, however when - # you assign the body, you usually want to be able to make sure that you can access the attachments etc. - # - # Usage: - # - # mail.body = "Hello, this is\nthe body text" - # # => "Hello, this is\nthe body" - # mail.body - # # => "Hello, this is\nthe body" - @body_parsed = false - parse_body(StringInput.new(str)) - parse_body - @body_port.wopen {|f| f.write str } - str - end - - alias preamble quoted_body - alias preamble= quoted_body= - - def epilogue - parse_body - @epilogue.dup - end - - def epilogue=( str ) - parse_body - @epilogue = str - str - end - - def parts - parse_body - @parts - end - - def each_part( &block ) - parts().each(&block) - end - - # Returns true if the content type of this part of the email is - # a disposition attachment - def disposition_is_attachment? - (self['content-disposition'] && self['content-disposition'].disposition == "attachment") - end - - # Returns true if this part's content main type is text, else returns false. - # By main type is meant "text/plain" is text. "text/html" is text - def content_type_is_text? - self.header['content-type'] && (self.header['content-type'].main_type != "text") - end - - private - - def parse_body( f = nil ) - return if @body_parsed - if f - parse_body_0 f - else - @port.ropen {|f| - skip_header f - parse_body_0 f - } - end - @body_parsed = true - end - - def skip_header( f ) - while line = f.gets - return if /\A[\r\n]*\z/ === line - end - end - - def parse_body_0( f ) - if multipart? - read_multipart f - else - @body_port = @config.new_body_port(self) - @body_port.wopen {|w| - w.write f.read - } - end - end - - def read_multipart( src ) - bound = @header['content-type'].params['boundary'] - is_sep = /\A--#{Regexp.quote bound}(?:--)?[ \t]*(?:\n|\r\n|\r)/ - lastbound = "--#{bound}--" - - ports = [ @config.new_preamble_port(self) ] - begin - f = ports.last.wopen - while line = src.gets - if is_sep === line - f.close - break if line.strip == lastbound - ports.push @config.new_part_port(self) - f = ports.last.wopen - else - f << line - end - end - @epilogue = (src.read || '') - ensure - f.close if f and not f.closed? - end - - @body_port = ports.shift - @parts = ports.map {|p| self.class.new(p, @config) } - end - - end # class Mail - -end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mailbox.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mailbox.rb deleted file mode 100644 index b0bc6a7f74..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mailbox.rb +++ /dev/null @@ -1,495 +0,0 @@ -=begin rdoc - -= Mailbox and Mbox interaction class - -=end -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# 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. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -require 'tmail/port' -require 'socket' -require 'mutex_m' - - -unless [].respond_to?(:sort_by) -module Enumerable#:nodoc: - def sort_by - map {|i| [yield(i), i] }.sort {|a,b| a.first <=> b.first }.map {|i| i[1] } - end -end -end - - -module TMail - - class MhMailbox - - PORT_CLASS = MhPort - - def initialize( dir ) - edir = File.expand_path(dir) - raise ArgumentError, "not directory: #{dir}"\ - unless FileTest.directory? edir - @dirname = edir - @last_file = nil - @last_atime = nil - end - - def directory - @dirname - end - - alias dirname directory - - attr_accessor :last_atime - - def inspect - "#<#{self.class} #{@dirname}>" - end - - def close - end - - def new_port - PORT_CLASS.new(next_file_name()) - end - - def each_port - mail_files().each do |path| - yield PORT_CLASS.new(path) - end - @last_atime = Time.now - end - - alias each each_port - - def reverse_each_port - mail_files().reverse_each do |path| - yield PORT_CLASS.new(path) - end - @last_atime = Time.now - end - - alias reverse_each reverse_each_port - - # old #each_mail returns Port - #def each_mail - # each_port do |port| - # yield Mail.new(port) - # end - #end - - def each_new_port( mtime = nil, &block ) - mtime ||= @last_atime - return each_port(&block) unless mtime - return unless File.mtime(@dirname) >= mtime - - mail_files().each do |path| - yield PORT_CLASS.new(path) if File.mtime(path) > mtime - end - @last_atime = Time.now - end - - private - - def mail_files - Dir.entries(@dirname)\ - .select {|s| /\A\d+\z/ === s }\ - .map {|s| s.to_i }\ - .sort\ - .map {|i| "#{@dirname}/#{i}" }\ - .select {|path| FileTest.file? path } - end - - def next_file_name - unless n = @last_file - n = 0 - Dir.entries(@dirname)\ - .select {|s| /\A\d+\z/ === s }\ - .map {|s| s.to_i }.sort\ - .each do |i| - next unless FileTest.file? "#{@dirname}/#{i}" - n = i - end - end - begin - n += 1 - end while FileTest.exist? "#{@dirname}/#{n}" - @last_file = n - - "#{@dirname}/#{n}" - end - - end # MhMailbox - - MhLoader = MhMailbox - - - class UNIXMbox - - class << self - alias newobj new - end - - # Creates a new mailbox object that you can iterate through to collect the - # emails from with "each_port". - # - # You need to pass it a filename of a unix mailbox format file, the format of this - # file can be researched at this page at {wikipedia}[link:http://en.wikipedia.org/wiki/Mbox] - # - # ==== Parameters - # - # +filename+: The filename of the mailbox you want to open - # - # +tmpdir+: Can be set to override TMail using the system environment's temp dir. TMail will first - # use the temp dir specified by you (if any) or then the temp dir specified in the Environment's TEMP - # value then the value in the Environment's TMP value or failing all of the above, '/tmp' - # - # +readonly+: If set to false, each email you take from the mail box will be removed from the mailbox. - # default is *false* - ie, it *WILL* truncate your mailbox file to ZERO once it has read the emails out. - # - # ==== Options: - # - # None - # - # ==== Examples: - # - # # First show using readonly true: - # - # require 'ftools' - # File.size("../test/fixtures/mailbox") - # #=> 20426 - # - # mailbox = TMail::UNIXMbox.new("../test/fixtures/mailbox", nil, true) - # #=> # - # - # mailbox.each_port do |port| - # mail = TMail::Mail.new(port) - # puts mail.subject - # end - # #Testing mailbox 1 - # #Testing mailbox 2 - # #Testing mailbox 3 - # #Testing mailbox 4 - # require 'ftools' - # File.size?("../test/fixtures/mailbox") - # #=> 20426 - # - # # Now show with readonly set to the default false - # - # mailbox = TMail::UNIXMbox.new("../test/fixtures/mailbox") - # #=> # - # - # mailbox.each_port do |port| - # mail = TMail::Mail.new(port) - # puts mail.subject - # end - # #Testing mailbox 1 - # #Testing mailbox 2 - # #Testing mailbox 3 - # #Testing mailbox 4 - # - # File.size?("../test/fixtures/mailbox") - # #=> nil - def UNIXMbox.new( filename, tmpdir = nil, readonly = false ) - tmpdir = ENV['TEMP'] || ENV['TMP'] || '/tmp' - newobj(filename, "#{tmpdir}/ruby_tmail_#{$$}_#{rand()}", readonly, false) - end - - def UNIXMbox.lock( fname ) - begin - f = File.open(fname, 'r+') - f.flock File::LOCK_EX - yield f - ensure - f.flock File::LOCK_UN - f.close if f and not f.closed? - end - end - - def UNIXMbox.static_new( fname, dir, readonly = false ) - newobj(fname, dir, readonly, true) - end - - def initialize( fname, mhdir, readonly, static ) - @filename = fname - @readonly = readonly - @closed = false - - Dir.mkdir mhdir - @real = MhMailbox.new(mhdir) - @finalizer = UNIXMbox.mkfinal(@real, @filename, !@readonly, !static) - ObjectSpace.define_finalizer self, @finalizer - end - - def UNIXMbox.mkfinal( mh, mboxfile, writeback_p, cleanup_p ) - lambda { - if writeback_p - lock(mboxfile) {|f| - mh.each_port do |port| - f.puts create_from_line(port) - port.ropen {|r| - f.puts r.read - } - end - } - end - if cleanup_p - Dir.foreach(mh.dirname) do |fname| - next if /\A\.\.?\z/ === fname - File.unlink "#{mh.dirname}/#{fname}" - end - Dir.rmdir mh.dirname - end - } - end - - # make _From line - def UNIXMbox.create_from_line( port ) - sprintf 'From %s %s', - fromaddr(), TextUtils.time2str(File.mtime(port.filename)) - end - - def UNIXMbox.fromaddr(port) - h = HeaderField.new_from_port(port, 'Return-Path') || - HeaderField.new_from_port(port, 'From') || - HeaderField.new_from_port(port, 'EnvelopeSender') or return 'nobody' - a = h.addrs[0] or return 'nobody' - a.spec - end - - def close - return if @closed - - ObjectSpace.undefine_finalizer self - @finalizer.call - @finalizer = nil - @real = nil - @closed = true - @updated = nil - end - - def each_port( &block ) - close_check - update - @real.each_port(&block) - end - - alias each each_port - - def reverse_each_port( &block ) - close_check - update - @real.reverse_each_port(&block) - end - - alias reverse_each reverse_each_port - - # old #each_mail returns Port - #def each_mail( &block ) - # each_port do |port| - # yield Mail.new(port) - # end - #end - - def each_new_port( mtime = nil ) - close_check - update - @real.each_new_port(mtime) {|p| yield p } - end - - def new_port - close_check - @real.new_port - end - - private - - def close_check - @closed and raise ArgumentError, 'accessing already closed mbox' - end - - def update - return if FileTest.zero?(@filename) - return if @updated and File.mtime(@filename) < @updated - w = nil - port = nil - time = nil - UNIXMbox.lock(@filename) {|f| - begin - f.each do |line| - if /\AFrom / === line - w.close if w - File.utime time, time, port.filename if time - - port = @real.new_port - w = port.wopen - time = fromline2time(line) - else - w.print line if w - end - end - ensure - if w and not w.closed? - w.close - File.utime time, time, port.filename if time - end - end - f.truncate(0) unless @readonly - @updated = Time.now - } - end - - def fromline2time( line ) - m = /\AFrom \S+ \w+ (\w+) (\d+) (\d+):(\d+):(\d+) (\d+)/.match(line) \ - or return nil - Time.local(m[6].to_i, m[1], m[2].to_i, m[3].to_i, m[4].to_i, m[5].to_i) - end - - end # UNIXMbox - - MboxLoader = UNIXMbox - - - class Maildir - - extend Mutex_m - - PORT_CLASS = MaildirPort - - @seq = 0 - def Maildir.unique_number - synchronize { - @seq += 1 - return @seq - } - end - - def initialize( dir = nil ) - @dirname = dir || ENV['MAILDIR'] - raise ArgumentError, "not directory: #{@dirname}"\ - unless FileTest.directory? @dirname - @new = "#{@dirname}/new" - @tmp = "#{@dirname}/tmp" - @cur = "#{@dirname}/cur" - end - - def directory - @dirname - end - - def inspect - "#<#{self.class} #{@dirname}>" - end - - def close - end - - def each_port - mail_files(@cur).each do |path| - yield PORT_CLASS.new(path) - end - end - - alias each each_port - - def reverse_each_port - mail_files(@cur).reverse_each do |path| - yield PORT_CLASS.new(path) - end - end - - alias reverse_each reverse_each_port - - def new_port - fname = nil - tmpfname = nil - newfname = nil - - begin - fname = "#{Time.now.to_i}.#{$$}_#{Maildir.unique_number}.#{Socket.gethostname}" - - tmpfname = "#{@tmp}/#{fname}" - newfname = "#{@new}/#{fname}" - end while FileTest.exist? tmpfname - - if block_given? - File.open(tmpfname, 'w') {|f| yield f } - File.rename tmpfname, newfname - PORT_CLASS.new(newfname) - else - File.open(tmpfname, 'w') {|f| f.write "\n\n" } - PORT_CLASS.new(tmpfname) - end - end - - def each_new_port - mail_files(@new).each do |path| - dest = @cur + '/' + File.basename(path) - File.rename path, dest - yield PORT_CLASS.new(dest) - end - - check_tmp - end - - TOO_OLD = 60 * 60 * 36 # 36 hour - - def check_tmp - old = Time.now.to_i - TOO_OLD - - each_filename(@tmp) do |full, fname| - if FileTest.file? full and - File.stat(full).mtime.to_i < old - File.unlink full - end - end - end - - private - - def mail_files( dir ) - Dir.entries(dir)\ - .select {|s| s[0] != ?. }\ - .sort_by {|s| s.slice(/\A\d+/).to_i }\ - .map {|s| "#{dir}/#{s}" }\ - .select {|path| FileTest.file? path } - end - - def each_filename( dir ) - Dir.foreach(dir) do |fname| - path = "#{dir}/#{fname}" - if fname[0] != ?. and FileTest.file? path - yield path, fname - end - end - end - - end # Maildir - - MaildirLoader = Maildir - -end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/main.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/main.rb deleted file mode 100644 index e52772793f..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/main.rb +++ /dev/null @@ -1,6 +0,0 @@ -#:stopdoc: -require 'tmail/version' -require 'tmail/mail' -require 'tmail/mailbox' -require 'tmail/core_extensions' -#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mbox.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mbox.rb deleted file mode 100644 index 6c0e251102..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mbox.rb +++ /dev/null @@ -1,3 +0,0 @@ -#:stopdoc: -require 'tmail/mailbox' -#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/net.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/net.rb deleted file mode 100644 index 65147228a1..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/net.rb +++ /dev/null @@ -1,248 +0,0 @@ -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# 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. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -#:stopdoc: -require 'nkf' -#:startdoc: - -module TMail - - class Mail - - def send_to( smtp ) - do_send_to(smtp) do - ready_to_send - end - end - - def send_text_to( smtp ) - do_send_to(smtp) do - ready_to_send - mime_encode - end - end - - def do_send_to( smtp ) - from = from_address or raise ArgumentError, 'no from address' - (dests = destinations).empty? and raise ArgumentError, 'no receipient' - yield - send_to_0 smtp, from, dests - end - private :do_send_to - - def send_to_0( smtp, from, to ) - smtp.ready(from, to) do |f| - encoded "\r\n", 'j', f, '' - end - end - - def ready_to_send - delete_no_send_fields - add_message_id - add_date - end - - NOSEND_FIELDS = %w( - received - bcc - ) - - def delete_no_send_fields - NOSEND_FIELDS.each do |nm| - delete nm - end - delete_if {|n,v| v.empty? } - end - - def add_message_id( fqdn = nil ) - self.message_id = ::TMail::new_message_id(fqdn) - end - - def add_date - self.date = Time.now - end - - def mime_encode - if parts.empty? - mime_encode_singlepart - else - mime_encode_multipart true - end - end - - def mime_encode_singlepart - self.mime_version = '1.0' - b = body - if NKF.guess(b) != NKF::BINARY - mime_encode_text b - else - mime_encode_binary b - end - end - - def mime_encode_text( body ) - self.body = NKF.nkf('-j -m0', body) - self.set_content_type 'text', 'plain', {'charset' => 'iso-2022-jp'} - self.encoding = '7bit' - end - - def mime_encode_binary( body ) - self.body = [body].pack('m') - self.set_content_type 'application', 'octet-stream' - self.encoding = 'Base64' - end - - def mime_encode_multipart( top = true ) - self.mime_version = '1.0' if top - self.set_content_type 'multipart', 'mixed' - e = encoding(nil) - if e and not /\A(?:7bit|8bit|binary)\z/i === e - raise ArgumentError, - 'using C.T.Encoding with multipart mail is not permitted' - end - end - - end - - #:stopdoc: - class DeleteFields - - NOSEND_FIELDS = %w( - received - bcc - ) - - def initialize( nosend = nil, delempty = true ) - @no_send_fields = nosend || NOSEND_FIELDS.dup - @delete_empty_fields = delempty - end - - attr :no_send_fields - attr :delete_empty_fields, true - - def exec( mail ) - @no_send_fields.each do |nm| - delete nm - end - delete_if {|n,v| v.empty? } if @delete_empty_fields - end - - end - #:startdoc: - - #:stopdoc: - class AddMessageId - - def initialize( fqdn = nil ) - @fqdn = fqdn - end - - attr :fqdn, true - - def exec( mail ) - mail.message_id = ::TMail::new_msgid(@fqdn) - end - - end - #:startdoc: - - #:stopdoc: - class AddDate - - def exec( mail ) - mail.date = Time.now - end - - end - #:startdoc: - - #:stopdoc: - class MimeEncodeAuto - - def initialize( s = nil, m = nil ) - @singlepart_composer = s || MimeEncodeSingle.new - @multipart_composer = m || MimeEncodeMulti.new - end - - attr :singlepart_composer - attr :multipart_composer - - def exec( mail ) - if mail._builtin_multipart? - then @multipart_composer - else @singlepart_composer end.exec mail - end - - end - #:startdoc: - - #:stopdoc: - class MimeEncodeSingle - - def exec( mail ) - mail.mime_version = '1.0' - b = mail.body - if NKF.guess(b) != NKF::BINARY - on_text b - else - on_binary b - end - end - - def on_text( body ) - mail.body = NKF.nkf('-j -m0', body) - mail.set_content_type 'text', 'plain', {'charset' => 'iso-2022-jp'} - mail.encoding = '7bit' - end - - def on_binary( body ) - mail.body = [body].pack('m') - mail.set_content_type 'application', 'octet-stream' - mail.encoding = 'Base64' - end - - end - #:startdoc: - - #:stopdoc: - class MimeEncodeMulti - - def exec( mail, top = true ) - mail.mime_version = '1.0' if top - mail.set_content_type 'multipart', 'mixed' - e = encoding(nil) - if e and not /\A(?:7bit|8bit|binary)\z/i === e - raise ArgumentError, - 'using C.T.Encoding with multipart mail is not permitted' - end - mail.parts.each do |m| - exec m, false if m._builtin_multipart? - end - end - - end - #:startdoc: -end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/obsolete.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/obsolete.rb deleted file mode 100644 index 22b0a126ca..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/obsolete.rb +++ /dev/null @@ -1,132 +0,0 @@ -=begin rdoc - -= Obsolete methods that are depriciated - -If you really want to see them, go to lib/tmail/obsolete.rb and view to your -heart's content. - -=end -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# 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. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ -#:stopdoc: -module TMail #:nodoc: - - class Mail - alias include? key? - alias has_key? key? - - def values - ret = [] - each_field {|v| ret.push v } - ret - end - - def value?( val ) - HeaderField === val or return false - - [ @header[val.name.downcase] ].flatten.include? val - end - - alias has_value? value? - end - - class Mail - def from_addr( default = nil ) - addr, = from_addrs(nil) - addr || default - end - - def from_address( default = nil ) - if a = from_addr(nil) - a.spec - else - default - end - end - - alias from_address= from_addrs= - - def from_phrase( default = nil ) - if a = from_addr(nil) - a.phrase - else - default - end - end - - alias msgid message_id - alias msgid= message_id= - - alias each_dest each_destination - end - - class Address - alias route routes - alias addr spec - - def spec=( str ) - @local, @domain = str.split(/@/,2).map {|s| s.split(/\./) } - end - - alias addr= spec= - alias address= spec= - end - - class MhMailbox - alias new_mail new_port - alias each_mail each_port - alias each_newmail each_new_port - end - class UNIXMbox - alias new_mail new_port - alias each_mail each_port - alias each_newmail each_new_port - end - class Maildir - alias new_mail new_port - alias each_mail each_port - alias each_newmail each_new_port - end - - extend TextUtils - - class << self - alias msgid? message_id? - alias boundary new_boundary - alias msgid new_message_id - alias new_msgid new_message_id - end - - def Mail.boundary - ::TMail.new_boundary - end - - def Mail.msgid - ::TMail.new_message_id - end - -end # module TMail -#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/parser.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/parser.rb deleted file mode 100644 index ab1a828471..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/parser.rb +++ /dev/null @@ -1,1476 +0,0 @@ -#:stopdoc: -# DO NOT MODIFY!!!! -# This file is automatically generated by racc 1.4.5 -# from racc grammer file "parser.y". -# -# -# parser.rb: generated by racc (runtime embedded) -# -###### racc/parser.rb begin -unless $".index 'racc/parser.rb' -$".push 'racc/parser.rb' - -self.class.module_eval <<'..end racc/parser.rb modeval..id8076474214', 'racc/parser.rb', 1 -# -# $Id: parser.rb,v 1.7 2005/11/20 17:31:32 aamine Exp $ -# -# Copyright (c) 1999-2005 Minero Aoki -# -# This program is free software. -# You can distribute/modify this program under the same terms of ruby. -# -# As a special exception, when this code is copied by Racc -# into a Racc output file, you may use that output file -# without restriction. -# - -unless defined?(NotImplementedError) - NotImplementedError = NotImplementError -end - -module Racc - class ParseError < StandardError; end -end -unless defined?(::ParseError) - ParseError = Racc::ParseError -end - -module Racc - - unless defined?(Racc_No_Extentions) - Racc_No_Extentions = false - end - - class Parser - - Racc_Runtime_Version = '1.4.5' - Racc_Runtime_Revision = '$Revision: 1.7 $'.split[1] - - Racc_Runtime_Core_Version_R = '1.4.5' - Racc_Runtime_Core_Revision_R = '$Revision: 1.7 $'.split[1] - begin - require 'racc/cparse' - # Racc_Runtime_Core_Version_C = (defined in extention) - Racc_Runtime_Core_Revision_C = Racc_Runtime_Core_Id_C.split[2] - unless new.respond_to?(:_racc_do_parse_c, true) - raise LoadError, 'old cparse.so' - end - if Racc_No_Extentions - raise LoadError, 'selecting ruby version of racc runtime core' - end - - Racc_Main_Parsing_Routine = :_racc_do_parse_c - Racc_YY_Parse_Method = :_racc_yyparse_c - Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_C - Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_C - Racc_Runtime_Type = 'c' - rescue LoadError - Racc_Main_Parsing_Routine = :_racc_do_parse_rb - Racc_YY_Parse_Method = :_racc_yyparse_rb - Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_R - Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_R - Racc_Runtime_Type = 'ruby' - end - - def Parser.racc_runtime_type - Racc_Runtime_Type - end - - private - - def _racc_setup - @yydebug = false unless self.class::Racc_debug_parser - @yydebug = false unless defined?(@yydebug) - if @yydebug - @racc_debug_out = $stderr unless defined?(@racc_debug_out) - @racc_debug_out ||= $stderr - end - arg = self.class::Racc_arg - arg[13] = true if arg.size < 14 - arg - end - - def _racc_init_sysvars - @racc_state = [0] - @racc_tstack = [] - @racc_vstack = [] - - @racc_t = nil - @racc_val = nil - - @racc_read_next = true - - @racc_user_yyerror = false - @racc_error_status = 0 - end - - ### - ### do_parse - ### - - def do_parse - __send__(Racc_Main_Parsing_Routine, _racc_setup(), false) - end - - def next_token - raise NotImplementedError, "#{self.class}\#next_token is not defined" - end - - def _racc_do_parse_rb(arg, in_debug) - action_table, action_check, action_default, action_pointer, - goto_table, goto_check, goto_default, goto_pointer, - nt_base, reduce_table, token_table, shift_n, - reduce_n, use_result, * = arg - - _racc_init_sysvars - tok = act = i = nil - nerr = 0 - - catch(:racc_end_parse) { - while true - if i = action_pointer[@racc_state[-1]] - if @racc_read_next - if @racc_t != 0 # not EOF - tok, @racc_val = next_token() - unless tok # EOF - @racc_t = 0 - else - @racc_t = (token_table[tok] or 1) # error token - end - racc_read_token(@racc_t, tok, @racc_val) if @yydebug - @racc_read_next = false - end - end - i += @racc_t - unless i >= 0 and - act = action_table[i] and - action_check[i] == @racc_state[-1] - act = action_default[@racc_state[-1]] - end - else - act = action_default[@racc_state[-1]] - end - while act = _racc_evalact(act, arg) - ; - end - end - } - end - - ### - ### yyparse - ### - - def yyparse(recv, mid) - __send__(Racc_YY_Parse_Method, recv, mid, _racc_setup(), true) - end - - def _racc_yyparse_rb(recv, mid, arg, c_debug) - action_table, action_check, action_default, action_pointer, - goto_table, goto_check, goto_default, goto_pointer, - nt_base, reduce_table, token_table, shift_n, - reduce_n, use_result, * = arg - - _racc_init_sysvars - tok = nil - act = nil - i = nil - nerr = 0 - - catch(:racc_end_parse) { - until i = action_pointer[@racc_state[-1]] - while act = _racc_evalact(action_default[@racc_state[-1]], arg) - ; - end - end - recv.__send__(mid) do |tok, val| - unless tok - @racc_t = 0 - else - @racc_t = (token_table[tok] or 1) # error token - end - @racc_val = val - @racc_read_next = false - - i += @racc_t - unless i >= 0 and - act = action_table[i] and - action_check[i] == @racc_state[-1] - act = action_default[@racc_state[-1]] - end - while act = _racc_evalact(act, arg) - ; - end - - while not (i = action_pointer[@racc_state[-1]]) or - not @racc_read_next or - @racc_t == 0 # $ - unless i and i += @racc_t and - i >= 0 and - act = action_table[i] and - action_check[i] == @racc_state[-1] - act = action_default[@racc_state[-1]] - end - while act = _racc_evalact(act, arg) - ; - end - end - end - } - end - - ### - ### common - ### - - def _racc_evalact(act, arg) - action_table, action_check, action_default, action_pointer, - goto_table, goto_check, goto_default, goto_pointer, - nt_base, reduce_table, token_table, shift_n, - reduce_n, use_result, * = arg - nerr = 0 # tmp - - if act > 0 and act < shift_n - # - # shift - # - if @racc_error_status > 0 - @racc_error_status -= 1 unless @racc_t == 1 # error token - end - @racc_vstack.push @racc_val - @racc_state.push act - @racc_read_next = true - if @yydebug - @racc_tstack.push @racc_t - racc_shift @racc_t, @racc_tstack, @racc_vstack - end - - elsif act < 0 and act > -reduce_n - # - # reduce - # - code = catch(:racc_jump) { - @racc_state.push _racc_do_reduce(arg, act) - false - } - if code - case code - when 1 # yyerror - @racc_user_yyerror = true # user_yyerror - return -reduce_n - when 2 # yyaccept - return shift_n - else - raise '[Racc Bug] unknown jump code' - end - end - - elsif act == shift_n - # - # accept - # - racc_accept if @yydebug - throw :racc_end_parse, @racc_vstack[0] - - elsif act == -reduce_n - # - # error - # - case @racc_error_status - when 0 - unless arg[21] # user_yyerror - nerr += 1 - on_error @racc_t, @racc_val, @racc_vstack - end - when 3 - if @racc_t == 0 # is $ - throw :racc_end_parse, nil - end - @racc_read_next = true - end - @racc_user_yyerror = false - @racc_error_status = 3 - while true - if i = action_pointer[@racc_state[-1]] - i += 1 # error token - if i >= 0 and - (act = action_table[i]) and - action_check[i] == @racc_state[-1] - break - end - end - throw :racc_end_parse, nil if @racc_state.size <= 1 - @racc_state.pop - @racc_vstack.pop - if @yydebug - @racc_tstack.pop - racc_e_pop @racc_state, @racc_tstack, @racc_vstack - end - end - return act - - else - raise "[Racc Bug] unknown action #{act.inspect}" - end - - racc_next_state(@racc_state[-1], @racc_state) if @yydebug - - nil - end - - def _racc_do_reduce(arg, act) - action_table, action_check, action_default, action_pointer, - goto_table, goto_check, goto_default, goto_pointer, - nt_base, reduce_table, token_table, shift_n, - reduce_n, use_result, * = arg - state = @racc_state - vstack = @racc_vstack - tstack = @racc_tstack - - i = act * -3 - len = reduce_table[i] - reduce_to = reduce_table[i+1] - method_id = reduce_table[i+2] - void_array = [] - - tmp_t = tstack[-len, len] if @yydebug - tmp_v = vstack[-len, len] - tstack[-len, len] = void_array if @yydebug - vstack[-len, len] = void_array - state[-len, len] = void_array - - # tstack must be updated AFTER method call - if use_result - vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0]) - else - vstack.push __send__(method_id, tmp_v, vstack) - end - tstack.push reduce_to - - racc_reduce(tmp_t, reduce_to, tstack, vstack) if @yydebug - - k1 = reduce_to - nt_base - if i = goto_pointer[k1] - i += state[-1] - if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1 - return curstate - end - end - goto_default[k1] - end - - def on_error(t, val, vstack) - raise ParseError, sprintf("\nparse error on value %s (%s)", - val.inspect, token_to_str(t) || '?') - end - - def yyerror - throw :racc_jump, 1 - end - - def yyaccept - throw :racc_jump, 2 - end - - def yyerrok - @racc_error_status = 0 - end - - # - # for debugging output - # - - def racc_read_token(t, tok, val) - @racc_debug_out.print 'read ' - @racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') ' - @racc_debug_out.puts val.inspect - @racc_debug_out.puts - end - - def racc_shift(tok, tstack, vstack) - @racc_debug_out.puts "shift #{racc_token2str tok}" - racc_print_stacks tstack, vstack - @racc_debug_out.puts - end - - def racc_reduce(toks, sim, tstack, vstack) - out = @racc_debug_out - out.print 'reduce ' - if toks.empty? - out.print ' ' - else - toks.each {|t| out.print ' ', racc_token2str(t) } - end - out.puts " --> #{racc_token2str(sim)}" - - racc_print_stacks tstack, vstack - @racc_debug_out.puts - end - - def racc_accept - @racc_debug_out.puts 'accept' - @racc_debug_out.puts - end - - def racc_e_pop(state, tstack, vstack) - @racc_debug_out.puts 'error recovering mode: pop token' - racc_print_states state - racc_print_stacks tstack, vstack - @racc_debug_out.puts - end - - def racc_next_state(curstate, state) - @racc_debug_out.puts "goto #{curstate}" - racc_print_states state - @racc_debug_out.puts - end - - def racc_print_stacks(t, v) - out = @racc_debug_out - out.print ' [' - t.each_index do |i| - out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')' - end - out.puts ' ]' - end - - def racc_print_states(s) - out = @racc_debug_out - out.print ' [' - s.each {|st| out.print ' ', st } - out.puts ' ]' - end - - def racc_token2str(tok) - self.class::Racc_token_to_s_table[tok] or - raise "[Racc Bug] can't convert token #{tok} to string" - end - - def token_to_str(t) - self.class::Racc_token_to_s_table[t] - end - - end - -end -..end racc/parser.rb modeval..id8076474214 -end -###### racc/parser.rb end - - -# -# parser.rb -# -# Copyright (c) 1998-2007 Minero Aoki -# -# This program is free software. -# You can distribute/modify this program under the terms of -# the GNU Lesser General Public License version 2.1. -# - -require 'tmail/scanner' -require 'tmail/utils' - - -module TMail - - class Parser < Racc::Parser - -module_eval <<'..end parser.y modeval..id7b0b3dccb7', 'parser.y', 340 - - include TextUtils - - def self.parse( ident, str, cmt = nil ) - new.parse(ident, str, cmt) - end - - MAILP_DEBUG = false - - def initialize - self.debug = MAILP_DEBUG - end - - def debug=( flag ) - @yydebug = flag && Racc_debug_parser - @scanner_debug = flag - end - - def debug - @yydebug - end - - def parse( ident, str, comments = nil ) - @scanner = Scanner.new(str, ident, comments) - @scanner.debug = @scanner_debug - @first = [ident, ident] - result = yyparse(self, :parse_in) - comments.map! {|c| to_kcode(c) } if comments - result - end - - private - - def parse_in( &block ) - yield @first - @scanner.scan(&block) - end - - def on_error( t, val, vstack ) - raise SyntaxError, "parse error on token #{racc_token2str t}" - end - -..end parser.y modeval..id7b0b3dccb7 - -##### racc 1.4.5 generates ### - -racc_reduce_table = [ - 0, 0, :racc_error, - 2, 35, :_reduce_1, - 2, 35, :_reduce_2, - 2, 35, :_reduce_3, - 2, 35, :_reduce_4, - 2, 35, :_reduce_5, - 2, 35, :_reduce_6, - 2, 35, :_reduce_7, - 2, 35, :_reduce_8, - 2, 35, :_reduce_9, - 2, 35, :_reduce_10, - 2, 35, :_reduce_11, - 2, 35, :_reduce_12, - 6, 36, :_reduce_13, - 0, 48, :_reduce_none, - 2, 48, :_reduce_none, - 3, 49, :_reduce_16, - 5, 49, :_reduce_17, - 1, 50, :_reduce_18, - 7, 37, :_reduce_19, - 0, 51, :_reduce_none, - 2, 51, :_reduce_21, - 0, 52, :_reduce_none, - 2, 52, :_reduce_23, - 1, 58, :_reduce_24, - 3, 58, :_reduce_25, - 2, 58, :_reduce_26, - 0, 53, :_reduce_none, - 2, 53, :_reduce_28, - 0, 54, :_reduce_29, - 3, 54, :_reduce_30, - 0, 55, :_reduce_none, - 2, 55, :_reduce_32, - 2, 55, :_reduce_33, - 0, 56, :_reduce_none, - 2, 56, :_reduce_35, - 1, 61, :_reduce_36, - 1, 61, :_reduce_37, - 0, 57, :_reduce_none, - 2, 57, :_reduce_39, - 1, 38, :_reduce_none, - 1, 38, :_reduce_none, - 3, 38, :_reduce_none, - 1, 46, :_reduce_none, - 1, 46, :_reduce_none, - 1, 46, :_reduce_none, - 1, 39, :_reduce_none, - 2, 39, :_reduce_47, - 1, 64, :_reduce_48, - 3, 64, :_reduce_49, - 1, 68, :_reduce_none, - 1, 68, :_reduce_none, - 1, 69, :_reduce_52, - 3, 69, :_reduce_53, - 1, 47, :_reduce_none, - 1, 47, :_reduce_none, - 2, 47, :_reduce_56, - 2, 67, :_reduce_none, - 3, 65, :_reduce_58, - 2, 65, :_reduce_59, - 1, 70, :_reduce_60, - 2, 70, :_reduce_61, - 4, 62, :_reduce_62, - 3, 62, :_reduce_63, - 2, 72, :_reduce_none, - 2, 73, :_reduce_65, - 4, 73, :_reduce_66, - 3, 63, :_reduce_67, - 1, 63, :_reduce_68, - 1, 74, :_reduce_none, - 2, 74, :_reduce_70, - 1, 71, :_reduce_71, - 3, 71, :_reduce_72, - 1, 59, :_reduce_73, - 3, 59, :_reduce_74, - 1, 76, :_reduce_75, - 2, 76, :_reduce_76, - 1, 75, :_reduce_none, - 1, 75, :_reduce_none, - 1, 75, :_reduce_none, - 1, 77, :_reduce_none, - 1, 77, :_reduce_none, - 1, 77, :_reduce_none, - 1, 66, :_reduce_none, - 2, 66, :_reduce_none, - 3, 60, :_reduce_85, - 1, 40, :_reduce_86, - 3, 40, :_reduce_87, - 1, 79, :_reduce_none, - 2, 79, :_reduce_89, - 1, 41, :_reduce_90, - 2, 41, :_reduce_91, - 3, 42, :_reduce_92, - 5, 43, :_reduce_93, - 3, 43, :_reduce_94, - 0, 80, :_reduce_95, - 5, 80, :_reduce_96, - 5, 80, :_reduce_97, - 1, 44, :_reduce_98, - 3, 45, :_reduce_99, - 0, 81, :_reduce_none, - 1, 81, :_reduce_none, - 1, 78, :_reduce_none, - 1, 78, :_reduce_none, - 1, 78, :_reduce_none, - 1, 78, :_reduce_none, - 1, 78, :_reduce_none, - 1, 78, :_reduce_none, - 1, 78, :_reduce_none ] - -racc_reduce_n = 109 - -racc_shift_n = 167 - -racc_action_table = [ - -70, -69, 23, 25, 145, 146, 29, 31, 105, 106, - 16, 17, 20, 22, 136, 27, -70, -69, 32, 101, - -70, -69, 153, 100, 113, 115, -70, -69, -70, 109, - 75, 23, 25, 101, 154, 29, 31, 142, 143, 16, - 17, 20, 22, 107, 27, 23, 25, 32, 98, 29, - 31, 96, 94, 16, 17, 20, 22, 78, 27, 23, - 25, 32, 112, 29, 31, 74, 91, 16, 17, 20, - 22, 88, 117, 92, 81, 32, 23, 25, 80, 123, - 29, 31, 100, 125, 16, 17, 20, 22, 126, 23, - 25, 109, 32, 29, 31, 91, 128, 16, 17, 20, - 22, 129, 27, 23, 25, 32, 101, 29, 31, 101, - 130, 16, 17, 20, 22, 79, 52, 23, 25, 32, - 78, 29, 31, 133, 78, 16, 17, 20, 22, 77, - 23, 25, 75, 32, 29, 31, 65, 62, 16, 17, - 20, 22, 139, 23, 25, 101, 32, 29, 31, 60, - 100, 16, 17, 20, 22, 44, 27, 101, 147, 32, - 23, 25, 120, 148, 29, 31, 151, 152, 16, 17, - 20, 22, 42, 27, 156, 158, 32, 23, 25, 120, - 40, 29, 31, 15, 163, 16, 17, 20, 22, 40, - 27, 23, 25, 32, 68, 29, 31, 165, 166, 16, - 17, 20, 22, nil, 27, 23, 25, 32, nil, 29, - 31, 74, nil, 16, 17, 20, 22, nil, 23, 25, - nil, 32, 29, 31, nil, nil, 16, 17, 20, 22, - nil, 23, 25, nil, 32, 29, 31, nil, nil, 16, - 17, 20, 22, nil, 23, 25, nil, 32, 29, 31, - nil, nil, 16, 17, 20, 22, nil, 23, 25, nil, - 32, 29, 31, nil, nil, 16, 17, 20, 22, nil, - 27, 23, 25, 32, nil, 29, 31, nil, nil, 16, - 17, 20, 22, nil, 23, 25, nil, 32, 29, 31, - nil, nil, 16, 17, 20, 22, nil, 23, 25, nil, - 32, 29, 31, nil, nil, 16, 17, 20, 22, nil, - 84, 25, nil, 32, 29, 31, nil, 87, 16, 17, - 20, 22, 4, 6, 7, 8, 9, 10, 11, 12, - 13, 1, 2, 3, 84, 25, nil, nil, 29, 31, - nil, 87, 16, 17, 20, 22, 84, 25, nil, nil, - 29, 31, nil, 87, 16, 17, 20, 22, 84, 25, - nil, nil, 29, 31, nil, 87, 16, 17, 20, 22, - 84, 25, nil, nil, 29, 31, nil, 87, 16, 17, - 20, 22, 84, 25, nil, nil, 29, 31, nil, 87, - 16, 17, 20, 22, 84, 25, nil, nil, 29, 31, - nil, 87, 16, 17, 20, 22 ] - -racc_action_check = [ - 75, 28, 68, 68, 136, 136, 68, 68, 72, 72, - 68, 68, 68, 68, 126, 68, 75, 28, 68, 67, - 75, 28, 143, 66, 86, 86, 75, 28, 75, 75, - 28, 3, 3, 86, 143, 3, 3, 134, 134, 3, - 3, 3, 3, 73, 3, 151, 151, 3, 62, 151, - 151, 60, 56, 151, 151, 151, 151, 51, 151, 52, - 52, 151, 80, 52, 52, 52, 50, 52, 52, 52, - 52, 45, 89, 52, 42, 52, 71, 71, 41, 96, - 71, 71, 97, 98, 71, 71, 71, 71, 100, 7, - 7, 101, 71, 7, 7, 102, 104, 7, 7, 7, - 7, 105, 7, 8, 8, 7, 108, 8, 8, 111, - 112, 8, 8, 8, 8, 40, 8, 9, 9, 8, - 36, 9, 9, 117, 121, 9, 9, 9, 9, 33, - 10, 10, 70, 9, 10, 10, 13, 12, 10, 10, - 10, 10, 130, 2, 2, 131, 10, 2, 2, 11, - 135, 2, 2, 2, 2, 6, 2, 138, 139, 2, - 90, 90, 90, 140, 90, 90, 141, 142, 90, 90, - 90, 90, 5, 90, 147, 150, 90, 127, 127, 127, - 4, 127, 127, 1, 156, 127, 127, 127, 127, 158, - 127, 26, 26, 127, 26, 26, 26, 162, 163, 26, - 26, 26, 26, nil, 26, 27, 27, 26, nil, 27, - 27, 27, nil, 27, 27, 27, 27, nil, 154, 154, - nil, 27, 154, 154, nil, nil, 154, 154, 154, 154, - nil, 122, 122, nil, 154, 122, 122, nil, nil, 122, - 122, 122, 122, nil, 76, 76, nil, 122, 76, 76, - nil, nil, 76, 76, 76, 76, nil, 38, 38, nil, - 76, 38, 38, nil, nil, 38, 38, 38, 38, nil, - 38, 55, 55, 38, nil, 55, 55, nil, nil, 55, - 55, 55, 55, nil, 94, 94, nil, 55, 94, 94, - nil, nil, 94, 94, 94, 94, nil, 59, 59, nil, - 94, 59, 59, nil, nil, 59, 59, 59, 59, nil, - 114, 114, nil, 59, 114, 114, nil, 114, 114, 114, - 114, 114, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 77, 77, nil, nil, 77, 77, - nil, 77, 77, 77, 77, 77, 44, 44, nil, nil, - 44, 44, nil, 44, 44, 44, 44, 44, 113, 113, - nil, nil, 113, 113, nil, 113, 113, 113, 113, 113, - 88, 88, nil, nil, 88, 88, nil, 88, 88, 88, - 88, 88, 74, 74, nil, nil, 74, 74, nil, 74, - 74, 74, 74, 74, 129, 129, nil, nil, 129, 129, - nil, 129, 129, 129, 129, 129 ] - -racc_action_pointer = [ - 320, 152, 129, 17, 165, 172, 137, 75, 89, 103, - 116, 135, 106, 105, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, 177, 191, 1, nil, - nil, nil, nil, 109, nil, nil, 94, nil, 243, nil, - 99, 64, 74, nil, 332, 52, nil, nil, nil, nil, - 50, 31, 45, nil, nil, 257, 36, nil, nil, 283, - 22, nil, 16, nil, nil, nil, -3, -10, -12, nil, - 103, 62, -8, 15, 368, 0, 230, 320, nil, nil, - 47, nil, nil, nil, nil, nil, 4, nil, 356, 50, - 146, nil, nil, nil, 270, nil, 65, 56, 52, nil, - 57, 62, 79, nil, 68, 81, nil, nil, 77, nil, - nil, 80, 96, 344, 296, nil, nil, 108, nil, nil, - nil, 98, 217, nil, nil, nil, -19, 163, nil, 380, - 128, 116, nil, nil, 14, 124, -26, nil, 128, 141, - 148, 141, 152, 7, nil, nil, nil, 160, nil, nil, - 149, 31, nil, nil, 204, nil, 167, nil, 174, nil, - nil, nil, 169, 184, nil, nil, nil ] - -racc_action_default = [ - -109, -109, -109, -109, -14, -109, -20, -109, -109, -109, - -109, -109, -109, -109, -10, -95, -105, -106, -77, -44, - -107, -11, -108, -79, -43, -102, -109, -109, -60, -103, - -55, -104, -78, -68, -54, -71, -45, -12, -109, -1, - -109, -109, -109, -2, -109, -22, -51, -48, -50, -3, - -40, -41, -109, -46, -4, -86, -5, -88, -6, -90, - -109, -7, -95, -8, -9, -98, -100, -61, -59, -56, - -69, -109, -109, -109, -109, -75, -109, -109, -57, -15, - -109, 167, -73, -80, -82, -21, -24, -81, -109, -27, - -109, -83, -47, -89, -109, -91, -109, -100, -109, -99, - -101, -75, -58, -52, -109, -109, -64, -63, -65, -76, - -72, -67, -109, -109, -109, -26, -23, -109, -29, -49, - -84, -42, -87, -92, -94, -95, -109, -109, -62, -109, - -109, -25, -74, -28, -31, -100, -109, -53, -66, -109, - -109, -34, -109, -109, -93, -96, -97, -109, -18, -13, - -38, -109, -30, -33, -109, -32, -16, -19, -14, -35, - -36, -37, -109, -109, -39, -85, -17 ] - -racc_goto_table = [ - 39, 67, 70, 73, 38, 66, 69, 24, 37, 57, - 59, 36, 55, 67, 99, 90, 85, 157, 69, 108, - 83, 134, 111, 76, 49, 53, 141, 70, 73, 150, - 118, 89, 45, 155, 159, 149, 140, 21, 14, 19, - 119, 102, 64, 63, 61, 124, 70, 104, 58, 132, - 83, 56, 97, 83, 54, 93, 43, 5, 131, 95, - 116, nil, 76, nil, 83, 76, nil, 127, nil, 38, - nil, nil, nil, 103, 138, nil, 110, nil, nil, nil, - nil, nil, nil, 144, nil, nil, nil, nil, nil, 83, - 83, nil, nil, nil, 57, nil, nil, 122, nil, 121, - nil, nil, nil, nil, nil, 83, nil, nil, nil, nil, - nil, nil, nil, nil, nil, 135, nil, nil, nil, nil, - nil, nil, 93, nil, nil, nil, 70, 161, 38, 70, - 162, 160, 137, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, 164 ] - -racc_goto_check = [ - 2, 37, 37, 29, 36, 46, 28, 13, 13, 41, - 41, 31, 45, 37, 47, 32, 24, 23, 28, 25, - 44, 20, 25, 42, 4, 4, 21, 37, 29, 22, - 19, 18, 17, 26, 27, 16, 15, 12, 11, 33, - 34, 35, 10, 9, 8, 47, 37, 29, 7, 43, - 44, 6, 46, 44, 5, 41, 3, 1, 25, 41, - 24, nil, 42, nil, 44, 42, nil, 32, nil, 36, - nil, nil, nil, 13, 25, nil, 41, nil, nil, nil, - nil, nil, nil, 47, nil, nil, nil, nil, nil, 44, - 44, nil, nil, nil, 41, nil, nil, 45, nil, 31, - nil, nil, nil, nil, nil, 44, nil, nil, nil, nil, - nil, nil, nil, nil, nil, 46, nil, nil, nil, nil, - nil, nil, 41, nil, nil, nil, 37, 29, 36, 37, - 29, 28, 13, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, 2 ] - -racc_goto_pointer = [ - nil, 57, -4, 50, 17, 46, 42, 38, 33, 31, - 29, 37, 35, 5, nil, -94, -105, 26, -14, -59, - -97, -108, -112, -133, -28, -55, -110, -117, -20, -24, - nil, 9, -35, 37, -50, -27, 1, -25, nil, nil, - nil, 0, -5, -65, -24, 3, -10, -52 ] - -racc_goto_default = [ - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, 48, 41, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, 86, nil, nil, 30, 34, - 50, 51, nil, 46, 47, nil, 26, 28, 71, 72, - 33, 35, 114, 82, 18, nil, nil, nil ] - -racc_token_table = { - false => 0, - Object.new => 1, - :DATETIME => 2, - :RECEIVED => 3, - :MADDRESS => 4, - :RETPATH => 5, - :KEYWORDS => 6, - :ENCRYPTED => 7, - :MIMEVERSION => 8, - :CTYPE => 9, - :CENCODING => 10, - :CDISPOSITION => 11, - :ADDRESS => 12, - :MAILBOX => 13, - :DIGIT => 14, - :ATOM => 15, - "," => 16, - ":" => 17, - :FROM => 18, - :BY => 19, - "@" => 20, - :DOMLIT => 21, - :VIA => 22, - :WITH => 23, - :ID => 24, - :FOR => 25, - ";" => 26, - "<" => 27, - ">" => 28, - "." => 29, - :QUOTED => 30, - :TOKEN => 31, - "/" => 32, - "=" => 33 } - -racc_use_result_var = false - -racc_nt_base = 34 - -Racc_arg = [ - racc_action_table, - racc_action_check, - racc_action_default, - racc_action_pointer, - racc_goto_table, - racc_goto_check, - racc_goto_default, - racc_goto_pointer, - racc_nt_base, - racc_reduce_table, - racc_token_table, - racc_shift_n, - racc_reduce_n, - racc_use_result_var ] - -Racc_token_to_s_table = [ -'$end', -'error', -'DATETIME', -'RECEIVED', -'MADDRESS', -'RETPATH', -'KEYWORDS', -'ENCRYPTED', -'MIMEVERSION', -'CTYPE', -'CENCODING', -'CDISPOSITION', -'ADDRESS', -'MAILBOX', -'DIGIT', -'ATOM', -'","', -'":"', -'FROM', -'BY', -'"@"', -'DOMLIT', -'VIA', -'WITH', -'ID', -'FOR', -'";"', -'"<"', -'">"', -'"."', -'QUOTED', -'TOKEN', -'"/"', -'"="', -'$start', -'content', -'datetime', -'received', -'addrs_TOP', -'retpath', -'keys', -'enc', -'version', -'ctype', -'cencode', -'cdisp', -'addr_TOP', -'mbox', -'day', -'hour', -'zone', -'from', -'by', -'via', -'with', -'id', -'for', -'received_datetime', -'received_domain', -'domain', -'msgid', -'received_addrspec', -'routeaddr', -'spec', -'addrs', -'group_bare', -'commas', -'group', -'addr', -'mboxes', -'addr_phrase', -'local_head', -'routes', -'at_domains', -'local', -'word', -'dots', -'domword', -'atom', -'phrase', -'params', -'opt_semicolon'] - -Racc_debug_parser = false - -##### racc system variables end ##### - - # reduce 0 omitted - -module_eval <<'.,.,', 'parser.y', 16 - def _reduce_1( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 17 - def _reduce_2( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 18 - def _reduce_3( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 19 - def _reduce_4( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 20 - def _reduce_5( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 21 - def _reduce_6( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 22 - def _reduce_7( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 23 - def _reduce_8( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 24 - def _reduce_9( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 25 - def _reduce_10( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 26 - def _reduce_11( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 27 - def _reduce_12( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 36 - def _reduce_13( val, _values) - t = Time.gm(val[3].to_i, val[2], val[1].to_i, 0, 0, 0) - (t + val[4] - val[5]).localtime - end -.,., - - # reduce 14 omitted - - # reduce 15 omitted - -module_eval <<'.,.,', 'parser.y', 45 - def _reduce_16( val, _values) - (val[0].to_i * 60 * 60) + - (val[2].to_i * 60) - end -.,., - -module_eval <<'.,.,', 'parser.y', 51 - def _reduce_17( val, _values) - (val[0].to_i * 60 * 60) + - (val[2].to_i * 60) + - (val[4].to_i) - end -.,., - -module_eval <<'.,.,', 'parser.y', 56 - def _reduce_18( val, _values) - timezone_string_to_unixtime(val[0]) - end -.,., - -module_eval <<'.,.,', 'parser.y', 61 - def _reduce_19( val, _values) - val - end -.,., - - # reduce 20 omitted - -module_eval <<'.,.,', 'parser.y', 67 - def _reduce_21( val, _values) - val[1] - end -.,., - - # reduce 22 omitted - -module_eval <<'.,.,', 'parser.y', 73 - def _reduce_23( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 79 - def _reduce_24( val, _values) - join_domain(val[0]) - end -.,., - -module_eval <<'.,.,', 'parser.y', 83 - def _reduce_25( val, _values) - join_domain(val[2]) - end -.,., - -module_eval <<'.,.,', 'parser.y', 87 - def _reduce_26( val, _values) - join_domain(val[0]) - end -.,., - - # reduce 27 omitted - -module_eval <<'.,.,', 'parser.y', 93 - def _reduce_28( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 98 - def _reduce_29( val, _values) - [] - end -.,., - -module_eval <<'.,.,', 'parser.y', 103 - def _reduce_30( val, _values) - val[0].push val[2] - val[0] - end -.,., - - # reduce 31 omitted - -module_eval <<'.,.,', 'parser.y', 109 - def _reduce_32( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 113 - def _reduce_33( val, _values) - val[1] - end -.,., - - # reduce 34 omitted - -module_eval <<'.,.,', 'parser.y', 119 - def _reduce_35( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 125 - def _reduce_36( val, _values) - val[0].spec - end -.,., - -module_eval <<'.,.,', 'parser.y', 129 - def _reduce_37( val, _values) - val[0].spec - end -.,., - - # reduce 38 omitted - -module_eval <<'.,.,', 'parser.y', 136 - def _reduce_39( val, _values) - val[1] - end -.,., - - # reduce 40 omitted - - # reduce 41 omitted - - # reduce 42 omitted - - # reduce 43 omitted - - # reduce 44 omitted - - # reduce 45 omitted - - # reduce 46 omitted - -module_eval <<'.,.,', 'parser.y', 146 - def _reduce_47( val, _values) - [ Address.new(nil, nil) ] - end -.,., - -module_eval <<'.,.,', 'parser.y', 152 - def _reduce_48( val, _values) - val - end -.,., - -module_eval <<'.,.,', 'parser.y', 157 - def _reduce_49( val, _values) - val[0].push val[2] - val[0] - end -.,., - - # reduce 50 omitted - - # reduce 51 omitted - -module_eval <<'.,.,', 'parser.y', 165 - def _reduce_52( val, _values) - val - end -.,., - -module_eval <<'.,.,', 'parser.y', 170 - def _reduce_53( val, _values) - val[0].push val[2] - val[0] - end -.,., - - # reduce 54 omitted - - # reduce 55 omitted - -module_eval <<'.,.,', 'parser.y', 178 - def _reduce_56( val, _values) - val[1].phrase = Decoder.decode(val[0]) - val[1] - end -.,., - - # reduce 57 omitted - -module_eval <<'.,.,', 'parser.y', 185 - def _reduce_58( val, _values) - AddressGroup.new(val[0], val[2]) - end -.,., - -module_eval <<'.,.,', 'parser.y', 185 - def _reduce_59( val, _values) - AddressGroup.new(val[0], []) - end -.,., - -module_eval <<'.,.,', 'parser.y', 188 - def _reduce_60( val, _values) - val[0].join('.') - end -.,., - -module_eval <<'.,.,', 'parser.y', 189 - def _reduce_61( val, _values) - val[0] << ' ' << val[1].join('.') - end -.,., - -module_eval <<'.,.,', 'parser.y', 196 - def _reduce_62( val, _values) - val[2].routes.replace val[1] - val[2] - end -.,., - -module_eval <<'.,.,', 'parser.y', 200 - def _reduce_63( val, _values) - val[1] - end -.,., - - # reduce 64 omitted - -module_eval <<'.,.,', 'parser.y', 203 - def _reduce_65( val, _values) - [ val[1].join('.') ] - end -.,., - -module_eval <<'.,.,', 'parser.y', 204 - def _reduce_66( val, _values) - val[0].push val[3].join('.'); val[0] - end -.,., - -module_eval <<'.,.,', 'parser.y', 206 - def _reduce_67( val, _values) - Address.new( val[0], val[2] ) - end -.,., - -module_eval <<'.,.,', 'parser.y', 207 - def _reduce_68( val, _values) - Address.new( val[0], nil ) - end -.,., - - # reduce 69 omitted - -module_eval <<'.,.,', 'parser.y', 210 - def _reduce_70( val, _values) - val[0].push ''; val[0] - end -.,., - -module_eval <<'.,.,', 'parser.y', 213 - def _reduce_71( val, _values) - val - end -.,., - -module_eval <<'.,.,', 'parser.y', 222 - def _reduce_72( val, _values) - val[1].times do - val[0].push '' - end - val[0].push val[2] - val[0] - end -.,., - -module_eval <<'.,.,', 'parser.y', 224 - def _reduce_73( val, _values) - val - end -.,., - -module_eval <<'.,.,', 'parser.y', 233 - def _reduce_74( val, _values) - val[1].times do - val[0].push '' - end - val[0].push val[2] - val[0] - end -.,., - -module_eval <<'.,.,', 'parser.y', 234 - def _reduce_75( val, _values) - 0 - end -.,., - -module_eval <<'.,.,', 'parser.y', 235 - def _reduce_76( val, _values) - 1 - end -.,., - - # reduce 77 omitted - - # reduce 78 omitted - - # reduce 79 omitted - - # reduce 80 omitted - - # reduce 81 omitted - - # reduce 82 omitted - - # reduce 83 omitted - - # reduce 84 omitted - -module_eval <<'.,.,', 'parser.y', 253 - def _reduce_85( val, _values) - val[1] = val[1].spec - val.join('') - end -.,., - -module_eval <<'.,.,', 'parser.y', 254 - def _reduce_86( val, _values) - val - end -.,., - -module_eval <<'.,.,', 'parser.y', 255 - def _reduce_87( val, _values) - val[0].push val[2]; val[0] - end -.,., - - # reduce 88 omitted - -module_eval <<'.,.,', 'parser.y', 258 - def _reduce_89( val, _values) - val[0] << ' ' << val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 265 - def _reduce_90( val, _values) - val.push nil - val - end -.,., - -module_eval <<'.,.,', 'parser.y', 269 - def _reduce_91( val, _values) - val - end -.,., - -module_eval <<'.,.,', 'parser.y', 274 - def _reduce_92( val, _values) - [ val[0].to_i, val[2].to_i ] - end -.,., - -module_eval <<'.,.,', 'parser.y', 279 - def _reduce_93( val, _values) - [ val[0].downcase, val[2].downcase, decode_params(val[3]) ] - end -.,., - -module_eval <<'.,.,', 'parser.y', 283 - def _reduce_94( val, _values) - [ val[0].downcase, nil, decode_params(val[1]) ] - end -.,., - -module_eval <<'.,.,', 'parser.y', 288 - def _reduce_95( val, _values) - {} - end -.,., - -module_eval <<'.,.,', 'parser.y', 293 - def _reduce_96( val, _values) - val[0][ val[2].downcase ] = ('"' + val[4].to_s + '"') - val[0] - end -.,., - -module_eval <<'.,.,', 'parser.y', 298 - def _reduce_97( val, _values) - val[0][ val[2].downcase ] = val[4] - val[0] - end -.,., - -module_eval <<'.,.,', 'parser.y', 303 - def _reduce_98( val, _values) - val[0].downcase - end -.,., - -module_eval <<'.,.,', 'parser.y', 308 - def _reduce_99( val, _values) - [ val[0].downcase, decode_params(val[1]) ] - end -.,., - - # reduce 100 omitted - - # reduce 101 omitted - - # reduce 102 omitted - - # reduce 103 omitted - - # reduce 104 omitted - - # reduce 105 omitted - - # reduce 106 omitted - - # reduce 107 omitted - - # reduce 108 omitted - - def _reduce_none( val, _values) - val[0] - end - - end # class Parser - -end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/port.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/port.rb deleted file mode 100644 index 445f0e632b..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/port.rb +++ /dev/null @@ -1,379 +0,0 @@ -=begin rdoc - -= Port class - -=end -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# 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. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -require 'tmail/stringio' - - -module TMail - - class Port - def reproducible? - false - end - end - - - ### - ### FilePort - ### - - class FilePort < Port - - def initialize( fname ) - @filename = File.expand_path(fname) - super() - end - - attr_reader :filename - - alias ident filename - - def ==( other ) - other.respond_to?(:filename) and @filename == other.filename - end - - alias eql? == - - def hash - @filename.hash - end - - def inspect - "#<#{self.class}:#{@filename}>" - end - - def reproducible? - true - end - - def size - File.size @filename - end - - - def ropen( &block ) - File.open(@filename, &block) - end - - def wopen( &block ) - File.open(@filename, 'w', &block) - end - - def aopen( &block ) - File.open(@filename, 'a', &block) - end - - - def read_all - ropen {|f| - return f.read - } - end - - - def remove - File.unlink @filename - end - - def move_to( port ) - begin - File.link @filename, port.filename - rescue Errno::EXDEV - copy_to port - end - File.unlink @filename - end - - alias mv move_to - - def copy_to( port ) - if FilePort === port - copy_file @filename, port.filename - else - File.open(@filename) {|r| - port.wopen {|w| - while s = r.sysread(4096) - w.write << s - end - } } - end - end - - alias cp copy_to - - private - - # from fileutils.rb - def copy_file( src, dest ) - st = r = w = nil - - File.open(src, 'rb') {|r| - File.open(dest, 'wb') {|w| - st = r.stat - begin - while true - w.write r.sysread(st.blksize) - end - rescue EOFError - end - } } - end - - end - - - module MailFlags - - def seen=( b ) - set_status 'S', b - end - - def seen? - get_status 'S' - end - - def replied=( b ) - set_status 'R', b - end - - def replied? - get_status 'R' - end - - def flagged=( b ) - set_status 'F', b - end - - def flagged? - get_status 'F' - end - - private - - def procinfostr( str, tag, true_p ) - a = str.upcase.split(//) - a.push true_p ? tag : nil - a.delete tag unless true_p - a.compact.sort.join('').squeeze - end - - end - - - class MhPort < FilePort - - include MailFlags - - private - - def set_status( tag, flag ) - begin - tmpfile = @filename + '.tmailtmp.' + $$.to_s - File.open(tmpfile, 'w') {|f| - write_status f, tag, flag - } - File.unlink @filename - File.link tmpfile, @filename - ensure - File.unlink tmpfile - end - end - - def write_status( f, tag, flag ) - stat = '' - File.open(@filename) {|r| - while line = r.gets - if line.strip.empty? - break - elsif m = /\AX-TMail-Status:/i.match(line) - stat = m.post_match.strip - else - f.print line - end - end - - s = procinfostr(stat, tag, flag) - f.puts 'X-TMail-Status: ' + s unless s.empty? - f.puts - - while s = r.read(2048) - f.write s - end - } - end - - def get_status( tag ) - File.foreach(@filename) {|line| - return false if line.strip.empty? - if m = /\AX-TMail-Status:/i.match(line) - return m.post_match.strip.include?(tag[0]) - end - } - false - end - - end - - - class MaildirPort < FilePort - - def move_to_new - new = replace_dir(@filename, 'new') - File.rename @filename, new - @filename = new - end - - def move_to_cur - new = replace_dir(@filename, 'cur') - File.rename @filename, new - @filename = new - end - - def replace_dir( path, dir ) - "#{File.dirname File.dirname(path)}/#{dir}/#{File.basename path}" - end - private :replace_dir - - - include MailFlags - - private - - MAIL_FILE = /\A(\d+\.[\d_]+\.[^:]+)(?:\:(\d),(\w+)?)?\z/ - - def set_status( tag, flag ) - if m = MAIL_FILE.match(File.basename(@filename)) - s, uniq, type, info, = m.to_a - return if type and type != '2' # do not change anything - newname = File.dirname(@filename) + '/' + - uniq + ':2,' + procinfostr(info.to_s, tag, flag) - else - newname = @filename + ':2,' + tag - end - - File.link @filename, newname - File.unlink @filename - @filename = newname - end - - def get_status( tag ) - m = MAIL_FILE.match(File.basename(@filename)) or return false - m[2] == '2' and m[3].to_s.include?(tag[0]) - end - - end - - - ### - ### StringPort - ### - - class StringPort < Port - - def initialize( str = '' ) - @buffer = str - super() - end - - def string - @buffer - end - - def to_s - @buffer.dup - end - - alias read_all to_s - - def size - @buffer.size - end - - def ==( other ) - StringPort === other and @buffer.equal? other.string - end - - alias eql? == - - def hash - @buffer.object_id.hash - end - - def inspect - "#<#{self.class}:id=#{sprintf '0x%x', @buffer.object_id}>" - end - - def reproducible? - true - end - - def ropen( &block ) - @buffer or raise Errno::ENOENT, "#{inspect} is already removed" - StringInput.open(@buffer, &block) - end - - def wopen( &block ) - @buffer = '' - StringOutput.new(@buffer, &block) - end - - def aopen( &block ) - @buffer ||= '' - StringOutput.new(@buffer, &block) - end - - def remove - @buffer = nil - end - - alias rm remove - - def copy_to( port ) - port.wopen {|f| - f.write @buffer - } - end - - alias cp copy_to - - def move_to( port ) - if StringPort === port - str = @buffer - port.instance_eval { @buffer = str } - else - copy_to port - end - remove - end - - end - -end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/quoting.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/quoting.rb deleted file mode 100644 index cb9f4288f1..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/quoting.rb +++ /dev/null @@ -1,118 +0,0 @@ -=begin rdoc - -= Quoting methods - -=end -module TMail - class Mail - def subject(to_charset = 'utf-8') - Unquoter.unquote_and_convert_to(quoted_subject, to_charset) - end - - def unquoted_body(to_charset = 'utf-8') - from_charset = sub_header("content-type", "charset") - case (content_transfer_encoding || "7bit").downcase - when "quoted-printable" - # the default charset is set to iso-8859-1 instead of 'us-ascii'. - # This is needed as many mailer do not set the charset but send in ISO. This is only used if no charset is set. - if !from_charset.blank? && from_charset.downcase == 'us-ascii' - from_charset = 'iso-8859-1' - end - - Unquoter.unquote_quoted_printable_and_convert_to(quoted_body, - to_charset, from_charset, true) - when "base64" - Unquoter.unquote_base64_and_convert_to(quoted_body, to_charset, - from_charset) - when "7bit", "8bit" - Unquoter.convert_to(quoted_body, to_charset, from_charset) - when "binary" - quoted_body - else - quoted_body - end - end - - def body(to_charset = 'utf-8', &block) - attachment_presenter = block || Proc.new { |file_name| "Attachment: #{file_name}\n" } - - if multipart? - parts.collect { |part| - header = part["content-type"] - - if part.multipart? - part.body(to_charset, &attachment_presenter) - elsif header.nil? - "" - elsif !attachment?(part) - part.unquoted_body(to_charset) - else - attachment_presenter.call(header["name"] || "(unnamed)") - end - }.join - else - unquoted_body(to_charset) - end - end - end - - class Unquoter - class << self - def unquote_and_convert_to(text, to_charset, from_charset = "iso-8859-1", preserve_underscores=false) - return "" if text.nil? - text.gsub(/(.*?)(?:(?:=\?(.*?)\?(.)\?(.*?)\?=)|$)/) do - before = $1 - from_charset = $2 - quoting_method = $3 - text = $4 - - before = convert_to(before, to_charset, from_charset) if before.length > 0 - before + case quoting_method - when "q", "Q" then - unquote_quoted_printable_and_convert_to(text, to_charset, from_charset, preserve_underscores) - when "b", "B" then - unquote_base64_and_convert_to(text, to_charset, from_charset) - when nil then - # will be nil at the end of the string, due to the nature of - # the regex used. - "" - else - raise "unknown quoting method #{quoting_method.inspect}" - end - end - end - - def unquote_quoted_printable_and_convert_to(text, to, from, preserve_underscores=false) - text = text.gsub(/_/, " ") unless preserve_underscores - text = text.gsub(/\r\n|\r/, "\n") # normalize newlines - convert_to(text.unpack("M*").first, to, from) - end - - def unquote_base64_and_convert_to(text, to, from) - convert_to(Base64.decode(text), to, from) - end - - begin - require 'iconv' - def convert_to(text, to, from) - return text unless to && from - text ? Iconv.iconv(to, from, text).first : "" - rescue Iconv::IllegalSequence, Iconv::InvalidEncoding, Errno::EINVAL - # the 'from' parameter specifies a charset other than what the text - # actually is...not much we can do in this case but just return the - # unconverted text. - # - # Ditto if either parameter represents an unknown charset, like - # X-UNKNOWN. - text - end - rescue LoadError - # Not providing quoting support - def convert_to(text, to, from) - warn "Action Mailer: iconv not loaded; ignoring conversion from #{from} to #{to} (#{__FILE__}:#{__LINE__})" - text - end - end - end - end -end diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/require_arch.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/require_arch.rb deleted file mode 100644 index b4fffb8abb..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/require_arch.rb +++ /dev/null @@ -1,58 +0,0 @@ -#:stopdoc: -require 'rbconfig' - -# Attempts to require anative extension. -# Falls back to pure-ruby version, if it fails. -# -# This uses Config::CONFIG['arch'] from rbconfig. - -def require_arch(fname) - arch = Config::CONFIG['arch'] - begin - path = File.join("tmail", arch, fname) - require path - rescue LoadError => e - # try pre-built Windows binaries - if arch =~ /mswin/ - require File.join("tmail", 'mswin32', fname) - else - raise e - end - end -end - - -# def require_arch(fname) -# dext = Config::CONFIG['DLEXT'] -# begin -# if File.extname(fname) == dext -# path = fname -# else -# path = File.join("tmail","#{fname}.#{dext}") -# end -# require path -# rescue LoadError => e -# begin -# arch = Config::CONFIG['arch'] -# path = File.join("tmail", arch, "#{fname}.#{dext}") -# require path -# rescue LoadError -# case path -# when /i686/ -# path.sub!('i686', 'i586') -# when /i586/ -# path.sub!('i586', 'i486') -# when /i486/ -# path.sub!('i486', 'i386') -# else -# begin -# require fname + '.rb' -# rescue LoadError -# raise e -# end -# end -# retry -# end -# end -# end -#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner.rb deleted file mode 100644 index a5d01396b8..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner.rb +++ /dev/null @@ -1,49 +0,0 @@ -=begin rdoc - -= Scanner for TMail - -=end -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# 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. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ -#:stopdoc: -#require 'tmail/require_arch' -require 'tmail/utils' -require 'tmail/config' - -module TMail - # NOTE: It woiuld be nice if these two libs could boith be called "tmailscanner", and - # the native extension would have precedence. However RubyGems boffs that up b/c - # it does not gaurantee load_path order. - begin - raise LoadError, 'Turned off native extentions by user choice' if ENV['NORUBYEXT'] - require('tmail/tmailscanner') # c extension - Scanner = TMailScanner - rescue LoadError - require 'tmail/scanner_r' - Scanner = TMailScanner - end -end -#:stopdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner_r.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner_r.rb deleted file mode 100644 index f2075502d8..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner_r.rb +++ /dev/null @@ -1,261 +0,0 @@ -# scanner_r.rb -# -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# 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. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ -#:stopdoc: -require 'tmail/config' - -module TMail - - class TMailScanner - - Version = '1.2.3' - Version.freeze - - MIME_HEADERS = { - :CTYPE => true, - :CENCODING => true, - :CDISPOSITION => true - } - - alnum = 'a-zA-Z0-9' - atomsyms = %q[ _#!$%&`'*+-{|}~^/=? ].strip - tokensyms = %q[ _#!$%&`'*+-{|}~^@. ].strip - atomchars = alnum + Regexp.quote(atomsyms) - tokenchars = alnum + Regexp.quote(tokensyms) - iso2022str = '\e(?!\(B)..(?:[^\e]+|\e(?!\(B)..)*\e\(B' - - eucstr = "(?:[\xa1-\xfe][\xa1-\xfe])+" - sjisstr = "(?:[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc])+" - utf8str = "(?:[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf][\x80-\xbf])+" - - quoted_with_iso2022 = /\A(?:[^\\\e"]+|#{iso2022str})+/n - domlit_with_iso2022 = /\A(?:[^\\\e\]]+|#{iso2022str})+/n - comment_with_iso2022 = /\A(?:[^\\\e()]+|#{iso2022str})+/n - - quoted_without_iso2022 = /\A[^\\"]+/n - domlit_without_iso2022 = /\A[^\\\]]+/n - comment_without_iso2022 = /\A[^\\()]+/n - - PATTERN_TABLE = {} - PATTERN_TABLE['EUC'] = - [ - /\A(?:[#{atomchars}]+|#{iso2022str}|#{eucstr})+/n, - /\A(?:[#{tokenchars}]+|#{iso2022str}|#{eucstr})+/n, - quoted_with_iso2022, - domlit_with_iso2022, - comment_with_iso2022 - ] - PATTERN_TABLE['SJIS'] = - [ - /\A(?:[#{atomchars}]+|#{iso2022str}|#{sjisstr})+/n, - /\A(?:[#{tokenchars}]+|#{iso2022str}|#{sjisstr})+/n, - quoted_with_iso2022, - domlit_with_iso2022, - comment_with_iso2022 - ] - PATTERN_TABLE['UTF8'] = - [ - /\A(?:[#{atomchars}]+|#{utf8str})+/n, - /\A(?:[#{tokenchars}]+|#{utf8str})+/n, - quoted_without_iso2022, - domlit_without_iso2022, - comment_without_iso2022 - ] - PATTERN_TABLE['NONE'] = - [ - /\A[#{atomchars}]+/n, - /\A[#{tokenchars}]+/n, - quoted_without_iso2022, - domlit_without_iso2022, - comment_without_iso2022 - ] - - - def initialize( str, scantype, comments ) - init_scanner str - @comments = comments || [] - @debug = false - - # fix scanner mode - @received = (scantype == :RECEIVED) - @is_mime_header = MIME_HEADERS[scantype] - - atom, token, @quoted_re, @domlit_re, @comment_re = PATTERN_TABLE[TMail.KCODE] - @word_re = (MIME_HEADERS[scantype] ? token : atom) - end - - attr_accessor :debug - - def scan( &block ) - if @debug - scan_main do |arr| - s, v = arr - printf "%7d %-10s %s\n", - rest_size(), - s.respond_to?(:id2name) ? s.id2name : s.inspect, - v.inspect - yield arr - end - else - scan_main(&block) - end - end - - private - - RECV_TOKEN = { - 'from' => :FROM, - 'by' => :BY, - 'via' => :VIA, - 'with' => :WITH, - 'id' => :ID, - 'for' => :FOR - } - - def scan_main - until eof? - if skip(/\A[\n\r\t ]+/n) # LWSP - break if eof? - end - - if s = readstr(@word_re) - if @is_mime_header - yield [:TOKEN, s] - else - # atom - if /\A\d+\z/ === s - yield [:DIGIT, s] - elsif @received - yield [RECV_TOKEN[s.downcase] || :ATOM, s] - else - yield [:ATOM, s] - end - end - - elsif skip(/\A"/) - yield [:QUOTED, scan_quoted_word()] - - elsif skip(/\A\[/) - yield [:DOMLIT, scan_domain_literal()] - - elsif skip(/\A\(/) - @comments.push scan_comment() - - else - c = readchar() - yield [c, c] - end - end - - yield [false, '$'] - end - - def scan_quoted_word - scan_qstr(@quoted_re, /\A"/, 'quoted-word') - end - - def scan_domain_literal - '[' + scan_qstr(@domlit_re, /\A\]/, 'domain-literal') + ']' - end - - def scan_qstr( pattern, terminal, type ) - result = '' - until eof? - if s = readstr(pattern) then result << s - elsif skip(terminal) then return result - elsif skip(/\A\\/) then result << readchar() - else - raise "TMail FATAL: not match in #{type}" - end - end - scan_error! "found unterminated #{type}" - end - - def scan_comment - result = '' - nest = 1 - content = @comment_re - - until eof? - if s = readstr(content) then result << s - elsif skip(/\A\)/) then nest -= 1 - return result if nest == 0 - result << ')' - elsif skip(/\A\(/) then nest += 1 - result << '(' - elsif skip(/\A\\/) then result << readchar() - else - raise 'TMail FATAL: not match in comment' - end - end - scan_error! 'found unterminated comment' - end - - # string scanner - - def init_scanner( str ) - @src = str - end - - def eof? - @src.empty? - end - - def rest_size - @src.size - end - - def readstr( re ) - if m = re.match(@src) - @src = m.post_match - m[0] - else - nil - end - end - - def readchar - readstr(/\A./) - end - - def skip( re ) - if m = re.match(@src) - @src = m.post_match - true - else - false - end - end - - def scan_error!( msg ) - raise SyntaxError, msg - end - - end - -end # module TMail -#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/stringio.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/stringio.rb deleted file mode 100644 index 8357398788..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/stringio.rb +++ /dev/null @@ -1,280 +0,0 @@ -# encoding: utf-8 -=begin rdoc - -= String handling class - -=end -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# 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. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -class StringInput#:nodoc: - - include Enumerable - - class << self - - def new( str ) - if block_given? - begin - f = super - yield f - ensure - f.close if f - end - else - super - end - end - - alias open new - - end - - def initialize( str ) - @src = str - @pos = 0 - @closed = false - @lineno = 0 - end - - attr_reader :lineno - - def string - @src - end - - def inspect - "#<#{self.class}:#{@closed ? 'closed' : 'open'},src=#{@src[0,30].inspect}>" - end - - def close - stream_check! - @pos = nil - @closed = true - end - - def closed? - @closed - end - - def pos - stream_check! - [@pos, @src.size].min - end - - alias tell pos - - def seek( offset, whence = IO::SEEK_SET ) - stream_check! - case whence - when IO::SEEK_SET - @pos = offset - when IO::SEEK_CUR - @pos += offset - when IO::SEEK_END - @pos = @src.size - offset - else - raise ArgumentError, "unknown seek flag: #{whence}" - end - @pos = 0 if @pos < 0 - @pos = [@pos, @src.size + 1].min - offset - end - - def rewind - stream_check! - @pos = 0 - end - - def eof? - stream_check! - @pos > @src.size - end - - def each( &block ) - stream_check! - begin - @src.each(&block) - ensure - @pos = 0 - end - end - - def gets - stream_check! - if idx = @src.index(?\n, @pos) - idx += 1 # "\n".size - line = @src[ @pos ... idx ] - @pos = idx - @pos += 1 if @pos == @src.size - else - line = @src[ @pos .. -1 ] - @pos = @src.size + 1 - end - @lineno += 1 - - line - end - - def getc - stream_check! - ch = @src[@pos] - @pos += 1 - @pos += 1 if @pos == @src.size - ch - end - - def read( len = nil ) - stream_check! - return read_all unless len - str = @src[@pos, len] - @pos += len - @pos += 1 if @pos == @src.size - str - end - - alias sysread read - - def read_all - stream_check! - return nil if eof? - rest = @src[@pos ... @src.size] - @pos = @src.size + 1 - rest - end - - def stream_check! - @closed and raise IOError, 'closed stream' - end - -end - - -class StringOutput#:nodoc: - - class << self - - def new( str = '' ) - if block_given? - begin - f = super - yield f - ensure - f.close if f - end - else - super - end - end - - alias open new - - end - - def initialize( str = '' ) - @dest = str - @closed = false - end - - def close - @closed = true - end - - def closed? - @closed - end - - def string - @dest - end - - alias value string - alias to_str string - - def size - @dest.size - end - - alias pos size - - def inspect - "#<#{self.class}:#{@dest ? 'open' : 'closed'},#{object_id}>" - end - - def print( *args ) - stream_check! - raise ArgumentError, 'wrong # of argument (0 for >1)' if args.empty? - args.each do |s| - raise ArgumentError, 'nil not allowed' if s.nil? - @dest << s.to_s - end - nil - end - - def puts( *args ) - stream_check! - args.each do |str| - @dest << (s = str.to_s) - @dest << "\n" unless s[-1] == ?\n - end - @dest << "\n" if args.empty? - nil - end - - def putc( ch ) - stream_check! - @dest << ch.chr - nil - end - - def printf( *args ) - stream_check! - @dest << sprintf(*args) - nil - end - - def write( str ) - stream_check! - s = str.to_s - @dest << s - s.size - end - - alias syswrite write - - def <<( str ) - stream_check! - @dest << str.to_s - self - end - - private - - def stream_check! - @closed and raise IOError, 'closed stream' - end - -end diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/utils.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/utils.rb deleted file mode 100644 index 9a3afe8985..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/utils.rb +++ /dev/null @@ -1,337 +0,0 @@ -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# 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. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -# = TMail - The EMail Swiss Army Knife for Ruby -# -# The TMail library provides you with a very complete way to handle and manipulate EMails -# from within your Ruby programs. -# -# Used as the backbone for email handling by the Ruby on Rails and Nitro web frameworks as -# well as a bunch of other Ruby apps including the Ruby-Talk mailing list to newsgroup email -# gateway, it is a proven and reliable email handler that won't let you down. -# -# Originally created by Minero Aoki, TMail has been recently picked up by Mikel Lindsaar and -# is being actively maintained. Numerous backlogged bug fixes have been applied as well as -# Ruby 1.9 compatibility and a swath of documentation to boot. -# -# TMail allows you to treat an email totally as an object and allow you to get on with your -# own programming without having to worry about crafting the perfect email address validation -# parser, or assembling an email from all it's component parts. -# -# TMail handles the most complex part of the email - the header. It generates and parses -# headers and provides you with instant access to their innards through simple and logically -# named accessor and setter methods. -# -# TMail also provides a wrapper to Net/SMTP as well as Unix Mailbox handling methods to -# directly read emails from your unix mailbox, parse them and use them. -# -# Following is the comprehensive list of methods to access TMail::Mail objects. You can also -# check out TMail::Mail, TMail::Address and TMail::Headers for other lists. -module TMail - - # Provides an exception to throw on errors in Syntax within TMail's parsers - class SyntaxError < StandardError; end - - # Provides a new email boundary to separate parts of the email. This is a random - # string based off the current time, so should be fairly unique. - # - # For Example: - # - # TMail.new_boundary - # #=> "mimepart_47bf656968207_25a8fbb80114" - # TMail.new_boundary - # #=> "mimepart_47bf66051de4_25a8fbb80240" - def TMail.new_boundary - 'mimepart_' + random_tag - end - - # Provides a new email message ID. You can use this to generate unique email message - # id's for your email so you can track them. - # - # Optionally takes a fully qualified domain name (default to the current hostname - # returned by Socket.gethostname) that will be appended to the message ID. - # - # For Example: - # - # email.message_id = TMail.new_message_id - # #=> "<47bf66845380e_25a8fbb80332@baci.local.tmail>" - # email.to_s - # #=> "Message-Id: <47bf668b633f1_25a8fbb80475@baci.local.tmail>\n\n" - # email.message_id = TMail.new_message_id("lindsaar.net") - # #=> "<47bf668b633f1_25a8fbb80475@lindsaar.net.tmail>" - # email.to_s - # #=> "Message-Id: <47bf668b633f1_25a8fbb80475@lindsaar.net.tmail>\n\n" - def TMail.new_message_id( fqdn = nil ) - fqdn ||= ::Socket.gethostname - "<#{random_tag()}@#{fqdn}.tmail>" - end - - #:stopdoc: - def TMail.random_tag #:nodoc: - @uniq += 1 - t = Time.now - sprintf('%x%x_%x%x%d%x', - t.to_i, t.tv_usec, - $$, Thread.current.object_id, @uniq, rand(255)) - end - private_class_method :random_tag - - @uniq = 0 - - #:startdoc: - - # Text Utils provides a namespace to define TOKENs, ATOMs, PHRASEs and CONTROL characters that - # are OK per RFC 2822. - # - # It also provides methods you can call to determine if a string is safe - module TextUtils - - aspecial = %Q|()<>[]:;.\\,"| - tspecial = %Q|()<>[];:\\,"/?=| - lwsp = %Q| \t\r\n| - control = %Q|\x00-\x1f\x7f-\xff| - - CONTROL_CHAR = /[#{control}]/n - ATOM_UNSAFE = /[#{Regexp.quote aspecial}#{control}#{lwsp}]/n - PHRASE_UNSAFE = /[#{Regexp.quote aspecial}#{control}]/n - TOKEN_UNSAFE = /[#{Regexp.quote tspecial}#{control}#{lwsp}]/n - - # Returns true if the string supplied is free from characters not allowed as an ATOM - def atom_safe?( str ) - not ATOM_UNSAFE === str - end - - # If the string supplied has ATOM unsafe characters in it, will return the string quoted - # in double quotes, otherwise returns the string unmodified - def quote_atom( str ) - (ATOM_UNSAFE === str) ? dquote(str) : str - end - - # If the string supplied has PHRASE unsafe characters in it, will return the string quoted - # in double quotes, otherwise returns the string unmodified - def quote_phrase( str ) - (PHRASE_UNSAFE === str) ? dquote(str) : str - end - - # Returns true if the string supplied is free from characters not allowed as a TOKEN - def token_safe?( str ) - not TOKEN_UNSAFE === str - end - - # If the string supplied has TOKEN unsafe characters in it, will return the string quoted - # in double quotes, otherwise returns the string unmodified - def quote_token( str ) - (TOKEN_UNSAFE === str) ? dquote(str) : str - end - - # Wraps supplied string in double quotes unless it is already wrapped - # Returns double quoted string - def dquote( str ) #:nodoc: - unless str =~ /^".*?"$/ - '"' + str.gsub(/["\\]/n) {|s| '\\' + s } + '"' - else - str - end - end - private :dquote - - # Unwraps supplied string from inside double quotes - # Returns unquoted string - def unquote( str ) - str =~ /^"(.*?)"$/ ? $1 : str - end - - # Provides a method to join a domain name by it's parts and also makes it - # ATOM safe by quoting it as needed - def join_domain( arr ) - arr.map {|i| - if /\A\[.*\]\z/ === i - i - else - quote_atom(i) - end - }.join('.') - end - - #:stopdoc: - ZONESTR_TABLE = { - 'jst' => 9 * 60, - 'eet' => 2 * 60, - 'bst' => 1 * 60, - 'met' => 1 * 60, - 'gmt' => 0, - 'utc' => 0, - 'ut' => 0, - 'nst' => -(3 * 60 + 30), - 'ast' => -4 * 60, - 'edt' => -4 * 60, - 'est' => -5 * 60, - 'cdt' => -5 * 60, - 'cst' => -6 * 60, - 'mdt' => -6 * 60, - 'mst' => -7 * 60, - 'pdt' => -7 * 60, - 'pst' => -8 * 60, - 'a' => -1 * 60, - 'b' => -2 * 60, - 'c' => -3 * 60, - 'd' => -4 * 60, - 'e' => -5 * 60, - 'f' => -6 * 60, - 'g' => -7 * 60, - 'h' => -8 * 60, - 'i' => -9 * 60, - # j not use - 'k' => -10 * 60, - 'l' => -11 * 60, - 'm' => -12 * 60, - 'n' => 1 * 60, - 'o' => 2 * 60, - 'p' => 3 * 60, - 'q' => 4 * 60, - 'r' => 5 * 60, - 's' => 6 * 60, - 't' => 7 * 60, - 'u' => 8 * 60, - 'v' => 9 * 60, - 'w' => 10 * 60, - 'x' => 11 * 60, - 'y' => 12 * 60, - 'z' => 0 * 60 - } - #:startdoc: - - # Takes a time zone string from an EMail and converts it to Unix Time (seconds) - def timezone_string_to_unixtime( str ) - if m = /([\+\-])(\d\d?)(\d\d)/.match(str) - sec = (m[2].to_i * 60 + m[3].to_i) * 60 - m[1] == '-' ? -sec : sec - else - min = ZONESTR_TABLE[str.downcase] or - raise SyntaxError, "wrong timezone format '#{str}'" - min * 60 - end - end - - #:stopdoc: - WDAY = %w( Sun Mon Tue Wed Thu Fri Sat TMailBUG ) - MONTH = %w( TMailBUG Jan Feb Mar Apr May Jun - Jul Aug Sep Oct Nov Dec TMailBUG ) - - def time2str( tm ) - # [ruby-list:7928] - gmt = Time.at(tm.to_i) - gmt.gmtime - offset = tm.to_i - Time.local(*gmt.to_a[0,6].reverse).to_i - - # DO NOT USE strftime: setlocale() breaks it - sprintf '%s, %s %s %d %02d:%02d:%02d %+.2d%.2d', - WDAY[tm.wday], tm.mday, MONTH[tm.month], - tm.year, tm.hour, tm.min, tm.sec, - *(offset / 60).divmod(60) - end - - - MESSAGE_ID = /<[^\@>]+\@[^>\@]+>/ - - def message_id?( str ) - MESSAGE_ID === str - end - - - MIME_ENCODED = /=\?[^\s?=]+\?[QB]\?[^\s?=]+\?=/i - - def mime_encoded?( str ) - MIME_ENCODED === str - end - - - def decode_params( hash ) - new = Hash.new - encoded = nil - hash.each do |key, value| - if m = /\*(?:(\d+)\*)?\z/.match(key) - ((encoded ||= {})[m.pre_match] ||= [])[(m[1] || 0).to_i] = value - else - new[key] = to_kcode(value) - end - end - if encoded - encoded.each do |key, strings| - new[key] = decode_RFC2231(strings.join('')) - end - end - - new - end - - NKF_FLAGS = { - 'EUC' => '-e -m', - 'SJIS' => '-s -m' - } - - def to_kcode( str ) - flag = NKF_FLAGS[TMail.KCODE] or return str - NKF.nkf(flag, str) - end - - RFC2231_ENCODED = /\A(?:iso-2022-jp|euc-jp|shift_jis|us-ascii)?'[a-z]*'/in - - def decode_RFC2231( str ) - m = RFC2231_ENCODED.match(str) or return str - begin - to_kcode(m.post_match.gsub(/%[\da-f]{2}/in) {|s| s[1,2].hex.chr }) - rescue - m.post_match.gsub(/%[\da-f]{2}/in, "") - end - end - - def quote_boundary - # Make sure the Content-Type boundary= parameter is quoted if it contains illegal characters - # (to ensure any special characters in the boundary text are escaped from the parser - # (such as = in MS Outlook's boundary text)) - if @body =~ /^(.*)boundary=(.*)$/m - preamble = $1 - remainder = $2 - if remainder =~ /;/ - remainder =~ /^(.*?)(;.*)$/m - boundary_text = $1 - post = $2.chomp - else - boundary_text = remainder.chomp - end - if boundary_text =~ /[\/\?\=]/ - boundary_text = "\"#{boundary_text}\"" unless boundary_text =~ /^".*?"$/ - @body = "#{preamble}boundary=#{boundary_text}#{post}" - end - end - end - #:startdoc: - - - end - -end diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/version.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/version.rb deleted file mode 100644 index 6bf8cc8061..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/version.rb +++ /dev/null @@ -1,39 +0,0 @@ -# -# version.rb -# -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# 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. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -#:stopdoc: -module TMail - module VERSION - MAJOR = 1 - MINOR = 2 - TINY = 2 - - STRING = [MAJOR, MINOR, TINY].join('.') - end -end diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail.rb new file mode 100644 index 0000000000..18003659a6 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail.rb @@ -0,0 +1,5 @@ +require 'tmail/version' +require 'tmail/mail' +require 'tmail/mailbox' +require 'tmail/core_extensions' +require 'tmail/net' diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/address.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/address.rb new file mode 100644 index 0000000000..fa8e5bcd8c --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/address.rb @@ -0,0 +1,426 @@ +=begin rdoc + += Address handling class + +=end +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# 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. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + +require 'tmail/encode' +require 'tmail/parser' + + +module TMail + + # = Class Address + # + # Provides a complete handling library for email addresses. Can parse a string of an + # address directly or take in preformatted addresses themseleves. Allows you to add + # and remove phrases from the front of the address and provides a compare function for + # email addresses. + # + # == Parsing and Handling a Valid Address: + # + # Just pass the email address in as a string to Address.parse: + # + # email = TMail::Address.parse('Mikel Lindsaar ) + # #=> # + # email.address + # #=> "mikel@lindsaar.net" + # email.local + # #=> "mikel" + # email.domain + # #=> "lindsaar.net" + # email.name # Aliased as phrase as well + # #=> "Mikel Lindsaar" + # + # == Detecting an Invalid Address + # + # If you want to check the syntactical validity of an email address, just pass it to + # Address.parse and catch any SyntaxError: + # + # begin + # TMail::Mail.parse("mikel 2@@@@@ me .com") + # rescue TMail::SyntaxError + # puts("Invalid Email Address Detected") + # else + # puts("Address is valid") + # end + # #=> "Invalid Email Address Detected" + class Address + + include TextUtils #:nodoc: + + # Sometimes you need to parse an address, TMail can do it for you and provide you with + # a fairly robust method of detecting a valid address. + # + # Takes in a string, returns a TMail::Address object. + # + # Raises a TMail::SyntaxError on invalid email format + def Address.parse( str ) + Parser.parse :ADDRESS, special_quote_address(str) + end + + def Address.special_quote_address(str) #:nodoc: + # Takes a string which is an address and adds quotation marks to special + # edge case methods that the RACC parser can not handle. + # + # Right now just handles two edge cases: + # + # Full stop as the last character of the display name: + # Mikel L. + # Returns: + # "Mikel L." + # + # Unquoted @ symbol in the display name: + # mikel@me.com + # Returns: + # "mikel@me.com" + # + # Any other address not matching these patterns just gets returned as is. + case + # This handles the missing "" in an older version of Apple Mail.app + # around the display name when the display name contains a '@' + # like 'mikel@me.com ' + # Just quotes it to: '"mikel@me.com" ' + when str =~ /\A([^"].+@.+[^"])\s(<.*?>)\Z/ + return "\"#{$1}\" #{$2}" + # This handles cases where 'Mikel A. ' which is a trailing + # full stop before the address section. Just quotes it to + # '"Mikel A. " + when str =~ /\A(.*?\.)\s(<.*?>)\Z/ + return "\"#{$1}\" #{$2}" + else + str + end + end + + def address_group? #:nodoc: + false + end + + # Address.new(local, domain) + # + # Accepts: + # + # * local - Left of the at symbol + # + # * domain - Array of the domain split at the periods. + # + # For example: + # + # Address.new("mikel", ["lindsaar", "net"]) + # #=> "#" + def initialize( local, domain ) + if domain + domain.each do |s| + raise SyntaxError, 'empty word in domain' if s.empty? + end + end + + # This is to catch an unquoted "@" symbol in the local part of the + # address. Handles addresses like <"@"@me.com> and makes sure they + # stay like <"@"@me.com> (previously were becomming <@@me.com>) + if local && (local.join == '@' || local.join =~ /\A[^"].*?@.*?[^"]\Z/) + @local = "\"#{local.join}\"" + else + @local = local + end + + @domain = domain + @name = nil + @routes = [] + end + + # Provides the name or 'phrase' of the email address. + # + # For Example: + # + # email = TMail::Address.parse("Mikel Lindsaar ") + # email.name + # #=> "Mikel Lindsaar" + def name + @name + end + + # Setter method for the name or phrase of the email + # + # For Example: + # + # email = TMail::Address.parse("mikel@lindsaar.net") + # email.name + # #=> nil + # email.name = "Mikel Lindsaar" + # email.to_s + # #=> "Mikel Lindsaar " + def name=( str ) + @name = str + @name = nil if str and str.empty? + end + + #:stopdoc: + alias phrase name + alias phrase= name= + #:startdoc: + + # This is still here from RFC 822, and is now obsolete per RFC2822 Section 4. + # + # "When interpreting addresses, the route portion SHOULD be ignored." + # + # It is still here, so you can access it. + # + # Routes return the route portion at the front of the email address, if any. + # + # For Example: + # email = TMail::Address.parse( "<@sa,@another:Mikel@me.com>") + # => # + # email.to_s + # => "<@sa,@another:Mikel@me.com>" + # email.routes + # => ["sa", "another"] + def routes + @routes + end + + def inspect #:nodoc: + "#<#{self.class} #{address()}>" + end + + # Returns the local part of the email address + # + # For Example: + # + # email = TMail::Address.parse("mikel@lindsaar.net") + # email.local + # #=> "mikel" + def local + return nil unless @local + return '""' if @local.size == 1 and @local[0].empty? + # Check to see if it is an array before trying to map it + if @local.respond_to?(:map) + @local.map {|i| quote_atom(i) }.join('.') + else + quote_atom(@local) + end + end + + # Returns the domain part of the email address + # + # For Example: + # + # email = TMail::Address.parse("mikel@lindsaar.net") + # email.local + # #=> "lindsaar.net" + def domain + return nil unless @domain + join_domain(@domain) + end + + # Returns the full specific address itself + # + # For Example: + # + # email = TMail::Address.parse("mikel@lindsaar.net") + # email.address + # #=> "mikel@lindsaar.net" + def spec + s = self.local + d = self.domain + if s and d + s + '@' + d + else + s + end + end + + alias address spec + + # Provides == function to the email. Only checks the actual address + # and ignores the name/phrase component + # + # For Example + # + # addr1 = TMail::Address.parse("My Address ") + # #=> "#" + # addr2 = TMail::Address.parse("Another ") + # #=> "#" + # addr1 == addr2 + # #=> true + def ==( other ) + other.respond_to? :spec and self.spec == other.spec + end + + alias eql? == + + # Provides a unique hash value for this record against the local and domain + # parts, ignores the name/phrase value + # + # email = TMail::Address.parse("mikel@lindsaar.net") + # email.hash + # #=> 18767598 + def hash + @local.hash ^ @domain.hash + end + + # Duplicates a TMail::Address object returning the duplicate + # + # addr1 = TMail::Address.parse("mikel@lindsaar.net") + # addr2 = addr1.dup + # addr1.id == addr2.id + # #=> false + def dup + obj = self.class.new(@local.dup, @domain.dup) + obj.name = @name.dup if @name + obj.routes.replace @routes + obj + end + + include StrategyInterface #:nodoc: + + def accept( strategy, dummy1 = nil, dummy2 = nil ) #:nodoc: + unless @local + strategy.meta '<>' # empty return-path + return + end + + spec_p = (not @name and @routes.empty?) + if @name + strategy.phrase @name + strategy.space + end + tmp = spec_p ? '' : '<' + unless @routes.empty? + tmp << @routes.map {|i| '@' + i }.join(',') << ':' + end + tmp << self.spec + tmp << '>' unless spec_p + strategy.meta tmp + strategy.lwsp '' + end + + end + + + class AddressGroup + + include Enumerable + + def address_group? + true + end + + def initialize( name, addrs ) + @name = name + @addresses = addrs + end + + attr_reader :name + + def ==( other ) + other.respond_to? :to_a and @addresses == other.to_a + end + + alias eql? == + + def hash + map {|i| i.hash }.hash + end + + def []( idx ) + @addresses[idx] + end + + def size + @addresses.size + end + + def empty? + @addresses.empty? + end + + def each( &block ) + @addresses.each(&block) + end + + def to_a + @addresses.dup + end + + alias to_ary to_a + + def include?( a ) + @addresses.include? a + end + + def flatten + set = [] + @addresses.each do |a| + if a.respond_to? :flatten + set.concat a.flatten + else + set.push a + end + end + set + end + + def each_address( &block ) + flatten.each(&block) + end + + def add( a ) + @addresses.push a + end + + alias push add + + def delete( a ) + @addresses.delete a + end + + include StrategyInterface + + def accept( strategy, dummy1 = nil, dummy2 = nil ) + strategy.phrase @name + strategy.meta ':' + strategy.space + first = true + each do |mbox| + if first + first = false + else + strategy.meta ',' + end + strategy.space + mbox.accept strategy + end + strategy.meta ';' + strategy.lwsp '' + end + + end + +end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/attachments.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/attachments.rb new file mode 100644 index 0000000000..5dc5efae5e --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/attachments.rb @@ -0,0 +1,46 @@ +=begin rdoc + += Attachment handling file + +=end + +require 'stringio' + +module TMail + class Attachment < StringIO + attr_accessor :original_filename, :content_type + end + + class Mail + def has_attachments? + multipart? && parts.any? { |part| attachment?(part) } + end + + def attachment?(part) + part.disposition_is_attachment? || part.content_type_is_text? + end + + def attachments + if multipart? + parts.collect { |part| + if part.multipart? + part.attachments + elsif attachment?(part) + content = part.body # unquoted automatically by TMail#body + file_name = (part['content-location'] && + part['content-location'].body) || + part.sub_header("content-type", "name") || + part.sub_header("content-disposition", "filename") + + next if file_name.blank? || content.blank? + + attachment = Attachment.new(content) + attachment.original_filename = file_name.strip + attachment.content_type = part.content_type + attachment + end + }.flatten.compact + end + end + end +end diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/base64.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/base64.rb new file mode 100644 index 0000000000..e294c62960 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/base64.rb @@ -0,0 +1,46 @@ +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# 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. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ +#:stopdoc: +module TMail + module Base64 + + module_function + + def folding_encode( str, eol = "\n", limit = 60 ) + [str].pack('m') + end + + def encode( str ) + [str].pack('m').tr( "\r\n", '' ) + end + + def decode( str, strict = false ) + str.unpack('m').first + end + + end +end +#:startdoc: diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/compat.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/compat.rb new file mode 100644 index 0000000000..1275df79a6 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/compat.rb @@ -0,0 +1,41 @@ +#:stopdoc: +unless Enumerable.method_defined?(:map) + module Enumerable #:nodoc: + alias map collect + end +end + +unless Enumerable.method_defined?(:select) + module Enumerable #:nodoc: + alias select find_all + end +end + +unless Enumerable.method_defined?(:reject) + module Enumerable #:nodoc: + def reject + result = [] + each do |i| + result.push i unless yield(i) + end + result + end + end +end + +unless Enumerable.method_defined?(:sort_by) + module Enumerable #:nodoc: + def sort_by + map {|i| [yield(i), i] }.sort.map {|val, i| i } + end + end +end + +unless File.respond_to?(:read) + def File.read(fname) #:nodoc: + File.open(fname) {|f| + return f.read + } + end +end +#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/config.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/config.rb new file mode 100644 index 0000000000..3a876dcdbd --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/config.rb @@ -0,0 +1,67 @@ +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# 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. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ +#:stopdoc: +module TMail + + class Config + + def initialize( strict ) + @strict_parse = strict + @strict_base64decode = strict + end + + def strict_parse? + @strict_parse + end + + attr_writer :strict_parse + + def strict_base64decode? + @strict_base64decode + end + + attr_writer :strict_base64decode + + def new_body_port( mail ) + StringPort.new + end + + alias new_preamble_port new_body_port + alias new_part_port new_body_port + + end + + DEFAULT_CONFIG = Config.new(false) + DEFAULT_STRICT_CONFIG = Config.new(true) + + def Config.to_config( arg ) + return DEFAULT_STRICT_CONFIG if arg == true + return DEFAULT_CONFIG if arg == false + arg or DEFAULT_CONFIG + end + +end +#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/core_extensions.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/core_extensions.rb new file mode 100644 index 0000000000..da62c33bbf --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/core_extensions.rb @@ -0,0 +1,63 @@ +#:stopdoc: +unless Object.respond_to?(:blank?) + class Object + # Check first to see if we are in a Rails environment, no need to + # define these methods if we are + + # 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? + if respond_to?(:empty?) && respond_to?(:strip) + empty? or strip.empty? + elsif respond_to?(:empty?) + empty? + else + !self + end + end + end + + class NilClass + def blank? + true + end + end + + class FalseClass + def blank? + true + end + end + + class TrueClass + def blank? + false + end + end + + class Array + alias_method :blank?, :empty? + end + + class Hash + alias_method :blank?, :empty? + end + + class String + def blank? + empty? || strip.empty? + end + end + + class Numeric + def blank? + false + end + end +end +#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/encode.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/encode.rb new file mode 100644 index 0000000000..458dbbfe6a --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/encode.rb @@ -0,0 +1,581 @@ +#-- +# = COPYRIGHT: +# +# Copyright (c) 1998-2003 Minero Aoki +# +# 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. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ +#:stopdoc: +require 'nkf' +require 'tmail/base64' +require 'tmail/stringio' +require 'tmail/utils' +#:startdoc: + + +module TMail + + #:stopdoc: + class << self + attr_accessor :KCODE + end + self.KCODE = 'NONE' + + module StrategyInterface + + def create_dest( obj ) + case obj + when nil + StringOutput.new + when String + StringOutput.new(obj) + when IO, StringOutput + obj + else + raise TypeError, 'cannot handle this type of object for dest' + end + end + module_function :create_dest + + #:startdoc: + # Returns the TMail object encoded and ready to be sent via SMTP etc. + # You should call this before you are packaging up your email to + # correctly escape all the values that need escaping in the email, line + # wrap the email etc. + # + # It is also a good idea to call this before you marshal or serialize + # a TMail object. + # + # For Example: + # + # email = TMail::Load(my_email_file) + # email_to_send = email.encoded + def encoded( eol = "\r\n", charset = 'j', dest = nil ) + accept_strategy Encoder, eol, charset, dest + end + + # Returns the TMail object decoded and ready to be used by you, your + # program etc. + # + # You should call this before you are packaging up your email to + # correctly escape all the values that need escaping in the email, line + # wrap the email etc. + # + # For Example: + # + # email = TMail::Load(my_email_file) + # email_to_send = email.encoded + def decoded( eol = "\n", charset = 'e', dest = nil ) + # Turn the E-Mail into a string and return it with all + # encoded characters decoded. alias for to_s + accept_strategy Decoder, eol, charset, dest + end + + alias to_s decoded + + def accept_strategy( klass, eol, charset, dest = nil ) #:nodoc: + dest ||= '' + accept klass.new( create_dest(dest), charset, eol ) + dest + end + + end + + #:stopdoc: + + ### + ### MIME B encoding decoder + ### + + class Decoder + + include TextUtils + + encoded = '=\?(?:iso-2022-jp|euc-jp|shift_jis)\?[QB]\?[a-z0-9+/=]+\?=' + ENCODED_WORDS = /#{encoded}(?:\s+#{encoded})*/i + + OUTPUT_ENCODING = { + 'EUC' => 'e', + 'SJIS' => 's', + } + + def self.decode( str, encoding = nil ) + encoding ||= (OUTPUT_ENCODING[TMail.KCODE] || 'j') + opt = '-mS' + encoding + str.gsub(ENCODED_WORDS) {|s| NKF.nkf(opt, s) } + end + + def initialize( dest, encoding = nil, eol = "\n" ) + @f = StrategyInterface.create_dest(dest) + @encoding = (/\A[ejs]/ === encoding) ? encoding[0,1] : nil + @eol = eol + end + + def decode( str ) + self.class.decode(str, @encoding) + end + private :decode + + def terminate + end + + def header_line( str ) + @f << decode(str) + end + + def header_name( nm ) + @f << nm << ': ' + end + + def header_body( str ) + @f << decode(str) + end + + def space + @f << ' ' + end + + alias spc space + + def lwsp( str ) + @f << str + end + + def meta( str ) + @f << str + end + + def text( str ) + @f << decode(str) + end + + def phrase( str ) + @f << quote_phrase(decode(str)) + end + + def kv_pair( k, v ) + v = dquote(v) unless token_safe?(v) + @f << k << '=' << v + end + + def puts( str = nil ) + @f << str if str + @f << @eol + end + + def write( str ) + @f << str + end + + end + + + ### + ### MIME B-encoding encoder + ### + + # + # FIXME: This class can handle only (euc-jp/shift_jis -> iso-2022-jp). + # + class Encoder + + include TextUtils + + BENCODE_DEBUG = false unless defined?(BENCODE_DEBUG) + + def Encoder.encode( str ) + e = new() + e.header_body str + e.terminate + e.dest.string + end + + SPACER = "\t" + MAX_LINE_LEN = 78 + RFC_2822_MAX_LENGTH = 998 + + OPTIONS = { + 'EUC' => '-Ej -m0', + 'SJIS' => '-Sj -m0', + 'UTF8' => nil, # FIXME + 'NONE' => nil + } + + def initialize( dest = nil, encoding = nil, eol = "\r\n", limit = nil ) + @f = StrategyInterface.create_dest(dest) + @opt = OPTIONS[TMail.KCODE] + @eol = eol + @folded = false + @preserve_quotes = true + reset + end + + def preserve_quotes=( bool ) + @preserve_quotes + end + + def preserve_quotes + @preserve_quotes + end + + def normalize_encoding( str ) + if @opt + then NKF.nkf(@opt, str) + else str + end + end + + def reset + @text = '' + @lwsp = '' + @curlen = 0 + end + + def terminate + add_lwsp '' + reset + end + + def dest + @f + end + + def puts( str = nil ) + @f << str if str + @f << @eol + end + + def write( str ) + @f << str + end + + # + # add + # + + def header_line( line ) + scanadd line + end + + def header_name( name ) + add_text name.split(/-/).map {|i| i.capitalize }.join('-') + add_text ':' + add_lwsp ' ' + end + + def header_body( str ) + scanadd normalize_encoding(str) + end + + def space + add_lwsp ' ' + end + + alias spc space + + def lwsp( str ) + add_lwsp str.sub(/[\r\n]+[^\r\n]*\z/, '') + end + + def meta( str ) + add_text str + end + + def text( str ) + scanadd normalize_encoding(str) + end + + def phrase( str ) + str = normalize_encoding(str) + if CONTROL_CHAR === str + scanadd str + else + add_text quote_phrase(str) + end + end + + # FIXME: implement line folding + # + def kv_pair( k, v ) + return if v.nil? + v = normalize_encoding(v) + if token_safe?(v) + add_text k + '=' + v + elsif not CONTROL_CHAR === v + add_text k + '=' + quote_token(v) + else + # apply RFC2231 encoding + kv = k + '*=' + "iso-2022-jp'ja'" + encode_value(v) + add_text kv + end + end + + def encode_value( str ) + str.gsub(TOKEN_UNSAFE) {|s| '%%%02x' % s[0] } + end + + private + + def scanadd( str, force = false ) + types = '' + strs = [] + if str.respond_to?(:encoding) + enc = str.encoding + str.force_encoding(Encoding::ASCII_8BIT) + end + until str.empty? + if m = /\A[^\e\t\r\n ]+/.match(str) + types << (force ? 'j' : 'a') + if str.respond_to?(:encoding) + strs.push m[0].force_encoding(enc) + else + strs.push m[0] + end + elsif m = /\A[\t\r\n ]+/.match(str) + types << 's' + if str.respond_to?(:encoding) + strs.push m[0].force_encoding(enc) + else + strs.push m[0] + end + + elsif m = /\A\e../.match(str) + esc = m[0] + str = m.post_match + if esc != "\e(B" and m = /\A[^\e]+/.match(str) + types << 'j' + if str.respond_to?(:encoding) + strs.push m[0].force_encoding(enc) + else + strs.push m[0] + end + end + + else + raise 'TMail FATAL: encoder scan fail' + end + (str = m.post_match) unless m.nil? + end + + do_encode types, strs + end + + def do_encode( types, strs ) + # + # result : (A|E)(S(A|E))* + # E : W(SW)* + # W : (J|A)+ but must contain J # (J|A)*J(J|A)* + # A : <> + # J : <> + # S : <> + # + # An encoding unit is `E'. + # Input (parameter `types') is (J|A)(J|A|S)*(J|A) + # + if BENCODE_DEBUG + puts + puts '-- do_encode ------------' + puts types.split(//).join(' ') + p strs + end + + e = /[ja]*j[ja]*(?:s[ja]*j[ja]*)*/ + + while m = e.match(types) + pre = m.pre_match + concat_A_S pre, strs[0, pre.size] unless pre.empty? + concat_E m[0], strs[m.begin(0) ... m.end(0)] + types = m.post_match + strs.slice! 0, m.end(0) + end + concat_A_S types, strs + end + + def concat_A_S( types, strs ) + if RUBY_VERSION < '1.9' + a = ?a; s = ?s + else + a = 'a'.ord; s = 's'.ord + end + i = 0 + types.each_byte do |t| + case t + when a then add_text strs[i] + when s then add_lwsp strs[i] + else + raise "TMail FATAL: unknown flag: #{t.chr}" + end + i += 1 + end + end + + METHOD_ID = { + ?j => :extract_J, + ?e => :extract_E, + ?a => :extract_A, + ?s => :extract_S + } + + def concat_E( types, strs ) + if BENCODE_DEBUG + puts '---- concat_E' + puts "types=#{types.split(//).join(' ')}" + puts "strs =#{strs.inspect}" + end + + flush() unless @text.empty? + + chunk = '' + strs.each_with_index do |s,i| + mid = METHOD_ID[types[i]] + until s.empty? + unless c = __send__(mid, chunk.size, s) + add_with_encode chunk unless chunk.empty? + flush + chunk = '' + fold + c = __send__(mid, 0, s) + raise 'TMail FATAL: extract fail' unless c + end + chunk << c + end + end + add_with_encode chunk unless chunk.empty? + end + + def extract_J( chunksize, str ) + size = max_bytes(chunksize, str.size) - 6 + size = (size % 2 == 0) ? (size) : (size - 1) + return nil if size <= 0 + if str.respond_to?(:encoding) + enc = str.encoding + str.force_encoding(Encoding::ASCII_8BIT) + "\e$B#{str.slice!(0, size)}\e(B".force_encoding(enc) + else + "\e$B#{str.slice!(0, size)}\e(B" + end + end + + def extract_A( chunksize, str ) + size = max_bytes(chunksize, str.size) + return nil if size <= 0 + str.slice!(0, size) + end + + alias extract_S extract_A + + def max_bytes( chunksize, ssize ) + (restsize() - '=?iso-2022-jp?B??='.size) / 4 * 3 - chunksize + end + + # + # free length buffer + # + + def add_text( str ) + @text << str + # puts '---- text -------------------------------------' + # puts "+ #{str.inspect}" + # puts "txt >>>#{@text.inspect}<<<" + end + + def add_with_encode( str ) + @text << "=?iso-2022-jp?B?#{Base64.encode(str)}?=" + end + + def add_lwsp( lwsp ) + # puts '---- lwsp -------------------------------------' + # puts "+ #{lwsp.inspect}" + fold if restsize() <= 0 + flush(@folded) + @lwsp = lwsp + end + + def flush(folded = false) + # puts '---- flush ----' + # puts "spc >>>#{@lwsp.inspect}<<<" + # puts "txt >>>#{@text.inspect}<<<" + @f << @lwsp << @text + if folded + @curlen = 0 + else + @curlen += (@lwsp.size + @text.size) + end + @text = '' + @lwsp = '' + end + + def fold + # puts '---- fold ----' + unless @f.string =~ /^.*?:$/ + @f << @eol + @lwsp = SPACER + else + fold_header + @folded = true + end + @curlen = 0 + end + + def fold_header + # Called because line is too long - so we need to wrap. + # First look for whitespace in the text + # if it has text, fold there + # check the remaining text, if too long, fold again + # if it doesn't, then don't fold unless the line goes beyond 998 chars + + # Check the text to see if there is whitespace, or if not + @wrapped_text = [] + until @text.blank? + fold_the_string + end + @text = @wrapped_text.join("#{@eol}#{SPACER}") + end + + def fold_the_string + whitespace_location = @text =~ /\s/ || @text.length + # Is the location of the whitespace shorter than the RCF_2822_MAX_LENGTH? + # if there is no whitespace in the string, then this + unless mazsize(whitespace_location) <= 0 + @text.strip! + @wrapped_text << @text.slice!(0...whitespace_location) + # If it is not less, we have to wrap it destructively + else + slice_point = RFC_2822_MAX_LENGTH - @curlen - @lwsp.length + @text.strip! + @wrapped_text << @text.slice!(0...slice_point) + end + end + + def restsize + MAX_LINE_LEN - (@curlen + @lwsp.size + @text.size) + end + + def mazsize(whitespace_location) + # Per RFC2822, the maximum length of a line is 998 chars + RFC_2822_MAX_LENGTH - (@curlen + @lwsp.size + whitespace_location) + end + + end + #:startdoc: +end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/header.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/header.rb new file mode 100644 index 0000000000..9153dcd7c6 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/header.rb @@ -0,0 +1,960 @@ +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# 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. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + +require 'tmail/encode' +require 'tmail/address' +require 'tmail/parser' +require 'tmail/config' +require 'tmail/utils' + +#:startdoc: +module TMail + + # Provides methods to handle and manipulate headers in the email + class HeaderField + + include TextUtils + + class << self + + alias newobj new + + def new( name, body, conf = DEFAULT_CONFIG ) + klass = FNAME_TO_CLASS[name.downcase] || UnstructuredHeader + klass.newobj body, conf + end + + # Returns a HeaderField object matching the header you specify in the "name" param. + # Requires an initialized TMail::Port to be passed in. + # + # The method searches the header of the Port you pass into it to find a match on + # the header line you pass. Once a match is found, it will unwrap the matching line + # as needed to return an initialized HeaderField object. + # + # If you want to get the Envelope sender of the email object, pass in "EnvelopeSender", + # if you want the From address of the email itself, pass in 'From'. + # + # This is because a mailbox doesn't have the : after the From that designates the + # beginning of the envelope sender (which can be different to the from address of + # the emial) + # + # Other fields can be passed as normal, "Reply-To", "Received" etc. + # + # Note: Change of behaviour in 1.2.1 => returns nil if it does not find the specified + # header field, otherwise returns an instantiated object of the correct header class + # + # For example: + # port = TMail::FilePort.new("/test/fixtures/raw_email_simple") + # h = TMail::HeaderField.new_from_port(port, "From") + # h.addrs.to_s #=> "Mikel Lindsaar " + # h = TMail::HeaderField.new_from_port(port, "EvelopeSender") + # h.addrs.to_s #=> "mike@anotherplace.com.au" + # h = TMail::HeaderField.new_from_port(port, "SomeWeirdHeaderField") + # h #=> nil + def new_from_port( port, name, conf = DEFAULT_CONFIG ) + if name == "EnvelopeSender" + name = "From" + re = Regexp.new('\A(From) ', 'i') + else + re = Regexp.new('\A(' + Regexp.quote(name) + '):', 'i') + end + str = nil + port.ropen {|f| + f.each do |line| + if m = re.match(line) then str = m.post_match.strip + elsif str and /\A[\t ]/ === line then str << ' ' << line.strip + elsif /\A-*\s*\z/ === line then break + elsif str then break + end + end + } + new(name, str, Config.to_config(conf)) if str + end + + def internal_new( name, conf ) + FNAME_TO_CLASS[name].newobj('', conf, true) + end + + end # class << self + + def initialize( body, conf, intern = false ) + @body = body + @config = conf + + @illegal = false + @parsed = false + + if intern + @parsed = true + parse_init + end + end + + def inspect + "#<#{self.class} #{@body.inspect}>" + end + + def illegal? + @illegal + end + + def empty? + ensure_parsed + return true if @illegal + isempty? + end + + private + + def ensure_parsed + return if @parsed + @parsed = true + parse + end + + # defabstract parse + # end + + def clear_parse_status + @parsed = false + @illegal = false + end + + public + + def body + ensure_parsed + v = Decoder.new(s = '') + do_accept v + v.terminate + s + end + + def body=( str ) + @body = str + clear_parse_status + end + + include StrategyInterface + + def accept( strategy ) + ensure_parsed + do_accept strategy + strategy.terminate + end + + # abstract do_accept + + end + + + class UnstructuredHeader < HeaderField + + def body + ensure_parsed + @body + end + + def body=( arg ) + ensure_parsed + @body = arg + end + + private + + def parse_init + end + + def parse + @body = Decoder.decode(@body.gsub(/\n|\r\n|\r/, '')) + end + + def isempty? + not @body + end + + def do_accept( strategy ) + strategy.text @body + end + + end + + + class StructuredHeader < HeaderField + + def comments + ensure_parsed + if @comments[0] + [Decoder.decode(@comments[0])] + else + @comments + end + end + + private + + def parse + save = nil + + begin + parse_init + do_parse + rescue SyntaxError + if not save and mime_encoded? @body + save = @body + @body = Decoder.decode(save) + retry + elsif save + @body = save + end + + @illegal = true + raise if @config.strict_parse? + end + end + + def parse_init + @comments = [] + init + end + + def do_parse + quote_boundary + obj = Parser.parse(self.class::PARSE_TYPE, @body, @comments) + set obj if obj + end + + end + + + class DateTimeHeader < StructuredHeader + + PARSE_TYPE = :DATETIME + + def date + ensure_parsed + @date + end + + def date=( arg ) + ensure_parsed + @date = arg + end + + private + + def init + @date = nil + end + + def set( t ) + @date = t + end + + def isempty? + not @date + end + + def do_accept( strategy ) + strategy.meta time2str(@date) + end + + end + + + class AddressHeader < StructuredHeader + + PARSE_TYPE = :MADDRESS + + def addrs + ensure_parsed + @addrs + end + + private + + def init + @addrs = [] + end + + def set( a ) + @addrs = a + end + + def isempty? + @addrs.empty? + end + + def do_accept( strategy ) + first = true + @addrs.each do |a| + if first + first = false + else + strategy.meta ',' + strategy.space + end + a.accept strategy + end + + @comments.each do |c| + strategy.space + strategy.meta '(' + strategy.text c + strategy.meta ')' + end + end + + end + + + class ReturnPathHeader < AddressHeader + + PARSE_TYPE = :RETPATH + + def addr + addrs()[0] + end + + def spec + a = addr() or return nil + a.spec + end + + def routes + a = addr() or return nil + a.routes + end + + private + + def do_accept( strategy ) + a = addr() + + strategy.meta '<' + unless a.routes.empty? + strategy.meta a.routes.map {|i| '@' + i }.join(',') + strategy.meta ':' + end + spec = a.spec + strategy.meta spec if spec + strategy.meta '>' + end + + end + + + class SingleAddressHeader < AddressHeader + + def addr + addrs()[0] + end + + private + + def do_accept( strategy ) + a = addr() + a.accept strategy + @comments.each do |c| + strategy.space + strategy.meta '(' + strategy.text c + strategy.meta ')' + end + end + + end + + + class MessageIdHeader < StructuredHeader + + def id + ensure_parsed + @id + end + + def id=( arg ) + ensure_parsed + @id = arg + end + + private + + def init + @id = nil + end + + def isempty? + not @id + end + + def do_parse + @id = @body.slice(MESSAGE_ID) or + raise SyntaxError, "wrong Message-ID format: #{@body}" + end + + def do_accept( strategy ) + strategy.meta @id + end + + end + + + class ReferencesHeader < StructuredHeader + + def refs + ensure_parsed + @refs + end + + def each_id + self.refs.each do |i| + yield i if MESSAGE_ID === i + end + end + + def ids + ensure_parsed + @ids + end + + def each_phrase + self.refs.each do |i| + yield i unless MESSAGE_ID === i + end + end + + def phrases + ret = [] + each_phrase {|i| ret.push i } + ret + end + + private + + def init + @refs = [] + @ids = [] + end + + def isempty? + @ids.empty? + end + + def do_parse + str = @body + while m = MESSAGE_ID.match(str) + pre = m.pre_match.strip + @refs.push pre unless pre.empty? + @refs.push s = m[0] + @ids.push s + str = m.post_match + end + str = str.strip + @refs.push str unless str.empty? + end + + def do_accept( strategy ) + first = true + @ids.each do |i| + if first + first = false + else + strategy.space + end + strategy.meta i + end + end + + end + + + class ReceivedHeader < StructuredHeader + + PARSE_TYPE = :RECEIVED + + def from + ensure_parsed + @from + end + + def from=( arg ) + ensure_parsed + @from = arg + end + + def by + ensure_parsed + @by + end + + def by=( arg ) + ensure_parsed + @by = arg + end + + def via + ensure_parsed + @via + end + + def via=( arg ) + ensure_parsed + @via = arg + end + + def with + ensure_parsed + @with + end + + def id + ensure_parsed + @id + end + + def id=( arg ) + ensure_parsed + @id = arg + end + + def _for + ensure_parsed + @_for + end + + def _for=( arg ) + ensure_parsed + @_for = arg + end + + def date + ensure_parsed + @date + end + + def date=( arg ) + ensure_parsed + @date = arg + end + + private + + def init + @from = @by = @via = @with = @id = @_for = nil + @with = [] + @date = nil + end + + def set( args ) + @from, @by, @via, @with, @id, @_for, @date = *args + end + + def isempty? + @with.empty? and not (@from or @by or @via or @id or @_for or @date) + end + + def do_accept( strategy ) + list = [] + list.push 'from ' + @from if @from + list.push 'by ' + @by if @by + list.push 'via ' + @via if @via + @with.each do |i| + list.push 'with ' + i + end + list.push 'id ' + @id if @id + list.push 'for <' + @_for + '>' if @_for + + first = true + list.each do |i| + strategy.space unless first + strategy.meta i + first = false + end + if @date + strategy.meta ';' + strategy.space + strategy.meta time2str(@date) + end + end + + end + + + class KeywordsHeader < StructuredHeader + + PARSE_TYPE = :KEYWORDS + + def keys + ensure_parsed + @keys + end + + private + + def init + @keys = [] + end + + def set( a ) + @keys = a + end + + def isempty? + @keys.empty? + end + + def do_accept( strategy ) + first = true + @keys.each do |i| + if first + first = false + else + strategy.meta ',' + end + strategy.meta i + end + end + + end + + + class EncryptedHeader < StructuredHeader + + PARSE_TYPE = :ENCRYPTED + + def encrypter + ensure_parsed + @encrypter + end + + def encrypter=( arg ) + ensure_parsed + @encrypter = arg + end + + def keyword + ensure_parsed + @keyword + end + + def keyword=( arg ) + ensure_parsed + @keyword = arg + end + + private + + def init + @encrypter = nil + @keyword = nil + end + + def set( args ) + @encrypter, @keyword = args + end + + def isempty? + not (@encrypter or @keyword) + end + + def do_accept( strategy ) + if @key + strategy.meta @encrypter + ',' + strategy.space + strategy.meta @keyword + else + strategy.meta @encrypter + end + end + + end + + + class MimeVersionHeader < StructuredHeader + + PARSE_TYPE = :MIMEVERSION + + def major + ensure_parsed + @major + end + + def major=( arg ) + ensure_parsed + @major = arg + end + + def minor + ensure_parsed + @minor + end + + def minor=( arg ) + ensure_parsed + @minor = arg + end + + def version + sprintf('%d.%d', major, minor) + end + + private + + def init + @major = nil + @minor = nil + end + + def set( args ) + @major, @minor = *args + end + + def isempty? + not (@major or @minor) + end + + def do_accept( strategy ) + strategy.meta sprintf('%d.%d', @major, @minor) + end + + end + + + class ContentTypeHeader < StructuredHeader + + PARSE_TYPE = :CTYPE + + def main_type + ensure_parsed + @main + end + + def main_type=( arg ) + ensure_parsed + @main = arg.downcase + end + + def sub_type + ensure_parsed + @sub + end + + def sub_type=( arg ) + ensure_parsed + @sub = arg.downcase + end + + def content_type + ensure_parsed + @sub ? sprintf('%s/%s', @main, @sub) : @main + end + + def params + ensure_parsed + unless @params.blank? + @params.each do |k, v| + @params[k] = unquote(v) + end + end + @params + end + + def []( key ) + ensure_parsed + @params and unquote(@params[key]) + end + + def []=( key, val ) + ensure_parsed + (@params ||= {})[key] = val + end + + private + + def init + @main = @sub = @params = nil + end + + def set( args ) + @main, @sub, @params = *args + end + + def isempty? + not (@main or @sub) + end + + def do_accept( strategy ) + if @sub + strategy.meta sprintf('%s/%s', @main, @sub) + else + strategy.meta @main + end + @params.each do |k,v| + if v + strategy.meta ';' + strategy.space + strategy.kv_pair k, v + end + end + end + + end + + + class ContentTransferEncodingHeader < StructuredHeader + + PARSE_TYPE = :CENCODING + + def encoding + ensure_parsed + @encoding + end + + def encoding=( arg ) + ensure_parsed + @encoding = arg + end + + private + + def init + @encoding = nil + end + + def set( s ) + @encoding = s + end + + def isempty? + not @encoding + end + + def do_accept( strategy ) + strategy.meta @encoding.capitalize + end + + end + + + class ContentDispositionHeader < StructuredHeader + + PARSE_TYPE = :CDISPOSITION + + def disposition + ensure_parsed + @disposition + end + + def disposition=( str ) + ensure_parsed + @disposition = str.downcase + end + + def params + ensure_parsed + unless @params.blank? + @params.each do |k, v| + @params[k] = unquote(v) + end + end + @params + end + + def []( key ) + ensure_parsed + @params and unquote(@params[key]) + end + + def []=( key, val ) + ensure_parsed + (@params ||= {})[key] = val + end + + private + + def init + @disposition = @params = nil + end + + def set( args ) + @disposition, @params = *args + end + + def isempty? + not @disposition and (not @params or @params.empty?) + end + + def do_accept( strategy ) + strategy.meta @disposition + @params.each do |k,v| + strategy.meta ';' + strategy.space + strategy.kv_pair k, unquote(v) + end + end + + end + + + class HeaderField # redefine + + FNAME_TO_CLASS = { + 'date' => DateTimeHeader, + 'resent-date' => DateTimeHeader, + 'to' => AddressHeader, + 'cc' => AddressHeader, + 'bcc' => AddressHeader, + 'from' => AddressHeader, + 'reply-to' => AddressHeader, + 'resent-to' => AddressHeader, + 'resent-cc' => AddressHeader, + 'resent-bcc' => AddressHeader, + 'resent-from' => AddressHeader, + 'resent-reply-to' => AddressHeader, + 'sender' => SingleAddressHeader, + 'resent-sender' => SingleAddressHeader, + 'return-path' => ReturnPathHeader, + 'message-id' => MessageIdHeader, + 'resent-message-id' => MessageIdHeader, + 'in-reply-to' => ReferencesHeader, + 'received' => ReceivedHeader, + 'references' => ReferencesHeader, + 'keywords' => KeywordsHeader, + 'encrypted' => EncryptedHeader, + 'mime-version' => MimeVersionHeader, + 'content-type' => ContentTypeHeader, + 'content-transfer-encoding' => ContentTransferEncodingHeader, + 'content-disposition' => ContentDispositionHeader, + 'content-id' => MessageIdHeader, + 'subject' => UnstructuredHeader, + 'comments' => UnstructuredHeader, + 'content-description' => UnstructuredHeader + } + + end + +end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/index.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/index.rb new file mode 100644 index 0000000000..554e2fd696 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/index.rb @@ -0,0 +1,9 @@ +#:stopdoc: +# This is here for Rolls. +# Rolls uses this instead of lib/tmail.rb. + +require 'tmail/version' +require 'tmail/mail' +require 'tmail/mailbox' +require 'tmail/core_extensions' +#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/interface.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/interface.rb new file mode 100644 index 0000000000..a6d428d7d6 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/interface.rb @@ -0,0 +1,1130 @@ +=begin rdoc + += interface.rb Provides an interface to the TMail object + +=end +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# 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. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + +# TMail::Mail objects get accessed primarily through the methods in this file. +# +# + +require 'tmail/utils' + +module TMail + + class Mail + + # Allows you to query the mail object with a string to get the contents + # of the field you want. + # + # Returns a string of the exact contnts of the field + # + # mail.from = "mikel " + # mail.header_string("From") #=> "mikel " + def header_string( name, default = nil ) + h = @header[name.downcase] or return default + h.to_s + end + + #:stopdoc: + #-- + #== Attributes + + include TextUtils + + def set_string_array_attr( key, strs ) + strs.flatten! + if strs.empty? + @header.delete key.downcase + else + store key, strs.join(', ') + end + strs + end + private :set_string_array_attr + + def set_string_attr( key, str ) + if str + store key, str + else + @header.delete key.downcase + end + str + end + private :set_string_attr + + def set_addrfield( name, arg ) + if arg + h = HeaderField.internal_new(name, @config) + h.addrs.replace [arg].flatten + @header[name] = h + else + @header.delete name + end + arg + end + private :set_addrfield + + def addrs2specs( addrs ) + return nil unless addrs + list = addrs.map {|addr| + if addr.address_group? + then addr.map {|a| a.spec } + else addr.spec + end + }.flatten + return nil if list.empty? + list + end + private :addrs2specs + + #:startdoc: + + #== Date and Time methods + + # Returns the date of the email message as per the "date" header value or returns + # nil by default (if no date field exists). + # + # You can also pass whatever default you want into this method and it will return + # that instead of nil if there is no date already set. + def date( default = nil ) + if h = @header['date'] + h.date + else + default + end + end + + # Destructively sets the date of the mail object with the passed Time instance, + # returns a Time instance set to the date/time of the mail + # + # Example: + # + # now = Time.now + # mail.date = now + # mail.date #=> Sat Nov 03 18:47:50 +1100 2007 + # mail.date.class #=> Time + def date=( time ) + if time + store 'Date', time2str(time) + else + @header.delete 'date' + end + time + end + + # Returns the time of the mail message formatted to your taste using a + # strftime format string. If no date set returns nil by default or whatever value + # you pass as the second optional parameter. + # + # time = Time.now # (on Nov 16 2007) + # mail.date = time + # mail.strftime("%D") #=> "11/16/07" + def strftime( fmt, default = nil ) + if t = date + t.strftime(fmt) + else + default + end + end + + #== Destination methods + + # Return a TMail::Addresses instance for each entry in the "To:" field of the mail object header. + # + # If the "To:" field does not exist, will return nil by default or the value you + # pass as the optional parameter. + # + # Example: + # + # mail = TMail::Mail.new + # mail.to_addrs #=> nil + # mail.to_addrs([]) #=> [] + # mail.to = "Mikel , another Mikel " + # mail.to_addrs #=> [#, #] + def to_addrs( default = nil ) + if h = @header['to'] + h.addrs + else + default + end + end + + # Return a TMail::Addresses instance for each entry in the "Cc:" field of the mail object header. + # + # If the "Cc:" field does not exist, will return nil by default or the value you + # pass as the optional parameter. + # + # Example: + # + # mail = TMail::Mail.new + # mail.cc_addrs #=> nil + # mail.cc_addrs([]) #=> [] + # mail.cc = "Mikel , another Mikel " + # mail.cc_addrs #=> [#, #] + def cc_addrs( default = nil ) + if h = @header['cc'] + h.addrs + else + default + end + end + + # Return a TMail::Addresses instance for each entry in the "Bcc:" field of the mail object header. + # + # If the "Bcc:" field does not exist, will return nil by default or the value you + # pass as the optional parameter. + # + # Example: + # + # mail = TMail::Mail.new + # mail.bcc_addrs #=> nil + # mail.bcc_addrs([]) #=> [] + # mail.bcc = "Mikel , another Mikel " + # mail.bcc_addrs #=> [#, #] + def bcc_addrs( default = nil ) + if h = @header['bcc'] + h.addrs + else + default + end + end + + # Destructively set the to field of the "To:" header to equal the passed in string. + # + # TMail will parse your contents and turn each valid email address into a TMail::Address + # object before assigning it to the mail message. + # + # Example: + # + # mail = TMail::Mail.new + # mail.to = "Mikel , another Mikel " + # mail.to_addrs #=> [#, #] + def to_addrs=( arg ) + set_addrfield 'to', arg + end + + # Destructively set the to field of the "Cc:" header to equal the passed in string. + # + # TMail will parse your contents and turn each valid email address into a TMail::Address + # object before assigning it to the mail message. + # + # Example: + # + # mail = TMail::Mail.new + # mail.cc = "Mikel , another Mikel " + # mail.cc_addrs #=> [#, #] + def cc_addrs=( arg ) + set_addrfield 'cc', arg + end + + # Destructively set the to field of the "Bcc:" header to equal the passed in string. + # + # TMail will parse your contents and turn each valid email address into a TMail::Address + # object before assigning it to the mail message. + # + # Example: + # + # mail = TMail::Mail.new + # mail.bcc = "Mikel , another Mikel " + # mail.bcc_addrs #=> [#, #] + def bcc_addrs=( arg ) + set_addrfield 'bcc', arg + end + + # Returns who the email is to as an Array of email addresses as opposed to an Array of + # TMail::Address objects which is what Mail#to_addrs returns + # + # Example: + # + # mail = TMail::Mail.new + # mail.to = "Mikel , another Mikel " + # mail.to #=> ["mikel@me.org", "mikel@you.org"] + def to( default = nil ) + addrs2specs(to_addrs(nil)) || default + end + + # Returns who the email cc'd as an Array of email addresses as opposed to an Array of + # TMail::Address objects which is what Mail#to_addrs returns + # + # Example: + # + # mail = TMail::Mail.new + # mail.cc = "Mikel , another Mikel " + # mail.cc #=> ["mikel@me.org", "mikel@you.org"] + def cc( default = nil ) + addrs2specs(cc_addrs(nil)) || default + end + + # Returns who the email bcc'd as an Array of email addresses as opposed to an Array of + # TMail::Address objects which is what Mail#to_addrs returns + # + # Example: + # + # mail = TMail::Mail.new + # mail.bcc = "Mikel , another Mikel " + # mail.bcc #=> ["mikel@me.org", "mikel@you.org"] + def bcc( default = nil ) + addrs2specs(bcc_addrs(nil)) || default + end + + # Destructively sets the "To:" field to the passed array of strings (which should be valid + # email addresses) + # + # Example: + # + # mail = TMail::Mail.new + # mail.to = ["mikel@abc.com", "Mikel "] + # mail.to #=> ["mikel@abc.org", "mikel@xyz.org"] + # mail['to'].to_s #=> "mikel@abc.com, Mikel " + def to=( *strs ) + set_string_array_attr 'To', strs + end + + # Destructively sets the "Cc:" field to the passed array of strings (which should be valid + # email addresses) + # + # Example: + # + # mail = TMail::Mail.new + # mail.cc = ["mikel@abc.com", "Mikel "] + # mail.cc #=> ["mikel@abc.org", "mikel@xyz.org"] + # mail['cc'].to_s #=> "mikel@abc.com, Mikel " + def cc=( *strs ) + set_string_array_attr 'Cc', strs + end + + # Destructively sets the "Bcc:" field to the passed array of strings (which should be valid + # email addresses) + # + # Example: + # + # mail = TMail::Mail.new + # mail.bcc = ["mikel@abc.com", "Mikel "] + # mail.bcc #=> ["mikel@abc.org", "mikel@xyz.org"] + # mail['bcc'].to_s #=> "mikel@abc.com, Mikel " + def bcc=( *strs ) + set_string_array_attr 'Bcc', strs + end + + #== Originator methods + + # Return a TMail::Addresses instance for each entry in the "From:" field of the mail object header. + # + # If the "From:" field does not exist, will return nil by default or the value you + # pass as the optional parameter. + # + # Example: + # + # mail = TMail::Mail.new + # mail.from_addrs #=> nil + # mail.from_addrs([]) #=> [] + # mail.from = "Mikel , another Mikel " + # mail.from_addrs #=> [#, #] + def from_addrs( default = nil ) + if h = @header['from'] + h.addrs + else + default + end + end + + # Destructively set the to value of the "From:" header to equal the passed in string. + # + # TMail will parse your contents and turn each valid email address into a TMail::Address + # object before assigning it to the mail message. + # + # Example: + # + # mail = TMail::Mail.new + # mail.from_addrs = "Mikel , another Mikel " + # mail.from_addrs #=> [#, #] + def from_addrs=( arg ) + set_addrfield 'from', arg + end + + # Returns who the email is from as an Array of email address strings instead to an Array of + # TMail::Address objects which is what Mail#from_addrs returns + # + # Example: + # + # mail = TMail::Mail.new + # mail.from = "Mikel , another Mikel " + # mail.from #=> ["mikel@me.org", "mikel@you.org"] + def from( default = nil ) + addrs2specs(from_addrs(nil)) || default + end + + # Destructively sets the "From:" field to the passed array of strings (which should be valid + # email addresses) + # + # Example: + # + # mail = TMail::Mail.new + # mail.from = ["mikel@abc.com", "Mikel "] + # mail.from #=> ["mikel@abc.org", "mikel@xyz.org"] + # mail['from'].to_s #=> "mikel@abc.com, Mikel " + def from=( *strs ) + set_string_array_attr 'From', strs + end + + # Returns the "friendly" human readable part of the address + # + # Example: + # + # mail = TMail::Mail.new + # mail.from = "Mikel Lindsaar " + # mail.friendly_from #=> "Mikel Lindsaar" + def friendly_from( default = nil ) + h = @header['from'] + a, = h.addrs + return default unless a + return a.phrase if a.phrase + return h.comments.join(' ') unless h.comments.empty? + a.spec + end + + # Return a TMail::Addresses instance for each entry in the "Reply-To:" field of the mail object header. + # + # If the "Reply-To:" field does not exist, will return nil by default or the value you + # pass as the optional parameter. + # + # Example: + # + # mail = TMail::Mail.new + # mail.reply_to_addrs #=> nil + # mail.reply_to_addrs([]) #=> [] + # mail.reply_to = "Mikel , another Mikel " + # mail.reply_to_addrs #=> [#, #] + def reply_to_addrs( default = nil ) + if h = @header['reply-to'] + h.addrs.blank? ? default : h.addrs + else + default + end + end + + # Destructively set the to value of the "Reply-To:" header to equal the passed in argument. + # + # TMail will parse your contents and turn each valid email address into a TMail::Address + # object before assigning it to the mail message. + # + # Example: + # + # mail = TMail::Mail.new + # mail.reply_to_addrs = "Mikel , another Mikel " + # mail.reply_to_addrs #=> [#, #] + def reply_to_addrs=( arg ) + set_addrfield 'reply-to', arg + end + + # Returns who the email is from as an Array of email address strings instead to an Array of + # TMail::Address objects which is what Mail#reply_to_addrs returns + # + # Example: + # + # mail = TMail::Mail.new + # mail.reply_to = "Mikel , another Mikel " + # mail.reply_to #=> ["mikel@me.org", "mikel@you.org"] + def reply_to( default = nil ) + addrs2specs(reply_to_addrs(nil)) || default + end + + # Destructively sets the "Reply-To:" field to the passed array of strings (which should be valid + # email addresses) + # + # Example: + # + # mail = TMail::Mail.new + # mail.reply_to = ["mikel@abc.com", "Mikel "] + # mail.reply_to #=> ["mikel@abc.org", "mikel@xyz.org"] + # mail['reply_to'].to_s #=> "mikel@abc.com, Mikel " + def reply_to=( *strs ) + set_string_array_attr 'Reply-To', strs + end + + # Return a TMail::Addresses instance of the "Sender:" field of the mail object header. + # + # If the "Sender:" field does not exist, will return nil by default or the value you + # pass as the optional parameter. + # + # Example: + # + # mail = TMail::Mail.new + # mail.sender #=> nil + # mail.sender([]) #=> [] + # mail.sender = "Mikel " + # mail.reply_to_addrs #=> [#] + def sender_addr( default = nil ) + f = @header['sender'] or return default + f.addr or return default + end + + # Destructively set the to value of the "Sender:" header to equal the passed in argument. + # + # TMail will parse your contents and turn each valid email address into a TMail::Address + # object before assigning it to the mail message. + # + # Example: + # + # mail = TMail::Mail.new + # mail.sender_addrs = "Mikel , another Mikel " + # mail.sender_addrs #=> [#, #] + def sender_addr=( addr ) + if addr + h = HeaderField.internal_new('sender', @config) + h.addr = addr + @header['sender'] = h + else + @header.delete 'sender' + end + addr + end + + # Returns who the sender of this mail is as string instead to an Array of + # TMail::Address objects which is what Mail#sender_addr returns + # + # Example: + # + # mail = TMail::Mail.new + # mail.sender = "Mikel " + # mail.sender #=> "mikel@me.org" + def sender( default = nil ) + f = @header['sender'] or return default + a = f.addr or return default + a.spec + end + + # Destructively sets the "Sender:" field to the passed string (which should be a valid + # email address) + # + # Example: + # + # mail = TMail::Mail.new + # mail.sender = "mikel@abc.com" + # mail.sender #=> "mikel@abc.org" + # mail['sender'].to_s #=> "mikel@abc.com" + def sender=( str ) + set_string_attr 'Sender', str + end + + #== Subject methods + + # Returns the subject of the mail instance. + # + # If the subject field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.subject #=> nil + # mail.subject("") #=> "" + # mail.subject = "Hello" + # mail.subject #=> "Hello" + def subject( default = nil ) + if h = @header['subject'] + h.body + else + default + end + end + alias quoted_subject subject + + # Destructively sets the passed string as the subject of the mail message. + # + # Example + # + # mail = TMail::Mail.new + # mail.subject #=> "This subject" + # mail.subject = "Another subject" + # mail.subject #=> "Another subject" + def subject=( str ) + set_string_attr 'Subject', str + end + + #== Message Identity & Threading Methods + + # Returns the message ID for this mail object instance. + # + # If the message_id field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.message_id #=> nil + # mail.message_id(TMail.new_message_id) #=> "<47404c5326d9c_2ad4fbb80161@baci.local.tmail>" + # mail.message_id = TMail.new_message_id + # mail.message_id #=> "<47404c5326d9c_2ad4fbb80161@baci.local.tmail>" + def message_id( default = nil ) + if h = @header['message-id'] + h.id || default + else + default + end + end + + # Destructively sets the message ID of the mail object instance to the passed in string + # + # Invalid message IDs are ignored (silently, unless configured otherwise) and result in + # a nil message ID. Left and right angle brackets are required. + # + # Example: + # + # mail = TMail::Mail.new + # mail.message_id = "<348F04F142D69C21-291E56D292BC@xxxx.net>" + # mail.message_id #=> "<348F04F142D69C21-291E56D292BC@xxxx.net>" + # mail.message_id = "this_is_my_badly_formatted_message_id" + # mail.message_id #=> nil + def message_id=( str ) + set_string_attr 'Message-Id', str + end + + # Returns the "In-Reply-To:" field contents as an array of this mail instance if it exists + # + # If the in_reply_to field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.in_reply_to #=> nil + # mail.in_reply_to([]) #=> [] + # TMail::Mail.load("../test/fixtures/raw_email_reply") + # mail.in_reply_to #=> ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] + def in_reply_to( default = nil ) + if h = @header['in-reply-to'] + h.ids + else + default + end + end + + # Destructively sets the value of the "In-Reply-To:" field of an email. + # + # Accepts an array of a single string of a message id + # + # Example: + # + # mail = TMail::Mail.new + # mail.in_reply_to = ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] + # mail.in_reply_to #=> ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] + def in_reply_to=( *idstrs ) + set_string_array_attr 'In-Reply-To', idstrs + end + + # Returns the references of this email (prior messages relating to this message) + # as an array of message ID strings. Useful when you are trying to thread an + # email. + # + # If the references field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.references #=> nil + # mail.references([]) #=> [] + # mail = TMail::Mail.load("../test/fixtures/raw_email_reply") + # mail.references #=> ["<473FF3B8.9020707@xxx.org>", "<348F04F142D69C21-291E56D292BC@xxxx.net>"] + def references( default = nil ) + if h = @header['references'] + h.refs + else + default + end + end + + # Destructively sets the value of the "References:" field of an email. + # + # Accepts an array of strings of message IDs + # + # Example: + # + # mail = TMail::Mail.new + # mail.references = ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] + # mail.references #=> ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] + def references=( *strs ) + set_string_array_attr 'References', strs + end + + #== MIME header methods + + # Returns the listed MIME version of this email from the "Mime-Version:" header field + # + # If the mime_version field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.mime_version #=> nil + # mail.mime_version([]) #=> [] + # mail = TMail::Mail.load("../test/fixtures/raw_email") + # mail.mime_version #=> "1.0" + def mime_version( default = nil ) + if h = @header['mime-version'] + h.version || default + else + default + end + end + + def mime_version=( m, opt = nil ) + if opt + if h = @header['mime-version'] + h.major = m + h.minor = opt + else + store 'Mime-Version', "#{m}.#{opt}" + end + else + store 'Mime-Version', m + end + m + end + + # Returns the current "Content-Type" of the mail instance. + # + # If the content_type field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.content_type #=> nil + # mail.content_type([]) #=> [] + # mail = TMail::Mail.load("../test/fixtures/raw_email") + # mail.content_type #=> "text/plain" + def content_type( default = nil ) + if h = @header['content-type'] + h.content_type || default + else + default + end + end + + # Returns the current main type of the "Content-Type" of the mail instance. + # + # If the content_type field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.main_type #=> nil + # mail.main_type([]) #=> [] + # mail = TMail::Mail.load("../test/fixtures/raw_email") + # mail.main_type #=> "text" + def main_type( default = nil ) + if h = @header['content-type'] + h.main_type || default + else + default + end + end + + # Returns the current sub type of the "Content-Type" of the mail instance. + # + # If the content_type field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.sub_type #=> nil + # mail.sub_type([]) #=> [] + # mail = TMail::Mail.load("../test/fixtures/raw_email") + # mail.sub_type #=> "plain" + def sub_type( default = nil ) + if h = @header['content-type'] + h.sub_type || default + else + default + end + end + + # Destructively sets the "Content-Type:" header field of this mail object + # + # Allows you to set the main type, sub type as well as parameters to the field. + # The main type and sub type need to be a string. + # + # The optional params hash can be passed with keys as symbols and values as a string, + # or strings as keys and values. + # + # Example: + # + # mail = TMail::Mail.new + # mail.set_content_type("text", "plain") + # mail.to_s #=> "Content-Type: text/plain\n\n" + # + # mail.set_content_type("text", "plain", {:charset => "EUC-KR", :format => "flowed"}) + # mail.to_s #=> "Content-Type: text/plain; charset=EUC-KR; format=flowed\n\n" + # + # mail.set_content_type("text", "plain", {"charset" => "EUC-KR", "format" => "flowed"}) + # mail.to_s #=> "Content-Type: text/plain; charset=EUC-KR; format=flowed\n\n" + def set_content_type( str, sub = nil, param = nil ) + if sub + main, sub = str, sub + else + main, sub = str.split(%r, 2) + raise ArgumentError, "sub type missing: #{str.inspect}" unless sub + end + if h = @header['content-type'] + h.main_type = main + h.sub_type = sub + h.params.clear + else + store 'Content-Type', "#{main}/#{sub}" + end + @header['content-type'].params.replace param if param + str + end + + alias content_type= set_content_type + + # Returns the named type parameter as a string, from the "Content-Type:" header. + # + # Example: + # + # mail = TMail::Mail.new + # mail.type_param("charset") #=> nil + # mail.type_param("charset", []) #=> [] + # mail.set_content_type("text", "plain", {:charset => "EUC-KR", :format => "flowed"}) + # mail.type_param("charset") #=> "EUC-KR" + # mail.type_param("format") #=> "flowed" + def type_param( name, default = nil ) + if h = @header['content-type'] + h[name] || default + else + default + end + end + + # Returns the character set of the email. Returns nil if no encoding set or returns + # whatever default you pass as a parameter - note passing the parameter does NOT change + # the mail object in any way. + # + # Example: + # + # mail = TMail::Mail.load("path_to/utf8_email") + # mail.charset #=> "UTF-8" + # + # mail = TMail::Mail.new + # mail.charset #=> nil + # mail.charset("US-ASCII") #=> "US-ASCII" + def charset( default = nil ) + if h = @header['content-type'] + h['charset'] or default + else + default + end + end + + # Destructively sets the character set used by this mail object to the passed string, you + # should note though that this does nothing to the mail body, just changes the header + # value, you will need to transliterate the body as well to match whatever you put + # in this header value if you are changing character sets. + # + # Example: + # + # mail = TMail::Mail.new + # mail.charset #=> nil + # mail.charset = "UTF-8" + # mail.charset #=> "UTF-8" + def charset=( str ) + if str + if h = @header[ 'content-type' ] + h['charset'] = str + else + store 'Content-Type', "text/plain; charset=#{str}" + end + end + str + end + + # Returns the transfer encoding of the email. Returns nil if no encoding set or returns + # whatever default you pass as a parameter - note passing the parameter does NOT change + # the mail object in any way. + # + # Example: + # + # mail = TMail::Mail.load("path_to/base64_encoded_email") + # mail.transfer_encoding #=> "base64" + # + # mail = TMail::Mail.new + # mail.transfer_encoding #=> nil + # mail.transfer_encoding("base64") #=> "base64" + def transfer_encoding( default = nil ) + if h = @header['content-transfer-encoding'] + h.encoding || default + else + default + end + end + + # Destructively sets the transfer encoding of the mail object to the passed string, you + # should note though that this does nothing to the mail body, just changes the header + # value, you will need to encode or decode the body as well to match whatever you put + # in this header value. + # + # Example: + # + # mail = TMail::Mail.new + # mail.transfer_encoding #=> nil + # mail.transfer_encoding = "base64" + # mail.transfer_encoding #=> "base64" + def transfer_encoding=( str ) + set_string_attr 'Content-Transfer-Encoding', str + end + + alias encoding transfer_encoding + alias encoding= transfer_encoding= + alias content_transfer_encoding transfer_encoding + alias content_transfer_encoding= transfer_encoding= + + # Returns the content-disposition of the mail object, returns nil or the passed + # default value if given + # + # Example: + # + # mail = TMail::Mail.load("path_to/raw_mail_with_attachment") + # mail.disposition #=> "attachment" + # + # mail = TMail::Mail.load("path_to/plain_simple_email") + # mail.disposition #=> nil + # mail.disposition(false) #=> false + def disposition( default = nil ) + if h = @header['content-disposition'] + h.disposition || default + else + default + end + end + + alias content_disposition disposition + + # Allows you to set the content-disposition of the mail object. Accepts a type + # and a hash of parameters. + # + # Example: + # + # mail.set_disposition("attachment", {:filename => "test.rb"}) + # mail.disposition #=> "attachment" + # mail['content-disposition'].to_s #=> "attachment; filename=test.rb" + def set_disposition( str, params = nil ) + if h = @header['content-disposition'] + h.disposition = str + h.params.clear + else + store('Content-Disposition', str) + h = @header['content-disposition'] + end + h.params.replace params if params + end + + alias disposition= set_disposition + alias set_content_disposition set_disposition + alias content_disposition= set_disposition + + # Returns the value of a parameter in an existing content-disposition header + # + # Example: + # + # mail.set_disposition("attachment", {:filename => "test.rb"}) + # mail['content-disposition'].to_s #=> "attachment; filename=test.rb" + # mail.disposition_param("filename") #=> "test.rb" + # mail.disposition_param("missing_param_key") #=> nil + # mail.disposition_param("missing_param_key", false) #=> false + # mail.disposition_param("missing_param_key", "Nothing to see here") #=> "Nothing to see here" + def disposition_param( name, default = nil ) + if h = @header['content-disposition'] + h[name] || default + else + default + end + end + + # Convert the Mail object's body into a Base64 encoded email + # returning the modified Mail object + def base64_encode! + store 'Content-Transfer-Encoding', 'Base64' + self.body = base64_encode + end + + # Return the result of encoding the TMail::Mail object body + # without altering the current body + def base64_encode + Base64.folding_encode(self.body) + end + + # Convert the Mail object's body into a Base64 decoded email + # returning the modified Mail object + def base64_decode! + if /base64/i === self.transfer_encoding('') + store 'Content-Transfer-Encoding', '8bit' + self.body = base64_decode + end + end + + # Returns the result of decoding the TMail::Mail object body + # without altering the current body + def base64_decode + Base64.decode(self.body, @config.strict_base64decode?) + end + + # Returns an array of each destination in the email message including to: cc: or bcc: + # + # Example: + # + # mail.to = "Mikel " + # mail.cc = "Trans " + # mail.bcc = "bob " + # mail.destinations #=> ["mikel@lindsaar.net", "t@t.com", "bob@me.com"] + def destinations( default = nil ) + ret = [] + %w( to cc bcc ).each do |nm| + if h = @header[nm] + h.addrs.each {|i| ret.push i.address } + end + end + ret.empty? ? default : ret + end + + # Yields a block of destination, yielding each as a string. + # (from the destinations example) + # mail.each_destination { |d| puts "#{d.class}: #{d}" } + # String: mikel@lindsaar.net + # String: t@t.com + # String: bob@me.com + def each_destination( &block ) + destinations([]).each do |i| + if Address === i + yield i + else + i.each(&block) + end + end + end + + alias each_dest each_destination + + # Returns an array of reply to addresses that the Mail object has, + # or if the Mail message has no reply-to, returns an array of the + # Mail objects from addresses. Else returns the default which can + # either be passed as a parameter or defaults to nil + # + # Example: + # mail.from = "Mikel " + # mail.reply_to = nil + # mail.reply_addresses #=> [""] + # + def reply_addresses( default = nil ) + reply_to_addrs(nil) or from_addrs(nil) or default + end + + # Returns the "sender" field as an array -> useful to find out who to + # send an error email to. + def error_reply_addresses( default = nil ) + if s = sender(nil) + [s] + else + from_addrs(default) + end + end + + # Returns true if the Mail object is a multipart message + def multipart? + main_type('').downcase == 'multipart' + end + + # Creates a new email in reply to self. Sets the In-Reply-To and + # References headers for you automagically. + # + # Example: + # mail = TMail::Mail.load("my_email") + # reply_email = mail.create_reply + # reply_email.class #=> TMail::Mail + # reply_email.references #=> [""] + # reply_email.in_reply_to #=> [""] + def create_reply + setup_reply create_empty_mail() + end + + # Creates a new email in reply to self. Sets the In-Reply-To and + # References headers for you automagically. + # + # Example: + # mail = TMail::Mail.load("my_email") + # forward_email = mail.create_forward + # forward_email.class #=> TMail::Mail + # forward_email.content_type #=> "multipart/mixed" + # forward_email.body #=> "Attachment: (unnamed)" + # forward_email.encoded #=> Returns the original email as a MIME attachment + def create_forward + setup_forward create_empty_mail() + end + + #:stopdoc: + private + + def create_empty_mail + self.class.new(StringPort.new(''), @config) + end + + def setup_reply( mail ) + if tmp = reply_addresses(nil) + mail.to_addrs = tmp + end + + mid = message_id(nil) + tmp = references(nil) || [] + tmp.push mid if mid + mail.in_reply_to = [mid] if mid + mail.references = tmp unless tmp.empty? + mail.subject = 'Re: ' + subject('').sub(/\A(?:\[[^\]]+\])?(?:\s*Re:)*\s*/i, '') + mail.mime_version = '1.0' + mail + end + + def setup_forward( mail ) + m = Mail.new(StringPort.new('')) + m.body = decoded + m.set_content_type 'message', 'rfc822' + m.encoding = encoding('7bit') + mail.parts.push m + # call encoded to reparse the message + mail.encoded + mail + end + + #:startdoc: + end # class Mail + +end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/loader.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/loader.rb new file mode 100644 index 0000000000..6c0e251102 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/loader.rb @@ -0,0 +1,3 @@ +#:stopdoc: +require 'tmail/mailbox' +#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb new file mode 100644 index 0000000000..5a319907ae --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb @@ -0,0 +1,578 @@ +=begin rdoc + += Mail class + +=end +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# 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. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + + + +require 'tmail/interface' +require 'tmail/encode' +require 'tmail/header' +require 'tmail/port' +require 'tmail/config' +require 'tmail/utils' +require 'tmail/attachments' +require 'tmail/quoting' +require 'socket' + +module TMail + + # == Mail Class + # + # Accessing a TMail object done via the TMail::Mail class. As email can be fairly complex + # creatures, you will find a large amount of accessor and setter methods in this class! + # + # Most of the below methods handle the header, in fact, what TMail does best is handle the + # header of the email object. There are only a few methods that deal directly with the body + # of the email, such as base64_encode and base64_decode. + # + # === Using TMail inside your code + # + # The usual way is to install the gem (see the {README}[link:/README] on how to do this) and + # then put at the top of your class: + # + # require 'tmail' + # + # You can then create a new TMail object in your code with: + # + # @email = TMail::Mail.new + # + # Or if you have an email as a string, you can initialize a new TMail::Mail object and get it + # to parse that string for you like so: + # + # @email = TMail::Mail.parse(email_text) + # + # You can also read a single email off the disk, for example: + # + # @email = TMail::Mail.load('filename.txt') + # + # Also, you can read a mailbox (usual unix mbox format) and end up with an array of TMail + # objects by doing something like this: + # + # # Note, we pass true as the last variable to open the mailbox read only + # mailbox = TMail::UNIXMbox.new("mailbox", nil, true) + # @emails = [] + # mailbox.each_port { |m| @emails << TMail::Mail.new(m) } + # + class Mail + + class << self + + # Opens an email that has been saved out as a file by itself. + # + # This function will read a file non-destructively and then parse + # the contents and return a TMail::Mail object. + # + # Does not handle multiple email mailboxes (like a unix mbox) for that + # use the TMail::UNIXMbox class. + # + # Example: + # mail = TMail::Mail.load('filename') + # + def load( fname ) + new(FilePort.new(fname)) + end + + alias load_from load + alias loadfrom load + + # Parses an email from the supplied string and returns a TMail::Mail + # object. + # + # Example: + # require 'rubygems'; require 'tmail' + # email_string =< # bodyport=nil> + # mail.body + # #=> "Hello there Mikel!\n\n" + def parse( str ) + new(StringPort.new(str)) + end + + end + + def initialize( port = nil, conf = DEFAULT_CONFIG ) #:nodoc: + @port = port || StringPort.new + @config = Config.to_config(conf) + + @header = {} + @body_port = nil + @body_parsed = false + @epilogue = '' + @parts = [] + + @port.ropen {|f| + parse_header f + parse_body f unless @port.reproducible? + } + end + + # Provides access to the port this email is using to hold it's data + # + # Example: + # mail = TMail::Mail.parse(email_string) + # mail.port + # #=> # + attr_reader :port + + def inspect + "\#<#{self.class} port=#{@port.inspect} bodyport=#{@body_port.inspect}>" + end + + # + # to_s interfaces + # + + public + + include StrategyInterface + + def write_back( eol = "\n", charset = 'e' ) + parse_body + @port.wopen {|stream| encoded eol, charset, stream } + end + + def accept( strategy ) + with_multipart_encoding(strategy) { + ordered_each do |name, field| + next if field.empty? + strategy.header_name canonical(name) + field.accept strategy + strategy.puts + end + strategy.puts + body_port().ropen {|r| + strategy.write r.read + } + } + end + + private + + def canonical( name ) + name.split(/-/).map {|s| s.capitalize }.join('-') + end + + def with_multipart_encoding( strategy ) + if parts().empty? # DO NOT USE @parts + yield + + else + bound = ::TMail.new_boundary + if @header.key? 'content-type' + @header['content-type'].params['boundary'] = bound + else + store 'Content-Type', % + end + + yield + + parts().each do |tm| + strategy.puts + strategy.puts '--' + bound + tm.accept strategy + end + strategy.puts + strategy.puts '--' + bound + '--' + strategy.write epilogue() + end + end + + ### + ### header + ### + + public + + ALLOW_MULTIPLE = { + 'received' => true, + 'resent-date' => true, + 'resent-from' => true, + 'resent-sender' => true, + 'resent-to' => true, + 'resent-cc' => true, + 'resent-bcc' => true, + 'resent-message-id' => true, + 'comments' => true, + 'keywords' => true + } + USE_ARRAY = ALLOW_MULTIPLE + + def header + @header.dup + end + + # Returns a TMail::AddressHeader object of the field you are querying. + # Examples: + # @mail['from'] #=> # + # @mail['to'] #=> # + # + # You can get the string value of this by passing "to_s" to the query: + # Example: + # @mail['to'].to_s #=> "mikel@test.com.au" + def []( key ) + @header[key.downcase] + end + + def sub_header(key, param) + (hdr = self[key]) ? hdr[param] : nil + end + + alias fetch [] + + # Allows you to set or delete TMail header objects at will. + # Eamples: + # @mail = TMail::Mail.new + # @mail['to'].to_s # => 'mikel@test.com.au' + # @mail['to'] = 'mikel@elsewhere.org' + # @mail['to'].to_s # => 'mikel@elsewhere.org' + # @mail.encoded # => "To: mikel@elsewhere.org\r\n\r\n" + # @mail['to'] = nil + # @mail['to'].to_s # => nil + # @mail.encoded # => "\r\n" + # + # Note: setting mail[] = nil actualy deletes the header field in question from the object, + # it does not just set the value of the hash to nil + def []=( key, val ) + dkey = key.downcase + + if val.nil? + @header.delete dkey + return nil + end + + case val + when String + header = new_hf(key, val) + when HeaderField + ; + when Array + ALLOW_MULTIPLE.include? dkey or + raise ArgumentError, "#{key}: Header must not be multiple" + @header[dkey] = val + return val + else + header = new_hf(key, val.to_s) + end + if ALLOW_MULTIPLE.include? dkey + (@header[dkey] ||= []).push header + else + @header[dkey] = header + end + + val + end + + alias store []= + + # Allows you to loop through each header in the TMail::Mail object in a block + # Example: + # @mail['to'] = 'mikel@elsewhere.org' + # @mail['from'] = 'me@me.com' + # @mail.each_header { |k,v| puts "#{k} = #{v}" } + # # => from = me@me.com + # # => to = mikel@elsewhere.org + def each_header + @header.each do |key, val| + [val].flatten.each {|v| yield key, v } + end + end + + alias each_pair each_header + + def each_header_name( &block ) + @header.each_key(&block) + end + + alias each_key each_header_name + + def each_field( &block ) + @header.values.flatten.each(&block) + end + + alias each_value each_field + + FIELD_ORDER = %w( + return-path received + resent-date resent-from resent-sender resent-to + resent-cc resent-bcc resent-message-id + date from sender reply-to to cc bcc + message-id in-reply-to references + subject comments keywords + mime-version content-type content-transfer-encoding + content-disposition content-description + ) + + def ordered_each + list = @header.keys + FIELD_ORDER.each do |name| + if list.delete(name) + [@header[name]].flatten.each {|v| yield name, v } + end + end + list.each do |name| + [@header[name]].flatten.each {|v| yield name, v } + end + end + + def clear + @header.clear + end + + def delete( key ) + @header.delete key.downcase + end + + def delete_if + @header.delete_if do |key,val| + if Array === val + val.delete_if {|v| yield key, v } + val.empty? + else + yield key, val + end + end + end + + def keys + @header.keys + end + + def key?( key ) + @header.key? key.downcase + end + + def values_at( *args ) + args.map {|k| @header[k.downcase] }.flatten + end + + alias indexes values_at + alias indices values_at + + private + + def parse_header( f ) + name = field = nil + unixfrom = nil + + while line = f.gets + case line + when /\A[ \t]/ # continue from prev line + raise SyntaxError, 'mail is began by space' unless field + field << ' ' << line.strip + + when /\A([^\: \t]+):\s*/ # new header line + add_hf name, field if field + name = $1 + field = $' #.strip + + when /\A\-*\s*\z/ # end of header + add_hf name, field if field + name = field = nil + break + + when /\AFrom (\S+)/ + unixfrom = $1 + + when /^charset=.*/ + + else + raise SyntaxError, "wrong mail header: '#{line.inspect}'" + end + end + add_hf name, field if name + + if unixfrom + add_hf 'Return-Path', "<#{unixfrom}>" unless @header['return-path'] + end + end + + def add_hf( name, field ) + key = name.downcase + field = new_hf(name, field) + + if ALLOW_MULTIPLE.include? key + (@header[key] ||= []).push field + else + @header[key] = field + end + end + + def new_hf( name, field ) + HeaderField.new(name, field, @config) + end + + ### + ### body + ### + + public + + def body_port + parse_body + @body_port + end + + def each( &block ) + body_port().ropen {|f| f.each(&block) } + end + + def quoted_body + body_port.ropen {|f| return f.read } + end + + def quoted_body= str + body_port.wopen { |f| f.write str } + str + end + + def body=( str ) + # Sets the body of the email to a new (encoded) string. + # + # We also reparses the email if the body is ever reassigned, this is a performance hit, however when + # you assign the body, you usually want to be able to make sure that you can access the attachments etc. + # + # Usage: + # + # mail.body = "Hello, this is\nthe body text" + # # => "Hello, this is\nthe body" + # mail.body + # # => "Hello, this is\nthe body" + @body_parsed = false + parse_body(StringInput.new(str)) + parse_body + @body_port.wopen {|f| f.write str } + str + end + + alias preamble quoted_body + alias preamble= quoted_body= + + def epilogue + parse_body + @epilogue.dup + end + + def epilogue=( str ) + parse_body + @epilogue = str + str + end + + def parts + parse_body + @parts + end + + def each_part( &block ) + parts().each(&block) + end + + # Returns true if the content type of this part of the email is + # a disposition attachment + def disposition_is_attachment? + (self['content-disposition'] && self['content-disposition'].disposition == "attachment") + end + + # Returns true if this part's content main type is text, else returns false. + # By main type is meant "text/plain" is text. "text/html" is text + def content_type_is_text? + self.header['content-type'] && (self.header['content-type'].main_type != "text") + end + + private + + def parse_body( f = nil ) + return if @body_parsed + if f + parse_body_0 f + else + @port.ropen {|f| + skip_header f + parse_body_0 f + } + end + @body_parsed = true + end + + def skip_header( f ) + while line = f.gets + return if /\A[\r\n]*\z/ === line + end + end + + def parse_body_0( f ) + if multipart? + read_multipart f + else + @body_port = @config.new_body_port(self) + @body_port.wopen {|w| + w.write f.read + } + end + end + + def read_multipart( src ) + bound = @header['content-type'].params['boundary'] + is_sep = /\A--#{Regexp.quote bound}(?:--)?[ \t]*(?:\n|\r\n|\r)/ + lastbound = "--#{bound}--" + + ports = [ @config.new_preamble_port(self) ] + begin + f = ports.last.wopen + while line = src.gets + if is_sep === line + f.close + break if line.strip == lastbound + ports.push @config.new_part_port(self) + f = ports.last.wopen + else + f << line + end + end + @epilogue = (src.read || '') + ensure + f.close if f and not f.closed? + end + + @body_port = ports.shift + @parts = ports.map {|p| self.class.new(p, @config) } + end + + end # class Mail + +end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mailbox.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mailbox.rb new file mode 100644 index 0000000000..b0bc6a7f74 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mailbox.rb @@ -0,0 +1,495 @@ +=begin rdoc + += Mailbox and Mbox interaction class + +=end +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# 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. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + +require 'tmail/port' +require 'socket' +require 'mutex_m' + + +unless [].respond_to?(:sort_by) +module Enumerable#:nodoc: + def sort_by + map {|i| [yield(i), i] }.sort {|a,b| a.first <=> b.first }.map {|i| i[1] } + end +end +end + + +module TMail + + class MhMailbox + + PORT_CLASS = MhPort + + def initialize( dir ) + edir = File.expand_path(dir) + raise ArgumentError, "not directory: #{dir}"\ + unless FileTest.directory? edir + @dirname = edir + @last_file = nil + @last_atime = nil + end + + def directory + @dirname + end + + alias dirname directory + + attr_accessor :last_atime + + def inspect + "#<#{self.class} #{@dirname}>" + end + + def close + end + + def new_port + PORT_CLASS.new(next_file_name()) + end + + def each_port + mail_files().each do |path| + yield PORT_CLASS.new(path) + end + @last_atime = Time.now + end + + alias each each_port + + def reverse_each_port + mail_files().reverse_each do |path| + yield PORT_CLASS.new(path) + end + @last_atime = Time.now + end + + alias reverse_each reverse_each_port + + # old #each_mail returns Port + #def each_mail + # each_port do |port| + # yield Mail.new(port) + # end + #end + + def each_new_port( mtime = nil, &block ) + mtime ||= @last_atime + return each_port(&block) unless mtime + return unless File.mtime(@dirname) >= mtime + + mail_files().each do |path| + yield PORT_CLASS.new(path) if File.mtime(path) > mtime + end + @last_atime = Time.now + end + + private + + def mail_files + Dir.entries(@dirname)\ + .select {|s| /\A\d+\z/ === s }\ + .map {|s| s.to_i }\ + .sort\ + .map {|i| "#{@dirname}/#{i}" }\ + .select {|path| FileTest.file? path } + end + + def next_file_name + unless n = @last_file + n = 0 + Dir.entries(@dirname)\ + .select {|s| /\A\d+\z/ === s }\ + .map {|s| s.to_i }.sort\ + .each do |i| + next unless FileTest.file? "#{@dirname}/#{i}" + n = i + end + end + begin + n += 1 + end while FileTest.exist? "#{@dirname}/#{n}" + @last_file = n + + "#{@dirname}/#{n}" + end + + end # MhMailbox + + MhLoader = MhMailbox + + + class UNIXMbox + + class << self + alias newobj new + end + + # Creates a new mailbox object that you can iterate through to collect the + # emails from with "each_port". + # + # You need to pass it a filename of a unix mailbox format file, the format of this + # file can be researched at this page at {wikipedia}[link:http://en.wikipedia.org/wiki/Mbox] + # + # ==== Parameters + # + # +filename+: The filename of the mailbox you want to open + # + # +tmpdir+: Can be set to override TMail using the system environment's temp dir. TMail will first + # use the temp dir specified by you (if any) or then the temp dir specified in the Environment's TEMP + # value then the value in the Environment's TMP value or failing all of the above, '/tmp' + # + # +readonly+: If set to false, each email you take from the mail box will be removed from the mailbox. + # default is *false* - ie, it *WILL* truncate your mailbox file to ZERO once it has read the emails out. + # + # ==== Options: + # + # None + # + # ==== Examples: + # + # # First show using readonly true: + # + # require 'ftools' + # File.size("../test/fixtures/mailbox") + # #=> 20426 + # + # mailbox = TMail::UNIXMbox.new("../test/fixtures/mailbox", nil, true) + # #=> # + # + # mailbox.each_port do |port| + # mail = TMail::Mail.new(port) + # puts mail.subject + # end + # #Testing mailbox 1 + # #Testing mailbox 2 + # #Testing mailbox 3 + # #Testing mailbox 4 + # require 'ftools' + # File.size?("../test/fixtures/mailbox") + # #=> 20426 + # + # # Now show with readonly set to the default false + # + # mailbox = TMail::UNIXMbox.new("../test/fixtures/mailbox") + # #=> # + # + # mailbox.each_port do |port| + # mail = TMail::Mail.new(port) + # puts mail.subject + # end + # #Testing mailbox 1 + # #Testing mailbox 2 + # #Testing mailbox 3 + # #Testing mailbox 4 + # + # File.size?("../test/fixtures/mailbox") + # #=> nil + def UNIXMbox.new( filename, tmpdir = nil, readonly = false ) + tmpdir = ENV['TEMP'] || ENV['TMP'] || '/tmp' + newobj(filename, "#{tmpdir}/ruby_tmail_#{$$}_#{rand()}", readonly, false) + end + + def UNIXMbox.lock( fname ) + begin + f = File.open(fname, 'r+') + f.flock File::LOCK_EX + yield f + ensure + f.flock File::LOCK_UN + f.close if f and not f.closed? + end + end + + def UNIXMbox.static_new( fname, dir, readonly = false ) + newobj(fname, dir, readonly, true) + end + + def initialize( fname, mhdir, readonly, static ) + @filename = fname + @readonly = readonly + @closed = false + + Dir.mkdir mhdir + @real = MhMailbox.new(mhdir) + @finalizer = UNIXMbox.mkfinal(@real, @filename, !@readonly, !static) + ObjectSpace.define_finalizer self, @finalizer + end + + def UNIXMbox.mkfinal( mh, mboxfile, writeback_p, cleanup_p ) + lambda { + if writeback_p + lock(mboxfile) {|f| + mh.each_port do |port| + f.puts create_from_line(port) + port.ropen {|r| + f.puts r.read + } + end + } + end + if cleanup_p + Dir.foreach(mh.dirname) do |fname| + next if /\A\.\.?\z/ === fname + File.unlink "#{mh.dirname}/#{fname}" + end + Dir.rmdir mh.dirname + end + } + end + + # make _From line + def UNIXMbox.create_from_line( port ) + sprintf 'From %s %s', + fromaddr(), TextUtils.time2str(File.mtime(port.filename)) + end + + def UNIXMbox.fromaddr(port) + h = HeaderField.new_from_port(port, 'Return-Path') || + HeaderField.new_from_port(port, 'From') || + HeaderField.new_from_port(port, 'EnvelopeSender') or return 'nobody' + a = h.addrs[0] or return 'nobody' + a.spec + end + + def close + return if @closed + + ObjectSpace.undefine_finalizer self + @finalizer.call + @finalizer = nil + @real = nil + @closed = true + @updated = nil + end + + def each_port( &block ) + close_check + update + @real.each_port(&block) + end + + alias each each_port + + def reverse_each_port( &block ) + close_check + update + @real.reverse_each_port(&block) + end + + alias reverse_each reverse_each_port + + # old #each_mail returns Port + #def each_mail( &block ) + # each_port do |port| + # yield Mail.new(port) + # end + #end + + def each_new_port( mtime = nil ) + close_check + update + @real.each_new_port(mtime) {|p| yield p } + end + + def new_port + close_check + @real.new_port + end + + private + + def close_check + @closed and raise ArgumentError, 'accessing already closed mbox' + end + + def update + return if FileTest.zero?(@filename) + return if @updated and File.mtime(@filename) < @updated + w = nil + port = nil + time = nil + UNIXMbox.lock(@filename) {|f| + begin + f.each do |line| + if /\AFrom / === line + w.close if w + File.utime time, time, port.filename if time + + port = @real.new_port + w = port.wopen + time = fromline2time(line) + else + w.print line if w + end + end + ensure + if w and not w.closed? + w.close + File.utime time, time, port.filename if time + end + end + f.truncate(0) unless @readonly + @updated = Time.now + } + end + + def fromline2time( line ) + m = /\AFrom \S+ \w+ (\w+) (\d+) (\d+):(\d+):(\d+) (\d+)/.match(line) \ + or return nil + Time.local(m[6].to_i, m[1], m[2].to_i, m[3].to_i, m[4].to_i, m[5].to_i) + end + + end # UNIXMbox + + MboxLoader = UNIXMbox + + + class Maildir + + extend Mutex_m + + PORT_CLASS = MaildirPort + + @seq = 0 + def Maildir.unique_number + synchronize { + @seq += 1 + return @seq + } + end + + def initialize( dir = nil ) + @dirname = dir || ENV['MAILDIR'] + raise ArgumentError, "not directory: #{@dirname}"\ + unless FileTest.directory? @dirname + @new = "#{@dirname}/new" + @tmp = "#{@dirname}/tmp" + @cur = "#{@dirname}/cur" + end + + def directory + @dirname + end + + def inspect + "#<#{self.class} #{@dirname}>" + end + + def close + end + + def each_port + mail_files(@cur).each do |path| + yield PORT_CLASS.new(path) + end + end + + alias each each_port + + def reverse_each_port + mail_files(@cur).reverse_each do |path| + yield PORT_CLASS.new(path) + end + end + + alias reverse_each reverse_each_port + + def new_port + fname = nil + tmpfname = nil + newfname = nil + + begin + fname = "#{Time.now.to_i}.#{$$}_#{Maildir.unique_number}.#{Socket.gethostname}" + + tmpfname = "#{@tmp}/#{fname}" + newfname = "#{@new}/#{fname}" + end while FileTest.exist? tmpfname + + if block_given? + File.open(tmpfname, 'w') {|f| yield f } + File.rename tmpfname, newfname + PORT_CLASS.new(newfname) + else + File.open(tmpfname, 'w') {|f| f.write "\n\n" } + PORT_CLASS.new(tmpfname) + end + end + + def each_new_port + mail_files(@new).each do |path| + dest = @cur + '/' + File.basename(path) + File.rename path, dest + yield PORT_CLASS.new(dest) + end + + check_tmp + end + + TOO_OLD = 60 * 60 * 36 # 36 hour + + def check_tmp + old = Time.now.to_i - TOO_OLD + + each_filename(@tmp) do |full, fname| + if FileTest.file? full and + File.stat(full).mtime.to_i < old + File.unlink full + end + end + end + + private + + def mail_files( dir ) + Dir.entries(dir)\ + .select {|s| s[0] != ?. }\ + .sort_by {|s| s.slice(/\A\d+/).to_i }\ + .map {|s| "#{dir}/#{s}" }\ + .select {|path| FileTest.file? path } + end + + def each_filename( dir ) + Dir.foreach(dir) do |fname| + path = "#{dir}/#{fname}" + if fname[0] != ?. and FileTest.file? path + yield path, fname + end + end + end + + end # Maildir + + MaildirLoader = Maildir + +end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/main.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/main.rb new file mode 100644 index 0000000000..e52772793f --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/main.rb @@ -0,0 +1,6 @@ +#:stopdoc: +require 'tmail/version' +require 'tmail/mail' +require 'tmail/mailbox' +require 'tmail/core_extensions' +#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mbox.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mbox.rb new file mode 100644 index 0000000000..6c0e251102 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mbox.rb @@ -0,0 +1,3 @@ +#:stopdoc: +require 'tmail/mailbox' +#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/net.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/net.rb new file mode 100644 index 0000000000..65147228a1 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/net.rb @@ -0,0 +1,248 @@ +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# 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. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + +#:stopdoc: +require 'nkf' +#:startdoc: + +module TMail + + class Mail + + def send_to( smtp ) + do_send_to(smtp) do + ready_to_send + end + end + + def send_text_to( smtp ) + do_send_to(smtp) do + ready_to_send + mime_encode + end + end + + def do_send_to( smtp ) + from = from_address or raise ArgumentError, 'no from address' + (dests = destinations).empty? and raise ArgumentError, 'no receipient' + yield + send_to_0 smtp, from, dests + end + private :do_send_to + + def send_to_0( smtp, from, to ) + smtp.ready(from, to) do |f| + encoded "\r\n", 'j', f, '' + end + end + + def ready_to_send + delete_no_send_fields + add_message_id + add_date + end + + NOSEND_FIELDS = %w( + received + bcc + ) + + def delete_no_send_fields + NOSEND_FIELDS.each do |nm| + delete nm + end + delete_if {|n,v| v.empty? } + end + + def add_message_id( fqdn = nil ) + self.message_id = ::TMail::new_message_id(fqdn) + end + + def add_date + self.date = Time.now + end + + def mime_encode + if parts.empty? + mime_encode_singlepart + else + mime_encode_multipart true + end + end + + def mime_encode_singlepart + self.mime_version = '1.0' + b = body + if NKF.guess(b) != NKF::BINARY + mime_encode_text b + else + mime_encode_binary b + end + end + + def mime_encode_text( body ) + self.body = NKF.nkf('-j -m0', body) + self.set_content_type 'text', 'plain', {'charset' => 'iso-2022-jp'} + self.encoding = '7bit' + end + + def mime_encode_binary( body ) + self.body = [body].pack('m') + self.set_content_type 'application', 'octet-stream' + self.encoding = 'Base64' + end + + def mime_encode_multipart( top = true ) + self.mime_version = '1.0' if top + self.set_content_type 'multipart', 'mixed' + e = encoding(nil) + if e and not /\A(?:7bit|8bit|binary)\z/i === e + raise ArgumentError, + 'using C.T.Encoding with multipart mail is not permitted' + end + end + + end + + #:stopdoc: + class DeleteFields + + NOSEND_FIELDS = %w( + received + bcc + ) + + def initialize( nosend = nil, delempty = true ) + @no_send_fields = nosend || NOSEND_FIELDS.dup + @delete_empty_fields = delempty + end + + attr :no_send_fields + attr :delete_empty_fields, true + + def exec( mail ) + @no_send_fields.each do |nm| + delete nm + end + delete_if {|n,v| v.empty? } if @delete_empty_fields + end + + end + #:startdoc: + + #:stopdoc: + class AddMessageId + + def initialize( fqdn = nil ) + @fqdn = fqdn + end + + attr :fqdn, true + + def exec( mail ) + mail.message_id = ::TMail::new_msgid(@fqdn) + end + + end + #:startdoc: + + #:stopdoc: + class AddDate + + def exec( mail ) + mail.date = Time.now + end + + end + #:startdoc: + + #:stopdoc: + class MimeEncodeAuto + + def initialize( s = nil, m = nil ) + @singlepart_composer = s || MimeEncodeSingle.new + @multipart_composer = m || MimeEncodeMulti.new + end + + attr :singlepart_composer + attr :multipart_composer + + def exec( mail ) + if mail._builtin_multipart? + then @multipart_composer + else @singlepart_composer end.exec mail + end + + end + #:startdoc: + + #:stopdoc: + class MimeEncodeSingle + + def exec( mail ) + mail.mime_version = '1.0' + b = mail.body + if NKF.guess(b) != NKF::BINARY + on_text b + else + on_binary b + end + end + + def on_text( body ) + mail.body = NKF.nkf('-j -m0', body) + mail.set_content_type 'text', 'plain', {'charset' => 'iso-2022-jp'} + mail.encoding = '7bit' + end + + def on_binary( body ) + mail.body = [body].pack('m') + mail.set_content_type 'application', 'octet-stream' + mail.encoding = 'Base64' + end + + end + #:startdoc: + + #:stopdoc: + class MimeEncodeMulti + + def exec( mail, top = true ) + mail.mime_version = '1.0' if top + mail.set_content_type 'multipart', 'mixed' + e = encoding(nil) + if e and not /\A(?:7bit|8bit|binary)\z/i === e + raise ArgumentError, + 'using C.T.Encoding with multipart mail is not permitted' + end + mail.parts.each do |m| + exec m, false if m._builtin_multipart? + end + end + + end + #:startdoc: +end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/obsolete.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/obsolete.rb new file mode 100644 index 0000000000..22b0a126ca --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/obsolete.rb @@ -0,0 +1,132 @@ +=begin rdoc + += Obsolete methods that are depriciated + +If you really want to see them, go to lib/tmail/obsolete.rb and view to your +heart's content. + +=end +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# 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. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ +#:stopdoc: +module TMail #:nodoc: + + class Mail + alias include? key? + alias has_key? key? + + def values + ret = [] + each_field {|v| ret.push v } + ret + end + + def value?( val ) + HeaderField === val or return false + + [ @header[val.name.downcase] ].flatten.include? val + end + + alias has_value? value? + end + + class Mail + def from_addr( default = nil ) + addr, = from_addrs(nil) + addr || default + end + + def from_address( default = nil ) + if a = from_addr(nil) + a.spec + else + default + end + end + + alias from_address= from_addrs= + + def from_phrase( default = nil ) + if a = from_addr(nil) + a.phrase + else + default + end + end + + alias msgid message_id + alias msgid= message_id= + + alias each_dest each_destination + end + + class Address + alias route routes + alias addr spec + + def spec=( str ) + @local, @domain = str.split(/@/,2).map {|s| s.split(/\./) } + end + + alias addr= spec= + alias address= spec= + end + + class MhMailbox + alias new_mail new_port + alias each_mail each_port + alias each_newmail each_new_port + end + class UNIXMbox + alias new_mail new_port + alias each_mail each_port + alias each_newmail each_new_port + end + class Maildir + alias new_mail new_port + alias each_mail each_port + alias each_newmail each_new_port + end + + extend TextUtils + + class << self + alias msgid? message_id? + alias boundary new_boundary + alias msgid new_message_id + alias new_msgid new_message_id + end + + def Mail.boundary + ::TMail.new_boundary + end + + def Mail.msgid + ::TMail.new_message_id + end + +end # module TMail +#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/parser.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/parser.rb new file mode 100644 index 0000000000..ab1a828471 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/parser.rb @@ -0,0 +1,1476 @@ +#:stopdoc: +# DO NOT MODIFY!!!! +# This file is automatically generated by racc 1.4.5 +# from racc grammer file "parser.y". +# +# +# parser.rb: generated by racc (runtime embedded) +# +###### racc/parser.rb begin +unless $".index 'racc/parser.rb' +$".push 'racc/parser.rb' + +self.class.module_eval <<'..end racc/parser.rb modeval..id8076474214', 'racc/parser.rb', 1 +# +# $Id: parser.rb,v 1.7 2005/11/20 17:31:32 aamine Exp $ +# +# Copyright (c) 1999-2005 Minero Aoki +# +# This program is free software. +# You can distribute/modify this program under the same terms of ruby. +# +# As a special exception, when this code is copied by Racc +# into a Racc output file, you may use that output file +# without restriction. +# + +unless defined?(NotImplementedError) + NotImplementedError = NotImplementError +end + +module Racc + class ParseError < StandardError; end +end +unless defined?(::ParseError) + ParseError = Racc::ParseError +end + +module Racc + + unless defined?(Racc_No_Extentions) + Racc_No_Extentions = false + end + + class Parser + + Racc_Runtime_Version = '1.4.5' + Racc_Runtime_Revision = '$Revision: 1.7 $'.split[1] + + Racc_Runtime_Core_Version_R = '1.4.5' + Racc_Runtime_Core_Revision_R = '$Revision: 1.7 $'.split[1] + begin + require 'racc/cparse' + # Racc_Runtime_Core_Version_C = (defined in extention) + Racc_Runtime_Core_Revision_C = Racc_Runtime_Core_Id_C.split[2] + unless new.respond_to?(:_racc_do_parse_c, true) + raise LoadError, 'old cparse.so' + end + if Racc_No_Extentions + raise LoadError, 'selecting ruby version of racc runtime core' + end + + Racc_Main_Parsing_Routine = :_racc_do_parse_c + Racc_YY_Parse_Method = :_racc_yyparse_c + Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_C + Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_C + Racc_Runtime_Type = 'c' + rescue LoadError + Racc_Main_Parsing_Routine = :_racc_do_parse_rb + Racc_YY_Parse_Method = :_racc_yyparse_rb + Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_R + Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_R + Racc_Runtime_Type = 'ruby' + end + + def Parser.racc_runtime_type + Racc_Runtime_Type + end + + private + + def _racc_setup + @yydebug = false unless self.class::Racc_debug_parser + @yydebug = false unless defined?(@yydebug) + if @yydebug + @racc_debug_out = $stderr unless defined?(@racc_debug_out) + @racc_debug_out ||= $stderr + end + arg = self.class::Racc_arg + arg[13] = true if arg.size < 14 + arg + end + + def _racc_init_sysvars + @racc_state = [0] + @racc_tstack = [] + @racc_vstack = [] + + @racc_t = nil + @racc_val = nil + + @racc_read_next = true + + @racc_user_yyerror = false + @racc_error_status = 0 + end + + ### + ### do_parse + ### + + def do_parse + __send__(Racc_Main_Parsing_Routine, _racc_setup(), false) + end + + def next_token + raise NotImplementedError, "#{self.class}\#next_token is not defined" + end + + def _racc_do_parse_rb(arg, in_debug) + action_table, action_check, action_default, action_pointer, + goto_table, goto_check, goto_default, goto_pointer, + nt_base, reduce_table, token_table, shift_n, + reduce_n, use_result, * = arg + + _racc_init_sysvars + tok = act = i = nil + nerr = 0 + + catch(:racc_end_parse) { + while true + if i = action_pointer[@racc_state[-1]] + if @racc_read_next + if @racc_t != 0 # not EOF + tok, @racc_val = next_token() + unless tok # EOF + @racc_t = 0 + else + @racc_t = (token_table[tok] or 1) # error token + end + racc_read_token(@racc_t, tok, @racc_val) if @yydebug + @racc_read_next = false + end + end + i += @racc_t + unless i >= 0 and + act = action_table[i] and + action_check[i] == @racc_state[-1] + act = action_default[@racc_state[-1]] + end + else + act = action_default[@racc_state[-1]] + end + while act = _racc_evalact(act, arg) + ; + end + end + } + end + + ### + ### yyparse + ### + + def yyparse(recv, mid) + __send__(Racc_YY_Parse_Method, recv, mid, _racc_setup(), true) + end + + def _racc_yyparse_rb(recv, mid, arg, c_debug) + action_table, action_check, action_default, action_pointer, + goto_table, goto_check, goto_default, goto_pointer, + nt_base, reduce_table, token_table, shift_n, + reduce_n, use_result, * = arg + + _racc_init_sysvars + tok = nil + act = nil + i = nil + nerr = 0 + + catch(:racc_end_parse) { + until i = action_pointer[@racc_state[-1]] + while act = _racc_evalact(action_default[@racc_state[-1]], arg) + ; + end + end + recv.__send__(mid) do |tok, val| + unless tok + @racc_t = 0 + else + @racc_t = (token_table[tok] or 1) # error token + end + @racc_val = val + @racc_read_next = false + + i += @racc_t + unless i >= 0 and + act = action_table[i] and + action_check[i] == @racc_state[-1] + act = action_default[@racc_state[-1]] + end + while act = _racc_evalact(act, arg) + ; + end + + while not (i = action_pointer[@racc_state[-1]]) or + not @racc_read_next or + @racc_t == 0 # $ + unless i and i += @racc_t and + i >= 0 and + act = action_table[i] and + action_check[i] == @racc_state[-1] + act = action_default[@racc_state[-1]] + end + while act = _racc_evalact(act, arg) + ; + end + end + end + } + end + + ### + ### common + ### + + def _racc_evalact(act, arg) + action_table, action_check, action_default, action_pointer, + goto_table, goto_check, goto_default, goto_pointer, + nt_base, reduce_table, token_table, shift_n, + reduce_n, use_result, * = arg + nerr = 0 # tmp + + if act > 0 and act < shift_n + # + # shift + # + if @racc_error_status > 0 + @racc_error_status -= 1 unless @racc_t == 1 # error token + end + @racc_vstack.push @racc_val + @racc_state.push act + @racc_read_next = true + if @yydebug + @racc_tstack.push @racc_t + racc_shift @racc_t, @racc_tstack, @racc_vstack + end + + elsif act < 0 and act > -reduce_n + # + # reduce + # + code = catch(:racc_jump) { + @racc_state.push _racc_do_reduce(arg, act) + false + } + if code + case code + when 1 # yyerror + @racc_user_yyerror = true # user_yyerror + return -reduce_n + when 2 # yyaccept + return shift_n + else + raise '[Racc Bug] unknown jump code' + end + end + + elsif act == shift_n + # + # accept + # + racc_accept if @yydebug + throw :racc_end_parse, @racc_vstack[0] + + elsif act == -reduce_n + # + # error + # + case @racc_error_status + when 0 + unless arg[21] # user_yyerror + nerr += 1 + on_error @racc_t, @racc_val, @racc_vstack + end + when 3 + if @racc_t == 0 # is $ + throw :racc_end_parse, nil + end + @racc_read_next = true + end + @racc_user_yyerror = false + @racc_error_status = 3 + while true + if i = action_pointer[@racc_state[-1]] + i += 1 # error token + if i >= 0 and + (act = action_table[i]) and + action_check[i] == @racc_state[-1] + break + end + end + throw :racc_end_parse, nil if @racc_state.size <= 1 + @racc_state.pop + @racc_vstack.pop + if @yydebug + @racc_tstack.pop + racc_e_pop @racc_state, @racc_tstack, @racc_vstack + end + end + return act + + else + raise "[Racc Bug] unknown action #{act.inspect}" + end + + racc_next_state(@racc_state[-1], @racc_state) if @yydebug + + nil + end + + def _racc_do_reduce(arg, act) + action_table, action_check, action_default, action_pointer, + goto_table, goto_check, goto_default, goto_pointer, + nt_base, reduce_table, token_table, shift_n, + reduce_n, use_result, * = arg + state = @racc_state + vstack = @racc_vstack + tstack = @racc_tstack + + i = act * -3 + len = reduce_table[i] + reduce_to = reduce_table[i+1] + method_id = reduce_table[i+2] + void_array = [] + + tmp_t = tstack[-len, len] if @yydebug + tmp_v = vstack[-len, len] + tstack[-len, len] = void_array if @yydebug + vstack[-len, len] = void_array + state[-len, len] = void_array + + # tstack must be updated AFTER method call + if use_result + vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0]) + else + vstack.push __send__(method_id, tmp_v, vstack) + end + tstack.push reduce_to + + racc_reduce(tmp_t, reduce_to, tstack, vstack) if @yydebug + + k1 = reduce_to - nt_base + if i = goto_pointer[k1] + i += state[-1] + if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1 + return curstate + end + end + goto_default[k1] + end + + def on_error(t, val, vstack) + raise ParseError, sprintf("\nparse error on value %s (%s)", + val.inspect, token_to_str(t) || '?') + end + + def yyerror + throw :racc_jump, 1 + end + + def yyaccept + throw :racc_jump, 2 + end + + def yyerrok + @racc_error_status = 0 + end + + # + # for debugging output + # + + def racc_read_token(t, tok, val) + @racc_debug_out.print 'read ' + @racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') ' + @racc_debug_out.puts val.inspect + @racc_debug_out.puts + end + + def racc_shift(tok, tstack, vstack) + @racc_debug_out.puts "shift #{racc_token2str tok}" + racc_print_stacks tstack, vstack + @racc_debug_out.puts + end + + def racc_reduce(toks, sim, tstack, vstack) + out = @racc_debug_out + out.print 'reduce ' + if toks.empty? + out.print ' ' + else + toks.each {|t| out.print ' ', racc_token2str(t) } + end + out.puts " --> #{racc_token2str(sim)}" + + racc_print_stacks tstack, vstack + @racc_debug_out.puts + end + + def racc_accept + @racc_debug_out.puts 'accept' + @racc_debug_out.puts + end + + def racc_e_pop(state, tstack, vstack) + @racc_debug_out.puts 'error recovering mode: pop token' + racc_print_states state + racc_print_stacks tstack, vstack + @racc_debug_out.puts + end + + def racc_next_state(curstate, state) + @racc_debug_out.puts "goto #{curstate}" + racc_print_states state + @racc_debug_out.puts + end + + def racc_print_stacks(t, v) + out = @racc_debug_out + out.print ' [' + t.each_index do |i| + out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')' + end + out.puts ' ]' + end + + def racc_print_states(s) + out = @racc_debug_out + out.print ' [' + s.each {|st| out.print ' ', st } + out.puts ' ]' + end + + def racc_token2str(tok) + self.class::Racc_token_to_s_table[tok] or + raise "[Racc Bug] can't convert token #{tok} to string" + end + + def token_to_str(t) + self.class::Racc_token_to_s_table[t] + end + + end + +end +..end racc/parser.rb modeval..id8076474214 +end +###### racc/parser.rb end + + +# +# parser.rb +# +# Copyright (c) 1998-2007 Minero Aoki +# +# This program is free software. +# You can distribute/modify this program under the terms of +# the GNU Lesser General Public License version 2.1. +# + +require 'tmail/scanner' +require 'tmail/utils' + + +module TMail + + class Parser < Racc::Parser + +module_eval <<'..end parser.y modeval..id7b0b3dccb7', 'parser.y', 340 + + include TextUtils + + def self.parse( ident, str, cmt = nil ) + new.parse(ident, str, cmt) + end + + MAILP_DEBUG = false + + def initialize + self.debug = MAILP_DEBUG + end + + def debug=( flag ) + @yydebug = flag && Racc_debug_parser + @scanner_debug = flag + end + + def debug + @yydebug + end + + def parse( ident, str, comments = nil ) + @scanner = Scanner.new(str, ident, comments) + @scanner.debug = @scanner_debug + @first = [ident, ident] + result = yyparse(self, :parse_in) + comments.map! {|c| to_kcode(c) } if comments + result + end + + private + + def parse_in( &block ) + yield @first + @scanner.scan(&block) + end + + def on_error( t, val, vstack ) + raise SyntaxError, "parse error on token #{racc_token2str t}" + end + +..end parser.y modeval..id7b0b3dccb7 + +##### racc 1.4.5 generates ### + +racc_reduce_table = [ + 0, 0, :racc_error, + 2, 35, :_reduce_1, + 2, 35, :_reduce_2, + 2, 35, :_reduce_3, + 2, 35, :_reduce_4, + 2, 35, :_reduce_5, + 2, 35, :_reduce_6, + 2, 35, :_reduce_7, + 2, 35, :_reduce_8, + 2, 35, :_reduce_9, + 2, 35, :_reduce_10, + 2, 35, :_reduce_11, + 2, 35, :_reduce_12, + 6, 36, :_reduce_13, + 0, 48, :_reduce_none, + 2, 48, :_reduce_none, + 3, 49, :_reduce_16, + 5, 49, :_reduce_17, + 1, 50, :_reduce_18, + 7, 37, :_reduce_19, + 0, 51, :_reduce_none, + 2, 51, :_reduce_21, + 0, 52, :_reduce_none, + 2, 52, :_reduce_23, + 1, 58, :_reduce_24, + 3, 58, :_reduce_25, + 2, 58, :_reduce_26, + 0, 53, :_reduce_none, + 2, 53, :_reduce_28, + 0, 54, :_reduce_29, + 3, 54, :_reduce_30, + 0, 55, :_reduce_none, + 2, 55, :_reduce_32, + 2, 55, :_reduce_33, + 0, 56, :_reduce_none, + 2, 56, :_reduce_35, + 1, 61, :_reduce_36, + 1, 61, :_reduce_37, + 0, 57, :_reduce_none, + 2, 57, :_reduce_39, + 1, 38, :_reduce_none, + 1, 38, :_reduce_none, + 3, 38, :_reduce_none, + 1, 46, :_reduce_none, + 1, 46, :_reduce_none, + 1, 46, :_reduce_none, + 1, 39, :_reduce_none, + 2, 39, :_reduce_47, + 1, 64, :_reduce_48, + 3, 64, :_reduce_49, + 1, 68, :_reduce_none, + 1, 68, :_reduce_none, + 1, 69, :_reduce_52, + 3, 69, :_reduce_53, + 1, 47, :_reduce_none, + 1, 47, :_reduce_none, + 2, 47, :_reduce_56, + 2, 67, :_reduce_none, + 3, 65, :_reduce_58, + 2, 65, :_reduce_59, + 1, 70, :_reduce_60, + 2, 70, :_reduce_61, + 4, 62, :_reduce_62, + 3, 62, :_reduce_63, + 2, 72, :_reduce_none, + 2, 73, :_reduce_65, + 4, 73, :_reduce_66, + 3, 63, :_reduce_67, + 1, 63, :_reduce_68, + 1, 74, :_reduce_none, + 2, 74, :_reduce_70, + 1, 71, :_reduce_71, + 3, 71, :_reduce_72, + 1, 59, :_reduce_73, + 3, 59, :_reduce_74, + 1, 76, :_reduce_75, + 2, 76, :_reduce_76, + 1, 75, :_reduce_none, + 1, 75, :_reduce_none, + 1, 75, :_reduce_none, + 1, 77, :_reduce_none, + 1, 77, :_reduce_none, + 1, 77, :_reduce_none, + 1, 66, :_reduce_none, + 2, 66, :_reduce_none, + 3, 60, :_reduce_85, + 1, 40, :_reduce_86, + 3, 40, :_reduce_87, + 1, 79, :_reduce_none, + 2, 79, :_reduce_89, + 1, 41, :_reduce_90, + 2, 41, :_reduce_91, + 3, 42, :_reduce_92, + 5, 43, :_reduce_93, + 3, 43, :_reduce_94, + 0, 80, :_reduce_95, + 5, 80, :_reduce_96, + 5, 80, :_reduce_97, + 1, 44, :_reduce_98, + 3, 45, :_reduce_99, + 0, 81, :_reduce_none, + 1, 81, :_reduce_none, + 1, 78, :_reduce_none, + 1, 78, :_reduce_none, + 1, 78, :_reduce_none, + 1, 78, :_reduce_none, + 1, 78, :_reduce_none, + 1, 78, :_reduce_none, + 1, 78, :_reduce_none ] + +racc_reduce_n = 109 + +racc_shift_n = 167 + +racc_action_table = [ + -70, -69, 23, 25, 145, 146, 29, 31, 105, 106, + 16, 17, 20, 22, 136, 27, -70, -69, 32, 101, + -70, -69, 153, 100, 113, 115, -70, -69, -70, 109, + 75, 23, 25, 101, 154, 29, 31, 142, 143, 16, + 17, 20, 22, 107, 27, 23, 25, 32, 98, 29, + 31, 96, 94, 16, 17, 20, 22, 78, 27, 23, + 25, 32, 112, 29, 31, 74, 91, 16, 17, 20, + 22, 88, 117, 92, 81, 32, 23, 25, 80, 123, + 29, 31, 100, 125, 16, 17, 20, 22, 126, 23, + 25, 109, 32, 29, 31, 91, 128, 16, 17, 20, + 22, 129, 27, 23, 25, 32, 101, 29, 31, 101, + 130, 16, 17, 20, 22, 79, 52, 23, 25, 32, + 78, 29, 31, 133, 78, 16, 17, 20, 22, 77, + 23, 25, 75, 32, 29, 31, 65, 62, 16, 17, + 20, 22, 139, 23, 25, 101, 32, 29, 31, 60, + 100, 16, 17, 20, 22, 44, 27, 101, 147, 32, + 23, 25, 120, 148, 29, 31, 151, 152, 16, 17, + 20, 22, 42, 27, 156, 158, 32, 23, 25, 120, + 40, 29, 31, 15, 163, 16, 17, 20, 22, 40, + 27, 23, 25, 32, 68, 29, 31, 165, 166, 16, + 17, 20, 22, nil, 27, 23, 25, 32, nil, 29, + 31, 74, nil, 16, 17, 20, 22, nil, 23, 25, + nil, 32, 29, 31, nil, nil, 16, 17, 20, 22, + nil, 23, 25, nil, 32, 29, 31, nil, nil, 16, + 17, 20, 22, nil, 23, 25, nil, 32, 29, 31, + nil, nil, 16, 17, 20, 22, nil, 23, 25, nil, + 32, 29, 31, nil, nil, 16, 17, 20, 22, nil, + 27, 23, 25, 32, nil, 29, 31, nil, nil, 16, + 17, 20, 22, nil, 23, 25, nil, 32, 29, 31, + nil, nil, 16, 17, 20, 22, nil, 23, 25, nil, + 32, 29, 31, nil, nil, 16, 17, 20, 22, nil, + 84, 25, nil, 32, 29, 31, nil, 87, 16, 17, + 20, 22, 4, 6, 7, 8, 9, 10, 11, 12, + 13, 1, 2, 3, 84, 25, nil, nil, 29, 31, + nil, 87, 16, 17, 20, 22, 84, 25, nil, nil, + 29, 31, nil, 87, 16, 17, 20, 22, 84, 25, + nil, nil, 29, 31, nil, 87, 16, 17, 20, 22, + 84, 25, nil, nil, 29, 31, nil, 87, 16, 17, + 20, 22, 84, 25, nil, nil, 29, 31, nil, 87, + 16, 17, 20, 22, 84, 25, nil, nil, 29, 31, + nil, 87, 16, 17, 20, 22 ] + +racc_action_check = [ + 75, 28, 68, 68, 136, 136, 68, 68, 72, 72, + 68, 68, 68, 68, 126, 68, 75, 28, 68, 67, + 75, 28, 143, 66, 86, 86, 75, 28, 75, 75, + 28, 3, 3, 86, 143, 3, 3, 134, 134, 3, + 3, 3, 3, 73, 3, 151, 151, 3, 62, 151, + 151, 60, 56, 151, 151, 151, 151, 51, 151, 52, + 52, 151, 80, 52, 52, 52, 50, 52, 52, 52, + 52, 45, 89, 52, 42, 52, 71, 71, 41, 96, + 71, 71, 97, 98, 71, 71, 71, 71, 100, 7, + 7, 101, 71, 7, 7, 102, 104, 7, 7, 7, + 7, 105, 7, 8, 8, 7, 108, 8, 8, 111, + 112, 8, 8, 8, 8, 40, 8, 9, 9, 8, + 36, 9, 9, 117, 121, 9, 9, 9, 9, 33, + 10, 10, 70, 9, 10, 10, 13, 12, 10, 10, + 10, 10, 130, 2, 2, 131, 10, 2, 2, 11, + 135, 2, 2, 2, 2, 6, 2, 138, 139, 2, + 90, 90, 90, 140, 90, 90, 141, 142, 90, 90, + 90, 90, 5, 90, 147, 150, 90, 127, 127, 127, + 4, 127, 127, 1, 156, 127, 127, 127, 127, 158, + 127, 26, 26, 127, 26, 26, 26, 162, 163, 26, + 26, 26, 26, nil, 26, 27, 27, 26, nil, 27, + 27, 27, nil, 27, 27, 27, 27, nil, 154, 154, + nil, 27, 154, 154, nil, nil, 154, 154, 154, 154, + nil, 122, 122, nil, 154, 122, 122, nil, nil, 122, + 122, 122, 122, nil, 76, 76, nil, 122, 76, 76, + nil, nil, 76, 76, 76, 76, nil, 38, 38, nil, + 76, 38, 38, nil, nil, 38, 38, 38, 38, nil, + 38, 55, 55, 38, nil, 55, 55, nil, nil, 55, + 55, 55, 55, nil, 94, 94, nil, 55, 94, 94, + nil, nil, 94, 94, 94, 94, nil, 59, 59, nil, + 94, 59, 59, nil, nil, 59, 59, 59, 59, nil, + 114, 114, nil, 59, 114, 114, nil, 114, 114, 114, + 114, 114, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 77, 77, nil, nil, 77, 77, + nil, 77, 77, 77, 77, 77, 44, 44, nil, nil, + 44, 44, nil, 44, 44, 44, 44, 44, 113, 113, + nil, nil, 113, 113, nil, 113, 113, 113, 113, 113, + 88, 88, nil, nil, 88, 88, nil, 88, 88, 88, + 88, 88, 74, 74, nil, nil, 74, 74, nil, 74, + 74, 74, 74, 74, 129, 129, nil, nil, 129, 129, + nil, 129, 129, 129, 129, 129 ] + +racc_action_pointer = [ + 320, 152, 129, 17, 165, 172, 137, 75, 89, 103, + 116, 135, 106, 105, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, 177, 191, 1, nil, + nil, nil, nil, 109, nil, nil, 94, nil, 243, nil, + 99, 64, 74, nil, 332, 52, nil, nil, nil, nil, + 50, 31, 45, nil, nil, 257, 36, nil, nil, 283, + 22, nil, 16, nil, nil, nil, -3, -10, -12, nil, + 103, 62, -8, 15, 368, 0, 230, 320, nil, nil, + 47, nil, nil, nil, nil, nil, 4, nil, 356, 50, + 146, nil, nil, nil, 270, nil, 65, 56, 52, nil, + 57, 62, 79, nil, 68, 81, nil, nil, 77, nil, + nil, 80, 96, 344, 296, nil, nil, 108, nil, nil, + nil, 98, 217, nil, nil, nil, -19, 163, nil, 380, + 128, 116, nil, nil, 14, 124, -26, nil, 128, 141, + 148, 141, 152, 7, nil, nil, nil, 160, nil, nil, + 149, 31, nil, nil, 204, nil, 167, nil, 174, nil, + nil, nil, 169, 184, nil, nil, nil ] + +racc_action_default = [ + -109, -109, -109, -109, -14, -109, -20, -109, -109, -109, + -109, -109, -109, -109, -10, -95, -105, -106, -77, -44, + -107, -11, -108, -79, -43, -102, -109, -109, -60, -103, + -55, -104, -78, -68, -54, -71, -45, -12, -109, -1, + -109, -109, -109, -2, -109, -22, -51, -48, -50, -3, + -40, -41, -109, -46, -4, -86, -5, -88, -6, -90, + -109, -7, -95, -8, -9, -98, -100, -61, -59, -56, + -69, -109, -109, -109, -109, -75, -109, -109, -57, -15, + -109, 167, -73, -80, -82, -21, -24, -81, -109, -27, + -109, -83, -47, -89, -109, -91, -109, -100, -109, -99, + -101, -75, -58, -52, -109, -109, -64, -63, -65, -76, + -72, -67, -109, -109, -109, -26, -23, -109, -29, -49, + -84, -42, -87, -92, -94, -95, -109, -109, -62, -109, + -109, -25, -74, -28, -31, -100, -109, -53, -66, -109, + -109, -34, -109, -109, -93, -96, -97, -109, -18, -13, + -38, -109, -30, -33, -109, -32, -16, -19, -14, -35, + -36, -37, -109, -109, -39, -85, -17 ] + +racc_goto_table = [ + 39, 67, 70, 73, 38, 66, 69, 24, 37, 57, + 59, 36, 55, 67, 99, 90, 85, 157, 69, 108, + 83, 134, 111, 76, 49, 53, 141, 70, 73, 150, + 118, 89, 45, 155, 159, 149, 140, 21, 14, 19, + 119, 102, 64, 63, 61, 124, 70, 104, 58, 132, + 83, 56, 97, 83, 54, 93, 43, 5, 131, 95, + 116, nil, 76, nil, 83, 76, nil, 127, nil, 38, + nil, nil, nil, 103, 138, nil, 110, nil, nil, nil, + nil, nil, nil, 144, nil, nil, nil, nil, nil, 83, + 83, nil, nil, nil, 57, nil, nil, 122, nil, 121, + nil, nil, nil, nil, nil, 83, nil, nil, nil, nil, + nil, nil, nil, nil, nil, 135, nil, nil, nil, nil, + nil, nil, 93, nil, nil, nil, 70, 161, 38, 70, + 162, 160, 137, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, 164 ] + +racc_goto_check = [ + 2, 37, 37, 29, 36, 46, 28, 13, 13, 41, + 41, 31, 45, 37, 47, 32, 24, 23, 28, 25, + 44, 20, 25, 42, 4, 4, 21, 37, 29, 22, + 19, 18, 17, 26, 27, 16, 15, 12, 11, 33, + 34, 35, 10, 9, 8, 47, 37, 29, 7, 43, + 44, 6, 46, 44, 5, 41, 3, 1, 25, 41, + 24, nil, 42, nil, 44, 42, nil, 32, nil, 36, + nil, nil, nil, 13, 25, nil, 41, nil, nil, nil, + nil, nil, nil, 47, nil, nil, nil, nil, nil, 44, + 44, nil, nil, nil, 41, nil, nil, 45, nil, 31, + nil, nil, nil, nil, nil, 44, nil, nil, nil, nil, + nil, nil, nil, nil, nil, 46, nil, nil, nil, nil, + nil, nil, 41, nil, nil, nil, 37, 29, 36, 37, + 29, 28, 13, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, 2 ] + +racc_goto_pointer = [ + nil, 57, -4, 50, 17, 46, 42, 38, 33, 31, + 29, 37, 35, 5, nil, -94, -105, 26, -14, -59, + -97, -108, -112, -133, -28, -55, -110, -117, -20, -24, + nil, 9, -35, 37, -50, -27, 1, -25, nil, nil, + nil, 0, -5, -65, -24, 3, -10, -52 ] + +racc_goto_default = [ + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, 48, 41, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, 86, nil, nil, 30, 34, + 50, 51, nil, 46, 47, nil, 26, 28, 71, 72, + 33, 35, 114, 82, 18, nil, nil, nil ] + +racc_token_table = { + false => 0, + Object.new => 1, + :DATETIME => 2, + :RECEIVED => 3, + :MADDRESS => 4, + :RETPATH => 5, + :KEYWORDS => 6, + :ENCRYPTED => 7, + :MIMEVERSION => 8, + :CTYPE => 9, + :CENCODING => 10, + :CDISPOSITION => 11, + :ADDRESS => 12, + :MAILBOX => 13, + :DIGIT => 14, + :ATOM => 15, + "," => 16, + ":" => 17, + :FROM => 18, + :BY => 19, + "@" => 20, + :DOMLIT => 21, + :VIA => 22, + :WITH => 23, + :ID => 24, + :FOR => 25, + ";" => 26, + "<" => 27, + ">" => 28, + "." => 29, + :QUOTED => 30, + :TOKEN => 31, + "/" => 32, + "=" => 33 } + +racc_use_result_var = false + +racc_nt_base = 34 + +Racc_arg = [ + racc_action_table, + racc_action_check, + racc_action_default, + racc_action_pointer, + racc_goto_table, + racc_goto_check, + racc_goto_default, + racc_goto_pointer, + racc_nt_base, + racc_reduce_table, + racc_token_table, + racc_shift_n, + racc_reduce_n, + racc_use_result_var ] + +Racc_token_to_s_table = [ +'$end', +'error', +'DATETIME', +'RECEIVED', +'MADDRESS', +'RETPATH', +'KEYWORDS', +'ENCRYPTED', +'MIMEVERSION', +'CTYPE', +'CENCODING', +'CDISPOSITION', +'ADDRESS', +'MAILBOX', +'DIGIT', +'ATOM', +'","', +'":"', +'FROM', +'BY', +'"@"', +'DOMLIT', +'VIA', +'WITH', +'ID', +'FOR', +'";"', +'"<"', +'">"', +'"."', +'QUOTED', +'TOKEN', +'"/"', +'"="', +'$start', +'content', +'datetime', +'received', +'addrs_TOP', +'retpath', +'keys', +'enc', +'version', +'ctype', +'cencode', +'cdisp', +'addr_TOP', +'mbox', +'day', +'hour', +'zone', +'from', +'by', +'via', +'with', +'id', +'for', +'received_datetime', +'received_domain', +'domain', +'msgid', +'received_addrspec', +'routeaddr', +'spec', +'addrs', +'group_bare', +'commas', +'group', +'addr', +'mboxes', +'addr_phrase', +'local_head', +'routes', +'at_domains', +'local', +'word', +'dots', +'domword', +'atom', +'phrase', +'params', +'opt_semicolon'] + +Racc_debug_parser = false + +##### racc system variables end ##### + + # reduce 0 omitted + +module_eval <<'.,.,', 'parser.y', 16 + def _reduce_1( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 17 + def _reduce_2( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 18 + def _reduce_3( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 19 + def _reduce_4( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 20 + def _reduce_5( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 21 + def _reduce_6( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 22 + def _reduce_7( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 23 + def _reduce_8( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 24 + def _reduce_9( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 25 + def _reduce_10( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 26 + def _reduce_11( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 27 + def _reduce_12( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 36 + def _reduce_13( val, _values) + t = Time.gm(val[3].to_i, val[2], val[1].to_i, 0, 0, 0) + (t + val[4] - val[5]).localtime + end +.,., + + # reduce 14 omitted + + # reduce 15 omitted + +module_eval <<'.,.,', 'parser.y', 45 + def _reduce_16( val, _values) + (val[0].to_i * 60 * 60) + + (val[2].to_i * 60) + end +.,., + +module_eval <<'.,.,', 'parser.y', 51 + def _reduce_17( val, _values) + (val[0].to_i * 60 * 60) + + (val[2].to_i * 60) + + (val[4].to_i) + end +.,., + +module_eval <<'.,.,', 'parser.y', 56 + def _reduce_18( val, _values) + timezone_string_to_unixtime(val[0]) + end +.,., + +module_eval <<'.,.,', 'parser.y', 61 + def _reduce_19( val, _values) + val + end +.,., + + # reduce 20 omitted + +module_eval <<'.,.,', 'parser.y', 67 + def _reduce_21( val, _values) + val[1] + end +.,., + + # reduce 22 omitted + +module_eval <<'.,.,', 'parser.y', 73 + def _reduce_23( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 79 + def _reduce_24( val, _values) + join_domain(val[0]) + end +.,., + +module_eval <<'.,.,', 'parser.y', 83 + def _reduce_25( val, _values) + join_domain(val[2]) + end +.,., + +module_eval <<'.,.,', 'parser.y', 87 + def _reduce_26( val, _values) + join_domain(val[0]) + end +.,., + + # reduce 27 omitted + +module_eval <<'.,.,', 'parser.y', 93 + def _reduce_28( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 98 + def _reduce_29( val, _values) + [] + end +.,., + +module_eval <<'.,.,', 'parser.y', 103 + def _reduce_30( val, _values) + val[0].push val[2] + val[0] + end +.,., + + # reduce 31 omitted + +module_eval <<'.,.,', 'parser.y', 109 + def _reduce_32( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 113 + def _reduce_33( val, _values) + val[1] + end +.,., + + # reduce 34 omitted + +module_eval <<'.,.,', 'parser.y', 119 + def _reduce_35( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 125 + def _reduce_36( val, _values) + val[0].spec + end +.,., + +module_eval <<'.,.,', 'parser.y', 129 + def _reduce_37( val, _values) + val[0].spec + end +.,., + + # reduce 38 omitted + +module_eval <<'.,.,', 'parser.y', 136 + def _reduce_39( val, _values) + val[1] + end +.,., + + # reduce 40 omitted + + # reduce 41 omitted + + # reduce 42 omitted + + # reduce 43 omitted + + # reduce 44 omitted + + # reduce 45 omitted + + # reduce 46 omitted + +module_eval <<'.,.,', 'parser.y', 146 + def _reduce_47( val, _values) + [ Address.new(nil, nil) ] + end +.,., + +module_eval <<'.,.,', 'parser.y', 152 + def _reduce_48( val, _values) + val + end +.,., + +module_eval <<'.,.,', 'parser.y', 157 + def _reduce_49( val, _values) + val[0].push val[2] + val[0] + end +.,., + + # reduce 50 omitted + + # reduce 51 omitted + +module_eval <<'.,.,', 'parser.y', 165 + def _reduce_52( val, _values) + val + end +.,., + +module_eval <<'.,.,', 'parser.y', 170 + def _reduce_53( val, _values) + val[0].push val[2] + val[0] + end +.,., + + # reduce 54 omitted + + # reduce 55 omitted + +module_eval <<'.,.,', 'parser.y', 178 + def _reduce_56( val, _values) + val[1].phrase = Decoder.decode(val[0]) + val[1] + end +.,., + + # reduce 57 omitted + +module_eval <<'.,.,', 'parser.y', 185 + def _reduce_58( val, _values) + AddressGroup.new(val[0], val[2]) + end +.,., + +module_eval <<'.,.,', 'parser.y', 185 + def _reduce_59( val, _values) + AddressGroup.new(val[0], []) + end +.,., + +module_eval <<'.,.,', 'parser.y', 188 + def _reduce_60( val, _values) + val[0].join('.') + end +.,., + +module_eval <<'.,.,', 'parser.y', 189 + def _reduce_61( val, _values) + val[0] << ' ' << val[1].join('.') + end +.,., + +module_eval <<'.,.,', 'parser.y', 196 + def _reduce_62( val, _values) + val[2].routes.replace val[1] + val[2] + end +.,., + +module_eval <<'.,.,', 'parser.y', 200 + def _reduce_63( val, _values) + val[1] + end +.,., + + # reduce 64 omitted + +module_eval <<'.,.,', 'parser.y', 203 + def _reduce_65( val, _values) + [ val[1].join('.') ] + end +.,., + +module_eval <<'.,.,', 'parser.y', 204 + def _reduce_66( val, _values) + val[0].push val[3].join('.'); val[0] + end +.,., + +module_eval <<'.,.,', 'parser.y', 206 + def _reduce_67( val, _values) + Address.new( val[0], val[2] ) + end +.,., + +module_eval <<'.,.,', 'parser.y', 207 + def _reduce_68( val, _values) + Address.new( val[0], nil ) + end +.,., + + # reduce 69 omitted + +module_eval <<'.,.,', 'parser.y', 210 + def _reduce_70( val, _values) + val[0].push ''; val[0] + end +.,., + +module_eval <<'.,.,', 'parser.y', 213 + def _reduce_71( val, _values) + val + end +.,., + +module_eval <<'.,.,', 'parser.y', 222 + def _reduce_72( val, _values) + val[1].times do + val[0].push '' + end + val[0].push val[2] + val[0] + end +.,., + +module_eval <<'.,.,', 'parser.y', 224 + def _reduce_73( val, _values) + val + end +.,., + +module_eval <<'.,.,', 'parser.y', 233 + def _reduce_74( val, _values) + val[1].times do + val[0].push '' + end + val[0].push val[2] + val[0] + end +.,., + +module_eval <<'.,.,', 'parser.y', 234 + def _reduce_75( val, _values) + 0 + end +.,., + +module_eval <<'.,.,', 'parser.y', 235 + def _reduce_76( val, _values) + 1 + end +.,., + + # reduce 77 omitted + + # reduce 78 omitted + + # reduce 79 omitted + + # reduce 80 omitted + + # reduce 81 omitted + + # reduce 82 omitted + + # reduce 83 omitted + + # reduce 84 omitted + +module_eval <<'.,.,', 'parser.y', 253 + def _reduce_85( val, _values) + val[1] = val[1].spec + val.join('') + end +.,., + +module_eval <<'.,.,', 'parser.y', 254 + def _reduce_86( val, _values) + val + end +.,., + +module_eval <<'.,.,', 'parser.y', 255 + def _reduce_87( val, _values) + val[0].push val[2]; val[0] + end +.,., + + # reduce 88 omitted + +module_eval <<'.,.,', 'parser.y', 258 + def _reduce_89( val, _values) + val[0] << ' ' << val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 265 + def _reduce_90( val, _values) + val.push nil + val + end +.,., + +module_eval <<'.,.,', 'parser.y', 269 + def _reduce_91( val, _values) + val + end +.,., + +module_eval <<'.,.,', 'parser.y', 274 + def _reduce_92( val, _values) + [ val[0].to_i, val[2].to_i ] + end +.,., + +module_eval <<'.,.,', 'parser.y', 279 + def _reduce_93( val, _values) + [ val[0].downcase, val[2].downcase, decode_params(val[3]) ] + end +.,., + +module_eval <<'.,.,', 'parser.y', 283 + def _reduce_94( val, _values) + [ val[0].downcase, nil, decode_params(val[1]) ] + end +.,., + +module_eval <<'.,.,', 'parser.y', 288 + def _reduce_95( val, _values) + {} + end +.,., + +module_eval <<'.,.,', 'parser.y', 293 + def _reduce_96( val, _values) + val[0][ val[2].downcase ] = ('"' + val[4].to_s + '"') + val[0] + end +.,., + +module_eval <<'.,.,', 'parser.y', 298 + def _reduce_97( val, _values) + val[0][ val[2].downcase ] = val[4] + val[0] + end +.,., + +module_eval <<'.,.,', 'parser.y', 303 + def _reduce_98( val, _values) + val[0].downcase + end +.,., + +module_eval <<'.,.,', 'parser.y', 308 + def _reduce_99( val, _values) + [ val[0].downcase, decode_params(val[1]) ] + end +.,., + + # reduce 100 omitted + + # reduce 101 omitted + + # reduce 102 omitted + + # reduce 103 omitted + + # reduce 104 omitted + + # reduce 105 omitted + + # reduce 106 omitted + + # reduce 107 omitted + + # reduce 108 omitted + + def _reduce_none( val, _values) + val[0] + end + + end # class Parser + +end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/port.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/port.rb new file mode 100644 index 0000000000..445f0e632b --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/port.rb @@ -0,0 +1,379 @@ +=begin rdoc + += Port class + +=end +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# 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. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + +require 'tmail/stringio' + + +module TMail + + class Port + def reproducible? + false + end + end + + + ### + ### FilePort + ### + + class FilePort < Port + + def initialize( fname ) + @filename = File.expand_path(fname) + super() + end + + attr_reader :filename + + alias ident filename + + def ==( other ) + other.respond_to?(:filename) and @filename == other.filename + end + + alias eql? == + + def hash + @filename.hash + end + + def inspect + "#<#{self.class}:#{@filename}>" + end + + def reproducible? + true + end + + def size + File.size @filename + end + + + def ropen( &block ) + File.open(@filename, &block) + end + + def wopen( &block ) + File.open(@filename, 'w', &block) + end + + def aopen( &block ) + File.open(@filename, 'a', &block) + end + + + def read_all + ropen {|f| + return f.read + } + end + + + def remove + File.unlink @filename + end + + def move_to( port ) + begin + File.link @filename, port.filename + rescue Errno::EXDEV + copy_to port + end + File.unlink @filename + end + + alias mv move_to + + def copy_to( port ) + if FilePort === port + copy_file @filename, port.filename + else + File.open(@filename) {|r| + port.wopen {|w| + while s = r.sysread(4096) + w.write << s + end + } } + end + end + + alias cp copy_to + + private + + # from fileutils.rb + def copy_file( src, dest ) + st = r = w = nil + + File.open(src, 'rb') {|r| + File.open(dest, 'wb') {|w| + st = r.stat + begin + while true + w.write r.sysread(st.blksize) + end + rescue EOFError + end + } } + end + + end + + + module MailFlags + + def seen=( b ) + set_status 'S', b + end + + def seen? + get_status 'S' + end + + def replied=( b ) + set_status 'R', b + end + + def replied? + get_status 'R' + end + + def flagged=( b ) + set_status 'F', b + end + + def flagged? + get_status 'F' + end + + private + + def procinfostr( str, tag, true_p ) + a = str.upcase.split(//) + a.push true_p ? tag : nil + a.delete tag unless true_p + a.compact.sort.join('').squeeze + end + + end + + + class MhPort < FilePort + + include MailFlags + + private + + def set_status( tag, flag ) + begin + tmpfile = @filename + '.tmailtmp.' + $$.to_s + File.open(tmpfile, 'w') {|f| + write_status f, tag, flag + } + File.unlink @filename + File.link tmpfile, @filename + ensure + File.unlink tmpfile + end + end + + def write_status( f, tag, flag ) + stat = '' + File.open(@filename) {|r| + while line = r.gets + if line.strip.empty? + break + elsif m = /\AX-TMail-Status:/i.match(line) + stat = m.post_match.strip + else + f.print line + end + end + + s = procinfostr(stat, tag, flag) + f.puts 'X-TMail-Status: ' + s unless s.empty? + f.puts + + while s = r.read(2048) + f.write s + end + } + end + + def get_status( tag ) + File.foreach(@filename) {|line| + return false if line.strip.empty? + if m = /\AX-TMail-Status:/i.match(line) + return m.post_match.strip.include?(tag[0]) + end + } + false + end + + end + + + class MaildirPort < FilePort + + def move_to_new + new = replace_dir(@filename, 'new') + File.rename @filename, new + @filename = new + end + + def move_to_cur + new = replace_dir(@filename, 'cur') + File.rename @filename, new + @filename = new + end + + def replace_dir( path, dir ) + "#{File.dirname File.dirname(path)}/#{dir}/#{File.basename path}" + end + private :replace_dir + + + include MailFlags + + private + + MAIL_FILE = /\A(\d+\.[\d_]+\.[^:]+)(?:\:(\d),(\w+)?)?\z/ + + def set_status( tag, flag ) + if m = MAIL_FILE.match(File.basename(@filename)) + s, uniq, type, info, = m.to_a + return if type and type != '2' # do not change anything + newname = File.dirname(@filename) + '/' + + uniq + ':2,' + procinfostr(info.to_s, tag, flag) + else + newname = @filename + ':2,' + tag + end + + File.link @filename, newname + File.unlink @filename + @filename = newname + end + + def get_status( tag ) + m = MAIL_FILE.match(File.basename(@filename)) or return false + m[2] == '2' and m[3].to_s.include?(tag[0]) + end + + end + + + ### + ### StringPort + ### + + class StringPort < Port + + def initialize( str = '' ) + @buffer = str + super() + end + + def string + @buffer + end + + def to_s + @buffer.dup + end + + alias read_all to_s + + def size + @buffer.size + end + + def ==( other ) + StringPort === other and @buffer.equal? other.string + end + + alias eql? == + + def hash + @buffer.object_id.hash + end + + def inspect + "#<#{self.class}:id=#{sprintf '0x%x', @buffer.object_id}>" + end + + def reproducible? + true + end + + def ropen( &block ) + @buffer or raise Errno::ENOENT, "#{inspect} is already removed" + StringInput.open(@buffer, &block) + end + + def wopen( &block ) + @buffer = '' + StringOutput.new(@buffer, &block) + end + + def aopen( &block ) + @buffer ||= '' + StringOutput.new(@buffer, &block) + end + + def remove + @buffer = nil + end + + alias rm remove + + def copy_to( port ) + port.wopen {|f| + f.write @buffer + } + end + + alias cp copy_to + + def move_to( port ) + if StringPort === port + str = @buffer + port.instance_eval { @buffer = str } + else + copy_to port + end + remove + end + + end + +end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/quoting.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/quoting.rb new file mode 100644 index 0000000000..cb9f4288f1 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/quoting.rb @@ -0,0 +1,118 @@ +=begin rdoc + += Quoting methods + +=end +module TMail + class Mail + def subject(to_charset = 'utf-8') + Unquoter.unquote_and_convert_to(quoted_subject, to_charset) + end + + def unquoted_body(to_charset = 'utf-8') + from_charset = sub_header("content-type", "charset") + case (content_transfer_encoding || "7bit").downcase + when "quoted-printable" + # the default charset is set to iso-8859-1 instead of 'us-ascii'. + # This is needed as many mailer do not set the charset but send in ISO. This is only used if no charset is set. + if !from_charset.blank? && from_charset.downcase == 'us-ascii' + from_charset = 'iso-8859-1' + end + + Unquoter.unquote_quoted_printable_and_convert_to(quoted_body, + to_charset, from_charset, true) + when "base64" + Unquoter.unquote_base64_and_convert_to(quoted_body, to_charset, + from_charset) + when "7bit", "8bit" + Unquoter.convert_to(quoted_body, to_charset, from_charset) + when "binary" + quoted_body + else + quoted_body + end + end + + def body(to_charset = 'utf-8', &block) + attachment_presenter = block || Proc.new { |file_name| "Attachment: #{file_name}\n" } + + if multipart? + parts.collect { |part| + header = part["content-type"] + + if part.multipart? + part.body(to_charset, &attachment_presenter) + elsif header.nil? + "" + elsif !attachment?(part) + part.unquoted_body(to_charset) + else + attachment_presenter.call(header["name"] || "(unnamed)") + end + }.join + else + unquoted_body(to_charset) + end + end + end + + class Unquoter + class << self + def unquote_and_convert_to(text, to_charset, from_charset = "iso-8859-1", preserve_underscores=false) + return "" if text.nil? + text.gsub(/(.*?)(?:(?:=\?(.*?)\?(.)\?(.*?)\?=)|$)/) do + before = $1 + from_charset = $2 + quoting_method = $3 + text = $4 + + before = convert_to(before, to_charset, from_charset) if before.length > 0 + before + case quoting_method + when "q", "Q" then + unquote_quoted_printable_and_convert_to(text, to_charset, from_charset, preserve_underscores) + when "b", "B" then + unquote_base64_and_convert_to(text, to_charset, from_charset) + when nil then + # will be nil at the end of the string, due to the nature of + # the regex used. + "" + else + raise "unknown quoting method #{quoting_method.inspect}" + end + end + end + + def unquote_quoted_printable_and_convert_to(text, to, from, preserve_underscores=false) + text = text.gsub(/_/, " ") unless preserve_underscores + text = text.gsub(/\r\n|\r/, "\n") # normalize newlines + convert_to(text.unpack("M*").first, to, from) + end + + def unquote_base64_and_convert_to(text, to, from) + convert_to(Base64.decode(text), to, from) + end + + begin + require 'iconv' + def convert_to(text, to, from) + return text unless to && from + text ? Iconv.iconv(to, from, text).first : "" + rescue Iconv::IllegalSequence, Iconv::InvalidEncoding, Errno::EINVAL + # the 'from' parameter specifies a charset other than what the text + # actually is...not much we can do in this case but just return the + # unconverted text. + # + # Ditto if either parameter represents an unknown charset, like + # X-UNKNOWN. + text + end + rescue LoadError + # Not providing quoting support + def convert_to(text, to, from) + warn "Action Mailer: iconv not loaded; ignoring conversion from #{from} to #{to} (#{__FILE__}:#{__LINE__})" + text + end + end + end + end +end diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/require_arch.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/require_arch.rb new file mode 100644 index 0000000000..b4fffb8abb --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/require_arch.rb @@ -0,0 +1,58 @@ +#:stopdoc: +require 'rbconfig' + +# Attempts to require anative extension. +# Falls back to pure-ruby version, if it fails. +# +# This uses Config::CONFIG['arch'] from rbconfig. + +def require_arch(fname) + arch = Config::CONFIG['arch'] + begin + path = File.join("tmail", arch, fname) + require path + rescue LoadError => e + # try pre-built Windows binaries + if arch =~ /mswin/ + require File.join("tmail", 'mswin32', fname) + else + raise e + end + end +end + + +# def require_arch(fname) +# dext = Config::CONFIG['DLEXT'] +# begin +# if File.extname(fname) == dext +# path = fname +# else +# path = File.join("tmail","#{fname}.#{dext}") +# end +# require path +# rescue LoadError => e +# begin +# arch = Config::CONFIG['arch'] +# path = File.join("tmail", arch, "#{fname}.#{dext}") +# require path +# rescue LoadError +# case path +# when /i686/ +# path.sub!('i686', 'i586') +# when /i586/ +# path.sub!('i586', 'i486') +# when /i486/ +# path.sub!('i486', 'i386') +# else +# begin +# require fname + '.rb' +# rescue LoadError +# raise e +# end +# end +# retry +# end +# end +# end +#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner.rb new file mode 100644 index 0000000000..a5d01396b8 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner.rb @@ -0,0 +1,49 @@ +=begin rdoc + += Scanner for TMail + +=end +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# 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. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ +#:stopdoc: +#require 'tmail/require_arch' +require 'tmail/utils' +require 'tmail/config' + +module TMail + # NOTE: It woiuld be nice if these two libs could boith be called "tmailscanner", and + # the native extension would have precedence. However RubyGems boffs that up b/c + # it does not gaurantee load_path order. + begin + raise LoadError, 'Turned off native extentions by user choice' if ENV['NORUBYEXT'] + require('tmail/tmailscanner') # c extension + Scanner = TMailScanner + rescue LoadError + require 'tmail/scanner_r' + Scanner = TMailScanner + end +end +#:stopdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner_r.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner_r.rb new file mode 100644 index 0000000000..f2075502d8 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner_r.rb @@ -0,0 +1,261 @@ +# scanner_r.rb +# +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# 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. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ +#:stopdoc: +require 'tmail/config' + +module TMail + + class TMailScanner + + Version = '1.2.3' + Version.freeze + + MIME_HEADERS = { + :CTYPE => true, + :CENCODING => true, + :CDISPOSITION => true + } + + alnum = 'a-zA-Z0-9' + atomsyms = %q[ _#!$%&`'*+-{|}~^/=? ].strip + tokensyms = %q[ _#!$%&`'*+-{|}~^@. ].strip + atomchars = alnum + Regexp.quote(atomsyms) + tokenchars = alnum + Regexp.quote(tokensyms) + iso2022str = '\e(?!\(B)..(?:[^\e]+|\e(?!\(B)..)*\e\(B' + + eucstr = "(?:[\xa1-\xfe][\xa1-\xfe])+" + sjisstr = "(?:[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc])+" + utf8str = "(?:[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf][\x80-\xbf])+" + + quoted_with_iso2022 = /\A(?:[^\\\e"]+|#{iso2022str})+/n + domlit_with_iso2022 = /\A(?:[^\\\e\]]+|#{iso2022str})+/n + comment_with_iso2022 = /\A(?:[^\\\e()]+|#{iso2022str})+/n + + quoted_without_iso2022 = /\A[^\\"]+/n + domlit_without_iso2022 = /\A[^\\\]]+/n + comment_without_iso2022 = /\A[^\\()]+/n + + PATTERN_TABLE = {} + PATTERN_TABLE['EUC'] = + [ + /\A(?:[#{atomchars}]+|#{iso2022str}|#{eucstr})+/n, + /\A(?:[#{tokenchars}]+|#{iso2022str}|#{eucstr})+/n, + quoted_with_iso2022, + domlit_with_iso2022, + comment_with_iso2022 + ] + PATTERN_TABLE['SJIS'] = + [ + /\A(?:[#{atomchars}]+|#{iso2022str}|#{sjisstr})+/n, + /\A(?:[#{tokenchars}]+|#{iso2022str}|#{sjisstr})+/n, + quoted_with_iso2022, + domlit_with_iso2022, + comment_with_iso2022 + ] + PATTERN_TABLE['UTF8'] = + [ + /\A(?:[#{atomchars}]+|#{utf8str})+/n, + /\A(?:[#{tokenchars}]+|#{utf8str})+/n, + quoted_without_iso2022, + domlit_without_iso2022, + comment_without_iso2022 + ] + PATTERN_TABLE['NONE'] = + [ + /\A[#{atomchars}]+/n, + /\A[#{tokenchars}]+/n, + quoted_without_iso2022, + domlit_without_iso2022, + comment_without_iso2022 + ] + + + def initialize( str, scantype, comments ) + init_scanner str + @comments = comments || [] + @debug = false + + # fix scanner mode + @received = (scantype == :RECEIVED) + @is_mime_header = MIME_HEADERS[scantype] + + atom, token, @quoted_re, @domlit_re, @comment_re = PATTERN_TABLE[TMail.KCODE] + @word_re = (MIME_HEADERS[scantype] ? token : atom) + end + + attr_accessor :debug + + def scan( &block ) + if @debug + scan_main do |arr| + s, v = arr + printf "%7d %-10s %s\n", + rest_size(), + s.respond_to?(:id2name) ? s.id2name : s.inspect, + v.inspect + yield arr + end + else + scan_main(&block) + end + end + + private + + RECV_TOKEN = { + 'from' => :FROM, + 'by' => :BY, + 'via' => :VIA, + 'with' => :WITH, + 'id' => :ID, + 'for' => :FOR + } + + def scan_main + until eof? + if skip(/\A[\n\r\t ]+/n) # LWSP + break if eof? + end + + if s = readstr(@word_re) + if @is_mime_header + yield [:TOKEN, s] + else + # atom + if /\A\d+\z/ === s + yield [:DIGIT, s] + elsif @received + yield [RECV_TOKEN[s.downcase] || :ATOM, s] + else + yield [:ATOM, s] + end + end + + elsif skip(/\A"/) + yield [:QUOTED, scan_quoted_word()] + + elsif skip(/\A\[/) + yield [:DOMLIT, scan_domain_literal()] + + elsif skip(/\A\(/) + @comments.push scan_comment() + + else + c = readchar() + yield [c, c] + end + end + + yield [false, '$'] + end + + def scan_quoted_word + scan_qstr(@quoted_re, /\A"/, 'quoted-word') + end + + def scan_domain_literal + '[' + scan_qstr(@domlit_re, /\A\]/, 'domain-literal') + ']' + end + + def scan_qstr( pattern, terminal, type ) + result = '' + until eof? + if s = readstr(pattern) then result << s + elsif skip(terminal) then return result + elsif skip(/\A\\/) then result << readchar() + else + raise "TMail FATAL: not match in #{type}" + end + end + scan_error! "found unterminated #{type}" + end + + def scan_comment + result = '' + nest = 1 + content = @comment_re + + until eof? + if s = readstr(content) then result << s + elsif skip(/\A\)/) then nest -= 1 + return result if nest == 0 + result << ')' + elsif skip(/\A\(/) then nest += 1 + result << '(' + elsif skip(/\A\\/) then result << readchar() + else + raise 'TMail FATAL: not match in comment' + end + end + scan_error! 'found unterminated comment' + end + + # string scanner + + def init_scanner( str ) + @src = str + end + + def eof? + @src.empty? + end + + def rest_size + @src.size + end + + def readstr( re ) + if m = re.match(@src) + @src = m.post_match + m[0] + else + nil + end + end + + def readchar + readstr(/\A./) + end + + def skip( re ) + if m = re.match(@src) + @src = m.post_match + true + else + false + end + end + + def scan_error!( msg ) + raise SyntaxError, msg + end + + end + +end # module TMail +#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/stringio.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/stringio.rb new file mode 100644 index 0000000000..8357398788 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/stringio.rb @@ -0,0 +1,280 @@ +# encoding: utf-8 +=begin rdoc + += String handling class + +=end +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# 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. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + +class StringInput#:nodoc: + + include Enumerable + + class << self + + def new( str ) + if block_given? + begin + f = super + yield f + ensure + f.close if f + end + else + super + end + end + + alias open new + + end + + def initialize( str ) + @src = str + @pos = 0 + @closed = false + @lineno = 0 + end + + attr_reader :lineno + + def string + @src + end + + def inspect + "#<#{self.class}:#{@closed ? 'closed' : 'open'},src=#{@src[0,30].inspect}>" + end + + def close + stream_check! + @pos = nil + @closed = true + end + + def closed? + @closed + end + + def pos + stream_check! + [@pos, @src.size].min + end + + alias tell pos + + def seek( offset, whence = IO::SEEK_SET ) + stream_check! + case whence + when IO::SEEK_SET + @pos = offset + when IO::SEEK_CUR + @pos += offset + when IO::SEEK_END + @pos = @src.size - offset + else + raise ArgumentError, "unknown seek flag: #{whence}" + end + @pos = 0 if @pos < 0 + @pos = [@pos, @src.size + 1].min + offset + end + + def rewind + stream_check! + @pos = 0 + end + + def eof? + stream_check! + @pos > @src.size + end + + def each( &block ) + stream_check! + begin + @src.each(&block) + ensure + @pos = 0 + end + end + + def gets + stream_check! + if idx = @src.index(?\n, @pos) + idx += 1 # "\n".size + line = @src[ @pos ... idx ] + @pos = idx + @pos += 1 if @pos == @src.size + else + line = @src[ @pos .. -1 ] + @pos = @src.size + 1 + end + @lineno += 1 + + line + end + + def getc + stream_check! + ch = @src[@pos] + @pos += 1 + @pos += 1 if @pos == @src.size + ch + end + + def read( len = nil ) + stream_check! + return read_all unless len + str = @src[@pos, len] + @pos += len + @pos += 1 if @pos == @src.size + str + end + + alias sysread read + + def read_all + stream_check! + return nil if eof? + rest = @src[@pos ... @src.size] + @pos = @src.size + 1 + rest + end + + def stream_check! + @closed and raise IOError, 'closed stream' + end + +end + + +class StringOutput#:nodoc: + + class << self + + def new( str = '' ) + if block_given? + begin + f = super + yield f + ensure + f.close if f + end + else + super + end + end + + alias open new + + end + + def initialize( str = '' ) + @dest = str + @closed = false + end + + def close + @closed = true + end + + def closed? + @closed + end + + def string + @dest + end + + alias value string + alias to_str string + + def size + @dest.size + end + + alias pos size + + def inspect + "#<#{self.class}:#{@dest ? 'open' : 'closed'},#{object_id}>" + end + + def print( *args ) + stream_check! + raise ArgumentError, 'wrong # of argument (0 for >1)' if args.empty? + args.each do |s| + raise ArgumentError, 'nil not allowed' if s.nil? + @dest << s.to_s + end + nil + end + + def puts( *args ) + stream_check! + args.each do |str| + @dest << (s = str.to_s) + @dest << "\n" unless s[-1] == ?\n + end + @dest << "\n" if args.empty? + nil + end + + def putc( ch ) + stream_check! + @dest << ch.chr + nil + end + + def printf( *args ) + stream_check! + @dest << sprintf(*args) + nil + end + + def write( str ) + stream_check! + s = str.to_s + @dest << s + s.size + end + + alias syswrite write + + def <<( str ) + stream_check! + @dest << str.to_s + self + end + + private + + def stream_check! + @closed and raise IOError, 'closed stream' + end + +end diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/utils.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/utils.rb new file mode 100644 index 0000000000..dc594a4229 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/utils.rb @@ -0,0 +1,337 @@ +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# 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. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + +# = TMail - The EMail Swiss Army Knife for Ruby +# +# The TMail library provides you with a very complete way to handle and manipulate EMails +# from within your Ruby programs. +# +# Used as the backbone for email handling by the Ruby on Rails and Nitro web frameworks as +# well as a bunch of other Ruby apps including the Ruby-Talk mailing list to newsgroup email +# gateway, it is a proven and reliable email handler that won't let you down. +# +# Originally created by Minero Aoki, TMail has been recently picked up by Mikel Lindsaar and +# is being actively maintained. Numerous backlogged bug fixes have been applied as well as +# Ruby 1.9 compatibility and a swath of documentation to boot. +# +# TMail allows you to treat an email totally as an object and allow you to get on with your +# own programming without having to worry about crafting the perfect email address validation +# parser, or assembling an email from all it's component parts. +# +# TMail handles the most complex part of the email - the header. It generates and parses +# headers and provides you with instant access to their innards through simple and logically +# named accessor and setter methods. +# +# TMail also provides a wrapper to Net/SMTP as well as Unix Mailbox handling methods to +# directly read emails from your unix mailbox, parse them and use them. +# +# Following is the comprehensive list of methods to access TMail::Mail objects. You can also +# check out TMail::Mail, TMail::Address and TMail::Headers for other lists. +module TMail + + # Provides an exception to throw on errors in Syntax within TMail's parsers + class SyntaxError < StandardError; end + + # Provides a new email boundary to separate parts of the email. This is a random + # string based off the current time, so should be fairly unique. + # + # For Example: + # + # TMail.new_boundary + # #=> "mimepart_47bf656968207_25a8fbb80114" + # TMail.new_boundary + # #=> "mimepart_47bf66051de4_25a8fbb80240" + def TMail.new_boundary + 'mimepart_' + random_tag + end + + # Provides a new email message ID. You can use this to generate unique email message + # id's for your email so you can track them. + # + # Optionally takes a fully qualified domain name (default to the current hostname + # returned by Socket.gethostname) that will be appended to the message ID. + # + # For Example: + # + # email.message_id = TMail.new_message_id + # #=> "<47bf66845380e_25a8fbb80332@baci.local.tmail>" + # email.to_s + # #=> "Message-Id: <47bf668b633f1_25a8fbb80475@baci.local.tmail>\n\n" + # email.message_id = TMail.new_message_id("lindsaar.net") + # #=> "<47bf668b633f1_25a8fbb80475@lindsaar.net.tmail>" + # email.to_s + # #=> "Message-Id: <47bf668b633f1_25a8fbb80475@lindsaar.net.tmail>\n\n" + def TMail.new_message_id( fqdn = nil ) + fqdn ||= ::Socket.gethostname + "<#{random_tag()}@#{fqdn}.tmail>" + end + + #:stopdoc: + def TMail.random_tag #:nodoc: + @uniq += 1 + t = Time.now + sprintf('%x%x_%x%x%d%x', + t.to_i, t.tv_usec, + $$, Thread.current.object_id, @uniq, rand(255)) + end + private_class_method :random_tag + + @uniq = 0 + + #:startdoc: + + # Text Utils provides a namespace to define TOKENs, ATOMs, PHRASEs and CONTROL characters that + # are OK per RFC 2822. + # + # It also provides methods you can call to determine if a string is safe + module TextUtils + + aspecial = %Q|()<>[]:;.\\,"| + tspecial = %Q|()<>[];:\\,"/?=| + lwsp = %Q| \t\r\n| + control = %Q|\x00-\x1f\x7f-\xff| + + CONTROL_CHAR = /[#{control}]/n + ATOM_UNSAFE = /[#{Regexp.quote aspecial}#{control}#{lwsp}]/n + PHRASE_UNSAFE = /[#{Regexp.quote aspecial}#{control}]/n + TOKEN_UNSAFE = /[#{Regexp.quote tspecial}#{control}#{lwsp}]/n + + # Returns true if the string supplied is free from characters not allowed as an ATOM + def atom_safe?( str ) + not ATOM_UNSAFE === str + end + + # If the string supplied has ATOM unsafe characters in it, will return the string quoted + # in double quotes, otherwise returns the string unmodified + def quote_atom( str ) + (ATOM_UNSAFE === str) ? dquote(str) : str + end + + # If the string supplied has PHRASE unsafe characters in it, will return the string quoted + # in double quotes, otherwise returns the string unmodified + def quote_phrase( str ) + (PHRASE_UNSAFE === str) ? dquote(str) : str + end + + # Returns true if the string supplied is free from characters not allowed as a TOKEN + def token_safe?( str ) + not TOKEN_UNSAFE === str + end + + # If the string supplied has TOKEN unsafe characters in it, will return the string quoted + # in double quotes, otherwise returns the string unmodified + def quote_token( str ) + (TOKEN_UNSAFE === str) ? dquote(str) : str + end + + # Wraps supplied string in double quotes unless it is already wrapped + # Returns double quoted string + def dquote( str ) #:nodoc: + unless str =~ /^".*?"$/ + '"' + str.gsub(/["\\]/n) {|s| '\\' + s } + '"' + else + str + end + end + private :dquote + + # Unwraps supplied string from inside double quotes + # Returns unquoted string + def unquote( str ) + str =~ /^"(.*?)"$/ ? $1 : str + end + + # Provides a method to join a domain name by it's parts and also makes it + # ATOM safe by quoting it as needed + def join_domain( arr ) + arr.map {|i| + if /\A\[.*\]\z/ === i + i + else + quote_atom(i) + end + }.join('.') + end + + #:stopdoc: + ZONESTR_TABLE = { + 'jst' => 9 * 60, + 'eet' => 2 * 60, + 'bst' => 1 * 60, + 'met' => 1 * 60, + 'gmt' => 0, + 'utc' => 0, + 'ut' => 0, + 'nst' => -(3 * 60 + 30), + 'ast' => -4 * 60, + 'edt' => -4 * 60, + 'est' => -5 * 60, + 'cdt' => -5 * 60, + 'cst' => -6 * 60, + 'mdt' => -6 * 60, + 'mst' => -7 * 60, + 'pdt' => -7 * 60, + 'pst' => -8 * 60, + 'a' => -1 * 60, + 'b' => -2 * 60, + 'c' => -3 * 60, + 'd' => -4 * 60, + 'e' => -5 * 60, + 'f' => -6 * 60, + 'g' => -7 * 60, + 'h' => -8 * 60, + 'i' => -9 * 60, + # j not use + 'k' => -10 * 60, + 'l' => -11 * 60, + 'm' => -12 * 60, + 'n' => 1 * 60, + 'o' => 2 * 60, + 'p' => 3 * 60, + 'q' => 4 * 60, + 'r' => 5 * 60, + 's' => 6 * 60, + 't' => 7 * 60, + 'u' => 8 * 60, + 'v' => 9 * 60, + 'w' => 10 * 60, + 'x' => 11 * 60, + 'y' => 12 * 60, + 'z' => 0 * 60 + } + #:startdoc: + + # Takes a time zone string from an EMail and converts it to Unix Time (seconds) + def timezone_string_to_unixtime( str ) + if m = /([\+\-])(\d\d?)(\d\d)/.match(str) + sec = (m[2].to_i * 60 + m[3].to_i) * 60 + m[1] == '-' ? -sec : sec + else + min = ZONESTR_TABLE[str.downcase] or + raise SyntaxError, "wrong timezone format '#{str}'" + min * 60 + end + end + + #:stopdoc: + WDAY = %w( Sun Mon Tue Wed Thu Fri Sat TMailBUG ) + MONTH = %w( TMailBUG Jan Feb Mar Apr May Jun + Jul Aug Sep Oct Nov Dec TMailBUG ) + + def time2str( tm ) + # [ruby-list:7928] + gmt = Time.at(tm.to_i) + gmt.gmtime + offset = tm.to_i - Time.local(*gmt.to_a[0,6].reverse).to_i + + # DO NOT USE strftime: setlocale() breaks it + sprintf '%s, %s %s %d %02d:%02d:%02d %+.2d%.2d', + WDAY[tm.wday], tm.mday, MONTH[tm.month], + tm.year, tm.hour, tm.min, tm.sec, + *(offset / 60).divmod(60) + end + + + MESSAGE_ID = /<[^\@>]+\@[^>\@]+>/ + + def message_id?( str ) + MESSAGE_ID === str + end + + + MIME_ENCODED = /=\?[^\s?=]+\?[QB]\?[^\s?=]+\?=/i + + def mime_encoded?( str ) + MIME_ENCODED === str + end + + + def decode_params( hash ) + new = Hash.new + encoded = nil + hash.each do |key, value| + if m = /\*(?:(\d+)\*)?\z/.match(key) + ((encoded ||= {})[m.pre_match] ||= [])[(m[1] || 0).to_i] = value + else + new[key] = to_kcode(value) + end + end + if encoded + encoded.each do |key, strings| + new[key] = decode_RFC2231(strings.join('')) + end + end + + new + end + + NKF_FLAGS = { + 'EUC' => '-e -m', + 'SJIS' => '-s -m' + } + + def to_kcode( str ) + flag = NKF_FLAGS[TMail.KCODE] or return str + NKF.nkf(flag, str) + end + + RFC2231_ENCODED = /\A(?:iso-2022-jp|euc-jp|shift_jis|us-ascii)?'[a-z]*'/in + + def decode_RFC2231( str ) + m = RFC2231_ENCODED.match(str) or return str + begin + to_kcode(m.post_match.gsub(/%[\da-f]{2}/in) {|s| s[1,2].hex.chr }) + rescue + m.post_match.gsub(/%[\da-f]{2}/in, "") + end + end + + def quote_boundary + # Make sure the Content-Type boundary= parameter is quoted if it contains illegal characters + # (to ensure any special characters in the boundary text are escaped from the parser + # (such as = in MS Outlook's boundary text)) + if @body =~ /^(.*)boundary=(.*)$/m + preamble = $1 + remainder = $2 + if remainder =~ /;/ + remainder =~ /^(.*?)(;.*)$/m + boundary_text = $1 + post = $2.chomp + else + boundary_text = remainder.chomp + end + if boundary_text =~ /[\/\?\=]/ + boundary_text = "\"#{boundary_text}\"" unless boundary_text =~ /^".*?"$/ + @body = "#{preamble}boundary=#{boundary_text}#{post}" + end + end + end + #:startdoc: + + + end + +end diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/version.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/version.rb new file mode 100644 index 0000000000..95228497c0 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/version.rb @@ -0,0 +1,39 @@ +# +# version.rb +# +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# 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. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + +#:stopdoc: +module TMail + module VERSION + MAJOR = 1 + MINOR = 2 + TINY = 3 + + STRING = [MAJOR, MINOR, TINY].join('.') + end +end -- cgit v1.2.3 From a34cc42a2c29928bcdc75b700343f978a9524e58 Mon Sep 17 00:00:00 2001 From: Nate Wiger Date: Mon, 19 May 2008 11:42:37 -0700 Subject: - Updated tzinfo to use Rational() instead of Rational.new! due to "private method new!" in Ruby 1.9 - Added ^object_id$ as ignore pattern to fixing "redefining object_id" issue in Ruby 1.9 Signed-off-by: Jeremy Kemper --- .../associations/association_proxy.rb | 2 +- activerecord/lib/active_record/named_scope.rb | 4 +- .../vendor/tzinfo-0.3.8/tzinfo/offset_rationals.rb | 114 ++++++++++----------- 3 files changed, 60 insertions(+), 60 deletions(-) diff --git a/activerecord/lib/active_record/associations/association_proxy.rb b/activerecord/lib/active_record/associations/association_proxy.rb index 68503a3c40..ec16af3897 100644 --- a/activerecord/lib/active_record/associations/association_proxy.rb +++ b/activerecord/lib/active_record/associations/association_proxy.rb @@ -49,7 +49,7 @@ module ActiveRecord alias_method :proxy_respond_to?, :respond_to? alias_method :proxy_extend, :extend delegate :to_param, :to => :proxy_target - instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_)/ } + instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_|^object_id$)/ } def initialize(owner, reflection) @owner, @reflection = owner, reflection diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index d43ebefc3b..06edaed3d5 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -102,7 +102,7 @@ module ActiveRecord class Scope attr_reader :proxy_scope, :proxy_options - [].methods.each { |m| delegate m, :to => :proxy_found unless m =~ /(^__|^nil\?|^send|class|extend|find|count|sum|average|maximum|minimum|paginate)/ } + [].methods.each { |m| delegate m, :to => :proxy_found unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|find|count|sum|average|maximum|minimum|paginate)/ } delegate :scopes, :with_scope, :to => :proxy_scope def initialize(proxy_scope, options, &block) @@ -136,4 +136,4 @@ module ActiveRecord end end end -end \ No newline at end of file +end diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/offset_rationals.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/offset_rationals.rb index 5857de623d..32fa4123f1 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/offset_rationals.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/offset_rationals.rb @@ -27,63 +27,63 @@ module TZInfo # -14 and +14 hours to avoid having to call gcd at runtime. module OffsetRationals #:nodoc: @@rational_cache = { - -50400 => Rational.new!(-7,12), - -48600 => Rational.new!(-9,16), - -46800 => Rational.new!(-13,24), - -45000 => Rational.new!(-25,48), - -43200 => Rational.new!(-1,2), - -41400 => Rational.new!(-23,48), - -39600 => Rational.new!(-11,24), - -37800 => Rational.new!(-7,16), - -36000 => Rational.new!(-5,12), - -34200 => Rational.new!(-19,48), - -32400 => Rational.new!(-3,8), - -30600 => Rational.new!(-17,48), - -28800 => Rational.new!(-1,3), - -27000 => Rational.new!(-5,16), - -25200 => Rational.new!(-7,24), - -23400 => Rational.new!(-13,48), - -21600 => Rational.new!(-1,4), - -19800 => Rational.new!(-11,48), - -18000 => Rational.new!(-5,24), - -16200 => Rational.new!(-3,16), - -14400 => Rational.new!(-1,6), - -12600 => Rational.new!(-7,48), - -10800 => Rational.new!(-1,8), - -9000 => Rational.new!(-5,48), - -7200 => Rational.new!(-1,12), - -5400 => Rational.new!(-1,16), - -3600 => Rational.new!(-1,24), - -1800 => Rational.new!(-1,48), - 0 => Rational.new!(0,1), - 1800 => Rational.new!(1,48), - 3600 => Rational.new!(1,24), - 5400 => Rational.new!(1,16), - 7200 => Rational.new!(1,12), - 9000 => Rational.new!(5,48), - 10800 => Rational.new!(1,8), - 12600 => Rational.new!(7,48), - 14400 => Rational.new!(1,6), - 16200 => Rational.new!(3,16), - 18000 => Rational.new!(5,24), - 19800 => Rational.new!(11,48), - 21600 => Rational.new!(1,4), - 23400 => Rational.new!(13,48), - 25200 => Rational.new!(7,24), - 27000 => Rational.new!(5,16), - 28800 => Rational.new!(1,3), - 30600 => Rational.new!(17,48), - 32400 => Rational.new!(3,8), - 34200 => Rational.new!(19,48), - 36000 => Rational.new!(5,12), - 37800 => Rational.new!(7,16), - 39600 => Rational.new!(11,24), - 41400 => Rational.new!(23,48), - 43200 => Rational.new!(1,2), - 45000 => Rational.new!(25,48), - 46800 => Rational.new!(13,24), - 48600 => Rational.new!(9,16), - 50400 => Rational.new!(7,12)} + -50400 => Rational(-7,12), + -48600 => Rational(-9,16), + -46800 => Rational(-13,24), + -45000 => Rational(-25,48), + -43200 => Rational(-1,2), + -41400 => Rational(-23,48), + -39600 => Rational(-11,24), + -37800 => Rational(-7,16), + -36000 => Rational(-5,12), + -34200 => Rational(-19,48), + -32400 => Rational(-3,8), + -30600 => Rational(-17,48), + -28800 => Rational(-1,3), + -27000 => Rational(-5,16), + -25200 => Rational(-7,24), + -23400 => Rational(-13,48), + -21600 => Rational(-1,4), + -19800 => Rational(-11,48), + -18000 => Rational(-5,24), + -16200 => Rational(-3,16), + -14400 => Rational(-1,6), + -12600 => Rational(-7,48), + -10800 => Rational(-1,8), + -9000 => Rational(-5,48), + -7200 => Rational(-1,12), + -5400 => Rational(-1,16), + -3600 => Rational(-1,24), + -1800 => Rational(-1,48), + 0 => Rational(0,1), + 1800 => Rational(1,48), + 3600 => Rational(1,24), + 5400 => Rational(1,16), + 7200 => Rational(1,12), + 9000 => Rational(5,48), + 10800 => Rational(1,8), + 12600 => Rational(7,48), + 14400 => Rational(1,6), + 16200 => Rational(3,16), + 18000 => Rational(5,24), + 19800 => Rational(11,48), + 21600 => Rational(1,4), + 23400 => Rational(13,48), + 25200 => Rational(7,24), + 27000 => Rational(5,16), + 28800 => Rational(1,3), + 30600 => Rational(17,48), + 32400 => Rational(3,8), + 34200 => Rational(19,48), + 36000 => Rational(5,12), + 37800 => Rational(7,16), + 39600 => Rational(11,24), + 41400 => Rational(23,48), + 43200 => Rational(1,2), + 45000 => Rational(25,48), + 46800 => Rational(13,24), + 48600 => Rational(9,16), + 50400 => Rational(7,12)} # Returns a Rational expressing the fraction of a day that offset in # seconds represents (i.e. equivalent to Rational(offset, 86400)). -- cgit v1.2.3 From 1b0128c5413ace12dee45e9db328cff866a5bb06 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 19 May 2008 19:12:25 -0700 Subject: Don't rely on association proxying object_id. [#225 state:resolved] --- activerecord/test/cases/associations/belongs_to_associations_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index b8ec9117af..4382ba17ef 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -54,8 +54,8 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase original_proxy = citibank.firm citibank.firm = another_firm - assert_equal first_firm.object_id, original_proxy.object_id - assert_equal another_firm.object_id, citibank.firm.object_id + assert_equal first_firm.object_id, original_proxy.target.object_id + assert_equal another_firm.object_id, citibank.firm.target.object_id end def test_creating_the_belonging_object -- cgit v1.2.3 From 089251581137b041828a7e6dcbf75ecbef55b4a3 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Tue, 20 May 2008 11:10:38 +0100 Subject: Ensure add_column gives valid error for sqlite. [Gunnar Wolf, Pratik] [#197 state:resolved] SQLite#add_column executes "VACUUM", which fails if inside a live transaction. This patch ensures a valid exception is raised if add_column is executed within a live transaction for sqlite adapter. --- .../connection_adapters/sqlite_adapter.rb | 4 ++++ activerecord/test/cases/transactions_test.rb | 26 ++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index 8abbc6d0a4..51cfd10e5c 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -214,6 +214,10 @@ module ActiveRecord end def add_column(table_name, column_name, type, options = {}) #:nodoc: + if @connection.respond_to?(:transaction_active?) && @connection.transaction_active? + raise StatementInvalid, 'Cannot add columns to a SQLite database while inside a transaction' + end + super(table_name, column_name, type, options) # See last paragraph on http://www.sqlite.org/lang_altertable.html execute "VACUUM" diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index 63f04e3014..06a76eacc3 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -179,6 +179,32 @@ class TransactionTest < ActiveRecord::TestCase end end + def test_sqlite_add_column_in_transaction_raises_statement_invalid + return true unless current_adapter?(:SQLite3Adapter, :SQLiteAdapter) + + # Test first if column creation/deletion works correctly when no + # transaction is in place. + # + # We go back to the connection for the column queries because + # Topic.columns is cached and won't report changes to the DB + + assert_nothing_raised do + Topic.reset_column_information + Topic.connection.add_column('topics', 'stuff', :string) + assert Topic.column_names.include?('stuff') + + Topic.reset_column_information + Topic.connection.remove_column('topics', 'stuff') + assert !Topic.column_names.include?('stuff') + end + + # Test now inside a transaction: add_column should raise a StatementInvalid + Topic.transaction do + assert_raises(ActiveRecord::StatementInvalid) { Topic.connection.add_column('topics', 'stuff', :string) } + raise ActiveRecord::Rollback + end + end + private def add_exception_raising_after_save_callback_to_topic Topic.class_eval { def after_save() raise "Make the transaction rollback" end } -- cgit v1.2.3 From 633e9b4c5656a18dc5cb1eff95d47fc1824b2c27 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Tue, 20 May 2008 12:37:35 +0200 Subject: revised conventions in time zone related docs --- .../lib/active_record/attribute_methods.rb | 8 +++---- .../lib/active_support/core_ext/time/zones.rb | 24 +++++++++---------- activesupport/lib/active_support/time_with_zone.rb | 28 +++++++++++----------- .../lib/active_support/values/time_zone.rb | 10 ++++---- 4 files changed, 35 insertions(+), 35 deletions(-) diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index d753778d52..09346bec5c 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -162,8 +162,8 @@ module ActiveRecord evaluate_attribute_method attr_name, "def #{attr_name}; unserialize_attribute('#{attr_name}'); end" end - # Defined for all datetime and timestamp attributes when time_zone_aware_attributes are enabled. - # This enhanced read method automatically converts the UTC time stored in the database to the time zone stored in Time.zone + # Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled. + # This enhanced read method automatically converts the UTC time stored in the database to the time zone stored in Time.zone. def define_read_method_for_time_zone_conversion(attr_name) method_body = <<-EOV def #{attr_name}(reload = false) @@ -176,7 +176,7 @@ module ActiveRecord evaluate_attribute_method attr_name, method_body end - # Define an attribute ? method. + # Defines a predicate method attr_name?. def define_question_method(attr_name) evaluate_attribute_method attr_name, "def #{attr_name}?; query_attribute('#{attr_name}'); end", "#{attr_name}?" end @@ -185,7 +185,7 @@ module ActiveRecord evaluate_attribute_method attr_name, "def #{attr_name}=(new_value);write_attribute('#{attr_name}', new_value);end", "#{attr_name}=" end - # Defined for all datetime and timestamp attributes when time_zone_aware_attributes are enabled. + # Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled. # This enhanced write method will automatically convert the time passed to it to the zone stored in Time.zone. def define_write_method_for_time_zone_conversion(attr_name) method_body = <<-EOV diff --git a/activesupport/lib/active_support/core_ext/time/zones.rb b/activesupport/lib/active_support/core_ext/time/zones.rb index cf28d0fa95..9fff748d6c 100644 --- a/activesupport/lib/active_support/core_ext/time/zones.rb +++ b/activesupport/lib/active_support/core_ext/time/zones.rb @@ -10,21 +10,21 @@ module ActiveSupport #:nodoc: attr_accessor :zone_default # Returns the TimeZone for the current request, if this has been set (via Time.zone=). - # If Time.zone has not been set for the current request, returns the TimeZone specified in config.time_zone + # If Time.zone has not been set for the current request, returns the TimeZone specified in config.time_zone. def zone Thread.current[:time_zone] || zone_default end - # Sets Time.zone to a TimeZone object for the current request/thread. + # Sets Time.zone to a TimeZone object for the current request/thread. # # This method accepts any of the following: # - # * a Rails TimeZone object - # * an identifier for a Rails TimeZone object (e.g., "Eastern Time (US & Canada)", -5.hours) - # * a TZInfo::Timezone object - # * an identifier for a TZInfo::Timezone object (e.g., "America/New_York") + # * A Rails TimeZone object. + # * An identifier for a Rails TimeZone object (e.g., "Eastern Time (US & Canada)", -5.hours). + # * A TZInfo::Timezone object. + # * An identifier for a TZInfo::Timezone object (e.g., "America/New_York"). # - # Here's an example of how you might set Time.zone on a per request basis -- current_user.time_zone + # Here's an example of how you might set Time.zone on a per request basis -- current_user.time_zone # just needs to return a string identifying the user's preferred TimeZone: # # class ApplicationController < ActionController::Base @@ -38,7 +38,7 @@ module ActiveSupport #:nodoc: Thread.current[:time_zone] = get_zone(time_zone) end - # Allows override of Time.zone locally inside supplied block; resets Time.zone to existing value when done + # Allows override of Time.zone locally inside supplied block; resets Time.zone to existing value when done. def use_zone(time_zone) old_zone, ::Time.zone = ::Time.zone, get_zone(time_zone) yield @@ -46,7 +46,7 @@ module ActiveSupport #:nodoc: ::Time.zone = old_zone end - # Returns Time.zone.now when config.time_zone is set, otherwise just returns Time.now. + # Returns Time.zone.now when config.time_zone is set, otherwise just returns Time.now. def current ::Time.zone_default ? ::Time.zone.now : ::Time.now end @@ -65,16 +65,16 @@ module ActiveSupport #:nodoc: end end - # Returns the simultaneous time in Time.zone. + # Returns the simultaneous time in Time.zone. # # Time.zone = 'Hawaii' # => 'Hawaii' # Time.utc(2000).in_time_zone # => Fri, 31 Dec 1999 14:00:00 HST -10:00 # - # This method is similar to Time#localtime, except that it uses Time.zone as the local zone + # This method is similar to Time#localtime, except that it uses Time.zone as the local zone # instead of the operating system's time zone. # # You can also pass in a TimeZone instance or string that identifies a TimeZone as an argument, - # and the conversion will be based on that zone instead of Time.zone. + # and the conversion will be based on that zone instead of Time.zone. # # Time.utc(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00 def in_time_zone(zone = ::Time.zone) diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index c9fb615fa5..3e87716ae0 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -1,10 +1,10 @@ require 'tzinfo' module ActiveSupport # A Time-like class that can represent a time in any time zone. Necessary because standard Ruby Time instances are - # limited to UTC and the system's ENV['TZ'] zone. + # limited to UTC and the system's ENV['TZ'] zone. # - # You shouldn't ever need to create a TimeWithZone instance directly via .new -- instead, Rails provides the methods - # #local, #parse, #at and #now on TimeZone instances, and #in_time_zone on Time and DateTime instances, for a more + # You shouldn't ever need to create a TimeWithZone instance directly via new -- instead, Rails provides the methods + # +local+, +parse+, +at+ and +now+ on TimeZone instances, and +in_time_zone+ on Time and DateTime instances, for a more # user-friendly syntax. Examples: # # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)' @@ -38,12 +38,12 @@ module ActiveSupport @period = @utc ? period : get_period_and_ensure_valid_local_time end - # Returns a Time or DateTime instance that represents the time in time_zone + # Returns a Time or DateTime instance that represents the time in +time_zone+. def time @time ||= period.to_local(@utc) end - # Returns a Time or DateTime instance that represents the time in UTC + # Returns a Time or DateTime instance that represents the time in UTC. def utc @utc ||= period.to_utc(@time) end @@ -52,18 +52,18 @@ module ActiveSupport alias_method :getutc, :utc alias_method :gmtime, :utc - # Returns the underlying TZInfo::TimezonePeriod + # Returns the underlying TZInfo::TimezonePeriod. def period @period ||= time_zone.period_for_utc(@utc) end - # Returns the simultaneous time in Time.zone, or the specified zone + # Returns the simultaneous time in Time.zone, or the specified zone. def in_time_zone(new_zone = ::Time.zone) return self if time_zone == new_zone utc.in_time_zone(new_zone) end - # Returns a Time.local() instance of the simultaneous time in your system's ENV['TZ'] zone + # Returns a Time.local() instance of the simultaneous time in your system's ENV['TZ'] zone def localtime utc.getlocal end @@ -146,7 +146,7 @@ module ActiveSupport time.strftime(format) end - # Use the time in UTC for comparisons + # Use the time in UTC for comparisons. def <=>(other) utc <=> other end @@ -159,7 +159,7 @@ module ActiveSupport utc == other end - # If wrapped #time is a DateTime, use DateTime#since instead of +. + # If wrapped +time+ is a DateTime, use DateTime#since instead of +. # Otherwise, just pass on to +method_missing+. def +(other) result = utc.acts_like?(:date) ? utc.since(other) : utc + other rescue utc.since(other) @@ -225,7 +225,7 @@ module ActiveSupport utc.to_datetime.new_offset(Rational(utc_offset, 86_400)) end - # so that self acts_like?(:time) + # So that self acts_like?(:time). def acts_like_time? true end @@ -236,7 +236,7 @@ module ActiveSupport end alias_method :kind_of?, :is_a? - # Neuter freeze because freezing can cause problems with lazy loading of attributes + # Neuter freeze because freezing can cause problems with lazy loading of attributes. def freeze self end @@ -249,14 +249,14 @@ module ActiveSupport initialize(variables[0], ::Time.send!(:get_zone, variables[1]), variables[2]) end - # Ensure proxy class responds to all methods that underlying time instance responds to + # Ensure proxy class responds to all methods that underlying time instance responds to. def respond_to?(sym) # consistently respond false to acts_like?(:date), regardless of whether #time is a Time or DateTime return false if sym.to_s == 'acts_like_date?' super || time.respond_to?(sym) end - # Send the missing method to time instance, and wrap result in a new TimeWithZone with the existing time_zone + # Send the missing method to +time+ instance, and wrap result in a new TimeWithZone with the existing +time_zone+. def method_missing(sym, *args, &block) result = time.__send__(sym, *args, &block) result.acts_like?(:time) ? self.class.new(nil, time_zone, result) : result diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 886c3e952d..5007e1b204 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -1,11 +1,11 @@ # The TimeZone class serves as a wrapper around TZInfo::Timezone instances. It allows us to do the following: # -# * limit the set of zones provided by TZInfo to a meaningful subset of 142 zones -# * retrieve and display zones with a friendlier name (e.g., "Eastern Time (US & Canada)" instead of "America/New_York") -# * lazily load TZInfo::Timezone instances only when they're needed -# * create ActiveSupport::TimeWithZone instances via TimeZone #local, #parse, #at and #now methods +# * Limit the set of zones provided by TZInfo to a meaningful subset of 142 zones. +# * Retrieve and display zones with a friendlier name (e.g., "Eastern Time (US & Canada)" instead of "America/New_York"). +# * Lazily load TZInfo::Timezone instances only when they're needed. +# * Create ActiveSupport::TimeWithZone instances via TimeZone's +local+, +parse+, +at+ and +now+ methods. # -# If you set config.time_zone in the Rails Initializer, you can access this TimeZone object via Time.zone: +# If you set config.time_zone in the Rails Initializer, you can access this TimeZone object via Time.zone: # # # environment.rb: # Rails::Initializer.run do |config| -- cgit v1.2.3 From 02674a892b992132707cc923e2ab45c11ca5d418 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Tue, 20 May 2008 12:41:50 +0200 Subject: details left in previous revision of time zone related docs --- activesupport/lib/active_support/core_ext/time/zones.rb | 2 +- activesupport/lib/active_support/time_with_zone.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/time/zones.rb b/activesupport/lib/active_support/core_ext/time/zones.rb index 9fff748d6c..079ecdd48e 100644 --- a/activesupport/lib/active_support/core_ext/time/zones.rb +++ b/activesupport/lib/active_support/core_ext/time/zones.rb @@ -10,7 +10,7 @@ module ActiveSupport #:nodoc: attr_accessor :zone_default # Returns the TimeZone for the current request, if this has been set (via Time.zone=). - # If Time.zone has not been set for the current request, returns the TimeZone specified in config.time_zone. + # If Time.zone has not been set for the current request, returns the TimeZone specified in config.time_zone. def zone Thread.current[:time_zone] || zone_default end diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index 3e87716ae0..ece95eeae9 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -225,12 +225,12 @@ module ActiveSupport utc.to_datetime.new_offset(Rational(utc_offset, 86_400)) end - # So that self acts_like?(:time). + # So that +self+ acts_like?(:time). def acts_like_time? true end - # Say we're a Time to thwart type checking + # Say we're a Time to thwart type checking. def is_a?(klass) klass == ::Time || super end -- cgit v1.2.3 From ebb642fa3a2b1a4e31abf9610ca634e6bb5d57d3 Mon Sep 17 00:00:00 2001 From: Tom Ward Date: Tue, 29 Apr 2008 13:21:51 +0100 Subject: Fix Dependencies watch_frames collection. [#24 state:resolved] Previously, the code collecting watch_frames could fail leaving watch_frames defined but nil. The cleanup code checks watch_frames is defined, but not that it holds a value, raising an undefined method on NilClass error rather than the original cause. This can make debugging the underlying cause a total pain. Signed-off-by: Pratik Naik --- activesupport/lib/active_support/dependencies.rb | 2 +- activesupport/test/dependencies_test.rb | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index eaba46dd9c..25225d5615 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -384,7 +384,7 @@ module Dependencies #:nodoc: return new_constants ensure # Remove the stack frames that we added. - if defined?(watch_frames) && ! watch_frames.empty? + if defined?(watch_frames) && ! watch_frames.blank? frame_ids = watch_frames.collect(&:object_id) constant_watch_stack.delete_if do |watch_frame| frame_ids.include? watch_frame.object_id diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb index 9e98e764fd..1e19e12da9 100644 --- a/activesupport/test/dependencies_test.rb +++ b/activesupport/test/dependencies_test.rb @@ -584,6 +584,12 @@ class DependenciesTest < Test::Unit::TestCase assert_equal [], m end + def test_new_constants_in_with_illegal_module_name_raises_correct_error + assert_raises(NameError) do + Dependencies.new_constants_in("Illegal-Name") {} + end + end + def test_file_with_multiple_constants_and_require_dependency with_loading 'autoloading_fixtures' do assert ! defined?(MultipleConstantFile) -- cgit v1.2.3 From 73c59638549686fccc749ffd3ac53cb533c5fd61 Mon Sep 17 00:00:00 2001 From: Ryan Bates Date: Tue, 20 May 2008 12:11:25 +0100 Subject: Add first/last methods to associations/named_scope. [#226 state:resolved] Signed-off-by: Pratik Naik --- activerecord/CHANGELOG | 2 + .../associations/association_collection.rb | 25 +++++++- activerecord/lib/active_record/named_scope.rb | 24 +++++++- .../has_and_belongs_to_many_associations_test.rb | 2 + .../associations/has_many_associations_test.rb | 66 ++++++++++++++++++++++ .../test/cases/associations/join_model_test.rb | 2 + activerecord/test/cases/associations_test.rb | 4 +- activerecord/test/cases/named_scope_test.rb | 28 +++++++++ 8 files changed, 149 insertions(+), 4 deletions(-) diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index cd526a52a7..78082665a4 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,3 +1,5 @@ +* Add first/last methods to associations/named_scope. Resolved #226. [Ryan Bates] + *2.1.0 RC1 (May 11th, 2008)* * Ensure hm:t preloading honours reflection options. Resolves #137. [Frederick Cheung] diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 7e47bf7bdf..2d3750e107 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -48,6 +48,26 @@ module ActiveRecord end end + # fetch first using SQL if possible + def first(*args) + if fetch_first_or_last_using_find? args + find(:first, *args) + else + load_target unless loaded? + @target.first(*args) + end + end + + # fetch last using SQL if possible + def last(*args) + if fetch_first_or_last_using_find? args + find(:last, *args) + else + load_target unless loaded? + @target.last(*args) + end + end + def to_ary load_target @target.to_ary @@ -330,7 +350,10 @@ module ActiveRecord raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved" end end - + + def fetch_first_or_last_using_find?(args) + args.first.kind_of?(Hash) || !(loaded? || @owner.new_record? || @reflection.options[:finder_sql] || !@target.blank? || args.first.kind_of?(Integer)) + end end end end diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 06edaed3d5..c7cf1731c1 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -102,7 +102,13 @@ module ActiveRecord class Scope attr_reader :proxy_scope, :proxy_options - [].methods.each { |m| delegate m, :to => :proxy_found unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|find|count|sum|average|maximum|minimum|paginate)/ } + + [].methods.each do |m| + unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|find|count|sum|average|maximum|minimum|paginate|first|last)/ + delegate m, :to => :proxy_found + end + end + delegate :scopes, :with_scope, :to => :proxy_scope def initialize(proxy_scope, options, &block) @@ -115,6 +121,22 @@ module ActiveRecord load_found; self end + def first(*args) + if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash)) + proxy_found.first(*args) + else + find(:first, *args) + end + end + + def last(*args) + if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash)) + proxy_found.last(*args) + else + find(:last, *args) + end + end + protected def proxy_found @found || load_found diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb index 64565141f9..294b993c55 100644 --- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb @@ -401,6 +401,8 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase def test_include_uses_array_include_after_loaded project = projects(:active_record) + project.developers.class # force load target + developer = project.developers.first assert_no_queries do diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 9e26e2ad58..53b55022eb 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -818,6 +818,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_include_uses_array_include_after_loaded firm = companies(:first_firm) + firm.clients.class # force load target + client = firm.clients.first assert_no_queries do @@ -857,4 +859,68 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert ! firm.clients.include?(client) end + def test_calling_first_or_last_on_association_should_not_load_association + firm = companies(:first_firm) + firm.clients.first + firm.clients.last + assert !firm.clients.loaded? + end + + def test_calling_first_or_last_on_loaded_association_should_not_fetch_with_query + firm = companies(:first_firm) + firm.clients.class # force load target + assert firm.clients.loaded? + + assert_no_queries do + firm.clients.first + assert_equal 2, firm.clients.first(2).size + firm.clients.last + assert_equal 2, firm.clients.last(2).size + end + end + + def test_calling_first_or_last_on_existing_record_with_build_should_load_association + firm = companies(:first_firm) + firm.clients.build(:name => 'Foo') + assert !firm.clients.loaded? + + assert_queries 1 do + firm.clients.first + firm.clients.last + end + + assert firm.clients.loaded? + end + + def test_calling_first_or_last_on_new_record_should_not_run_queries + firm = Firm.new + + assert_no_queries do + firm.clients.first + firm.clients.last + end + end + + def test_calling_first_or_last_with_find_options_on_loaded_association_should_fetch_with_query + firm = companies(:first_firm) + firm.clients.class # force load target + + assert_queries 2 do + assert firm.clients.loaded? + firm.clients.first(:order => 'name') + firm.clients.last(:order => 'name') + end + end + + def test_calling_first_or_last_with_integer_on_association_should_load_association + firm = companies(:first_firm) + + assert_queries 1 do + firm.clients.first(2) + firm.clients.last(2) + end + + assert firm.clients.loaded? + end + end diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb index 952ea63706..9e79d9c8a1 100644 --- a/activerecord/test/cases/associations/join_model_test.rb +++ b/activerecord/test/cases/associations/join_model_test.rb @@ -664,6 +664,8 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_has_many_through_include_uses_array_include_after_loaded david = authors(:david) + david.categories.class # force load target + category = david.categories.first assert_no_queries do diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb index d8fe98bf57..3ad8c608e0 100755 --- a/activerecord/test/cases/associations_test.rb +++ b/activerecord/test/cases/associations_test.rb @@ -99,12 +99,12 @@ class AssociationProxyTest < ActiveRecord::TestCase david = authors(:david) assert_equal david, david.posts.proxy_owner assert_equal david.class.reflect_on_association(:posts), david.posts.proxy_reflection - david.posts.first # force load target + david.posts.class # force load target assert_equal david.posts, david.posts.proxy_target assert_equal david, david.posts_with_extension.testing_proxy_owner assert_equal david.class.reflect_on_association(:posts_with_extension), david.posts_with_extension.testing_proxy_reflection - david.posts_with_extension.first # force load target + david.posts_with_extension.class # force load target assert_equal david.posts_with_extension, david.posts_with_extension.testing_proxy_target end diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb index 9730f93579..8f2fc53d67 100644 --- a/activerecord/test/cases/named_scope_test.rb +++ b/activerecord/test/cases/named_scope_test.rb @@ -118,4 +118,32 @@ class NamedScopeTest < ActiveRecord::TestCase assert_equal expected_proxy_options, Topic.approved.proxy_options end + def test_first_and_last_should_support_find_options + assert_equal Topic.base.first(:order => 'title'), Topic.base.find(:first, :order => 'title') + assert_equal Topic.base.last(:order => 'title'), Topic.base.find(:last, :order => 'title') + end + + def test_first_and_last_should_allow_integers_for_limit + assert_equal Topic.base.first(2), Topic.base.to_a.first(2) + assert_equal Topic.base.last(2), Topic.base.to_a.last(2) + end + + def test_first_and_last_should_not_use_query_when_results_are_loaded + topics = Topic.base + topics.reload # force load + assert_no_queries do + topics.first + topics.last + end + end + + def test_first_and_last_find_options_should_use_query_when_results_are_loaded + topics = Topic.base + topics.reload # force load + assert_queries(2) do + topics.first(:order => 'title') + topics.last(:order => 'title') + end + end + end -- cgit v1.2.3 From 964392f57ad6408718458f229270b4082799d233 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Tue, 20 May 2008 16:56:22 +0200 Subject: revised docs of first/last in AR base and association collection --- .../lib/active_record/associations/association_collection.rb | 4 ++-- activerecord/lib/active_record/base.rb | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 2d3750e107..83b1fedb28 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -48,7 +48,7 @@ module ActiveRecord end end - # fetch first using SQL if possible + # Fetches the first one using SQL if possible. def first(*args) if fetch_first_or_last_using_find? args find(:first, *args) @@ -58,7 +58,7 @@ module ActiveRecord end end - # fetch last using SQL if possible + # Fetches the last one using SQL if possible. def last(*args) if fetch_first_or_last_using_find? args find(:last, *args) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 35f18e9fa0..ea971a4c07 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -532,14 +532,14 @@ module ActiveRecord #:nodoc: end end - # This is an alias for find(:first). You can pass in all the same arguments to this method as you can - # to find(:first) + # A convenience wrapper for find(:first, *args). You can pass in all the + # same arguments to this method as you can to find(:first). def first(*args) find(:first, *args) end - # This is an alias for find(:last). You can pass in all the same arguments to this method as you can - # to find(:last) + # A convenience wrapper for find(:last, *args). You can pass in all the + # same arguments to this method as you can to find(:last). def last(*args) find(:last, *args) end -- cgit v1.2.3 From 281edce6db8accc7d4a0e9ab01892631d9d0ebc3 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Tue, 20 May 2008 20:50:46 +0100 Subject: Ensure nil to '' doesn't get recorded by dirty for nullable integer columns. [#150 state:resolved] [Jason Dew, Pratik] --- activerecord/lib/active_record/dirty.rb | 24 ++++++++++++++++-------- activerecord/test/cases/dirty_test.rb | 10 ++++++++++ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/activerecord/lib/active_record/dirty.rb b/activerecord/lib/active_record/dirty.rb index 6034963811..49f1204fa1 100644 --- a/activerecord/lib/active_record/dirty.rb +++ b/activerecord/lib/active_record/dirty.rb @@ -117,14 +117,7 @@ module ActiveRecord # The attribute already has an unsaved change. unless changed_attributes.include?(attr) old = clone_attribute_value(:read_attribute, attr) - - # Remember the original value if it's different. - typecasted = if column = column_for_attribute(attr) - column.type_cast(value) - else - value - end - changed_attributes[attr] = old unless old == typecasted + changed_attributes[attr] = old if field_changed?(attr, old, value) end # Carry on. @@ -138,5 +131,20 @@ module ActiveRecord update_without_dirty end end + + def field_changed?(attr, old, value) + if column = column_for_attribute(attr) + if column.type == :integer && column.null && old.nil? + # For nullable integer columns, NULL gets stored in database for blank (i.e. '') values. + # Hence we don't record it as a change if the value changes from nil to ''. + value = nil if value.blank? + else + value = column.type_cast(value) + end + end + + old != value + end + end end diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index 1266eb5036..62178977f9 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -44,6 +44,16 @@ class DirtyTest < ActiveRecord::TestCase assert_nil pirate.catchphrase_change end + def test_nullable_integer_not_marked_as_changed_if_new_value_is_blank + pirate = Pirate.new + + ["", nil].each do |value| + pirate.parrot_id = value + assert !pirate.parrot_id_changed? + assert_nil pirate.parrot_id_change + end + end + def test_object_should_be_changed_if_any_attribute_is_changed pirate = Pirate.new assert !pirate.changed? -- cgit v1.2.3 From 19d7b1d22bd68af00244ddc3e1f35cec187e9120 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Wed, 21 May 2008 10:46:28 +0100 Subject: Verbose ActiveRecord::AssociationTypeMismatch exception message. [#189 state:resolved] --- activerecord/lib/active_record/associations/association_proxy.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations/association_proxy.rb b/activerecord/lib/active_record/associations/association_proxy.rb index ec16af3897..11c64243a2 100644 --- a/activerecord/lib/active_record/associations/association_proxy.rb +++ b/activerecord/lib/active_record/associations/association_proxy.rb @@ -210,7 +210,8 @@ module ActiveRecord def raise_on_type_mismatch(record) unless record.is_a?(@reflection.klass) - raise ActiveRecord::AssociationTypeMismatch, "#{@reflection.klass} expected, got #{record.class}" + message = "#{@reflection.class_name}(##{@reflection.klass.object_id}) expected, got #{record.class}(##{record.class.object_id})" + raise ActiveRecord::AssociationTypeMismatch, message end end -- cgit v1.2.3 From 401690fea3d136581231444966eaa21f5c376b3b Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 21 May 2008 13:30:49 +0200 Subject: revised case of constants in Action Controller --- .../action_controller/assertions/selector_assertions.rb | 6 +++--- actionpack/lib/action_controller/base.rb | 2 +- actionpack/lib/action_controller/cgi_ext/cookie.rb | 2 +- actionpack/lib/action_controller/cgi_process.rb | 2 +- actionpack/lib/action_controller/helpers.rb | 14 +++++++------- actionpack/lib/action_controller/integration.rb | 2 +- actionpack/lib/action_controller/test_process.rb | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/actionpack/lib/action_controller/assertions/selector_assertions.rb b/actionpack/lib/action_controller/assertions/selector_assertions.rb index 871fb23c1e..d3594e711c 100644 --- a/actionpack/lib/action_controller/assertions/selector_assertions.rb +++ b/actionpack/lib/action_controller/assertions/selector_assertions.rb @@ -44,8 +44,8 @@ module ActionController # base element and any of its children. Returns an empty array if no # match is found. # - # The selector may be a CSS selector expression (+String+), an expression - # with substitution values (+Array+) or an HTML::Selector object. + # The selector may be a CSS selector expression (String), an expression + # with substitution values (Array) or an HTML::Selector object. # # ==== Examples # # Selects all div tags @@ -130,7 +130,7 @@ module ActionController # assert_select "li" # end # - # The selector may be a CSS selector expression (+String+), an expression + # The selector may be a CSS selector expression (String), an expression # with substitution values, or an HTML::Selector object. # # === Equality Tests diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index f89afa15fa..a036600c2b 100755 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -104,7 +104,7 @@ module ActionController #:nodoc: # end # # Actions, by default, render a template in the app/views directory corresponding to the name of the controller and action - # after executing code in the action. For example, the +index+ action of the +GuestBookController+ would render the + # after executing code in the action. For example, the +index+ action of the GuestBookController would render the # template app/views/guestbook/index.erb by default after populating the @entries instance variable. # # Unlike index, the sign action will not render a template. After performing its main purpose (creating a diff --git a/actionpack/lib/action_controller/cgi_ext/cookie.rb b/actionpack/lib/action_controller/cgi_ext/cookie.rb index a244e2a39a..efef91ccf6 100644 --- a/actionpack/lib/action_controller/cgi_ext/cookie.rb +++ b/actionpack/lib/action_controller/cgi_ext/cookie.rb @@ -18,7 +18,7 @@ class CGI #:nodoc: # path:: the path for which this cookie applies. Defaults to the # base directory of the CGI script. # domain:: the domain for which this cookie applies. - # expires:: the time at which this cookie expires, as a +Time+ object. + # expires:: the time at which this cookie expires, as a Time object. # secure:: whether this cookie is a secure cookie or not (default to # false). Secure cookies are only transmitted to HTTPS # servers. diff --git a/actionpack/lib/action_controller/cgi_process.rb b/actionpack/lib/action_controller/cgi_process.rb index 7e58c98bf2..8bc5e4c3a7 100644 --- a/actionpack/lib/action_controller/cgi_process.rb +++ b/actionpack/lib/action_controller/cgi_process.rb @@ -15,7 +15,7 @@ module ActionController #:nodoc: # * :new_session - if true, force creation of a new session. If not set, a new session is only created if none currently # exists. If false, a new session is never created, and if none currently exists and the +session_id+ option is not set, # an ArgumentError is raised. - # * :session_expires - the time the current session expires, as a +Time+ object. If not set, the session will continue + # * :session_expires - the time the current session expires, as a Time object. If not set, the session will continue # indefinitely. # * :session_domain - the hostname domain for which this session is valid. If not set, defaults to the hostname of the # server. diff --git a/actionpack/lib/action_controller/helpers.rb b/actionpack/lib/action_controller/helpers.rb index a8bead4d34..ce5e8be54c 100644 --- a/actionpack/lib/action_controller/helpers.rb +++ b/actionpack/lib/action_controller/helpers.rb @@ -20,7 +20,7 @@ module ActionController #:nodoc: end # The Rails framework provides a large number of helpers for working with +assets+, +dates+, +forms+, - # +numbers+ and +ActiveRecord+ objects, to name a few. These helpers are available to all templates + # +numbers+ and Active Record objects, to name a few. These helpers are available to all templates # by default. # # In addition to using the standard template helpers provided in the Rails framework, creating custom helpers to @@ -32,7 +32,7 @@ module ActionController #:nodoc: # controller which inherits from it. # # ==== Examples - # The +to_s+ method from the +Time+ class can be wrapped in a helper method to display a custom message if + # The +to_s+ method from the Time class can be wrapped in a helper method to display a custom message if # the Time object is blank: # # module FormattedTimeHelper @@ -41,7 +41,7 @@ module ActionController #:nodoc: # end # end # - # +FormattedTimeHelper+ can now be included in a controller, using the +helper+ class method: + # FormattedTimeHelper can now be included in a controller, using the +helper+ class method: # # class EventsController < ActionController::Base # helper FormattedTimeHelper @@ -74,22 +74,22 @@ module ActionController #:nodoc: # The +helper+ class method can take a series of helper module names, a block, or both. # - # * *args: One or more +Modules+, +Strings+ or +Symbols+, or the special symbol :all. + # * *args: One or more modules, strings or symbols, or the special symbol :all. # * &block: A block defining helper methods. # # ==== Examples - # When the argument is a +String+ or +Symbol+, the method will provide the "_helper" suffix, require the file + # When the argument is a string or symbol, the method will provide the "_helper" suffix, require the file # and include the module in the template class. The second form illustrates how to include custom helpers # when working with namespaced controllers, or other cases where the file containing the helper definition is not # in one of Rails' standard load paths: # helper :foo # => requires 'foo_helper' and includes FooHelper # helper 'resources/foo' # => requires 'resources/foo_helper' and includes Resources::FooHelper # - # When the argument is a +Module+, it will be included directly in the template class. + # When the argument is a module it will be included directly in the template class. # helper FooHelper # => includes FooHelper # # When the argument is the symbol :all, the controller will include all helpers from - # app/helpers/**/*.rb under +RAILS_ROOT+. + # app/helpers/**/*.rb under RAILS_ROOT. # helper :all # # Additionally, the +helper+ class method can receive and evaluate a block, making the methods defined available diff --git a/actionpack/lib/action_controller/integration.rb b/actionpack/lib/action_controller/integration.rb index a2fe631172..bd69d02ed7 100644 --- a/actionpack/lib/action_controller/integration.rb +++ b/actionpack/lib/action_controller/integration.rb @@ -58,7 +58,7 @@ module ActionController class MultiPartNeededException < Exception end - # Create and initialize a new +Session+ instance. + # Create and initialize a new Session instance. def initialize reset! end diff --git a/actionpack/lib/action_controller/test_process.rb b/actionpack/lib/action_controller/test_process.rb index b9966e38d5..0cf143210d 100644 --- a/actionpack/lib/action_controller/test_process.rb +++ b/actionpack/lib/action_controller/test_process.rb @@ -3,7 +3,7 @@ require 'action_controller/test_case' module ActionController #:nodoc: class Base - # Process a test request called with a +TestRequest+ object. + # Process a test request called with a TestRequest object. def self.process_test(request) new.process_test(request) end -- cgit v1.2.3 From 8174d91273d7e844787b6b2b138567ed787d4a56 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 21 May 2008 13:39:50 +0200 Subject: revised font of constants in Action View --- actionpack/lib/action_view/helpers/form_options_helper.rb | 4 ++-- actionpack/lib/action_view/helpers/scriptaculous_helper.rb | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index 59d95d3631..40428a19bf 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -119,7 +119,7 @@ module ActionView # end # end # - # Sample usage (selecting the associated +Author+ for an instance of +Post+, @post): + # Sample usage (selecting the associated Author for an instance of +Post+, @post): # collection_select(:post, :author_id, Author.find(:all), :id, :name_with_initial, {:prompt => true}) # # If @post.author_id is already 1, this would return: @@ -172,7 +172,7 @@ module ActionView # Accepts a container (hash, array, enumerable, your type) and returns a string of option tags. Given a container # where the elements respond to first and last (such as a two-element array), the "lasts" serve as option values and # the "firsts" as option text. Hashes are turned into this form automatically, so the keys become "firsts" and values - # become lasts. If +selected+ is specified, the matching "last" or element will get the selected option-tag. +Selected+ + # become lasts. If +selected+ is specified, the matching "last" or element will get the selected option-tag. +selected+ # may also be an array of values to be selected when using a multiple select. # # Examples (call, result): diff --git a/actionpack/lib/action_view/helpers/scriptaculous_helper.rb b/actionpack/lib/action_view/helpers/scriptaculous_helper.rb index 12b4cfd3f8..f948ddc6b0 100644 --- a/actionpack/lib/action_view/helpers/scriptaculous_helper.rb +++ b/actionpack/lib/action_view/helpers/scriptaculous_helper.rb @@ -202,9 +202,9 @@ module ActionView # :onDrop => "function(draggable_element, droppable_element, event) { alert('I like bananas') }" # # This callback gets three parameters: - # The +Draggable+ element, the +Droppable+ element and the - # +Event+ object. You can extract additional information about the - # drop - like if the Ctrl or Shift keys were pressed - from the +Event+ object. + # The Draggable element, the Droppable element and the + # Event object. You can extract additional information about the + # drop - like if the Ctrl or Shift keys were pressed - from the Event object. # # :with:: A JavaScript expression specifying the parameters for the XMLHttpRequest. # Any expressions should return a valid URL query string. -- cgit v1.2.3 From e5a74231d571beca82d2bb5c29e42a48fb6cc624 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 21 May 2008 13:46:11 +0200 Subject: revised font of constants in Action View --- actionpack/lib/action_view/helpers/form_options_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index 40428a19bf..fca3881d9b 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -119,7 +119,7 @@ module ActionView # end # end # - # Sample usage (selecting the associated Author for an instance of +Post+, @post): + # Sample usage (selecting the associated Author for an instance of Post, @post): # collection_select(:post, :author_id, Author.find(:all), :id, :name_with_initial, {:prompt => true}) # # If @post.author_id is already 1, this would return: -- cgit v1.2.3 From fb1858d5ecd808f9abdcb2f56ee61702d5076bf6 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 21 May 2008 13:53:11 +0200 Subject: revised font of constants in Active Record --- activerecord/lib/active_record/aggregations.rb | 18 +++++++++--------- activerecord/lib/active_record/associations.rb | 2 +- activerecord/lib/active_record/base.rb | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index a8c8c7f3dc..a5d3a50ef1 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -92,19 +92,19 @@ module ActiveRecord # # == Writing value objects # - # Value objects are immutable and interchangeable objects that represent a given value, such as a +Money+ object representing - # $5. Two +Money+ objects both representing $5 should be equal (through methods such as == and <=> from +Comparable+ if ranking - # makes sense). This is unlike entity objects where equality is determined by identity. An entity class such as +Customer+ can + # Value objects are immutable and interchangeable objects that represent a given value, such as a Money object representing + # $5. Two Money objects both representing $5 should be equal (through methods such as == and <=> from Comparable if ranking + # makes sense). This is unlike entity objects where equality is determined by identity. An entity class such as Customer can # easily have two different objects that both have an address on Hyancintvej. Entity identity is determined by object or - # relational unique identifiers (such as primary keys). Normal ActiveRecord::Base classes are entity objects. + # relational unique identifiers (such as primary keys). Normal ActiveRecord::Base classes are entity objects. # - # It's also important to treat the value objects as immutable. Don't allow the +Money+ object to have its amount changed after - # creation. Create a new Money object with the new value instead. This is exemplified by the Money#exchanged_to method that + # It's also important to treat the value objects as immutable. Don't allow the Money object to have its amount changed after + # creation. Create a new Money object with the new value instead. This is exemplified by the Money#exchanged_to method that # returns a new value object instead of changing its own values. Active Record won't persist value objects that have been # changed through means other than the writer method. # # The immutable requirement is enforced by Active Record by freezing any object assigned as a value object. Attempting to - # change it afterwards will result in a ActiveSupport::FrozenObjectError. + # change it afterwards will result in a ActiveSupport::FrozenObjectError. # # Read more about value objects on http://c2.com/cgi/wiki?ValueObject and on the dangers of not keeping value objects # immutable on http://c2.com/cgi/wiki?ValueObjectsShouldBeImmutable @@ -123,8 +123,8 @@ module ActiveRecord # # Options are: # * :class_name - specify the class name of the association. Use it only if that name can't be inferred - # from the part id. So composed_of :address will by default be linked to the +Address+ class, but - # if the real class name is +CompanyAddress+, you'll have to specify it with this option. + # from the part id. So composed_of :address will by default be linked to the Address class, but + # if the real class name is CompanyAddress, you'll have to specify it with this option. # * :mapping - specifies a number of mapping arrays (attribute, parameter) that bind an attribute name # to a constructor parameter on the value class. # * :allow_nil - specifies that the aggregate object will not be instantiated when all mapped diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index ce3d273a42..31096ccd71 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -950,7 +950,7 @@ module ActiveRecord # # Deprecated: Any additional fields added to the join table will be placed as attributes when pulling records out through # +has_and_belongs_to_many+ associations. Records returned from join tables with additional attributes will be marked as - # +ReadOnly+ (because we can't save changes to the additional attributes). It's strongly recommended that you upgrade any + # readonly (because we can't save changes to the additional attributes). It's strongly recommended that you upgrade any # associations with attributes to a real join model (see introduction). # # Adds the following methods for retrieval and query: diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index ea971a4c07..457f1e841f 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -70,7 +70,7 @@ module ActiveRecord #:nodoc: # instantiation, for example, when two users edit the same wiki page and one starts editing and saves # the page before the other. # - # Read more about optimistic locking in +ActiveRecord::Locking+ module RDoc. + # Read more about optimistic locking in ActiveRecord::Locking module RDoc. class StaleObjectError < ActiveRecordError end @@ -407,7 +407,7 @@ module ActiveRecord #:nodoc: @@table_name_suffix = "" # Indicates whether table names should be the pluralized versions of the corresponding class names. - # If true, the default table name for a +Product+ class will be +products+. If false, it would just be +product+. + # If true, the default table name for a Product class will be +products+. If false, it would just be +product+. # See table_name for the full rules on table/class naming. This is true, by default. cattr_accessor :pluralize_table_names, :instance_writer => false @@pluralize_table_names = true @@ -943,7 +943,7 @@ module ActiveRecord #:nodoc: # If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object, # then specify the name of that attribute using this method and it will be handled automatically. # The serialization is done through YAML. If +class_name+ is specified, the serialized object must be of that - # class on retrieval or +SerializationTypeMismatch+ will be raised. + # class on retrieval or SerializationTypeMismatch will be raised. # # ==== Attributes # -- cgit v1.2.3 From 08cac396ccecc60026d0bb7b4a179cb99e06ff41 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 21 May 2008 13:54:40 +0200 Subject: revised font of constants in Railties --- railties/lib/initializer.rb | 6 +++--- railties/lib/rails_generator/base.rb | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb index dfd43042be..dd716cf501 100644 --- a/railties/lib/initializer.rb +++ b/railties/lib/initializer.rb @@ -326,7 +326,7 @@ module Rails end end - # If the +RAILS_DEFAULT_LOGGER+ constant is already set, this initialization + # If the RAILS_DEFAULT_LOGGER constant is already set, this initialization # routine does nothing. If the constant is not set, and Configuration#logger # is not +nil+, this also does nothing. Otherwise, a new logger instance # is created at Configuration#log_path, with a default log level of @@ -362,7 +362,7 @@ module Rails # Sets the logger for ActiveRecord, ActionController, and ActionMailer # (but only for those frameworks that are to be loaded). If the framework's # logger is already set, it is not changed, otherwise it is set to use - # +RAILS_DEFAULT_LOGGER+. + # RAILS_DEFAULT_LOGGER. def initialize_framework_logging for framework in ([ :active_record, :action_controller, :action_mailer ] & configuration.frameworks) framework.to_s.camelize.constantize.const_get("Base").logger ||= RAILS_DEFAULT_LOGGER @@ -685,7 +685,7 @@ module Rails end # Return the currently selected environment. By default, it returns the - # value of the +RAILS_ENV+ constant. + # value of the RAILS_ENV constant. def environment ::RAILS_ENV end diff --git a/railties/lib/rails_generator/base.rb b/railties/lib/rails_generator/base.rb index 1ebcff9062..b5cfe79867 100644 --- a/railties/lib/rails_generator/base.rb +++ b/railties/lib/rails_generator/base.rb @@ -36,7 +36,7 @@ module Rails # view.html.erb # # The directory name (+controller+) matches the name of the generator file - # (controller_generator.rb) and class (+ControllerGenerator+). The files + # (controller_generator.rb) and class (ControllerGenerator). The files # that will be copied or used as templates are stored in the +templates+ # directory. # -- cgit v1.2.3 From 7e8b2b6bf28fdb4b3a92ba93286ec8b77ef0b6c1 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 21 May 2008 14:01:00 +0200 Subject: revised conventions in cookie.rb --- actionpack/lib/action_controller/cgi_ext/cookie.rb | 35 +++++++++++----------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/actionpack/lib/action_controller/cgi_ext/cookie.rb b/actionpack/lib/action_controller/cgi_ext/cookie.rb index efef91ccf6..ef033fb4f3 100644 --- a/actionpack/lib/action_controller/cgi_ext/cookie.rb +++ b/actionpack/lib/action_controller/cgi_ext/cookie.rb @@ -6,25 +6,24 @@ class CGI #:nodoc: attr_accessor :name, :value, :path, :domain, :expires attr_reader :secure, :http_only - # Create a new CGI::Cookie object. + # Creates a new CGI::Cookie object. # # The contents of the cookie can be specified as a +name+ and one # or more +value+ arguments. Alternatively, the contents can # be specified as a single hash argument. The possible keywords of # this hash are as follows: # - # name:: the name of the cookie. Required. - # value:: the cookie's value or list of values. - # path:: the path for which this cookie applies. Defaults to the - # base directory of the CGI script. - # domain:: the domain for which this cookie applies. - # expires:: the time at which this cookie expires, as a Time object. - # secure:: whether this cookie is a secure cookie or not (default to - # false). Secure cookies are only transmitted to HTTPS - # servers. - # http_only:: whether this cookie can be accessed by client side scripts (e.g. document.cookie) or only over HTTP - # More details: http://msdn2.microsoft.com/en-us/library/system.web.httpcookie.httponly.aspx - # Defaults to false. + # * :name - The name of the cookie. Required. + # * :value - The cookie's value or list of values. + # * :path - The path for which this cookie applies. Defaults to the + # base directory of the CGI script. + # * :domain - The domain for which this cookie applies. + # * :expires - The time at which this cookie expires, as a Time object. + # * :secure - Whether this cookie is a secure cookie or not (defaults to + # +false+). Secure cookies are only transmitted to HTTPS servers. + # * :http_only - Whether this cookie can be accessed by client side scripts (e.g. document.cookie) or only over HTTP. + # More details in http://msdn2.microsoft.com/en-us/library/system.web.httpcookie.httponly.aspx. Defaults to +false+. + # # These keywords correspond to attributes of the cookie object. def initialize(name = '', *value) if name.kind_of?(String) @@ -56,17 +55,17 @@ class CGI #:nodoc: super(@value) end - # Set whether the Cookie is a secure cookie or not. + # Sets whether the Cookie is a secure cookie or not. def secure=(val) @secure = val == true end - # Set whether the Cookie is an HTTP only cookie or not. + # Sets whether the Cookie is an HTTP only cookie or not. def http_only=(val) @http_only = val == true end - # Convert the Cookie to its string representation. + # Converts the Cookie to its string representation. def to_s buf = '' buf << @name << '=' @@ -79,11 +78,11 @@ class CGI #:nodoc: buf end - # Parse a raw cookie string into a hash of cookie-name=>Cookie + # Parses a raw cookie string into a hash of cookie-name => cookie-object # pairs. # # cookies = CGI::Cookie::parse("raw_cookie_string") - # # { "name1" => cookie1, "name2" => cookie2, ... } + # # => { "name1" => cookie1, "name2" => cookie2, ... } # def self.parse(raw_cookie) cookies = Hash.new([]) -- cgit v1.2.3 From d79becdf21fd85432eceead107c37ccb5dea33c1 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 21 May 2008 14:46:30 +0200 Subject: revised conventions and minor details in scriptaculous_helper.rb --- .../action_view/helpers/scriptaculous_helper.rb | 166 ++++++++++----------- 1 file changed, 82 insertions(+), 84 deletions(-) diff --git a/actionpack/lib/action_view/helpers/scriptaculous_helper.rb b/actionpack/lib/action_view/helpers/scriptaculous_helper.rb index f948ddc6b0..658480c016 100644 --- a/actionpack/lib/action_view/helpers/scriptaculous_helper.rb +++ b/actionpack/lib/action_view/helpers/scriptaculous_helper.rb @@ -26,9 +26,9 @@ module ActionView # :url => { :action => "reload" }, # :complete => visual_effect(:highlight, "posts", :duration => 0.5) # - # If no element_id is given, it assumes "element" which should be a local + # If no +element_id+ is given, it assumes "element" which should be a local # variable in the generated JavaScript execution context. This can be - # used for example with drop_receiving_element: + # used for example with +drop_receiving_element+: # # <%= drop_receiving_element (...), :loading => visual_effect(:fade) %> # @@ -79,60 +79,60 @@ module ActionView # # Additional +options+ are: # - # :format:: A regular expression to determine what to send - # as the serialized id to the server (the default - # is /^[^_]*_(.*)$/). - # - # :constraint:: Whether to constrain the dragging to either :horizontal - # or :vertical (or false to make it unconstrained). - # - # :overlap:: Calculate the item overlap in the :horizontal or - # :vertical direction. - # - # :tag:: Which children of the container element to treat as - # sortable (default is li). - # - # :containment:: Takes an element or array of elements to treat as - # potential drop targets (defaults to the original - # target element). - # - # :only:: A CSS class name or arry of class names used to filter - # out child elements as candidates. - # - # :scroll:: Determines whether to scroll the list during drag - # operations if the list runs past the visual border. - # - # :tree:: Determines whether to treat nested lists as part of the - # main sortable list. This means that you can create multi- - # layer lists, and not only sort items at the same level, - # but drag and sort items between levels. - # - # :hoverclass:: If set, the Droppable will have this additional CSS class - # when an accepted Draggable is hovered over it. - # - # :handle:: Sets whether the element should only be draggable by an - # embedded handle. The value may be a string referencing a - # CSS class value (as of script.aculo.us V1.5). The first - # child/grandchild/etc. element found within the element - # that has this CSS class value will be used as the handle. - # - # :ghosting:: Clones the element and drags the clone, leaving the original - # in place until the clone is dropped (default is false). - # - # :dropOnEmpty:: If set to true, the Sortable container will be made into - # a Droppable, that can receive a Draggable (as according to - # the containment rules) as a child element when there are no - # more elements inside (default is false). - # - # :onChange:: Called whenever the sort order changes while dragging. When - # dragging from one Sortable to another, the callback is - # called once on each Sortable. Gets the affected element as - # its parameter. - # - # :onUpdate:: Called when the drag ends and the Sortable's order is - # changed in any way. When dragging from one Sortable to - # another, the callback is called once on each Sortable. Gets - # the container as its parameter. + # * :format - A regular expression to determine what to send + # as the serialized id to the server (the default + # is /^[^_]*_(.*)$/). + # + # * :constraint - Whether to constrain the dragging to either :horizontal + # or :vertical (or false to make it unconstrained). + # + # * :overlap - Calculate the item overlap in the :horizontal or + # :vertical direction. + # + # * :tag - Which children of the container element to treat as + # sortable (default is li). + # + # * :containment - Takes an element or array of elements to treat as + # potential drop targets (defaults to the original + # target element). + # + # * :only - A CSS class name or arry of class names used to filter + # out child elements as candidates. + # + # * :scroll - Determines whether to scroll the list during drag + # operations if the list runs past the visual border. + # + # * :tree - Determines whether to treat nested lists as part of the + # main sortable list. This means that you can create multi- + # layer lists, and not only sort items at the same level, + # but drag and sort items between levels. + # + # * :hoverclass - If set, the Droppable will have this additional CSS class + # when an accepted Draggable is hovered over it. + # + # * :handle - Sets whether the element should only be draggable by an + # embedded handle. The value may be a string referencing a + # CSS class value (as of script.aculo.us V1.5). The first + # child/grandchild/etc. element found within the element + # that has this CSS class value will be used as the handle. + # + # * :ghosting - Clones the element and drags the clone, leaving the original + # in place until the clone is dropped (default is false). + # + # * :dropOnEmpty - If true the Sortable container will be made into + # a Droppable, that can receive a Draggable (as according to + # the containment rules) as a child element when there are no + # more elements inside (default is false). + # + # * :onChange - Called whenever the sort order changes while dragging. When + # dragging from one Sortable to another, the callback is + # called once on each Sortable. Gets the affected element as + # its parameter. + # + # * :onUpdate - Called when the drag ends and the Sortable's order is + # changed in any way. When dragging from one Sortable to + # another, the callback is called once on each Sortable. Gets + # the container as its parameter. # # See http://script.aculo.us for more documentation. def sortable_element(element_id, options = {}) @@ -170,8 +170,8 @@ module ActionView end # Makes the element with the DOM ID specified by +element_id+ receive - # dropped draggable elements (created by draggable_element). - # and make an AJAX call By default, the action called gets the DOM ID + # dropped draggable elements (created by +draggable_element+). + # and make an AJAX call. By default, the action called gets the DOM ID # of the element as parameter. # # Example: @@ -182,32 +182,30 @@ module ActionView # http://script.aculo.us for more documentation. # # Some of these +options+ include: - # :accept:: Set this to a string or an array of strings describing the - # allowable CSS classes that the draggable_element must have in order - # to be accepted by this drop_receiving_element. - # - # :confirm:: Adds a confirmation dialog. - # - # Example: - # :confirm => "Are you sure you want to do this?" - # - # :hoverclass:: If set, the drop_receiving_element will have this additional CSS class - # when an accepted draggable_element is hovered over it. - # - # :onDrop:: Called when a draggable_element is dropped onto this element. - # Override this callback with a javascript expression to - # change the default drop behavour. - # - # Example: - # :onDrop => "function(draggable_element, droppable_element, event) { alert('I like bananas') }" - # - # This callback gets three parameters: - # The Draggable element, the Droppable element and the - # Event object. You can extract additional information about the - # drop - like if the Ctrl or Shift keys were pressed - from the Event object. - # - # :with:: A JavaScript expression specifying the parameters for the XMLHttpRequest. - # Any expressions should return a valid URL query string. + # * :accept - Set this to a string or an array of strings describing the + # allowable CSS classes that the +draggable_element+ must have in order + # to be accepted by this +drop_receiving_element+. + # + # * :confirm - Adds a confirmation dialog. Example: + # + # :confirm => "Are you sure you want to do this?" + # + # * :hoverclass - If set, the +drop_receiving_element+ will have this additional CSS class + # when an accepted +draggable_element+ is hovered over it. + # + # * :onDrop - Called when a +draggable_element+ is dropped onto this element. + # Override this callback with a JavaScript expression to + # change the default drop behavour. Example: + # + # :onDrop => "function(draggable_element, droppable_element, event) { alert('I like bananas') }" + # + # This callback gets three parameters: + # The Draggable element, the Droppable element and the + # Event object. You can extract additional information about the + # drop - like if the Ctrl or Shift keys were pressed - from the Event object. + # + # * :with - A JavaScript expression specifying the parameters for the XMLHttpRequest. + # Any expressions should return a valid URL query string. def drop_receiving_element(element_id, options = {}) javascript_tag(drop_receiving_element_js(element_id, options).chop!) end -- cgit v1.2.3 From 028a236f102cb617d1c3e39d3de9d51b99c4fd61 Mon Sep 17 00:00:00 2001 From: Alex Wayne Date: Wed, 21 May 2008 08:10:47 -0700 Subject: Added documentation for ActiveResource::HttpMock. Special thanks to Clever Title Pending: http://seangeo.blogspot.com/2007/09/testing-activeresource.html --- activeresource/lib/active_resource/http_mock.rb | 89 ++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 9 deletions(-) diff --git a/activeresource/lib/active_resource/http_mock.rb b/activeresource/lib/active_resource/http_mock.rb index d1c1412575..82e3bc8370 100644 --- a/activeresource/lib/active_resource/http_mock.rb +++ b/activeresource/lib/active_resource/http_mock.rb @@ -2,9 +2,53 @@ require 'active_resource/connection' module ActiveResource class InvalidRequestError < StandardError; end #:nodoc: - + + # One thing that has always been a pain with remote web services is testing. The HttpMock + # class makes it easy to test your Active Resource models by creating a set of mock responses to specific + # requests. + # + # To test your Active Resource model, you simply call the ActiveResource::HttpMock.respond_to + # method with an attached block. The block declares a set of URIs with expected input, and the output + # each request should return. The passed in block has any number of entries in the following generalized + # format: + # + # mock.http_method(path, request_headers = {}, body = nil, status = 200, response_headers = {}) + # + # * http_method - The HTTP method to listen for. This can be +get+, +post+, +put+, +delete+ or + # +head+. + # * path - A string, starting with a "/", defining the URI that is expected to be + # called. + # * request_headers - Headers that are expected along with the request. This argument uses a + # hash format, such as { "Content-Type" => "application/xml" }. This mock will only trigger + # if your tests sends a request with identical headers. + # * body - The data to be returned. This should be a string of ActiveResource parseable content, + # such as XML. + # * status - The HTTP response code, as an integer, to return with the response. + # * response_headers - Headers to be returned with the response. Uses the same hash format as + # request_headers listed above. + # + # In order for a mock to deliver its content, the incoming request must match by the http_method, + # +path+ and request_headers. If no match is found an InvalidRequestError exception + # will be raised letting you know you need to create a new mock for that request. + # + # ==== Example + # def setup + # @matz = { :id => 1, :name => "Matz" }.to_xml(:root => "person") + # ActiveResource::HttpMock.respond_to do |mock| + # mock.post "/people.xml", {}, @matz, 201, "Location" => "/people/1.xml" + # mock.get "/people/1.xml", {}, @matz + # mock.put "/people/1.xml", {}, nil, 204 + # mock.delete "/people/1.xml", {}, nil, 200 + # end + # end + # + # def test_get_matz + # person = Person.find(1) + # assert_equal "Matz", person.name + # end + # class HttpMock - class Responder + class Responder #:nodoc: def initialize(responses) @responses = responses end @@ -19,15 +63,41 @@ module ActiveResource end class << self + + # Returns an array of all request objects that have been sent to the mock. You can use this to check + # wether or not your model actually sent an HTTP request. + # + # ==== Example + # def setup + # @matz = { :id => 1, :name => "Matz" }.to_xml(:root => "person") + # ActiveResource::HttpMock.respond_to do |mock| + # mock.get "/people/1.xml", {}, @matz + # end + # end + # + # def test_should_request_remote_service + # person = Person.find(1) # Call the remote service + # + # # This request object has the same HTTP method and path as declared by the mock + # expected_request = ActiveResource::Request.new(:get, "/people/1.xml") + # + # # Assert that the mock received, and responded to, the expected request from the model + # assert ActiveResource::HttpMock.requests.include?(expected_request) + # end def requests @@requests ||= [] end - + + # Returns a hash of request => response pairs for all all responses this mock has delivered, where +request+ + # is an instance of ActiveResource::Request and the response is, naturally, an instance of + # ActiveResource::Response. def responses @@responses ||= {} end - - def respond_to(pairs = {}) + + # Accepts a block which declares a set of requests and responses for the HttpMock to respond to. See the main + # ActiveResource::HttpMock description for a more detailed explanation. + def respond_to(pairs = {}) #:yields: mock reset! pairs.each do |(path, response)| responses[path] = response @@ -39,7 +109,8 @@ module ActiveResource Responder.new(responses) end end - + + # Deletes all logged requests and responses. def reset! requests.clear responses.clear @@ -65,8 +136,8 @@ module ActiveResource end EOE end - - def initialize(site) + + def initialize(site) #:nodoc: @site = site end end @@ -135,7 +206,7 @@ module ActiveResource end end - class Connection + class Connection private silence_warnings do def http -- cgit v1.2.3 From 6e3521e6134e7f0d0b27834266e41354290c4e7e Mon Sep 17 00:00:00 2001 From: Erkki Eilonen Date: Wed, 14 May 2008 17:07:21 +0300 Subject: Improve check_box_checked? to use include? for Array values. [#193 state:resolved] Signed-off-by: Pratik Naik --- actionpack/lib/action_view/helpers/form_helper.rb | 2 ++ actionpack/test/template/form_helper_test.rb | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 6d97038da9..0962be2c79 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -616,6 +616,8 @@ module ActionView value != 0 when String value == checked_value + when Array + value.include?(checked_value) else value.to_i != 0 end diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 4538b6dc6f..af99e6243d 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -181,6 +181,17 @@ class FormHelperTest < ActionView::TestCase '', check_box("post", "secret?") ) + + @post.secret = ['0'] + assert_dom_equal( + '', + check_box("post", "secret") + ) + @post.secret = ['1'] + assert_dom_equal( + '', + check_box("post", "secret") + ) end def test_check_box_with_explicit_checked_and_unchecked_values -- cgit v1.2.3 From 262d23d763c05bbe5f433a99cb9f02e48a8cdd4a Mon Sep 17 00:00:00 2001 From: Ryan Bates Date: Wed, 21 May 2008 08:27:20 -0700 Subject: ActiveRecord::Base#reload should clear dirty attributes. [#231 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/dirty.rb | 8 ++++++++ activerecord/test/cases/dirty_test.rb | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/activerecord/lib/active_record/dirty.rb b/activerecord/lib/active_record/dirty.rb index 49f1204fa1..8fdc763292 100644 --- a/activerecord/lib/active_record/dirty.rb +++ b/activerecord/lib/active_record/dirty.rb @@ -40,6 +40,7 @@ module ActiveRecord base.alias_method_chain :save, :dirty base.alias_method_chain :save!, :dirty base.alias_method_chain :update, :dirty + base.alias_method_chain :reload, :dirty base.superclass_delegating_accessor :partial_updates base.partial_updates = false @@ -84,6 +85,13 @@ module ActiveRecord status end + # reload the record and clears changed attributes. + def reload_with_dirty(*args) #:nodoc: + record = reload_without_dirty(*args) + changed_attributes.clear + record + end + private # Map of change attr => original value. def changed_attributes diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index 62178977f9..c011ffaf57 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -137,6 +137,14 @@ class DirtyTest < ActiveRecord::TestCase check_pirate_after_save_failure(pirate) end + def test_reload_should_clear_changed_attributes + pirate = Pirate.create!(:catchphrase => "shiver me timbers") + pirate.catchphrase = "*hic*" + assert pirate.changed? + pirate.reload + assert !pirate.changed? + end + private def with_partial_updates(klass, on = true) old = klass.partial_updates? -- cgit v1.2.3 From bc0e24040b900c1800c95172dc2532c82e8b28f6 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 21 May 2008 21:49:45 +0200 Subject: revised conventions in http_mock.rb docs --- activeresource/lib/active_resource/http_mock.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/activeresource/lib/active_resource/http_mock.rb b/activeresource/lib/active_resource/http_mock.rb index 82e3bc8370..cf102da379 100644 --- a/activeresource/lib/active_resource/http_mock.rb +++ b/activeresource/lib/active_resource/http_mock.rb @@ -3,11 +3,11 @@ require 'active_resource/connection' module ActiveResource class InvalidRequestError < StandardError; end #:nodoc: - # One thing that has always been a pain with remote web services is testing. The HttpMock + # One thing that has always been a pain with remote web services is testing. The HttpMock # class makes it easy to test your Active Resource models by creating a set of mock responses to specific # requests. # - # To test your Active Resource model, you simply call the ActiveResource::HttpMock.respond_to + # To test your Active Resource model, you simply call the ActiveResource::HttpMock.respond_to # method with an attached block. The block declares a set of URIs with expected input, and the output # each request should return. The passed in block has any number of entries in the following generalized # format: @@ -16,7 +16,7 @@ module ActiveResource # # * http_method - The HTTP method to listen for. This can be +get+, +post+, +put+, +delete+ or # +head+. - # * path - A string, starting with a "/", defining the URI that is expected to be + # * path - A string, starting with a "/", defining the URI that is expected to be # called. # * request_headers - Headers that are expected along with the request. This argument uses a # hash format, such as { "Content-Type" => "application/xml" }. This mock will only trigger @@ -28,7 +28,7 @@ module ActiveResource # request_headers listed above. # # In order for a mock to deliver its content, the incoming request must match by the http_method, - # +path+ and request_headers. If no match is found an InvalidRequestError exception + # +path+ and request_headers. If no match is found an InvalidRequestError exception # will be raised letting you know you need to create a new mock for that request. # # ==== Example @@ -89,14 +89,14 @@ module ActiveResource end # Returns a hash of request => response pairs for all all responses this mock has delivered, where +request+ - # is an instance of ActiveResource::Request and the response is, naturally, an instance of - # ActiveResource::Response. + # is an instance of ActiveResource::Request and the response is, naturally, an instance of + # ActiveResource::Response. def responses @@responses ||= {} end # Accepts a block which declares a set of requests and responses for the HttpMock to respond to. See the main - # ActiveResource::HttpMock description for a more detailed explanation. + # ActiveResource::HttpMock description for a more detailed explanation. def respond_to(pairs = {}) #:yields: mock reset! pairs.each do |(path, response)| -- cgit v1.2.3 From 49738f000b9c7e2902cf17e5e13943e5015f91b8 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 21 May 2008 22:34:18 +0200 Subject: gsub("ActiveRecord", "Active Record") --- .../assertions/model_assertions.rb | 3 ++- .../lib/action_controller/polymorphic_routes.rb | 2 +- .../lib/action_view/helpers/form_options_helper.rb | 2 +- .../lib/action_view/helpers/form_tag_helper.rb | 2 +- .../lib/action_view/helpers/record_tag_helper.rb | 4 +-- activerecord/lib/active_record/associations.rb | 6 ++--- .../lib/active_record/attribute_methods.rb | 2 +- activerecord/lib/active_record/base.rb | 30 +++++++++++----------- activerecord/lib/active_record/fixtures.rb | 18 ++++++------- activerecord/lib/active_record/migration.rb | 2 +- activerecord/lib/active_record/named_scope.rb | 2 +- activerecord/lib/active_record/observer.rb | 2 +- activerecord/lib/active_record/schema_dumper.rb | 2 +- activerecord/lib/active_record/transactions.rb | 4 +-- .../configs/initializers/new_rails_defaults.rb | 8 +++--- railties/environments/environment.rb | 2 +- railties/lib/initializer.rb | 18 ++++++------- 17 files changed, 55 insertions(+), 54 deletions(-) diff --git a/actionpack/lib/action_controller/assertions/model_assertions.rb b/actionpack/lib/action_controller/assertions/model_assertions.rb index 0b4313055a..d25214bb66 100644 --- a/actionpack/lib/action_controller/assertions/model_assertions.rb +++ b/actionpack/lib/action_controller/assertions/model_assertions.rb @@ -1,7 +1,8 @@ module ActionController module Assertions module ModelAssertions - # Ensures that the passed record is valid by ActiveRecord standards and returns any error messages if it is not. + # Ensures that the passed record is valid by Active Record standards and + # returns any error messages if it is not. # # ==== Examples # diff --git a/actionpack/lib/action_controller/polymorphic_routes.rb b/actionpack/lib/action_controller/polymorphic_routes.rb index e2b7716aa2..c083993fc0 100644 --- a/actionpack/lib/action_controller/polymorphic_routes.rb +++ b/actionpack/lib/action_controller/polymorphic_routes.rb @@ -1,6 +1,6 @@ module ActionController # Polymorphic URL helpers are methods for smart resolution to a named route call when - # given an ActiveRecord model instance. They are to be used in combination with + # given an Active Record model instance. They are to be used in combination with # ActionController::Resources. # # These methods are useful when you want to generate correct URL or path to a RESTful diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index fca3881d9b..e0a097e367 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -298,7 +298,7 @@ module ActionView # a TimeZone. # # By default, +model+ is the TimeZone constant (which can be obtained - # in ActiveRecord as a value object). The only requirement is that the + # in Active Record as a value object). The only requirement is that the # +model+ parameter be an object that responds to +all+, and returns # an array of objects that represent time zones. # diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 922a0662fe..0ad6cc1302 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -3,7 +3,7 @@ require 'action_view/helpers/tag_helper' module ActionView module Helpers - # Provides a number of methods for creating form tags that doesn't rely on an ActiveRecord object assigned to the template like + # Provides a number of methods for creating form tags that doesn't rely on an Active Record object assigned to the template like # FormHelper does. Instead, you provide the names and values manually. # # NOTE: The HTML options disabled, readonly, and multiple can all be treated as booleans. So specifying diff --git a/actionpack/lib/action_view/helpers/record_tag_helper.rb b/actionpack/lib/action_view/helpers/record_tag_helper.rb index 40b66be79f..66c596f3a9 100644 --- a/actionpack/lib/action_view/helpers/record_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/record_tag_helper.rb @@ -2,7 +2,7 @@ module ActionView module Helpers module RecordTagHelper # Produces a wrapper DIV element with id and class parameters that - # relate to the specified ActiveRecord object. Usage example: + # relate to the specified Active Record object. Usage example: # # <% div_for(@person, :class => "foo") do %> # <%=h @person.name %> @@ -17,7 +17,7 @@ module ActionView end # content_tag_for creates an HTML element with id and class parameters - # that relate to the specified ActiveRecord object. For example: + # that relate to the specified Active Record object. For example: # # <% content_tag_for(:tr, @person) do %> # <%=h @person.first_name %> diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 31096ccd71..ec4c497d37 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -155,7 +155,7 @@ module ActiveRecord # # == Cardinality and associations # - # ActiveRecord associations can be used to describe one-to-one, one-to-many and many-to-many + # Active Record associations can be used to describe one-to-one, one-to-many and many-to-many # relationships between models. Each model uses an association to describe its role in # the relation. The +belongs_to+ association is always used in the model that has # the foreign key. @@ -520,13 +520,13 @@ module ActiveRecord # # will execute one query to load the addresses and load the addressables with one query per addressable type. # For example if all the addressables are either of class Person or Company then a total of 3 queries will be executed. The list of - # addressable types to load is determined on the back of the addresses loaded. This is not supported if ActiveRecord has to fallback + # addressable types to load is determined on the back of the addresses loaded. This is not supported if Active Record has to fallback # to the previous implementation of eager loading and will raise ActiveRecord::EagerLoadPolymorphicError. The reason is that the parent # model's type is a column value so its corresponding table name cannot be put in the +FROM+/+JOIN+ clauses of that query. # # == Table Aliasing # - # ActiveRecord uses table aliasing in the case that a table is referenced multiple times in a join. If a table is referenced only once, + # Active Record uses table aliasing in the case that a table is referenced multiple times in a join. If a table is referenced only once, # the standard table name is used. The second time, the table is aliased as #{reflection_name}_#{parent_table_name}. Indexes are appended # for any more successive uses of the table name. # diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 09346bec5c..fab16a4446 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -94,7 +94,7 @@ module ActiveRecord end # Checks whether the method is defined in the model or any of its subclasses - # that also derive from ActiveRecord. Raises DangerousAttributeError if the + # that also derive from Active Record. Raises DangerousAttributeError if the # method is defined by Active Record though. def instance_method_already_implemented?(method_name) method_name = method_name.to_s diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 457f1e841f..dab1fd7ee8 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -2,7 +2,7 @@ require 'yaml' require 'set' module ActiveRecord #:nodoc: - # Generic ActiveRecord exception class. + # Generic Active Record exception class. class ActiveRecordError < StandardError end @@ -30,19 +30,19 @@ module ActiveRecord #:nodoc: class SerializationTypeMismatch < ActiveRecordError end - # Raised when adapter not specified on connection (or configuration file config/database.yml misses adapter field). + # Raised when adapter not specified on connection (or configuration file config/database.yml misses adapter field). class AdapterNotSpecified < ActiveRecordError end - # Raised when ActiveRecord cannot find database adapter specified in config/database.yml or programmatically. + # Raised when Active Record cannot find database adapter specified in config/database.yml or programmatically. class AdapterNotFound < ActiveRecordError end - # Raised when connection to the database could not been established (for example when connection= is given a nil object). + # Raised when connection to the database could not been established (for example when connection= is given a nil object). class ConnectionNotEstablished < ActiveRecordError end - # Raised when ActiveRecord cannot find record by given id or set of ids. + # Raised when Active Record cannot find record by given id or set of ids. class RecordNotFound < ActiveRecordError end @@ -83,12 +83,12 @@ module ActiveRecord #:nodoc: class ReadOnlyRecord < ActiveRecordError end - # Used by ActiveRecord transaction mechanism to distinguish rollback from other exceptional situations. + # Used by Active Record transaction mechanism to distinguish rollback from other exceptional situations. # You can use it to roll your transaction back explicitly in the block passed to +transaction+ method. class Rollback < ActiveRecordError end - # Raised when attribute has a name reserved by ActiveRecord (when attribute has name of one of ActiveRecord instance methods). + # Raised when attribute has a name reserved by Active Record (when attribute has name of one of Active Record instance methods). class DangerousAttributeError < ActiveRecordError end @@ -966,7 +966,7 @@ module ActiveRecord #:nodoc: # Guesses the table name (in forced lower-case) based on the name of the class in the inheritance hierarchy descending - # directly from ActiveRecord. So if the hierarchy looks like: Reply < Message < ActiveRecord, then Message is used + # directly from ActiveRecord::Base. So if the hierarchy looks like: Reply < Message < ActiveRecord::Base, then Message is used # to guess the table name even when called on Reply. The rules used to do the guess are handled by the Inflector class # in Active Support, which knows almost all common English inflections. You can add new inflections in config/initializers/inflections.rb. # @@ -985,8 +985,8 @@ module ActiveRecord #:nodoc: # file class table_name # invoice/lineitem.rb Invoice::Lineitem lineitems # - # Additionally, the class-level table_name_prefix is prepended and the - # table_name_suffix is appended. So if you have "myapp_" as a prefix, + # Additionally, the class-level +table_name_prefix+ is prepended and the + # +table_name_suffix+ is appended. So if you have "myapp_" as a prefix, # the table name guess for an Invoice class becomes "myapp_invoices". # Invoice::Lineitem becomes "myapp_invoice_lineitems". # @@ -1902,7 +1902,7 @@ module ActiveRecord #:nodoc: end end - # Returns the class descending directly from ActiveRecord in the inheritance hierarchy. + # Returns the class descending directly from Active Record in the inheritance hierarchy. def class_of_active_record_descendant(klass) if klass.superclass == Base || klass.superclass.abstract_class? klass @@ -1913,7 +1913,7 @@ module ActiveRecord #:nodoc: end end - # Returns the name of the class descending directly from ActiveRecord in the inheritance hierarchy. + # Returns the name of the class descending directly from Active Record in the inheritance hierarchy. def class_name_of_active_record_descendant(klass) #:nodoc: klass.base_class.name end @@ -2500,9 +2500,9 @@ module ActiveRecord #:nodoc: id end - # Sets the attribute used for single table inheritance to this class name if this is not the ActiveRecord descendent. - # Considering the hierarchy Reply < Message < ActiveRecord, this makes it possible to do Reply.new without having to - # set Reply[Reply.inheritance_column] = "Reply" yourself. No such attribute would be set for objects of the + # Sets the attribute used for single table inheritance to this class name if this is not the ActiveRecord::Base descendent. + # Considering the hierarchy Reply < Message < ActiveRecord::Base, this makes it possible to do Reply.new without having to + # set Reply[Reply.inheritance_column] = "Reply" yourself. No such attribute would be set for objects of the # Message class in that example. def ensure_proper_type unless self.class.descends_from_active_record? diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 796ee13d3d..c4cbe5d52f 100755 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -258,7 +258,7 @@ end # reginald: # generated id: 324201669 # name: Reginald the Pirate # -# ActiveRecord looks at the fixture's model class, discovers the correct +# Active Record looks at the fixture's model class, discovers the correct # primary key, and generates it right before inserting the fixture # into the database. # @@ -268,7 +268,7 @@ end # == Label references for associations (belongs_to, has_one, has_many) # # Specifying foreign keys in fixtures can be very fragile, not to -# mention difficult to read. Since ActiveRecord can figure out the ID of +# mention difficult to read. Since Active Record can figure out the ID of # any fixture from its label, you can specify FK's by label instead of ID. # # === belongs_to @@ -305,7 +305,7 @@ end # name: George the Monkey # pirate: reginald # -# Pow! All is made clear. ActiveRecord reflects on the fixture's model class, +# Pow! All is made clear. Active Record reflects on the fixture's model class, # finds all the +belongs_to+ associations, and allows you to specify # a target *label* for the *association* (monkey: george) rather than # a target *id* for the *FK* (monkey_id: 1). @@ -313,7 +313,7 @@ end # ==== Polymorphic belongs_to # # Supporting polymorphic relationships is a little bit more complicated, since -# ActiveRecord needs to know what type your association is pointing at. Something +# Active Record needs to know what type your association is pointing at. Something # like this should look familiar: # # ### in fruit.rb @@ -333,7 +333,7 @@ end # apple: # eater: george (Monkey) # -# Just provide the polymorphic target type and ActiveRecord will take care of the rest. +# Just provide the polymorphic target type and Active Record will take care of the rest. # # === has_and_belongs_to_many # @@ -396,15 +396,15 @@ end # # Zap! No more fruits_monkeys.yml file. We've specified the list of fruits # on George's fixture, but we could've just as easily specified a list -# of monkeys on each fruit. As with +belongs_to+, ActiveRecord reflects on +# of monkeys on each fruit. As with +belongs_to+, Active Record reflects on # the fixture's model class and discovers the +has_and_belongs_to_many+ # associations. # # == Autofilled timestamp columns # -# If your table/model specifies any of ActiveRecord's -# standard timestamp columns (created_at, created_on, updated_at, updated_on), -# they will automatically be set to Time.now. +# If your table/model specifies any of Active Record's +# standard timestamp columns (+created_at+, +created_on+, +updated_at+, +updated_on+), +# they will automatically be set to Time.now. # # If you've set specific values, they'll be left alone. # diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index df512a996a..b47b01e99a 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -377,7 +377,7 @@ module ActiveRecord end def proper_table_name(name) - # Use the ActiveRecord objects own table_name, or pre/suffix from ActiveRecord::Base if name is a symbol/string + # Use the Active Record objects own table_name, or pre/suffix from ActiveRecord::Base if name is a symbol/string name.table_name rescue "#{ActiveRecord::Base.table_name_prefix}#{name}#{ActiveRecord::Base.table_name_suffix}" end end diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index c7cf1731c1..62eecbf9be 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -41,7 +41,7 @@ module ActiveRecord # Nested finds and calculations also work with these compositions: Shirt.red.dry_clean_only.count returns the number of garments # for which these criteria obtain. Similarly with Shirt.red.dry_clean_only.average(:thread_count). # - # All scopes are available as class methods on the ActiveRecord descendent upon which the scopes were defined. But they are also available to + # All scopes are available as class methods on the ActiveRecord::Base descendent upon which the scopes were defined. But they are also available to # has_many associations. If, # # class Person < ActiveRecord::Base diff --git a/activerecord/lib/active_record/observer.rb b/activerecord/lib/active_record/observer.rb index 45e4d5b704..6e55e36b7d 100644 --- a/activerecord/lib/active_record/observer.rb +++ b/activerecord/lib/active_record/observer.rb @@ -30,7 +30,7 @@ module ActiveRecord @observers ||= [] end - # Instantiate the global ActiveRecord observers + # Instantiate the global Active Record observers. def instantiate_observers return if @observers.blank? @observers.each do |observer| diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb index 826662d3ee..b90ed88c6b 100644 --- a/activerecord/lib/active_record/schema_dumper.rb +++ b/activerecord/lib/active_record/schema_dumper.rb @@ -38,7 +38,7 @@ module ActiveRecord stream.puts <
Balance record is transactionally saved even diff --git a/railties/configs/initializers/new_rails_defaults.rb b/railties/configs/initializers/new_rails_defaults.rb index 1a718608ae..2d7889ef22 100644 --- a/railties/configs/initializers/new_rails_defaults.rb +++ b/railties/configs/initializers/new_rails_defaults.rb @@ -4,15 +4,15 @@ # Only save the attributes that have changed since the record was loaded. ActiveRecord::Base.partial_updates = true -# Include ActiveRecord class name as root for JSON serialized output. +# Include Active Record class name as root for JSON serialized output. ActiveRecord::Base.include_root_in_json = true -# Store the full class name (including module namespace) in STI type column +# Store the full class name (including module namespace) in STI type column. ActiveRecord::Base.store_full_sti_class = true -# Use ISO 8601 format for JSON serialized times and dates +# Use ISO 8601 format for JSON serialized times and dates. ActiveSupport.use_standard_json_time_format = true -# Don't escape HTML entities in JSON, leave that for the #json_escape helper +# Don't escape HTML entities in JSON, leave that for the #json_escape helper. # if you're including raw json in an HTML page. ActiveSupport.escape_html_entities_in_json = false \ No newline at end of file diff --git a/railties/environments/environment.rb b/railties/environments/environment.rb index c33b80da4f..cf00bb6bc8 100644 --- a/railties/environments/environment.rb +++ b/railties/environments/environment.rb @@ -38,7 +38,7 @@ Rails::Initializer.run do |config| # (by default production uses :info, the others :debug) # config.log_level = :debug - # Make Time.zone default to the specified zone, and make ActiveRecord store time values + # Make Time.zone default to the specified zone, and make Active Record store time values # in the database in UTC, and return them converted to the specified local zone. # Run `rake -D time` for a list of tasks for finding time zone names. Uncomment to use default local time. config.time_zone = 'UTC' diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb index dd716cf501..2deccd1078 100644 --- a/railties/lib/initializer.rb +++ b/railties/lib/initializer.rb @@ -160,8 +160,8 @@ module Rails end # If Rails is vendored and RubyGems is available, install stub GemSpecs - # for Rails, ActiveSupport, ActiveRecord, ActionPack, ActionMailer, and - # ActiveResource. This allows Gem plugins to depend on Rails even when + # for Rails, Active Support, Active Record, Action Pack, Action Mailer, and + # Active Resource. This allows Gem plugins to depend on Rails even when # the Gem version of Rails shouldn't be loaded. def install_gem_spec_stubs unless Rails.respond_to?(:vendor_rails?) @@ -210,8 +210,8 @@ module Rails end # Requires all frameworks specified by the Configuration#frameworks - # list. By default, all frameworks (ActiveRecord, ActiveSupport, - # ActionPack, ActionMailer, and ActiveResource) are loaded. + # list. By default, all frameworks (Active Record, Active Support, + # Action Pack, Action Mailer, and Active Resource) are loaded. def require_frameworks configuration.frameworks.each { |framework| require(framework.to_s) } rescue LoadError => e @@ -359,7 +359,7 @@ module Rails silence_warnings { Object.const_set "RAILS_DEFAULT_LOGGER", logger } end - # Sets the logger for ActiveRecord, ActionController, and ActionMailer + # Sets the logger for Active Record, Action Controller, and Action Mailer # (but only for those frameworks that are to be loaded). If the framework's # logger is already set, it is not changed, otherwise it is set to use # RAILS_DEFAULT_LOGGER. @@ -409,7 +409,7 @@ module Rails end end - # Sets the default value for Time.zone, and turns on ActiveRecord time_zone_aware_attributes. + # Sets the default value for Time.zone, and turns on ActiveRecord::Base#time_zone_aware_attributes. # If assigned value cannot be matched to a TimeZone, an exception will be raised. def initialize_time_zone if configuration.time_zone @@ -618,9 +618,9 @@ module Rails end alias_method :breakpoint_server=, :breakpoint_server - # Sets the default time_zone. Setting this will enable time_zone - # awareness for ActiveRecord models and set the ActiveRecord default - # timezone to :utc. + # Sets the default +time_zone+. Setting this will enable +time_zone+ + # awareness for Active Record models and set the Active Record default + # timezone to :utc. attr_accessor :time_zone # Create a new Configuration instance, initialized with the default -- cgit v1.2.3 From 066b56149c56b2ea0ebec4c92c9d825edbfb6607 Mon Sep 17 00:00:00 2001 From: Joshua French Date: Wed, 21 May 2008 15:38:58 -0500 Subject: Revised example conventions in active_record/base --- activerecord/lib/active_record/base.rb | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 457f1e841f..0eb55391be 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -458,7 +458,9 @@ module ActiveRecord #:nodoc: # If no records are found, an empty array is returned. Use # Model.find(:all, *args) or its shortcut Model.all(*args). # - # All approaches accept an options hash as their last parameter. The options are: + # All approaches accept an options hash as their last parameter. + # + # ==== Attributes # # * :conditions - An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro. # * :order - An SQL fragment like "created_at DESC, name". @@ -479,7 +481,9 @@ module ActiveRecord #:nodoc: # * :lock - An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE". # :lock => true gives connection's default exclusive lock, usually "FOR UPDATE". # - # Examples for find by id: + # ==== Examples + # + # # find by id # Person.find(1) # returns the object for ID = 1 # Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6) # Person.find([7, 17]) # returns an array for objects with IDs in (7, 17) @@ -490,17 +494,19 @@ module ActiveRecord #:nodoc: # provide since database rows are unordered. Give an explicit :order # to ensure the results are sorted. # - # Examples for find first: + # ==== Examples + # + # # find first # Person.find(:first) # returns the first object fetched by SELECT * FROM people # Person.find(:first, :conditions => [ "user_name = ?", user_name]) # Person.find(:first, :order => "created_on DESC", :offset => 5) # - # Examples for find last: + # # find last # Person.find(:last) # returns the last object fetched by SELECT * FROM people # Person.find(:last, :conditions => [ "user_name = ?", user_name]) # Person.find(:last, :order => "created_on DESC", :offset => 5) # - # Examples for find all: + # # find all # Person.find(:all) # returns an array of objects for all the rows fetched by SELECT * FROM people # Person.find(:all, :conditions => [ "category IN (?)", categories], :limit => 50) # Person.find(:all, :conditions => { :friends => ["Bob", "Steve", "Fred"] } @@ -943,7 +949,7 @@ module ActiveRecord #:nodoc: # If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object, # then specify the name of that attribute using this method and it will be handled automatically. # The serialization is done through YAML. If +class_name+ is specified, the serialized object must be of that - # class on retrieval or SerializationTypeMismatch will be raised. + # class on retrieval or +SerializationTypeMismatch+ will be raised. # # ==== Attributes # @@ -971,7 +977,9 @@ module ActiveRecord #:nodoc: # in Active Support, which knows almost all common English inflections. You can add new inflections in config/initializers/inflections.rb. # # Nested classes are given table names prefixed by the singular form of - # the parent's table name. Enclosing modules are not considered. Examples: + # the parent's table name. Enclosing modules are not considered. + # + # ==== Examples # # class Invoice < ActiveRecord::Base; end; # file class table_name @@ -1065,8 +1073,6 @@ module ActiveRecord #:nodoc: # Sets the table name to use to the given value, or (if the value # is nil or false) to the value returned by the given block. # - # Example: - # # class Project < ActiveRecord::Base # set_table_name "project" # end @@ -1079,8 +1085,6 @@ module ActiveRecord #:nodoc: # or (if the value is nil or false) to the value returned by the given # block. # - # Example: - # # class Project < ActiveRecord::Base # set_primary_key "sysid" # end @@ -1093,8 +1097,6 @@ module ActiveRecord #:nodoc: # or (if the value # is nil or false) to the value returned by the # given block. # - # Example: - # # class Project < ActiveRecord::Base # set_inheritance_column do # original_inheritance_column + "_id" @@ -1116,8 +1118,6 @@ module ActiveRecord #:nodoc: # If a sequence name is not explicitly set when using PostgreSQL, it # will discover the sequence corresponding to your primary key for you. # - # Example: - # # class Project < ActiveRecord::Base # set_sequence_name "projectseq" # default would have been "project_seq" # end @@ -2144,7 +2144,9 @@ module ActiveRecord #:nodoc: (id = self.id) ? id.to_s : nil # Be sure to stringify the id for routes end - # Returns a cache key that can be used to identify this record. Examples: + # Returns a cache key that can be used to identify this record. + # + # ==== Examples # # Product.new.cache_key # => "products/new" # Product.find(5).cache_key # => "products/5" (updated_at not available) -- cgit v1.2.3 From 1edbdbbfa8c516e687dcf43e37544ee72596540d Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 21 May 2008 22:58:10 +0200 Subject: gsub("ActiveSupport", "Active Support") --- activeresource/lib/active_resource/base.rb | 2 +- activesupport/lib/active_support/core_ext/object/misc.rb | 2 +- activesupport/lib/active_support/json.rb | 2 +- activesupport/lib/active_support/values/time_zone.rb | 2 +- railties/lib/initializer.rb | 14 +++++++------- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index 08fd0123f6..961f5e6f7f 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -820,7 +820,7 @@ module ActiveResource # ==== Options # The +options+ parameter is handed off to the +to_xml+ method on each # attribute, so it has the same options as the +to_xml+ methods in - # ActiveSupport. + # Active Support. # # * :indent - Set the indent level for the XML output (default is +2+). # * :dasherize - Boolean option to determine whether or not element names should diff --git a/activesupport/lib/active_support/core_ext/object/misc.rb b/activesupport/lib/active_support/core_ext/object/misc.rb index a3637d7a8a..8384a12327 100644 --- a/activesupport/lib/active_support/core_ext/object/misc.rb +++ b/activesupport/lib/active_support/core_ext/object/misc.rb @@ -48,7 +48,7 @@ class Object yield ActiveSupport::OptionMerger.new(self, options) end - # A duck-type assistant method. For example, ActiveSupport extends Date + # A duck-type assistant method. For example, Active Support 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 diff --git a/activesupport/lib/active_support/json.rb b/activesupport/lib/active_support/json.rb index bbda2c9fa3..54a7becd0f 100644 --- a/activesupport/lib/active_support/json.rb +++ b/activesupport/lib/active_support/json.rb @@ -1,5 +1,5 @@ module ActiveSupport - # If true, use ISO 8601 format for dates and times. Otherwise, fall back to the ActiveSupport legacy format. + # If true, use ISO 8601 format for dates and times. Otherwise, fall back to the Active Support legacy format. mattr_accessor :use_standard_json_time_format class << self diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 5007e1b204..4d7239d8cf 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -16,7 +16,7 @@ # Time.zone.name # => "Eastern Time (US & Canada)" # Time.zone.now # => Sun, 18 May 2008 14:30:44 EDT -04:00 # -# The version of TZInfo bundled with ActiveSupport only includes the definitions necessary to support the zones +# The version of TZInfo bundled with Active Support only includes the definitions necessary to support the zones # defined by the TimeZone class. If you need to use zones that aren't defined by TimeZone, you'll need to install the TZInfo gem # (if a recent version of the gem is installed locally, this will be used instead of the bundled version.) class TimeZone diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb index 2deccd1078..c767e1ff7d 100644 --- a/railties/lib/initializer.rb +++ b/railties/lib/initializer.rb @@ -475,22 +475,22 @@ module Rails # The application's base directory. attr_reader :root_path - # A stub for setting options on ActionController::Base + # A stub for setting options on ActionController::Base. attr_accessor :action_controller - # A stub for setting options on ActionMailer::Base + # A stub for setting options on ActionMailer::Base. attr_accessor :action_mailer - # A stub for setting options on ActionView::Base + # A stub for setting options on ActionView::Base. attr_accessor :action_view - # A stub for setting options on ActiveRecord::Base + # A stub for setting options on ActiveRecord::Base. attr_accessor :active_record - # A stub for setting options on ActiveRecord::Base + # A stub for setting options on ActiveRecord::Base. attr_accessor :active_resource - # A stub for setting options on ActiveSupport + # A stub for setting options on ActiveSupport. attr_accessor :active_support # Whether or not classes should be cached (set to false if you want @@ -843,7 +843,7 @@ end # Needs to be duplicated from Active Support since its needed before Active # Support is available. Here both Options and Hash are namespaced to prevent -# conflicts with other implementations AND with the classes residing in ActiveSupport. +# conflicts with other implementations AND with the classes residing in Active Support. class Rails::OrderedOptions < Array #:nodoc: def []=(key, value) key = key.to_sym -- cgit v1.2.3 From 11f0fd5c6febed712194b0494b2e4de85b131c26 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 21 May 2008 23:20:28 +0200 Subject: gsub("ActionController", "Action Controller") --- actionmailer/lib/action_mailer/base.rb | 2 +- actionpack/lib/action_view/helpers/url_helper.rb | 2 +- railties/lib/initializer.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 7ab6e37503..dbc6801146 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -54,7 +54,7 @@ module ActionMailer #:nodoc: # # = Mailer views # - # Like ActionController, each mailer class has a corresponding view directory + # Like Action Controller, each mailer class has a corresponding view directory # in which each method of the class looks for a template with its name. # To define a template to be used with a mailing, create an .erb file with the same name as the method # in your mailer model. For example, in the mailer defined above, the template at diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index 38c8d18cb0..4b12adf225 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -10,7 +10,7 @@ module ActionView include JavaScriptHelper # Returns the URL for the set of +options+ provided. This takes the - # same options as url_for in ActionController (see the + # same options as +url_for+ in Action Controller (see the # documentation for ActionController::Base#url_for). Note that by default # :only_path is true so you'll get the relative /controller/action # instead of the fully qualified URL like http://example.com/controller/action. diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb index c767e1ff7d..150e76af77 100644 --- a/railties/lib/initializer.rb +++ b/railties/lib/initializer.rb @@ -380,7 +380,7 @@ module Rails ActionController::Base.view_paths = [configuration.view_path] if configuration.frameworks.include?(:action_controller) && ActionController::Base.view_paths.empty? end - # If ActionController is not one of the loaded frameworks (Configuration#frameworks) + # If Action Controller is not one of the loaded frameworks (Configuration#frameworks) # this does nothing. Otherwise, it loads the routing definitions and sets up # loading module used to lazily load controllers (Configuration#controller_paths). def initialize_routing -- cgit v1.2.3 From 46f0836d60da3e1e3508b1e03cd123cf8c58df6e Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 21 May 2008 23:30:26 +0200 Subject: gsub("ActionPack", "Action Pack") --- actionpack/lib/action_controller/mime_type.rb | 2 +- activeresource/lib/active_resource/base.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_controller/mime_type.rb b/actionpack/lib/action_controller/mime_type.rb index 1d6c8e704b..fa123f7808 100644 --- a/actionpack/lib/action_controller/mime_type.rb +++ b/actionpack/lib/action_controller/mime_type.rb @@ -158,7 +158,7 @@ module Mime end end - # Returns true if ActionPack should check requests using this Mime Type for possible request forgery. See + # Returns true if Action Pack should check requests using this Mime Type for possible request forgery. See # ActionController::RequestForgerProtection. def verify_request? !@@unverifiable_types.include?(to_sym) diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index 961f5e6f7f..6e0d7e9d1d 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -701,7 +701,7 @@ module ActiveResource attributes[self.class.primary_key] = id end - # Allows ActiveResource objects to be used as parameters in ActionPack URL generation. + # Allows ActiveResource objects to be used as parameters in Action Pack URL generation. def to_param id && id.to_s end -- cgit v1.2.3 From 291333d93a443d378e8837d97e04f06911ff85ab Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 21 May 2008 23:36:18 +0200 Subject: gsub("ActiveResource", "Active Resource") --- activeresource/lib/active_resource/base.rb | 8 ++++---- activeresource/lib/active_resource/custom_methods.rb | 4 ++-- activeresource/lib/active_resource/formats/xml_format.rb | 2 +- activeresource/lib/active_resource/http_mock.rb | 2 +- activeresource/lib/active_resource/validations.rb | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index 6e0d7e9d1d..b38b4c0194 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -127,7 +127,7 @@ module ActiveResource # # GET http://api.people.com:3000/people/999.xml # ryan = Person.find(999) # 404, raises ActiveResource::ResourceNotFound # - # 404 is just one of the HTTP error response codes that ActiveResource will handle with its own exception. The + # 404 is just one of the HTTP error response codes that Active Resource will handle with its own exception. The # following HTTP response codes will also result in these exceptions: # # * 200..399 - Valid response, no exception @@ -201,7 +201,7 @@ module ActiveResource class << self # Gets the URI of the REST resources to map for this class. The site variable is required - # ActiveResource's mapping to work. + # Active Resource's mapping to work. def site # Not using superclass_delegating_reader because don't want subclasses to modify superclass instance # @@ -226,7 +226,7 @@ module ActiveResource end # Sets the URI of the REST resources to map for this class to the value in the +site+ argument. - # The site variable is required ActiveResource's mapping to work. + # The site variable is required Active Resource's mapping to work. def site=(site) @connection = nil if site.nil? @@ -701,7 +701,7 @@ module ActiveResource attributes[self.class.primary_key] = id end - # Allows ActiveResource objects to be used as parameters in Action Pack URL generation. + # Allows Active Resource objects to be used as parameters in Action Pack URL generation. def to_param id && id.to_s end diff --git a/activeresource/lib/active_resource/custom_methods.rb b/activeresource/lib/active_resource/custom_methods.rb index 52a4a4f10b..33a2fffaa0 100644 --- a/activeresource/lib/active_resource/custom_methods.rb +++ b/activeresource/lib/active_resource/custom_methods.rb @@ -48,8 +48,8 @@ module ActiveResource # # => [{:id => 1, :name => 'Ryan'}] # # Note: the objects returned from this method are not automatically converted - # into ActiveResource instances - they are ordinary Hashes. If you are expecting - # ActiveResource instances, use the find class method with the + # into Active Resource instances - they are ordinary Hashes. If you are expecting + # Active Resource instances, use the find class method with the # :from option. For example: # # Person.find(:all, :from => :active) diff --git a/activeresource/lib/active_resource/formats/xml_format.rb b/activeresource/lib/active_resource/formats/xml_format.rb index 01c28dcee6..5e97ffa776 100644 --- a/activeresource/lib/active_resource/formats/xml_format.rb +++ b/activeresource/lib/active_resource/formats/xml_format.rb @@ -21,7 +21,7 @@ module ActiveResource private # Manipulate from_xml Hash, because xml_simple is not exactly what we - # want for ActiveResource. + # want for Active Resource. def from_xml_data(data) if data.is_a?(Hash) && data.keys.size == 1 data.values.first diff --git a/activeresource/lib/active_resource/http_mock.rb b/activeresource/lib/active_resource/http_mock.rb index cf102da379..ab219ef19d 100644 --- a/activeresource/lib/active_resource/http_mock.rb +++ b/activeresource/lib/active_resource/http_mock.rb @@ -21,7 +21,7 @@ module ActiveResource # * request_headers - Headers that are expected along with the request. This argument uses a # hash format, such as { "Content-Type" => "application/xml" }. This mock will only trigger # if your tests sends a request with identical headers. - # * body - The data to be returned. This should be a string of ActiveResource parseable content, + # * body - The data to be returned. This should be a string of Active Resource parseable content, # such as XML. # * status - The HTTP response code, as an integer, to return with the response. # * response_headers - Headers to be returned with the response. Uses the same hash format as diff --git a/activeresource/lib/active_resource/validations.rb b/activeresource/lib/active_resource/validations.rb index b955db6ec1..a7c624f309 100644 --- a/activeresource/lib/active_resource/validations.rb +++ b/activeresource/lib/active_resource/validations.rb @@ -216,7 +216,7 @@ module ActiveResource end end - # Module to allow validation of ActiveResource objects, which creates an Errors instance for every resource. + # Module to allow validation of Active Resource objects, which creates an Errors instance for every resource. # Methods are implemented by overriding Base#validate or its variants Each of these methods can inspect # the state of the object, which usually means ensuring that a number of attributes have a certain value # (such as not empty, within a given range, matching a certain regular expression and so on). -- cgit v1.2.3 From e89b4bc0c787d7010ba653d1cf0e0f5a2766b2f5 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 21 May 2008 23:38:26 +0200 Subject: gsub("ActionMailer", "Action Mailer") --- actionmailer/lib/action_mailer/base.rb | 6 +++--- railties/environments/test.rb | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index dbc6801146..030bb178da 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -5,12 +5,12 @@ require 'action_mailer/utils' require 'tmail/net' module ActionMailer #:nodoc: - # ActionMailer allows you to send email from your application using a mailer model and views. + # Action Mailer allows you to send email from your application using a mailer model and views. # # # = Mailer Models # - # To use ActionMailer, you need to create a mailer model. + # To use Action Mailer, you need to create a mailer model. # # $ script/generate mailer Notifier # @@ -157,7 +157,7 @@ module ActionMailer #:nodoc: # end # end # - # Multipart messages can also be used implicitly because ActionMailer will automatically + # Multipart messages can also be used implicitly because Action Mailer will automatically # detect and use multipart templates, where each template is named after the name of the action, followed # by the content type. Each such detected template will be added as separate part to the message. # diff --git a/railties/environments/test.rb b/railties/environments/test.rb index 58850a7974..1e709e1d19 100644 --- a/railties/environments/test.rb +++ b/railties/environments/test.rb @@ -16,7 +16,7 @@ config.action_controller.perform_caching = false # Disable request forgery protection in test environment config.action_controller.allow_forgery_protection = false -# Tell ActionMailer not to deliver emails to the real world. +# Tell Action Mailer not to deliver emails to the real world. # The :test delivery method accumulates sent emails in the # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test -- cgit v1.2.3 From 4617139bcc21ccb875d25baf06c3124692061cf2 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 21 May 2008 23:47:57 +0200 Subject: regular font for a constant --- activerecord/lib/active_record/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 55fc803e3c..c393128621 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -949,7 +949,7 @@ module ActiveRecord #:nodoc: # If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object, # then specify the name of that attribute using this method and it will be handled automatically. # The serialization is done through YAML. If +class_name+ is specified, the serialized object must be of that - # class on retrieval or +SerializationTypeMismatch+ will be raised. + # class on retrieval or SerializationTypeMismatch will be raised. # # ==== Attributes # -- cgit v1.2.3 From dd9938a44ee3a7bb6c42527a1be6fcec70bf4772 Mon Sep 17 00:00:00 2001 From: Frederick Cheung Date: Wed, 21 May 2008 21:03:38 +0100 Subject: Fix mysql 4.1 incompatibility in the active record schema tests. Signed-off-by: Michael Koziarski [#233 state:resolved ] --- .../test/cases/active_schema_test_mysql.rb | 73 ++++++++++++---------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/activerecord/test/cases/active_schema_test_mysql.rb b/activerecord/test/cases/active_schema_test_mysql.rb index ddf3e82162..2a42dc3517 100644 --- a/activerecord/test/cases/active_schema_test_mysql.rb +++ b/activerecord/test/cases/active_schema_test_mysql.rb @@ -40,47 +40,56 @@ class ActiveSchemaTest < ActiveRecord::TestCase end def test_add_timestamps - #we need to actually modify some data, so we make execute to point to the original method - ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do - alias_method :execute_with_stub, :execute - alias_method :execute, :execute_without_stub - end - ActiveRecord::Base.connection.create_table :delete_me do |t| - end - ActiveRecord::Base.connection.add_timestamps :delete_me - assert_equal ActiveRecord::Base.connection.execute("SHOW FIELDS FROM delete_me where FIELD='updated_at' AND TYPE='datetime'").num_rows, 1 - assert_equal ActiveRecord::Base.connection.execute("SHOW FIELDS FROM delete_me where FIELD='created_at' AND TYPE='datetime'").num_rows, 1 - ensure - ActiveRecord::Base.connection.drop_table :delete_me rescue nil - #before finishing, we restore the alias to the mock-up method - ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do - alias_method :execute, :execute_with_stub + with_real_execute do + begin + ActiveRecord::Base.connection.create_table :delete_me do |t| + end + ActiveRecord::Base.connection.add_timestamps :delete_me + assert column_present?('delete_me', 'updated_at', 'datetime') + assert column_present?('delete_me', 'created_at', 'datetime') + ensure + ActiveRecord::Base.connection.drop_table :delete_me rescue nil + end end end def test_remove_timestamps - #we need to actually modify some data, so we make execute to point to the original method - ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do - alias_method :execute_with_stub, :execute - alias_method :execute, :execute_without_stub - end - ActiveRecord::Base.connection.create_table :delete_me do |t| - t.timestamps - end - ActiveRecord::Base.connection.remove_timestamps :delete_me - assert_equal ActiveRecord::Base.connection.execute("SHOW FIELDS FROM delete_me where FIELD='updated_at' AND TYPE='datetime'").num_rows, 0 - assert_equal ActiveRecord::Base.connection.execute("SHOW FIELDS FROM delete_me where FIELD='created_at' AND TYPE='datetime'").num_rows, 0 - ensure - ActiveRecord::Base.connection.drop_table :delete_me rescue nil - #before finishing, we restore the alias to the mock-up method - ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do - alias_method :execute, :execute_with_stub + with_real_execute do + begin + ActiveRecord::Base.connection.create_table :delete_me do |t| + t.timestamps + end + ActiveRecord::Base.connection.remove_timestamps :delete_me + assert !column_present?('delete_me', 'updated_at', 'datetime') + assert !column_present?('delete_me', 'created_at', 'datetime') + ensure + ActiveRecord::Base.connection.drop_table :delete_me rescue nil + end end end - private + def with_real_execute + #we need to actually modify some data, so we make execute point to the original method + ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do + alias_method :execute_with_stub, :execute + alias_method :execute, :execute_without_stub + end + yield + ensure + #before finishing, we restore the alias to the mock-up method + ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do + alias_method :execute, :execute_with_stub + end + end + + def method_missing(method_symbol, *arguments) ActiveRecord::Base.connection.send(method_symbol, *arguments) end + + def column_present?(table_name, column_name, type) + results = ActiveRecord::Base.connection.select_all("SHOW FIELDS FROM #{table_name} LIKE '#{column_name}'") + results.first && results.first['Type'] == type + end end -- cgit v1.2.3 From 314e556e6fb7278e37f6105fedbe5fc51f7f848a Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 21 May 2008 11:54:24 -0700 Subject: Parentheses should be acceptable characters for auto_link_urls. [#234 state:resolved] Signed-off-by: Pratik Naik --- actionpack/lib/action_view/helpers/text_helper.rb | 2 +- actionpack/test/template/text_helper_test.rb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 55d2a68327..b710157f51 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -464,7 +464,7 @@ module ActionView [-\w]+ # subdomain or domain (?:\.[-\w]+)* # remaining subdomains or domain (?::\d+)? # port - (?:/(?:(?:[~\w\+@%=-]|(?:[,.;:][^\s$]))+)?)* # path + (?:/(?:(?:[~\w\+@%=\(\)-]|(?:[,.;:][^\s$]))+)?)* # path (?:\?[\w\+@%&=.;-]+)? # query string (?:\#[\w\-]*)? # trailing anchor ) diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb index 337697bf5c..36c939f761 100644 --- a/actionpack/test/template/text_helper_test.rb +++ b/actionpack/test/template/text_helper_test.rb @@ -186,6 +186,7 @@ class TextHelperTest < ActionView::TestCase http://en.wikipedia.org/wiki/Wikipedia:Today%27s_featured_picture_%28animation%29/January_20%2C_2007 http://www.mail-archive.com/rails@lists.rubyonrails.org/ http://www.amazon.com/Testing-Equal-Sign-In-Path/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1198861734&sr=8-1 + http://en.wikipedia.org/wiki/Sprite_(computer_graphics) ) urls.each do |url| -- cgit v1.2.3 From 4e084c3d9860c31fca21395c13031f04bb510b15 Mon Sep 17 00:00:00 2001 From: Ryan Bates Date: Wed, 21 May 2008 16:12:54 -0700 Subject: Add Rails.version. [#236 state:resolved] Signed-off-by: Pratik Naik --- railties/lib/commands/console.rb | 4 ++-- railties/lib/initializer.rb | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/railties/lib/commands/console.rb b/railties/lib/commands/console.rb index edffe4f1e6..2b9d92f647 100644 --- a/railties/lib/commands/console.rb +++ b/railties/lib/commands/console.rb @@ -24,9 +24,9 @@ ENV['RAILS_ENV'] = case ARGV.first end if options[:sandbox] - puts "Loading #{ENV['RAILS_ENV']} environment in sandbox (Rails #{Rails::VERSION::STRING})" + puts "Loading #{ENV['RAILS_ENV']} environment in sandbox (Rails #{Rails.version})" puts "Any modifications you make will be rolled back on exit" else - puts "Loading #{ENV['RAILS_ENV']} environment (Rails #{Rails::VERSION::STRING})" + puts "Loading #{ENV['RAILS_ENV']} environment (Rails #{Rails.version})" end exec "#{options[:irb]} #{libs} --simple-prompt" diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb index dfd43042be..2e56485989 100644 --- a/railties/lib/initializer.rb +++ b/railties/lib/initializer.rb @@ -43,6 +43,10 @@ module Rails RAILS_CACHE end + def version + VERSION::STRING + end + def public_path @@public_path ||= self.root ? File.join(self.root, "public") : "public" end -- cgit v1.2.3 From c2036adf7658f56c924e2a206731ee63b628f34f Mon Sep 17 00:00:00 2001 From: Lawrence Pit Date: Thu, 22 May 2008 12:06:27 +0100 Subject: Show rails version when the server starts. [#235 state:resolved] Signed-off-by: Pratik Naik --- railties/lib/commands/servers/lighttpd.rb | 2 +- railties/lib/commands/servers/mongrel.rb | 2 +- railties/lib/commands/servers/webrick.rb | 2 +- railties/lib/rails/mongrel_server/commands.rb | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/railties/lib/commands/servers/lighttpd.rb b/railties/lib/commands/servers/lighttpd.rb index 07d4f9d0bf..c9d13e86f3 100644 --- a/railties/lib/commands/servers/lighttpd.rb +++ b/railties/lib/commands/servers/lighttpd.rb @@ -62,7 +62,7 @@ config = IO.read(config_file) default_port, default_ip = 3000, '0.0.0.0' port = config.scan(/^\s*server.port\s*=\s*(\d+)/).first rescue default_port ip = config.scan(/^\s*server.bind\s*=\s*"([^"]+)"/).first rescue default_ip -puts "=> Rails application starting on http://#{ip || default_ip}:#{port || default_port}" +puts "=> Rails #{Rails.version} application starting on http://#{ip || default_ip}:#{port || default_port}" tail_thread = nil diff --git a/railties/lib/commands/servers/mongrel.rb b/railties/lib/commands/servers/mongrel.rb index f59265e698..7bb110f63a 100644 --- a/railties/lib/commands/servers/mongrel.rb +++ b/railties/lib/commands/servers/mongrel.rb @@ -32,7 +32,7 @@ ARGV.clone.options do |opts| opts.parse! end -puts "=> Rails application starting on http://#{OPTIONS[:ip]}:#{OPTIONS[:port]}" +puts "=> Rails #{Rails.version} application starting on http://#{OPTIONS[:ip]}:#{OPTIONS[:port]}" parameters = [ "start", diff --git a/railties/lib/commands/servers/webrick.rb b/railties/lib/commands/servers/webrick.rb index b950376150..18c8897cc8 100644 --- a/railties/lib/commands/servers/webrick.rb +++ b/railties/lib/commands/servers/webrick.rb @@ -61,6 +61,6 @@ require 'webrick_server' OPTIONS['working_directory'] = File.expand_path(RAILS_ROOT) -puts "=> Rails application started on http://#{OPTIONS[:ip]}:#{OPTIONS[:port]}" +puts "=> Rails #{Rails.version} application started on http://#{OPTIONS[:ip]}:#{OPTIONS[:port]}" puts "=> Ctrl-C to shutdown server; call with --help for options" if OPTIONS[:server_type] == WEBrick::SimpleServer DispatchServlet.dispatch(OPTIONS) diff --git a/railties/lib/rails/mongrel_server/commands.rb b/railties/lib/rails/mongrel_server/commands.rb index 3786a56fde..0a92f418ad 100644 --- a/railties/lib/rails/mongrel_server/commands.rb +++ b/railties/lib/rails/mongrel_server/commands.rb @@ -119,7 +119,7 @@ module Rails config = RailsConfigurator.new(settings) do defaults[:log] = $stdout if defaults[:environment] == 'development' - Mongrel.log("=> Rails application starting on http://#{defaults[:host]}:#{defaults[:port]}") + Mongrel.log("=> Rails #{Rails.version} application starting on http://#{defaults[:host]}:#{defaults[:port]}") unless defaults[:daemon] Mongrel.log("=> Call with -d to detach") -- cgit v1.2.3 From cff2291df5d1df106ae8cf116655f0703f53f8c3 Mon Sep 17 00:00:00 2001 From: Frederick Cheung Date: Thu, 22 May 2008 11:19:10 +0100 Subject: Fix failing tests on mysql 4.1 & ruby 1.8.4. [#237 state:resolved] Signed-off-by: Pratik Naik --- activerecord/test/cases/migration_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 527856b4c0..f36255e209 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -281,7 +281,7 @@ if ActiveRecord::Base.connection.supports_migrations? # Do a manual insertion if current_adapter?(:OracleAdapter) Person.connection.execute "insert into people (id, wealth) values (people_seq.nextval, 12345678901234567890.0123456789)" - elsif current_adapter?(:OpenBaseAdapter) + elsif current_adapter?(:OpenBaseAdapter) || (current_adapter?(:MysqlAdapter) && Mysql.client_version < 50003) #before mysql 5.0.3 decimals stored as strings Person.connection.execute "insert into people (wealth) values ('12345678901234567890.0123456789')" else Person.connection.execute "insert into people (wealth) values (12345678901234567890.0123456789)" @@ -384,7 +384,7 @@ if ActiveRecord::Base.connection.supports_migrations? assert_not_equal "Z", bob.moment_of_truth.zone # US/Eastern is -5 hours from GMT assert_equal Rational(-5, 24), bob.moment_of_truth.offset - assert_equal "-05:00", bob.moment_of_truth.zone + assert_match /\A-05:?00\Z/, bob.moment_of_truth.zone #ruby 1.8.6 uses HH:MM, prior versions use HHMM assert_equal DateTime::ITALY, bob.moment_of_truth.start end end -- cgit v1.2.3 From 1a73e98660b29a2ce9eccd5b0776367a4969a012 Mon Sep 17 00:00:00 2001 From: Kevin Glowacz Date: Thu, 22 May 2008 14:21:33 -0500 Subject: Fix auto_link helper for already linked urls. [#72 state:resolved] Signed-off-by: Pratik Naik --- actionpack/lib/action_view/helpers/text_helper.rb | 4 ++-- actionpack/test/template/text_helper_test.rb | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index b710157f51..669a285424 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -454,7 +454,7 @@ module ActionView ( # leading text <\w+.*?>| # leading HTML tag, or [^=!:'"/]| # leading punctuation, or - | # nothing + ^ # beginning of line ) ( (?:https?://)| # protocol spec, or @@ -468,7 +468,7 @@ module ActionView (?:\?[\w\+@%&=.;-]+)? # query string (?:\#[\w\-]*)? # trailing anchor ) - ([[:punct:]]|\s|<|$) # trailing text + ([[:punct:]]|<|$|) # trailing text }x unless const_defined?(:AUTO_LINK_RE) # Turns all urls into clickable links. If a block is given, each url diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb index 36c939f761..62cdca03d1 100644 --- a/actionpack/test/template/text_helper_test.rb +++ b/actionpack/test/template/text_helper_test.rb @@ -264,6 +264,7 @@ class TextHelperTest < ActionView::TestCase assert_equal '', auto_link(nil) assert_equal '', auto_link('') assert_equal "#{link_result} #{link_result} #{link_result}", auto_link("#{link_raw} #{link_raw} #{link_raw}") + assert_equal 'Ruby On Rails', auto_link('Ruby On Rails') end def test_auto_link_at_eol -- cgit v1.2.3 From 888d5059bdb71e6d034d0c09d7e3b3e235fd8507 Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Thu, 22 May 2008 19:28:52 +1200 Subject: Return Partial Updates to be purely opt in to prevent users from inadvertently corrupting data. --- railties/configs/initializers/new_rails_defaults.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/railties/configs/initializers/new_rails_defaults.rb b/railties/configs/initializers/new_rails_defaults.rb index 1a718608ae..b959c6d549 100644 --- a/railties/configs/initializers/new_rails_defaults.rb +++ b/railties/configs/initializers/new_rails_defaults.rb @@ -1,9 +1,6 @@ # These settings change the behavior of Rails 2 apps and will be defaults # for Rails 3. You can remove this initializer when Rails 3 is released. -# Only save the attributes that have changed since the record was loaded. -ActiveRecord::Base.partial_updates = true - # Include ActiveRecord class name as root for JSON serialized output. ActiveRecord::Base.include_root_in_json = true -- cgit v1.2.3 From 5b8d0f134a5766aa1b3d0945b79f04d2bb911c02 Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Fri, 23 May 2008 09:07:38 +1200 Subject: Mention partial updates in environment.rb to make it easier for people to opt-in if they know it's safe --- railties/environments/environment.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/railties/environments/environment.rb b/railties/environments/environment.rb index c33b80da4f..d03447e1d3 100644 --- a/railties/environments/environment.rb +++ b/railties/environments/environment.rb @@ -64,4 +64,7 @@ Rails::Initializer.run do |config| # Activate observers that should always be running # config.active_record.observers = :cacher, :garbage_collector + + # Make ActiveRecord only save the attributes that have changed since the record was loaded. + # config.active_record.partial_updates = true end \ No newline at end of file -- cgit v1.2.3 From 82601290cd6bbf8a8a100622cc9c5164128611a0 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Fri, 23 May 2008 00:21:35 +0200 Subject: fixed indentation in description list --- actionpack/lib/action_view/helpers/form_tag_helper.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 0ad6cc1302..ca58f4ba26 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -14,9 +14,9 @@ module ActionView # # ==== Options # * :multipart - If set to true, the enctype is set to "multipart/form-data". - # * :method - The method to use when submitting the form, usually either "get" or "post". - # If "put", "delete", or another verb is used, a hidden input with name _method - # is added to simulate the verb over post. + # * :method - The method to use when submitting the form, usually either "get" or "post". + # If "put", "delete", or another verb is used, a hidden input with name _method + # is added to simulate the verb over post. # * A list of parameters to feed to the URL the form will be posted to. # # ==== Examples -- cgit v1.2.3 From 098c2104e2c2bad8c8f28b502e82649397a67253 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Fri, 23 May 2008 00:28:22 +0200 Subject: fixed indentation in description lists --- .../action_view/helpers/scriptaculous_helper.rb | 115 ++++++++++----------- 1 file changed, 56 insertions(+), 59 deletions(-) diff --git a/actionpack/lib/action_view/helpers/scriptaculous_helper.rb b/actionpack/lib/action_view/helpers/scriptaculous_helper.rb index 658480c016..c9b2761cb8 100644 --- a/actionpack/lib/action_view/helpers/scriptaculous_helper.rb +++ b/actionpack/lib/action_view/helpers/scriptaculous_helper.rb @@ -67,6 +67,7 @@ module ActionView # element as parameters. # # Example: + # # <%= sortable_element("my_list", :url => { :action => "order" }) %> # # In the example, the action gets a "my_list" array parameter @@ -79,60 +80,56 @@ module ActionView # # Additional +options+ are: # - # * :format - A regular expression to determine what to send - # as the serialized id to the server (the default - # is /^[^_]*_(.*)$/). + # * :format - A regular expression to determine what to send as the + # serialized id to the server (the default is /^[^_]*_(.*)$/). # - # * :constraint - Whether to constrain the dragging to either :horizontal - # or :vertical (or false to make it unconstrained). + # * :constraint - Whether to constrain the dragging to either + # :horizontal or :vertical (or false to make it unconstrained). # - # * :overlap - Calculate the item overlap in the :horizontal or - # :vertical direction. + # * :overlap - Calculate the item overlap in the :horizontal + # or :vertical direction. # - # * :tag - Which children of the container element to treat as - # sortable (default is li). + # * :tag - Which children of the container element to treat as + # sortable (default is li). # # * :containment - Takes an element or array of elements to treat as - # potential drop targets (defaults to the original - # target element). + # potential drop targets (defaults to the original target element). # - # * :only - A CSS class name or arry of class names used to filter - # out child elements as candidates. + # * :only - A CSS class name or arry of class names used to filter + # out child elements as candidates. # - # * :scroll - Determines whether to scroll the list during drag - # operations if the list runs past the visual border. + # * :scroll - Determines whether to scroll the list during drag + # operations if the list runs past the visual border. # - # * :tree - Determines whether to treat nested lists as part of the - # main sortable list. This means that you can create multi- - # layer lists, and not only sort items at the same level, - # but drag and sort items between levels. + # * :tree - Determines whether to treat nested lists as part of the + # main sortable list. This means that you can create multi-layer lists, + # and not only sort items at the same level, but drag and sort items + # between levels. # - # * :hoverclass - If set, the Droppable will have this additional CSS class - # when an accepted Draggable is hovered over it. + # * :hoverclass - If set, the Droppable will have this additional CSS class + # when an accepted Draggable is hovered over it. # - # * :handle - Sets whether the element should only be draggable by an - # embedded handle. The value may be a string referencing a - # CSS class value (as of script.aculo.us V1.5). The first - # child/grandchild/etc. element found within the element - # that has this CSS class value will be used as the handle. + # * :handle - Sets whether the element should only be draggable by an + # embedded handle. The value may be a string referencing a CSS class value + # (as of script.aculo.us V1.5). The first child/grandchild/etc. element + # found within the element that has this CSS class value will be used as + # the handle. # - # * :ghosting - Clones the element and drags the clone, leaving the original - # in place until the clone is dropped (default is false). + # * :ghosting - Clones the element and drags the clone, leaving + # the original in place until the clone is dropped (default is false). # # * :dropOnEmpty - If true the Sortable container will be made into - # a Droppable, that can receive a Draggable (as according to - # the containment rules) as a child element when there are no - # more elements inside (default is false). - # - # * :onChange - Called whenever the sort order changes while dragging. When - # dragging from one Sortable to another, the callback is - # called once on each Sortable. Gets the affected element as - # its parameter. - # - # * :onUpdate - Called when the drag ends and the Sortable's order is - # changed in any way. When dragging from one Sortable to - # another, the callback is called once on each Sortable. Gets - # the container as its parameter. + # a Droppable, that can receive a Draggable (as according to the containment + # rules) as a child element when there are no more elements inside (default + # is false). + # + # * :onChange - Called whenever the sort order changes while dragging. When + # dragging from one Sortable to another, the callback is called once on each + # Sortable. Gets the affected element as its parameter. + # + # * :onUpdate - Called when the drag ends and the Sortable's order is + # changed in any way. When dragging from one Sortable to another, the callback + # is called once on each Sortable. Gets the container as its parameter. # # See http://script.aculo.us for more documentation. def sortable_element(element_id, options = {}) @@ -182,30 +179,30 @@ module ActionView # http://script.aculo.us for more documentation. # # Some of these +options+ include: - # * :accept - Set this to a string or an array of strings describing the - # allowable CSS classes that the +draggable_element+ must have in order - # to be accepted by this +drop_receiving_element+. - # - # * :confirm - Adds a confirmation dialog. Example: + # * :accept - Set this to a string or an array of strings describing the + # allowable CSS classes that the +draggable_element+ must have in order + # to be accepted by this +drop_receiving_element+. # - # :confirm => "Are you sure you want to do this?" + # * :confirm - Adds a confirmation dialog. Example: + # + # :confirm => "Are you sure you want to do this?" # - # * :hoverclass - If set, the +drop_receiving_element+ will have this additional CSS class - # when an accepted +draggable_element+ is hovered over it. + # * :hoverclass - If set, the +drop_receiving_element+ will have + # this additional CSS class when an accepted +draggable_element+ is + # hovered over it. # - # * :onDrop - Called when a +draggable_element+ is dropped onto this element. - # Override this callback with a JavaScript expression to - # change the default drop behavour. Example: + # * :onDrop - Called when a +draggable_element+ is dropped onto + # this element. Override this callback with a JavaScript expression to + # change the default drop behavour. Example: # - # :onDrop => "function(draggable_element, droppable_element, event) { alert('I like bananas') }" + # :onDrop => "function(draggable_element, droppable_element, event) { alert('I like bananas') }" # - # This callback gets three parameters: - # The Draggable element, the Droppable element and the - # Event object. You can extract additional information about the - # drop - like if the Ctrl or Shift keys were pressed - from the Event object. + # This callback gets three parameters: The Draggable element, the Droppable + # element and the Event object. You can extract additional information about + # the drop - like if the Ctrl or Shift keys were pressed - from the Event object. # - # * :with - A JavaScript expression specifying the parameters for the XMLHttpRequest. - # Any expressions should return a valid URL query string. + # * :with - A JavaScript expression specifying the parameters for + # the XMLHttpRequest. Any expressions should return a valid URL query string. def drop_receiving_element(element_id, options = {}) javascript_tag(drop_receiving_element_js(element_id, options).chop!) end -- cgit v1.2.3 From 22a47cb1aeee8ada2396ddf0270c45749b59f16e Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Fri, 23 May 2008 00:40:20 +0200 Subject: revision of inflector.rb docs --- activesupport/lib/active_support/inflector.rb | 114 +++++++++++++------------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb index 0fd44324bb..d319d58a85 100644 --- a/activesupport/lib/active_support/inflector.rb +++ b/activesupport/lib/active_support/inflector.rb @@ -109,13 +109,13 @@ module Inflector # 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" + # 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 @@ -127,15 +127,15 @@ module Inflector end end - # The reverse of pluralize, returns the singular form of a word in a string. + # 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" + # 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 @@ -147,16 +147,16 @@ module Inflector end end - # By default, camelize converts strings to UpperCamelCase. If the argument to camelize - # is set to ":lower" then camelize produces lowerCamelCase. + # 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 + # +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" + # 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(/(?:^|_)(.)/) { $1.upcase } @@ -166,12 +166,12 @@ module Inflector 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 + # 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 + # +titleize+ is also aliased as as +titlecase+. # - # Examples + # Examples: # "man from the boondocks".titleize #=> "Man From The Boondocks" # "x-men: the last stand".titleize #=> "X Men: The Last Stand" def titleize(word) @@ -182,9 +182,9 @@ module Inflector # # Changes '::' to '/' to convert namespaces to paths. # - # Examples - # "ActiveRecord".underscore #=> "active_record" - # "ActiveRecord::Errors".underscore #=> active_record/errors + # 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'). @@ -195,52 +195,52 @@ module Inflector # Replaces underscores with dashes in the string. # - # Example - # "puni_puni" #=> "puni-puni" + # 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. + # Capitalizes the first word and turns underscores into spaces and strips a + # trailing "_id", if any. Like +titleize+, this is meant for creating pretty output. # - # Examples - # "employee_salary" #=> "Employee salary" - # "author_id" #=> "Author" + # 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 + # Removes the module part from the expression in the string. # - # Examples - # "ActiveRecord::CoreExtensions::String::Inflections".demodulize #=> "Inflections" - # "Inflections".demodulize #=> "Inflections" + # 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. + # 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" + # "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 plural 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.) + # follow +classify+ with +constantize+.) # - # Examples - # "egg_and_hams".classify #=> "EggAndHam" - # "posts".classify #=> "Post" + # Examples: + # "egg_and_hams".classify # => "EggAndHam" + # "posts".classify # => "Post" # - # Singular names are not handled correctly - # "business".classify #=> "Busines" + # Singular names are not handled correctly: + # "business".classify # => "Busines" def classify(table_name) # strip out any leading schema name camelize(singularize(table_name.to_s.sub(/.*\./, ''))) @@ -250,10 +250,10 @@ module Inflector # +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" + # 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 @@ -283,10 +283,10 @@ module Inflector 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. + # Turns a number into an ordinal string used to denote the position in an + # ordered sequence such as 1st, 2nd, 3rd, 4th. # - # Examples + # Examples: # ordinalize(1) # => "1st" # ordinalize(2) # => "2nd" # ordinalize(1002) # => "1002nd" -- cgit v1.2.3 From 63946cfb0ecb1a30b254920df7daee57b36ce7ec Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Fri, 23 May 2008 01:03:00 +0200 Subject: overall cleanup of "#=>" and other minor details --- .../lib/action_controller/polymorphic_routes.rb | 11 +++++------ actionpack/lib/action_view/helpers/form_helper.rb | 6 +++--- activerecord/lib/active_record/calculations.rb | 14 ++++++++------ .../abstract/schema_definitions.rb | 22 +++++++++++----------- activeresource/lib/active_resource/base.rb | 22 +++++++++++----------- .../lib/active_resource/custom_methods.rb | 10 +++++----- .../lib/active_support/core_ext/string/unicode.rb | 10 +++++----- .../active_support/core_ext/time/conversions.rb | 2 +- activesupport/lib/active_support/inflector.rb | 4 ++-- .../lib/active_support/multibyte/chars.rb | 2 +- .../multibyte/handlers/utf8_handler.rb | 18 ++++++++---------- 11 files changed, 60 insertions(+), 61 deletions(-) diff --git a/actionpack/lib/action_controller/polymorphic_routes.rb b/actionpack/lib/action_controller/polymorphic_routes.rb index c083993fc0..509fa6a08e 100644 --- a/actionpack/lib/action_controller/polymorphic_routes.rb +++ b/actionpack/lib/action_controller/polymorphic_routes.rb @@ -9,7 +9,9 @@ module ActionController # Nested resources and/or namespaces are also supported, as illustrated in the example: # # polymorphic_url([:admin, @article, @comment]) - # #-> results in: + # + # results in: + # # admin_article_comment_url(@article, @comment) # # == Usage within the framework @@ -38,11 +40,8 @@ module ActionController # # Example usage: # - # edit_polymorphic_path(@post) - # #=> /posts/1/edit - # - # formatted_polymorphic_path([@post, :pdf]) - # #=> /posts/1.pdf + # edit_polymorphic_path(@post) # => "/posts/1/edit" + # formatted_polymorphic_path([@post, :pdf]) # => "/posts/1.pdf" module PolymorphicRoutes # Constructs a call to a named RESTful route for the given record and returns the # resulting URL string. For example: diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 3d80d508b9..0791feb9ac 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -324,13 +324,13 @@ module ActionView # # ==== Examples # label(:post, :title) - # #=> + # # => # # label(:post, :title, "A short title") - # #=> + # # => # # label(:post, :title, "A short title", :class => "title_label") - # #=> + # # => # def label(object_name, method, text = nil, options = {}) InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_label_tag(text, options) diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb index fec9bee38f..10e8330d1c 100644 --- a/activerecord/lib/active_record/calculations.rb +++ b/activerecord/lib/active_record/calculations.rb @@ -245,12 +245,14 @@ module ActiveRecord options.assert_valid_keys(CALCULATIONS_OPTIONS) end - # Converts a given key to the value that the database adapter returns as - # a usable column name. - # users.id #=> users_id - # sum(id) #=> sum_id - # count(distinct users.id) #=> count_distinct_users_id - # count(*) #=> count_all + # Converts the given keys to the value that the database adapter returns as + # a usable column name: + # + # column_alias_for("users.id") # => "users_id" + # column_alias_for("sum(id)") # => "sum_id" + # column_alias_for("count(distinct users.id)") # => "count_distinct_users_id" + # column_alias_for("count(*)") # => "count_all" + # column_alias_for("count", "id") # => "count_id" def column_alias_for(*keys) connection.table_alias_for(keys.join(' ').downcase.gsub(/\*/, 'all').gsub(/\W+/, ' ').strip.gsub(/ +/, '_')) end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 18f1175f5f..e4e950d481 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -92,7 +92,7 @@ module ActiveRecord # Returns the human name of the column name. # # ===== Examples - # Column.new('sales_stage', ...).human_name #=> 'Sales stage' + # Column.new('sales_stage', ...).human_name # => 'Sales stage' def human_name Base.human_attribute_name(@name) end @@ -350,28 +350,28 @@ module ActiveRecord # == Examples # # Assuming td is an instance of TableDefinition # td.column(:granted, :boolean) - # #=> granted BOOLEAN + # # granted BOOLEAN # # td.column(:picture, :binary, :limit => 2.megabytes) - # #=> picture BLOB(2097152) + # # => picture BLOB(2097152) # # td.column(:sales_stage, :string, :limit => 20, :default => 'new', :null => false) - # #=> sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL + # # => sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL # - # def.column(:bill_gates_money, :decimal, :precision => 15, :scale => 2) - # #=> bill_gates_money DECIMAL(15,2) + # td.column(:bill_gates_money, :decimal, :precision => 15, :scale => 2) + # # => bill_gates_money DECIMAL(15,2) # - # def.column(:sensor_reading, :decimal, :precision => 30, :scale => 20) - # #=> sensor_reading DECIMAL(30,20) + # td.column(:sensor_reading, :decimal, :precision => 30, :scale => 20) + # # => sensor_reading DECIMAL(30,20) # # # While :scale defaults to zero on most databases, it # # probably wouldn't hurt to include it. - # def.column(:huge_integer, :decimal, :precision => 30) - # #=> huge_integer DECIMAL(30) + # td.column(:huge_integer, :decimal, :precision => 30) + # # => huge_integer DECIMAL(30) # # == Short-hand examples # - # Instead of calling column directly, you can also work with the short-hand definitions for the default types. + # Instead of calling +column+ directly, you can also work with the short-hand definitions for the default types. # They use the type as the method name instead of as a parameter and allow for multiple columns to be defined # in a single statement. # diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index b38b4c0194..463ee9f1e7 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -34,18 +34,18 @@ module ActiveResource # from REST web services. # # ryan = Person.new(:first => 'Ryan', :last => 'Daigle') - # ryan.save #=> true - # ryan.id #=> 2 - # Person.exists?(ryan.id) #=> true - # ryan.exists? #=> true + # ryan.save # => true + # ryan.id # => 2 + # Person.exists?(ryan.id) # => true + # ryan.exists? # => true # # ryan = Person.find(1) - # # => Resource holding our newly created Person object + # # Resource holding our newly created Person object # # ryan.first = 'Rizzle' - # ryan.save #=> true + # ryan.save # => true # - # ryan.destroy #=> true + # ryan.destroy # => true # # As you can see, these are very similar to Active Record's lifecycle methods for database records. # You can read more about each of these methods in their respective documentation. @@ -156,8 +156,8 @@ module ActiveResource # then fail (with a false return value) and the validation errors can be accessed on the resource in question. # # ryan = Person.find(1) - # ryan.first #=> '' - # ryan.save #=> false + # ryan.first # => '' + # ryan.save # => false # # # When # # PUT http://api.people.com:3000/people/1.xml @@ -167,8 +167,8 @@ module ActiveResource # # First cannot be empty # # # - # ryan.errors.invalid?(:first) #=> true - # ryan.errors.full_messages #=> ['First cannot be empty'] + # ryan.errors.invalid?(:first) # => true + # ryan.errors.full_messages # => ['First cannot be empty'] # # Learn more about Active Resource's validation features in the ActiveResource::Validations documentation. # diff --git a/activeresource/lib/active_resource/custom_methods.rb b/activeresource/lib/active_resource/custom_methods.rb index 33a2fffaa0..4c8699288c 100644 --- a/activeresource/lib/active_resource/custom_methods.rb +++ b/activeresource/lib/active_resource/custom_methods.rb @@ -7,12 +7,12 @@ module ActiveResource # :member => { :promote => :put, :deactivate => :delete } # :collection => { :active => :get } # - # This route set creates routes for the following http requests: + # This route set creates routes for the following HTTP requests: # - # POST /people/new/register.xml #=> PeopleController.register - # PUT /people/1/promote.xml #=> PeopleController.promote with :id => 1 - # DELETE /people/1/deactivate.xml #=> PeopleController.deactivate with :id => 1 - # GET /people/active.xml #=> PeopleController.active + # POST /people/new/register.xml # PeopleController.register + # PUT /people/1/promote.xml # PeopleController.promote with :id => 1 + # DELETE /people/1/deactivate.xml # PeopleController.deactivate with :id => 1 + # GET /people/active.xml # PeopleController.active # # Using this module, Active Resource can use these custom REST methods just like the # standard methods. diff --git a/activesupport/lib/active_support/core_ext/string/unicode.rb b/activesupport/lib/active_support/core_ext/string/unicode.rb index ba16d4d866..5e20534d1d 100644 --- a/activesupport/lib/active_support/core_ext/string/unicode.rb +++ b/activesupport/lib/active_support/core_ext/string/unicode.rb @@ -17,17 +17,17 @@ module ActiveSupport #:nodoc: # string overrides can also be called through the +chars+ proxy. # # name = 'Claus Müller' - # name.reverse #=> "rell??M sualC" - # name.length #=> 13 + # name.reverse # => "rell??M sualC" + # name.length # => 13 # - # name.chars.reverse.to_s #=> "rellüM sualC" - # name.chars.length #=> 12 + # 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 + # 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 diff --git a/activesupport/lib/active_support/core_ext/time/conversions.rb b/activesupport/lib/active_support/core_ext/time/conversions.rb index edca5b8a98..9054008309 100644 --- a/activesupport/lib/active_support/core_ext/time/conversions.rb +++ b/activesupport/lib/active_support/core_ext/time/conversions.rb @@ -59,7 +59,7 @@ module ActiveSupport #:nodoc: # Converts a Time object to a Date, dropping hour, minute, and second precision. # # my_time = Time.now # => Mon Nov 12 22:59:51 -0500 2007 - # my_time.to_date #=> Mon, 12 Nov 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 diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb index d319d58a85..a4fd619317 100644 --- a/activesupport/lib/active_support/inflector.rb +++ b/activesupport/lib/active_support/inflector.rb @@ -172,8 +172,8 @@ module Inflector # +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" + # "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 diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb index 65114415eb..ee716de39e 100644 --- a/activesupport/lib/active_support/multibyte/chars.rb +++ b/activesupport/lib/active_support/multibyte/chars.rb @@ -10,7 +10,7 @@ module ActiveSupport::Multibyte #:nodoc: # 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" + # "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. diff --git a/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb b/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb index 0166b69ac3..aa9c16f575 100644 --- a/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb +++ b/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb @@ -147,13 +147,11 @@ module ActiveSupport::Multibyte::Handlers #:nodoc: # # s = "Müller" # s.chars[2] = "e" # Replace character with offset 2 - # s - # #=> "Müeler" + # s # => "Müeler" # # s = "Müller" # s.chars[1, 2] = "ö" # Replace 2 characters at character offset 1 - # s - # #=> "Möler" + # s # => "Möler" def []=(str, *args) replace_by = args.pop # Indexed replace with regular expressions already works @@ -183,10 +181,10 @@ module ActiveSupport::Multibyte::Handlers #:nodoc: # Example: # # "¾ cup".chars.rjust(8).to_s - # #=> " ¾ cup" + # # => " ¾ cup" # # "¾ cup".chars.rjust(8, " ").to_s # Use non-breaking whitespace - # #=> "   ¾ cup" + # # => "   ¾ cup" def rjust(str, integer, padstr=' ') justify(str, integer, :right, padstr) end @@ -196,10 +194,10 @@ module ActiveSupport::Multibyte::Handlers #:nodoc: # Example: # # "¾ cup".chars.rjust(8).to_s - # #=> "¾ cup " + # # => "¾ cup " # # "¾ cup".chars.rjust(8, " ").to_s # Use non-breaking whitespace - # #=> "¾ cup   " + # # => "¾ cup   " def ljust(str, integer, padstr=' ') justify(str, integer, :left, padstr) end @@ -209,10 +207,10 @@ module ActiveSupport::Multibyte::Handlers #:nodoc: # Example: # # "¾ cup".chars.center(8).to_s - # #=> " ¾ cup " + # # => " ¾ cup " # # "¾ cup".chars.center(8, " ").to_s # Use non-breaking whitespace - # #=> " ¾ cup  " + # # => " ¾ cup  " def center(str, integer, padstr=' ') justify(str, integer, :center, padstr) end -- cgit v1.2.3 From 4d276cfafbd0ebd6564d402c3c716803be04a179 Mon Sep 17 00:00:00 2001 From: Henrik N Date: Fri, 23 May 2008 11:15:40 +0200 Subject: environment.rb template 'rake gem:install' should be 'rake gems:install'. --- railties/environments/environment.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/environments/environment.rb b/railties/environments/environment.rb index cf00bb6bc8..eaa7464ec9 100644 --- a/railties/environments/environment.rb +++ b/railties/environments/environment.rb @@ -21,7 +21,7 @@ Rails::Initializer.run do |config| # config.frameworks -= [ :active_record, :active_resource, :action_mailer ] # Specify gems that this application depends on. - # They can then be installed with rake gem:install on new installations. + # They can then be installed with rake gems:install on new installations. # config.gem "bj" # config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net" # config.gem "aws-s3", :lib => "aws/s3" -- cgit v1.2.3 From 88ef718361de56cd8900fd5c0a191e2ac420e680 Mon Sep 17 00:00:00 2001 From: Henrik N Date: Fri, 23 May 2008 11:28:19 +0200 Subject: Consistently use "rake foo:bar" instead of 'rake foo:bar', `rake foo:bar` or rake foo:bar. --- actionpack/lib/action_controller/session/cookie_store.rb | 2 +- railties/configs/databases/frontbase.yml | 4 ++-- railties/configs/databases/mysql.yml | 4 ++-- railties/configs/databases/oracle.yml | 4 ++-- railties/configs/databases/postgresql.yml | 4 ++-- railties/configs/databases/sqlite2.yml | 4 ++-- railties/configs/databases/sqlite3.yml | 4 ++-- railties/environments/environment.rb | 6 +++--- railties/lib/initializer.rb | 6 +++--- railties/lib/tasks/databases.rake | 2 +- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/actionpack/lib/action_controller/session/cookie_store.rb b/actionpack/lib/action_controller/session/cookie_store.rb index ada1862c3e..b477c1f7da 100644 --- a/actionpack/lib/action_controller/session/cookie_store.rb +++ b/actionpack/lib/action_controller/session/cookie_store.rb @@ -34,7 +34,7 @@ require 'openssl' # to generate the HMAC message digest # such as 'MD5', 'RIPEMD160', 'SHA256', etc. # # To generate a secret key for an existing application, run -# `rake secret` and set the key in config/environment.rb. +# "rake secret" and set the key in config/environment.rb. # # Note that changing digest or secret invalidates all existing sessions! class CGI::Session::CookieStore diff --git a/railties/configs/databases/frontbase.yml b/railties/configs/databases/frontbase.yml index 2eed3133a1..c0c3588be1 100644 --- a/railties/configs/databases/frontbase.yml +++ b/railties/configs/databases/frontbase.yml @@ -10,8 +10,8 @@ development: username: <%= app_name %> password: '' -# Warning: The database defined as 'test' will be erased and -# re-generated from your development database when you run 'rake'. +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: adapter: frontbase diff --git a/railties/configs/databases/mysql.yml b/railties/configs/databases/mysql.yml index c5c894c5e1..7fcadcdf2c 100644 --- a/railties/configs/databases/mysql.yml +++ b/railties/configs/databases/mysql.yml @@ -26,8 +26,8 @@ development: host: localhost <% end -%> -# Warning: The database defined as 'test' will be erased and -# re-generated from your development database when you run 'rake'. +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: adapter: mysql diff --git a/railties/configs/databases/oracle.yml b/railties/configs/databases/oracle.yml index 822d998543..a1883f6256 100644 --- a/railties/configs/databases/oracle.yml +++ b/railties/configs/databases/oracle.yml @@ -23,8 +23,8 @@ development: username: <%= app_name %> password: -# Warning: The database defined as 'test' will be erased and -# re-generated from your development database when you run 'rake'. +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: adapter: oracle diff --git a/railties/configs/databases/postgresql.yml b/railties/configs/databases/postgresql.yml index c1b911a9a4..36f6e5ae49 100644 --- a/railties/configs/databases/postgresql.yml +++ b/railties/configs/databases/postgresql.yml @@ -30,8 +30,8 @@ development: # The server defaults to notice. #min_messages: warning -# Warning: The database defined as 'test' will be erased and -# re-generated from your development database when you run 'rake'. +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: adapter: postgresql diff --git a/railties/configs/databases/sqlite2.yml b/railties/configs/databases/sqlite2.yml index 26d3957d79..fc48bd6753 100644 --- a/railties/configs/databases/sqlite2.yml +++ b/railties/configs/databases/sqlite2.yml @@ -4,8 +4,8 @@ development: adapter: sqlite database: db/development.sqlite2 -# Warning: The database defined as 'test' will be erased and -# re-generated from your development database when you run 'rake'. +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: adapter: sqlite diff --git a/railties/configs/databases/sqlite3.yml b/railties/configs/databases/sqlite3.yml index b444b03cd4..fff44a4124 100644 --- a/railties/configs/databases/sqlite3.yml +++ b/railties/configs/databases/sqlite3.yml @@ -5,8 +5,8 @@ development: database: db/development.sqlite3 timeout: 5000 -# Warning: The database defined as 'test' will be erased and -# re-generated from your development database when you run 'rake'. +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: adapter: sqlite3 diff --git a/railties/environments/environment.rb b/railties/environments/environment.rb index eaa7464ec9..2086c609af 100644 --- a/railties/environments/environment.rb +++ b/railties/environments/environment.rb @@ -21,7 +21,7 @@ Rails::Initializer.run do |config| # config.frameworks -= [ :active_record, :active_resource, :action_mailer ] # Specify gems that this application depends on. - # They can then be installed with rake gems:install on new installations. + # They can then be installed with "rake gems:install" on new installations. # config.gem "bj" # config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net" # config.gem "aws-s3", :lib => "aws/s3" @@ -40,7 +40,7 @@ Rails::Initializer.run do |config| # Make Time.zone default to the specified zone, and make Active Record store time values # in the database in UTC, and return them converted to the specified local zone. - # Run `rake -D time` for a list of tasks for finding time zone names. Uncomment to use default local time. + # Run "rake -D time" for a list of tasks for finding time zone names. Uncomment to use default local time. config.time_zone = 'UTC' # Your secret key for verifying cookie session data integrity. @@ -54,7 +54,7 @@ Rails::Initializer.run do |config| # Use the database for sessions instead of the cookie-based default, # which shouldn't be used to store highly confidential information - # (create the session table with 'rake db:sessions:create') + # (create the session table with "rake db:sessions:create") # config.action_controller.session_store = :active_record_store # Use SQL instead of Active Record's schema dumper when creating the test database. diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb index 98cc206765..8f963cb4a5 100644 --- a/railties/lib/initializer.rb +++ b/railties/lib/initializer.rb @@ -169,7 +169,7 @@ module Rails # the Gem version of Rails shouldn't be loaded. def install_gem_spec_stubs unless Rails.respond_to?(:vendor_rails?) - abort "Your config/boot.rb is outdated: Run 'rake rails:update'." + abort %{Your config/boot.rb is outdated: Run "rake rails:update".} end if Rails.vendor_rails? @@ -289,7 +289,7 @@ module Rails def load_observers if configuration.frameworks.include?(:active_record) if @configuration.gems.any? { |g| !g.loaded? } - puts "Unable to instantiate observers, some gems that this application depends on are missing. Run 'rake gems:install'" + puts %{Unable to instantiate observers, some gems that this application depends on are missing. Run "rake gems:install"} else ActiveRecord::Base.instantiate_observers end @@ -419,7 +419,7 @@ module Rails if configuration.time_zone zone_default = Time.send!(:get_zone, configuration.time_zone) unless zone_default - raise "Value assigned to config.time_zone not recognized. Run `rake -D time` for a list of tasks for finding appropriate time zone names." + raise %{Value assigned to config.time_zone not recognized. Run "rake -D time" for a list of tasks for finding appropriate time zone names.} end Time.zone_default = zone_default if configuration.frameworks.include?(:active_record) diff --git a/railties/lib/tasks/databases.rake b/railties/lib/tasks/databases.rake index f40f8463f7..8077d0a401 100644 --- a/railties/lib/tasks/databases.rake +++ b/railties/lib/tasks/databases.rake @@ -173,7 +173,7 @@ namespace :db do pending_migrations.each do |pending_migration| puts ' %4d %s' % [pending_migration.version, pending_migration.name] end - abort "Run `rake db:migrate` to update your database then try again." + abort %{Run "rake db:migrate" to update your database then try again.} end end end -- cgit v1.2.3 From 8072ebcacc642cc0e7937e61051b9fe05507f037 Mon Sep 17 00:00:00 2001 From: Henrik N Date: Fri, 23 May 2008 11:44:37 +0200 Subject: Document Integer#even? and #odd? edge cases: zero and negative numbers. --- .../lib/active_support/core_ext/integer/even_odd.rb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/integer/even_odd.rb b/activesupport/lib/active_support/core_ext/integer/even_odd.rb index cfc6b4c6d6..b1d1e28062 100644 --- a/activesupport/lib/active_support/core_ext/integer/even_odd.rb +++ b/activesupport/lib/active_support/core_ext/integer/even_odd.rb @@ -3,10 +3,14 @@ module ActiveSupport #: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 + # 2.even? # => true + # 2.odd? # => false + # 1.even? # => false + # 1.odd? # => true + # 0.even? # => true + # 0.odd? # => false + # -1.even? # => false + # -1.odd? # => true module EvenOdd def multiple_of?(number) self % number == 0 -- cgit v1.2.3 From 11ea3e947a1b5a59a5f77ba392a32f57e157903e Mon Sep 17 00:00:00 2001 From: Cody Fauser Date: Fri, 23 May 2008 16:38:40 -0400 Subject: Fixup weird RDoc markup that does not render correctly --- .../connection_adapters/abstract/schema_definitions.rb | 6 +++--- activerecord/lib/active_record/named_scope.rb | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index e4e950d481..f968b9b173 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -16,9 +16,9 @@ module ActiveRecord # Instantiates a new column in the table. # - # +name+ is the column's name, as in supplier_id int(11). - # +default+ is the type-casted default value, such as sales_stage varchar(20) default 'new'. - # +sql_type+ is only used to extract the column's length, if necessary. For example, company_name varchar(60). + # +name+ is the column's name, such as supplier_id in supplier_id int(11). + # +default+ is the type-casted default value, such as +new+ in sales_stage varchar(20) default 'new'. + # +sql_type+ is only used to extract the column's length, if necessary. For example +60+ in company_name varchar(60). # +null+ determines if this column allows +NULL+ values. def initialize(name, default, sql_type = nil, null = true) @name, @sql_type, @null = name, sql_type, null diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 62eecbf9be..69b7da7700 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -2,9 +2,7 @@ module ActiveRecord module NamedScope # All subclasses of ActiveRecord::Base have two named_scopes: # * all, which is similar to a find(:all) query, and - # * scoped, which allows for the creation of anonymous scopes, on the fly: - # - # Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions) + # * scoped, which allows for the creation of anonymous scopes, on the fly: Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions) # # These anonymous scopes tend to be useful when procedurally generating complex queries, where passing # intermediate values (scopes) around as first-class objects is convenient. -- cgit v1.2.3 From 8d0b4fa39fab6e5d1e3382b4b137cc47e559b0be Mon Sep 17 00:00:00 2001 From: josevalim Date: Fri, 23 May 2008 11:20:13 +0200 Subject: Added :select option to has_one and belongs_to, remove unused :order option on belongs_to. Signed-off-by: Michael Koziarski [#241 state:resolved] --- activerecord/lib/active_record/associations.rb | 16 +++++++++------- .../active_record/associations/belongs_to_association.rb | 5 +++-- .../associations/belongs_to_polymorphic_association.rb | 5 +++-- .../active_record/associations/has_one_association.rb | 5 +++-- .../cases/associations/belongs_to_associations_test.rb | 5 +++++ .../test/cases/associations/has_one_associations_test.rb | 5 +++++ activerecord/test/models/company.rb | 2 ++ 7 files changed, 30 insertions(+), 13 deletions(-) mode change 100644 => 100755 activerecord/lib/active_record/associations.rb mode change 100644 => 100755 activerecord/lib/active_record/associations/belongs_to_association.rb mode change 100644 => 100755 activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb mode change 100644 => 100755 activerecord/lib/active_record/associations/has_one_association.rb mode change 100644 => 100755 activerecord/test/cases/associations/belongs_to_associations_test.rb mode change 100644 => 100755 activerecord/test/cases/associations/has_one_associations_test.rb diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb old mode 100644 new mode 100755 index 95caf68692..6c21fed8ea --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -667,7 +667,7 @@ module ActiveRecord # * :limit - An integer determining the limit on the number of rows that should be returned. # * :offset - An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows. # * :select - By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join - # but not include the joined columns. + # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will rise an error. # * :as - Specifies a polymorphic interface (See belongs_to). # * :through - Specifies a Join Model through which to perform the query. Options for :class_name and :foreign_key # are ignored, as the association uses the source reflection. You can only use a :through query through a belongs_to @@ -747,6 +747,8 @@ module ActiveRecord # as the default :foreign_key. # * :include - Specify second-order associations that should be eager loaded when this object is loaded. # * :as - Specifies a polymorphic interface (See belongs_to). + # * :select - By default, this is * as in SELECT * FROM, but can be changed if, for example, you want to do a join + # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error. # * :through: Specifies a Join Model through which to perform the query. Options for :class_name and :foreign_key # are ignored, as the association uses the source reflection. You can only use a :through query through a # has_one or belongs_to association on the join model. @@ -821,8 +823,8 @@ module ActiveRecord # if the real class name is Person, you'll have to specify it with this option. # * :conditions - Specify the conditions that the associated object must meet in order to be included as a +WHERE+ # SQL fragment, such as authorized = 1. - # * :order - Specify the order in which the associated objects are returned as an ORDER BY SQL fragment, - # such as last_name, first_name DESC. + # * :select - By default, this is * as in SELECT * FROM, but can be changed if, for example, you want to do a join + # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error. # * :foreign_key - Specify the foreign key used for the association. By default this is guessed to be the name # of the association with an "_id" suffix. So a class that defines a belongs_to :person association will use # "person_id" as the default :foreign_key. Similarly, belongs_to :favorite_person, :class_name => "Person" @@ -1011,7 +1013,7 @@ module ActiveRecord # * :limit - An integer determining the limit on the number of rows that should be returned. # * :offset - An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows. # * :select - By default, this is * as in SELECT * FROM, but can be changed if, for example, you want to do a join - # but not include the joined columns. + # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error. # * :readonly - If true, all the associated objects are readonly through the association. # # Option examples: @@ -1341,7 +1343,7 @@ module ActiveRecord def create_has_one_reflection(association_id, options) options.assert_valid_keys( - :class_name, :foreign_key, :remote, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly + :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly ) create_reflection(:has_one, association_id, options, self) @@ -1349,14 +1351,14 @@ module ActiveRecord def create_has_one_through_reflection(association_id, options) options.assert_valid_keys( - :class_name, :foreign_key, :remote, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :through, :source, :source_type + :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :through, :source, :source_type ) create_reflection(:has_one, association_id, options, self) end def create_belongs_to_reflection(association_id, options) options.assert_valid_keys( - :class_name, :foreign_key, :foreign_type, :remote, :conditions, :order, :include, :dependent, + :class_name, :foreign_key, :foreign_type, :remote, :select, :conditions, :include, :dependent, :counter_cache, :extend, :polymorphic, :readonly ) diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb old mode 100644 new mode 100755 index 9ff3f13592..7c28cbdd07 --- a/activerecord/lib/active_record/associations/belongs_to_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_association.rb @@ -42,10 +42,11 @@ module ActiveRecord private def find_target @reflection.klass.find( - @owner[@reflection.primary_key_name], + @owner[@reflection.primary_key_name], + :select => @reflection.options[:select], :conditions => conditions, :include => @reflection.options[:include], - :readonly => @reflection.options[:readonly] + :readonly => @reflection.options[:readonly] ) end diff --git a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb old mode 100644 new mode 100755 index 9549b959fc..df4ae38f38 --- a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb @@ -29,12 +29,13 @@ module ActiveRecord if @reflection.options[:conditions] association_class.find( - @owner[@reflection.primary_key_name], + @owner[@reflection.primary_key_name], + :select => @reflection.options[:select], :conditions => conditions, :include => @reflection.options[:include] ) else - association_class.find(@owner[@reflection.primary_key_name], :include => @reflection.options[:include]) + association_class.find(@owner[@reflection.primary_key_name], :select => @reflection.options[:select], :include => @reflection.options[:include]) end end diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb old mode 100644 new mode 100755 index 3ff9fe3b9f..c2b3503e0d --- a/activerecord/lib/active_record/associations/has_one_association.rb +++ b/activerecord/lib/active_record/associations/has_one_association.rb @@ -51,10 +51,11 @@ module ActiveRecord private def find_target @reflection.klass.find(:first, - :conditions => @finder_sql, + :conditions => @finder_sql, + :select => @reflection.options[:select], :order => @reflection.options[:order], :include => @reflection.options[:include], - :readonly => @reflection.options[:readonly] + :readonly => @reflection.options[:readonly] ) end diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb old mode 100644 new mode 100755 index 4382ba17ef..3073eae355 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -92,6 +92,11 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_not_nil Company.find(3).firm_with_condition, "Microsoft should have a firm" end + def test_with_select + assert_equal Company.find(2).firm_with_select.attributes.size, 1 + assert_equal Company.find(2, :include => :firm_with_select ).firm_with_select.attributes.size, 1 + end + def test_belongs_to_counter debate = Topic.create("title" => "debate") assert_equal 0, debate.send(:read_attribute, "replies_count"), "No replies yet" diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb old mode 100644 new mode 100755 index 9e99caa7b7..e7d4de8246 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -24,6 +24,11 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert_queries(0) { firms.each(&:account) } end + def test_with_select + assert_equal Firm.find(1).account_with_select.attributes.size, 2 + assert_equal Firm.find(1, :include => :account_with_select).attributes.size, 2 + end + def test_can_marshal_has_one_association_with_nil_target firm = Firm.new assert_nothing_raised do diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb index f637490c59..cc521d2a02 100755 --- a/activerecord/test/models/company.rb +++ b/activerecord/test/models/company.rb @@ -47,6 +47,7 @@ class Firm < Company has_many :readonly_clients, :class_name => 'Client', :readonly => true has_one :account, :foreign_key => "firm_id", :dependent => :destroy + has_one :account_with_select, :foreign_key => "firm_id", :select => "id, firm_id" has_one :readonly_account, :foreign_key => "firm_id", :class_name => "Account", :readonly => true end @@ -64,6 +65,7 @@ end class Client < Company belongs_to :firm, :foreign_key => "client_of" belongs_to :firm_with_basic_id, :class_name => "Firm", :foreign_key => "firm_id" + belongs_to :firm_with_select, :class_name => "Firm", :foreign_key => "firm_id", :select => "id" belongs_to :firm_with_other_name, :class_name => "Firm", :foreign_key => "client_of" belongs_to :firm_with_condition, :class_name => "Firm", :foreign_key => "client_of", :conditions => ["1 = ?", 1] belongs_to :readonly_firm, :class_name => "Firm", :foreign_key => "firm_id", :readonly => true -- cgit v1.2.3 From b88ceb7dc8d31bdbea95ab4242bbdee17178cda9 Mon Sep 17 00:00:00 2001 From: Trevor Turk Date: Fri, 23 May 2008 15:51:56 -0500 Subject: add failing test case for block-setting of attributes via association Signed-off-by: Michael Koziarski --- activerecord/test/cases/associations_test.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb index 3ad8c608e0..034fe14996 100755 --- a/activerecord/test/cases/associations_test.rb +++ b/activerecord/test/cases/associations_test.rb @@ -160,6 +160,15 @@ class AssociationProxyTest < ActiveRecord::TestCase assert_equal 1, developer.reload.audit_logs.size end + def test_create_via_association_with_block + post1 = Post.create(:title => "setting body with a block") {|p| p.body = "will work"} + assert_equal post1.body, "will work" + assert_nothing_raised do + post2 = authors(:david).posts.create(:title => "setting body with a block") {|p| p.body = "won't work"} + end + assert_equal post2.body, "won't work" + end + def test_failed_reload_returns_nil p = setup_dangling_association assert_nil p.author.reload -- cgit v1.2.3 From 6cba97d2a449faf21aec9fe9d4434067e414226f Mon Sep 17 00:00:00 2001 From: Ryan Bates Date: Fri, 23 May 2008 14:57:11 -0700 Subject: Create through associations can now work with blocks. Signed-off-by: Michael Koziarski [#248 state:resolved] --- .../active_record/associations/association_collection.rb | 10 ++++++++-- activerecord/test/cases/associations_test.rb | 15 +++++++++------ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 2d3750e107..2f03197012 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -166,12 +166,18 @@ module ActiveRecord if attrs.is_a?(Array) attrs.collect { |attr| create(attr) } else - create_record(attrs) { |record| record.save } + create_record(attrs) do |record| + yield(record) if block_given? + record.save + end end end def create!(attrs = {}) - create_record(attrs) { |record| record.save! } + create_record(attrs) do |record| + yield(record) if block_given? + record.save! + end end # Returns the size of the collection by executing a SELECT COUNT(*) query if the collection hasn't been loaded and diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb index 034fe14996..59349dd7cf 100755 --- a/activerecord/test/cases/associations_test.rb +++ b/activerecord/test/cases/associations_test.rb @@ -161,12 +161,15 @@ class AssociationProxyTest < ActiveRecord::TestCase end def test_create_via_association_with_block - post1 = Post.create(:title => "setting body with a block") {|p| p.body = "will work"} - assert_equal post1.body, "will work" - assert_nothing_raised do - post2 = authors(:david).posts.create(:title => "setting body with a block") {|p| p.body = "won't work"} - end - assert_equal post2.body, "won't work" + post = authors(:david).posts.create(:title => "New on Edge") {|p| p.body = "More cool stuff!"} + assert_equal post.title, "New on Edge" + assert_equal post.body, "More cool stuff!" + end + + def test_create_with_bang_via_association_with_block + post = authors(:david).posts.create!(:title => "New on Edge") {|p| p.body = "More cool stuff!"} + assert_equal post.title, "New on Edge" + assert_equal post.body, "More cool stuff!" end def test_failed_reload_returns_nil -- cgit v1.2.3 From 6277fd91133a3566333612857510d74de60d67f4 Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Sat, 24 May 2008 18:34:59 +1200 Subject: Fix faulty tests introduced in 8d0b4fa39 --- activerecord/test/cases/associations/has_one_associations_test.rb | 2 +- activerecord/test/cases/reflection_test.rb | 5 +++-- activerecord/test/models/company.rb | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index e7d4de8246..abc7ee7e9d 100755 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -26,7 +26,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase def test_with_select assert_equal Firm.find(1).account_with_select.attributes.size, 2 - assert_equal Firm.find(1, :include => :account_with_select).attributes.size, 2 + assert_equal Firm.find(1, :include => :account_with_select).account_with_select.attributes.size, 2 end def test_can_marshal_has_one_association_with_nil_target diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index c8ee40ea09..8b4d232554 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -159,9 +159,10 @@ class ReflectionTest < ActiveRecord::TestCase end def test_reflection_of_all_associations - assert_equal 19, Firm.reflect_on_all_associations.size + # FIXME these assertions bust a lot + assert_equal 20, Firm.reflect_on_all_associations.size assert_equal 16, Firm.reflect_on_all_associations(:has_many).size - assert_equal 3, Firm.reflect_on_all_associations(:has_one).size + assert_equal 4, Firm.reflect_on_all_associations(:has_one).size assert_equal 0, Firm.reflect_on_all_associations(:belongs_to).size end diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb index cc521d2a02..70f83fa8e6 100755 --- a/activerecord/test/models/company.rb +++ b/activerecord/test/models/company.rb @@ -47,7 +47,7 @@ class Firm < Company has_many :readonly_clients, :class_name => 'Client', :readonly => true has_one :account, :foreign_key => "firm_id", :dependent => :destroy - has_one :account_with_select, :foreign_key => "firm_id", :select => "id, firm_id" + has_one :account_with_select, :foreign_key => "firm_id", :select => "id, firm_id", :class_name=>'Account' has_one :readonly_account, :foreign_key => "firm_id", :class_name => "Account", :readonly => true end -- cgit v1.2.3 From 98dc582742779081e71e697fcdf8d9ae2b421b16 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sun, 25 May 2008 12:29:00 +0100 Subject: Merge docrails. Signed-off-by: Pratik Naik --- actionmailer/lib/action_mailer/base.rb | 14 +- actionmailer/lib/action_mailer/helpers.rb | 2 +- actionmailer/lib/action_mailer/part.rb | 4 +- .../assertions/model_assertions.rb | 3 +- .../assertions/routing_assertions.rb | 6 +- .../assertions/selector_assertions.rb | 26 +-- .../action_controller/assertions/tag_assertions.rb | 6 +- actionpack/lib/action_controller/base.rb | 14 +- actionpack/lib/action_controller/cgi_ext/cookie.rb | 35 ++-- actionpack/lib/action_controller/cgi_process.rb | 2 +- actionpack/lib/action_controller/filters.rb | 40 ++-- actionpack/lib/action_controller/helpers.rb | 14 +- actionpack/lib/action_controller/integration.rb | 18 +- actionpack/lib/action_controller/mime_type.rb | 4 +- .../lib/action_controller/polymorphic_routes.rb | 13 +- actionpack/lib/action_controller/resources.rb | 6 +- .../lib/action_controller/routing/builder.rb | 6 +- .../lib/action_controller/session/cookie_store.rb | 2 +- actionpack/lib/action_controller/test_process.rb | 4 +- .../lib/action_view/helpers/asset_tag_helper.rb | 24 +-- actionpack/lib/action_view/helpers/form_helper.rb | 95 +++++---- .../lib/action_view/helpers/form_options_helper.rb | 40 ++-- .../lib/action_view/helpers/form_tag_helper.rb | 8 +- .../lib/action_view/helpers/prototype_helper.rb | 8 +- .../lib/action_view/helpers/record_tag_helper.rb | 4 +- .../lib/action_view/helpers/sanitize_helper.rb | 31 +-- .../action_view/helpers/scriptaculous_helper.rb | 163 ++++++++-------- actionpack/lib/action_view/helpers/url_helper.rb | 2 +- actionpack/lib/action_view/template.rb | 4 +- activerecord/lib/active_record/aggregations.rb | 18 +- activerecord/lib/active_record/associations.rb | 124 ++++++------ .../associations/association_collection.rb | 4 +- .../associations/has_many_through_association.rb | 2 +- .../lib/active_record/attribute_methods.rb | 10 +- activerecord/lib/active_record/base.rb | 214 +++++++++++---------- activerecord/lib/active_record/calculations.rb | 22 ++- activerecord/lib/active_record/callbacks.rb | 2 +- .../abstract/connection_specification.rb | 2 +- .../abstract/database_statements.rb | 4 +- .../abstract/schema_definitions.rb | 32 +-- .../abstract/schema_statements.rb | 2 +- .../connection_adapters/postgresql_adapter.rb | 2 +- activerecord/lib/active_record/fixtures.rb | 49 ++--- .../lib/active_record/locking/optimistic.rb | 14 +- activerecord/lib/active_record/migration.rb | 4 +- activerecord/lib/active_record/named_scope.rb | 6 +- activerecord/lib/active_record/observer.rb | 4 +- activerecord/lib/active_record/schema.rb | 4 +- activerecord/lib/active_record/schema_dumper.rb | 2 +- .../active_record/serializers/xml_serializer.rb | 6 +- activerecord/lib/active_record/transactions.rb | 4 +- activerecord/lib/active_record/validations.rb | 4 +- activeresource/lib/active_resource/base.rb | 32 +-- .../lib/active_resource/custom_methods.rb | 14 +- .../lib/active_resource/formats/xml_format.rb | 2 +- activeresource/lib/active_resource/http_mock.rb | 77 +++++++- activeresource/lib/active_resource/validations.rb | 4 +- .../active_support/core_ext/hash/conversions.rb | 2 +- .../active_support/core_ext/integer/even_odd.rb | 12 +- .../lib/active_support/core_ext/object/misc.rb | 2 +- .../lib/active_support/core_ext/string/unicode.rb | 10 +- .../active_support/core_ext/time/conversions.rb | 2 +- .../lib/active_support/core_ext/time/zones.rb | 24 +-- activesupport/lib/active_support/deprecation.rb | 4 +- activesupport/lib/active_support/inflector.rb | 118 ++++++------ activesupport/lib/active_support/json.rb | 2 +- activesupport/lib/active_support/json/decoding.rb | 2 +- .../lib/active_support/multibyte/chars.rb | 2 +- .../multibyte/handlers/utf8_handler.rb | 18 +- activesupport/lib/active_support/time_with_zone.rb | 34 ++-- .../lib/active_support/values/time_zone.rb | 14 +- railties/configs/databases/frontbase.yml | 4 +- railties/configs/databases/mysql.yml | 4 +- railties/configs/databases/oracle.yml | 6 +- railties/configs/databases/postgresql.yml | 4 +- railties/configs/databases/sqlite2.yml | 4 +- railties/configs/databases/sqlite3.yml | 4 +- .../configs/initializers/new_rails_defaults.rb | 8 +- railties/environments/environment.rb | 8 +- railties/environments/test.rb | 2 +- railties/lib/initializer.rb | 46 ++--- railties/lib/rails_generator/base.rb | 2 +- railties/lib/tasks/databases.rake | 2 +- .../about_yml_plugins/bad_about_yml/about.yml | 2 +- railties/test/generators/generator_test_helper.rb | 60 +++--- 85 files changed, 886 insertions(+), 778 deletions(-) diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 7ed133d099..030bb178da 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -5,12 +5,12 @@ require 'action_mailer/utils' require 'tmail/net' module ActionMailer #:nodoc: - # ActionMailer allows you to send email from your application using a mailer model and views. + # Action Mailer allows you to send email from your application using a mailer model and views. # # # = Mailer Models # - # To use ActionMailer, you need to create a mailer model. + # To use Action Mailer, you need to create a mailer model. # # $ script/generate mailer Notifier # @@ -54,7 +54,7 @@ module ActionMailer #:nodoc: # # = Mailer views # - # Like ActionController, each mailer class has a corresponding view directory + # Like Action Controller, each mailer class has a corresponding view directory # in which each method of the class looks for a template with its name. # To define a template to be used with a mailing, create an .erb file with the same name as the method # in your mailer model. For example, in the mailer defined above, the template at @@ -157,7 +157,7 @@ module ActionMailer #:nodoc: # end # end # - # Multipart messages can also be used implicitly because ActionMailer will automatically + # Multipart messages can also be used implicitly because Action Mailer will automatically # detect and use multipart templates, where each template is named after the name of the action, followed # by the content type. Each such detected template will be added as separate part to the message. # @@ -383,8 +383,8 @@ module ActionMailer #:nodoc: # Receives a raw email, parses it into an email object, decodes it, # instantiates a new mailer, and passes the email object to the mailer - # object's #receive method. If you want your mailer to be able to - # process incoming messages, you'll need to implement a #receive + # object's +receive+ method. If you want your mailer to be able to + # process incoming messages, you'll need to implement a +receive+ # method that accepts the email object as a parameter: # # class MyMailer < ActionMailer::Base @@ -490,7 +490,7 @@ module ActionMailer #:nodoc: end # Delivers a TMail::Mail object. By default, it delivers the cached mail - # object (from the #create! method). If no cached mail object exists, and + # object (from the create! method). If no cached mail object exists, and # no alternate has been given as the parameter, this will fail. def deliver!(mail = @mail) raise "no mail object available for delivery!" unless mail diff --git a/actionmailer/lib/action_mailer/helpers.rb b/actionmailer/lib/action_mailer/helpers.rb index 3e5ed9e9d7..9c5fcc6afb 100644 --- a/actionmailer/lib/action_mailer/helpers.rb +++ b/actionmailer/lib/action_mailer/helpers.rb @@ -34,7 +34,7 @@ module ActionMailer # helper FooHelper # includes FooHelper in the template class. # helper { def foo() "#{bar} is the very best" end } - # evaluates the block in the template class, adding method #foo. + # evaluates the block in the template class, adding method +foo+. # helper(:three, BlindHelper) { def mice() 'mice' end } # does all three. def helper(*args, &block) diff --git a/actionmailer/lib/action_mailer/part.rb b/actionmailer/lib/action_mailer/part.rb index de1b1689f7..2dabf15f08 100644 --- a/actionmailer/lib/action_mailer/part.rb +++ b/actionmailer/lib/action_mailer/part.rb @@ -5,7 +5,7 @@ require 'action_mailer/utils' module ActionMailer # Represents a subpart of an email message. It shares many similar # attributes of ActionMailer::Base. Although you can create parts manually - # and add them to the #parts list of the mailer, it is easier + # and add them to the +parts+ list of the mailer, it is easier # to use the helper methods in ActionMailer::PartContainer. class Part include ActionMailer::AdvAttrAccessor @@ -13,7 +13,7 @@ module ActionMailer # Represents the body of the part, as a string. This should not be a # Hash (like ActionMailer::Base), but if you want a template to be rendered - # into the body of a subpart you can do it with the mailer's #render method + # into the body of a subpart you can do it with the mailer's +render+ method # and assign the result here. adv_attr_accessor :body diff --git a/actionpack/lib/action_controller/assertions/model_assertions.rb b/actionpack/lib/action_controller/assertions/model_assertions.rb index 0b4313055a..d25214bb66 100644 --- a/actionpack/lib/action_controller/assertions/model_assertions.rb +++ b/actionpack/lib/action_controller/assertions/model_assertions.rb @@ -1,7 +1,8 @@ module ActionController module Assertions module ModelAssertions - # Ensures that the passed record is valid by ActiveRecord standards and returns any error messages if it is not. + # Ensures that the passed record is valid by Active Record standards and + # returns any error messages if it is not. # # ==== Examples # diff --git a/actionpack/lib/action_controller/assertions/routing_assertions.rb b/actionpack/lib/action_controller/assertions/routing_assertions.rb index 2acd003243..491b72d586 100644 --- a/actionpack/lib/action_controller/assertions/routing_assertions.rb +++ b/actionpack/lib/action_controller/assertions/routing_assertions.rb @@ -59,7 +59,7 @@ module ActionController end end - # Asserts that the provided options can be used to generate the provided path. This is the inverse of #assert_recognizes. + # Asserts that the provided options can be used to generate the provided path. This is the inverse of +assert_recognizes+. # The +extras+ parameter is used to tell the request the names and values of additional request parameters that would be in # a query string. The +message+ parameter allows you to specify a custom error message for assertion failures. # @@ -96,8 +96,8 @@ module ActionController end # Asserts that path and options match both ways; in other words, it verifies that path generates - # options and then that options generates path. This essentially combines #assert_recognizes - # and #assert_generates into one step. + # options and then that options generates path. This essentially combines +assert_recognizes+ + # and +assert_generates+ into one step. # # The +extras+ hash allows you to specify options that would normally be provided as a query string to the action. The # +message+ parameter allows you to specify a custom error message to display upon failure. diff --git a/actionpack/lib/action_controller/assertions/selector_assertions.rb b/actionpack/lib/action_controller/assertions/selector_assertions.rb index 9ef093acfc..d3594e711c 100644 --- a/actionpack/lib/action_controller/assertions/selector_assertions.rb +++ b/actionpack/lib/action_controller/assertions/selector_assertions.rb @@ -12,12 +12,12 @@ module ActionController NO_STRIP = %w{pre script style textarea} end - # Adds the #assert_select method for use in Rails functional + # Adds the +assert_select+ method for use in Rails functional # test cases, which can be used to make assertions on the response HTML of a controller - # action. You can also call #assert_select within another #assert_select to + # action. You can also call +assert_select+ within another +assert_select+ to # make assertions on elements selected by the enclosing assertion. # - # Use #css_select to select elements without making an assertions, either + # Use +css_select+ to select elements without making an assertions, either # from the response HTML or elements selected by the enclosing assertion. # # In addition to HTML responses, you can make the following assertions: @@ -44,8 +44,8 @@ module ActionController # base element and any of its children. Returns an empty array if no # match is found. # - # The selector may be a CSS selector expression (+String+), an expression - # with substitution values (+Array+) or an HTML::Selector object. + # The selector may be a CSS selector expression (String), an expression + # with substitution values (Array) or an HTML::Selector object. # # ==== Examples # # Selects all div tags @@ -114,8 +114,8 @@ module ActionController # starting from (and including) that element and all its children in # depth-first order. # - # If no element if specified, calling #assert_select will select from the - # response HTML. Calling #assert_select inside an #assert_select block will + # If no element if specified, calling +assert_select+ will select from the + # response HTML. Calling #assert_select inside an +assert_select+ block will # run the assertion for each element selected by the enclosing assertion. # # ==== Example @@ -130,7 +130,7 @@ module ActionController # assert_select "li" # end # - # The selector may be a CSS selector expression (+String+), an expression + # The selector may be a CSS selector expression (String), an expression # with substitution values, or an HTML::Selector object. # # === Equality Tests @@ -356,16 +356,16 @@ module ActionController # # === Using blocks # - # Without a block, #assert_select_rjs merely asserts that the response + # Without a block, +assert_select_rjs+ merely asserts that the response # contains one or more RJS statements that replace or update content. # - # With a block, #assert_select_rjs also selects all elements used in + # With a block, +assert_select_rjs+ also selects all elements used in # these statements and passes them to the block. Nested assertions are # supported. # - # Calling #assert_select_rjs with no arguments and using nested asserts + # Calling +assert_select_rjs+ with no arguments and using nested asserts # asserts that the HTML content is returned by one or more RJS statements. - # Using #assert_select directly makes the same assertion on the content, + # Using +assert_select+ directly makes the same assertion on the content, # but without distinguishing whether the content is returned in an HTML # or JavaScript. # @@ -601,7 +601,7 @@ module ActionController RJS_PATTERN_UNICODE_ESCAPED_CHAR = /\\u([0-9a-zA-Z]{4})/ end - # #assert_select and #css_select call this to obtain the content in the HTML + # +assert_select+ and +css_select+ call this to obtain the content in the HTML # page, or from all the RJS statements, depending on the type of response. def response_from_page_or_rjs() content_type = @response.content_type diff --git a/actionpack/lib/action_controller/assertions/tag_assertions.rb b/actionpack/lib/action_controller/assertions/tag_assertions.rb index 4ac489520a..90ba3668fb 100644 --- a/actionpack/lib/action_controller/assertions/tag_assertions.rb +++ b/actionpack/lib/action_controller/assertions/tag_assertions.rb @@ -91,7 +91,7 @@ module ActionController # :descendant => { :tag => "span", # :child => /hello world/ } # - # Please note: #assert_tag and #assert_no_tag only work + # Please note: +assert_tag+ and +assert_no_tag+ only work # with well-formed XHTML. They recognize a few tags as implicitly self-closing # (like br and hr and such) but will not work correctly with tags # that allow optional closing tags (p, li, td). You must explicitly @@ -104,8 +104,8 @@ module ActionController end end - # Identical to #assert_tag, but asserts that a matching tag does _not_ - # exist. (See #assert_tag for a full discussion of the syntax.) + # Identical to +assert_tag+, but asserts that a matching tag does _not_ + # exist. (See +assert_tag+ for a full discussion of the syntax.) # # === Examples # # Assert that there is not a "div" containing a "p" diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index ea55fe42ce..a036600c2b 100755 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -104,7 +104,7 @@ module ActionController #:nodoc: # end # # Actions, by default, render a template in the app/views directory corresponding to the name of the controller and action - # after executing code in the action. For example, the +index+ action of the +GuestBookController+ would render the + # after executing code in the action. For example, the +index+ action of the GuestBookController would render the # template app/views/guestbook/index.erb by default after populating the @entries instance variable. # # Unlike index, the sign action will not render a template. After performing its main purpose (creating a @@ -118,10 +118,10 @@ module ActionController #:nodoc: # # Requests are processed by the Action Controller framework by extracting the value of the "action" key in the request parameters. # This value should hold the name of the action to be performed. Once the action has been identified, the remaining - # request parameters, the session (if one is available), and the full request with all the http headers are made available to + # request parameters, the session (if one is available), and the full request with all the HTTP headers are made available to # the action through instance variables. Then the action is performed. # - # The full request object is available with the request accessor and is primarily used to query for http headers. These queries + # The full request object is available with the request accessor and is primarily used to query for HTTP headers. These queries # are made by accessing the environment hash, like this: # # def server_ip @@ -291,10 +291,10 @@ module ActionController #:nodoc: cattr_accessor :allow_concurrency # Modern REST web services often need to submit complex data to the web application. - # The param_parsers hash lets you register handlers which will process the http body and add parameters to the - # params hash. These handlers are invoked for post and put requests. + # The @@param_parsers hash lets you register handlers which will process the HTTP body and add parameters to the + # params hash. These handlers are invoked for POST and PUT requests. # - # By default application/xml is enabled. A XmlSimple class with the same param name as the root will be instantiated + # By default application/xml is enabled. A XmlSimple class with the same param name as the root will be instantiated # in the params. This allows XML requests to mask themselves as regular form submissions, so you can have one # action serve both regular forms and web service requests. # @@ -307,7 +307,7 @@ module ActionController #:nodoc: # # Note: Up until release 1.1 of Rails, Action Controller would default to using XmlSimple configured to discard the # root node for such requests. The new default is to keep the root, such that "David" results - # in params[:r][:name] for "David" instead of params[:name]. To get the old behavior, you can + # in params[:r][:name] for "David" instead of params[:name]. To get the old behavior, you can # re-register XmlSimple as application/xml handler ike this: # # ActionController::Base.param_parsers[Mime::XML] = diff --git a/actionpack/lib/action_controller/cgi_ext/cookie.rb b/actionpack/lib/action_controller/cgi_ext/cookie.rb index a244e2a39a..ef033fb4f3 100644 --- a/actionpack/lib/action_controller/cgi_ext/cookie.rb +++ b/actionpack/lib/action_controller/cgi_ext/cookie.rb @@ -6,25 +6,24 @@ class CGI #:nodoc: attr_accessor :name, :value, :path, :domain, :expires attr_reader :secure, :http_only - # Create a new CGI::Cookie object. + # Creates a new CGI::Cookie object. # # The contents of the cookie can be specified as a +name+ and one # or more +value+ arguments. Alternatively, the contents can # be specified as a single hash argument. The possible keywords of # this hash are as follows: # - # name:: the name of the cookie. Required. - # value:: the cookie's value or list of values. - # path:: the path for which this cookie applies. Defaults to the - # base directory of the CGI script. - # domain:: the domain for which this cookie applies. - # expires:: the time at which this cookie expires, as a +Time+ object. - # secure:: whether this cookie is a secure cookie or not (default to - # false). Secure cookies are only transmitted to HTTPS - # servers. - # http_only:: whether this cookie can be accessed by client side scripts (e.g. document.cookie) or only over HTTP - # More details: http://msdn2.microsoft.com/en-us/library/system.web.httpcookie.httponly.aspx - # Defaults to false. + # * :name - The name of the cookie. Required. + # * :value - The cookie's value or list of values. + # * :path - The path for which this cookie applies. Defaults to the + # base directory of the CGI script. + # * :domain - The domain for which this cookie applies. + # * :expires - The time at which this cookie expires, as a Time object. + # * :secure - Whether this cookie is a secure cookie or not (defaults to + # +false+). Secure cookies are only transmitted to HTTPS servers. + # * :http_only - Whether this cookie can be accessed by client side scripts (e.g. document.cookie) or only over HTTP. + # More details in http://msdn2.microsoft.com/en-us/library/system.web.httpcookie.httponly.aspx. Defaults to +false+. + # # These keywords correspond to attributes of the cookie object. def initialize(name = '', *value) if name.kind_of?(String) @@ -56,17 +55,17 @@ class CGI #:nodoc: super(@value) end - # Set whether the Cookie is a secure cookie or not. + # Sets whether the Cookie is a secure cookie or not. def secure=(val) @secure = val == true end - # Set whether the Cookie is an HTTP only cookie or not. + # Sets whether the Cookie is an HTTP only cookie or not. def http_only=(val) @http_only = val == true end - # Convert the Cookie to its string representation. + # Converts the Cookie to its string representation. def to_s buf = '' buf << @name << '=' @@ -79,11 +78,11 @@ class CGI #:nodoc: buf end - # Parse a raw cookie string into a hash of cookie-name=>Cookie + # Parses a raw cookie string into a hash of cookie-name => cookie-object # pairs. # # cookies = CGI::Cookie::parse("raw_cookie_string") - # # { "name1" => cookie1, "name2" => cookie2, ... } + # # => { "name1" => cookie1, "name2" => cookie2, ... } # def self.parse(raw_cookie) cookies = Hash.new([]) diff --git a/actionpack/lib/action_controller/cgi_process.rb b/actionpack/lib/action_controller/cgi_process.rb index 7e58c98bf2..8bc5e4c3a7 100644 --- a/actionpack/lib/action_controller/cgi_process.rb +++ b/actionpack/lib/action_controller/cgi_process.rb @@ -15,7 +15,7 @@ module ActionController #:nodoc: # * :new_session - if true, force creation of a new session. If not set, a new session is only created if none currently # exists. If false, a new session is never created, and if none currently exists and the +session_id+ option is not set, # an ArgumentError is raised. - # * :session_expires - the time the current session expires, as a +Time+ object. If not set, the session will continue + # * :session_expires - the time the current session expires, as a Time object. If not set, the session will continue # indefinitely. # * :session_domain - the hostname domain for which this session is valid. If not set, defaults to the hostname of the # server. diff --git a/actionpack/lib/action_controller/filters.rb b/actionpack/lib/action_controller/filters.rb index 6d0c83eb40..60d92d9b98 100644 --- a/actionpack/lib/action_controller/filters.rb +++ b/actionpack/lib/action_controller/filters.rb @@ -100,10 +100,10 @@ module ActionController #:nodoc: # # Around filters wrap an action, executing code both before and after. # They may be declared as method references, blocks, or objects responding - # to #filter or to both #before and #after. + # to +filter+ or to both +before+ and +after+. # - # To use a method as an around_filter, pass a symbol naming the Ruby method. - # Yield (or block.call) within the method to run the action. + # To use a method as an +around_filter+, pass a symbol naming the Ruby method. + # Yield (or block.call) within the method to run the action. # # around_filter :catch_exceptions # @@ -115,9 +115,9 @@ module ActionController #:nodoc: # raise # end # - # To use a block as an around_filter, pass a block taking as args both + # To use a block as an +around_filter+, pass a block taking as args both # the controller and the action block. You can't call yield directly from - # an around_filter block; explicitly call the action block instead: + # an +around_filter+ block; explicitly call the action block instead: # # around_filter do |controller, action| # logger.debug "before #{controller.action_name}" @@ -125,7 +125,7 @@ module ActionController #:nodoc: # logger.debug "after #{controller.action_name}" # end # - # To use a filter object with around_filter, pass an object responding + # To use a filter object with +around_filter+, pass an object responding # to :filter or both :before and :after. With a # filter method, yield to the block as above: # @@ -137,7 +137,7 @@ module ActionController #:nodoc: # end # end # - # With before and after methods: + # With +before+ and +after+ methods: # # around_filter Authorizer.new # @@ -154,9 +154,9 @@ module ActionController #:nodoc: # end # end # - # If the filter has before and after methods, the before method will be - # called before the action. If before renders or redirects, the filter chain is - # halted and after will not be run. See Filter Chain Halting below for + # If the filter has +before+ and +after+ methods, the +before+ method will be + # called before the action. If +before+ renders or redirects, the filter chain is + # halted and +after+ will not be run. See Filter Chain Halting below for # an example. # # == Filter chain skipping @@ -215,7 +215,7 @@ module ActionController #:nodoc: # # before_filter and around_filter may halt the request # before a controller action is run. This is useful, for example, to deny - # access to unauthenticated users or to redirect from http to https. + # access to unauthenticated users or to redirect from HTTP to HTTPS. # Simply call render or redirect. After filters will not be executed if the filter # chain is halted. # @@ -241,10 +241,10 @@ module ActionController #:nodoc: # . / # #after (actual filter code is run, unless the around filter does not yield) # - # If #around returns before yielding, #after will still not be run. The #before - # filter and controller action will not be run. If #before renders or redirects, - # the second half of #around and will still run but #after and the - # action will not. If #around fails to yield, #after will not be run. + # If +around+ returns before yielding, +after+ will still not be run. The +before+ + # filter and controller action will not be run. If +before+ renders or redirects, + # the second half of +around+ and will still run but +after+ and the + # action will not. If +around+ fails to yield, +after+ will not be run. class FilterChain < ActiveSupport::Callbacks::CallbackChain #:nodoc: def append_filter_to_chain(filters, filter_type, &block) @@ -471,7 +471,7 @@ module ActionController #:nodoc: # Shorthand for append_after_filter since it's the most common. alias :after_filter :append_after_filter - # If you append_around_filter A.new, B.new, the filter chain looks like + # If you append_around_filter A.new, B.new, the filter chain looks like # # B#before # A#before @@ -479,13 +479,13 @@ module ActionController #:nodoc: # A#after # B#after # - # With around filters which yield to the action block, #before and #after + # With around filters which yield to the action block, +before+ and +after+ # are the code before and after the yield. def append_around_filter(*filters, &block) filter_chain.append_filter_to_chain(filters, :around, &block) end - # If you prepend_around_filter A.new, B.new, the filter chain looks like: + # If you prepend_around_filter A.new, B.new, the filter chain looks like: # # A#before # B#before @@ -493,13 +493,13 @@ module ActionController #:nodoc: # B#after # A#after # - # With around filters which yield to the action block, #before and #after + # With around filters which yield to the action block, +before+ and +after+ # are the code before and after the yield. def prepend_around_filter(*filters, &block) filter_chain.prepend_filter_to_chain(filters, :around, &block) end - # Shorthand for append_around_filter since it's the most common. + # Shorthand for +append_around_filter+ since it's the most common. alias :around_filter :append_around_filter # Removes the specified filters from the +before+ filter chain. Note that this only works for skipping method-reference diff --git a/actionpack/lib/action_controller/helpers.rb b/actionpack/lib/action_controller/helpers.rb index a8bead4d34..ce5e8be54c 100644 --- a/actionpack/lib/action_controller/helpers.rb +++ b/actionpack/lib/action_controller/helpers.rb @@ -20,7 +20,7 @@ module ActionController #:nodoc: end # The Rails framework provides a large number of helpers for working with +assets+, +dates+, +forms+, - # +numbers+ and +ActiveRecord+ objects, to name a few. These helpers are available to all templates + # +numbers+ and Active Record objects, to name a few. These helpers are available to all templates # by default. # # In addition to using the standard template helpers provided in the Rails framework, creating custom helpers to @@ -32,7 +32,7 @@ module ActionController #:nodoc: # controller which inherits from it. # # ==== Examples - # The +to_s+ method from the +Time+ class can be wrapped in a helper method to display a custom message if + # The +to_s+ method from the Time class can be wrapped in a helper method to display a custom message if # the Time object is blank: # # module FormattedTimeHelper @@ -41,7 +41,7 @@ module ActionController #:nodoc: # end # end # - # +FormattedTimeHelper+ can now be included in a controller, using the +helper+ class method: + # FormattedTimeHelper can now be included in a controller, using the +helper+ class method: # # class EventsController < ActionController::Base # helper FormattedTimeHelper @@ -74,22 +74,22 @@ module ActionController #:nodoc: # The +helper+ class method can take a series of helper module names, a block, or both. # - # * *args: One or more +Modules+, +Strings+ or +Symbols+, or the special symbol :all. + # * *args: One or more modules, strings or symbols, or the special symbol :all. # * &block: A block defining helper methods. # # ==== Examples - # When the argument is a +String+ or +Symbol+, the method will provide the "_helper" suffix, require the file + # When the argument is a string or symbol, the method will provide the "_helper" suffix, require the file # and include the module in the template class. The second form illustrates how to include custom helpers # when working with namespaced controllers, or other cases where the file containing the helper definition is not # in one of Rails' standard load paths: # helper :foo # => requires 'foo_helper' and includes FooHelper # helper 'resources/foo' # => requires 'resources/foo_helper' and includes Resources::FooHelper # - # When the argument is a +Module+, it will be included directly in the template class. + # When the argument is a module it will be included directly in the template class. # helper FooHelper # => includes FooHelper # # When the argument is the symbol :all, the controller will include all helpers from - # app/helpers/**/*.rb under +RAILS_ROOT+. + # app/helpers/**/*.rb under RAILS_ROOT. # helper :all # # Additionally, the +helper+ class method can receive and evaluate a block, making the methods defined available diff --git a/actionpack/lib/action_controller/integration.rb b/actionpack/lib/action_controller/integration.rb index f0fc1945a9..bd69d02ed7 100644 --- a/actionpack/lib/action_controller/integration.rb +++ b/actionpack/lib/action_controller/integration.rb @@ -58,7 +58,7 @@ module ActionController class MultiPartNeededException < Exception end - # Create and initialize a new +Session+ instance. + # Create and initialize a new Session instance. def initialize reset! end @@ -136,25 +136,25 @@ module ActionController end # Performs a GET request, following any subsequent redirect. - # See #request_via_redirect() for more information. + # See +request_via_redirect+ for more information. def get_via_redirect(path, parameters = nil, headers = nil) request_via_redirect(:get, path, parameters, headers) end # Performs a POST request, following any subsequent redirect. - # See #request_via_redirect() for more information. + # See +request_via_redirect+ for more information. def post_via_redirect(path, parameters = nil, headers = nil) request_via_redirect(:post, path, parameters, headers) end # Performs a PUT request, following any subsequent redirect. - # See #request_via_redirect() for more information. + # See +request_via_redirect+ for more information. def put_via_redirect(path, parameters = nil, headers = nil) request_via_redirect(:put, path, parameters, headers) end # Performs a DELETE request, following any subsequent redirect. - # See #request_via_redirect() for more information. + # See +request_via_redirect+ for more information. def delete_via_redirect(path, parameters = nil, headers = nil) request_via_redirect(:delete, path, parameters, headers) end @@ -166,12 +166,12 @@ module ActionController # Performs a GET request with the given parameters. The parameters may # be +nil+, a Hash, or a string that is appropriately encoded - # (application/x-www-form-urlencoded or multipart/form-data). The headers - # should be a hash. The keys will automatically be upcased, with the + # (application/x-www-form-urlencoded or multipart/form-data). + # The headers should be a hash. The keys will automatically be upcased, with the # prefix 'HTTP_' added if needed. # - # You can also perform POST, PUT, DELETE, and HEAD requests with #post, - # #put, #delete, and #head. + # You can also perform POST, PUT, DELETE, and HEAD requests with +post+, + # +put+, +delete+, and +head+. def get(path, parameters = nil, headers = nil) process :get, path, parameters, headers end diff --git a/actionpack/lib/action_controller/mime_type.rb b/actionpack/lib/action_controller/mime_type.rb index f43e2ba06d..fa123f7808 100644 --- a/actionpack/lib/action_controller/mime_type.rb +++ b/actionpack/lib/action_controller/mime_type.rb @@ -104,7 +104,7 @@ module Mime list[text_xml].name = Mime::XML.to_s end - # Look for more specific xml-based types and sort them ahead of app/xml + # Look for more specific XML-based types and sort them ahead of app/xml if app_xml idx = app_xml @@ -158,7 +158,7 @@ module Mime end end - # Returns true if ActionPack should check requests using this Mime Type for possible request forgery. See + # Returns true if Action Pack should check requests using this Mime Type for possible request forgery. See # ActionController::RequestForgerProtection. def verify_request? !@@unverifiable_types.include?(to_sym) diff --git a/actionpack/lib/action_controller/polymorphic_routes.rb b/actionpack/lib/action_controller/polymorphic_routes.rb index e2b7716aa2..509fa6a08e 100644 --- a/actionpack/lib/action_controller/polymorphic_routes.rb +++ b/actionpack/lib/action_controller/polymorphic_routes.rb @@ -1,6 +1,6 @@ module ActionController # Polymorphic URL helpers are methods for smart resolution to a named route call when - # given an ActiveRecord model instance. They are to be used in combination with + # given an Active Record model instance. They are to be used in combination with # ActionController::Resources. # # These methods are useful when you want to generate correct URL or path to a RESTful @@ -9,7 +9,9 @@ module ActionController # Nested resources and/or namespaces are also supported, as illustrated in the example: # # polymorphic_url([:admin, @article, @comment]) - # #-> results in: + # + # results in: + # # admin_article_comment_url(@article, @comment) # # == Usage within the framework @@ -38,11 +40,8 @@ module ActionController # # Example usage: # - # edit_polymorphic_path(@post) - # #=> /posts/1/edit - # - # formatted_polymorphic_path([@post, :pdf]) - # #=> /posts/1.pdf + # edit_polymorphic_path(@post) # => "/posts/1/edit" + # formatted_polymorphic_path([@post, :pdf]) # => "/posts/1.pdf" module PolymorphicRoutes # Constructs a call to a named RESTful route for the given record and returns the # resulting URL string. For example: diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/resources.rb index 26f75780c1..9fb1f9fa39 100644 --- a/actionpack/lib/action_controller/resources.rb +++ b/actionpack/lib/action_controller/resources.rb @@ -191,7 +191,7 @@ module ActionController # end # end # - # Along with the routes themselves, #resources generates named routes for use in + # Along with the routes themselves, +resources+ generates named routes for use in # controllers and views. map.resources :messages produces the following named routes and helpers: # # Named Route Helpers @@ -208,7 +208,7 @@ module ActionController # edit_message edit_message_url(id), hash_for_edit_message_url(id), # edit_message_path(id), hash_for_edit_message_path(id) # - # You can use these helpers instead of #url_for or methods that take #url_for parameters. For example: + # You can use these helpers instead of +url_for+ or methods that take +url_for+ parameters. For example: # # redirect_to :controller => 'messages', :action => 'index' # # and @@ -406,7 +406,7 @@ module ActionController # end # end # - # Along with the routes themselves, #resource generates named routes for + # Along with the routes themselves, +resource+ generates named routes for # use in controllers and views. map.resource :account produces # these named routes and helpers: # diff --git a/actionpack/lib/action_controller/routing/builder.rb b/actionpack/lib/action_controller/routing/builder.rb index b1a98d1a51..4740113ed0 100644 --- a/actionpack/lib/action_controller/routing/builder.rb +++ b/actionpack/lib/action_controller/routing/builder.rb @@ -23,9 +23,9 @@ module ActionController # Accepts a "route path" (a string defining a route), and returns the array # of segments that corresponds to it. Note that the segment array is only # partially initialized--the defaults and requirements, for instance, need - # to be set separately, via the #assign_route_options method, and the - # #optional? method for each segment will not be reliable until after - # #assign_route_options is called, as well. + # to be set separately, via the +assign_route_options+ method, and the + # optional? method for each segment will not be reliable until after + # +assign_route_options+ is called, as well. def segments_for_route_path(path) rest, segments = path, [] diff --git a/actionpack/lib/action_controller/session/cookie_store.rb b/actionpack/lib/action_controller/session/cookie_store.rb index ada1862c3e..b477c1f7da 100644 --- a/actionpack/lib/action_controller/session/cookie_store.rb +++ b/actionpack/lib/action_controller/session/cookie_store.rb @@ -34,7 +34,7 @@ require 'openssl' # to generate the HMAC message digest # such as 'MD5', 'RIPEMD160', 'SHA256', etc. # # To generate a secret key for an existing application, run -# `rake secret` and set the key in config/environment.rb. +# "rake secret" and set the key in config/environment.rb. # # Note that changing digest or secret invalidates all existing sessions! class CGI::Session::CookieStore diff --git a/actionpack/lib/action_controller/test_process.rb b/actionpack/lib/action_controller/test_process.rb index f03ed5b2a7..0cf143210d 100644 --- a/actionpack/lib/action_controller/test_process.rb +++ b/actionpack/lib/action_controller/test_process.rb @@ -3,7 +3,7 @@ require 'action_controller/test_case' module ActionController #:nodoc: class Base - # Process a test request called with a +TestRequest+ object. + # Process a test request called with a TestRequest object. def self.process_test(request) new.process_test(request) end @@ -358,7 +358,7 @@ module ActionController #:nodoc: module TestProcess def self.included(base) - # execute the request simulating a specific http method and set/volley the response + # execute the request simulating a specific HTTP method and set/volley the response %w( get post put delete head ).each do |method| base.class_eval <<-EOV, __FILE__, __LINE__ def #{method}(action, parameters = nil, session = nil, flash = nil) diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index dfc7e2b3ed..e5a95a961c 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -11,8 +11,8 @@ module ActionView # === Using asset hosts # By default, Rails links to these assets on the current host in the public # folder, but you can direct Rails to link to assets from a dedicated assets server by - # setting ActionController::Base.asset_host in your environment.rb. For example, - # let's say your asset host is assets.example.com. + # setting ActionController::Base.asset_host in your config/environment.rb. For example, + # let's say your asset host is assets.example.com. # # ActionController::Base.asset_host = "assets.example.com" # image_tag("rails.png") @@ -22,8 +22,8 @@ module ActionView # # This is useful since browsers typically open at most two connections to a single host, # which means your assets often wait in single file for their turn to load. You can - # alleviate this by using a %d wildcard in asset_host (for example, "assets%d.example.com") - # to automatically distribute asset requests among four hosts (e.g., assets0.example.com through assets3.example.com) + # alleviate this by using a %d wildcard in asset_host (for example, "assets%d.example.com") + # to automatically distribute asset requests among four hosts (e.g., "assets0.example.com" through "assets3.example.com") # so browsers will open eight connections rather than two. # # image_tag("rails.png") @@ -293,9 +293,9 @@ module ActionView end # Computes the path to a stylesheet asset in the public stylesheets directory. - # If the +source+ filename has no extension, .css will be appended. + # If the +source+ filename has no extension, .css will be appended. # Full paths from the document root will be passed through. - # Used internally by stylesheet_link_tag to build the stylesheet path. + # Used internally by +stylesheet_link_tag+ to build the stylesheet path. # # ==== Examples # stylesheet_path "style" # => /stylesheets/style.css @@ -309,7 +309,7 @@ module ActionView alias_method :path_to_stylesheet, :stylesheet_path # aliased to avoid conflicts with a stylesheet_path named route # Returns a stylesheet link tag for the sources specified as arguments. If - # you don't specify an extension, .css will be appended automatically. + # you don't specify an extension, .css will be appended automatically. # You can modify the link attributes by passing a hash as the last argument. # # ==== Examples @@ -379,7 +379,7 @@ module ActionView # Computes the path to an image asset in the public images directory. # Full paths from the document root will be passed through. - # Used internally by image_tag to build the image path. + # Used internally by +image_tag+ to build the image path. # # ==== Examples # image_path("edit") # => /images/edit @@ -454,8 +454,8 @@ module ActionView end end - # Add the .ext if not present. Return full URLs otherwise untouched. - # Prefix with /dir/ if lacking a leading /. Account for relative URL + # Add the the extension +ext+ if not present. Return full URLs otherwise untouched. + # Prefix with /dir/ if lacking a leading +/+. Account for relative URL # roots. Rewrite the asset path for cache-busting asset ids. Include # asset host, if configured, with the correct request protocol. def compute_public_path(source, dir, ext = nil, include_host = true) @@ -502,9 +502,9 @@ module ActionView end end - # Pick an asset host for this source. Returns nil if no host is set, + # Pick an asset host for this source. Returns +nil+ if no host is set, # the host if no wildcard is set, the host interpolated with the - # numbers 0-3 if it contains %d (the number is the source hash mod 4), + # numbers 0-3 if it contains %d (the number is the source hash mod 4), # or the value returned from invoking the proc if it's a proc. def compute_asset_host(source) if host = ActionController::Base.asset_host diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 0962be2c79..0791feb9ac 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -86,15 +86,15 @@ module ActionView # <%= f.text_field :author %>
# <% end %> # - # There, +form_for+ is able to generate the rest of RESTful parameters + # There, +form_for+ is able to generate the rest of RESTful form parameters # based on introspection on the record, but to understand what it does we # need to dig first into the alternative generic usage it is based upon. # # === Generic form_for # - # The generic way to call +form_for+ requires a few arguments: + # The generic way to call +form_for+ yields a form builder around a model: # - # <% form_for :person, @person, :url => { :action => "update" } do |f| %> + # <% form_for :person, :url => { :action => "update" } do |f| %> # <%= f.error_messages %> # First name: <%= f.text_field :first_name %>
# Last name : <%= f.text_field :last_name %>
@@ -102,21 +102,48 @@ module ActionView # Admin? : <%= f.check_box :admin %>
# <% end %> # + # There, the first argument is a symbol or string with the name of the + # object the form is about, and also the name of the instance variable the + # object is stored in. + # + # The form builder acts as a regular form helper that somehow carries the + # model. Thus, the idea is that + # + # <%= f.text_field :first_name %> + # + # gets expanded to + # + # <%= text_field :person, :first_name %> + # + # If the instance variable is not @person you can pass the actual + # record as the second argument: + # + # <% form_for :person, person, :url => { :action => "update" } do |f| %> + # ... + # <% end %> + # + # In that case you can think + # + # <%= f.text_field :first_name %> + # + # gets expanded to + # + # <%= text_field :person, :first_name, :object => person %> + # + # You can even display error messages of the wrapped model this way: + # + # <%= f.error_messages %> + # + # In any of its variants, the rightmost argument to +form_for+ is an + # optional hash of options: + # + # * :url - The URL the form is submitted to. It takes the same fields + # you pass to +url_for+ or +link_to+. In particular you may pass here a + # named route directly as well. Defaults to the current action. + # * :html - Optional HTML attributes for the form tag. + # # Worth noting is that the +form_for+ tag is called in a ERb evaluation block, - # not an ERb output block. So that's <% %>, not <%= %>. Also - # worth noting is that +form_for+ yields a form builder object, in this - # example as +f+, which emulates the API for the stand-alone FormHelper - # methods, but without the object name. So instead of text_field :person, :name, - # you get away with f.text_field :name. Notice that you can even do - # <%= f.error_messages %> to display the error messsages of the model - # object in question. - # - # Even further, the +form_for+ method allows you to more easily escape the - # instance variable convention. So while the stand-alone approach would require - # text_field :person, :name, :object => person to work with local - # variables instead of instance ones, the +form_for+ calls remain the same. - # You simply declare once with :person, person and all subsequent - # field calls save :person and :object => person. + # not an ERb output block. So that's <% %>, not <%= %>. # # Also note that +form_for+ doesn't create an exclusive scope. It's still # possible to use both the stand-alone FormHelper methods and methods from @@ -133,40 +160,32 @@ module ActionView # designed to work with an object as base, like FormOptionHelper#collection_select # and DateHelper#datetime_select. # - # HTML attributes for the form tag can be given as :html => {...}. - # For example: - # - # <% form_for :person, @person, :html => {:id => 'person_form'} do |f| %> - # ... - # <% end %> - # - # The above form will then have the +id+ attribute with the value "person_form", - # which you can then style with CSS or manipulate with JavaScript. - # - # === Relying on record identification + # === Resource-oriented style # # As we said above, in addition to manually configuring the +form_for+ call, - # you can rely on record identification, which will use the conventions and - # named routes of that approach. This is the preferred way to use +form_for+ - # nowadays: + # you can rely on automated resource identification, which will use the conventions + # and named routes of that approach. This is the preferred way to use +form_for+ + # nowadays. + # + # For example, if @post is an existing record you want to edit # - # <% form_for(@post) do |f| %> + # <% form_for @post do |f| %> # ... # <% end %> # - # This will expand to be the same as: + # is equivalent to something like: # # <% form_for :post, @post, :url => post_path(@post), :html => { :method => :put, :class => "edit_post", :id => "edit_post_45" } do |f| %> # ... # <% end %> # - # And for new records: + # And for new records # # <% form_for(Post.new) do |f| %> # ... # <% end %> # - # This will expand to be the same as: + # expands to # # <% form_for :post, Post.new, :url => posts_path, :html => { :class => "new_post", :id => "new_post" } do |f| %> # ... @@ -305,13 +324,13 @@ module ActionView # # ==== Examples # label(:post, :title) - # #=> + # # => # # label(:post, :title, "A short title") - # #=> + # # => # # label(:post, :title, "A short title", :class => "title_label") - # #=> + # # => # def label(object_name, method, text = nil, options = {}) InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_label_tag(text, options) diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index 6f3818659e..e0a097e367 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -119,7 +119,7 @@ module ActionView # end # end # - # Sample usage (selecting the associated +Author+ for an instance of +Post+, @post): + # Sample usage (selecting the associated Author for an instance of Post, @post): # collection_select(:post, :author_id, Author.find(:all), :id, :name_with_initial, {:prompt => true}) # # If @post.author_id is already 1, this would return: @@ -144,7 +144,7 @@ module ActionView # In addition to the :include_blank option documented above, # this method also supports a :model option, which defaults # to TimeZone. This may be used by users to specify a different time - # zone model object. (See #time_zone_options_for_select for more + # zone model object. (See +time_zone_options_for_select+ for more # information.) # # You can also supply an array of TimeZone objects @@ -153,7 +153,7 @@ module ActionView # obtaining a list of the US time zones.) # # Finally, this method supports a :default option, which selects - # a default TimeZone if the object's time zone is nil. + # a default TimeZone if the object's time zone is +nil+. # # Examples: # time_zone_select( "user", "time_zone", nil, :include_blank => true) @@ -172,7 +172,7 @@ module ActionView # Accepts a container (hash, array, enumerable, your type) and returns a string of option tags. Given a container # where the elements respond to first and last (such as a two-element array), the "lasts" serve as option values and # the "firsts" as option text. Hashes are turned into this form automatically, so the keys become "firsts" and values - # become lasts. If +selected+ is specified, the matching "last" or element will get the selected option-tag. +Selected+ + # become lasts. If +selected+ is specified, the matching "last" or element will get the selected option-tag. +selected+ # may also be an array of values to be selected when using a multiple select. # # Examples (call, result): @@ -217,24 +217,22 @@ module ActionView options_for_select(options, selected) end - # Returns a string of tags, like #options_from_collection_for_select, but + # Returns a string of tags, like options_from_collection_for_select, but # groups them by tags based on the object relationships of the arguments. # # Parameters: - # +collection+:: An array of objects representing the tags - # +group_method+:: The name of a method which, when called on a member of +collection+, returns an - # array of child objects representing the tags - # +group_label_method+:: The name of a method which, when called on a member of +collection+, returns a - # string to be used as the +label+ attribute for its tag - # +option_key_method+:: The name of a method which, when called on a child object of a member of - # +collection+, returns a value to be used as the +value+ attribute for its - # tag - # +option_value_method+:: The name of a method which, when called on a child object of a member of - # +collection+, returns a value to be used as the contents of its - # tag - # +selected_key+:: A value equal to the +value+ attribute for one of the tags, - # which will have the +selected+ attribute set. Corresponds to the return value - # of one of the calls to +option_key_method+. If +nil+, no selection is made. + # * +collection+ - An array of objects representing the tags. + # * +group_method+ - The name of a method which, when called on a member of +collection+, returns an + # array of child objects representing the tags. + # * group_label_method+ - The name of a method which, when called on a member of +collection+, returns a + # string to be used as the +label+ attribute for its tag. + # * +option_key_method+ - The name of a method which, when called on a child object of a member of + # +collection+, returns a value to be used as the +value+ attribute for its tag. + # * +option_value_method+ - The name of a method which, when called on a child object of a member of + # +collection+, returns a value to be used as the contents of its tag. + # * +selected_key+ - A value equal to the +value+ attribute for one of the tags, + # which will have the +selected+ attribute set. Corresponds to the return value of one of the calls + # to +option_key_method+. If +nil+, no selection is made. # # Example object structure for use with this method: # class Continent < ActiveRecord::Base @@ -300,8 +298,8 @@ module ActionView # a TimeZone. # # By default, +model+ is the TimeZone constant (which can be obtained - # in ActiveRecord as a value object). The only requirement is that the - # +model+ parameter be an object that responds to #all, and returns + # in Active Record as a value object). The only requirement is that the + # +model+ parameter be an object that responds to +all+, and returns # an array of objects that represent time zones. # # NOTE: Only the option tags are returned, you have to wrap this call in diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 922a0662fe..ca58f4ba26 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -3,7 +3,7 @@ require 'action_view/helpers/tag_helper' module ActionView module Helpers - # Provides a number of methods for creating form tags that doesn't rely on an ActiveRecord object assigned to the template like + # Provides a number of methods for creating form tags that doesn't rely on an Active Record object assigned to the template like # FormHelper does. Instead, you provide the names and values manually. # # NOTE: The HTML options disabled, readonly, and multiple can all be treated as booleans. So specifying @@ -14,9 +14,9 @@ module ActionView # # ==== Options # * :multipart - If set to true, the enctype is set to "multipart/form-data". - # * :method - The method to use when submitting the form, usually either "get" or "post". - # If "put", "delete", or another verb is used, a hidden input with name _method - # is added to simulate the verb over post. + # * :method - The method to use when submitting the form, usually either "get" or "post". + # If "put", "delete", or another verb is used, a hidden input with name _method + # is added to simulate the verb over post. # * A list of parameters to feed to the URL the form will be posted to. # # ==== Examples diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index 04bf5f2a30..602832e470 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -595,8 +595,8 @@ module ActionView # JavaScript sent with a Content-type of "text/javascript". # # Create new instances with PrototypeHelper#update_page or with - # ActionController::Base#render, then call #insert_html, #replace_html, - # #remove, #show, #hide, #visual_effect, or any other of the built-in + # ActionController::Base#render, then call +insert_html+, +replace_html+, + # +remove+, +show+, +hide+, +visual_effect+, or any other of the built-in # methods on the yielded generator in any order you like to modify the # content and appearance of the current page. # @@ -687,7 +687,7 @@ module ActionView end end - # Returns an object whose #to_json evaluates to +code+. Use this to pass a literal JavaScript + # Returns an object whose to_json evaluates to +code+. Use this to pass a literal JavaScript # expression as an argument to another JavaScriptGenerator method. def literal(code) ActiveSupport::JSON::Variable.new(code.to_s) @@ -1173,7 +1173,7 @@ module ActionView super(generator) end - # The JSON Encoder calls this to check for the #to_json method + # The JSON Encoder calls this to check for the +to_json+ method # Since it's a blank slate object, I suppose it responds to anything. def respond_to?(method) true diff --git a/actionpack/lib/action_view/helpers/record_tag_helper.rb b/actionpack/lib/action_view/helpers/record_tag_helper.rb index 40b66be79f..66c596f3a9 100644 --- a/actionpack/lib/action_view/helpers/record_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/record_tag_helper.rb @@ -2,7 +2,7 @@ module ActionView module Helpers module RecordTagHelper # Produces a wrapper DIV element with id and class parameters that - # relate to the specified ActiveRecord object. Usage example: + # relate to the specified Active Record object. Usage example: # # <% div_for(@person, :class => "foo") do %> # <%=h @person.name %> @@ -17,7 +17,7 @@ module ActionView end # content_tag_for creates an HTML element with id and class parameters - # that relate to the specified ActiveRecord object. For example: + # that relate to the specified Active Record object. For example: # # <% content_tag_for(:tr, @person) do %> # <%=h @person.first_name %> diff --git a/actionpack/lib/action_view/helpers/sanitize_helper.rb b/actionpack/lib/action_view/helpers/sanitize_helper.rb index 6c0a7ec25c..b0dacfe964 100644 --- a/actionpack/lib/action_view/helpers/sanitize_helper.rb +++ b/actionpack/lib/action_view/helpers/sanitize_helper.rb @@ -57,7 +57,7 @@ module ActionView self.class.white_list_sanitizer.sanitize(html, options) end - # Sanitizes a block of css code. Used by #sanitize when it comes across a style attribute + # Sanitizes a block of CSS code. Used by +sanitize+ when it comes across a style attribute. def sanitize_css(style) self.class.white_list_sanitizer.sanitize_css(style) end @@ -111,8 +111,8 @@ module ActionView end end - # Gets the HTML::FullSanitizer instance used by strip_tags. Replace with - # any object that responds to #sanitize + # Gets the HTML::FullSanitizer instance used by +strip_tags+. Replace with + # any object that responds to +sanitize+. # # Rails::Initializer.run do |config| # config.action_view.full_sanitizer = MySpecialSanitizer.new @@ -122,8 +122,8 @@ module ActionView @full_sanitizer ||= HTML::FullSanitizer.new end - # Gets the HTML::LinkSanitizer instance used by strip_links. Replace with - # any object that responds to #sanitize + # Gets the HTML::LinkSanitizer instance used by +strip_links+. Replace with + # any object that responds to +sanitize+. # # Rails::Initializer.run do |config| # config.action_view.link_sanitizer = MySpecialSanitizer.new @@ -133,8 +133,8 @@ module ActionView @link_sanitizer ||= HTML::LinkSanitizer.new end - # Gets the HTML::WhiteListSanitizer instance used by sanitize and sanitize_css. - # Replace with any object that responds to #sanitize + # Gets the HTML::WhiteListSanitizer instance used by sanitize and +sanitize_css+. + # Replace with any object that responds to +sanitize+. # # Rails::Initializer.run do |config| # config.action_view.white_list_sanitizer = MySpecialSanitizer.new @@ -144,7 +144,7 @@ module ActionView @white_list_sanitizer ||= HTML::WhiteListSanitizer.new end - # Adds valid HTML attributes that the #sanitize helper checks for URIs. + # Adds valid HTML attributes that the +sanitize+ helper checks for URIs. # # Rails::Initializer.run do |config| # config.action_view.sanitized_uri_attributes = 'lowsrc', 'target' @@ -154,7 +154,7 @@ module ActionView HTML::WhiteListSanitizer.uri_attributes.merge(attributes) end - # Adds to the Set of 'bad' tags for the #sanitize helper. + # Adds to the Set of 'bad' tags for the +sanitize+ helper. # # Rails::Initializer.run do |config| # config.action_view.sanitized_bad_tags = 'embed', 'object' @@ -163,7 +163,8 @@ module ActionView def sanitized_bad_tags=(attributes) HTML::WhiteListSanitizer.bad_tags.merge(attributes) end - # Adds to the Set of allowed tags for the #sanitize helper. + + # Adds to the Set of allowed tags for the +sanitize+ helper. # # Rails::Initializer.run do |config| # config.action_view.sanitized_allowed_tags = 'table', 'tr', 'td' @@ -173,7 +174,7 @@ module ActionView HTML::WhiteListSanitizer.allowed_tags.merge(attributes) end - # Adds to the Set of allowed html attributes for the #sanitize helper. + # Adds to the Set of allowed HTML attributes for the +sanitize+ helper. # # Rails::Initializer.run do |config| # config.action_view.sanitized_allowed_attributes = 'onclick', 'longdesc' @@ -183,7 +184,7 @@ module ActionView HTML::WhiteListSanitizer.allowed_attributes.merge(attributes) end - # Adds to the Set of allowed css properties for the #sanitize and #sanitize_css heleprs. + # Adds to the Set of allowed CSS properties for the #sanitize and +sanitize_css+ heleprs. # # Rails::Initializer.run do |config| # config.action_view.sanitized_allowed_css_properties = 'expression' @@ -193,7 +194,7 @@ module ActionView HTML::WhiteListSanitizer.allowed_css_properties.merge(attributes) end - # Adds to the Set of allowed css keywords for the #sanitize and #sanitize_css helpers. + # Adds to the Set of allowed CSS keywords for the +sanitize+ and +sanitize_css+ helpers. # # Rails::Initializer.run do |config| # config.action_view.sanitized_allowed_css_keywords = 'expression' @@ -203,7 +204,7 @@ module ActionView HTML::WhiteListSanitizer.allowed_css_keywords.merge(attributes) end - # Adds to the Set of allowed shorthand css properties for the #sanitize and #sanitize_css helpers. + # Adds to the Set of allowed shorthand CSS properties for the +sanitize+ and +sanitize_css+ helpers. # # Rails::Initializer.run do |config| # config.action_view.sanitized_shorthand_css_properties = 'expression' @@ -213,7 +214,7 @@ module ActionView HTML::WhiteListSanitizer.shorthand_css_properties.merge(attributes) end - # Adds to the Set of allowed protocols for the #sanitize helper. + # Adds to the Set of allowed protocols for the +sanitize+ helper. # # Rails::Initializer.run do |config| # config.action_view.sanitized_allowed_protocols = 'ssh', 'feed' diff --git a/actionpack/lib/action_view/helpers/scriptaculous_helper.rb b/actionpack/lib/action_view/helpers/scriptaculous_helper.rb index 12b4cfd3f8..c9b2761cb8 100644 --- a/actionpack/lib/action_view/helpers/scriptaculous_helper.rb +++ b/actionpack/lib/action_view/helpers/scriptaculous_helper.rb @@ -26,9 +26,9 @@ module ActionView # :url => { :action => "reload" }, # :complete => visual_effect(:highlight, "posts", :duration => 0.5) # - # If no element_id is given, it assumes "element" which should be a local + # If no +element_id+ is given, it assumes "element" which should be a local # variable in the generated JavaScript execution context. This can be - # used for example with drop_receiving_element: + # used for example with +drop_receiving_element+: # # <%= drop_receiving_element (...), :loading => visual_effect(:fade) %> # @@ -67,6 +67,7 @@ module ActionView # element as parameters. # # Example: + # # <%= sortable_element("my_list", :url => { :action => "order" }) %> # # In the example, the action gets a "my_list" array parameter @@ -79,60 +80,56 @@ module ActionView # # Additional +options+ are: # - # :format:: A regular expression to determine what to send - # as the serialized id to the server (the default - # is /^[^_]*_(.*)$/). - # - # :constraint:: Whether to constrain the dragging to either :horizontal - # or :vertical (or false to make it unconstrained). - # - # :overlap:: Calculate the item overlap in the :horizontal or - # :vertical direction. - # - # :tag:: Which children of the container element to treat as - # sortable (default is li). - # - # :containment:: Takes an element or array of elements to treat as - # potential drop targets (defaults to the original - # target element). - # - # :only:: A CSS class name or arry of class names used to filter - # out child elements as candidates. - # - # :scroll:: Determines whether to scroll the list during drag - # operations if the list runs past the visual border. - # - # :tree:: Determines whether to treat nested lists as part of the - # main sortable list. This means that you can create multi- - # layer lists, and not only sort items at the same level, - # but drag and sort items between levels. - # - # :hoverclass:: If set, the Droppable will have this additional CSS class - # when an accepted Draggable is hovered over it. - # - # :handle:: Sets whether the element should only be draggable by an - # embedded handle. The value may be a string referencing a - # CSS class value (as of script.aculo.us V1.5). The first - # child/grandchild/etc. element found within the element - # that has this CSS class value will be used as the handle. - # - # :ghosting:: Clones the element and drags the clone, leaving the original - # in place until the clone is dropped (default is false). - # - # :dropOnEmpty:: If set to true, the Sortable container will be made into - # a Droppable, that can receive a Draggable (as according to - # the containment rules) as a child element when there are no - # more elements inside (default is false). - # - # :onChange:: Called whenever the sort order changes while dragging. When - # dragging from one Sortable to another, the callback is - # called once on each Sortable. Gets the affected element as - # its parameter. - # - # :onUpdate:: Called when the drag ends and the Sortable's order is - # changed in any way. When dragging from one Sortable to - # another, the callback is called once on each Sortable. Gets - # the container as its parameter. + # * :format - A regular expression to determine what to send as the + # serialized id to the server (the default is /^[^_]*_(.*)$/). + # + # * :constraint - Whether to constrain the dragging to either + # :horizontal or :vertical (or false to make it unconstrained). + # + # * :overlap - Calculate the item overlap in the :horizontal + # or :vertical direction. + # + # * :tag - Which children of the container element to treat as + # sortable (default is li). + # + # * :containment - Takes an element or array of elements to treat as + # potential drop targets (defaults to the original target element). + # + # * :only - A CSS class name or arry of class names used to filter + # out child elements as candidates. + # + # * :scroll - Determines whether to scroll the list during drag + # operations if the list runs past the visual border. + # + # * :tree - Determines whether to treat nested lists as part of the + # main sortable list. This means that you can create multi-layer lists, + # and not only sort items at the same level, but drag and sort items + # between levels. + # + # * :hoverclass - If set, the Droppable will have this additional CSS class + # when an accepted Draggable is hovered over it. + # + # * :handle - Sets whether the element should only be draggable by an + # embedded handle. The value may be a string referencing a CSS class value + # (as of script.aculo.us V1.5). The first child/grandchild/etc. element + # found within the element that has this CSS class value will be used as + # the handle. + # + # * :ghosting - Clones the element and drags the clone, leaving + # the original in place until the clone is dropped (default is false). + # + # * :dropOnEmpty - If true the Sortable container will be made into + # a Droppable, that can receive a Draggable (as according to the containment + # rules) as a child element when there are no more elements inside (default + # is false). + # + # * :onChange - Called whenever the sort order changes while dragging. When + # dragging from one Sortable to another, the callback is called once on each + # Sortable. Gets the affected element as its parameter. + # + # * :onUpdate - Called when the drag ends and the Sortable's order is + # changed in any way. When dragging from one Sortable to another, the callback + # is called once on each Sortable. Gets the container as its parameter. # # See http://script.aculo.us for more documentation. def sortable_element(element_id, options = {}) @@ -170,8 +167,8 @@ module ActionView end # Makes the element with the DOM ID specified by +element_id+ receive - # dropped draggable elements (created by draggable_element). - # and make an AJAX call By default, the action called gets the DOM ID + # dropped draggable elements (created by +draggable_element+). + # and make an AJAX call. By default, the action called gets the DOM ID # of the element as parameter. # # Example: @@ -182,32 +179,30 @@ module ActionView # http://script.aculo.us for more documentation. # # Some of these +options+ include: - # :accept:: Set this to a string or an array of strings describing the - # allowable CSS classes that the draggable_element must have in order - # to be accepted by this drop_receiving_element. - # - # :confirm:: Adds a confirmation dialog. - # - # Example: - # :confirm => "Are you sure you want to do this?" - # - # :hoverclass:: If set, the drop_receiving_element will have this additional CSS class - # when an accepted draggable_element is hovered over it. - # - # :onDrop:: Called when a draggable_element is dropped onto this element. - # Override this callback with a javascript expression to - # change the default drop behavour. - # - # Example: - # :onDrop => "function(draggable_element, droppable_element, event) { alert('I like bananas') }" - # - # This callback gets three parameters: - # The +Draggable+ element, the +Droppable+ element and the - # +Event+ object. You can extract additional information about the - # drop - like if the Ctrl or Shift keys were pressed - from the +Event+ object. - # - # :with:: A JavaScript expression specifying the parameters for the XMLHttpRequest. - # Any expressions should return a valid URL query string. + # * :accept - Set this to a string or an array of strings describing the + # allowable CSS classes that the +draggable_element+ must have in order + # to be accepted by this +drop_receiving_element+. + # + # * :confirm - Adds a confirmation dialog. Example: + # + # :confirm => "Are you sure you want to do this?" + # + # * :hoverclass - If set, the +drop_receiving_element+ will have + # this additional CSS class when an accepted +draggable_element+ is + # hovered over it. + # + # * :onDrop - Called when a +draggable_element+ is dropped onto + # this element. Override this callback with a JavaScript expression to + # change the default drop behavour. Example: + # + # :onDrop => "function(draggable_element, droppable_element, event) { alert('I like bananas') }" + # + # This callback gets three parameters: The Draggable element, the Droppable + # element and the Event object. You can extract additional information about + # the drop - like if the Ctrl or Shift keys were pressed - from the Event object. + # + # * :with - A JavaScript expression specifying the parameters for + # the XMLHttpRequest. Any expressions should return a valid URL query string. def drop_receiving_element(element_id, options = {}) javascript_tag(drop_receiving_element_js(element_id, options).chop!) end diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index 38c8d18cb0..4b12adf225 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -10,7 +10,7 @@ module ActionView include JavaScriptHelper # Returns the URL for the set of +options+ provided. This takes the - # same options as url_for in ActionController (see the + # same options as +url_for+ in Action Controller (see the # documentation for ActionController::Base#url_for). Note that by default # :only_path is true so you'll get the relative /controller/action # instead of the fully qualified URL like http://example.com/controller/action. diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index 2cda3d94b5..369526188f 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -93,9 +93,9 @@ module ActionView #:nodoc: # Register a class that knows how to handle template files with the given # extension. This can be used to implement new template types. # The constructor for the class must take the ActiveView::Base instance - # as a parameter, and the class must implement a #render method that + # as a parameter, and the class must implement a +render+ method that # takes the contents of the template to render as well as the Hash of - # local assigns available to the template. The #render method ought to + # local assigns available to the template. The +render+ method ought to # return the rendered template as a string. def self.register_template_handler(extension, klass) @@template_handlers[extension.to_sym] = klass diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index 61446cde36..a5d3a50ef1 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -92,19 +92,19 @@ module ActiveRecord # # == Writing value objects # - # Value objects are immutable and interchangeable objects that represent a given value, such as a +Money+ object representing - # $5. Two +Money+ objects both representing $5 should be equal (through methods such as == and <=> from +Comparable+ if ranking - # makes sense). This is unlike entity objects where equality is determined by identity. An entity class such as +Customer+ can + # Value objects are immutable and interchangeable objects that represent a given value, such as a Money object representing + # $5. Two Money objects both representing $5 should be equal (through methods such as == and <=> from Comparable if ranking + # makes sense). This is unlike entity objects where equality is determined by identity. An entity class such as Customer can # easily have two different objects that both have an address on Hyancintvej. Entity identity is determined by object or - # relational unique identifiers (such as primary keys). Normal ActiveRecord::Base classes are entity objects. + # relational unique identifiers (such as primary keys). Normal ActiveRecord::Base classes are entity objects. # - # It's also important to treat the value objects as immutable. Don't allow the +Money+ object to have its amount changed after - # creation. Create a new +Money+ object with the new value instead. This is exemplified by the Money#exchanged_to method that + # It's also important to treat the value objects as immutable. Don't allow the Money object to have its amount changed after + # creation. Create a new Money object with the new value instead. This is exemplified by the Money#exchanged_to method that # returns a new value object instead of changing its own values. Active Record won't persist value objects that have been # changed through means other than the writer method. # # The immutable requirement is enforced by Active Record by freezing any object assigned as a value object. Attempting to - # change it afterwards will result in a ActiveSupport::FrozenObjectError. + # change it afterwards will result in a ActiveSupport::FrozenObjectError. # # Read more about value objects on http://c2.com/cgi/wiki?ValueObject and on the dangers of not keeping value objects # immutable on http://c2.com/cgi/wiki?ValueObjectsShouldBeImmutable @@ -123,8 +123,8 @@ module ActiveRecord # # Options are: # * :class_name - specify the class name of the association. Use it only if that name can't be inferred - # from the part id. So composed_of :address will by default be linked to the +Address+ class, but - # if the real class name is +CompanyAddress+, you'll have to specify it with this option. + # from the part id. So composed_of :address will by default be linked to the Address class, but + # if the real class name is CompanyAddress, you'll have to specify it with this option. # * :mapping - specifies a number of mapping arrays (attribute, parameter) that bind an attribute name # to a constructor parameter on the value class. # * :allow_nil - specifies that the aggregate object will not be instantiated when all mapped diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 6c21fed8ea..a3d1bbbada 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -155,7 +155,7 @@ module ActiveRecord # # == Cardinality and associations # - # ActiveRecord associations can be used to describe one-to-one, one-to-many and many-to-many + # Active Record associations can be used to describe one-to-one, one-to-many and many-to-many # relationships between models. Each model uses an association to describe its role in # the relation. The +belongs_to+ association is always used in the model that has # the foreign key. @@ -441,9 +441,9 @@ module ActiveRecord # # == Eager loading of associations # - # Eager loading is a way to find objects of a certain class and a number of named associations along with it in a single SQL call. This is + # Eager loading is a way to find objects of a certain class and a number of named associations. This is # one of the easiest ways of to prevent the dreaded 1+N problem in which fetching 100 posts that each need to display their author - # triggers 101 database queries. Through the use of eager loading, the 101 queries can be reduced to 1. Example: + # triggers 101 database queries. Through the use of eager loading, the 101 queries can be reduced to 2. Example: # # class Post < ActiveRecord::Base # belongs_to :author @@ -452,7 +452,7 @@ module ActiveRecord # # Consider the following loop using the class above: # - # for post in Post.find(:all) + # for post in Post.all # puts "Post: " + post.title # puts "Written by: " + post.author.name # puts "Last comment on: " + post.comments.first.created_on @@ -462,14 +462,15 @@ module ActiveRecord # # for post in Post.find(:all, :include => :author) # - # This references the name of the +belongs_to+ association that also used the :author symbol, so the find will now weave in a join something - # like this: LEFT OUTER JOIN authors ON authors.id = posts.author_id. Doing so will cut down the number of queries from 201 to 101. + # This references the name of the +belongs_to+ association that also used the :author symbol. After loading the posts, find + # will collect the +author_id+ from each one and load all the referenced authors with one query. Doing so will cut down the number of queries from 201 to 102. # # We can improve upon the situation further by referencing both associations in the finder with: # # for post in Post.find(:all, :include => [ :author, :comments ]) # - # That'll add another join along the lines of: LEFT OUTER JOIN comments ON comments.post_id = posts.id. And we'll be down to 1 query. + # This will load all comments with a single query. This reduces the total number of queries to 3. More generally the number of queries + # will be 1 plus the number of associations named (except if some of the associations are polymorphic +belongs_to+ - see below). # # To include a deep hierarchy of associations, use a hash: # @@ -482,81 +483,91 @@ module ActiveRecord # the number of queries. The database still needs to send all the data to Active Record and it still needs to be processed. So it's no # catch-all for performance problems, but it's a great way to cut down on the number of queries in a situation as the one described above. # - # Since the eager loading pulls from multiple tables, you'll have to disambiguate any column references in both conditions and orders. So - # :order => "posts.id DESC" will work while :order => "id DESC" will not. Because eager loading generates the +SELECT+ statement too, the - # :select option is ignored. + # Since only one table is loaded at a time, conditions or orders cannot reference tables other than the main one. If this is the case + # Active Record falls back to the previously used LEFT OUTER JOIN based strategy. For example + # + # Post.find(:all, :include => [ :author, :comments ], :conditions => ['comments.approved = ?', true]) # - # You can use eager loading on multiple associations from the same table, but you cannot use those associations in orders and conditions - # as there is currently not any way to disambiguate them. Eager loading will not pull additional attributes on join tables, so "rich - # associations" with +has_and_belongs_to_many+ are not a good fit for eager loading. + # will result in a single SQL query with joins along the lines of: LEFT OUTER JOIN comments ON comments.post_id = posts.id and + # LEFT OUTER JOIN authors ON authors.id = posts.author_id. Note that using conditions like this can have unintended consequences. + # In the above example posts with no approved comments are not returned at all, because the conditions apply to the SQL statement as a whole + # and not just to the association. You must disambiguate column references for this fallback to happen, for example + # :order => "author.name DESC" will work but :order => "name DESC" will not. + # + # If you do want eagerload only some members of an association it is usually more natural to :include an association + # which has conditions defined on it: + # + # class Post < ActiveRecord::Base + # has_many :approved_comments, :class_name => 'Comment', :conditions => ['approved = ?', true] + # end + # + # Post.find(:all, :include => :approved_comments) + # + # will load posts and eager load the +approved_comments+ association, which contains only those comments that have been approved. # # When eager loaded, conditions are interpolated in the context of the model class, not the model instance. Conditions are lazily interpolated # before the actual model exists. # - # Eager loading is not supported with polymorphic associations up to (and including) - # version 2.0.2. Given + # Eager loading is supported with polymorphic associations. # # class Address < ActiveRecord::Base # belongs_to :addressable, :polymorphic => true # end # - # a call that tries to eager load the addressable model - # - # Address.find(:all, :include => :addressable) # INVALID - # - # will raise ActiveRecord::EagerLoadPolymorphicError. The reason is that the parent model's type - # is a column value so its corresponding table name cannot be put in the +FROM+/+JOIN+ clauses of that early query. + # A call that tries to eager load the addressable model # - # In versions greater than 2.0.2 eager loading in polymorphic associations is supported - # thanks to a change in the overall preloading strategy. + # Address.find(:all, :include => :addressable) # - # It does work the other way around though: if the User model is addressable you can eager load - # their addresses with :include just fine, every piece needed to construct the query is known beforehand. + # will execute one query to load the addresses and load the addressables with one query per addressable type. + # For example if all the addressables are either of class Person or Company then a total of 3 queries will be executed. The list of + # addressable types to load is determined on the back of the addresses loaded. This is not supported if Active Record has to fallback + # to the previous implementation of eager loading and will raise ActiveRecord::EagerLoadPolymorphicError. The reason is that the parent + # model's type is a column value so its corresponding table name cannot be put in the +FROM+/+JOIN+ clauses of that query. # # == Table Aliasing # - # ActiveRecord uses table aliasing in the case that a table is referenced multiple times in a join. If a table is referenced only once, + # Active Record uses table aliasing in the case that a table is referenced multiple times in a join. If a table is referenced only once, # the standard table name is used. The second time, the table is aliased as #{reflection_name}_#{parent_table_name}. Indexes are appended # for any more successive uses of the table name. # - # Post.find :all, :include => :comments - # # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... - # Post.find :all, :include => :special_comments # STI - # # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... AND comments.type = 'SpecialComment' - # Post.find :all, :include => [:comments, :special_comments] # special_comments is the reflection name, posts is the parent table name - # # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... LEFT OUTER JOIN comments special_comments_posts + # Post.find :all, :joins => :comments + # # => SELECT ... FROM posts INNER JOIN comments ON ... + # Post.find :all, :joins => :special_comments # STI + # # => SELECT ... FROM posts INNER JOIN comments ON ... AND comments.type = 'SpecialComment' + # Post.find :all, :joins => [:comments, :special_comments] # special_comments is the reflection name, posts is the parent table name + # # => SELECT ... FROM posts INNER JOIN comments ON ... INNER JOIN comments special_comments_posts # # Acts as tree example: # - # TreeMixin.find :all, :include => :children - # # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ... - # TreeMixin.find :all, :include => {:children => :parent} # using cascading eager includes - # # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ... - # LEFT OUTER JOIN parents_mixins ... - # TreeMixin.find :all, :include => {:children => {:parent => :children}} - # # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ... - # LEFT OUTER JOIN parents_mixins ... - # LEFT OUTER JOIN mixins childrens_mixins_2 + # TreeMixin.find :all, :joins => :children + # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ... + # TreeMixin.find :all, :joins => {:children => :parent} + # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ... + # INNER JOIN parents_mixins ... + # TreeMixin.find :all, :joins => {:children => {:parent => :children}} + # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ... + # INNER JOIN parents_mixins ... + # INNER JOIN mixins childrens_mixins_2 # # Has and Belongs to Many join tables use the same idea, but add a _join suffix: # - # Post.find :all, :include => :categories - # # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ... - # Post.find :all, :include => {:categories => :posts} - # # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ... - # LEFT OUTER JOIN categories_posts posts_categories_join LEFT OUTER JOIN posts posts_categories - # Post.find :all, :include => {:categories => {:posts => :categories}} - # # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ... - # LEFT OUTER JOIN categories_posts posts_categories_join LEFT OUTER JOIN posts posts_categories - # LEFT OUTER JOIN categories_posts categories_posts_join LEFT OUTER JOIN categories categories_posts + # Post.find :all, :joins => :categories + # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ... + # Post.find :all, :joins => {:categories => :posts} + # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ... + # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories + # Post.find :all, :joins => {:categories => {:posts => :categories}} + # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ... + # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories + # INNER JOIN categories_posts categories_posts_join INNER JOIN categories categories_posts_2 # # If you wish to specify your own custom joins using a :joins option, those table names will take precedence over the eager associations: # - # Post.find :all, :include => :comments, :joins => "inner join comments ..." - # # => SELECT ... FROM posts LEFT OUTER JOIN comments_posts ON ... INNER JOIN comments ... - # Post.find :all, :include => [:comments, :special_comments], :joins => "inner join comments ..." - # # => SELECT ... FROM posts LEFT OUTER JOIN comments comments_posts ON ... - # LEFT OUTER JOIN comments special_comments_posts ... + # Post.find :all, :joins => :comments, :joins => "inner join comments ..." + # # => SELECT ... FROM posts INNER JOIN comments_posts ON ... INNER JOIN comments ... + # Post.find :all, :joins => [:comments, :special_comments], :joins => "inner join comments ..." + # # => SELECT ... FROM posts INNER JOIN comments comments_posts ON ... + # INNER JOIN comments special_comments_posts ... # INNER JOIN comments ... # # Table aliases are automatically truncated according to the maximum length of table identifiers according to the specific database. @@ -842,7 +853,6 @@ module ActiveRecord # this results in a counter with +NULL+ value, which will never increment. # Note: Specifying a counter cache will add it to that model's list of readonly attributes using +attr_readonly+. # * :include - Specify second-order associations that should be eager loaded when this object is loaded. - # Not allowed if the association is polymorphic. # * :polymorphic - Specify this association is a polymorphic association by passing +true+. # Note: If you've enabled the counter cache, then you may want to add the counter cache attribute # to the +attr_readonly+ list in the associated classes (e.g. class Post; attr_readonly :comments_count; end). @@ -942,7 +952,7 @@ module ActiveRecord # # Deprecated: Any additional fields added to the join table will be placed as attributes when pulling records out through # +has_and_belongs_to_many+ associations. Records returned from join tables with additional attributes will be marked as - # +ReadOnly+ (because we can't save changes to the additional attributes). It's strongly recommended that you upgrade any + # readonly (because we can't save changes to the additional attributes). It's strongly recommended that you upgrade any # associations with attributes to a real join model (see introduction). # # Adds the following methods for retrieval and query: diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 2f03197012..52d2a9864e 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -48,7 +48,7 @@ module ActiveRecord end end - # fetch first using SQL if possible + # Fetches the first one using SQL if possible. def first(*args) if fetch_first_or_last_using_find? args find(:first, *args) @@ -58,7 +58,7 @@ module ActiveRecord end end - # fetch last using SQL if possible + # Fetches the last one using SQL if possible. def last(*args) if fetch_first_or_last_using_find? args find(:last, *args) diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index f683669615..ebcf462f2e 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -34,7 +34,7 @@ module ActiveRecord def count(*args) column_name, options = @reflection.klass.send(:construct_count_options_from_args, *args) if @reflection.options[:uniq] - # This is needed because 'SELECT count(DISTINCT *)..' is not valid sql statement. + # This is needed because 'SELECT count(DISTINCT *)..' is not valid SQL statement. column_name = "#{@reflection.quoted_table_name}.#{@reflection.klass.primary_key}" if column_name == :all options.merge!(:distinct => true) end diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index d753778d52..fab16a4446 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -94,7 +94,7 @@ module ActiveRecord end # Checks whether the method is defined in the model or any of its subclasses - # that also derive from ActiveRecord. Raises DangerousAttributeError if the + # that also derive from Active Record. Raises DangerousAttributeError if the # method is defined by Active Record though. def instance_method_already_implemented?(method_name) method_name = method_name.to_s @@ -162,8 +162,8 @@ module ActiveRecord evaluate_attribute_method attr_name, "def #{attr_name}; unserialize_attribute('#{attr_name}'); end" end - # Defined for all datetime and timestamp attributes when time_zone_aware_attributes are enabled. - # This enhanced read method automatically converts the UTC time stored in the database to the time zone stored in Time.zone + # Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled. + # This enhanced read method automatically converts the UTC time stored in the database to the time zone stored in Time.zone. def define_read_method_for_time_zone_conversion(attr_name) method_body = <<-EOV def #{attr_name}(reload = false) @@ -176,7 +176,7 @@ module ActiveRecord evaluate_attribute_method attr_name, method_body end - # Define an attribute ? method. + # Defines a predicate method attr_name?. def define_question_method(attr_name) evaluate_attribute_method attr_name, "def #{attr_name}?; query_attribute('#{attr_name}'); end", "#{attr_name}?" end @@ -185,7 +185,7 @@ module ActiveRecord evaluate_attribute_method attr_name, "def #{attr_name}=(new_value);write_attribute('#{attr_name}', new_value);end", "#{attr_name}=" end - # Defined for all datetime and timestamp attributes when time_zone_aware_attributes are enabled. + # Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled. # This enhanced write method will automatically convert the time passed to it to the zone stored in Time.zone. def define_write_method_for_time_zone_conversion(attr_name) method_body = <<-EOV diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 5351f55200..c393128621 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -2,7 +2,7 @@ require 'yaml' require 'set' module ActiveRecord #:nodoc: - # Generic ActiveRecord exception class. + # Generic Active Record exception class. class ActiveRecordError < StandardError end @@ -30,19 +30,19 @@ module ActiveRecord #:nodoc: class SerializationTypeMismatch < ActiveRecordError end - # Raised when adapter not specified on connection (or configuration file config/database.yml misses adapter field). + # Raised when adapter not specified on connection (or configuration file config/database.yml misses adapter field). class AdapterNotSpecified < ActiveRecordError end - # Raised when ActiveRecord cannot find database adapter specified in config/database.yml or programmatically. + # Raised when Active Record cannot find database adapter specified in config/database.yml or programmatically. class AdapterNotFound < ActiveRecordError end - # Raised when connection to the database could not been established (for example when connection= is given a nil object). + # Raised when connection to the database could not been established (for example when connection= is given a nil object). class ConnectionNotEstablished < ActiveRecordError end - # Raised when ActiveRecord cannot find record by given id or set of ids. + # Raised when Active Record cannot find record by given id or set of ids. class RecordNotFound < ActiveRecordError end @@ -70,7 +70,7 @@ module ActiveRecord #:nodoc: # instantiation, for example, when two users edit the same wiki page and one starts editing and saves # the page before the other. # - # Read more about optimistic locking in +ActiveRecord::Locking+ module RDoc. + # Read more about optimistic locking in ActiveRecord::Locking module RDoc. class StaleObjectError < ActiveRecordError end @@ -83,12 +83,12 @@ module ActiveRecord #:nodoc: class ReadOnlyRecord < ActiveRecordError end - # Used by ActiveRecord transaction mechanism to distinguish rollback from other exceptional situations. + # Used by Active Record transaction mechanism to distinguish rollback from other exceptional situations. # You can use it to roll your transaction back explicitly in the block passed to +transaction+ method. class Rollback < ActiveRecordError end - # Raised when attribute has a name reserved by ActiveRecord (when attribute has name of one of ActiveRecord instance methods). + # Raised when attribute has a name reserved by Active Record (when attribute has name of one of Active Record instance methods). class DangerousAttributeError < ActiveRecordError end @@ -200,7 +200,7 @@ module ActiveRecord #:nodoc: # # All column values are automatically available through basic accessors on the Active Record object, but sometimes you # want to specialize this behavior. This can be done by overwriting the default accessors (using the same - # name as the attribute) and calling read_attribute(attr_name) and write_attribute(attr_name, value) to actually change things. + # name as the attribute) and calling read_attribute(attr_name) and write_attribute(attr_name, value) to actually change things. # Example: # # class Song < ActiveRecord::Base @@ -215,8 +215,8 @@ module ActiveRecord #:nodoc: # end # end # - # You can alternatively use self[:attribute]=(value) and self[:attribute] instead of write_attribute(:attribute, value) and - # read_attribute(:attribute) as a shorter form. + # You can alternatively use self[:attribute]=(value) and self[:attribute] instead of write_attribute(:attribute, value) and + # read_attribute(:attribute) as a shorter form. # # == Attribute query methods # @@ -236,7 +236,7 @@ module ActiveRecord #:nodoc: # # Sometimes you want to be able to read the raw attribute data without having the column-determined typecast run its course first. # That can be done by using the _before_type_cast accessors that all attributes have. For example, if your Account model - # has a balance attribute, you can call account.balance_before_type_cast or account.id_before_type_cast. + # has a balance attribute, you can call account.balance_before_type_cast or account.id_before_type_cast. # # This is especially useful in validation situations where the user might supply a string for an integer field and you want to display # the original string back in an error message. Accessing the attribute normally would typecast the string to 0, which isn't what you @@ -245,8 +245,8 @@ module ActiveRecord #:nodoc: # == Dynamic attribute-based finders # # Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects by simple queries without turning to SQL. They work by - # appending the name of an attribute to find_by_ or find_all_by_, so you get finders like Person.find_by_user_name, - # Person.find_all_by_last_name, Payment.find_by_transaction_id. So instead of writing + # appending the name of an attribute to find_by_ or find_all_by_, so you get finders like Person.find_by_user_name, + # Person.find_all_by_last_name, and Payment.find_by_transaction_id. So instead of writing # Person.find(:first, :conditions => ["user_name = ?", user_name]), you just do Person.find_by_user_name(user_name). # And instead of writing Person.find(:all, :conditions => ["last_name = ?", last_name]), you just do Person.find_all_by_last_name(last_name). # @@ -255,8 +255,8 @@ module ActiveRecord #:nodoc: # Person.find(:first, :conditions => ["user_name = ? AND password = ?", user_name, password]), you just do # Person.find_by_user_name_and_password(user_name, password). # - # It's even possible to use all the additional parameters to find. For example, the full interface for Payment.find_all_by_amount - # is actually Payment.find_all_by_amount(amount, options). And the full interface to Person.find_by_user_name is + # It's even possible to use all the additional parameters to find. For example, the full interface for Payment.find_all_by_amount + # is actually Payment.find_all_by_amount(amount, options). And the full interface to Person.find_by_user_name is # actually Person.find_by_user_name(user_name, options). So you could call Payment.find_all_by_amount(50, :order => "created_on"). # # The same dynamic finder style can be used to create the object if it doesn't already exist. This dynamic finder is called with @@ -316,8 +316,8 @@ module ActiveRecord #:nodoc: # class Client < Company; end # class PriorityClient < Client; end # - # When you do Firm.create(:name => "37signals"), this record will be saved in the companies table with type = "Firm". You can then - # fetch this row again using Company.find(:first, "name = '37signals'") and it will return a Firm object. + # When you do Firm.create(:name => "37signals"), this record will be saved in the companies table with type = "Firm". You can then + # fetch this row again using Company.find(:first, "name = '37signals'") and it will return a Firm object. # # If you don't have a type column defined in your table, single-table inheritance won't be triggered. In that case, it'll work just # like normal subclasses with no special magic for differentiating between them or reloading the right type with find. @@ -329,8 +329,8 @@ module ActiveRecord #:nodoc: # # Connections are usually created through ActiveRecord::Base.establish_connection and retrieved by ActiveRecord::Base.connection. # All classes inheriting from ActiveRecord::Base will use this connection. But you can also set a class-specific connection. - # For example, if Course is an ActiveRecord::Base, but resides in a different database, you can just say Course.establish_connection - # and Course *and all its subclasses* will use this connection instead. + # For example, if Course is an ActiveRecord::Base, but resides in a different database, you can just say Course.establish_connection + # and Course and all of its subclasses will use this connection instead. # # This feature is implemented by keeping a connection pool in ActiveRecord::Base that is a Hash indexed by the class. If a connection is # requested, the retrieve_connection method will go up the class-hierarchy until a connection is found in the connection pool. @@ -407,7 +407,7 @@ module ActiveRecord #:nodoc: @@table_name_suffix = "" # Indicates whether table names should be the pluralized versions of the corresponding class names. - # If true, the default table name for a +Product+ class will be +products+. If false, it would just be +product+. + # If true, the default table name for a Product class will be +products+. If false, it would just be +product+. # See table_name for the full rules on table/class naming. This is true, by default. cattr_accessor :pluralize_table_names, :instance_writer => false @@pluralize_table_names = true @@ -446,36 +446,44 @@ module ActiveRecord #:nodoc: class << self # Class methods # Find operates with four different retrieval approaches: # - # * Find by id: This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]). + # * Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]). # If no record can be found for all of the listed ids, then RecordNotFound will be raised. - # * Find first: This will return the first record matched by the options used. These options can either be specific - # conditions or merely an order. If no record can be matched, nil is returned. - # * Find last: This will return the last record matched by the options used. These options can either be specific - # conditions or merely an order. If no record can be matched, nil is returned. - # * Find all: This will return all the records matched by the options used. If no records are found, an empty array is returned. - # - # All approaches accept an options hash as their last parameter. The options are: - # - # * :conditions: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro. - # * :order: An SQL fragment like "created_at DESC, name". - # * :group: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause. - # * :limit: An integer determining the limit on the number of rows that should be returned. - # * :offset: An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4. - # * :joins: Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed) - # or named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s). + # * Find first - This will return the first record matched by the options used. These options can either be specific + # conditions or merely an order. If no record can be matched, +nil+ is returned. Use + # Model.find(:first, *args) or its shortcut Model.first(*args). + # * Find last - This will return the last record matched by the options used. These options can either be specific + # conditions or merely an order. If no record can be matched, +nil+ is returned. Use + # Model.find(:last, *args) or its shortcut Model.last(*args). + # * Find all - This will return all the records matched by the options used. + # If no records are found, an empty array is returned. Use + # Model.find(:all, *args) or its shortcut Model.all(*args). + # + # All approaches accept an options hash as their last parameter. + # + # ==== Attributes + # + # * :conditions - An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro. + # * :order - An SQL fragment like "created_at DESC, name". + # * :group - An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause. + # * :limit - An integer determining the limit on the number of rows that should be returned. + # * :offset - An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4. + # * :joins - Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed) + # or named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s). # If the value is a string, then the records will be returned read-only since they will have attributes that do not correspond to the table's columns. # Pass :readonly => false to override. - # * :include: Names associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer + # * :include - Names associations that should be loaded alongside. The symbols named refer # to already defined associations. See eager loading under Associations. - # * :select: By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join but not + # * :select - By default, this is "*" as in "SELECT * FROM", but can be changed if you, for example, want to do a join but not # include the joined columns. - # * :from: By default, this is the table name of the class, but can be changed to an alternate table name (or even the name + # * :from - By default, this is the table name of the class, but can be changed to an alternate table name (or even the name # of a database view). - # * :readonly: Mark the returned records read-only so they cannot be saved or updated. - # * :lock: An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE". + # * :readonly - Mark the returned records read-only so they cannot be saved or updated. + # * :lock - An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE". # :lock => true gives connection's default exclusive lock, usually "FOR UPDATE". # - # Examples for find by id: + # ==== Examples + # + # # find by id # Person.find(1) # returns the object for ID = 1 # Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6) # Person.find([7, 17]) # returns an array for objects with IDs in (7, 17) @@ -486,17 +494,19 @@ module ActiveRecord #:nodoc: # provide since database rows are unordered. Give an explicit :order # to ensure the results are sorted. # - # Examples for find first: + # ==== Examples + # + # # find first # Person.find(:first) # returns the first object fetched by SELECT * FROM people # Person.find(:first, :conditions => [ "user_name = ?", user_name]) # Person.find(:first, :order => "created_on DESC", :offset => 5) # - # Examples for find last: + # # find last # Person.find(:last) # returns the last object fetched by SELECT * FROM people # Person.find(:last, :conditions => [ "user_name = ?", user_name]) # Person.find(:last, :order => "created_on DESC", :offset => 5) # - # Examples for find all: + # # find all # Person.find(:all) # returns an array of objects for all the rows fetched by SELECT * FROM people # Person.find(:all, :conditions => [ "category IN (?)", categories], :limit => 50) # Person.find(:all, :conditions => { :friends => ["Bob", "Steve", "Fred"] } @@ -504,11 +514,12 @@ module ActiveRecord #:nodoc: # Person.find(:all, :include => [ :account, :friends ]) # Person.find(:all, :group => "category") # - # Example for find with a lock. Imagine two concurrent transactions: - # each will read person.visits == 2, add 1 to it, and save, resulting - # in two saves of person.visits = 3. By locking the row, the second + # Example for find with a lock: Imagine two concurrent transactions: + # each will read person.visits == 2, add 1 to it, and save, resulting + # in two saves of person.visits = 3. By locking the row, the second # transaction has to wait until the first is finished; we get the - # expected person.visits == 4. + # expected person.visits == 4. + # # Person.transaction do # person = Person.find(1, :lock => true) # person.visits += 1 @@ -527,14 +538,14 @@ module ActiveRecord #:nodoc: end end - # This is an alias for find(:first). You can pass in all the same arguments to this method as you can - # to find(:first) + # A convenience wrapper for find(:first, *args). You can pass in all the + # same arguments to this method as you can to find(:first). def first(*args) find(:first, *args) end - # This is an alias for find(:last). You can pass in all the same arguments to this method as you can - # to find(:last) + # A convenience wrapper for find(:last, *args). You can pass in all the + # same arguments to this method as you can to find(:last). def last(*args) find(:last, *args) end @@ -545,8 +556,7 @@ module ActiveRecord #:nodoc: find(:all, *args) end - # - # Executes a custom sql query against your database and returns all the results. The results will + # Executes a custom SQL query against your database and returns all the results. The results will # be returned as an array with columns requested encapsulated as attributes of the model you call # this method from. If you call +Product.find_by_sql+ then the results will be returned in a Product # object with the attributes you specified in the SQL query. @@ -555,13 +565,13 @@ module ActiveRecord #:nodoc: # SELECT will be attributes of the model, whether or not they are columns of the corresponding # table. # - # The +sql+ parameter is a full sql query as a string. It will be called as is, there will be + # The +sql+ parameter is a full SQL query as a string. It will be called as is, there will be # no database agnostic conversions performed. This should be a last resort because using, for example, # MySQL specific terms will lock you to using that particular database engine or require you to # change your call if you switch engines # # ==== Examples - # # A simple sql query spanning multiple tables + # # A simple SQL query spanning multiple tables # Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id" # > [#"Ruby Meetup", "first_name"=>"Quentin"}>, ...] # @@ -860,9 +870,15 @@ module ActiveRecord #:nodoc: end - # Attributes named in this macro are protected from mass-assignment, such as new(attributes) and - # attributes=(attributes). Their assignment will simply be ignored. Instead, you can use the direct writer - # methods to do assignment. This is meant to protect sensitive attributes from being overwritten by URL/form hackers. Example: + # Attributes named in this macro are protected from mass-assignment, + # such as new(attributes), + # update_attributes(attributes), or + # attributes=(attributes). + # + # Mass-assignment to these attributes will simply be ignored, to assign + # to them you can use direct writer methods. This is meant to protect + # sensitive attributes from being overwritten by malicious users + # tampering with URLs or forms. # # class Customer < ActiveRecord::Base # attr_protected :credit_rating @@ -876,7 +892,8 @@ module ActiveRecord #:nodoc: # customer.credit_rating = "Average" # customer.credit_rating # => "Average" # - # To start from an all-closed default and enable attributes as needed, have a look at attr_accessible. + # To start from an all-closed default and enable attributes as needed, + # have a look at +attr_accessible+. def attr_protected(*attributes) write_inheritable_attribute("attr_protected", Set.new(attributes.map(&:to_s)) + (protected_attributes || [])) end @@ -886,19 +903,18 @@ module ActiveRecord #:nodoc: read_inheritable_attribute("attr_protected") end - # Similar to the attr_protected macro, this protects attributes of your model from mass-assignment, - # such as new(attributes) and attributes=(attributes) - # however, it does it in the opposite way. This locks all attributes and only allows access to the - # attributes specified. Assignment to attributes not in this list will be ignored and need to be set - # using the direct writer methods instead. This is meant to protect sensitive attributes from being - # overwritten by URL/form hackers. If you'd rather start from an all-open default and restrict - # attributes as needed, have a look at attr_protected. - # - # ==== Attributes - # - # * *attributes A comma separated list of symbols that represent columns _not_ to be protected + # Specifies a white list of model attributes that can be set via + # mass-assignment, such as new(attributes), + # update_attributes(attributes), or + # attributes=(attributes) # - # ==== Examples + # This is the opposite of the +attr_protected+ macro: Mass-assignment + # will only set attributes in this list, to assign to the rest of + # attributes you can use direct writer methods. This is meant to protect + # sensitive attributes from being overwritten by malicious users + # tampering with URLs or forms. If you'd rather start from an all-open + # default and restrict attributes as needed, have a look at + # +attr_protected+. # # class Customer < ActiveRecord::Base # attr_accessible :name, :nickname @@ -933,7 +949,7 @@ module ActiveRecord #:nodoc: # If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object, # then specify the name of that attribute using this method and it will be handled automatically. # The serialization is done through YAML. If +class_name+ is specified, the serialized object must be of that - # class on retrieval or +SerializationTypeMismatch+ will be raised. + # class on retrieval or SerializationTypeMismatch will be raised. # # ==== Attributes # @@ -956,12 +972,14 @@ module ActiveRecord #:nodoc: # Guesses the table name (in forced lower-case) based on the name of the class in the inheritance hierarchy descending - # directly from ActiveRecord. So if the hierarchy looks like: Reply < Message < ActiveRecord, then Message is used + # directly from ActiveRecord::Base. So if the hierarchy looks like: Reply < Message < ActiveRecord::Base, then Message is used # to guess the table name even when called on Reply. The rules used to do the guess are handled by the Inflector class # in Active Support, which knows almost all common English inflections. You can add new inflections in config/initializers/inflections.rb. # # Nested classes are given table names prefixed by the singular form of - # the parent's table name. Enclosing modules are not considered. Examples: + # the parent's table name. Enclosing modules are not considered. + # + # ==== Examples # # class Invoice < ActiveRecord::Base; end; # file class table_name @@ -975,8 +993,8 @@ module ActiveRecord #:nodoc: # file class table_name # invoice/lineitem.rb Invoice::Lineitem lineitems # - # Additionally, the class-level table_name_prefix is prepended and the - # table_name_suffix is appended. So if you have "myapp_" as a prefix, + # Additionally, the class-level +table_name_prefix+ is prepended and the + # +table_name_suffix+ is appended. So if you have "myapp_" as a prefix, # the table name guess for an Invoice class becomes "myapp_invoices". # Invoice::Lineitem becomes "myapp_invoice_lineitems". # @@ -1055,8 +1073,6 @@ module ActiveRecord #:nodoc: # Sets the table name to use to the given value, or (if the value # is nil or false) to the value returned by the given block. # - # Example: - # # class Project < ActiveRecord::Base # set_table_name "project" # end @@ -1069,8 +1085,6 @@ module ActiveRecord #:nodoc: # or (if the value is nil or false) to the value returned by the given # block. # - # Example: - # # class Project < ActiveRecord::Base # set_primary_key "sysid" # end @@ -1083,8 +1097,6 @@ module ActiveRecord #:nodoc: # or (if the value # is nil or false) to the value returned by the # given block. # - # Example: - # # class Project < ActiveRecord::Base # set_inheritance_column do # original_inheritance_column + "_id" @@ -1106,8 +1118,6 @@ module ActiveRecord #:nodoc: # If a sequence name is not explicitly set when using PostgreSQL, it # will discover the sequence corresponding to your primary key for you. # - # Example: - # # class Project < ActiveRecord::Base # set_sequence_name "projectseq" # default would have been "project_seq" # end @@ -1267,7 +1277,7 @@ module ActiveRecord #:nodoc: class_of_active_record_descendant(self) end - # Set this to true if this is an abstract class (see #abstract_class?). + # Set this to true if this is an abstract class (see abstract_class?). attr_accessor :abstract_class # Returns whether this class is a base AR class. If A is a base class and @@ -1714,8 +1724,8 @@ module ActiveRecord #:nodoc: end - # Defines an "attribute" method (like #inheritance_column or - # #table_name). A new (class) method will be created with the + # Defines an "attribute" method (like +inheritance_column+ or + # +table_name+). A new (class) method will be created with the # given name. If a value is specified, the new method will # return that value (as a string). Otherwise, the given block # will be used to compute the value of the method. @@ -1892,7 +1902,7 @@ module ActiveRecord #:nodoc: end end - # Returns the class descending directly from ActiveRecord in the inheritance hierarchy. + # Returns the class descending directly from Active Record in the inheritance hierarchy. def class_of_active_record_descendant(klass) if klass.superclass == Base || klass.superclass.abstract_class? klass @@ -1903,12 +1913,12 @@ module ActiveRecord #:nodoc: end end - # Returns the name of the class descending directly from ActiveRecord in the inheritance hierarchy. + # Returns the name of the class descending directly from Active Record in the inheritance hierarchy. def class_name_of_active_record_descendant(klass) #:nodoc: klass.base_class.name end - # Accepts an array, hash, or string of sql conditions and sanitizes + # Accepts an array, hash, or string of SQL conditions and sanitizes # them into a valid SQL fragment for a WHERE clause. # ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'" # { :name => "foo'bar", :group_id => 4 } returns "name='foo''bar' and group_id='4'" @@ -1924,7 +1934,7 @@ module ActiveRecord #:nodoc: end alias_method :sanitize_sql, :sanitize_sql_for_conditions - # Accepts an array, hash, or string of sql conditions and sanitizes + # Accepts an array, hash, or string of SQL conditions and sanitizes # them into a valid SQL fragment for a SET clause. # { :name => nil, :group_id => 4 } returns "name = NULL , group_id='4'" def sanitize_sql_for_assignment(assignments) @@ -1940,7 +1950,7 @@ module ActiveRecord #:nodoc: mapping.first.is_a?(Array) ? mapping : [mapping] end - # Accepts a hash of sql conditions and replaces those attributes + # Accepts a hash of SQL conditions and replaces those attributes # that correspond to a +composed_of+ relationship with their expanded # aggregate attribute values. # Given: @@ -2013,7 +2023,7 @@ module ActiveRecord #:nodoc: end # Accepts an array of conditions. The array has each value - # sanitized and interpolated into the sql statement. + # sanitized and interpolated into the SQL statement. # ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'" def sanitize_sql_array(ary) statement, *values = ary @@ -2134,7 +2144,9 @@ module ActiveRecord #:nodoc: (id = self.id) ? id.to_s : nil # Be sure to stringify the id for routes end - # Returns a cache key that can be used to identify this record. Examples: + # Returns a cache key that can be used to identify this record. + # + # ==== Examples # # Product.new.cache_key # => "products/new" # Product.find(5).cache_key # => "products/5" (updated_at not available) @@ -2490,9 +2502,9 @@ module ActiveRecord #:nodoc: id end - # Sets the attribute used for single table inheritance to this class name if this is not the ActiveRecord descendent. - # Considering the hierarchy Reply < Message < ActiveRecord, this makes it possible to do Reply.new without having to - # set Reply[Reply.inheritance_column] = "Reply" yourself. No such attribute would be set for objects of the + # Sets the attribute used for single table inheritance to this class name if this is not the ActiveRecord::Base descendent. + # Considering the hierarchy Reply < Message < ActiveRecord::Base, this makes it possible to do Reply.new without having to + # set Reply[Reply.inheritance_column] = "Reply" yourself. No such attribute would be set for objects of the # Message class in that example. def ensure_proper_type unless self.class.descends_from_active_record? @@ -2564,7 +2576,7 @@ module ActiveRecord #:nodoc: self.class.connection.quote(value, column) end - # Interpolate custom sql string in instance context. + # Interpolate custom SQL string in instance context. # Optional record argument is meant for custom insert_sql. def interpolate_sql(sql, record = nil) instance_eval("%@#{sql.gsub('@', '\@')}@") diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb index 3c5caefe3b..10e8330d1c 100644 --- a/activerecord/lib/active_record/calculations.rb +++ b/activerecord/lib/active_record/calculations.rb @@ -46,28 +46,28 @@ module ActiveRecord calculate(:count, *construct_count_options_from_args(*args)) end - # Calculates the average value on a given column. The value is returned as a float. See #calculate for examples with options. + # Calculates the average value on a given column. The value is returned as a float. See +calculate+ for examples with options. # # Person.average('age') def average(column_name, options = {}) calculate(:avg, column_name, options) end - # Calculates the minimum value on a given column. The value is returned with the same data type of the column. See #calculate for examples with options. + # Calculates the minimum value on a given column. The value is returned with the same data type of the column. See +calculate+ for examples with options. # # Person.minimum('age') def minimum(column_name, options = {}) calculate(:min, column_name, options) end - # Calculates the maximum value on a given column. The value is returned with the same data type of the column. See #calculate for examples with options. + # Calculates the maximum value on a given column. The value is returned with the same data type of the column. See +calculate+ for examples with options. # # Person.maximum('age') def maximum(column_name, options = {}) calculate(:max, column_name, options) end - # Calculates the sum of values on a given column. The value is returned with the same data type of the column. See #calculate for examples with options. + # Calculates the sum of values on a given column. The value is returned with the same data type of the column. See +calculate+ for examples with options. # # Person.sum('age') def sum(column_name, options = {}) @@ -245,12 +245,14 @@ module ActiveRecord options.assert_valid_keys(CALCULATIONS_OPTIONS) end - # Converts a given key to the value that the database adapter returns as - # a usable column name. - # users.id #=> users_id - # sum(id) #=> sum_id - # count(distinct users.id) #=> count_distinct_users_id - # count(*) #=> count_all + # Converts the given keys to the value that the database adapter returns as + # a usable column name: + # + # column_alias_for("users.id") # => "users_id" + # column_alias_for("sum(id)") # => "sum_id" + # column_alias_for("count(distinct users.id)") # => "count_distinct_users_id" + # column_alias_for("count(*)") # => "count_all" + # column_alias_for("count", "id") # => "count_id" def column_alias_for(*keys) connection.table_alias_for(keys.join(' ').downcase.gsub(/\*/, 'all').gsub(/\W+/, ' ').strip.gsub(/ +/, '_')) end diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb index a469af682b..41ec5c5e61 100755 --- a/activerecord/lib/active_record/callbacks.rb +++ b/activerecord/lib/active_record/callbacks.rb @@ -161,7 +161,7 @@ module ActiveRecord # == before_validation* returning statements # # If the returning value of a +before_validation+ callback can be evaluated to +false+, the process will be aborted and Base#save will return +false+. - # If Base#save! is called it will raise a +RecordNotSaved+ exception. + # If Base#save! is called it will raise a RecordNotSaved exception. # Nothing will be appended to the errors object. # # == Canceling callbacks diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb index 34627dfaf9..2a8807fb78 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb @@ -193,7 +193,7 @@ module ActiveRecord # :database => "path/to/dbfile" # ) # - # Also accepts keys as strings (for parsing from yaml for example): + # Also accepts keys as strings (for parsing from YAML for example): # # ActiveRecord::Base.establish_connection( # "adapter" => "sqlite", diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index 589acd3945..16d405d3bd 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -29,7 +29,7 @@ module ActiveRecord end # Returns an array of arrays containing the field values. - # Order is the same as that returned by #columns. + # Order is the same as that returned by +columns+. def select_rows(sql, name = nil) raise NotImplementedError, "select_rows is an abstract method" end @@ -93,7 +93,7 @@ module ActiveRecord # done if the transaction block raises an exception or returns false. def rollback_db_transaction() end - # Alias for #add_limit_offset!. + # Alias for add_limit_offset!. def add_limit!(sql, options) add_limit_offset!(sql, options) if options end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index fdb18b234c..f968b9b173 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -16,9 +16,9 @@ module ActiveRecord # Instantiates a new column in the table. # - # +name+ is the column's name, as in supplier_id int(11). - # +default+ is the type-casted default value, such as sales_stage varchar(20) default 'new'. - # +sql_type+ is only used to extract the column's length, if necessary. For example, company_name varchar(60). + # +name+ is the column's name, such as supplier_id in supplier_id int(11). + # +default+ is the type-casted default value, such as +new+ in sales_stage varchar(20) default 'new'. + # +sql_type+ is only used to extract the column's length, if necessary. For example +60+ in company_name varchar(60). # +null+ determines if this column allows +NULL+ values. def initialize(name, default, sql_type = nil, null = true) @name, @sql_type, @null = name, sql_type, null @@ -92,7 +92,7 @@ module ActiveRecord # Returns the human name of the column name. # # ===== Examples - # Column.new('sales_stage', ...).human_name #=> 'Sales stage' + # Column.new('sales_stage', ...).human_name # => 'Sales stage' def human_name Base.human_attribute_name(@name) end @@ -270,7 +270,7 @@ module ActiveRecord end # Represents a SQL table in an abstract way. - # Columns are stored as a ColumnDefinition in the #columns attribute. + # Columns are stored as a ColumnDefinition in the +columns+ attribute. class TableDefinition attr_accessor :columns @@ -350,28 +350,28 @@ module ActiveRecord # == Examples # # Assuming td is an instance of TableDefinition # td.column(:granted, :boolean) - # #=> granted BOOLEAN + # # granted BOOLEAN # # td.column(:picture, :binary, :limit => 2.megabytes) - # #=> picture BLOB(2097152) + # # => picture BLOB(2097152) # # td.column(:sales_stage, :string, :limit => 20, :default => 'new', :null => false) - # #=> sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL + # # => sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL # - # def.column(:bill_gates_money, :decimal, :precision => 15, :scale => 2) - # #=> bill_gates_money DECIMAL(15,2) + # td.column(:bill_gates_money, :decimal, :precision => 15, :scale => 2) + # # => bill_gates_money DECIMAL(15,2) # - # def.column(:sensor_reading, :decimal, :precision => 30, :scale => 20) - # #=> sensor_reading DECIMAL(30,20) + # td.column(:sensor_reading, :decimal, :precision => 30, :scale => 20) + # # => sensor_reading DECIMAL(30,20) # # # While :scale defaults to zero on most databases, it # # probably wouldn't hurt to include it. - # def.column(:huge_integer, :decimal, :precision => 30) - # #=> huge_integer DECIMAL(30) + # td.column(:huge_integer, :decimal, :precision => 30) + # # => huge_integer DECIMAL(30) # # == Short-hand examples # - # Instead of calling column directly, you can also work with the short-hand definitions for the default types. + # Instead of calling +column+ directly, you can also work with the short-hand definitions for the default types. # They use the type as the method name instead of as a parameter and allow for multiple columns to be defined # in a single statement. # @@ -395,7 +395,7 @@ module ActiveRecord # end # # There's a short-hand method for each of the type values declared at the top. And then there's - # TableDefinition#timestamps that'll add created_at and updated_at as datetimes. + # TableDefinition#timestamps that'll add created_at and +updated_at+ as datetimes. # # TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type # column if the :polymorphic option is supplied. If :polymorphic is a hash of options, these will be diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index b57d0a3ef7..67d70b3886 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -32,7 +32,7 @@ module ActiveRecord def columns(table_name, name = nil) end # Creates a new table - # There are two ways to work with #create_table. You can use the block + # There are two ways to work with +create_table+. You can use the block # form or the regular form, like this: # # === Block form diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 2ec2d80af4..7dbfbb41f6 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -776,7 +776,7 @@ module ActiveRecord # Returns an ORDER BY clause for the passed order option. # # PostgreSQL does not allow arbitrary ordering when using DISTINCT ON, so we work around this - # by wrapping the sql as a sub-select and ordering in that query. + # by wrapping the +sql+ string as a sub-select and ordering in that query. def add_order_by_for_association_limiting!(sql, options) #:nodoc: return sql if options[:order].blank? diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index ac06cdbe43..c4cbe5d52f 100755 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -33,8 +33,8 @@ end # # Unlike single-file fixtures, YAML fixtures are stored in a single file per model, which are placed in the directory appointed # by ActiveSupport::TestCase.fixture_path=(path) (this is automatically configured for Rails, so you can just -# put your files in /test/fixtures/). The fixture file ends with the .yml file extension (Rails example: -# "/test/fixtures/web_sites.yml"). The format of a YAML fixture file looks like this: +# put your files in /test/fixtures/). The fixture file ends with the .yml file extension (Rails example: +# /test/fixtures/web_sites.yml). The format of a YAML fixture file looks like this: # # rubyonrails: # id: 1 @@ -67,7 +67,8 @@ end # = CSV fixtures # # Fixtures can also be kept in the Comma Separated Value format. Akin to YAML fixtures, CSV fixtures are stored -# in a single file, but instead end with the .csv file extension (Rails example: "/test/fixtures/web_sites.csv") +# in a single file, but instead end with the .csv file extension +# (Rails example: /test/fixtures/web_sites.csv). # # The format of this type of fixture file is much more compact than the others, but also a little harder to read by us # humans. The first line of the CSV file is a comma-separated list of field names. The rest of the file is then comprised @@ -93,11 +94,11 @@ end # This type of fixture was the original format for Active Record that has since been deprecated in favor of the YAML and CSV formats. # Fixtures for this format are created by placing text files in a sub-directory (with the name of the model) to the directory # appointed by ActiveSupport::TestCase.fixture_path=(path) (this is automatically configured for Rails, so you can just -# put your files in /test/fixtures// -- like /test/fixtures/web_sites/ for the WebSite -# model). +# put your files in /test/fixtures// -- +# like /test/fixtures/web_sites/ for the WebSite model). # # Each text file placed in this directory represents a "record". Usually these types of fixtures are named without -# extensions, but if you are on a Windows machine, you might consider adding .txt as the extension. Here's what the +# extensions, but if you are on a Windows machine, you might consider adding .txt as the extension. Here's what the # above example might look like: # # web_sites/google @@ -138,20 +139,20 @@ end # # In addition to being available in the database, the fixtures are also loaded into a hash stored in an instance variable # of the test case. It is named after the symbol... so, in our example, there would be a hash available called -# @web_sites. This is where the "fixture name" comes into play. +# @web_sites. This is where the "fixture name" comes into play. # -# On top of that, each record is automatically "found" (using Model.find(id)) and placed in the instance variable of its name. -# So for the YAML fixtures, we'd get @rubyonrails and @google, which could be interrogated using regular Active Record semantics: +# On top of that, each record is automatically "found" (using Model.find(id)) and placed in the instance variable of its name. +# So for the YAML fixtures, we'd get @rubyonrails and @google, which could be interrogated using regular Active Record semantics: # # # test if the object created from the fixture data has the same attributes as the data itself # def test_find # assert_equal @web_sites["rubyonrails"]["name"], @rubyonrails.name # end # -# As seen above, the data hash created from the YAML fixtures would have @web_sites["rubyonrails"]["url"] return -# "http://www.rubyonrails.org" and @web_sites["google"]["name"] would return "Google". The same fixtures, but loaded -# from a CSV fixture file, would be accessible via @web_sites["web_site_1"]["name"] == "Ruby on Rails" and have the individual -# fixtures available as instance variables @web_site_1 and @web_site_2. +# As seen above, the data hash created from the YAML fixtures would have @web_sites["rubyonrails"]["url"] return +# "http://www.rubyonrails.org" and @web_sites["google"]["name"] would return "Google". The same fixtures, but loaded +# from a CSV fixture file, would be accessible via @web_sites["web_site_1"]["name"] == "Ruby on Rails" and have the individual +# fixtures available as instance variables @web_site_1 and @web_site_2. # # If you do not wish to use instantiated fixtures (usually for performance reasons) there are two options. # @@ -184,7 +185,7 @@ end # # This will create 1000 very simple YAML fixtures. # -# Using ERb, you can also inject dynamic values into your fixtures with inserts like <%= Date.today.strftime("%Y-%m-%d") %>. +# Using ERb, you can also inject dynamic values into your fixtures with inserts like <%= Date.today.strftime("%Y-%m-%d") %>. # This is however a feature to be used with some caution. The point of fixtures are that they're stable units of predictable # sample data. If you feel that you need to inject dynamic values, then perhaps you should reexamine whether your application # is properly testable. Hence, dynamic values in fixtures are to be considered a code smell. @@ -257,7 +258,7 @@ end # reginald: # generated id: 324201669 # name: Reginald the Pirate # -# ActiveRecord looks at the fixture's model class, discovers the correct +# Active Record looks at the fixture's model class, discovers the correct # primary key, and generates it right before inserting the fixture # into the database. # @@ -267,7 +268,7 @@ end # == Label references for associations (belongs_to, has_one, has_many) # # Specifying foreign keys in fixtures can be very fragile, not to -# mention difficult to read. Since ActiveRecord can figure out the ID of +# mention difficult to read. Since Active Record can figure out the ID of # any fixture from its label, you can specify FK's by label instead of ID. # # === belongs_to @@ -304,15 +305,15 @@ end # name: George the Monkey # pirate: reginald # -# Pow! All is made clear. ActiveRecord reflects on the fixture's model class, +# Pow! All is made clear. Active Record reflects on the fixture's model class, # finds all the +belongs_to+ associations, and allows you to specify # a target *label* for the *association* (monkey: george) rather than -# a target *id* for the *FK* (monkey_id: 1). +# a target *id* for the *FK* (monkey_id: 1). # # ==== Polymorphic belongs_to # # Supporting polymorphic relationships is a little bit more complicated, since -# ActiveRecord needs to know what type your association is pointing at. Something +# Active Record needs to know what type your association is pointing at. Something # like this should look familiar: # # ### in fruit.rb @@ -332,7 +333,7 @@ end # apple: # eater: george (Monkey) # -# Just provide the polymorphic target type and ActiveRecord will take care of the rest. +# Just provide the polymorphic target type and Active Record will take care of the rest. # # === has_and_belongs_to_many # @@ -395,15 +396,15 @@ end # # Zap! No more fruits_monkeys.yml file. We've specified the list of fruits # on George's fixture, but we could've just as easily specified a list -# of monkeys on each fruit. As with +belongs_to+, ActiveRecord reflects on +# of monkeys on each fruit. As with +belongs_to+, Active Record reflects on # the fixture's model class and discovers the +has_and_belongs_to_many+ # associations. # # == Autofilled timestamp columns # -# If your table/model specifies any of ActiveRecord's -# standard timestamp columns (created_at, created_on, updated_at, updated_on), -# they will automatically be set to Time.now. +# If your table/model specifies any of Active Record's +# standard timestamp columns (+created_at+, +created_on+, +updated_at+, +updated_on+), +# they will automatically be set to Time.now. # # If you've set specific values, they'll be left alone. # diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index 65f88cfdc7..c66034d18b 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -107,20 +107,20 @@ module ActiveRecord end # Is optimistic locking enabled for this table? Returns true if the - # #lock_optimistically flag is set to true (which it is, by default) - # and the table includes the #locking_column column (defaults to - # lock_version). + # +lock_optimistically+ flag is set to true (which it is, by default) + # and the table includes the +locking_column+ column (defaults to + # +lock_version+). def locking_enabled? lock_optimistically && columns_hash[locking_column] end - # Set the column to use for optimistic locking. Defaults to lock_version. + # Set the column to use for optimistic locking. Defaults to +lock_version+. def set_locking_column(value = nil, &block) define_attr_method :locking_column, value, &block value end - # The version column used for optimistic locking. Defaults to lock_version. + # The version column used for optimistic locking. Defaults to +lock_version+. def locking_column reset_locking_column end @@ -130,12 +130,12 @@ module ActiveRecord connection.quote_column_name(locking_column) end - # Reset the column used for optimistic locking back to the lock_version default. + # Reset the column used for optimistic locking back to the +lock_version+ default. def reset_locking_column set_locking_column DEFAULT_LOCKING_COLUMN end - # make sure the lock version column gets updated when counters are + # Make sure the lock version column gets updated when counters are # updated. def update_counters_with_lock(id, counters) counters = counters.merge(locking_column => 1) if locking_enabled? diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 5cc9f4e197..b47b01e99a 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -208,7 +208,7 @@ module ActiveRecord # # You can quiet them down by setting ActiveRecord::Migration.verbose = false. # - # You can also insert your own messages and benchmarks by using the #say_with_time + # You can also insert your own messages and benchmarks by using the +say_with_time+ # method: # # def self.up @@ -377,7 +377,7 @@ module ActiveRecord end def proper_table_name(name) - # Use the ActiveRecord objects own table_name, or pre/suffix from ActiveRecord::Base if name is a symbol/string + # Use the Active Record objects own table_name, or pre/suffix from ActiveRecord::Base if name is a symbol/string name.table_name rescue "#{ActiveRecord::Base.table_name_prefix}#{name}#{ActiveRecord::Base.table_name_suffix}" end end diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index c7cf1731c1..69b7da7700 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -2,9 +2,7 @@ module ActiveRecord module NamedScope # All subclasses of ActiveRecord::Base have two named_scopes: # * all, which is similar to a find(:all) query, and - # * scoped, which allows for the creation of anonymous scopes, on the fly: - # - # Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions) + # * scoped, which allows for the creation of anonymous scopes, on the fly: Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions) # # These anonymous scopes tend to be useful when procedurally generating complex queries, where passing # intermediate values (scopes) around as first-class objects is convenient. @@ -41,7 +39,7 @@ module ActiveRecord # Nested finds and calculations also work with these compositions: Shirt.red.dry_clean_only.count returns the number of garments # for which these criteria obtain. Similarly with Shirt.red.dry_clean_only.average(:thread_count). # - # All scopes are available as class methods on the ActiveRecord descendent upon which the scopes were defined. But they are also available to + # All scopes are available as class methods on the ActiveRecord::Base descendent upon which the scopes were defined. But they are also available to # has_many associations. If, # # class Person < ActiveRecord::Base diff --git a/activerecord/lib/active_record/observer.rb b/activerecord/lib/active_record/observer.rb index 2b0728fc25..6e55e36b7d 100644 --- a/activerecord/lib/active_record/observer.rb +++ b/activerecord/lib/active_record/observer.rb @@ -19,7 +19,7 @@ module ActiveRecord # # Same as above, just using explicit class references # ActiveRecord::Base.observers = Cacher, GarbageCollector # - # Note: Setting this does not instantiate the observers yet. #instantiate_observers is + # Note: Setting this does not instantiate the observers yet. +instantiate_observers+ is # called during startup, and before each development request. def observers=(*observers) @observers = observers.flatten @@ -30,7 +30,7 @@ module ActiveRecord @observers ||= [] end - # Instantiate the global ActiveRecord observers + # Instantiate the global Active Record observers. def instantiate_observers return if @observers.blank? @observers.each do |observer| diff --git a/activerecord/lib/active_record/schema.rb b/activerecord/lib/active_record/schema.rb index d6b254fcf9..8a32cf1ca2 100644 --- a/activerecord/lib/active_record/schema.rb +++ b/activerecord/lib/active_record/schema.rb @@ -30,8 +30,8 @@ module ActiveRecord # Eval the given block. All methods available to the current connection # adapter are available within the block, so you can easily use the - # database definition DSL to build up your schema (#create_table, - # #add_index, etc.). + # database definition DSL to build up your schema (+create_table+, + # +add_index+, etc.). # # The +info+ hash is optional, and if given is used to define metadata # about the current schema (currently, only the schema's version): diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb index 826662d3ee..b90ed88c6b 100644 --- a/activerecord/lib/active_record/schema_dumper.rb +++ b/activerecord/lib/active_record/schema_dumper.rb @@ -38,7 +38,7 @@ module ActiveRecord stream.puts <
tag! escapes all values # to ensure that valid XML is generated. For known binary # values, it is at least an order of magnitude faster to # Base64 encode binary values and directly put them in the # output XML than to pass the original value or the Base64 - # encoded value to the #tag! method. It definitely makes + # encoded value to the tag! method. It definitely makes # no sense to Base64 encode the value and then give it to - # #tag!, since that just adds additional overhead. + # tag!, since that just adds additional overhead. def needs_encoding? ![ :binary, :date, :datetime, :boolean, :float, :integer ].include?(type) end diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index 13cb5f3f48..3b6835762c 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -30,9 +30,9 @@ module ActiveRecord # Exceptions will force a ROLLBACK that returns the database to the state before the transaction was begun. Be aware, though, # that the objects will _not_ have their instance data returned to their pre-transactional state. # - # == Different ActiveRecord classes in a single transaction + # == Different Active Record classes in a single transaction # - # Though the transaction class method is called on some ActiveRecord class, + # Though the transaction class method is called on some Active Record class, # the objects within the transaction block need not all be instances of # that class. # In this example a Balance record is transactionally saved even diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index b3a75121ed..0e150bddb2 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -301,7 +301,7 @@ module ActiveRecord :odd => 'odd?', :even => 'even?' }.freeze # Adds a validation method or block to the class. This is useful when - # overriding the #validate instance method becomes too unwieldly and + # overriding the +validate+ instance method becomes too unwieldly and # you're looking for more descriptive declaration of your validations. # # This can be done with a symbol pointing to a method: @@ -326,7 +326,7 @@ module ActiveRecord # end # end # - # This usage applies to #validate_on_create and #validate_on_update as well. + # This usage applies to +validate_on_create+ and +validate_on_update+ as well. # Validates each attribute against a block. # diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index 08fd0123f6..463ee9f1e7 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -34,18 +34,18 @@ module ActiveResource # from REST web services. # # ryan = Person.new(:first => 'Ryan', :last => 'Daigle') - # ryan.save #=> true - # ryan.id #=> 2 - # Person.exists?(ryan.id) #=> true - # ryan.exists? #=> true + # ryan.save # => true + # ryan.id # => 2 + # Person.exists?(ryan.id) # => true + # ryan.exists? # => true # # ryan = Person.find(1) - # # => Resource holding our newly created Person object + # # Resource holding our newly created Person object # # ryan.first = 'Rizzle' - # ryan.save #=> true + # ryan.save # => true # - # ryan.destroy #=> true + # ryan.destroy # => true # # As you can see, these are very similar to Active Record's lifecycle methods for database records. # You can read more about each of these methods in their respective documentation. @@ -127,7 +127,7 @@ module ActiveResource # # GET http://api.people.com:3000/people/999.xml # ryan = Person.find(999) # 404, raises ActiveResource::ResourceNotFound # - # 404 is just one of the HTTP error response codes that ActiveResource will handle with its own exception. The + # 404 is just one of the HTTP error response codes that Active Resource will handle with its own exception. The # following HTTP response codes will also result in these exceptions: # # * 200..399 - Valid response, no exception @@ -156,8 +156,8 @@ module ActiveResource # then fail (with a false return value) and the validation errors can be accessed on the resource in question. # # ryan = Person.find(1) - # ryan.first #=> '' - # ryan.save #=> false + # ryan.first # => '' + # ryan.save # => false # # # When # # PUT http://api.people.com:3000/people/1.xml @@ -167,8 +167,8 @@ module ActiveResource # # First cannot be empty # # # - # ryan.errors.invalid?(:first) #=> true - # ryan.errors.full_messages #=> ['First cannot be empty'] + # ryan.errors.invalid?(:first) # => true + # ryan.errors.full_messages # => ['First cannot be empty'] # # Learn more about Active Resource's validation features in the ActiveResource::Validations documentation. # @@ -201,7 +201,7 @@ module ActiveResource class << self # Gets the URI of the REST resources to map for this class. The site variable is required - # ActiveResource's mapping to work. + # Active Resource's mapping to work. def site # Not using superclass_delegating_reader because don't want subclasses to modify superclass instance # @@ -226,7 +226,7 @@ module ActiveResource end # Sets the URI of the REST resources to map for this class to the value in the +site+ argument. - # The site variable is required ActiveResource's mapping to work. + # The site variable is required Active Resource's mapping to work. def site=(site) @connection = nil if site.nil? @@ -701,7 +701,7 @@ module ActiveResource attributes[self.class.primary_key] = id end - # Allows ActiveResource objects to be used as parameters in ActionPack URL generation. + # Allows Active Resource objects to be used as parameters in Action Pack URL generation. def to_param id && id.to_s end @@ -820,7 +820,7 @@ module ActiveResource # ==== Options # The +options+ parameter is handed off to the +to_xml+ method on each # attribute, so it has the same options as the +to_xml+ methods in - # ActiveSupport. + # Active Support. # # * :indent - Set the indent level for the XML output (default is +2+). # * :dasherize - Boolean option to determine whether or not element names should diff --git a/activeresource/lib/active_resource/custom_methods.rb b/activeresource/lib/active_resource/custom_methods.rb index 52a4a4f10b..4c8699288c 100644 --- a/activeresource/lib/active_resource/custom_methods.rb +++ b/activeresource/lib/active_resource/custom_methods.rb @@ -7,12 +7,12 @@ module ActiveResource # :member => { :promote => :put, :deactivate => :delete } # :collection => { :active => :get } # - # This route set creates routes for the following http requests: + # This route set creates routes for the following HTTP requests: # - # POST /people/new/register.xml #=> PeopleController.register - # PUT /people/1/promote.xml #=> PeopleController.promote with :id => 1 - # DELETE /people/1/deactivate.xml #=> PeopleController.deactivate with :id => 1 - # GET /people/active.xml #=> PeopleController.active + # POST /people/new/register.xml # PeopleController.register + # PUT /people/1/promote.xml # PeopleController.promote with :id => 1 + # DELETE /people/1/deactivate.xml # PeopleController.deactivate with :id => 1 + # GET /people/active.xml # PeopleController.active # # Using this module, Active Resource can use these custom REST methods just like the # standard methods. @@ -48,8 +48,8 @@ module ActiveResource # # => [{:id => 1, :name => 'Ryan'}] # # Note: the objects returned from this method are not automatically converted - # into ActiveResource instances - they are ordinary Hashes. If you are expecting - # ActiveResource instances, use the find class method with the + # into Active Resource instances - they are ordinary Hashes. If you are expecting + # Active Resource instances, use the find class method with the # :from option. For example: # # Person.find(:all, :from => :active) diff --git a/activeresource/lib/active_resource/formats/xml_format.rb b/activeresource/lib/active_resource/formats/xml_format.rb index 01c28dcee6..5e97ffa776 100644 --- a/activeresource/lib/active_resource/formats/xml_format.rb +++ b/activeresource/lib/active_resource/formats/xml_format.rb @@ -21,7 +21,7 @@ module ActiveResource private # Manipulate from_xml Hash, because xml_simple is not exactly what we - # want for ActiveResource. + # want for Active Resource. def from_xml_data(data) if data.is_a?(Hash) && data.keys.size == 1 data.values.first diff --git a/activeresource/lib/active_resource/http_mock.rb b/activeresource/lib/active_resource/http_mock.rb index d1c1412575..22f83ae910 100644 --- a/activeresource/lib/active_resource/http_mock.rb +++ b/activeresource/lib/active_resource/http_mock.rb @@ -3,8 +3,52 @@ require 'active_resource/connection' module ActiveResource class InvalidRequestError < StandardError; end #:nodoc: + # One thing that has always been a pain with remote web services is testing. The HttpMock + # class makes it easy to test your Active Resource models by creating a set of mock responses to specific + # requests. + # + # To test your Active Resource model, you simply call the ActiveResource::HttpMock.respond_to + # method with an attached block. The block declares a set of URIs with expected input, and the output + # each request should return. The passed in block has any number of entries in the following generalized + # format: + # + # mock.http_method(path, request_headers = {}, body = nil, status = 200, response_headers = {}) + # + # * http_method - The HTTP method to listen for. This can be +get+, +post+, +put+, +delete+ or + # +head+. + # * path - A string, starting with a "/", defining the URI that is expected to be + # called. + # * request_headers - Headers that are expected along with the request. This argument uses a + # hash format, such as { "Content-Type" => "application/xml" }. This mock will only trigger + # if your tests sends a request with identical headers. + # * body - The data to be returned. This should be a string of Active Resource parseable content, + # such as XML. + # * status - The HTTP response code, as an integer, to return with the response. + # * response_headers - Headers to be returned with the response. Uses the same hash format as + # request_headers listed above. + # + # In order for a mock to deliver its content, the incoming request must match by the http_method, + # +path+ and request_headers. If no match is found an InvalidRequestError exception + # will be raised letting you know you need to create a new mock for that request. + # + # ==== Example + # def setup + # @matz = { :id => 1, :name => "Matz" }.to_xml(:root => "person") + # ActiveResource::HttpMock.respond_to do |mock| + # mock.post "/people.xml", {}, @matz, 201, "Location" => "/people/1.xml" + # mock.get "/people/1.xml", {}, @matz + # mock.put "/people/1.xml", {}, nil, 204 + # mock.delete "/people/1.xml", {}, nil, 200 + # end + # end + # + # def test_get_matz + # person = Person.find(1) + # assert_equal "Matz", person.name + # end + # class HttpMock - class Responder + class Responder #:nodoc: def initialize(responses) @responses = responses end @@ -19,15 +63,41 @@ module ActiveResource end class << self + + # Returns an array of all request objects that have been sent to the mock. You can use this to check + # wether or not your model actually sent an HTTP request. + # + # ==== Example + # def setup + # @matz = { :id => 1, :name => "Matz" }.to_xml(:root => "person") + # ActiveResource::HttpMock.respond_to do |mock| + # mock.get "/people/1.xml", {}, @matz + # end + # end + # + # def test_should_request_remote_service + # person = Person.find(1) # Call the remote service + # + # # This request object has the same HTTP method and path as declared by the mock + # expected_request = ActiveResource::Request.new(:get, "/people/1.xml") + # + # # Assert that the mock received, and responded to, the expected request from the model + # assert ActiveResource::HttpMock.requests.include?(expected_request) + # end def requests @@requests ||= [] end + # Returns a hash of request => response pairs for all all responses this mock has delivered, where +request+ + # is an instance of ActiveResource::Request and the response is, naturally, an instance of + # ActiveResource::Response. def responses @@responses ||= {} end - def respond_to(pairs = {}) + # Accepts a block which declares a set of requests and responses for the HttpMock to respond to. See the main + # ActiveResource::HttpMock description for a more detailed explanation. + def respond_to(pairs = {}) #:yields: mock reset! pairs.each do |(path, response)| responses[path] = response @@ -40,6 +110,7 @@ module ActiveResource end end + # Deletes all logged requests and responses. def reset! requests.clear responses.clear @@ -66,7 +137,7 @@ module ActiveResource EOE end - def initialize(site) + def initialize(site) #:nodoc: @site = site end end diff --git a/activeresource/lib/active_resource/validations.rb b/activeresource/lib/active_resource/validations.rb index 57d2ae559d..a7c624f309 100644 --- a/activeresource/lib/active_resource/validations.rb +++ b/activeresource/lib/active_resource/validations.rb @@ -216,8 +216,8 @@ module ActiveResource end end - # Module to allow validation of ActiveResource objects, which creates an Errors instance for every resource. - # Methods are implemented by overriding +Base#validate+ or its variants Each of these methods can inspect + # Module to allow validation of Active Resource objects, which creates an Errors instance for every resource. + # Methods are implemented by overriding Base#validate or its variants Each of these methods can inspect # the state of the object, which usually means ensuring that a number of attributes have a certain value # (such as not empty, within a given range, matching a certain regular expression and so on). # diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb index a023118885..2c606b401b 100644 --- a/activesupport/lib/active_support/core_ext/hash/conversions.rb +++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb @@ -212,7 +212,7 @@ module ActiveSupport #:nodoc: nil # If the type is the only element which makes it then # this still makes the value nil, except if type is - # a xml node(where type['value'] is a Hash) + # a XML node(where type['value'] is a Hash) elsif value['type'] && value.size == 1 && !value['type'].is_a?(::Hash) nil else diff --git a/activesupport/lib/active_support/core_ext/integer/even_odd.rb b/activesupport/lib/active_support/core_ext/integer/even_odd.rb index cfc6b4c6d6..b1d1e28062 100644 --- a/activesupport/lib/active_support/core_ext/integer/even_odd.rb +++ b/activesupport/lib/active_support/core_ext/integer/even_odd.rb @@ -3,10 +3,14 @@ module ActiveSupport #: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 + # 2.even? # => true + # 2.odd? # => false + # 1.even? # => false + # 1.odd? # => true + # 0.even? # => true + # 0.odd? # => false + # -1.even? # => false + # -1.odd? # => true module EvenOdd def multiple_of?(number) self % number == 0 diff --git a/activesupport/lib/active_support/core_ext/object/misc.rb b/activesupport/lib/active_support/core_ext/object/misc.rb index a3637d7a8a..8384a12327 100644 --- a/activesupport/lib/active_support/core_ext/object/misc.rb +++ b/activesupport/lib/active_support/core_ext/object/misc.rb @@ -48,7 +48,7 @@ class Object yield ActiveSupport::OptionMerger.new(self, options) end - # A duck-type assistant method. For example, ActiveSupport extends Date + # A duck-type assistant method. For example, Active Support 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 diff --git a/activesupport/lib/active_support/core_ext/string/unicode.rb b/activesupport/lib/active_support/core_ext/string/unicode.rb index ba16d4d866..5e20534d1d 100644 --- a/activesupport/lib/active_support/core_ext/string/unicode.rb +++ b/activesupport/lib/active_support/core_ext/string/unicode.rb @@ -17,17 +17,17 @@ module ActiveSupport #:nodoc: # string overrides can also be called through the +chars+ proxy. # # name = 'Claus Müller' - # name.reverse #=> "rell??M sualC" - # name.length #=> 13 + # name.reverse # => "rell??M sualC" + # name.length # => 13 # - # name.chars.reverse.to_s #=> "rellüM sualC" - # name.chars.length #=> 12 + # 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 + # 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 diff --git a/activesupport/lib/active_support/core_ext/time/conversions.rb b/activesupport/lib/active_support/core_ext/time/conversions.rb index edca5b8a98..9054008309 100644 --- a/activesupport/lib/active_support/core_ext/time/conversions.rb +++ b/activesupport/lib/active_support/core_ext/time/conversions.rb @@ -59,7 +59,7 @@ module ActiveSupport #:nodoc: # Converts a Time object to a Date, dropping hour, minute, and second precision. # # my_time = Time.now # => Mon Nov 12 22:59:51 -0500 2007 - # my_time.to_date #=> Mon, 12 Nov 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 diff --git a/activesupport/lib/active_support/core_ext/time/zones.rb b/activesupport/lib/active_support/core_ext/time/zones.rb index cf28d0fa95..079ecdd48e 100644 --- a/activesupport/lib/active_support/core_ext/time/zones.rb +++ b/activesupport/lib/active_support/core_ext/time/zones.rb @@ -10,21 +10,21 @@ module ActiveSupport #:nodoc: attr_accessor :zone_default # Returns the TimeZone for the current request, if this has been set (via Time.zone=). - # If Time.zone has not been set for the current request, returns the TimeZone specified in config.time_zone + # If Time.zone has not been set for the current request, returns the TimeZone specified in config.time_zone. def zone Thread.current[:time_zone] || zone_default end - # Sets Time.zone to a TimeZone object for the current request/thread. + # Sets Time.zone to a TimeZone object for the current request/thread. # # This method accepts any of the following: # - # * a Rails TimeZone object - # * an identifier for a Rails TimeZone object (e.g., "Eastern Time (US & Canada)", -5.hours) - # * a TZInfo::Timezone object - # * an identifier for a TZInfo::Timezone object (e.g., "America/New_York") + # * A Rails TimeZone object. + # * An identifier for a Rails TimeZone object (e.g., "Eastern Time (US & Canada)", -5.hours). + # * A TZInfo::Timezone object. + # * An identifier for a TZInfo::Timezone object (e.g., "America/New_York"). # - # Here's an example of how you might set Time.zone on a per request basis -- current_user.time_zone + # Here's an example of how you might set Time.zone on a per request basis -- current_user.time_zone # just needs to return a string identifying the user's preferred TimeZone: # # class ApplicationController < ActionController::Base @@ -38,7 +38,7 @@ module ActiveSupport #:nodoc: Thread.current[:time_zone] = get_zone(time_zone) end - # Allows override of Time.zone locally inside supplied block; resets Time.zone to existing value when done + # Allows override of Time.zone locally inside supplied block; resets Time.zone to existing value when done. def use_zone(time_zone) old_zone, ::Time.zone = ::Time.zone, get_zone(time_zone) yield @@ -46,7 +46,7 @@ module ActiveSupport #:nodoc: ::Time.zone = old_zone end - # Returns Time.zone.now when config.time_zone is set, otherwise just returns Time.now. + # Returns Time.zone.now when config.time_zone is set, otherwise just returns Time.now. def current ::Time.zone_default ? ::Time.zone.now : ::Time.now end @@ -65,16 +65,16 @@ module ActiveSupport #:nodoc: end end - # Returns the simultaneous time in Time.zone. + # Returns the simultaneous time in Time.zone. # # Time.zone = 'Hawaii' # => 'Hawaii' # Time.utc(2000).in_time_zone # => Fri, 31 Dec 1999 14:00:00 HST -10:00 # - # This method is similar to Time#localtime, except that it uses Time.zone as the local zone + # This method is similar to Time#localtime, except that it uses Time.zone as the local zone # instead of the operating system's time zone. # # You can also pass in a TimeZone instance or string that identifies a TimeZone as an argument, - # and the conversion will be based on that zone instead of Time.zone. + # and the conversion will be based on that zone instead of Time.zone. # # Time.utc(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00 def in_time_zone(zone = ::Time.zone) diff --git a/activesupport/lib/active_support/deprecation.rb b/activesupport/lib/active_support/deprecation.rb index 6aa379b550..758aef5445 100644 --- a/activesupport/lib/active_support/deprecation.rb +++ b/activesupport/lib/active_support/deprecation.rb @@ -144,8 +144,8 @@ module ActiveSupport end end - # Stand-in for @request, @attributes, @params, etc which emits deprecation - # warnings on any method call (except #inspect). + # 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 =~ /^__/ } diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb index 0fd44324bb..a4fd619317 100644 --- a/activesupport/lib/active_support/inflector.rb +++ b/activesupport/lib/active_support/inflector.rb @@ -109,13 +109,13 @@ module Inflector # 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" + # 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 @@ -127,15 +127,15 @@ module Inflector end end - # The reverse of pluralize, returns the singular form of a word in a string. + # 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" + # 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 @@ -147,16 +147,16 @@ module Inflector end end - # By default, camelize converts strings to UpperCamelCase. If the argument to camelize - # is set to ":lower" then camelize produces lowerCamelCase. + # 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 + # +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" + # 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(/(?:^|_)(.)/) { $1.upcase } @@ -166,14 +166,14 @@ module Inflector 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 + # 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 + # +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" + # 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 @@ -182,9 +182,9 @@ module Inflector # # Changes '::' to '/' to convert namespaces to paths. # - # Examples - # "ActiveRecord".underscore #=> "active_record" - # "ActiveRecord::Errors".underscore #=> active_record/errors + # 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'). @@ -195,52 +195,52 @@ module Inflector # Replaces underscores with dashes in the string. # - # Example - # "puni_puni" #=> "puni-puni" + # 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. + # Capitalizes the first word and turns underscores into spaces and strips a + # trailing "_id", if any. Like +titleize+, this is meant for creating pretty output. # - # Examples - # "employee_salary" #=> "Employee salary" - # "author_id" #=> "Author" + # 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 + # Removes the module part from the expression in the string. # - # Examples - # "ActiveRecord::CoreExtensions::String::Inflections".demodulize #=> "Inflections" - # "Inflections".demodulize #=> "Inflections" + # 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. + # 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" + # "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 plural 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.) + # follow +classify+ with +constantize+.) # - # Examples - # "egg_and_hams".classify #=> "EggAndHam" - # "posts".classify #=> "Post" + # Examples: + # "egg_and_hams".classify # => "EggAndHam" + # "posts".classify # => "Post" # - # Singular names are not handled correctly - # "business".classify #=> "Busines" + # Singular names are not handled correctly: + # "business".classify # => "Busines" def classify(table_name) # strip out any leading schema name camelize(singularize(table_name.to_s.sub(/.*\./, ''))) @@ -250,10 +250,10 @@ module Inflector # +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" + # 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 @@ -283,10 +283,10 @@ module Inflector 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. + # Turns a number into an ordinal string used to denote the position in an + # ordered sequence such as 1st, 2nd, 3rd, 4th. # - # Examples + # Examples: # ordinalize(1) # => "1st" # ordinalize(2) # => "2nd" # ordinalize(1002) # => "1002nd" diff --git a/activesupport/lib/active_support/json.rb b/activesupport/lib/active_support/json.rb index bbda2c9fa3..54a7becd0f 100644 --- a/activesupport/lib/active_support/json.rb +++ b/activesupport/lib/active_support/json.rb @@ -1,5 +1,5 @@ module ActiveSupport - # If true, use ISO 8601 format for dates and times. Otherwise, fall back to the ActiveSupport legacy format. + # If true, use ISO 8601 format for dates and times. Otherwise, fall back to the Active Support legacy format. mattr_accessor :use_standard_json_time_format class << self diff --git a/activesupport/lib/active_support/json/decoding.rb b/activesupport/lib/active_support/json/decoding.rb index c58001f49f..fdb219dbf7 100644 --- a/activesupport/lib/active_support/json/decoding.rb +++ b/activesupport/lib/active_support/json/decoding.rb @@ -31,7 +31,7 @@ module ActiveSupport 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 + # the position in the final YAML output total_marks = marks.size times << pos+total_marks << scanner.pos+total_marks end diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb index 65114415eb..ee716de39e 100644 --- a/activesupport/lib/active_support/multibyte/chars.rb +++ b/activesupport/lib/active_support/multibyte/chars.rb @@ -10,7 +10,7 @@ module ActiveSupport::Multibyte #:nodoc: # 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" + # "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. diff --git a/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb b/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb index 0166b69ac3..aa9c16f575 100644 --- a/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb +++ b/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb @@ -147,13 +147,11 @@ module ActiveSupport::Multibyte::Handlers #:nodoc: # # s = "Müller" # s.chars[2] = "e" # Replace character with offset 2 - # s - # #=> "Müeler" + # s # => "Müeler" # # s = "Müller" # s.chars[1, 2] = "ö" # Replace 2 characters at character offset 1 - # s - # #=> "Möler" + # s # => "Möler" def []=(str, *args) replace_by = args.pop # Indexed replace with regular expressions already works @@ -183,10 +181,10 @@ module ActiveSupport::Multibyte::Handlers #:nodoc: # Example: # # "¾ cup".chars.rjust(8).to_s - # #=> " ¾ cup" + # # => " ¾ cup" # # "¾ cup".chars.rjust(8, " ").to_s # Use non-breaking whitespace - # #=> "   ¾ cup" + # # => "   ¾ cup" def rjust(str, integer, padstr=' ') justify(str, integer, :right, padstr) end @@ -196,10 +194,10 @@ module ActiveSupport::Multibyte::Handlers #:nodoc: # Example: # # "¾ cup".chars.rjust(8).to_s - # #=> "¾ cup " + # # => "¾ cup " # # "¾ cup".chars.rjust(8, " ").to_s # Use non-breaking whitespace - # #=> "¾ cup   " + # # => "¾ cup   " def ljust(str, integer, padstr=' ') justify(str, integer, :left, padstr) end @@ -209,10 +207,10 @@ module ActiveSupport::Multibyte::Handlers #:nodoc: # Example: # # "¾ cup".chars.center(8).to_s - # #=> " ¾ cup " + # # => " ¾ cup " # # "¾ cup".chars.center(8, " ").to_s # Use non-breaking whitespace - # #=> " ¾ cup  " + # # => " ¾ cup  " def center(str, integer, padstr=' ') justify(str, integer, :center, padstr) end diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index 64c935717d..ece95eeae9 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -1,10 +1,10 @@ require 'tzinfo' module ActiveSupport # A Time-like class that can represent a time in any time zone. Necessary because standard Ruby Time instances are - # limited to UTC and the system's ENV['TZ'] zone. + # limited to UTC and the system's ENV['TZ'] zone. # - # You shouldn't ever need to create a TimeWithZone instance directly via .new -- instead, Rails provides the methods - # #local, #parse, #at and #now on TimeZone instances, and #in_time_zone on Time and DateTime instances, for a more + # You shouldn't ever need to create a TimeWithZone instance directly via new -- instead, Rails provides the methods + # +local+, +parse+, +at+ and +now+ on TimeZone instances, and +in_time_zone+ on Time and DateTime instances, for a more # user-friendly syntax. Examples: # # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)' @@ -38,12 +38,12 @@ module ActiveSupport @period = @utc ? period : get_period_and_ensure_valid_local_time end - # Returns a Time or DateTime instance that represents the time in time_zone + # Returns a Time or DateTime instance that represents the time in +time_zone+. def time @time ||= period.to_local(@utc) end - # Returns a Time or DateTime instance that represents the time in UTC + # Returns a Time or DateTime instance that represents the time in UTC. def utc @utc ||= period.to_utc(@time) end @@ -52,18 +52,18 @@ module ActiveSupport alias_method :getutc, :utc alias_method :gmtime, :utc - # Returns the underlying TZInfo::TimezonePeriod + # Returns the underlying TZInfo::TimezonePeriod. def period @period ||= time_zone.period_for_utc(@utc) end - # Returns the simultaneous time in Time.zone, or the specified zone + # Returns the simultaneous time in Time.zone, or the specified zone. def in_time_zone(new_zone = ::Time.zone) return self if time_zone == new_zone utc.in_time_zone(new_zone) end - # Returns a Time.local() instance of the simultaneous time in your system's ENV['TZ'] zone + # Returns a Time.local() instance of the simultaneous time in your system's ENV['TZ'] zone def localtime utc.getlocal end @@ -89,7 +89,7 @@ module ActiveSupport utc? && alternate_utc_string || utc_offset.to_utc_offset_s(colon) end - # Time uses #zone to display the time zone abbreviation, so we're duck-typing it + # Time uses +zone+ to display the time zone abbreviation, so we're duck-typing it. def zone period.zone_identifier.to_s end @@ -146,7 +146,7 @@ module ActiveSupport time.strftime(format) end - # Use the time in UTC for comparisons + # Use the time in UTC for comparisons. def <=>(other) utc <=> other end @@ -159,8 +159,8 @@ module ActiveSupport utc == other end - # If wrapped #time is a DateTime, use DateTime#since instead of #+ - # Otherwise, just pass on to #method_missing + # If wrapped +time+ is a DateTime, use DateTime#since instead of +. + # Otherwise, just pass on to +method_missing+. def +(other) result = utc.acts_like?(:date) ? utc.since(other) : utc + other rescue utc.since(other) result.in_time_zone(time_zone) @@ -225,18 +225,18 @@ module ActiveSupport utc.to_datetime.new_offset(Rational(utc_offset, 86_400)) end - # so that self acts_like?(:time) + # So that +self+ acts_like?(:time). def acts_like_time? true end - # Say we're a Time to thwart type checking + # Say we're a Time to thwart type checking. def is_a?(klass) klass == ::Time || super end alias_method :kind_of?, :is_a? - # Neuter freeze because freezing can cause problems with lazy loading of attributes + # Neuter freeze because freezing can cause problems with lazy loading of attributes. def freeze self end @@ -249,14 +249,14 @@ module ActiveSupport initialize(variables[0], ::Time.send!(:get_zone, variables[1]), variables[2]) end - # Ensure proxy class responds to all methods that underlying time instance responds to + # Ensure proxy class responds to all methods that underlying time instance responds to. def respond_to?(sym) # consistently respond false to acts_like?(:date), regardless of whether #time is a Time or DateTime return false if sym.to_s == 'acts_like_date?' super || time.respond_to?(sym) end - # Send the missing method to time instance, and wrap result in a new TimeWithZone with the existing time_zone + # Send the missing method to +time+ instance, and wrap result in a new TimeWithZone with the existing +time_zone+. def method_missing(sym, *args, &block) result = time.__send__(sym, *args, &block) result.acts_like?(:time) ? self.class.new(nil, time_zone, result) : result diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 5340b5ed28..4d7239d8cf 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -1,11 +1,11 @@ # The TimeZone class serves as a wrapper around TZInfo::Timezone instances. It allows us to do the following: # -# * limit the set of zones provided by TZInfo to a meaningful subset of 142 zones -# * retrieve and display zones with a friendlier name (e.g., "Eastern Time (US & Canada)" instead of "America/New_York") -# * lazily load TZInfo::Timezone instances only when they're needed -# * create ActiveSupport::TimeWithZone instances via TimeZone #local, #parse, #at and #now methods +# * Limit the set of zones provided by TZInfo to a meaningful subset of 142 zones. +# * Retrieve and display zones with a friendlier name (e.g., "Eastern Time (US & Canada)" instead of "America/New_York"). +# * Lazily load TZInfo::Timezone instances only when they're needed. +# * Create ActiveSupport::TimeWithZone instances via TimeZone's +local+, +parse+, +at+ and +now+ methods. # -# If you set config.time_zone in the Rails Initializer, you can access this TimeZone object via Time.zone: +# If you set config.time_zone in the Rails Initializer, you can access this TimeZone object via Time.zone: # # # environment.rb: # Rails::Initializer.run do |config| @@ -16,7 +16,7 @@ # Time.zone.name # => "Eastern Time (US & Canada)" # Time.zone.now # => Sun, 18 May 2008 14:30:44 EDT -04:00 # -# The version of TZInfo bundled with ActiveSupport only includes the definitions necessary to support the zones +# The version of TZInfo bundled with Active Support only includes the definitions necessary to support the zones # defined by the TimeZone class. If you need to use zones that aren't defined by TimeZone, you'll need to install the TZInfo gem # (if a recent version of the gem is installed locally, this will be used instead of the bundled version.) class TimeZone @@ -356,7 +356,7 @@ class TimeZone # 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.) + # this class with the +composed_of+ macro.) def new(name) self[name] end diff --git a/railties/configs/databases/frontbase.yml b/railties/configs/databases/frontbase.yml index 2eed3133a1..c0c3588be1 100644 --- a/railties/configs/databases/frontbase.yml +++ b/railties/configs/databases/frontbase.yml @@ -10,8 +10,8 @@ development: username: <%= app_name %> password: '' -# Warning: The database defined as 'test' will be erased and -# re-generated from your development database when you run 'rake'. +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: adapter: frontbase diff --git a/railties/configs/databases/mysql.yml b/railties/configs/databases/mysql.yml index c5c894c5e1..7fcadcdf2c 100644 --- a/railties/configs/databases/mysql.yml +++ b/railties/configs/databases/mysql.yml @@ -26,8 +26,8 @@ development: host: localhost <% end -%> -# Warning: The database defined as 'test' will be erased and -# re-generated from your development database when you run 'rake'. +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: adapter: mysql diff --git a/railties/configs/databases/oracle.yml b/railties/configs/databases/oracle.yml index c86cbdbaba..a1883f6256 100644 --- a/railties/configs/databases/oracle.yml +++ b/railties/configs/databases/oracle.yml @@ -4,7 +4,7 @@ # http://rubyforge.org/projects/ruby-oci8/ # # Specify your database using any valid connection syntax, such as a -# tnsnames.ora service name, or a sql connect url string of the form: +# tnsnames.ora service name, or a SQL connect url string of the form: # # //host:[port][/service name] # @@ -23,8 +23,8 @@ development: username: <%= app_name %> password: -# Warning: The database defined as 'test' will be erased and -# re-generated from your development database when you run 'rake'. +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: adapter: oracle diff --git a/railties/configs/databases/postgresql.yml b/railties/configs/databases/postgresql.yml index c1b911a9a4..36f6e5ae49 100644 --- a/railties/configs/databases/postgresql.yml +++ b/railties/configs/databases/postgresql.yml @@ -30,8 +30,8 @@ development: # The server defaults to notice. #min_messages: warning -# Warning: The database defined as 'test' will be erased and -# re-generated from your development database when you run 'rake'. +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: adapter: postgresql diff --git a/railties/configs/databases/sqlite2.yml b/railties/configs/databases/sqlite2.yml index 26d3957d79..fc48bd6753 100644 --- a/railties/configs/databases/sqlite2.yml +++ b/railties/configs/databases/sqlite2.yml @@ -4,8 +4,8 @@ development: adapter: sqlite database: db/development.sqlite2 -# Warning: The database defined as 'test' will be erased and -# re-generated from your development database when you run 'rake'. +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: adapter: sqlite diff --git a/railties/configs/databases/sqlite3.yml b/railties/configs/databases/sqlite3.yml index b444b03cd4..fff44a4124 100644 --- a/railties/configs/databases/sqlite3.yml +++ b/railties/configs/databases/sqlite3.yml @@ -5,8 +5,8 @@ development: database: db/development.sqlite3 timeout: 5000 -# Warning: The database defined as 'test' will be erased and -# re-generated from your development database when you run 'rake'. +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: adapter: sqlite3 diff --git a/railties/configs/initializers/new_rails_defaults.rb b/railties/configs/initializers/new_rails_defaults.rb index b959c6d549..5e60c0ade4 100644 --- a/railties/configs/initializers/new_rails_defaults.rb +++ b/railties/configs/initializers/new_rails_defaults.rb @@ -1,15 +1,15 @@ # These settings change the behavior of Rails 2 apps and will be defaults # for Rails 3. You can remove this initializer when Rails 3 is released. -# Include ActiveRecord class name as root for JSON serialized output. +# Include Active Record class name as root for JSON serialized output. ActiveRecord::Base.include_root_in_json = true -# Store the full class name (including module namespace) in STI type column +# Store the full class name (including module namespace) in STI type column. ActiveRecord::Base.store_full_sti_class = true -# Use ISO 8601 format for JSON serialized times and dates +# Use ISO 8601 format for JSON serialized times and dates. ActiveSupport.use_standard_json_time_format = true -# Don't escape HTML entities in JSON, leave that for the #json_escape helper +# Don't escape HTML entities in JSON, leave that for the #json_escape helper. # if you're including raw json in an HTML page. ActiveSupport.escape_html_entities_in_json = false \ No newline at end of file diff --git a/railties/environments/environment.rb b/railties/environments/environment.rb index d03447e1d3..468fa45ef6 100644 --- a/railties/environments/environment.rb +++ b/railties/environments/environment.rb @@ -21,7 +21,7 @@ Rails::Initializer.run do |config| # config.frameworks -= [ :active_record, :active_resource, :action_mailer ] # Specify gems that this application depends on. - # They can then be installed with rake gem:install on new installations. + # They can then be installed with "rake gems:install" on new installations. # config.gem "bj" # config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net" # config.gem "aws-s3", :lib => "aws/s3" @@ -38,9 +38,9 @@ Rails::Initializer.run do |config| # (by default production uses :info, the others :debug) # config.log_level = :debug - # Make Time.zone default to the specified zone, and make ActiveRecord store time values + # Make Time.zone default to the specified zone, and make Active Record store time values # in the database in UTC, and return them converted to the specified local zone. - # Run `rake -D time` for a list of tasks for finding time zone names. Uncomment to use default local time. + # Run "rake -D time" for a list of tasks for finding time zone names. Uncomment to use default local time. config.time_zone = 'UTC' # Your secret key for verifying cookie session data integrity. @@ -54,7 +54,7 @@ Rails::Initializer.run do |config| # Use the database for sessions instead of the cookie-based default, # which shouldn't be used to store highly confidential information - # (create the session table with 'rake db:sessions:create') + # (create the session table with "rake db:sessions:create") # config.action_controller.session_store = :active_record_store # Use SQL instead of Active Record's schema dumper when creating the test database. diff --git a/railties/environments/test.rb b/railties/environments/test.rb index 58850a7974..1e709e1d19 100644 --- a/railties/environments/test.rb +++ b/railties/environments/test.rb @@ -16,7 +16,7 @@ config.action_controller.perform_caching = false # Disable request forgery protection in test environment config.action_controller.allow_forgery_protection = false -# Tell ActionMailer not to deliver emails to the real world. +# Tell Action Mailer not to deliver emails to the real world. # The :test delivery method accumulates sent emails in the # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb index 2e56485989..8f963cb4a5 100644 --- a/railties/lib/initializer.rb +++ b/railties/lib/initializer.rb @@ -164,12 +164,12 @@ module Rails end # If Rails is vendored and RubyGems is available, install stub GemSpecs - # for Rails, ActiveSupport, ActiveRecord, ActionPack, ActionMailer, and - # ActiveResource. This allows Gem plugins to depend on Rails even when + # for Rails, Active Support, Active Record, Action Pack, Action Mailer, and + # Active Resource. This allows Gem plugins to depend on Rails even when # the Gem version of Rails shouldn't be loaded. def install_gem_spec_stubs unless Rails.respond_to?(:vendor_rails?) - abort "Your config/boot.rb is outdated: Run 'rake rails:update'." + abort %{Your config/boot.rb is outdated: Run "rake rails:update".} end if Rails.vendor_rails? @@ -214,8 +214,8 @@ module Rails end # Requires all frameworks specified by the Configuration#frameworks - # list. By default, all frameworks (ActiveRecord, ActiveSupport, - # ActionPack, ActionMailer, and ActiveResource) are loaded. + # list. By default, all frameworks (Active Record, Active Support, + # Action Pack, Action Mailer, and Active Resource) are loaded. def require_frameworks configuration.frameworks.each { |framework| require(framework.to_s) } rescue LoadError => e @@ -289,7 +289,7 @@ module Rails def load_observers if configuration.frameworks.include?(:active_record) if @configuration.gems.any? { |g| !g.loaded? } - puts "Unable to instantiate observers, some gems that this application depends on are missing. Run 'rake gems:install'" + puts %{Unable to instantiate observers, some gems that this application depends on are missing. Run "rake gems:install"} else ActiveRecord::Base.instantiate_observers end @@ -330,7 +330,7 @@ module Rails end end - # If the +RAILS_DEFAULT_LOGGER+ constant is already set, this initialization + # If the RAILS_DEFAULT_LOGGER constant is already set, this initialization # routine does nothing. If the constant is not set, and Configuration#logger # is not +nil+, this also does nothing. Otherwise, a new logger instance # is created at Configuration#log_path, with a default log level of @@ -363,10 +363,10 @@ module Rails silence_warnings { Object.const_set "RAILS_DEFAULT_LOGGER", logger } end - # Sets the logger for ActiveRecord, ActionController, and ActionMailer + # Sets the logger for Active Record, Action Controller, and Action Mailer # (but only for those frameworks that are to be loaded). If the framework's # logger is already set, it is not changed, otherwise it is set to use - # +RAILS_DEFAULT_LOGGER+. + # RAILS_DEFAULT_LOGGER. def initialize_framework_logging for framework in ([ :active_record, :action_controller, :action_mailer ] & configuration.frameworks) framework.to_s.camelize.constantize.const_get("Base").logger ||= RAILS_DEFAULT_LOGGER @@ -384,7 +384,7 @@ module Rails ActionController::Base.view_paths = [configuration.view_path] if configuration.frameworks.include?(:action_controller) && ActionController::Base.view_paths.empty? end - # If ActionController is not one of the loaded frameworks (Configuration#frameworks) + # If Action Controller is not one of the loaded frameworks (Configuration#frameworks) # this does nothing. Otherwise, it loads the routing definitions and sets up # loading module used to lazily load controllers (Configuration#controller_paths). def initialize_routing @@ -413,13 +413,13 @@ module Rails end end - # Sets the default value for Time.zone, and turns on ActiveRecord time_zone_aware_attributes. + # Sets the default value for Time.zone, and turns on ActiveRecord::Base#time_zone_aware_attributes. # If assigned value cannot be matched to a TimeZone, an exception will be raised. def initialize_time_zone if configuration.time_zone zone_default = Time.send!(:get_zone, configuration.time_zone) unless zone_default - raise "Value assigned to config.time_zone not recognized. Run `rake -D time` for a list of tasks for finding appropriate time zone names." + raise %{Value assigned to config.time_zone not recognized. Run "rake -D time" for a list of tasks for finding appropriate time zone names.} end Time.zone_default = zone_default if configuration.frameworks.include?(:active_record) @@ -479,22 +479,22 @@ module Rails # The application's base directory. attr_reader :root_path - # A stub for setting options on ActionController::Base + # A stub for setting options on ActionController::Base. attr_accessor :action_controller - # A stub for setting options on ActionMailer::Base + # A stub for setting options on ActionMailer::Base. attr_accessor :action_mailer - # A stub for setting options on ActionView::Base + # A stub for setting options on ActionView::Base. attr_accessor :action_view - # A stub for setting options on ActiveRecord::Base + # A stub for setting options on ActiveRecord::Base. attr_accessor :active_record - # A stub for setting options on ActiveRecord::Base + # A stub for setting options on ActiveRecord::Base. attr_accessor :active_resource - # A stub for setting options on ActiveSupport + # A stub for setting options on ActiveSupport. attr_accessor :active_support # Whether or not classes should be cached (set to false if you want @@ -622,9 +622,9 @@ module Rails end alias_method :breakpoint_server=, :breakpoint_server - # Sets the default time_zone. Setting this will enable time_zone - # awareness for ActiveRecord models and set the ActiveRecord default - # timezone to :utc. + # Sets the default +time_zone+. Setting this will enable +time_zone+ + # awareness for Active Record models and set the Active Record default + # timezone to :utc. attr_accessor :time_zone # Create a new Configuration instance, initialized with the default @@ -689,7 +689,7 @@ module Rails end # Return the currently selected environment. By default, it returns the - # value of the +RAILS_ENV+ constant. + # value of the RAILS_ENV constant. def environment ::RAILS_ENV end @@ -847,7 +847,7 @@ end # Needs to be duplicated from Active Support since its needed before Active # Support is available. Here both Options and Hash are namespaced to prevent -# conflicts with other implementations AND with the classes residing in ActiveSupport. +# conflicts with other implementations AND with the classes residing in Active Support. class Rails::OrderedOptions < Array #:nodoc: def []=(key, value) key = key.to_sym diff --git a/railties/lib/rails_generator/base.rb b/railties/lib/rails_generator/base.rb index 1ebcff9062..b5cfe79867 100644 --- a/railties/lib/rails_generator/base.rb +++ b/railties/lib/rails_generator/base.rb @@ -36,7 +36,7 @@ module Rails # view.html.erb # # The directory name (+controller+) matches the name of the generator file - # (controller_generator.rb) and class (+ControllerGenerator+). The files + # (controller_generator.rb) and class (ControllerGenerator). The files # that will be copied or used as templates are stored in the +templates+ # directory. # diff --git a/railties/lib/tasks/databases.rake b/railties/lib/tasks/databases.rake index f40f8463f7..8077d0a401 100644 --- a/railties/lib/tasks/databases.rake +++ b/railties/lib/tasks/databases.rake @@ -173,7 +173,7 @@ namespace :db do pending_migrations.each do |pending_migration| puts ' %4d %s' % [pending_migration.version, pending_migration.name] end - abort "Run `rake db:migrate` to update your database then try again." + abort %{Run "rake db:migrate" to update your database then try again.} end end end diff --git a/railties/test/fixtures/about_yml_plugins/bad_about_yml/about.yml b/railties/test/fixtures/about_yml_plugins/bad_about_yml/about.yml index 79d5721a53..fe80872a16 100644 --- a/railties/test/fixtures/about_yml_plugins/bad_about_yml/about.yml +++ b/railties/test/fixtures/about_yml_plugins/bad_about_yml/about.yml @@ -1 +1 @@ -# an empty yaml file - any content in here seems to get parsed as a string \ No newline at end of file +# an empty YAML file - any content in here seems to get parsed as a string \ No newline at end of file diff --git a/railties/test/generators/generator_test_helper.rb b/railties/test/generators/generator_test_helper.rb index c99df6e2d3..05dca3400e 100644 --- a/railties/test/generators/generator_test_helper.rb +++ b/railties/test/generators/generator_test_helper.rb @@ -86,19 +86,19 @@ class GeneratorTestCase < Test::Unit::TestCase # don't complain, test/unit end - # Instantiates the Generator + # Instantiates the Generator. def build_generator(name, params) Rails::Generator::Base.instance(name, params) end - # Runs the create command (like the command line does) + # Runs the +create+ command (like the command line does). def run_generator(name, params) silence_generator do build_generator(name, params).command(:create).invoke! end end - # Silences the logger temporarily and returns the output as a String + # Silences the logger temporarily and returns the output as a String. def silence_generator logger_original = Rails::Generator::Base.logger myout = StringIO.new @@ -108,7 +108,7 @@ class GeneratorTestCase < Test::Unit::TestCase myout.string end - # asserts that the given controller was generated. + # Asserts that the given controller was generated. # It takes a name or symbol without the _controller part and an optional super class. # The contents of the class source file is passed to a block. def assert_generated_controller_for(name, parent = "ApplicationController") @@ -117,44 +117,44 @@ class GeneratorTestCase < Test::Unit::TestCase end end - # asserts that the given model was generated. + # Asserts that the given model was generated. # It takes a name or symbol and an optional super class. - # the contents of the class source file is passed to a block. + # The contents of the class source file is passed to a block. def assert_generated_model_for(name, parent = "ActiveRecord::Base") assert_generated_class "app/models/#{name.to_s.underscore}", parent do |body| yield body if block_given? end end - # asserts that the given helper was generated. - # It takes a name or symbol without the _helper part - # the contents of the module source file is passed to a block. + # Asserts that the given helper was generated. + # It takes a name or symbol without the _helper part. + # The contents of the module source file is passed to a block. def assert_generated_helper_for(name) assert_generated_module "app/helpers/#{name.to_s.underscore}_helper" do |body| yield body if block_given? end end - # asserts that the given functional test was generated. + # Asserts that the given functional test was generated. # It takes a name or symbol without the _controller_test part and an optional super class. - # the contents of the class source file is passed to a block. + # The contents of the class source file is passed to a block. def assert_generated_functional_test_for(name, parent = "ActionController::TestCase") assert_generated_class "test/functional/#{name.to_s.underscore}_controller_test",parent do |body| yield body if block_given? end end - # asserts that the given unit test was generated. + # Asserts that the given unit test was generated. # It takes a name or symbol without the _test part and an optional super class. - # the contents of the class source file is passed to a block. + # The contents of the class source file is passed to a block. def assert_generated_unit_test_for(name, parent = "ActiveSupport::TestCase") assert_generated_class "test/unit/#{name.to_s.underscore}_test", parent do |body| yield body if block_given? end end - # asserts that the given file was generated. - # the contents of the file is passed to a block. + # Asserts that the given file was generated. + # The contents of the file is passed to a block. def assert_generated_file(path) assert_file_exists(path) File.open("#{RAILS_ROOT}/#{path}") do |f| @@ -168,9 +168,9 @@ class GeneratorTestCase < Test::Unit::TestCase "The file '#{RAILS_ROOT}/#{path}' should exist" end - # asserts that the given class source file was generated. + # Asserts that the given class source file was generated. # It takes a path without the .rb part and an optional super class. - # the contents of the class source file is passed to a block. + # The contents of the class source file is passed to a block. def assert_generated_class(path, parent = nil) # FIXME: Sucky way to detect namespaced classes if path.split('/').size > 3 @@ -187,9 +187,9 @@ class GeneratorTestCase < Test::Unit::TestCase end end - # asserts that the given module source file was generated. + # Asserts that the given module source file was generated. # It takes a path without the .rb part. - # the contents of the class source file is passed to a block. + # The contents of the class source file is passed to a block. def assert_generated_module(path) # FIXME: Sucky way to detect namespaced modules if path.split('/').size > 3 @@ -206,18 +206,18 @@ class GeneratorTestCase < Test::Unit::TestCase end end - # asserts that the given css stylesheet file was generated. + # Asserts that the given CSS stylesheet file was generated. # It takes a path without the .css part. - # the contents of the stylesheet source file is passed to a block. + # The contents of the stylesheet source file is passed to a block. def assert_generated_stylesheet(path) assert_generated_file("public/stylesheets/#{path}.css") do |body| yield body if block_given? end end - # asserts that the given yaml file was generated. + # Asserts that the given YAML file was generated. # It takes a path without the .yml part. - # the parsed yaml tree is passed to a block. + # The parsed YAML tree is passed to a block. def assert_generated_yaml(path) assert_generated_file("#{path}.yml") do |body| yaml = YAML.load(body) @@ -226,18 +226,18 @@ class GeneratorTestCase < Test::Unit::TestCase end end - # asserts that the given fixtures yaml file was generated. + # Asserts that the given fixtures yaml file was generated. # It takes a fixture name without the .yml part. - # the parsed yaml tree is passed to a block. + # The parsed YAML tree is passed to a block. def assert_generated_fixtures_for(name) assert_generated_yaml "test/fixtures/#{name.to_s.underscore}" do |yaml| yield yaml if block_given? end end - # asserts that the given views were generated. + # Asserts that the given views were generated. # It takes a controller name and a list of views (including extensions). - # The body of each view is passed to a block + # The body of each view is passed to a block. def assert_generated_views_for(name, *actions) actions.each do |action| assert_generated_file("app/views/#{name.to_s.underscore}/#{action}") do |body| @@ -262,7 +262,7 @@ class GeneratorTestCase < Test::Unit::TestCase assert !File.exist?(migration_file), "should not create migration #{migration_file}" end - # asserts that the given resource was added to the routes. + # Asserts that the given resource was added to the routes. def assert_added_route_for(name) assert_generated_file("config/routes.rb") do |body| assert_match /map.resources :#{name.to_s.underscore}/, body, @@ -270,7 +270,7 @@ class GeneratorTestCase < Test::Unit::TestCase end end - # asserts that the given methods are defined in the body. + # Asserts that the given methods are defined in the body. # This does assume standard rails code conventions with regards to the source code. # The body of each individual method is passed to a block. def assert_has_method(body, *methods) @@ -280,7 +280,7 @@ class GeneratorTestCase < Test::Unit::TestCase end end - # asserts that the given column is defined in the migration + # Asserts that the given column is defined in the migration. def assert_generated_column(body, name, type) assert_match /t\.#{type.to_s} :#{name.to_s}/, body, "should have column #{name.to_s} defined" end -- cgit v1.2.3 From 8cad2844038f1fa34945981ce7e6cb630b483a3e Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sun, 25 May 2008 12:37:43 +0100 Subject: Merge --- activeresource/lib/active_resource/http_mock.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activeresource/lib/active_resource/http_mock.rb b/activeresource/lib/active_resource/http_mock.rb index ab219ef19d..dbff57ec2f 100644 --- a/activeresource/lib/active_resource/http_mock.rb +++ b/activeresource/lib/active_resource/http_mock.rb @@ -206,7 +206,7 @@ module ActiveResource end end - class Connection + class Connection private silence_warnings do def http -- cgit v1.2.3 From c82f317eaab7a350d0952621bb9962465de87790 Mon Sep 17 00:00:00 2001 From: Henrik N Date: Sun, 25 May 2008 16:17:04 +0200 Subject: yaml -> YAML --- railties/test/generators/generator_test_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/test/generators/generator_test_helper.rb b/railties/test/generators/generator_test_helper.rb index 05dca3400e..80d5b145be 100644 --- a/railties/test/generators/generator_test_helper.rb +++ b/railties/test/generators/generator_test_helper.rb @@ -226,7 +226,7 @@ class GeneratorTestCase < Test::Unit::TestCase end end - # Asserts that the given fixtures yaml file was generated. + # Asserts that the given fixtures YAML file was generated. # It takes a fixture name without the .yml part. # The parsed YAML tree is passed to a block. def assert_generated_fixtures_for(name) -- cgit v1.2.3 From f88267d532ecbfebb66b95863a4875b65507ddf3 Mon Sep 17 00:00:00 2001 From: gbuesing Date: Sun, 25 May 2008 11:56:29 -0500 Subject: TimeZone#to_s shows offset as GMT instead of UTC, because GMT will be more familiar to end users (see time zone selects used by Windows OS, google.com and yahoo.com.) Reverts [8370] --- activesupport/CHANGELOG | 2 ++ activesupport/lib/active_support/values/time_zone.rb | 2 +- activesupport/test/time_zone_test.rb | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 6250f33998..7e408840c4 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,3 +1,5 @@ +* TimeZone#to_s shows offset as GMT instead of UTC, because GMT will be more familiar to end users (see time zone selects used by Windows OS, google.com and yahoo.com.) Reverts [8370] [Geoff Buesing] + * Hash.from_xml: datetime xml types overflow to Ruby DateTime class when out of range of Time. Adding tests for utc offsets [Geoff Buesing] * TimeWithZone #+ and #- : ensure overflow to DateTime with Numeric arg [Geoff Buesing] diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 4d7239d8cf..a71c819fba 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -202,7 +202,7 @@ class TimeZone # Returns a textual representation of this time zone. def to_s - "(UTC#{formatted_offset}) #{name}" + "(GMT#{formatted_offset}) #{name}" end # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from given values. Example: diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb index 3757ddcedb..f3069b589b 100644 --- a/activesupport/test/time_zone_test.rb +++ b/activesupport/test/time_zone_test.rb @@ -252,7 +252,7 @@ class TimeZoneTest < Test::Unit::TestCase end def test_to_s - assert_equal "(UTC+03:00) Moscow", TimeZone['Moscow'].to_s + assert_equal "(GMT+03:00) Moscow", TimeZone['Moscow'].to_s end def test_all_sorted -- cgit v1.2.3 From 80bc36d808ba24ee7957aa5149336756824671c9 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 25 May 2008 20:39:45 +0200 Subject: revised markup in dirty.rb docs --- activerecord/lib/active_record/dirty.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/activerecord/lib/active_record/dirty.rb b/activerecord/lib/active_record/dirty.rb index 8fdc763292..d8355d2143 100644 --- a/activerecord/lib/active_record/dirty.rb +++ b/activerecord/lib/active_record/dirty.rb @@ -62,7 +62,7 @@ module ActiveRecord changed_attributes.keys end - # Map of changed attrs => [original value, new value] + # Map of changed attrs => [original value, new value]. # person.changes # => {} # person.name = 'bob' # person.changes # => { 'name' => ['bill', 'bob'] } @@ -93,27 +93,27 @@ module ActiveRecord end private - # Map of change attr => original value. + # Map of change attr => original value. def changed_attributes @changed_attributes ||= {} end - # Handle *_changed? for method_missing. + # Handle *_changed? for +method_missing+. def attribute_changed?(attr) changed_attributes.include?(attr) end - # Handle *_change for method_missing. + # Handle *_change for +method_missing+. def attribute_change(attr) [changed_attributes[attr], __send__(attr)] if attribute_changed?(attr) end - # Handle *_was for method_missing. + # Handle *_was for +method_missing+. def attribute_was(attr) attribute_changed?(attr) ? changed_attributes[attr] : __send__(attr) end - # Handle *_will_change! for method_missing. + # Handle *_will_change! for +method_missing+. def attribute_will_change!(attr) changed_attributes[attr] = clone_attribute_value(:read_attribute, attr) end -- cgit v1.2.3 From 9d9c96af56986b84a732aa609569b5035825f5f8 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 25 May 2008 20:51:18 +0200 Subject: revised some conventions in validations docs --- activerecord/lib/active_record/validations.rb | 46 +++++++++++++-------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 0e150bddb2..7f04dc4c1a 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -1,5 +1,5 @@ module ActiveRecord - # Raised by save! and create! when the record is invalid. Use the + # Raised by save! and create! when the record is invalid. Use the # +record+ method to retrieve the record which did not validate. # begin # complex_operation_that_calls_save!_internally @@ -52,7 +52,7 @@ module ActiveRecord # Adds an error to the base object instead of any particular attribute. This is used # to report errors that don't tie to any specific attribute, but rather to the object # as a whole. These error messages don't get prepended with any field name when iterating - # with each_full, so they should be complete sentences. + # with +each_full+, so they should be complete sentences. def add_to_base(msg) add(:base, msg) end @@ -97,7 +97,7 @@ module ActiveRecord !@errors[attribute.to_s].nil? end - # Returns nil, if no errors are associated with the specified +attribute+. + # Returns +nil+, if no errors are associated with the specified +attribute+. # Returns the error message, if one error is associated with the specified +attribute+. # Returns an array of error messages, if more than one error is associated with the specified +attribute+. # @@ -118,7 +118,7 @@ module ActiveRecord alias :[] :on - # Returns errors assigned to the base object through add_to_base according to the normal rules of on(attribute). + # Returns errors assigned to the base object through +add_to_base+ according to the normal rules of on(attribute). def on_base on(:base) end @@ -131,15 +131,15 @@ module ActiveRecord # end # # company = Company.create(:address => '123 First St.') - # company.errors.each{|attr,msg| puts "#{attr} - #{msg}" } # => - # name - is too short (minimum is 5 characters) - # name - can't be blank - # address - can't be blank + # company.errors.each{|attr,msg| puts "#{attr} - #{msg}" } + # # => name - is too short (minimum is 5 characters) + # # name - can't be blank + # # address - can't be blank def each @errors.each_key { |attr| @errors[attr].each { |msg| yield attr, msg } } end - # Yields each full error message added. So Person.errors.add("first_name", "can't be empty") will be returned + # Yields each full error message added. So Person.errors.add("first_name", "can't be empty") will be returned # through iteration as "First name can't be empty". # # class Company < ActiveRecord::Base @@ -148,10 +148,10 @@ module ActiveRecord # end # # company = Company.create(:address => '123 First St.') - # company.errors.each_full{|msg| puts msg } # => - # Name is too short (minimum is 5 characters) - # Name can't be blank - # Address can't be blank + # company.errors.each_full{|msg| puts msg } + # # => Name is too short (minimum is 5 characters) + # # Name can't be blank + # # Address can't be blank def each_full full_messages.each { |msg| yield msg } end @@ -164,8 +164,8 @@ module ActiveRecord # end # # company = Company.create(:address => '123 First St.') - # company.errors.full_messages # => - # ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Address can't be blank"] + # company.errors.full_messages + # # => ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Address can't be blank"] def full_messages full_messages = [] @@ -209,13 +209,13 @@ module ActiveRecord # end # # company = Company.create(:address => '123 First St.') - # company.errors.to_xml # => - # - # - # Name is too short (minimum is 5 characters) - # Name can't be blank - # Address can't be blank - # + # company.errors.to_xml + # # => + # # + # # Name is too short (minimum is 5 characters) + # # Name can't be blank + # # Address can't be blank + # # def to_xml(options={}) options[:root] ||= "errors" options[:indent] ||= 2 @@ -261,7 +261,7 @@ module ActiveRecord # person.errors.on "phone_number" # => "has invalid format" # person.errors.each_full { |msg| puts msg } # # => "Last name can't be empty\n" + - # "Phone number has invalid format" + # # "Phone number has invalid format" # # person.attributes = { "last_name" => "Heinemeier", "phone_number" => "555-555" } # person.save # => true (and person is now saved in the database) -- cgit v1.2.3 From c5d37c0662a65ce9723d668f57b59457e79ee5ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tarmo=20T=C3=A4nav?= Date: Mon, 26 May 2008 01:28:56 +0300 Subject: Fix tests for postgres 8.3.x Made test_with_limiting_with_custom_select not dependent on database default order. Fixed tests with non-US monetary locale. The monetary type is fixed precision so it should not expect the database to return a float. Signed-off-by: Pratik Naik --- activerecord/test/cases/datatype_test_postgresql.rb | 8 ++++---- activerecord/test/cases/finder_test.rb | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/activerecord/test/cases/datatype_test_postgresql.rb b/activerecord/test/cases/datatype_test_postgresql.rb index 41726ce518..bff092b5d7 100644 --- a/activerecord/test/cases/datatype_test_postgresql.rb +++ b/activerecord/test/cases/datatype_test_postgresql.rb @@ -30,8 +30,8 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase @connection.execute("INSERT INTO postgresql_arrays (commission_by_quarter, nicknames) VALUES ( '{35000,21000,18000,17000}', '{foo,bar,baz}' )") @first_array = PostgresqlArray.find(1) - @connection.execute("INSERT INTO postgresql_moneys (wealth) VALUES ('$567.89')") - @connection.execute("INSERT INTO postgresql_moneys (wealth) VALUES ('-$567.89')") + @connection.execute("INSERT INTO postgresql_moneys (wealth) VALUES ('567.89'::money)") + @connection.execute("INSERT INTO postgresql_moneys (wealth) VALUES ('-567.89'::money)") @first_money = PostgresqlMoney.find(1) @second_money = PostgresqlMoney.find(2) @@ -143,11 +143,11 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase end def test_update_money - new_value = 123.45 + new_value = BigDecimal.new('123.45') assert @first_money.wealth = new_value assert @first_money.save assert @first_money.reload - assert_equal @first_money.wealth, new_value + assert_equal new_value, @first_money.wealth end def test_update_number diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 5c0f0e2ef1..80936d51f3 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -867,7 +867,7 @@ class FinderTest < ActiveRecord::TestCase end def test_with_limiting_with_custom_select - posts = Post.find(:all, :include => :author, :select => ' posts.*, authors.id as "author_id"', :limit => 3) + posts = Post.find(:all, :include => :author, :select => ' posts.*, authors.id as "author_id"', :limit => 3, :order => 'posts.id') assert_equal 3, posts.size assert_equal [0, 1, 1], posts.map(&:author_id).sort end -- cgit v1.2.3 From 7520770c825eab21079dd2b69b1199f138294301 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 26 May 2008 01:38:56 -0700 Subject: Don't require AV::TestCases to have a helper class. Only include the helper class in setup if it hasn't been already. --- actionpack/lib/action_view/test_case.rb | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index b2e6589d81..16fedd9732 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -1,14 +1,6 @@ require 'active_support/test_case' module ActionView - class NonInferrableHelperError < ActionViewError - def initialize(name) - super "Unable to determine the helper to test from #{name}. " + - "You'll need to specify it using tests YourHelper in your " + - "test case definition" - end - end - class TestCase < ActiveSupport::TestCase class_inheritable_accessor :helper_class @@helper_class = nil @@ -29,7 +21,7 @@ module ActionView def determine_default_helper_class(name) name.sub(/Test$/, '').constantize rescue NameError - raise NonInferrableHelperError.new(name) + nil end end @@ -42,7 +34,9 @@ module ActionView setup :setup_with_helper_class def setup_with_helper_class - self.class.send(:include, helper_class) + if helper_class && !self.class.ancestors.include?(helper_class) + self.class.send(:include, helper_class) + end end class TestController < ActionController::Base -- cgit v1.2.3 From 888a2927b65889465ce7a1a71e87d37640a2b41b Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 26 May 2008 01:39:21 -0700 Subject: Remove superfluous tests directive --- actionpack/test/template/prototype_helper_test.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb index 5e00eadb8d..53a250f9d5 100644 --- a/actionpack/test/template/prototype_helper_test.rb +++ b/actionpack/test/template/prototype_helper_test.rb @@ -25,8 +25,6 @@ class Author::Nested < Author; end class PrototypeHelperBaseTest < ActionView::TestCase - tests ActionView::Helpers::PrototypeHelper - attr_accessor :template_format def setup -- cgit v1.2.3 From bb64660c30705e3864f1ffa5beeafe7d09813ad9 Mon Sep 17 00:00:00 2001 From: Balint Erdi Date: Tue, 27 May 2008 23:52:00 +0200 Subject: a tiny, one-word change Signed-off-by: Balint Erdi --- actionpack/lib/action_controller/caching/fragments.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_controller/caching/fragments.rb b/actionpack/lib/action_controller/caching/fragments.rb index e4f5de44ab..578e031a17 100644 --- a/actionpack/lib/action_controller/caching/fragments.rb +++ b/actionpack/lib/action_controller/caching/fragments.rb @@ -2,7 +2,7 @@ module ActionController #:nodoc: module Caching # Fragment caching is used for caching various blocks within templates without caching the entire action as a whole. This is useful when # certain elements of an action change frequently or depend on complicated state while other parts rarely change or can be shared amongst multiple - # parties. The caching is doing using the cache helper available in the Action View. A template with caching might look something like: + # parties. The caching is done using the cache helper available in the Action View. A template with caching might look something like: # # Hello <%= @name %> # <% cache do %> -- cgit v1.2.3 From c5bd2318be0395b7f90c39a29d671c955d1a5d49 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Tue, 27 May 2008 23:53:21 +0200 Subject: small fix in ActiveResource::Base docs --- activeresource/lib/active_resource/base.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index 463ee9f1e7..26931e5e4a 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -200,7 +200,7 @@ module ActiveResource cattr_accessor :logger class << self - # Gets the URI of the REST resources to map for this class. The site variable is required + # Gets the URI of the REST resources to map for this class. The site variable is required for # Active Resource's mapping to work. def site # Not using superclass_delegating_reader because don't want subclasses to modify superclass instance @@ -226,7 +226,7 @@ module ActiveResource end # Sets the URI of the REST resources to map for this class to the value in the +site+ argument. - # The site variable is required Active Resource's mapping to work. + # The site variable is required for Active Resource's mapping to work. def site=(site) @connection = nil if site.nil? -- cgit v1.2.3 From 7ac40187864c5a9d1837fb59dea170acd30699c5 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Tue, 27 May 2008 23:58:45 +0200 Subject: Active Resource instance -> ActiveResource::Base instance --- activeresource/lib/active_resource/custom_methods.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activeresource/lib/active_resource/custom_methods.rb b/activeresource/lib/active_resource/custom_methods.rb index 4c8699288c..770116ceb7 100644 --- a/activeresource/lib/active_resource/custom_methods.rb +++ b/activeresource/lib/active_resource/custom_methods.rb @@ -48,8 +48,8 @@ module ActiveResource # # => [{:id => 1, :name => 'Ryan'}] # # Note: the objects returned from this method are not automatically converted - # into Active Resource instances - they are ordinary Hashes. If you are expecting - # Active Resource instances, use the find class method with the + # into ActiveResource::Base instances - they are ordinary Hashes. If you are expecting + # ActiveResource::Base instances, use the find class method with the # :from option. For example: # # Person.find(:all, :from => :active) -- cgit v1.2.3 From 4be3c2c92fed516aca2fcb1ba9fc253bda580d25 Mon Sep 17 00:00:00 2001 From: Nick Plante Date: Tue, 27 May 2008 23:21:34 -0400 Subject: fix spelling error --- activeresource/lib/active_resource/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index 26931e5e4a..82aa133bb1 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -298,7 +298,7 @@ module ActiveResource @timeout = timeout end - # Gets tthe number of seconds after which requests to the REST API should time out. + # Gets the number of seconds after which requests to the REST API should time out. def timeout if defined?(@timeout) @timeout -- cgit v1.2.3 From a8e32152fcd07786fc6b0a58d999267bc3ddec04 Mon Sep 17 00:00:00 2001 From: Nick Plante Date: Tue, 27 May 2008 23:32:47 -0400 Subject: update language and use proper fonts for method names --- activeresource/lib/active_resource/base.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index 82aa133bb1..253d336dc9 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -426,16 +426,16 @@ module ActiveResource alias_method :set_primary_key, :primary_key= #:nodoc: - # Create a new resource instance and request to the remote service + # Creates a new resource instance and makes a request to the remote service # that it be saved, making it equivalent to the following simultaneous calls: # # ryan = Person.new(:first => 'ryan') # ryan.save # - # The newly created resource is returned. If a failure has occurred an - # exception will be raised (see save). If the resource is invalid and - # has not been saved then valid? will return false, - # while new? will still return true. + # Returns the newly created resource. If a failure has occurred an + # exception will be raised (see save). If the resource is invalid and + # has not been saved then valid? will return false, + # while new? will still return true. # # ==== Examples # Person.create(:name => 'Jeremy', :email => 'myname@nospam.com', :enabled => true) -- cgit v1.2.3 From c2fbcba16d2349285368c86b849db946dc0e7d57 Mon Sep 17 00:00:00 2001 From: Ryan Bates Date: Tue, 27 May 2008 07:31:53 -0700 Subject: Ensure named_scope#empty? uses count query. [#262 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/named_scope.rb | 6 +++++- activerecord/test/cases/named_scope_test.rb | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 69b7da7700..b0c8a8b815 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -102,7 +102,7 @@ module ActiveRecord attr_reader :proxy_scope, :proxy_options [].methods.each do |m| - unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|find|count|sum|average|maximum|minimum|paginate|first|last)/ + unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|find|count|sum|average|maximum|minimum|paginate|first|last|empty?)/ delegate m, :to => :proxy_found end end @@ -135,6 +135,10 @@ module ActiveRecord end end + def empty? + @found ? @found.empty? : count.zero? + end + protected def proxy_found @found || load_found diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb index 8f2fc53d67..d890cf7936 100644 --- a/activerecord/test/cases/named_scope_test.rb +++ b/activerecord/test/cases/named_scope_test.rb @@ -146,4 +146,12 @@ class NamedScopeTest < ActiveRecord::TestCase end end + def test_empty_should_not_load_results + topics = Topic.base + assert_queries(2) do + topics.empty? # use count query + topics.collect # force load + topics.empty? # use loaded (no query) + end + end end -- cgit v1.2.3 From 5b69bcde07513499158dc98c47084fb9882fdf78 Mon Sep 17 00:00:00 2001 From: Jacqui Maher Date: Wed, 28 May 2008 10:10:24 -0400 Subject: fixed typo in url_helper & added comments on usage to js (link|button)_to_function helpers --- .../lib/action_view/helpers/javascript_helper.rb | 23 +++++++++++++++++++--- actionpack/lib/action_view/helpers/url_helper.rb | 2 +- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb index 1ea3cbd74e..ed931e064f 100644 --- a/actionpack/lib/action_view/helpers/javascript_helper.rb +++ b/actionpack/lib/action_view/helpers/javascript_helper.rb @@ -43,14 +43,23 @@ module ActionView end include PrototypeHelper - - # Returns a link that will trigger a JavaScript +function+ using the + + # Returns a link of the given +name+ that will trigger a JavaScript +function+ using the # onclick handler and return false after the fact. # + # The first argument +name+ is used as the link text. + # + # The next arguments are optional and may include the javascript function definition and a hash of html_options. + # # The +function+ argument can be omitted in favor of an +update_page+ # block, which evaluates to a string when the template is rendered # (instead of making an Ajax request first). # + # The +html_options+ will accept a hash of html attributes for the link tag. Some examples are :class => "nav_button", :id => "articles_nav_button" + # + # Note: if you choose to specify the javascript function in a block, but would like to pass html_options, set the +function+ parameter to nil + # + # # Examples: # link_to_function "Greeting", "alert('Hello world!')" # Produces: @@ -94,13 +103,21 @@ module ActionView ) end - # Returns a button that'll trigger a JavaScript +function+ using the + # Returns a button with the given +name+ text that'll trigger a JavaScript +function+ using the # onclick handler. # + # The first argument +name+ is used as the button's value or display text. + # + # The next arguments are optional and may include the javascript function definition and a hash of html_options. + # # The +function+ argument can be omitted in favor of an +update_page+ # block, which evaluates to a string when the template is rendered # (instead of making an Ajax request first). # + # The +html_options+ will accept a hash of html attributes for the link tag. Some examples are :class => "nav_button", :id => "articles_nav_button" + # + # Note: if you choose to specify the javascript function in a block, but would like to pass html_options, set the +function+ parameter to nil + # # Examples: # button_to_function "Greeting", "alert('Hello world!')" # button_to_function "Delete", "if (confirm('Really?')) do_delete()" diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index 4b12adf225..7bb189420b 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -173,7 +173,7 @@ module ActionView # link_to "Nonsense search", searches_path(:foo => "bar", :baz => "quux") # # => Nonsense search # - # The three options specfic to +link_to+ (:confirm, :popup, and :method) are used as follows: + # The three options specific to +link_to+ (:confirm, :popup, and :method) are used as follows: # # link_to "Visit Other Site", "http://www.rubyonrails.org/", :confirm => "Are you sure?" # # => Visit Other Site -- cgit v1.2.3 From c75cfa0e545024b8011a9b350c911ee590a4d3a0 Mon Sep 17 00:00:00 2001 From: scottwillson Date: Wed, 28 May 2008 07:38:20 -0700 Subject: Updated README example to ActionController::TestCase from Test::Unit::TestCase. Added usage example for ActionController::TestCase. --- actionpack/README | 18 ++++++------------ actionpack/lib/action_controller/test_case.rb | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/actionpack/README b/actionpack/README index 2746c3cc43..6090089bb9 100644 --- a/actionpack/README +++ b/actionpack/README @@ -31,7 +31,7 @@ http://www.rubyonrails.org. A short rundown of the major features: * Actions grouped in controller as methods instead of separate command objects - and can therefore share helper methods. + and can therefore share helper methods BlogController < ActionController::Base def show @@ -168,7 +168,7 @@ A short rundown of the major features: {Learn more}[link:classes/ActionController/Base.html] -* Javascript and Ajax integration. +* Javascript and Ajax integration link_to_function "Greeting", "alert('Hello world!')" link_to_remote "Delete this post", :update => "posts", @@ -177,7 +177,7 @@ A short rundown of the major features: {Learn more}[link:classes/ActionView/Helpers/JavaScriptHelper.html] -* Pagination for navigating lists of results. +* Pagination for navigating lists of results # controller def list @@ -192,15 +192,9 @@ A short rundown of the major features: {Learn more}[link:classes/ActionController/Pagination.html] -* Easy testing of both controller and template result through TestRequest/Response - - class LoginControllerTest < Test::Unit::TestCase - def setup - @controller = LoginController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - end +* Easy testing of both controller and rendered template through ActionController::TestCase + class LoginControllerTest < ActionController::TestCase def test_failing_authenticate process :authenticate, :user_name => "nop", :password => "" assert flash.has_key?(:alert) @@ -208,7 +202,7 @@ A short rundown of the major features: end end - {Learn more}[link:classes/ActionController/TestRequest.html] + {Learn more}[link:classes/ActionController/TestCase.html] * Automated benchmarking and integrated logging diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index 77c6f26eac..f26e65ba34 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -15,6 +15,27 @@ module ActionController end end + # Superclass for Action Controller functional tests. Infers the controller under test from the test class name, + # and creates @controller, @request, @response instance variables. + # + # class WidgetsControllerTest < ActionController::TestCase + # def test_index + # get :index + # end + # end + # + # * @controller - WidgetController.new + # * @request - ActionController::TestRequest.new + # * @response - ActionController::TestResponse.new + # + # (Earlier versions of Rails required each functional test to subclass Test::Unit::TestCase and define + # @controller, @request, @response in +setup+.) + # + # If the controller cannot be inferred from the test class name, you can explicity set it with +tests+. + # + # class SpecialEdgeCaseWidgetsControllerTest < ActionController::TestCase + # tests WidgetController + # end class TestCase < ActiveSupport::TestCase # When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline # (bystepping the regular exception handling from rescue_action). If the request.remote_addr is anything else, the regular @@ -41,6 +62,8 @@ module ActionController @@controller_class = nil class << self + # Sets the controller class name. Useful if the name can't be inferred from test class. + # Expects +controller_class+ as a constant. Example: tests WidgetController. def tests(controller_class) self.controller_class = controller_class end -- cgit v1.2.3 From 4d248543429918bc5a63e109e6f2327ffab9848b Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Wed, 28 May 2008 22:58:45 +0100 Subject: Ensure correct db time is reported in production logs. --- .../active_record/connection_adapters/abstract_adapter.rb | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 8c286f64db..f48b107a2a 100755 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -128,15 +128,11 @@ module ActiveRecord protected def log(sql, name) if block_given? - if @logger and @logger.debug? - result = nil - seconds = Benchmark.realtime { result = yield } - @runtime += seconds - log_info(sql, name, seconds) - result - else - yield - end + result = nil + seconds = Benchmark.realtime { result = yield } + @runtime += seconds + log_info(sql, name, seconds) + result else log_info(sql, name, 0) nil -- cgit v1.2.3 From 305eb5b031b1f2489e9963368358b7e9a16c0d00 Mon Sep 17 00:00:00 2001 From: JD Huntington Date: Wed, 28 May 2008 23:49:09 -0700 Subject: added useful example for actionview's debug() --- actionpack/lib/action_view/helpers/debug_helper.rb | 33 +++++++++++++--------- .../lib/action_view/helpers/form_options_helper.rb | 8 ++++-- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/actionpack/lib/action_view/helpers/debug_helper.rb b/actionpack/lib/action_view/helpers/debug_helper.rb index 20de7e465f..ea70a697de 100644 --- a/actionpack/lib/action_view/helpers/debug_helper.rb +++ b/actionpack/lib/action_view/helpers/debug_helper.rb @@ -2,21 +2,28 @@ module ActionView module Helpers # Provides a set of methods for making it easier to debug Rails objects. module DebugHelper - # Returns a
-tag that has +object+ dumped by YAML. This creates a very
-      # readable way to inspect an object.
+      # Returns a YAML representation of +object+ wrapped with 
 and 
. + # If the object cannot be converted to YAML using +to_yaml+, +inspect+ will be called instead. + # Useful for inspecting an object at the time of rendering. # # ==== Example - # my_hash = {'first' => 1, 'second' => 'two', 'third' => [1,2,3]} - # debug(my_hash) # - # =>
--- 
-      #  first: 1
-      #  second: two
-      #  third: 
-      #  - 1
-      #  - 2
-      #  - 3
-      #  
+ # @user = User.new({ :username => 'testing', :password => 'xyz', :age => 42}) %> + # debug(@user) + # # => + #
--- !ruby/object:User 
+      #   attributes: 
+      #     updated_at: 
+      #     username: testing
+      #   
+      #     age: 42
+      #     password: xyz
+      #     created_at: 
+      #   attributes_cache: {}
+      #   
+      #   new_record: true
+      #   
+ def debug(object) begin Marshal::dump(object) @@ -28,4 +35,4 @@ module ActionView end end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index e0a097e367..c0cba24be4 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -271,9 +271,11 @@ module ActionView end end - # Returns a string of option tags for pretty much any country in the world. Supply a country name as +selected+ to - # have it marked as the selected option tag. You can also supply an array of countries as +priority_countries+, so - # that they will be listed above the rest of the (long) list. + # Returns a string of option tags for most countries in the + # world (as defined in COUNTRIES). Supply a country name as + # +selected+ to have it marked as the selected option tag. You + # can also supply an array of countries as +priority_countries+, + # so that they will be listed above the rest of the (long) list. # # NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag. def country_options_for_select(selected = nil, priority_countries = nil) -- cgit v1.2.3 From abb1bd2efa43b8efbb3faf4ccfb9246704a9044c Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Thu, 29 May 2008 10:20:39 +0100 Subject: Ensure AssociationCollection#count works with empty condition. [#271 state:resolved] [Jan De Poorter] --- activerecord/lib/active_record/associations/has_many_association.rb | 2 +- activerecord/test/cases/associations/has_many_associations_test.rb | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index 963a938485..f584a97cbb 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -9,7 +9,7 @@ module ActiveRecord @reflection.klass.count_by_sql(@finder_sql) else column_name, options = @reflection.klass.send(:construct_count_options_from_args, *args) - options[:conditions] = options[:conditions].nil? ? + options[:conditions] = options[:conditions].blank? ? @finder_sql : @finder_sql + " AND (#{sanitize_sql(options[:conditions])})" options[:include] ||= @reflection.options[:include] diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 53b55022eb..cbc621b411 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -32,6 +32,10 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 2, Firm.find(:first).plain_clients.count end + def test_counting_with_empty_hash_conditions + assert_equal 2, Firm.find(:first).plain_clients.count(:conditions => {}) + end + def test_counting_with_single_conditions assert_equal 2, Firm.find(:first).plain_clients.count(:conditions => '1=1') end -- cgit v1.2.3 From cf6299dbd73a8cb6d74265df03d01abe885e686a Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 23 May 2008 10:40:36 -0700 Subject: Add ActionMailer#reply_to. [#245 state:resolved] Signed-off-by: Pratik Naik --- actionmailer/lib/action_mailer/base.rb | 20 +++++++++++------- actionmailer/lib/action_mailer/quoting.rb | 2 +- actionmailer/test/mail_service_test.rb | 34 +++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 030bb178da..e065132107 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -35,7 +35,8 @@ module ActionMailer #:nodoc: # * subject - The subject of your email. Sets the Subject: header. # * from - Who the email you are sending is from. Sets the From: header. # * cc - Takes one or more email addresses. These addresses will receive a carbon copy of your email. Sets the Cc: header. - # * bcc - Takes one or more email address. These addresses will receive a blind carbon copy of your email. Sets the Bcc: header. + # * bcc - Takes one or more email addresses. These addresses will receive a blind carbon copy of your email. Sets the Bcc: header. + # * reply_to - Takes one or more email addresses. These addresses will be listed as the default recipients when replying to your email. Sets the Reply-To: header. # * sent_on - The date on which the message was sent. If not set, the header wil be set by the delivery agent. # * content_type - Specify the content type of the message. Defaults to text/plain. # * headers - Specify additional headers to be set for the message, e.g. headers 'X-Mail-Count' => 107370. @@ -317,6 +318,10 @@ module ActionMailer #:nodoc: # Specify the from address for the message. adv_attr_accessor :from + # Specify the address (if different than the "from" address) to direct + # replies to this message. + adv_attr_accessor :reply_to + # Specify additional headers to be added to the message. adv_attr_accessor :headers @@ -576,13 +581,14 @@ module ActionMailer #:nodoc: def create_mail m = TMail::Mail.new - m.subject, = quote_any_if_necessary(charset, subject) - m.to, m.from = quote_any_address_if_necessary(charset, recipients, from) - m.bcc = quote_address_if_necessary(bcc, charset) unless bcc.nil? - m.cc = quote_address_if_necessary(cc, charset) unless cc.nil? - + m.subject, = quote_any_if_necessary(charset, subject) + m.to, m.from = quote_any_address_if_necessary(charset, recipients, from) + m.bcc = quote_address_if_necessary(bcc, charset) unless bcc.nil? + m.cc = quote_address_if_necessary(cc, charset) unless cc.nil? + m.reply_to = quote_address_if_necessary(reply_to, charset) unless reply_to.nil? m.mime_version = mime_version unless mime_version.nil? - m.date = sent_on.to_time rescue sent_on if sent_on + m.date = sent_on.to_time rescue sent_on if sent_on + headers.each { |k, v| m[k] = v } real_content_type, ctype_attrs = parse_content_type diff --git a/actionmailer/lib/action_mailer/quoting.rb b/actionmailer/lib/action_mailer/quoting.rb index b222432787..a2f2c70799 100644 --- a/actionmailer/lib/action_mailer/quoting.rb +++ b/actionmailer/lib/action_mailer/quoting.rb @@ -40,7 +40,7 @@ module ActionMailer # regular email address, or it can be a phrase followed by an address in # brackets. The phrase is the only part that will be quoted, and only if # it needs to be. This allows extended characters to be used in the - # "to", "from", "cc", and "bcc" headers. + # "to", "from", "cc", "bcc" and "reply-to" headers. def quote_address_if_necessary(address, charset) if Array === address address.map { |a| quote_address_if_necessary(a, charset) } diff --git a/actionmailer/test/mail_service_test.rb b/actionmailer/test/mail_service_test.rb index 57a651ccd4..e5ecb0e254 100755 --- a/actionmailer/test/mail_service_test.rb +++ b/actionmailer/test/mail_service_test.rb @@ -40,6 +40,15 @@ class TestMailer < ActionMailer::Base body "Nothing to see here." end + def different_reply_to(recipient) + recipients recipient + subject "testing reply_to" + from "system@loudthinking.com" + sent_on Time.local(2008, 5, 23) + reply_to "atraver@gmail.com" + body "Nothing to see here." + end + def iso_charset(recipient) @recipients = recipient @subject = "testing isø charsets" @@ -445,6 +454,31 @@ class ActionMailerTest < Test::Unit::TestCase assert_equal expected.encoded, ActionMailer::Base.deliveries.first.encoded end + def test_reply_to + expected = new_mail + + expected.to = @recipient + expected.subject = "testing reply_to" + expected.body = "Nothing to see here." + expected.from = "system@loudthinking.com" + expected.reply_to = "atraver@gmail.com" + expected.date = Time.local 2008, 5, 23 + + created = nil + assert_nothing_raised do + created = TestMailer.create_different_reply_to @recipient + end + assert_not_nil created + assert_equal expected.encoded, created.encoded + + assert_nothing_raised do + TestMailer.deliver_different_reply_to @recipient + end + + assert_not_nil ActionMailer::Base.deliveries.first + assert_equal expected.encoded, ActionMailer::Base.deliveries.first.encoded + end + def test_iso_charset expected = new_mail( "iso-8859-1" ) expected.to = @recipient -- cgit v1.2.3 From 235d635708dd72bee0828457af5397c79750483a Mon Sep 17 00:00:00 2001 From: Andrew White Date: Thu, 29 May 2008 12:59:29 +0100 Subject: Ensure :select passed in options overrides the one from the scope. [#239 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/base.rb | 2 +- activerecord/test/cases/method_scoping_test.rb | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index c393128621..d2d9bda6ba 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1457,7 +1457,7 @@ module ActiveRecord #:nodoc: def construct_finder_sql(options) scope = scope(:find) - sql = "SELECT #{(scope && scope[:select]) || options[:select] || (options[:joins] && quoted_table_name + '.*') || '*'} " + sql = "SELECT #{options[:select] || (scope && scope[:select]) || (options[:joins] && quoted_table_name + '.*') || '*'} " sql << "FROM #{(scope && scope[:from]) || options[:from] || quoted_table_name} " add_joins!(sql, options, scope) diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb index 4b5bd6c951..1a9a875730 100644 --- a/activerecord/test/cases/method_scoping_test.rb +++ b/activerecord/test/cases/method_scoping_test.rb @@ -50,6 +50,22 @@ class MethodScopingTest < ActiveRecord::TestCase end end + def test_scoped_find_select + Developer.with_scope(:find => { :select => "id, name" }) do + developer = Developer.find(:first, :conditions => "name = 'David'") + assert_equal "David", developer.name + assert !developer.has_attribute?(:salary) + end + end + + def test_options_select_replaces_scope_select + Developer.with_scope(:find => { :select => "id, name" }) do + developer = Developer.find(:first, :select => 'id, salary', :conditions => "name = 'David'") + assert_equal 80000, developer.salary + assert !developer.has_attribute?(:name) + end + end + def test_scoped_count Developer.with_scope(:find => { :conditions => "name = 'David'" }) do assert_equal 1, Developer.count -- cgit v1.2.3 From d2e2c02879110602909f31a804e4eb4a6f3419b5 Mon Sep 17 00:00:00 2001 From: Jeremy McAnally Date: Thu, 29 May 2008 13:29:51 -0400 Subject: Start narrative documtentation --- railties/doc/guides/activerecord/basics.markdown | 56 ++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 railties/doc/guides/activerecord/basics.markdown diff --git a/railties/doc/guides/activerecord/basics.markdown b/railties/doc/guides/activerecord/basics.markdown new file mode 100644 index 0000000000..de882b45e6 --- /dev/null +++ b/railties/doc/guides/activerecord/basics.markdown @@ -0,0 +1,56 @@ +Active Record Basics +==================== + + + +The ActiveRecord Pattern +------------------------ + +Active Record (the library) conforms to the active record design pattern. The active record pattern is a design pattern often found in applications that use relational database. The name comes from by Martin Fowler's book *Patterns of Enterprise Application Architecture*, in which he describes an active record object as: + +> An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data. + +So, an object that follows the active record pattern encapsulates both data and behavior; in other words, they are responsible for saving and loading to the database and also for any domain logic that acts on the data. The data structure of the Active Record should exactly match that of the database: one field in the class for each column in the table. + +The Active Record class typically has methods that do the following: + +* Construct an instances of an Active Record class from a SQL result +* Construct a new class instance for insertion into the table +* Get and set column values +* Wrap business logic where appropriate +* Update existing objects and update the related rows in the database + +Mapping Your Database +--------------------- + +### Plural tables, singular classes ### + +### Schema lives in the database ### + +Creating Records +---------------- + +### Using save ### + +### Using create ### + +Retrieving Existing Rows +------------------------ + +### Using find ### + +### Using find_by_* ### + +Editing and Updating Rows +------------------------- + +### Editing an instance + +### Using update_all/update_attributes ### + +Deleting Data +------------- + +### Destroying a record ### + +### Deleting a record ### \ No newline at end of file -- cgit v1.2.3 From 377b2fdd0817d4706df9a5de13e651f1928c5e81 Mon Sep 17 00:00:00 2001 From: Cheah Chu Yeow Date: Thu, 29 May 2008 12:15:12 -0700 Subject: Add examples for #to_json for Date, Time, DateTime, TimeWithZone for the case when ActiveSupport.use_standard_json_time_format = true (and also when it is false). --- activesupport/lib/active_support/json.rb | 2 +- activesupport/lib/active_support/json/encoders/date.rb | 11 +++++++++-- .../lib/active_support/json/encoders/date_time.rb | 11 +++++++++-- activesupport/lib/active_support/json/encoders/time.rb | 13 ++++++++++--- activesupport/lib/active_support/time_with_zone.rb | 14 +++++++++++++- 5 files changed, 42 insertions(+), 9 deletions(-) diff --git a/activesupport/lib/active_support/json.rb b/activesupport/lib/active_support/json.rb index 54a7becd0f..2bdb4a7b11 100644 --- a/activesupport/lib/active_support/json.rb +++ b/activesupport/lib/active_support/json.rb @@ -1,5 +1,5 @@ module ActiveSupport - # If true, use ISO 8601 format for dates and times. Otherwise, fall back to the Active Support legacy format. + # If true, use ISO 8601 format for dates and times. Otherwise, fall back to the Active Support legacy format. mattr_accessor :use_standard_json_time_format class << self diff --git a/activesupport/lib/active_support/json/encoders/date.rb b/activesupport/lib/active_support/json/encoders/date.rb index cb9419d29d..1fc99c466f 100644 --- a/activesupport/lib/active_support/json/encoders/date.rb +++ b/activesupport/lib/active_support/json/encoders/date.rb @@ -1,7 +1,14 @@ class Date - # Returns a JSON string representing the date. + # Returns a JSON string representing the date. If ActiveSupport.use_standard_json_time_format is set to true, the + # ISO 8601 format is used. # - # ==== Example: + # ==== Examples: + # + # # With ActiveSupport.use_standard_json_time_format = true + # Date.new(2005,2,1).to_json + # # => "2005-02-01" + # + # # With ActiveSupport.use_standard_json_time_format = false # Date.new(2005,2,1).to_json # # => "2005/02/01" def to_json(options = nil) diff --git a/activesupport/lib/active_support/json/encoders/date_time.rb b/activesupport/lib/active_support/json/encoders/date_time.rb index d41c3e9786..cd96cda1f7 100644 --- a/activesupport/lib/active_support/json/encoders/date_time.rb +++ b/activesupport/lib/active_support/json/encoders/date_time.rb @@ -1,7 +1,14 @@ class DateTime - # Returns a JSON string representing the datetime. + # Returns a JSON string representing the datetime. If ActiveSupport.use_standard_json_time_format is set to true, the + # ISO 8601 format is used. # - # ==== Example: + # ==== Examples: + # + # # With ActiveSupport.use_standard_json_time_format = true + # DateTime.civil(2005,2,1,15,15,10).to_json + # # => "2005-02-01T15:15:10+00:00" + # + # # With ActiveSupport.use_standard_json_time_format = false # DateTime.civil(2005,2,1,15,15,10).to_json # # => "2005/02/01 15:15:10 +0000" def to_json(options = nil) diff --git a/activesupport/lib/active_support/json/encoders/time.rb b/activesupport/lib/active_support/json/encoders/time.rb index 57ed3c9e31..09fc614889 100644 --- a/activesupport/lib/active_support/json/encoders/time.rb +++ b/activesupport/lib/active_support/json/encoders/time.rb @@ -1,9 +1,16 @@ class Time - # Returns a JSON string representing the time. + # Returns a JSON string representing the time. If ActiveSupport.use_standard_json_time_format is set to true, the + # ISO 8601 format is used. # - # ==== Example: + # ==== Examples: + # + # # With ActiveSupport.use_standard_json_time_format = true + # Time.utc(2005,2,1,15,15,10).to_json + # # => "2005-02-01T15:15:10Z" + # + # # With ActiveSupport.use_standard_json_time_format = false # Time.utc(2005,2,1,15,15,10).to_json - # # => 2005/02/01 15:15:10 +0000" + # # => "2005/02/01 15:15:10 +0000" def to_json(options = nil) if ActiveSupport.use_standard_json_time_format xmlschema.inspect diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index ece95eeae9..e6f2fd4e7c 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -102,7 +102,19 @@ module ActiveSupport "#{time.strftime("%Y-%m-%dT%H:%M:%S")}#{formatted_offset(true, 'Z')}" end alias_method :iso8601, :xmlschema - + + # Returns a JSON string representing the TimeWithZone. If ActiveSupport.use_standard_json_time_format is set to + # true, the ISO 8601 format is used. + # + # ==== Examples: + # + # # With ActiveSupport.use_standard_json_time_format = true + # Time.utc(2005,2,1,15,15,10).in_time_zone.to_json + # # => "2005-02-01T15:15:10Z" + # + # # With ActiveSupport.use_standard_json_time_format = false + # Time.utc(2005,2,1,15,15,10).in_time_zone.to_json + # # => "2005/02/01 15:15:10 +0000" def to_json(options = nil) if ActiveSupport.use_standard_json_time_format xmlschema.inspect -- cgit v1.2.3 From 1b0654ea41d15552c19f767570d4f551d617e742 Mon Sep 17 00:00:00 2001 From: Tekin Suleyman Date: Thu, 29 May 2008 18:40:30 +0100 Subject: Ensure script/plugin installs ssh/git plugins. [#277 state:resolved] Signed-off-by: Pratik Naik --- railties/lib/commands/plugin.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/lib/commands/plugin.rb b/railties/lib/commands/plugin.rb index d12d002c4e..105819ce90 100644 --- a/railties/lib/commands/plugin.rb +++ b/railties/lib/commands/plugin.rb @@ -163,7 +163,7 @@ class Plugin end def git_url? - @uri =~ /^git:\/\// || @url =~ /\.git$/ + @uri =~ /^git:\/\// || @uri =~ /\.git$/ end def installed? -- cgit v1.2.3 From 8a090aa93dcd707c915fe0010e5d4446d1690c97 Mon Sep 17 00:00:00 2001 From: Nick Laiacona Date: Thu, 29 May 2008 16:42:32 -0700 Subject: First draft of the ActionView Partials guide. --- railties/doc/guides/actionview/partials.markdown | 91 ++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 railties/doc/guides/actionview/partials.markdown diff --git a/railties/doc/guides/actionview/partials.markdown b/railties/doc/guides/actionview/partials.markdown new file mode 100644 index 0000000000..9f387fbafb --- /dev/null +++ b/railties/doc/guides/actionview/partials.markdown @@ -0,0 +1,91 @@ +A Guide to Using Partials +=============================== + +This guide elaborates on the use and function of partials in Ruby on Rails. As your Rails application grows, your view templates can start to contain a lot of duplicate view code. To manage and reduce this complexity, you can by abstract view template code into partials. Partials are reusable snippets of eRB template code stored in separate files with an underscore ('_') prefix. + +Partials can be located anywhere in the `app/views` directory. File extensions for partials work just like other template files, they bear an extension that denotes what kind of code they generate. For example, `_animal.html.erb` and `_animal.xml.erb` are valid filenames for partials. + +Partials can be inserted in eRB template code by calling the `render` method with the `:partial` option. For example: + + <%= render :partial => 'foo' %> + +This inserts the result of evaluating the template `_foo.html.erb` into the parent template file at this location. Note that `render` assumes that the partial will be in the same directory as the calling parent template and have the same file extension. Partials can be located anywhere within the `app/views` directory. To use a partial located in a different directory then it the parent, add a '/' before it: + + <%= render :partial => '/common/foo' %> + +Loads the partial file from the `app/views/common/_foo.html.erb` directory. + +Abstracting views into partials can be approached in a number of different ways, depending on the situation. Sometimes, the code that you are abstracting is a specialized view of an object or a collection of objects. Other times, you can look at partials as a reusable subroutine. We'll explore each of these approaches and when to use them as well as the syntax for calling them. + +Partials as a View Subroutine +----------------------------- + +Using the `:locals` option, you can pass a hash of values which will be treated as local variables within the partial template. + + <%= render :partial => "person", :locals => { :name => "david" } %> + +The variable `name` contains the value `"david"` within the `_person.html.erb` template. Passing variables in this way allows you to create modular, reusable template files. Note that if you want to make local variables that are optional in some use cases, you will have to set them to a sentinel value such as `nil` when they have not been passed. So, in the example above, if the `name` variable is optional in some use cases, you must set: + + <% name ||= nil -%> + +So that you can later check: + + <% if name -%> +

Hello, <%= name %>!

+ <% end -%> + +Otherwise, the if statement will throw an error at runtime. + +Another thing to be aware of is that instance variables that are visible to the parent view template are visible to the partial. So you might be tempted to do this: + + <%= render :partial => "person" %> + +And then within the partial: + + <% if @name -%> +

Hello, <%= @name %>!

+ <% end -%> + +The potential snag here is that if multiple templates start to rely on this partial, you will need to maintain an instance variable with the same name across all of these templates and controllers. This approach can quickly become brittle if overused. + +Partials as a View of an Object +-------------------------------- + +Another way to look at partials is to view them as mini-views of a particular object or instance variable. Use the `:object` option to pass an object assigns that object to an instance variable named after the partial itself. For example: + + # Renders the partial, making @new_person available through + # the local variable 'person' + render :partial => "person", :object => @new_person + +If the instance variable `name` in the parent template matches the name of the partial, you can use a shortcut: + + render :partial => "person" + +Now the value that was in `@person` in the parent template is accessible as `person` in the partial. + +Partials as a View of a Collection +----------------------------------- + +Often it is the case that you need to display not just a single object, but a collection of objects. Rather than having to constantly nest the same partial within the same iterator code, Rails provides a syntactical shortcut using the `:collection` option: + + # Renders a collection of the same partial by making each element + # of @winners available through the local variable "person" as it + # builds the complete response. + render :partial => "person", :collection => @winners + +This calls the `_person.html.erb` partial for each person in the `@winners` collection. This also creates a local variable within the partial called `partial_counter` which contains the index of the current value. So for example: + + <%= partial_counter %>) <%= person -%> + +Where `@winners` contains three people, produces the following output: + + 1) Bill + 2) Jeff + 3) Nick + +One last detail, you can place an arbitrary snippet of code in between the objects using the `:spacer_template` option. + + # Renders the same collection of partials, but also renders the + # person_divider partial between each person partial. + render :partial => "person", :collection => @winners, :spacer_template => "person_divider" + -- cgit v1.2.3 From 569fe2d1fab551ec2404cb12f6036d06cb9020cf Mon Sep 17 00:00:00 2001 From: Bill Garr Date: Thu, 29 May 2008 17:02:00 -0700 Subject: first draft on helpers --- railties/doc/guides/actionview/helpers.markdown | 91 +++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 railties/doc/guides/actionview/helpers.markdown diff --git a/railties/doc/guides/actionview/helpers.markdown b/railties/doc/guides/actionview/helpers.markdown new file mode 100644 index 0000000000..c191c5e5ef --- /dev/null +++ b/railties/doc/guides/actionview/helpers.markdown @@ -0,0 +1,91 @@ +Helpers +==================== + +Helper Basics +------------------------ + +Helpers allow you to encapsulate rendering tasks as reusable functions. Helpers are modules, not classes, so their methods execute in the context in which they are called. They get included in a controller (typically the ApplicationController) using the helper function, like so + + Class ApplicationController < ActionController::Base + … + helper :menu + + def … + end + end + +In this way, methods in the menu helper are made available to any view or partial in your application. These methods can accept parameters, for example controller instance variables (eg; records or record collections gathered by you current controller), items from the view or partial’s locals[] hash or items from the params[] hash. You may wish to pass your controller instance variables and items from the params[] hash to the locals hash before rendering (See the section on partials). Helper methods can also accept an executable block of code. + +It is important to remember, though, that helpers are for rendering, and that they become available once a controller method has returned, while Rails is engaged in rendering the contents generated by a controller method. This means that helper methods are not available from within the methods of your controllers. + +Helpers can accomplish a variety of tasks, from formatting a complex tag for embedding content for a browser plugin (eg; Flash), to assembling a menu of options appropriate for the current context of your application, to generating sections of forms that get assembled on-the-fly. + +Helpers are organized around rendering tasks, so it is not necessary (nor necessarily desirable) to organize them around your application’s controllers or models. In fact, one of the benefits of helpers is that they are not connected via a rendering pipeline to specific controllers, like views and partials are. They can and should handle more generalized tasks. + +Here is a very simple, pseudo-example: + + module MenuHelper + def menu(records, menu_options={}) + item_options = menu_options.merge({}) + items = records.collect |record| do + menu_item(record, options) + end + content_tag(“ul”, items, options) + end + + def menu_item(record, item_options={})) + action = item_options[:action] + action ||= “show” + content_tag(“li”, link_to(record.title, :action => action, item_options) + end + end + + +This helper will require that records passed into it have certain fields (notably :title). The helper could be written to use this as a default, allowing the field to be overwritten by an element of item_options. + +Look at the Rails API for examples of helpers included in Rails, eg; [`ActionView::Helpers::ActiveRecordHelper`](http://api.rubyonrails.org/classes/ActionView/Helpers/ActiveRecordHelper.html). + +Passing Blocks to Helper Methods +------------------------ + +We mentioned before that blocks can be passed to helper methods. This allows for an interesting wrinkle: a block passed to a helper method can cause it to render a partial, which can then be wrapped by the helper method’s output. This can make your helper method much more reusable. It doesn’t need to know anything about the internals about what it is rendering, it just contextualizes it for the page. You can also use the helper to modify the locals hash for the partial, based on some configuration information unique to the current controller. You could implement a flexible themes system in this way. + + +Partials vs. Helpers? +------------------------ + +In general, the choice between using a partial vs. using a helper depends on the amount of flexibility you need. If the task is more about reacting to conditions than performing actual rendering, you may likely want a helper method. If you want to be able to call it from a variety of views, again, you may want to use a helper method. You can expect to extract helper methods out of code in views and partials during refactoring. + + +Tutorial -- Calling a Helper [UNFINISHED] +------------------------ + +1. Create a Rails application using `rails helper_test` +Notice the code: + + class ApplicationController < ActionController::Base + helper :all # include all helpers, all the time +For this tutorial, we'll keep this code, but you will likely want to exert more control over loading your helpers. + +2. Configure a database of your choice for the app. + +3. Inside of the `/app/helpers/` directory, create a new file called, `menu_helper.rb`. Write this in the file: + + module MenuHelpers + def menu(records, item_proc=nil) + items = records.collect{ |record| + menu_item(record, item_proc) + } + content_tag("ul", items) + end + + def menu_item(record, item_proc=nil) + item_url = item_proc.call(record) + item_url ||= { :action => :show } + content_tag("li", link_to(record.name, item_url)) + end + end + +4. Create a scaffold for some object in your app, using `./script/generate scaffold widgets`. +5. Create a database table for your widgets, with at least the fields `name` and `id`. Create a few widgets. +6. Call the menu command twice from `index.html.erb`, once using the default action, and once supplying a Proc to generate urls. \ No newline at end of file -- cgit v1.2.3 From 8ea92f3cd48755210ae0ea0b6bee203dd897cd1b Mon Sep 17 00:00:00 2001 From: Jeff Dean Date: Thu, 29 May 2008 18:32:18 -0700 Subject: Added a tutorial for how to create and test plugins --- .../doc/guides/creating_plugins/basics.markdown | 803 +++++++++++++++++++++ 1 file changed, 803 insertions(+) create mode 100644 railties/doc/guides/creating_plugins/basics.markdown diff --git a/railties/doc/guides/creating_plugins/basics.markdown b/railties/doc/guides/creating_plugins/basics.markdown new file mode 100644 index 0000000000..bb60ee90d0 --- /dev/null +++ b/railties/doc/guides/creating_plugins/basics.markdown @@ -0,0 +1,803 @@ +Creating Plugin Basics +==================== + +Pretend for a moment that you are an avid bird watcher. Your favorite bird is the Yaffle, and you want to create a plugin that allows other developers to share in the Yaffle goodness. + +In this tutorial you will learn how to create a plugin that includes: + +Core Extensions - extending String: + + # Anywhere + "hello".squawk # => "squawk! hello! squawk!" + +An acts\_as\_yaffle method for Active Record models that adds a "squawk" method: + + class Hickwall < ActiveRecord::Base + acts_as_yaffle :yaffle_text_field => :last_sang_at + end + + Hickwall.new.squawk("Hello World") + +A view helper that will print out squawking info: + + squawk_info_for(@hickwall) + +A generator that creates a migration to add squawk columns to a model: + + script/generate yaffle hickwall + +A custom generator command: + + class YaffleGenerator < Rails::Generator::NamedBase + def manifest + m.yaffle_definition + end + end + end + +A custom route method: + + ActionController::Routing::Routes.draw do |map| + map.yaffles + end + +In addition you'll learn how to: + +* test your plugins +* work with init.rb, how to store model, views, controllers, helpers and even other plugins in your plugins +* create documentation for your plugin. + +Create the basic app +--------------------- + +In this tutorial we will create a basic rails application with 1 resource: bird. Start out by building the basic rails app: + +> The following instructions will work for sqlite3. For more detailed instructions on how to create a rails app for other databases see the API docs. + + rails plugin_demo + cd plugin_demo + script/generate scaffold bird name:string + rake db:migrate + script/server + +Then navigate to [http://localhost:3000/birds](http://localhost:3000/birds). Make sure you have a functioning rails app before continuing. + +Create the plugin +----------------------- + +The built-in Rails plugin generator stubs out a new plugin. Pass the plugin name, either CamelCased or under_scored, as an argument. Pass --with-generator to add an example generator also. + +This creates a plugin in vendor/plugins including an init.rb and README as well as standard lib, task, and test directories. + +Examples: + + ./script/generate plugin BrowserFilters + ./script/generate plugin BrowserFilters --with-generator + +Later in the plugin we will create a generator, so go ahead and add the --with-generator option now: + + script/generate plugin yaffle --with-generator + +You should see the following output: + + create vendor/plugins/yaffle/lib + create vendor/plugins/yaffle/tasks + create vendor/plugins/yaffle/test + create vendor/plugins/yaffle/README + create vendor/plugins/yaffle/MIT-LICENSE + create vendor/plugins/yaffle/Rakefile + create vendor/plugins/yaffle/init.rb + create vendor/plugins/yaffle/install.rb + create vendor/plugins/yaffle/uninstall.rb + create vendor/plugins/yaffle/lib/yaffle.rb + create vendor/plugins/yaffle/tasks/yaffle_tasks.rake + create vendor/plugins/yaffle/test/core_ext_test.rb + create vendor/plugins/yaffle/generators + create vendor/plugins/yaffle/generators/yaffle + create vendor/plugins/yaffle/generators/yaffle/templates + create vendor/plugins/yaffle/generators/yaffle/yaffle_generator.rb + create vendor/plugins/yaffle/generators/yaffle/USAGE + +For this plugin you won't need the file vendor/plugins/yaffle/lib/yaffle.rb so you can delete that. + + rm vendor/plugins/yaffle/lib/yaffle.rb + +> Editor's note: many plugin authors prefer to keep this file, and add all of the require statements in it. That way, they only line in init.rb would be `require "yaffle"` +> If you are developing a plugin that has a lot of files in the lib directory, you may want to create a subdirectory like lib/yaffle and store your files in there. That way your init.rb file stays clean + +Testing Setup +------------------------ + +Testing plugins that use the entire Rails stack can be complex, and the generator doesn't offer any help. In this tutorial you will learn how to test your plugin against multiple different adapters using ActiveRecord. This tutorial will not cover how to use fixtures in plugin tests. + +To setup your plugin to allow for easy testing you'll need to add 3 files: + +* A database.yml file with all of your connection strings +* A schema.rb file with your table definitions +* A test helper that sets up the database before your tests + +For this plugin you'll need 2 tables/models, Hickwalls and Wickwalls, so add the following files: + + # File: vendor/plugins/yaffle/test/database.yml + + sqlite: + :adapter: sqlite + :dbfile: yaffle_plugin.sqlite.db + sqlite3: + :adapter: sqlite3 + :dbfile: yaffle_plugin.sqlite3.db + postgresql: + :adapter: postgresql + :username: postgres + :password: postgres + :database: yaffle_plugin_test + :min_messages: ERROR + mysql: + :adapter: mysql + :host: localhost + :username: rails + :password: + :database: yaffle_plugin_test + + # File: vendor/plugins/yaffle/test/test_helper.rb + + ActiveRecord::Schema.define(:version => 0) do + create_table :hickwalls, :force => true do |t| + t.string :name + t.string :last_squawk + t.datetime :last_squawked_at + end + create_table :wickwalls, :force => true do |t| + t.string :name + t.string :last_tweet + t.datetime :last_tweeted_at + end + end + + # File: vendor/plugins/yaffle/test/test_helper.rb + + ENV['RAILS_ENV'] = 'test' + ENV['RAILS_ROOT'] ||= File.dirname(__FILE__) + '/../../../..' + + require 'test/unit' + require File.expand_path(File.join(ENV['RAILS_ROOT'], 'config/environment.rb')) + + config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml')) + ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log") + + db_adapter = ENV['DB'] + + # no db passed, try one of these fine config-free DBs before bombing. + db_adapter ||= + begin + require 'rubygems' + require 'sqlite' + 'sqlite' + rescue MissingSourceFile + begin + require 'sqlite3' + 'sqlite3' + rescue MissingSourceFile + end + end + + if db_adapter.nil? + raise "No DB Adapter selected. Pass the DB= option to pick one, or install Sqlite or Sqlite3." + end + + ActiveRecord::Base.establish_connection(config[db_adapter]) + + load(File.dirname(__FILE__) + "/schema.rb") + + require File.dirname(__FILE__) + '/../init.rb' + + class Hickwall < ActiveRecord::Base + acts_as_yaffle + end + + class Wickwall < ActiveRecord::Base + acts_as_yaffle :yaffle_text_field => :last_tweet, :yaffle_date_field => :last_tweeted_at + end + +Update a core class: Adding "to\_squawk" to String +----------------------- + +To update a core class you will have to: + +* Write tests for the desired functionality +* Create a file for the code you wish to use +* Require that file from your init.rb + +Most plugins store their code classes in the plugin's lib directory. When you add a file to the lib directory, you must also require that file from init.rb. The file you are going to add for this tutorial is `lib/core_ext.rb` + +First, you need to write the tests. Testing plugins is very similar to testing rails apps. The generated test file should look something like this: + + # File: vendor/plugins/yaffle/test/core_ext_test.rb + + require 'test/unit' + + class CoreExtTest < Test::Unit::TestCase + # Replace this with your real tests. + def test_this_plugin + flunk + end + end + +Start off by removing the default test, and adding a require statement for your test helper. + + # File: vendor/plugins/yaffle/test/core_ext_test.rb + + require 'test/unit' + require File.dirname(__FILE__) + '/test_helper.rb' + + class CoreExtTest < Test::Unit::TestCase + end + +Navigate to your plugin directory and run `rake test` + + cd vendor/plugins/yaffle + rake test + +Your test should fail with `no such file to load -- ./test/../lib/core_ext.rb (LoadError)` because we haven't created any file yet. Create the file `lib/core_ext.rb` and re-run the tests. You should see a different error message: + + 1.) Failure ... + No tests were specified + +Great - now you are ready to start development. The first thing we'll do is to add a method to String called `to_squawk` which will prefix the string with the word "squawk! ". The test will look something like this: + + # File: vendor/plugins/yaffle/init.rb + + class CoreExtTest < Test::Unit::TestCase + def test_string_should_respond_to_squawk + assert_equal true, "".respond_to?(:to_squawk) + end + def test_string_prepend_empty_strings_with_the_word_squawk + assert_equal "squawk!", "".to_squawk + end + def test_string_prepend_non_empty_strings_with_the_word_squawk + assert_equal "squawk! Hello World", "Hello World".to_squawk + end + end + + # File: vendor/plugins/yaffle/init.rb + + require "core_ext" + + # File: vendor/plugins/yaffle/lib/core_ext.rb + + class String + # returns the current string, prefixed by "squawk!" + def to_squawk + "squawk! #{self}".strip + end + end + +To test that your method does what it says it does, run the unit tests. To make sure your code is picked up by + +To test this, fire up a console and start squawking: + + script/console + >> "Hello World".to_squawk + => "squawk! Hello World" + +If that worked, congratulations! You just created your first test-driven plugin that extends a core ruby class. + +Adding an `acts_as_yaffle` method to ActiveRecord models +----------------------- + +A common pattern in plugins is to add a method called `acts_as_something` to models. In this case, you want to write a method called `acts_as_yaffle` that adds a squawk method to your models. + +To keep things clean, create a new test file called `acts_as_yaffle_test.rb` in your plugin's test directory and require your test helper. + + # File: vendor/plugins/yaffle/test/acts_as_yaffle_test.rb + + require File.dirname(__FILE__) + '/test_helper.rb' + + class Hickwall < ActiveRecord::Base + acts_as_yaffle + end + + class ActsAsYaffleTest < Test::Unit::TestCase + end + + # File: vendor/plugins/lib/acts_as_yaffle.rb + + module Yaffle + end + +One of the most common plugin patterns for `acts_as_yaffle` plugins is to structure your file like so: + + module Yaffle + def self.included(base) + base.send :extend, ClassMethods + end + + module ClassMethods + # any method placed here will apply to classes, like Hickwall + def acts_as_something + send :include, InstanceMethods + end + end + + module InstanceMethods + # any method placed here will apply to instaces, like @hickwall + end + end + +With structure you can easily separate the methods that will be used for the class (like `Hickwall.some_method`) and the instance (like `@hickwell.some_method`). + +Let's add class method named `acts_as_yaffle` - testing it out first. You already defined the ActiveRecord models in your test helper, so if you run tests now they will fail. + +Back in your `acts\_as\_yaffle` file, update ClassMethods like so: + + module ClassMethods + def acts_as_yaffle(options = {}) + send :include, InstanceMethods + end + end + +Now that test should pass. Since your plugin is going to work with field names, you need to allow people to define the field names, in case there is a naming conflict. You can write a few simple tests for this: + + # File: vendor/plugins/yaffle/test/acts_as_yaffle_test.rb + + require File.dirname(__FILE__) + '/test_helper.rb' + + class ActsAsYaffleTest < Test::Unit::TestCase + def test_a_hickwalls_yaffle_text_field_should_be_last_squawk + assert_equal "last_squawk", Hickwall.yaffle_text_field + end + def test_a_hickwalls_yaffle_date_field_should_be_last_squawked_at + assert_equal "last_squawked_at", Hickwall.yaffle_date_field + end + def test_a_wickwalls_yaffle_text_field_should_be_last_tweet + assert_equal "last_tweet", Wickwall.yaffle_text_field + end + def test_a_wickwalls_yaffle_date_field_should_be_last_tweeted_at + assert_equal "last_tweeted_at", Wickwall.yaffle_date_field + end + end + +To make these tests pass, you could modify your `acts_as_yaffle` file like so: + + # File: vendor/plugins/yaffle/lib/acts_as_yaffle.rb + + module Yaffle + def self.included(base) + base.send :extend, ClassMethods + end + + module ClassMethods + def acts_as_yaffle(options = {}) + cattr_accessor :yaffle_text_field, :yaffle_date_field + self.yaffle_text_field = (options[:yaffle_text_field] || :last_squawk).to_s + self.yaffle_date_field = (options[:yaffle_date_field] || :last_squawked_at).to_s + send :include, InstanceMethods + end + end + + module InstanceMethods + end + end + +Now you can add tests for the instance methods, and the instance method itself: + + # File: vendor/plugins/yaffle/test/acts_as_yaffle_test.rb + + require File.dirname(__FILE__) + '/test_helper.rb' + + class ActsAsYaffleTest < Test::Unit::TestCase + + def test_a_hickwalls_yaffle_text_field_should_be_last_squawk + assert_equal "last_squawk", Hickwall.yaffle_text_field + end + def test_a_hickwalls_yaffle_date_field_should_be_last_squawked_at + assert_equal "last_squawked_at", Hickwall.yaffle_date_field + end + + def test_a_wickwalls_yaffle_text_field_should_be_last_squawk + assert_equal "last_tweet", Wickwall.yaffle_text_field + end + def test_a_wickwalls_yaffle_date_field_should_be_last_squawked_at + assert_equal "last_tweeted_at", Wickwall.yaffle_date_field + end + + def test_hickwalls_squawk_should_populate_last_squawk + hickwall = Hickwall.new + hickwall.squawk("Hello World") + assert_equal "squawk! Hello World", hickwall.last_squawk + end + def test_hickwalls_squawk_should_populate_last_squawked_at + hickwall = Hickwall.new + hickwall.squawk("Hello World") + assert_equal Date.today, hickwall.last_squawked_at + end + + def test_wickwalls_squawk_should_populate_last_tweet + wickwall = Wickwall.new + wickwall.squawk("Hello World") + assert_equal "squawk! Hello World", wickwall.last_tweet + end + def test_wickwalls_squawk_should_populate_last_tweeted_at + wickwall = Wickwall.new + wickwall.squawk("Hello World") + assert_equal Date.today, wickwall.last_tweeted_at + end + end + + # File: vendor/plugins/yaffle/lib/acts_as_yaffle.rb + + module Yaffle + def self.included(base) + base.send :extend, ClassMethods + end + + module ClassMethods + def acts_as_yaffle(options = {}) + cattr_accessor :yaffle_text_field, :yaffle_date_field + self.yaffle_text_field = (options[:yaffle_text_field] || :last_squawk).to_s + self.yaffle_date_field = (options[:yaffle_date_field] || :last_squawked_at).to_s + send :include, InstanceMethods + end + end + + module InstanceMethods + def squawk(string) + write_attribute(self.class.yaffle_text_field, string.to_squawk) + write_attribute(self.class.yaffle_date_field, Date.today) + end + end + end + +Note the use of write_attribute to write to the field in model. + +Create a view helper +----------------------- + +Creating a view helper is a 3-step process: + +* Add an appropriately named file to the lib directory +* Require the file and hooks in init.rb +* Write the tests + +First, create the test to define the functionality you want: + + # File: vendor/plugins/yaffle/test/view_helpers_test.rb + + require File.dirname(__FILE__) + '/test_helper.rb' + include YaffleViewHelper + + class ViewHelpersTest < Test::Unit::TestCase + def test_squawk_info_for_should_return_the_text_and_date + time = Time.now + hickwall = Hickwall.new + hickwall.last_squawk = "Hello World" + hickwall.last_squawked_at = time + assert_equal "Hello World, #{time.to_s}", squawk_info_for(hickwall) + end + end + +Then add the following statements to init.rb: + + # File: vendor/plugins/yaffle/init.rb + + require "view_helpers" + ActionView::Base.send :include, YaffleViewHelper + +Then add the view helpers file and + + # File: vendor/plugins/yaffle/lib/view_helpers.rb + + module YaffleViewHelper + def squawk_info_for(yaffle) + returning "" do |result| + result << yaffle.read_attribute(yaffle.class.yaffle_text_field) + result << ", " + result << yaffle.read_attribute(yaffle.class.yaffle_date_field).to_s + end + end + end + +You can also test this in script/console by using the "helper" method: + + script/console + >> helper.squawk_info_for(@some_yaffle_instance) + +Create a migration generator +----------------------- + +When you created the plugin above, you specified the --with-generator option, so you already have the generator stubs in your plugin. + +We'll be relying on the built-in rails generate template for this tutorial. Going into the details of generators is beyond the scope of this tutorial. + +Type: + + script/generate + +You should see the line: + + Plugins (vendor/plugins): yaffle + +When you run `script/generate yaffle` you should see the contents of your USAGE file. For this plugin, the USAGE file looks like this: + + Description: + Creates a migration that adds yaffle squawk fields to the given model + + Example: + ./script/generate yaffle hickwall + + This will create: + db/migrate/TIMESTAMP_add_yaffle_fields_to_hickwall + +Now you can add code to your generator: + + # File: vendor/plugins/yaffle/generators/yaffle/yaffle_generator.rb + + class YaffleGenerator < Rails::Generator::NamedBase + def manifest + record do |m| + m.migration_template 'migration:migration.rb', "db/migrate", {:assigns => yaffle_local_assigns, + :migration_file_name => "add_yaffle_fields_to_#{custom_file_name}" + } + end + end + + private + def custom_file_name + custom_name = class_name.underscore.downcase + custom_name = custom_name.pluralize if ActiveRecord::Base.pluralize_table_names + end + + def yaffle_local_assigns + returning(assigns = {}) do + assigns[:migration_action] = "add" + assigns[:class_name] = "add_yaffle_fields_to_#{custom_file_name}" + assigns[:table_name] = custom_file_name + assigns[:attributes] = [Rails::Generator::GeneratedAttribute.new("last_squawk", "string")] + assigns[:attributes] << Rails::Generator::GeneratedAttribute.new("last_squawked_at", "datetime") + end + end + end + +Note that you need to be aware of whether or not table names are pluralized. + +This does a few things: + +* Reuses the built in rails migration_template method +* Reuses the built-in rails migration template + +When you run the generator like + + script/generate yaffle bird + +You will see a new file: + + # File: db/migrate/20080529225649_add_yaffle_fields_to_birds.rb + + class AddYaffleFieldsToBirds < ActiveRecord::Migration + def self.up + add_column :birds, :last_squawk, :string + add_column :birds, :last_squawked_at, :datetime + end + + def self.down + remove_column :birds, :last_squawked_at + remove_column :birds, :last_squawk + end + end + +Adding custom generator commands +------------------------ + +You may have noticed above that you can used one of the built-in rails migration commands `m.migration_template`. You can create your own commands for these, using the following steps: + +1. Add the require and hook statements to init.rb +2. Create the commands - creating 3 sets, Create, Destroy, List +3. Add the method to your generator + +Working with the internals of generators is beyond the scope of this tutorial, but here is a basic example: + + # File: vendor/plugins/yaffle/init.rb + + require "commands" + Rails::Generator::Commands::Create.send :include, Yaffle::Generator::Commands::Create + Rails::Generator::Commands::Destroy.send :include, Yaffle::Generator::Commands::Destroy + Rails::Generator::Commands::List.send :include, Yaffle::Generator::Commands::List + + # File: vendor/plugins/yaffle/lib/commands.rb + + require 'rails_generator' + require 'rails_generator/commands' + + module Yaffle #:nodoc: + module Generator #:nodoc: + module Commands #:nodoc: + module Create + def yaffle_definition + file("definition.txt", "definition.txt") + end + end + + module Destroy + def yaffle_definition + file("definition.txt", "definition.txt") + end + end + + module List + def yaffle_definition + file("definition.txt", "definition.txt") + end + end + end + end + end + + # File: vendor/plugins/yaffle/generators/yaffle/templates/definition.txt + + Yaffle is a bird + + # File: vendor/plugins/yaffle/generators/yaffle/yaffle_generator.rb + + class YaffleGenerator < Rails::Generator::NamedBase + def manifest + m.yaffle_definition + end + end + end + +This example just uses the built-in "file" method, but you could do anything that ruby allows. + +Adding Routes +------------------------ + +Testing routes in plugins can be complex, especially if the controllers are also in the plugin itself. Jamis Buck showed a great example of this in [http://weblog.jamisbuck.org/2006/10/26/monkey-patching-rails-extending-routes-2](http://weblog.jamisbuck.org/2006/10/26/monkey-patching-rails-extending-routes-2) + + # File: vendor/plugins/yaffle/test/routing_test.rb + + require "#{File.dirname(__FILE__)}/test_helper" + + class RoutingTest < Test::Unit::TestCase + + def setup + ActionController::Routing::Routes.draw do |map| + map.yaffles + end + end + + def test_yaffles_route + assert_recognition :get, "/yaffles", :controller => "yaffles_controller", :action => "index" + end + + private + + # yes, I know about assert_recognizes, but it has proven problematic to + # use in these tests, since it uses RouteSet#recognize (which actually + # tries to instantiate the controller) and because it uses an awkward + # parameter order. + def assert_recognition(method, path, options) + result = ActionController::Routing::Routes.recognize_path(path, :method => method) + assert_equal options, result + end + end + + # File: vendor/plugins/yaffle/init.rb + + require "routing" + ActionController::Routing::RouteSet::Mapper.send :include, Yaffle::Routing::MapperExtensions + + # File: vendor/plugins/yaffle/lib/routing.rb + + module Yaffle #:nodoc: + module Routing #:nodoc: + module MapperExtensions + def yaffles + @set.add_route("/yaffles", {:controller => "yaffles_controller", :action => "index"}) + end + end + end + end + + # File: config/routes.rb + + ActionController::Routing::Routes.draw do |map| + ... + map.yaffles + end + +You can also see if your routes work by running `rake routes` from your app directory. + +Generate RDoc Documentation +----------------------- + +Once your plugin is stable, the tests pass on all database and you are ready to deploy do everyone else a favor and document it! Luckily, writing documentation for your plugin is easy. + +The first step is to update the README file with detailed information about how to use your plugin. A few key things to include are: + +* Your name +* How to install +* How to add the functionality to the app (several examples of common use cases) +* Warning, gotchas or tips that might help save users time + +Once your README is solid, go through and add rdoc comments to all of the methods that developers will use. + +Before you generate your documentation, be sure to go through and add nodoc comments to those modules and methods that are not important to your users. + +Once your comments are good to go, navigate to your plugin directory and run + + rake rdoc + +Working with init.rb +------------------------ + +The plugin initializer script init.rb is invoked via `eval` (not require) so it has slightly different behavior. + +If you reopen any classes in init.rb itself your changes will potentially be made to the wrong module. There are 2 ways around this: + +The first way is to explicitly define the top-level module space for all modules and classes, like ::Hash + + # File: vendor/plugins/yaffle/init.rb + + class ::Hash + def is_a_special_hash? + true + end + end + +OR you can use module\_eval or class\_eval + + # File: vendor/plugins/yaffle/init.rb + + Hash.class_eval do + def is_a_special_hash? + true + end + end + +Storing models, views, helpers, and controllers in your plugins +------------------------ + +You can easily store models, views, helpers and controllers in plugins. Just create a folder for each in the lib folder, add them to the load path and remove them from the load once path: + + # File: vendor/plugins/yaffle/init.rb + + %w{ models controllers helpers }.each do |dir| + path = File.join(directory, 'lib', dir) + $LOAD_PATH << path + Dependencies.load_paths << path + Dependencies.load_once_paths.delete(path) + end + +Adding directories to the load path makes them appear just like files in the the main app directory - except that they are only loaded once, so you have to restart the web server to see the changes in the browser. + +Adding directories to the load once paths allow those changes to picked up as soon as you save the file - without having to restart the web server. + +Storing plugins in alternate locations +------------------------- + +You can store plugins wherever you want - you just have to add those plugins to the plugins path in environment.rb + +Since the plugin is only loaded after the plugin paths are defined, you can't redefine this in your plugins - but it may be good to now. + +You can even store plugins inside of other plugins for complete plugin madness! + + config.plugin_paths << File.join(RAILS_ROOT,"vendor","plugins","yaffle","lib","plugins") + +Plugin Loaders and Plugin Locators +------------------------ + +If the built-in plugin behavior is inadequate, you can change almost every aspect of the location and loading process. You can write your own plugin locators and plugin loaders, but that's beyond the scope of this tutorial. + +Custom Plugin Generators +------------------------ + +If you are an RSpec fan, you can install the rspec\_plugin\_generator, which will generate the spec folder and database for you. + +[http://github.com/pat-maddox/rspec-plugin-generator/tree/master](http://github.com/pat-maddox/rspec-plugin-generator/tree/master) + +References +------------------------ + +* [http://nubyonrails.com/articles/the-complete-guide-to-rails-plugins-part-i](http://nubyonrails.com/articles/the-complete-guide-to-rails-plugins-part-i) +* [http://nubyonrails.com/articles/2006/05/09/the-complete-guide-to-rails-plugins-part-ii](http://nubyonrails.com/articles/2006/05/09/the-complete-guide-to-rails-plugins-part-ii) +* [http://github.com/technoweenie/attachment_fu/tree/master](http://github.com/technoweenie/attachment_fu/tree/master) +* [http://daddy.platte.name/2007/05/rails-plugins-keep-initrb-thin.html](http://daddy.platte.name/2007/05/rails-plugins-keep-initrb-thin.html) -- cgit v1.2.3 From bf8defba08b0f8ec55197bd95232c29ea4e0ba6d Mon Sep 17 00:00:00 2001 From: Jeff Dean Date: Thu, 29 May 2008 20:16:18 -0700 Subject: added documentation for rake tasks to the plugin tutorial --- .../doc/guides/creating_plugins/basics.markdown | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/railties/doc/guides/creating_plugins/basics.markdown b/railties/doc/guides/creating_plugins/basics.markdown index bb60ee90d0..7311f78e20 100644 --- a/railties/doc/guides/creating_plugins/basics.markdown +++ b/railties/doc/guides/creating_plugins/basics.markdown @@ -771,6 +771,28 @@ Adding directories to the load path makes them appear just like files in the the Adding directories to the load once paths allow those changes to picked up as soon as you save the file - without having to restart the web server. +Writing custom rake tasks in your plugin +------------------------- + +When you created the plugin with the built-in rails generator, it generated a rake file for you in `vendor/plugins/yaffle/tasks/yaffle.rake`. Any rake task you add here will be available to the app. + +Many plugin authors put all of their rake tasks into a common namespace that is the same as the plugin, like so: + + # File: vendor/plugins/yaffle/tasks/yaffle.rake + + namespace :yaffle do + desc "Prints out the word 'Yaffle'" + task :squawk => :environment do + puts "squawk!" + end + end + +When you run `rake -T` from your plugin you will see + + yaffle:squawk "Prints out..." + +You can add as many files as you want in the tasks directory, and if they end in .rake Rails will pick them up. + Storing plugins in alternate locations ------------------------- -- cgit v1.2.3 From 131dd0e912f4ba1880eb53dfbf2f9add277a183e Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 30 May 2008 02:31:39 -0700 Subject: git ignore rubinius .rbc files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e57310cdc8..8c5dfb64e1 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ actionpack/pkg actionmailer/pkg activesupport/pkg railties/pkg +*.rbc -- cgit v1.2.3 From 946f51449a2531b8c1a92035b4482ae633d56894 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 30 May 2008 02:39:00 -0700 Subject: Require ruby-prof 0.6.1 or later. Use resume/pause to omit extraneous machinery from profile. --- .../lib/action_controller/request_profiler.rb | 25 +++++++++++++++------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/actionpack/lib/action_controller/request_profiler.rb b/actionpack/lib/action_controller/request_profiler.rb index 8a18d194bd..a6471d0c08 100755 --- a/actionpack/lib/action_controller/request_profiler.rb +++ b/actionpack/lib/action_controller/request_profiler.rb @@ -17,13 +17,13 @@ module ActionController reset! end - def benchmark(n) + def benchmark(n, profiling = false) @quiet = true print ' ' result = Benchmark.realtime do n.times do |i| - run + run(profiling) print_progress(i) end end @@ -43,8 +43,15 @@ module ActionController script = File.read(script_path) source = <<-end_source - def run - #{script} + def run(profiling = false) + if profiling + RubyProf.resume do + #{script} + end + else + #{script} + end + old_request_count = request_count reset! self.request_count = old_request_count @@ -91,21 +98,22 @@ module ActionController def profile(sandbox) load_ruby_prof - results = RubyProf.profile { benchmark(sandbox) } + benchmark(sandbox, true) + results = RubyProf.stop show_profile_results results results end - def benchmark(sandbox) + def benchmark(sandbox, profiling = false) sandbox.request_count = 0 - elapsed = sandbox.benchmark(options[:n]).to_f + elapsed = sandbox.benchmark(options[:n], profiling).to_f count = sandbox.request_count.to_i puts '%.2f sec, %d requests, %d req/sec' % [elapsed, count, count / elapsed] end def warmup(sandbox) - Benchmark.realtime { sandbox.run } + Benchmark.realtime { sandbox.run(false) } end def default_options @@ -136,6 +144,7 @@ module ActionController protected def load_ruby_prof begin + gem 'ruby-prof', '>= 0.6.1' require 'ruby-prof' if mode = options[:measure] RubyProf.measure_mode = RubyProf.const_get(mode.upcase) -- cgit v1.2.3 From 2ce1be3ac4823ccdfbe36ff5548a562aa5106d2e Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 30 May 2008 04:16:57 -0700 Subject: Enable partial updates by default --- activerecord/lib/active_record/dirty.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/dirty.rb b/activerecord/lib/active_record/dirty.rb index 8fdc763292..b32e17e990 100644 --- a/activerecord/lib/active_record/dirty.rb +++ b/activerecord/lib/active_record/dirty.rb @@ -43,7 +43,7 @@ module ActiveRecord base.alias_method_chain :reload, :dirty base.superclass_delegating_accessor :partial_updates - base.partial_updates = false + base.partial_updates = true end # Do any attributes have unsaved changes? -- cgit v1.2.3 From 03ba5d7b5183e7cb199a21aa6e06d646f7a5cbfe Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 30 May 2008 04:36:00 -0700 Subject: Ensure query assertion counts are the same when partial updates are enabled --- activerecord/test/cases/associations/has_many_associations_test.rb | 2 ++ .../test/cases/associations/has_many_through_associations_test.rb | 1 + 2 files changed, 3 insertions(+) diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index cbc621b411..dbfa025efb 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -350,6 +350,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal "Another Client", new_client.name assert new_client.new_record? assert_equal new_client, company.clients_of_firm.last + company.name += '-changed' assert_queries(2) { assert company.save } assert !new_client.new_record? assert_equal 2, company.clients_of_firm(true).size @@ -360,6 +361,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase new_clients = assert_no_queries { company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) } assert_equal 2, new_clients.size + company.name += '-changed' assert_queries(3) { assert company.save } assert_equal 3, company.clients_of_firm(true).size end diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index 5561361bca..05155f6303 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -59,6 +59,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase # * 2 new records = 4 # + 1 query to save the actual post = 5 assert_queries(5) do + posts(:thinking).body += '-changed' posts(:thinking).save end -- cgit v1.2.3 From 1b43884c729662e4f0b12f4141dc493ead7da258 Mon Sep 17 00:00:00 2001 From: Jeff Dean Date: Fri, 30 May 2008 10:03:57 -0700 Subject: made the headings more consistent --- .../doc/guides/creating_plugins/basics.markdown | 31 +++++++++++----------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/railties/doc/guides/creating_plugins/basics.markdown b/railties/doc/guides/creating_plugins/basics.markdown index 7311f78e20..9e0092c144 100644 --- a/railties/doc/guides/creating_plugins/basics.markdown +++ b/railties/doc/guides/creating_plugins/basics.markdown @@ -10,7 +10,7 @@ Core Extensions - extending String: # Anywhere "hello".squawk # => "squawk! hello! squawk!" -An acts\_as\_yaffle method for Active Record models that adds a "squawk" method: +An `acts_as_yaffle` method for Active Record models that adds a "squawk" method: class Hickwall < ActiveRecord::Base acts_as_yaffle :yaffle_text_field => :last_sang_at @@ -46,6 +46,7 @@ In addition you'll learn how to: * test your plugins * work with init.rb, how to store model, views, controllers, helpers and even other plugins in your plugins * create documentation for your plugin. +* write custom rake tasks in your plugin Create the basic app --------------------- @@ -105,7 +106,7 @@ For this plugin you won't need the file vendor/plugins/yaffle/lib/yaffle.rb so y > Editor's note: many plugin authors prefer to keep this file, and add all of the require statements in it. That way, they only line in init.rb would be `require "yaffle"` > If you are developing a plugin that has a lot of files in the lib directory, you may want to create a subdirectory like lib/yaffle and store your files in there. That way your init.rb file stays clean -Testing Setup +Setup the plugin for testing ------------------------ Testing plugins that use the entire Rails stack can be complex, and the generator doesn't offer any help. In this tutorial you will learn how to test your plugin against multiple different adapters using ActiveRecord. This tutorial will not cover how to use fixtures in plugin tests. @@ -199,7 +200,7 @@ For this plugin you'll need 2 tables/models, Hickwalls and Wickwalls, so add the acts_as_yaffle :yaffle_text_field => :last_tweet, :yaffle_date_field => :last_tweeted_at end -Update a core class: Adding "to\_squawk" to String +Add a `to_squawk` method to String ----------------------- To update a core class you will have to: @@ -282,7 +283,7 @@ To test this, fire up a console and start squawking: If that worked, congratulations! You just created your first test-driven plugin that extends a core ruby class. -Adding an `acts_as_yaffle` method to ActiveRecord models +Add an `acts_as_yaffle` method to ActiveRecord ----------------------- A common pattern in plugins is to add a method called `acts_as_something` to models. In this case, you want to write a method called `acts_as_yaffle` that adds a squawk method to your models. @@ -328,7 +329,7 @@ With structure you can easily separate the methods that will be used for the cla Let's add class method named `acts_as_yaffle` - testing it out first. You already defined the ActiveRecord models in your test helper, so if you run tests now they will fail. -Back in your `acts\_as\_yaffle` file, update ClassMethods like so: +Back in your `acts_as_yaffle` file, update ClassMethods like so: module ClassMethods def acts_as_yaffle(options = {}) @@ -585,7 +586,7 @@ You will see a new file: end end -Adding custom generator commands +Add a custom generator command ------------------------ You may have noticed above that you can used one of the built-in rails migration commands `m.migration_template`. You can create your own commands for these, using the following steps: @@ -647,7 +648,7 @@ Working with the internals of generators is beyond the scope of this tutorial, b This example just uses the built-in "file" method, but you could do anything that ruby allows. -Adding Routes +Add a Custom Route ------------------------ Testing routes in plugins can be complex, especially if the controllers are also in the plugin itself. Jamis Buck showed a great example of this in [http://weblog.jamisbuck.org/2006/10/26/monkey-patching-rails-extending-routes-2](http://weblog.jamisbuck.org/2006/10/26/monkey-patching-rails-extending-routes-2) @@ -726,7 +727,7 @@ Once your comments are good to go, navigate to your plugin directory and run rake rdoc -Working with init.rb +Work with init.rb ------------------------ The plugin initializer script init.rb is invoked via `eval` (not require) so it has slightly different behavior. @@ -743,7 +744,7 @@ The first way is to explicitly define the top-level module space for all modules end end -OR you can use module\_eval or class\_eval +OR you can use `module_eval` or `class_eval` # File: vendor/plugins/yaffle/init.rb @@ -753,7 +754,7 @@ OR you can use module\_eval or class\_eval end end -Storing models, views, helpers, and controllers in your plugins +Store models, views, helpers, and controllers in your plugins ------------------------ You can easily store models, views, helpers and controllers in plugins. Just create a folder for each in the lib folder, add them to the load path and remove them from the load once path: @@ -771,7 +772,7 @@ Adding directories to the load path makes them appear just like files in the the Adding directories to the load once paths allow those changes to picked up as soon as you save the file - without having to restart the web server. -Writing custom rake tasks in your plugin +Write custom rake tasks in your plugin ------------------------- When you created the plugin with the built-in rails generator, it generated a rake file for you in `vendor/plugins/yaffle/tasks/yaffle.rake`. Any rake task you add here will be available to the app. @@ -793,7 +794,7 @@ When you run `rake -T` from your plugin you will see You can add as many files as you want in the tasks directory, and if they end in .rake Rails will pick them up. -Storing plugins in alternate locations +Store plugins in alternate locations ------------------------- You can store plugins wherever you want - you just have to add those plugins to the plugins path in environment.rb @@ -804,15 +805,15 @@ You can even store plugins inside of other plugins for complete plugin madness! config.plugin_paths << File.join(RAILS_ROOT,"vendor","plugins","yaffle","lib","plugins") -Plugin Loaders and Plugin Locators +Create your own Plugin Loaders and Plugin Locators ------------------------ If the built-in plugin behavior is inadequate, you can change almost every aspect of the location and loading process. You can write your own plugin locators and plugin loaders, but that's beyond the scope of this tutorial. -Custom Plugin Generators +Use Custom Plugin Generators ------------------------ -If you are an RSpec fan, you can install the rspec\_plugin\_generator, which will generate the spec folder and database for you. +If you are an RSpec fan, you can install the `rspec_plugin_generator`, which will generate the spec folder and database for you. [http://github.com/pat-maddox/rspec-plugin-generator/tree/master](http://github.com/pat-maddox/rspec-plugin-generator/tree/master) -- cgit v1.2.3 From 60e37868e40ac11f07cbda81f24dcdb0a9c68783 Mon Sep 17 00:00:00 2001 From: Jeff Dean Date: Fri, 30 May 2008 10:13:29 -0700 Subject: added final tree structure, changed String to String.class_eval do --- .../doc/guides/creating_plugins/basics.markdown | 44 ++++++++++++++++++++-- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/railties/doc/guides/creating_plugins/basics.markdown b/railties/doc/guides/creating_plugins/basics.markdown index 9e0092c144..a7b5d53478 100644 --- a/railties/doc/guides/creating_plugins/basics.markdown +++ b/railties/doc/guides/creating_plugins/basics.markdown @@ -266,16 +266,15 @@ Great - now you are ready to start development. The first thing we'll do is to # File: vendor/plugins/yaffle/lib/core_ext.rb - class String - # returns the current string, prefixed by "squawk!" + String.class_eval do def to_squawk "squawk! #{self}".strip end end -To test that your method does what it says it does, run the unit tests. To make sure your code is picked up by +When monkey-patching existing classes it's often better to use `class_eval` instead of opening the class directly. -To test this, fire up a console and start squawking: +To test that your method does what it says it does, run the unit tests. To test this manually, fire up a console and start squawking: script/console >> "Hello World".to_squawk @@ -824,3 +823,40 @@ References * [http://nubyonrails.com/articles/2006/05/09/the-complete-guide-to-rails-plugins-part-ii](http://nubyonrails.com/articles/2006/05/09/the-complete-guide-to-rails-plugins-part-ii) * [http://github.com/technoweenie/attachment_fu/tree/master](http://github.com/technoweenie/attachment_fu/tree/master) * [http://daddy.platte.name/2007/05/rails-plugins-keep-initrb-thin.html](http://daddy.platte.name/2007/05/rails-plugins-keep-initrb-thin.html) + +Appendices +------------------------ + +The final plugin should have a directory structure that looks something like this: + + |-- MIT-LICENSE + |-- README + |-- Rakefile + |-- generators + | `-- yaffle + | |-- USAGE + | |-- templates + | | `-- definition.txt + | `-- yaffle_generator.rb + |-- init.rb + |-- install.rb + |-- lib + | |-- acts_as_yaffle.rb + | |-- commands.rb + | |-- core_ext.rb + | |-- routing.rb + | `-- view_helpers.rb + |-- tasks + | `-- yaffle_tasks.rake + |-- test + | |-- acts_as_yaffle_test.rb + | |-- core_ext_test.rb + | |-- database.yml + | |-- debug.log + | |-- routing_test.rb + | |-- schema.rb + | |-- test_helper.rb + | `-- view_helpers_test.rb + |-- uninstall.rb + `-- yaffle_plugin.sqlite3.db + -- cgit v1.2.3 From f7015336f66d284cff8ecb89df9f430791ac57ea Mon Sep 17 00:00:00 2001 From: Ryan Bates Date: Sat, 31 May 2008 12:36:07 -0700 Subject: Fix default nil tests for MySQL 5.0.51 [#192 state:resolved] Signed-off-by: Joshua Peek --- activerecord/test/cases/defaults_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb index bd19ffcc29..2ea85417da 100644 --- a/activerecord/test/cases/defaults_test.rb +++ b/activerecord/test/cases/defaults_test.rb @@ -5,7 +5,7 @@ require 'models/entrant' class DefaultTest < ActiveRecord::TestCase def test_nil_defaults_for_not_null_columns column_defaults = - if current_adapter?(:MysqlAdapter) + if current_adapter?(:MysqlAdapter) && Mysql.client_version < 50051 { 'id' => nil, 'name' => '', 'course_id' => nil } else { 'id' => nil, 'name' => nil, 'course_id' => nil } -- cgit v1.2.3 From aef47dcf937a5c9f150c50b73cffd9fa9eb64915 Mon Sep 17 00:00:00 2001 From: Tim Harper Date: Tue, 13 May 2008 19:17:40 -0600 Subject: belongs_to polymorphic association assignments update the foreign_id and foreign_type fields regardless of whether the record being assigned is new or not. fixes the following scenarios: * I have validates_inclusion_of on the type field for a polymorphic belongs_to association. I assign a new record to the model's polymorphic relationship of the proper type. validation fails because the type field has not been updated. * I replace the value for a ppolymorphic association to a new record of another class. The type field still says its the previous class, and the id field points to the previous record as well. --- .../belongs_to_polymorphic_association.rb | 6 ++--- .../associations/belongs_to_associations_test.rb | 29 +++++++++++++++++++++- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb index df4ae38f38..d8146daa54 100755 --- a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb @@ -7,10 +7,8 @@ module ActiveRecord else @target = (AssociationProxy === record ? record.target : record) - unless record.new_record? - @owner[@reflection.primary_key_name] = record.id - @owner[@reflection.options[:foreign_type]] = record.class.base_class.name.to_s - end + @owner[@reflection.primary_key_name] = record.id + @owner[@reflection.options[:foreign_type]] = record.class.base_class.name.to_s @updated = true end diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 3073eae355..e0da8bfb7a 100755 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -12,6 +12,8 @@ require 'models/author' require 'models/tag' require 'models/tagging' require 'models/comment' +require 'models/sponsor' +require 'models/member' class BelongsToAssociationsTest < ActiveRecord::TestCase fixtures :accounts, :companies, :developers, :projects, :topics, @@ -381,5 +383,30 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_raise(ActiveRecord::ReadOnlyRecord) { companies(:first_client).readonly_firm.save! } assert companies(:first_client).readonly_firm.readonly? end - + + def test_polymorphic_assignment_foreign_type_field_updating + # should update when assigning a saved record + sponsor = Sponsor.new + member = Member.create + sponsor.sponsorable = member + assert_equal "Member", sponsor.sponsorable_type + + # should update when assigning a new record + sponsor = Sponsor.new + member = Member.new + sponsor.sponsorable = member + assert_equal "Member", sponsor.sponsorable_type + end + + def test_polymorphic_assignment_updates_foreign_id_field_for_new_and_saved_records + sponsor = Sponsor.new + saved_member = Member.create + new_member = Member.new + + sponsor.sponsorable = saved_member + assert_equal saved_member.id, sponsor.sponsorable_id + + sponsor.sponsorable = new_member + assert_equal nil, sponsor.sponsorable_id + end end -- cgit v1.2.3 From 0580b31b36c0f7dd1a0f8bdd1b1806e3bd65b22d Mon Sep 17 00:00:00 2001 From: Tim Harper Date: Tue, 13 May 2008 19:17:40 -0600 Subject: belongs_to polymorphic association assignments update the foreign_id and foreign_type fields regardless of whether the record being assigned is new or not. fixes the following scenarios: * I have validates_inclusion_of on the type field for a polymorphic belongs_to association. I assign a new record to the model's polymorphic relationship of the proper type. validation fails because the type field has not been updated. * I replace the value for a ppolymorphic association to a new record of another class. The type field still says its the previous class, and the id field points to the previous record as well. [#191 state:closed] --- .../belongs_to_polymorphic_association.rb | 6 ++--- .../associations/belongs_to_associations_test.rb | 29 +++++++++++++++++++++- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb index df4ae38f38..d8146daa54 100755 --- a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb @@ -7,10 +7,8 @@ module ActiveRecord else @target = (AssociationProxy === record ? record.target : record) - unless record.new_record? - @owner[@reflection.primary_key_name] = record.id - @owner[@reflection.options[:foreign_type]] = record.class.base_class.name.to_s - end + @owner[@reflection.primary_key_name] = record.id + @owner[@reflection.options[:foreign_type]] = record.class.base_class.name.to_s @updated = true end diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 3073eae355..e0da8bfb7a 100755 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -12,6 +12,8 @@ require 'models/author' require 'models/tag' require 'models/tagging' require 'models/comment' +require 'models/sponsor' +require 'models/member' class BelongsToAssociationsTest < ActiveRecord::TestCase fixtures :accounts, :companies, :developers, :projects, :topics, @@ -381,5 +383,30 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_raise(ActiveRecord::ReadOnlyRecord) { companies(:first_client).readonly_firm.save! } assert companies(:first_client).readonly_firm.readonly? end - + + def test_polymorphic_assignment_foreign_type_field_updating + # should update when assigning a saved record + sponsor = Sponsor.new + member = Member.create + sponsor.sponsorable = member + assert_equal "Member", sponsor.sponsorable_type + + # should update when assigning a new record + sponsor = Sponsor.new + member = Member.new + sponsor.sponsorable = member + assert_equal "Member", sponsor.sponsorable_type + end + + def test_polymorphic_assignment_updates_foreign_id_field_for_new_and_saved_records + sponsor = Sponsor.new + saved_member = Member.create + new_member = Member.new + + sponsor.sponsorable = saved_member + assert_equal saved_member.id, sponsor.sponsorable_id + + sponsor.sponsorable = new_member + assert_equal nil, sponsor.sponsorable_id + end end -- cgit v1.2.3 From 77e45352e7e947f1df1bfb8fe7d9e4e133224dd9 Mon Sep 17 00:00:00 2001 From: Tom Ward Date: Sat, 31 May 2008 13:33:38 -0700 Subject: Fixed Dependencies so load errors are not masked behind a 'Expected x.rb to define X' message when mechanism is not set to :load [#87 state:resolved] Signed-off-by: Joshua Peek --- activesupport/lib/active_support/dependencies.rb | 19 ++++++++++--------- activesupport/test/dependencies_test.rb | 20 ++++++++++++++------ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index 25225d5615..da2ece610a 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -82,9 +82,10 @@ module Dependencies #:nodoc: # infinite loop with mutual dependencies. loaded << expanded - if load? - log "loading #{file_name}" - begin + begin + if load? + log "loading #{file_name}" + # Enable warnings iff this file has not been loaded before and # warnings_on_first_load is set. load_args = ["#{file_name}.rb"] @@ -95,13 +96,13 @@ module Dependencies #:nodoc: else enable_warnings { result = load_file(*load_args) } end - rescue Exception - loaded.delete expanded - raise + else + log "requiring #{file_name}" + result = require file_name end - else - log "requiring #{file_name}" - result = require file_name + rescue Exception + loaded.delete expanded + raise end # Record history *after* loading so first load gets warnings. diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb index 1e19e12da9..0309ab6858 100644 --- a/activesupport/test/dependencies_test.rb +++ b/activesupport/test/dependencies_test.rb @@ -673,7 +673,7 @@ class DependenciesTest < Test::Unit::TestCase 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 @@ -686,11 +686,20 @@ class DependenciesTest < Test::Unit::TestCase 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_error_when_mechanism_not_set_to_load + with_loading 'autoloading_fixtures' do + Dependencies.mechanism = :require + 2.times do + assert_raise(NameError) {"RaisesNameError".constantize} + end + end + 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!" @@ -714,7 +723,7 @@ class DependenciesTest < Test::Unit::TestCase 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 @@ -724,7 +733,7 @@ class DependenciesTest < Test::Unit::TestCase 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 @@ -737,7 +746,7 @@ class DependenciesTest < Test::Unit::TestCase 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] @@ -753,5 +762,4 @@ class DependenciesTest < Test::Unit::TestCase ensure Dependencies.load_once_paths = [] end - end -- cgit v1.2.3 From eb007e4197d6b6513e5accda79cf7edc3d773888 Mon Sep 17 00:00:00 2001 From: Cheah Chu Yeow Date: Sat, 31 May 2008 13:46:02 -0700 Subject: Make a note about script/destroy in 'script/generate scaffold' usage description. Make a note about 'script/generate scaffold' requiring a singular model name. Remove :nodoc: for a documented method. --- activeresource/lib/active_resource/base.rb | 4 ++-- .../rails_generator/generators/components/scaffold/USAGE | 14 +++++++++----- railties/lib/rails_generator/scripts/destroy.rb | 13 ++++++------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index 253d336dc9..ca9e665ba3 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -288,7 +288,7 @@ module ActiveResource end # Returns the current format, default is ActiveResource::Formats::XmlFormat. - def format # :nodoc: + def format read_inheritable_attribute("format") || ActiveResource::Formats[:xml] end @@ -812,7 +812,7 @@ module ActiveResource # Person.delete(guys_id) # that_guy.exists? # => false def exists? - !new? && self.class.exists?(to_param, :params => prefix_options) + !new? && self.class.exists?(to_param, :params => prefix_options) end # A method to convert the the resource to an XML string. diff --git a/railties/lib/rails_generator/generators/components/scaffold/USAGE b/railties/lib/rails_generator/generators/components/scaffold/USAGE index a0e4baea08..810aea16f1 100644 --- a/railties/lib/rails_generator/generators/components/scaffold/USAGE +++ b/railties/lib/rails_generator/generators/components/scaffold/USAGE @@ -1,10 +1,11 @@ Description: Scaffolds an entire resource, from model and migration to controller and views, along with a full test suite. The resource is ready to use as a - starting point for your restful, resource-oriented application. + starting point for your RESTful, resource-oriented application. - Pass the name of the model, either CamelCased or under_scored, as the first - argument, and an optional list of attribute pairs. + Pass the name of the model (in singular form), either CamelCased or + under_scored, as the first argument, and an optional list of attribute + pairs. Attribute pairs are column_name:sql_type arguments specifying the model's attributes. Timestamps are added by default, so you don't have to @@ -13,13 +14,16 @@ Description: You don't have to think up every attribute up front, but it helps to sketch out a few so you can start working with the resource immediately. - For example, `scaffold post title:string body:text published:boolean` + For example, 'scaffold post title:string body:text published:boolean' gives you a model with those three attributes, a controller that handles the create/show/update/destroy, forms to create and edit your posts, and an index that lists them all, as well as a map.resources :posts declaration in config/routes.rb. + If you want to remove all the generated files, run + 'script/destroy scaffold ModelName'. + Examples: - `./script/generate scaffold post` # no attributes, view will be anemic + `./script/generate scaffold post` `./script/generate scaffold post title:string body:text published:boolean` `./script/generate scaffold purchase order_id:integer amount:decimal` diff --git a/railties/lib/rails_generator/scripts/destroy.rb b/railties/lib/rails_generator/scripts/destroy.rb index 4fcbc3e0df..a7c2a14751 100644 --- a/railties/lib/rails_generator/scripts/destroy.rb +++ b/railties/lib/rails_generator/scripts/destroy.rb @@ -3,7 +3,7 @@ require File.dirname(__FILE__) + '/../scripts' module Rails::Generator::Scripts class Destroy < Base mandatory_options :command => :destroy - + protected def usage_message usage = "\nInstalled Generators\n" @@ -15,14 +15,13 @@ module Rails::Generator::Scripts usage << < Date: Sat, 31 May 2008 14:12:50 -0700 Subject: Fix spelling in deprecation warning (affect -> effect) --- actionpack/lib/action_view/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index f398756550..c236666dcd 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -170,7 +170,7 @@ module ActionView #:nodoc: cattr_accessor :cache_template_loading def self.cache_template_extensions=(*args) - ActiveSupport::Deprecation.warn("config.action_view.cache_template_extensions option has been deprecated and has no affect. " << + ActiveSupport::Deprecation.warn("config.action_view.cache_template_extensions option has been deprecated and has no effect. " << "Please remove it from your config files.", caller) end -- cgit v1.2.3 From 4e4bcb4c6b08ed392cd5576dcfc252ef574a1b88 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 31 May 2008 14:54:17 -0700 Subject: Ruby 1.8.7 compat: TimeWithZone# and Chars#respond_to? pass along the include_private argument --- activesupport/lib/active_support/multibyte/chars.rb | 12 +++++++----- activesupport/lib/active_support/time_with_zone.rb | 8 ++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb index ee716de39e..185d03020c 100644 --- a/activesupport/lib/active_support/multibyte/chars.rb +++ b/activesupport/lib/active_support/multibyte/chars.rb @@ -40,13 +40,15 @@ module ActiveSupport::Multibyte #:nodoc: # 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 + def respond_to?(method, include_priv = false) + super || @string.respond_to?(method, include_priv) || + handler.respond_to?(method, include_priv) || + (method.to_s =~ /(.*)!/ && handler.respond_to?($1, include_priv)) || + false end - + # Create a new Chars instance. def initialize(str) @string = str.respond_to?(:string) ? str.string : str diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index ece95eeae9..bfc5b16039 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -248,14 +248,14 @@ module ActiveSupport def marshal_load(variables) initialize(variables[0], ::Time.send!(:get_zone, variables[1]), variables[2]) end - + # Ensure proxy class responds to all methods that underlying time instance responds to. - def respond_to?(sym) + def respond_to?(sym, include_priv = false) # consistently respond false to acts_like?(:date), regardless of whether #time is a Time or DateTime return false if sym.to_s == 'acts_like_date?' - super || time.respond_to?(sym) + super || time.respond_to?(sym, include_priv) end - + # Send the missing method to +time+ instance, and wrap result in a new TimeWithZone with the existing +time_zone+. def method_missing(sym, *args, &block) result = time.__send__(sym, *args, &block) -- cgit v1.2.3 From 0abf0da0016abc455145810d7060a10e0b56b0b6 Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Sat, 31 May 2008 14:58:34 -0700 Subject: Don't provide the password with dbconsole unless explicitly opted in. Some operating system configurations allow other users to view your process list or environmental variables. This option should not be used on shared hosts. http://dev.mysql.com/doc/refman/5.0/en/password-security.html http://www.postgresql.org/docs/8.3/static/libpq-envars.html --- railties/lib/commands/dbconsole.rb | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/railties/lib/commands/dbconsole.rb b/railties/lib/commands/dbconsole.rb index b81997aa59..17acb7b68f 100644 --- a/railties/lib/commands/dbconsole.rb +++ b/railties/lib/commands/dbconsole.rb @@ -2,8 +2,13 @@ require 'erb' require 'yaml' require 'optparse' +include_password = false + OptionParser.new do |opt| - opt.banner = "Usage: dbconsole [environment]" + opt.banner = "Usage: dbconsole [options] [environment]" + opt.on("-p", "--include-password", "Automatically provide the database from database.yml") do |v| + include_password = true + end opt.parse!(ARGV) abort opt.to_s unless (0..1).include?(ARGV.size) end @@ -31,10 +36,13 @@ when "mysql" 'port' => '--port', 'socket' => '--socket', 'username' => '--user', - 'password' => '--password', 'encoding' => '--default-character-set' }.map { |opt, arg| "#{arg}=#{config[opt]}" if config[opt] }.compact + if config['password'] && include_password + args << "--password=#{config['password']}" + end + args << config['database'] exec(find_cmd('mysql5', 'mysql'), *args) @@ -43,7 +51,7 @@ when "postgresql" ENV['PGUSER'] = config["username"] if config["username"] ENV['PGHOST'] = config["host"] if config["host"] ENV['PGPORT'] = config["port"].to_s if config["port"] - ENV['PGPASSWORD'] = config["password"].to_s if config["password"] + ENV['PGPASSWORD'] = config["password"].to_s if config["password"] && include_password exec(find_cmd('psql'), config["database"]) when "sqlite" -- cgit v1.2.3 From 3a9775076fc4f99f8d7ad9a554a9ef8798c8fad7 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sat, 31 May 2008 15:32:51 -0700 Subject: Removed suggestion for turning off partial updates. --- railties/environments/environment.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/railties/environments/environment.rb b/railties/environments/environment.rb index 468fa45ef6..a85ade371b 100644 --- a/railties/environments/environment.rb +++ b/railties/environments/environment.rb @@ -64,7 +64,4 @@ Rails::Initializer.run do |config| # Activate observers that should always be running # config.active_record.observers = :cacher, :garbage_collector - - # Make ActiveRecord only save the attributes that have changed since the record was loaded. - # config.active_record.partial_updates = true -end \ No newline at end of file +end -- cgit v1.2.3 From 7391f7728d96c2ec0113de57f3316c191043ad2c Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 31 May 2008 15:31:04 -0700 Subject: Ruby 1.8.7 compat: work around broken DelegateClass#respond_to? --- actionpack/lib/action_controller/cgi_ext/cookie.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/actionpack/lib/action_controller/cgi_ext/cookie.rb b/actionpack/lib/action_controller/cgi_ext/cookie.rb index ef033fb4f3..009ddd1c64 100644 --- a/actionpack/lib/action_controller/cgi_ext/cookie.rb +++ b/actionpack/lib/action_controller/cgi_ext/cookie.rb @@ -78,6 +78,12 @@ class CGI #:nodoc: buf end + # FIXME: work around broken 1.8.7 DelegateClass#respond_to? + def respond_to?(method, include_private = false) + return true if super(method) + return __getobj__.respond_to?(method, include_private) + end + # Parses a raw cookie string into a hash of cookie-name => cookie-object # pairs. # -- cgit v1.2.3 From 9b75483bf361f44046d1cb86bd2acae6c4f856f3 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sat, 31 May 2008 15:51:01 -0700 Subject: Added better error message for when the class name is already used (and dont show suggestions if there are none) --- railties/lib/rails_generator/commands.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/railties/lib/rails_generator/commands.rb b/railties/lib/rails_generator/commands.rb index 03b7d354a6..08ecbfb5cf 100644 --- a/railties/lib/rails_generator/commands.rb +++ b/railties/lib/rails_generator/commands.rb @@ -380,12 +380,14 @@ HELP # Thanks to Florian Gross (flgr). def raise_class_collision(class_name) message = < Date: Fri, 16 May 2008 07:19:00 -0500 Subject: Run gem install as external command. [#210 state:resolved] --- railties/lib/rails/gem_dependency.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/railties/lib/rails/gem_dependency.rb b/railties/lib/rails/gem_dependency.rb index 2034841cd2..582861abf4 100644 --- a/railties/lib/rails/gem_dependency.rb +++ b/railties/lib/rails/gem_dependency.rb @@ -73,7 +73,7 @@ module Rails end def install - Gem::GemRunner.new.run(install_command) + puts `#{gem_command} #{install_command.join(' ')}` end def unpack_to(directory) @@ -100,6 +100,10 @@ private ################################################################### def specification @spec ||= Gem.source_index.search(Gem::Dependency.new(@name, @requirement)).sort_by { |s| s.version }.last end + + def gem_command + RUBY_PLATFORM =~ /win32/ ? 'gem.bat' : 'gem' + end def install_command cmd = %w(install) << @name -- cgit v1.2.3 From 9c4f00350a61987afad50ebb8d319d7e889b6cfd Mon Sep 17 00:00:00 2001 From: rick Date: Sat, 31 May 2008 15:58:08 -0700 Subject: fix Gem installation command with versions --- railties/CHANGELOG | 4 ++++ railties/lib/rails/gem_dependency.rb | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/railties/CHANGELOG b/railties/CHANGELOG index 11d2926f31..c765dedae5 100644 --- a/railties/CHANGELOG +++ b/railties/CHANGELOG @@ -1,3 +1,7 @@ +*SVN* + +* Use a system command to install gems, since GemRunner exits the ruby process. #210 [Tim Morgan] + *2.1.0 RC1 (May 11th, 2008)* * script/dbconsole fires up the command-line database client. #102 [Steve Purcell] diff --git a/railties/lib/rails/gem_dependency.rb b/railties/lib/rails/gem_dependency.rb index 582861abf4..22ee0e3601 100644 --- a/railties/lib/rails/gem_dependency.rb +++ b/railties/lib/rails/gem_dependency.rb @@ -73,7 +73,9 @@ module Rails end def install - puts `#{gem_command} #{install_command.join(' ')}` + cmd = "#{gem_command} #{install_command.join(' ')}" + puts cmd + puts %x(#{cmd}) end def unpack_to(directory) @@ -107,7 +109,7 @@ private ################################################################### def install_command cmd = %w(install) << @name - cmd << "--version" << "#{@requirement.to_s}" if @requirement + cmd << "--version" << %("#{@requirement.to_s}") if @requirement cmd << "--source" << @source if @source cmd end -- cgit v1.2.3 From d5bcff172b6253684cf5cc3345a3d390096ba957 Mon Sep 17 00:00:00 2001 From: rick Date: Sat, 31 May 2008 16:36:34 -0700 Subject: Consolidate error messages for missing gems, and skip them when running rake gems:* tasks. [rick] --- railties/CHANGELOG | 2 ++ railties/lib/initializer.rb | 43 ++++++++++++++++++++++++++---------- railties/lib/rails/gem_dependency.rb | 1 - railties/lib/tasks/gems.rake | 12 +++++++--- 4 files changed, 42 insertions(+), 16 deletions(-) diff --git a/railties/CHANGELOG b/railties/CHANGELOG index c765dedae5..7f1c6ad747 100644 --- a/railties/CHANGELOG +++ b/railties/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Consolidate error messages for missing gems, and skip them when running rake gems:* tasks. [rick] + * Use a system command to install gems, since GemRunner exits the ruby process. #210 [Tim Morgan] *2.1.0 RC1 (May 11th, 2008)* diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb index 8f963cb4a5..ca63fa734b 100644 --- a/railties/lib/initializer.rb +++ b/railties/lib/initializer.rb @@ -140,7 +140,8 @@ module Rails # pick up any gems that plugins depend on add_gem_load_paths load_gems - + check_gem_dependencies + load_application_initializers # the framework is now fully initialized @@ -153,6 +154,7 @@ module Rails initialize_routing # Observers are loaded after plugins in case Observers or observed models are modified by plugins. + load_observers end @@ -241,7 +243,24 @@ module Rails end def load_gems - @configuration.gems.each &:load + @configuration.gems.each(&:load) + end + + def check_gem_dependencies + unloaded_gems = @configuration.gems.reject { |g| g.loaded? } + if unloaded_gems.size > 0 + @gems_dependencies_loaded = false + # don't print if the gems rake tasks are being run + unless $rails_gem_installer + puts %{These gems that this application depends on are missing:} + unloaded_gems.each do |gem| + puts " - #{gem.name}" + end + puts %{Run "rake gems:install" to install them.} + end + else + @gems_dependencies_loaded = true + end end # Loads all plugins in config.plugin_paths. plugin_paths @@ -287,12 +306,8 @@ module Rails end def load_observers - if configuration.frameworks.include?(:active_record) - if @configuration.gems.any? { |g| !g.loaded? } - puts %{Unable to instantiate observers, some gems that this application depends on are missing. Run "rake gems:install"} - else - ActiveRecord::Base.instantiate_observers - end + if @gems_dependencies_loaded && configuration.frameworks.include?(:active_record) + ActiveRecord::Base.instantiate_observers end end @@ -447,14 +462,18 @@ module Rails # Fires the user-supplied after_initialize block (Configuration#after_initialize) def after_initialize - configuration.after_initialize_blocks.each do |block| - block.call + if @gems_dependencies_loaded + configuration.after_initialize_blocks.each do |block| + block.call + end end end def load_application_initializers - Dir["#{configuration.root_path}/config/initializers/**/*.rb"].sort.each do |initializer| - load(initializer) + if @gems_dependencies_loaded + Dir["#{configuration.root_path}/config/initializers/**/*.rb"].sort.each do |initializer| + load(initializer) + end end end diff --git a/railties/lib/rails/gem_dependency.rb b/railties/lib/rails/gem_dependency.rb index 22ee0e3601..0e39f6fd0a 100644 --- a/railties/lib/rails/gem_dependency.rb +++ b/railties/lib/rails/gem_dependency.rb @@ -36,7 +36,6 @@ module Rails end @load_paths_added = true rescue Gem::LoadError - puts $!.to_s end def dependencies diff --git a/railties/lib/tasks/gems.rake b/railties/lib/tasks/gems.rake index c18fea2d60..0321e60e0f 100644 --- a/railties/lib/tasks/gems.rake +++ b/railties/lib/tasks/gems.rake @@ -1,5 +1,5 @@ desc "List the gems that this rails application depends on" -task :gems => :environment do +task :gems => 'gems:base' do Rails.configuration.gems.each do |gem| code = gem.loaded? ? (gem.frozen? ? "F" : "I") : " " puts "[#{code}] #{gem.name} #{gem.requirement.to_s}" @@ -10,8 +10,14 @@ task :gems => :environment do end namespace :gems do + task :base do + $rails_gem_installer = true + Rake::Task[:environment].invoke + end + desc "Build any native extensions for unpacked gems" task :build do + $rails_gem_installer = true require 'rails/gem_builder' Dir[File.join(RAILS_ROOT, 'vendor', 'gems', '*')].each do |gem_dir| spec_file = File.join(gem_dir, '.specification') @@ -24,14 +30,14 @@ namespace :gems do end desc "Installs all required gems for this application." - task :install => :environment do + task :install => :base do require 'rubygems' require 'rubygems/gem_runner' Rails.configuration.gems.each { |gem| gem.install unless gem.loaded? } end desc "Unpacks the specified gem into vendor/gems." - task :unpack => :environment do + task :unpack => :base do require 'rubygems' require 'rubygems/gem_runner' Rails.configuration.gems.each do |gem| -- cgit v1.2.3 From 224c8e6afb464a4b04621189963ec03d1d3487d0 Mon Sep 17 00:00:00 2001 From: Dmitriy Timokhin Date: Wed, 7 May 2008 17:43:12 +0400 Subject: Expose GemPlugin load_paths so they can be added to Dependencies.load_paths. Also use full_gem_path as root of GemPlugin to make things compatible. [#213 state:resolved] --- railties/lib/rails/plugin.rb | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/railties/lib/rails/plugin.rb b/railties/lib/rails/plugin.rb index 04f7e37a20..fdaec34c59 100644 --- a/railties/lib/rails/plugin.rb +++ b/railties/lib/rails/plugin.rb @@ -98,23 +98,19 @@ module Rails end end - # This Plugin subclass represents a Gem plugin. It behaves exactly like a - # "traditional" Rails plugin, but doesn't expose any additional load paths, - # since RubyGems has already taken care of things. + # This Plugin subclass represents a Gem plugin. Although RubyGems has already + # taken care of $LOAD_PATH's, it have to expose its load_path's to add them + # to Dependencies.load_paths. class GemPlugin < Plugin # Initialize this plugin from a Gem::Specification. def initialize(spec) - super(File.join(spec.full_gem_path, "rails")) + super(File.join(spec.full_gem_path)) @name = spec.name end - def valid? - true - end - - def load_paths - [] + def init_path + File.join(directory, 'rails', 'init.rb') end end end \ No newline at end of file -- cgit v1.2.3 From a6e79083273dfb1a62aa8ff02db07454c65729ff Mon Sep 17 00:00:00 2001 From: rick Date: Sat, 31 May 2008 16:46:47 -0700 Subject: fix doc typos --- railties/lib/rails/plugin.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/railties/lib/rails/plugin.rb b/railties/lib/rails/plugin.rb index fdaec34c59..256f4b0132 100644 --- a/railties/lib/rails/plugin.rb +++ b/railties/lib/rails/plugin.rb @@ -99,10 +99,9 @@ module Rails end # This Plugin subclass represents a Gem plugin. Although RubyGems has already - # taken care of $LOAD_PATH's, it have to expose its load_path's to add them + # taken care of $LOAD_PATHs, it exposes its load_paths to add them # to Dependencies.load_paths. class GemPlugin < Plugin - # Initialize this plugin from a Gem::Specification. def initialize(spec) super(File.join(spec.full_gem_path)) -- cgit v1.2.3 From ef0ea782b1f5cf7b08e74ea3002a16c708f66645 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sat, 31 May 2008 16:57:46 -0700 Subject: Added SQL escaping for :limit and :offset [#288 state:closed] (Aaron Bedra, Steven Bristol, Jonathan Wiess) --- .../abstract/database_statements.rb | 9 +++++++-- activerecord/test/cases/adapter_test.rb | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index 16d405d3bd..5358491cde 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -106,11 +106,16 @@ module ActiveRecord # SELECT * FROM suppliers LIMIT 10 OFFSET 50 def add_limit_offset!(sql, options) if limit = options[:limit] - sql << " LIMIT #{limit}" + sql << " LIMIT #{sanitize_limit(limit)}" if offset = options[:offset] - sql << " OFFSET #{offset}" + sql << " OFFSET #{offset.to_i}" end end + sql + end + + def sanitize_limit(limit) + limit.to_s[/,/] ? limit.split(',').map{ |i| i.to_i }.join(',') : limit.to_i end # Appends a locking clause to an SQL statement. diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index 91504af901..c77446f880 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -104,4 +104,24 @@ class AdapterTest < ActiveRecord::TestCase end end + def test_add_limit_offset_should_sanitize_sql_injection_for_limit_without_comas + sql_inject = "1 select * from schema" + assert_equal " LIMIT 1", @connection.add_limit_offset!("", :limit=>sql_inject) + if current_adapter?(:MysqlAdapter) + assert_equal " LIMIT 7, 1", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7) + else + assert_equal " LIMIT 1 OFFSET 7", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7) + end + end + + def test_add_limit_offset_should_sanitize_sql_injection_for_limit_with_comas + sql_inject = "1, 7 procedure help()" + if current_adapter?(:MysqlAdapter) + assert_equal " LIMIT 1,7", @connection.add_limit_offset!("", :limit=>sql_inject) + assert_equal " LIMIT 7, 1", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7) + else + assert_equal " LIMIT 1,7", @connection.add_limit_offset!("", :limit=>sql_inject) + assert_equal " LIMIT 1,7 OFFSET 7", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7) + end + end end -- cgit v1.2.3 From f6e921f9568d7f2e4807edf8728e6b0df8991816 Mon Sep 17 00:00:00 2001 From: "John D. Hume" Date: Wed, 28 May 2008 23:35:56 -0400 Subject: Substitute value into validates_format_of message Signed-off-by: Michael Koziarski --- activerecord/lib/active_record/validations.rb | 2 +- activerecord/test/cases/validations_test.rb | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 0e150bddb2..c97aafb126 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -692,7 +692,7 @@ module ActiveRecord raise(ArgumentError, "A regular expression must be supplied as the :with option of the configuration hash") unless configuration[:with].is_a?(Regexp) validates_each(attr_names, configuration) do |record, attr_name, value| - record.errors.add(attr_name, configuration[:message]) unless value.to_s =~ configuration[:with] + record.errors.add(attr_name, configuration[:message] % value) unless value.to_s =~ configuration[:with] end end diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb index a4d9da4806..7b71647d25 100755 --- a/activerecord/test/cases/validations_test.rb +++ b/activerecord/test/cases/validations_test.rb @@ -583,6 +583,12 @@ class ValidationsTest < ActiveRecord::TestCase assert_nil t.errors.on(:title) end + def test_validate_format_with_formatted_message + Topic.validates_format_of(:title, :with => /^Valid Title$/, :message => "can't be %s") + t = Topic.create(:title => 'Invalid title') + assert_equal "can't be Invalid title", t.errors.on(:title) + end + def test_validates_inclusion_of Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ) ) -- cgit v1.2.3 From ef21e013338461f33bf85f5cf6edd84b5ce9b6fe Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Sat, 31 May 2008 16:39:32 -0700 Subject: Remove dead code, and the tests for it. --- actionpack/lib/action_view/compiled_templates.rb | 69 -------- .../test/template/compiled_templates_test.rb | 192 --------------------- 2 files changed, 261 deletions(-) delete mode 100644 actionpack/lib/action_view/compiled_templates.rb delete mode 100644 actionpack/test/template/compiled_templates_test.rb diff --git a/actionpack/lib/action_view/compiled_templates.rb b/actionpack/lib/action_view/compiled_templates.rb deleted file mode 100644 index 5a286432e3..0000000000 --- a/actionpack/lib/action_view/compiled_templates.rb +++ /dev/null @@ -1,69 +0,0 @@ -module ActionView - - # CompiledTemplates modules hold methods that have been compiled. - # Templates are compiled into these methods so that they do not need to be - # read and parsed for each request. - # - # Each template may be compiled into one or more methods. Each method accepts a given - # set of parameters which is used to implement local assigns passing. - # - # To use a compiled template module, create a new instance and include it into the class - # in which you want the template to be rendered. - class CompiledTemplates < Module - attr_reader :method_names - - def initialize - @method_names = Hash.new do |hash, key| - hash[key] = "__compiled_method_#{(hash.length + 1)}" - end - @mtimes = {} - end - - # Return the full key for the given identifier and argument names - def full_key(identifier, arg_names) - [identifier, arg_names] - end - - # Return the selector for this method or nil if it has not been compiled - def selector(identifier, arg_names) - key = full_key(identifier, arg_names) - method_names.key?(key) ? method_names[key] : nil - end - alias :compiled? :selector - - # Return the time at which the method for the given identifier and argument names was compiled. - def mtime(identifier, arg_names) - @mtimes[full_key(identifier, arg_names)] - end - - # Compile the provided source code for the given argument names and with the given initial line number. - # The identifier should be unique to this source. - # - # The file_name, if provided will appear in backtraces. If not provided, the file_name defaults - # to the identifier. - # - # This method will return the selector for the compiled version of this method. - def compile_source(identifier, arg_names, source, initial_line_number = 0, file_name = nil) - file_name ||= identifier - name = method_names[full_key(identifier, arg_names)] - arg_desc = arg_names.empty? ? '' : "(#{arg_names * ', '})" - fake_file_name = "#{file_name}#{arg_desc}" # Include the arguments for this version (for now) - - method_def = wrap_source(name, arg_names, source) - - begin - module_eval(method_def, fake_file_name, initial_line_number) - @mtimes[full_key(identifier, arg_names)] = Time.now - rescue Exception => e # errors from compiled source - e.blame_file! identifier - raise - end - name - end - - # Wrap the provided source in a def ... end block. - def wrap_source(name, arg_names, source) - "def #{name}(#{arg_names * ', '})\n#{source}\nend" - end - end -end diff --git a/actionpack/test/template/compiled_templates_test.rb b/actionpack/test/template/compiled_templates_test.rb deleted file mode 100644 index 73e7ec1d76..0000000000 --- a/actionpack/test/template/compiled_templates_test.rb +++ /dev/null @@ -1,192 +0,0 @@ -require 'abstract_unit' -require 'action_view/helpers/date_helper' -require 'action_view/compiled_templates' - -class CompiledTemplateTests < Test::Unit::TestCase - def setup - @ct = ActionView::CompiledTemplates.new - @v = Class.new - @v.send :include, @ct - @a = './test_compile_template_a.rhtml' - @b = './test_compile_template_b.rhtml' - @s = './test_compile_template_link.rhtml' - end - def teardown - [@a, @b, @s].each do |f| - FileUtils.rm(f) if File.exist?(f) || File.symlink?(f) - end - end - attr_reader :ct, :v - - def test_name_allocation - hi_world = ct.method_names['hi world'] - hi_sexy = ct.method_names['hi sexy'] - wish_upon_a_star = ct.method_names['I love seeing decent error messages'] - - assert_equal hi_world, ct.method_names['hi world'] - assert_equal hi_sexy, ct.method_names['hi sexy'] - assert_equal wish_upon_a_star, ct.method_names['I love seeing decent error messages'] - assert_equal 3, [hi_world, hi_sexy, wish_upon_a_star].uniq.length - end - - def test_wrap_source - assert_equal( - "def aliased_assignment(value)\nself.value = value\nend", - @ct.wrap_source(:aliased_assignment, [:value], 'self.value = value') - ) - - assert_equal( - "def simple()\nnil\nend", - @ct.wrap_source(:simple, [], 'nil') - ) - end - - def test_compile_source_single_method - selector = ct.compile_source('doubling method', [:a], 'a + a') - assert_equal 2, @v.new.send(selector, 1) - assert_equal 4, @v.new.send(selector, 2) - assert_equal -4, @v.new.send(selector, -2) - assert_equal 0, @v.new.send(selector, 0) - selector - end - - def test_compile_source_two_method - sel1 = test_compile_source_single_method # compile the method in the other test - sel2 = ct.compile_source('doubling method', [:a, :b], 'a + b + a + b') - assert_not_equal sel1, sel2 - - assert_equal 2, @v.new.send(sel1, 1) - assert_equal 4, @v.new.send(sel1, 2) - - assert_equal 6, @v.new.send(sel2, 1, 2) - assert_equal 32, @v.new.send(sel2, 15, 1) - end - - def test_mtime - t1 = Time.now - - test_compile_source_single_method - mtime = ct.mtime('doubling method', [:a]) - - assert mtime < Time.now - assert mtime > t1 - end - - uses_mocha 'test_compile_time' do - - def test_compile_time - t = Time.now - - File.open(@a, "w"){|f| f.puts @a} - File.open(@b, "w"){|f| f.puts @b} - # windows doesn't support symlinks (even under cygwin) - windows = (RUBY_PLATFORM =~ /win32/) - `ln -s #{@a} #{@s}` unless windows - - v = ActionView::Base.new - v.base_path = '.' - v.cache_template_loading = false - - ta = ActionView::Template.new(v, @a, false, {}) - tb = ActionView::Template.new(v, @b, false, {}) - ts = ActionView::Template.new(v, @s, false, {}) - - @handler_class = ActionView::Template.handler_class_for_extension(:rhtml) - @handler = @handler_class.new(v) - - # All templates were created at t+1 - File::Stat.any_instance.expects(:mtime).times(windows ? 2 : 3).returns(t + 1.second) - - # private methods template_changed_since? and compile_template? - # should report true for all since they have not been compiled - assert @handler.send(:template_changed_since?, @a, t) - assert @handler.send(:template_changed_since?, @b, t) - assert @handler.send(:template_changed_since?, @s, t) unless windows - - assert @handler.send(:compile_template?, ta) - assert @handler.send(:compile_template?, tb) - assert @handler.send(:compile_template?, ts) unless windows - - # All templates are rendered at t+2 - Time.expects(:now).times(windows ? 2 : 3).returns(t + 2.seconds) - v.send(:render_template, ta) - v.send(:render_template, tb) - v.send(:render_template, ts) unless windows - a_n = v.method_names[@a] - b_n = v.method_names[@b] - s_n = v.method_names[@s] unless windows - # all of the files have changed since last compile - assert @handler.compile_time[a_n] > t - assert @handler.compile_time[b_n] > t - assert @handler.compile_time[s_n] > t unless windows - - # private methods template_changed_since? and compile_template? - # should report false for all since none have changed since compile - File::Stat.any_instance.expects(:mtime).times(windows ? 6 : 12).returns(t + 1.second) - assert !@handler.send(:template_changed_since?, @a, @handler.compile_time[a_n]) - assert !@handler.send(:template_changed_since?, @b, @handler.compile_time[b_n]) - assert !@handler.send(:template_changed_since?, @s, @handler.compile_time[s_n]) unless windows - assert !@handler.send(:compile_template?, ta) - assert !@handler.send(:compile_template?, tb) - assert !@handler.send(:compile_template?, ts) unless windows - v.send(:render_template, ta) - v.send(:render_template, tb) - v.send(:render_template, ts) unless windows - # none of the files have changed since last compile - assert @handler.compile_time[a_n] < t + 3.seconds - assert @handler.compile_time[b_n] < t + 3.seconds - assert @handler.compile_time[s_n] < t + 3.seconds unless windows - - `rm #{@s}; ln -s #{@b} #{@s}` unless windows - # private methods template_changed_since? and compile_template? - # should report true for symlink since it has changed since compile - - # t + 3.seconds is for the symlink - File::Stat.any_instance.expects(:mtime).times(windows ? 6 : 9).returns( - *(windows ? [ t + 1.second, t + 1.second ] : - [ t + 1.second, t + 1.second, t + 3.second ]) * 3) - assert !@handler.send(:template_changed_since?, @a, @handler.compile_time[a_n]) - assert !@handler.send(:template_changed_since?, @b, @handler.compile_time[b_n]) - assert @handler.send(:template_changed_since?, @s, @handler.compile_time[s_n]) unless windows - assert !@handler.send(:compile_template?, ta) - assert !@handler.send(:compile_template?, tb) - assert @handler.send(:compile_template?, ts) unless windows - - # Only the symlink template gets rendered at t+3 - Time.stubs(:now).returns(t + 3.seconds) unless windows - v.send(:render_template, ta) - v.send(:render_template, tb) - v.send(:render_template, ts) unless windows - # the symlink has changed since last compile - assert @handler.compile_time[a_n] < t + 3.seconds - assert @handler.compile_time[b_n] < t + 3.seconds - assert_equal @handler.compile_time[s_n], t + 3.seconds unless windows - - FileUtils.touch @b - # private methods template_changed_since? and compile_template? - # should report true for symlink and file at end of symlink - # since it has changed since last compile - # - # t+4 is for @b and also for the file that @s points to, which is @b - File::Stat.any_instance.expects(:mtime).times(windows ? 6 : 12).returns( - *(windows ? [ t + 1.second, t + 4.seconds ] : - [ t + 1.second, t + 4.seconds, t + 3.second, t + 4.seconds ]) * 3) - assert !@handler.send(:template_changed_since?, @a, @handler.compile_time[a_n]) - assert @handler.send(:template_changed_since?, @b, @handler.compile_time[b_n]) - assert @handler.send(:template_changed_since?, @s, @handler.compile_time[s_n]) unless windows - assert !@handler.send(:compile_template?, ta) - assert @handler.send(:compile_template?, tb) - assert @handler.send(:compile_template?, ts) unless windows - - Time.expects(:now).times(windows ? 1 : 2).returns(t + 5.seconds) - v.send(:render_template, ta) - v.send(:render_template, tb) - v.send(:render_template, ts) unless windows - # the file at the end of the symlink has changed since last compile - # both the symlink and the file at the end of it should be recompiled - assert @handler.compile_time[a_n] < t + 5.seconds - assert_equal @handler.compile_time[b_n], t + 5.seconds - assert_equal @handler.compile_time[s_n], t + 5.seconds unless windows - end - end -end -- cgit v1.2.3 From f9db7695fe3c148c8d1077f1564e5b94d126b83b Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sat, 31 May 2008 17:03:03 -0700 Subject: Making ready for release of 2.1 --- actionmailer/CHANGELOG | 2 +- actionmailer/Rakefile | 2 +- actionmailer/lib/action_mailer/version.rb | 4 ++-- actionpack/CHANGELOG | 4 ++-- actionpack/Rakefile | 2 +- actionpack/lib/action_pack/version.rb | 4 ++-- activerecord/CHANGELOG | 6 ++++-- activerecord/Rakefile | 2 +- activerecord/lib/active_record/version.rb | 4 ++-- activerecord/test/connections/native_mysql/connection.rb | 4 ++-- activeresource/CHANGELOG | 2 +- activeresource/Rakefile | 2 +- activeresource/lib/active_resource/version.rb | 4 ++-- activesupport/CHANGELOG | 4 ++-- activesupport/lib/active_support/version.rb | 4 ++-- railties/CHANGELOG | 8 +------- railties/Rakefile | 10 +++++----- railties/lib/rails/version.rb | 4 ++-- release.rb | 7 ++----- 19 files changed, 36 insertions(+), 43 deletions(-) diff --git a/actionmailer/CHANGELOG b/actionmailer/CHANGELOG index b2ce462f0c..bdae0d4d3d 100644 --- a/actionmailer/CHANGELOG +++ b/actionmailer/CHANGELOG @@ -1,4 +1,4 @@ -*2.1.0 RC1 (May 11th, 2008)* +*2.1.0 (May 31st, 2008)* * Fixed that a return-path header would be ignored #7572 [joost] diff --git a/actionmailer/Rakefile b/actionmailer/Rakefile index 22ed396417..c09526cbef 100755 --- a/actionmailer/Rakefile +++ b/actionmailer/Rakefile @@ -55,7 +55,7 @@ spec = Gem::Specification.new do |s| s.rubyforge_project = "actionmailer" s.homepage = "http://www.rubyonrails.org" - s.add_dependency('actionpack', '= 2.0.991' + PKG_BUILD) + s.add_dependency('actionpack', '= 2.1.0' + PKG_BUILD) s.has_rdoc = true s.requirements << 'none' diff --git a/actionmailer/lib/action_mailer/version.rb b/actionmailer/lib/action_mailer/version.rb index 88b9a3c200..c35b648baf 100644 --- a/actionmailer/lib/action_mailer/version.rb +++ b/actionmailer/lib/action_mailer/version.rb @@ -1,8 +1,8 @@ module ActionMailer module VERSION #:nodoc: MAJOR = 2 - MINOR = 0 - TINY = 991 + MINOR = 1 + TINY = 0 STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 5c4bfbf3c9..cb684a925d 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,6 +1,6 @@ -* InstanceTag#default_time_from_options overflows to DateTime [Geoff Buesing] +*2.1.0 (May 31st, 2008)* -*2.1.0 RC1 (May 11th, 2008)* +* InstanceTag#default_time_from_options overflows to DateTime [Geoff Buesing] * Fixed that forgery protection can be used without session tracking (Peter Jones) [#139] diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 0147a5c1e8..b37f756c1e 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -76,7 +76,7 @@ spec = Gem::Specification.new do |s| s.has_rdoc = true s.requirements << 'none' - s.add_dependency('activesupport', '= 2.0.991' + PKG_BUILD) + s.add_dependency('activesupport', '= 2.1.0' + PKG_BUILD) s.require_path = 'lib' s.autorequire = 'action_controller' diff --git a/actionpack/lib/action_pack/version.rb b/actionpack/lib/action_pack/version.rb index 70fc1ced8c..c67654d9a8 100644 --- a/actionpack/lib/action_pack/version.rb +++ b/actionpack/lib/action_pack/version.rb @@ -1,8 +1,8 @@ module ActionPack #:nodoc: module VERSION #:nodoc: MAJOR = 2 - MINOR = 0 - TINY = 991 + MINOR = 1 + TINY = 0 STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 78082665a4..f901e432d5 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,6 +1,8 @@ -* Add first/last methods to associations/named_scope. Resolved #226. [Ryan Bates] +*2.1.0 (May 31st, 2008)* -*2.1.0 RC1 (May 11th, 2008)* +* Added SQL escaping for :limit and :offset #288 [Aaron Bedra, Steven Bristol, Jonathan Wiess] + +* Added first/last methods to associations/named_scope. Resolved #226. [Ryan Bates] * Ensure hm:t preloading honours reflection options. Resolves #137. [Frederick Cheung] diff --git a/activerecord/Rakefile b/activerecord/Rakefile index 043ab6d551..fc068b16c3 100755 --- a/activerecord/Rakefile +++ b/activerecord/Rakefile @@ -171,7 +171,7 @@ spec = Gem::Specification.new do |s| s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) } end - s.add_dependency('activesupport', '= 2.0.991' + PKG_BUILD) + s.add_dependency('activesupport', '= 2.1.0' + PKG_BUILD) s.files.delete FIXTURES_ROOT + "/fixture_database.sqlite" s.files.delete FIXTURES_ROOT + "/fixture_database_2.sqlite" diff --git a/activerecord/lib/active_record/version.rb b/activerecord/lib/active_record/version.rb index 1463e84764..aaadef9979 100644 --- a/activerecord/lib/active_record/version.rb +++ b/activerecord/lib/active_record/version.rb @@ -1,8 +1,8 @@ module ActiveRecord module VERSION #:nodoc: MAJOR = 2 - MINOR = 0 - TINY = 991 + MINOR = 1 + TINY = 0 STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/activerecord/test/connections/native_mysql/connection.rb b/activerecord/test/connections/native_mysql/connection.rb index 1fab444e58..3ee031f384 100644 --- a/activerecord/test/connections/native_mysql/connection.rb +++ b/activerecord/test/connections/native_mysql/connection.rb @@ -12,13 +12,13 @@ ActiveRecord::Base.logger = RAILS_DEFAULT_LOGGER ActiveRecord::Base.configurations = { 'arunit' => { :adapter => 'mysql', - :username => 'rails', + :username => 'root', :encoding => 'utf8', :database => 'activerecord_unittest', }, 'arunit2' => { :adapter => 'mysql', - :username => 'rails', + :username => 'root', :database => 'activerecord_unittest2' } } diff --git a/activeresource/CHANGELOG b/activeresource/CHANGELOG index 9aa7d455a2..e124e40dd1 100644 --- a/activeresource/CHANGELOG +++ b/activeresource/CHANGELOG @@ -1,4 +1,4 @@ -*2.1.0 RC1 (May 11th, 2008)* +*2.1.0 (May 31st, 2008)* * Fixed response logging to use length instead of the entire thing (seangeo) [#27] diff --git a/activeresource/Rakefile b/activeresource/Rakefile index 75fe52aea8..9fd0ec4921 100644 --- a/activeresource/Rakefile +++ b/activeresource/Rakefile @@ -64,7 +64,7 @@ spec = Gem::Specification.new do |s| s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) } end - s.add_dependency('activesupport', '= 2.0.991' + PKG_BUILD) + s.add_dependency('activesupport', '= 2.1.0' + PKG_BUILD) s.require_path = 'lib' s.autorequire = 'active_resource' diff --git a/activeresource/lib/active_resource/version.rb b/activeresource/lib/active_resource/version.rb index 34fb05b703..88798ea1c1 100644 --- a/activeresource/lib/active_resource/version.rb +++ b/activeresource/lib/active_resource/version.rb @@ -1,8 +1,8 @@ module ActiveResource module VERSION #:nodoc: MAJOR = 2 - MINOR = 0 - TINY = 991 + MINOR = 1 + TINY = 0 STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 7e408840c4..690bb987dc 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,3 +1,5 @@ +*2.1.0 (May 31st, 2008)* + * TimeZone#to_s shows offset as GMT instead of UTC, because GMT will be more familiar to end users (see time zone selects used by Windows OS, google.com and yahoo.com.) Reverts [8370] [Geoff Buesing] * Hash.from_xml: datetime xml types overflow to Ruby DateTime class when out of range of Time. Adding tests for utc offsets [Geoff Buesing] @@ -6,8 +8,6 @@ * Time#to_json: don't convert to utc before encoding. References #175 [Geoff Buesing] -*2.1.0 RC1 (May 11th, 2008)* - * Remove unused JSON::RESERVED_WORDS, JSON.valid_identifier? and JSON.reserved_word? methods. Resolves #164. [Cheah Chu Yeow] * Adding Date.current, which returns Time.zone.today if config.time_zone is set; otherwise returns Date.today [Geoff Buesing] diff --git a/activesupport/lib/active_support/version.rb b/activesupport/lib/active_support/version.rb index f3d141cf72..b346459a9b 100644 --- a/activesupport/lib/active_support/version.rb +++ b/activesupport/lib/active_support/version.rb @@ -1,8 +1,8 @@ module ActiveSupport module VERSION #:nodoc: MAJOR = 2 - MINOR = 0 - TINY = 991 + MINOR = 1 + TINY = 0 STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/railties/CHANGELOG b/railties/CHANGELOG index 7f1c6ad747..fe517755ef 100644 --- a/railties/CHANGELOG +++ b/railties/CHANGELOG @@ -1,10 +1,4 @@ -*SVN* - -* Consolidate error messages for missing gems, and skip them when running rake gems:* tasks. [rick] - -* Use a system command to install gems, since GemRunner exits the ruby process. #210 [Tim Morgan] - -*2.1.0 RC1 (May 11th, 2008)* +*2.1.0 (May 31st, 2008)* * script/dbconsole fires up the command-line database client. #102 [Steve Purcell] diff --git a/railties/Rakefile b/railties/Rakefile index 45ba394299..a1d1095c37 100644 --- a/railties/Rakefile +++ b/railties/Rakefile @@ -304,11 +304,11 @@ spec = Gem::Specification.new do |s| EOF s.add_dependency('rake', '>= 0.8.1') - s.add_dependency('activesupport', '= 2.0.991' + PKG_BUILD) - s.add_dependency('activerecord', '= 2.0.991' + PKG_BUILD) - s.add_dependency('actionpack', '= 2.0.991' + PKG_BUILD) - s.add_dependency('actionmailer', '= 2.0.991' + PKG_BUILD) - s.add_dependency('activeresource', '= 2.0.991' + PKG_BUILD) + s.add_dependency('activesupport', '= 2.1.0' + PKG_BUILD) + s.add_dependency('activerecord', '= 2.1.0' + PKG_BUILD) + s.add_dependency('actionpack', '= 2.1.0' + PKG_BUILD) + s.add_dependency('actionmailer', '= 2.1.0' + PKG_BUILD) + s.add_dependency('activeresource', '= 2.1.0' + PKG_BUILD) s.rdoc_options << '--exclude' << '.' s.has_rdoc = false diff --git a/railties/lib/rails/version.rb b/railties/lib/rails/version.rb index fea63beea9..48d24da52e 100644 --- a/railties/lib/rails/version.rb +++ b/railties/lib/rails/version.rb @@ -1,8 +1,8 @@ module Rails module VERSION #:nodoc: MAJOR = 2 - MINOR = 0 - TINY = 991 + MINOR = 1 + TINY = 0 STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/release.rb b/release.rb index 94d2219525..2e1e8610b1 100755 --- a/release.rb +++ b/release.rb @@ -4,7 +4,7 @@ VERSION = ARGV.first PACKAGES = %w(activesupport activerecord actionpack actionmailer activeresource) # Checkout source -`rm -rf release && svn export http://dev.rubyonrails.org/svn/rails/trunk release` +# `rm -rf release && svn export http://dev.rubyonrails.org/svn/rails/trunk release` # Create Rails packages `cd release/railties && rake template=jamis package` @@ -19,7 +19,4 @@ end # Upload rails tgz/zip `rubyforge add_release rails rails 'REL #{VERSION}' release/rails-#{VERSION}.tgz` -`rubyforge add_release rails rails 'REL #{VERSION}' release/rails-#{VERSION}.zip` - -# Create SVN tag -puts "Remember to create SVN tag" +`rubyforge add_release rails rails 'REL #{VERSION}' release/rails-#{VERSION}.zip` \ No newline at end of file -- cgit v1.2.3 From ea03b0885c110003496c1f99dc7d9d2f1534955b Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 31 May 2008 17:07:44 -0700 Subject: revert mysql test credential change --- activerecord/test/connections/native_mysql/connection.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/test/connections/native_mysql/connection.rb b/activerecord/test/connections/native_mysql/connection.rb index 3ee031f384..1fab444e58 100644 --- a/activerecord/test/connections/native_mysql/connection.rb +++ b/activerecord/test/connections/native_mysql/connection.rb @@ -12,13 +12,13 @@ ActiveRecord::Base.logger = RAILS_DEFAULT_LOGGER ActiveRecord::Base.configurations = { 'arunit' => { :adapter => 'mysql', - :username => 'root', + :username => 'rails', :encoding => 'utf8', :database => 'activerecord_unittest', }, 'arunit2' => { :adapter => 'mysql', - :username => 'root', + :username => 'rails', :database => 'activerecord_unittest2' } } -- cgit v1.2.3 From 72483c0d4c1e4ea794919974100acc2f255f6fd2 Mon Sep 17 00:00:00 2001 From: rick Date: Sat, 31 May 2008 17:13:11 -0700 Subject: Add ActiveRecord::Base.sti_name that checks ActiveRecord::Base#store_full_sti_class? and returns either the full or demodulized name. [rick] [#114 state:resolved] --- activerecord/CHANGELOG | 2 ++ .../associations/has_many_through_association.rb | 2 +- activerecord/lib/active_record/base.rb | 16 ++++++++++++---- activerecord/test/cases/inheritance_test.rb | 18 +++++++++++++++++- 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 78082665a4..31e1c22f0d 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,3 +1,5 @@ +* Add ActiveRecord::Base.sti_name that checks ActiveRecord::Base#store_full_sti_class? and returns either the full or demodulized name. [rick] + * Add first/last methods to associations/named_scope. Resolved #226. [Ryan Bates] *2.1.0 RC1 (May 11th, 2008)* diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index ebcf462f2e..52ced36d16 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -237,7 +237,7 @@ module ActiveRecord end def build_sti_condition - "#{@reflection.through_reflection.quoted_table_name}.#{@reflection.through_reflection.klass.inheritance_column} = #{@reflection.klass.quote_value(@reflection.through_reflection.klass.name.demodulize)}" + "#{@reflection.through_reflection.quoted_table_name}.#{@reflection.through_reflection.klass.inheritance_column} = #{@reflection.klass.quote_value(@reflection.through_reflection.klass.sti_name)}" end alias_method :sql_conditions, :conditions diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index d2d9bda6ba..92a24ecc5f 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1293,6 +1293,10 @@ module ActiveRecord #:nodoc: super end + def sti_name + store_full_sti_class ? name : name.demodulize + end + private def find_initial(options) options.update(:limit => 1) @@ -1452,7 +1456,11 @@ module ActiveRecord #:nodoc: # Nest the type name in the same module as this class. # Bar is "MyApp::Business::Bar" relative to MyApp::Business::Foo def type_name_with_module(type_name) - (/^::/ =~ type_name) ? type_name : "#{parent.name}::#{type_name}" + if store_full_sti_class + type_name + else + (/^::/ =~ type_name) ? type_name : "#{parent.name}::#{type_name}" + end end def construct_finder_sql(options) @@ -1571,8 +1579,8 @@ module ActiveRecord #:nodoc: def type_condition quoted_inheritance_column = connection.quote_column_name(inheritance_column) - type_condition = subclasses.inject("#{quoted_table_name}.#{quoted_inheritance_column} = '#{store_full_sti_class ? name : name.demodulize}' ") do |condition, subclass| - condition << "OR #{quoted_table_name}.#{quoted_inheritance_column} = '#{store_full_sti_class ? subclass.name : subclass.name.demodulize}' " + type_condition = subclasses.inject("#{quoted_table_name}.#{quoted_inheritance_column} = '#{sti_name}' ") do |condition, subclass| + condition << "OR #{quoted_table_name}.#{quoted_inheritance_column} = '#{subclass.sti_name}' " end " (#{type_condition}) " @@ -2508,7 +2516,7 @@ module ActiveRecord #:nodoc: # Message class in that example. def ensure_proper_type unless self.class.descends_from_active_record? - write_attribute(self.class.inheritance_column, store_full_sti_class ? self.class.name : self.class.name.demodulize) + write_attribute(self.class.inheritance_column, self.class.sti_name) end end diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb index 27394924a1..f09b617e6d 100755 --- a/activerecord/test/cases/inheritance_test.rb +++ b/activerecord/test/cases/inheritance_test.rb @@ -5,7 +5,23 @@ require 'models/subscriber' class InheritanceTest < ActiveRecord::TestCase fixtures :companies, :projects, :subscribers, :accounts - + + def test_class_with_store_full_sti_class_returns_full_name + old = ActiveRecord::Base.store_full_sti_class + ActiveRecord::Base.store_full_sti_class = true + assert_equal 'Namespaced::Company', Namespaced::Company.sti_name + ensure + ActiveRecord::Base.store_full_sti_class = old + end + + def test_class_without_store_full_sti_class_returns_demodulized_name + old = ActiveRecord::Base.store_full_sti_class + ActiveRecord::Base.store_full_sti_class = false + assert_equal 'Company', Namespaced::Company.sti_name + ensure + ActiveRecord::Base.store_full_sti_class = old + end + def test_should_store_demodulized_class_name_with_store_full_sti_class_option_disabled old = ActiveRecord::Base.store_full_sti_class ActiveRecord::Base.store_full_sti_class = false -- cgit v1.2.3 From 71528b1825ce5184b23d09f923cb72f4073ce8ed Mon Sep 17 00:00:00 2001 From: rick Date: Sat, 31 May 2008 17:22:16 -0700 Subject: Previously we only added the "lib" subdirectory to the load path when setting up gem dependencies for frozen gems. Now we add the "ext" subdirectory as well for those gems which have compiled C extensions as well. [Wincent Colaiuta] [#268 state:resolved] --- railties/lib/rails/gem_dependency.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/railties/lib/rails/gem_dependency.rb b/railties/lib/rails/gem_dependency.rb index 0e39f6fd0a..9f088a18dd 100644 --- a/railties/lib/rails/gem_dependency.rb +++ b/railties/lib/rails/gem_dependency.rb @@ -31,7 +31,9 @@ module Rails args << @requirement.to_s if @requirement gem *args else - $LOAD_PATH << File.join(unpacked_paths.first, 'lib') + $LOAD_PATH.unshift File.join(unpacked_paths.first, 'lib') + ext = File.join(unpacked_paths.first, 'ext') + $LOAD_PATH.unshift(ext) if File.exist?(ext) @frozen = true end @load_paths_added = true -- cgit v1.2.3 From 3282bf3b5016f0c9028cfff1012e8c31a13b40b7 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 1 Jun 2008 09:15:11 -0700 Subject: Added SQL escaping for :limit and :offset in MySQL [Jonathan Wiess] --- activerecord/CHANGELOG | 5 +++++ activerecord/lib/active_record/connection_adapters/mysql_adapter.rb | 3 ++- activerecord/test/cases/adapter_test.rb | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 1c7c977141..a65771648e 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,3 +1,8 @@ +*Edge* + +* Added SQL escaping for :limit and :offset in MySQL [Jonathan Wiess] + + *2.1.0 (May 31st, 2008)* * Add ActiveRecord::Base.sti_name that checks ActiveRecord::Base#store_full_sti_class? and returns either the full or demodulized name. [rick] diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index f00a2c8950..653b45021d 100755 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -336,10 +336,11 @@ module ActiveRecord def add_limit_offset!(sql, options) #:nodoc: if limit = options[:limit] + limit = sanitize_limit(limit) unless offset = options[:offset] sql << " LIMIT #{limit}" else - sql << " LIMIT #{offset}, #{limit}" + sql << " LIMIT #{offset.to_i}, #{limit}" end end end diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index c77446f880..11f9870534 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -118,7 +118,7 @@ class AdapterTest < ActiveRecord::TestCase sql_inject = "1, 7 procedure help()" if current_adapter?(:MysqlAdapter) assert_equal " LIMIT 1,7", @connection.add_limit_offset!("", :limit=>sql_inject) - assert_equal " LIMIT 7, 1", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7) + assert_equal " LIMIT 7, 1", @connection.add_limit_offset!("", :limit=> '1 ; DROP TABLE USERS', :offset=>7) else assert_equal " LIMIT 1,7", @connection.add_limit_offset!("", :limit=>sql_inject) assert_equal " LIMIT 1,7 OFFSET 7", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7) -- cgit v1.2.3 From 06cb20708be13fbf736447aa0e5e6dd7d64c8b5d Mon Sep 17 00:00:00 2001 From: Ezra Zygmuntowicz Date: Sun, 1 Jun 2008 11:25:11 -0700 Subject: Added Rack processor Signed-off-by: Joshua Peek --- actionpack/CHANGELOG | 3 + actionpack/lib/action_controller.rb | 1 + actionpack/lib/action_controller/dispatcher.rb | 8 +- actionpack/lib/action_controller/rack_process.rb | 321 +++++++++++++++++++++++ actionpack/test/controller/cgi_test.rb | 33 +++ actionpack/test/controller/rack_test.rb | 150 +++++++++++ 6 files changed, 515 insertions(+), 1 deletion(-) create mode 100644 actionpack/lib/action_controller/rack_process.rb create mode 100644 actionpack/test/controller/rack_test.rb diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index cb684a925d..9622029362 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,3 +1,6 @@ +* Added Rack processor [Ezra Zygmuntowicz, Josh Peek] + + *2.1.0 (May 31st, 2008)* * InstanceTag#default_time_from_options overflows to DateTime [Geoff Buesing] diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index 810a5fb9b5..3c4a339d50 100755 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -53,6 +53,7 @@ require 'action_controller/streaming' require 'action_controller/session_management' require 'action_controller/http_authentication' require 'action_controller/components' +require 'action_controller/rack_process' require 'action_controller/record_identifier' require 'action_controller/request_forgery_protection' require 'action_controller/headers' diff --git a/actionpack/lib/action_controller/dispatcher.rb b/actionpack/lib/action_controller/dispatcher.rb index 6e1e7a261f..b40f1ba9be 100644 --- a/actionpack/lib/action_controller/dispatcher.rb +++ b/actionpack/lib/action_controller/dispatcher.rb @@ -96,7 +96,7 @@ module ActionController include ActiveSupport::Callbacks define_callbacks :prepare_dispatch, :before_dispatch, :after_dispatch - def initialize(output, request = nil, response = nil) + def initialize(output = $stdout, request = nil, response = nil) @output, @request, @response = output, request, response end @@ -123,6 +123,12 @@ module ActionController failsafe_rescue exception end + def call(env) + @request = RackRequest.new(env) + @response = RackResponse.new + dispatch + end + def reload_application # Run prepare callbacks before every request in development mode run_callbacks :prepare_dispatch diff --git a/actionpack/lib/action_controller/rack_process.rb b/actionpack/lib/action_controller/rack_process.rb new file mode 100644 index 0000000000..16625519b6 --- /dev/null +++ b/actionpack/lib/action_controller/rack_process.rb @@ -0,0 +1,321 @@ +require 'action_controller/cgi_ext' +require 'action_controller/session/cookie_store' + +module ActionController #:nodoc: + class RackRequest < AbstractRequest #:nodoc: + attr_accessor :env, :session_options + + class SessionFixationAttempt < StandardError #:nodoc: + end + + DEFAULT_SESSION_OPTIONS = { + :database_manager => CGI::Session::CookieStore, # store data in cookie + :prefix => "ruby_sess.", # prefix session file names + :session_path => "/", # available to all paths in app + :session_key => "_session_id", + :cookie_only => true + } unless const_defined?(:DEFAULT_SESSION_OPTIONS) + + def initialize(env, session_options = DEFAULT_SESSION_OPTIONS) + @session_options = session_options + @env = env + @cgi = CGIWrapper.new(self) + super() + end + + # The request body is an IO input stream. If the RAW_POST_DATA environment + # variable is already set, wrap it in a StringIO. + def body + if raw_post = env['RAW_POST_DATA'] + StringIO.new(raw_post) + else + @env['rack.input'] + end + end + + def key?(key) + @env.key? key + end + + def query_parameters + @query_parameters ||= self.class.parse_query_parameters(query_string) + end + + def request_parameters + @request_parameters ||= parse_formatted_request_parameters + end + + def cookies + return {} unless @env["HTTP_COOKIE"] + + if @env["rack.request.cookie_string"] == @env["HTTP_COOKIE"] + @env["rack.request.cookie_hash"] + else + @env["rack.request.cookie_string"] = @env["HTTP_COOKIE"] + # According to RFC 2109: + # If multiple cookies satisfy the criteria above, they are ordered in + # the Cookie header such that those with more specific Path attributes + # precede those with less specific. Ordering with respect to other + # attributes (e.g., Domain) is unspecified. + @env["rack.request.cookie_hash"] = + parse_query(@env["rack.request.cookie_string"], ';,').inject({}) { |h, (k,v)| + h[k] = Array === v ? v.first : v + h + } + end + end + + def host_with_port_without_standard_port_handling + if forwarded = @env["HTTP_X_FORWARDED_HOST"] + forwarded.split(/,\s?/).last + elsif http_host = @env['HTTP_HOST'] + http_host + elsif server_name = @env['SERVER_NAME'] + server_name + else + "#{env['SERVER_ADDR']}:#{env['SERVER_PORT']}" + end + end + + def host + host_with_port_without_standard_port_handling.sub(/:\d+$/, '') + end + + def port + if host_with_port_without_standard_port_handling =~ /:(\d+)$/ + $1.to_i + else + standard_port + end + end + + def remote_addr + @env['REMOTE_ADDR'] + end + + def session + unless defined?(@session) + if @session_options == false + @session = Hash.new + else + stale_session_check! do + if cookie_only? && query_parameters[session_options_with_string_keys['session_key']] + raise SessionFixationAttempt + end + case value = session_options_with_string_keys['new_session'] + when true + @session = new_session + when false + begin + @session = CGI::Session.new(@cgi, session_options_with_string_keys) + # CGI::Session raises ArgumentError if 'new_session' == false + # and no session cookie or query param is present. + rescue ArgumentError + @session = Hash.new + end + when nil + @session = CGI::Session.new(@cgi, session_options_with_string_keys) + else + raise ArgumentError, "Invalid new_session option: #{value}" + end + @session['__valid_session'] + end + end + end + @session + end + + def reset_session + @session.delete if defined?(@session) && @session.is_a?(CGI::Session) + @session = new_session + end + + private + # Delete an old session if it exists then create a new one. + def new_session + if @session_options == false + Hash.new + else + CGI::Session.new(@cgi, session_options_with_string_keys.merge("new_session" => false)).delete rescue nil + CGI::Session.new(@cgi, session_options_with_string_keys.merge("new_session" => true)) + end + end + + def cookie_only? + session_options_with_string_keys['cookie_only'] + end + + def stale_session_check! + yield + rescue ArgumentError => argument_error + if argument_error.message =~ %r{undefined class/module ([\w:]*\w)} + begin + # Note that the regexp does not allow $1 to end with a ':' + $1.constantize + rescue LoadError, NameError => const_error + raise ActionController::SessionRestoreError, <<-end_msg +Session contains objects whose class definition isn\'t available. +Remember to require the classes for all objects kept in the session. +(Original exception: #{const_error.message} [#{const_error.class}]) +end_msg + end + + retry + else + raise + end + end + + def session_options_with_string_keys + @session_options_with_string_keys ||= DEFAULT_SESSION_OPTIONS.merge(@session_options).stringify_keys + end + + # From Rack::Utils + def parse_query(qs, d = '&;') + params = {} + (qs || '').split(/[#{d}] */n).inject(params) { |h,p| + k, v = unescape(p).split('=',2) + if cur = params[k] + if cur.class == Array + params[k] << v + else + params[k] = [cur, v] + end + else + params[k] = v + end + } + + return params + end + + def unescape(s) + s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){ + [$1.delete('%')].pack('H*') + } + end + end + + class RackResponse < AbstractResponse #:nodoc: + attr_accessor :status + + def initialize + @writer = lambda { |x| @body << x } + @block = nil + super() + end + + def out(output = $stdout, &block) + @block = block + normalize_headers(@headers) + if [204, 304].include?(@status.to_i) + @headers.delete "Content-Type" + [status.to_i, @headers.to_hash, []] + else + [status.to_i, @headers.to_hash, self] + end + end + alias to_a out + + def each(&callback) + if @body.respond_to?(:call) + @writer = lambda { |x| callback.call(x) } + @body.call(self, self) + else + @body.each(&callback) + end + + @writer = callback + @block.call(self) if @block + end + + def write(str) + @writer.call str.to_s + str + end + + def close + @body.close if @body.respond_to?(:close) + end + + def empty? + @block == nil && @body.empty? + end + + private + def normalize_headers(options = "text/html") + if options.is_a?(String) + headers['Content-Type'] = options unless headers['Content-Type'] + else + headers['Content-Length'] = options.delete('Content-Length').to_s if options['Content-Length'] + + headers['Content-Type'] = options.delete('type') || "text/html" + headers['Content-Type'] += "; charset=" + options.delete('charset') if options['charset'] + + headers['Content-Language'] = options.delete('language') if options['language'] + headers['Expires'] = options.delete('expires') if options['expires'] + + @status = options.delete('Status') if options['Status'] + @status ||= 200 + # Convert 'cookie' header to 'Set-Cookie' headers. + # Because Set-Cookie header can appear more the once in the response body, + # we store it in a line break seperated string that will be translated to + # multiple Set-Cookie header by the handler. + if cookie = options.delete('cookie') + cookies = [] + + case cookie + when Array then cookie.each { |c| cookies << c.to_s } + when Hash then cookie.each { |_, c| cookies << c.to_s } + else cookies << cookie.to_s + end + + @output_cookies.each { |c| cookies << c.to_s } if @output_cookies + + headers['Set-Cookie'] = [headers['Set-Cookie'], cookies].compact.join("\n") + end + + options.each { |k,v| headers[k] = v } + end + + "" + end + end + + class CGIWrapper < ::CGI + def initialize(request, *args) + @request = request + @args = *args + @input = request.body + + super *args + end + + def params + @params ||= @request.params + end + + def cookies + @request.cookies + end + + def query_string + @request.query_string + end + + # Used to wrap the normal args variable used inside CGI. + def args + @args + end + + # Used to wrap the normal env_table variable used inside CGI. + def env_table + @request.env + end + + # Used to wrap the normal stdinput variable used inside CGI. + def stdinput + @input + end + end +end diff --git a/actionpack/test/controller/cgi_test.rb b/actionpack/test/controller/cgi_test.rb index 87f72fda77..f0f3a4b826 100755 --- a/actionpack/test/controller/cgi_test.rb +++ b/actionpack/test/controller/cgi_test.rb @@ -114,3 +114,36 @@ class CgiRequestNeedsRewoundTest < BaseCgiTest assert_equal 0, request.body.pos end end + +class CgiResponseTest < BaseCgiTest + def setup + super + @fake_cgi.expects(:header).returns("HTTP/1.0 200 OK\nContent-Type: text/html\n") + @response = ActionController::CgiResponse.new(@fake_cgi) + @output = StringIO.new('') + end + + def test_simple_output + @response.body = "Hello, World!" + + @response.out(@output) + assert_equal "HTTP/1.0 200 OK\nContent-Type: text/html\nHello, World!", @output.string + end + + def test_head_request + @fake_cgi.env_table['REQUEST_METHOD'] = 'HEAD' + @response.body = "Hello, World!" + + @response.out(@output) + assert_equal "HTTP/1.0 200 OK\nContent-Type: text/html\n", @output.string + end + + def test_streaming_block + @response.body = Proc.new do |response, output| + 5.times { |n| output.write(n) } + end + + @response.out(@output) + assert_equal "HTTP/1.0 200 OK\nContent-Type: text/html\n01234", @output.string + end +end diff --git a/actionpack/test/controller/rack_test.rb b/actionpack/test/controller/rack_test.rb new file mode 100644 index 0000000000..cd4151783e --- /dev/null +++ b/actionpack/test/controller/rack_test.rb @@ -0,0 +1,150 @@ +require 'abstract_unit' +require 'action_controller/rack_process' + +class BaseRackTest < Test::Unit::TestCase + def setup + @env = {"HTTP_MAX_FORWARDS"=>"10", "SERVER_NAME"=>"glu.ttono.us:8007", "FCGI_ROLE"=>"RESPONDER", "HTTP_X_FORWARDED_HOST"=>"glu.ttono.us", "HTTP_ACCEPT_ENCODING"=>"gzip, deflate", "HTTP_USER_AGENT"=>"Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/312.5.1 (KHTML, like Gecko) Safari/312.3.1", "PATH_INFO"=>"", "HTTP_ACCEPT_LANGUAGE"=>"en", "HTTP_HOST"=>"glu.ttono.us:8007", "SERVER_PROTOCOL"=>"HTTP/1.1", "REDIRECT_URI"=>"/dispatch.fcgi", "SCRIPT_NAME"=>"/dispatch.fcgi", "SERVER_ADDR"=>"207.7.108.53", "REMOTE_ADDR"=>"207.7.108.53", "SERVER_SOFTWARE"=>"lighttpd/1.4.5", "HTTP_COOKIE"=>"_session_id=c84ace84796670c052c6ceb2451fb0f2; is_admin=yes", "HTTP_X_FORWARDED_SERVER"=>"glu.ttono.us", "REQUEST_URI"=>"/admin", "DOCUMENT_ROOT"=>"/home/kevinc/sites/typo/public", "SERVER_PORT"=>"8007", "QUERY_STRING"=>"", "REMOTE_PORT"=>"63137", "GATEWAY_INTERFACE"=>"CGI/1.1", "HTTP_X_FORWARDED_FOR"=>"65.88.180.234", "HTTP_ACCEPT"=>"*/*", "SCRIPT_FILENAME"=>"/home/kevinc/sites/typo/public/dispatch.fcgi", "REDIRECT_STATUS"=>"200", "REQUEST_METHOD"=>"GET"} + # some Nokia phone browsers omit the space after the semicolon separator. + # some developers have grown accustomed to using comma in cookie values. + @alt_cookie_fmt_request_hash = {"HTTP_COOKIE"=>"_session_id=c84ace847,96670c052c6ceb2451fb0f2;is_admin=yes"} + @request = ActionController::RackRequest.new(@env) + end + + def default_test; end +end + + +class RackRequestTest < BaseRackTest + def test_proxy_request + assert_equal 'glu.ttono.us', @request.host_with_port + end + + def test_http_host + @env.delete "HTTP_X_FORWARDED_HOST" + @env['HTTP_HOST'] = "rubyonrails.org:8080" + assert_equal "rubyonrails.org:8080", @request.host_with_port + + @env['HTTP_X_FORWARDED_HOST'] = "www.firsthost.org, www.secondhost.org" + assert_equal "www.secondhost.org", @request.host + end + + def test_http_host_with_default_port_overrides_server_port + @env.delete "HTTP_X_FORWARDED_HOST" + @env['HTTP_HOST'] = "rubyonrails.org" + assert_equal "rubyonrails.org", @request.host_with_port + end + + def test_host_with_port_defaults_to_server_name_if_no_host_headers + @env.delete "HTTP_X_FORWARDED_HOST" + @env.delete "HTTP_HOST" + assert_equal "glu.ttono.us:8007", @request.host_with_port + end + + def test_host_with_port_falls_back_to_server_addr_if_necessary + @env.delete "HTTP_X_FORWARDED_HOST" + @env.delete "HTTP_HOST" + @env.delete "SERVER_NAME" + assert_equal "207.7.108.53:8007", @request.host_with_port + end + + def test_host_with_port_if_http_standard_port_is_specified + @env['HTTP_X_FORWARDED_HOST'] = "glu.ttono.us:80" + assert_equal "glu.ttono.us", @request.host_with_port + end + + def test_host_with_port_if_https_standard_port_is_specified + @env['HTTP_X_FORWARDED_PROTO'] = "https" + @env['HTTP_X_FORWARDED_HOST'] = "glu.ttono.us:443" + assert_equal "glu.ttono.us", @request.host_with_port + end + + def test_host_if_ipv6_reference + @env.delete "HTTP_X_FORWARDED_HOST" + @env['HTTP_HOST'] = "[2001:1234:5678:9abc:def0::dead:beef]" + assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", @request.host + end + + def test_host_if_ipv6_reference_with_port + @env.delete "HTTP_X_FORWARDED_HOST" + @env['HTTP_HOST'] = "[2001:1234:5678:9abc:def0::dead:beef]:8008" + assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", @request.host + end + + def test_cookie_syntax_resilience + cookies = CGI::Cookie::parse(@env["HTTP_COOKIE"]); + assert_equal ["c84ace84796670c052c6ceb2451fb0f2"], cookies["_session_id"], cookies.inspect + assert_equal ["yes"], cookies["is_admin"], cookies.inspect + + alt_cookies = CGI::Cookie::parse(@alt_cookie_fmt_request_hash["HTTP_COOKIE"]); + assert_equal ["c84ace847,96670c052c6ceb2451fb0f2"], alt_cookies["_session_id"], alt_cookies.inspect + assert_equal ["yes"], alt_cookies["is_admin"], alt_cookies.inspect + end +end + + +class RackRequestParamsParsingTest < BaseRackTest + def test_doesnt_break_when_content_type_has_charset + data = 'flamenco=love' + @request.env['CONTENT_LENGTH'] = data.length + @request.env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=utf-8' + @request.env['RAW_POST_DATA'] = data + assert_equal({"flamenco"=> "love"}, @request.request_parameters) + end + + def test_doesnt_interpret_request_uri_as_query_string_when_missing + @request.env['REQUEST_URI'] = 'foo' + assert_equal({}, @request.query_parameters) + end +end + + +class RackRequestNeedsRewoundTest < BaseRackTest + def test_body_should_be_rewound + data = 'foo' + @env['rack.input'] = StringIO.new(data) + @env['CONTENT_LENGTH'] = data.length + @env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=utf-8' + + # Read the request body by parsing params. + request = ActionController::RackRequest.new(@env) + request.request_parameters + + # Should have rewound the body. + assert_equal 0, request.body.pos + end +end + + +class RackResponseTest < BaseRackTest + def setup + super + @response = ActionController::RackResponse.new + @output = StringIO.new('') + end + + def test_simple_output + @response.body = "Hello, World!" + + status, headers, body = @response.out(@output) + assert_equal 200, status + assert_equal({"Content-Type" => "text/html", "Cache-Control" => "no-cache", "Set-Cookie" => ""}, headers) + + parts = [] + body.each { |part| parts << part } + assert_equal ["Hello, World!"], parts + end + + def test_streaming_block + @response.body = Proc.new do |response, output| + 5.times { |n| output.write(n) } + end + + status, headers, body = @response.out(@output) + assert_equal 200, status + assert_equal({"Content-Type" => "text/html", "Cache-Control" => "no-cache", "Set-Cookie" => ""}, headers) + + parts = [] + body.each { |part| parts << part } + assert_equal ["0", "1", "2", "3", "4"], parts + end +end -- cgit v1.2.3 From a980eb8c7734f14109d8c2a02a88dafdf682e0dc Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 1 Jun 2008 13:18:31 -0700 Subject: Added Rack middleware to handle static files. --- railties/lib/initializer.rb | 1 + railties/lib/rails/rack.rb | 5 +++++ railties/lib/rails/rack/static.rb | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 railties/lib/rails/rack.rb create mode 100644 railties/lib/rails/rack/static.rb diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb index ca63fa734b..bdadfeea8f 100644 --- a/railties/lib/initializer.rb +++ b/railties/lib/initializer.rb @@ -8,6 +8,7 @@ require 'rails/version' require 'rails/plugin/locator' require 'rails/plugin/loader' require 'rails/gem_dependency' +require 'rails/rack' RAILS_ENV = (ENV['RAILS_ENV'] || 'development').dup unless defined?(RAILS_ENV) diff --git a/railties/lib/rails/rack.rb b/railties/lib/rails/rack.rb new file mode 100644 index 0000000000..abcd0741bf --- /dev/null +++ b/railties/lib/rails/rack.rb @@ -0,0 +1,5 @@ +module Rails + module Rack + autoload :Static, "rails/rack/static" + end +end diff --git a/railties/lib/rails/rack/static.rb b/railties/lib/rails/rack/static.rb new file mode 100644 index 0000000000..45eb0e5921 --- /dev/null +++ b/railties/lib/rails/rack/static.rb @@ -0,0 +1,35 @@ +module Rails + module Rack + class Static + FILE_METHODS = %w(GET HEAD).freeze + + def initialize(app) + @app = app + @file_server = ::Rack::File.new(File.join(RAILS_ROOT, "public")) + end + + def call(env) + path = env['PATH_INFO'].chomp('/') + method = env['REQUEST_METHOD'] + cached_path = (path.empty? ? 'index' : path) + ::ActionController::Base.page_cache_extension + + if FILE_METHODS.include?(method) + if file_exist?(path) + return @file_server.call(env) + elsif file_exist?(cached_path) + env['PATH_INFO'] = cached_path + return @file_server.call(env) + end + end + + @app.call(env) + end + + private + def file_exist?(path) + full_path = File.join(@file_server.root, ::Rack::Utils.unescape(path)) + File.file?(full_path) && File.readable?(full_path) + end + end + end +end -- cgit v1.2.3 From ad3c97cea6dd0714652db7d9b5b4d06b81e5c035 Mon Sep 17 00:00:00 2001 From: Grant Hollingworth Date: Sat, 31 May 2008 09:44:17 -0700 Subject: fixed typo: extra word --- activesupport/lib/active_support/core_ext/hash/except.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/core_ext/hash/except.rb b/activesupport/lib/active_support/core_ext/hash/except.rb index 8362cd880e..64d690965a 100644 --- a/activesupport/lib/active_support/core_ext/hash/except.rb +++ b/activesupport/lib/active_support/core_ext/hash/except.rb @@ -14,7 +14,7 @@ module ActiveSupport #:nodoc: reject { |key,| rejected.include?(key) } end - # Replaces the hash without only the given keys. + # Replaces the hash without the given keys. def except!(*keys) replace(except(*keys)) end -- cgit v1.2.3 From d4b7cd99e8e7051c9d3ed6722f9627d5d4dea4e9 Mon Sep 17 00:00:00 2001 From: Evan Farrar Date: Wed, 4 Jun 2008 22:58:28 -0500 Subject: Mass typo and misspelling fix. --- actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/address.rb | 4 ++-- actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/header.rb | 2 +- .../lib/action_mailer/vendor/tmail-1.2.3/tmail/interface.rb | 2 +- actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb | 4 ++-- actionpack/lib/action_controller/base.rb | 2 +- actionpack/lib/action_controller/integration.rb | 2 +- actionpack/lib/action_controller/rack_process.rb | 2 +- actionpack/lib/action_controller/request.rb | 6 +++--- actionpack/lib/action_controller/request_forgery_protection.rb | 2 +- actionpack/lib/action_controller/test_process.rb | 2 +- .../lib/action_controller/vendor/html-scanner/html/selector.rb | 4 ++-- actionpack/lib/action_view/helpers/active_record_helper.rb | 2 +- actionpack/lib/action_view/helpers/form_helper.rb | 2 +- actionpack/lib/action_view/helpers/prototype_helper.rb | 2 +- actionpack/lib/action_view/helpers/sanitize_helper.rb | 2 +- actionpack/lib/action_view/helpers/scriptaculous_helper.rb | 2 +- activerecord/lib/active_record/association_preload.rb | 2 +- activerecord/lib/active_record/base.rb | 6 +++--- activerecord/lib/active_record/callbacks.rb | 2 +- .../active_record/connection_adapters/abstract/schema_statements.rb | 2 +- .../lib/active_record/connection_adapters/postgresql_adapter.rb | 2 +- activerecord/lib/active_record/validations.rb | 2 +- activeresource/lib/active_resource/base.rb | 2 +- activeresource/lib/active_resource/http_mock.rb | 2 +- activesupport/lib/active_support/core_ext/bigdecimal/conversions.rb | 2 +- activesupport/lib/active_support/core_ext/string/inflections.rb | 4 ++-- activesupport/lib/active_support/core_ext/time/calculations.rb | 2 +- activesupport/lib/active_support/dependencies.rb | 2 +- activesupport/lib/active_support/inflector.rb | 4 ++-- activesupport/lib/active_support/values/time_zone.rb | 2 +- .../lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb | 2 +- .../lib/active_support/vendor/memcache-client-1.5.0/memcache.rb | 4 ++-- .../lib/active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone.rb | 2 +- .../active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone_info.rb | 2 +- .../active_support/vendor/tzinfo-0.3.8/tzinfo/linked_timezone.rb | 2 +- .../lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone.rb | 2 +- .../vendor/tzinfo-0.3.8/tzinfo/timezone_transition_info.rb | 2 +- .../lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb | 6 +++--- railties/lib/commands/process/spawner.rb | 4 ++-- railties/lib/initializer.rb | 2 +- railties/lib/rails_generator/commands.rb | 2 +- railties/lib/rails_generator/scripts.rb | 2 +- railties/lib/rails_generator/secret_key_generator.rb | 2 +- 43 files changed, 56 insertions(+), 56 deletions(-) diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/address.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/address.rb index fa8e5bcd8c..982ad5b661 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/address.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/address.rb @@ -38,7 +38,7 @@ module TMail # = Class Address # # Provides a complete handling library for email addresses. Can parse a string of an - # address directly or take in preformatted addresses themseleves. Allows you to add + # address directly or take in preformatted addresses themselves. Allows you to add # and remove phrases from the front of the address and provides a compare function for # email addresses. # @@ -143,7 +143,7 @@ module TMail # This is to catch an unquoted "@" symbol in the local part of the # address. Handles addresses like <"@"@me.com> and makes sure they - # stay like <"@"@me.com> (previously were becomming <@@me.com>) + # stay like <"@"@me.com> (previously were becoming <@@me.com>) if local && (local.join == '@' || local.join =~ /\A[^"].*?@.*?[^"]\Z/) @local = "\"#{local.join}\"" else diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/header.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/header.rb index 9153dcd7c6..dbdefcf979 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/header.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/header.rb @@ -59,7 +59,7 @@ module TMail # # This is because a mailbox doesn't have the : after the From that designates the # beginning of the envelope sender (which can be different to the from address of - # the emial) + # the email) # # Other fields can be passed as normal, "Reply-To", "Received" etc. # diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/interface.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/interface.rb index a6d428d7d6..2fc2dbdfc7 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/interface.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/interface.rb @@ -42,7 +42,7 @@ module TMail # Allows you to query the mail object with a string to get the contents # of the field you want. # - # Returns a string of the exact contnts of the field + # Returns a string of the exact contents of the field # # mail.from = "mikel " # mail.header_string("From") #=> "mikel " diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb index 5a319907ae..c3a8803dc4 100644 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb @@ -255,7 +255,7 @@ module TMail alias fetch [] # Allows you to set or delete TMail header objects at will. - # Eamples: + # Examples: # @mail = TMail::Mail.new # @mail['to'].to_s # => 'mikel@test.com.au' # @mail['to'] = 'mikel@elsewhere.org' @@ -265,7 +265,7 @@ module TMail # @mail['to'].to_s # => nil # @mail.encoded # => "\r\n" # - # Note: setting mail[] = nil actualy deletes the header field in question from the object, + # Note: setting mail[] = nil actually deletes the header field in question from the object, # it does not just set the value of the hash to nil def []=( key, val ) dkey = key.downcase diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index a036600c2b..6222c3205d 100755 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -347,7 +347,7 @@ module ActionController #:nodoc: cattr_accessor :optimise_named_routes self.optimise_named_routes = true - # Controls whether request forgergy protection is turned on or not. Turned off by default only in test mode. + # Controls whether request forgery protection is turned on or not. Turned off by default only in test mode. class_inheritable_accessor :allow_forgery_protection self.allow_forgery_protection = true diff --git a/actionpack/lib/action_controller/integration.rb b/actionpack/lib/action_controller/integration.rb index bd69d02ed7..12e1b4d493 100644 --- a/actionpack/lib/action_controller/integration.rb +++ b/actionpack/lib/action_controller/integration.rb @@ -100,7 +100,7 @@ module ActionController @https = flag end - # Return +true+ if the session is mimicing a secure HTTPS request. + # Return +true+ if the session is mimicking a secure HTTPS request. # # if session.https? # ... diff --git a/actionpack/lib/action_controller/rack_process.rb b/actionpack/lib/action_controller/rack_process.rb index 16625519b6..f42212e740 100644 --- a/actionpack/lib/action_controller/rack_process.rb +++ b/actionpack/lib/action_controller/rack_process.rb @@ -259,7 +259,7 @@ end_msg @status ||= 200 # Convert 'cookie' header to 'Set-Cookie' headers. # Because Set-Cookie header can appear more the once in the response body, - # we store it in a line break seperated string that will be translated to + # we store it in a line break separated string that will be translated to # multiple Set-Cookie header by the handler. if cookie = options.delete('cookie') cookies = [] diff --git a/actionpack/lib/action_controller/request.rb b/actionpack/lib/action_controller/request.rb index a35b904194..914163a709 100755 --- a/actionpack/lib/action_controller/request.rb +++ b/actionpack/lib/action_controller/request.rb @@ -61,7 +61,7 @@ module ActionController request_method == :head end - # Provides acccess to the request's HTTP headers, for example: + # Provides access to the request's HTTP headers, for example: # request.headers["Content-Type"] # => "text/plain" def headers @headers ||= ActionController::Http::Headers.new(@env) @@ -231,7 +231,7 @@ EOM parts[0..-(tld_length+2)] end - # Return the query string, accounting for server idiosyncracies. + # Return the query string, accounting for server idiosyncrasies. def query_string if uri = @env['REQUEST_URI'] uri.split('?', 2)[1] || '' @@ -240,7 +240,7 @@ EOM end end - # Return the request URI, accounting for server idiosyncracies. + # Return the request URI, accounting for server idiosyncrasies. # WEBrick includes the full URL. IIS leaves REQUEST_URI blank. def request_uri if uri = @env['REQUEST_URI'] diff --git a/actionpack/lib/action_controller/request_forgery_protection.rb b/actionpack/lib/action_controller/request_forgery_protection.rb index 02c9d59d07..05a6d8bb79 100644 --- a/actionpack/lib/action_controller/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/request_forgery_protection.rb @@ -17,7 +17,7 @@ module ActionController #:nodoc: # forged link from another site, is done by embedding a token based on the session (which an attacker wouldn't know) in all # forms and Ajax requests generated by Rails and then verifying the authenticity of that token in the controller. Only # HTML/JavaScript requests are checked, so this will not protect your XML API (presumably you'll have a different authentication - # scheme there anyway). Also, GET requests are not protected as these should be indempotent anyway. + # scheme there anyway). Also, GET requests are not protected as these should be idempotent anyway. # # This is turned on with the protect_from_forgery method, which will check the token and raise an # ActionController::InvalidAuthenticityToken if it doesn't match what was expected. You can customize the error message in diff --git a/actionpack/lib/action_controller/test_process.rb b/actionpack/lib/action_controller/test_process.rb index 0cf143210d..f179d9b1c7 100644 --- a/actionpack/lib/action_controller/test_process.rb +++ b/actionpack/lib/action_controller/test_process.rb @@ -222,7 +222,7 @@ module ActionController #:nodoc: !rendered_file.nil? end - # A shortcut to the flash. Returns an empyt hash if no session flash exists. + # A shortcut to the flash. Returns an empty hash if no session flash exists. def flash session['flash'] || {} end diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb index 1a3c770254..376bb87409 100644 --- a/actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb +++ b/actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb @@ -64,7 +64,7 @@ module HTML # # When using a combination of the above, the element name comes first # followed by identifier, class names, attributes, pseudo classes and - # negation in any order. Do not seprate these parts with spaces! + # negation in any order. Do not separate these parts with spaces! # Space separation is used for descendant selectors. # # For example: @@ -158,7 +158,7 @@ module HTML # * :not(selector) -- Match the element only if the element does not # match the simple selector. # - # As you can see, :nth-child pseudo class and its varient can get quite + # As you can see, :nth-child pseudo class and its variant can get quite # tricky and the CSS specification doesn't do a much better job explaining it. # But after reading the examples and trying a few combinations, it's easy to # figure out. diff --git a/actionpack/lib/action_view/helpers/active_record_helper.rb b/actionpack/lib/action_view/helpers/active_record_helper.rb index f3f204cc97..e788ebf359 100644 --- a/actionpack/lib/action_view/helpers/active_record_helper.rb +++ b/actionpack/lib/action_view/helpers/active_record_helper.rb @@ -141,7 +141,7 @@ module ActionView # # error_messages_for 'user_common', 'user', :object_name => 'user' # - # If the objects cannot be located as instance variables, you can add an extra :object paremeter which gives the actual + # If the objects cannot be located as instance variables, you can add an extra :object parameter which gives the actual # object (or array of objects to use): # # error_messages_for 'user', :object => @question.user diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 0791feb9ac..7d85799038 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -76,7 +76,7 @@ module ActionView # Creates a form and a scope around a specific model object that is used as # a base for questioning about values for the fields. # - # Rails provides succint resource-oriented form generation with +form_for+ + # Rails provides succinct resource-oriented form generation with +form_for+ # like this: # # <% form_for @offer do |f| %> diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index 602832e470..c731824f18 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -61,7 +61,7 @@ module ActionView # # == Designing your Rails actions for Ajax # When building your action handlers (that is, the Rails actions that receive your background requests), it's - # important to remember a few things. First, whatever your action would normall return to the browser, it will + # important to remember a few things. First, whatever your action would normally return to the browser, it will # return to the Ajax call. As such, you typically don't want to render with a layout. This call will cause # the layout to be transmitted back to your page, and, if you have a full HTML/CSS, will likely mess a lot of things up. # You can turn the layout off on particular actions by doing the following: diff --git a/actionpack/lib/action_view/helpers/sanitize_helper.rb b/actionpack/lib/action_view/helpers/sanitize_helper.rb index b0dacfe964..c3c03394ee 100644 --- a/actionpack/lib/action_view/helpers/sanitize_helper.rb +++ b/actionpack/lib/action_view/helpers/sanitize_helper.rb @@ -184,7 +184,7 @@ module ActionView HTML::WhiteListSanitizer.allowed_attributes.merge(attributes) end - # Adds to the Set of allowed CSS properties for the #sanitize and +sanitize_css+ heleprs. + # Adds to the Set of allowed CSS properties for the #sanitize and +sanitize_css+ helpers. # # Rails::Initializer.run do |config| # config.action_view.sanitized_allowed_css_properties = 'expression' diff --git a/actionpack/lib/action_view/helpers/scriptaculous_helper.rb b/actionpack/lib/action_view/helpers/scriptaculous_helper.rb index c9b2761cb8..b938c1a801 100644 --- a/actionpack/lib/action_view/helpers/scriptaculous_helper.rb +++ b/actionpack/lib/action_view/helpers/scriptaculous_helper.rb @@ -193,7 +193,7 @@ module ActionView # # * :onDrop - Called when a +draggable_element+ is dropped onto # this element. Override this callback with a JavaScript expression to - # change the default drop behavour. Example: + # change the default drop behaviour. Example: # # :onDrop => "function(draggable_element, droppable_element, event) { alert('I like bananas') }" # diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index a3d1f12b03..087ed2a587 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -34,7 +34,7 @@ module ActiveRecord class_to_reflection = {} # Not all records have the same class, so group then preload # group on the reflection itself so that if various subclass share the same association then we do not split them - # unncessarily + # unnecessarily records.group_by {|record| class_to_reflection[record.class] ||= record.class.reflections[association]}.each do |reflection, records| raise ConfigurationError, "Association named '#{ association }' was not found; perhaps you misspelled it?" unless reflection send("preload_#{reflection.macro}_association", records, reflection, preload_options) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 92a24ecc5f..23318517fe 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -6,7 +6,7 @@ module ActiveRecord #:nodoc: class ActiveRecordError < StandardError end - # Raised when the single-table inheritance mechanism failes to locate the subclass + # Raised when the single-table inheritance mechanism fails to locate the subclass # (for example due to improper usage of column that +inheritance_column+ points to). class SubclassNotFound < ActiveRecordError #:nodoc: end @@ -97,7 +97,7 @@ module ActiveRecord #:nodoc: class MissingAttributeError < NoMethodError end - # Raised when an error occured while doing a mass assignment to an attribute through the + # Raised when an error occurred while doing a mass assignment to an attribute through the # attributes= method. The exception has an +attribute+ property that is the name of the # offending attribute. class AttributeAssignmentError < ActiveRecordError @@ -271,7 +271,7 @@ module ActiveRecord #:nodoc: # # Now 'Bob' exist and is an 'admin' # User.find_or_create_by_name('Bob', :age => 40) { |u| u.admin = true } # - # Use the find_or_initialize_by_ finder if you want to return a new record without saving it first. Protected attributes won't be setted unless they are given in a block. For example: + # Use the find_or_initialize_by_ finder if you want to return a new record without saving it first. Protected attributes won't be set unless they are given in a block. For example: # # # No 'Winter' tag exists # winter = Tag.find_or_initialize_by_name("Winter") diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb index 41ec5c5e61..6c2f65df05 100755 --- a/activerecord/lib/active_record/callbacks.rb +++ b/activerecord/lib/active_record/callbacks.rb @@ -50,7 +50,7 @@ module ActiveRecord # # == Inheritable callback queues # - # Besides the overwriteable callback methods, it's also possible to register callbacks through the use of the callback macros. + # Besides the overwritable callback methods, it's also possible to register callbacks through the use of the callback macros. # Their main advantage is that the macros add behavior into a callback queue that is kept intact down through an inheritance # hierarchy. Example: # diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 67d70b3886..a2a1bb8c82 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -372,7 +372,7 @@ module ActiveRecord def add_column_options!(sql, options) #:nodoc: sql << " DEFAULT #{quote(options[:default], options[:column])}" if options_include_default?(options) - # must explcitly check for :null to allow change_column to work on migrations + # must explicitly check for :null to allow change_column to work on migrations if options.has_key? :null if options[:null] == false sql << " NOT NULL" diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 7dbfbb41f6..7dc7398b0a 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -805,7 +805,7 @@ module ActiveRecord end private - # The internal PostgreSQL identifer of the money data type. + # The internal PostgreSQL identifier of the money data type. MONEY_COLUMN_TYPE_OID = 790 #:nodoc: # Connects to a PostgreSQL server and sets up the adapter depending on the diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index b9339c2924..52805ea851 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -301,7 +301,7 @@ module ActiveRecord :odd => 'odd?', :even => 'even?' }.freeze # Adds a validation method or block to the class. This is useful when - # overriding the +validate+ instance method becomes too unwieldly and + # overriding the +validate+ instance method becomes too unwieldy and # you're looking for more descriptive declaration of your validations. # # This can be done with a symbol pointing to a method: diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index ca9e665ba3..59e0888c2b 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -111,7 +111,7 @@ module ActiveResource # over HTTPS. # # Note: Some values cannot be provided in the URL passed to site. e.g. email addresses - # as usernames. In those situations you should use the seperate user and password option. + # as usernames. In those situations you should use the separate user and password option. # == Errors & Validation # # Error handling and validation is handled in much the same manner as you're used to seeing in diff --git a/activeresource/lib/active_resource/http_mock.rb b/activeresource/lib/active_resource/http_mock.rb index 22f83ae910..554fc3bcfc 100644 --- a/activeresource/lib/active_resource/http_mock.rb +++ b/activeresource/lib/active_resource/http_mock.rb @@ -65,7 +65,7 @@ module ActiveResource class << self # Returns an array of all request objects that have been sent to the mock. You can use this to check - # wether or not your model actually sent an HTTP request. + # if your model actually sent an HTTP request. # # ==== Example # def setup diff --git a/activesupport/lib/active_support/core_ext/bigdecimal/conversions.rb b/activesupport/lib/active_support/core_ext/bigdecimal/conversions.rb index d2b01b1b8d..94c7c779f7 100644 --- a/activesupport/lib/active_support/core_ext/bigdecimal/conversions.rb +++ b/activesupport/lib/active_support/core_ext/bigdecimal/conversions.rb @@ -21,7 +21,7 @@ module ActiveSupport #:nodoc: # This emits the number without any scientific notation. # I prefer it to using self.to_f.to_s, which would lose precision. # - # Note that YAML allows that when reconsituting floats + # Note that YAML allows that when reconstituting floats # to native types, some precision may get lost. # There is no full precision real YAML tag that I am aware of. str = self.to_s diff --git a/activesupport/lib/active_support/core_ext/string/inflections.rb b/activesupport/lib/active_support/core_ext/string/inflections.rb index a009d7c085..3bbad7dad8 100644 --- a/activesupport/lib/active_support/core_ext/string/inflections.rb +++ b/activesupport/lib/active_support/core_ext/string/inflections.rb @@ -24,8 +24,8 @@ module ActiveSupport #:nodoc: # # "posts".singularize # => "post" # "octopi".singularize # => "octopus" - # "sheep".singluarize # => "sheep" - # "word".singluarize # => "word" + # "sheep".singularize # => "sheep" + # "word".singularize # => "word" # "the blue mailmen".singularize # => "the blue mailman" # "CamelOctopi".singularize # => "CamelOctopus" def singularize diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb index 2cce782676..cd234c9b89 100644 --- a/activesupport/lib/active_support/core_ext/time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/time/calculations.rb @@ -261,7 +261,7 @@ module ActiveSupport #:nodoc: # Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances # can be chronologically compared with a Time def compare_with_coercion(other) - # if other is an ActiveSupport::TimeWithZone, coerce a Time instance from it so we can do <=> comparision + # if other is an ActiveSupport::TimeWithZone, coerce a Time instance from it so we can do <=> comparison other = other.comparable_time if other.respond_to?(:comparable_time) if other.acts_like?(:date) # other is a Date/DateTime, so coerce self #to_datetime and hand off to DateTime#<=> diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index da2ece610a..8f3aa4f848 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -129,7 +129,7 @@ module Dependencies #:nodoc: if Module.method(:const_defined?).arity == 1 # Does this module define this constant? - # Wrapper to accomodate changing Module#const_defined? in Ruby 1.9 + # Wrapper to accommodate changing Module#const_defined? in Ruby 1.9 def uninherited_const_defined?(mod, const) mod.const_defined?(const) end diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb index a4fd619317..d7f44cb2b9 100644 --- a/activesupport/lib/active_support/inflector.rb +++ b/activesupport/lib/active_support/inflector.rb @@ -132,8 +132,8 @@ module Inflector # Examples: # "posts".singularize # => "post" # "octopi".singularize # => "octopus" - # "sheep".singluarize # => "sheep" - # "word".singluarize # => "word" + # "sheep".singularize # => "sheep" + # "word".singularize # => "word" # "the blue mailmen".singularize # => "the blue mailman" # "CamelOctopi".singularize # => "CamelOctopus" def singularize(word) diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index a71c819fba..64d734f039 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -192,7 +192,7 @@ class TimeZone utc_offset == 0 && alternate_utc_string || utc_offset.to_utc_offset_s(colon) end - # Compare this time zone to the parameter. The two are comapred first on + # Compare this time zone to the parameter. The two are compared first on # their offsets, and then by name. def <=>(zone) result = (utc_offset <=> zone.utc_offset) diff --git a/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb b/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb index 91fcd21e13..b373e4da3c 100644 --- a/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb +++ b/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb @@ -20,7 +20,7 @@ module Builder # markup. # # Usage: - # xe = Builder::XmlEvents.new(hander) + # xe = Builder::XmlEvents.new(handler) # xe.title("HI") # Sends start_tag/end_tag/text messages to the handler. # # Indentation may also be selected by providing value for the diff --git a/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb b/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb index dda7f2c30e..30113201a6 100644 --- a/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb +++ b/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb @@ -119,7 +119,7 @@ class MemCache # Valid options for +opts+ are: # # [:namespace] Prepends this value to all keys added or retrieved. - # [:readonly] Raises an exeception on cache writes when true. + # [:readonly] Raises an exception on cache writes when true. # [:multithread] Wraps cache access in a Mutex for thread safety. # # Other options are ignored. @@ -207,7 +207,7 @@ class MemCache end ## - # Deceremets the value for +key+ by +amount+ and returns the new value. + # Decrements the value for +key+ by +amount+ and returns the new value. # +key+ must already exist. If +key+ is not an integer, it is assumed to be # 0. +key+ can not be decremented below 0. diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone.rb index 5eccbdf0db..2510e90b5b 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone.rb @@ -38,7 +38,7 @@ module TZInfo # Returns the set of TimezonePeriod instances that are valid for the given # local time as an array. If you just want a single period, use - # period_for_local instead and specify how abiguities should be resolved. + # period_for_local instead and specify how ambiguities should be resolved. # Raises PeriodNotFound if no periods are found for the given time. def periods_for_local(local) info.periods_for_local(local) diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone_info.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone_info.rb index f34fabc36a..d2a6620dd2 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone_info.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/data_timezone_info.rb @@ -64,7 +64,7 @@ module TZInfo # ArgumentError will be raised if a transition is added out of order. # offset_id refers to an id defined with offset. ArgumentError will be # raised if the offset_id cannot be found. numerator_or_time and - # denomiator specify the time the transition occurs as. See + # denominator specify the time the transition occurs as. See # TimezoneTransitionInfo for more detail about specifying times. def transition(year, month, offset_id, numerator_or_time, denominator = nil) offset = @offsets[offset_id] diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/linked_timezone.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/linked_timezone.rb index f8ec4fca87..c757485b84 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/linked_timezone.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/linked_timezone.rb @@ -36,7 +36,7 @@ module TZInfo # Returns the set of TimezonePeriod instances that are valid for the given # local time as an array. If you just want a single period, use - # period_for_local instead and specify how abiguities should be resolved. + # period_for_local instead and specify how ambiguities should be resolved. # Raises PeriodNotFound if no periods are found for the given time. def periods_for_local(local) @linked_timezone.periods_for_local(local) diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone.rb index 04f2f2f0a5..910eefca02 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone.rb @@ -121,7 +121,7 @@ module TZInfo TimezoneProxy.new(identifier) end - # If identifier is nil calls super(), otherwise calls get. An identfier + # If identifier is nil calls super(), otherwise calls get. An identifier # should always be passed in when called externally. def self.new(identifier = nil) if identifier diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_transition_info.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_transition_info.rb index 6ae1b7df97..146c131708 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_transition_info.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.8/tzinfo/timezone_transition_info.rb @@ -37,7 +37,7 @@ module TZInfo attr_reader :numerator_or_time protected :numerator_or_time - # Either the denominotor of the DateTime if the transition time is defined + # Either the denominator of the DateTime if the transition time is defined # as a DateTime, otherwise nil. attr_reader :denominator protected :denominator diff --git a/activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb b/activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb index 0de24c0eff..ec6dab513f 100644 --- a/activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb +++ b/activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb @@ -121,7 +121,7 @@ class XmlSimple # Create a "global" cache. @@cache = Cache.new - # Creates and intializes a new XmlSimple object. + # Creates and initializes a new XmlSimple object. # # defaults:: # Default values for options. @@ -497,7 +497,7 @@ class XmlSimple } end - # Fold Hases containing a single anonymous Array up into just the Array. + # Fold Hashes 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) @@ -907,7 +907,7 @@ class XmlSimple # Thanks to Norbert Gawor for a bugfix. # # value:: - # Value to be checked for emptyness. + # Value to be checked for emptiness. def empty(value) case value when Hash diff --git a/railties/lib/commands/process/spawner.rb b/railties/lib/commands/process/spawner.rb index fd09daa55b..dc0008698a 100644 --- a/railties/lib/commands/process/spawner.rb +++ b/railties/lib/commands/process/spawner.rb @@ -66,9 +66,9 @@ class MongrelSpawner < Spawner "-l #{OPTIONS[:rails_root]}/log/mongrel.log" # Add prefix functionality to spawner's call to mongrel_rails - # Digging through monrel's project subversion server, the earliest + # Digging through mongrel's project subversion server, the earliest # Tag that has prefix implemented in the bin/mongrel_rails file - # is 0.3.15 which also happens to be the earilest tag listed. + # is 0.3.15 which also happens to be the earliest tag listed. # References: http://mongrel.rubyforge.org/svn/tags if Mongrel::Const::MONGREL_VERSION.to_f >=0.3 && !OPTIONS[:prefix].nil? cmd = cmd + " --prefix #{OPTIONS[:prefix]}" diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb index bdadfeea8f..ec065e6f3c 100644 --- a/railties/lib/initializer.rb +++ b/railties/lib/initializer.rb @@ -87,7 +87,7 @@ module Rails # Rails::Initializer.run(:set_load_path) # # This is useful if you only want the load path initialized, without - # incuring the overhead of completely loading the entire environment. + # incurring the overhead of completely loading the entire environment. def self.run(command = :process, configuration = Configuration.new) yield configuration if block_given? initializer = new configuration diff --git a/railties/lib/rails_generator/commands.rb b/railties/lib/rails_generator/commands.rb index 08ecbfb5cf..c0f8d05dde 100644 --- a/railties/lib/rails_generator/commands.rb +++ b/railties/lib/rails_generator/commands.rb @@ -155,7 +155,7 @@ HELP # such as the rest of the user's app. def class_collisions(*class_names) - # Initialize some check varibles + # Initialize some check variables last_class = Object current_class = nil name = nil diff --git a/railties/lib/rails_generator/scripts.rb b/railties/lib/rails_generator/scripts.rb index f857f68de4..9b1a99838a 100644 --- a/railties/lib/rails_generator/scripts.rb +++ b/railties/lib/rails_generator/scripts.rb @@ -45,7 +45,7 @@ module Rails usage = "\nInstalled Generators\n" Rails::Generator::Base.sources.inject([]) do |mem, source| # Using an association list instead of a hash to preserve order, - # for esthetic reasons more than anything else. + # for aesthetic reasons more than anything else. label = source.label.to_s.capitalize pair = mem.assoc(label) mem << (pair = [label, []]) if pair.nil? diff --git a/railties/lib/rails_generator/secret_key_generator.rb b/railties/lib/rails_generator/secret_key_generator.rb index 64fbbb90f8..5ae492312e 100644 --- a/railties/lib/rails_generator/secret_key_generator.rb +++ b/railties/lib/rails_generator/secret_key_generator.rb @@ -23,7 +23,7 @@ module Rails # Generate a random secret key by using the Win32 API. Raises LoadError # if the current platform cannot make use of the Win32 API. Raises - # SystemCallError if some other error occured. + # SystemCallError if some other error occurred. def generate_secret_with_win32_api # Following code is based on David Garamond's GUID library for Ruby. require 'Win32API' -- cgit v1.2.3