Compare commits

...

896 Commits

Author SHA1 Message Date
Aman Gupta
daecedf14d drop tmail 2013-02-28 05:15:08 -08:00
Aman Gupta
76d83c0d5c use OutputBuffer#safe_append= for <%== to avoid extra string allocations 2013-02-26 01:07:29 -08:00
Aman Gupta
7335865bd9 avoid method call 2013-02-26 01:06:36 -08:00
Aman Gupta
e43316238d flush whitespace before statements to preserve line numbers 2013-02-25 22:13:11 -08:00
Aman Gupta
c3c6f25ec7 Merge pull request #3 from github/no-escape_once
XSS escaping
2013-02-24 21:47:24 -08:00
Aman Gupta
331461a65e optimize generated erb to reduce method calls
before:

        ');@output_buffer.append= ( content_icon row[:content] );@output_buffer.safe_concat('
');@output_buffer.safe_concat('        ');@output_buffer.append= ( spinner_img );@output_buffer.safe_concat('
');@output_buffer.safe_concat('      </td>
      <td class="content">
        ');@output_buffer.append= ( content_link row[:content] );@output_buffer.safe_concat('
');@output_buffer.safe_concat('      </td>
      <td class="message">
');

after:

        ';@output_buffer.append=( content_icon row[:content] );@output_buffer.safe_append='
        ';@output_buffer.append=( spinner_img );@output_buffer.safe_append='
      </td>
      <td class="content">
        ';@output_buffer.append=( content_link row[:content] );@output_buffer.safe_append='
      </td>
      <td class="message">
';
2013-02-22 02:56:17 -08:00
Aman Gupta
fd05501b4d ActionView::OutputBuffer and Erubis handler from rails 3.2 2013-02-21 06:03:01 -08:00
Aman Gupta
0fa76e01de ActiveSupport::SafeBuffer from upstream rails 3.2 2013-02-21 04:54:58 -08:00
Aman Gupta
1c215bab58 integrate monkey-patches from rails_xss/action_view 2013-02-21 03:20:01 -08:00
Aman Gupta
c7238a0746 faster html escaping code from rails master 2013-02-21 02:44:37 -08:00
Aman Gupta
71123b2913 fix boot on 1.9.3-p385
rails-2.3.14.github14/lib/initializer.rb:906:in `replace': can't modify frozen String (RuntimeError)
  from gems/rails-2.3.14.github14/lib/initializer.rb:906:in `set_root_path!'
  from gems/rails-2.3.14.github14/lib/initializer.rb:860:in `initialize'
  from gems/rails-2.3.14.github14/lib/initializer.rb:110:in `new'
  from gems/rails-2.3.14.github14/lib/initializer.rb:110:in `run'
  from github/config/environment.rb:22:in `<top (required)>'
2013-02-20 02:45:37 -08:00
Xavier Noria
2eede7e5ac s/escape_once/html_escape/, since html safety is the contract that now says whether something has to be escaped
Conflicts:
	actionpack/CHANGELOG
	actionpack/lib/action_view/helpers/form_tag_helper.rb
	actionpack/lib/action_view/helpers/url_helper.rb
	actionpack/test/template/url_helper_test.rb
2013-02-16 20:44:20 -08:00
Xavier Noria
507b8182cf url_for no longer escapes HTML, the :escape option is also gone
Rationale: url_for is just a path/URL generator, it is the responsability of the caller to escape conveniently HTML needs it, JavaScript needs different escaping, a text mail needs no escaping at all, etc.

Backported to 2.3. Conflicts:
	actionpack/CHANGELOG
	actionpack/lib/action_view/helpers/url_helper.rb
	actionpack/test/template/url_helper_test.rb
2013-02-16 20:32:13 -08:00
rizwanreza
3df96518be Allow content_tag options to take an array [#1741 state:resolved] [rizwanreza, Nick Quaranto]
Example:
  content_tag('p', "limelight", :class => ["song", "play"])
  # => <p class="song play">limelight</p>

Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2013-02-16 20:22:41 -08:00
Aman Gupta
84420c7f12 short-circuit String#blank? when string is empty 2013-02-16 17:06:30 -08:00
Aman Gupta
c57e85fd13 Revert "ignore "invalid byte sequence in UTF-8" from String#=~"
This reverts commit 18e9b2ffc9.
2013-02-16 17:05:59 -08:00
Corey Donohoe
2eca011798 Merge pull request #2 from github/cve-2013-0277
apply patch for cve-2013-0277
2013-02-11 10:51:52 -08:00
Corey Donohoe
f6cf01337f apply patch for cve-2013-0277 2013-02-11 10:47:45 -08:00
Corey Donohoe
0ad86343c6 Merge pull request #1 from github/cve-2013-0333
Backport Patches for CVE-2013-0333
2013-01-28 16:33:32 -08:00
Corey Donohoe
42524c2bf1 backport patches for CVE-2013-0333
https://groups.google.com/forum/?fromgroups=#!topic/rubyonrails-security/1h2DR63ViGo
2013-01-28 13:23:53 -08:00
rick
46f1ddbff9 backport dynamic finder fix (CVE-2012-5664) 2013-01-02 15:02:25 -07:00
Aman Gupta
b18f5c9af1 bump mocha dependency 2012-12-08 20:35:13 -08:00
Aman Gupta
18e9b2ffc9 ignore "invalid byte sequence in UTF-8" from String#=~ 2012-11-15 04:33:45 -08:00
Aman Gupta
9ec3637bc5 backport String#encoding_aware? and String#blank? encoding fixes from rails3 2012-11-13 20:50:29 -08:00
Aman Gupta
ba9248e6e3 Remove call to Kernel#gem 2012-11-09 14:47:38 -08:00
Joshua Peek
a27559cddf Skip primary key check for HABTM inserts 2012-09-05 21:43:48 -05:00
Aman Gupta
e786726603 fix encoding errors inside ActiveSupport::BufferedLogger
http://developer.uservoice.com/blog/2012/03/04/how-to-upgrade-a-rails-2-3-app-to-ruby-1-9-3/
2012-08-17 18:14:52 -07:00
Aman Gupta
a1d2a22047 fix TZInfo on ruby 1.9
http://developer.uservoice.com/blog/2012/03/04/how-to-upgrade-a-rails-2-3-app-to-ruby-1-9-3/
2012-08-16 11:52:43 -07:00
Aman Gupta
d43ecd5b32 fix multiple queries when chaining named scopes
https://rails.lighthouseapp.com/projects/8994/tickets/5410-multiple-database-queries-when-chaining-named-scopes-with-rails-238-and-ruby-192
2012-08-15 17:35:23 -07:00
Aman Gupta
61359bf6ad Use String#encode to do transliteration on ruby 1.9 2012-08-15 11:30:20 -07:00
Aman Gupta
a2beda1177 force binary strings when logging sql statements 2012-08-14 12:52:51 -07:00
Aman Gupta
52c895d565 handle load errors on 1.9
https://github.com/rails/rails/pull/3745
http://groups.google.com/group/rubyonrails-core/browse_thread/thread/81be70a119260e59?pli=1
2012-08-14 12:52:31 -07:00
Aman Gupta
74f90612ec avoid iconv require warning on 1.9 2012-08-14 12:52:01 -07:00
Justin Collins
a6eb61b7e4 Fix SQL injection via nested hashes in conditions 2012-06-12 23:14:10 -07:00
Ryan Tomayko
fe11782158 Merge remote-tracking branch 'github/rack-1.x' into 2-3-github 2011-11-17 12:57:09 -08:00
Ryan Tomayko
899e99a025 pin to rack ~> 1.1 instead of ~> 1.1.0
Some pretty gnarly bugs and security issues are present in the
latest rack 1.1.x release. There are 1.2.x and 1.3.x releases that
correct these.

This changes the gem dependencies to allow for rack versions > 1.1.
At GitHub we're on 1.2.4 (latest 1.2.x release at present) and
should have some results from real world testing soon.
2011-11-17 12:51:32 -08:00
Aaron Patterson
e0774e4730 fixing utf8 escape vulerability 2011-08-16 14:58:39 -07:00
Aaron Patterson
60f783d9ce fixing strip tags vulnerability 2011-08-16 14:58:13 -07:00
Aaron Patterson
6b46d65597 fixing sql injection problem 2011-08-16 14:57:48 -07:00
Aaron Patterson
fb1588c5ff 2.3.14. yay. :'( 2011-08-16 14:57:05 -07:00
Aaron Patterson
dea5a10f71 bumping to 2.3.13 2011-08-16 14:34:14 -07:00
Aaron Patterson
11dafeaa75 fixing response splitting problem 2011-08-16 14:25:45 -07:00
Aaron Patterson
bb99aa1149 adding notification for rdoc 2011-08-16 14:24:44 -07:00
Aaron Patterson
b132992978 we should not ignore all gems in here 2011-08-04 16:34:20 -07:00
Xavier Noria
78a1fda7c8 contrib app minor tweak 2011-07-27 13:23:42 -07:00
José Valim
8d02083f23 Merge pull request #1740 from Antiarchitect/2-3-stable
Fix OrderedHash merging with block given.
2011-06-17 06:25:39 -07:00
Andrey Voronkov
b1c36b7088 Added tests for OrderedHash merging with block. 2011-06-16 23:56:39 -07:00
Andrey Voronkov
b2d4142fb7 Fix OrderedHash merging with block given. 2011-06-16 16:47:29 -07:00
Brian Cardarella
1aae5e70ef Remove deprecation warning for ActiveRecord::Errors#generate_message. This is the same API that ActiveModel ended up using and that won't be changing. 2011-06-09 14:59:33 -07:00
Aaron Patterson
a2a34133d8 find the spec from the source index, then activate it 2011-06-06 20:22:47 -07:00
Ryan Davis
79aa54d0c7 + Switched to newer rdoc and gem package tasks (and their requires).
+ Fixed deprecated usage in gemspecs.

Bumped the version to 2.3.12 so I could test locally with actual
installs. If this is bad form for this project, please beat me up and
I'll split them out.
2011-05-25 01:49:15 -07:00
Ryan Davis
3ad5fd1879 Removed the bulk of the deprecations by simply not calling refresh.
This may cause problems. I dunno.
The real solution is to get rid of all of this mess and use gem paths properly.
2011-05-12 16:02:41 -07:00
Ryan Davis
4c3725723f Fixed buggy gem activation. Don't pass a dependency to gem, pass the
name and requirement. Better, just activate the spec for the
dependency (1.8 only)
2011-05-12 16:01:56 -07:00
Ryan Davis
c20a4d18e3 Removed buggy GemDependency#requirement override. Overrides should NEVER change the semantics of the parent (returning nil if default). 2011-05-12 16:01:10 -07:00
Ryan Davis
01a9fbbcca Fix broken GemDependency#==. You should ALWAYS check the class! 2011-05-12 16:00:28 -07:00
Ryan Davis
8d4ca9edc6 Fix stupid emacsisms. Just makes things more readable. 2011-05-12 16:00:03 -07:00
José Valim
d793a56121 Merged pull request #198 from robdimarco/2-3-stable.
Patch for issue 6440 - Session Reset undefined method `destroy' for {}:Hash
2011-04-28 00:37:53 -07:00
José Valim
f424efe97f Merged pull request #331 from daphonz/2-3-stable.
Dynamic find_or_create_by_x_and_y always creates new records in Rails 2.3.11
2011-04-28 00:20:15 -07:00
Casey Dreier
9f7ff621bd Fixing dynamic finders on associations to properly send arguments to the find_by_* method. Closes issue #330.
Commit fdfc8e3b9 introduced a bugfix to prevent additional values passed
to a dynamic find_or_create_by_x methods from confusing the finder.
This patch also broke the essential behavior of this method on an
association by incorrectly sending arguments to the find_by_x methods.
The finder method would always see its inputs as a single array of
values instead of individual arguments, almost guaranteeing that the
finder call would be incorrect, and that we'd always create a new
record instead.

This patch adds a splat operator to the parameter array we send along to
the dynamic finder so that it receives its inputs correctly, and
includes an additional test to ensure that repeated calls to
find_or_create_by_x only creates one new record.
2011-04-27 21:57:24 -04:00
gmarik
b0be721dd9 respect :expire_after option
- it was broken after
[commit](e0eb8e9c65)
- there's also
[issue](https://rails.lighthouseapp.com/projects/8994/tickets/6634-railsrack-inconsistency-about-expires_afterexpires-cookie-option)

- also: maybe it worth making Rack understand :expire_after as we
duplicate same logic in [cookie_store](https://github.com/gmarik/rails/blob/v2.3.11/actionpack/lib/action_controller/session/cookie_store.rb#L114)

Signed-off-by: José Valim <jose.valim@gmail.com>
2011-04-14 13:48:35 +02:00
Rob Di Marco
8ca8ac379d Fixed bug 6440 by checking that destroy exists on the session 2011-02-28 22:54:03 -05:00
Rob Di Marco
589ce09564 Unit test that shows calling reset session twice results in an exception 2011-02-28 22:53:36 -05:00
Vijay Dev
6c42c142e2 fix incorrect version in deprecation message
Signed-off-by: Santiago Pastorino <santiago@wyeworks.com>
2011-02-20 13:32:18 -02:00
Aaron Patterson
abc06a2f76 rubygems 1.5.0 compatibility. Thanks Tim Serong 2011-02-09 15:24:14 -08:00
Michael Koziarski
b0c3d451a2 Prepare for the 2.3.11 release 2011-02-09 09:30:53 +13:00
Michael Koziarski
7e86f9b4d2 Change the CSRF whitelisting to only apply to get requests
Unfortunately the previous method of browser detection and XHR whitelisting is unable to prevent requests issued from some Flash animations and Java applets.  To ease the work required to include the CSRF token in ajax requests rails now supports providing the token in a custom http header:

 X-CSRF-Token: ...

This fixes CVE-2011-0447
2011-02-09 09:20:17 +13:00
Michael Koziarski
abe97736b8 Be sure to javascript_escape the email address to prevent apostrophes inadvertently causing javascript errors.
This fixes CVE-2011-0446
2011-02-09 09:20:16 +13:00
Aaron Patterson
7e0f60d2ed fixing invalid yaml [#4418 state:resolved]
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2011-02-01 13:30:58 -08:00
Jamis Buck
3afa5385c9 Revert "make TestCaseTest work for pre-1.9 rubies, too"
This reverts commit 8378a44ff9.
2011-01-19 15:57:16 -07:00
Jamis Buck
c545331f9e Revert "scrub instance variables from test cases on teardown"
This reverts commit b5cf2b4b82.
2011-01-19 15:57:16 -07:00
Jamis Buck
cd0ecff00b Revert "rein in GC during tests by making them run (at most) once per second"
This reverts commit a0c761dc6b.
2011-01-19 15:57:14 -07:00
Jamis Buck
a0c761dc6b rein in GC during tests by making them run (at most) once per second
this can provide a significant performance boost during testing, by
preventing the GC from running too frequently.
2011-01-19 10:27:53 -07:00
Jamis Buck
b5cf2b4b82 scrub instance variables from test cases on teardown
this prevents test state from accumulating, resulting in leaked
objects and slow tests due to overactive GC.
2011-01-19 10:12:18 -07:00
Jamis Buck
8378a44ff9 make TestCaseTest work for pre-1.9 rubies, too 2011-01-19 10:08:02 -07:00
Johnathan Ritzi
4f0c8ef9f1 Fix doc for #check_box [#6311 state:resolved]
Signed-off-by: Xavier Noria <fxn@hashref.com>
2011-01-19 08:47:19 +01:00
Jeremy Kemper
bc302f2aec Revert "use Object#class instead of Object#type"
This reverts commit 08d94d3f7e.
2011-01-10 14:14:25 -08:00
Tomasz Pajor
08d94d3f7e use Object#class instead of Object#type 2011-01-09 15:12:25 -08:00
Mikel Lindsaar
10ec012f58 Updating documentation on ActionMailer base to show a multipart email with attachments 2011-01-02 11:13:44 +11:00
Mikel Lindsaar
92fd824480 Correcting actionmailer guide for Rails 2.3 2011-01-02 11:08:44 +11:00
Michael Koziarski
6d916329b8 Require thread explicitly rather than relying on rubygems to do it. 2010-12-20 11:16:55 +13:00
Michael Koziarski
84465a2cc1 Revert "In nested_attributes when association is not loaded and association record is saved then in memory record attributes should be saved"
This reverts commit 12bbc34aca.

It caused errors when combined with attr_accessible, piggy back attributes fetched by :select, etc.  Leaving it in 3.0, but removing from 2.3
2010-12-08 09:48:54 +13:00
Will Bryant
0fee359278 Don't add non-new records back to the target array after loading targets on associations, as that makes destroy_all destroy any created records that don't match the scope destroy_all is called on
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2010-12-08 09:48:16 +13:00
Pascal Friederich
e0eb8e9c65 Let Rack::Utils.set_cookie_header! create the Set-Cookie header instead of manually fiddling with the response headers [#4941 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-12-01 11:58:45 +01:00
José Valim
2826324e56 Revert "Fix AbstractStore so that it preserves Set-Cookie header as an array, rather than as newline separated strings"
This reverts commit 36b91e34f4.

Conflicts:

	actionpack/test/activerecord/active_record_store_test.rb
2010-12-01 11:48:31 +01:00
Alexandru Catighera
1681ede605 Fix ActiveRecord calculations when grouped by multiple fields 2010-11-16 11:06:49 -08:00
Tom Stuart
44db47c63e Backport BlankSlate removal from ActiveSupport::BasicObject [#5911 state:resolved]
This is a backport of dd15a3fee0.

Signed-off-by: Andrew White <andyw@pixeltrix.co.uk>
2010-11-03 11:03:38 +00:00
Andrew White
25139ac92c Don't write out secure cookies unless the request is secure 2010-10-27 15:04:29 +01:00
Andrew White
0e52a609fd Don't create a deprecation proxy object if the variable was passed in local_assigns [#1671 state:resolved] 2010-10-26 12:57:21 +01:00
Aaron Patterson
df78de2bc8 removing space errors 2010-10-21 10:30:18 -07:00
Omar Qureshi
36b91e34f4 Fix AbstractStore so that it preserves Set-Cookie header as an array, rather than as newline separated strings 2010-10-21 10:28:54 -07:00
toby cabot
bdfddb09d7 bug 1108: yield to block provided to find_or_create_by_x
Starting in 2.3.8 we stopped yielding to blocks passed in to
find_or_create_by_x methods.  This patch restores that behavior and
adds a case to test it.
2010-10-20 17:23:54 -07:00
toby cabot
fdfc8e3b9c bug 1108: fix a bug with find_or_create_by and additional values
There was a bug with find_or_create_by_x introduced in 2.3.9 - if you
included extra parameters for the create() then those parameters would
confuse the find() so you'd never get to the create().  This patch
filters the parameters so we only pass to find() the subset that it's
interested in.  The code for the filtering was modelled on the code in
base.rb's method_missing().
2010-10-20 17:23:54 -07:00
Michael Koziarski
f5ed5c317e Prepare for the 2.3.10 release 2010-10-15 08:41:59 +13:00
Michael Koziarski
96183e0f28 Revert 7d2173ec5c which introduced a security vulnerability.
This addresses  CVE-2010-3933
2010-10-15 08:30:34 +13:00
Geoff Buesing
f2e32e4fd7 require 'uri' in action_controller/url_rewriter [#5555 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-10-12 00:58:29 +02:00
Aaron Patterson
8beb84fa33 calling correct method on minitest for test name when teardown callback fails 2010-10-04 09:29:37 -07:00
Aaron Patterson
a448e74661 [#5406 state:resolved] calling the correct method on minitest to obtain the test name 2010-10-04 09:28:21 -07:00
Aaron Patterson
fb526a0470 fixing space errors 2010-09-30 10:29:46 -07:00
Marcelo Giorgi
96c19ff7cc AssociationCollection#include? working properly for objects added with build method [#3472 state:resolved] 2010-09-30 10:28:25 -07:00
Marcelo Giorgi
9b78af95be Remove duplication of conditions generated for associations when used in conjunction with named_scopes [#4634 state: resolved] 2010-09-30 09:04:04 -07:00
Emilio Tagua
5a63df211d Add examples to performance script that were included in version 3. 2010-09-30 09:54:01 -03:00
Emilio Tagua
1851596db5 Use detect instead select to avoid sh [..] command not found. 2010-09-30 09:52:47 -03:00
Marcelo Giorgi
0665182950 Preserving :include options for hmt association with an order but without conditions [#5262 state:resolved] 2010-09-28 09:56:10 -07:00
Ryan Wallace
515917f5d8 Add test to demonstrate failure with eager loading hmt where the association has an order. 2010-09-28 09:54:32 -07:00
Étienne Barrié
bc52d81306 Fix add_index with a symbol #4891 2010-09-27 10:26:01 -07:00
Michael Koziarski
dbbf2fd19c Revert "Makes form_helper use overriden model accessors backport"
This change introduced breakages and test failures.

This reverts commit 8141f0894e.
2010-09-27 12:20:54 +13:00
Andrew Kaspick
9476d628a3 memoized protected methods should remain protected
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2010-09-27 11:50:54 +13:00
Colin Casey
7240e8af6a Fix for imposed version number as last part of gem directory name for frozen gems
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-09-24 13:16:51 +02:00
Colin Casey
f2990620d7 Test for imposed version number as last part of gem directory name for frozen gems
[#4295 state:resolved]

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-09-24 13:16:50 +02:00
W. Andrew Loe III
17f2fb44c0 Only send secure cookies over SSL. 2010-09-14 11:52:40 -07:00
Emilio Tagua
8c049c6b20 Add more examples in performance script.
[#5610 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-09-10 13:15:46 -07:00
Jeremy Kemper
761c9cd5db Ruby 1.9 compat: convert Pathname to string 2010-09-10 12:23:41 -07:00
Andrew Kaspick
a159fd0b8c Fix fixtures in integration test sessions
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2010-09-10 10:45:23 +12:00
Erik Michaels-Ober
e8b84ab1b4 Add support for mysql2 adapter 2010-09-10 02:13:56 +08:00
Erik Michaels-Ober
383ea02e38 Fix typo in deprecation warning
Object#returning should be Kernel#returning
2010-09-10 02:13:56 +08:00
Mikel Lindsaar
597fb1da94 Adding documentation to redirect_to and status code option references 2010-09-09 14:00:09 +10:00
Mislav Marohnić
c6e33d30c1 fix setting session cookie with activerecord and memcache store
Commit f8f3653 broke setting the session ID cookie for requests without 'HTTP_COOKIE' header
when using activerecord or memcache store. Integration tests didn't catch this because they
always set the HTTP_COOKIE header for mock requests, so now this is changed to only set the
header if there are cookies.

[#5581 state:committed]

Signed-off-by: Santiago Pastorino <santiago@wyeworks.com>
2010-09-08 12:59:48 -03:00
Jeremy Kemper
a61a39ecd4 Rails 2.3.9 2010-09-04 14:36:40 -07:00
Ken Collins
b64d1fe637 Conversion of a two dimensional array that is ruby 1.8.6 safe. Fix paren warnings too.
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2010-09-03 14:38:28 +12:00
Jeremy Kemper
6f17422ca7 require 'thread' for Mutex dependency 2010-08-31 16:38:52 -07:00
Mikel Lindsaar
bac12fa5fc Adding option to ActiveResource to allow you to not reset the previously stored requests and responses by passing false to respond_to
Backport of commit 2a1b23f851ea3d4634fc68b74fe6b1afed23d3ef on rails/master
2010-08-29 22:55:02 -07:00
Mikel Lindsaar
56fdfeb265 Back porting HttpMock test from Rails 3 master 2010-08-29 22:55:02 -07:00
Mikel Lindsaar
881712cf50 Updating documentation on ActiveResource HTTP Mock and also adding test coverage 2010-08-29 22:55:02 -07:00
Jeremy Kemper
b2c91983dc Prepare for Rails 2.3.9. Release 2.3.9.pre gems. 2010-08-29 20:19:05 -07:00
Jeremy Kemper
bdace5d6aa Exclude guides from gem to keep file size small 2010-08-29 17:54:13 -07:00
Mikel Lindsaar
0fcb4302e1 Make ActiveResource::InvalidRequestError more user friendly
Signed-off-by: Xavier Noria <fxn@hashref.com>
2010-08-25 10:11:06 +02:00
Xavier Noria
11361a9e79 restores railties/README as home page of the API 2010-08-20 04:19:34 +02:00
Xavier Noria
add3ccbca6 revises guides generation 2010-08-20 04:13:15 +02:00
Jeff Lawson
d35a67bba3 Bug Fix -- clean up connection after stored procedure [#3151 state:resolved] for 2-3-stable 2010-08-18 08:33:47 -07:00
Jeff Lawson
7e79889d1c Bug Fix -- clean up connection after stored procedure [#3151 state:resolved] for 2-3-stable 2010-08-18 08:33:47 -07:00
Santiago Pastorino
43e2bbe28e Making time_zone_options_for_select return a html_safe string master backport 2010-08-15 10:07:38 -03:00
Michael Koziarski
b154b97ea4 Revert "Ruby 1.9.2: explicitly raise NoMethodError for attempts at explicit coercion"
This reverts commit 64082b350c.

This change broke compatibility with 1.8.6 and was only needed for older 1.9.2 versions

Conflicts:

	activerecord/lib/active_record/attribute_methods.rb
2010-08-11 10:53:06 +12:00
Xavier Noria
15cafbe267 it is no longer true that load_paths are going to be removed in final 2010-08-05 00:04:43 +02:00
Subba Rao Pasupuleti
12bbc34aca In nested_attributes when association is not loaded and association record is saved then in memory record attributes should be saved
[#5053 state:resolved]

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-08-03 10:56:51 +02:00
Santiago Pastorino
8141f0894e Makes form_helper use overriden model accessors backport
[#3374]
2010-08-01 19:49:45 -03:00
Leigh Caplan
27651c1fad Test to ensure that falsy objects aren't wrapped by deprecation proxies 2010-07-26 09:54:26 -07:00
Leigh Caplan
a9ef2fd56c Override new on proxy objects so that they never wrap nil or false. 2010-07-26 09:54:26 -07:00
Santiago Pastorino
ae63d5c90d Changes Object#returning with Object#tap on guides 2010-07-25 17:10:37 -07:00
Santiago Pastorino
6f3896751a Changelog update for Object#responding deprecation
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-07-25 23:08:50 +02:00
Santiago Pastorino
5b0f839054 Deprecates Object#returning in favor of Object#tap
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-07-25 22:49:10 +02:00
Santiago Pastorino
a5d8c95a7c Changes the usage of Object#returning with Object#tap
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-07-25 22:49:06 +02:00
Subba Rao Pasupuleti
dec2c4f4e3 renaming test name to fix accidently override [#5076 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-07-18 11:20:25 +02:00
Neeraj Singh
99cdea7cbe update_attribute and updated_attributes! are now wrapped in a transaction
[#922 state:resolved]

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-07-18 11:20:25 +02:00
Aaron Patterson
c2d13a9a53 changing fixtures back to superclass_delegating_accessor until we can convert them to class_attributes 2010-07-17 18:57:24 -07:00
Jon Yurek
fb615cd7fd Fix for integration tests not serializing arrays in multipart forms correctly.
Signed-off-by: wycats <wycats@gmail.com>
2010-07-17 13:01:50 -05:00
Aaron Patterson
4ae4828953 backporting a couple missing files. sorry folks! 2010-07-16 08:41:53 -07:00
Michael Koziarski
f57ca87729 Only skip eager loading the code if dependency_loading is still enabled.
Otherwise rake tasks which depend on environment will get errors about missing constants.
2010-07-16 17:06:32 +12:00
Aaron Patterson
7b6383f263 fixing performance regression from 2.3.5 -> 2.3.8 2010-07-15 15:59:19 -07:00
Michael Lovitt
257a29d3cc Sessions should not be created until written to and session data should be destroyed on reset. [#4938 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-07-14 08:04:37 +02:00
Jacob Lewallen
8298bef72e Set destroyed=true in opt locking's destroy [#5058 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-07-14 08:03:02 +02:00
Mike Breen
046c900df2 A generated plugin's test are not run by 'rake test'
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-07-08 23:08:22 +02:00
Ken Collins
504f7cfbb3 Fix the #using_limitable_reflections? helper to work correctly by not examining the length of an array which contains false/true, hence always passing.
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-07-08 23:08:11 +02:00
Grant Ammons
0963774c0a fixes #2362, eager loading :through associations will join the :source model if there are :conditions
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-07-08 23:08:05 +02:00
Mislav Marohnić
2d3bc99b0d test that ActiveRecord destroy and destroy_all return destroyed records
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-07-08 11:35:56 -07:00
Mislav Marohnić
ba9c469113 add missing require to ActiveRecord "base_test.rb"
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-07-08 11:35:46 -07:00
José Valim
bfbdeeae30 Use bind instead of instance_exec cause it may be causing memory leaks. Also, provide a simpler and sane implementation for scoped. [#5044 state:resolved] 2010-07-04 16:19:40 +02:00
Aaron Patterson
67e18c523c fisting Session::AbstractStore#clear to actually clear the session. [#5030 state:resolved]
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-07-01 14:47:28 -07:00
James Le Cuirot
526f1e5f15 Don't remove scheduled destroys when loading an association.
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-07-01 01:07:24 +02:00
Jan Berkel
f8f4872fcc Backported patch from [#4762]
URL fragments should not have safe characters escaped. Ref: Appendix A,
  http://tools.ietf.org/rfc/rfc3986.txt

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-30 13:27:28 +02:00
Aaron Patterson
fad166c152 AssociationCollection#create_by_*, find_or_create_by_* work properly now. [#1108 state:resolved]
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-06-29 16:33:12 -07:00
Leigh Caplan
78e4d88c70 Rewrite the clause to pluck the existing value from zones_map before performing a lookup. [#4942 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-29 17:54:18 +02:00
David Trasbo
ac42e6951f Deprecate ActiveRecord::Base#class_name [#379 state:committed]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-29 17:54:05 +02:00
David Trasbo
d0d10f51d7 Only tell users that the Rails gem is missing if it's actually the case [#2901 state:committed]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-29 17:53:57 +02:00
Prem Sichanugrist
69c4e4ce65 Fix [54a5088cd5] where the i18n gem was wrongly updated to 0.4.1.
I've tested and confirm that `2-3-stable` will use the vendored `i18n` gem if there's no `i18n` gem with version >= 0.4.1 installed

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-29 17:53:48 +02:00
Leigh Caplan
80473e035a test that unknown zones don't store mapping keys
[#4942]

Signed-off-by: Santiago Pastorino <santiago@wyeworks.com>
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-28 22:20:34 +02:00
Santiago Pastorino
70af7efa16 Don't store incorrect values in zones_map backport
[#4942 state:committed]

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-28 22:20:34 +02:00
Evgeniy Dolzhenko
56b35afbdd Add module_eval missing file_name and line_number args
[#4712 state:resolved]

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-27 08:49:54 +02:00
José Valim
0e9190c902 Tidy up tests in previous commit since they did not assure an OrderedHash is returned (the test would pass for an array and would pass by chance for hashes).
[#4875 state:resolved]
2010-06-26 18:16:09 +02:00
chaitanyav
449cf50d85 Add OrderedHash#invert to preserve order in ruby 1.8
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-26 18:13:45 +02:00
Paul Mucur
05defcd63a Alias ActiveSupport::OrderedHash#update to ActiveSupport::OrderedHash.merge!
This ensures that an OrderedHash's keys are set up appropriately when using update.

[#4973 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-06-25 15:18:39 -07:00
Prem Sichanugrist
f8f365346e Make sure that Rails doesn't resent session_id cookie over and over again if it's already there [#2485 state:resolved]
This apply to only Active Record store and Memcached store, as they both store only the session_id, which will be unchanged, in the cookie.

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-25 09:47:56 +02:00
Xavier Noria
4a745ca670 deprecates load_(once_)paths in dependencies and app config in favor of autolaod_(once_)paths 2010-06-24 00:00:45 +02:00
José Valim
68bfd8a392 Use size for Ruby 1.8.6 compatibility. 2010-06-23 17:53:02 +02:00
Neeraj Singh
549b2ad77c fixes to the tests for patch #4909
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-23 17:34:45 +02:00
kane
09a23d2290 quote scoped columns in validates_uniqueness_of [#4909 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-23 17:34:40 +02:00
George Montana Harkin
7d2173ec5c Fixes #2415 by creating a new instance of the Model when saving attributes to that model and the associated attributes already exist. Tests included. [#2415 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-23 17:31:22 +02:00
Neeraj Singh
cc53229378 Fragment cache not generating the proper cache key in log
[#4827 state:resolved]

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-23 09:11:48 +02:00
Maxim Chernyak
844da12ba6 Fix eager loading of polymorphic has_one associations nested-included under polymorphic belongs_to associations. [#3233 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-23 09:09:46 +02:00
Neeraj Singh
a9c69f3bb0 test for #1570
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-23 09:08:55 +02:00
Paweł Kondzior
687d7f52c4 STI should identify itself inside named_scope
[#1570 state:resovled]

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-23 09:07:46 +02:00
Michael Koziarski
cbf36cf57c Revert "make text_field and hidden_field omit the value attribute if the developer explicitly passes in :value => nil [#4839 state:reopened]"
This reverts commit 52c922fad1
2010-06-23 16:54:05 +12:00
Michael Koziarski
52c922fad1 make text_field and hidden_field omit the value attribute if the developer explicitly passes in :value => nil [#4839 state:resolved]
Signed-off-by: Michael Koziarski <michael@koziarski.com>

Conflicts:

	actionpack/lib/action_view/helpers/form_helper.rb
2010-06-23 16:25:19 +12:00
Jeff Dean
da93d69bcb remove_column should raise an ArgumentError when no columns are passed [#4803 state:resolved]
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2010-06-23 16:23:03 +12:00
Jeremy Kemper
e703fc101b CI: add i18n gem 2010-06-22 14:11:14 -07:00
Jesse Storimer
85b6d79d8a CookieStore should preserve the Set-Cookie header Array [#4743 state:resolved]
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-06-22 11:25:32 -07:00
Prem Sichanugrist
5ed6a8447b Change all i18n interpolations from {{...}} to %{...}
This will silent all warning if there's a i18n version 0.4.x gem install on user's machine.

[#4913 state:resolved]

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-21 01:14:36 +02:00
Prem Sichanugrist
54a5088cd5 Update bundled i18n gem to 0.4.1 to make sure every project will be warn about using deprecated %{..} interpolation.
This will also make sure that by changing {{..}} into %{..} won't break any Rails 2.3.x application, since it would load the vendored version if it's not satisfy the version requirement.

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-21 01:13:37 +02:00
James Le Cuirot
08302d2feb When not overwriting unsaved updates in nested attributes, allow already-saved records to be refreshed.
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-20 00:33:39 +02:00
Maxime RETY
c7e875abdb Fix Yajl backend discovery in ActiveSupport::JSON
[#4897]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-06-18 20:12:16 -07:00
Master Lambaster
1ac00a6844 Fix test which prevents connection reset on failing and remove hardcoded connection
[#4689 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-06-18 15:28:56 -07:00
Pratik Naik
e4accdec0c Fix AR perf script 2010-06-10 00:00:17 +05:30
James Le Cuirot
b41c3ba154 Don't overwrite unsaved updates when loading an association but preserve the order of the loaded records. [#4642 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2010-06-09 18:20:15 +05:30
Prem Sichanugrist
0f44d37d04 Make sure that rails recognized the full notation of IPv6 loopback address, and recognize 127.0.0.0/8 in IPv4
[#3257 state:resolved]

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-06-08 19:47:18 +02:00
Xavier Noria
ed8cabcec2 deprecates Array#random_element in favor of Array#sample, backported from Ruby 1.9, thanks to Marc-Andre Lafortune 2010-06-05 02:11:33 +02:00
Andrew
3d6ed50187 Don't rewrap system level exceptions with StatementInvalid
Signed-off-by: Michael Koziarski <michael@koziarski.com>
[#896 state:committed]
2010-05-29 16:00:54 +12:00
Michael Koziarski
b760d699a8 Merge commit 'mislav/counter_cache_2-3-stable' into 2-3-stable 2010-05-29 14:05:31 +12:00
Michael Koziarski
5796a92433 Merge commit 'mislav/auto_link_2-3-stable' into 2-3-stable 2010-05-29 14:05:21 +12:00
Santiago Pastorino
b1a97a4998 removes an unneeded alias
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-05-26 16:10:31 +02:00
Jeremy Kemper
a815f0c5a3 Shift SafeBuffer#concat responsibility over to rails_xss 2010-05-25 14:27:40 -07:00
Jeremy Kemper
9da7ff8842 Bump 2-3-stable to 2.3.9 2010-05-25 09:50:34 -07:00
Xavier Noria
2ed893bdce get railties/README back to the home page of the API 2010-05-25 17:18:50 +02:00
Santiago Pastorino
240f4e944c SQLite: forward compatibility with future driver releases
[#4633]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-05-24 20:53:26 -07:00
Jeremy Kemper
f7e27bd078 i18n: t() handles single keys returning an Array, also 2010-05-24 20:41:28 -07:00
Jeremy Kemper
6a9e188c0c HTML safety: fix textarea with nil content 2010-05-24 20:13:07 -07:00
Jeremy Kemper
aa449141b4 Work around strange Ruby 1.9 autoload issue by using absolute load paths for tests (for Active Model too) 2010-05-24 16:18:29 -07:00
Santiago Pastorino
a9032c885f Error messages for asserts
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-05-24 16:05:39 -07:00
Jeremy Kemper
e8ba5265e0 Work around strange Ruby 1.9 autoload issue by using absolute load paths for tests (ditto for other components' tests) 2010-05-24 16:05:34 -07:00
José Valim
50f3754525 Ensure translations work with symbols. 2010-05-24 23:38:49 +02:00
Santiago Pastorino
4986d5ed04 translate helper method using an array is deprecated
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-05-24 23:38:48 +02:00
Jeremy Kemper
4fef5af9c3 2.3.7.pre1: fixes HTML escaping when *not* using rails_xss 2010-05-24 14:02:38 -07:00
Jeremy Kemper
e5af56abfe Add global gem task 2010-05-24 13:48:13 -07:00
Jeremy Kemper
9d3bd87045 Work around strange Ruby 1.9 autoload issue by using absolute load paths for tests 2010-05-24 12:16:33 -07:00
Santiago Pastorino
6b0616d1b8 translation method of TranslationHelper module returns a SafeBuffer Array backport
[#4675 state:committed]

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-05-24 20:56:44 +02:00
Santiago Pastorino
d3da1a2c66 Revert "translation method of TranslationHelper module returns always SafeBuffer [#4194 status:resolved]"
This reverts commit 2310aef29b.

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-05-24 20:56:44 +02:00
wycats
8e6a044b2b Needs to work on 1.8 too 2010-05-24 11:29:12 -07:00
wycats
50b7c0c104 Give the ERB String the encoding of the original template 2010-05-24 11:18:20 -07:00
Jeremy Kemper
c66013e2c5 Fix that captured content (e.g. with form_for or div_for) would be HTML-escaped even without the rails_xss plugin installed. Rails 2.3.7, we barely knew ya... 2010-05-24 09:12:00 -07:00
Lance Ivy
9e08e196fa Ensure auto_link does not ignore multiple trailing punctuations
[#2504 state:resolved]
2010-05-24 11:47:36 +02:00
Mislav Marohnić
17b4fd25e4 avoid auto_linking already linked emails; more robust detection of linked URLs
References #1523  [#1862 state:resolved]  [#3591 state:resolved]

Add test that shows how link text can contain HTML if needed:
the trick is using block form in combination with `raw`.
Let link text be automatically HTML-escaped

[#2017 state:resolved]
2010-05-24 11:18:20 +02:00
Mislav Marohnić
bd9ca9aed0 auto_link: support arbitrary URI schemes like "ftp:" and "file:"
recognizes all URI scheme allowed characters, such as colon and period.

[#3494 state:resolved]
2010-05-24 11:18:20 +02:00
Jeremy Kemper
f97da34b4f Bump 2-3-stable to 2.3.8 2010-05-24 01:39:19 -07:00
Jeremy Kemper
326188c25e 2.3.7 release: fix rails_xss compatibility 2010-05-24 00:04:41 -07:00
Jeremy Kemper
60e82a3ca2 Move tests for deprecated String#html_safe! to plugin 2010-05-23 22:07:47 -07:00
Jeremy Kemper
3ff921a65a rails_xss handles deprecated String html safety, when installed 2010-05-23 21:30:43 -07:00
Santiago Pastorino
b10bf834b7 Make use of safe_concat on TextHelper concat
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-05-23 16:51:52 -07:00
Jeremy Kemper
86f0287993 Revert "Don't always mark the argument to #concat as HTML-safe."
This reverts commit e53791f8c0.
2010-05-23 16:51:47 -07:00
Jeremy Kemper
ab2d7c8b5d Use a non-XSS-protected output buffer for view tests 2010-05-23 16:21:44 -07:00
Jeremy Kemper
ca5f5d97b9 Fix test rendering unmarked but safe HTML 2010-05-23 15:28:40 -07:00
Nathan Weizenbaum
e3f14d12cd Don't incompatibly monkeypatch ERB.
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-05-23 15:02:24 -07:00
Nathan Weizenbaum
e53791f8c0 Don't always mark the argument to #concat as HTML-safe.
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-05-23 15:00:14 -07:00
Nathan Weizenbaum
48fbe7b0d8 Mark all raw HTML being concatted as HTML-safe.
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-05-23 14:57:45 -07:00
Jeremy Kemper
55e88eeee4 Bump 2-3-stable to 2.3.7 2010-05-23 01:39:45 -07:00
Jeremy Kemper
56bb5504dd 2.3.6 release 2010-05-22 23:53:40 -07:00
Jeremy Kemper
d8f0a58dcb Remove miscommit from 57337cd 2010-05-22 23:46:03 -07:00
Aaron Patterson
a637b5f447 backporting beda2d43 for newer sqlite-ruby bindings
Signed-off-by: Xavier Noria <fxn@hashref.com>
2010-05-22 20:52:15 +02:00
Xavier Noria
25ec61330b 1.9 compat: deprecated last_(month|year) in favor of prev_(month|year) 2010-05-19 00:59:02 +02:00
Jeremy Kemper
9d99e610be Revert "Don't carry default value when changing column for a binary type on MySQL"
Broke mysql tests.

This reverts commit ddadcc7cf8.

Conflicts:

	activerecord/test/cases/migration_test.rb

[#3234 state:open]
2010-05-18 11:03:59 -07:00
Étienne Barrié
99bcce7ec1 make add_index and remove_index more resilient; new rename_index method; track database limits
[#3452 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-05-18 10:51:36 -07:00
Ian White
a5696e36c6 Nested records (re: autosave) are now updated even when the intermediate parent record is unchanged [#4242]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-05-18 16:10:44 +02:00
José Valim
94878c61a3 Deprecate legacy CGI options in SessionStores. 2010-05-18 03:25:57 +02:00
Xavier Noria
bb2327d9ab method rename to fix a broken test 2010-05-18 00:31:41 +02:00
Rizwan Reza
32b0b5f7b2 Deprecate Array#rand in favor of Array#random_element [#4555 stated:committed]
Signed-off-by: Xavier Noria <fxn@hashref.com>
2010-05-17 23:56:44 +02:00
José Valim
76608b13d2 superclass_delegating_accessor does not accept options. 2010-05-17 12:37:42 +02:00
Jeremy Kemper
cd3d30d569 CI: bump rack to 1.1 2010-05-16 13:35:42 -07:00
Rizwan Reza
74206aeff2 Rack dependency bumped to 1.1.0, tests passing. [#3558 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-05-16 22:19:25 +02:00
Wijnand Wiersma
5b1f4c51ce Postgresql doesn't allow to change a string type column to a binary type. Skip this test for postgresql for now.
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-05-16 15:15:16 +02:00
Jeff Kreeftmeijer
ec017e158a Added assert_attribute_type to clean up GeneratedAttributeTest [#2377 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-05-16 12:08:55 +02:00
Matthew Rudy Jacobs
5d979de1a9 when we run rake rails:freeze:edge update the value of the "REVISION" file rather than creating a new file "REVISION_ce706..." each time [#1694 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-05-16 10:42:48 +02:00
Nobuhiro IMAI
e535b45c86 make fixture accessors private
prevent to be run fixture accessor (e.g. test_foos for TestFoo model) as a test case

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-05-16 10:35:23 +02:00
Neeraj Singh
3570f3e7f6 Fix broken integration test in 2.x [#4565 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-05-16 10:32:53 +02:00
Jeff Kreeftmeijer
3568c5cee0 using :time_select when the attribute type is :time in the scaffold generator. [#2377 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-05-16 10:32:15 +02:00
Elomar França
ddadcc7cf8 Don't carry default value when changing column for a binary type on MySQL [#3234 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-05-16 10:30:47 +02:00
Lawrence Pit
0706bdce60 docs + test for each_error
[#3185 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-05-15 11:49:04 -07:00
Jeff Kreeftmeijer
5d7ad7ba41 make sure as is set before trying to build an #{as}_counter. [#2804 state:resolved]
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-05-15 11:18:31 -07:00
Neeraj Singh
22b020db3e db:drop:all throws error when database does not exist [#2997 state:resolved]
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-05-15 10:33:52 -07:00
Jeff Kreeftmeijer
2de364636c partial counters with :as [#2804 state:resolved]
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-05-15 10:32:45 -07:00
Josh Kalderimis
8e7a64d090 backported AR correction to find_each and find_in_batches to raise when the user uses select but does not specify the primary key
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-05-15 09:51:58 +02:00
José Valim
6949d6f54f Remove deprecated tests according to 8e679f1 2010-05-14 23:43:21 +02:00
Santiago Pastorino
c4ef7bb2a0 to_json and to_xml tests added to ActiveResource
[#4529 state:resolved]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-05-12 13:40:09 -07:00
Pratik Naik
7cbc546d39 Use superclass_delegating_accessor for connection handlers 2010-05-12 17:43:02 +01:00
Jeremy Kemper
9ab1154523 Drop require removed by 8e679f1 2010-05-11 22:39:53 -07:00
Santiago Pastorino
ad73a3aec4 type_cast_calculated_value refactor: value is never a Fixnum here. Fix test since SQLite returns Float.
[#4514 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-05-11 22:28:36 -07:00
José Valim
8e679f1854 Remove i18n interpolation deprecation. It has been around since 2.2. 2010-05-11 22:13:03 +02:00
Pratik Naik
3c1bb40b6b Make sure schema dumper doesnt throw up when there are no index lengths 2010-05-09 12:42:15 +01:00
Pratik Naik
77adb4bc20 Revert "Revert "Add index length support for MySQL [#1852 state:resolved]" (breaks the build)"
This reverts commit eababa35cf.
2010-05-09 12:34:07 +01:00
Carl Lerche
eababa35cf Revert "Add index length support for MySQL [#1852 state:resolved]" (breaks the build)
This reverts commit 3616141fa2.
2010-05-08 23:56:06 +03:00
Santiago Pastorino
555801c908 The intention here was to assign to different objects ht: Radar 2010-05-08 23:34:07 +03:00
Emili Parreno
3616141fa2 Add index length support for MySQL [#1852 state:resolved]
Example:

  add_index(:accounts, :name, :name => 'by_name', :length => 10)
  => CREATE INDEX by_name ON accounts(name(10))

  add_index(:accounts, [:name, :surname], :name => 'by_name_surname', :length => {:name => 10, :surname => 15})
  => CREATE INDEX by_name_surname ON accounts(name(10), surname(15))

Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2010-05-08 12:43:34 +01:00
Santiago Pastorino
f967b352d2 Make find_or_create and find_or_initialize work mixing explicit parameters and a hash. ht: Marc-André Lafortune
[#4457 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-05-07 13:29:51 -07:00
Santiago Pastorino
adcfb4e8bd simple_format should return html_safe but not escape text, that's for rails_xss plugin [#3767 state:committed]
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-05-07 11:56:53 -07:00
Brian Lopez
6d1344de5e add support for mysql2 adapter to dbconsole
[#4532 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-05-04 15:47:12 -07:00
Pratik Naik
f194d65f36 Use primary key in conditions, not 'id' [#4395 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>

Conflicts:

	activerecord/test/cases/nested_attributes_test.rb
2010-05-04 22:45:16 +01:00
Jatinder Singh
aeff1719ab AR JSON Serializer now supports custom root option.
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-05-04 13:18:27 -07:00
Brian Lopez
6dbc75fd76 Allow pre-casted values (other than nil) to pass through from calculations un-touched
[#4514 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-05-04 12:27:24 -07:00
Pratik Naik
04fa5af6a6 Use class_inheritable_accessor for connection_handler 2010-05-04 17:52:53 +01:00
Marius Nuennerich
0d767fd24f repair the activesupport message encryptor tests for me, do so in the same way as jeremy did with message verifier
[#4517 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-05-01 10:08:05 -07:00
Neeraj Singh
dcf0f97514 making rake:migrate VERSION=0 a noop called in succession. [#2137 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-04-29 13:32:12 +02:00
Curtis Hawthorne
ce5af2fefe Destroy respects optimistic locking.
Now works with :dependent => :destroy and includes unit tests for that
case.  Also includes better error messages when updating/deleting stale
objects.

[#1966 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-04-27 21:52:22 -07:00
Joe Martinez
aa401bd75a Add ActiveResource::Base.include_root_in_json, like Active Record, to serialize instances as hash of model name -> attributes hash rather than the bare attributes hash. [#2584 state:committed]
Signed-off-by: Santiago Pastorino <santiago@wyeworks.com>
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-04-26 15:19:03 -07:00
Jeremy Kemper
9e262de3d8 Fix backport error: wrong exception name 2010-04-24 19:38:10 -07:00
Jeremy Kemper
8716ee44e5 Fix unstated AS::Multibyte dependency 2010-04-24 17:52:12 -07:00
Cezary Baginski
ec7716abcd actionpack: added missing encoding comments [#4466 state:resolved]
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-04-24 17:30:59 -07:00
Jeremy Kemper
f6e71c674c Expect an incompatible encoding exception when a template with a magic comment renders a partial without one and its source encoding doesn't match the default external encoding 2010-04-24 17:12:05 -07:00
Jeremy Kemper
fb545f4c60 Expect an incompatible encoding exception when a template doesn't have a magic comment and its source encoding doesn't match the default external encoding 2010-04-24 17:12:00 -07:00
Akira Matsuda
4082001331 Fix pattern to match various magic comment formats 2010-04-24 17:05:38 -07:00
Jeremy Kemper
70034d820f Ensure ERB source begins with the encoding comment 2010-04-24 17:04:50 -07:00
Jeremy Kemper
81e06075b7 Ruby 1.9: ERB template encoding using a magic comment at the top of the file 2010-04-24 17:01:52 -07:00
Jeremy Kemper
457a54653d Remove quoted_string_prefix entirely since PostgreSQL was the only database adapter relying on it. 2010-04-24 16:27:34 -07:00
Jeremy Kemper
5c0ad82236 PostgreSQL: remove the unnecessary heuristic checking whether the value is escaped 2010-04-24 15:52:51 -07:00
Jeremy Kemper
c9e15709ae PostgreSQL: use standard-conforming strings if possible 2010-04-24 15:36:31 -07:00
Eugene Pimenov
cec44f5838 PostgreSQL adapter: escape_bytea, quote_string and unescape_bytea aren't thread-safe in Ruby 1.8 [#3237 state:resolved]
Signed-off-by: wycats <wycats@gmail.com>
2010-04-24 13:12:14 -07:00
Sam Elliott and Santiago Pastorino
c401102a27 Is not nessesary to have @_rails_html_safe instance var when the string is unsafe, also it breaks to_yaml [#3535 state:committed] 2010-04-23 09:35:18 +12:00
Santiago Pastorino
d891754535 load tzinfo on initialize only
Signed-off-by: Xavier Noria <fxn@hashref.com>
2010-04-21 09:24:46 -07:00
Santiago Pastorino
49943a7120 TimeZones lazy load
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-04-20 21:40:49 -07:00
Jeremy Kemper
2401af4d6f MemoryStore#read_multi(*keys) for dev-mode compatibility with memcache store 2010-04-19 00:18:20 -07:00
Jeremy Kemper
fd5c6e2c97 Upgrade bundled i18n from 1.3.3 to 1.3.7 2010-04-17 12:38:16 -07:00
Jeremy Kemper
8b79c7c202 Fix 1.9-specific syntax error in test 2010-04-17 12:37:56 -07:00
Mislav Marohnić
4b36dafb35 String#starts/ends_with? should return false for non-string argument, not raise error
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-04-17 00:07:26 -07:00
Mislav Marohnić
8be3e09fcf fix reset_counters to work even with complex class names
e.g. it guesses that a belongs_to association to Namespace::MyModel is
named "my_model", unlike before where it would look up an association
named "namespace::mymodel" and fail.
2010-04-17 03:13:13 +02:00
Mislav Marohnić
ef0591efc2 cleanup update/reset_counters; refactor tests 2010-04-17 03:13:00 +02:00
Jeremy Kemper
c55cdd816c Distinguish test for 1.8.6 compat 2010-04-16 11:35:33 -07:00
Mislav Marohnić
c519215aa8 ruby 1.8.7 compat: starts/ends_with? doesn't cast to string
`starts/ends_with?` methods shouldn't cast argument to string because
ruby 1.8.7 doesn't seem to do that. for example:

    "foobar".ends_with?(:bar)
    # => true in ActiveSupport implementation, false in ruby 1.8.7

[#3199 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-04-16 11:22:50 -07:00
Eugene Pimenov
18ba648e0d Implement find_in_batches without with_scope [#2227 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2010-04-15 01:13:16 +01:00
Xavier Noria
b8b568e53b fix dash -> edit in an example, and a few touches now that we are here 2010-04-14 11:57:36 -07:00
Pratik Naik
5efb1503dd Ensure not to load the entire association when bulk updating existing records using nested attributes 2010-04-14 01:51:43 +01:00
Anil Wadghule
c69dc1afaa Fix for plugin not getting installed on Windows environment [#4320 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-04-12 11:12:42 +02:00
Yaroslav Markin
a84e9b4f31 Fix Array#to_xml to produce valid markup when working with namespaced classes [#3624 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-04-10 18:16:46 +02:00
Vicki Ball
dae247316d made error_message_on work by passing in the object name if there is no object [#3246 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-04-10 14:02:34 +02:00
Jeremy Kemper
2cd29f4297 Only set response etag if body is not blank 2010-04-09 20:19:03 -07:00
Jeremy Kemper
d91d6fe15f CI: show all headers for diagnosis 2010-04-09 20:06:35 -07:00
Jeremy Kemper
efec9b24db Refactor for readability 2010-04-09 19:33:42 -07:00
Jeremy Kemper
56c5290fce CI: message for some outstanding failures 2010-04-09 19:32:47 -07:00
José Valim
4a02437a8d Fix a failure added on 958b0e977a 2010-04-09 22:19:49 +02:00
Santiago Pastorino
958b0e977a fix stack trace lines on class_eval
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-04-09 22:06:51 +02:00
José Valim
f87a518f81 Fix tests broken in 0653a6d30e 2010-04-09 09:23:09 +02:00
Rolf Bjaanes
fcec7402eb Changed the way inflections for uncountables work for 'funky jeans'
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-04-09 09:04:33 +02:00
David Heinemeier Hansson
0653a6d30e Fixed that default locale templates should be used if the current locale template is missing [DHH] 2010-04-08 17:15:11 -07:00
Santiago Pastorino
cfb31edb54 Generate routes for nested resources with nil object raise RoutingError [#4262 state:committed]
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-04-06 21:28:51 -07:00
Simon Effenberg
1d7368200f remove_index now uses quote_table_name() [#4300 state:resolved]
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2010-04-06 14:16:40 +12:00
Kristopher Murata
642d5d297e Parameterize should accept malformed utf8 characters [#4323 state:resolved]
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-04-04 11:57:31 -07:00
Andrew White
e617af13a2 Backport of lazy evaluation of has_many ..., :dependent => :___
[#2627 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-04-04 07:01:38 -07:00
Jeremy Kemper
a72bcdb8ae Check more carefully for vendored tzinfo 2010-04-02 14:39:03 -07:00
Jeremy Kemper
19161e08b3 Adjust test in case tzinfo is not available 2010-04-02 14:05:15 -07:00
Jeremy Kemper
e2ec41a9a6 CI: add tzinfo 2010-04-02 14:01:26 -07:00
Santiago Pastorino
2c148cd96a delegate unknown timezones to TZInfo 2010-04-02 17:45:45 -03:00
Santiago Pastorino
de7925de8a utc_offset is no longer required on TimeZone and if it's not supplied we delegate to TZInfo 2010-04-02 16:53:45 -03:00
Jeremy Kemper
aa48c79ae4 HTML safety: give a deprecation warning if an array of option tags is passed to select tag. Be sure to join the tag yourself and mark them .html_safe 2010-03-31 19:49:29 -07:00
David Heinemeier Hansson
1668ad3baf Added Object#presence that returns the object if it's #present? otherwise returns nil [DHH/Colin Kelley] 2010-03-31 18:27:08 -07:00
Pratik Naik
1f44fc90c6 Dont use Rails 3 finder syntax in Rails 2.3.x test [#4303 state:resolved] 2010-03-31 14:14:56 +01:00
Pratik Naik
0e57c70baf Dont try to load the record from the db if preloading didn't find anything 2010-03-31 12:57:06 +01:00
Xavier Noria
a0454dcd1a avoid method redefined; discarding old empty? warning [Santiago Pastorino] 2010-03-30 17:23:44 -07:00
Santiago Pastorino
e329eab0c9 Don't cache the utc_offset we are already caching the timezone [#4301]
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-03-30 16:36:28 -07:00
Juanjo Bazan
4b08679ba9 New assertion: assert_present
Signed-off-by: Xavier Noria <fxn@hashref.com>
2010-03-30 16:02:40 -07:00
Juanjo Bazan
ccb1beeb5b new assertion: assert_blank
Signed-off-by: Xavier Noria <fxn@hashref.com>
2010-03-30 15:59:09 -07:00
Joseph Wilk
ea6ef768a7 Fixed a bug where create_table could not be called without a block [#2221 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2010-03-30 15:00:44 +13:00
Dudley Flanders
bf563bd904 Trivial doc update on nested attributes delete renaming
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-03-30 01:40:51 +02:00
Joey Aghion
715b34fdff use supplied primary key when eager-loading belongs_to associations rather than default primary key
[#765]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-03-29 15:33:45 -07:00
Ernie Miller
00b95eb265 belongs_to associations now honor :primary_key option for joins
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-03-29 15:33:37 -07:00
Andrew White
03d5d0b5f5 Add the ability to specify table_name_prefix on individual modules
[#4032 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-03-29 08:55:21 -07:00
Santiago Pastorino
bc2af911f9 backport of inconsistency with cattr_reader and matter_reader with some tweaks
Signed-off-by: wycats <wycats@gmail.com>
2010-03-28 14:03:27 -07:00
Santiago Pastorino
0f18904e2b flatten not needed here
Signed-off-by: wycats <wycats@gmail.com>
2010-03-28 14:03:27 -07:00
Santiago Pastorino
cf7ed7cf2d Time marshalling backported [#4286 state:committed]
Signed-off-by: wycats <wycats@gmail.com>
2010-03-28 14:03:07 -07:00
Joe Rafaniello
c1b2200085 Marshaling a time object added an instance variable to the object which affected the quoting of serialized attributes because the to_yaml of the original object did not match the to_yaml of the marshaled one. Also, Marshal.dump was modifying the source object which the client may not be aware of.
Signed-off-by: wycats <wycats@gmail.com>
2010-03-27 04:33:19 -07:00
José Valim
157c1808b9 Added compatibility to Ruby 1.9.2. 2010-03-26 20:21:07 +01:00
Emilio Tagua
ac7b5a23ba Allow deprecation messages with or without a final period.
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-03-25 15:44:16 +01:00
Rodrigo Kochenburger
0022fa309b Set mailer template_root as absolute path [#2263 state:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-03-25 15:36:12 +01:00
Tom Lea
97e07a88fe Fix incorrect relative paths being used when looking up templates.
The bug will manifest itself by failing to locate templates when running tests,
or when running as a daemon (from /).

It relates the the different behavior of ActionView::Template::Path#to_s and
ActionView::Template::Path#to_str when a RAILS_ROOT is defined. #to_s reports
a path relative to the root, and #to_str reports an absolute path.

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-03-25 15:33:05 +01:00
Santiago Pastorino
629afe9f19 ActionView::SafeBuffer should be there for backwards compatibility [#4241 state:committed]
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2010-03-22 14:07:53 +13:00
Bruno Michel
26f2cce232 button_to should generate an html_safe string
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2010-03-22 14:07:42 +13:00
Jeremy Kemper
c0137f62d4 Don't rely on Active Support being loaded here 2010-03-16 19:45:00 -07:00
Jeremy Kemper
f175d19e2a Bundler returns a Pathname from #loaded_from; work around it 2010-03-16 17:55:25 -07:00
Santiago Pastorino
9cfa87519d scope_key_by_partial fix for Ruby 1.9 when there's virtual_path
[#4202 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-03-16 16:05:24 -07:00
Santiago Pastorino
2310aef29b translation method of TranslationHelper module returns always SafeBuffer [#4194 status:resolved]
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-03-16 13:49:59 -07:00
James Golick
27aa22826c Improve performance of multibyte utils.
Switch from using String#match to using String#=~. There's no need to
generate a MatchData for each iteration since we're not using it.

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-03-16 10:04:33 -07:00
Manfred Stienstra
2d3c58068c Improve performance of Multibyte::Utils.
Replace explicit for-loops by faster enumeration methods.

[#3158]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-03-16 10:04:33 -07:00
Santiago Pastorino
374e49b467 Change array entries to safe doesn't worth then the array is joined as a string losing the safe property of his entries
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-03-16 13:14:58 +01:00
Santiago Pastorino
ebf300f41b object_and_class_ext_test warnings removed
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-03-15 19:07:31 -07:00
Jeremy Kemper
b3d32a5b28 to_str works here 2010-03-15 11:19:46 -07:00
Bas Van Klinkenberg
b99914cc3e Fixed a bug in JSON decoding with Yaml backend, where a combination of dates, escaped or unicode encoded data and arrays would make the parser fail with a ParseError exception.
[#2831]

Signed-off-by: Yehuda Katz <wycats@gmail.com>
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-03-14 21:50:22 -07:00
Jeremy Kemper
9b209e8cb8 read_ and write_fragment cache preserve html safety yet cache strings only 2010-03-14 18:55:13 -07:00
Santiago Pastorino
056f957b22 There's a Ruby issue with File.basename different versions returns different things, so we shouldn't test that
[#4174]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-03-14 13:37:30 -07:00
Jeremy Kemper
40c393cb84 Be sure to pass through args to to_yaml 2010-03-11 18:37:36 -08:00
Jeremy Kemper
eed8a8863d Write strings to fragment cache, not outputbuffers 2010-03-11 17:32:26 -08:00
Jeremy Kemper
ec760a57d1 OutputBuffer#to_yaml should return string yaml, not some custom class dump 2010-03-11 17:08:33 -08:00
Sam Ruby
cbc0201a3e Add deprecation warning for overwrite_params and remove rdoc
[#4073 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-03-10 16:26:04 -08:00
Jeremy Kemper
abb8fbde73 Disprefer JSONGem decoder since it only decodes JSON objects 2010-03-09 11:06:31 -08:00
Aaron Patterson
5a806f6759 converting inject to each and map
[#4119 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-03-06 20:32:19 -08:00
Stijn Mathysen
f6f75e84c5 Removed the + sign as an accepted character from the parameterize method, as a + sign is interpreted by the browser as a space, possibly resulting in a "ArgumentError: illegal character in key"
[#4080 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-03-05 14:10:37 -08:00
Santiago Pastorino
d3a8152203 Adds disable option to date_helpers generated hidden fields when html_options specifies it. ht by Marc Schütz
[#3807 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-03-05 13:49:23 -08:00
Jeremy Kemper
3969148a13 Deprecate omitting the leading slash on a path arg to assert_redirected_to 2010-03-02 14:14:37 -08:00
Bryan Helmkamp
1e64cdf8c9 Bump version constants to 2.3.6 to more easily support generating prerelease gems 2010-03-01 18:24:55 -08:00
Jeremy Kemper
f56a1631be Typo: _tasks -> _paths 2010-02-26 08:54:42 -08:00
Jeremy Kemper
f4ce042795 Add *.gem, pkg, and .bundle to .gitignore. Remove globs that should be in user's global ignores. 2010-02-26 08:10:33 -08:00
Jeremy Kemper
ed7322f336 Deprecate toplevel plugins tasks in favor of lib/tasks for Rails 3 forward compat 2010-02-26 08:09:41 -08:00
Tobias Bielohlawek
b06e5dce97 fixed a 'RecordNotFound' bug when calling 'reload' on a object which doesn't met the default_scope conditions, added test [#3166 status:resolved]
The reload method didn't made use of 'with_exclusive_scope' when reloading the object. This lead to a RecordNotFound exception, in case the object doesn't met the default_scope condition (anymore) - which is obviously a bug. This quick fix makes use of with_exclusive_scope in the reload method as well. See test for full example.

Signed-off-by: José Valim <jose.valim@gmail.com>
2010-02-26 11:39:15 +01:00
Jeremy Kemper
5695b1bdd9 Fill in for I18n.normalize_translation_keys removed from 0.3.4 2010-02-25 15:16:49 -08:00
Christoph Schiessl
268c9040d5 remove rubygems (version >= 1.3.6) deprecation message by replacing Gem::Dependency#version_requirements with Gem::Dependency#requirement
[#4026 state:committed]

Signed-off-by: Prem Sichanugrist <s@sikachu.com>
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-02-25 12:53:14 -08:00
Jeremy Kemper
63a7ef0d74 Use Object#singleton_class instead of #metaclass. Prefer Ruby's choice. 2010-02-25 11:11:09 -08:00
Jeremy Kemper
3a3fa7f817 Missed singleton_class 2010-02-25 10:54:36 -08:00
Jeremy Kemper
5b4e7c3fa0 Missing fileutils require 2010-02-24 18:54:49 -08:00
Santiago Pastorino
0307dbaba9 add time_separator for minutes only if minutes aren't hidden
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-02-24 18:41:29 -08:00
Santiago Pastorino
39bcf14b34 missing html_safe added and tests 2010-02-19 15:34:18 -08:00
Santiago Pastorino
24911757de missings html_safe added 2010-02-19 14:36:49 -08:00
Santiago Pastorino
64d28f61ad ruby 1.9 array.to_s returns a string representing an escaped array 2010-02-19 14:04:03 -08:00
Santiago Pastorino
397262a4ee i18n translate with arrays issue solved 2010-02-19 14:03:50 -08:00
Santiago Pastorino and José Ignacio Costa
62c802c622 html_escape mail_to when encode javascript and not hex 2010-02-19 13:40:05 -08:00
Santiago Pastorino and José Ignacio Costa
d7ee4bbcfa Making SafeBuffer << an alias for concat method 2010-02-19 13:37:19 -08:00
Jeremy Kemper
3926107aff Use FileUtils.mv instead of rename to copy in case of cross-device links 2010-02-18 10:48:56 -08:00
Martin Andert
6227ec11f0 Fix error_messages_for i18n issue if object_name has underscores [#3629 status:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-02-17 21:07:05 +01:00
Santiago Pastorino and José Ignacio Costa
4158282e32 simple_format returns a safe buffer escaping unsafe input [Santiago Pastorino] (Closes #3767)
Signed-off-by: David Heinemeier Hansson <david@loudthinking.com>
2010-02-12 17:25:11 -08:00
Gabriel Mansour
6451e864b9 Fix pluralization for numbers formatted like '1.00'
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-02-07 12:15:10 -08:00
Jeremy Kemper
84541c4997 Update CHANGELOG 2010-02-06 20:24:24 -08:00
Jeremy Kemper
6f9f1d3aef Merge remote branch 'mikel/2-3-stable' into 2-3-stable 2010-02-06 20:19:21 -08:00
Mikel Lindsaar
1bf79f19a0 Reindended and handled old ruby syntax 2010-02-07 15:17:03 +11:00
Mikel Lindsaar
16b6d4216f Fixed test to check using 8Bit and verified, removed stray require 2010-02-07 15:16:50 +11:00
Jeremy Kemper
f85ab90e4f Ruby 1.9: cookie header parser works with either newline-delimited strings or arrays 2010-02-06 19:57:06 -08:00
Mikel Lindsaar
4645cd1499 Updating to TMail 1.2.7 2010-02-07 12:26:58 +11:00
Mikel Lindsaar
d53a590594 Fixing TMail encoding problem, porting to ActionMailer 2010-02-07 12:26:03 +11:00
Mikel Lindsaar
9a042baefb Changing test, TMail now encodes this correctly 2010-02-07 12:25:30 +11:00
Mikel Lindsaar
696ec1f979 Changed version of TMail to 1.2.6 2010-02-06 15:00:43 +11:00
Santiago Pastorino and José Ignacio Costa
564ace6a01 Fixed html_safe test cases which weren't testing correctly backport from 3.0
[#3869 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-02-05 13:51:21 -08:00
Santiago Pastorino and José Ignacio Costa
8a0e8f0669 Tests for html_safe! backwards compatibility are restored 2010-02-05 19:06:23 -02:00
Jeremy Kemper
d5b4f4debf Automatically prefer Yajl or JSON backend over Yaml, if available 2010-02-05 12:31:18 -08:00
Brian Lopez
83b4c161fc Add yajl-ruby as a JSON parsing backend
[#2666 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-02-05 12:31:12 -08:00
Santiago Pastorino and José Ignacio Costa
55c1a86ea4 Added backwards compatibility for html_safe! 2010-02-05 18:19:42 -02:00
Santiago Pastorino and José Ignacio Costa
9ca6df83f6 Backport html_safe. Use latest rails_xss plugin for forward-compatibility with Rails 3. 2010-02-05 11:07:56 -08:00
Joshua Peek
0c0da1a6e0 Fix empty Set-Cookie headers [#3811 state:resolved] 2010-02-02 08:53:16 -06:00
Matt Duncan
b362b394f6 Bump year in MIT licenses
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2010-02-02 08:47:10 -06:00
Jeremy Kemper
02e51500d5 Cherry-pick bd74060 from i18n master to fix broken string interpolation 2010-01-28 16:24:58 -08:00
Jatinder Singh
158e7b63ab Use format of ARes rather than content-type of remote errors to load errors.
[#1956 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-01-27 18:27:55 -08:00
Geoff Buesing
3f7729a66e Time#- with a DateTime argument behaves the same as with a Time argument, i.e. returns the difference between self and arg as a Float [#3476 status:resolved] 2010-01-27 20:24:53 -06:00
snusnu
ce50c960c1 active_support/ordered_hash now requires yaml 2010-01-27 18:14:06 -08:00
Gregor Schmidt
57337cd74d Adding custom yaml (de-)serialization for OrderedHash
[#3608 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-01-27 15:30:25 -08:00
Prem Sichanugrist
652bdeb3c3 Update vendored i18n gem to 0.3.3 [#3492 status:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-01-21 09:45:43 +01:00
Prem Sichanugrist
ef10988fdd Fix bug that causes to_utf_offset_s to returns wrong offset when hour < 0 and not in hundreds [#3741 status:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-01-19 20:35:09 +01:00
Prem Sichanugrist
6012e575bb Make local_request? to returns true when facing ::1 IPv6 address [#3257 status:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-01-18 08:29:53 +01:00
José Valim
c50609c9f0 Merge remote branch 'eloy/2-3-stable' into 2-3-stable 2010-01-09 00:25:14 +01:00
David Heinemeier Hansson
94de32b6eb Merge branch '2-3-stable' of github.com:rails/rails into 2-3-stable 2010-01-08 13:46:02 -08:00
David Heinemeier Hansson
4682035381 Fixed that PrototypeHelper#update_page should return html_safe [DHH] 2010-01-08 13:45:51 -08:00
Jeffrey Hardy
6e9b01fddb Allow AR::Schema's migrations_path to be overwritten by subclasses. Defaults to 'db/migrate'
[#3671 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-01-08 13:09:50 -08:00
Eloy Duran
51e6124e6a Renamed AssociationReflection #collection_association? to #collection?. 2010-01-08 21:44:06 +01:00
Eloy Duran
c9a3929a75 Rollback the transaction when one of the autosave associations fails to save. [#3391 state:resolved] 2010-01-08 21:36:27 +01:00
Lawrence Pit
eb22c248de Exclude unchanged records from the collection being considered for autosave. [#2578 state:resolved]
Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
2010-01-08 21:36:27 +01:00
Bryan Stearns
2aef092625 Add failing test that triggers the stack overflow for #2578.
Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
2010-01-08 21:36:26 +01:00
David Heinemeier Hansson
d5ba7c3ea4 Fixed that much of DateHelper wouldn't return html_safe? strings [DHH] 2010-01-08 11:48:38 -08:00
David Heinemeier Hansson
45e192d05c Fixed that fragment caching should return a cache hit as html_safe (or it would all just get escaped) [DHH] 2010-01-07 17:39:32 -08:00
Eloy Duran
0dbe0f670e Raise a RecordNotFound if an ID in nested attributes is given but doesn't return a record. [#2415 state:resolved] 2010-01-07 13:20:43 +01:00
Eloy Duran
6d056c7175 Moved the validation logic to the association reflection and refactored autosave_association.rb a bit. 2010-01-07 13:20:43 +01:00
Eloy Duran
b3bd101796 Remove deprecated '_delete' option from NestedAttributes. 2010-01-07 13:20:42 +01:00
Eloy Duran
3d17d79bbf Removed unnecessary call to #try and cleaned up a bit more. 2010-01-07 13:20:42 +01:00
Eloy Duran
4b7a439bd1 Don't use strings for callbacks, as these will be evaled. Rather use symbols, which uses a direct method dispatch.
Patch by Comron Sattari. [#3429 state:resolved]
2010-01-07 13:20:42 +01:00
Eloy Duran
c48a71c7e4 Cleanup some code in nested_attributes.rb, autosave_association.rb, and associations.rb with AssociationReflection#collection_association?
Also cache the result value.
2010-01-07 13:20:42 +01:00
Eloy Duran
f12dd62d47 Add AssociationReflection#collection_association? which returns true if it's for a has_many or has_and_belongs_to_many association. 2010-01-07 13:20:42 +01:00
Eloy Duran
e20ac99026 Refactored nested attributes a bit after last commit. 2010-01-07 13:20:42 +01:00
Mike Breen
69db137f89 Allows you to pass :all_blank to :reject_if option to automatically create a Proc that will reject any record with blank attributes.
[#2501 state:resolved]

Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
2010-01-07 13:20:41 +01:00
José Valim
b7fd42626a Use helpers.label instead of views.labels. 2010-01-07 02:28:10 +01:00
José Valim
319e4aa263 Make ActionPack specs work when I18n 0.3.3 is installed as gem. 2010-01-05 00:27:50 +01:00
Hongli Lai (Phusion)
1012dec88f The failsafe middleware should flush the logger upon logging the error, otherwise nothing will be written to the log file.
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2010-01-05 10:39:42 +13:00
Zach Brock
f32c96eb76 fixing autolinking other protocols
Signed-off-by: Michael Koziarski <michael@koziarski.com>
[#3494 state:committed]
2010-01-05 10:39:12 +13:00
Stefan Penner
c362a76d00 Fixed multiparameter attribute assignment bug RE: Ticket 3131
http://rails.lighthouseapp.com/projects/8994/tickets/3131-multiparamter_attribute-assignment-fails-when-used-via-assoication
2010-01-02 23:48:09 -08:00
Stefan Penner
b3dd14adbe Failing test case RE: Ticket 3131
http://rails.lighthouseapp.com/projects/8994/tickets/3131-multiparamter_attribute-assignment-fails-when-used-via-assoication
2010-01-02 23:48:08 -08:00
Carsten Gehling
f5714abc3d I18n label helper [#745 status:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2010-01-02 23:38:01 +01:00
Willem van Bergen
37c51594b9 Added two SAX-based backends for XmlMini, using both LibXML and Nokogiri.
[#3636]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-01-01 13:18:43 -08:00
Willem van Bergen
12f6fd0f26 Bugfixes, speed improvements and code cleanup for Nokogiri's and LibXML's XmlMini backend
[#3641]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2010-01-01 13:17:02 -08:00
Jeremy Kemper
54bc4852ea Fix pg test 2009-12-28 13:05:44 -08:00
Eloy Duran
90f001ba39 Refactored previous changes to nested attributes. 2009-12-28 21:08:20 +01:00
Michael Siebert
7074c5a629 Add an :update_only option to accepts_nested_attributes_for for to-one associations. [#2563 state:resolved]
Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
2009-12-28 19:02:01 +01:00
Eloy Duran
146a750568 Make sure to not add autosave callbacks multiple times. [#3575 state:resolved]
This makes sure that, in a HABTM association, only one join record is craeted.
2009-12-28 16:46:48 +01:00
Murray Steele
3470b306bb Make polymorphic_inverse_of in Reflection throw an InverseOfAssociationNotFoundError if the supplied class doesn't have the appropriate association. [#3520 state:resolved]
Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
2009-12-28 14:21:42 +01:00
Murray Steele
603b28c84c Provide a slightly more robust we_can_set_the_inverse_on_this? method for polymorphic belongs_to associations. [#3520 state:resolved]
Also add a new test for polymorphic belongs_to that test direct accessor assignment, not just .replace assignment.

Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
2009-12-28 14:21:18 +01:00
George Ogata
cca75ca23f Add inverse polymorphic association support. [#3520 state:resolved]
Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
2009-12-28 14:20:58 +01:00
Murray Steele
592085be83 Add more tests for the various ways we can assign objects to associations. [#3513 state:resolved]
Get rid of a duplicate set_inverse_instance call if you use new_record(true) (e.g. you want to replace the existing instance).

Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
2009-12-28 14:20:33 +01:00
George Ogata
ed5b89483a Set inverse for #replace on a has_one association. [#3513 state:resolved]
Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
2009-12-28 14:18:46 +01:00
Frederick Cheung
ab09ffd41e honour :inverse_of for joins based include
Signed-off-by: Michael Koziarski <michael@koziarski.com>
Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
2009-12-28 13:32:04 +01:00
Frederick Cheung
894c9b112c honour inverse_of when preloading associations
Signed-off-by: Michael Koziarski <michael@koziarski.com>
Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
2009-12-28 13:31:29 +01:00
David Heinemeier Hansson
1684aa113e Fix tests 2009-12-27 15:23:51 -08:00
David Heinemeier Hansson
2675e4ef83 Translated strings in the view are assumed html_safe (Closes #3401) 2009-12-24 20:33:25 -08:00
Dwayne Litzenberger
a900205676 Fix ActiveSupport::JSON encoding of control characters [\x00-\x1f]
According to RFC 4627, only the following Unicode code points are
allowed unescaped in JSON:

  unescaped = %x20-21 / %x23-5B / %x5D-10FFFF

However, ActiveSupport::JSON did not escape the range %x00-1f.  This caused
parse errors when trying to decode the resulting output.

[#3345 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-12-23 11:46:25 -08:00
Murray Steele
5374fb3cad Providing support for :inverse_of as an option to associations.
You can now add an :inverse_of option to has_one, has_many and belongs_to associations.  This is best described with an example:

class Man < ActiveRecord::Base
  has_one :face, :inverse_of => :man
end

class Face < ActiveRecord::Base
  belongs_to :man, :inverse_of => :face
end

m = Man.first
f = m.face

Without :inverse_of m and f.man would be different instances of the same object (f.man being pulled from the database again).  With these new :inverse_of options m and f.man are the same in memory instance.

Currently :inverse_of supports has_one and has_many (but not the :through variants) associations.  It also supplies inverse support for belongs_to associations where the inverse is a has_one and it's not a polymorphic.

Signed-off-by: Murray Steele <muz@h-lame.com>
Signed-off-by: Michael Koziarski <michael@koziarski.com>
Signed-off-by: José Valim <jose.valim@gmail.com>
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>

Conflicts:

	activerecord/lib/active_record/associations/belongs_to_association.rb
	activerecord/lib/active_record/associations/has_one_association.rb
2009-12-21 13:13:32 -08:00
David Heinemeier Hansson
8bb3b9bcff Models with no attributes should just have empty hash fixtures [Sam] (Closes #3563) 2009-12-17 17:53:33 -08:00
David Heinemeier Hansson
e6cadd422b Added :alert, :notice, and :flash as options to ActionController::Base#redirect_to that'll automatically set the proper flash before the redirection [DHH] Added ActionController::Base#notice/= and ActionController::Base#alert/= as a convenience accessors in both the controller and the view for flash[:notice]/= and flash[:alert]/= [DHH] 2009-12-17 11:34:47 -08:00
David Heinemeier Hansson
48cd7dfcf8 Fix the app generator of cookie_verification_secret.rb 2009-12-16 14:06:20 -08:00
José Valim
1c3711b21b Fix another regression due to the inclusion of ActiveRecord::Error.
If a string is supplied to :default, it should not be used a
translation key (we already have :message for that).
[#3564 status:resolved]

Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-12-16 14:18:46 -06:00
Will
b1bbf90dff When passing force_reload = true to an association, don't use the query cache [#1827 state:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-12-16 10:49:40 -06:00
David Heinemeier Hansson
1229ef7bf3 Accessing nonexistant cookies through the signed jar should not raise an exception 2009-12-15 21:27:38 -08:00
David Heinemeier Hansson
6d1494cec6 Its cookie_verifier_secret 2009-12-15 21:03:57 -08:00
David Heinemeier Hansson
0200e20f14 Added cookies.permanent, cookies.signed, and cookies.permanent.signed accessor for common cookie actions [DHH] 2009-12-15 20:01:48 -08:00
Geoff Buesing
e4ebaab1cb Add test for TimeWithZone#to_i with wrapped DateTime 2009-12-15 08:41:57 -06:00
Serguei Filimonov
754bbaaf37 Added #to_i to DateTime in ActiveSupport so #to_yaml works correctly on ActiveRecord models with DateTime attributes. 2009-12-15 08:34:02 -06:00
David Heinemeier Hansson
f039bbb13e Dont be an ass and leave merge shit in stable, please 2009-12-14 18:07:37 -08:00
David Heinemeier Hansson
fda3ac6e68 Add Enumerable#exclude? to bring parity to Enumerable#include? and avoid if !x.include?/else calls [DHH] 2009-12-14 18:01:47 -08:00
John Pignata
1d9468b44e Fix postgresql AR test failure
Due to the ordering of the returning result set, the test fails under the postgresql adapter. Order results by id prior to checking the first item

[#3542 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-12-11 15:15:37 -06:00
Jeremy Kemper
b9f352316e Ruby 1.9.2: exclude to_str from explicit coercion check too 2009-12-06 16:54:53 -08:00
Jeremy Kemper
64082b350c Ruby 1.9.2: explicitly raise NoMethodError for attempts at explicit coercion 2009-12-06 16:46:01 -08:00
Jeremy Kemper
b92ff78df6 Ruby 1.9: don't rely on . in load path 2009-12-06 15:34:13 -08:00
Gabe da Silveira
43d2cb8e93 Replace reset_counter_cache with reset_counters that has API inline with existing update_counters method
[#1211 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-12-03 23:25:41 -08:00
Ben Marini
ccb197b2e6 Add support for Mysql column positioning via #add_column and #change_column
add_column and change_column in the Mysql adapter now accept some
additional options:
:first => true        # Put the column in front of all the columns
:after => column_name # Put the colmn after 'column_name'

add_column :new_col, :string, :first => true
add_column :another_col, :integer, :default => 0, :after => :new_col

[#3286 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-12-03 23:10:35 -08:00
Michael Koziarski
c253d7b2db 1.9 Fix for exception views. 2009-12-03 10:27:11 +13:00
Mat Brown
2f1ded3067 Fix instance_eval calls to association proxies
In the current stable, ActiveRecord::Associations::AssociationProxy#method_missing calls yield() if a block is given, causing the block to always be evaluated in its calling context. However, in the case of instance_eval, correct behavior requires that the block be passed directly to the @target, rather than being evaluated inside a different block. Incidentally, this also simplifies the code slightly.

[#3412 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-12-02 12:46:36 -08:00
Mike Breen
1db3a27961 Implement ActiveRecord#reset_counter_cache
[#1211 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-12-02 12:08:57 -08:00
Joey A
da61a6c967 avoid generating invalid SMTP commands in ruby pre 1.9
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-11-28 13:26:29 +13:00
Gabe da Silveira
bfe0328580 Make sure strip_tags removes tags which start with a non-printable character
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-11-27 10:04:22 +13:00
Eric Chapweske
3719bd3e95 Decode http_authentication creditentials without generating abitrary symbols. 2009-11-27 09:57:10 +13:00
Michael Koziarski
c7057a213d Remove strange .diff file 2009-11-25 18:56:30 +13:00
Michael Koziarski
ec542caf58 Prepare for the 2.3.5 release 2009-11-25 18:56:12 +13:00
David Heinemeier Hansson
27b935dec6 Merge branch '2-3-stable' of github.com:rails/rails into 2-3-stable 2009-11-23 15:35:42 -06:00
David Heinemeier Hansson
d796fc638f Fixed that the debugger wouldn't go into IRB mode because of left-over ARGVs [DHH] 2009-11-23 15:35:25 -06:00
Joshua Peek
0f0f977625 Revert "Prefix Internet Explorer's accepted mime types with sensible defaults."
IE XHR requests are misinterpreted as HTML instead of JS.

This reverts commit c680f2372e.
2009-11-23 11:19:39 -06:00
Jeremy Kemper
0bc150c884 Rails 3: move core_ext/blank to core_ext/object/blank for forward compatibility 2009-11-22 14:50:12 -08:00
Michael Koziarski
93085a7d6c Handle a nil logger when generating Deprecation warnings 2009-11-19 14:22:36 +13:00
Jeremy Kemper
a942d66597 Extract form_authenticity_param instance method so it's overridable in subclasses 2009-11-17 23:36:48 -08:00
Gabe da Silveira
df0720b8b7 Insert generated association members in the same order they are specified when assigning to a has_many :through using the generated *_ids method
[#3491 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-11-17 22:24:53 -08:00
Jeremy Kemper
ed320cd896 Revert "Ensure Model#destroy respects optimistic locking"
Unresolved issues with :dependent => :destroy and counter caching.

[#1966 state:open]

This reverts commit 0d922885fb.
2009-11-17 15:31:02 -08:00
Will Read
88d2e4ca6f Allow explicit placement of hidden id element for nested models.
[#3259 state:resolved]

Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
2009-11-15 21:50:35 +01:00
Jeremy Kemper
6da0365383 Loosen i18n gem deps from ~> to >= 2009-11-14 03:33:12 -08:00
Jeremy Kemper
78f5ecf02f CI: test AR + sqlite 2 on 1.8 only 2009-11-13 23:32:32 -08:00
Jeremy Kemper
6950f0cef2 Typo 2009-11-13 19:40:59 -08:00
Jeremy Kemper
4c3477ce77 Ruby 1.9: skip fcgi handler tests 2009-11-13 19:27:01 -08:00
Jeremy Kemper
4ffe2e171a CI: upgrade mysql, mocha, sqlite3-ruby 2009-11-13 18:44:07 -08:00
Jeremy Kemper
90f3272f1d Remove weird zombie test 2009-11-13 18:16:11 -08:00
Jeremy Kemper
c27cb5e1d4 Ruby 1.9: remove dep on T::U::AssertionFailedError 2009-11-13 18:05:14 -08:00
Jeremy Kemper
9abab5ba02 Test railties earlier rather than having to wait through AR 2009-11-13 13:15:03 -08:00
Jeremy Kemper
61bb491cbe Ruby 1.9.2: use super rather than raise our own NoMethodError to work around to_ary issues 2009-11-13 13:03:10 -08:00
Jeremy Kemper
3fa8ca5845 Ruby 1.9.2: StringIO no longer has #path 2009-11-13 13:02:29 -08:00
Jeremy Kemper
2d67ef9416 Ruby 1.9.2: prefer Array.wrap to [foo].flatten 2009-11-13 12:59:16 -08:00
Jeremy Kemper
f62a8831fe test-unit 2: filter_backtrace is private 2009-11-13 12:47:07 -08:00
Jeremy Kemper
3a3dfe4996 Ruby 1.9.2: fix broken to_ary expectation 2009-11-13 12:42:40 -08:00
Jeremy Kemper
de0384008c Ruby 1.9.2: disallow explicit coercion via method_missing. Only give friendly nil errors for Array and Active Record methods. 2009-11-13 12:28:37 -08:00
David Vrensk
4bc58a215f Rdoc for changes introduced in 6339e5d36, 542d6a0abd.
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-11-12 11:20:34 -08:00
José Valim
a4540128a4 [PATCH] Optimize Error I18n to avoid unecessary lookups and just retrieve values when needed [#3477 status:resolved].
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-11-10 12:26:33 -06:00
Matt Jones
6c0028d5cc delete correct records for a has_many with :primary_key and :dependent => :delete_all
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-11-10 18:07:04 +13:00
Bryan Helmkamp
22e1f4b307 Silence warning: instance variable @selected not initialized 2009-11-09 17:24:18 -05:00
Bryan Helmkamp
b45d44cff0 Silence warning: ambiguous first argument; put parentheses or even spaces 2009-11-09 17:24:13 -05:00
Bryan Helmkamp
40f0ef7a37 Silence warning: instance variable @segment not initialized 2009-11-09 17:24:09 -05:00
Bryan Helmkamp
ea345a540f Silence warning: instance variable @integration_session not initialized 2009-11-09 17:24:03 -05:00
Bryan Helmkamp
ae5e2f5919 Silence warning: instance variable @auto_index not initialized 2009-11-09 17:23:59 -05:00
Bryan Helmkamp
8073e47262 Silence warning: instance variable @explicit_view_paths not initialized 2009-11-09 17:23:55 -05:00
Bryan Helmkamp
a0d28dcfd4 Silence warning: instance variable @real_format not initialized 2009-11-09 17:23:50 -05:00
Bryan Helmkamp
17fda24523 Silence warning: instance variable @controller not initialized 2009-11-09 17:23:37 -05:00
Bryan Helmkamp
a3ab2b0ee1 Silence warning: instance variable @session not initialized 2009-11-09 17:23:30 -05:00
Jeremy Kemper
bfb931b865 Bump CI rack to 1.0.1 2009-11-09 12:43:10 -08:00
Jeremy Kemper
97a7cdca17 Merge commit 'brynary/2-3-stable' into 2-3-stable 2009-11-09 12:26:21 -08:00
Bryan Helmkamp
b68861a00f Silence warning: method redefined; discarding old template 2009-11-09 15:15:09 -05:00
Bryan Helmkamp
2ccd4e790e Silence warning: method redefined; discarding old filename 2009-11-09 15:14:18 -05:00
Bryan Helmkamp
8820bb7eff Silence warning: discarding old h 2009-11-09 15:12:33 -05:00
Jeremy Kemper
fd0289f3dd Bump Rack to 1.0.1. Ensure integration test input is ASCII. 2009-11-09 11:21:12 -08:00
Jeremy Kemper
a3e129f79b Shush 2009-11-09 10:36:31 -08:00
Jeremy Kemper
d81c606fba Work around Float faux precision 2009-11-09 10:34:16 -08:00
Jeremy Kemper
9ea850027c Ruby 1.9 doesn't recognize EM SPACE as whitespace, breaking String#strip 2009-11-09 10:26:28 -08:00
Bryan Helmkamp
d988507dca Fix Ruby warning: method redefined; discarding old breakpoint 2009-11-09 12:57:04 -05:00
Bryan Helmkamp
6fdd60e65c Fix Ruby warning: instance variable @loaded not initialized 2009-11-09 12:57:04 -05:00
Bryan Helmkamp
1a93e93d1b Fix some Ruby warnings: `*' interpreted as argument prefix 2009-11-09 12:57:04 -05:00
Chris Hapgood
d36f8a2bf2 Share ActionView::TestCase's output_buffer with view for concat support.
[#3467 state:resolved]

Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
2009-11-07 00:15:11 +01:00
Chris Hapgood
df9a47e4b8 Make some assertions in the ActionView::TestCase tests actually do something.
[#3468 state:resolved]

Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
2009-11-06 23:59:45 +01:00
Eloy Duran
6b2291f330 Define autosave association callbacks when using accepts_nested_attributes_for.
This way we don't define all the validation methods for all associations by
default, but only when needed.

[#3355 state:resolved]
2009-11-06 23:53:33 +01:00
Chris Hapgood
c3ef028b81 Fix OrderedHash#replace
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-11-05 21:16:06 +13:00
Matias Flores
4ae03b2d5a Fix chars.reverse for multibyte decomposed strings
[#597 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-11-02 17:59:40 -08:00
José Valim
7ba80252a5 Make polymorphic_url work with symbols again and refactor it [#1384 status:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-10-28 14:15:16 -05:00
José Valim
f5f7c40f3a Fix nested attributes error messages which is broken in 2.3.4. It still copies the message from child to parent, but does the lookup in the child, not in the parent, avoiding error messages duplication (as happened in 2.3.3). [#3147 state:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-10-28 13:44:24 -05:00
Yehuda Katz
fdf356d74b Fixed HTTP digest to properly return 401 when the Authorization header has no nonce specified, or the Authorization header specifies Basic auth [#2968 state:resolved] 2009-10-21 12:04:59 -07:00
Mike Gunderloy
9edfdef2a7 Fix bad assumption in BacktraceCleaner test [#3249 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-10-18 17:23:28 -02:00
Travis Briggs
eb30c69544 Ensure number_to_human_size does not strip zeros from the end [#1763 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-10-17 13:37:46 +13:00
Michael Koziarski
459749c30c Backport the xss_safe? method for plugin authors targetting 2.3 and master 2009-10-15 17:19:24 +13:00
George Ogata
e10b0ddc7b Make IntegrationTest::Runner propagate method_missing to ancestors.
Fixes RSpec integration example groups, which mixes its Matchers
module into ActiveSupport::TestCase.

Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-10-15 11:02:02 +13:00
Jeffrey Hardy
bbaf3a04f5 CookieJar#delete should return the key's value, consistent with a Hash
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-10-14 11:51:11 -07:00
Jeremy Kemper
7454d1874c Mark html safety 2009-10-09 18:37:38 -07:00
Pratik Naik
c23706b787 Add a :limit option to specify the maximum number of records that can be processed by accepts_nested_attributes_for
Conflicts:

	activerecord/lib/active_record/nested_attributes.rb
2009-10-09 16:11:22 +01:00
Pratik Naik
4010b49de8 Store entire options hash in the class var rather than just the reject_if proc for the nested attributes
Conflicts:

	activerecord/lib/active_record/nested_attributes.rb
	activerecord/test/cases/nested_attributes_test.rb
2009-10-09 15:47:31 +01:00
Pratik Naik
c47c5af1c8 Mute log info coming from the local_cache strategy 2009-10-09 15:12:01 +01:00
Pratik Naik
48b30608a4 Ensure MessageVerifier raises appropriate exception on tampered data 2009-10-09 02:26:37 +01:00
Michael Koziarski
95b7e4f7d7 field_error_proc needs to return a safe string 2009-10-08 14:02:12 +13:00
Michael Koziarski
80da8eb43d Merge the prerequisites for on-by-default XSS escaping into rails.
This consists of:

* String#html_safe! a method to mark a string as 'safe'
* ActionView::SafeBuffer a string subclass which escapes anything unsafe which is concatenated to it
* Calls to String#html_safe! throughout the rails helpers
* a 'raw' helper which lets you concatenate trusted HTML from non-safety-aware sources (e.g. presantized strings in the DB)

Note, this does *not* give you on-by-default XSS escaping in 2.3 applications.  To get that you'll need to install a plugin:

http://github.com/nzkoz/rails_xss
2009-10-08 13:59:21 +13:00
Pratik Naik
a69316b293 Use indifferent access attributes instead of stringifying them 2009-10-08 00:14:52 +01:00
Pratik Naik
e2127991a1 Allow accepts_nested_attributes_for :reject_if option accept symbols for using a method 2009-10-07 23:45:40 +01:00
pivotal
6f2c4991ef Explicitly require ActionController's CGI extensions so they're properly loaded before the first request.
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-10-08 09:56:23 +13:00
Bryan Helmkamp
0f14d7b6d3 Only load rake tasks from tasks/**/*.rake and lib/tasks/**/*.rake in plugins
Previously, it was **/tasks/**/*.rake, and that loaded some paths that shouldn't be like:

  * vendor/plugins/admin_assistant/test_rails_app/lib/tasks/rspec.rake
  * vendor/plugins/will_paginate/test/tasks.rake

Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-10-08 09:53:33 +13:00
Jesse Proudman
58f14438a9 Running rake dev leaves ERB in environment.rb. The existing Rake task was just copying the file across. This patch modifies the Rake task to use the same ERB processing string used on database.yml, which cleans up the environment.rb file.
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-10-07 08:44:59 +13:00
Pratik Naik
91b61a8d16 Monkey patch Rack::Lint to allow string subclass body 2009-10-06 15:55:56 +01:00
Jeffrey Hardy
f98302e46b MessageVerifier#verify raises InvalidSignature if the signature is blank
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-10-05 13:39:10 -07:00
Joshua Peek
11cce5bde9 Coerce all out going body parts to Strings 2009-10-05 14:21:57 -05:00
Bryan Helmkamp
1d7412b135 Reduce specificity of logging test to avoid dependency on the system clock
Signed-off-by: Yehuda Katz <wycats@gmail.com>
2009-09-29 17:10:01 -07:00
Chad Woolley
1901747001 reduce max size of fixture IDs to fix sqlite2 tests, because sqlite2 was getting negative and changing values for ID field. See http://www.sqlite.org/datatypes.html
Signed-off-by: Yehuda Katz <wycats@gmail.com>
2009-09-29 02:53:45 -07:00
Chad Woolley
f95a7f896e make mysql and postgresql rebuild databases on every CI build, to prevent breakages such as collation and character set changing
Signed-off-by: Yehuda Katz <wycats@gmail.com>
2009-09-27 21:57:41 -07:00
Yehuda Katz
26f22a28e9 Merge branch '2-3-stable' of git@github.com:rails/rails into 2-3-stable 2009-09-27 21:57:30 -07:00
John Trupiano
f489b3341c Introduce :almost keyword for distance_of_time_in_words. Make 1.75 days - 2 days return '2 days'.
Signed-off-by: Michael Koziarski <michael@koziarski.com>
[#3266 state:committed]
2009-09-28 14:56:19 +13:00
Jay Pignata
b372b4c875 Enhancing distance_of_time_in_words to prefix year output with over and about depending upon how many months have elapsed
Signed-off-by: Michael Koziarski <michael@koziarski.com>
[#3106 state:committed]
2009-09-28 14:56:14 +13:00
Luciano G Panaro
14a6794a8e Make has_one with :conditions hash scope build or creation of the associated object with those conditions
Signed-off-by: Michael Koziarski <michael@koziarski.com>
[#3088 state:committed]
2009-09-28 14:51:14 +13:00
Gaspard Bucher
8371d6f0c1 Fixes a bug where layouts provided with an absolute path would not be found because they were prefixed by 'layouts'. This bug only appears if the path does not contain the word 'layouts'.
Signed-off-by: Michael Koziarski <michael@koziarski.com>
[#3207 state:committed]
2009-09-28 14:40:21 +13:00
Chad Woolley
4a11ca1c7e include nokogiri gem, so activesupport nokogiri tests run
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-09-26 12:23:18 -05:00
Eloy Duran
b18248ff05 The DomAssertions now also strip surrounding whitespace inside tags. 2009-09-25 17:46:21 +02:00
Eloy Duran
deac481eb7 Made assert_dom_equal and assert_dom_not_equal ignore meaningless whitespace.
Also changed message of assert_dom_equal to be like assert_equal.
2009-09-25 17:05:30 +02:00
Eloy Duran
cddd4746f9 Rewrote ActionView::TestCase.
The test case now mimicks the template environment more closely, so it's
possible to use render, load helper dependencies.

This also fixes assert_select, and similar assertions. Because view tests
and helpers generally don't render full templates assert_select looks
first in rendered and then in output_buffer to find the rendered output.
2009-09-25 15:51:27 +02:00
Manfred Stienstra
c680f2372e Prefix Internet Explorer's accepted mime types with sensible defaults. 2009-09-25 15:47:33 +02:00
Michael Gunderloy
6222ac1a91 Fix variable error in Nokogiri XmlMini code [#3242 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-09-22 00:23:59 +01:00
Aaron Patterson
e18752868a making nokogiri to hash less clever, more fast O_o
[#2243 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-09-17 11:53:09 -07:00
Jeremy Kemper
1488c6cc9e Fix brittle content-type check. [#1956 state:committed] 2009-09-17 11:39:59 -07:00
Justin Bailey
4f5cac53b7 Enable use of MySQL stored procedures by default.
[#3204 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-09-17 10:59:41 -07:00
Developer
179b4512d1 Allow Nokogiri XmlMini backend to process cdata elements
[#3219 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-09-17 10:30:08 -07:00
Jeremy Kemper
ff0377dea5 Fix failing dependencies test relying on . being in LOAD_PATH 2009-09-13 05:44:16 -07:00
Jeremy Kemper
f503a483d4 Extract repetitive method 2009-09-13 05:44:09 -07:00
Jeremy Kemper
abd7bd311a Clean up spurious JSON decoding test failure 2009-09-13 05:43:10 -07:00
Jeremy Kemper
09b197f957 Ruby 1.9 compat: fix regexp slice test 2009-09-13 05:30:59 -07:00
Jeremy Kemper
c6fe042b29 Ruby 1.9: fix Time#beginning_of_day inaccuracy due to subtracting a Float 2009-09-13 05:07:21 -07:00
Jeremy Kemper
8dca666ba1 Silence warning for Encoding.default_external= 2009-09-13 04:49:08 -07:00
Jeremy Kemper
477dfa4c79 Use Encoding.default_external, not _internal 2009-09-13 04:49:02 -07:00
sdsykes
8afeec20e0 Ruby 1.9 compat: corrected instance_methods check
[#3156 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-09-13 02:58:36 -07:00
Michael Koziarski
6ddb7de407 Dup the arguments to string compare so we can use force_encoding.
Conflicts:

	activesupport/lib/active_support/message_verifier.rb
2009-09-13 10:37:41 +12:00
Eloy Duran
2524ac84e6 Removed some superfluous conditionals from the autosave association validation methods.
Which are unneeded now that we only define them when needed.
2009-09-12 15:03:05 +02:00
Alexey Kovyrin
c0245493cb Define autosave association validation methods only when needed. [#3161 state:resolved]
Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
2009-09-12 14:55:34 +02:00
Eloy Duran
9290051b85 Added some documentation about setting :autosave => false on an association. 2009-09-12 13:43:17 +02:00
Eloy Duran
c665faac09 During autosave, ignore records that already have been destroyed. [#2537 state:resolved] 2009-09-12 13:43:17 +02:00
Graeme Porteous
a070873771 Fix has_one with foreign_key and primary_key association bug which caused the associated object being lost when saving the owner. [#1756 state:resolved]
Mixed in a bit from patch by ransom-briggs. [#2813 state:resolved]

Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
2009-09-12 13:43:16 +02:00
José Valim
11c338735c Rename nested attributes _delete to _destroy to reflect its actual behavior and DSL (:allow_destroy). Deprecation warning added. [#2889 state:resolved]
Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
2009-09-12 13:36:42 +02:00
Dmitry Polushkin
c52a50ec51 Fix autosave association to skip validation if it is marked for destruction. [#2064 state:resolved]
Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
2009-09-12 13:36:42 +02:00
Eloy Duran
2420d6272c Explicitely setting `autosave => false' should override new_record autosaving. [#2214 state:resolved]
Original author is Jacob.
2009-09-12 13:23:05 +02:00
Andrew France
55bc0c76f8 Allow fields_for on a nested_attributes association to accept an explicit collection to be used. [#2648 state:resolved]
Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
2009-09-12 13:16:30 +02:00
Lance Ivy
7c1e4ef64b Don't cascade autosave validation to destroyed children. [#2761 state:resolved]
Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
2009-09-12 13:16:30 +02:00
Mike Breen
52a50db6c0 Raise an exception with friendlier error message when attempting to build a polymorphic belongs_to with accepts_nested_attributes_for. [#2318 state:resolved]
Signed-off-by: Eloy Duran <eloy.de.enige@gmail.com>
2009-09-12 13:16:30 +02:00
sdsykes
d48d3d0f41 Fix habtm associations when using multiple databases
[#3128]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-09-12 02:55:33 -07:00
Jeremy Kemper
3f59a73cb6 activesupport -> active_support 2009-09-12 02:47:25 -07:00
Jeremy Kemper
08d15f86c4 Deprecate "Allow frameworks to be required by their gem name"
This has just been confusing. Better to educate than band-aid.

This deprecates commit 18a24274ec.
Originally from http://dev.rubyonrails.org/ticket/8845 [drnic]
2009-09-12 02:45:33 -07:00
Akira Matsuda
c5e3309bb4 Ruby 1.9 compat: Avoid using the return value of FileUtils.mkdir_p, as it does not return a String but an Array in Ruby 1.9
[#2018 state:committed milestone:2.3.5]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-09-11 19:21:31 -07:00
Akira Matsuda
44fbc86ab8 Ensure validation errors to be ordered in declared order
[#2301 state:committed milestone:2.3.5]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-09-11 18:37:32 -07:00
Akira Matsuda
596406f90a Fix default_error_messages back to the original message
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-09-11 18:31:28 -07:00
Akira Matsuda
3413643e83 1.9 compat: let -c option work with Ruby 1.9
[#3109 state:committed milestone:2.3.5]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-09-11 18:06:51 -07:00
Akira Matsuda
028d449fe9 1.9 compat: let -g option work with Ruby 1.9
[#3105 state:committed milestone:2.3.5]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-09-11 18:06:51 -07:00
Jakub Kuźma
5de75398c4 ruby 1.9 friendly secure_compare
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-09-12 12:47:53 +12:00
Shugo Maeda
d2cf33e903 Removed the copyright notice not to show it in the result of 'ri ActiveRecord'. 2009-09-11 15:18:08 -07:00
Nathaniel Talbott
ab9efe9e16 Fix filtering parameters when there are Fixnum or other un-dupable values.
[#3184 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-09-10 18:52:45 -07:00
Beau Harrington
a32eeebdcb Remove redundant checks for valid character regexp in ActiveSupport::Multibyte#clean and #verify.
[#3181 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-09-10 17:37:16 -07:00
José Valim
e1b109633c Allow scope to be changed for ActiveRecord::Errors#generate_full_message and change deprecation message [#1687 state:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-09-08 10:38:45 -05:00
Jeremy Kemper
8a2cfe9de4 Ruby 1.9: fix MessageVerifier#secure_compare 2009-09-08 14:06:35 +09:00
Michael Koziarski
a43ef2436c Prepare for 2.3.4 release 2009-09-04 09:56:09 +12:00
Michael Koziarski
9a68c72b4b Clean tag attributes before passing through the escape_once logic.
Addresses CVE-2009-3009
2009-09-04 09:26:13 +12:00
Manfred Stienstra
07c69380cf Add verify and clean methods to ActiveSupport::Multibyte.
When accepting character input from outside of your application you can't
blindly trust that all strings are properly encoded. With these methods
you can check incoming strings and clean them up if necessary.

Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-09-04 09:26:13 +12:00
Coda Hale
1f07a89c59 Fix timing attack vulnerability in ActiveSupport::MessageVerifier.
Use a constant-time comparison algorithm to compare the candidate HMAC with the calculated HMAC to prevent leaking information about the calculated HMAC.

Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-09-04 09:26:13 +12:00
Jeremy Kemper
2b82708b0e Revert "Assert primary key does not exist in habtm when the association is defined, instead of doing that everytime a record is inserted."
Test failures on PostgreSQL.

[#3128]

This reverts commit 594a281d66.
2009-09-02 13:57:33 -07:00
José Valim
594a281d66 Assert primary key does not exist in habtm when the association is defined, instead of doing that everytime a record is inserted.
[#3128 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-09-01 10:18:47 -07:00
Geoff Buesing
6bf17770af Rails::Info doesn't require version for unwanted frameworks
[#3124 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-09-01 02:29:46 -07:00
Joshua Peek
6fdfe4cb5f Deprecated "best fit" detection is to difficult. Just provide a switch to toggle the new behavor on.
# new_rails_defaults.rb
  ActionController::Routing.generate_best_match = false
2009-08-31 16:09:47 -05:00
Jay Pignata
49c4a79e59 Duplicating the options hash in Date#advance to prevent modification of the original [#1133 state:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-08-31 13:01:34 -05:00
Antonio Tapiador del Dujo
49342d1745 I18n support for plugins
Rails will now automatically add locale files found in any engine's locale
directory to the I18n.load_path (i.e. files that match the glob pattern
"config/locales/**/*.{rb,yml}" relative to engine directories).

[#2325 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-30 13:38:10 -07:00
Jay Pignata
ff8cb50f25 Ensuring that a singular model name is set for use in controllers when scaffold is passed a plural model name
[#3062 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-30 13:31:16 -07:00
Chad Woolley
70ed47f5b4 CI config updates: do not send CI emails unless explicitly enabled, use 'gem update --system', and send emails from an address which can post to the core list
[#3116 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-30 00:06:39 -07:00
Sven Fuchs + Mateo Murphy
13fb26b714 Fix ActiveRecord Error message I18n:
* allow messages and full_messages to be lazily translated at any time
* allow locales to be swapped and still obtain correctly localized messages
* allow localized global and error-type specific full_message formats
* extract an Error class

[#1687 state:open]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-29 09:48:16 -07:00
Jeremy Kemper
05d7409ae5 Prefer utf8_unicode_ci (better) over utf8_general_ci (faster) 2009-08-27 23:09:21 -07:00
Jeffrey Hardy
058459dc22 When running multiple test tasks, don't abort early if one produces failures
[#3107 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-27 11:17:25 -07:00
Jeffrey Hardy
8a49183563 Don't use AR::Base.connection for fixture column quoting. Use the connection given to Fixtures.new
[#3104 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-26 14:53:32 -07:00
Jeffrey Hardy
4240890b28 UrlRewriter#rewrite_url should call #to_param on the value given in :anchor option, just as #url_for does
[#2746 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-26 14:11:39 -07:00
Akira Matsuda
e46e67c71f I18n: use I18n for select helpers' prompt text
[#2252 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-26 13:56:15 -07:00
Jeremy Kemper
3cd245b7fa Revert "I18n: use I18n for select helpers' prompt text"
Broke CI.

[#2252 state:open]

This reverts commit d725ad39da.
2009-08-26 12:12:04 -07:00
Sven Fuchs
a4838ee466 allow ActiveRecord#RecordInvalid exception message to be localized
[#2754 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-26 11:23:30 -07:00
Akira Matsuda
d725ad39da I18n: use I18n for select helpers' prompt text
[#2252 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-26 09:39:01 -07:00
Jeremy Kemper
e213f0caaa Fix typo 2009-08-25 13:43:20 -07:00
Emilio Tagua
38d6e65c5a timestamps gives a created_at field not created_on.
[#3093 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-25 13:43:14 -07:00
Jeremy Kemper
f1355e6a4d Benchmark script via miloops' arel fork via DataMapper's AR comparison script 2009-08-25 13:43:03 -07:00
Jeremy Kemper
d6a944f778 Add active_support/all for forward compatibility. 2009-08-23 17:18:23 -07:00
Mike Gunderloy
9127c5b7f5 Fix trivial typo in template runner example [#3082 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-20 13:35:21 +01:00
Yehuda Katz
5f6e788e27 Removes examples so it can be replaced with separate repo 2009-08-18 11:15:31 -07:00
David Heinemeier Hansson
f3c7bbeedd Added db/seeds.rb as a default file for storing seed data for the database. Can be loaded with rake db:seed (or created alongside the db with db:setup). (This is also known as the "Stop Putting Gawd Damn Seed Data In Your Migrations" feature) [DHH]
Conflicts:

	railties/CHANGELOG
2009-08-18 16:08:50 +01:00
Pratik Naik
b9f668ea94 Deprecate SQLite2Adapter and DeprecatedSQLiteAdapter 2009-08-17 14:49:31 +01:00
Jeremy Kemper
d8ae3d5a8b 2-3-stable CI notifies rails core list 2009-08-15 20:31:02 -07:00
Jeremy Kemper
1cb433ce78 Bump pg gem requirement to 0.8.0. Build psql db with UTF8 encoding. 2009-08-15 19:04:16 -07:00
Hongli Lai (Phusion)
14b6ab0f01 Fix reloading of metal pieces.
- Do not hold references to old metal objects after metal classes have been reloaded.
- Obtain the reloader lock before building the middleware stack, so that reloading of metal pieces works in the face of multithreading.

[#2873 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-15 18:00:49 -07:00
Jay Pignata
1cf32ad35a Adding a call to logger from params_parser to give detailed debug information when invalid xml or json is posted
[#2481 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-15 16:46:43 -07:00
Jeremy Kemper
75a483e18e Normalize route generation order: associations, yield block, then own routes. 2009-08-15 15:58:20 -07:00
Jeremy Kemper
061b0ba6cb Refine the deprecated route check to explicitly check whether the future route pick comes before the deprecated route that was found. 2009-08-15 15:53:45 -07:00
Jatinder Singh
dbc62ad225 Fix ActiveResource load test for 64bit machines [#3051 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-15 19:57:22 +01:00
Jay Pignata
a249cad5ef Fix calculation tests on sqlite2 [#3053 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-15 19:52:08 +01:00
Jay Pignata
dad0f62dc9 Fix test_has_many_through_polymorphic_has_one on sqlite2 [#3054 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-15 19:27:35 +01:00
Jeremy Kemper
6f5d1f3190 'would of' => 'will be' 2009-08-11 01:25:15 -05:00
Bryan Helmkamp
e82b43599e Allow delegating to nil, because the method might actually exist on it 2009-08-10 18:49:37 -05:00
Hongli Lai (Phusion)
a91969803e Correctly unlock the reloader lock if the underlying app raises an exception.
[#2873 state:incomplete]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-10 16:18:35 -05:00
Kamal Fariz Mahyuddin
9284bcc35a find_cmd should return the full path of the db command
[#1488 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-10 00:04:51 -07:00
codeape
9a42096e95 Introduce grouped_collection_select helper.
[#1249 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-10 00:00:02 -07:00
Erik Ostrom
4e014379a3 Correctly handle offsets in Multibyte::Chars#index and #rindex.
The offset in codepoints was being passed directly to the wrapped string's index/rindex method. Now we translate the offset into bytes first.

[#3028 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 23:32:08 -07:00
Cristi Balan
25fe43bc14 Add tests for scoping schema_migrations index by global table prefix and suffix
[#1543 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 22:58:35 -07:00
Tim Peters
9e96f37edd Use table prefix and suffix for schema_migrations index.
[#1543 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 22:57:37 -07:00
Fabien Jakimowicz
c3da22c042 Add support for errors in JSON format.
[#1956 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 22:41:56 -07:00
Daniel Sheppard
9341655fa3 Fix that JSON parser fails to read escaped backslashes.
[#973 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 22:32:13 -07:00
Leonardo Borges
5c74cffae6 PostgreSQL: XML datatype support
[#1874 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 22:26:26 -07:00
Jaime Bellmyer
9d51f62866 raises an exception on habtm join table inserts if join table contains a primary key. Caches this check to save time on subsequent inserts.
[#2086 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 22:20:02 -07:00
Jaime Bellmyer
9a3a7983c3 raises exception (ActiveRecord::ConfigurationError with message) on habtm association creation if join table contains a primary key
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 22:19:56 -07:00
José Valim
e972acc0d7 Allow radio buttons to work with booleans.
[#2937 state:committed]

Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-09 22:15:35 -07:00
Morgan Schweers
d0bdff0799 Fix that creating a table whose primary key prefix type is :table_name generates an incorrectly pluralized primary key.
[#872 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 21:59:08 -07:00
Jeremy Kemper
011baa0f65 Fix test dependency on taggings 2009-08-09 21:31:22 -07:00
Gabe da Silveira
9bc80f4dd1 Fix that counter_cache breaks with has_many :dependent => :nullify.
[#1196 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 21:31:13 -07:00
Jatinder Singh
8a49af3158 AR should respect default values for MySQL BINARY and VARBINARY columns.
[#1273 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 21:05:29 -07:00
Joshua Peek
ff643ce967 Deprecate router generation "best match" sorting 2009-08-09 22:52:14 -05:00
Joshua Nichols
ebb6606a4d Only load db/schema.rb if it exists; otherwise, display a message to run db:migrate or remove active_record in environment.rb.
[#3012 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 20:19:31 -07:00
Joshua Nichols
15fd67e9d8 Backported XML serialization behavior from master for dealing with root nodes that have modules.
ie,
- the root node is dasherized, such that MyApplication::Business::Project becomes <my-application-project-business-project>
- association children nodes have type attributes, such that MyApplication::Business::Developer becomes <developer type="MyApplication::Project::Developer">

[#2723 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 20:13:42 -07:00
Dan Croak
33c054d7e0 has_many :through create should not raise validation errors
[#2934 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 18:47:25 -07:00
jeem
cc3183d4be make private_and_public_methods unmemoizable [#2372 state:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-08-09 20:04:15 -05:00
Max Lapshin
9e29c084eb Make sure link_to generates the form with the specified :href if any [#2254 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-10 01:00:07 +01:00
Visnu Pitiyanuvath
ecc9b705d7 Allow ho:through#build when the owner is a new record [#1749 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-10 00:49:51 +01:00
Tristan Dunn
491f1b5f36 Prevent overwriting of table name in merging SQL conditions [#2949 state:resolved] 2009-08-10 00:41:53 +01:00
Gabe da Silveira
b763858ed5 Enable has_many :through for going through a has_one association on the join model [#2719 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-10 00:34:32 +01:00
Arthur Zapparoli
9bcacf4962 Removed duplicated tests [#3026 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-10 00:08:50 +01:00
Arthur Zapparoli
18b4ac6992 Model#human_attribute_name now accept symbols [#3025 status:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2009-08-09 23:56:18 +01:00
Matt Duncan
ba961250bd Fixed to_label_tag to accept id attribute without changing for attribute [#2660 status:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2009-08-09 23:56:06 +01:00
Grzegorz Forysinski
59c3b0d0de Ensure ActiveResource#load works with numeric arrays [Grzegorz Forysinski, Elad Meidar]
[#2305 state:resolved]

Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-09 23:40:06 +01:00
Jordan Brough
be017fd7d5 Active Resource recognizes 410 as Resource Gone now [#2316 state:resolved] [Jordan Brough, Jatinder Singh]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>

Conflicts:

	activeresource/lib/active_resource/exceptions.rb

Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-09 23:33:11 +01:00
Vladimir Meremyanin
93f5d9d5f0 Make sure association conditions work with :include and :joins [#358 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-09 23:10:34 +01:00
Tristan Dunn
7908cfabf7 No longer require database name for MySQL to allow cross database selects.
[#1122 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 14:36:51 -07:00
Hugo Peixoto
39de15f136 Added both the documentation and a test case for the collection path name customization feature.
[#1218 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 14:27:04 -07:00
Bence Nagy
250e718355 path_names could be used to customize collection actions too
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 14:27:04 -07:00
Jatinder Singh
323f58f19f Make ActiveResource#exists? work [#3020 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-09 22:25:20 +01:00
Joshua Nichols
29a5549b34 Added back support for destroying an association's object by id. [#2306 status:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2009-08-09 21:47:06 +01:00
David Burger
c9d4bcf163 Fix that Hash#to_xml and Array#to_xml shouldn't modify their options hashes [#672 state:resolved] [David Burger, Dana Jones]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-09 21:47:06 +01:00
Hugo Peixoto
2c4f4a8734 With multiparameter date attributes, the behaviour when empty fields are present is now coherent with the one described in the date_select documentation.
[#1715 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 13:39:31 -07:00
Roy Nicholson
de0b073f3e Add ability to set SSL options on ARes connections.
[#2370 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 13:23:48 -07:00
Elise Huard
f6f04f1549 validate uniqueness with limit in utf8
[#2653 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 12:53:09 -07:00
Hugo Peixoto
a8286af3c3 Added a uniqueness validation test that uses diacritics.
[#2883 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 11:56:16 -07:00
Jeremy Kemper
d44b5c6219 Fix that RedCloth shouldn't be required to run tests 2009-08-09 11:02:45 -07:00
Simon Jefford
c41fb5865f Add test for routes_for_controller_and_action deprecation [#3023]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-09 18:26:22 +01:00
Dan Croak
8058a1d7d7 Deprecation warning for routes_for_controller_and_action. Use routes_for instead. [#3023]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-09 18:01:54 +01:00
Matt Conway
d3a802cee0 Allow connect_timeout, read_timeout and write_timeout settings for MySQL [#2544 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-09 17:15:40 +01:00
railsbob
80d8608102 Ensure hm:t#find does not assign nil to :include [#1845 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-09 17:03:38 +01:00
rizwanreza
d1202cfeb2 Support passing Redcloth options via textilize helper [#2973 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-09 16:42:50 +01:00
Mike Breen
8056c57a94 Serialized attributes should only be saved with partial_updates when the serialized attribute is present [#2397 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-09 16:36:54 +01:00
Hugo Peixoto
5e4b946927 Fixed the end_of_* to work with Time.usec (and Time.nsec in ruby1.9) [#1225 status:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2009-08-09 16:11:55 +01:00
Hugo Peixoto
5f6623b1b4 added tests for namespaced models generation and fixed a bug related to it. Also fixed a pluralization=false issue.
Signed-off-by: José Valim <jose.valim@gmail.com>
2009-08-09 16:11:42 +01:00
Michael Siebert
4c96030d05 Fix deprecating =-methods by using send [#2431 status:resolved]
Signed-off-by: José Valim <jose.valim@gmail.com>
2009-08-09 16:11:36 +01:00
José Valim
2d2216fadb Make http digest work with different server/browser combinations. [#3006 status:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-09 16:11:27 +01:00
Dmitry Ratnikov
32c23552f5 Changed to use klass instead of constantizing in assign_ids generated method
[#260 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-09 02:51:39 -07:00
Jeremy Kemper
83cc7de2a4 Setting connection timeout also affects Net::HTTP open_timeout.
[#2947 state:resolved]
2009-08-09 02:28:27 -07:00
Yehuda Katz
ee8fe3ae4e Update bench harness in 2.3 to match master output 2009-08-09 05:45:44 -03:00
Yehuda Katz
3cad1df22e Benchmarks 2009-08-09 05:45:44 -03:00
Yehuda Katz
7d40ba1cbf Added benchmark to 2-3 2009-08-09 05:45:44 -03:00
Rich Bradley
0b95a2afab Fix for nested :include with namespaced models.
[#260 state:committed]
2009-08-09 00:31:05 -07:00
Tristan Dunn
9aa9bad024 Don't define a default primary key in the schema dumper.
[#1908 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-08 19:32:03 -07:00
Rob
a25296ab05 Fix binary fixture test on Windows
[#2597 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-08 19:18:54 -07:00
Hugo Peixoto
ac9f9a9c3e MySQL: fix diacritic uniqueness test by setting the default character set and collation to utf8/utf8_unicode_ci
[#2883 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-08 19:04:05 -07:00
Michael Koziarski
796b7c6ce6 Don't call additional methods on builders passed to the atom_feed helper.
Additionally, actually test that the atom_feed helper works with :xml as an option.

[#1836 state:committed]
2009-08-09 13:09:24 +12:00
Marc-Andre Lafortune
819c347f43 Enumerable#sum now works will all enumerables, even if they don't respond to :size
[#2489 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-08 17:51:34 -07:00
Matt Duncan
407fbb5090 Adding :from scoping to ActiveRecord calculations
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-08-09 12:42:47 +12:00
Jan Schwenzien
389449d9ae Fix HTTP basic authentication for long credentials [#2572 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-09 01:28:07 +01:00
Nick Quaranto and Josh Nichols
d39c45690e Adding a deprecation warning for output.flush when rendering a proc or lambda
[#2893 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-08 17:23:40 -07:00
Steve St. Martin
679a0bf17f Update truncate documentation / examples to more clearly demonstrate its actual behavior
[#3016 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-08 17:13:15 -07:00
Michael Koziarski
cd5e784389 Depend on rubygems 1.3.2
Also move the min_version definition up a line so it's present in the rescue block down below.
2009-08-09 11:13:12 +12:00
Marshall Huss
791c388039 HTTP proxy support
[#2133 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-08 15:35:59 -07:00
Jeremy Kemper
ab6d295ce4 Fix caller in assert_redirected_to deprecation warning.
[#2932 state:committed]
2009-08-08 14:45:45 -07:00
Emilio Tagua
6843fb9265 Fix models load order to be able to run unit tests.
[#2550 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-08 22:29:35 +01:00
Josh Sharpe
9aaeb18781 Tidy up the AR tests, removing duplicates and making tests clearer / more focussed.
Signed-off-by: Michael Koziarski <michael@koziarski.com>

[#2774 state:committed]
2009-08-08 14:52:16 +12:00
Mike Breen
1c6c216d91 Add option to routes task to target a specific controller with CONTROLLER=x.
Signed-off-by: Michael Koziarski <michael@koziarski.com>
[#2928 state:committed]
2009-08-08 14:39:00 +12:00
Matt Duncan
f73d34c131 Default sent_on time to now in ActionMailer
Signed-off-by: Michael Koziarski <michael@koziarski.com>
[#2607 state:committed]
2009-08-08 14:10:46 +12:00
Brendan Schwartz
e1d27eedce Ruby 1.9 compat: fix for SSL in Active Resource
[#1272 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-07 12:25:13 -07:00
Jeremy Kemper
4b33155428 Merge branch '2-3-stable' of git@github.com:rails/rails into 2-3-stable 2009-08-05 17:09:43 -07:00
Akira Matsuda
8dab61d146 Ruby 1.9.2 compat: Array#* uses to_str instead of to_s to join values since Ruby 1.9.2
[#2959 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-05 17:09:20 -07:00
rick
55501b9f6a move the serialized AR record logic to #as_json. Leave ActiveRecord::Base#to_json to use the same Object#to_json implementation, but keep it around for documentation purposes. 2009-08-05 16:27:02 -07:00
Sven Fuchs
5a0e295911 Make app template git adapter sync back output immediately by using system() instead of backticks [#2047 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-08-05 19:40:11 +01:00
Michael Koziarski
95db8aaa5f Run the view tests too 2009-08-05 18:42:56 +12:00
Sven Fuchs
bf00de03de Stop messing with supposedly-deprecated interpolation placeholders when no interpolation values have been passed.
[#2885 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-01 20:51:15 -07:00
Jeremy Kemper
6cbcfffeb1 Ruby 1.9: fix reloader tests using lambdas with no env arg 2009-08-01 20:18:22 -07:00
Jeremy Kemper
f09ceb55c0 Ruby 1.9: fix encoding for test_file_stream 2009-08-01 20:17:30 -07:00
Sava Chankov
dc559f274f Ruby 1.9: fix Content-Length for multibyte send_data streaming
[#2661 state:resolved]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-01 20:07:12 -07:00
Jeremy Kemper
7244425b93 Extract String#bytesize shim 2009-08-01 19:52:00 -07:00
Jeremy Kemper
21029451d7 Fix errant require 2009-08-01 19:50:54 -07:00
Jeremy Kemper
32cfd4c2f8 SQLite: deprecate the 'dbfile' option in favor of 'database.' 2009-08-01 18:22:32 -07:00
Hongli Lai (Phusion)
d37ac7958f Make the new code reloading behavior work with multithreaded environments such as Mongrel.
[#2948 state:incomplete]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-08-01 13:25:38 -07:00
Jeremy Kemper
17f336e2f0 Revert "Methods invoked within named scope Procs should respect the scope stack. [#1267 state:resolved]"
This reverts commit 6a13376525.

Conflicts:

	activerecord/test/cases/named_scope_test.rb
2009-07-29 16:53:49 -07:00
Ross Kaffenburger and Bryan Helmkamp
523f3ba8da Don't check authenticity tokens for any AJAX requests 2009-07-27 23:15:35 +01:00
Luke Melia
60122e81a3 Avoid loading the ActiveRecord::SessionStore class on initialization if it is not in use [#2737 state:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-07-27 23:13:56 +01:00
Sebastian Delmont
ead5d88bf1 Fix filter_parameter_logging of non-hash values within array params
Signed-off-by: Michael Koziarski <michael@koziarski.com>
[#2927 state:committed]
2009-07-23 09:33:29 +12:00
Michael Koziarski
143c55d325 Memoize cookies so that updates to cookies are available in the current request. [#2733 state:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>

Conflicts:

	actionpack/test/controller/cookie_test.rb
2009-07-22 09:46:53 +12:00
Akira Matsuda
be4d743645 Ruby 1.9.2 compat: name method was renamed to __name__ since MiniTest 1.4.x [#2922 state:resolved]
Signed-off-by: Yehuda Katz <wycats@gmail.com>
2009-07-21 01:17:53 -07:00
Akira Matsuda
7a427a83ca Ruby 1.9.2 compat: Use File#expand_path for require path because "." will not be included in LOAD_PATH since Ruby 1.9.2 [#2921 state:resolved]
Signed-off-by: Yehuda Katz <wycats@gmail.com>
2009-07-21 01:17:20 -07:00
Michael Koziarski
c7bcbb983f Forgot to bump the railties versions 2009-07-19 17:27:45 +12:00
Michael Koziarski
a147becfb8 Move from referencing the BlueCloth constant directly, to referencing Markdown.
This supports alternative implementations of markdown such as rpeg-markdown or rdiscount, and later releases of bluecloth.  There are some performance issues with earlier releases of bluecloth, and you should probably upgrade.  In the event that you can't you can place the following code into an initializer:

  Markdown = BlueCloth
2009-07-16 13:30:47 +12:00
Szymon Nowak
b3ec7b2d03 Add primary_key option to belongs_to association
[#765 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-07-15 18:14:00 -07:00
Joshua Peek
ae85927ea8 Correctly setup the rack gem dependency. 2009-07-12 19:31:41 -05:00
Joshua Peek
f36d9a6758 Go back to depending on Rack 1.0.x gem 2009-07-12 19:28:04 -05:00
Michael Koziarski
18e68d9524 Prepare version numbers, changelogs and gem dependencies for 2.3.3. 2009-07-12 15:43:39 +12:00
Michael Koziarski
6a50d6c8e3 Match tests with new reloading behaviour 2009-07-08 17:30:33 +12:00
Hongli Lai (Phusion)
bc2c4a4595 Cleanup application after #close has been called on the Rack response body, not when AC::Reload#call is done.
The Rack body might lazily evaluate its output, which is for example the case
if one calls 'render :text => lambda { ... }'. The code which lazily evaluates
the output might use other application classes. So we will want to defer
cleanup until the Rack request is completely finished.

Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-07-08 13:46:10 +12:00
Lawrence Pit
29c5985849 Use the i18n gem if present instead of vendor code. [#2871 state:resolved]
Signed-off-by: Yehuda Katz <wycats@gmail.com>
2009-07-07 18:38:02 -07:00
Hongli Lai (Phusion)
d8f8066cd1 Add support for dumping non-standard primary keys when using the SQLite3 adapter. Fix unit tests so that this feature is tested for all adapters.
Signed-off-by: Yehuda Katz <wycats@yehuda-katzs-macbookpro41.local>
2009-07-07 16:17:49 -07:00
Hongli Lai (Phusion)
31254bedae Mocha >= 0.9.7 is required, otherwise mocking doesn't work. [#2874 state:resolved]
Signed-off-by: Yehuda Katz <wycats@yehuda-katzs-macbookpro41.local>
2009-07-07 16:14:22 -07:00
Jesús García Sáez
6673001a5e Allow symbols on routes declaration (:controller and :action values) [#2828 state:resolved]
Signed-off-by: Yehuda Katz + Carl Lerche <ykatz+clerche@engineyard.com>
2009-07-02 12:19:38 -07:00
Brian Abreu
944f4fc7d2 Fixed ActiveSupport::OrderedHash::[] work identically to ::Hash::[] in ruby 1.8.7 [#2832 state:resolved]
Signed-off-by: Yehuda Katz + Carl Lerche <ykatz+clerche@engineyard.com>
2009-07-02 12:01:46 -07:00
Jarl Friis
1c855ad4e7 My suggestion to fix ticket 2401 [#2401 state:resolved]
Signed-off-by: Yehuda Katz + Carl Lerche <ykatz+clerche@engineyard.com>
2009-07-02 11:56:56 -07:00
Levin Alexander
d8fff7d9d5 make #inspect if zero length duration return '0 seconds' instead of empty string [#2838 state:resolved]
Signed-off-by: Yehuda Katz + Carl Lerche <ykatz+clerche@engineyard.com>
2009-07-02 11:23:04 -07:00
Yehuda Katz + Carl Lerche
281c1a82de Fixes a number of tests that inexplicably didn't fail when we committed the original patch 2009-07-02 10:50:39 -07:00
J.D. Hollis
f6f24b71a4 Only check for built extensions on gem dependencies that are in vendor/gems. [#2825 state:resolved]
Signed-off-by: Yehuda Katz + Carl Lerche <ykatz+clerche@engineyard.com>
2009-07-02 10:28:25 -07:00
Elliot Winkler
0d3c5f0a82 Patch FormTagHelper so that when a form tag is created, the div which holds the form authenticity token is set to display:inline [#2846 state:resolved]
Signed-off-by: Yehuda Katz + Carl Lerche <ykatz+clerche@engineyard.com>
2009-07-01 17:12:45 -07:00
Yehuda Katz + Carl Lerche
4d8fd8d335 Fixes bug where Memcached connections get corrupted when an invalid expire is passed in [#2854 state:resolved] 2009-07-01 17:00:08 -07:00
Jeremy Kemper
5217c16b09 JSON.escape returns UTF-8 strings
[#2849 state:resolved]
2009-07-01 16:27:13 -07:00
Yehuda Katz + Carl Lerche
97ad936148 Updates CI to use latest mocha 2009-07-01 13:49:35 -07:00
Jeremy Kemper
dfdf8e5dab Merge branch '2-3-stable' of git@github.com:rails/rails into 2-3-stable 2009-07-01 12:55:47 -07:00
Yehuda Katz + Carl Lerche
a8bd3c8a10 Move mocha down below initial T::U require and bump version to 0.9.7 [#2858 state:resolved] 2009-07-01 12:09:32 -07:00
Yehuda Katz + Carl Lerche
e10305f0f4 Accept Symbol for contoller name [#2855 state:resolved]
Signed-off-by: Yehuda Katz + Carl Lerche <ykatz+clerche@engineyard.com>
2009-07-01 11:51:09 -07:00
Chris Mear
eb52dc3db7 Make text_area_tag escape contents by default.
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-06-27 13:15:53 +12:00
Michael Koziarski
9407f6e9a4 Make filter_parameters work correctly with array parameters.
Conflicts:

	actionpack/lib/action_controller/base/filter_parameter_logging.rb
2009-06-27 13:11:01 +12:00
Joshua Peek
6720b25b2d send_data should set Content-Length as a string 2009-06-25 14:44:09 -05:00
Jeremy Kemper
22554745b7 Turn on autolist for debugging also 2009-06-18 21:54:56 -04:00
Jeremy Kemper
8b9b954f40 Friendlier runtime exception if delegatee is nil 2009-06-18 20:11:02 -04:00
Jeremy Kemper
b75bc05bc5 Delegated methods report the expected file/line in backtraces 2009-06-18 18:06:42 -04:00
Joshua Peek
a491b19502 Add :concat option to asset tag helpers to force concatenation.
This is useful for working around IE's stylesheet limit.

  stylesheet_link_tag :all, :concat => true
2009-06-15 10:23:55 -05:00
Luca Guidi
447d60e9ed Bytes calculation speed up
[#2800 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-06-13 14:06:01 -07:00
Jeremy Kemper
cb9429a259 Update memcache-client to 1.7.4 for cheaper timeouts 2009-06-11 22:34:23 -07:00
Joshua Peek
25fde77674 Vendor rack 1.0.x stable 2009-06-11 19:39:21 -05:00
Andrew Kaspick
d3d4822262 allow absolute paths for the asset caches
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-06-11 16:33:01 +12:00
Jeremy Kemper
7e1bcef985 Remove dead AbstractRequest autoload 2009-06-09 23:51:04 -07:00
Michael Koziarski
19c38a9b70 Whitelist the methods which are called by multiparameter attribute assignment.
This prevents users from causing NoMethodErrors and the like by editing the parameter names, and closes a potential exploit of CVE-2009-1904.
2009-06-10 12:11:18 +12:00
Matt Jones
f43404d42b Fix incorrect specification path in GemDependency#from_directory_name
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-06-10 09:54:49 +12:00
Stephen Anderson
cd14a4a00e Sanitized the id generated by text_area_tag helper method. text_area_tag('item[description]') should return: <textarea id="item_description" name="item[description]"></textarea> instead of: <textarea id="item[description]" name="item[description]"></textarea> The old id was causing HTML validation failures.
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-06-09 20:36:37 +12:00
David Stevenson
898a8801ff Made label target radio button tags with values. Radio button now respects inherited :index options when generating id.
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-06-09 20:29:02 +12:00
Friedrich Göpel
72d111a21c 1.9 compatibility - don't pass an array as the from address as this ends up generating invalid SMTP commands. 2009-06-09 20:24:19 +12:00
Steven Luscher
d63fab344f Fixes #2439. ActionController::Integration::Session no longer mangles multiparameter attribute params when processing multipart requests.
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-06-09 20:14:01 +12:00
Eugene Pimenov
c5c022c705 PostgreSQL adapter should call thread safe quote_string function
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-06-09 20:11:51 +12:00
Tom Ward
d97073337c Change autoload declaration in ActionView::Helpers from JavascriptHelper to JavascriptHelper, matching the actual helper name. Also removed require from UrlHelper which was inadvertently preventing the autoload typo from causing a failure.
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-06-09 20:08:23 +12:00
Michael Koziarski
b1a044b629 Revert "Ensure HasManyThroughAssociation#destroy delete orphan records"
This reverts commit 7a85927da2.

There's still some debate about the intended behaviour in the ticket, leaving in master but removing prior to shipping 2.3.3
2009-06-09 20:03:36 +12:00
Matt Jones
2c3d2906b2 Fix several issues with the 2.3.2 gem loader.
Incorporates the following:

- migrates back small change to gems:build:force from bfc1609a50 to finish closing #2266.

- unrolls to_proc calls in gems.rake, to match the change in master.

- fixes #2722 by passing the options hash to dependencies during build. (includes a test)

- fixes #2721 by loading the specification directly in from_directory_name. Adds an option to opt-out of specification loading when needed (in gems:refresh_specs, for instance). Includes tests.

- fixes #2679 by refreshing specs for all frozen gems rather than just gems loaded from the environment.

- fixes #2678 by passing the options hash to dependencies during unpack.

Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-06-09 19:57:23 +12:00
nate
056ddbdcfb A test to show that http_authentication needs to fail authentication if the password procedure returns nil. Also includes a fix to validate_digest_response to fail validation if the password procedure returns nil.
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-06-09 19:47:16 +12:00
Pratik Naik
5fb66a3abb Vendor Rack edge ( commit : 815342a8e15db564b766f209ffb1e340233f064f ) 2009-06-08 23:47:36 -07:00
Jeremy Kemper
e70272e2a4 Clearer String#first and #last edge cases. Fix that 'foo'.first(0) == 'foo' instead of '' 2009-06-08 20:42:39 -07:00
Jeremy Kemper
63d0c33787 Fix AR json encoding 2009-06-08 20:42:39 -07:00
Jeremy Kemper
f9b2227649 Qualify constant references in BasicObjects 2009-06-08 20:42:39 -07:00
Jeremy Kemper
756e82d1b6 Prefer JSON.encode(value) to value.to_json 2009-06-08 20:42:39 -07:00
Jeremy Kemper
74f16a56e7 Simplify json decoder backend lazy load 2009-06-08 20:42:39 -07:00
Jeremy Kemper
f1e75e4378 Add #element and #collection to ModelName 2009-06-08 20:42:39 -07:00
Jeremy Kemper
cc5d313a48 Lazier Rakefile requires to avoid needing full rake gem on 1.9 2009-06-08 20:42:39 -07:00
Jeremy Kemper
91727ae5e4 Ruby 1.9: sqlite escape encoding 2009-06-08 20:42:31 -07:00
Jeremy Kemper
91fbdfd5b3 Failsafe doesn't return bare String body 2009-06-08 20:35:52 -07:00
Jeremy Kemper
05abd7c196 Check for to_str instead of String 2009-06-08 20:35:52 -07:00
Jeremy Kemper
aebd1ba5b4 Integration tests use Rack::Lint on 1.9 also 2009-06-08 20:35:51 -07:00
Jeremy Kemper
ec10f13939 Ruby 1.9: fix json encoding 2009-06-08 15:18:11 -07:00
Jeremy Kemper
01f820c3b2 Use to_json instead of rails_to_json 2009-06-08 14:09:16 -07:00
Jeremy Kemper
a69ee11968 JSON: split encoding and coercion 2009-06-08 01:37:28 -07:00
Jeremy Kemper
4a78dae2ab Revert rails_to_json -> to_json so we don't break compatibility
[#2753 state:resolved]
2009-06-08 00:11:12 -07:00
Jeremy Kemper
4b4164e8a8 Don't rely on Rails.logger 2009-06-08 00:09:50 -07:00
Tim Connor
84a755b27e Work around a gem dependency edge case that prevents Rails from booting..
If you have a frozen gem with unfrozen dependencies (for instance if the
dependency has native extensions so can't be frozen) you can have a
nightmare upgrade problem, where you cannot rake gems:install, because
rake is broken by a gem loading problem.

If you bump up your frozen gem to a newer version that requires a newer
dependency, everybody else on the team will have rake broken by that
dependency mismatch, since you will have had to specify the dependency
in your config.gems, otherwise nobody will have installed it, since the
parent is frozen. And now the config.gems loading code will kill rake.

[#2609 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-06-05 23:06:19 -07:00
Michael Koziarski
b600bf2cd7 name is case sensitive, update tests to reflect that 2009-06-01 14:21:08 +12:00
Han Kessels
4d7c597e84 fix for IE incompatibility of :disable_with in submit_tag
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-06-01 14:03:35 +12:00
Ian Terrell
a92790ab86 added a failing test case for counting has_many :through associations with scopes
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-06-01 13:54:56 +12:00
Michael Koziarski
34c3162c5c Revert "Ensure calculations respect scoped :select". Broke .count on a has_many :through association.
This reverts commit 6543426c73.
2009-06-01 13:54:20 +12:00
Joshua Peek
c73cf7d2c0 Revert "Only save the session if we're actually writing to it [#2703 state:resolved]"
This reverts commit 14edaa104d.
2009-05-30 09:36:32 -05:00
Johan Sörensen
14edaa104d Only save the session if we're actually writing to it [#2703 state:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-05-28 09:32:16 -05:00
Johan Sörensen
dc94c09503 The FlashHash and friends causes a lot of needless session storing, when we know for a fact that there's no content in the flash. By not storing the empty hash in the session we save a lot of communication with the various session backends, while still keeping the same interface to the flash. [#2703 state:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-05-28 09:22:35 -05:00
Hongli Lai (Phusion)
34a1ed0df8 Make the Failsafe middleware attempt to render 500.html during failsafe response rendering. Also make the default static failsafe response more friendly, in case 500.html rendering fails. [#2715 state:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-05-27 14:59:11 -05:00
calavera
4196616778 ensure initialize_database_middleware doesn't use ActionController if action_controller framework is not enabled [#2680 state:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-05-27 14:56:26 -05:00
Joshua Peek
b4c7b3e893 Ensure Memcache local cache returns duplicated values [#2302 state:resolved] 2009-05-27 14:55:13 -05:00
Hongli Lai (Phusion)
9b2a665aff activesupport/json/encoders fix that to_json should call rails_to_json, not just be an alias to the rails_to_json method defined in Object. Fixes #2690
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-05-25 15:28:14 +02:00
Eloy Duran
a70c78177a Ensure the parent record is always saved when the child is invalid. [#2249 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-05-20 21:19:30 +02:00
Bryan Helmkamp
542d6a0abd Use duck typing to also allow MemCache-like object when initializing a MemCacheStore
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-05-19 16:58:20 -07:00
Jeremy Kemper
2a657725f1 Mark pending release in changelog instead of edge 2009-05-19 10:59:24 -07:00
Bryan Helmkamp
6339e5d360 Allow MemCacheStore to be initialized with a MemCache object instead of addresses and options 2009-05-19 10:58:30 -07:00
Jeremy Kemper
9fcadcbd68 Fix imprecise float comparison 2009-05-18 14:34:32 -07:00
Joe Van Dyk
ad85771221 Add ability to get multiple memcached keys at the same time (via MemCacheStore#read_multi).
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-05-18 13:44:45 -07:00
Ken Collins
50608ecccd Reimplement Fixtures.identify so that it consistently generates identities across ruby versions.
[#2633 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-05-18 13:42:04 -07:00
Luca Guidi
7a85927da2 Ensure HasManyThroughAssociation#destroy delete orphan records [#2251 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-05-18 22:31:14 +02:00
Pratik Naik
97b75c9f16 Make sure default_scope#create checks for options[:conditions] [#2181 state:resolved] [James Le Cuirot] 2009-05-18 21:27:55 +02:00
Pratik Naik
dbb0258279 Ensure HTTP Digest auth uses appropriate HTTP method [#2490 state:resolved] [Steve Madsen] 2009-05-18 17:00:29 +02:00
rick
2b5e4f38f5 load the JSON Backend lazily. 2009-05-17 19:16:11 -07:00
Jeremy Kemper
5b80ead2a3 Extract json string escaping 2009-05-17 18:42:56 -07:00
Jeremy Kemper
cc47d3ff0c Only Object to_json alias is needed. Prefer nil options. 2009-05-17 18:42:44 -07:00
rick
d052e9fb58 Add pluggable JSON backends with support for the JSON gem.
Example: ActiveSupport::JSON.backend = "JSONGem"

All internal Rails JSON encoding is now handled by
ActiveSupport::JSON.encode().  Use of #to_json is not recommended, as it
may clash with other libraries that overwrite it.  However, you can
recover Rails specific functionality
if you really want to use #to_json.

    gem 'json'
    ActiveSupport::JSON.backend = "JSONGem"

    class ActiveRecord::Base
      alias to_json rails_to_json
    end
2009-05-17 18:40:38 -07:00
Joshua Peek
43e537b9e8 Missed a file from the previous commit 2009-05-17 14:45:06 -05:00
Joshua Peek
e30016c29e Fix reset_session with ActiveRecord store [#2200 state:resolved] 2009-05-17 14:44:19 -05:00
Mike Breen
f383a4aa33 Allow assert_template to take a symbol [#2011 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-05-17 19:40:18 +02:00
Paulo Schneider
14b769899c Fix typo in the generated routes.rb [#2433 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-05-17 15:00:41 +02:00
Jacob Kjeldahl
d5f018eb10 Supply valid ruby-prof parameters [#1804 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-05-17 14:53:50 +02:00
Daniel Guettler
4cd40726eb has_one :through should not create a new association when assigned nil [#698 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-05-17 14:50:09 +02:00
Pratik Naik
ba92e83bcc Include guides directory in the rails gem 2009-05-16 17:08:34 +02:00
José Valim
66ead4f148 Allow strings to be sent as collection to select.
Signed-off-by: Michael Koziarski <michael@koziarski.com>
[#2391 state:committed]
2009-05-15 15:30:42 +12:00
Joshua Peek
f7cb7fce4c Sweeper does not belong in Sweeping module 2009-05-14 16:47:24 -05:00
Peter Marklund
0380e9ca5f Changed ActiveRecord::Base#exists? to invoke find_initial so that it is compatible with, and doesn't lose, :include scopes (references to eager loaded tables)
Signed-off-by: Michael Koziarski <michael@koziarski.com>
[#2543 state:committed]
2009-05-14 20:42:13 +12:00
Jeremy Kemper
35e1785081 Revert "Fixed bug with polymorphic has_one :as pointing to an STI record"
[#2594 state:open]

This reverts commit 93c557828e.
2009-05-11 12:21:59 -07:00
Douglas F Shearer
2bcb2443a9 ActiveSupport::OrderedHash[1,2,3,4] creates an OrderedHash instead of a Hash.
[#2615 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-05-11 11:46:43 -07:00
Joshua Peek
4051dd3412 Fix syntax error from 5ac05f15 2009-05-09 22:22:14 -05:00
Anthony Crumley
88d5e3341d Fixed eager load error on find with include => [:table_name] and hash conditions like {:table_name => {:column => 'value'}}
Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-05-10 13:33:22 +12:00
John Small
7bf9bf3dd6 Add configuration options for :dasherize and :camelize calls to Hash#to_xml
People using ActiveResource & REST to integrate with other systems need to be able to control the default dasherize behavior of Hash.to_xml.
Currently there is no test for a default value, but existing code asssumes it's true. This patch adds tests for the default value and adds
mattr_accessor to ActiveSupport for :dasherize_xml and :camelize_xml. These module attributes set the defaults for :dasherize and :camelize in
rename_keys inside Hash#to_xml. The tests have been changed to separate out the testing of the parameter options for :camelize
and :dasherize so that we only test one thing at a time. We also test default values for :camelize_xml and :dasherize_xml.

The module attribute dasherize_xml is set to true in this patch to maintain existing code. But at some point in the future it should be set to
false because Hash#to_xml probably should not set underscores to dashes by default.

Changed documentation on ActiveResource#to_xml to correctly describe the behaviour of Hash#to_xml. The previous documentation said that
the default for :dasherize was false, in fact it was and still is true, but we now have a way to change the default. I've also added
documentation for the :camelize option.

Signed-off-by: Michael Koziarski <michael@koziarski.com>
2009-05-10 13:09:40 +12:00
Ken Collins
6dec3c45fc ActiveSupport::OrderedHash#to_a method returns an ordered set of arrays. Matches ruby1.9's Hash#to_a.
Signed-off-by: Michael Koziarski <michael@koziarski.com>
[#2629 state:committed]
2009-05-10 13:05:14 +12:00
Joshua Peek
e61cceb37f Don't stream each line of the body, just send the whole thing 2009-05-08 17:00:16 -05:00
Joshua Peek
7f1f16c01f Deprecate assert_redirect_to's partial hash matching. This will be fully removed in 3.0. 2009-05-04 20:24:49 -05:00
Wincent Colaiuta
5ac05f15c6 Extract ActionController::Caching::Sweeper into separate file [#1977 state:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-05-04 20:17:27 -05:00
Tim Connor
49169f7a6a fix problems with requires in metal choking under development reloading [#2579 state:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-05-04 20:12:16 -05:00
codebrulee
ebe8dd6108 Remove stray underscore from the hash conversion methods which broke backwards compatibility with Hash.from_xml
Also add an all-caps test to prevent future regressions
2009-05-04 09:51:35 -07:00
Ruy Asan
17e712d3a3 Added routing test for irregular ID requirements and custom member action.
[#2595 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-05-01 15:02:51 -07:00
Ruy Asan
93c557828e Fixed bug with polymorphic has_one :as pointing to an STI record
[#2594 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-05-01 14:49:38 -07:00
Alexander Podgorbunsky
628b4ad679 Default scope :order should be overridden by named scopes.
[#2346 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-05-01 14:45:35 -07:00
Jeremy Kemper
a5ed7eede6 Missed commit for 7c4b325e0a 2009-04-30 16:49:34 -07:00
John F. Douthat
d1d1894c2f Fix action-cached exception responses.
Methods raising ActiveRecord::RecordNotFound were returning 404 on first request and 200 OK with blank body on subsequent requests.

[#2533 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-04-30 16:48:07 -07:00
Jeremy Kemper
7c4b325e0a Fix render :json => nil [#2589 state:resolved] 2009-04-30 16:47:42 -07:00
David Dollar
00eee49e1e Additional tests for the gem subsystem
* test_gem_ignores_development_dependencies
  * test_gem_guards_against_duplicate_unpacks
  * test_gem_does_not_unpack_framework_gems

[#2236 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-04-29 08:08:48 -07:00
David Dollar
6e3bede928 Attempt to deal with more cases of gems with native components.
This commit adds a rudimentary check for 'unbuilt' gems, so that we can abort
the application load if there are any gems that have native components that
have not yet been built.

The rake task gems:build has now only builds 'unbuilt' gems as a result.

The rake task gems:build:force has been added to deal with cases of incomplete
builds, or any case where you need to force the build of all of your gems.

Changes the gems:build task to get its gem list by parsing directory entries
in vendor/gems, which sidesteps the chicken/egg issues involved with having a
gem unpacked into vendor/gems without before its native bits are compiled.

[#2266 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-04-28 23:19:18 -07:00
Stephen Bannasch
4b68debb1c add JRuby-JDOM backend for XmlMini
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
2009-04-26 16:23:22 -07:00
Hongli Lai (Phusion)
2633108e1f Fix environment variable testing code in failsafe.rb.
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-04-26 11:22:44 -05:00
Hongli Lai (Phusion)
5e57e2fa58 Remove reference to Rack::RewindableInput, which has been removed a while ago.
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-04-26 11:21:15 -05:00
Yehuda Katz
cb9a1f17f0 Updated 2-3-stable to Rack 1.0 2009-04-25 12:47:51 -07:00
Joshua Peek
61a1456937 Remove RewindableInput middleware since all input MUST be rewindable according to a recent change in the Rack 1.0 SPEC 2009-04-25 14:05:58 -05:00
Joshua Peek
16f36b6171 Remove vendored version of Rack 2009-04-25 13:59:26 -05:00
Joshua Peek
2d9b45722c Remove pending rack specifications until they are official 2009-04-25 13:44:34 -05:00
Jeremy Kemper
617d7eb57b Merge branch '2-3-stable' of git@github.com:rails/rails into 2-3-stable 2009-04-22 01:08:53 -07:00
Pratik Naik
09a976ac58 Change table to prevent copying indexes on sqlite2 2009-04-21 13:29:00 +01:00
Pratik Naik
5bbd097ce9 Specify :group with the table name for it to work on sqlite3 2009-04-21 13:12:15 +01:00
Pratik Naik
3267097393 Fix tests for sqlite3 3.6.xx 2009-04-21 13:08:26 +01:00
Max Lapshin
5a4603fafb Fixed dumping from postgresql columns in index in wrong order. [#2515 state:resolved]
Signed-off-by: Tarmo Tänav <tarmo@itech.ee>
2009-04-21 11:45:02 +01:00
Scott Woods
70ba90b072 Quote table names when casting to regclass so that capitalized tables are supported. [#2418 state:resolved]
Signed-off-by: Tarmo Tänav <tarmo@itech.ee>
2009-04-21 11:44:54 +01:00
Max Lapshin
de4cc53f74 Fixed wrong quoting of index names in postgres [#2402 state:resolved]
Signed-off-by: Tarmo Tänav <tarmo@itech.ee>
2009-04-21 11:44:47 +01:00
Max Lapshin
6060123470 Support multiple schemas in table names for postgresql [#390 state:resolved]
Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
2009-04-21 11:40:12 +01:00
Pratik Naik
fc2421b784 Ensure :dependent => :delete_all works for association with hash conditions 2009-04-21 11:33:27 +01:00
Pratik Naik
375e8976e3 Ensure JoinAssociation uses aliased table name when multiple associations have hash conditions on the same table 2009-04-20 13:56:03 +01:00
Mislav Marohnić
35c5727ace Always buffer rack.input if it is not rewindable
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-04-17 21:54:09 -05:00
Mislav Marohnić
878aec9d95 Improve rewindable input test coverage so tests fail when you remove the middleware
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-04-17 19:35:25 -05:00
Jeremy Kemper
c9a3d99164 Clearer String#first and #last edge cases. Fix that foo.first(0) == instead of foo. 2009-04-17 18:06:47 -05:00
David Heinemeier Hansson
fa750e08a8 Added :touch option to belongs_to associations that will touch the parent record when the current record is saved or destroyed [DHH] 2009-04-16 17:26:10 -05:00
David Heinemeier Hansson
50e867480a Added ActiveRecord::Base#touch to update the updated_at/on attributes with the current time [DHH] 2009-04-16 16:48:07 -05:00
Doug McInnes
dc69d9308a Fix for TestResponse.cookies returning cookies unescaped [#1867 state:resolved]
Signed-off-by: David Heinemeier Hansson <david@loudthinking.com>
2009-04-07 13:22:21 -05:00
Kenny Ortmann
ace154d067 added tests for session options being defaulted correctly to rack defaults [#2403 state:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-04-07 11:08:04 -05:00
Ryan Angilly
651611999d adding session_options initialization and test [#2303 state:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-03-24 10:53:29 -05:00
thedarkone
6a1267a0b1 Fix template extension parsing. [#2315 state:resolved] [#2284 state:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-03-24 10:53:24 -05:00
thedarkone
d2e6a0fbc3 Simplify handling of absolute path templates. [#2276 state:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-03-24 10:53:20 -05:00
David Dollar
dace54b2e9 Updates tests to cause the tests for the Request class not to proxy through a fake TestRequest object [#2278 state:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-03-24 10:53:14 -05:00
Peter Marklund
daffa5cbdd Reset request_parameters in TestRequest#recycle! to avoid multiple posts clobbering each other [#2271 state:resolved]
Signed-off-by: Joshua Peek <josh@joshpeek.com>
2009-03-24 10:53:07 -05:00
Joshua Peek
c91912700d just kill brittle test 2009-03-24 10:52:49 -05:00
721 changed files with 21461 additions and 19055 deletions

5
.gitignore vendored
View File

@@ -1,3 +1,5 @@
pkg
.bundle
debug.log
doc/rdoc
activeresource/doc
@@ -15,6 +17,3 @@ railties/test/500.html
railties/doc/guides/html/images
railties/doc/guides/html/stylesheets
railties/guides/output
*.rbc
*.swp
*.swo

View File

@@ -1,10 +1,9 @@
require 'rake'
require 'rake/rdoctask'
require 'rake/contrib/sshpublisher'
require 'rdoc/task'
env = %(PKG_BUILD="#{ENV['PKG_BUILD']}") if ENV['PKG_BUILD']
PROJECTS = %w(activesupport actionpack actionmailer activeresource activerecord railties)
PROJECTS = %w(activesupport railties actionpack actionmailer activeresource activerecord)
Dir["#{File.dirname(__FILE__)}/*/lib/*/version.rb"].each do |version_path|
require version_path
@@ -13,7 +12,7 @@ end
desc 'Run all tests by default'
task :default => :test
%w(test rdoc pgem package release).each do |task_name|
%w(test rdoc pgem package release gem).each do |task_name|
desc "Run #{task_name} task for all projects"
task task_name do
PROJECTS.each do |project|
@@ -24,13 +23,15 @@ end
desc "Generate documentation for the Rails framework"
Rake::RDocTask.new do |rdoc|
RDoc::Task.new do |rdoc|
rdoc.rdoc_dir = 'doc/rdoc'
rdoc.title = "Ruby on Rails Documentation"
rdoc.main = "railties/README"
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.options << '-A cattr_accessor=object'
rdoc.options << '--charset' << 'utf-8'
rdoc.options << '--main' << 'railties/README'
rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : './doc/template/horo'
@@ -74,6 +75,7 @@ end
desc "Publish API docs for Rails as a whole and for each component"
task :pdoc => :rdoc do
require 'rake/contrib/sshpublisher'
Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/api", "doc/rdoc").upload
PROJECTS.each do |project|
system %(cd #{project} && #{env} #{$0} pdoc)

View File

@@ -1,3 +1,32 @@
*2.3.11 (February 9, 2011)*
*2.3.10 (October 15, 2010)*
*2.3.9 (September 4, 2010)*
*2.3.8 (May 24, 2010)*
*2.3.7 (May 24, 2010)*
* Version bump.
*2.3.6 (May 23, 2010)*
* Upgrade TMail from 1.2.3 to 1.2.7. [Mikel Lindsaar]
*2.3.5 (November 25, 2009)*
* Minor Bug Fixes and deprecation warnings
*2.3.4 (September 4, 2009)*
* Minor bug fixes.
*2.3.3 (July 12, 2009)*
* No changes, just a version bump.
*2.3.2 [Final] (March 15, 2009)*
* Fixed that ActionMailer should send correctly formatted Return-Path in MAIL FROM for SMTP #1842 [Matt Jones]

View File

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

View File

@@ -1,10 +1,9 @@
require 'rubygems'
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
require 'rdoc/task'
require 'rake/packagetask'
require 'rake/gempackagetask'
require 'rake/contrib/sshpublisher'
require 'rubygems/package_task'
require File.join(File.dirname(__FILE__), 'lib', 'action_mailer', 'version')
PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
@@ -30,7 +29,7 @@ Rake::TestTask.new { |t|
# Generate the RDoc documentation
Rake::RDocTask.new { |rdoc|
RDoc::Task.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'
@@ -55,19 +54,17 @@ spec = Gem::Specification.new do |s|
s.rubyforge_project = "actionmailer"
s.homepage = "http://www.rubyonrails.org"
s.add_dependency('actionpack', '= 2.3.2' + PKG_BUILD)
s.add_dependency('actionpack', '= 2.3.14' + 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
Rake::GemPackageTask.new(spec) do |p|
Gem::PackageTask.new(spec) do |p|
p.gem_spec = spec
p.need_tar = true
p.need_zip = true
@@ -76,12 +73,14 @@ end
desc "Publish the API documentation"
task :pgem => [:package] do
require 'rake/contrib/sshpublisher'
Rake::SshFilePublisher.new("gems.rubyonrails.org", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
`ssh gems.rubyonrails.org '/u/sites/gems/gemupdate.sh'`
end
desc "Publish the API documentation"
task :pdoc => [:rdoc] do
require 'rake/contrib/sshpublisher'
Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/am", "doc").upload
end

View File

@@ -1,5 +1,5 @@
#--
# Copyright (c) 2004-2009 David Heinemeier Hansson
# Copyright (c) 2004-2010 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -58,5 +58,3 @@ module Net
end
autoload :MailHelper, 'action_mailer/mail_helper'
require 'action_mailer/vendor/tmail'

View File

@@ -195,6 +195,39 @@ module ActionMailer #:nodoc:
# end
# end
#
# = Multipart Emails with Attachments
#
# Multipart emails that also have attachments can be created by nesting a "multipart/alternative" part
# within an email that has its content type set to "multipart/mixed". This would also need two templates
# in place within +app/views/mailer+ called "welcome_email.text.html.erb" and "welcome_email.text.plain.erb"
#
# class ApplicationMailer < ActionMailer::Base
# def signup_notification(recipient)
# recipients recipient.email_address_with_name
# subject "New account information"
# from "system@example.com"
# content_type "multipart/mixed"
#
# part "multipart/alternative" do |alternative|
#
# alternative.part "text/html" do |html|
# html.body = render_message("welcome_email.text.html", :message => "<h1>HTML content</h1>")
# end
#
# alternative.part "text/plain" do |plain|
# plain.body = render_message("welcome_email.text.plain", :message => "text content")
# end
#
# end
#
# attachment :content_type => "image/png",
# :body => File.read(File.join(RAILS_ROOT, 'public/images/rails.png'))
#
# attachment "application/pdf" do |a|
# a.body = File.read('/Users/mikel/Code/mail/spec/fixtures/attachments/test.pdf')
# end
# end
# end
#
# = Configuration options
#
@@ -278,7 +311,7 @@ module ActionMailer #:nodoc:
@@raise_delivery_errors = true
cattr_accessor :raise_delivery_errors
superclass_delegating_accessor :delivery_method
class_attribute :delivery_method
self.delivery_method = :smtp
@@perform_deliveries = true
@@ -543,6 +576,7 @@ module ActionMailer #:nodoc:
@headers ||= {}
@body ||= {}
@mime_version = @@default_mime_version.dup if @@default_mime_version
@sent_on ||= Time.now
end
def render_message(method_name, body)
@@ -592,7 +626,7 @@ module ActionMailer #:nodoc:
end
def template_path
"#{template_root}/#{mailer_name}"
File.join(template_root, mailer_name)
end
def initialize_template_class(assigns)
@@ -674,7 +708,7 @@ module ActionMailer #:nodoc:
def perform_delivery_smtp(mail)
destinations = mail.destinations
mail.ready_to_send
sender = (mail['return-path'] && mail['return-path'].spec) || mail.from
sender = (mail['return-path'] && mail['return-path'].spec) || Array(mail.from).first
smtp = Net::SMTP.new(smtp_settings[:address], smtp_settings[:port])
smtp.enable_starttls_auto if smtp_settings[:enable_starttls_auto] && smtp.respond_to?(:enable_starttls_auto)

View File

@@ -105,7 +105,7 @@ module ActionMailer
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
initialize_template_class_without_helper(assigns).tap do |template|
template.extend self.class.master_helper_module
end
end

View File

@@ -1,3 +1,4 @@
# encoding: us-ascii
module ActionMailer
module Quoting #:nodoc:
# Convert the given text into quoted printable format, with an instruction

View File

@@ -1,5 +0,0 @@
require 'tmail/version'
require 'tmail/mail'
require 'tmail/mailbox'
require 'tmail/core_extensions'
require 'tmail/net'

View File

@@ -1,426 +0,0 @@
=begin rdoc
= Address handling class
=end
#--
# 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
#
# Provides a complete handling library for email addresses. Can parse a string of an
# address directly or take in preformatted addresses themselves. Allows you to add
# and remove phrases from the front of the address and provides a compare function for
# email addresses.
#
# == Parsing and Handling a Valid Address:
#
# Just pass the email address in as a string to Address.parse:
#
# email = TMail::Address.parse('Mikel Lindsaar <mikel@lindsaar.net>)
# #=> #<TMail::Address mikel@lindsaar.net>
# email.address
# #=> "mikel@lindsaar.net"
# email.local
# #=> "mikel"
# email.domain
# #=> "lindsaar.net"
# email.name # Aliased as phrase as well
# #=> "Mikel Lindsaar"
#
# == Detecting an Invalid Address
#
# If you want to check the syntactical validity of an email address, just pass it to
# Address.parse and catch any SyntaxError:
#
# begin
# TMail::Mail.parse("mikel 2@@@@@ me .com")
# rescue TMail::SyntaxError
# puts("Invalid Email Address Detected")
# else
# puts("Address is valid")
# end
# #=> "Invalid Email Address Detected"
class Address
include TextUtils #:nodoc:
# Sometimes you need to parse an address, TMail can do it for you and provide you with
# a fairly robust method of detecting a valid address.
#
# Takes in a string, returns a TMail::Address object.
#
# Raises a TMail::SyntaxError on invalid email format
def Address.parse( str )
Parser.parse :ADDRESS, special_quote_address(str)
end
def Address.special_quote_address(str) #:nodoc:
# Takes a string which is an address and adds quotation marks to special
# edge case methods that the RACC parser can not handle.
#
# Right now just handles two edge cases:
#
# Full stop as the last character of the display name:
# Mikel L. <mikel@me.com>
# Returns:
# "Mikel L." <mikel@me.com>
#
# Unquoted @ symbol in the display name:
# mikel@me.com <mikel@me.com>
# Returns:
# "mikel@me.com" <mikel@me.com>
#
# Any other address not matching these patterns just gets returned as is.
case
# This handles the missing "" in an older version of Apple Mail.app
# around the display name when the display name contains a '@'
# like 'mikel@me.com <mikel@me.com>'
# Just quotes it to: '"mikel@me.com" <mikel@me.com>'
when str =~ /\A([^"].+@.+[^"])\s(<.*?>)\Z/
return "\"#{$1}\" #{$2}"
# This handles cases where 'Mikel A. <mikel@me.com>' which is a trailing
# full stop before the address section. Just quotes it to
# '"Mikel A. <mikel@me.com>"
when str =~ /\A(.*?\.)\s(<.*?>)\Z/
return "\"#{$1}\" #{$2}"
else
str
end
end
def address_group? #:nodoc:
false
end
# Address.new(local, domain)
#
# Accepts:
#
# * local - Left of the at symbol
#
# * domain - Array of the domain split at the periods.
#
# For example:
#
# Address.new("mikel", ["lindsaar", "net"])
# #=> "#<TMail::Address mikel@lindsaar.net>"
def initialize( local, domain )
if domain
domain.each do |s|
raise SyntaxError, 'empty word in domain' if s.empty?
end
end
# This is to catch an unquoted "@" symbol in the local part of the
# address. Handles addresses like <"@"@me.com> and makes sure they
# stay like <"@"@me.com> (previously were becoming <@@me.com>)
if local && (local.join == '@' || local.join =~ /\A[^"].*?@.*?[^"]\Z/)
@local = "\"#{local.join}\""
else
@local = local
end
@domain = domain
@name = nil
@routes = []
end
# Provides the name or 'phrase' of the email address.
#
# For Example:
#
# email = TMail::Address.parse("Mikel Lindsaar <mikel@lindsaar.net>")
# email.name
# #=> "Mikel Lindsaar"
def name
@name
end
# Setter method for the name or phrase of the email
#
# For Example:
#
# email = TMail::Address.parse("mikel@lindsaar.net")
# email.name
# #=> nil
# email.name = "Mikel Lindsaar"
# email.to_s
# #=> "Mikel Lindsaar <mikel@me.com>"
def name=( str )
@name = str
@name = nil if str and str.empty?
end
#:stopdoc:
alias phrase name
alias phrase= name=
#:startdoc:
# This is still here from RFC 822, and is now obsolete per RFC2822 Section 4.
#
# "When interpreting addresses, the route portion SHOULD be ignored."
#
# It is still here, so you can access it.
#
# Routes return the route portion at the front of the email address, if any.
#
# For Example:
# email = TMail::Address.parse( "<@sa,@another:Mikel@me.com>")
# => #<TMail::Address Mikel@me.com>
# email.to_s
# => "<@sa,@another:Mikel@me.com>"
# email.routes
# => ["sa", "another"]
def routes
@routes
end
def inspect #:nodoc:
"#<#{self.class} #{address()}>"
end
# Returns the local part of the email address
#
# For Example:
#
# email = TMail::Address.parse("mikel@lindsaar.net")
# email.local
# #=> "mikel"
def local
return nil unless @local
return '""' if @local.size == 1 and @local[0].empty?
# Check to see if it is an array before trying to map it
if @local.respond_to?(:map)
@local.map {|i| quote_atom(i) }.join('.')
else
quote_atom(@local)
end
end
# Returns the domain part of the email address
#
# For Example:
#
# email = TMail::Address.parse("mikel@lindsaar.net")
# email.local
# #=> "lindsaar.net"
def domain
return nil unless @domain
join_domain(@domain)
end
# Returns the full specific address itself
#
# For Example:
#
# email = TMail::Address.parse("mikel@lindsaar.net")
# email.address
# #=> "mikel@lindsaar.net"
def spec
s = self.local
d = self.domain
if s and d
s + '@' + d
else
s
end
end
alias address spec
# Provides == function to the email. Only checks the actual address
# and ignores the name/phrase component
#
# For Example
#
# addr1 = TMail::Address.parse("My Address <mikel@lindsaar.net>")
# #=> "#<TMail::Address mikel@lindsaar.net>"
# addr2 = TMail::Address.parse("Another <mikel@lindsaar.net>")
# #=> "#<TMail::Address mikel@lindsaar.net>"
# addr1 == addr2
# #=> true
def ==( other )
other.respond_to? :spec and self.spec == other.spec
end
alias eql? ==
# Provides a unique hash value for this record against the local and domain
# parts, ignores the name/phrase value
#
# email = TMail::Address.parse("mikel@lindsaar.net")
# email.hash
# #=> 18767598
def hash
@local.hash ^ @domain.hash
end
# Duplicates a TMail::Address object returning the duplicate
#
# addr1 = TMail::Address.parse("mikel@lindsaar.net")
# addr2 = addr1.dup
# addr1.id == addr2.id
# #=> false
def dup
obj = self.class.new(@local.dup, @domain.dup)
obj.name = @name.dup if @name
obj.routes.replace @routes
obj
end
include StrategyInterface #:nodoc:
def accept( strategy, dummy1 = nil, dummy2 = nil ) #:nodoc:
unless @local
strategy.meta '<>' # empty return-path
return
end
spec_p = (not @name and @routes.empty?)
if @name
strategy.phrase @name
strategy.space
end
tmp = spec_p ? '' : '<'
unless @routes.empty?
tmp << @routes.map {|i| '@' + i }.join(',') << ':'
end
tmp << self.spec
tmp << '>' unless spec_p
strategy.meta tmp
strategy.lwsp ''
end
end
class AddressGroup
include Enumerable
def address_group?
true
end
def initialize( name, addrs )
@name = name
@addresses = addrs
end
attr_reader :name
def ==( other )
other.respond_to? :to_a and @addresses == other.to_a
end
alias eql? ==
def hash
map {|i| i.hash }.hash
end
def []( idx )
@addresses[idx]
end
def size
@addresses.size
end
def empty?
@addresses.empty?
end
def each( &block )
@addresses.each(&block)
end
def to_a
@addresses.dup
end
alias to_ary to_a
def include?( a )
@addresses.include? a
end
def flatten
set = []
@addresses.each do |a|
if a.respond_to? :flatten
set.concat a.flatten
else
set.push a
end
end
set
end
def each_address( &block )
flatten.each(&block)
end
def add( a )
@addresses.push a
end
alias push add
def delete( a )
@addresses.delete a
end
include StrategyInterface
def accept( strategy, dummy1 = nil, dummy2 = nil )
strategy.phrase @name
strategy.meta ':'
strategy.space
first = true
each do |mbox|
if first
first = false
else
strategy.meta ','
end
strategy.space
mbox.accept strategy
end
strategy.meta ';'
strategy.lwsp ''
end
end
end # module TMail

View File

@@ -1,46 +0,0 @@
=begin rdoc
= Attachment handling file
=end
require 'stringio'
module TMail
class Attachment < StringIO
attr_accessor :original_filename, :content_type
end
class Mail
def has_attachments?
multipart? && parts.any? { |part| attachment?(part) }
end
def attachment?(part)
part.disposition_is_attachment? || part.content_type_is_text?
end
def attachments
if multipart?
parts.collect { |part|
if part.multipart?
part.attachments
elsif attachment?(part)
content = part.body # unquoted automatically by TMail#body
file_name = (part['content-location'] &&
part['content-location'].body) ||
part.sub_header("content-type", "name") ||
part.sub_header("content-disposition", "filename")
next if file_name.blank? || content.blank?
attachment = Attachment.new(content)
attachment.original_filename = file_name.strip
attachment.content_type = part.content_type
attachment
end
}.flatten.compact
end
end
end
end

View File

@@ -1,46 +0,0 @@
#--
# 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.
#++
#:stopdoc:
module TMail
module Base64
module_function
def folding_encode( str, eol = "\n", limit = 60 )
[str].pack('m')
end
def encode( str )
[str].pack('m').tr( "\r\n", '' )
end
def decode( str, strict = false )
str.unpack('m').first
end
end
end
#:startdoc:

View File

@@ -1,41 +0,0 @@
#:stopdoc:
unless Enumerable.method_defined?(:map)
module Enumerable #:nodoc:
alias map collect
end
end
unless Enumerable.method_defined?(:select)
module Enumerable #:nodoc:
alias select find_all
end
end
unless Enumerable.method_defined?(:reject)
module Enumerable #:nodoc:
def reject
result = []
each do |i|
result.push i unless yield(i)
end
result
end
end
end
unless Enumerable.method_defined?(:sort_by)
module Enumerable #:nodoc:
def sort_by
map {|i| [yield(i), i] }.sort.map {|val, i| i }
end
end
end
unless File.respond_to?(:read)
def File.read(fname) #:nodoc:
File.open(fname) {|f|
return f.read
}
end
end
#:startdoc:

View File

@@ -1,67 +0,0 @@
#--
# 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.
#++
#:stopdoc:
module TMail
class Config
def initialize( strict )
@strict_parse = strict
@strict_base64decode = strict
end
def strict_parse?
@strict_parse
end
attr_writer :strict_parse
def strict_base64decode?
@strict_base64decode
end
attr_writer :strict_base64decode
def new_body_port( mail )
StringPort.new
end
alias new_preamble_port new_body_port
alias new_part_port new_body_port
end
DEFAULT_CONFIG = Config.new(false)
DEFAULT_STRICT_CONFIG = Config.new(true)
def Config.to_config( arg )
return DEFAULT_STRICT_CONFIG if arg == true
return DEFAULT_CONFIG if arg == false
arg or DEFAULT_CONFIG
end
end
#:startdoc:

View File

@@ -1,63 +0,0 @@
#:stopdoc:
unless Object.respond_to?(:blank?)
class Object
# Check first to see if we are in a Rails environment, no need to
# define these methods if we are
# An object is blank if it's nil, empty, or a whitespace string.
# For example, "", " ", nil, [], and {} are blank.
#
# This simplifies
# if !address.nil? && !address.empty?
# to
# if !address.blank?
def blank?
if respond_to?(:empty?) && respond_to?(:strip)
empty? or strip.empty?
elsif respond_to?(:empty?)
empty?
else
!self
end
end
end
class NilClass
def blank?
true
end
end
class FalseClass
def blank?
true
end
end
class TrueClass
def blank?
false
end
end
class Array
alias_method :blank?, :empty?
end
class Hash
alias_method :blank?, :empty?
end
class String
def blank?
empty? || strip.empty?
end
end
class Numeric
def blank?
false
end
end
end
#:startdoc:

View File

@@ -1,581 +0,0 @@
#--
# = COPYRIGHT:
#
# 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.
#++
#:stopdoc:
require 'nkf'
require 'tmail/base64'
require 'tmail/stringio'
require 'tmail/utils'
#:startdoc:
module TMail
#:stopdoc:
class << self
attr_accessor :KCODE
end
self.KCODE = 'NONE'
module StrategyInterface
def create_dest( obj )
case obj
when nil
StringOutput.new
when String
StringOutput.new(obj)
when IO, StringOutput
obj
else
raise TypeError, 'cannot handle this type of object for dest'
end
end
module_function :create_dest
#:startdoc:
# Returns the TMail object encoded and ready to be sent via SMTP etc.
# You should call this before you are packaging up your email to
# correctly escape all the values that need escaping in the email, line
# wrap the email etc.
#
# It is also a good idea to call this before you marshal or serialize
# a TMail object.
#
# For Example:
#
# email = TMail::Load(my_email_file)
# email_to_send = email.encoded
def encoded( eol = "\r\n", charset = 'j', dest = nil )
accept_strategy Encoder, eol, charset, dest
end
# Returns the TMail object decoded and ready to be used by you, your
# program etc.
#
# You should call this before you are packaging up your email to
# correctly escape all the values that need escaping in the email, line
# wrap the email etc.
#
# For Example:
#
# email = TMail::Load(my_email_file)
# email_to_send = email.encoded
def decoded( eol = "\n", charset = 'e', dest = nil )
# Turn the E-Mail into a string and return it with all
# encoded characters decoded. alias for to_s
accept_strategy Decoder, eol, charset, dest
end
alias to_s decoded
def accept_strategy( klass, eol, charset, dest = nil ) #:nodoc:
dest ||= ''
accept klass.new( create_dest(dest), charset, eol )
dest
end
end
#:stopdoc:
###
### MIME B encoding decoder
###
class Decoder
include TextUtils
encoded = '=\?(?:iso-2022-jp|euc-jp|shift_jis)\?[QB]\?[a-z0-9+/=]+\?='
ENCODED_WORDS = /#{encoded}(?:\s+#{encoded})*/i
OUTPUT_ENCODING = {
'EUC' => 'e',
'SJIS' => 's',
}
def self.decode( str, encoding = nil )
encoding ||= (OUTPUT_ENCODING[TMail.KCODE] || 'j')
opt = '-mS' + encoding
str.gsub(ENCODED_WORDS) {|s| NKF.nkf(opt, s) }
end
def initialize( dest, encoding = nil, eol = "\n" )
@f = StrategyInterface.create_dest(dest)
@encoding = (/\A[ejs]/ === encoding) ? encoding[0,1] : nil
@eol = eol
end
def decode( str )
self.class.decode(str, @encoding)
end
private :decode
def terminate
end
def header_line( str )
@f << decode(str)
end
def header_name( nm )
@f << nm << ': '
end
def header_body( str )
@f << decode(str)
end
def space
@f << ' '
end
alias spc space
def lwsp( str )
@f << str
end
def meta( str )
@f << str
end
def text( str )
@f << decode(str)
end
def phrase( str )
@f << quote_phrase(decode(str))
end
def kv_pair( k, v )
v = dquote(v) unless token_safe?(v)
@f << k << '=' << v
end
def puts( str = nil )
@f << str if str
@f << @eol
end
def write( str )
@f << str
end
end
###
### MIME B-encoding encoder
###
#
# FIXME: This class can handle only (euc-jp/shift_jis -> iso-2022-jp).
#
class Encoder
include TextUtils
BENCODE_DEBUG = false unless defined?(BENCODE_DEBUG)
def Encoder.encode( str )
e = new()
e.header_body str
e.terminate
e.dest.string
end
SPACER = "\t"
MAX_LINE_LEN = 78
RFC_2822_MAX_LENGTH = 998
OPTIONS = {
'EUC' => '-Ej -m0',
'SJIS' => '-Sj -m0',
'UTF8' => nil, # FIXME
'NONE' => nil
}
def initialize( dest = nil, encoding = nil, eol = "\r\n", limit = nil )
@f = StrategyInterface.create_dest(dest)
@opt = OPTIONS[TMail.KCODE]
@eol = eol
@folded = false
@preserve_quotes = true
reset
end
def preserve_quotes=( bool )
@preserve_quotes
end
def preserve_quotes
@preserve_quotes
end
def normalize_encoding( str )
if @opt
then NKF.nkf(@opt, str)
else str
end
end
def reset
@text = ''
@lwsp = ''
@curlen = 0
end
def terminate
add_lwsp ''
reset
end
def dest
@f
end
def puts( str = nil )
@f << str if str
@f << @eol
end
def write( str )
@f << str
end
#
# add
#
def header_line( line )
scanadd line
end
def header_name( name )
add_text name.split(/-/).map {|i| i.capitalize }.join('-')
add_text ':'
add_lwsp ' '
end
def header_body( str )
scanadd normalize_encoding(str)
end
def space
add_lwsp ' '
end
alias spc space
def lwsp( str )
add_lwsp str.sub(/[\r\n]+[^\r\n]*\z/, '')
end
def meta( str )
add_text str
end
def text( str )
scanadd normalize_encoding(str)
end
def phrase( str )
str = normalize_encoding(str)
if CONTROL_CHAR === str
scanadd str
else
add_text quote_phrase(str)
end
end
# FIXME: implement line folding
#
def kv_pair( k, v )
return if v.nil?
v = normalize_encoding(v)
if token_safe?(v)
add_text k + '=' + v
elsif not CONTROL_CHAR === v
add_text k + '=' + quote_token(v)
else
# apply RFC2231 encoding
kv = k + '*=' + "iso-2022-jp'ja'" + encode_value(v)
add_text kv
end
end
def encode_value( str )
str.gsub(TOKEN_UNSAFE) {|s| '%%%02x' % s[0] }
end
private
def scanadd( str, force = false )
types = ''
strs = []
if str.respond_to?(:encoding)
enc = str.encoding
str.force_encoding(Encoding::ASCII_8BIT)
end
until str.empty?
if m = /\A[^\e\t\r\n ]+/.match(str)
types << (force ? 'j' : 'a')
if str.respond_to?(:encoding)
strs.push m[0].force_encoding(enc)
else
strs.push m[0]
end
elsif m = /\A[\t\r\n ]+/.match(str)
types << 's'
if str.respond_to?(:encoding)
strs.push m[0].force_encoding(enc)
else
strs.push m[0]
end
elsif m = /\A\e../.match(str)
esc = m[0]
str = m.post_match
if esc != "\e(B" and m = /\A[^\e]+/.match(str)
types << 'j'
if str.respond_to?(:encoding)
strs.push m[0].force_encoding(enc)
else
strs.push m[0]
end
end
else
raise 'TMail FATAL: encoder scan fail'
end
(str = m.post_match) unless m.nil?
end
do_encode types, strs
end
def do_encode( types, strs )
#
# result : (A|E)(S(A|E))*
# E : W(SW)*
# W : (J|A)+ but must contain J # (J|A)*J(J|A)*
# A : <<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 )
if RUBY_VERSION < '1.9'
a = ?a; s = ?s
else
a = 'a'.ord; s = 's'.ord
end
i = 0
types.each_byte do |t|
case t
when a then add_text strs[i]
when s then add_lwsp strs[i]
else
raise "TMail FATAL: unknown flag: #{t.chr}"
end
i += 1
end
end
METHOD_ID = {
?j => :extract_J,
?e => :extract_E,
?a => :extract_A,
?s => :extract_S
}
def concat_E( types, strs )
if BENCODE_DEBUG
puts '---- concat_E'
puts "types=#{types.split(//).join(' ')}"
puts "strs =#{strs.inspect}"
end
flush() unless @text.empty?
chunk = ''
strs.each_with_index do |s,i|
mid = METHOD_ID[types[i]]
until s.empty?
unless c = __send__(mid, chunk.size, s)
add_with_encode chunk unless chunk.empty?
flush
chunk = ''
fold
c = __send__(mid, 0, s)
raise 'TMail FATAL: extract fail' unless c
end
chunk << c
end
end
add_with_encode chunk unless chunk.empty?
end
def extract_J( chunksize, str )
size = max_bytes(chunksize, str.size) - 6
size = (size % 2 == 0) ? (size) : (size - 1)
return nil if size <= 0
if str.respond_to?(:encoding)
enc = str.encoding
str.force_encoding(Encoding::ASCII_8BIT)
"\e$B#{str.slice!(0, size)}\e(B".force_encoding(enc)
else
"\e$B#{str.slice!(0, size)}\e(B"
end
end
def extract_A( chunksize, str )
size = max_bytes(chunksize, str.size)
return nil if size <= 0
str.slice!(0, size)
end
alias extract_S extract_A
def max_bytes( chunksize, ssize )
(restsize() - '=?iso-2022-jp?B??='.size) / 4 * 3 - chunksize
end
#
# free length buffer
#
def add_text( str )
@text << str
# puts '---- text -------------------------------------'
# puts "+ #{str.inspect}"
# puts "txt >>>#{@text.inspect}<<<"
end
def add_with_encode( str )
@text << "=?iso-2022-jp?B?#{Base64.encode(str)}?="
end
def add_lwsp( lwsp )
# puts '---- lwsp -------------------------------------'
# puts "+ #{lwsp.inspect}"
fold if restsize() <= 0
flush(@folded)
@lwsp = lwsp
end
def flush(folded = false)
# puts '---- flush ----'
# puts "spc >>>#{@lwsp.inspect}<<<"
# puts "txt >>>#{@text.inspect}<<<"
@f << @lwsp << @text
if folded
@curlen = 0
else
@curlen += (@lwsp.size + @text.size)
end
@text = ''
@lwsp = ''
end
def fold
# puts '---- fold ----'
unless @f.string =~ /^.*?:$/
@f << @eol
@lwsp = SPACER
else
fold_header
@folded = true
end
@curlen = 0
end
def fold_header
# Called because line is too long - so we need to wrap.
# First look for whitespace in the text
# if it has text, fold there
# check the remaining text, if too long, fold again
# if it doesn't, then don't fold unless the line goes beyond 998 chars
# Check the text to see if there is whitespace, or if not
@wrapped_text = []
until @text.blank?
fold_the_string
end
@text = @wrapped_text.join("#{@eol}#{SPACER}")
end
def fold_the_string
whitespace_location = @text =~ /\s/ || @text.length
# Is the location of the whitespace shorter than the RCF_2822_MAX_LENGTH?
# if there is no whitespace in the string, then this
unless mazsize(whitespace_location) <= 0
@text.strip!
@wrapped_text << @text.slice!(0...whitespace_location)
# If it is not less, we have to wrap it destructively
else
slice_point = RFC_2822_MAX_LENGTH - @curlen - @lwsp.length
@text.strip!
@wrapped_text << @text.slice!(0...slice_point)
end
end
def restsize
MAX_LINE_LEN - (@curlen + @lwsp.size + @text.size)
end
def mazsize(whitespace_location)
# Per RFC2822, the maximum length of a line is 998 chars
RFC_2822_MAX_LENGTH - (@curlen + @lwsp.size + whitespace_location)
end
end
#:startdoc:
end # module TMail

View File

@@ -1,960 +0,0 @@
#--
# 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'
#:startdoc:
module TMail
# Provides methods to handle and manipulate headers in the email
class HeaderField
include TextUtils
class << self
alias newobj new
def new( name, body, conf = DEFAULT_CONFIG )
klass = FNAME_TO_CLASS[name.downcase] || UnstructuredHeader
klass.newobj body, conf
end
# Returns a HeaderField object matching the header you specify in the "name" param.
# Requires an initialized TMail::Port to be passed in.
#
# The method searches the header of the Port you pass into it to find a match on
# the header line you pass. Once a match is found, it will unwrap the matching line
# as needed to return an initialized HeaderField object.
#
# If you want to get the Envelope sender of the email object, pass in "EnvelopeSender",
# if you want the From address of the email itself, pass in 'From'.
#
# This is because a mailbox doesn't have the : after the From that designates the
# beginning of the envelope sender (which can be different to the from address of
# the email)
#
# Other fields can be passed as normal, "Reply-To", "Received" etc.
#
# Note: Change of behaviour in 1.2.1 => returns nil if it does not find the specified
# header field, otherwise returns an instantiated object of the correct header class
#
# For example:
# port = TMail::FilePort.new("/test/fixtures/raw_email_simple")
# h = TMail::HeaderField.new_from_port(port, "From")
# h.addrs.to_s #=> "Mikel Lindsaar <mikel@nowhere.com>"
# h = TMail::HeaderField.new_from_port(port, "EvelopeSender")
# h.addrs.to_s #=> "mike@anotherplace.com.au"
# h = TMail::HeaderField.new_from_port(port, "SomeWeirdHeaderField")
# h #=> nil
def new_from_port( port, name, conf = DEFAULT_CONFIG )
if name == "EnvelopeSender"
name = "From"
re = Regexp.new('\A(From) ', 'i')
else
re = Regexp.new('\A(' + Regexp.quote(name) + '):', 'i')
end
str = nil
port.ropen {|f|
f.each do |line|
if m = re.match(line) then str = m.post_match.strip
elsif str and /\A[\t ]/ === line then str << ' ' << line.strip
elsif /\A-*\s*\z/ === line then break
elsif str then break
end
end
}
new(name, str, Config.to_config(conf)) if str
end
def internal_new( name, conf )
FNAME_TO_CLASS[name].newobj('', conf, true)
end
end # class << self
def initialize( body, conf, intern = false )
@body = body
@config = conf
@illegal = false
@parsed = false
if intern
@parsed = true
parse_init
end
end
def inspect
"#<#{self.class} #{@body.inspect}>"
end
def illegal?
@illegal
end
def empty?
ensure_parsed
return true if @illegal
isempty?
end
private
def ensure_parsed
return if @parsed
@parsed = true
parse
end
# defabstract parse
# end
def clear_parse_status
@parsed = false
@illegal = false
end
public
def body
ensure_parsed
v = Decoder.new(s = '')
do_accept v
v.terminate
s
end
def body=( str )
@body = str
clear_parse_status
end
include StrategyInterface
def accept( strategy )
ensure_parsed
do_accept strategy
strategy.terminate
end
# abstract do_accept
end
class UnstructuredHeader < HeaderField
def body
ensure_parsed
@body
end
def body=( arg )
ensure_parsed
@body = arg
end
private
def parse_init
end
def parse
@body = Decoder.decode(@body.gsub(/\n|\r\n|\r/, ''))
end
def isempty?
not @body
end
def do_accept( strategy )
strategy.text @body
end
end
class StructuredHeader < HeaderField
def comments
ensure_parsed
if @comments[0]
[Decoder.decode(@comments[0])]
else
@comments
end
end
private
def parse
save = nil
begin
parse_init
do_parse
rescue SyntaxError
if not save and mime_encoded? @body
save = @body
@body = Decoder.decode(save)
retry
elsif save
@body = save
end
@illegal = true
raise if @config.strict_parse?
end
end
def parse_init
@comments = []
init
end
def do_parse
quote_boundary
obj = Parser.parse(self.class::PARSE_TYPE, @body, @comments)
set obj if obj
end
end
class DateTimeHeader < StructuredHeader
PARSE_TYPE = :DATETIME
def date
ensure_parsed
@date
end
def date=( arg )
ensure_parsed
@date = arg
end
private
def init
@date = nil
end
def set( t )
@date = t
end
def isempty?
not @date
end
def do_accept( strategy )
strategy.meta time2str(@date)
end
end
class AddressHeader < StructuredHeader
PARSE_TYPE = :MADDRESS
def addrs
ensure_parsed
@addrs
end
private
def init
@addrs = []
end
def set( a )
@addrs = a
end
def isempty?
@addrs.empty?
end
def do_accept( strategy )
first = true
@addrs.each do |a|
if first
first = false
else
strategy.meta ','
strategy.space
end
a.accept strategy
end
@comments.each do |c|
strategy.space
strategy.meta '('
strategy.text c
strategy.meta ')'
end
end
end
class ReturnPathHeader < AddressHeader
PARSE_TYPE = :RETPATH
def addr
addrs()[0]
end
def spec
a = addr() or return nil
a.spec
end
def routes
a = addr() or return nil
a.routes
end
private
def do_accept( strategy )
a = addr()
strategy.meta '<'
unless a.routes.empty?
strategy.meta a.routes.map {|i| '@' + i }.join(',')
strategy.meta ':'
end
spec = a.spec
strategy.meta spec if spec
strategy.meta '>'
end
end
class SingleAddressHeader < AddressHeader
def addr
addrs()[0]
end
private
def do_accept( strategy )
a = addr()
a.accept strategy
@comments.each do |c|
strategy.space
strategy.meta '('
strategy.text c
strategy.meta ')'
end
end
end
class MessageIdHeader < StructuredHeader
def id
ensure_parsed
@id
end
def id=( arg )
ensure_parsed
@id = arg
end
private
def init
@id = nil
end
def isempty?
not @id
end
def do_parse
@id = @body.slice(MESSAGE_ID) or
raise SyntaxError, "wrong Message-ID format: #{@body}"
end
def do_accept( strategy )
strategy.meta @id
end
end
class ReferencesHeader < StructuredHeader
def refs
ensure_parsed
@refs
end
def each_id
self.refs.each do |i|
yield i if MESSAGE_ID === i
end
end
def ids
ensure_parsed
@ids
end
def each_phrase
self.refs.each do |i|
yield i unless MESSAGE_ID === i
end
end
def phrases
ret = []
each_phrase {|i| ret.push i }
ret
end
private
def init
@refs = []
@ids = []
end
def isempty?
@ids.empty?
end
def do_parse
str = @body
while m = MESSAGE_ID.match(str)
pre = m.pre_match.strip
@refs.push pre unless pre.empty?
@refs.push s = m[0]
@ids.push s
str = m.post_match
end
str = str.strip
@refs.push str unless str.empty?
end
def do_accept( strategy )
first = true
@ids.each do |i|
if first
first = false
else
strategy.space
end
strategy.meta i
end
end
end
class ReceivedHeader < StructuredHeader
PARSE_TYPE = :RECEIVED
def from
ensure_parsed
@from
end
def from=( arg )
ensure_parsed
@from = arg
end
def by
ensure_parsed
@by
end
def by=( arg )
ensure_parsed
@by = arg
end
def via
ensure_parsed
@via
end
def via=( arg )
ensure_parsed
@via = arg
end
def with
ensure_parsed
@with
end
def id
ensure_parsed
@id
end
def id=( arg )
ensure_parsed
@id = arg
end
def _for
ensure_parsed
@_for
end
def _for=( arg )
ensure_parsed
@_for = arg
end
def date
ensure_parsed
@date
end
def date=( arg )
ensure_parsed
@date = arg
end
private
def init
@from = @by = @via = @with = @id = @_for = nil
@with = []
@date = nil
end
def set( args )
@from, @by, @via, @with, @id, @_for, @date = *args
end
def isempty?
@with.empty? and not (@from or @by or @via or @id or @_for or @date)
end
def do_accept( strategy )
list = []
list.push 'from ' + @from if @from
list.push 'by ' + @by if @by
list.push 'via ' + @via if @via
@with.each do |i|
list.push 'with ' + i
end
list.push 'id ' + @id if @id
list.push 'for <' + @_for + '>' if @_for
first = true
list.each do |i|
strategy.space unless first
strategy.meta i
first = false
end
if @date
strategy.meta ';'
strategy.space
strategy.meta time2str(@date)
end
end
end
class KeywordsHeader < StructuredHeader
PARSE_TYPE = :KEYWORDS
def keys
ensure_parsed
@keys
end
private
def init
@keys = []
end
def set( a )
@keys = a
end
def isempty?
@keys.empty?
end
def do_accept( strategy )
first = true
@keys.each do |i|
if first
first = false
else
strategy.meta ','
end
strategy.meta i
end
end
end
class EncryptedHeader < StructuredHeader
PARSE_TYPE = :ENCRYPTED
def encrypter
ensure_parsed
@encrypter
end
def encrypter=( arg )
ensure_parsed
@encrypter = arg
end
def keyword
ensure_parsed
@keyword
end
def keyword=( arg )
ensure_parsed
@keyword = arg
end
private
def init
@encrypter = nil
@keyword = nil
end
def set( args )
@encrypter, @keyword = args
end
def isempty?
not (@encrypter or @keyword)
end
def do_accept( strategy )
if @key
strategy.meta @encrypter + ','
strategy.space
strategy.meta @keyword
else
strategy.meta @encrypter
end
end
end
class MimeVersionHeader < StructuredHeader
PARSE_TYPE = :MIMEVERSION
def major
ensure_parsed
@major
end
def major=( arg )
ensure_parsed
@major = arg
end
def minor
ensure_parsed
@minor
end
def minor=( arg )
ensure_parsed
@minor = arg
end
def version
sprintf('%d.%d', major, minor)
end
private
def init
@major = nil
@minor = nil
end
def set( args )
@major, @minor = *args
end
def isempty?
not (@major or @minor)
end
def do_accept( strategy )
strategy.meta sprintf('%d.%d', @major, @minor)
end
end
class ContentTypeHeader < StructuredHeader
PARSE_TYPE = :CTYPE
def main_type
ensure_parsed
@main
end
def main_type=( arg )
ensure_parsed
@main = arg.downcase
end
def sub_type
ensure_parsed
@sub
end
def sub_type=( arg )
ensure_parsed
@sub = arg.downcase
end
def content_type
ensure_parsed
@sub ? sprintf('%s/%s', @main, @sub) : @main
end
def params
ensure_parsed
unless @params.blank?
@params.each do |k, v|
@params[k] = unquote(v)
end
end
@params
end
def []( key )
ensure_parsed
@params and unquote(@params[key])
end
def []=( key, val )
ensure_parsed
(@params ||= {})[key] = val
end
private
def init
@main = @sub = @params = nil
end
def set( args )
@main, @sub, @params = *args
end
def isempty?
not (@main or @sub)
end
def do_accept( strategy )
if @sub
strategy.meta sprintf('%s/%s', @main, @sub)
else
strategy.meta @main
end
@params.each do |k,v|
if v
strategy.meta ';'
strategy.space
strategy.kv_pair k, v
end
end
end
end
class ContentTransferEncodingHeader < StructuredHeader
PARSE_TYPE = :CENCODING
def encoding
ensure_parsed
@encoding
end
def encoding=( arg )
ensure_parsed
@encoding = arg
end
private
def init
@encoding = nil
end
def set( s )
@encoding = s
end
def isempty?
not @encoding
end
def do_accept( strategy )
strategy.meta @encoding.capitalize
end
end
class ContentDispositionHeader < StructuredHeader
PARSE_TYPE = :CDISPOSITION
def disposition
ensure_parsed
@disposition
end
def disposition=( str )
ensure_parsed
@disposition = str.downcase
end
def params
ensure_parsed
unless @params.blank?
@params.each do |k, v|
@params[k] = unquote(v)
end
end
@params
end
def []( key )
ensure_parsed
@params and unquote(@params[key])
end
def []=( key, val )
ensure_parsed
(@params ||= {})[key] = val
end
private
def init
@disposition = @params = nil
end
def set( args )
@disposition, @params = *args
end
def isempty?
not @disposition and (not @params or @params.empty?)
end
def do_accept( strategy )
strategy.meta @disposition
@params.each do |k,v|
strategy.meta ';'
strategy.space
strategy.kv_pair k, unquote(v)
end
end
end
class HeaderField # redefine
FNAME_TO_CLASS = {
'date' => DateTimeHeader,
'resent-date' => DateTimeHeader,
'to' => AddressHeader,
'cc' => AddressHeader,
'bcc' => AddressHeader,
'from' => AddressHeader,
'reply-to' => AddressHeader,
'resent-to' => AddressHeader,
'resent-cc' => AddressHeader,
'resent-bcc' => AddressHeader,
'resent-from' => AddressHeader,
'resent-reply-to' => AddressHeader,
'sender' => SingleAddressHeader,
'resent-sender' => SingleAddressHeader,
'return-path' => ReturnPathHeader,
'message-id' => MessageIdHeader,
'resent-message-id' => MessageIdHeader,
'in-reply-to' => ReferencesHeader,
'received' => ReceivedHeader,
'references' => ReferencesHeader,
'keywords' => KeywordsHeader,
'encrypted' => EncryptedHeader,
'mime-version' => MimeVersionHeader,
'content-type' => ContentTypeHeader,
'content-transfer-encoding' => ContentTransferEncodingHeader,
'content-disposition' => ContentDispositionHeader,
'content-id' => MessageIdHeader,
'subject' => UnstructuredHeader,
'comments' => UnstructuredHeader,
'content-description' => UnstructuredHeader
}
end
end # module TMail

View File

@@ -1,9 +0,0 @@
#:stopdoc:
# This is here for Rolls.
# Rolls uses this instead of lib/tmail.rb.
require 'tmail/version'
require 'tmail/mail'
require 'tmail/mailbox'
require 'tmail/core_extensions'
#:startdoc:

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +0,0 @@
#:stopdoc:
require 'tmail/mailbox'
#:startdoc:

View File

@@ -1,578 +0,0 @@
=begin rdoc
= Mail class
=end
#--
# 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/interface'
require 'tmail/encode'
require 'tmail/header'
require 'tmail/port'
require 'tmail/config'
require 'tmail/utils'
require 'tmail/attachments'
require 'tmail/quoting'
require 'socket'
module TMail
# == Mail Class
#
# Accessing a TMail object done via the TMail::Mail class. As email can be fairly complex
# creatures, you will find a large amount of accessor and setter methods in this class!
#
# Most of the below methods handle the header, in fact, what TMail does best is handle the
# header of the email object. There are only a few methods that deal directly with the body
# of the email, such as base64_encode and base64_decode.
#
# === Using TMail inside your code
#
# The usual way is to install the gem (see the {README}[link:/README] on how to do this) and
# then put at the top of your class:
#
# require 'tmail'
#
# You can then create a new TMail object in your code with:
#
# @email = TMail::Mail.new
#
# Or if you have an email as a string, you can initialize a new TMail::Mail object and get it
# to parse that string for you like so:
#
# @email = TMail::Mail.parse(email_text)
#
# You can also read a single email off the disk, for example:
#
# @email = TMail::Mail.load('filename.txt')
#
# Also, you can read a mailbox (usual unix mbox format) and end up with an array of TMail
# objects by doing something like this:
#
# # Note, we pass true as the last variable to open the mailbox read only
# mailbox = TMail::UNIXMbox.new("mailbox", nil, true)
# @emails = []
# mailbox.each_port { |m| @emails << TMail::Mail.new(m) }
#
class Mail
class << self
# Opens an email that has been saved out as a file by itself.
#
# This function will read a file non-destructively and then parse
# the contents and return a TMail::Mail object.
#
# Does not handle multiple email mailboxes (like a unix mbox) for that
# use the TMail::UNIXMbox class.
#
# Example:
# mail = TMail::Mail.load('filename')
#
def load( fname )
new(FilePort.new(fname))
end
alias load_from load
alias loadfrom load
# Parses an email from the supplied string and returns a TMail::Mail
# object.
#
# Example:
# require 'rubygems'; require 'tmail'
# email_string =<<HEREDOC
# To: mikel@lindsaar.net
# From: mikel@me.com
# Subject: This is a short Email
#
# Hello there Mikel!
#
# HEREDOC
# mail = TMail::Mail.parse(email_string)
# #=> #<TMail::Mail port=#<TMail::StringPort:id=0xa30ac0> bodyport=nil>
# mail.body
# #=> "Hello there Mikel!\n\n"
def parse( str )
new(StringPort.new(str))
end
end
def initialize( port = nil, conf = DEFAULT_CONFIG ) #:nodoc:
@port = port || StringPort.new
@config = Config.to_config(conf)
@header = {}
@body_port = nil
@body_parsed = false
@epilogue = ''
@parts = []
@port.ropen {|f|
parse_header f
parse_body f unless @port.reproducible?
}
end
# Provides access to the port this email is using to hold it's data
#
# Example:
# mail = TMail::Mail.parse(email_string)
# mail.port
# #=> #<TMail::StringPort:id=0xa2c952>
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
# Returns a TMail::AddressHeader object of the field you are querying.
# Examples:
# @mail['from'] #=> #<TMail::AddressHeader "mikel@test.com.au">
# @mail['to'] #=> #<TMail::AddressHeader "mikel@test.com.au">
#
# You can get the string value of this by passing "to_s" to the query:
# Example:
# @mail['to'].to_s #=> "mikel@test.com.au"
def []( key )
@header[key.downcase]
end
def sub_header(key, param)
(hdr = self[key]) ? hdr[param] : nil
end
alias fetch []
# Allows you to set or delete TMail header objects at will.
# Examples:
# @mail = TMail::Mail.new
# @mail['to'].to_s # => 'mikel@test.com.au'
# @mail['to'] = 'mikel@elsewhere.org'
# @mail['to'].to_s # => 'mikel@elsewhere.org'
# @mail.encoded # => "To: mikel@elsewhere.org\r\n\r\n"
# @mail['to'] = nil
# @mail['to'].to_s # => nil
# @mail.encoded # => "\r\n"
#
# Note: setting mail[] = nil actually deletes the header field in question from the object,
# it does not just set the value of the hash to nil
def []=( key, val )
dkey = key.downcase
if val.nil?
@header.delete dkey
return nil
end
case val
when String
header = new_hf(key, val)
when HeaderField
;
when Array
ALLOW_MULTIPLE.include? dkey or
raise ArgumentError, "#{key}: Header must not be multiple"
@header[dkey] = val
return val
else
header = new_hf(key, val.to_s)
end
if ALLOW_MULTIPLE.include? dkey
(@header[dkey] ||= []).push header
else
@header[dkey] = header
end
val
end
alias store []=
# Allows you to loop through each header in the TMail::Mail object in a block
# Example:
# @mail['to'] = 'mikel@elsewhere.org'
# @mail['from'] = 'me@me.com'
# @mail.each_header { |k,v| puts "#{k} = #{v}" }
# # => from = me@me.com
# # => to = mikel@elsewhere.org
def each_header
@header.each do |key, val|
[val].flatten.each {|v| yield key, v }
end
end
alias each_pair each_header
def each_header_name( &block )
@header.each_key(&block)
end
alias each_key each_header_name
def each_field( &block )
@header.values.flatten.each(&block)
end
alias each_value each_field
FIELD_ORDER = %w(
return-path received
resent-date resent-from resent-sender resent-to
resent-cc resent-bcc resent-message-id
date from sender reply-to to cc bcc
message-id in-reply-to references
subject comments keywords
mime-version content-type content-transfer-encoding
content-disposition content-description
)
def ordered_each
list = @header.keys
FIELD_ORDER.each do |name|
if list.delete(name)
[@header[name]].flatten.each {|v| yield name, v }
end
end
list.each do |name|
[@header[name]].flatten.each {|v| yield name, v }
end
end
def clear
@header.clear
end
def delete( key )
@header.delete key.downcase
end
def delete_if
@header.delete_if do |key,val|
if Array === val
val.delete_if {|v| yield key, v }
val.empty?
else
yield key, val
end
end
end
def keys
@header.keys
end
def key?( key )
@header.key? key.downcase
end
def values_at( *args )
args.map {|k| @header[k.downcase] }.flatten
end
alias indexes values_at
alias indices values_at
private
def parse_header( f )
name = field = nil
unixfrom = nil
while line = f.gets
case line
when /\A[ \t]/ # continue from prev line
raise SyntaxError, 'mail is began by space' unless field
field << ' ' << line.strip
when /\A([^\: \t]+):\s*/ # new header line
add_hf name, field if field
name = $1
field = $' #.strip
when /\A\-*\s*\z/ # end of header
add_hf name, field if field
name = field = nil
break
when /\AFrom (\S+)/
unixfrom = $1
when /^charset=.*/
else
raise SyntaxError, "wrong mail header: '#{line.inspect}'"
end
end
add_hf name, field if name
if unixfrom
add_hf 'Return-Path', "<#{unixfrom}>" unless @header['return-path']
end
end
def add_hf( name, field )
key = name.downcase
field = new_hf(name, field)
if ALLOW_MULTIPLE.include? key
(@header[key] ||= []).push field
else
@header[key] = field
end
end
def new_hf( name, field )
HeaderField.new(name, field, @config)
end
###
### body
###
public
def body_port
parse_body
@body_port
end
def each( &block )
body_port().ropen {|f| f.each(&block) }
end
def quoted_body
body_port.ropen {|f| return f.read }
end
def quoted_body= str
body_port.wopen { |f| f.write str }
str
end
def body=( str )
# Sets the body of the email to a new (encoded) string.
#
# We also reparses the email if the body is ever reassigned, this is a performance hit, however when
# you assign the body, you usually want to be able to make sure that you can access the attachments etc.
#
# Usage:
#
# mail.body = "Hello, this is\nthe body text"
# # => "Hello, this is\nthe body"
# mail.body
# # => "Hello, this is\nthe body"
@body_parsed = false
parse_body(StringInput.new(str))
parse_body
@body_port.wopen {|f| f.write str }
str
end
alias preamble quoted_body
alias preamble= quoted_body=
def epilogue
parse_body
@epilogue.dup
end
def epilogue=( str )
parse_body
@epilogue = str
str
end
def parts
parse_body
@parts
end
def each_part( &block )
parts().each(&block)
end
# Returns true if the content type of this part of the email is
# a disposition attachment
def disposition_is_attachment?
(self['content-disposition'] && self['content-disposition'].disposition == "attachment")
end
# Returns true if this part's content main type is text, else returns false.
# By main type is meant "text/plain" is text. "text/html" is text
def content_type_is_text?
self.header['content-type'] && (self.header['content-type'].main_type != "text")
end
private
def parse_body( f = nil )
return if @body_parsed
if f
parse_body_0 f
else
@port.ropen {|f|
skip_header f
parse_body_0 f
}
end
@body_parsed = true
end
def skip_header( f )
while line = f.gets
return if /\A[\r\n]*\z/ === line
end
end
def parse_body_0( f )
if multipart?
read_multipart f
else
@body_port = @config.new_body_port(self)
@body_port.wopen {|w|
w.write f.read
}
end
end
def read_multipart( src )
bound = @header['content-type'].params['boundary']
is_sep = /\A--#{Regexp.quote bound}(?:--)?[ \t]*(?:\n|\r\n|\r)/
lastbound = "--#{bound}--"
ports = [ @config.new_preamble_port(self) ]
begin
f = ports.last.wopen
while line = src.gets
if is_sep === line
f.close
break if line.strip == lastbound
ports.push @config.new_part_port(self)
f = ports.last.wopen
else
f << line
end
end
@epilogue = (src.read || '')
ensure
f.close if f and not f.closed?
end
@body_port = ports.shift
@parts = ports.map {|p| self.class.new(p, @config) }
end
end # class Mail
end # module TMail

View File

@@ -1,495 +0,0 @@
=begin rdoc
= Mailbox and Mbox interaction class
=end
#--
# 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
class << self
alias newobj new
end
# Creates a new mailbox object that you can iterate through to collect the
# emails from with "each_port".
#
# You need to pass it a filename of a unix mailbox format file, the format of this
# file can be researched at this page at {wikipedia}[link:http://en.wikipedia.org/wiki/Mbox]
#
# ==== Parameters
#
# +filename+: The filename of the mailbox you want to open
#
# +tmpdir+: Can be set to override TMail using the system environment's temp dir. TMail will first
# use the temp dir specified by you (if any) or then the temp dir specified in the Environment's TEMP
# value then the value in the Environment's TMP value or failing all of the above, '/tmp'
#
# +readonly+: If set to false, each email you take from the mail box will be removed from the mailbox.
# default is *false* - ie, it *WILL* truncate your mailbox file to ZERO once it has read the emails out.
#
# ==== Options:
#
# None
#
# ==== Examples:
#
# # First show using readonly true:
#
# require 'ftools'
# File.size("../test/fixtures/mailbox")
# #=> 20426
#
# mailbox = TMail::UNIXMbox.new("../test/fixtures/mailbox", nil, true)
# #=> #<TMail::UNIXMbox:0x14a2aa8 @readonly=true.....>
#
# mailbox.each_port do |port|
# mail = TMail::Mail.new(port)
# puts mail.subject
# end
# #Testing mailbox 1
# #Testing mailbox 2
# #Testing mailbox 3
# #Testing mailbox 4
# require 'ftools'
# File.size?("../test/fixtures/mailbox")
# #=> 20426
#
# # Now show with readonly set to the default false
#
# mailbox = TMail::UNIXMbox.new("../test/fixtures/mailbox")
# #=> #<TMail::UNIXMbox:0x14a2aa8 @readonly=false.....>
#
# mailbox.each_port do |port|
# mail = TMail::Mail.new(port)
# puts mail.subject
# end
# #Testing mailbox 1
# #Testing mailbox 2
# #Testing mailbox 3
# #Testing mailbox 4
#
# File.size?("../test/fixtures/mailbox")
# #=> nil
def UNIXMbox.new( filename, tmpdir = nil, readonly = false )
tmpdir = ENV['TEMP'] || ENV['TMP'] || '/tmp'
newobj(filename, "#{tmpdir}/ruby_tmail_#{$$}_#{rand()}", readonly, false)
end
def UNIXMbox.lock( fname )
begin
f = File.open(fname, 'r+')
f.flock File::LOCK_EX
yield f
ensure
f.flock File::LOCK_UN
f.close if f and not f.closed?
end
end
def UNIXMbox.static_new( fname, dir, readonly = false )
newobj(fname, dir, readonly, true)
end
def initialize( fname, mhdir, readonly, static )
@filename = fname
@readonly = readonly
@closed = false
Dir.mkdir mhdir
@real = MhMailbox.new(mhdir)
@finalizer = UNIXMbox.mkfinal(@real, @filename, !@readonly, !static)
ObjectSpace.define_finalizer self, @finalizer
end
def UNIXMbox.mkfinal( mh, mboxfile, writeback_p, cleanup_p )
lambda {
if writeback_p
lock(mboxfile) {|f|
mh.each_port do |port|
f.puts create_from_line(port)
port.ropen {|r|
f.puts r.read
}
end
}
end
if cleanup_p
Dir.foreach(mh.dirname) do |fname|
next if /\A\.\.?\z/ === fname
File.unlink "#{mh.dirname}/#{fname}"
end
Dir.rmdir mh.dirname
end
}
end
# make _From line
def UNIXMbox.create_from_line( port )
sprintf 'From %s %s',
fromaddr(), TextUtils.time2str(File.mtime(port.filename))
end
def UNIXMbox.fromaddr(port)
h = HeaderField.new_from_port(port, 'Return-Path') ||
HeaderField.new_from_port(port, 'From') ||
HeaderField.new_from_port(port, 'EnvelopeSender') or return 'nobody'
a = h.addrs[0] or return 'nobody'
a.spec
end
def close
return if @closed
ObjectSpace.undefine_finalizer self
@finalizer.call
@finalizer = nil
@real = nil
@closed = true
@updated = nil
end
def each_port( &block )
close_check
update
@real.each_port(&block)
end
alias each each_port
def reverse_each_port( &block )
close_check
update
@real.reverse_each_port(&block)
end
alias reverse_each reverse_each_port
# old #each_mail returns Port
#def each_mail( &block )
# each_port do |port|
# yield Mail.new(port)
# end
#end
def each_new_port( mtime = nil )
close_check
update
@real.each_new_port(mtime) {|p| yield p }
end
def new_port
close_check
@real.new_port
end
private
def close_check
@closed and raise ArgumentError, 'accessing already closed mbox'
end
def update
return if FileTest.zero?(@filename)
return if @updated and File.mtime(@filename) < @updated
w = nil
port = nil
time = nil
UNIXMbox.lock(@filename) {|f|
begin
f.each do |line|
if /\AFrom / === line
w.close if w
File.utime time, time, port.filename if time
port = @real.new_port
w = port.wopen
time = fromline2time(line)
else
w.print line if w
end
end
ensure
if w and not w.closed?
w.close
File.utime time, time, port.filename if time
end
end
f.truncate(0) unless @readonly
@updated = Time.now
}
end
def fromline2time( line )
m = /\AFrom \S+ \w+ (\w+) (\d+) (\d+):(\d+):(\d+) (\d+)/.match(line) \
or return nil
Time.local(m[6].to_i, m[1], m[2].to_i, m[3].to_i, m[4].to_i, m[5].to_i)
end
end # UNIXMbox
MboxLoader = UNIXMbox
class Maildir
extend Mutex_m
PORT_CLASS = MaildirPort
@seq = 0
def Maildir.unique_number
synchronize {
@seq += 1
return @seq
}
end
def initialize( dir = nil )
@dirname = dir || ENV['MAILDIR']
raise ArgumentError, "not directory: #{@dirname}"\
unless FileTest.directory? @dirname
@new = "#{@dirname}/new"
@tmp = "#{@dirname}/tmp"
@cur = "#{@dirname}/cur"
end
def directory
@dirname
end
def inspect
"#<#{self.class} #{@dirname}>"
end
def close
end
def each_port
mail_files(@cur).each do |path|
yield PORT_CLASS.new(path)
end
end
alias each each_port
def reverse_each_port
mail_files(@cur).reverse_each do |path|
yield PORT_CLASS.new(path)
end
end
alias reverse_each reverse_each_port
def new_port
fname = nil
tmpfname = nil
newfname = nil
begin
fname = "#{Time.now.to_i}.#{$$}_#{Maildir.unique_number}.#{Socket.gethostname}"
tmpfname = "#{@tmp}/#{fname}"
newfname = "#{@new}/#{fname}"
end while FileTest.exist? tmpfname
if block_given?
File.open(tmpfname, 'w') {|f| yield f }
File.rename tmpfname, newfname
PORT_CLASS.new(newfname)
else
File.open(tmpfname, 'w') {|f| f.write "\n\n" }
PORT_CLASS.new(tmpfname)
end
end
def each_new_port
mail_files(@new).each do |path|
dest = @cur + '/' + File.basename(path)
File.rename path, dest
yield PORT_CLASS.new(dest)
end
check_tmp
end
TOO_OLD = 60 * 60 * 36 # 36 hour
def check_tmp
old = Time.now.to_i - TOO_OLD
each_filename(@tmp) do |full, fname|
if FileTest.file? full and
File.stat(full).mtime.to_i < old
File.unlink full
end
end
end
private
def mail_files( dir )
Dir.entries(dir)\
.select {|s| s[0] != ?. }\
.sort_by {|s| s.slice(/\A\d+/).to_i }\
.map {|s| "#{dir}/#{s}" }\
.select {|path| FileTest.file? path }
end
def each_filename( dir )
Dir.foreach(dir) do |fname|
path = "#{dir}/#{fname}"
if fname[0] != ?. and FileTest.file? path
yield path, fname
end
end
end
end # Maildir
MaildirLoader = Maildir
end # module TMail

View File

@@ -1,6 +0,0 @@
#:stopdoc:
require 'tmail/version'
require 'tmail/mail'
require 'tmail/mailbox'
require 'tmail/core_extensions'
#:startdoc:

View File

@@ -1,3 +0,0 @@
#:stopdoc:
require 'tmail/mailbox'
#:startdoc:

View File

@@ -1,248 +0,0 @@
#--
# 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.
#++
#:stopdoc:
require 'nkf'
#:startdoc:
module TMail
class Mail
def send_to( smtp )
do_send_to(smtp) do
ready_to_send
end
end
def send_text_to( smtp )
do_send_to(smtp) do
ready_to_send
mime_encode
end
end
def do_send_to( smtp )
from = from_address or raise ArgumentError, 'no from address'
(dests = destinations).empty? and raise ArgumentError, 'no receipient'
yield
send_to_0 smtp, from, dests
end
private :do_send_to
def send_to_0( smtp, from, to )
smtp.ready(from, to) do |f|
encoded "\r\n", 'j', f, ''
end
end
def ready_to_send
delete_no_send_fields
add_message_id
add_date
end
NOSEND_FIELDS = %w(
received
bcc
)
def delete_no_send_fields
NOSEND_FIELDS.each do |nm|
delete nm
end
delete_if {|n,v| v.empty? }
end
def add_message_id( fqdn = nil )
self.message_id = ::TMail::new_message_id(fqdn)
end
def add_date
self.date = Time.now
end
def mime_encode
if parts.empty?
mime_encode_singlepart
else
mime_encode_multipart true
end
end
def mime_encode_singlepart
self.mime_version = '1.0'
b = body
if NKF.guess(b) != NKF::BINARY
mime_encode_text b
else
mime_encode_binary b
end
end
def mime_encode_text( body )
self.body = NKF.nkf('-j -m0', body)
self.set_content_type 'text', 'plain', {'charset' => 'iso-2022-jp'}
self.encoding = '7bit'
end
def mime_encode_binary( body )
self.body = [body].pack('m')
self.set_content_type 'application', 'octet-stream'
self.encoding = 'Base64'
end
def mime_encode_multipart( top = true )
self.mime_version = '1.0' if top
self.set_content_type 'multipart', 'mixed'
e = encoding(nil)
if e and not /\A(?:7bit|8bit|binary)\z/i === e
raise ArgumentError,
'using C.T.Encoding with multipart mail is not permitted'
end
end
end
#:stopdoc:
class DeleteFields
NOSEND_FIELDS = %w(
received
bcc
)
def initialize( nosend = nil, delempty = true )
@no_send_fields = nosend || NOSEND_FIELDS.dup
@delete_empty_fields = delempty
end
attr :no_send_fields
attr :delete_empty_fields, true
def exec( mail )
@no_send_fields.each do |nm|
delete nm
end
delete_if {|n,v| v.empty? } if @delete_empty_fields
end
end
#:startdoc:
#:stopdoc:
class AddMessageId
def initialize( fqdn = nil )
@fqdn = fqdn
end
attr :fqdn, true
def exec( mail )
mail.message_id = ::TMail::new_msgid(@fqdn)
end
end
#:startdoc:
#:stopdoc:
class AddDate
def exec( mail )
mail.date = Time.now
end
end
#:startdoc:
#:stopdoc:
class MimeEncodeAuto
def initialize( s = nil, m = nil )
@singlepart_composer = s || MimeEncodeSingle.new
@multipart_composer = m || MimeEncodeMulti.new
end
attr :singlepart_composer
attr :multipart_composer
def exec( mail )
if mail._builtin_multipart?
then @multipart_composer
else @singlepart_composer end.exec mail
end
end
#:startdoc:
#:stopdoc:
class MimeEncodeSingle
def exec( mail )
mail.mime_version = '1.0'
b = mail.body
if NKF.guess(b) != NKF::BINARY
on_text b
else
on_binary b
end
end
def on_text( body )
mail.body = NKF.nkf('-j -m0', body)
mail.set_content_type 'text', 'plain', {'charset' => 'iso-2022-jp'}
mail.encoding = '7bit'
end
def on_binary( body )
mail.body = [body].pack('m')
mail.set_content_type 'application', 'octet-stream'
mail.encoding = 'Base64'
end
end
#:startdoc:
#:stopdoc:
class MimeEncodeMulti
def exec( mail, top = true )
mail.mime_version = '1.0' if top
mail.set_content_type 'multipart', 'mixed'
e = encoding(nil)
if e and not /\A(?:7bit|8bit|binary)\z/i === e
raise ArgumentError,
'using C.T.Encoding with multipart mail is not permitted'
end
mail.parts.each do |m|
exec m, false if m._builtin_multipart?
end
end
end
#:startdoc:
end # module TMail

View File

@@ -1,132 +0,0 @@
=begin rdoc
= Obsolete methods that are depriciated
If you really want to see them, go to lib/tmail/obsolete.rb and view to your
heart's content.
=end
#--
# Copyright (c) 1998-2003 Minero Aoki <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.
#++
#:stopdoc:
module TMail #:nodoc:
class Mail
alias include? key?
alias has_key? key?
def values
ret = []
each_field {|v| ret.push v }
ret
end
def value?( val )
HeaderField === val or return false
[ @header[val.name.downcase] ].flatten.include? val
end
alias has_value? value?
end
class Mail
def from_addr( default = nil )
addr, = from_addrs(nil)
addr || default
end
def from_address( default = nil )
if a = from_addr(nil)
a.spec
else
default
end
end
alias from_address= from_addrs=
def from_phrase( default = nil )
if a = from_addr(nil)
a.phrase
else
default
end
end
alias msgid message_id
alias msgid= message_id=
alias each_dest each_destination
end
class Address
alias route routes
alias addr spec
def spec=( str )
@local, @domain = str.split(/@/,2).map {|s| s.split(/\./) }
end
alias addr= spec=
alias address= spec=
end
class MhMailbox
alias new_mail new_port
alias each_mail each_port
alias each_newmail each_new_port
end
class UNIXMbox
alias new_mail new_port
alias each_mail each_port
alias each_newmail each_new_port
end
class Maildir
alias new_mail new_port
alias each_mail each_port
alias each_newmail each_new_port
end
extend TextUtils
class << self
alias msgid? message_id?
alias boundary new_boundary
alias msgid new_message_id
alias new_msgid new_message_id
end
def Mail.boundary
::TMail.new_boundary
end
def Mail.msgid
::TMail.new_message_id
end
end # module TMail
#:startdoc:

File diff suppressed because it is too large Load Diff

View File

@@ -1,379 +0,0 @@
=begin rdoc
= Port class
=end
#--
# 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

@@ -1,118 +0,0 @@
=begin rdoc
= Quoting methods
=end
module TMail
class Mail
def subject(to_charset = 'utf-8')
Unquoter.unquote_and_convert_to(quoted_subject, to_charset)
end
def unquoted_body(to_charset = 'utf-8')
from_charset = sub_header("content-type", "charset")
case (content_transfer_encoding || "7bit").downcase
when "quoted-printable"
# the default charset is set to iso-8859-1 instead of 'us-ascii'.
# This is needed as many mailer do not set the charset but send in ISO. This is only used if no charset is set.
if !from_charset.blank? && from_charset.downcase == 'us-ascii'
from_charset = 'iso-8859-1'
end
Unquoter.unquote_quoted_printable_and_convert_to(quoted_body,
to_charset, from_charset, true)
when "base64"
Unquoter.unquote_base64_and_convert_to(quoted_body, to_charset,
from_charset)
when "7bit", "8bit"
Unquoter.convert_to(quoted_body, to_charset, from_charset)
when "binary"
quoted_body
else
quoted_body
end
end
def body(to_charset = 'utf-8', &block)
attachment_presenter = block || Proc.new { |file_name| "Attachment: #{file_name}\n" }
if multipart?
parts.collect { |part|
header = part["content-type"]
if part.multipart?
part.body(to_charset, &attachment_presenter)
elsif header.nil?
""
elsif !attachment?(part)
part.unquoted_body(to_charset)
else
attachment_presenter.call(header["name"] || "(unnamed)")
end
}.join
else
unquoted_body(to_charset)
end
end
end
class Unquoter
class << self
def unquote_and_convert_to(text, to_charset, from_charset = "iso-8859-1", preserve_underscores=false)
return "" if text.nil?
text.gsub(/(.*?)(?:(?:=\?(.*?)\?(.)\?(.*?)\?=)|$)/) do
before = $1
from_charset = $2
quoting_method = $3
text = $4
before = convert_to(before, to_charset, from_charset) if before.length > 0
before + case quoting_method
when "q", "Q" then
unquote_quoted_printable_and_convert_to(text, to_charset, from_charset, preserve_underscores)
when "b", "B" then
unquote_base64_and_convert_to(text, to_charset, from_charset)
when nil then
# will be nil at the end of the string, due to the nature of
# the regex used.
""
else
raise "unknown quoting method #{quoting_method.inspect}"
end
end
end
def unquote_quoted_printable_and_convert_to(text, to, from, preserve_underscores=false)
text = text.gsub(/_/, " ") unless preserve_underscores
text = text.gsub(/\r\n|\r/, "\n") # normalize newlines
convert_to(text.unpack("M*").first, to, from)
end
def unquote_base64_and_convert_to(text, to, from)
convert_to(Base64.decode(text), to, from)
end
begin
require 'iconv'
def convert_to(text, to, from)
return text unless to && from
text ? Iconv.iconv(to, from, text).first : ""
rescue Iconv::IllegalSequence, Iconv::InvalidEncoding, Errno::EINVAL
# the 'from' parameter specifies a charset other than what the text
# actually is...not much we can do in this case but just return the
# unconverted text.
#
# Ditto if either parameter represents an unknown charset, like
# X-UNKNOWN.
text
end
rescue LoadError
# Not providing quoting support
def convert_to(text, to, from)
warn "Action Mailer: iconv not loaded; ignoring conversion from #{from} to #{to} (#{__FILE__}:#{__LINE__})"
text
end
end
end
end
end

View File

@@ -1,58 +0,0 @@
#:stopdoc:
require 'rbconfig'
# Attempts to require anative extension.
# Falls back to pure-ruby version, if it fails.
#
# This uses Config::CONFIG['arch'] from rbconfig.
def require_arch(fname)
arch = Config::CONFIG['arch']
begin
path = File.join("tmail", arch, fname)
require path
rescue LoadError => e
# try pre-built Windows binaries
if arch =~ /mswin/
require File.join("tmail", 'mswin32', fname)
else
raise e
end
end
end
# def require_arch(fname)
# dext = Config::CONFIG['DLEXT']
# begin
# if File.extname(fname) == dext
# path = fname
# else
# path = File.join("tmail","#{fname}.#{dext}")
# end
# require path
# rescue LoadError => e
# begin
# arch = Config::CONFIG['arch']
# path = File.join("tmail", arch, "#{fname}.#{dext}")
# require path
# rescue LoadError
# case path
# when /i686/
# path.sub!('i686', 'i586')
# when /i586/
# path.sub!('i586', 'i486')
# when /i486/
# path.sub!('i486', 'i386')
# else
# begin
# require fname + '.rb'
# rescue LoadError
# raise e
# end
# end
# retry
# end
# end
# end
#:startdoc:

View File

@@ -1,49 +0,0 @@
=begin rdoc
= Scanner for TMail
=end
#--
# 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.
#++
#:stopdoc:
#require 'tmail/require_arch'
require 'tmail/utils'
require 'tmail/config'
module TMail
# NOTE: It woiuld be nice if these two libs could boith be called "tmailscanner", and
# the native extension would have precedence. However RubyGems boffs that up b/c
# it does not gaurantee load_path order.
begin
raise LoadError, 'Turned off native extentions by user choice' if ENV['NORUBYEXT']
require('tmail/tmailscanner') # c extension
Scanner = TMailScanner
rescue LoadError
require 'tmail/scanner_r'
Scanner = TMailScanner
end
end
#:stopdoc:

View File

@@ -1,261 +0,0 @@
# 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.
#++
#:stopdoc:
require 'tmail/config'
module TMail
class TMailScanner
Version = '1.2.3'
Version.freeze
MIME_HEADERS = {
:CTYPE => true,
:CENCODING => true,
:CDISPOSITION => true
}
alnum = 'a-zA-Z0-9'
atomsyms = %q[ _#!$%&`'*+-{|}~^/=? ].strip
tokensyms = %q[ _#!$%&`'*+-{|}~^@. ].strip
atomchars = alnum + Regexp.quote(atomsyms)
tokenchars = alnum + Regexp.quote(tokensyms)
iso2022str = '\e(?!\(B)..(?:[^\e]+|\e(?!\(B)..)*\e\(B'
eucstr = "(?:[\xa1-\xfe][\xa1-\xfe])+"
sjisstr = "(?:[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc])+"
utf8str = "(?:[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf][\x80-\xbf])+"
quoted_with_iso2022 = /\A(?:[^\\\e"]+|#{iso2022str})+/n
domlit_with_iso2022 = /\A(?:[^\\\e\]]+|#{iso2022str})+/n
comment_with_iso2022 = /\A(?:[^\\\e()]+|#{iso2022str})+/n
quoted_without_iso2022 = /\A[^\\"]+/n
domlit_without_iso2022 = /\A[^\\\]]+/n
comment_without_iso2022 = /\A[^\\()]+/n
PATTERN_TABLE = {}
PATTERN_TABLE['EUC'] =
[
/\A(?:[#{atomchars}]+|#{iso2022str}|#{eucstr})+/n,
/\A(?:[#{tokenchars}]+|#{iso2022str}|#{eucstr})+/n,
quoted_with_iso2022,
domlit_with_iso2022,
comment_with_iso2022
]
PATTERN_TABLE['SJIS'] =
[
/\A(?:[#{atomchars}]+|#{iso2022str}|#{sjisstr})+/n,
/\A(?:[#{tokenchars}]+|#{iso2022str}|#{sjisstr})+/n,
quoted_with_iso2022,
domlit_with_iso2022,
comment_with_iso2022
]
PATTERN_TABLE['UTF8'] =
[
/\A(?:[#{atomchars}]+|#{utf8str})+/n,
/\A(?:[#{tokenchars}]+|#{utf8str})+/n,
quoted_without_iso2022,
domlit_without_iso2022,
comment_without_iso2022
]
PATTERN_TABLE['NONE'] =
[
/\A[#{atomchars}]+/n,
/\A[#{tokenchars}]+/n,
quoted_without_iso2022,
domlit_without_iso2022,
comment_without_iso2022
]
def initialize( str, scantype, comments )
init_scanner str
@comments = comments || []
@debug = false
# fix scanner mode
@received = (scantype == :RECEIVED)
@is_mime_header = MIME_HEADERS[scantype]
atom, token, @quoted_re, @domlit_re, @comment_re = PATTERN_TABLE[TMail.KCODE]
@word_re = (MIME_HEADERS[scantype] ? token : atom)
end
attr_accessor :debug
def scan( &block )
if @debug
scan_main do |arr|
s, v = arr
printf "%7d %-10s %s\n",
rest_size(),
s.respond_to?(:id2name) ? s.id2name : s.inspect,
v.inspect
yield arr
end
else
scan_main(&block)
end
end
private
RECV_TOKEN = {
'from' => :FROM,
'by' => :BY,
'via' => :VIA,
'with' => :WITH,
'id' => :ID,
'for' => :FOR
}
def scan_main
until eof?
if skip(/\A[\n\r\t ]+/n) # LWSP
break if eof?
end
if s = readstr(@word_re)
if @is_mime_header
yield [:TOKEN, s]
else
# atom
if /\A\d+\z/ === s
yield [:DIGIT, s]
elsif @received
yield [RECV_TOKEN[s.downcase] || :ATOM, s]
else
yield [:ATOM, s]
end
end
elsif skip(/\A"/)
yield [:QUOTED, scan_quoted_word()]
elsif skip(/\A\[/)
yield [:DOMLIT, scan_domain_literal()]
elsif skip(/\A\(/)
@comments.push scan_comment()
else
c = readchar()
yield [c, c]
end
end
yield [false, '$']
end
def scan_quoted_word
scan_qstr(@quoted_re, /\A"/, 'quoted-word')
end
def scan_domain_literal
'[' + scan_qstr(@domlit_re, /\A\]/, 'domain-literal') + ']'
end
def scan_qstr( pattern, terminal, type )
result = ''
until eof?
if s = readstr(pattern) then result << s
elsif skip(terminal) then return result
elsif skip(/\A\\/) then result << readchar()
else
raise "TMail FATAL: not match in #{type}"
end
end
scan_error! "found unterminated #{type}"
end
def scan_comment
result = ''
nest = 1
content = @comment_re
until eof?
if s = readstr(content) then result << s
elsif skip(/\A\)/) then nest -= 1
return result if nest == 0
result << ')'
elsif skip(/\A\(/) then nest += 1
result << '('
elsif skip(/\A\\/) then result << readchar()
else
raise 'TMail FATAL: not match in comment'
end
end
scan_error! 'found unterminated comment'
end
# string scanner
def init_scanner( str )
@src = str
end
def eof?
@src.empty?
end
def rest_size
@src.size
end
def readstr( re )
if m = re.match(@src)
@src = m.post_match
m[0]
else
nil
end
end
def readchar
readstr(/\A./)
end
def skip( re )
if m = re.match(@src)
@src = m.post_match
true
else
false
end
end
def scan_error!( msg )
raise SyntaxError, msg
end
end
end # module TMail
#:startdoc:

View File

@@ -1,280 +0,0 @@
# encoding: utf-8
=begin rdoc
= String handling class
=end
#--
# 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'},#{object_id}>"
end
def print( *args )
stream_check!
raise ArgumentError, 'wrong # of argument (0 for >1)' if args.empty?
args.each do |s|
raise ArgumentError, 'nil not allowed' if s.nil?
@dest << s.to_s
end
nil
end
def puts( *args )
stream_check!
args.each do |str|
@dest << (s = str.to_s)
@dest << "\n" unless s[-1] == ?\n
end
@dest << "\n" if args.empty?
nil
end
def putc( ch )
stream_check!
@dest << ch.chr
nil
end
def printf( *args )
stream_check!
@dest << sprintf(*args)
nil
end
def write( str )
stream_check!
s = str.to_s
@dest << s
s.size
end
alias syswrite write
def <<( str )
stream_check!
@dest << str.to_s
self
end
private
def stream_check!
@closed and raise IOError, 'closed stream'
end
end

View File

@@ -1,337 +0,0 @@
#--
# 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.
#++
# = TMail - The EMail Swiss Army Knife for Ruby
#
# The TMail library provides you with a very complete way to handle and manipulate EMails
# from within your Ruby programs.
#
# Used as the backbone for email handling by the Ruby on Rails and Nitro web frameworks as
# well as a bunch of other Ruby apps including the Ruby-Talk mailing list to newsgroup email
# gateway, it is a proven and reliable email handler that won't let you down.
#
# Originally created by Minero Aoki, TMail has been recently picked up by Mikel Lindsaar and
# is being actively maintained. Numerous backlogged bug fixes have been applied as well as
# Ruby 1.9 compatibility and a swath of documentation to boot.
#
# TMail allows you to treat an email totally as an object and allow you to get on with your
# own programming without having to worry about crafting the perfect email address validation
# parser, or assembling an email from all it's component parts.
#
# TMail handles the most complex part of the email - the header. It generates and parses
# headers and provides you with instant access to their innards through simple and logically
# named accessor and setter methods.
#
# TMail also provides a wrapper to Net/SMTP as well as Unix Mailbox handling methods to
# directly read emails from your unix mailbox, parse them and use them.
#
# Following is the comprehensive list of methods to access TMail::Mail objects. You can also
# check out TMail::Mail, TMail::Address and TMail::Headers for other lists.
module TMail
# Provides an exception to throw on errors in Syntax within TMail's parsers
class SyntaxError < StandardError; end
# Provides a new email boundary to separate parts of the email. This is a random
# string based off the current time, so should be fairly unique.
#
# For Example:
#
# TMail.new_boundary
# #=> "mimepart_47bf656968207_25a8fbb80114"
# TMail.new_boundary
# #=> "mimepart_47bf66051de4_25a8fbb80240"
def TMail.new_boundary
'mimepart_' + random_tag
end
# Provides a new email message ID. You can use this to generate unique email message
# id's for your email so you can track them.
#
# Optionally takes a fully qualified domain name (default to the current hostname
# returned by Socket.gethostname) that will be appended to the message ID.
#
# For Example:
#
# email.message_id = TMail.new_message_id
# #=> "<47bf66845380e_25a8fbb80332@baci.local.tmail>"
# email.to_s
# #=> "Message-Id: <47bf668b633f1_25a8fbb80475@baci.local.tmail>\n\n"
# email.message_id = TMail.new_message_id("lindsaar.net")
# #=> "<47bf668b633f1_25a8fbb80475@lindsaar.net.tmail>"
# email.to_s
# #=> "Message-Id: <47bf668b633f1_25a8fbb80475@lindsaar.net.tmail>\n\n"
def TMail.new_message_id( fqdn = nil )
fqdn ||= ::Socket.gethostname
"<#{random_tag()}@#{fqdn}.tmail>"
end
#:stopdoc:
def TMail.random_tag #:nodoc:
@uniq += 1
t = Time.now
sprintf('%x%x_%x%x%d%x',
t.to_i, t.tv_usec,
$$, Thread.current.object_id, @uniq, rand(255))
end
private_class_method :random_tag
@uniq = 0
#:startdoc:
# Text Utils provides a namespace to define TOKENs, ATOMs, PHRASEs and CONTROL characters that
# are OK per RFC 2822.
#
# It also provides methods you can call to determine if a string is safe
module TextUtils
aspecial = %Q|()<>[]:;.\\,"|
tspecial = %Q|()<>[];:\\,"/?=|
lwsp = %Q| \t\r\n|
control = %Q|\x00-\x1f\x7f-\xff|
CONTROL_CHAR = /[#{control}]/n
ATOM_UNSAFE = /[#{Regexp.quote aspecial}#{control}#{lwsp}]/n
PHRASE_UNSAFE = /[#{Regexp.quote aspecial}#{control}]/n
TOKEN_UNSAFE = /[#{Regexp.quote tspecial}#{control}#{lwsp}]/n
# Returns true if the string supplied is free from characters not allowed as an ATOM
def atom_safe?( str )
not ATOM_UNSAFE === str
end
# If the string supplied has ATOM unsafe characters in it, will return the string quoted
# in double quotes, otherwise returns the string unmodified
def quote_atom( str )
(ATOM_UNSAFE === str) ? dquote(str) : str
end
# If the string supplied has PHRASE unsafe characters in it, will return the string quoted
# in double quotes, otherwise returns the string unmodified
def quote_phrase( str )
(PHRASE_UNSAFE === str) ? dquote(str) : str
end
# Returns true if the string supplied is free from characters not allowed as a TOKEN
def token_safe?( str )
not TOKEN_UNSAFE === str
end
# If the string supplied has TOKEN unsafe characters in it, will return the string quoted
# in double quotes, otherwise returns the string unmodified
def quote_token( str )
(TOKEN_UNSAFE === str) ? dquote(str) : str
end
# Wraps supplied string in double quotes unless it is already wrapped
# Returns double quoted string
def dquote( str ) #:nodoc:
unless str =~ /^".*?"$/
'"' + str.gsub(/["\\]/n) {|s| '\\' + s } + '"'
else
str
end
end
private :dquote
# Unwraps supplied string from inside double quotes
# Returns unquoted string
def unquote( str )
str =~ /^"(.*?)"$/ ? $1 : str
end
# Provides a method to join a domain name by it's parts and also makes it
# ATOM safe by quoting it as needed
def join_domain( arr )
arr.map {|i|
if /\A\[.*\]\z/ === i
i
else
quote_atom(i)
end
}.join('.')
end
#:stopdoc:
ZONESTR_TABLE = {
'jst' => 9 * 60,
'eet' => 2 * 60,
'bst' => 1 * 60,
'met' => 1 * 60,
'gmt' => 0,
'utc' => 0,
'ut' => 0,
'nst' => -(3 * 60 + 30),
'ast' => -4 * 60,
'edt' => -4 * 60,
'est' => -5 * 60,
'cdt' => -5 * 60,
'cst' => -6 * 60,
'mdt' => -6 * 60,
'mst' => -7 * 60,
'pdt' => -7 * 60,
'pst' => -8 * 60,
'a' => -1 * 60,
'b' => -2 * 60,
'c' => -3 * 60,
'd' => -4 * 60,
'e' => -5 * 60,
'f' => -6 * 60,
'g' => -7 * 60,
'h' => -8 * 60,
'i' => -9 * 60,
# j not use
'k' => -10 * 60,
'l' => -11 * 60,
'm' => -12 * 60,
'n' => 1 * 60,
'o' => 2 * 60,
'p' => 3 * 60,
'q' => 4 * 60,
'r' => 5 * 60,
's' => 6 * 60,
't' => 7 * 60,
'u' => 8 * 60,
'v' => 9 * 60,
'w' => 10 * 60,
'x' => 11 * 60,
'y' => 12 * 60,
'z' => 0 * 60
}
#:startdoc:
# Takes a time zone string from an EMail and converts it to Unix Time (seconds)
def timezone_string_to_unixtime( str )
if m = /([\+\-])(\d\d?)(\d\d)/.match(str)
sec = (m[2].to_i * 60 + m[3].to_i) * 60
m[1] == '-' ? -sec : sec
else
min = ZONESTR_TABLE[str.downcase] or
raise SyntaxError, "wrong timezone format '#{str}'"
min * 60
end
end
#:stopdoc:
WDAY = %w( Sun Mon Tue Wed Thu Fri Sat TMailBUG )
MONTH = %w( TMailBUG Jan Feb Mar Apr May Jun
Jul Aug Sep Oct Nov Dec TMailBUG )
def time2str( tm )
# [ruby-list:7928]
gmt = Time.at(tm.to_i)
gmt.gmtime
offset = tm.to_i - Time.local(*gmt.to_a[0,6].reverse).to_i
# DO NOT USE strftime: setlocale() breaks it
sprintf '%s, %s %s %d %02d:%02d:%02d %+.2d%.2d',
WDAY[tm.wday], tm.mday, MONTH[tm.month],
tm.year, tm.hour, tm.min, tm.sec,
*(offset / 60).divmod(60)
end
MESSAGE_ID = /<[^\@>]+\@[^>\@]+>/
def message_id?( str )
MESSAGE_ID === str
end
MIME_ENCODED = /=\?[^\s?=]+\?[QB]\?[^\s?=]+\?=/i
def mime_encoded?( str )
MIME_ENCODED === str
end
def decode_params( hash )
new = Hash.new
encoded = nil
hash.each do |key, value|
if m = /\*(?:(\d+)\*)?\z/.match(key)
((encoded ||= {})[m.pre_match] ||= [])[(m[1] || 0).to_i] = value
else
new[key] = to_kcode(value)
end
end
if encoded
encoded.each do |key, strings|
new[key] = decode_RFC2231(strings.join(''))
end
end
new
end
NKF_FLAGS = {
'EUC' => '-e -m',
'SJIS' => '-s -m'
}
def to_kcode( str )
flag = NKF_FLAGS[TMail.KCODE] or return str
NKF.nkf(flag, str)
end
RFC2231_ENCODED = /\A(?:iso-2022-jp|euc-jp|shift_jis|us-ascii)?'[a-z]*'/in
def decode_RFC2231( str )
m = RFC2231_ENCODED.match(str) or return str
begin
to_kcode(m.post_match.gsub(/%[\da-f]{2}/in) {|s| s[1,2].hex.chr })
rescue
m.post_match.gsub(/%[\da-f]{2}/in, "")
end
end
def quote_boundary
# Make sure the Content-Type boundary= parameter is quoted if it contains illegal characters
# (to ensure any special characters in the boundary text are escaped from the parser
# (such as = in MS Outlook's boundary text))
if @body =~ /^(.*)boundary=(.*)$/m
preamble = $1
remainder = $2
if remainder =~ /;/
remainder =~ /^(.*?)(;.*)$/m
boundary_text = $1
post = $2.chomp
else
boundary_text = remainder.chomp
end
if boundary_text =~ /[\/\?\=]/
boundary_text = "\"#{boundary_text}\"" unless boundary_text =~ /^".*?"$/
@body = "#{preamble}boundary=#{boundary_text}#{post}"
end
end
end
#:startdoc:
end
end

View File

@@ -1,39 +0,0 @@
#
# version.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.
#++
#:stopdoc:
module TMail
module VERSION
MAJOR = 1
MINOR = 2
TINY = 3
STRING = [MAJOR, MINOR, TINY].join('.')
end
end

View File

@@ -1,17 +0,0 @@
# Prefer gems to the bundled libs.
require 'rubygems'
begin
gem 'tmail', '~> 1.2.3'
rescue Gem::LoadError
$:.unshift "#{File.dirname(__FILE__)}/tmail-1.2.3"
end
module TMail
end
require 'tmail'
silence_warnings do
TMail::Encoder.const_set("MAX_LINE_LEN", 200)
end

View File

@@ -2,7 +2,7 @@ module ActionMailer
module VERSION #:nodoc:
MAJOR = 2
MINOR = 3
TINY = 2
TINY = 14
STRING = [MAJOR, MINOR, TINY].join('.')
end

View File

@@ -1 +1,2 @@
require 'action_mailer'
ActiveSupport::Deprecation.warn 'require "actionmailer" is deprecated and will be removed in Rails 3. Use require "action_mailer" instead.'

View File

@@ -1,12 +1,9 @@
require 'rubygems'
require 'test/unit'
gem 'mocha', '>= 0.9.5'
require 'mocha'
$:.unshift "#{File.dirname(__FILE__)}/../lib"
$:.unshift "#{File.dirname(__FILE__)}/../../activesupport/lib"
$:.unshift "#{File.dirname(__FILE__)}/../../actionpack/lib"
$:.unshift File.expand_path('../../lib', __FILE__)
$:.unshift File.expand_path('../../../activesupport/lib', __FILE__)
$:.unshift File.expand_path('../../../actionpack/lib', __FILE__)
require 'action_mailer'
require 'action_mailer/test_case'
@@ -20,7 +17,7 @@ ActionView::Template.register_template_handler :bak, lambda { |template| "Lame b
$:.unshift "#{File.dirname(__FILE__)}/fixtures/helpers"
ActionView::Base.cache_template_loading = true
FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
FIXTURE_LOAD_PATH = File.expand_path(File.join(File.dirname(__FILE__), 'fixtures'))
ActionMailer::Base.template_root = FIXTURE_LOAD_PATH
class MockSMTP

View File

@@ -1,5 +1,5 @@
module ExampleHelper
def example_format(text)
"<em><strong><small>#{text}</small></strong></em>"
"<em><strong><small>#{h(text)}</small></strong></em>".html_safe
end
end

View File

@@ -18,7 +18,6 @@ class TestMailer < ActionMailer::Base
@recipients = recipient
@subject = "[Signed up] Welcome #{recipient}"
@from = "system@loudthinking.com"
@sent_on = Time.local(2004, 12, 12)
@body["recipient"] = recipient
end
@@ -30,6 +29,18 @@ class TestMailer < ActionMailer::Base
self.body = "Goodbye, Mr. #{recipient}"
end
def from_with_name
from "System <system@loudthinking.com>"
recipients "root@loudthinking.com"
body "Nothing to see here."
end
def from_without_name
from "system@loudthinking.com"
recipients "root@loudthinking.com"
body "Nothing to see here."
end
def cc_bcc(recipient)
recipients recipient
subject "testing bcc/cc"
@@ -356,12 +367,14 @@ class ActionMailerTest < Test::Unit::TestCase
end
def test_signed_up
Time.stubs(:now => Time.now)
expected = new_mail
expected.to = @recipient
expected.subject = "[Signed up] Welcome #{@recipient}"
expected.body = "Hello there, \n\nMr. #{@recipient}"
expected.from = "system@loudthinking.com"
expected.date = Time.local(2004, 12, 12)
expected.date = Time.now
created = nil
assert_nothing_raised { created = TestMailer.create_signed_up(@recipient) }
@@ -453,6 +466,28 @@ class ActionMailerTest < Test::Unit::TestCase
assert_equal expected.encoded, ActionMailer::Base.deliveries.first.encoded
end
def test_from_without_name_for_smtp
ActionMailer::Base.delivery_method = :smtp
TestMailer.deliver_from_without_name
mail = MockSMTP.deliveries.first
assert_not_nil mail
mail, from, to = mail
assert_equal 'system@loudthinking.com', from.to_s
end
def test_from_with_name_for_smtp
ActionMailer::Base.delivery_method = :smtp
TestMailer.deliver_from_with_name
mail = MockSMTP.deliveries.first
assert_not_nil mail
mail, from, to = mail
assert_equal 'system@loudthinking.com', from.to_s
end
def test_reply_to
expected = new_mail
@@ -569,7 +604,9 @@ class ActionMailerTest < Test::Unit::TestCase
mail = TestMailer.create_signed_up(@recipient)
logger = mock()
logger.expects(:info).with("Sent mail to #{@recipient}")
logger.expects(:debug).with("\n#{mail.encoded}")
logger.expects(:debug).with() do |logged_text|
logged_text =~ /\[Signed up\] Welcome/
end
TestMailer.logger = logger
TestMailer.deliver_signed_up(@recipient)
end
@@ -697,8 +734,8 @@ EOF
expected.date = Time.local 2004, 12, 12
created = TestMailer.create_utf8_body @recipient
assert_match(/\nFrom: =\?utf-8\?Q\?Foo_.*?\?= <extended@example.net>\r/, created.encoded)
assert_match(/\nTo: =\?utf-8\?Q\?Foo_.*?\?= <extended@example.net>, Example Recipient <me/, created.encoded)
assert_match(/From:\ =\?utf\-8\?Q\?Foo_=C3=A1=C3=AB=C3=B4_=C3=AE=C3=BC\?=\ <extended@example\.net>/, created.encoded)
assert_match(/To:\ =\?utf\-8\?Q\?Foo_=C3=A1=C3=AB=C3=B4_=C3=AE=C3=BC\?=\ <extended@example\.net>/, created.encoded)
end
def test_receive_decodes_base64_encoded_mail
@@ -824,6 +861,26 @@ EOF
assert_equal "text/yaml", mail.parts[2].content_type
end
def test_implicitly_path_when_running_from_none_rails_root
exected_path = File.expand_path(File.join(File.dirname(__FILE__), "fixtures", "test_mailer"))
with_a_rails_root do
Dir.chdir "/" do
template_path = TestMailer.allocate.send(:template_path)
assert_equal exected_path, File.expand_path(template_path)
end
end
end
def test_implicitly_multipart_messages_run_from_another_location_with_a_rails_root
with_a_rails_root do
Dir.chdir "/" do
mail = TestMailer.create_implicitly_multipart_example(@recipient)
assert_equal 3, mail.parts.length
end
end
end
def test_implicitly_multipart_messages_with_charset
mail = TestMailer.create_implicitly_multipart_example(@recipient, 'iso-8859-1')
@@ -972,6 +1029,16 @@ EOF
ensure
ActionMailer::Base.smtp_settings[:enable_starttls_auto] = true
end
private
def with_a_rails_root
old_root = ::RAILS_ROOT if defined? ::RAILS_ROOT
Object.const_set(:RAILS_ROOT, File.join(File.dirname(__FILE__)))
yield
ensure
Object.send(:remove_const, :RAILS_ROOT) if defined? ::RAILS_ROOT
Object.const_set(:RAILS_ROOT, old_root) if old_root
end
end
class InheritableTemplateRootTest < Test::Unit::TestCase

View File

@@ -23,9 +23,13 @@ class QuotingTest < Test::Unit::TestCase
end
def test_unqoute_multiple
a ="=?utf-8?q?Re=3A_=5B12=5D_=23137=3A_Inkonsistente_verwendung_von_=22Hin?==?utf-8?b?enVmw7xnZW4i?="
b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8')
assert_equal "Re: [12] #137: Inkonsistente verwendung von \"Hinzuf\303\274gen\"", b
quoted ="=?utf-8?q?Re=3A_=5B12=5D_=23137=3A_Inkonsistente_verwendung_von_=22Hin?==?utf-8?b?enVmw7xnZW4i?="
actual = TMail::Unquoter.unquote_and_convert_to(quoted, 'utf-8')
expected = "Re: [12] #137: Inkonsistente verwendung von \"Hinzuf\303\274gen\""
expected.force_encoding 'ASCII-8BIT' if expected.respond_to?(:force_encoding)
assert_equal expected, actual
end
def test_unqoute_in_the_middle
@@ -71,7 +75,9 @@ class QuotingTest < Test::Unit::TestCase
def test_email_with_partially_quoted_subject
mail = TMail::Mail.parse(IO.read("#{File.dirname(__FILE__)}/fixtures/raw_email_with_partially_quoted_subject"))
assert_equal "Re: Test: \"\346\274\242\345\255\227\" mid \"\346\274\242\345\255\227\" tail", mail.subject
expected = "Re: Test: \"\346\274\242\345\255\227\" mid \"\346\274\242\345\255\227\" tail"
expected.force_encoding('ASCII-8BIT') if expected.respond_to?(:force_encoding)
assert_equal expected, mail.subject
end
private

View File

@@ -1,7 +1,101 @@
*2.3.11 (February 9, 2011)*
* Two security fixes. CVE-2011-0446, CVE-2011-0447
*2.3.10 (October 15, 2010)*
*2.3.9 (September 4, 2010)*
* Version bump.
*2.3.8 (May 24, 2010)*
* HTML safety: fix compatibility *without* the optional rails_xss plugin.
*2.3.7 (May 24, 2010)*
* HTML safety: fix compatibility with the optional rails_xss plugin. [Nathan Weizenbaum, Santiago Pastorino]
*2.3.6 (May 23, 2010)*
* JSON: set Base.include_root_in_json = true to include a root value in the JSON: {"post": {"title": ...}}. Mirrors the Active Record option. #2584 [Matthew Moore, Joe Martinez, Elad Meidar, Santiago Pastorino]
* Ruby 1.9: ERB template encoding using a magic comment at the top of the file. [Jeremy Kemper]
<%# encoding: utf-8 %>
* Fixed that default locale templates should be used if the current locale template is missing [DHH]
* Fixed that PrototypeHelper#update_page should return html_safe [DHH]
* Fixed that much of DateHelper wouldn't return html_safe? strings [DHH]
* Fixed that fragment caching should return a cache hit as html_safe (or it would all just get escaped) [DHH]
* Introduce String#html_safe for rails_xss plugin and forward-compatibility with Rails 3. [Michael Koziarski, Santiago Pastorino, José Ignacio Costa]
* Added :alert, :notice, and :flash as options to ActionController::Base#redirect_to that'll automatically set the proper flash before the redirection [DHH]. Examples:
flash[:notice] = 'Post was created'
redirect_to(@post)
...becomes:
redirect_to(@post, :notice => 'Post was created')
* Added ActionController::Base#notice/= and ActionController::Base#alert/= as a convenience accessors in both the controller and the view for flash[:notice]/= and flash[:alert]/= [DHH]
* Added cookies.permanent, cookies.signed, and cookies.permanent.signed accessor for common cookie actions [DHH]. Examples:
cookies.permanent[:prefers_open_id] = true
# => Set-Cookie: prefers_open_id=true; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
cookies.signed[:discount] = 45
# => Set-Cookie: discount=BAhpMg==--2c1c6906c90a3bc4fd54a51ffb41dffa4bf6b5f7; path=/
cookies.signed[:discount]
# => 45 (if the cookie was changed, you'll get a InvalidSignature exception)
cookies.permanent.signed[:remember_me] = current_user.id
# => Set-Cookie: discount=BAhU--848956038e692d7046deab32b7131856ab20e14e; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
...to use the signed cookies, you need to set a secret to ActionController::Base.cookie_verifier_secret (automatically done in config/initializers/cookie_verification_secret.rb for new Rails applications).
*2.3.5 (November 25, 2009)*
* Minor Bug Fixes and deprecation warnings
* Ruby 1.9 Support
* Fix filtering parameters when there are Fixnum or other un-dupable values.
* Improvements to ActionView::TestCase
* Compatiblity with the rails_xss plugin
*2.3.4 (September 4, 2009)*
* Sanitize multibyte strings before escaping them with escape_once. CVE-2009-3009
* Introduce grouped_collection_select helper. #1249 [Dan Codeape, Erik Ostrom]
* Ruby 1.9: fix Content-Length for multibyte send_data streaming. #2661 [Sava Chankov]
*2.3.3 (July 12, 2009)*
* Fixed that TestResponse.cookies was returning cookies unescaped #1867 [Doug McInnes]
*2.3.2 [Final] (March 15, 2009)*
* Fixed that redirection would just log the options, not the final url (which lead to "Redirected to #<Post:0x23150b8>") [DHH]
* Don't check authenticity tokens for any AJAX requests [Ross Kaffenberger/Bryan Helmkamp]
* Added ability to pass in :public => true to fresh_when, stale?, and expires_in to make the request proxy cachable #2095 [Gregg Pollack]
* Fixed that passing a custom form builder would be forwarded to nested fields_for calls #2023 [Eloy Duran/Nate Wiger]
@@ -1841,7 +1935,7 @@ superclass' view_paths. [Rick Olson]
* Update documentation for erb trim syntax. #5651 [matt@mattmargolis.net]
* Pass :id => nil or :class => nil to error_messages_for to supress that html attribute. #3586 [olivier_ansaldi@yahoo.com, sebastien@goetzilla.info]
* Pass :id => nil or :class => nil to error_messages_for to supress that html attribute. #3586 [olivier_ansaldi@yahoo.com]
* Reset @html_document between requests so assert_tag works. #4810 [Jarkko Laine, easleydp@gmail.com]
@@ -2438,7 +2532,7 @@ superclass' view_paths. [Rick Olson]
* Provide support for decimal columns to form helpers. Closes #5672. [Dave Thomas]
* Pass :id => nil or :class => nil to error_messages_for to supress that html attribute. #3586 [olivier_ansaldi@yahoo.com, sebastien@goetzilla.info]
* Pass :id => nil or :class => nil to error_messages_for to supress that html attribute. #3586 [olivier_ansaldi@yahoo.com]
* Reset @html_document between requests so assert_tag works. #4810 [Jarkko Laine, easleydp@gmail.com]

View File

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

View File

@@ -155,20 +155,20 @@ A short rundown of the major features:
map.connect 'clients/:client_name/:project_name/:controller/:action'
Accessing /clients/37signals/basecamp/project/dash calls ProjectController#dash with
{ "client_name" => "37signals", "project_name" => "basecamp" } in params[:params]
{ "client_name" => "37signals", "project_name" => "basecamp" }.
From that URL, you can rewrite the redirect in a number of ways:
From that URL you can redirect providing new parameters in a number of ways:
redirect_to(:action => "edit") =>
/clients/37signals/basecamp/project/dash
redirect_to :action => "edit"
# /clients/37signals/basecamp/project/edit
redirect_to(:client_name => "nextangle", :project_name => "rails") =>
/clients/nextangle/rails/project/dash
redirect_to :client_name => "nextangle", :project_name => "rails"
# /clients/nextangle/rails/project/dash
{Learn more}[link:classes/ActionController/Base.html]
* Javascript and Ajax integration
* JavaScript and Ajax integration
link_to_function "Greeting", "alert('Hello world!')"
link_to_remote "Delete this post", :update => "posts",

View File

@@ -1,10 +1,9 @@
require 'rubygems'
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
require 'rdoc/task'
require 'rake/packagetask'
require 'rake/gempackagetask'
require 'rake/contrib/sshpublisher'
require 'rubygems/package_task'
require File.join(File.dirname(__FILE__), 'lib', 'action_pack', 'version')
PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
@@ -30,7 +29,7 @@ Rake::TestTask.new(:test_action_pack) do |t|
# make sure we include the tests in alphabetical order as on some systems
# this will not happen automatically and the tests (as a whole) will error
t.test_files = Dir.glob( "test/[cft]*/**/*_test.rb" ).sort
t.test_files = Dir.glob( "test/[cftv]*/**/*_test.rb" ).sort
t.verbose = true
#t.warning = true
@@ -46,7 +45,7 @@ end
# Genereate the RDoc documentation
Rake::RDocTask.new { |rdoc|
RDoc::Task.new { |rdoc|
rdoc.rdoc_dir = 'doc'
rdoc.title = "Action Pack -- On rails from request to response"
rdoc.options << '--line-numbers' << '--inline-source'
@@ -77,13 +76,13 @@ spec = Gem::Specification.new do |s|
s.rubyforge_project = "actionpack"
s.homepage = "http://www.rubyonrails.org"
s.has_rdoc = true
s.requirements << 'none'
s.add_dependency('activesupport', '= 2.3.2' + PKG_BUILD)
s.add_dependency('activesupport', '= 2.3.14' + PKG_BUILD)
s.add_dependency('erubis', '~> 2.7.0')
s.add_dependency('rack', '~> 1.1')
s.require_path = 'lib'
s.autorequire = 'action_controller'
s.files = [ "Rakefile", "install.rb", "README", "RUNNING_UNIT_TESTS", "CHANGELOG", "MIT-LICENSE" ]
dist_dirs.each do |dir|
@@ -91,7 +90,7 @@ spec = Gem::Specification.new do |s|
end
end
Rake::GemPackageTask.new(spec) do |p|
Gem::PackageTask.new(spec) do |p|
p.gem_spec = spec
p.need_tar = true
p.need_zip = true
@@ -136,12 +135,14 @@ task :update_js => [ :update_scriptaculous ]
desc "Publish the API documentation"
task :pgem => [:package] do
require 'rake/contrib/sshpublisher'
Rake::SshFilePublisher.new("gems.rubyonrails.org", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
`ssh gems.rubyonrails.org '/u/sites/gems/gemupdate.sh'`
end
desc "Publish the API documentation"
task :pdoc => [:rdoc] do
require 'rake/contrib/sshpublisher'
Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/ap", "doc").upload
end

View File

@@ -1,5 +1,5 @@
#--
# Copyright (c) 2004-2009 David Heinemeier Hansson
# Copyright (c) 2004-2010 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -31,12 +31,8 @@ rescue LoadError
end
end
begin
gem 'rack', '~> 1.0.0'
require 'rack'
rescue Gem::LoadError
require 'action_controller/vendor/rack-1.0/rack'
end
require 'rack'
require 'action_controller/cgi_ext'
module ActionController
# TODO: Review explicit to see if they will automatically be handled by
@@ -45,7 +41,6 @@ module ActionController
[Base, CGIHandler, CgiRequest, Request, Response, Http::Headers, UrlRewriter, UrlWriter]
end
autoload :AbstractRequest, 'action_controller/request'
autoload :Base, 'action_controller/base'
autoload :Benchmarking, 'action_controller/benchmarking'
autoload :Caching, 'action_controller/caching'
@@ -75,6 +70,7 @@ module ActionController
autoload :SessionManagement, 'action_controller/session_management'
autoload :StatusCodes, 'action_controller/status_codes'
autoload :Streaming, 'action_controller/streaming'
autoload :StringCoercion, 'action_controller/string_coercion'
autoload :TestCase, 'action_controller/test_case'
autoload :TestProcess, 'action_controller/test_process'
autoload :Translation, 'action_controller/translation'

View File

@@ -1,6 +1,18 @@
module ActionController
module Assertions
module DomAssertions
def self.strip_whitespace!(nodes)
nodes.reject! do |node|
if node.is_a?(HTML::Text)
node.content.strip!
node.content.empty?
else
strip_whitespace! node.children
false
end
end
end
# Test two HTML strings for equivalency (e.g., identical up to reordering of attributes)
#
# ==== Examples
@@ -12,13 +24,15 @@ module ActionController
clean_backtrace do
expected_dom = HTML::Document.new(expected).root
actual_dom = HTML::Document.new(actual).root
full_message = build_message(message, "<?> expected to be == to\n<?>.", expected_dom.to_s, actual_dom.to_s)
DomAssertions.strip_whitespace!(expected_dom.children)
DomAssertions.strip_whitespace!(actual_dom.children)
full_message = build_message(message, "<?> expected but was\n<?>.", expected_dom.to_s, actual_dom.to_s)
assert_block(full_message) { expected_dom == actual_dom }
end
end
# The negated form of +assert_dom_equivalent+.
# The negated form of +assert_dom_equal+.
#
# ==== Examples
#
@@ -29,8 +43,10 @@ module ActionController
clean_backtrace do
expected_dom = HTML::Document.new(expected).root
actual_dom = HTML::Document.new(actual).root
full_message = build_message(message, "<?> expected to be != to\n<?>.", expected_dom.to_s, actual_dom.to_s)
DomAssertions.strip_whitespace!(expected_dom.children)
DomAssertions.strip_whitespace!(actual_dom.children)
full_message = build_message(message, "<?> expected to be != to\n<?>.", expected_dom.to_s, actual_dom.to_s)
assert_block(full_message) { expected_dom != actual_dom }
end
end

View File

@@ -63,7 +63,12 @@ module ActionController
# Support partial arguments for hash redirections
if options.is_a?(Hash) && @response.redirected_to.is_a?(Hash)
return true if options.all? {|(key, value)| @response.redirected_to[key] == value}
if options.all? {|(key, value)| @response.redirected_to[key] == value}
callstack = caller.dup
callstack.slice!(0, 2)
::ActiveSupport::Deprecation.warn("Using assert_redirected_to with partial hash arguments is deprecated. Specify the full set arguments instead", callstack)
return true
end
end
redirected_to_after_normalisation = normalize_argument_to_redirection(@response.redirected_to)
@@ -82,6 +87,9 @@ module ActionController
# # assert that the "new" view template was rendered
# assert_template "new"
#
# # assert that the "new" view template was rendered with Symbol
# assert_template :new
#
# # assert that the "_customer" partial was rendered twice
# assert_template :partial => '_customer', :count => 2
#
@@ -91,7 +99,7 @@ module ActionController
def assert_template(options = {}, message = nil)
clean_backtrace do
case options
when NilClass, String
when NilClass, String, Symbol
rendered = @response.rendered[:template].to_s
msg = build_message(message,
"expecting <?> but rendering with <?>",
@@ -100,7 +108,7 @@ module ActionController
if options.nil?
@response.rendered[:template].blank?
else
rendered.to_s.match(options)
rendered.to_s.match(options.to_s)
end
end
when Hash
@@ -123,6 +131,8 @@ module ActionController
assert @response.rendered[:partials].empty?,
"Expected no partials to be rendered"
end
else
raise ArgumentError
end
end
end
@@ -134,16 +144,25 @@ module ActionController
end
def normalize_argument_to_redirection(fragment)
after_routing = @controller.url_for(fragment)
if after_routing =~ %r{^\w+://.*}
after_routing
else
# FIXME - this should probably get removed.
if after_routing.first != '/'
after_routing = '/' + after_routing
case fragment
when %r{^\w[\w\d+.-]*:.*}
fragment
when String
if fragment =~ %r{^\w[\w\d+.-]*:.*}
fragment
else
if fragment !~ /^\//
ActiveSupport::Deprecation.warn "Omitting the leading slash on a path with assert_redirected_to is deprecated. Use '/#{fragment}' instead.", caller(2)
fragment = "/#{fragment}"
end
@request.protocol + @request.host_with_port + fragment
end
@request.protocol + @request.host_with_port + after_routing
end
when :back
raise RedirectBackError unless refer = @request.headers["Referer"]
refer
else
@controller.url_for(fragment)
end.gsub(/[\r\n]/, '')
end
end
end

View File

@@ -16,7 +16,7 @@ module ActionController
#
# Use +css_select+ to select elements without making an assertions, either
# from the response HTML or elements selected by the enclosing assertion.
#
#
# In addition to HTML responses, you can make the following assertions:
# * +assert_select_rjs+ - Assertions on HTML content of RJS update and insertion operations.
# * +assert_select_encoded+ - Assertions on HTML encoded inside XML, for example for dealing with feed item descriptions.
@@ -24,6 +24,12 @@ module ActionController
#
# Also see HTML::Selector to learn how to use selectors.
module SelectorAssertions
def initialize(*args)
super
@selected = nil
end
# :call-seq:
# css_select(selector) => array
# css_select(element, selector) => array
@@ -53,8 +59,8 @@ module ActionController
# end
#
# # Selects all list items in unordered lists
# items = css_select("ul>li")
#
# items = css_select("ul>li")
#
# # Selects all form tags and then all inputs inside the form
# forms = css_select("form")
# forms.each do |form|
@@ -212,7 +218,7 @@ module ActionController
# Otherwise just operate on the response document.
root = response_from_page_or_rjs
end
# First or second argument is the selector: string and we pass
# all remaining arguments. Array and we pass the argument. Also
# accepts selector itself.
@@ -225,7 +231,7 @@ module ActionController
selector = arg
else raise ArgumentError, "Expecting a selector as the first argument"
end
# Next argument is used for equality tests.
equals = {}
case arg = args.shift
@@ -315,10 +321,10 @@ module ActionController
# Returns all matches elements.
matches
end
def count_description(min, max) #:nodoc:
pluralize = lambda {|word, quantity| word << (quantity == 1 ? '' : 's')}
if min && max && (max != min)
"between #{min} and #{max} elements"
elsif min && !(min == 1 && max == 1)
@@ -327,7 +333,7 @@ module ActionController
"at most #{max} #{pluralize['element', max]}"
end
end
# :call-seq:
# assert_select_rjs(id?) { |elements| ... }
# assert_select_rjs(statement, id?) { |elements| ... }
@@ -344,7 +350,7 @@ module ActionController
# that update or insert an element with that identifier.
#
# Use the first argument to narrow down assertions to only statements
# of that type. Possible values are <tt>:replace</tt>, <tt>:replace_html</tt>,
# of that type. Possible values are <tt>:replace</tt>, <tt>:replace_html</tt>,
# <tt>:show</tt>, <tt>:hide</tt>, <tt>:toggle</tt>, <tt>:remove</tt> and
# <tt>:insert_html</tt>.
#
@@ -488,7 +494,7 @@ module ActionController
# end
# end
# end
#
#
#
# # Selects all paragraph tags from within the description of an RSS feed
# assert_select_feed :rss, 2.0 do

View File

@@ -491,9 +491,18 @@ module ActionController #:nodoc:
filtered_parameters[key] = '[FILTERED]'
elsif value.is_a?(Hash)
filtered_parameters[key] = filter_parameters(value)
elsif value.is_a?(Array)
filtered_parameters[key] = value.collect do |item|
case item
when Hash, Array
filter_parameters(item)
else
item
end
end
elsif block_given?
key = key.dup
value = value.dup if value
value = value.dup if value.duplicable?
yield key, value
filtered_parameters[key] = value
else
@@ -607,15 +616,6 @@ module ActionController #:nodoc:
# displayed on:
#
# url_for :controller => 'posts', :action => nil
#
# If you explicitly want to create a URL that's almost the same as the current URL, you can do so using the
# <tt>:overwrite_params</tt> options. Say for your posts you have different views for showing and printing them.
# Then, in the show view, you get the URL for the print view like this
#
# url_for :overwrite_params => { :action => 'print' }
#
# This takes the current URL as is and only exchanges the action. In contrast, <tt>url_for :action => 'print'</tt>
# would have slashed-off the path components after the changed action.
def url_for(options = {})
options ||= {}
case options
@@ -810,7 +810,6 @@ module ActionController #:nodoc:
# render :text => proc { |response, output|
# 10_000_000.times do |i|
# output.write("This is line #{i}\n")
# output.flush
# end
# }
#
@@ -950,8 +949,9 @@ module ActionController #:nodoc:
response.content_type ||= Mime::JS
render_for_text(js, options[:status])
elsif json = options[:json]
json = json.to_json unless json.is_a?(String)
elsif options.include?(:json)
json = options[:json]
json = ActiveSupport::JSON.encode(json) unless json.is_a?(String)
json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
response.content_type ||= Mime::JSON
render_for_text(json, options[:status])
@@ -1083,13 +1083,24 @@ module ActionController #:nodoc:
# The redirection happens as a "302 Moved" header unless otherwise specified.
#
# Examples:
# redirect_to post_url(@post), :status=>:found
# redirect_to :action=>'atom', :status=>:moved_permanently
# redirect_to post_url(@post), :status=>301
# redirect_to :action=>'atom', :status=>302
# redirect_to post_url(@post), :status => :found
# redirect_to :action=>'atom', :status => :moved_permanently
# redirect_to post_url(@post), :status => 301
# redirect_to :action=>'atom', :status => 302
#
# When using <tt>redirect_to :back</tt>, if there is no referrer,
# RedirectBackError will be raised. You may specify some fallback
# The status code can either be a standard {HTTP Status code}[http://www.iana.org/assignments/http-status-codes] as an
# integer, or a symbol representing the downcased, underscored and symbolized description.
#
# It is also possible to assign a flash message as part of the redirection. There are two special accessors for commonly used the flash names
# +alert+ and +notice+ as well as a general purpose +flash+ bucket.
#
# Examples:
# redirect_to post_url(@post), :alert => "Watch it, mister!"
# redirect_to post_url(@post), :status=> :found, :notice => "Pay attention to the road"
# redirect_to post_url(@post), :status => 301, :flash => { :updated_post_id => @post.id }
# redirect_to { :action=>'atom' }, :alert => "Something serious happened"
#
# When using <tt>redirect_to :back</tt>, if there is no referrer, RedirectBackError will be raised. You may specify some fallback
# behavior for this case by rescuing RedirectBackError.
def redirect_to(options = {}, response_status = {}) #:doc:
raise ActionControllerError.new("Cannot redirect to nil!") if options.nil?
@@ -1403,7 +1414,7 @@ module ActionController #:nodoc:
end
Base.class_eval do
[ Filters, Layout, Benchmarking, Rescue, Flash, MimeResponds, Helpers,
[ Filters, Layout, Benchmarking, Rescue, MimeResponds, Helpers, Flash,
Cookies, Caching, Verification, Streaming, SessionManagement,
HttpAuthentication::Basic::ControllerMethods, HttpAuthentication::Digest::ControllerMethods,
RecordIdentifier, RequestForgeryProtection, Translation

View File

@@ -22,12 +22,13 @@ module ActionController #:nodoc:
# ActionController::Base.cache_store = :file_store, "/path/to/cache/directory"
# ActionController::Base.cache_store = :drb_store, "druby://localhost:9192"
# ActionController::Base.cache_store = :mem_cache_store, "localhost"
# ActionController::Base.cache_store = :mem_cache_store, Memcached::Rails.new("localhost:11211")
# ActionController::Base.cache_store = MyOwnStore.new("parameter")
module Caching
autoload :Actions, 'action_controller/caching/actions'
autoload :Fragments, 'action_controller/caching/fragments'
autoload :Pages, 'action_controller/caching/pages'
autoload :Sweeper, 'action_controller/caching/sweeping'
autoload :Sweeper, 'action_controller/caching/sweeper'
autoload :Sweeping, 'action_controller/caching/sweeping'
def self.included(base) #:nodoc:

View File

@@ -61,7 +61,9 @@ module ActionController #:nodoc:
filter_options = { :only => actions, :if => options.delete(:if), :unless => options.delete(:unless) }
cache_filter = ActionCacheFilter.new(:layout => options.delete(:layout), :cache_path => options.delete(:cache_path), :store_options => options)
around_filter(cache_filter, filter_options)
around_filter(filter_options) do |controller, action|
cache_filter.filter(controller, action)
end
end
end
@@ -83,6 +85,12 @@ module ActionController #:nodoc:
@options = options
end
def filter(controller, action)
should_continue = before(controller)
action.call if should_continue
after(controller)
end
def before(controller)
cache_path = ActionCachePath.new(controller, path_options_for(controller, @options.slice(:cache_path)))
if cache = controller.read_fragment(cache_path.path, @options[:store_options])

View File

@@ -37,7 +37,7 @@ module ActionController #:nodoc:
def fragment_for(buffer, name = {}, options = nil, &block) #:nodoc:
if perform_caching
if cache = read_fragment(name, options)
buffer.concat(cache)
buffer.safe_concat(cache.html_safe)
else
pos = buffer.length
block.call
@@ -52,9 +52,9 @@ module ActionController #:nodoc:
def write_fragment(key, content, options = nil)
return content unless cache_configured?
key = fragment_cache_key(key)
self.class.benchmark "Cached fragment miss: #{key}" do
key = fragment_cache_key(key)
content = content.html_safe.to_str if content.respond_to?(:html_safe)
cache_store.write(key, content, options)
end
@@ -66,9 +66,9 @@ module ActionController #:nodoc:
return unless cache_configured?
key = fragment_cache_key(key)
self.class.benchmark "Cached fragment hit: #{key}" do
cache_store.read(key, options)
result = cache_store.read(key, options)
result.respond_to?(:html_safe) ? result.html_safe : result
end
end

View File

@@ -0,0 +1,45 @@
require 'active_record'
module ActionController #:nodoc:
module Caching
class Sweeper < ActiveRecord::Observer #:nodoc:
attr_accessor :controller
def before(controller)
self.controller = controller
callback(:before) if controller.perform_caching
end
def after(controller)
callback(:after) if controller.perform_caching
# Clean up, so that the controller can be collected after this request
self.controller = nil
end
protected
# gets the action cache path for the given options.
def action_path_for(options)
ActionController::Caching::Actions::ActionCachePath.path_for(controller, options)
end
# Retrieve instance variables set in the controller.
def assigns(key)
controller.instance_variable_get("@#{key}")
end
private
def callback(timing)
controller_callback_method_name = "#{timing}_#{controller.controller_name.underscore}"
action_callback_method_name = "#{controller_callback_method_name}_#{controller.action_name}"
__send__(controller_callback_method_name) if respond_to?(controller_callback_method_name, true)
__send__(action_callback_method_name) if respond_to?(action_callback_method_name, true)
end
def method_missing(method, *arguments, &block)
return if @controller.nil?
@controller.__send__(method, *arguments, &block)
end
end
end
end

View File

@@ -51,47 +51,5 @@ module ActionController #:nodoc:
end
end
end
if defined?(ActiveRecord) and defined?(ActiveRecord::Observer)
class Sweeper < ActiveRecord::Observer #:nodoc:
attr_accessor :controller
def before(controller)
self.controller = controller
callback(:before) if controller.perform_caching
end
def after(controller)
callback(:after) if controller.perform_caching
# Clean up, so that the controller can be collected after this request
self.controller = nil
end
protected
# gets the action cache path for the given options.
def action_path_for(options)
ActionController::Caching::Actions::ActionCachePath.path_for(controller, options)
end
# Retrieve instance variables set in the controller.
def assigns(key)
controller.instance_variable_get("@#{key}")
end
private
def callback(timing)
controller_callback_method_name = "#{timing}_#{controller.controller_name.underscore}"
action_callback_method_name = "#{controller_callback_method_name}_#{controller.action_name}"
__send__(controller_callback_method_name) if respond_to?(controller_callback_method_name, true)
__send__(action_callback_method_name) if respond_to?(action_callback_method_name, true)
end
def method_missing(method, *arguments, &block)
return if @controller.nil?
@controller.__send__(method, *arguments, &block)
end
end
end
end
end

View File

@@ -46,18 +46,21 @@ module ActionController #:nodoc:
module Cookies
def self.included(base)
base.helper_method :cookies
base.cattr_accessor :cookie_verifier_secret
end
protected
# Returns the cookie container, which operates as described above.
def cookies
CookieJar.new(self)
@cookies ||= CookieJar.new(self)
end
end
class CookieJar < Hash #:nodoc:
attr_reader :controller
def initialize(controller)
@controller, @cookies = controller, controller.request.cookies
@controller, @cookies, @secure = controller, controller.request.cookies, controller.request.ssl?
super()
update(@cookies)
end
@@ -78,7 +81,7 @@ module ActionController #:nodoc:
options[:path] = "/" unless options.has_key?(:path)
super(key.to_s, options[:value])
@controller.response.set_cookie(key, options)
@controller.response.set_cookie(key, options) if write_cookie?(options)
end
# Removes the cookie on the client machine by setting the value to an empty string
@@ -87,8 +90,108 @@ module ActionController #:nodoc:
def delete(key, options = {})
options.symbolize_keys!
options[:path] = "/" unless options.has_key?(:path)
super(key.to_s)
value = super(key.to_s)
@controller.response.delete_cookie(key, options)
value
end
# Returns a jar that'll automatically set the assigned cookies to have an expiration date 20 years from now. Example:
#
# cookies.permanent[:prefers_open_id] = true
# # => Set-Cookie: prefers_open_id=true; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
#
# This jar is only meant for writing. You'll read permanent cookies through the regular accessor.
#
# This jar allows chaining with the signed jar as well, so you can set permanent, signed cookies. Examples:
#
# cookies.permanent.signed[:remember_me] = current_user.id
# # => Set-Cookie: discount=BAhU--848956038e692d7046deab32b7131856ab20e14e; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
def permanent
@permanent ||= PermanentCookieJar.new(self)
end
# Returns a jar that'll automatically generate a signed representation of cookie value and verify it when reading from
# the cookie again. This is useful for creating cookies with values that the user is not supposed to change. If a signed
# cookie was tampered with by the user (or a 3rd party), an ActiveSupport::MessageVerifier::InvalidSignature exception will
# be raised.
#
# This jar requires that you set a suitable secret for the verification on ActionController::Base.cookie_verifier_secret.
#
# Example:
#
# cookies.signed[:discount] = 45
# # => Set-Cookie: discount=BAhpMg==--2c1c6906c90a3bc4fd54a51ffb41dffa4bf6b5f7; path=/
#
# cookies.signed[:discount] # => 45
def signed
@signed ||= SignedCookieJar.new(self)
end
private
def write_cookie?(cookie)
@secure || !cookie[:secure] || defined?(Rails.env) && Rails.env.development?
end
end
class PermanentCookieJar < CookieJar #:nodoc:
def initialize(parent_jar)
@parent_jar = parent_jar
end
def []=(key, options)
if options.is_a?(Hash)
options.symbolize_keys!
else
options = { :value => options }
end
options[:expires] = 20.years.from_now
@parent_jar[key] = options
end
def signed
@signed ||= SignedCookieJar.new(self)
end
def controller
@parent_jar.controller
end
def method_missing(method, *arguments, &block)
@parent_jar.send(method, *arguments, &block)
end
end
class SignedCookieJar < CookieJar #:nodoc:
def initialize(parent_jar)
unless parent_jar.controller.class.cookie_verifier_secret
raise "You must set ActionController::Base.cookie_verifier_secret to use signed cookies"
end
@parent_jar = parent_jar
@verifier = ActiveSupport::MessageVerifier.new(@parent_jar.controller.class.cookie_verifier_secret)
end
def [](name)
if value = @parent_jar[name]
@verifier.verify(value)
end
end
def []=(key, options)
if options.is_a?(Hash)
options.symbolize_keys!
options[:value] = @verifier.generate(options[:value])
else
options = { :value => @verifier.generate(options) }
end
@parent_jar[key] = options
end
def method_missing(method, *arguments, &block)
@parent_jar.send(method, *arguments, &block)
end
end
end

View File

@@ -2,13 +2,12 @@ module ActionController
# Dispatches requests to the appropriate controller and takes care of
# reloading the app after each request when Dependencies.load? is true.
class Dispatcher
@@cache_classes = true
class << self
def define_dispatcher_callbacks(cache_classes)
@@cache_classes = cache_classes
unless cache_classes
unless self.middleware.include?(Reloader)
self.middleware.insert_after(Failsafe, Reloader)
end
ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false
end
@@ -79,7 +78,7 @@ module ActionController
# DEPRECATE: Remove arguments, since they are only used by CGI
def initialize(output = $stdout, request = nil, response = nil)
@output = output
@app = @@middleware.build(lambda { |env| self.dup._call(env) })
build_middleware_stack if @@cache_classes
end
def dispatch
@@ -103,7 +102,18 @@ module ActionController
end
def call(env)
@app.call(env)
if @@cache_classes
@app.call(env)
else
Reloader.run do
# When class reloading is turned on, we will want to rebuild the
# middleware stack every time we process a request. If we don't
# rebuild the middleware stack, then the stack may contain references
# to old classes metal classes, which will b0rk class reloading.
build_middleware_stack
@app.call(env)
end
end
end
def _call(env)
@@ -114,5 +124,10 @@ module ActionController
def flush_logger
Base.logger.flush
end
private
def build_middleware_stack
@app = @@middleware.build(lambda { |env| self.dup._call(env) })
end
end
end

View File

@@ -1,4 +1,19 @@
require 'erb'
module ActionController
# The Failsafe middleware is usually the top-most middleware in the Rack
# middleware chain. It returns the underlying middleware's response, but if
# the underlying middle raises an exception then Failsafe will log the
# exception into the Rails log file, and will attempt to return an error
# message response.
#
# Failsafe is a last resort for logging errors and for telling the HTTP
# client that something went wrong. Do not confuse this with the
# ActionController::Rescue module, which is responsible for catching
# exceptions at deeper levels. Unlike Failsafe, which is as simple as
# possible, Rescue provides features that allow developers to hook into
# the error handling logic, and can customize the error message response
# based on the HTTP client's IP.
class Failsafe
cattr_accessor :error_file_path
self.error_file_path = Rails.public_path if defined?(Rails.public_path)
@@ -11,7 +26,7 @@ module ActionController
@app.call(env)
rescue Exception => exception
# Reraise exception in test environment
if env["rack.test"]
if defined?(Rails) && Rails.env.test?
raise exception
else
failsafe_response(exception)
@@ -21,24 +36,44 @@ module ActionController
private
def failsafe_response(exception)
log_failsafe_exception(exception)
[500, {'Content-Type' => 'text/html'}, failsafe_response_body]
[500, {'Content-Type' => 'text/html'}, [failsafe_response_body]]
rescue Exception => failsafe_error # Logger or IO errors
$stderr.puts "Error during failsafe response: #{failsafe_error}"
end
def failsafe_response_body
error_path = "#{self.class.error_file_path}/500.html"
if File.exist?(error_path)
File.read(error_path)
error_template_path = "#{self.class.error_file_path}/500.html"
if File.exist?(error_template_path)
begin
result = render_template(error_template_path)
rescue Exception
result = nil
end
else
"<html><body><h1>500 Internal Server Error</h1></body></html>"
result = nil
end
if result.nil?
result = "<html><body><h1>500 Internal Server Error</h1>" <<
"If you are the administrator of this website, then please read this web " <<
"application's log file to find out what went wrong.</body></html>"
end
result
end
# The default 500.html uses the h() method.
def h(text) # :nodoc:
ERB::Util.h(text)
end
def render_template(filename)
ERB.new(File.read(filename)).result(binding)
end
def log_failsafe_exception(exception)
message = "/!\\ FAILSAFE /!\\ #{Time.now}\n Status: 500 Internal Server Error\n"
message << " #{exception}\n #{exception.backtrace.join("\n ")}" if exception
failsafe_logger.fatal(message)
failsafe_logger.flush if failsafe_logger.respond_to?(:flush)
end
def failsafe_logger

View File

@@ -29,8 +29,13 @@ module ActionController #:nodoc:
def self.included(base)
base.class_eval do
include InstanceMethods
alias_method_chain :perform_action, :flash
alias_method_chain :reset_session, :flash
alias_method_chain :redirect_to, :flash
helper_method :alert
helper_method :notice
end
end
@@ -120,6 +125,11 @@ module ActionController #:nodoc:
(@used.keys - keys).each{ |k| @used.delete(k) }
end
def store(session, key = "flash")
return if self.empty?
session[key] = self
end
private
# Used internally by the <tt>keep</tt> and <tt>discard</tt> methods
# use() # marks the entire flash as used
@@ -139,7 +149,10 @@ module ActionController #:nodoc:
protected
def perform_action_with_flash
perform_action_without_flash
remove_instance_variable(:@_flash) if defined? @_flash
if defined? @_flash
@_flash.store(session)
remove_instance_variable(:@_flash)
end
end
def reset_session_with_flash
@@ -147,17 +160,54 @@ module ActionController #:nodoc:
remove_instance_variable(:@_flash) if defined? @_flash
end
def redirect_to_with_flash(options = {}, response_status_and_flash = {}) #:doc:
if alert = response_status_and_flash.delete(:alert)
flash[:alert] = alert
end
if notice = response_status_and_flash.delete(:notice)
flash[:notice] = notice
end
if other_flashes = response_status_and_flash.delete(:flash)
flash.update(other_flashes)
end
redirect_to_without_flash(options, response_status_and_flash)
end
# Access the contents of the flash. Use <tt>flash["notice"]</tt> to
# read a notice you put there or <tt>flash["notice"] = "hello"</tt>
# to put a new one.
def flash #:doc:
unless defined? @_flash
@_flash = session["flash"] ||= FlashHash.new
if !defined?(@_flash)
@_flash = session["flash"] || FlashHash.new
@_flash.sweep
end
@_flash
end
# Convenience accessor for flash[:alert]
def alert
flash[:alert]
end
# Convenience accessor for flash[:alert]=
def alert=(message)
flash[:alert] = message
end
# Convenience accessor for flash[:notice]
def notice
flash[:notice]
end
# Convenience accessor for flash[:notice]=
def notice=(message)
flash[:notice] = message
end
end
end
end

View File

@@ -139,7 +139,7 @@ module ActionController
end
def decode_credentials(request)
ActiveSupport::Base64.decode64(authorization(request).split.last || '')
ActiveSupport::Base64.decode64(authorization(request).split(' ', 2).last || '')
end
def encode_credentials(user_name, password)
@@ -183,7 +183,7 @@ module ActionController
request.env['REDIRECT_X_HTTP_AUTHORIZATION']
end
# Raises error unless the request credentials response value matches the expected value.
# Returns false unless the request credentials response value matches the expected value.
# First try the password as a ha1 digest password. If this fails, then try it as a plain
# text password.
def validate_digest_response(request, realm, &password_procedure)
@@ -192,9 +192,13 @@ module ActionController
if valid_nonce && realm == credentials[:realm] && opaque == credentials[:opaque]
password = password_procedure.call(credentials[:username])
return false unless password
method = request.env['rack.methodoverride.original_method'] || request.env['REQUEST_METHOD']
uri = credentials[:uri][0,1] == '/' ? request.request_uri : request.url
[true, false].any? do |password_is_ha1|
expected = expected_response(request.env['REQUEST_METHOD'], request.env['REQUEST_URI'], credentials, password, password_is_ha1)
expected = expected_response(method, uri, credentials, password, password_is_ha1)
expected == credentials[:response]
end
end
@@ -223,9 +227,9 @@ module ActionController
end
def decode_credentials(header)
header.to_s.gsub(/^Digest\s+/,'').split(',').inject({}) do |hash, pair|
header.to_s.gsub(/^Digest\s+/,'').split(',').inject({}.with_indifferent_access) do |hash, pair|
key, value = pair.split('=', 2)
hash[key.strip.to_sym] = value.to_s.gsub(/^"|"$/,'').gsub(/'/, '')
hash[key.strip] = value.to_s.gsub(/^"|"$/,'').gsub(/'/, '')
hash
end
end
@@ -285,6 +289,7 @@ module ActionController
# allow a user to use new nonce without prompting user again for their
# username and password.
def validate_nonce(request, value, seconds_to_timeout=5*60)
return false if value.nil?
t = Base64.decode64(value).split(":").first.to_i
nonce(t) == value && (t - Time.now.to_i).abs <= seconds_to_timeout
end

View File

@@ -1,6 +1,7 @@
require 'stringio'
require 'uri'
require 'active_support/test_case'
require 'action_controller/rack_lint_patch'
module ActionController
module Integration #:nodoc:
@@ -268,7 +269,9 @@ module ActionController
env["QUERY_STRING"] ||= ""
data = data.is_a?(IO) ? data : StringIO.new(data || '')
data ||= ''
data.force_encoding(Encoding::ASCII_8BIT) if data.respond_to?(:force_encoding)
data = data.is_a?(IO) ? data : StringIO.new(data)
env.update(
"REQUEST_METHOD" => method.to_s.upcase,
@@ -284,7 +287,6 @@ module ActionController
"REMOTE_ADDR" => remote_addr,
"CONTENT_TYPE" => "application/x-www-form-urlencoded",
"CONTENT_LENGTH" => data ? data.length.to_s : nil,
"HTTP_COOKIE" => encode_cookies,
"HTTP_ACCEPT" => accept,
"rack.version" => [0,1],
@@ -292,11 +294,11 @@ module ActionController
"rack.errors" => StringIO.new,
"rack.multithread" => true,
"rack.multiprocess" => true,
"rack.run_once" => false,
"rack.test" => true
"rack.run_once" => false
)
env['HTTP_COOKIE'] = encode_cookies if cookies.any?
(headers || {}).each do |key, value|
key = key.to_s.upcase.gsub(/-/, "_")
key = "HTTP_#{key}" unless env.has_key?(key) || key =~ /^HTTP_/
@@ -311,12 +313,7 @@ module ActionController
ActionController::Base.clear_last_instantiation!
app = @application
# Rack::Lint doesn't accept String headers or bodies in Ruby 1.9
unless RUBY_VERSION >= '1.9.0' && Rack.release <= '0.9.0'
app = Rack::Lint.new(app)
end
app = Rack::Lint.new(@application)
status, headers, body = app.call(env)
@request_count += 1
@@ -327,13 +324,15 @@ module ActionController
@headers = Rack::Utils::HeaderHash.new(headers)
(@headers['Set-Cookie'] || "").split("\n").each do |cookie|
cookies = @headers['Set-Cookie']
cookies = cookies.to_s.split("\n") unless cookies.is_a?(Array)
cookies.each do |cookie|
name, value = cookie.match(/^([^=]*)=([^;]*);/)[1,2]
@cookies[name] = value
end
@body = ""
if body.is_a?(String)
if body.respond_to?(:to_str)
@body << body
else
body.each { |part| @body << part }
@@ -357,6 +356,8 @@ module ActionController
# used in integration tests.
@response.extend(TestResponseBehavior)
body.close if body.respond_to?(:close)
return @status
rescue MultiPartNeededException
boundary = "----------XnJLe9ZIbbGUYtzPQJ16u1"
@@ -414,15 +415,25 @@ module ActionController
end
def multipart_requestify(params, first=true)
returning Hash.new do |p|
Array.new.tap do |p|
params.each do |key, value|
k = first ? CGI.escape(key.to_s) : "[#{CGI.escape(key.to_s)}]"
k = first ? key.to_s : "[#{key.to_s}]"
if Hash === value
multipart_requestify(value, false).each do |subkey, subvalue|
p[k + subkey] = subvalue
p << [k + subkey, subvalue]
end
elsif Array === value
value.each do |element|
if Hash === element || Array === element
multipart_requestify(element, false).each do |subkey, subvalue|
p << ["#{k}[]#{subkey}", subvalue]
end
else
p << ["#{k}[]", element]
end
end
else
p[k] = value
p << [k, value]
end
end
end
@@ -453,6 +464,7 @@ EOF
end
end.join("")+"--#{boundary}--\r"
end
end
# A module used to extend ActionController::Base, so that integration tests
@@ -483,6 +495,11 @@ EOF
end
module Runner
def initialize(*args)
super
@integration_session = nil
end
# Reset the current session. This is useful for testing multiple sessions
# in a single test case.
def reset!
@@ -495,7 +512,7 @@ EOF
reset! unless @integration_session
# reset the html_document variable, but only for new get/post calls
@html_document = nil unless %w(cookies assigns).include?(method)
returning @integration_session.__send__(method, *args) do
@integration_session.__send__(method, *args).tap do
copy_session_variables!
end
end
@@ -519,7 +536,7 @@ EOF
if self.class.respond_to?(:fixture_table_names)
self.class.fixture_table_names.each do |table_name|
name = table_name.tr(".", "_")
next unless respond_to?(name)
next unless respond_to?(name, true)
extras.__send__(:define_method, name) { |*args|
delegate.send(name, *args)
}
@@ -550,8 +567,12 @@ EOF
# Delegate unhandled messages to the current session instance.
def method_missing(sym, *args, &block)
reset! unless @integration_session
returning @integration_session.__send__(sym, *args, &block) do
copy_session_variables!
if @integration_session.respond_to?(sym)
@integration_session.__send__(sym, *args, &block).tap do
copy_session_variables!
end
else
super
end
end
end

View File

@@ -194,6 +194,11 @@ module ActionController #:nodoc:
end
end
def initialize(*args)
super
@real_format = nil
end
# Returns the name of the active layout. If the layout was specified as a method reference (through a symbol), this method
# is called and the return value is used. Likewise if the layout was specified as an inline method (through a proc or method
# object). If the layout was defined without a directory, layouts is assumed. So <tt>layout "weblog/standard"</tt> will return
@@ -221,7 +226,7 @@ module ActionController #:nodoc:
end
def find_layout(layout, format, html_fallback=false) #:nodoc:
view_paths.find_template(layout.to_s =~ /layouts\// ? layout : "layouts/#{layout}", format, html_fallback)
view_paths.find_template(layout.to_s =~ /\A\/|layouts\// ? layout : "layouts/#{layout}", format, html_fallback)
rescue ActionView::MissingTemplate
raise if Mime::Type.lookup_by_extension(format.to_s).html?
end

View File

@@ -7,7 +7,8 @@ use "ActionController::Failsafe"
use lambda { ActionController::Base.session_store },
lambda { ActionController::Base.session_options }
use "ActionController::RewindableInput"
use "ActionController::ParamsParser"
use "Rack::MethodOverride"
use "Rack::Head"
use "ActionController::StringCoercion"

View File

@@ -47,6 +47,8 @@ module ActionController
false
end
rescue Exception => e # YAML, XML or Ruby code block errors
logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{request.raw_post}"
raise
{ "body" => request.raw_post,
"content_type" => request.content_type,
@@ -67,5 +69,9 @@ module ActionController
nil
end
def logger
defined?(Rails.logger) ? Rails.logger : Logger.new($stderr)
end
end
end

View File

@@ -76,8 +76,7 @@ module ActionController
record_or_hash_or_array = record_or_hash_or_array[0] if record_or_hash_or_array.size == 1
end
record = extract_record(record_or_hash_or_array)
namespace = extract_namespace(record_or_hash_or_array)
record = extract_record(record_or_hash_or_array)
args = case record_or_hash_or_array
when Hash; [ record_or_hash_or_array ]
@@ -98,8 +97,7 @@ module ActionController
end
args.delete_if {|arg| arg.is_a?(Symbol) || arg.is_a?(String)}
named_route = build_named_route_call(record_or_hash_or_array, namespace, inflection, options)
named_route = build_named_route_call(record_or_hash_or_array, inflection, options)
url_options = options.except(:action, :routing_type)
unless url_options.empty?
@@ -117,7 +115,7 @@ module ActionController
end
%w(edit new).each do |action|
module_eval <<-EOT, __FILE__, __LINE__
module_eval <<-EOT, __FILE__, __LINE__ + 1
def #{action}_polymorphic_url(record_or_hash, options = {}) # def edit_polymorphic_url(record_or_hash, options = {})
polymorphic_url( # polymorphic_url(
record_or_hash, # record_or_hash,
@@ -153,7 +151,7 @@ module ActionController
options[:routing_type] || :url
end
def build_named_route_call(records, namespace, inflection, options = {})
def build_named_route_call(records, inflection, options = {})
unless records.is_a?(Array)
record = extract_record(records)
route = ''
@@ -163,7 +161,7 @@ module ActionController
if parent.is_a?(Symbol) || parent.is_a?(String)
string << "#{parent}_"
else
string << "#{RecordIdentifier.__send__("plural_class_name", parent)}".singularize
string << RecordIdentifier.__send__("plural_class_name", parent).singularize
string << "_"
end
end
@@ -172,12 +170,12 @@ module ActionController
if record.is_a?(Symbol) || record.is_a?(String)
route << "#{record}_"
else
route << "#{RecordIdentifier.__send__("plural_class_name", record)}"
route << RecordIdentifier.__send__("plural_class_name", record)
route = route.singularize if inflection == :singular
route << "_"
end
action_prefix(options) + namespace + route + routing_type(options).to_s
action_prefix(options) + route + routing_type(options).to_s
end
def extract_record(record_or_hash_or_array)
@@ -187,18 +185,5 @@ module ActionController
else record_or_hash_or_array
end
end
# Remove the first symbols from the array and return the url prefix
# implied by those symbols.
def extract_namespace(record_or_hash_or_array)
return "" unless record_or_hash_or_array.is_a?(Array)
namespace_keys = []
while (key = record_or_hash_or_array.first) && key.is_a?(String) || key.is_a?(Symbol)
namespace_keys << record_or_hash_or_array.shift
end
namespace_keys.map {|k| "#{k}_"}.join
end
end
end

View File

@@ -0,0 +1,36 @@
# Rack 1.0 does not allow string subclass body. This does not play well with our ActiveSupport::SafeBuffer.
# The next release of Rack will be allowing string subclass body - http://github.com/rack/rack/commit/de668df02802a0335376a81ba709270e43ba9d55
# TODO : Remove this monkey patch after the next release of Rack
module RackLintPatch
module AllowStringSubclass
def self.included(base)
base.send :alias_method, :each, :each_with_hack
end
def each_with_hack
@closed = false
@body.each { |part|
assert("Body yielded non-string value #{part.inspect}") {
part.kind_of?(String)
}
yield part
}
if @body.respond_to?(:to_path)
assert("The file identified by body.to_path does not exist") {
::File.exist? @body.to_path
}
end
end
end
begin
app = proc {|env| [200, {"Content-Type" => "text/plain", "Content-Length" => "12"}, [Class.new(String).new("Hello World!")]] }
response = Rack::MockRequest.new(Rack::Lint.new(app)).get('/')
rescue Rack::Lint::LintError => e
raise(e) unless e.message =~ /Body yielded non-string value/
Rack::Lint.send :include, AllowStringSubclass
end
end

View File

@@ -1,14 +1,54 @@
require 'thread'
module ActionController
class Reloader
def initialize(app)
@app = app
@@default_lock = Mutex.new
cattr_accessor :default_lock
class BodyWrapper
def initialize(body, lock)
@body = body
@lock = lock
end
def close
@body.close if @body.respond_to?(:close)
ensure
Dispatcher.cleanup_application
@lock.unlock
end
def method_missing(*args, &block)
@body.send(*args, &block)
end
def respond_to?(symbol, include_private = false)
symbol == :close || @body.respond_to?(symbol, include_private)
end
end
def call(env)
Dispatcher.reload_application
@app.call(env)
ensure
Dispatcher.cleanup_application
def self.run(lock = @@default_lock)
lock.lock
begin
Dispatcher.reload_application
status, headers, body = yield
# We do not want to call 'cleanup_application' in an ensure block
# because the returned Rack response body may lazily generate its data. This
# is for example the case if one calls
#
# render :text => lambda { ... code here which refers to application models ... }
#
# in an ActionController.
#
# Instead, we will want to cleanup the application code after the request is
# completely finished. So we wrap the body in a BodyWrapper class so that
# when the Rack handler calls #close during the end of the request, we get to
# run our cleanup code.
[status, headers, BodyWrapper.new(body, lock)]
rescue Exception
lock.unlock
raise
end
end
end
end

View File

@@ -95,6 +95,10 @@ module ActionController
end
end
def media_type
content_type.to_s
end
# Returns the accepted MIME type for the request.
def accepts
@accepts ||= begin
@@ -383,7 +387,7 @@ EOM
alias_method :params, :parameters
def path_parameters=(parameters) #:nodoc:
@env["rack.routing_args"] = parameters
@env["action_controller.request.path_parameters"] = parameters
@symbolized_path_parameters = @parameters = nil
end
@@ -399,7 +403,7 @@ EOM
#
# See <tt>symbolized_path_parameters</tt> for symbolized keys.
def path_parameters
@env["rack.routing_args"] ||= {}
@env["action_controller.request.path_parameters"] ||= {}
end
# The request body is an IO input stream. If the RAW_POST_DATA environment
@@ -442,8 +446,10 @@ EOM
end
def reset_session
@env['rack.session.options'].delete(:id)
@env['rack.session'] = {}
# session may be a hash, if so, we do not want to call destroy
# fixes issue 6440
session.destroy if session and session.respond_to?(:destroy)
self.session = {}
end
def session_options

View File

@@ -76,21 +76,29 @@ module ActionController #:nodoc:
protected
# The actual before_filter that is used. Modify this to change how you handle unverified requests.
def verify_authenticity_token
verified_request? || raise(ActionController::InvalidAuthenticityToken)
verified_request? || handle_unverified_request
end
def handle_unverified_request
reset_session
end
# Returns true or false if a request is verified. Checks:
#
# * is the format restricted? By default, only HTML and AJAX requests are checked.
# * is the format restricted? By default, only HTML requests are checked.
# * is it a GET request? Gets should be safe and idempotent
# * Does the form_authenticity_token match the given token value from the params?
def verified_request?
!protect_against_forgery? ||
request.method == :get ||
!verifiable_request_format? ||
form_authenticity_token == params[request_forgery_protection_token]
!protect_against_forgery? ||
request.get? ||
form_authenticity_token == form_authenticity_param ||
form_authenticity_token == request.headers['X-CSRF-Token']
end
def form_authenticity_param
params[request_forgery_protection_token]
end
def verifiable_request_format?
!request.content_type.nil? && request.content_type.verify_request?
end

View File

@@ -15,7 +15,7 @@ module ActionController #:nodoc:
# behavior is achieved by overriding the <tt>rescue_action_in_public</tt>
# and <tt>rescue_action_locally</tt> methods.
module Rescue
LOCALHOST = '127.0.0.1'.freeze
LOCALHOST = [/^127\.0\.0\.\d{1,3}$/, /^::1$/, /^0:0:0:0:0:0:0:1(%.*)?$/].freeze
DEFAULT_RESCUE_RESPONSE = :internal_server_error
DEFAULT_RESCUE_RESPONSES = {
@@ -122,7 +122,7 @@ module ActionController #:nodoc:
# method if you wish to redefine the meaning of a local request to
# include remote IP addresses or other criteria.
def local_request? #:doc:
request.remote_addr == LOCALHOST && request.remote_ip == LOCALHOST
LOCALHOST.any?{ |local_ip| request.remote_addr =~ local_ip && request.remote_ip =~ local_ip }
end
# Render detailed diagnostics for unhandled exceptions rescued from

View File

@@ -317,9 +317,10 @@ module ActionController
# notes.resources :attachments
# end
#
# * <tt>:path_names</tt> - Specify different names for the 'new' and 'edit' actions. For example:
# * <tt>:path_names</tt> - Specify different path names for the actions. For example:
# # new_products_path == '/productos/nuevo'
# map.resources :products, :as => 'productos', :path_names => { :new => 'nuevo', :edit => 'editar' }
# # bids_product_path(1) == '/productos/1/licitacoes'
# map.resources :products, :as => 'productos', :member => { :bids => :get }, :path_names => { :new => 'nuevo', :bids => 'licitacoes' }
#
# You can also set default action names from an environment, like this:
# config.action_controller.resources_path_names = { :new => 'nuevo', :edit => 'editar' }
@@ -525,16 +526,16 @@ module ActionController
resource = Resource.new(entities, options)
with_options :controller => resource.controller do |map|
map_collection_actions(map, resource)
map_default_collection_actions(map, resource)
map_new_actions(map, resource)
map_member_actions(map, resource)
map_associations(resource, options)
if block_given?
with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block)
end
map_collection_actions(map, resource)
map_default_collection_actions(map, resource)
map_new_actions(map, resource)
map_member_actions(map, resource)
end
end
@@ -542,16 +543,16 @@ module ActionController
resource = SingletonResource.new(entities, options)
with_options :controller => resource.controller do |map|
map_collection_actions(map, resource)
map_new_actions(map, resource)
map_member_actions(map, resource)
map_default_singleton_actions(map, resource)
map_associations(resource, options)
if block_given?
with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block)
end
map_collection_actions(map, resource)
map_new_actions(map, resource)
map_member_actions(map, resource)
map_default_singleton_actions(map, resource)
end
end
@@ -586,7 +587,10 @@ module ActionController
resource.collection_methods.each do |method, actions|
actions.each do |action|
[method].flatten.each do |m|
map_resource_routes(map, resource, action, "#{resource.path}#{resource.action_separator}#{action}", "#{action}_#{resource.name_prefix}#{resource.plural}", m)
action_path = resource.options[:path_names][action] if resource.options[:path_names].is_a?(Hash)
action_path ||= action
map_resource_routes(map, resource, action, "#{resource.path}#{resource.action_separator}#{action_path}", "#{action}_#{resource.name_prefix}#{resource.plural}", m)
end
end
end
@@ -655,7 +659,7 @@ module ActionController
end
def add_conditions_for(conditions, method)
returning({:conditions => conditions.dup}) do |options|
({:conditions => conditions.dup}).tap do |options|
options[:conditions][:method] = method unless method == :any
end
end

View File

@@ -47,7 +47,8 @@ module ActionController # :nodoc:
@block = nil
@body = "",
@session, @assigns = [], []
@session = []
@assigns = []
end
def location; headers['Location'] end
@@ -63,12 +64,13 @@ module ActionController # :nodoc:
# the character set information will also be included in the content type
# information.
def content_type=(mime_type)
self.headers["Content-Type"] =
new_content_type =
if mime_type =~ /charset/ || (c = charset).nil?
mime_type.to_s
else
"#{mime_type}; charset=#{c}"
end
self.headers["Content-Type"] = URI.escape(new_content_type, "\r\n")
end
# Returns the response's content MIME type, or nil if content type has been set.
@@ -116,11 +118,7 @@ module ActionController # :nodoc:
end
def etag=(etag)
if etag.blank?
headers.delete('ETag')
else
headers['ETag'] = %("#{Digest::MD5.hexdigest(ActiveSupport::Cache.expand_cache_key(etag))}")
end
headers['ETag'] = %("#{Digest::MD5.hexdigest(ActiveSupport::Cache.expand_cache_key(etag))}")
end
def redirect(url, status)
@@ -151,8 +149,8 @@ module ActionController # :nodoc:
if @body.respond_to?(:call)
@writer = lambda { |x| callback.call(x) }
@body.call(self, self)
elsif @body.is_a?(String)
@body.each_line(&callback)
elsif @body.respond_to?(:to_str)
yield @body
else
@body.each(&callback)
end
@@ -166,6 +164,12 @@ module ActionController # :nodoc:
str
end
def flush #:nodoc:
ActiveSupport::Deprecation.warn(
'Calling output.flush is no longer needed for streaming output ' +
'because ActionController::Response automatically handles it', caller)
end
def set_cookie(key, value)
if value.has_key?(:http_only)
ActiveSupport::Deprecation.warn(
@@ -195,7 +199,7 @@ module ActionController # :nodoc:
def nonempty_ok_response?
ok = !status || status.to_s[0..2] == '200'
ok && body.is_a?(String) && !body.empty?
ok && body.is_a?(String) && !body.blank?
end
def set_conditional_cache_control!
@@ -226,7 +230,8 @@ module ActionController # :nodoc:
end
def convert_cookies!
headers['Set-Cookie'] = Array(headers['Set-Cookie']).compact
cookies = Array(headers['Set-Cookie']).compact
headers['Set-Cookie'] = cookies unless cookies.empty?
end
end
end

View File

@@ -1,28 +0,0 @@
module ActionController
class RewindableInput
class RewindableIO < ActiveSupport::BasicObject
def initialize(io)
@io = io
@rewindable = io.is_a?(::StringIO)
end
def method_missing(method, *args, &block)
unless @rewindable
@io = ::StringIO.new(@io.read)
@rewindable = true
end
@io.__send__(method, *args, &block)
end
end
def initialize(app)
@app = app
end
def call(env)
env['rack.input'] = RewindableIO.new(env['rack.input'])
@app.call(env)
end
end
end

View File

@@ -271,6 +271,9 @@ module ActionController
ALLOWED_REQUIREMENTS_FOR_OPTIMISATION = [:controller, :action].to_set
mattr_accessor :generate_best_match
self.generate_best_match = true
# The root paths which may contain controller files
mattr_accessor :controller_paths
self.controller_paths = []
@@ -374,7 +377,7 @@ module ActionController
ActiveSupport::Inflector.module_eval do
# Ensures that routes are reloaded when Rails inflections are updated.
def inflections_with_route_reloading(&block)
returning(inflections_without_route_reloading(&block)) {
(inflections_without_route_reloading(&block)).tap {
ActionController::Routing::Routes.reload! if block_given?
}
end

View File

@@ -65,7 +65,7 @@ module ActionController
# map.connect '/page/:id', :controller => 'pages', :action => 'show', :id => /\d+/
#
def parameter_shell
@parameter_shell ||= returning({}) do |shell|
@parameter_shell ||= {}.tap do |shell|
requirements.each do |key, requirement|
shell[key] = requirement unless requirement.is_a? Regexp
end
@@ -76,7 +76,7 @@ module ActionController
# includes keys that appear inside the path, and keys that have requirements
# placed upon them.
def significant_keys
@significant_keys ||= returning([]) do |sk|
@significant_keys ||= [].tap do |sk|
segments.each { |segment| sk << segment.key if segment.respond_to? :key }
sk.concat requirements.keys
sk.uniq!
@@ -86,7 +86,7 @@ module ActionController
# Return a hash of key/value pairs representing the keys in the route that
# have defaults, or which are specified by non-regexp requirements.
def defaults
@defaults ||= returning({}) do |hash|
@defaults ||= {}.tap do |hash|
segments.each do |segment|
next unless segment.respond_to? :default
hash[segment.key] = segment.default unless segment.default.nil?

View File

@@ -174,6 +174,7 @@ module ActionController
#
named_helper_module_eval <<-end_eval # We use module_eval to avoid leaks
def #{selector}(*args) # def users_url(*args)
args.compact! #
#
#{generate_optimisation_block(route, kind)} # #{generate_optimisation_block(route, kind)}
#
@@ -305,6 +306,7 @@ module ActionController
end
def add_route(path, options = {})
options.each { |k, v| options[k] = v.to_s if [:controller, :action].include?(k) && v.is_a?(Symbol) }
route = builder.build(path, options)
routes << route
route
@@ -404,11 +406,14 @@ module ActionController
end
# don't use the recalled keys when determining which routes to check
routes = routes_by_controller[controller][action][options.reject {|k,v| !v}.keys.sort_by { |x| x.object_id }]
future_routes, deprecated_routes = routes_by_controller[controller][action][options.reject {|k,v| !v}.keys.sort_by { |x| x.object_id }]
routes = Routing.generate_best_match ? deprecated_routes : future_routes
routes.each do |route|
routes.each_with_index do |route, index|
results = route.__send__(method, options, merged, expire_on)
return results if results && (!results.is_a?(Array) || results.first)
if results && (!results.is_a?(Array) || results.first)
return results
end
end
end
@@ -436,7 +441,7 @@ module ActionController
def recognize(request)
params = recognize_path(request.path, extract_request_environment(request))
request.path_parameters = params.with_indifferent_access
"#{params[:controller].camelize}Controller".constantize
"#{params[:controller].to_s.camelize}Controller".constantize
end
def recognize_path(path, environment={})
@@ -447,7 +452,10 @@ module ActionController
@routes_by_controller ||= Hash.new do |controller_hash, controller|
controller_hash[controller] = Hash.new do |action_hash, action|
action_hash[action] = Hash.new do |key_hash, keys|
key_hash[keys] = routes_for_controller_and_action_and_keys(controller, action, keys)
key_hash[keys] = [
routes_for_controller_and_action_and_keys(controller, action, keys),
deprecated_routes_for_controller_and_action_and_keys(controller, action, keys)
]
end
end
end
@@ -459,10 +467,11 @@ module ActionController
merged = options if expire_on[:controller]
action = merged[:action] || 'index'
routes_by_controller[controller][action][merged.keys]
routes_by_controller[controller][action][merged.keys][1]
end
def routes_for_controller_and_action(controller, action)
ActiveSupport::Deprecation.warn "routes_for_controller_and_action() has been deprecated. Please use routes_for()"
selected = routes.select do |route|
route.matches_controller_and_action? controller, action
end
@@ -470,6 +479,12 @@ module ActionController
end
def routes_for_controller_and_action_and_keys(controller, action, keys)
routes.select do |route|
route.matches_controller_and_action? controller, action
end
end
def deprecated_routes_for_controller_and_action_and_keys(controller, action, keys)
selected = routes.select do |route|
route.matches_controller_and_action? controller, action
end

View File

@@ -2,13 +2,42 @@ require 'rack/utils'
module ActionController
module Session
class AbstractStore
class AbstractStore
ENV_SESSION_KEY = 'rack.session'.freeze
ENV_SESSION_OPTIONS_KEY = 'rack.session.options'.freeze
HTTP_COOKIE = 'HTTP_COOKIE'.freeze
SET_COOKIE = 'Set-Cookie'.freeze
# thin wrapper around Hash that allows us to lazily
# load session id into session_options
class OptionsHash < Hash
def initialize(by, env, default_options)
@by = by
@env = env
@session_id_loaded = false
merge!(default_options)
end
def [](key)
if key == :id
load_session_id! unless super(:id) || has_session_id?
end
super(key)
end
private
def has_session_id?
@session_id_loaded
end
def load_session_id!
self[:id] = @by.send(:extract_session_id, @env)
@session_id_loaded = true
end
end
class SessionHash < Hash
def initialize(by, env)
super()
@@ -25,21 +54,42 @@ module ActionController
end
def [](key)
load! unless @loaded
load_for_read!
super
end
def has_key?(key)
load_for_read!
super
end
def []=(key, value)
load! unless @loaded
load_for_write!
super
end
def clear
load_for_write!
super
end
def to_hash
load_for_read!
h = {}.replace(self)
h.delete_if { |k,v| v.nil? }
h
end
def update(hash)
load_for_write!
super
end
def delete(key)
load_for_write!
super
end
def data
ActiveSupport::Deprecation.warn(
"ActionController::Session::AbstractStore::SessionHash#data " +
@@ -48,40 +98,43 @@ module ActionController
end
def inspect
load! unless @loaded
load_for_read!
super
end
def exists?
return @exists if instance_variable_defined?(:@exists)
@exists = @by.send(:exists?, @env)
end
def loaded?
@loaded
end
def destroy
clear
@by.send(:destroy, @env) if @by
@env[ENV_SESSION_OPTIONS_KEY][:id] = nil if @env && @env[ENV_SESSION_OPTIONS_KEY]
@loaded = false
end
private
def loaded?
@loaded
def load_for_read!
load! if !loaded? && exists?
end
def load_for_write!
load! unless loaded?
end
def load!
stale_session_check! do
id, session = @by.send(:load_session, @env)
(@env[ENV_SESSION_OPTIONS_KEY] ||= {})[:id] = id
replace(session)
@loaded = true
end
id, session = @by.send(:load_session, @env)
@env[ENV_SESSION_OPTIONS_KEY][:id] = id
replace(session)
@loaded = true
end
def stale_session_check!
yield
rescue ArgumentError => argument_error
if argument_error.message =~ %r{undefined class/module ([\w:]*\w)}
begin
# Note that the regexp does not allow $1 to end with a ':'
$1.constantize
rescue LoadError, NameError => const_error
raise ActionController::SessionRestoreError, "Session contains objects whose class definition isn\\'t available.\nRemember to require the classes for all objects kept in the session.\n(Original exception: \#{const_error.message} [\#{const_error.class}])\n"
end
retry
else
raise
end
end
end
DEFAULT_OPTIONS = {
@@ -98,12 +151,18 @@ module ActionController
# Process legacy CGI options
options = options.symbolize_keys
if options.has_key?(:session_path)
ActiveSupport::Deprecation.warn "Giving :session_path to SessionStore is deprecated, " <<
"please use :path instead", caller
options[:path] = options.delete(:session_path)
end
if options.has_key?(:session_key)
ActiveSupport::Deprecation.warn "Giving :session_key to SessionStore is deprecated, " <<
"please use :key instead", caller
options[:key] = options.delete(:session_key)
end
if options.has_key?(:session_http_only)
ActiveSupport::Deprecation.warn "Giving :session_http_only to SessionStore is deprecated, " <<
"please use :httponly instead", caller
options[:httponly] = options.delete(:session_http_only)
end
@@ -114,18 +173,18 @@ module ActionController
end
def call(env)
session = SessionHash.new(self, env)
env[ENV_SESSION_KEY] = session
env[ENV_SESSION_OPTIONS_KEY] = @default_options.dup
prepare!(env)
response = @app.call(env)
session_data = env[ENV_SESSION_KEY]
options = env[ENV_SESSION_OPTIONS_KEY]
if !session_data.is_a?(AbstractStore::SessionHash) || session_data.send(:loaded?) || options[:expire_after]
session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.send(:loaded?)
if !session_data.is_a?(AbstractStore::SessionHash) || session_data.loaded? || options[:expire_after]
request = ActionController::Request.new(env)
return response if (options[:secure] && !request.ssl?)
session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.loaded?
sid = options[:id] || generate_sid
@@ -133,21 +192,12 @@ module ActionController
return response
end
cookie = Rack::Utils.escape(@key) + '=' + Rack::Utils.escape(sid)
cookie << "; domain=#{options[:domain]}" if options[:domain]
cookie << "; path=#{options[:path]}" if options[:path]
if options[:expire_after]
expiry = Time.now + options[:expire_after]
cookie << "; expires=#{expiry.httpdate}"
end
cookie << "; Secure" if options[:secure]
cookie << "; HttpOnly" if options[:httponly]
request_cookies = env["rack.request.cookie_hash"]
headers = response[1]
unless headers[SET_COOKIE].blank?
headers[SET_COOKIE] << "\n#{cookie}"
else
headers[SET_COOKIE] = cookie
if (request_cookies.nil? || request_cookies[@key] != sid) || options[:expire_after]
cookie = {:value => sid}
cookie[:expires] = Time.now + options[:expire_after] if options[:expire_after]
Rack::Utils.set_cookie_header!(response[1], @key, cookie.merge(options))
end
end
@@ -155,18 +205,39 @@ module ActionController
end
private
def prepare!(env)
env[ENV_SESSION_KEY] = SessionHash.new(self, env)
env[ENV_SESSION_OPTIONS_KEY] = OptionsHash.new(self, env, @default_options)
end
def generate_sid
ActiveSupport::SecureRandom.hex(16)
end
def load_session(env)
request = Rack::Request.new(env)
sid = request.cookies[@key]
unless @cookie_only
sid ||= request.params[@key]
stale_session_check! do
sid = current_session_id(env)
sid, session = get_session(env, sid)
[sid, session]
end
sid, session = get_session(env, sid)
[sid, session]
end
def extract_session_id(env)
stale_session_check! do
request = Rack::Request.new(env)
sid = request.cookies[@key]
sid ||= request.params[@key] unless @cookie_only
sid
end
end
def current_session_id(env)
env[ENV_SESSION_OPTIONS_KEY][:id]
end
def exists?(env)
current_session_id(env).present?
end
def get_session(env, sid)
@@ -176,6 +247,30 @@ module ActionController
def set_session(env, sid, session_data)
raise '#set_session needs to be implemented.'
end
def destroy(env)
raise '#destroy needs to be implemented.'
end
module SessionUtils
private
def stale_session_check!
yield
rescue ArgumentError => argument_error
if argument_error.message =~ %r{undefined class/module ([\w:]*\w)}
begin
# Note that the regexp does not allow $1 to end with a ':'
$1.constantize
rescue LoadError, NameError => const_error
raise ActionController::SessionRestoreError, "Session contains objects whose class definition isn\\'t available.\nRemember to require the classes for all objects kept in the session.\n(Original exception: \#{const_error.message} [\#{const_error.class}])\n"
end
retry
else
raise
end
end
end
include SessionUtils
end
end
end

View File

@@ -36,6 +36,8 @@ module ActionController
#
# Note that changing digest or secret invalidates all existing sessions!
class CookieStore
include AbstractStore::SessionUtils
# Cookies can typically store 4096 bytes.
MAX = 4096
SECRET_MIN_LENGTH = 30 # characters
@@ -50,7 +52,6 @@ module ActionController
ENV_SESSION_KEY = "rack.session".freeze
ENV_SESSION_OPTIONS_KEY = "rack.session.options".freeze
HTTP_SET_COOKIE = "Set-Cookie".freeze
# Raised when storing more than 4K of session data.
class CookieOverflow < StandardError; end
@@ -59,12 +60,18 @@ module ActionController
# Process legacy CGI options
options = options.symbolize_keys
if options.has_key?(:session_path)
ActiveSupport::Deprecation.warn "Giving :session_path to SessionStore is deprecated, " <<
"please use :path instead", caller
options[:path] = options.delete(:session_path)
end
if options.has_key?(:session_key)
ActiveSupport::Deprecation.warn "Giving :session_key to SessionStore is deprecated, " <<
"please use :key instead", caller
options[:key] = options.delete(:session_key)
end
if options.has_key?(:session_http_only)
ActiveSupport::Deprecation.warn "Giving :session_http_only to SessionStore is deprecated, " <<
"please use :httponly instead", caller
options[:httponly] = options.delete(:session_http_only)
end
@@ -87,73 +94,81 @@ module ActionController
end
def call(env)
env[ENV_SESSION_KEY] = AbstractStore::SessionHash.new(self, env)
env[ENV_SESSION_OPTIONS_KEY] = @default_options.dup
prepare!(env)
status, headers, body = @app.call(env)
session_data = env[ENV_SESSION_KEY]
options = env[ENV_SESSION_OPTIONS_KEY]
request = ActionController::Request.new(env)
if !(options[:secure] && !request.ssl?) && (!session_data.is_a?(AbstractStore::SessionHash) || session_data.loaded? || options[:expire_after])
session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.loaded?
if !session_data.is_a?(AbstractStore::SessionHash) || session_data.send(:loaded?) || options[:expire_after]
session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.send(:loaded?)
persistent_session_id!(session_data)
session_data = marshal(session_data.to_hash)
raise CookieOverflow if session_data.size > MAX
cookie = Hash.new
cookie[:value] = session_data
unless options[:expire_after].nil?
cookie[:expires] = Time.now + options[:expire_after]
end
cookie = build_cookie(@key, cookie.merge(options))
unless headers[HTTP_SET_COOKIE].blank?
headers[HTTP_SET_COOKIE] << "\n#{cookie}"
else
headers[HTTP_SET_COOKIE] = cookie
end
Rack::Utils.set_cookie_header!(headers, @key, cookie.merge(options))
end
[status, headers, body]
end
private
# Should be in Rack::Utils soon
def build_cookie(key, value)
case value
when Hash
domain = "; domain=" + value[:domain] if value[:domain]
path = "; path=" + value[:path] if value[:path]
# According to RFC 2109, we need dashes here.
# N.B.: cgi.rb uses spaces...
expires = "; expires=" + value[:expires].clone.gmtime.
strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires]
secure = "; secure" if value[:secure]
httponly = "; HttpOnly" if value[:httponly]
value = value[:value]
end
value = [value] unless Array === value
cookie = Rack::Utils.escape(key) + "=" +
value.map { |v| Rack::Utils.escape(v) }.join("&") +
"#{domain}#{path}#{expires}#{secure}#{httponly}"
def prepare!(env)
env[ENV_SESSION_KEY] = AbstractStore::SessionHash.new(self, env)
env[ENV_SESSION_OPTIONS_KEY] = AbstractStore::OptionsHash.new(self, env, @default_options)
end
def load_session(env)
request = Rack::Request.new(env)
session_data = request.cookies[@key]
data = unmarshal(session_data) || persistent_session_id!({})
data = unpacked_cookie_data(env)
data = persistent_session_id!(data)
[data[:session_id], data]
end
def extract_session_id(env)
if data = unpacked_cookie_data(env)
persistent_session_id!(data) unless data.empty?
data[:session_id]
else
nil
end
end
def current_session_id(env)
env[ENV_SESSION_OPTIONS_KEY][:id]
end
def exists?(env)
current_session_id(env).present?
end
def unpacked_cookie_data(env)
env["action_dispatch.request.unsigned_session_cookie"] ||= begin
stale_session_check! do
request = Rack::Request.new(env)
session_data = request.cookies[@key]
unmarshal(session_data) || {}
end
end
end
# Marshal a session hash into safe cookie data. Include an integrity hash.
def marshal(session)
@verifier.generate(persistent_session_id!(session))
@verifier.generate(session)
end
# Unmarshal cookie data to a hash and verify its integrity.
def unmarshal(cookie)
persistent_session_id!(@verifier.verify(cookie)) if cookie
@verifier.verify(cookie) if cookie
rescue ActiveSupport::MessageVerifier::InvalidSignature
nil
end
@@ -201,6 +216,10 @@ module ActionController
ActiveSupport::SecureRandom.hex(16)
end
def destroy(env)
# session data is stored on client; nothing to do here
end
def persistent_session_id!(data)
(data ||= {}).merge!(inject_persistent_session_id(data))
end

View File

@@ -1,6 +1,6 @@
begin
require_library_or_gem 'memcache'
require 'thread'
module ActionController
module Session
class MemCacheStore < AbstractStore
@@ -43,6 +43,15 @@ begin
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
return false
end
def destroy(env)
if sid = current_session_id(env)
@pool.delete(sid)
end
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
false
end
end
end
end

View File

@@ -1,3 +1,5 @@
require 'active_support/core_ext/string/bytesize'
module ActionController #:nodoc:
# Methods for sending arbitrary data and for streaming files to the browser,
# instead of rendering.
@@ -137,7 +139,7 @@ module ActionController #:nodoc:
# instead. See ActionController::Base#render for more information.
def send_data(data, options = {}) #:doc:
logger.info "Sending data #{options[:filename]}" if logger
send_file_headers! options.merge(:length => data.size)
send_file_headers! options.merge(:length => data.bytesize)
@performed_render = false
render :status => options[:status], :text => data
end
@@ -161,7 +163,7 @@ module ActionController #:nodoc:
content_type = content_type.to_s.strip # fixes a problem with extra '\r' with some browsers
headers.merge!(
'Content-Length' => options[:length],
'Content-Length' => options[:length].to_s,
'Content-Type' => content_type,
'Content-Disposition' => disposition,
'Content-Transfer-Encoding' => 'binary'

View File

@@ -0,0 +1,29 @@
module ActionController
class StringCoercion
class UglyBody < ActiveSupport::BasicObject
def initialize(body)
@body = body
end
def each
@body.each do |part|
yield part.to_s
end
end
private
def method_missing(*args, &block)
@body.__send__(*args, &block)
end
end
def initialize(app)
@app = app
end
def call(env)
status, headers, body = @app.call(env)
[status, headers, UglyBody.new(body)]
end
end
end

View File

@@ -15,12 +15,12 @@
show = "document.getElementById('#{name.gsub /\s/, '-'}').style.display='block';"
hide = (names - [name]).collect {|hide_name| "document.getElementById('#{hide_name.gsub /\s/, '-'}').style.display='none';"}
%>
<a href="#" onclick="<%= hide %><%= show %>; return false;"><%= name %></a> <%= '|' unless names.last == name %>
<a href="#" onclick="<%= hide.join %><%= show %>; return false;"><%= name %></a> <%= '|' unless names.last == name %>
<% end %>
<% traces.each do |name, trace| %>
<div id="<%= name.gsub /\s/, '-' %>" style="display: <%= name == "Application Trace" ? 'block' : 'none' %>;">
<pre><code><%= trace.join "\n" %></code></pre>
<pre><code><%=h trace.join "\n" %></code></pre>
</div>
<% end %>
</div>

View File

@@ -105,6 +105,11 @@ module ActionController
class TestCase < ActiveSupport::TestCase
include TestProcess
def initialize(*args)
super
@controller = nil
end
module Assertions
%w(response selector tag dom routing model).each do |kind|
include ActionController::Assertions.const_get("#{kind.camelize}Assertions")
@@ -195,7 +200,7 @@ module ActionController
@controller.send(:initialize_current_url)
end
end
# Cause the action to be rescued according to the regular rules for rescue_action when the visitor is not local
def rescue_action_in_public!
@request.remote_addr = '208.77.188.166' # example.com

View File

@@ -1,3 +1,4 @@
require 'rack/session/abstract/id'
module ActionController #:nodoc:
class TestRequest < Request #:nodoc:
attr_accessor :cookies, :session_options
@@ -13,6 +14,8 @@ module ActionController #:nodoc:
@query_parameters = {}
@session = TestSession.new
default_rack_options = Rack::Session::Abstract::ID::DEFAULT_OPTIONS
@session_options ||= {:id => generate_sid(default_rack_options[:sidbits])}.merge(default_rack_options)
initialize_default_values
initialize_containers
@@ -88,7 +91,7 @@ module ActionController #:nodoc:
@path || super()
end
def assign_parameters(controller_path, action, parameters)
def assign_parameters(controller_path, action, parameters = {})
parameters = parameters.symbolize_keys.merge(:controller => controller_path, :action => action)
extra_keys = ActionController::Routing::Routes.extra_keys(parameters)
non_path_parameters = get? ? query_parameters : request_parameters
@@ -110,6 +113,7 @@ module ActionController #:nodoc:
end
def recycle!
@env["action_controller.request.request_parameters"] = {}
self.query_parameters = {}
self.path_parameters = {}
@headers, @request_method, @accepts, @content_type = nil, nil, nil, nil
@@ -120,6 +124,10 @@ module ActionController #:nodoc:
end
private
def generate_sid(sidbits)
"%0#{sidbits / 4}x" % rand(2**sidbits - 1)
end
def initialize_containers
@cookies = {}
end
@@ -250,7 +258,7 @@ module ActionController #:nodoc:
def cookies
cookies = {}
Array(headers['Set-Cookie']).each do |cookie|
key, value = cookie.split(";").first.split("=")
key, value = cookie.split(";").first.split("=").map {|val| Rack::Utils.unescape(val)}
cookies[key] = value
end
cookies
@@ -442,7 +450,7 @@ module ActionController #:nodoc:
def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
@request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
@request.env['HTTP_ACCEPT'] = [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
returning __send__(request_method, action, parameters, session, flash) do
__send__(request_method, action, parameters, session, flash).tap do
@request.env.delete 'HTTP_X_REQUESTED_WITH'
@request.env.delete 'HTTP_ACCEPT'
end

View File

@@ -1,12 +1,12 @@
module ActionController
module Translation
def translate(*args)
I18n.translate *args
I18n.translate(*args)
end
alias :t :translate
def localize(*args)
I18n.localize *args
I18n.localize(*args)
end
alias :l :localize
end

View File

@@ -3,14 +3,14 @@ module ActionController
def self.included(base)
base.class_eval do
attr_accessor :original_path, :content_type
alias_method :local_path, :path
alias_method :local_path, :path if method_defined?(:path)
end
end
def self.extended(object)
object.class_eval do
attr_accessor :original_path, :content_type
alias_method :local_path, :path
alias_method :local_path, :path if method_defined?(:path)
end
end

View File

@@ -1,3 +1,5 @@
require 'uri'
module ActionController
# In <b>routes.rb</b> one defines URL-to-controller mappings, but the reverse
# is also possible: an URL can be generated from one of your routing definitions.
@@ -92,6 +94,14 @@ module ActionController
# end
# end
module UrlWriter
RESERVED_PCHAR = ':@&=+$,;%'
SAFE_PCHAR = "#{URI::REGEXP::PATTERN::UNRESERVED}#{RESERVED_PCHAR}"
if RUBY_VERSION >= '1.9'
UNSAFE_PCHAR = Regexp.new("[^#{SAFE_PCHAR}]", false).freeze
else
UNSAFE_PCHAR = Regexp.new("[^#{SAFE_PCHAR}]", false, 'N').freeze
end
def self.included(base) #:nodoc:
ActionController::Routing::Routes.install_helpers(base)
base.mattr_accessor :default_url_options
@@ -142,7 +152,7 @@ module ActionController
end
trailing_slash = options.delete(:trailing_slash) if options.key?(:trailing_slash)
url << ActionController::Base.relative_url_root.to_s unless options[:skip_relative_url_root]
anchor = "##{CGI.escape options.delete(:anchor).to_param.to_s}" if options[:anchor]
anchor = "##{URI.escape(options.delete(:anchor).to_param.to_s, UNSAFE_PCHAR)}" if options[:anchor]
generated = Routing::Routes.generate(options, {})
url << (trailing_slash ? generated.sub(/\?|\z/) { "/" + $& } : generated)
url << anchor if anchor
@@ -159,6 +169,9 @@ module ActionController
end
def rewrite(options = {})
if options.include?(:overwrite_params)
ActiveSupport::Deprecation.warn 'The :overwrite_params option is deprecated. Specify all the necessary parameters instead', caller
end
rewrite_url(options)
end
@@ -184,7 +197,7 @@ module ActionController
path = rewrite_path(options)
rewritten_url << ActionController::Base.relative_url_root.to_s unless options[:skip_relative_url_root]
rewritten_url << (options[:trailing_slash] ? path.sub(/\?|\z/) { "/" + $& } : path)
rewritten_url << "##{options[:anchor]}" if options[:anchor]
rewritten_url << "##{CGI.escape(options[:anchor].to_param.to_s)}" if options[:anchor]
rewritten_url
end
@@ -194,7 +207,7 @@ module ActionController
options = options.symbolize_keys
options.update(options[:params].symbolize_keys) if options[:params]
if (overwrite = options.delete(:overwrite_params))
if overwrite = options.delete(:overwrite_params)
options.update(@parameters.symbolize_keys)
options.update(overwrite.symbolize_keys)
end

View File

@@ -162,7 +162,7 @@ module HTML #:nodoc:
end
closing = ( scanner.scan(/\//) ? :close : nil )
return Text.new(parent, line, pos, content) unless name = scanner.scan(/[\w:-]+/)
return Text.new(parent, line, pos, content) unless name = scanner.scan(/[^\s!>\/]+/)
name.downcase!
unless closing

View File

@@ -1,89 +0,0 @@
# Copyright (C) 2007, 2008, 2009 Christian Neukirchen <purl.org/net/chneukirchen>
#
# Rack is freely distributable under the terms of an MIT-style license.
# See COPYING or http://www.opensource.org/licenses/mit-license.php.
$:.unshift(File.expand_path(File.dirname(__FILE__)))
# The Rack main module, serving as a namespace for all core Rack
# modules and classes.
#
# All modules meant for use in your application are <tt>autoload</tt>ed here,
# so it should be enough just to <tt>require rack.rb</tt> in your code.
module Rack
# The Rack protocol version number implemented.
VERSION = [0,1]
# Return the Rack protocol version as a dotted string.
def self.version
VERSION.join(".")
end
# Return the Rack release as a dotted string.
def self.release
"1.0 bundled"
end
autoload :Builder, "rack/builder"
autoload :Cascade, "rack/cascade"
autoload :Chunked, "rack/chunked"
autoload :CommonLogger, "rack/commonlogger"
autoload :ConditionalGet, "rack/conditionalget"
autoload :ContentLength, "rack/content_length"
autoload :ContentType, "rack/content_type"
autoload :File, "rack/file"
autoload :Deflater, "rack/deflater"
autoload :Directory, "rack/directory"
autoload :ForwardRequest, "rack/recursive"
autoload :Handler, "rack/handler"
autoload :Head, "rack/head"
autoload :Lint, "rack/lint"
autoload :Lock, "rack/lock"
autoload :MethodOverride, "rack/methodoverride"
autoload :Mime, "rack/mime"
autoload :Recursive, "rack/recursive"
autoload :Reloader, "rack/reloader"
autoload :ShowExceptions, "rack/showexceptions"
autoload :ShowStatus, "rack/showstatus"
autoload :Static, "rack/static"
autoload :URLMap, "rack/urlmap"
autoload :Utils, "rack/utils"
autoload :MockRequest, "rack/mock"
autoload :MockResponse, "rack/mock"
autoload :Request, "rack/request"
autoload :Response, "rack/response"
module Auth
autoload :Basic, "rack/auth/basic"
autoload :AbstractRequest, "rack/auth/abstract/request"
autoload :AbstractHandler, "rack/auth/abstract/handler"
autoload :OpenID, "rack/auth/openid"
module Digest
autoload :MD5, "rack/auth/digest/md5"
autoload :Nonce, "rack/auth/digest/nonce"
autoload :Params, "rack/auth/digest/params"
autoload :Request, "rack/auth/digest/request"
end
end
module Session
autoload :Cookie, "rack/session/cookie"
autoload :Pool, "rack/session/pool"
autoload :Memcache, "rack/session/memcache"
end
# *Adapters* connect Rack with third party web frameworks.
#
# Rack includes an adapter for Camping, see README for other
# frameworks supporting Rack in their code bases.
#
# Refer to the submodules for framework-specific calling details.
module Adapter
autoload :Camping, "rack/adapter/camping"
end
end

View File

@@ -1,22 +0,0 @@
module Rack
module Adapter
class Camping
def initialize(app)
@app = app
end
def call(env)
env["PATH_INFO"] ||= ""
env["SCRIPT_NAME"] ||= ""
controller = @app.run(env['rack.input'], env)
h = controller.headers
h.each_pair do |k,v|
if v.kind_of? URI
h[k] = v.to_s
end
end
[controller.status, controller.headers, [controller.body.to_s]]
end
end
end
end

View File

@@ -1,37 +0,0 @@
module Rack
module Auth
# Rack::Auth::AbstractHandler implements common authentication functionality.
#
# +realm+ should be set for all handlers.
class AbstractHandler
attr_accessor :realm
def initialize(app, realm=nil, &authenticator)
@app, @realm, @authenticator = app, realm, authenticator
end
private
def unauthorized(www_authenticate = challenge)
return [ 401,
{ 'Content-Type' => 'text/plain',
'Content-Length' => '0',
'WWW-Authenticate' => www_authenticate.to_s },
[]
]
end
def bad_request
return [ 400,
{ 'Content-Type' => 'text/plain',
'Content-Length' => '0' },
[]
]
end
end
end
end

View File

@@ -1,37 +0,0 @@
module Rack
module Auth
class AbstractRequest
def initialize(env)
@env = env
end
def provided?
!authorization_key.nil?
end
def parts
@parts ||= @env[authorization_key].split(' ', 2)
end
def scheme
@scheme ||= parts.first.downcase.to_sym
end
def params
@params ||= parts.last
end
private
AUTHORIZATION_KEYS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION']
def authorization_key
@authorization_key ||= AUTHORIZATION_KEYS.detect { |key| @env.has_key?(key) }
end
end
end
end

View File

@@ -1,58 +0,0 @@
require 'rack/auth/abstract/handler'
require 'rack/auth/abstract/request'
module Rack
module Auth
# Rack::Auth::Basic implements HTTP Basic Authentication, as per RFC 2617.
#
# Initialize with the Rack application that you want protecting,
# and a block that checks if a username and password pair are valid.
#
# See also: <tt>example/protectedlobster.rb</tt>
class Basic < AbstractHandler
def call(env)
auth = Basic::Request.new(env)
return unauthorized unless auth.provided?
return bad_request unless auth.basic?
if valid?(auth)
env['REMOTE_USER'] = auth.username
return @app.call(env)
end
unauthorized
end
private
def challenge
'Basic realm="%s"' % realm
end
def valid?(auth)
@authenticator.call(*auth.credentials)
end
class Request < Auth::AbstractRequest
def basic?
:basic == scheme
end
def credentials
@credentials ||= params.unpack("m*").first.split(/:/, 2)
end
def username
credentials.first
end
end
end
end
end

View File

@@ -1,124 +0,0 @@
require 'rack/auth/abstract/handler'
require 'rack/auth/digest/request'
require 'rack/auth/digest/params'
require 'rack/auth/digest/nonce'
require 'digest/md5'
module Rack
module Auth
module Digest
# Rack::Auth::Digest::MD5 implements the MD5 algorithm version of
# HTTP Digest Authentication, as per RFC 2617.
#
# Initialize with the [Rack] application that you want protecting,
# and a block that looks up a plaintext password for a given username.
#
# +opaque+ needs to be set to a constant base64/hexadecimal string.
#
class MD5 < AbstractHandler
attr_accessor :opaque
attr_writer :passwords_hashed
def initialize(*args)
super
@passwords_hashed = nil
end
def passwords_hashed?
!!@passwords_hashed
end
def call(env)
auth = Request.new(env)
unless auth.provided?
return unauthorized
end
if !auth.digest? || !auth.correct_uri? || !valid_qop?(auth)
return bad_request
end
if valid?(auth)
if auth.nonce.stale?
return unauthorized(challenge(:stale => true))
else
env['REMOTE_USER'] = auth.username
return @app.call(env)
end
end
unauthorized
end
private
QOP = 'auth'.freeze
def params(hash = {})
Params.new do |params|
params['realm'] = realm
params['nonce'] = Nonce.new.to_s
params['opaque'] = H(opaque)
params['qop'] = QOP
hash.each { |k, v| params[k] = v }
end
end
def challenge(hash = {})
"Digest #{params(hash)}"
end
def valid?(auth)
valid_opaque?(auth) && valid_nonce?(auth) && valid_digest?(auth)
end
def valid_qop?(auth)
QOP == auth.qop
end
def valid_opaque?(auth)
H(opaque) == auth.opaque
end
def valid_nonce?(auth)
auth.nonce.valid?
end
def valid_digest?(auth)
digest(auth, @authenticator.call(auth.username)) == auth.response
end
def md5(data)
::Digest::MD5.hexdigest(data)
end
alias :H :md5
def KD(secret, data)
H([secret, data] * ':')
end
def A1(auth, password)
[ auth.username, auth.realm, password ] * ':'
end
def A2(auth)
[ auth.method, auth.uri ] * ':'
end
def digest(auth, password)
password_hash = passwords_hashed? ? password : H(A1(auth, password))
KD(password_hash, [ auth.nonce, auth.nc, auth.cnonce, QOP, H(A2(auth)) ] * ':')
end
end
end
end
end

View File

@@ -1,51 +0,0 @@
require 'digest/md5'
module Rack
module Auth
module Digest
# Rack::Auth::Digest::Nonce is the default nonce generator for the
# Rack::Auth::Digest::MD5 authentication handler.
#
# +private_key+ needs to set to a constant string.
#
# +time_limit+ can be optionally set to an integer (number of seconds),
# to limit the validity of the generated nonces.
class Nonce
class << self
attr_accessor :private_key, :time_limit
end
def self.parse(string)
new(*string.unpack("m*").first.split(' ', 2))
end
def initialize(timestamp = Time.now, given_digest = nil)
@timestamp, @given_digest = timestamp.to_i, given_digest
end
def to_s
[([ @timestamp, digest ] * ' ')].pack("m*").strip
end
def digest
::Digest::MD5.hexdigest([ @timestamp, self.class.private_key ] * ':')
end
def valid?
digest == @given_digest
end
def stale?
!self.class.time_limit.nil? && (@timestamp - Time.now.to_i) < self.class.time_limit
end
def fresh?
!stale?
end
end
end
end
end

View File

@@ -1,55 +0,0 @@
module Rack
module Auth
module Digest
class Params < Hash
def self.parse(str)
split_header_value(str).inject(new) do |header, param|
k, v = param.split('=', 2)
header[k] = dequote(v)
header
end
end
def self.dequote(str) # From WEBrick::HTTPUtils
ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup
ret.gsub!(/\\(.)/, "\\1")
ret
end
def self.split_header_value(str)
str.scan( /(\w+\=(?:"[^\"]+"|[^,]+))/n ).collect{ |v| v[0] }
end
def initialize
super
yield self if block_given?
end
def [](k)
super k.to_s
end
def []=(k, v)
super k.to_s, v.to_s
end
UNQUOTED = ['qop', 'nc', 'stale']
def to_s
inject([]) do |parts, (k, v)|
parts << "#{k}=" + (UNQUOTED.include?(k) ? v.to_s : quote(v))
parts
end.join(', ')
end
def quote(str) # From WEBrick::HTTPUtils
'"' << str.gsub(/[\\\"]/o, "\\\1") << '"'
end
end
end
end
end

View File

@@ -1,40 +0,0 @@
require 'rack/auth/abstract/request'
require 'rack/auth/digest/params'
require 'rack/auth/digest/nonce'
module Rack
module Auth
module Digest
class Request < Auth::AbstractRequest
def method
@env['rack.methodoverride.original_method'] || @env['REQUEST_METHOD']
end
def digest?
:digest == scheme
end
def correct_uri?
(@env['SCRIPT_NAME'].to_s + @env['PATH_INFO'].to_s) == uri
end
def nonce
@nonce ||= Nonce.parse(params['nonce'])
end
def params
@params ||= Params.parse(parts.last)
end
def method_missing(sym)
if params.has_key? key = sym.to_s
return params[key]
end
super
end
end
end
end
end

View File

@@ -1,480 +0,0 @@
# AUTHOR: blink <blinketje@gmail.com>; blink#ruby-lang@irc.freenode.net
gem 'ruby-openid', '~> 2' if defined? Gem
require 'rack/request'
require 'rack/utils'
require 'rack/auth/abstract/handler'
require 'uri'
require 'openid' #gem
require 'openid/extension' #gem
require 'openid/store/memory' #gem
module Rack
class Request
def openid_request
@env['rack.auth.openid.request']
end
def openid_response
@env['rack.auth.openid.response']
end
end
module Auth
# Rack::Auth::OpenID provides a simple method for setting up an OpenID
# Consumer. It requires the ruby-openid library from janrain to operate,
# as well as a rack method of session management.
#
# The ruby-openid home page is at http://openidenabled.com/ruby-openid/.
#
# The OpenID specifications can be found at
# http://openid.net/specs/openid-authentication-1_1.html
# and
# http://openid.net/specs/openid-authentication-2_0.html. Documentation
# for published OpenID extensions and related topics can be found at
# http://openid.net/developers/specs/.
#
# It is recommended to read through the OpenID spec, as well as
# ruby-openid's documentation, to understand what exactly goes on. However
# a setup as simple as the presented examples is enough to provide
# Consumer functionality.
#
# This library strongly intends to utilize the OpenID 2.0 features of the
# ruby-openid library, which provides OpenID 1.0 compatiblity.
#
# NOTE: Due to the amount of data that this library stores in the
# session, Rack::Session::Cookie may fault.
class OpenID
class NoSession < RuntimeError; end
class BadExtension < RuntimeError; end
# Required for ruby-openid
ValidStatus = [:success, :setup_needed, :cancel, :failure]
# = Arguments
#
# The first argument is the realm, identifying the site they are trusting
# with their identity. This is required, also treated as the trust_root
# in OpenID 1.x exchanges.
#
# The optional second argument is a hash of options.
#
# == Options
#
# <tt>:return_to</tt> defines the url to return to after the client
# authenticates with the openid service provider. This url should point
# to where Rack::Auth::OpenID is mounted. If <tt>:return_to</tt> is not
# provided, return_to will be the current url which allows flexibility
# with caveats.
#
# <tt>:session_key</tt> defines the key to the session hash in the env.
# It defaults to 'rack.session'.
#
# <tt>:openid_param</tt> defines at what key in the request parameters to
# find the identifier to resolve. As per the 2.0 spec, the default is
# 'openid_identifier'.
#
# <tt>:store</tt> defined what OpenID Store to use for persistant
# information. By default a Store::Memory will be used.
#
# <tt>:immediate</tt> as true will make initial requests to be of an
# immediate type. This is false by default. See OpenID specification
# documentation.
#
# <tt>:extensions</tt> should be a hash of openid extension
# implementations. The key should be the extension main module, the value
# should be an array of arguments for extension::Request.new.
# The hash is iterated over and passed to #add_extension for processing.
# Please see #add_extension for further documentation.
#
# == Examples
#
# simple_oid = OpenID.new('http://mysite.com/')
#
# return_oid = OpenID.new('http://mysite.com/', {
# :return_to => 'http://mysite.com/openid'
# })
#
# complex_oid = OpenID.new('http://mysite.com/',
# :immediate => true,
# :extensions => {
# ::OpenID::SReg => [['email'],['nickname']]
# }
# )
#
# = Advanced
#
# Most of the functionality of this library is encapsulated such that
# expansion and overriding functions isn't difficult nor tricky.
# Alternately, to avoid opening up singleton objects or subclassing, a
# wrapper rack middleware can be composed to act upon Auth::OpenID's
# responses. See #check and #finish for locations of pertinent data.
#
# == Responses
#
# To change the responses that Auth::OpenID returns, override the methods
# #redirect, #bad_request, #unauthorized, #access_denied, and
# #foreign_server_failure.
#
# Additionally #confirm_post_params is used when the URI would exceed
# length limits on a GET request when doing the initial verification
# request.
#
# == Processing
#
# To change methods of processing completed transactions, override the
# methods #success, #setup_needed, #cancel, and #failure. Please ensure
# the returned object is a rack compatible response.
#
# The first argument is an OpenID::Response, the second is a
# Rack::Request of the current request, the last is the hash used in
# ruby-openid handling, which can be found manually at
# env['rack.session'][:openid].
#
# This is useful if you wanted to expand the processing done, such as
# setting up user accounts.
#
# oid_app = Rack::Auth::OpenID.new realm, :return_to => return_to
# def oid_app.success oid, request, session
# user = Models::User[oid.identity_url]
# user ||= Models::User.create_from_openid oid
# request['rack.session'][:user] = user.id
# redirect MyApp.site_home
# end
#
# site_map['/openid'] = oid_app
# map = Rack::URLMap.new site_map
# ...
def initialize(realm, options={})
realm = URI(realm)
raise ArgumentError, "Invalid realm: #{realm}" \
unless realm.absolute? \
and realm.fragment.nil? \
and realm.scheme =~ /^https?$/ \
and realm.host =~ /^(\*\.)?#{URI::REGEXP::PATTERN::URIC_NO_SLASH}+/
realm.path = '/' if realm.path.empty?
@realm = realm.to_s
if ruri = options[:return_to]
ruri = URI(ruri)
raise ArgumentError, "Invalid return_to: #{ruri}" \
unless ruri.absolute? \
and ruri.scheme =~ /^https?$/ \
and ruri.fragment.nil?
raise ArgumentError, "return_to #{ruri} not within realm #{realm}" \
unless self.within_realm?(ruri)
@return_to = ruri.to_s
end
@session_key = options[:session_key] || 'rack.session'
@openid_param = options[:openid_param] || 'openid_identifier'
@store = options[:store] || ::OpenID::Store::Memory.new
@immediate = !!options[:immediate]
@extensions = {}
if extensions = options.delete(:extensions)
extensions.each do |ext, args|
add_extension ext, *args
end
end
# Undocumented, semi-experimental
@anonymous = !!options[:anonymous]
end
attr_reader :realm, :return_to, :session_key, :openid_param, :store,
:immediate, :extensions
# Sets up and uses session data at <tt>:openid</tt> within the session.
# Errors in this setup will raise a NoSession exception.
#
# If the parameter 'openid.mode' is set, which implies a followup from
# the openid server, processing is passed to #finish and the result is
# returned. However, if there is no appropriate openid information in the
# session, a 400 error is returned.
#
# If the parameter specified by <tt>options[:openid_param]</tt> is
# present, processing is passed to #check and the result is returned.
#
# If neither of these conditions are met, #unauthorized is called.
def call(env)
env['rack.auth.openid'] = self
env_session = env[@session_key]
unless env_session and env_session.is_a?(Hash)
raise NoSession, 'No compatible session'
end
# let us work in our own namespace...
session = (env_session[:openid] ||= {})
unless session and session.is_a?(Hash)
raise NoSession, 'Incompatible openid session'
end
request = Rack::Request.new(env)
consumer = ::OpenID::Consumer.new(session, @store)
if mode = request.GET['openid.mode']
if session.key?(:openid_param)
finish(consumer, session, request)
else
bad_request
end
elsif request.GET[@openid_param]
check(consumer, session, request)
else
unauthorized
end
end
# As the first part of OpenID consumer action, #check retrieves the data
# required for completion.
#
# If all parameters fit within the max length of a URI, a 303 redirect
# will be returned. Otherwise #confirm_post_params will be called.
#
# Any messages from OpenID's request are logged to env['rack.errors']
#
# <tt>env['rack.auth.openid.request']</tt> is the openid checkid request
# instance.
#
# <tt>session[:openid_param]</tt> is set to the openid identifier
# provided by the user.
#
# <tt>session[:return_to]</tt> is set to the return_to uri given to the
# identity provider.
def check(consumer, session, req)
oid = consumer.begin(req.GET[@openid_param], @anonymous)
req.env['rack.auth.openid.request'] = oid
req.env['rack.errors'].puts(oid.message)
p oid if $DEBUG
## Extension support
extensions.each do |ext,args|
oid.add_extension(ext::Request.new(*args))
end
session[:openid_param] = req.GET[openid_param]
return_to_uri = return_to ? return_to : req.url
session[:return_to] = return_to_uri
immediate = session.key?(:setup_needed) ? false : immediate
if oid.send_redirect?(realm, return_to_uri, immediate)
uri = oid.redirect_url(realm, return_to_uri, immediate)
redirect(uri)
else
confirm_post_params(oid, realm, return_to_uri, immediate)
end
rescue ::OpenID::DiscoveryFailure => e
# thrown from inside OpenID::Consumer#begin by yadis stuff
req.env['rack.errors'].puts([e.message, *e.backtrace]*"\n")
return foreign_server_failure
end
# This is the final portion of authentication.
# If successful, a redirect to the realm is be returned.
# Data gathered from extensions are stored in session[:openid] with the
# extension's namespace uri as the key.
#
# Any messages from OpenID's response are logged to env['rack.errors']
#
# <tt>env['rack.auth.openid.response']</tt> will contain the openid
# response.
def finish(consumer, session, req)
oid = consumer.complete(req.GET, req.url)
req.env['rack.auth.openid.response'] = oid
req.env['rack.errors'].puts(oid.message)
p oid if $DEBUG
raise unless ValidStatus.include?(oid.status)
__send__(oid.status, oid, req, session)
end
# The first argument should be the main extension module.
# The extension module should contain the constants:
# * class Request, should have OpenID::Extension as an ancestor
# * class Response, should have OpenID::Extension as an ancestor
# * string NS_URI, which defining the namespace of the extension
#
# All trailing arguments will be passed to extension::Request.new in
# #check.
# The openid response will be passed to
# extension::Response#from_success_response, #get_extension_args will be
# called on the result to attain the gathered data.
#
# This method returns the key at which the response data will be found in
# the session, which is the namespace uri by default.
def add_extension(ext, *args)
raise BadExtension unless valid_extension?(ext)
extensions[ext] = args
return ext::NS_URI
end
# Checks the validitity, in the context of usage, of a submitted
# extension.
def valid_extension?(ext)
if not %w[NS_URI Request Response].all?{|c| ext.const_defined?(c) }
raise ArgumentError, 'Extension is missing constants.'
elsif not ext::Response.respond_to?(:from_success_response)
raise ArgumentError, 'Response is missing required method.'
end
return true
rescue
return false
end
# Checks the provided uri to ensure it'd be considered within the realm.
# is currently not compatible with wildcard realms.
def within_realm? uri
uri = URI.parse(uri.to_s)
realm = URI.parse(self.realm)
return false unless uri.absolute?
return false unless uri.path[0, realm.path.size] == realm.path
return false unless uri.host == realm.host or realm.host[/^\*\./]
# for wildcard support, is awkward with URI limitations
realm_match = Regexp.escape(realm.host).
sub(/^\*\./,"^#{URI::REGEXP::PATTERN::URIC_NO_SLASH}+.")+'$'
return false unless uri.host.match(realm_match)
return true
end
alias_method :include?, :within_realm?
protected
### These methods define some of the boilerplate responses.
# Returns an html form page for posting to an Identity Provider if the
# GET request would exceed the upper URI length limit.
def confirm_post_params(oid, realm, return_to, immediate)
Rack::Response.new.finish do |r|
r.write '<html><head><title>Confirm...</title></head><body>'
r.write oid.form_markup(realm, return_to, immediate)
r.write '</body></html>'
end
end
# Returns a 303 redirect with the destination of that provided by the
# argument.
def redirect(uri)
[ 303, {'Content-Length'=>'0', 'Content-Type'=>'text/plain',
'Location' => uri},
[] ]
end
# Returns an empty 400 response.
def bad_request
[ 400, {'Content-Type'=>'text/plain', 'Content-Length'=>'0'},
[''] ]
end
# Returns a basic unauthorized 401 response.
def unauthorized
[ 401, {'Content-Type' => 'text/plain', 'Content-Length' => '13'},
['Unauthorized.'] ]
end
# Returns a basic access denied 403 response.
def access_denied
[ 403, {'Content-Type' => 'text/plain', 'Content-Length' => '14'},
['Access denied.'] ]
end
# Returns a 503 response to be used if communication with the remote
# OpenID server fails.
def foreign_server_failure
[ 503, {'Content-Type'=>'text/plain', 'Content-Length' => '23'},
['Foreign server failure.'] ]
end
private
### These methods are called after a transaction is completed, depending
# on its outcome. These should all return a rack compatible response.
# You'd want to override these to provide additional functionality.
# Called to complete processing on a successful transaction.
# Within the openid session, :openid_identity and :openid_identifier are
# set to the user friendly and the standard representation of the
# validated identity. All other data in the openid session is cleared.
def success(oid, request, session)
session.clear
session[:openid_identity] = oid.display_identifier
session[:openid_identifier] = oid.identity_url
extensions.keys.each do |ext|
label = ext.name[/[^:]+$/].downcase
response = ext::Response.from_success_response(oid)
session[label] = response.data
end
redirect(realm)
end
# Called if the Identity Provider indicates further setup by the user is
# required.
# The identifier is retrived from the openid session at :openid_param.
# And :setup_needed is set to true to prevent looping.
def setup_needed(oid, request, session)
identifier = session[:openid_param]
session[:setup_needed] = true
redirect req.script_name + '?' + openid_param + '=' + identifier
end
# Called if the user indicates they wish to cancel identification.
# Data within openid session is cleared.
def cancel(oid, request, session)
session.clear
access_denied
end
# Called if the Identity Provider indicates the user is unable to confirm
# their identity. Data within the openid session is left alone, in case
# of swarm auth attacks.
def failure(oid, request, session)
unauthorized
end
end
# A class developed out of the request to use OpenID as an authentication
# middleware. The request will be sent to the OpenID instance unless the
# block evaluates to true. For example in rackup, you can use it as such:
#
# use Rack::Session::Pool
# use Rack::Auth::OpenIDAuth, realm, openid_options do |env|
# env['rack.session'][:authkey] == a_string
# end
# run RackApp
#
# Or simply:
#
# app = Rack::Auth::OpenIDAuth.new app, realm, openid_options, &auth
class OpenIDAuth < Rack::Auth::AbstractHandler
attr_reader :oid
def initialize(app, realm, options={}, &auth)
@oid = OpenID.new(realm, options)
super(app, &auth)
end
def call(env)
to = auth.call(env) ? @app : @oid
to.call env
end
end
end
end

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