aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwycats <wycats@gmail.com>2010-06-02 15:53:10 +0200
committerwycats <wycats@gmail.com>2010-06-02 15:53:10 +0200
commit26c5680bd01bd0e525eccc5d47a2e7126d9383f7 (patch)
treec655c56511ef89ba55c554a0aa7d82b1cd062f78
parentb870daba5ff71973b237616fb95f90bb321ae7fb (diff)
parent4b91daff13be43ed913a97ffc8ad1b3f77fd9690 (diff)
downloadrails-26c5680bd01bd0e525eccc5d47a2e7126d9383f7.tar.gz
rails-26c5680bd01bd0e525eccc5d47a2e7126d9383f7.tar.bz2
rails-26c5680bd01bd0e525eccc5d47a2e7126d9383f7.zip
Merge branch 'master' of github.com:rails/rails
-rw-r--r--Gemfile7
-rw-r--r--actionmailer/actionmailer.gemspec1
-rw-r--r--actionmailer/lib/action_mailer.rb6
-rw-r--r--actionmailer/lib/action_mailer/mail_helper.rb7
-rw-r--r--actionpack/actionpack.gemspec5
-rw-r--r--actionpack/lib/action_controller/metal.rb48
-rw-r--r--actionpack/lib/action_dispatch/middleware/stack.rb8
-rw-r--r--actionpack/lib/action_view/base.rb4
-rw-r--r--actionpack/lib/action_view/helpers/active_model_helper.rb7
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb32
-rw-r--r--actionpack/test/controller/new_base/middleware_test.rb33
-rw-r--r--activemodel/activemodel.gemspec2
-rw-r--r--activemodel/lib/active_model/errors.rb12
-rw-r--r--activerecord/activerecord.gemspec1
-rw-r--r--activerecord/lib/active_record/railties/databases.rake1
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb15
-rw-r--r--activerecord/test/cases/relations_test.rb5
-rw-r--r--activesupport/CHANGELOG2
-rw-r--r--activesupport/activesupport.gemspec5
-rw-r--r--activesupport/lib/active_support/builder.rb6
-rw-r--r--activesupport/lib/active_support/cache/mem_cache_store.rb7
-rw-r--r--activesupport/lib/active_support/core_ext/array/conversions.rb14
-rw-r--r--activesupport/lib/active_support/core_ext/hash/conversions.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/string/filters.rb29
-rw-r--r--activesupport/lib/active_support/core_ext/string/interpolation.rb1
-rw-r--r--activesupport/lib/active_support/i18n.rb9
-rw-r--r--activesupport/lib/active_support/values/time_zone.rb8
-rw-r--r--activesupport/test/core_ext/string_ext_test.rb29
-rw-r--r--railties/guides/source/action_view_overview.textile2
-rw-r--r--railties/guides/source/active_support_core_extensions.textile33
-rw-r--r--railties/guides/source/activerecord_validations_callbacks.textile14
-rw-r--r--railties/guides/source/generators.textile12
-rw-r--r--railties/guides/source/getting_started.textile2
-rw-r--r--railties/guides/source/nested_model_forms.textile4
-rw-r--r--railties/lib/rails/application.rb11
-rw-r--r--railties/lib/rails/application/finisher.rb2
-rw-r--r--railties/lib/rails/commands/destroy.rb1
-rwxr-xr-xrailties/lib/rails/commands/generate.rb1
-rw-r--r--railties/lib/rails/generators.rb8
-rw-r--r--railties/test/application/initializers/load_path_test.rb17
-rw-r--r--railties/test/generators/generators_test_helper.rb7
41 files changed, 316 insertions, 104 deletions
diff --git a/Gemfile b/Gemfile
index 3b347ea9ef..d57afc8630 100644
--- a/Gemfile
+++ b/Gemfile
@@ -21,6 +21,12 @@ elsif RUBY_ENGINE == "jruby"
gem "jruby-openssl"
end
+# AS
+gem "memcache-client", ">= 1.7.5"
+
+# AM
+gem "text-format", "~> 1.0.0"
+
# AR
if mri || RUBY_ENGINE == "rbx"
gem "sqlite3-ruby", "= 1.3.0.beta.2", :require => 'sqlite3'
@@ -39,7 +45,6 @@ elsif RUBY_ENGINE == "jruby"
end
# AP
-gem "rack-test", "0.5.3", :require => 'rack/test'
gem "RedCloth", ">= 4.2.2"
group :documentation do
diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec
index 280771e4db..4706b63b79 100644
--- a/actionmailer/actionmailer.gemspec
+++ b/actionmailer/actionmailer.gemspec
@@ -21,5 +21,4 @@ Gem::Specification.new do |s|
s.add_dependency('actionpack', version)
s.add_dependency('mail', '~> 2.2.1')
- s.add_dependency('text-format', '~> 1.0.0')
end
diff --git a/actionmailer/lib/action_mailer.rb b/actionmailer/lib/action_mailer.rb
index 70cc312634..6e2d288082 100644
--- a/actionmailer/lib/action_mailer.rb
+++ b/actionmailer/lib/action_mailer.rb
@@ -49,9 +49,3 @@ module ActionMailer
autoload :TestCase
autoload :TestHelper
end
-
-module Text
- extend ActiveSupport::Autoload
-
- autoload :Format, 'text/format'
-end
diff --git a/actionmailer/lib/action_mailer/mail_helper.rb b/actionmailer/lib/action_mailer/mail_helper.rb
index ab5c3469b2..aab6e12387 100644
--- a/actionmailer/lib/action_mailer/mail_helper.rb
+++ b/actionmailer/lib/action_mailer/mail_helper.rb
@@ -3,6 +3,13 @@ module ActionMailer
# Uses Text::Format to take the text and format it, indented two spaces for
# each line, and wrapped at 72 columns.
def block_format(text)
+ begin
+ require 'text/format'
+ rescue LoadError => e
+ $stderr.puts "You don't have text-format installed in your application. Please add it to your Gemfile and run bundle install"
+ raise e
+ end unless defined?(Text::Format)
+
formatted = text.split(/\n\r\n/).collect { |paragraph|
Text::Format.new(
:columns => 72, :first_indent => 2, :body_indent => 2, :text => paragraph
diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec
index a5abe9be10..0f45cb5a4a 100644
--- a/actionpack/actionpack.gemspec
+++ b/actionpack/actionpack.gemspec
@@ -21,8 +21,11 @@ Gem::Specification.new do |s|
s.add_dependency('activesupport', version)
s.add_dependency('activemodel', version)
+ s.add_dependency('builder', '~> 2.1.2')
+ s.add_dependency('i18n', '~> 0.4.0')
s.add_dependency('rack', '~> 1.1.0')
- s.add_dependency('rack-test', '~> 0.5.0')
+ s.add_dependency('rack-test', '~> 0.5.4')
s.add_dependency('rack-mount', '~> 0.6.3')
+ s.add_dependency('tzinfo', '~> 0.3.16')
s.add_dependency('erubis', '~> 2.6.5')
end
diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb
index 30aa34d956..775a5002e2 100644
--- a/actionpack/lib/action_controller/metal.rb
+++ b/actionpack/lib/action_controller/metal.rb
@@ -1,6 +1,48 @@
require 'active_support/core_ext/class/attribute'
+require 'active_support/core_ext/object/blank'
+require 'action_dispatch/middleware/stack'
module ActionController
+ # Extend ActionDispatch middleware stack to make it aware of options
+ # allowing the following syntax in controllers:
+ #
+ # class PostsController < ApplicationController
+ # use AuthenticationMiddleware, :except => [:index, :show]
+ # end
+ #
+ class MiddlewareStack < ActionDispatch::MiddlewareStack #:nodoc:
+ class Middleware < ActionDispatch::MiddlewareStack::Middleware #:nodoc:
+ def initialize(klass, *args)
+ options = args.extract_options!
+ @only = Array(options.delete(:only)).map(&:to_s)
+ @except = Array(options.delete(:except)).map(&:to_s)
+ args << options unless options.empty?
+ super
+ end
+
+ def valid?(action)
+ if @only.present?
+ @only.include?(action)
+ elsif @except.present?
+ !@except.include?(action)
+ else
+ true
+ end
+ end
+ end
+
+ def build(action, app=nil, &block)
+ app ||= block
+ action = action.to_s
+ raise "MiddlewareStack#build requires an app" unless app
+
+ reverse.inject(app) do |a, middleware|
+ middleware.valid?(action) ?
+ middleware.build(a) : a
+ end
+ end
+ end
+
# ActionController::Metal provides a way to get a valid Rack application from a controller.
#
# In AbstractController, dispatching is triggered directly by calling #process on a new controller.
@@ -91,10 +133,10 @@ module ActionController
end
class_attribute :middleware_stack
- self.middleware_stack = ActionDispatch::MiddlewareStack.new
+ self.middleware_stack = ActionController::MiddlewareStack.new
def self.inherited(base)
- self.middleware_stack = base.middleware_stack.dup
+ base.middleware_stack = self.middleware_stack.dup
super
end
@@ -120,7 +162,7 @@ module ActionController
# ==== Returns
# Proc:: A rack application
def self.action(name, klass = ActionDispatch::Request)
- middleware_stack.build do |env|
+ middleware_stack.build(name.to_s) do |env|
new.dispatch(name, klass.new(env))
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/stack.rb b/actionpack/lib/action_dispatch/middleware/stack.rb
index 0e5ab507df..e3180dba77 100644
--- a/actionpack/lib/action_dispatch/middleware/stack.rb
+++ b/actionpack/lib/action_dispatch/middleware/stack.rb
@@ -55,7 +55,7 @@ module ActionDispatch
def insert(index, *args, &block)
index = self.index(index) unless index.is_a?(Integer)
- middleware = Middleware.new(*args, &block)
+ middleware = self.class::Middleware.new(*args, &block)
super(index, middleware)
end
@@ -73,7 +73,7 @@ module ActionDispatch
end
def use(*args, &block)
- middleware = Middleware.new(*args, &block)
+ middleware = self.class::Middleware.new(*args, &block)
push(middleware)
end
@@ -82,8 +82,8 @@ module ActionDispatch
"was removed from the middleware stack", caller
end
- def build(app = nil, &blk)
- app ||= blk
+ def build(app = nil, &block)
+ app ||= block
raise "MiddlewareStack#build requires an app" unless app
reverse.inject(app) { |a, e| e.build(a) }
end
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index 735398d972..f4af763afe 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -165,6 +165,10 @@ module ActionView #:nodoc:
cattr_accessor :debug_rjs
@@debug_rjs = false
+ # Specify the proc used to decorate input tags that refer to attributes with errors.
+ cattr_accessor :field_error_proc
+ @@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe }
+
class_attribute :helpers
remove_method :helpers
attr_reader :helpers
diff --git a/actionpack/lib/action_view/helpers/active_model_helper.rb b/actionpack/lib/action_view/helpers/active_model_helper.rb
index 0cddd09eb0..8054de0af6 100644
--- a/actionpack/lib/action_view/helpers/active_model_helper.rb
+++ b/actionpack/lib/action_view/helpers/active_model_helper.rb
@@ -4,13 +4,6 @@ require 'active_support/core_ext/enumerable'
require 'active_support/core_ext/object/blank'
module ActionView
- ActiveSupport.on_load(:action_view) do
- class ActionView::Base
- @@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe }
- cattr_accessor :field_error_proc
- end
- end
-
module Helpers
module ActiveModelHelper
%w(input form error_messages_for error_message_on).each do |method|
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb
index 41423d4e2e..bfad9f8d31 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -1,4 +1,5 @@
require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/string/filters'
require 'action_view/helpers/tag_helper'
module ActionView
@@ -42,28 +43,25 @@ module ActionView
# ==== Examples
#
# truncate("Once upon a time in a world far far away")
- # # => Once upon a time in a world...
+ # # => "Once upon a time in a world..."
#
- # truncate("Once upon a time in a world far far away", :separator => ' ')
- # # => Once upon a time in a world...
+ # truncate("Once upon a time in a world far far away", :length => 17)
+ # # => "Once upon a ti..."
#
- # truncate("Once upon a time in a world far far away", :length => 14)
- # # => Once upon a...
+ # truncate("Once upon a time in a world far far away", :lenght => 17, :separator => ' ')
+ # # => "Once upon a..."
#
- # truncate("And they found that many people were sleeping better.", :length => 25, "(clipped)")
- # # => And they found t(clipped)
- #
- # truncate("And they found that many people were sleeping better.", :omission => "... (continued)", :length => 25)
- # # => And they f... (continued)
+ # truncate("And they found that many people were sleeping better.", :length => 25, :omission => '... (continued)')
+ # # => "And they f... (continued)"
#
# You can still use <tt>truncate</tt> with the old API that accepts the
# +length+ as its optional second and the +ellipsis+ as its
# optional third parameter:
# truncate("Once upon a time in a world far far away", 14)
- # # => Once upon a...
+ # # => "Once upon a..."
#
# truncate("And they found that many people were sleeping better.", 25, "... (continued)")
- # # => And they f... (continued)
+ # # => "And they f... (continued)"
def truncate(text, *args)
options = args.extract_options!
unless args.empty?
@@ -73,14 +71,10 @@ module ActionView
options[:length] = args[0] || 30
options[:omission] = args[1] || "..."
end
- options.reverse_merge!(:length => 30, :omission => "...")
- if text
- l = options[:length] - options[:omission].mb_chars.length
- chars = text.mb_chars
- stop = options[:separator] ? (chars.rindex(options[:separator].mb_chars, l) || l) : l
- (chars.length > options[:length] ? chars[0...stop] + options[:omission] : text).to_s
- end
+ options.reverse_merge!(:length => 30)
+
+ text.truncate(options.delete(:length), options) if text
end
# Highlights one or more +phrases+ everywhere in +text+ by inserting it into
diff --git a/actionpack/test/controller/new_base/middleware_test.rb b/actionpack/test/controller/new_base/middleware_test.rb
index 65942ebc15..26a66c91a6 100644
--- a/actionpack/test/controller/new_base/middleware_test.rb
+++ b/actionpack/test/controller/new_base/middleware_test.rb
@@ -28,7 +28,6 @@ module MiddlewareTest
class MyController < ActionController::Metal
use MyMiddleware
-
middleware.insert_before MyMiddleware, ExclaimerMiddleware
def index
@@ -39,8 +38,23 @@ module MiddlewareTest
class InheritedController < MyController
end
- module MiddlewareTests
- extend ActiveSupport::Testing::Declarative
+ class ActionsController < ActionController::Metal
+ use MyMiddleware, :only => :show
+ middleware.insert_before MyMiddleware, ExclaimerMiddleware, :except => :index
+
+ def index
+ self.response_body = "index"
+ end
+
+ def show
+ self.response_body = "show"
+ end
+ end
+
+ class TestMiddleware < ActiveSupport::TestCase
+ def setup
+ @app = MyController.action(:index)
+ end
test "middleware that is 'use'd is called as part of the Rack application" do
result = @app.call(env_for("/"))
@@ -52,13 +66,13 @@ module MiddlewareTest
result = @app.call(env_for("/"))
assert_equal "First!", result[1]["Middleware-Order"]
end
- end
- class TestMiddleware < ActiveSupport::TestCase
- include MiddlewareTests
+ test "middleware stack accepts only and except as options" do
+ result = ActionsController.action(:show).call(env_for("/"))
+ assert_equal "First!", result[1]["Middleware-Order"]
- def setup
- @app = MyController.action(:index)
+ result = ActionsController.action(:index).call(env_for("/"))
+ assert_nil result[1]["Middleware-Order"]
end
def env_for(url)
@@ -70,8 +84,5 @@ module MiddlewareTest
def setup
@app = InheritedController.action(:index)
end
-
- test "middleware inherits" do
- end
end
end
diff --git a/activemodel/activemodel.gemspec b/activemodel/activemodel.gemspec
index 9695911398..678007c0ef 100644
--- a/activemodel/activemodel.gemspec
+++ b/activemodel/activemodel.gemspec
@@ -20,4 +20,6 @@ Gem::Specification.new do |s|
s.has_rdoc = true
s.add_dependency('activesupport', version)
+ s.add_dependency('builder', '~> 2.1.2')
+ s.add_dependency('i18n', '~> 0.4.0')
end
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index 14afc5265f..15d468f5d8 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -170,13 +170,13 @@ module ActiveModel
end
end
- # Adds an error message (+messsage+) to the +attribute+, which will be returned on a call to <tt>on(attribute)</tt>
- # for the same attribute and ensure that this error object returns false when asked if <tt>empty?</tt>. More than one
- # error can be added to the same +attribute+ in which case an array will be returned on a call to <tt>on(attribute)</tt>.
- # If no +messsage+ is supplied, :invalid is assumed.
+ # Adds +message+ to the error messages on +attribute+, which will be returned on a call to
+ # <tt>on(attribute)</tt> for the same attribute. More than one error can be added to the same
+ # +attribute+ in which case an array will be returned on a call to <tt>on(attribute)</tt>.
+ # If no +message+ is supplied, <tt>:invalid</tt> is assumed.
#
- # If +message+ is a Symbol, it will be translated, using the appropriate scope (see translate_error).
- # If +message+ is a Proc, it will be called, allowing for things like Time.now to be used within an error
+ # If +message+ is a symbol, it will be translated using the appropriate scope (see +translate_error+).
+ # If +message+ is a proc, it will be called, allowing for things like <tt>Time.now</tt> to be used within an error.
def add(attribute, message = nil, options = {})
message ||= :invalid
message = generate_message(attribute, message, options) if message.is_a?(Symbol)
diff --git a/activerecord/activerecord.gemspec b/activerecord/activerecord.gemspec
index 59caa53be0..44c8fb83e1 100644
--- a/activerecord/activerecord.gemspec
+++ b/activerecord/activerecord.gemspec
@@ -24,4 +24,5 @@ Gem::Specification.new do |s|
s.add_dependency('activesupport', version)
s.add_dependency('activemodel', version)
s.add_dependency('arel', '~> 0.3.3')
+ s.add_dependency('tzinfo', '~> 0.3.16')
end
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index cb7eade0ab..952f2a3070 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -435,6 +435,7 @@ namespace :db do
task :create => :environment do
raise "Task unavailable to this database (no migration support)" unless ActiveRecord::Base.connection.supports_migrations?
require 'rails/generators'
+ Rails::Generators.configure!
require 'rails/generators/rails/session_migration/session_migration_generator'
Rails::Generators::SessionMigrationGenerator.start [ ENV["MIGRATION"] || "add_sessions_table" ]
end
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 6782554854..7a48a6596a 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -9,7 +9,7 @@ module ActiveRecord
(ActiveRecord::Relation::ASSOCIATION_METHODS + ActiveRecord::Relation::MULTI_VALUE_METHODS).each do |query_method|
attr_accessor :"#{query_method}_values"
- next if [:where, :having].include?(query_method)
+ next if [:where, :having, :select].include?(query_method)
class_eval <<-CEVAL, __FILE__, __LINE__ + 1
def #{query_method}(*args, &block)
new_relation = clone
@@ -21,6 +21,19 @@ module ActiveRecord
CEVAL
end
+ class_eval <<-CEVAL, __FILE__, __LINE__ + 1
+ def select(*args, &block)
+ if block_given?
+ to_a.select(&block)
+ else
+ new_relation = clone
+ value = Array.wrap(args.flatten).reject {|x| x.blank? }
+ new_relation.select_values += value if value.present?
+ new_relation
+ end
+ end
+ CEVAL
+
[:where, :having].each do |query_method|
class_eval <<-CEVAL, __FILE__, __LINE__ + 1
def #{query_method}(*args, &block)
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index b6815af67e..4097c5119e 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -112,6 +112,11 @@ class RelationTest < ActiveRecord::TestCase
assert_equal 4, developers.map(&:salary).uniq.size
end
+ def test_select_with_block
+ even_ids = Developer.scoped.select {|d| d.id % 2 == 0 }.map(&:id)
+ assert_equal [2, 4, 6, 8, 10], even_ids
+ end
+
def test_finding_with_hash_conditions_on_joined_table
firms = DependentFirm.joins(:account).where({:name => 'RailsCore', :accounts => { :credit_limit => 55..60 }}).to_a
assert_equal 1, firms.size
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG
index 0a25ad0406..d853788e00 100644
--- a/activesupport/CHANGELOG
+++ b/activesupport/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
+* Extracted String#truncate from TextHelper#truncate [DHH]
+
* Ruby 1.9: support UTF-8 case folding. #4595 [Norman Clarke]
* Renames Array#rand -> Array#random_element. [Santiago Pastorino, Rizwan Reza]
diff --git a/activesupport/activesupport.gemspec b/activesupport/activesupport.gemspec
index 09635c2f18..8611a1e5fa 100644
--- a/activesupport/activesupport.gemspec
+++ b/activesupport/activesupport.gemspec
@@ -18,9 +18,4 @@ Gem::Specification.new do |s|
s.require_path = 'lib'
s.has_rdoc = true
-
- s.add_dependency('i18n', '~> 0.4.0')
- s.add_dependency('tzinfo', '~> 0.3.16')
- s.add_dependency('builder', '~> 2.1.2')
- s.add_dependency('memcache-client', '>= 1.7.5')
end
diff --git a/activesupport/lib/active_support/builder.rb b/activesupport/lib/active_support/builder.rb
new file mode 100644
index 0000000000..321e462acd
--- /dev/null
+++ b/activesupport/lib/active_support/builder.rb
@@ -0,0 +1,6 @@
+begin
+ require 'builder'
+rescue LoadError => e
+ $stderr.puts "You don't have builder installed in your application. Please add it to your Gemfile and run bundle install"
+ raise e
+end
diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb
index d8377a208f..e3a2688e2f 100644
--- a/activesupport/lib/active_support/cache/mem_cache_store.rb
+++ b/activesupport/lib/active_support/cache/mem_cache_store.rb
@@ -1,4 +1,9 @@
-require 'memcache'
+begin
+ require 'memcache'
+rescue LoadError => e
+ $stderr.puts "You don't have memcache installed in your application. Please add it to your Gemfile and run bundle install"
+ raise e
+end
require 'digest/md5'
module ActiveSupport
diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb
index 2b07f05d27..79e3828817 100644
--- a/activesupport/lib/active_support/core_ext/array/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/array/conversions.rb
@@ -9,9 +9,15 @@ class Array
# * <tt>:two_words_connector</tt> - The sign or word used to join the elements in arrays with two elements (default: " and ")
# * <tt>:last_word_connector</tt> - The sign or word used to join the last element in arrays with three or more elements (default: ", and ")
def to_sentence(options = {})
- default_words_connector = I18n.translate(:'support.array.words_connector', :locale => options[:locale])
- default_two_words_connector = I18n.translate(:'support.array.two_words_connector', :locale => options[:locale])
- default_last_word_connector = I18n.translate(:'support.array.last_word_connector', :locale => options[:locale])
+ if defined?(I18n)
+ default_words_connector = I18n.translate(:'support.array.words_connector', :locale => options[:locale])
+ default_two_words_connector = I18n.translate(:'support.array.two_words_connector', :locale => options[:locale])
+ default_last_word_connector = I18n.translate(:'support.array.last_word_connector', :locale => options[:locale])
+ else
+ default_words_connector = ", "
+ default_two_words_connector = " and "
+ default_last_word_connector = ", and "
+ end
options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale)
options.reverse_merge! :words_connector => default_words_connector, :two_words_connector => default_two_words_connector, :last_word_connector => default_last_word_connector
@@ -128,7 +134,7 @@ class Array
# </messages>
#
def to_xml(options = {})
- require 'builder' unless defined?(Builder)
+ require 'active_support/builder' unless defined?(Builder)
options = options.dup
options[:indent] ||= 2
diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb
index 14e5d2f8ac..565c9af7fb 100644
--- a/activesupport/lib/active_support/core_ext/hash/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb
@@ -55,7 +55,7 @@ class Hash
# configure your own builder with the <tt>:builder</tt> option. The method also accepts
# options like <tt>:dasherize</tt> and friends, they are forwarded to the builder.
def to_xml(options = {})
- require 'builder' unless defined?(Builder)
+ require 'active_support/builder' unless defined?(Builder)
options = options.dup
options[:indent] ||= 2
diff --git a/activesupport/lib/active_support/core_ext/string/filters.rb b/activesupport/lib/active_support/core_ext/string/filters.rb
index 6fda7efef5..e15a1df9c9 100644
--- a/activesupport/lib/active_support/core_ext/string/filters.rb
+++ b/activesupport/lib/active_support/core_ext/string/filters.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/string/multibyte'
+
class String
# Returns the string, first removing all whitespace on both ends of
# the string, and then changing remaining consecutive whitespace
@@ -17,4 +19,31 @@ class String
gsub!(/\s+/, ' ')
self
end
+
+ # Truncates a given +text+ after a given <tt>length</tt> if +text+ is longer than <tt>length</tt>:
+ #
+ # "Once upon a time in a world far far away".truncate(27)
+ # # => "Once upon a time in a wo..."
+ #
+ # The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...")
+ # for a total length not exceeding <tt>:length</tt>:
+ #
+ # "Once upon a time in a world far far away".truncate(27, :separator => ' ')
+ # # => "Once upon a time in a..."
+ #
+ # Pass a <tt>:separator</tt> to truncate +text+ at a natural break:
+ #
+ # "And they found that many people were sleeping better.".truncate(25, :omission => "... (continued)")
+ # # => "And they f... (continued)"
+ def truncate(length, options = {})
+ text = self.dup
+ options[:omission] ||= "..."
+
+ length_with_room_for_omission = length - options[:omission].mb_chars.length
+ chars = text.mb_chars
+ stop = options[:separator] ?
+ (chars.rindex(options[:separator].mb_chars, length_with_room_for_omission) || length_with_room_for_omission) : length_with_room_for_omission
+
+ (chars.length > length ? chars[0...stop] + options[:omission] : text).to_s
+ end
end
diff --git a/activesupport/lib/active_support/core_ext/string/interpolation.rb b/activesupport/lib/active_support/core_ext/string/interpolation.rb
index 932117cc10..7f764e9de1 100644
--- a/activesupport/lib/active_support/core_ext/string/interpolation.rb
+++ b/activesupport/lib/active_support/core_ext/string/interpolation.rb
@@ -1 +1,2 @@
+require 'active_support/i18n'
require 'i18n/core_ext/string/interpolate'
diff --git a/activesupport/lib/active_support/i18n.rb b/activesupport/lib/active_support/i18n.rb
index 11af48d67e..0ffdd904fd 100644
--- a/activesupport/lib/active_support/i18n.rb
+++ b/activesupport/lib/active_support/i18n.rb
@@ -1,3 +1,8 @@
-require 'i18n'
+begin
+ require 'i18n'
+rescue LoadError => e
+ $stderr.puts "You don't have i18n installed in your application. Please add it to your Gemfile and run bundle install"
+ raise e
+end
I18n.load_path << "#{File.dirname(__FILE__)}/locale/en.yml"
-ActiveSupport.run_load_hooks(:i18n) \ No newline at end of file
+ActiveSupport.run_load_hooks(:i18n)
diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb
index 2ac5134911..67b37785f5 100644
--- a/activesupport/lib/active_support/values/time_zone.rb
+++ b/activesupport/lib/active_support/values/time_zone.rb
@@ -1,5 +1,11 @@
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/object/try'
+begin
+ require 'tzinfo'
+rescue LoadError => e
+ $stderr.puts "You don't have tzinfo installed in your application. Please add it to your Gemfile and run bundle install"
+ raise e
+end
# The TimeZone class serves as a wrapper around TZInfo::Timezone instances. It allows us to do the following:
#
@@ -313,7 +319,7 @@ module ActiveSupport
# TODO: Preload instead of lazy load for thread safety
def self.find_tzinfo(name)
- require 'tzinfo' unless defined?(::TZInfo)
+ require 'active_support/tzinfo' unless defined?(::TZInfo)
::TZInfo::TimezoneProxy.new(MAPPING[name] || name)
end
diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb
index 759b0ddcd6..d9702dd9ff 100644
--- a/activesupport/test/core_ext/string_ext_test.rb
+++ b/activesupport/test/core_ext/string_ext_test.rb
@@ -210,6 +210,35 @@ class StringInflectionsTest < Test::Unit::TestCase
# And changes the original string:
assert_equal original, expected
end
+
+ def test_truncate
+ assert_equal "Hello World!", "Hello World!".truncate(12)
+ assert_equal "Hello Wor...", "Hello World!!".truncate(12)
+ end
+
+ def test_truncate_with_omission_and_seperator
+ assert_equal "Hello[...]", "Hello World!".truncate(10, :omission => "[...]")
+ assert_equal "Hello[...]", "Hello Big World!".truncate(13, :omission => "[...]", :separator => ' ')
+ assert_equal "Hello Big[...]", "Hello Big World!".truncate(14, :omission => "[...]", :separator => ' ')
+ assert_equal "Hello Big[...]", "Hello Big World!".truncate(15, :omission => "[...]", :separator => ' ')
+ end
+
+ if RUBY_VERSION < '1.9.0'
+ def test_truncate_multibyte
+ with_kcode 'none' do
+ assert_equal "\354\225\210\353\205\225\355...", "\354\225\210\353\205\225\355\225\230\354\204\270\354\232\224".truncate(10)
+ end
+ with_kcode 'u' do
+ assert_equal "\354\225\204\353\246\254\353\236\221 \354\225\204\353\246\254 ...",
+ "\354\225\204\353\246\254\353\236\221 \354\225\204\353\246\254 \354\225\204\353\235\274\353\246\254\354\230\244".truncate(10)
+ end
+ end
+ else
+ def test_truncate_multibyte
+ assert_equal "\354\225\204\353\246\254\353\236\221 \354\225\204\353\246\254 ...".force_encoding('UTF-8'),
+ "\354\225\204\353\246\254\353\236\221 \354\225\204\353\246\254 \354\225\204\353\235\274\353\246\254\354\230\244".force_encoding('UTF-8').truncate(10)
+ end
+ end
end
class StringBehaviourTest < Test::Unit::TestCase
diff --git a/railties/guides/source/action_view_overview.textile b/railties/guides/source/action_view_overview.textile
index 43ebe87875..8b5eda0973 100644
--- a/railties/guides/source/action_view_overview.textile
+++ b/railties/guides/source/action_view_overview.textile
@@ -699,7 +699,7 @@ Creates a scope around a specific model object like form_for, but doesn‘t crea
First name: <%= person_form.text_field :first_name %>
Last name : <%= person_form.text_field :last_name %>
- <% fields_for @person.permission do |permission_fields| %>
+ <%= fields_for @person.permission do |permission_fields| %>
Admin? : <%= permission_fields.check_box :admin %>
<% end %>
<% end %>
diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile
index 08fddd2926..de82e871a6 100644
--- a/railties/guides/source/active_support_core_extensions.textile
+++ b/railties/guides/source/active_support_core_extensions.textile
@@ -1254,6 +1254,39 @@ There's also the destructive version +String#squish!+.
NOTE: Defined in +active_support/core_ext/string/filters.rb+.
+h4. +truncate+
+
+The method +truncate+ returns a copy of its receiver truncated after a given +length+:
+
+<ruby>
+"Oh dear! Oh dear! I shall be late!".truncate(20)
+# => "Oh dear! Oh dear!..."
+</ruby>
+
+Ellipsis can be customized with the +:omission+ option:
+
+<ruby>
+"Oh dear! Oh dear! I shall be late!".truncate(20, :omission => '&hellip;')
+# => "Oh dear! Oh &hellip;"
+</ruby>
+
+Note in particular that truncation takes into account the length of the omission string.
+
+Pass a +:separator+ to truncate the string at a natural break:
+
+<ruby>
+"Oh dear! Oh dear! I shall be late!".truncate(18)
+# => "Oh dear! Oh dea..."
+"Oh dear! Oh dear! I shall be late!".truncate(18, :separator => ' ')
+# => "Oh dear! Oh..."
+</ruby>
+
+In the above example "dear" gets cut first, but then +:separator+ prevents it.
+
+WARNING: The option +:separator+ can't be a regexp.
+
+NOTE: Defined in +active_support/core_ext/string/filters.rb+.
+
h4. Key-based Interpolation
In Ruby 1.9 the <tt>%</tt> string operator supports key-based interpolation, both formatted and unformatted:
diff --git a/railties/guides/source/activerecord_validations_callbacks.textile b/railties/guides/source/activerecord_validations_callbacks.textile
index 857551c9d5..d83ea57864 100644
--- a/railties/guides/source/activerecord_validations_callbacks.textile
+++ b/railties/guides/source/activerecord_validations_callbacks.textile
@@ -879,32 +879,28 @@ Here is a list with all the available Active Record callbacks, listed in the sam
h4. Creating an Object
* +before_validation+
-* +before_validation_on_create+
* +after_validation+
-* +after_validation_on_create+
* +before_save+
+* +after_save+
* +before_create+
-* INSERT OPERATION
+* +around_create+
* +after_create+
-* +after_save+
h4. Updating an Object
* +before_validation+
-* +before_validation_on_update+
* +after_validation+
-* +after_validation_on_update+
* +before_save+
+* +after_save+
* +before_update+
-* UPDATE OPERATION
+* +around_update+
* +after_update+
-* +after_save+
h4. Destroying an Object
* +before_destroy+
-* DELETE OPERATION
* +after_destroy+
+* +around_destroy+
WARNING. +after_save+ runs both on create and update, but always _after_ the more specific callbacks +after_create+ and +after_update+, no matter the order in which the macro calls were executed.
diff --git a/railties/guides/source/generators.textile b/railties/guides/source/generators.textile
index d3757e9733..b77a2837c3 100644
--- a/railties/guides/source/generators.textile
+++ b/railties/guides/source/generators.textile
@@ -322,14 +322,10 @@ config.generators do |g|
g.template_engine :erb
g.test_framework :shoulda, :fixture => false
g.stylesheets false
-end
-</ruby>
-
-And at the end of the same file:
-<ruby>
-require 'rails/generators'
-Rails::Generators.fallbacks[:shoulda] = :test_unit
+ # Add a fallback!
+ g.fallbacks[:should] = :test_unit
+end
</ruby>
Now, if create a Comment scaffold, you will see that shoulda generators are being invoked, and at the end, they are just falling back to test unit generators:
@@ -361,7 +357,7 @@ $ rails generate scaffold Comment body:text
create test/unit/helpers/comments_helper_test.rb
</shell>
-Such tool allows your generators to have single responsibility, increasing the code reuse and reducing the amount of code duplication.
+Such tool allows your generators to have single responsibility, increasing the code reuse and reducing the amount of duplication.
h3. Changelog
diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile
index fe623e969f..46e709d0f5 100644
--- a/railties/guides/source/getting_started.textile
+++ b/railties/guides/source/getting_started.textile
@@ -1342,7 +1342,7 @@ We also add a <tt>@post.tags.build</tt> at the top of this form, this is to make
Now create the folder <tt>app/views/tags</tt> and make a file in there called <tt>_form.html.erb</tt> which contains the form for the tag:
<erb>
-<% form.fields_for :tags do |tag_form| %>
+<%= form.fields_for :tags do |tag_form| %>
<div class="field">
<%= tag_form.label :name, 'Tag:' %>
<%= tag_form.text_field :name %>
diff --git a/railties/guides/source/nested_model_forms.textile b/railties/guides/source/nested_model_forms.textile
index 4a79902232..39b0c32f24 100644
--- a/railties/guides/source/nested_model_forms.textile
+++ b/railties/guides/source/nested_model_forms.textile
@@ -143,7 +143,7 @@ Now add a nested form for the +address+ association:
<%= form_for @person do |f| %>
<%= f.text_field :name %>
- <% f.fields_for :address do |af| %>
+ <%= f.fields_for :address do |af| %>
<%= f.text_field :street %>
<% end %>
<% end %>
@@ -184,7 +184,7 @@ The form code for an association collection is pretty similar to that of a singl
<%= form_for @person do |f| %>
<%= f.text_field :name %>
- <% f.fields_for :projects do |pf| %>
+ <%= f.fields_for :projects do |pf| %>
<%= f.text_field :name %>
<% end %>
<% end %>
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index 7416e94eeb..85ae8cbbb1 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -67,6 +67,7 @@ module Rails
raise "You cannot have more than one Rails::Application" if Rails.application
super
Rails.application = base.instance
+ Rails.application.add_lib_to_load_paths!
ActiveSupport.run_load_hooks(:before_configuration, base.instance)
end
@@ -83,11 +84,21 @@ module Rails
delegate :middleware, :to => :config
+ def add_lib_to_load_paths!
+ path = config.root.join('lib').to_s
+ $LOAD_PATH.unshift(path) if File.exists?(path)
+ end
+
def require_environment!
environment = paths.config.environment.to_a.first
require environment if environment
end
+ def eager_load!
+ railties.all(&:eager_load!)
+ super
+ end
+
def routes
@routes ||= ActionDispatch::Routing::RouteSet.new
end
diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb
index fbab4d5515..d7ff489336 100644
--- a/railties/lib/rails/application/finisher.rb
+++ b/railties/lib/rails/application/finisher.rb
@@ -38,7 +38,7 @@ module Rails
initializer :eager_load! do
if config.cache_classes && !$rails_rake_task
ActiveSupport.run_load_hooks(:before_eager_load, self)
- railties.all(&:eager_load!)
+ eager_load!
end
end
diff --git a/railties/lib/rails/commands/destroy.rb b/railties/lib/rails/commands/destroy.rb
index 9023c61bf2..db59cd8ad9 100644
--- a/railties/lib/rails/commands/destroy.rb
+++ b/railties/lib/rails/commands/destroy.rb
@@ -1,4 +1,5 @@
require 'rails/generators'
+Rails::Generators.configure!
if [nil, "-h", "--help"].include?(ARGV.first)
Rails::Generators.help 'destroy'
diff --git a/railties/lib/rails/commands/generate.rb b/railties/lib/rails/commands/generate.rb
index 7d05a30de8..1b3eef504a 100755
--- a/railties/lib/rails/commands/generate.rb
+++ b/railties/lib/rails/commands/generate.rb
@@ -1,4 +1,5 @@
require 'rails/generators'
+Rails::Generators.configure!
if [nil, "-h", "--help"].include?(ARGV.first)
Rails::Generators.help 'generate'
diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb
index fe8a6c0b94..af92757053 100644
--- a/railties/lib/rails/generators.rb
+++ b/railties/lib/rails/generators.rb
@@ -68,6 +68,7 @@ module Rails
options.deep_merge! config.options
fallbacks.merge! config.fallbacks
templates_path.concat config.templates
+ templates_path.uniq!
end
def self.templates_path
@@ -328,10 +329,5 @@ module Rails
paths.uniq!
paths
end
-
end
-end
-
-# If the application was already defined, configure generators,
-# otherwise you have to configure it by hand.
-Rails::Generators.configure! if Rails.respond_to?(:application) && Rails.application
+end \ No newline at end of file
diff --git a/railties/test/application/initializers/load_path_test.rb b/railties/test/application/initializers/load_path_test.rb
index b39b9ecaae..d31915e129 100644
--- a/railties/test/application/initializers/load_path_test.rb
+++ b/railties/test/application/initializers/load_path_test.rb
@@ -19,6 +19,23 @@ module ApplicationTests
assert $:.include?("#{app_path}/app/models")
end
+ test "initializing an application adds lib path on inheritance hook" do
+ app_file "lib/foo.rb", <<-RUBY
+ module Foo; end
+ RUBY
+
+ add_to_config <<-RUBY
+ require "foo"
+ raise "Expected Foo to be defined" unless defined?(Foo)
+ RUBY
+
+ assert_nothing_raised do
+ require "#{app_path}/config/environment"
+ end
+
+ assert $:.include?("#{app_path}/lib")
+ end
+
test "initializing an application eager load any path under app" do
app_file "app/anything/foo.rb", <<-RUBY
module Foo; end
diff --git a/railties/test/generators/generators_test_helper.rb b/railties/test/generators/generators_test_helper.rb
index d8bdb344f2..4a5a9b2932 100644
--- a/railties/test/generators/generators_test_helper.rb
+++ b/railties/test/generators/generators_test_helper.rb
@@ -1,4 +1,6 @@
require 'abstract_unit'
+require 'rails/generators'
+require 'rails/generators/test_case'
module Rails
def self.root
@@ -8,8 +10,9 @@ end
Rails.application.config.root = Rails.root
Rails.application.config.generators.templates = [File.join(Rails.root, "lib", "templates")]
-require 'rails/generators'
-require 'rails/generators/test_case'
+# Call configure to load the settings from
+# Rails.application.config.generators to Rails::Generators
+Rails::Generators.configure!
require 'active_record'
require 'action_dispatch'