Compare commits

..

315 Commits

Author SHA1 Message Date
David Heinemeier Hansson
478cd8223c Tagged 1.2.4 for release
git-svn-id: http://svn-commit.rubyonrails.org/rails/tags/rel_1-2-4@7741 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-05 04:11:29 +00:00
Michael Koziarski
a134f8f3c8 Actually add the file referenced in [7730]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7737 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-04 04:11:51 +00:00
Michael Koziarski
0a2404f5cc Merge rake routes to stable to help people upgrading.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7730 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-03 21:48:43 +00:00
Michael Koziarski
70a8e6a7d1 Forgotten changelog entry
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7721 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-02 05:52:16 +00:00
Michael Koziarski
6c773706b4 Disable non-cookie sessions to prevent Session Fixation Attacks. Closes #7952 [bradediger]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7720 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-02 05:51:51 +00:00
Michael Koziarski
779db44f74 Change the resource seperator from ; to / change the generated routes to use the new-style named routes. e.g. new_group_user_path(@group) instead of group_new_user_path(@group). [pixeltrix] Closes #8558
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7713 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-01 06:44:07 +00:00
Michael Koziarski
a11dc682a9 Merge sqlite test fixes from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7706 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-01 02:14:31 +00:00
Michael Koziarski
fe1ee81d1a Silence mocha warnings
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7703 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-10-01 01:56:25 +00:00
Jeremy Kemper
8943da41fd Revert [7414] which rearranged stable resource URLs. References #8558.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7600 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-09-23 22:03:09 +00:00
Tobias Lütke
3acd2bd721 Added new new_admin_products_url named route in addition to old admin_new_products_url syntax. latter syntax got a deprecation warning [pixeltrix]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7414 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-09-06 14:26:52 +00:00
Michael Koziarski
19dff14814 Merge 8801 fix to stable. Closes #8801
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7347 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-08-20 04:26:10 +00:00
Michael Koziarski
1dd0034134 Don't clobber :includes passed to count on has_many association. Closes #9175 [danger]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7328 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-08-16 04:58:45 +00:00
Michael Koziarski
e0fd18b2aa Merge [7235] to stable. References #9167 [danger]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7327 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-08-16 04:58:06 +00:00
Michael Koziarski
2503fd3c3a Ensure TestRequest#request_uri returns the right value when doing multiple GETs. Closes #4867 [alisdair@randomoracle.org, mpalmer]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7320 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-08-15 05:35:22 +00:00
Michael Koziarski
631bf6b203 Integration tests: introduce methods for other HTTP methods. Closes #6353. Merges [6203]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7319 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-08-15 03:57:17 +00:00
Michael Koziarski
6cc01c9579 Merge gem freezing fix to stable.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7277 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-08-05 01:37:43 +00:00
Michael Koziarski
e3670a0e24 Improve performance of action caching. Closes #8231 [skaes]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7185 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-07-14 08:53:32 +00:00
Michael Koziarski
40a188b18e Merge [7177] to release. [skaes] References #8891
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7178 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-07-11 02:39:31 +00:00
Michael Koziarski
d81ac8d6f3 Merge delete-with-options for cookies from trunk to release
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7161 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-07-01 23:35:07 +00:00
Jeremy Kemper
b29caa54e6 Merge [7086] to stable: demote Hash#to_xml to use XmlSimple#xml_in_string so it can't read files or stdin. References #8453.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7087 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-06-23 00:43:11 +00:00
Jeremy Kemper
7d517a145b Merge [7075] to stable: save associated records only if the association is already loaded. References #8713.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7076 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-06-21 20:50:53 +00:00
Jeremy Kemper
2ba8864782 1-2-stable: changing the :default Date format doesn't break date quoting. Closes #6312.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7012 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-06-13 01:26:36 +00:00
Jeremy Kemper
5c6a0d57ac Merge [7006] to stable: fix precedence error in failsafe rescue. References #8625.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7007 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-06-12 16:47:18 +00:00
Jeremy Kemper
74191edb22 Merge [7002] to stable: fix syntax error in dispatcher than wrecked failsafe responses. References #8625.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7003 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-06-11 18:06:29 +00:00
Jeremy Kemper
9c0e4de88b Deprecate pagination for Rails 1.2.4. Install the classic_pagination plugin for forward compatibility, or move to the superior will_paginate plugin. References #8157.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6993 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-06-11 01:01:32 +00:00
Michael Koziarski
1f5a26432d Fix template compile tests on windows [skaes] closes #8234
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6895 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-29 09:58:29 +00:00
Rick Olson
d5950cdd57 apply [6879] to stable. Closes #7293.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6880 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-28 15:54:39 +00:00
Jeremy Kemper
fe3fefeeec Add Active Resource to rails:freeze:edge and drop Action Web Service. Closes #8205.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6872 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-27 22:21:20 +00:00
Jeremy Kemper
3ad1a98556 Merge [6804] to stable: belongs_to assignment creates a new proxy rather than modifying its target in-place. References #8412.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6805 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-22 03:41:29 +00:00
Jeremy Kemper
099c206535 Merge [6802] to stable: fix filtered parameter logging with nil parameter values. References #8422.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6803 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-21 23:04:14 +00:00
Rick Olson
e5590d69e5 forgot binary fixture
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6800 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-21 19:50:17 +00:00
Rick Olson
b14378cd68 merge [6798] into stable.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6799 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-21 18:56:44 +00:00
Jeremy Kemper
07f92e8321 Merge [6796] to stable from trunk. Integration tests: alias xhr to xml_http_request and add a request_method argument instead of always using POST. References #7124.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6797 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-21 09:19:52 +00:00
Jeremy Kemper
788d4b0cc3 Merge [6793] to stable from trunk: document Object#blank?. References #6491.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6794 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-20 23:22:09 +00:00
Jeremy Kemper
6ba8d874a9 Merge [6790] to stable from trunk: document deep eager includes. References #6267.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6791 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-19 22:41:39 +00:00
Jeremy Kemper
75bf71d429 Revert [4706] which added incorrect docs. References #5684.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6789 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-19 22:15:28 +00:00
Jeremy Kemper
bed591c36c Merge [6787] to stable from trunk: document caches_action. References #5419.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6788 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-19 22:10:10 +00:00
Jeremy Kemper
d4c24b6bb4 Merge [6775] to stable from trunk: observe_form always sends the serialized form. References #5271.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6776 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-18 21:39:14 +00:00
Jeremy Kemper
173e2d2726 Merge [6738] to stable: extract Oracle CHAR column length. References #7866.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6739 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-15 19:32:35 +00:00
Michael Koziarski
cfcc188dd1 Stop depending on strange platform specific rounding behaviour in the number helper tests
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6680 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-06 04:49:56 +00:00
Michael Koziarski
a74560f8f0 don't depend on the order of hash.inspect in assertions.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6677 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-06 04:35:17 +00:00
Michael Koziarski
92caa99eb3 Allow asset tag tests to pass on windows
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6676 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-06 04:33:04 +00:00
Michael Koziarski
d137167ca9 fix actionpack tests broken by additional mocha methods
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6675 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-06 04:31:31 +00:00
Michael Koziarski
d080638370 Apply prepend_before_filter bugfix from stefan.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6671 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-06 04:19:11 +00:00
Rick Olson
0fd9743ae1 apply [6648] to 1.2 stable
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6651 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-02 21:03:08 +00:00
Rick Olson
cdc26bdec6 apply [6649] to stable, closes #8226 [Stefan Kaes]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6650 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-05-02 13:28:33 +00:00
David Heinemeier Hansson
f5977b205f Improved performance by relying less on exception raising #8159 [Blaine]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6571 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-04-24 16:58:24 +00:00
Rick Olson
67465f8a98 forgot to save changelog
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6544 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-04-20 21:41:06 +00:00
Rick Olson
e522f75cbc Return the string representation from an Xml Builder when rendering a partial. #5044 [tpope]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6543 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-04-20 21:40:47 +00:00
Rick Olson
b564d7e1e9 documentation project patches, closes #7342, #7319, #7316, #7190 [jeremymcanally]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6471 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-27 14:04:38 +00:00
Jeremy Kemper
24267c4f3f Merge [6455] from trunk. Fix PStore typo. References #7900.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6456 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-23 16:55:31 +00:00
Jeremy Kemper
e05afb1bcc Merge [6449] from trunk. Fixes SQLite binary encoding with utf8 kcode. References #7862.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6450 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-19 12:55:34 +00:00
Jeremy Kemper
98caf444f3 Merge [6446] from trunk. Never return nil from read_params for compatibility with plain CGI query params parser. References #7581.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6448 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-18 13:49:05 +00:00
Jeremy Kemper
53c87f9818 Merge [6445] from trunk. Consistently canonicalizes RAILS_ROOT on Windows and other platforms. References #6755.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6447 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-18 13:47:08 +00:00
Jeremy Kemper
eefa0a22b4 Merge [6431] from trunk. CGI::Session::Pstore performance. References #7583.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6432 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-16 05:55:31 +00:00
Nicholas Seckar
b41920de18 Merge [6426] to stable
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6428 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-14 23:40:59 +00:00
Jeremy Kemper
93d7ab48a1 Merge [6422] from trunk. Undeprecates verification with :redirect_to => :named_route. References #7525.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6423 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-14 01:43:14 +00:00
Jeremy Kemper
d10177d0f1 Clarify changelog entries.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6421 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-14 01:25:05 +00:00
David Heinemeier Hansson
91976d7e6d Only auto-push gems
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6418 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-13 23:20:00 +00:00
David Heinemeier Hansson
8ad39a0a47 Monkey doc around in an attempt to please rdoc
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6417 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-13 22:41:24 +00:00
David Heinemeier Hansson
1cd825751d Use inline rubyforge automation
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6416 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-13 22:31:07 +00:00
Rick Olson
30549718ac apply [6408] to stable
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6410 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-13 05:32:55 +00:00
David Heinemeier Hansson
736cca87dc Prepare for release of Rails 1.2.3
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6395 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-12 23:44:05 +00:00
Rick Olson
5552dadbb9 Apply [5709] to stable
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6390 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-12 18:01:28 +00:00
Jeremy Kemper
4a8d3d51f7 Merge [6364] from trunk. Consistently quote primary key column names. References #7763.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6365 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-09 03:25:37 +00:00
Jeremy Kemper
243cdde6a8 Merge [6360] from trunk. Fixes YAML Omap fixtures. References #2665.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6361 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-09 02:09:04 +00:00
Jeremy Kemper
a9ed24c2dd Merge [6344] from trunk. Check for MinGW when testing for Windows platform. References #2982.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6345 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-06 09:24:14 +00:00
Jeremy Kemper
b1e1088ab9 Merge [6336] from trunk. References #6466, #7153.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6337 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-05 11:37:18 +00:00
Jeremy Kemper
579daf5b39 Upgrade rake dependency from 0.7.1 to 0.7.2 to pull in its Ruby 1.8.6 compatibility fixes.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6329 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-04 23:37:17 +00:00
Jeremy Kemper
633d7579cf Ruby 1.8.6 compatibility: the bundled mysql.rb had used deprecated Digest::SHA1.new(...).digest instead of Digest::SHA1.digest(...)
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6328 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-04 23:23:05 +00:00
Jeremy Kemper
bbe3dea3fa Merge [6099] from trunk. Compatibility with Ruby 1.8.6: make private Time#to_date and #to_datetime public.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6281 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-03-02 11:08:52 +00:00
Jeremy Kemper
9679cb4d97 Merge [6253] from trunk. References #6680.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6254 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-27 06:37:54 +00:00
Rick Olson
742bee4256 apply [6248] to stable
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6250 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-27 03:27:14 +00:00
Jeremy Kemper
ee31d643eb Merge [6241] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6242 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-26 21:42:38 +00:00
Michael Koziarski
f44437454c Stop swallowing errors during rake test [Koz]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6175 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-20 03:10:21 +00:00
Jeremy Kemper
d1b93e7da2 Revert [6086] and [6087] since they caused a major regression with functional tests in 1.2.2. References #7372.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6145 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-10 03:55:12 +00:00
Jeremy Kemper
ae11519df8 Merge [6143] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6144 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-10 03:08:29 +00:00
Jeremy Kemper
e41f4894c4 Merge [6140] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6141 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-08 00:53:32 +00:00
David Heinemeier Hansson
e73bdfc31b Update date
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6131 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-06 02:26:18 +00:00
David Heinemeier Hansson
a422b8ba62 Prepare for release of Rails 1.2.2
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6124 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 22:12:33 +00:00
David Heinemeier Hansson
ed6509c843 Update release script on stable branch
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6123 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 22:04:19 +00:00
Michael Koziarski
41108fec89 Merge 5876 to release.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6122 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 21:30:59 +00:00
David Heinemeier Hansson
c4d8d97e9c Fix gem deprecation warnings, which also means depending on RubyGems 0.9.0+ [Chad Fowler]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6119 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 20:44:45 +00:00
Rick Olson
0ee158a3b9 Add much-needed html-scanner tests. Fixed CDATA parsing bug. [Rick]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6118 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 20:11:35 +00:00
Rick Olson
92b00efd70 fix problem with EMPTY_INHERITABLE_ATTRIBUTES being redefined
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6116 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 19:30:33 +00:00
Rick Olson
21fafdd290 apply [6113] to stable
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6114 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 19:12:55 +00:00
Rick Olson
86519a6ea8 Optimize Class Inheritable Attributes so that unnecessary hashes are not created. [Bruce Perens]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6112 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 18:38:07 +00:00
Rick Olson
6a04f3599e Don't create instance writer methods for class attributes. [Rick]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6109 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 18:05:49 +00:00
Rick Olson
58cb43cb53 Added :instance_writer option to #mattr_writer/accessor, #cattr_writer/accessor, and #class_inheritable_writer to skip the creation of the instance writer. [Rick]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6108 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 17:55:55 +00:00
Rick Olson
ef3ffd101e Add singleton resources from trunk [Rick Olson]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6107 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-02-04 17:19:45 +00:00
Michael Koziarski
6744e35b25 Deprecate server_settings renaming it to smtp_settings, add sendmail_settings to allow you to override the arguments to and location of the sendmail executable. [Koz]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6094 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-31 02:07:09 +00:00
Jamis Buck
7571380c9c When dealing with SQLite3, use the table_info pragma helper, so that the bindings can do some translation for when sqlite3 breaks incompatibly between point releases.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6092 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-30 16:33:39 +00:00
Jeremy Kemper
454842a1f6 Merge [6086] from trunk. References #7372.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6087 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-28 18:26:12 +00:00
Jeremy Kemper
57098ad859 Merge [6084] from trunk. References #7083.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6085 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-28 17:52:25 +00:00
David Heinemeier Hansson
b79c0a05b2 Remove noisy nodoc for Ruby 1.8.4
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6083 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-28 17:42:44 +00:00
Jeremy Kemper
2bc5e6cd14 Merge [6078] from trunk. References #6977.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6079 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-28 16:19:03 +00:00
Jeremy Kemper
4dc206c578 Merge [6075] from trunk. References #7228.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6077 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-28 15:55:32 +00:00
Jeremy Kemper
d6f6a41f1e Merge [6071] from trunk. References #7095.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6072 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-28 14:53:33 +00:00
Jeremy Kemper
1155252d37 Merge [6067] from trunk. References #6778.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6068 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-28 09:12:04 +00:00
Jeremy Kemper
9b24e1198b Merge [5434] from trunk. Reference #6495.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6066 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-28 09:02:09 +00:00
Jeremy Kemper
d4b6671cdb Merge [6064] from trunk. References #6778.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6065 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-28 08:51:33 +00:00
Jeremy Kemper
11a92b3582 Merge [6062] from trunk. References #7229.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6063 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-28 08:29:05 +00:00
David Heinemeier Hansson
7e33de46e5 Fixed NumberHelper#number_with_delimiter to use "." always for splitting the original number, not the delimiter parameter (closes #7389) [ceefour]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6045 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-26 21:49:36 +00:00
David Heinemeier Hansson
fe42e6cc1f stable becomes 1-1-stable, 1-2-pre-release becomes 1-2-stable
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@6042 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-26 21:16:51 +00:00
Rick Olson
c28a70c04b Require the dispatcher for Rails::Configuration#to_prepare. [Rick]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@6041 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-26 15:00:28 +00:00
Jeremy Kemper
553c23df82 Merge [5704], [6005], [6034] from trunk. References #7268, #7354.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@6035 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-24 19:08:37 +00:00
Jeremy Kemper
c9ed2f64ae Merge [6023] from trunk. References #7330.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@6024 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-24 01:33:56 +00:00
Jeremy Kemper
70f4a92c5d Merge [6014] from trunk. References #2928.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@6015 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-23 04:25:28 +00:00
David Heinemeier Hansson
a182d85cd9 Bump rails version too
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5989 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-18 21:29:13 +00:00
Thomas Fuchs
03e763ffc8 Update prototype.js to [5985], fixes content-type issue with simulated HTTP methods
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5987 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-18 20:27:17 +00:00
David Heinemeier Hansson
3ec808eadb Update versions in preparation for Rails 1.2.1
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5984 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-18 20:06:27 +00:00
David Heinemeier Hansson
f255db871b Fix nodoc breaking adapters (closes #7161)
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5983 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-18 16:52:47 +00:00
David Heinemeier Hansson
cfb3a80862 Keep the irrelevant stuff out with :nodoc:
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5981 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-18 06:31:55 +00:00
David Heinemeier Hansson
5c61b17077 Keep the irrelevant stuff out with :nodoc:
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5980 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-18 06:23:03 +00:00
Rick Olson
025f895415 Modernize cookie testing code, and increase coverage (Heckle++) #7101 [Kevin Clark]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5978 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-17 06:53:08 +00:00
Rick Olson
e9e86fd134 Heckling ActionController::Resources::Resource revealed that set_prefixes didn't break when :name_prefix was munged. #7081 [Kevin Clark]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5975 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-17 06:47:51 +00:00
Sam Stephenson
81b94c2f10 Apply [5970] to 1.2 branch
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5971 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-17 05:05:17 +00:00
David Heinemeier Hansson
a3dafb07ec Prepare for release of 1.2
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5968 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-17 04:41:02 +00:00
Rick Olson
cc99f3fc18 [DOC] clear up some ambiguity with the way has_and_belongs_to_many creates the default join table name. #7072 [jeremymcanally]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5961 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-16 06:31:53 +00:00
Michael Koziarski
d25ae9b6e1 Merge oracle fixes over to 1.2
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5959 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-16 01:41:52 +00:00
David Heinemeier Hansson
517628d028 Made sure that connections are only removed for SQLite
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5955 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-15 22:12:40 +00:00
Jeremy Kemper
5d0fd52305 Merge [5944] from trunk. References #7048.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5945 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-15 15:51:54 +00:00
Jeremy Kemper
aa30fc7914 Merge [5937] from trunk. References #6956.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5938 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-15 02:26:06 +00:00
Jeremy Kemper
5f114177ce Merge [5935] from trunk. References #3987, #6664.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5936 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-15 01:28:22 +00:00
Jeremy Kemper
143cc0ec2f Merge [5933] from trunk. References #7000.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5934 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-15 00:36:04 +00:00
Jeremy Kemper
5385859dcf Calculations don't modify their options hash. References [5931], [5426], closes #6929.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5932 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-14 16:22:33 +00:00
Jeremy Kemper
2d5bf4bbed Merge [5929] from trunk. References #6976.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5930 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-14 15:20:52 +00:00
Jeremy Kemper
2b6954aa8a Merge [5909], [5927] from trunk. References #6742, #7026.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5928 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-14 14:44:03 +00:00
Jeremy Kemper
68849e3239 Merge [5924] from trunk. References #7023.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5925 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-14 12:20:52 +00:00
Jeremy Kemper
debaf20803 Merge [5919] from trunk. References #7021.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5920 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-13 08:07:15 +00:00
Jeremy Kemper
8f84165cb4 Merge [5917] from trunk: unbundle flexmock.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5918 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-13 07:17:14 +00:00
Jeremy Kemper
18857ca2cb Merge [5914] from trunk. References #7015.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5915 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-13 04:10:18 +00:00
Jeremy Kemper
06c7584fba Merge [5907] from trunk. References #6482.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5908 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-12 10:19:12 +00:00
Jeremy Kemper
dd605e937f Merge [5904] from trunk. References #6252.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5906 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-12 09:13:05 +00:00
Jeremy Kemper
d12bcdac9d Merge [5901], [5902], [5903] from trunk. References #6156.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5905 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-12 09:12:28 +00:00
Jeremy Kemper
52923c9b55 Merge [5899] from trunk. References #6962.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5900 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-12 07:34:09 +00:00
Jeremy Kemper
1a7ce06e90 Merge [5895], [5896] from trunk. References #6891.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5897 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-12 07:04:53 +00:00
Jeremy Kemper
34603e7faf Merge [5893] from trunk. References #2541.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5894 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-12 06:28:51 +00:00
Jeremy Kemper
f7d25950f0 Merge [5891] from trunk. References #6635.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5892 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-12 05:45:31 +00:00
Jeremy Kemper
0ac6b5077f Merge [5889] from trunk. References #6030.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5890 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-12 05:36:43 +00:00
Jeremy Kemper
fd2b14c046 Merge [5887] from trunk. References #4668.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5888 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-12 05:24:07 +00:00
Rick Olson
86f78cd8b6 merge [5718] to 1.2 branch
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5880 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-11 16:29:44 +00:00
Rick Olson
398c1a504c add some more detail on nested resource docs [Rick]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5878 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-10 18:10:44 +00:00
Michael Koziarski
5bf40f7b79 Merge error_messages_on fix to 1.2
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5871 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-07 09:00:11 +00:00
Michael Koziarski
e76eae612f Merge oracle clob / serialize fix to 1.2
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5867 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 23:49:23 +00:00
Rick Olson
25c3ee407d add application.js filter to fix failing asset tag helper test
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5865 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 21:05:46 +00:00
Rick Olson
de9ccd8848 Slight doc tweak to the ActionView::Helpers::PrototypeHelper#replace docs. Closes #6922 [Steven Bristol]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5864 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 20:59:42 +00:00
Rick Olson
9cc2e0f2f4 Slight doc tweak to #prepend_filter. Closes #6493 [Jeremy Voorhis]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5861 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 20:45:58 +00:00
Rick Olson
1696c1f68d Add more extensive documentation to the AssetTagHelper. Closes #6452 [Bob Silva]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5860 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 20:43:57 +00:00
Rick Olson
2c1d0e2979 Clean up multiple calls to #stringify_keys in TagHelper, add better documentation and testing for TagHelper. Closes #6394 [Bob Silva]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5858 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 20:32:52 +00:00
Rick Olson
f1a4c44726 [DOCS] Apply more documentation for ActiveRecord Reflection. Closes #4055 [Robby Russell]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5856 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 20:23:25 +00:00
Rick Olson
382547dcbe [DOCS] Document :allow_nil option of #validate_uniqueness_of. Closes #3143 [Caio Chassot]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5854 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 20:18:21 +00:00
Rick Olson
376dcb8e02 [DOCS] fix reference to ActionController::Macros::AutoComplete for #text_field_with_auto_complete. Closes #2578 [Jan Prill]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5852 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 20:12:45 +00:00
David Heinemeier Hansson
ab3f6bcfaa Fixing release notes for RC2
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5848 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 04:11:40 +00:00
David Heinemeier Hansson
04383b974d Fixed that webrick would strip leading newlines and hang connection (closes #4156) [psross]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5847 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 04:09:38 +00:00
David Heinemeier Hansson
fde811e2f6 Applied [5845] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5846 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 04:07:21 +00:00
Michael Koziarski
83a21f75cf merge sybase changes to 1.2
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5840 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-05 00:16:54 +00:00
Rick Olson
e9a7b233f6 rollback [5833] and [5835]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5837 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-04 21:42:32 +00:00
Rick Olson
21e4825596 apply [5835] to 1.2 RC branch
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5836 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-04 21:31:48 +00:00
Rick Olson
622d70a11e apply [5833] to 1.2 RC branch
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5834 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-04 21:19:42 +00:00
Jamis Buck
c26cca3f45 Make sure html_document is reset between integration test requests
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5829 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-01 03:04:23 +00:00
Jeremy Kemper
b0303e1ac2 Merge [5826] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5827 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-01 01:36:48 +00:00
Jeremy Kemper
bdd09f50f8 Merge [5824] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5825 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-01 01:32:59 +00:00
Jeremy Kemper
6dc5756d39 Tighten new_session option check.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5822 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-01 01:27:55 +00:00
Jeremy Kemper
0120b226ba Merge [5820] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5821 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-01 01:14:02 +00:00
Jeremy Kemper
b6af22ec82 Missed additions from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5819 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-01 00:32:33 +00:00
Jeremy Kemper
4870becaeb Missed additions from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5818 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-01 00:30:20 +00:00
Jeremy Kemper
a68d1d35f8 Merge [5816] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5817 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2007-01-01 00:25:58 +00:00
Jeremy Kemper
a4e70d3e91 Merge [5814] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5815 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-31 23:54:28 +00:00
David Heinemeier Hansson
ba29222851 Make RDoc not spew errors on install because of HTML comments in code comments
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5813 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-31 19:28:28 +00:00
Nicholas Seckar
0ff4ede7ca Apply [5811] to RC
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5812 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-31 18:59:58 +00:00
Rick Olson
7269ee2da9 apply [5801] to 1.2 stable branch
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5802 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-27 22:19:36 +00:00
Michael Koziarski
59be73a1e7 Merge nil fix for error_message_on to RC, closes #6884
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5800 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-27 20:47:20 +00:00
Michael Koziarski
ce8e54e236 Apply doc fix to RC, closes #6522
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5798 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-27 20:42:51 +00:00
Michael Koziarski
155dcff431 Ensure dynamic finders are anchored to the beginning of the method name to prevent them from firing accidentally. [bradediger]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5796 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-27 20:39:48 +00:00
Rick Olson
df27fb873c apply [5790] to 1.2 stable branch
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5791 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-26 19:41:08 +00:00
David Heinemeier Hansson
4aa93358fa Apply [5740] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5789 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-26 18:00:43 +00:00
Rick Olson
3054a742df apply [5785] to 1.2 branch
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5788 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-25 09:41:16 +00:00
Rick Olson
1fb2f21d1a apply [5784] to 1.2 pre-release
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5787 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-25 09:37:06 +00:00
Nicholas Seckar
da8a896d86 Apply [5781] and [5782] to RC
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5783 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-24 15:19:04 +00:00
Jeremy Kemper
debd9ea2ce Merge [5746] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5765 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-21 19:30:27 +00:00
Jeremy Kemper
8ec9f4d2a0 Merge [5763] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5764 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-20 21:29:43 +00:00
Jeremy Kemper
4dcdf0834e Merge [5761] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5762 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-20 21:15:19 +00:00
Jeremy Kemper
a451fd1fbf Merge [5759] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5760 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-20 18:40:46 +00:00
Jeremy Kemper
c7e2b03424 Merge [5757] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5758 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-19 23:17:43 +00:00
Jeremy Kemper
6ccbef5862 Merge [5755] from trunk. Closes #6514, closes #6743.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5756 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-19 20:27:35 +00:00
Jeremy Kemper
498bca8ae8 Merge [5753] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5754 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-19 19:50:19 +00:00
Jeremy Kemper
c3c7648d20 Merge [5749],[5750],[5751] from trunk. References #6840.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5752 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-19 19:28:19 +00:00
Rick Olson
fe2e51b047 apply [5744] to 1.2 pre-release
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5745 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-19 03:12:38 +00:00
Jeremy Kemper
67cda1f54e Rollback accidental commit from [5686].
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5743 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-18 23:19:24 +00:00
Michael Koziarski
cda3d89983 Merge plugin changes back to 1.2
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5739 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-18 20:30:27 +00:00
Jeremy Kemper
0ae462a82d Merge [5730] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5731 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-17 08:31:27 +00:00
Jeremy Kemper
d5ca9a5814 Merge [5728] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5729 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-17 08:24:06 +00:00
Michael Koziarski
72d556a391 Merge [5722] to release
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5723 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-16 02:26:01 +00:00
Michael Koziarski
34bc074441 merge plugin loading changes to 1.2 release
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5721 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-15 23:51:13 +00:00
Jeremy Kemper
6df67f5607 Merge [5715] from trunk. Closes #6699.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5716 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-12 22:28:21 +00:00
Nicholas Seckar
590b192e02 Apply [5710] to RC
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5712 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-10 21:14:21 +00:00
Jeremy Kemper
67ac59afc8 Merge [5694]-[5698] from trunk: respond_to json and render :json => ...
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5699 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-06 23:26:18 +00:00
Jeremy Kemper
3d5fb40bb0 Partially merge [5691] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5693 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-06 22:11:30 +00:00
Jeremy Kemper
0c483d0c8d Merge [5689] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5690 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-06 20:29:16 +00:00
Jeremy Kemper
8804b7aeb7 Include svn revision in changelogs.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5687 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-06 19:30:04 +00:00
Jeremy Kemper
2876efb784 Merge [5685] from trunk. Closes #3811.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5686 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-06 19:27:05 +00:00
Jeremy Kemper
762fc5447f Merge [5682] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5683 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-05 22:09:18 +00:00
David Heinemeier Hansson
bd261ffd1f Fixed script/process/spawner to work properly with Mongrel including in -r (daemonize mode) [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5672 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-04 03:50:57 +00:00
David Heinemeier Hansson
ffb17e89ef Dropped the idea of automatically routing :format for the vanilla routes -- that will be a treat for map.resources. Deprecated the name route root as it'll be used as a shortcut for map.connect '' in Rails 2.0 (Rails 1.2). Added map.root as an alias for map.connect '' (Rails 2.0)
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5671 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-04 00:12:00 +00:00
David Heinemeier Hansson
2a08c4547a Documentation for generators (closes #6671) [topfunky]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5669 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-03 16:53:16 +00:00
David Heinemeier Hansson
2b68762f5a Fixed Array#to_xml when it contains a series of hashes (each piece would get its own XML declaration) (closes #6610) [thkarcher/cyu]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5668 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-03 16:47:53 +00:00
David Heinemeier Hansson
de3ec6c008 Wups
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5662 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-01 23:02:48 +00:00
Jeremy Kemper
2890b9648e Merge [5660] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5661 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-01 21:34:22 +00:00
David Heinemeier Hansson
98a0440a56 If only life was that simple (it didnt help)
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5658 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-01 05:56:51 +00:00
David Heinemeier Hansson
f09c8c4529 Replace the elaborate reloading connection checking scheme, just fix the Ruby-based MySQL adapter, ye?
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5656 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-12-01 05:37:56 +00:00
David Heinemeier Hansson
25d7ea8ad2 Refactored to use same option setup
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5654 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-30 22:22:02 +00:00
David Heinemeier Hansson
91cd8890c7 Fixed that script/server running against Mongrel should tail the proper log regardless of the environment [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5652 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-30 21:45:31 +00:00
Jeremy Kemper
87ef365a49 Merge [5435] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5651 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-29 22:58:21 +00:00
Jeremy Kemper
d6c28bfaed Use head. Stop last @response.redirect_url from bleeding through (should be recycled like request is).
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5645 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-28 23:38:29 +00:00
Jeremy Kemper
b2ae346484 Merge [5643] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5644 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-28 23:26:25 +00:00
Michael Koziarski
fb6cd55de7 ensure follow_redirect works with normalized headers
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5641 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-27 22:52:58 +00:00
Michael Koziarski
c4d4660de3 Ensure integration tests get the correct value of fixtures_path. Closes #6672
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5639 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-27 05:14:05 +00:00
David Heinemeier Hansson
205ae50d3f Only reload connections in development mode that supports (and requires that) -- in other words, only do it for SQLite (closes #6687, #6700) [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5637 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-26 22:10:55 +00:00
Jeremy Kemper
5b8bfc40e0 Merge [5635] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5636 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-26 05:37:09 +00:00
David Heinemeier Hansson
f83eedd440 Fix that redirects should set "Location" header, not "location", and remove dead CGI.redirect
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5634 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-26 05:04:57 +00:00
David Heinemeier Hansson
691c439129 redirect_to is the one place where _url should be used, not _path [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5633 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-26 04:42:13 +00:00
Jeremy Kemper
8f3e81ed53 Merge [5631] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5632 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-26 01:24:57 +00:00
Jeremy Kemper
fd8ee0a253 Merge [5629] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5630 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-26 01:02:45 +00:00
David Heinemeier Hansson
509c920d35 Tried delaying database disconnect until after dependency resolution (references #6687, #6700) [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5627 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-25 19:59:00 +00:00
David Heinemeier Hansson
cef81e71eb Dont set default charset if the response is sending a file. Closes #6689 [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5626 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-25 19:29:10 +00:00
Nicholas Seckar
3ee809655e Apply [5624] to RC. References #6698.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5625 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-25 17:16:52 +00:00
David Heinemeier Hansson
c3cbd6b806 Fixed that HEAD should return the proper Content-Length header (that is, actually use @body.size, not just 0) [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5622 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-23 23:52:25 +00:00
David Heinemeier Hansson
fe1e771222 * Added GET-masquarading for HEAD, so request.method will return :get even for HEADs. This will help anyone relying on case request.method to automatically work with HEAD and map.resources will also allow HEADs to all GET actions. Rails automatically throws away the response content in a reply to HEAD, so you dont even need to worry about that. If you, for whatever reason, still need to distinguish between GET and HEAD in some edge case, you can use Request#head? and even Request.headers["REQUEST_METHOD"] for get the "real" answer. Closes #6694 [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5621 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-23 23:24:47 +00:00
David Heinemeier Hansson
694957ce5a Added text/csv as a default mime type and included example on how to make your own in config/environment.rb [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5620 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-23 17:25:52 +00:00
David Heinemeier Hansson
12949bbc13 Added ActiveRecord::Base.clear_active_connections! in development mode so the database connection is not carried over from request to request. Some databases won't reread the schema if that doesn't happen (I'm looking at you SQLite), so you have to restart the server after each migration (= no fun) [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5617 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-23 05:16:44 +00:00
David Heinemeier Hansson
82e5ff7c6e Actually require the gem found
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5615 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-23 04:49:04 +00:00
David Heinemeier Hansson
783c16bd61 Made RAILS_GEM_VERSION work for beta gems too, so specifying 1.1.6 will give you 1.1.6.4520 if available [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5613 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-23 04:40:38 +00:00
David Heinemeier Hansson
34a3d04af1 Dont include the mime.yml anyway, Mongrel will just ship with more defaults instead
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5611 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-23 02:41:41 +00:00
David Heinemeier Hansson
766ca17c91 Update release date for RC
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5610 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-23 02:32:50 +00:00
Nicholas Seckar
ffa2c5fda5 Apply [5607] to RC. References #6669.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5608 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-22 16:38:06 +00:00
Thomas Fuchs
87ecb782e6 Merge [5602] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5603 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-20 23:45:47 +00:00
Jeremy Kemper
2043513f4c Merge [5586], [5596] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5599 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-20 12:20:16 +00:00
Jeremy Kemper
ef6c3c4289 Merge [5597] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5598 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-20 12:08:05 +00:00
Jeremy Kemper
af43e87f38 Merge [5591] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5592 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-20 11:05:12 +00:00
Jeremy Kemper
f2fd22c2d4 Merge [5589] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5590 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-20 10:55:41 +00:00
David Heinemeier Hansson
17921bafcb Proper dates
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5584 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-20 00:02:42 +00:00
Thomas Fuchs
36b3cb2c36 Merge 1-2-pre-release with [5581]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5582 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-19 23:08:27 +00:00
David Heinemeier Hansson
b93e4692b2 Made script/server work with -e and -d when using Mongrel [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5578 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-19 22:18:48 +00:00
Rick Olson
30e5436a3e merge [5571] and [5572] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5573 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-19 21:16:30 +00:00
David Heinemeier Hansson
9ba96771c3 Scaffold resource should have both a layout and a stylesheet [DHH]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5566 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-19 16:57:45 +00:00
Jeremy Kemper
97d9dca26f Merge [5561] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5562 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-19 09:59:55 +00:00
David Heinemeier Hansson
2a70f6f0a2 Update changelogs in preparation for RC
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5560 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-19 01:07:08 +00:00
David Heinemeier Hansson
1e532f6606 Merged [5503] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5559 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-18 19:17:13 +00:00
David Heinemeier Hansson
fb60a469c0 Merged [5485] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5558 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-18 19:12:22 +00:00
David Heinemeier Hansson
ac2295137c Merged [5482] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5557 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-18 19:10:18 +00:00
David Heinemeier Hansson
acfe119cb5 Merged [5473] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5556 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-18 19:05:13 +00:00
David Heinemeier Hansson
004a28de81 Merged [5546] and [5547] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5555 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-18 18:49:29 +00:00
David Heinemeier Hansson
0497868531 Active Resource will not ship with Rails 1.2
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5554 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-18 18:46:20 +00:00
Thomas Fuchs
23569d83b2 Update Prototype in RC to [5550]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5552 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-17 23:55:04 +00:00
Nicholas Seckar
bef626e2b1 Apply [5548] to RC
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5549 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-17 22:31:47 +00:00
Jeremy Kemper
b7f094e65e Merge [5543] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5545 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-17 13:11:59 +00:00
Jeremy Kemper
6baf9489d1 Merge [5541] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5542 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-16 22:51:17 +00:00
Jeremy Kemper
af33784698 Merge [5531] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5538 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-16 17:26:39 +00:00
Jeremy Kemper
a5631a5674 Merge [5535], [5536] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5537 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-16 06:45:06 +00:00
Jeremy Kemper
629b2ac36c Merge [5533] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5534 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-16 01:43:59 +00:00
Jeremy Kemper
dd1dc5e819 Merge [5521] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5522 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-14 09:23:17 +00:00
Jeremy Kemper
b8ff216f49 Merge [5518] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5519 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-14 02:52:14 +00:00
Tobias Lütke
924f5cdb61 Merge from [5516]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5517 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-13 20:30:18 +00:00
Jeremy Kemper
86bd0da7d0 Merge [5514] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5515 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-13 19:24:33 +00:00
Jeremy Kemper
35240ba66e Merge [5512] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5513 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-13 19:03:08 +00:00
Jeremy Kemper
b8a5d398b9 Merge [5509] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5510 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-13 07:40:20 +00:00
Jeremy Kemper
85c45051be Merge [5506] from trunk. Set Rails::VERSION::STRING to 1.1.6 pending 1.2 release.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5508 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-13 07:17:11 +00:00
Jeremy Kemper
f7c94e977b Merge [5501] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5502 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-13 01:10:13 +00:00
Sam Stephenson
69ada0e26e Merge [5497] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5500 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-12 03:48:45 +00:00
Sam Stephenson
9eaad14e8e Merge [5487] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5499 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-12 03:48:09 +00:00
Sam Stephenson
9f8c805f5d Merge [5486] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5498 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-12 03:47:27 +00:00
Jamis Buck
46b845e784 Add grep-based fallback to reaper, to work in pidless setups
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5494 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-12 02:51:43 +00:00
Jeremy Kemper
118764e47d Merge [5480] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5481 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-10 19:19:50 +00:00
Rick Olson
bcd50f1a37 merge [5476] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5479 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-10 18:35:24 +00:00
Jeremy Kemper
5aced86de6 Merge [5474] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5475 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-09 19:36:39 +00:00
Nicholas Seckar
792780a80c Apply [5471] to RC
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5472 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-09 18:38:04 +00:00
Jeremy Kemper
5e677b67b5 Merge [5469] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5470 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-09 08:10:14 +00:00
Jeremy Kemper
dfa070aab9 Merge [5466] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5467 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-07 21:47:01 +00:00
Jeremy Kemper
ba086a4fc0 Merge [5440], [5444], [5463], [5464] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5465 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-07 21:13:27 +00:00
Jeremy Kemper
cc299d1b94 Merge [5459] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5460 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-07 20:14:09 +00:00
Nicholas Seckar
cbffafb497 Remove temporary crutch to help ApplicationController be unloaded. Closes #6496.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5458 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-07 19:54:43 +00:00
Jamis Buck
84668af330 make add_order a tad faster
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5453 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-07 19:11:39 +00:00
Jeremy Kemper
013004b592 Merge [5445] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5446 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-07 00:20:07 +00:00
Jeremy Kemper
5f5d8c224b Merge [5442] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5443 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-06 21:49:35 +00:00
Thomas Fuchs
5887b183ce Merge [5438] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5439 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-06 09:45:39 +00:00
Jeremy Kemper
320875ad77 Merge [5432] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5433 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-05 19:05:00 +00:00
Jeremy Kemper
4aa358dd86 Merge [5429] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5430 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-05 02:42:42 +00:00
Jeremy Kemper
6439d0cd3e Merge [5427] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5428 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-05 02:16:34 +00:00
Scott Barron
7953eb170d merge [5424] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5425 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-03 18:21:23 +00:00
Jeremy Kemper
5350fda95d Merge [5422] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5423 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-03 04:18:52 +00:00
Jeremy Kemper
5fac326020 Merge [5420] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5421 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-03 00:41:48 +00:00
Jeremy Kemper
17e445813b Merge [5418] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5419 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 20:37:32 +00:00
Jeremy Kemper
a2edd4381e Merge [5416] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5417 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 20:22:28 +00:00
Michael Koziarski
2029b8a8f5 merge xmlsimple update to release branch
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5415 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 20:13:27 +00:00
Jeremy Kemper
53c49036ea Merge [5412] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5413 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 19:32:16 +00:00
Scott Barron
855e0f6f09 merge [5408] from trunk
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5409 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 18:39:37 +00:00
Jeremy Kemper
e4e1d2afa3 Merge [5405] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5406 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 18:13:49 +00:00
Jeremy Kemper
526afd3ae2 Merge [5403] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5404 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 10:12:29 +00:00
Jeremy Kemper
31b901aa65 Merge [5401] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5402 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 09:47:36 +00:00
Jeremy Kemper
a746e39584 Merge [5399] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5400 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 08:49:47 +00:00
Jeremy Kemper
f4d88039fd Merge [5397] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5398 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 08:38:44 +00:00
Jeremy Kemper
9f26164d37 Merge [5395] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5396 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 07:57:44 +00:00
Scott Barron
c7f28e01c8 Merge in [5392] and [5393] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5394 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 05:02:09 +00:00
Michael Koziarski
3311953d3f merge rakefile changes to prerelease
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5391 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 03:38:36 +00:00
Jeremy Kemper
ce0653b1c6 Merge [5388] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5389 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-02 02:23:45 +00:00
Nicholas Seckar
229e197ac7 Update dependencies to allow constants to be defined alongside their siblings. (Applying changeset [5386] to RC.)
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5387 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-01 23:24:17 +00:00
Jeremy Kemper
503c7c0afd Merge [5384] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5385 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-01 20:47:27 +00:00
Jeremy Kemper
8e01efee02 Merge [5379] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5383 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-01 19:41:01 +00:00
Jeremy Kemper
e09f224a5c Merge [5378] from trunk.
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5382 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-01 19:38:47 +00:00
Scott Barron
6eb941ee6c Merge breakpoint/1.8.5 fix from [5380]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5381 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-11-01 17:50:02 +00:00
Michael Koziarski
7e8dd0322c Revert environment.rb changes for autoloading
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5377 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-10-31 01:33:33 +00:00
Thomas Fuchs
159411f580 Update to latest Prototype, which doesnt serialize disabled form elements, adds clone() to arrays, empty/non-string Element.update() and adds a fixes excessive error reporting in WebKit beta versions [Thomas Fuchs]
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5372 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-10-28 16:56:09 +00:00
Michael Koziarski
746cfb3ded Merge Statistics cleanup to release branch
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5370 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-10-27 01:42:47 +00:00
David Heinemeier Hansson
2227a178ee Branches so we can just get the bug fixes out of the way before shipping 1.2
git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-pre-release@5368 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2006-10-26 17:05:00 +00:00
3097 changed files with 118438 additions and 244234 deletions

22
.gitignore vendored
View File

@@ -1,22 +0,0 @@
# Don't put *.swp, *.bak, etc here; those belong in a global ~/.gitignore.
# Check out http://help.github.com/ignore-files/ for how to set that up.
debug.log
.Gemfile
/.bundle
/.ruby-version
/pkg
/dist
/doc/rdoc
/*/doc
/*/test/tmp
/activerecord/sqlnet.log
/activemodel/test/fixtures/fixture_database.sqlite3
/activesupport/test/fixtures/isolation_test
/railties/test/500.html
/railties/test/fixtures/tmp
/railties/test/initializer/root/log
/railties/doc
/railties/guides/output
/railties/tmp
/RDOC_MAIN.rdoc

View File

@@ -1,28 +0,0 @@
script: 'ci/travis.rb'
before_install:
- gem install bundler
rvm:
- 1.8.7
- 1.9.2
- 1.9.3
- 2.0.0
env:
- "GEM=railties"
- "GEM=ap,am,amo,ares,as"
- "GEM=ar:mysql"
- "GEM=ar:mysql2"
- "GEM=ar:sqlite3"
- "GEM=ar:postgresql"
notifications:
email: false
irc:
on_success: change
on_failure: always
channels:
- "irc.freenode.org#rails-contrib"
campfire:
on_success: change
on_failure: always
rooms:
- secure: "YA1alef1ESHWGFNVwvmVGCkMe4cUy4j+UcNvMUESraceiAfVyRMAovlQBGs6\n9kBRm7DHYBUXYC2ABQoJbQRLDr/1B5JPf/M8+Qd7BKu8tcDC03U01SMHFLpO\naOs/HLXcDxtnnpL07tGVsm0zhMc5N8tq4/L3SHxK7Vi+TacwQzI="
bundler_args: --path vendor/bundle

View File

@@ -1,4 +0,0 @@
--exclude /templates/
--quiet
act*/lib/**/*.rb
railties/lib/**/*.rb

65
Gemfile
View File

@@ -1,65 +0,0 @@
source 'https://rubygems.org'
gemspec
if ENV['AREL']
gem 'arel', :path => ENV['AREL']
else
gem 'arel'
end
gem 'bcrypt-ruby', '~> 3.0.0'
gem 'jquery-rails'
if ENV['JOURNEY']
gem 'journey', :path => ENV['JOURNEY']
else
gem 'journey'
end
# This needs to be with require false to avoid
# it being automatically loaded by sprockets
gem 'uglifier', '>= 1.0.3', :require => false
# execjs >= 2.1.0 doesn't work with Ruby 1.8
gem 'execjs', '< 2.1.0'
gem 'rake', '>= 0.8.7'
gem 'mocha', '~> 0.14', :require => false
group :doc do
# The current sdoc cannot generate GitHub links due
# to a bug, but the PR that fixes it has been there
# for some weeks unapplied. As a temporary solution
# this is our own fork with the fix.
gem 'sdoc', :git => 'git://github.com/fxn/sdoc.git'
gem 'RedCloth', '~> 4.2'
gem 'w3c_validators'
end
# AS
gem 'memcache-client', '>= 1.8.5'
# Add your own local bundler stuff
instance_eval File.read '.Gemfile' if File.exists? '.Gemfile'
platforms :mri do
group :test do
gem 'ruby-prof', '~> 0.11.2' if RUBY_VERSION < '2.0'
end
end
platforms :ruby do
gem 'yajl-ruby'
gem 'nokogiri', '>= 1.4.5', '< 1.6'
# AR
gem 'sqlite3', '~> 1.3.5'
group :db do
gem 'pg', '>= 0.11.0'
gem 'mysql', '>= 2.8.1'
gem 'mysql2', '>= 0.3.10'
end
end
gem 'benchmark-ips'

View File

@@ -1,131 +0,0 @@
GIT
remote: git://github.com/fxn/sdoc.git
revision: 9977ca4ecf83a76d637861f79319b11830d51de5
specs:
sdoc (0.3.19)
json (>= 1.1.3)
rdoc (~> 3.10)
PATH
remote: .
specs:
actionmailer (3.2.19)
actionpack (= 3.2.19)
mail (~> 2.5.4)
actionpack (3.2.19)
activemodel (= 3.2.19)
activesupport (= 3.2.19)
builder (~> 3.2)
erubis (~> 2.7.0)
journey (~> 1.0.4)
rack (~> 1.4.5)
rack-cache (~> 1.2)
rack-test (~> 0.6.1)
activemodel (3.2.19)
activesupport (= 3.2.19)
builder (~> 3.2)
activerecord (3.2.19)
activemodel (= 3.2.19)
activesupport (= 3.2.19)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
activeresource (3.2.19)
activemodel (= 3.2.19)
activesupport (= 3.2.19)
activesupport (3.2.19)
i18n (~> 0.6, >= 0.6.4)
multi_json (~> 1.0)
rails (3.2.19)
actionmailer (= 3.2.19)
actionpack (= 3.2.19)
activerecord (= 3.2.19)
activeresource (= 3.2.19)
activesupport (= 3.2.19)
bundler (~> 1.0)
railties (= 3.2.19)
railties (3.2.19)
actionpack (= 3.2.19)
activesupport (= 3.2.19)
rack-ssl (~> 1.3.2)
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
GEM
remote: https://rubygems.org/
specs:
RedCloth (4.2.9)
arel (3.0.3)
bcrypt-ruby (3.0.1)
benchmark-ips (1.2.0)
builder (3.2.2)
erubis (2.7.0)
execjs (2.0.2)
i18n (0.6.11)
journey (1.0.4)
jquery-rails (3.1.0)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
json (1.8.1)
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
memcache-client (1.8.5)
metaclass (0.0.4)
mime-types (1.25.1)
mocha (0.14.0)
metaclass (~> 0.0.1)
multi_json (1.10.1)
mysql (2.9.1)
mysql2 (0.3.15)
nokogiri (1.5.11)
pg (0.17.1)
polyglot (0.3.5)
rack (1.4.5)
rack-cache (1.2)
rack (>= 0.4)
rack-ssl (1.3.4)
rack
rack-test (0.6.2)
rack (>= 1.0)
rake (10.2.2)
rdoc (3.12.2)
json (~> 1.4)
sqlite3 (1.3.9)
thor (0.19.1)
treetop (1.4.15)
polyglot
polyglot (>= 0.3.1)
tzinfo (0.3.41)
uglifier (2.5.0)
execjs (>= 0.3.0)
json (>= 1.8.0)
w3c_validators (1.2)
json
nokogiri
yajl-ruby (1.2.0)
PLATFORMS
ruby
DEPENDENCIES
RedCloth (~> 4.2)
arel
bcrypt-ruby (~> 3.0.0)
benchmark-ips
execjs (< 2.1.0)
journey
jquery-rails
memcache-client (>= 1.8.5)
mocha (~> 0.14)
mysql (>= 2.8.1)
mysql2 (>= 0.3.10)
nokogiri (>= 1.4.5, < 1.6)
pg (>= 0.11.0)
rails!
rake (>= 0.8.7)
sdoc!
sqlite3 (~> 1.3.5)
uglifier (>= 1.0.3)
w3c_validators
yajl-ruby

View File

@@ -1 +0,0 @@
3.2.19.github9

View File

@@ -1,77 +0,0 @@
== Welcome to Rails
Rails is a web-application framework that includes everything needed to create
database-backed web applications according to the {Model-View-Controller (MVC)}[http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller] pattern.
Understanding the MVC pattern is key to understanding Rails. MVC divides your application
into three layers, each with a specific responsibility.
The View layer is composed of "templates" that are responsible for providing
appropriate representations of your application's resources. Templates
can come in a variety of formats, but most view templates are \HTML with embedded Ruby
code (.erb files).
The Model layer represents your domain model (such as Account, Product, Person, Post)
and encapsulates the business logic that is specific to your application. In Rails,
database-backed model classes are derived from ActiveRecord::Base. Active Record allows
you to present the data from database rows as objects and embellish these data objects
with business logic methods. Although most Rails models are backed by a database, models
can also be ordinary Ruby classes, or Ruby classes that implement a set of interfaces as
provided by the ActiveModel module. You can read more about Active Record in its
{README}[link:/rails/rails/blob/master/activerecord/README.rdoc].
The Controller layer is responsible for handling incoming HTTP requests and providing a
suitable response. Usually this means returning \HTML, but Rails controllers can also
generate XML, JSON, PDFs, mobile-specific views, and more. Controllers manipulate models
and render view templates in order to generate the appropriate HTTP response.
In Rails, the Controller and View layers are handled together by Action Pack.
These two layers are bundled in a single package due to their heavy interdependence.
This is unlike the relationship between Active Record and Action Pack which are
independent. Each of these packages can be used independently outside of Rails. You
can read more about Action Pack in its {README}[link:/rails/rails/blob/master/actionpack/README.rdoc].
== Getting Started
1. Install Rails at the command prompt if you haven't yet:
gem install rails
2. At the command prompt, create a new Rails application:
rails new myapp
where "myapp" is the application name.
3. Change directory to +myapp+ and start the web server:
cd myapp; rails server
Run with <tt>--help</tt> for options.
4. Go to http://localhost:3000 and you'll see:
"Welcome aboard: You're riding Ruby on Rails!"
5. Follow the guidelines to start developing your application. You may find the following resources handy:
* The README file created within your application.
* The {Getting Started with Rails}[http://guides.rubyonrails.org/getting_started.html].
* The {Ruby on Rails Tutorial}[http://railstutorial.org/book].
* The {Ruby on Rails Guides}[http://guides.rubyonrails.org].
* The {API Documentation}[http://api.rubyonrails.org].
== Contributing
We encourage you to contribute to Ruby on Rails! Please check out the {Contributing to Rails
guide}[http://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html] for guidelines about how
to proceed. {Join us}[http://contributors.rubyonrails.org]!
== Build Status {<img src="https://secure.travis-ci.org/rails/rails.png"/>}[http://travis-ci.org/rails/rails]
== Dependency Status {<img src="https://gemnasium.com/rails/rails.png?travis"/>}[https://gemnasium.com/rails/rails]
== License
Ruby on Rails is released under the MIT license.

View File

@@ -1,238 +0,0 @@
= Releasing Rails
In this document, we'll cover the steps necessary to release Rails. Each
section contains steps to take during that time before the release. The times
suggested in each header are just that: suggestions. However, they should
really be considered as minimums.
== 10 Days before release
Today is mostly coordination tasks. Here are the things you must do today:
=== Is the CI green? If not, make it green. (See "Fixing the CI")
Do not release with a Red CI. You can find the CI status here:
http://travis-ci.org/#!/rails/rails
=== Is Sam Ruby happy? If not, make him happy.
Sam Ruby keeps a test suite that makes sure the code samples in his book (Agile
Web Development with Rails) all work. These are valuable integration tests
for Rails. You can check the status of his tests here:
http://intertwingly.net/projects/dashboard.html
Do not release with Red AWDwR tests.
=== Are the postgres tests green? If not, make them green
Currently Travis CI doesn't run the Active Record postgres tests. They are
working to resolve this, but in the mean time, it is crucial to ensure that
the tests are still green before release.
=== Do we have any git dependencies? If so, contact those authors.
Having git dependencies indicates that we depend on unreleased code.
Obviously rails cannot be released when it depends on unreleased code.
Contact the authors of those particular gems and work out a release date that
suits them.
=== Contact the security team (either Koz or tenderlove)
Let them know of your plans to release. There may be security issues to be
addressed, and that can impact your release date.
=== Notify implementors.
Ruby implementors have high stakes in making sure Rails works. Be kind and
give them a heads up that Rails will be released soonish.
Send an email just giving a heads up about the upcoming release to these
lists:
* team@jruby.org
* community@rubini.us
* rubyonrails-core@googlegroups.com
Implementors will love you and help you.
== 3 Days before release
This is when you should release the release candidate. Here are your tasks
for today:
=== Is the CI green? If not, make it green.
=== Is Sam Ruby happy? If not, make him happy.
=== Are the postgres tests green? If not, make them green
=== Contact the security team. CVE emails must be sent on this day.
=== Create a release branch.
From the stable branch, create a release branch. For example, if you're
releasing Rails 3.0.10, do this:
[aaron@higgins rails (3-0-stable)]$ git checkout -b 3-0-10
Switched to a new branch '3-0-10'
[aaron@higgins rails (3-0-10)]$
=== Update each CHANGELOG.
Many times commits are made without the CHANGELOG being updated. You should
review the commits since the last release, and fill in any missing information
for each CHANGELOG.
You can review the commits for the 3.0.10 release like this:
[aaron@higgins rails (3-0-10)]$ git log v3.0.9..
If you're doing a stable branch release, you should also ensure that all of
the CHANGELOG entries in the stable branch are also synced to the master
branch.
=== Update the RAILS_VERSION file to include the RC.
=== Build and test the gem.
Run `rake install` to generate the gems and install them locally. Then try
generating a new app and ensure that nothing explodes.
This will stop you from looking silly when you push an RC to rubygems.org and
then realise it is broken.
=== Release the gem.
IMPORTANT: Due to YAML parse problems on the rubygems.org server, it is safest
to use Ruby 1.8 when releasing.
Run `rake release`. This will populate the gemspecs with data from
RAILS_VERSION, commit the changes, tag it, and push the gems to rubygems.org.
Here are the commands that `rake release` should use, so you can understand
what to do in case anything goes wrong:
$ rake all:build
$ git commit -am'updating RAILS_VERSION'
$ git tag -m'tagging rc release' v3.0.10.rc1
$ git push
$ git push --tags
$ for i in $(ls dist); do gem push $i; done
=== Send Rails release announcements
Write a release announcement that includes the version, changes, and links to
github where people can find the specific commit list. Here are the mailing
lists where you should announce:
* rubyonrails-core@googlegroups.com
* rubyonrails-talk@googlegroups.com
* ruby-talk@ruby-lang.org
Use markdown format for your announcement. Remember to ask people to report
issues with the release candidate to the rails-core mailing list.
IMPORTANT: If any users experience regressions when using the release
candidate, you *must* postpone the release. Bugfix releases *should not*
break existing applications.
=== Post the announcement to the Rails blog.
If you used markdown format for your email, you can just paste it in to the
blog.
* http://weblog.rubyonrails.org
=== Post the announcement to the Rails twitter account.
== Time between release candidate and actual release
Check the rails-core mailing list and the github issue list for regressions in
the RC.
If any regressions are found, fix the regressions and repeat the release
candidate process. We will not release the final until 72 hours after the
last release candidate has been pushed. This means that if users find
regressions, the scheduled release date must be postponed.
When you fix the regressions, do not create a new branch. Fix them on the
stable branch, then cherry pick the commit to your release branch. No other
commits should be added to the release branch besides regression fixing commits.
== Day of release
Many of these steps are the same as for the release candidate, so if you need
more explanation on a particular step, so the RC steps.
Today, do this stuff in this order:
* Apply security patches to the release branch
* Update CHANGELOG with security fixes.
* Update RAILS_VERSION to remove the rc
* Build and test the gem
* Release the gems
* Email security lists
* Email general announcement lists
=== Emailing the rails security announce list
Email the security announce list once for each vulnerability fixed.
You can do this, or ask the security team to do it.
Email the security reports to:
* rubyonrails-security@googlegroups.com
* linux-distros@vs.openwall.org
Be sure to note the security fixes in your announcement along with CVE numbers
and links to each patch. Some people may not be able to upgrade right away,
so we need to give them the security fixes in patch form.
* Blog announcements
* Twitter announcements
* Merge the release branch to the stable branch.
* Drink beer (or other cocktail)
== Misc
=== Fixing the CI
There are two simple steps for fixing the CI:
1. Identify the problem
2. Fix it
Repeat these steps until the CI is green.
=== Manually trigger docs generation
We have a post-receive hook in GitHub that calls the docs server on pushes.
It triggers generation and publication of edge docs, updates the contrib app,
and generates and publishes stable docs if a new stable tag is detected.
The hook unfortunately is not invoked by tag pushing, so once the new stable
tag has been pushed to origin, please run
rake publish_docs
You should see something like this:
Rails master hook tasks scheduled:
* updates the local checkout
* updates Rails Contributors
* generates and publishes edge docs
If a new stable tag is detected it also
* generates and publishes stable docs
This needs typically a few minutes.
Note you do not need to specify the tag, the docs server figures it out.
Also, don't worry if you call that multiple times or the hook is triggered
again by some immediate regular push, if the scripts are running new calls
are just queued (in a queue of size 1).

198
Rakefile
View File

@@ -1,198 +0,0 @@
#!/usr/bin/env rake
require 'rdoc/task'
require 'sdoc'
require 'net/http'
$:.unshift File.expand_path('..', __FILE__)
require "tasks/release"
desc "Build gem files for all projects"
task :build => "all:build"
desc "Release all gems to gemcutter and create a tag"
task :release => "all:release"
PROJECTS = %w(activesupport activemodel actionpack actionmailer activeresource activerecord railties)
desc 'Run all tests by default'
task :default => %w(test test:isolated)
%w(test test:isolated package gem).each do |task_name|
desc "Run #{task_name} task for all projects"
task task_name do
errors = []
PROJECTS.each do |project|
system(%(cd #{project} && #{$0} #{task_name})) || errors << project
end
fail("Errors in #{errors.join(', ')}") unless errors.empty?
end
end
desc "Smoke-test all projects"
task :smoke do
(PROJECTS - %w(activerecord)).each do |project|
system %(cd #{project} && #{$0} test:isolated)
end
system %(cd activerecord && #{$0} sqlite3:isolated_test)
end
desc "Install gems for all projects."
task :install => :gem do
version = File.read("RAILS_VERSION").strip
(PROJECTS - ["railties"]).each do |project|
puts "INSTALLING #{project}"
system("gem install #{project}/pkg/#{project}-#{version}.gem --no-ri --no-rdoc")
end
system("gem install railties/pkg/railties-#{version}.gem --no-ri --no-rdoc")
system("gem install pkg/rails-#{version}.gem --no-ri --no-rdoc")
end
desc "Generate documentation for the Rails framework"
RDoc::Task.new do |rdoc|
RDOC_MAIN = 'RDOC_MAIN.rdoc'
# This is a hack.
#
# Backslashes are needed to prevent RDoc from autolinking "Rails" to the
# documentation of the Rails module. On the other hand, as of this
# writing README.rdoc is displayed in the front page of the project in
# GitHub, where backslashes are shown and look weird.
#
# The temporary solution is to have a README.rdoc without backslashes for
# GitHub, and gsub it to generate the main page of the API.
#
# Also, relative links in GitHub have to point to blobs, whereas in the API
# they need to point to files.
#
# The idea for the future is to have totally different files, since the
# API is no longer a generic entry point to Rails and deserves a
# dedicated main page specifically thought as an API entry point.
rdoc.before_running_rdoc do
rdoc_main = File.read('README.rdoc')
# The ^(?=\S) assertion prevents code blocks from being processed,
# since no autolinking happens there and RDoc displays the backslash
# otherwise.
rdoc_main.gsub!(/^(?=\S).*?\b(?=Rails)\b/) { "#$&\\" }
rdoc_main.gsub!(%r{link:/rails/rails/blob/master/(\w+)/README\.rdoc}, "link:files/\\1/README_rdoc.html")
# Remove Travis and Gemnasium status images from API pages. Only GitHub
# README page gets these images. Travis' https build image is used to avoid
# GitHub caching: http://about.travis-ci.org/docs/user/status-images
rdoc_main.gsub!(%r{^== (Build|Dependency) Status.*}, '')
File.open(RDOC_MAIN, 'w') do |f|
f.write(rdoc_main)
end
rdoc.rdoc_files.include(RDOC_MAIN)
end
rdoc.rdoc_dir = 'doc/rdoc'
rdoc.title = "Ruby on Rails Documentation"
rdoc.options << '-f' << 'sdoc'
rdoc.options << '-T' << 'rails'
rdoc.options << '-e' << 'UTF-8'
rdoc.options << '-g' # SDoc flag, link methods to GitHub
rdoc.options << '-m' << RDOC_MAIN
rdoc.rdoc_files.include('railties/CHANGELOG.md')
rdoc.rdoc_files.include('railties/MIT-LICENSE')
rdoc.rdoc_files.include('railties/README.rdoc')
rdoc.rdoc_files.include('railties/lib/**/*.rb')
rdoc.rdoc_files.exclude('railties/lib/rails/generators/**/templates/**/*.rb')
rdoc.rdoc_files.include('activerecord/README.rdoc')
rdoc.rdoc_files.include('activerecord/CHANGELOG.md')
rdoc.rdoc_files.include('activerecord/lib/active_record/**/*.rb')
rdoc.rdoc_files.exclude('activerecord/lib/active_record/vendor/*')
rdoc.rdoc_files.include('activeresource/README.rdoc')
rdoc.rdoc_files.include('activeresource/CHANGELOG.md')
rdoc.rdoc_files.include('activeresource/lib/active_resource.rb')
rdoc.rdoc_files.include('activeresource/lib/active_resource/*')
rdoc.rdoc_files.include('actionpack/README.rdoc')
rdoc.rdoc_files.include('actionpack/CHANGELOG.md')
rdoc.rdoc_files.include('actionpack/lib/abstract_controller/**/*.rb')
rdoc.rdoc_files.include('actionpack/lib/action_controller/**/*.rb')
rdoc.rdoc_files.include('actionpack/lib/action_dispatch/**/*.rb')
rdoc.rdoc_files.include('actionpack/lib/action_view/**/*.rb')
rdoc.rdoc_files.exclude('actionpack/lib/action_controller/vendor/*')
rdoc.rdoc_files.include('actionmailer/README.rdoc')
rdoc.rdoc_files.include('actionmailer/CHANGELOG.md')
rdoc.rdoc_files.include('actionmailer/lib/action_mailer/base.rb')
rdoc.rdoc_files.include('actionmailer/lib/action_mailer/mail_helper.rb')
rdoc.rdoc_files.exclude('actionmailer/lib/action_mailer/vendor/*')
rdoc.rdoc_files.include('activesupport/README.rdoc')
rdoc.rdoc_files.include('activesupport/CHANGELOG.md')
rdoc.rdoc_files.include('activesupport/lib/active_support/**/*.rb')
rdoc.rdoc_files.exclude('activesupport/lib/active_support/vendor/*')
rdoc.rdoc_files.include('activemodel/README.rdoc')
rdoc.rdoc_files.include('activemodel/CHANGELOG.md')
rdoc.rdoc_files.include('activemodel/lib/active_model/**/*.rb')
end
# Enhance rdoc task to copy referenced images also
task :rdoc do
FileUtils.mkdir_p "doc/rdoc/files/examples/"
FileUtils.copy "activerecord/examples/associations.png", "doc/rdoc/files/examples/associations.png"
end
desc 'Bump all versions to match version.rb'
task :update_versions do
require File.dirname(__FILE__) + "/version"
File.open("RAILS_VERSION", "w") do |f|
f.write Rails::VERSION::STRING + "\n"
end
constants = {
"activesupport" => "ActiveSupport",
"activemodel" => "ActiveModel",
"actionpack" => "ActionPack",
"actionmailer" => "ActionMailer",
"activeresource" => "ActiveResource",
"activerecord" => "ActiveRecord",
"railties" => "Rails"
}
version_file = File.read("version.rb")
PROJECTS.each do |project|
Dir["#{project}/lib/*/version.rb"].each do |file|
File.open(file, "w") do |f|
f.write version_file.gsub(/Rails/, constants[project])
end
end
end
end
#
# We have a webhook configured in Github that gets invoked after pushes.
# This hook triggers the following tasks:
#
# * updates the local checkout
# * updates Rails Contributors
# * generates and publishes edge docs
# * if there's a new stable tag, generates and publishes stable docs
#
# Everything is automated and you do NOT need to run this task normally.
#
# We publish a new version by tagging, and pushing a tag does not trigger
# that webhook. Stable docs would be updated by any subsequent regular
# push, but if you want that to happen right away just run this.
#
desc 'Publishes docs, run this AFTER a new stable tag has been pushed'
task :publish_docs do
Net::HTTP.new('api.rubyonrails.org', 8080).start do |http|
request = Net::HTTP::Post.new('/rails-master-hook')
response = http.request(request)
puts response.body
end
end

302
actionmailer/CHANGELOG Normal file
View File

@@ -0,0 +1,302 @@
*1.3.4* (October 4th, 2007)
* Depend on Action Pack 1.13.4
*1.3.3* (March 12th, 2007)
* Depend on Action Pack 1.13.3
*1.3.2* (February 5th, 2007)
* Deprecate server_settings renaming it to smtp_settings, add sendmail_settings to allow you to override the arguments to and location of the sendmail executable. [Koz]
*1.3.1* (January 16th, 2007)
* Depend on Action Pack 1.13.1
*1.3.0* (January 16th, 2007)
* Make mime version default to 1.0. closes #2323 [ror@andreas-s.net]
* Make sure quoted-printable text is decoded correctly when only portions of the text are encoded. closes #3154. [jon@siliconcircus.com]
* Make sure DOS newlines in quoted-printable text are normalized to unix newlines before unquoting. closes #4166 and #4452. [Jamis Buck]
* Fixed that iconv decoding should catch InvalidEncoding #3153 [jon@siliconcircus.com]
* Tighten rescue clauses. #5985 [james@grayproductions.net]
* Automatically included ActionController::UrlWriter, such that URL generation can happen within ActionMailer controllers. [DHH]
* Replace Reloadable with Reloadable::Deprecated. [Nicholas Seckar]
* Resolve action naming collision. #5520 [ssinghi@kreeti.com]
* ActionMailer::Base documentation rewrite. Closes #4991 [Kevin Clark, Marcel Molina Jr.]
* Replace alias method chaining with Module#alias_method_chain. [Marcel Molina Jr.]
* Replace Ruby's deprecated append_features in favor of included. [Marcel Molina Jr.]
*1.2.5* (August 10th, 2006)
* Depend on Action Pack 1.12.5
*1.2.4* (August 8th, 2006)
* Backport of documentation enhancements. [Kevin Clark, Marcel Molina Jr]
* Correct spurious documentation example code which results in a SyntaxError. [Marcel Molina Jr.]
* Mailer template root applies to a class and its subclasses rather than acting globally. #5555 [somekool@gmail.com]
*1.2.3* (June 29th, 2006)
* Depend on Action Pack 1.12.3
*1.2.2* (June 27th, 2006)
* Depend on Action Pack 1.12.2
*1.2.1* (April 6th, 2006)
* Be part of Rails 1.1.1
*1.2.0* (March 27th, 2006)
* Nil charset caused subject line to be improperly quoted in implicitly multipart messages #2662 [ehalvorsen+rails@runbox.com]
* Parse content-type apart before using it so that sub-parts of the header can be set correctly #2918 [Jamis Buck]
* Make custom headers work in subparts #4034 [elan@bluemandrill.com]
* Template paths with dot chars in them no longer mess up implicit template selection for multipart messages #3332 [Chad Fowler]
* Make sure anything with content-disposition of "attachment" is passed to the attachment presenter when parsing an email body [Jamis Buck]
* Make sure TMail#attachments includes anything with content-disposition of "attachment", regardless of content-type [Jamis Buck]
*1.1.5* (December 13th, 2005)
* Become part of Rails 1.0
*1.1.4* (December 7th, 2005)
* Rename Version constant to VERSION. #2802 [Marcel Molina Jr.]
* Stricter matching for implicitly multipart filenames excludes files ending in unsupported extensions (such as foo.rhtml.bak) and without a two-part content type (such as foo.text.rhtml or foo.text.really.plain.rhtml). #2398 [Dave Burt <dave@burt.id.au>, Jeremy Kemper]
*1.1.3* (November 7th, 2005)
* Allow Mailers to have custom initialize methods that set default instance variables for all mail actions #2563 [mrj@bigpond.net.au]
*1.1.2* (October 26th, 2005)
* Upgraded to Action Pack 1.10.2
*1.1.1* (October 19th, 2005)
* Upgraded to Action Pack 1.10.1
*1.1.0* (October 16th, 2005)
* Update and extend documentation (rdoc)
* Minero Aoki made TMail available to Rails/ActionMailer under the MIT license (instead of LGPL) [RubyConf '05]
* Austin Ziegler made Text::Simple available to Rails/ActionMailer under a MIT-like licens [See rails ML, subject "Text::Format Licence Exception" on Oct 15, 2005]
* Fix vendor require paths to prevent files being required twice
* Don't add charset to content-type header for a part that contains subparts (for AOL compatibility) #2013 [John Long]
* Preserve underscores when unquoting message bodies #1930
* Encode multibyte characters correctly #1894
* Multipart messages specify a MIME-Version header automatically #2003 [John Long]
* Add a unified render method to ActionMailer (delegates to ActionView::Base#render)
* Move mailer initialization to a separate (overridable) method, so that subclasses may alter the various defaults #1727
* Look at content-location header (if available) to determine filename of attachments #1670
* ActionMailer::Base.deliver(email) had been accidentally removed, but was documented in the Rails book #1849
* Fix problem with sendmail delivery where headers should be delimited by \n characters instead of \r\n, which confuses some mail readers #1742 [Kent Sibilev]
*1.0.1* (11 July, 2005)
* Bind to Action Pack 1.9.1
*1.0.0* (6 July, 2005)
* Avoid adding nil header values #1392
* Better multipart support with implicit multipart/alternative and sorting of subparts [John Long]
* Allow for nested parts in multipart mails #1570 [Flurin Egger]
* Normalize line endings in outgoing mail bodies to "\n" #1536 [John Long]
* Allow template to be explicitly specified #1448 [tuxie@dekadance.se]
* Allow specific "multipart/xxx" content-type to be set on multipart messages #1412 [Flurin Egger]
* Unquoted @ characters in headers are now accepted in spite of RFC 822 #1206
* Helper support (borrowed from ActionPack)
* Silently ignore Errno::EINVAL errors when converting text.
* Don't cause an error when parsing an encoded attachment name #1340 [lon@speedymac.com]
* Nested multipart message parts are correctly processed in TMail::Mail#body
* BCC headers are removed when sending via SMTP #1402
* Added 'content_type' accessor, to allow content type to be set on a per-message basis. content_type defaults to "text/plain".
* Silently ignore Iconv::IllegalSequence errors when converting text #1341 [lon@speedymac.com]
* Support attachments and multipart messages.
* Added new accessors for the various mail properties.
* Fix to only perform the charset conversion if a 'from' and a 'to' charset are given (make no assumptions about what the charset was) #1276 [Jamis Buck]
* Fix attachments and content-type problems #1276 [Jamis Buck]
* Fixed the TMail#body method to look at the content-transfer-encoding header and unquote the body according to the rules it specifies #1265 [Jamis Buck]
* Added unquoting even if the iconv lib can't be loaded--in that case, only the charset conversion is skipped #1265 [Jamis Buck]
* Added automatic decoding of base64 bodies #1214 [Jamis Buck]
* Added that delivery errors are caught in a way so the mail is still returned whether the delivery was successful or not
* Fixed that email address like "Jamis Buck, M.D." <wild.medicine@example.net> would cause the quoter to generate emails resulting in "bad address" errors from the mail server #1220 [Jamis Buck]
*0.9.1* (20th April, 2005)
* Depend on Action Pack 1.8.1
*0.9.0* (19th April, 2005)
* Added that deliver_* will now return the email that was sent
* Added that quoting to UTF-8 only happens if the characters used are in that range #955 [Jamis Buck]
* Fixed quoting for all address headers, not just to #955 [Jamis Buck]
* Fixed unquoting of emails that doesn't have an explicit charset #1036 [wolfgang@stufenlos.net]
*0.8.1* (27th March, 2005)
* Fixed that if charset was found that the end of a mime part declaration TMail would throw an error #919 [lon@speedymac.com]
* Fixed that TMail::Unquoter would fail to recognize quoting method if it was in lowercase #919 [lon@speedymac.com]
* Fixed that TMail::Encoder would fail when it attempts to parse e-mail addresses which are encoded using something other than the messages encoding method #919 [lon@speedymac.com]
* Added rescue for missing iconv library and throws warnings if subject/body is called on a TMail object without it instead
*0.8.0* (22th March, 2005)
* Added framework support for processing incoming emails with an Action Mailer class. See example in README.
*0.7.1* (7th March, 2005)
* Bind to newest Action Pack (1.5.1)
*0.7.0* (24th February, 2005)
* Added support for charsets for both subject and body. The default charset is now UTF-8 #673 [Jamis Buck]. Examples:
def iso_charset(recipient)
@recipients = recipient
@subject = "testing iso charsets"
@from = "system@loudthinking.com"
@body = "Nothing to see here."
@charset = "iso-8859-1"
end
def unencoded_subject(recipient)
@recipients = recipient
@subject = "testing unencoded subject"
@from = "system@loudthinking.com"
@body = "Nothing to see here."
@encode_subject = false
@charset = "iso-8859-1"
end
*0.6.1* (January 18th, 2005)
* Fixed sending of emails to use Tmail#from not the deprecated Tmail#from_address
*0.6* (January 17th, 2005)
* Fixed that bcc and cc should be settable through @bcc and @cc -- not just @headers["Bcc"] and @headers["Cc"] #453 [Eric Hodel]
* Fixed Action Mailer to be "warnings safe" so you can run with ruby -w and not get framework warnings #453 [Eric Hodel]
*0.5*
* Added access to custom headers, like cc, bcc, and reply-to #268 [Andreas Schwarz]. Example:
def post_notification(recipients, post)
@recipients = recipients
@from = post.author.email_address_with_name
@headers["bcc"] = SYSTEM_ADMINISTRATOR_EMAIL
@headers["reply-to"] = "notifications@example.com"
@subject = "[#{post.account.name} #{post.title}]"
@body["post"] = post
end
*0.4* (5)
* Consolidated the server configuration options into Base#server_settings= and expanded that with controls for authentication and more [Marten]
NOTE: This is an API change that could potentially break your application if you used the old application form. Please do change!
* Added Base#deliveries as an accessor for an array of emails sent out through that ActionMailer class when using the :test delivery option. [Jeremy Kemper]
* Added Base#perform_deliveries= which can be set to false to turn off the actual delivery of the email through smtp or sendmail.
This is especially useful for functional testing that shouldn't send off real emails, but still trigger delivery_* methods.
* Added option to specify delivery method with Base#delivery_method=. Default is :smtp and :sendmail is currently the only other option.
Sendmail is assumed to be present at "/usr/sbin/sendmail" if that option is used. [Kent Sibilev]
* Dropped "include TMail" as it added to much baggage into the default namespace (like Version) [Chad Fowler]
*0.3*
* First release

View File

@@ -1,123 +0,0 @@
## Rails 3.2.19 (Jul 2, 2014) ##
* No changes.
## Rails 3.2.18 (May 6, 2014) ##
* No changes.
## Rails 3.2.17 (Feb 18, 2014) ##
* No changes.
## Rails 3.2.16 (Dec 3, 2013) ##
* No changes.
## Rails 3.2.15 (Oct 16, 2013) ##
* No changes.
## Rails 3.2.14 (Jul 22, 2013) ##
* No changes.
## Rails 3.2.13 (Mar 18, 2013) ##
* No changes.
## Rails 3.2.12 (Feb 11, 2013) ##
* No changes.
## Rails 3.2.11 (Jan 8, 2013) ##
* No changes.
## Rails 3.2.10 (Jan 2, 2013) ##
* No changes.
## Rails 3.2.9 (Nov 12, 2012) ##
* The return value from mailer methods is no longer relevant. This fixes a bug,
which was introduced with 3.2.9.
Backport #8450
Fix #8448
class ExampleMailer < ActionMailer::Base
# in 3.2.9, returning a falsy value from a mailer action, prevented the email from beeing sent.
# With 3.2.10 the return value is no longer relevant. If you call mail() the email will be sent.
def nil_returning_mailer_action
mail()
nil
end
end
*Yves Senn*
## Rails 3.2.9 (Nov 12, 2012) ##
* Do not render views when mail() isn't called.
Fix #7761
*Yves Senn*
## Rails 3.2.8 (Aug 9, 2012) ##
* No changes.
## Rails 3.2.7 (Jul 26, 2012) ##
* No changes.
## Rails 3.2.6 (Jun 12, 2012) ##
* No changes.
## Rails 3.2.5 (Jun 1, 2012) ##
* No changes.
## Rails 3.2.4 (May 31, 2012) ##
* No changes.
## Rails 3.2.3 (March 30, 2012) ##
* Upgrade mail version to 2.4.3 *ML*
## Rails 3.2.2 (March 1, 2012) ##
* No changes.
## Rails 3.2.1 (January 26, 2012) ##
* No changes.
## Rails 3.2.0 (January 20, 2012) ##
* Upgrade mail version to 2.4.0 *ML*
* Remove Old ActionMailer API *Josh Kalderimis*
Please check [3-1-stable](https://github.com/rails/rails/blob/3-1-stable/actionmailer/CHANGELOG.md) for previous changes.

View File

@@ -1,4 +1,4 @@
Copyright (c) 2004-2011 David Heinemeier Hansson
Copyright (c) 2004-2006 David Heinemeier Hansson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

145
actionmailer/README Executable file
View File

@@ -0,0 +1,145 @@
= Action Mailer -- Easy email delivery and testing
Action Mailer is a framework for designing email-service layers. These layers
are used to consolidate code for sending out forgotten passwords, welcome
wishes on signup, invoices for billing, and any other use case that requires
a written notification to either a person or another system.
Additionally, an Action Mailer class can be used to process incoming email,
such as allowing a weblog to accept new posts from an email (which could even
have been sent from a phone).
== Sending emails
The framework works by setting up all the email details, except the body,
in methods on the service layer. Subject, recipients, sender, and timestamp
are all set up this way. An example of such a method:
def signed_up(recipient)
recipients recipient
subject "[Signed up] Welcome #{recipient}"
from "system@loudthinking.com"
body(:recipient => recipient)
end
The body of the email is created by using an Action View template (regular
ERb) that has the content of the body hash parameter available as instance variables.
So the corresponding body template for the method above could look like this:
Hello there,
Mr. <%= @recipient %>
And if the recipient was given as "david@loudthinking.com", the email
generated would look like this:
Date: Sun, 12 Dec 2004 00:00:00 +0100
From: system@loudthinking.com
To: david@loudthinking.com
Subject: [Signed up] Welcome david@loudthinking.com
Hello there,
Mr. david@loudthinking.com
You never actually call the instance methods like signed_up directly. Instead,
you call class methods like deliver_* and create_* that are automatically
created for each instance method. So if the signed_up method sat on
ApplicationMailer, it would look like this:
ApplicationMailer.create_signed_up("david@loudthinking.com") # => tmail object for testing
ApplicationMailer.deliver_signed_up("david@loudthinking.com") # sends the email
ApplicationMailer.new.signed_up("david@loudthinking.com") # won't work!
== Receiving emails
To receive emails, you need to implement a public instance method called receive that takes a
tmail object as its single parameter. The Action Mailer framework has a corresponding class method,
which is also called receive, that accepts a raw, unprocessed email as a string, which it then turns
into the tmail object and calls the receive instance method.
Example:
class Mailman < ActionMailer::Base
def receive(email)
page = Page.find_by_address(email.to.first)
page.emails.create(
:subject => email.subject, :body => email.body
)
if email.has_attachments?
for attachment in email.attachments
page.attachments.create({
:file => attachment, :description => email.subject
})
end
end
end
end
This Mailman can be the target for Postfix. In Rails, you would use the runner like this:
./script/runner 'Mailman.receive(STDIN.read)'
== Configuration
The Base class has the full list of configuration options. Here's an example:
ActionMailer::Base.server_settings = {
:address=>'smtp.yourserver.com', # default: localhost
:port=>'25', # default: 25
:user_name=>'user',
:password=>'pass',
:authentication=>:plain # :plain, :login or :cram_md5
}
== Dependencies
Action Mailer requires that the Action Pack is either available to be required immediately
or is accessible as a GEM.
== Bundled software
* tmail 0.10.8 by Minero Aoki released under LGPL
Read more on http://i.loveruby.net/en/prog/tmail.html
* Text::Format 0.63 by Austin Ziegler released under OpenSource
Read more on http://www.halostatue.ca/ruby/Text__Format.html
== Download
The latest version of Action Mailer can be found at
* http://rubyforge.org/project/showfiles.php?group_id=361
Documentation can be found at
* http://actionmailer.rubyonrails.org
== Installation
You can install Action Mailer with the following command.
% [sudo] ruby install.rb
from its distribution directory.
== License
Action Mailer is released under the MIT license.
== Support
The Action Mailer homepage is http://www.rubyonrails.org. You can find
the Action Mailer RubyForge page at http://rubyforge.org/projects/actionmailer.
And as Jim from Rake says:
Feel free to submit commits or feature requests. If you send a patch,
remember to update the corresponding unit tests. If fact, I prefer
new feature to be submitted in the form of new unit tests.

View File

@@ -1,163 +0,0 @@
= Action Mailer -- Easy email delivery and testing
Action Mailer is a framework for designing email-service layers. These layers
are used to consolidate code for sending out forgotten passwords, welcome
wishes on signup, invoices for billing, and any other use case that requires
a written notification to either a person or another system.
Action Mailer is in essence a wrapper around Action Controller and the
Mail gem. It provides a way to make emails using templates in the same
way that Action Controller renders views using templates.
Additionally, an Action Mailer class can be used to process incoming email,
such as allowing a blog to accept new posts from an email (which could even
have been sent from a phone).
== Sending emails
The framework works by initializing any instance variables you want to be
available in the email template, followed by a call to +mail+ to deliver
the email.
This can be as simple as:
class Notifier < ActionMailer::Base
delivers_from 'system@loudthinking.com'
def welcome(recipient)
@recipient = recipient
mail(:to => recipient,
:subject => "[Signed up] Welcome #{recipient}")
end
end
The body of the email is created by using an Action View template (regular
ERB) that has the instance variables that are declared in the mailer action.
So the corresponding body template for the method above could look like this:
Hello there,
Mr. <%= @recipient %>
Thank you for signing up!
And if the recipient was given as "david@loudthinking.com", the email
generated would look like this:
Date: Mon, 25 Jan 2010 22:48:09 +1100
From: system@loudthinking.com
To: david@loudthinking.com
Message-ID: <4b5d84f9dd6a5_7380800b81ac29578@void.loudthinking.com.mail>
Subject: [Signed up] Welcome david@loudthinking.com
Mime-Version: 1.0
Content-Type: text/plain;
charset="US-ASCII";
Content-Transfer-Encoding: 7bit
Hello there,
Mr. david@loudthinking.com
Thank you for signing up!
In previous version of Rails you would call <tt>create_method_name</tt> and
<tt>deliver_method_name</tt>. Rails 3.0 has a much simpler interface, you
simply call the method and optionally call +deliver+ on the return value.
Calling the method returns a Mail Message object:
message = Notifier.welcome # => Returns a Mail::Message object
message.deliver # => delivers the email
Or you can just chain the methods together like:
Notifier.welcome.deliver # Creates the email and sends it immediately
== Setting defaults
It is possible to set default values that will be used in every method in your Action Mailer class. To implement this functionality, you just call the public class method <tt>default</tt> which you get for free from ActionMailer::Base. This method accepts a Hash as the parameter. You can use any of the headers e-mail messages has, like <tt>:from</tt> as the key. You can also pass in a string as the key, like "Content-Type", but Action Mailer does this out of the box for you, so you won't need to worry about that. Finally it is also possible to pass in a Proc that will get evaluated when it is needed.
Note that every value you set with this method will get over written if you use the same key in your mailer method.
Example:
class Authenticationmailer < ActionMailer::Base
default :from => "awesome@application.com", :subject => Proc.new { "E-mail was generated at #{Time.now}" }
.....
end
== Receiving emails
To receive emails, you need to implement a public instance method called <tt>receive</tt> that takes an
email object as its single parameter. The Action Mailer framework has a corresponding class method,
which is also called <tt>receive</tt>, that accepts a raw, unprocessed email as a string, which it then turns
into the email object and calls the receive instance method.
Example:
class Mailman < ActionMailer::Base
def receive(email)
page = Page.find_by_address(email.to.first)
page.emails.create(
:subject => email.subject, :body => email.body
)
if email.has_attachments?
email.attachments.each do |attachment|
page.attachments.create({
:file => attachment, :description => email.subject
})
end
end
end
end
This Mailman can be the target for Postfix or other MTAs. In Rails, you would use the runner in the
trivial case like this:
rails 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
}
== Download and installation
The latest version of Action Mailer can be installed with RubyGems:
% [sudo] gem install actionmailer
Source code can be downloaded as part of the Rails project on GitHub
* https://github.com/rails/rails/tree/3-2-stable/actionmailer
== License
Action Mailer is released under the MIT license.
== Support
API documentation is at
* http://api.rubyonrails.org
Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here:
* https://github.com/rails/rails/issues

View File

@@ -1,7 +1,21 @@
#!/usr/bin/env rake
require 'rubygems'
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
require 'rake/packagetask'
require 'rubygems/package_task'
require 'rake/gempackagetask'
require 'rake/contrib/rubyforgepublisher'
require File.join(File.dirname(__FILE__), 'lib', 'action_mailer', 'version')
PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
PKG_NAME = 'actionmailer'
PKG_VERSION = ActionMailer::VERSION::STRING + PKG_BUILD
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
RELEASE_NAME = "REL #{PKG_VERSION}"
RUBY_FORGE_PROJECT = "actionmailer"
RUBY_FORGE_USER = "webster132"
desc "Default Task"
task :default => [ :test ]
@@ -9,28 +23,73 @@ task :default => [ :test ]
# Run the unit tests
Rake::TestTask.new { |t|
t.libs << "test"
t.pattern = 'test/**/*_test.rb'
t.warning = true
t.pattern = 'test/*_test.rb'
t.verbose = true
t.warning = false
}
namespace :test do
task :isolated do
ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME'))
Dir.glob("test/**/*_test.rb").all? do |file|
sh(ruby, '-Ilib:test', file)
end or raise "Failures"
end
# Genereate the RDoc documentation
Rake::RDocTask.new { |rdoc|
rdoc.rdoc_dir = 'doc'
rdoc.title = "Action Mailer -- Easy email delivery and testing"
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
rdoc.template = "#{ENV['template']}.rb" if ENV['template']
rdoc.rdoc_files.include('README', 'CHANGELOG')
rdoc.rdoc_files.include('lib/action_mailer.rb')
rdoc.rdoc_files.include('lib/action_mailer/*.rb')
}
# Create compressed packages
spec = Gem::Specification.new do |s|
s.platform = Gem::Platform::RUBY
s.name = PKG_NAME
s.summary = "Service layer for easy email delivery and testing."
s.description = %q{Makes it trivial to test and deliver emails sent from a single service layer.}
s.version = PKG_VERSION
s.author = "David Heinemeier Hansson"
s.email = "david@loudthinking.com"
s.rubyforge_project = "actionmailer"
s.homepage = "http://www.rubyonrails.org"
s.add_dependency('actionpack', '= 1.13.4' + PKG_BUILD)
s.has_rdoc = true
s.requirements << 'none'
s.require_path = 'lib'
s.autorequire = 'action_mailer'
s.files = [ "Rakefile", "install.rb", "README", "CHANGELOG", "MIT-LICENSE" ]
s.files = s.files + Dir.glob( "lib/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
s.files = s.files + Dir.glob( "test/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
end
spec = eval(File.read('actionmailer.gemspec'))
Gem::PackageTask.new(spec) do |p|
Rake::GemPackageTask.new(spec) do |p|
p.gem_spec = spec
p.need_tar = true
p.need_zip = true
end
desc "Release to gemcutter"
task :release => :package do
require 'rake/gemcutter'
Rake::Gemcutter::Tasks.new(spec).define
Rake::Task['gem:push'].invoke
desc "Publish the API documentation"
task :pgem => [:package] do
Rake::SshFilePublisher.new("davidhh@wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
end
desc "Publish the API documentation"
task :pdoc => [:rdoc] do
Rake::SshDirPublisher.new("davidhh@wrath.rubyonrails.org", "public_html/am", "doc").upload
end
desc "Publish the release files to RubyForge."
task :release => [ :package ] do
require 'rubyforge'
packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
rubyforge = RubyForge.new
rubyforge.login
rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages)
end

View File

@@ -1,24 +0,0 @@
version = File.read(File.expand_path("../../RAILS_VERSION", __FILE__)).strip
Gem::Specification.new do |s|
s.platform = Gem::Platform::RUBY
s.name = 'actionmailer'
s.version = version
s.summary = 'Email composition, delivery, and receiving framework (part of Rails).'
s.description = 'Email on Rails. Compose, deliver, receive, and test emails using the familiar controller/view pattern. First-class support for multipart email and attachments.'
s.license = 'MIT'
s.required_ruby_version = '>= 1.8.7'
s.author = 'David Heinemeier Hansson'
s.email = 'david@loudthinking.com'
s.homepage = 'http://www.rubyonrails.org'
s.files = Dir['CHANGELOG.md', 'README.rdoc', 'MIT-LICENSE', 'lib/**/*']
s.require_path = 'lib'
s.requirements << 'none'
s.add_dependency('actionpack', version)
s.add_dependency('mail', '~> 2.5.4')
end

30
actionmailer/install.rb Normal file
View File

@@ -0,0 +1,30 @@
require 'rbconfig'
require 'find'
require 'ftools'
include Config
# this was adapted from rdoc's install.rb by way of Log4r
$sitedir = CONFIG["sitelibdir"]
unless $sitedir
version = CONFIG["MAJOR"] + "." + CONFIG["MINOR"]
$libdir = File.join(CONFIG["libdir"], "ruby", version)
$sitedir = $:.find {|x| x =~ /site_ruby/ }
if !$sitedir
$sitedir = File.join($libdir, "site_ruby")
elsif $sitedir !~ Regexp.quote(version)
$sitedir = File.join($sitedir, version)
end
end
# the acual gruntwork
Dir.chdir("lib")
Find.find("action_mailer", "action_mailer.rb") { |f|
if f[-3..-1] == ".rb"
File::install(f, File.join($sitedir, *f.split(/\//)), 0644, true)
else
File::makedirs(File.join($sitedir, *f.split(/\//)))
end
}

53
actionmailer/lib/action_mailer.rb Normal file → Executable file
View File

@@ -1,5 +1,5 @@
#--
# Copyright (c) 2004-2011 David Heinemeier Hansson
# Copyright (c) 2004-2006 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -21,29 +21,30 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
actionpack_path = File.expand_path('../../../actionpack/lib', __FILE__)
$:.unshift(actionpack_path) if File.directory?(actionpack_path) && !$:.include?(actionpack_path)
require 'abstract_controller'
require 'action_view'
require 'action_mailer/version'
# Common Active Support usage in Action Mailer
require 'active_support/core_ext/class'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/array/uniq_by'
require 'active_support/core_ext/module/attr_internal'
require 'active_support/core_ext/module/delegation'
require 'active_support/core_ext/string/inflections'
require 'active_support/lazy_load_hooks'
module ActionMailer
extend ::ActiveSupport::Autoload
autoload :Collector
autoload :Base
autoload :DeliveryMethods
autoload :MailHelper
autoload :TestCase
autoload :TestHelper
unless defined?(ActionController)
begin
$:.unshift "#{File.dirname(__FILE__)}/../../actionpack/lib"
require 'action_controller'
rescue LoadError
require 'rubygems'
gem 'actionpack', '>= 1.12.5'
end
end
$:.unshift(File.dirname(__FILE__) + "/action_mailer/vendor/")
require 'action_mailer/base'
require 'action_mailer/helpers'
require 'action_mailer/mail_helper'
require 'action_mailer/quoting'
require 'tmail'
require 'net/smtp'
ActionMailer::Base.class_eval do
include ActionMailer::Quoting
include ActionMailer::Helpers
helper MailHelper
end
silence_warnings { TMail::Encoder.const_set("MAX_LINE_LEN", 200) }

View File

@@ -0,0 +1,30 @@
module ActionMailer
module AdvAttrAccessor #:nodoc:
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods #:nodoc:
def adv_attr_accessor(*names)
names.each do |name|
ivar = "@#{name}"
define_method("#{name}=") do |value|
instance_variable_set(ivar, value)
end
define_method(name) do |*parameters|
raise ArgumentError, "expected 0 or 1 parameters" unless parameters.length <= 1
if parameters.empty?
if instance_variables.include?(ivar)
instance_variable_get(ivar)
end
else
instance_variable_set(ivar, parameters.first)
end
end
end
end
end
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -1,30 +0,0 @@
require 'abstract_controller/collector'
require 'active_support/core_ext/hash/reverse_merge'
require 'active_support/core_ext/array/extract_options'
module ActionMailer #:nodoc:
class Collector
include AbstractController::Collector
attr_reader :responses
def initialize(context, &block)
@context = context
@responses = []
@default_render = block
end
def any(*args, &block)
options = args.extract_options!
raise "You have to supply at least one format" if args.empty?
args.each { |type| send(type, options.dup, &block) }
end
alias :all :any
def custom(mime, options={})
options.reverse_merge!(:content_type => mime.to_s)
@context.formats = [mime.to_sym]
options[:body] = block_given? ? yield : @default_render.call
@responses << options
end
end
end

View File

@@ -1,86 +0,0 @@
require 'tmpdir'
module ActionMailer
# This module handles everything related to mail delivery, from registering new
# delivery methods to configuring the mail object to be sent.
module DeliveryMethods
extend ActiveSupport::Concern
included do
class_attribute :delivery_methods, :delivery_method
# Do not make this inheritable, because we always want it to propagate
cattr_accessor :raise_delivery_errors
self.raise_delivery_errors = true
cattr_accessor :perform_deliveries
self.perform_deliveries = true
self.delivery_methods = {}.freeze
self.delivery_method = :smtp
add_delivery_method :smtp, Mail::SMTP,
:address => "localhost",
:port => 25,
:domain => 'localhost.localdomain',
:user_name => nil,
:password => nil,
:authentication => nil,
:enable_starttls_auto => true
add_delivery_method :file, Mail::FileDelivery,
:location => defined?(Rails.root) ? "#{Rails.root}/tmp/mails" : "#{Dir.tmpdir}/mails"
add_delivery_method :sendmail, Mail::Sendmail,
:location => '/usr/sbin/sendmail',
:arguments => '-i -t'
add_delivery_method :test, Mail::TestMailer
end
module ClassMethods
# Provides a list of emails that have been delivered by Mail::TestMailer
delegate :deliveries, :deliveries=, :to => Mail::TestMailer
# Adds a new delivery method through the given class using the given symbol
# as alias and the default options supplied:
#
# Example:
#
# add_delivery_method :sendmail, Mail::Sendmail,
# :location => '/usr/sbin/sendmail',
# :arguments => '-i -t'
#
def add_delivery_method(symbol, klass, default_options={})
class_attribute(:"#{symbol}_settings") unless respond_to?(:"#{symbol}_settings")
send(:"#{symbol}_settings=", default_options)
self.delivery_methods = delivery_methods.merge(symbol.to_sym => klass).freeze
end
def wrap_delivery_behavior(mail, method=nil) #:nodoc:
method ||= self.delivery_method
mail.delivery_handler = self
case method
when NilClass
raise "Delivery method cannot be nil"
when Symbol
if klass = delivery_methods[method.to_sym]
mail.delivery_method(klass, send(:"#{method}_settings"))
else
raise "Invalid delivery method #{method.inspect}"
end
else
mail.delivery_method(method)
end
mail.perform_deliveries = perform_deliveries
mail.raise_delivery_errors = raise_delivery_errors
end
end
def wrap_delivery_behavior!(*args) #:nodoc:
self.class.wrap_delivery_behavior(message, *args)
end
end
end

View File

@@ -0,0 +1,111 @@
module ActionMailer
module Helpers #:nodoc:
def self.included(base) #:nodoc:
# Initialize the base module to aggregate its helpers.
base.class_inheritable_accessor :master_helper_module
base.master_helper_module = Module.new
# Extend base with class methods to declare helpers.
base.extend(ClassMethods)
base.class_eval do
# Wrap inherited to create a new master helper module for subclasses.
class << self
alias_method_chain :inherited, :helper
end
# Wrap initialize_template_class to extend new template class
# instances with the master helper module.
alias_method_chain :initialize_template_class, :helper
end
end
module ClassMethods
# Makes all the (instance) methods in the helper module available to templates rendered through this controller.
# See ActionView::Helpers (link:classes/ActionView/Helpers.html) for more about making your own helper modules
# available to the templates.
def add_template_helper(helper_module) #:nodoc:
master_helper_module.module_eval "include #{helper_module}"
end
# Declare a helper:
# helper :foo
# requires 'foo_helper' and includes FooHelper in the template class.
# 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.
# helper(:three, BlindHelper) { def mice() 'mice' end }
# does all three.
def helper(*args, &block)
args.flatten.each do |arg|
case arg
when Module
add_template_helper(arg)
when String, Symbol
file_name = arg.to_s.underscore + '_helper'
class_name = file_name.camelize
begin
require_dependency(file_name)
rescue LoadError => load_error
requiree = / -- (.*?)(\.rb)?$/.match(load_error).to_a[1]
msg = (requiree == file_name) ? "Missing helper file helpers/#{file_name}.rb" : "Can't load file: #{requiree}"
raise LoadError.new(msg).copy_blame!(load_error)
end
add_template_helper(class_name.constantize)
else
raise ArgumentError, 'helper expects String, Symbol, or Module argument'
end
end
# Evaluate block in template class if given.
master_helper_module.module_eval(&block) if block_given?
end
# Declare a controller method as a helper. For example,
# helper_method :link_to
# def link_to(name, options) ... end
# makes the link_to controller method available in the view.
def helper_method(*methods)
methods.flatten.each do |method|
master_helper_module.module_eval <<-end_eval
def #{method}(*args, &block)
controller.send(%(#{method}), *args, &block)
end
end_eval
end
end
# Declare a controller attribute as a helper. For example,
# helper_attr :name
# attr_accessor :name
# makes the name and name= controller methods available in the view.
# The is a convenience wrapper for helper_method.
def helper_attr(*attrs)
attrs.flatten.each { |attr| helper_method(attr, "#{attr}=") }
end
private
def inherited_with_helper(child)
inherited_without_helper(child)
begin
child.master_helper_module = Module.new
child.master_helper_module.send :include, master_helper_module
child.helper child.name.underscore
rescue MissingSourceFile => e
raise unless e.is_missing?("helpers/#{child.name.underscore}_helper")
end
end
end
private
# Extend the template class instance with our controller's helper module.
def initialize_template_class_with_helper(assigns)
returning(template = initialize_template_class_without_helper(assigns)) do
template.extend self.class.master_helper_module
end
end
end
end

View File

@@ -1,22 +0,0 @@
require 'active_support/core_ext/array/wrap'
module ActionMailer
class LogSubscriber < ActiveSupport::LogSubscriber
def deliver(event)
recipients = Array.wrap(event.payload[:to]).join(', ')
info("\nSent mail to #{recipients} (#{format_duration(event.duration)})")
debug(event.payload[:mail])
end
def receive(event)
info("\nReceived mail (#{format_duration(event.duration)})")
debug(event.payload[:mail])
end
def logger
ActionMailer::Base.logger
end
end
end
ActionMailer::LogSubscriber.attach_to :action_mailer

View File

@@ -1,56 +1,19 @@
module ActionMailer
module MailHelper
# Uses Text::Format to take the text and format it, indented two spaces for
# each line, and wrapped at 72 columns.
def block_format(text)
formatted = text.split(/\n\r\n/).collect { |paragraph|
format_paragraph(paragraph)
}.join("\n")
require 'text/format'
# Make list points stand on their own line
formatted.gsub!(/[ ]*([*]+) ([^*]*)/) { |s| " #{$1} #{$2.strip}\n" }
formatted.gsub!(/[ ]*([#]+) ([^#]*)/) { |s| " #{$1} #{$2.strip}\n" }
module MailHelper
# Uses Text::Format to take the text and format it, indented two spaces for
# each line, and wrapped at 72 columns.
def block_format(text)
formatted = text.split(/\n\r\n/).collect { |paragraph|
Text::Format.new(
:columns => 72, :first_indent => 2, :body_indent => 2, :text => paragraph
).format
}.join("\n")
# Make list points stand on their own line
formatted.gsub!(/[ ]*([*]+) ([^*]*)/) { |s| " #{$1} #{$2.strip}\n" }
formatted.gsub!(/[ ]*([#]+) ([^#]*)/) { |s| " #{$1} #{$2.strip}\n" }
formatted
end
# Access the mailer instance.
def mailer
@_controller
end
# Access the message instance.
def message
@_message
end
# Access the message attachments list.
def attachments
@_message.attachments
end
# Returns +text+ wrapped at +len+ columns and indented +indent+ spaces.
#
# === Examples
#
# my_text = "Here is a sample text with more than 40 characters"
#
# format_paragraph(my_text, 25, 4)
# # => " Here is a sample text with\n more than 40 characters"
def format_paragraph(text, len = 72, indent = 2)
sentences = [[]]
text.split.each do |word|
if (sentences.last + [word]).join(' ').length > len
sentences << [word]
else
sentences.last << word
end
end
sentences.map { |sentence|
"#{" " * indent}#{sentence.join(' ')}"
}.join "\n"
end
formatted
end
end

View File

@@ -0,0 +1,113 @@
require 'action_mailer/adv_attr_accessor'
require 'action_mailer/part_container'
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
# to use the helper methods in ActionMailer::PartContainer.
class Part
include ActionMailer::AdvAttrAccessor
include ActionMailer::PartContainer
# 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
# and assign the result here.
adv_attr_accessor :body
# Specify the charset for this subpart. By default, it will be the charset
# of the containing part or mailer.
adv_attr_accessor :charset
# The content disposition of this part, typically either "inline" or
# "attachment".
adv_attr_accessor :content_disposition
# The content type of the part.
adv_attr_accessor :content_type
# The filename to use for this subpart (usually for attachments).
adv_attr_accessor :filename
# Accessor for specifying additional headers to include with this part.
adv_attr_accessor :headers
# The transfer encoding to use for this subpart, like "base64" or
# "quoted-printable".
adv_attr_accessor :transfer_encoding
# Create a new part from the given +params+ hash. The valid params keys
# correspond to the accessors.
def initialize(params)
@content_type = params[:content_type]
@content_disposition = params[:disposition] || "inline"
@charset = params[:charset]
@body = params[:body]
@filename = params[:filename]
@transfer_encoding = params[:transfer_encoding] || "quoted-printable"
@headers = params[:headers] || {}
@parts = []
end
# Convert the part to a mail object which can be included in the parts
# list of another mail object.
def to_mail(defaults)
part = TMail::Mail.new
real_content_type, ctype_attrs = parse_content_type(defaults)
if @parts.empty?
part.content_transfer_encoding = transfer_encoding || "quoted-printable"
case (transfer_encoding || "").downcase
when "base64" then
part.body = TMail::Base64.folding_encode(body)
when "quoted-printable"
part.body = [Utils.normalize_new_lines(body)].pack("M*")
else
part.body = body
end
# Always set the content_type after setting the body and or parts!
# Also don't set filename and name when there is none (like in
# non-attachment parts)
if content_disposition == "attachment"
ctype_attrs.delete "charset"
part.set_content_type(real_content_type, nil,
squish("name" => filename).merge(ctype_attrs))
part.set_content_disposition(content_disposition,
squish("filename" => filename).merge(ctype_attrs))
else
part.set_content_type(real_content_type, nil, ctype_attrs)
part.set_content_disposition(content_disposition)
end
else
if String === body
part = TMail::Mail.new
part.body = body
part.set_content_type(real_content_type, nil, ctype_attrs)
part.set_content_disposition "inline"
m.parts << part
end
@parts.each do |p|
prt = (TMail::Mail === p ? p : p.to_mail(defaults))
part.parts << prt
end
part.set_content_type(real_content_type, nil, ctype_attrs) if real_content_type =~ /multipart/
end
headers.each { |k,v| part[k] = v }
part
end
private
def squish(values={})
values.delete_if { |k,v| v.nil? }
end
end
end

View File

@@ -0,0 +1,51 @@
module ActionMailer
# Accessors and helpers that ActionMailer::Base and ActionMailer::Part have
# in common. Using these helpers you can easily add subparts or attachments
# to your message:
#
# def my_mail_message(...)
# ...
# part "text/plain" do |p|
# p.body "hello, world"
# p.transfer_encoding "base64"
# end
#
# attachment "image/jpg" do |a|
# a.body = File.read("hello.jpg")
# a.filename = "hello.jpg"
# end
# end
module PartContainer
# The list of subparts of this container
attr_reader :parts
# Add a part to a multipart message, with the given content-type. The
# part itself is yielded to the block so that other properties (charset,
# body, headers, etc.) can be set on it.
def part(params)
params = {:content_type => params} if String === params
part = Part.new(params)
yield part if block_given?
@parts << part
end
# Add an attachment to a multipart message. This is simply a part with the
# content-disposition set to "attachment".
def attachment(params, &block)
params = { :content_type => params } if String === params
params = { :disposition => "attachment",
:transfer_encoding => "base64" }.merge(params)
part(params, &block)
end
private
def parse_content_type(defaults=nil)
return [defaults && defaults.content_type, {}] if content_type.blank?
ctype, *attrs = content_type.split(/;\s*/)
attrs = attrs.inject({}) { |h,s| k,v = s.split(/=/, 2); h[k] = v; h }
[ctype, {"charset" => charset || defaults && defaults.charset}.merge(attrs)]
end
end
end

View File

@@ -0,0 +1,59 @@
module ActionMailer
module Quoting #:nodoc:
# Convert the given text into quoted printable format, with an instruction
# that the text be eventually interpreted in the given charset.
def quoted_printable(text, charset)
text = text.gsub( /[^a-z ]/i ) { quoted_printable_encode($&) }.
gsub( / /, "_" )
"=?#{charset}?Q?#{text}?="
end
# Convert the given character to quoted printable format, taking into
# account multi-byte characters (if executing with $KCODE="u", for instance)
def quoted_printable_encode(character)
result = ""
character.each_byte { |b| result << "=%02x" % b }
result
end
# A quick-and-dirty regexp for determining whether a string contains any
# characters that need escaping.
if !defined?(CHARS_NEEDING_QUOTING)
CHARS_NEEDING_QUOTING = /[\000-\011\013\014\016-\037\177-\377]/
end
# Quote the given text if it contains any "illegal" characters
def quote_if_necessary(text, charset)
(text =~ CHARS_NEEDING_QUOTING) ?
quoted_printable(text, charset) :
text
end
# Quote any of the given strings if they contain any "illegal" characters
def quote_any_if_necessary(charset, *args)
args.map { |v| quote_if_necessary(v, charset) }
end
# Quote the given address if it needs to be. The address may be a
# 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.
def quote_address_if_necessary(address, charset)
if Array === address
address.map { |a| quote_address_if_necessary(a, charset) }
elsif address =~ /^(\S.*)\s+(<.*>)$/
address = $2
phrase = quote_if_necessary($1.gsub(/^['"](.*)['"]$/, '\1'), charset)
"\"#{phrase}\" #{address}"
else
address
end
end
# Quote any of the given addresses, if they need to be.
def quote_any_address_if_necessary(charset, *args)
args.map { |v| quote_address_if_necessary(v, charset) }
end
end
end

View File

@@ -1,44 +0,0 @@
require "action_mailer"
require "rails"
require "abstract_controller/railties/routes_helpers"
module ActionMailer
class Railtie < Rails::Railtie
config.action_mailer = ActiveSupport::OrderedOptions.new
initializer "action_mailer.logger" do
ActiveSupport.on_load(:action_mailer) { self.logger ||= Rails.logger }
end
initializer "action_mailer.set_configs" do |app|
paths = app.config.paths
options = app.config.action_mailer
options.assets_dir ||= paths["public"].first
options.javascripts_dir ||= paths["public/javascripts"].first
options.stylesheets_dir ||= paths["public/stylesheets"].first
# make sure readers methods get compiled
options.asset_path ||= app.config.asset_path
options.asset_host ||= app.config.asset_host
options.relative_url_root ||= app.config.relative_url_root
ActiveSupport.on_load(:action_mailer) do
include AbstractController::UrlFor
extend ::AbstractController::Railties::RoutesHelpers.with(app.routes)
include app.routes.mounted_helpers
register_interceptors(options.delete(:interceptors))
register_observers(options.delete(:observers))
options.each { |k,v| send("#{k}=", v) }
end
end
initializer "action_mailer.compile_config_methods" do
ActiveSupport.on_load(:action_mailer) do
config.compile_methods! if config.respond_to?(:compile_methods!)
end
end
end
end

View File

@@ -1,82 +0,0 @@
require 'active_support/core_ext/class/attribute'
module ActionMailer
class NonInferrableMailerError < ::StandardError
def initialize(name)
super "Unable to determine the mailer to test from #{name}. " +
"You'll need to specify it using tests YourMailer in your " +
"test case definition"
end
end
class TestCase < ActiveSupport::TestCase
module Behavior
extend ActiveSupport::Concern
include TestHelper
included do
class_attribute :_mailer_class
setup :initialize_test_deliveries
setup :set_expected_mail
end
module ClassMethods
def tests(mailer)
case mailer
when String, Symbol
self._mailer_class = mailer.to_s.camelize.constantize
when Module
self._mailer_class = mailer
else
raise NonInferrableMailerError.new(mailer)
end
end
def mailer_class
if mailer = self._mailer_class
mailer
else
tests determine_default_mailer(name)
end
end
def determine_default_mailer(name)
name.sub(/Test$/, '').constantize
rescue NameError
raise NonInferrableMailerError.new(name)
end
end
protected
def initialize_test_deliveries
ActionMailer::Base.delivery_method = :test
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.deliveries.clear
end
def set_expected_mail
@expected = Mail.new
@expected.content_type ["text", "plain", { "charset" => charset }]
@expected.mime_version = '1.0'
end
private
def charset
"UTF-8"
end
def encode(subject)
Mail::Encodings.q_value_encode(subject, charset)
end
def read_fixture(action)
IO.readlines(File.join(Rails.root, 'test', 'fixtures', self.class.mailer_class.name.underscore, action))
end
end
include Behavior
end
end

View File

@@ -1,61 +0,0 @@
module ActionMailer
module TestHelper
extend ActiveSupport::Concern
# Asserts that the number of emails sent matches the given number.
#
# def test_emails
# assert_emails 0
# ContactMailer.deliver_contact
# assert_emails 1
# ContactMailer.deliver_contact
# assert_emails 2
# end
#
# If a block is passed, that block should cause the specified number of emails to be sent.
#
# def test_emails_again
# assert_emails 1 do
# ContactMailer.deliver_contact
# end
#
# assert_emails 2 do
# ContactMailer.deliver_contact
# ContactMailer.deliver_contact
# end
# end
def assert_emails(number)
if block_given?
original_count = ActionMailer::Base.deliveries.size
yield
new_count = ActionMailer::Base.deliveries.size
assert_equal original_count + number, new_count, "#{number} emails expected, but #{new_count - original_count} were sent"
else
assert_equal number, ActionMailer::Base.deliveries.size
end
end
# Assert that no emails have been sent.
#
# def test_emails
# assert_no_emails
# ContactMailer.deliver_contact
# assert_emails 1
# end
#
# If a block is passed, that block should not cause any emails to be sent.
#
# def test_emails_again
# assert_no_emails do
# # No emails should be sent from this block
# end
# end
#
# Note: This assertion is simply a shortcut for:
#
# assert_emails 0
def assert_no_emails(&block)
assert_emails 0, &block
end
end
end

View File

@@ -0,0 +1,8 @@
module ActionMailer
module Utils #:nodoc:
def normalize_new_lines(text)
text.to_s.gsub(/\r\n?/, "\n")
end
module_function :normalize_new_lines
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
require 'tmail/info'
require 'tmail/mail'
require 'tmail/mailbox'

View File

@@ -0,0 +1,242 @@
#
# address.rb
#
#--
# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
#
# 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
include TextUtils
def Address.parse( str )
Parser.parse :ADDRESS, str
end
def address_group?
false
end
def initialize( local, domain )
if domain
domain.each do |s|
raise SyntaxError, 'empty word in domain' if s.empty?
end
end
@local = local
@domain = domain
@name = nil
@routes = []
end
attr_reader :name
def name=( str )
@name = str
@name = nil if str and str.empty?
end
alias phrase name
alias phrase= name=
attr_reader :routes
def inspect
"#<#{self.class} #{address()}>"
end
def local
return nil unless @local
return '""' if @local.size == 1 and @local[0].empty?
@local.map {|i| quote_atom(i) }.join('.')
end
def domain
return nil unless @domain
join_domain(@domain)
end
def spec
s = self.local
d = self.domain
if s and d
s + '@' + d
else
s
end
end
alias address spec
def ==( other )
other.respond_to? :spec and self.spec == other.spec
end
alias eql? ==
def hash
@local.hash ^ @domain.hash
end
def dup
obj = self.class.new(@local.dup, @domain.dup)
obj.name = @name.dup if @name
obj.routes.replace @routes
obj
end
include StrategyInterface
def accept( strategy, dummy1 = nil, dummy2 = nil )
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

View File

@@ -0,0 +1,39 @@
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['content-disposition'] && part['content-disposition'].disposition == "attachment") ||
part.header['content-type'].main_type != "text"
end
def attachments
if multipart?
parts.collect { |part|
if 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
}.compact
end
end
end
end

View File

@@ -0,0 +1,71 @@
#
# base64.rb
#
#--
# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
#
# 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.
#++
module TMail
module Base64
module_function
def rb_folding_encode( str, eol = "\n", limit = 60 )
[str].pack('m')
end
def rb_encode( str )
[str].pack('m').tr( "\r\n", '' )
end
def rb_decode( str, strict = false )
str.unpack('m')
end
begin
require 'tmail/base64.so'
alias folding_encode c_folding_encode
alias encode c_encode
alias decode c_decode
class << self
alias folding_encode c_folding_encode
alias encode c_encode
alias decode c_decode
end
rescue LoadError
alias folding_encode rb_folding_encode
alias encode rb_encode
alias decode rb_decode
class << self
alias folding_encode rb_folding_encode
alias encode rb_encode
alias decode rb_decode
end
end
end
end

View File

@@ -0,0 +1,69 @@
#
# config.rb
#
#--
# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
#
# 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.
#++
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

View File

@@ -0,0 +1,467 @@
#
# encode.rb
#
#--
# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
#
# 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 'nkf'
require 'tmail/base64.rb'
require 'tmail/stringio'
require 'tmail/utils'
module TMail
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
def encoded( eol = "\r\n", charset = 'j', dest = nil )
accept_strategy Encoder, eol, charset, dest
end
def decoded( eol = "\n", charset = 'e', dest = nil )
accept_strategy Decoder, eol, charset, dest
end
alias to_s decoded
def accept_strategy( klass, eol, charset, dest = nil )
dest ||= ''
accept klass.new(create_dest(dest), charset, eol)
dest
end
end
###
### 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[$KCODE] || 'j')
opt = '-m' + 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 )
@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 = 70
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[$KCODE]
@eol = eol
reset
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 : <<A character string not to be encoded>>
# J : <<A character string to be encoded>>
# S : <<LWSP>>
#
# 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 )
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
@lwsp = lwsp
end
def flush
# puts '---- flush ----'
# puts "spc >>>#{@lwsp.inspect}<<<"
# puts "txt >>>#{@text.inspect}<<<"
@f << @lwsp << @text
@curlen += (@lwsp.size + @text.size)
@text = ''
@lwsp = ''
end
def fold
# puts '---- fold ----'
@f << @eol
@curlen = 0
@lwsp = SPACER
end
def restsize
MAX_LINE_LEN - (@curlen + @lwsp.size + @text.size)
end
end
end # module TMail

View File

@@ -0,0 +1,552 @@
#
# facade.rb
#
#--
# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
#
# 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/utils'
module TMail
class Mail
def header_string( name, default = nil )
h = @header[name.downcase] or return default
h.to_s
end
###
### 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
#
# date time
#
def date( default = nil )
if h = @header['date']
h.date
else
default
end
end
def date=( time )
if time
store 'Date', time2str(time)
else
@header.delete 'date'
end
time
end
def strftime( fmt, default = nil )
if t = date
t.strftime(fmt)
else
default
end
end
#
# destination
#
def to_addrs( default = nil )
if h = @header['to']
h.addrs
else
default
end
end
def cc_addrs( default = nil )
if h = @header['cc']
h.addrs
else
default
end
end
def bcc_addrs( default = nil )
if h = @header['bcc']
h.addrs
else
default
end
end
def to_addrs=( arg )
set_addrfield 'to', arg
end
def cc_addrs=( arg )
set_addrfield 'cc', arg
end
def bcc_addrs=( arg )
set_addrfield 'bcc', arg
end
def to( default = nil )
addrs2specs(to_addrs(nil)) || default
end
def cc( default = nil )
addrs2specs(cc_addrs(nil)) || default
end
def bcc( default = nil )
addrs2specs(bcc_addrs(nil)) || default
end
def to=( *strs )
set_string_array_attr 'To', strs
end
def cc=( *strs )
set_string_array_attr 'Cc', strs
end
def bcc=( *strs )
set_string_array_attr 'Bcc', strs
end
#
# originator
#
def from_addrs( default = nil )
if h = @header['from']
h.addrs
else
default
end
end
def from_addrs=( arg )
set_addrfield 'from', arg
end
def from( default = nil )
addrs2specs(from_addrs(nil)) || default
end
def from=( *strs )
set_string_array_attr 'From', strs
end
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
def reply_to_addrs( default = nil )
if h = @header['reply-to']
h.addrs
else
default
end
end
def reply_to_addrs=( arg )
set_addrfield 'reply-to', arg
end
def reply_to( default = nil )
addrs2specs(reply_to_addrs(nil)) || default
end
def reply_to=( *strs )
set_string_array_attr 'Reply-To', strs
end
def sender_addr( default = nil )
f = @header['sender'] or return default
f.addr or return default
end
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
def sender( default )
f = @header['sender'] or return default
a = f.addr or return default
a.spec
end
def sender=( str )
set_string_attr 'Sender', str
end
#
# subject
#
def subject( default = nil )
if h = @header['subject']
h.body
else
default
end
end
alias quoted_subject subject
def subject=( str )
set_string_attr 'Subject', str
end
#
# identity & threading
#
def message_id( default = nil )
if h = @header['message-id']
h.id || default
else
default
end
end
def message_id=( str )
set_string_attr 'Message-Id', str
end
def in_reply_to( default = nil )
if h = @header['in-reply-to']
h.ids
else
default
end
end
def in_reply_to=( *idstrs )
set_string_array_attr 'In-Reply-To', idstrs
end
def references( default = nil )
if h = @header['references']
h.refs
else
default
end
end
def references=( *strs )
set_string_array_attr 'References', strs
end
#
# MIME headers
#
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
def content_type( default = nil )
if h = @header['content-type']
h.content_type || default
else
default
end
end
def main_type( default = nil )
if h = @header['content-type']
h.main_type || default
else
default
end
end
def sub_type( default = nil )
if h = @header['content-type']
h.sub_type || default
else
default
end
end
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
def type_param( name, default = nil )
if h = @header['content-type']
h[name] || default
else
default
end
end
def charset( default = nil )
if h = @header['content-type']
h['charset'] or default
else
default
end
end
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
def transfer_encoding( default = nil )
if h = @header['content-transfer-encoding']
h.encoding || default
else
default
end
end
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=
def disposition( default = nil )
if h = @header['content-disposition']
h.disposition || default
else
default
end
end
alias content_disposition disposition
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
def disposition_param( name, default = nil )
if h = @header['content-disposition']
h[name] || default
else
default
end
end
###
### utils
###
def create_reply
mail = TMail::Mail.parse('')
mail.subject = 'Re: ' + subject('').sub(/\A(?:\[[^\]]+\])?(?:\s*Re:)*\s*/i, '')
mail.to_addrs = reply_addresses([])
mail.in_reply_to = [message_id(nil)].compact
mail.references = references([]) + [message_id(nil)].compact
mail.mime_version = '1.0'
mail
end
def base64_encode
store 'Content-Transfer-Encoding', 'Base64'
self.body = Base64.folding_encode(self.body)
end
def base64_decode
if /base64/i === self.transfer_encoding('')
store 'Content-Transfer-Encoding', '8bit'
self.body = Base64.decode(self.body, @config.strict_base64decode?)
end
end
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
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
def reply_addresses( default = nil )
reply_to_addrs(nil) or from_addrs(nil) or default
end
def error_reply_addresses( default = nil )
if s = sender(nil)
[s]
else
from_addrs(default)
end
end
def multipart?
main_type('').downcase == 'multipart'
end
end # class Mail
end # module TMail

View File

@@ -0,0 +1,914 @@
#
# header.rb
#
#--
# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
#
# 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'
module TMail
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
def new_from_port( port, name, conf = DEFAULT_CONFIG )
re = Regep.new('\A(' + Regexp.quote(name) + '):', 'i')
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))
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, dummy1 = nil, dummy2 = nil )
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
@comments
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
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
@params
end
def []( key )
ensure_parsed
@params and @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
@params
end
def []( key )
ensure_parsed
@params and @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, 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

View File

@@ -0,0 +1,35 @@
#
# info.rb
#
#--
# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
#
# 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.
#++
module TMail
Version = '0.10.7'
Copyright = 'Copyright (c) 1998-2002 Minero Aoki'
end

View File

@@ -0,0 +1 @@
require 'tmail/mailbox'

View File

@@ -0,0 +1,447 @@
#
# mail.rb
#
#--
# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
#
# 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/facade'
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
class Mail
class << self
def load( fname )
new(FilePort.new(fname))
end
alias load_from load
alias loadfrom load
def parse( str )
new(StringPort.new(str))
end
end
def initialize( port = nil, conf = DEFAULT_CONFIG )
@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
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', %<multipart/mixed; boundary="#{bound}">
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
def []( key )
@header[key.downcase]
end
def sub_header(key, param)
(hdr = self[key]) ? hdr[param] : nil
end
alias fetch []
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 []=
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
parse_body
@body_port.ropen {|f|
return f.read
}
end
def body=( str )
parse_body
@body_port.wopen {|f| f.write str }
str
end
alias preamble body
alias preamble= 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
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

View File

@@ -0,0 +1,433 @@
#
# mailbox.rb
#
#--
# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
#
# 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
def UNIXMbox.lock( fname )
begin
f = File.open(fname)
f.flock File::LOCK_EX
yield f
ensure
f.flock File::LOCK_UN
f.close if f and not f.closed?
end
end
class << self
alias newobj new
end
def UNIXMbox.new( fname, tmpdir = nil, readonly = false )
tmpdir = ENV['TEMP'] || ENV['TMP'] || '/tmp'
newobj(fname, "#{tmpdir}/ruby_tmail_#{$$}_#{rand()}", readonly, false)
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
h = HeaderField.new_from_port(port, 'Return-Path') ||
HeaderField.new_from_port(port, 'From') or return 'nobody'
a = h.addrs[0] or return 'nobody'
a.spec
end
private_class_method :fromaddr
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

View File

@@ -0,0 +1 @@
require 'tmail/mailbox'

View File

@@ -0,0 +1,280 @@
#
# net.rb
#
#--
# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
#
# 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 'nkf'
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
def create_empty_mail
self.class.new(StringPort.new(''), @config)
end
def create_reply
setup_reply create_empty_mail()
end
def setup_reply( m )
if tmp = reply_addresses(nil)
m.to_addrs = tmp
end
mid = message_id(nil)
tmp = references(nil) || []
tmp.push mid if mid
m.in_reply_to = [mid] if mid
m.references = tmp unless tmp.empty?
m.subject = 'Re: ' + subject('').sub(/\A(?:\s*re:)+/i, '')
m
end
def create_forward
setup_forward create_empty_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
end
end
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
class AddMessageId
def initialize( fqdn = nil )
@fqdn = fqdn
end
attr :fqdn, true
def exec( mail )
mail.message_id = ::TMail::new_msgid(@fqdn)
end
end
class AddDate
def exec( mail )
mail.date = Time.now
end
end
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
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
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
end # module TMail

View File

@@ -0,0 +1,135 @@
#
# obsolete.rb
#
#--
# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
#
# 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.
#++
module TMail
# mail.rb
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
# facade.rb
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
# address.rb
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
# mbox.rb
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
# utils.rb
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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,377 @@
#
# port.rb
#
#--
# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
#
# 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

View File

@@ -0,0 +1,131 @@
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"
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).first, 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
if __FILE__ == $0
require 'test/unit'
class TC_Unquoter < Test::Unit::TestCase
def test_unquote_quoted_printable
a ="=?ISO-8859-1?Q?[166417]_Bekr=E6ftelse_fra_Rejsefeber?="
b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8')
assert_equal "[166417] Bekr\303\246ftelse fra Rejsefeber", b
end
def test_unquote_base64
a ="=?ISO-8859-1?B?WzE2NjQxN10gQmVrcuZmdGVsc2UgZnJhIFJlanNlZmViZXI=?="
b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8')
assert_equal "[166417] Bekr\303\246ftelse fra Rejsefeber", b
end
def test_unquote_without_charset
a ="[166417]_Bekr=E6ftelse_fra_Rejsefeber"
b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8')
assert_equal "[166417]_Bekr=E6ftelse_fra_Rejsefeber", b
end
end
end

View File

@@ -0,0 +1,41 @@
#
# scanner.rb
#
#--
# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
#
# 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/utils'
module TMail
require 'tmail/scanner_r.rb'
begin
raise LoadError, 'Turn off Ruby extention by user choice' if ENV['NORUBYEXT']
require 'tmail/scanner_c.so'
Scanner = Scanner_C
rescue LoadError
Scanner = Scanner_R
end
end

View File

@@ -0,0 +1,263 @@
#
# scanner_r.rb
#
#--
# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
#
# 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/config'
module TMail
class Scanner_R
Version = '0.10.7'
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[$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

View File

@@ -0,0 +1,277 @@
#
# stringio.rb
#
#--
# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
#
# 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'},#{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

View File

@@ -0,0 +1 @@
require 'tmail'

View File

@@ -0,0 +1,238 @@
#
# utils.rb
#
#--
# Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
#
# 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.
#++
module TMail
class SyntaxError < StandardError; end
def TMail.new_boundary
'mimepart_' + random_tag
end
def TMail.new_message_id( fqdn = nil )
fqdn ||= ::Socket.gethostname
"<#{random_tag()}@#{fqdn}.tmail>"
end
def TMail.random_tag
@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
module TextUtils
aspecial = '()<>[]:;.\\,"'
tspecial = '()<>[];:\\,"/?='
lwsp = " \t\r\n"
control = '\x00-\x1f\x7f-\xff'
ATOM_UNSAFE = /[#{Regexp.quote aspecial}#{control}#{lwsp}]/n
PHRASE_UNSAFE = /[#{Regexp.quote aspecial}#{control}]/n
TOKEN_UNSAFE = /[#{Regexp.quote tspecial}#{control}#{lwsp}]/n
CONTROL_CHAR = /[#{control}]/n
def atom_safe?( str )
not ATOM_UNSAFE === str
end
def quote_atom( str )
(ATOM_UNSAFE === str) ? dquote(str) : str
end
def quote_phrase( str )
(PHRASE_UNSAFE === str) ? dquote(str) : str
end
def token_safe?( str )
not TOKEN_UNSAFE === str
end
def quote_token( str )
(TOKEN_UNSAFE === str) ? dquote(str) : str
end
def dquote( str )
'"' + str.gsub(/["\\]/n) {|s| '\\' + s } + '"'
end
private :dquote
def join_domain( arr )
arr.map {|i|
if /\A\[.*\]\z/ === i
i
else
quote_atom(i)
end
}.join('.')
end
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
}
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
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[$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
NKF.nkf(NKF_FLAGS[$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
end
end

View File

@@ -1,10 +1,9 @@
module ActionMailer
module VERSION #:nodoc:
MAJOR = 3
MINOR = 2
TINY = 19
PRE = nil
MAJOR = 1
MINOR = 3
TINY = 4
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
STRING = [MAJOR, MINOR, TINY].join('.')
end
end

View File

@@ -1,18 +0,0 @@
Description:
============
Stubs out a new mailer and its views. Pass the mailer name, either
CamelCased or under_scored, and an optional list of emails as arguments.
This generates a mailer class in app/mailers and invokes your template
engine and test framework generators.
Example:
========
rails generate mailer Notifications signup forgot_password invoice
creates a Notifications mailer class, views, test, and fixtures:
Mailer: app/mailers/notifications.rb
Views: app/views/notifications/signup.erb [...]
Test: test/functional/notifications_test.rb
Fixtures: test/fixtures/notifications/signup [...]

View File

@@ -1,16 +0,0 @@
module Rails
module Generators
class MailerGenerator < NamedBase
source_root File.expand_path("../templates", __FILE__)
argument :actions, :type => :array, :default => [], :banner => "method method"
check_class_collision
def create_mailer_file
template "mailer.rb", File.join('app/mailers', class_path, "#{file_name}.rb")
end
hook_for :template_engine, :test_framework
end
end
end

View File

@@ -1,18 +0,0 @@
<% module_namespacing do -%>
class <%= class_name %> < ActionMailer::Base
default <%= key_value :from, '"from@example.com"' %>
<% actions.each do |action| -%>
# Subject can be set in your I18n file at config/locales/en.yml
# with the following lookup:
#
# en.<%= file_path.gsub("/",".") %>.<%= action %>.subject
#
def <%= action %>
@greeting = "Hi"
mail <%= key_value :to, '"to@example.org"' %>
end
<% end -%>
end
<% end -%>

View File

@@ -1,49 +1,13 @@
# Pathname has a warning, so require it first while silencing
# warnings to shut it up.
#
# Also, in 1.9, Bundler creates warnings due to overriding
# Rubygems methods
begin
old, $VERBOSE = $VERBOSE, nil
require 'pathname'
require File.expand_path('../../../load_paths', __FILE__)
ensure
$VERBOSE = old
end
require 'active_support/core_ext/kernel/reporting'
require 'active_support/core_ext/string/encoding'
if "ruby".encoding_aware?
# These are the normal settings that will be set up by Railties
# TODO: Have these tests support other combinations of these values
silence_warnings do
Encoding.default_internal = "UTF-8"
Encoding.default_external = "UTF-8"
end
end
lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
require 'test/unit'
require 'action_mailer'
require 'action_mailer/test_case'
silence_warnings do
# These external dependencies have warnings :/
require 'mail'
end
$:.unshift "#{File.dirname(__FILE__)}/../lib"
require 'action_mailer'
# Show backtraces for deprecated behavior for quicker cleanup.
ActiveSupport::Deprecation.debug = true
# Bogus template processors
ActionView::Template.register_template_handler :haml, lambda { |template| "Look its HAML!".inspect }
ActionView::Template.register_template_handler :bak, lambda { |template| "Lame backup".inspect }
FIXTURE_LOAD_PATH = File.expand_path('fixtures', File.dirname(__FILE__))
ActionMailer::Base.view_paths = FIXTURE_LOAD_PATH
$:.unshift "#{File.dirname(__FILE__)}/fixtures/helpers"
ActionMailer::Base.template_root = "#{File.dirname(__FILE__)}/fixtures"
class MockSMTP
def self.deliveries
@@ -57,25 +21,10 @@ class MockSMTP
def sendmail(mail, from, to)
@@deliveries << [mail, from, to]
end
def start(*args)
yield self
end
end
class Net::SMTP
def self.new(*args)
MockSMTP.new
def self.start(*args)
yield MockSMTP.new
end
end
def set_delivery_method(method)
@old_delivery_method = ActionMailer::Base.delivery_method
ActionMailer::Base.delivery_method = method
end
def restore_delivery_method
ActionMailer::Base.delivery_method = @old_delivery_method
end
ActiveSupport::Deprecation.silenced = true

View File

@@ -1,56 +0,0 @@
require 'abstract_unit'
require 'action_controller'
class AssetHostMailer < ActionMailer::Base
def email_with_asset
mail :to => 'test@localhost',
:subject => 'testing email containing asset path while asset_host is set',
:from => 'tester@example.com'
end
end
class AssetHostTest < Test::Unit::TestCase
def setup
set_delivery_method :test
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.deliveries.clear
AssetHostMailer.configure do |c|
c.asset_host = "http://www.example.com"
c.assets_dir = ''
end
end
def teardown
restore_delivery_method
end
def test_asset_host_as_string
mail = AssetHostMailer.email_with_asset
assert_equal %Q{<img alt="Somelogo" src="http://www.example.com/images/somelogo.png" />}, mail.body.to_s.strip
end
def test_asset_host_as_one_argument_proc
AssetHostMailer.config.asset_host = Proc.new { |source|
if source.starts_with?('/images')
"http://images.example.com"
else
"http://assets.example.com"
end
}
mail = AssetHostMailer.email_with_asset
assert_equal %Q{<img alt="Somelogo" src="http://images.example.com/images/somelogo.png" />}, mail.body.to_s.strip
end
def test_asset_host_as_two_argument_proc
ActionController::Base.config.asset_host = Proc.new {|source,request|
if request && request.ssl?
"https://www.example.com"
else
"http://www.example.com"
end
}
mail = nil
assert_nothing_raised { mail = AssetHostMailer.email_with_asset }
assert_equal %Q{<img alt="Somelogo" src="http://www.example.com/images/somelogo.png" />}, mail.body.to_s.strip
end
end

View File

@@ -1,614 +0,0 @@
# encoding: utf-8
require 'abstract_unit'
require 'active_support/time'
require 'mailers/base_mailer'
require 'mailers/proc_mailer'
require 'mailers/asset_mailer'
class BaseTest < ActiveSupport::TestCase
def teardown
ActionMailer::Base.asset_host = nil
ActionMailer::Base.assets_dir = nil
end
test "method call to mail does not raise error" do
assert_nothing_raised { BaseMailer.welcome }
end
# Basic mail usage without block
test "mail() should set the headers of the mail message" do
email = BaseMailer.welcome
assert_equal(['system@test.lindsaar.net'], email.to)
assert_equal(['jose@test.plataformatec.com'], email.from)
assert_equal('The first email on new API!', email.subject)
end
test "mail() with from overwrites the class level default" do
email = BaseMailer.welcome(:from => 'someone@example.com',
:to => 'another@example.org')
assert_equal(['someone@example.com'], email.from)
assert_equal(['another@example.org'], email.to)
end
test "mail() with bcc, cc, content_type, charset, mime_version, reply_to and date" do
time = Time.now.beginning_of_day.to_datetime
email = BaseMailer.welcome(:bcc => 'bcc@test.lindsaar.net',
:cc => 'cc@test.lindsaar.net',
:content_type => 'multipart/mixed',
:charset => 'iso-8559-1',
:mime_version => '2.0',
:reply_to => 'reply-to@test.lindsaar.net',
:date => time)
assert_equal(['bcc@test.lindsaar.net'], email.bcc)
assert_equal(['cc@test.lindsaar.net'], email.cc)
assert_equal('multipart/mixed; charset=iso-8559-1', email.content_type)
assert_equal('iso-8559-1', email.charset)
assert_equal('2.0', email.mime_version)
assert_equal(['reply-to@test.lindsaar.net'], email.reply_to)
assert_equal(time, email.date)
end
test "mail() renders the template using the method being processed" do
email = BaseMailer.welcome
assert_equal("Welcome", email.body.encoded)
end
test "can pass in :body to the mail method hash" do
email = BaseMailer.welcome(:body => "Hello there")
assert_equal("text/plain", email.mime_type)
assert_equal("Hello there", email.body.encoded)
end
test "should set template content type if mail has only one part" do
mail = BaseMailer.html_only
assert_equal('text/html', mail.mime_type)
mail = BaseMailer.plain_text_only
assert_equal('text/plain', mail.mime_type)
end
# Custom headers
test "custom headers" do
email = BaseMailer.welcome
assert_equal("Not SPAM", email['X-SPAM'].decoded)
end
test "can pass random headers in as a hash to mail" do
hash = {'X-Special-Domain-Specific-Header' => "SecretValue",
'In-Reply-To' => '1234@mikel.me.com' }
mail = BaseMailer.welcome(hash)
assert_equal('SecretValue', mail['X-Special-Domain-Specific-Header'].decoded)
assert_equal('1234@mikel.me.com', mail['In-Reply-To'].decoded)
end
test "can pass random headers in as a hash to headers" do
hash = {'X-Special-Domain-Specific-Header' => "SecretValue",
'In-Reply-To' => '1234@mikel.me.com' }
mail = BaseMailer.welcome_with_headers(hash)
assert_equal('SecretValue', mail['X-Special-Domain-Specific-Header'].decoded)
assert_equal('1234@mikel.me.com', mail['In-Reply-To'].decoded)
end
# Attachments
test "attachment with content" do
email = BaseMailer.attachment_with_content
assert_equal(1, email.attachments.length)
assert_equal('invoice.pdf', email.attachments[0].filename)
assert_equal('This is test File content', email.attachments['invoice.pdf'].decoded)
end
test "attachment gets content type from filename" do
email = BaseMailer.attachment_with_content
assert_equal('invoice.pdf', email.attachments[0].filename)
end
test "attachment with hash" do
email = BaseMailer.attachment_with_hash
assert_equal(1, email.attachments.length)
assert_equal('invoice.jpg', email.attachments[0].filename)
expected = "\312\213\254\232)b"
expected.force_encoding(Encoding::BINARY) if '1.9'.respond_to?(:force_encoding)
assert_equal expected, email.attachments['invoice.jpg'].decoded
end
test "attachment with hash using default mail encoding" do
email = BaseMailer.attachment_with_hash_default_encoding
assert_equal(1, email.attachments.length)
assert_equal('invoice.jpg', email.attachments[0].filename)
expected = "\312\213\254\232)b"
expected.force_encoding(Encoding::BINARY) if '1.9'.respond_to?(:force_encoding)
assert_equal expected, email.attachments['invoice.jpg'].decoded
end
test "sets mime type to multipart/mixed when attachment is included" do
email = BaseMailer.attachment_with_content
assert_equal(1, email.attachments.length)
assert_equal("multipart/mixed", email.mime_type)
end
test "adds the rendered template as part" do
email = BaseMailer.attachment_with_content
assert_equal(2, email.parts.length)
assert_equal("multipart/mixed", email.mime_type)
assert_equal("text/html", email.parts[0].mime_type)
assert_equal("Attachment with content", email.parts[0].body.encoded)
assert_equal("application/pdf", email.parts[1].mime_type)
assert_equal("VGhpcyBpcyB0ZXN0IEZpbGUgY29udGVudA==\r\n", email.parts[1].body.encoded)
end
test "adds the given :body as part" do
email = BaseMailer.attachment_with_content(:body => "I'm the eggman")
assert_equal(2, email.parts.length)
assert_equal("multipart/mixed", email.mime_type)
assert_equal("text/plain", email.parts[0].mime_type)
assert_equal("I'm the eggman", email.parts[0].body.encoded)
assert_equal("application/pdf", email.parts[1].mime_type)
assert_equal("VGhpcyBpcyB0ZXN0IEZpbGUgY29udGVudA==\r\n", email.parts[1].body.encoded)
end
test "can embed an inline attachment" do
email = BaseMailer.inline_attachment
# Need to call #encoded to force the JIT sort on parts
email.encoded
assert_equal(2, email.parts.length)
assert_equal("multipart/related", email.mime_type)
assert_equal("multipart/alternative", email.parts[0].mime_type)
assert_equal("text/plain", email.parts[0].parts[0].mime_type)
assert_equal("text/html", email.parts[0].parts[1].mime_type)
assert_equal("logo.png", email.parts[1].filename)
end
# Defaults values
test "uses default charset from class" do
with_default BaseMailer, :charset => "US-ASCII" do
email = BaseMailer.welcome
assert_equal("US-ASCII", email.charset)
email = BaseMailer.welcome(:charset => "iso-8559-1")
assert_equal("iso-8559-1", email.charset)
end
end
test "uses default content type from class" do
with_default BaseMailer, :content_type => "text/html" do
email = BaseMailer.welcome
assert_equal("text/html", email.mime_type)
email = BaseMailer.welcome(:content_type => "text/plain")
assert_equal("text/plain", email.mime_type)
end
end
test "uses default mime version from class" do
with_default BaseMailer, :mime_version => "2.0" do
email = BaseMailer.welcome
assert_equal("2.0", email.mime_version)
email = BaseMailer.welcome(:mime_version => "1.0")
assert_equal("1.0", email.mime_version)
end
end
test "uses random default headers from class" do
with_default BaseMailer, "X-Custom" => "Custom" do
email = BaseMailer.welcome
assert_equal("Custom", email["X-Custom"].decoded)
end
end
test "subject gets default from I18n" do
BaseMailer.default :subject => nil
email = BaseMailer.welcome(:subject => nil)
assert_equal "Welcome", email.subject
I18n.backend.store_translations('en', :base_mailer => {:welcome => {:subject => "New Subject!"}})
email = BaseMailer.welcome(:subject => nil)
assert_equal "New Subject!", email.subject
end
test "translations are scoped properly" do
I18n.backend.store_translations('en', :base_mailer => {:email_with_translations => {:greet_user => "Hello %{name}!"}})
email = BaseMailer.email_with_translations
assert_equal 'Hello lifo!', email.body.encoded
end
# Implicit multipart
test "implicit multipart" do
email = BaseMailer.implicit_multipart
assert_equal(2, email.parts.size)
assert_equal("multipart/alternative", email.mime_type)
assert_equal("text/plain", email.parts[0].mime_type)
assert_equal("TEXT Implicit Multipart", email.parts[0].body.encoded)
assert_equal("text/html", email.parts[1].mime_type)
assert_equal("HTML Implicit Multipart", email.parts[1].body.encoded)
end
test "implicit multipart with sort order" do
order = ["text/html", "text/plain"]
with_default BaseMailer, :parts_order => order do
email = BaseMailer.implicit_multipart
assert_equal("text/html", email.parts[0].mime_type)
assert_equal("text/plain", email.parts[1].mime_type)
email = BaseMailer.implicit_multipart(:parts_order => order.reverse)
assert_equal("text/plain", email.parts[0].mime_type)
assert_equal("text/html", email.parts[1].mime_type)
end
end
test "implicit multipart with attachments creates nested parts" do
email = BaseMailer.implicit_multipart(:attachments => true)
assert_equal("application/pdf", email.parts[0].mime_type)
assert_equal("multipart/alternative", email.parts[1].mime_type)
assert_equal("text/plain", email.parts[1].parts[0].mime_type)
assert_equal("TEXT Implicit Multipart", email.parts[1].parts[0].body.encoded)
assert_equal("text/html", email.parts[1].parts[1].mime_type)
assert_equal("HTML Implicit Multipart", email.parts[1].parts[1].body.encoded)
end
test "implicit multipart with attachments and sort order" do
order = ["text/html", "text/plain"]
with_default BaseMailer, :parts_order => order do
email = BaseMailer.implicit_multipart(:attachments => true)
assert_equal("application/pdf", email.parts[0].mime_type)
assert_equal("multipart/alternative", email.parts[1].mime_type)
assert_equal("text/plain", email.parts[1].parts[1].mime_type)
assert_equal("text/html", email.parts[1].parts[0].mime_type)
end
end
test "implicit multipart with default locale" do
email = BaseMailer.implicit_with_locale
assert_equal(2, email.parts.size)
assert_equal("multipart/alternative", email.mime_type)
assert_equal("text/plain", email.parts[0].mime_type)
assert_equal("Implicit with locale TEXT", email.parts[0].body.encoded)
assert_equal("text/html", email.parts[1].mime_type)
assert_equal("Implicit with locale EN HTML", email.parts[1].body.encoded)
end
test "implicit multipart with other locale" do
swap I18n, :locale => :pl do
email = BaseMailer.implicit_with_locale
assert_equal(2, email.parts.size)
assert_equal("multipart/alternative", email.mime_type)
assert_equal("text/plain", email.parts[0].mime_type)
assert_equal("Implicit with locale PL TEXT", email.parts[0].body.encoded)
assert_equal("text/html", email.parts[1].mime_type)
assert_equal("Implicit with locale HTML", email.parts[1].body.encoded)
end
end
test "implicit multipart with several view paths uses the first one with template" do
old = BaseMailer.view_paths
begin
BaseMailer.view_paths = [File.join(FIXTURE_LOAD_PATH, "another.path")] + old.dup
email = BaseMailer.welcome
assert_equal("Welcome from another path", email.body.encoded)
ensure
BaseMailer.view_paths = old
end
end
test "implicit multipart with inexistent templates uses the next view path" do
old = BaseMailer.view_paths
begin
BaseMailer.view_paths = [File.join(FIXTURE_LOAD_PATH, "unknown")] + old.dup
email = BaseMailer.welcome
assert_equal("Welcome", email.body.encoded)
ensure
BaseMailer.view_paths = old
end
end
# Explicit multipart
test "explicit multipart" do
email = BaseMailer.explicit_multipart
assert_equal(2, email.parts.size)
assert_equal("multipart/alternative", email.mime_type)
assert_equal("text/plain", email.parts[0].mime_type)
assert_equal("TEXT Explicit Multipart", email.parts[0].body.encoded)
assert_equal("text/html", email.parts[1].mime_type)
assert_equal("HTML Explicit Multipart", email.parts[1].body.encoded)
end
test "explicit multipart have a boundary" do
mail = BaseMailer.explicit_multipart
assert_not_nil(mail.content_type_parameters[:boundary])
end
test "explicit multipart does not sort order" do
order = ["text/html", "text/plain"]
with_default BaseMailer, :parts_order => order do
email = BaseMailer.explicit_multipart
assert_equal("text/plain", email.parts[0].mime_type)
assert_equal("text/html", email.parts[1].mime_type)
email = BaseMailer.explicit_multipart(:parts_order => order.reverse)
assert_equal("text/plain", email.parts[0].mime_type)
assert_equal("text/html", email.parts[1].mime_type)
end
end
test "explicit multipart with attachments creates nested parts" do
email = BaseMailer.explicit_multipart(:attachments => true)
assert_equal("application/pdf", email.parts[0].mime_type)
assert_equal("multipart/alternative", email.parts[1].mime_type)
assert_equal("text/plain", email.parts[1].parts[0].mime_type)
assert_equal("TEXT Explicit Multipart", email.parts[1].parts[0].body.encoded)
assert_equal("text/html", email.parts[1].parts[1].mime_type)
assert_equal("HTML Explicit Multipart", email.parts[1].parts[1].body.encoded)
end
test "explicit multipart with templates" do
email = BaseMailer.explicit_multipart_templates
assert_equal(2, email.parts.size)
assert_equal("multipart/alternative", email.mime_type)
assert_equal("text/html", email.parts[0].mime_type)
assert_equal("HTML Explicit Multipart Templates", email.parts[0].body.encoded)
assert_equal("text/plain", email.parts[1].mime_type)
assert_equal("TEXT Explicit Multipart Templates", email.parts[1].body.encoded)
end
test "explicit multipart with format.any" do
email = BaseMailer.explicit_multipart_with_any
assert_equal(2, email.parts.size)
assert_equal("multipart/alternative", email.mime_type)
assert_equal("text/plain", email.parts[0].mime_type)
assert_equal("Format with any!", email.parts[0].body.encoded)
assert_equal("text/html", email.parts[1].mime_type)
assert_equal("Format with any!", email.parts[1].body.encoded)
end
test "explicit multipart with format(Hash)" do
email = BaseMailer.explicit_multipart_with_options(true)
email.ready_to_send!
assert_equal(2, email.parts.size)
assert_equal("multipart/alternative", email.mime_type)
assert_equal("text/plain", email.parts[0].mime_type)
assert_equal("base64", email.parts[0].content_transfer_encoding)
assert_equal("text/html", email.parts[1].mime_type)
assert_equal("7bit", email.parts[1].content_transfer_encoding)
end
test "explicit multipart with one part is rendered as body and options are merged" do
email = BaseMailer.explicit_multipart_with_options
assert_equal(0, email.parts.size)
assert_equal("text/plain", email.mime_type)
assert_equal("base64", email.content_transfer_encoding)
end
test "explicit multipart with one template has the expected format" do
email = BaseMailer.explicit_multipart_with_one_template
assert_equal(2, email.parts.size)
assert_equal("multipart/alternative", email.mime_type)
assert_equal("text/html", email.parts[0].mime_type)
assert_equal("[:html]", email.parts[0].body.encoded)
assert_equal("text/plain", email.parts[1].mime_type)
assert_equal("[:text]", email.parts[1].body.encoded)
end
# Class level API with method missing
test "should respond to action methods" do
assert_respond_to BaseMailer, :welcome
assert_respond_to BaseMailer, :implicit_multipart
assert !BaseMailer.respond_to?(:mail)
assert !BaseMailer.respond_to?(:headers)
end
test "calling just the action should return the generated mail object" do
BaseMailer.deliveries.clear
email = BaseMailer.welcome
assert_equal(0, BaseMailer.deliveries.length)
assert_equal('The first email on new API!', email.subject)
end
test "calling deliver on the action should deliver the mail object" do
BaseMailer.deliveries.clear
BaseMailer.expects(:deliver_mail).once
mail = BaseMailer.welcome.deliver
assert_instance_of Mail::Message, mail
end
test "calling deliver on the action should increment the deliveries collection if using the test mailer" do
BaseMailer.delivery_method = :test
BaseMailer.deliveries.clear
BaseMailer.welcome.deliver
assert_equal(1, BaseMailer.deliveries.length)
end
test "calling deliver, ActionMailer should yield back to mail to let it call :do_delivery on itself" do
mail = Mail::Message.new
mail.expects(:do_delivery).once
BaseMailer.expects(:welcome).returns(mail)
BaseMailer.welcome.deliver
end
# Rendering
test "you can specify a different template for implicit render" do
mail = BaseMailer.implicit_different_template('implicit_multipart').deliver
assert_equal("HTML Implicit Multipart", mail.html_part.body.decoded)
assert_equal("TEXT Implicit Multipart", mail.text_part.body.decoded)
end
test "you can specify a different template for explicit render" do
mail = BaseMailer.explicit_different_template('explicit_multipart_templates').deliver
assert_equal("HTML Explicit Multipart Templates", mail.html_part.body.decoded)
assert_equal("TEXT Explicit Multipart Templates", mail.text_part.body.decoded)
end
test "you can specify a different layout" do
mail = BaseMailer.different_layout('different_layout').deliver
assert_equal("HTML -- HTML", mail.html_part.body.decoded)
assert_equal("PLAIN -- PLAIN", mail.text_part.body.decoded)
end
test "you can specify the template path for implicit lookup" do
mail = BaseMailer.welcome_from_another_path('another.path/base_mailer').deliver
assert_equal("Welcome from another path", mail.body.encoded)
mail = BaseMailer.welcome_from_another_path(['unknown/invalid', 'another.path/base_mailer']).deliver
assert_equal("Welcome from another path", mail.body.encoded)
end
test "assets tags should use ActionMailer's asset_host settings" do
ActionMailer::Base.config.asset_host = "http://global.com"
ActionMailer::Base.config.assets_dir = "global/"
mail = AssetMailer.welcome
assert_equal(%{<img alt="Dummy" src="http://global.com/images/dummy.png" />}, mail.body.to_s.strip)
end
test "assets tags should use a Mailer's asset_host settings when available" do
ActionMailer::Base.config.asset_host = "global.com"
ActionMailer::Base.config.assets_dir = "global/"
AssetMailer.asset_host = "http://local.com"
mail = AssetMailer.welcome
assert_equal(%{<img alt="Dummy" src="http://local.com/images/dummy.png" />}, mail.body.to_s.strip)
end
test 'the view is not rendered when mail was never called' do
mail = BaseMailer.without_mail_call
assert_equal('', mail.body.to_s.strip)
mail.deliver
end
test 'the return value of mailer methods is not relevant' do
mail = BaseMailer.with_nil_as_return_value
assert_equal('Welcome', mail.body.to_s.strip)
mail.deliver
end
# Before and After hooks
class MyObserver
def self.delivered_email(mail)
end
end
class MySecondObserver
def self.delivered_email(mail)
end
end
test "you can register an observer to the mail object that gets informed on email delivery" do
ActionMailer::Base.register_observer(MyObserver)
mail = BaseMailer.welcome
MyObserver.expects(:delivered_email).with(mail)
mail.deliver
end
test "you can register an observer using its stringified name to the mail object that gets informed on email delivery" do
ActionMailer::Base.register_observer("BaseTest::MyObserver")
mail = BaseMailer.welcome
MyObserver.expects(:delivered_email).with(mail)
mail.deliver
end
test "you can register multiple observers to the mail object that both get informed on email delivery" do
ActionMailer::Base.register_observers("BaseTest::MyObserver", MySecondObserver)
mail = BaseMailer.welcome
MyObserver.expects(:delivered_email).with(mail)
MySecondObserver.expects(:delivered_email).with(mail)
mail.deliver
end
class MyInterceptor
def self.delivering_email(mail)
end
end
class MySecondInterceptor
def self.delivering_email(mail)
end
end
test "you can register an interceptor to the mail object that gets passed the mail object before delivery" do
ActionMailer::Base.register_interceptor(MyInterceptor)
mail = BaseMailer.welcome
MyInterceptor.expects(:delivering_email).with(mail)
mail.deliver
end
test "you can register an interceptor using its stringified name to the mail object that gets passed the mail object before delivery" do
ActionMailer::Base.register_interceptor("BaseTest::MyInterceptor")
mail = BaseMailer.welcome
MyInterceptor.expects(:delivering_email).with(mail)
mail.deliver
end
test "you can register multiple interceptors to the mail object that both get passed the mail object before delivery" do
ActionMailer::Base.register_interceptors("BaseTest::MyInterceptor", MySecondInterceptor)
mail = BaseMailer.welcome
MyInterceptor.expects(:delivering_email).with(mail)
MySecondInterceptor.expects(:delivering_email).with(mail)
mail.deliver
end
test "being able to put proc's into the defaults hash and they get evaluated on mail sending" do
mail1 = ProcMailer.welcome
yesterday = 1.day.ago
Time.stubs(:now).returns(yesterday)
mail2 = ProcMailer.welcome
assert(mail1['X-Proc-Method'].to_s.to_i > mail2['X-Proc-Method'].to_s.to_i)
end
test "we can call other defined methods on the class as needed" do
mail = ProcMailer.welcome
assert_equal("Thanks for signing up this afternoon", mail.subject)
end
test "action methods should be refreshed after defining new method" do
class FooMailer < ActionMailer::Base
# this triggers action_methods
self.respond_to?(:foo)
def notify
end
end
assert_equal ["notify"], FooMailer.action_methods
end
test "mailer can be anonymous" do
mailer = Class.new(ActionMailer::Base) do
def welcome
mail
end
end
assert_equal "anonymous", mailer.mailer_name
assert_equal "Welcome", mailer.welcome.subject
assert_equal "Anonymous mailer body", mailer.welcome.body.encoded.strip
end
protected
# Execute the block setting the given values and restoring old values after
# the block is executed.
def swap(klass, new_values)
old_values = {}
new_values.each do |key, value|
old_values[key] = klass.send key
klass.send :"#{key}=", value
end
yield
ensure
old_values.each do |key, value|
klass.send :"#{key}=", value
end
end
def with_default(klass, new_values)
old = klass.default_params
klass.default(new_values)
yield
ensure
klass.default_params = old
end
end

View File

@@ -1,172 +0,0 @@
require 'abstract_unit'
require 'mail'
class MyCustomDelivery
end
class BogusDelivery
def initialize(*)
end
def deliver!(mail)
raise "failed"
end
end
class DefaultsDeliveryMethodsTest < ActiveSupport::TestCase
test "default smtp settings" do
settings = { :address => "localhost",
:port => 25,
:domain => 'localhost.localdomain',
:user_name => nil,
:password => nil,
:authentication => nil,
:enable_starttls_auto => true }
assert_equal settings, ActionMailer::Base.smtp_settings
end
test "default file delivery settings" do
settings = {:location => "#{Dir.tmpdir}/mails"}
assert_equal settings, ActionMailer::Base.file_settings
end
test "default sendmail settings" do
settings = {:location => '/usr/sbin/sendmail',
:arguments => '-i -t'}
assert_equal settings, ActionMailer::Base.sendmail_settings
end
end
class CustomDeliveryMethodsTest < ActiveSupport::TestCase
def setup
@old_delivery_method = ActionMailer::Base.delivery_method
ActionMailer::Base.add_delivery_method :custom, MyCustomDelivery
end
def teardown
ActionMailer::Base.delivery_method = @old_delivery_method
new = ActionMailer::Base.delivery_methods.dup
new.delete(:custom)
ActionMailer::Base.delivery_methods = new
end
test "allow to add custom delivery method" do
ActionMailer::Base.delivery_method = :custom
assert_equal :custom, ActionMailer::Base.delivery_method
end
test "allow to customize custom settings" do
ActionMailer::Base.custom_settings = { :foo => :bar }
assert_equal Hash[:foo => :bar], ActionMailer::Base.custom_settings
end
test "respond to custom settings" do
assert_respond_to ActionMailer::Base, :custom_settings
assert_respond_to ActionMailer::Base, :custom_settings=
end
test "does not respond to unknown settings" do
assert_raise NoMethodError do
ActionMailer::Base.another_settings
end
end
end
class MailDeliveryTest < ActiveSupport::TestCase
class DeliveryMailer < ActionMailer::Base
DEFAULT_HEADERS = {
:to => 'mikel@test.lindsaar.net',
:from => 'jose@test.plataformatec.com'
}
def welcome(hash={})
mail(DEFAULT_HEADERS.merge(hash))
end
end
def setup
ActionMailer::Base.delivery_method = :smtp
end
def teardown
DeliveryMailer.delivery_method = :smtp
DeliveryMailer.perform_deliveries = true
DeliveryMailer.raise_delivery_errors = true
end
test "ActionMailer should be told when Mail gets delivered" do
DeliveryMailer.deliveries.clear
DeliveryMailer.expects(:deliver_mail).once
DeliveryMailer.welcome.deliver
end
test "delivery method can be customized per instance" do
email = DeliveryMailer.welcome.deliver
assert_instance_of Mail::SMTP, email.delivery_method
email = DeliveryMailer.welcome(:delivery_method => :test).deliver
assert_instance_of Mail::TestMailer, email.delivery_method
end
test "delivery method can be customized in subclasses not changing the parent" do
DeliveryMailer.delivery_method = :test
assert_equal :smtp, ActionMailer::Base.delivery_method
$BREAK = true
email = DeliveryMailer.welcome.deliver
assert_instance_of Mail::TestMailer, email.delivery_method
end
test "non registered delivery methods raises errors" do
DeliveryMailer.delivery_method = :unknown
assert_raise RuntimeError do
DeliveryMailer.welcome.deliver
end
end
test "does not perform deliveries if requested" do
DeliveryMailer.perform_deliveries = false
DeliveryMailer.deliveries.clear
Mail::Message.any_instance.expects(:deliver!).never
DeliveryMailer.welcome.deliver
end
test "does not append the deliveries collection if told not to perform the delivery" do
DeliveryMailer.perform_deliveries = false
DeliveryMailer.deliveries.clear
DeliveryMailer.welcome.deliver
assert_equal(0, DeliveryMailer.deliveries.length)
end
test "raise errors on bogus deliveries" do
DeliveryMailer.delivery_method = BogusDelivery
DeliveryMailer.deliveries.clear
assert_raise RuntimeError do
DeliveryMailer.welcome.deliver
end
end
test "does not increment the deliveries collection on error" do
DeliveryMailer.delivery_method = BogusDelivery
DeliveryMailer.deliveries.clear
assert_raise RuntimeError do
DeliveryMailer.welcome.deliver
end
assert_equal(0, DeliveryMailer.deliveries.length)
end
test "does not raise errors on bogus deliveries if set" do
DeliveryMailer.delivery_method = BogusDelivery
DeliveryMailer.raise_delivery_errors = false
assert_nothing_raised do
DeliveryMailer.welcome.deliver
end
end
test "does not increment the deliveries collection on bogus deliveries" do
DeliveryMailer.delivery_method = BogusDelivery
DeliveryMailer.raise_delivery_errors = false
DeliveryMailer.deliveries.clear
DeliveryMailer.welcome.deliver
assert_equal(0, DeliveryMailer.deliveries.length)
end
end

View File

@@ -1 +0,0 @@
Anonymous mailer body

View File

@@ -1 +0,0 @@
Welcome from another path

View File

@@ -1 +0,0 @@
<%= image_tag "somelogo.png" %>

View File

@@ -1 +0,0 @@
<%= image_tag "dummy.png" %>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -1 +0,0 @@
Inside

View File

@@ -1 +0,0 @@
text/html multipart

View File

@@ -1 +0,0 @@
text/plain multipart

View File

@@ -1 +0,0 @@
Attachment with content

View File

@@ -1 +0,0 @@
HTML

View File

@@ -1 +0,0 @@
PLAIN

View File

@@ -1 +0,0 @@
body_text

View File

@@ -1 +0,0 @@
<%= t('.greet_user', :name => 'lifo') %>

View File

@@ -1 +0,0 @@
HTML Explicit Multipart Templates

View File

@@ -1 +0,0 @@
TEXT Explicit Multipart Templates

View File

@@ -1 +0,0 @@
<%= self.formats.inspect %>

View File

@@ -1 +0,0 @@
<h1>Testing</h1>

View File

@@ -1 +0,0 @@
HTML Implicit Multipart

View File

@@ -1 +0,0 @@
TEXT Implicit Multipart

View File

@@ -1 +0,0 @@
Implicit with locale EN HTML

View File

@@ -1 +0,0 @@
Implicit with locale HTML

View File

@@ -1 +0,0 @@
Implicit with locale PL TEXT

View File

@@ -1 +0,0 @@
Implicit with locale TEXT

View File

@@ -1,5 +0,0 @@
<h1>Inline Image</h1>
<%= image_tag attachments['logo.png'].url %>
<p>This is an image that is inline</p>

View File

@@ -1,4 +0,0 @@
Inline Image
No image for you

View File

@@ -1 +0,0 @@
Testing

View File

@@ -1 +0,0 @@
Welcome

View File

@@ -1 +0,0 @@
<% raise 'the template should not be rendered' %>

View File

@@ -1 +0,0 @@
You logged out

View File

@@ -1 +0,0 @@
We do not spam

View File

@@ -0,0 +1 @@
Hello, <%= person_name %>. Thanks for registering!

View File

@@ -0,0 +1 @@
This message brought to you by <%= name_of_the_mailer_class %>.

View File

@@ -0,0 +1,5 @@
From "Romeo and Juliet":
<%= block_format @text %>
Good ol' Shakespeare.

View File

@@ -0,0 +1 @@
So, <%= test_format(@text) %>

Some files were not shown because too many files have changed in this diff Show More