diff options
author | wycats <wycats@gmail.com> | 2010-06-02 15:53:10 +0200 |
---|---|---|
committer | wycats <wycats@gmail.com> | 2010-06-02 15:53:10 +0200 |
commit | 26c5680bd01bd0e525eccc5d47a2e7126d9383f7 (patch) | |
tree | c655c56511ef89ba55c554a0aa7d82b1cd062f78 | |
parent | b870daba5ff71973b237616fb95f90bb321ae7fb (diff) | |
parent | 4b91daff13be43ed913a97ffc8ad1b3f77fd9690 (diff) | |
download | rails-26c5680bd01bd0e525eccc5d47a2e7126d9383f7.tar.gz rails-26c5680bd01bd0e525eccc5d47a2e7126d9383f7.tar.bz2 rails-26c5680bd01bd0e525eccc5d47a2e7126d9383f7.zip |
Merge branch 'master' of github.com:rails/rails
41 files changed, 316 insertions, 104 deletions
@@ -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 => '…') +# => "Oh dear! Oh …" +</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' |