diff options
author | Pratik Naik <pratiknaik@gmail.com> | 2008-09-13 20:25:18 +0100 |
---|---|---|
committer | Pratik Naik <pratiknaik@gmail.com> | 2008-09-13 20:25:18 +0100 |
commit | f6c0f688680778a7bf693a69ffee021e1122b01c (patch) | |
tree | 09699984d7a4f612689f19e3e0ccb663ae207d3f | |
parent | 25fd841fe0f1d6f43019595a06aef6d825f5f4d1 (diff) | |
parent | 96055414d6197b9705e408c17236f79372a007e5 (diff) | |
download | rails-f6c0f688680778a7bf693a69ffee021e1122b01c.tar.gz rails-f6c0f688680778a7bf693a69ffee021e1122b01c.tar.bz2 rails-f6c0f688680778a7bf693a69ffee021e1122b01c.zip |
Merge commit 'mainstream/master'
35 files changed, 379 insertions, 102 deletions
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index ed33f082b9..a926599e25 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -463,7 +463,8 @@ module ActionView end private - COMPUTED_PUBLIC_PATHS = ActiveSupport::Cache::MemoryStore.new.silence! + COMPUTED_PUBLIC_PATHS = {} + COMPUTED_PUBLIC_PATHS_GUARD = Mutex.new # Add the the extension +ext+ if not present. Return full URLs otherwise untouched. # Prefix with <tt>/dir/</tt> if lacking a leading +/+. Account for relative URL @@ -483,23 +484,24 @@ module ActionView dir, source, ext, include_host ].join end - source = COMPUTED_PUBLIC_PATHS.fetch(cache_key) do - begin - source += ".#{ext}" if ext && File.extname(source).blank? || File.exist?(File.join(ASSETS_DIR, dir, "#{source}.#{ext}")) - - if source =~ %r{^[-a-z]+://} - source - else - source = "/#{dir}/#{source}" unless source[0] == ?/ - if has_request - unless source =~ %r{^#{ActionController::Base.relative_url_root}/} - source = "#{ActionController::Base.relative_url_root}#{source}" + COMPUTED_PUBLIC_PATHS_GUARD.synchronize do + source = COMPUTED_PUBLIC_PATHS[cache_key] ||= + begin + source += ".#{ext}" if ext && File.extname(source).blank? || File.exist?(File.join(ASSETS_DIR, dir, "#{source}.#{ext}")) + + if source =~ %r{^[-a-z]+://} + source + else + source = "/#{dir}/#{source}" unless source[0] == ?/ + if has_request + unless source =~ %r{^#{ActionController::Base.relative_url_root}/} + source = "#{ActionController::Base.relative_url_root}#{source}" + end end - end - rewrite_asset_path(source) + rewrite_asset_path(source) + end end - end end if include_host && source !~ %r{^[-a-z]+://} diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 61fa34ac39..c60850fc77 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -95,7 +95,7 @@ module ActiveRecord records.each {|record| record.send(reflection.name).loaded} options = reflection.options - conditions = "t0.#{reflection.primary_key_name} IN (?)" + conditions = "t0.#{reflection.primary_key_name} #{in_or_equals_for_ids(ids)}" conditions << append_conditions(options, preload_options) associated_records = reflection.klass.find(:all, :conditions => [conditions, ids], @@ -222,8 +222,6 @@ module ActiveRecord table_name = klass.quoted_table_name primary_key = klass.primary_key - conditions = "#{table_name}.#{connection.quote_column_name(primary_key)} IN (?)" - conditions << append_conditions(options, preload_options) column_type = klass.columns.detect{|c| c.name == primary_key}.type ids = id_map.keys.uniq.map do |id| if column_type == :integer @@ -234,6 +232,8 @@ module ActiveRecord id end end + conditions = "#{table_name}.#{connection.quote_column_name(primary_key)} #{in_or_equals_for_ids(ids)}" + conditions << append_conditions(options, preload_options) associated_records = klass.find(:all, :conditions => [conditions, ids], :include => options[:include], :select => options[:select], @@ -248,10 +248,10 @@ module ActiveRecord table_name = reflection.klass.quoted_table_name if interface = reflection.options[:as] - conditions = "#{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_id"} IN (?) and #{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_type"} = '#{self.base_class.sti_name}'" + conditions = "#{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_id"} #{in_or_equals_for_ids(ids)} and #{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_type"} = '#{self.base_class.sti_name}'" else foreign_key = reflection.primary_key_name - conditions = "#{reflection.klass.quoted_table_name}.#{foreign_key} IN (?)" + conditions = "#{reflection.klass.quoted_table_name}.#{foreign_key} #{in_or_equals_for_ids(ids)}" end conditions << append_conditions(options, preload_options) @@ -277,6 +277,9 @@ module ActiveRecord sql end + def in_or_equals_for_ids(ids) + ids.size > 1 ? "IN (?)" : "= ?" + end end end end diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index aca2d770fc..5d91315aad 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1237,7 +1237,7 @@ module ActiveRecord association = instance_variable_get(ivar) if instance_variable_defined?(ivar) - if association.nil? || force_reload + if association.nil? || !association.loaded? || force_reload association = association_proxy_class.new(self, reflection) retval = association.reload if retval.nil? and association_proxy_class == BelongsToAssociation @@ -1266,6 +1266,13 @@ module ActiveRecord end end + if association_proxy_class == BelongsToAssociation + define_method("#{reflection.primary_key_name}=") do |target_id| + instance_variable_get(ivar).reset if instance_variable_defined?(ivar) + write_attribute(reflection.primary_key_name, target_id) + end + end + define_method("set_#{reflection.name}_target") do |target| return if target.nil? and association_proxy_class == BelongsToAssociation association = association_proxy_class.new(self, reflection) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index fc6d762fcd..91b69747e0 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -2152,7 +2152,7 @@ module ActiveRecord #:nodoc: end def quote_bound_value(value) #:nodoc: - if value.respond_to?(:map) && !value.is_a?(String) + if value.respond_to?(:map) && !value.acts_like?(:string) if value.respond_to?(:empty?) && value.empty? connection.quote(nil) else diff --git a/activerecord/lib/active_record/dirty.rb b/activerecord/lib/active_record/dirty.rb index 7e246e62ca..ae573799ae 100644 --- a/activerecord/lib/active_record/dirty.rb +++ b/activerecord/lib/active_record/dirty.rb @@ -34,8 +34,10 @@ module ActiveRecord # person.name << 'by' # person.name_change # => ['uncle bob', 'uncle bobby'] module Dirty + DIRTY_SUFFIXES = ['_changed?', '_change', '_will_change!', '_was'] + def self.included(base) - base.attribute_method_suffix '_changed?', '_change', '_will_change!', '_was' + base.attribute_method_suffix *DIRTY_SUFFIXES base.alias_method_chain :write_attribute, :dirty base.alias_method_chain :save, :dirty base.alias_method_chain :save!, :dirty @@ -44,6 +46,8 @@ module ActiveRecord base.superclass_delegating_accessor :partial_updates base.partial_updates = true + + base.send(:extend, ClassMethods) end # Do any attributes have unsaved changes? @@ -161,5 +165,19 @@ module ActiveRecord old != value end + module ClassMethods + def self.extended(base) + base.metaclass.alias_method_chain(:alias_attribute, :dirty) + end + + def alias_attribute_with_dirty(new_name, old_name) + alias_attribute_without_dirty(new_name, old_name) + DIRTY_SUFFIXES.each do |suffix| + module_eval <<-STR, __FILE__, __LINE__+1 + def #{new_name}#{suffix}; self.#{old_name}#{suffix}; end + STR + end + end + end end end diff --git a/activerecord/test/cases/aggregations_test.rb b/activerecord/test/cases/aggregations_test.rb index b6656c8631..4e0e1c7f15 100644 --- a/activerecord/test/cases/aggregations_test.rb +++ b/activerecord/test/cases/aggregations_test.rb @@ -130,12 +130,16 @@ class DeprecatedAggregationsTest < ActiveRecord::TestCase end def test_conversion_block_used_when_converter_option_is_nil - Person.composed_of(:balance, :class_name => "Money", :mapping => %w(balance amount)) { |balance| balance.to_money } + assert_deprecated 'conversion block has been deprecated' do + Person.composed_of(:balance, :class_name => "Money", :mapping => %w(balance amount)) { |balance| balance.to_money } + end assert_raise(NoMethodError) { Person.new.balance = 5 } end def test_converter_option_overrides_conversion_block - Person.composed_of(:balance, :class_name => "Money", :mapping => %w(balance amount), :converter => Proc.new { |balance| Money.new(balance) }) { |balance| balance.to_money } + assert_deprecated 'conversion block has been deprecated' do + Person.composed_of(:balance, :class_name => "Money", :mapping => %w(balance amount), :converter => Proc.new { |balance| Money.new(balance) }) { |balance| balance.to_money } + end person = Person.new assert_nothing_raised { person.balance = 5 } diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 9c718c4fef..37b6836a89 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -47,6 +47,19 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal apple.id, citibank.firm_id end + def test_foreign_key_assignment + # Test using an existing record + signals37 = accounts(:signals37) + assert_equal companies(:first_firm), signals37.firm + signals37.firm_id = companies(:another_firm).id + assert_equal companies(:another_firm), signals37.firm + + # Test using a new record + account = Account.new + account.firm_id = companies(:another_firm).id + assert_equal companies(:another_firm), account.firm + end + def test_no_unexpected_aliasing first_firm = companies(:first_firm) another_firm = companies(:another_firm) diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb index edca3c622b..9981f4c5d5 100644 --- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb @@ -636,6 +636,18 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase assert_equal 3, Developer.find(:all, :include => {:projects => :developers}, :conditions => 'developers_projects_join.joined_on IS NOT NULL', :group => group.join(",")).size end + def test_find_grouped + all_posts_from_category1 = Post.find(:all, :conditions => "category_id = 1", :joins => :categories) + grouped_posts_of_category1 = Post.find(:all, :conditions => "category_id = 1", :group => "author_id", :select => 'count(posts.id) as posts_count', :joins => :categories) + assert_equal 4, all_posts_from_category1.size + assert_equal 1, grouped_posts_of_category1.size + end + + def test_find_scoped_grouped + assert_equal 4, categories(:general).posts_gruoped_by_title.size + assert_equal 1, categories(:technology).posts_gruoped_by_title.size + end + def test_get_ids assert_equal projects(:active_record, :action_controller).map(&:id).sort, developers(:david).project_ids.sort assert_equal [projects(:active_record).id], developers(:jamis).project_ids diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index feac4b002b..5bcbc5eb5b 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -248,6 +248,11 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 1, grouped_clients_of_firm1.size end + def test_find_scoped_grouped + assert_equal 1, companies(:first_firm).clients_grouped_by_firm_id.length + assert_equal 2, companies(:first_firm).clients_grouped_by_name.length + end + def test_adding force_signal37_to_load_all_clients_of_firm natural = Client.new("name" => "Natural Company") diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb index 056a29438a..2050d16179 100644 --- a/activerecord/test/cases/associations_test.rb +++ b/activerecord/test/cases/associations_test.rb @@ -182,6 +182,18 @@ class AssociationProxyTest < ActiveRecord::TestCase assert_nil p.author.reset end + def test_reset_loads_association_next_time + welcome = posts(:welcome) + david = authors(:david) + author_assoc = welcome.author + + assert_equal david, welcome.author # So we can be sure the test works correctly + author_assoc.reset + assert !author_assoc.loaded? + assert_nil author_assoc.target + assert_equal david, welcome.author + end + def test_reload_returns_assocition david = developers(:david) assert_nothing_raised do diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index 4fe1d79f4d..39d38c4e1e 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -45,6 +45,19 @@ class DirtyTest < ActiveRecord::TestCase assert_nil pirate.catchphrase_change end + def test_aliased_attribute_changes + # the actual attribute here is name, title is an + # alias setup via alias_attribute + parrot = Parrot.new + assert !parrot.title_changed? + assert_nil parrot.title_change + + parrot.name = 'Sam' + assert parrot.title_changed? + assert_nil parrot.title_was + assert_equal parrot.name_change, parrot.title_change + end + def test_nullable_integer_not_marked_as_changed_if_new_value_is_blank pirate = Pirate.new diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 1cbc5182d6..cbdff382fe 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -169,6 +169,12 @@ class FinderTest < ActiveRecord::TestCase assert_equal("fixture_3", developers.first.name) end + def test_find_with_group + developers = Developer.find(:all, :group => "salary", :select => "salary") + assert_equal 4, developers.size + assert_equal 4, developers.map(&:salary).uniq.size + end + def test_find_with_entire_select_statement topics = Topic.find_by_sql "SELECT * FROM topics WHERE author_name = 'Mary'" @@ -297,7 +303,6 @@ class FinderTest < ActiveRecord::TestCase assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }) } end - def test_condition_interpolation assert_kind_of Firm, Company.find(:first, :conditions => ["name = '%s'", "37signals"]) assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!"]) @@ -392,7 +397,7 @@ class FinderTest < ActiveRecord::TestCase Company.find(:first, :conditions => ["id=? AND name = ?", 2]) } assert_raises(ActiveRecord::PreparedStatementInvalid) { - Company.find(:first, :conditions => ["id=?", 2, 3, 4]) + Company.find(:first, :conditions => ["id=?", 2, 3, 4]) } end @@ -455,6 +460,15 @@ class FinderTest < ActiveRecord::TestCase assert_equal ActiveRecord::Base.connection.quote(''), bind('?', '') end + def test_bind_chars + quoted_bambi = ActiveRecord::Base.connection.quote("Bambi") + quoted_bambi_and_thumper = ActiveRecord::Base.connection.quote("Bambi\nand\nThumper") + assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi") + assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper") + assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi".chars) + assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper".chars) + end + def test_bind_record o = Struct.new(:quoted_id).new(1) assert_equal '1', bind('?', o) diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb index 4fd38bfbc9..a39415618d 100644 --- a/activerecord/test/cases/inheritance_test.rb +++ b/activerecord/test/cases/inheritance_test.rb @@ -193,7 +193,7 @@ class InheritanceTest < ActiveRecord::TestCase def test_eager_load_belongs_to_primary_key_quoting con = Account.connection - assert_sql(/\(#{con.quote_table_name('companies')}.#{con.quote_column_name('id')} IN \(1\)\)/) do + assert_sql(/\(#{con.quote_table_name('companies')}.#{con.quote_column_name('id')} = 1\)/) do Account.find(1, :include => :firm) end end diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index 4b86e32dbf..e339ef41ab 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -160,8 +160,8 @@ class ReflectionTest < ActiveRecord::TestCase def test_reflection_of_all_associations # FIXME these assertions bust a lot - assert_equal 24, Firm.reflect_on_all_associations.size - assert_equal 18, Firm.reflect_on_all_associations(:has_many).size + assert_equal 26, Firm.reflect_on_all_associations.size + assert_equal 20, Firm.reflect_on_all_associations(:has_many).size assert_equal 6, Firm.reflect_on_all_associations(:has_one).size assert_equal 0, Firm.reflect_on_all_associations(:belongs_to).size end diff --git a/activerecord/test/cases/sanitize_test.rb b/activerecord/test/cases/sanitize_test.rb new file mode 100644 index 0000000000..0106572ced --- /dev/null +++ b/activerecord/test/cases/sanitize_test.rb @@ -0,0 +1,25 @@ +require "cases/helper" +require 'models/binary' + +class SanitizeTest < ActiveRecord::TestCase + def setup + end + + def test_sanitize_sql_array_handles_string_interpolation + quoted_bambi = ActiveRecord::Base.connection.quote_string("Bambi") + assert_equal "name=#{quoted_bambi}", Binary.send(:sanitize_sql_array, ["name=%s", "Bambi"]) + assert_equal "name=#{quoted_bambi}", Binary.send(:sanitize_sql_array, ["name=%s", "Bambi".chars]) + quoted_bambi_and_thumper = ActiveRecord::Base.connection.quote_string("Bambi\nand\nThumper") + assert_equal "name=#{quoted_bambi_and_thumper}",Binary.send(:sanitize_sql_array, ["name=%s", "Bambi\nand\nThumper"]) + assert_equal "name=#{quoted_bambi_and_thumper}",Binary.send(:sanitize_sql_array, ["name=%s", "Bambi\nand\nThumper".chars]) + end + + def test_sanitize_sql_array_handles_bind_variables + quoted_bambi = ActiveRecord::Base.connection.quote("Bambi") + assert_equal "name=#{quoted_bambi}", Binary.send(:sanitize_sql_array, ["name=?", "Bambi"]) + assert_equal "name=#{quoted_bambi}", Binary.send(:sanitize_sql_array, ["name=?", "Bambi".chars]) + quoted_bambi_and_thumper = ActiveRecord::Base.connection.quote("Bambi\nand\nThumper") + assert_equal "name=#{quoted_bambi_and_thumper}", Binary.send(:sanitize_sql_array, ["name=?", "Bambi\nand\nThumper"]) + assert_equal "name=#{quoted_bambi_and_thumper}", Binary.send(:sanitize_sql_array, ["name=?", "Bambi\nand\nThumper".chars]) + end +end diff --git a/activerecord/test/cases/validations_i18n_test.rb b/activerecord/test/cases/validations_i18n_test.rb index 090f347a20..e34890ef19 100644 --- a/activerecord/test/cases/validations_i18n_test.rb +++ b/activerecord/test/cases/validations_i18n_test.rb @@ -40,6 +40,32 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end end + def test_percent_s_interpolation_syntax_in_error_messages_still_works + ActiveSupport::Deprecation.silence do + result = I18n.t :does_not_exist, :default => "%s interpolation syntax is deprecated", :value => 'this' + assert_equal result, "this interpolation syntax is deprecated" + end + end + + def test_percent_s_interpolation_syntax_in_error_messages_is_deprecated + assert_deprecated('using %s in messages') do + I18n.t :does_not_exist, :default => "%s interpolation syntax is deprected", :value => 'this' + end + end + + def test_percent_d_interpolation_syntax_in_error_messages_still_works + ActiveSupport::Deprecation.silence do + result = I18n.t :does_not_exist, :default => "%d interpolation syntaxes are deprecated", :count => 2 + assert_equal result, "2 interpolation syntaxes are deprecated" + end + end + + def test_percent_d_interpolation_syntax_in_error_messages_is_deprecated + assert_deprecated('using %d in messages') do + I18n.t :does_not_exist, :default => "%d interpolation syntaxes are deprected", :count => 2 + end + end + # ActiveRecord::Errors uses_mocha 'ActiveRecord::Errors' do diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb index 4999d93a86..c049659327 100644 --- a/activerecord/test/cases/validations_test.rb +++ b/activerecord/test/cases/validations_test.rb @@ -364,6 +364,13 @@ class ValidationsTest < ActiveRecord::TestCase assert t2.save, "Should now save t2 as unique" end + def test_validates_uniquness_with_newline_chars + Topic.validates_uniqueness_of(:title, :case_sensitive => false) + + t = Topic.new("title" => "new\nline") + assert t.save, "Should save t as unique" + end + def test_validate_uniqueness_with_scope Reply.validates_uniqueness_of(:content, :scope => "parent_id") @@ -605,7 +612,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_validate_format_with_formatted_message - Topic.validates_format_of(:title, :with => /^Valid Title$/, :message => "can't be %s") + Topic.validates_format_of(:title, :with => /^Valid Title$/, :message => "can't be {{value}}") t = Topic.create(:title => 'Invalid title') assert_equal "can't be Invalid title", t.errors.on(:title) end @@ -666,7 +673,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_validates_inclusion_of_with_formatted_message - Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :message => "option %s is not in the list" ) + Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :message => "option {{value}} is not in the list" ) assert Topic.create("title" => "a", "content" => "abc").valid? @@ -691,7 +698,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_validates_exclusion_of_with_formatted_message - Topic.validates_exclusion_of( :title, :in => %w( abe monkey ), :message => "option %s is restricted" ) + Topic.validates_exclusion_of( :title, :in => %w( abe monkey ), :message => "option {{value}} is restricted" ) assert Topic.create("title" => "something", "content" => "abc") @@ -791,7 +798,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_optionally_validates_length_of_using_within_on_create - Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "my string is too long: %d" + Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "my string is too long: {{count}}" t = Topic.create("title" => "thisisnotvalid", "content" => "whatever") assert !t.save @@ -812,7 +819,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_optionally_validates_length_of_using_within_on_update - Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "my string is too short: %d" + Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "my string is too short: {{count}}" t = Topic.create("title" => "vali", "content" => "whatever") assert !t.save @@ -875,7 +882,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_validates_length_with_globally_modified_error_message ActiveSupport::Deprecation.silence do - ActiveRecord::Errors.default_error_messages[:too_short] = 'tu est trops petit hombre %d' + ActiveRecord::Errors.default_error_messages[:too_short] = 'tu est trops petit hombre {{count}}' end Topic.validates_length_of :title, :minimum => 10 t = Topic.create(:title => 'too short') @@ -919,7 +926,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_validates_length_of_custom_errors_for_minimum_with_message - Topic.validates_length_of( :title, :minimum=>5, :message=>"boo %d" ) + Topic.validates_length_of( :title, :minimum=>5, :message=>"boo {{count}}" ) t = Topic.create("title" => "uhoh", "content" => "whatever") assert !t.valid? assert t.errors.on(:title) @@ -927,7 +934,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_validates_length_of_custom_errors_for_minimum_with_too_short - Topic.validates_length_of( :title, :minimum=>5, :too_short=>"hoo %d" ) + Topic.validates_length_of( :title, :minimum=>5, :too_short=>"hoo {{count}}" ) t = Topic.create("title" => "uhoh", "content" => "whatever") assert !t.valid? assert t.errors.on(:title) @@ -935,7 +942,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_validates_length_of_custom_errors_for_maximum_with_message - Topic.validates_length_of( :title, :maximum=>5, :message=>"boo %d" ) + Topic.validates_length_of( :title, :maximum=>5, :message=>"boo {{count}}" ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert !t.valid? assert t.errors.on(:title) @@ -943,7 +950,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_validates_length_of_custom_errors_for_maximum_with_too_long - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d" ) + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}" ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert !t.valid? assert t.errors.on(:title) @@ -951,7 +958,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_validates_length_of_custom_errors_for_is_with_message - Topic.validates_length_of( :title, :is=>5, :message=>"boo %d" ) + Topic.validates_length_of( :title, :is=>5, :message=>"boo {{count}}" ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert !t.valid? assert t.errors.on(:title) @@ -959,7 +966,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_validates_length_of_custom_errors_for_is_with_wrong_length - Topic.validates_length_of( :title, :is=>5, :wrong_length=>"hoo %d" ) + Topic.validates_length_of( :title, :is=>5, :wrong_length=>"hoo {{count}}" ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert !t.valid? assert t.errors.on(:title) @@ -1025,7 +1032,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_optionally_validates_length_of_using_within_on_create_utf8 with_kcode('UTF8') do - Topic.validates_length_of :title, :within => 5..10, :on => :create, :too_long => "長すぎます: %d" + Topic.validates_length_of :title, :within => 5..10, :on => :create, :too_long => "長すぎます: {{count}}" t = Topic.create("title" => "一二三四五六七八九十A", "content" => "whatever") assert !t.save @@ -1048,7 +1055,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_optionally_validates_length_of_using_within_on_update_utf8 with_kcode('UTF8') do - Topic.validates_length_of :title, :within => 5..10, :on => :update, :too_short => "短すぎます: %d" + Topic.validates_length_of :title, :within => 5..10, :on => :update, :too_short => "短すぎます: {{count}}" t = Topic.create("title" => "一二三4", "content" => "whatever") assert !t.save @@ -1083,7 +1090,7 @@ class ValidationsTest < ActiveRecord::TestCase end def test_validates_length_of_with_block - Topic.validates_length_of :content, :minimum => 5, :too_short=>"Your essay must be at least %d words.", + Topic.validates_length_of :content, :minimum => 5, :too_short=>"Your essay must be at least {{count}} words.", :tokenizer => lambda {|str| str.scan(/\w+/) } t = Topic.create!(:content => "this content should be long enough") assert t.valid? @@ -1234,7 +1241,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_if_validation_using_method_true # When the method returns true - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :if => :condition_is_true ) + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => :condition_is_true ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert !t.valid? assert t.errors.on(:title) @@ -1243,7 +1250,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_unless_validation_using_method_true # When the method returns true - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :unless => :condition_is_true ) + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => :condition_is_true ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert t.valid? assert !t.errors.on(:title) @@ -1251,7 +1258,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_if_validation_using_method_false # When the method returns false - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :if => :condition_is_true_but_its_not ) + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => :condition_is_true_but_its_not ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert t.valid? assert !t.errors.on(:title) @@ -1259,7 +1266,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_unless_validation_using_method_false # When the method returns false - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :unless => :condition_is_true_but_its_not ) + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => :condition_is_true_but_its_not ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert !t.valid? assert t.errors.on(:title) @@ -1268,7 +1275,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_if_validation_using_string_true # When the evaluated string returns true - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :if => "a = 1; a == 1" ) + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => "a = 1; a == 1" ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert !t.valid? assert t.errors.on(:title) @@ -1277,7 +1284,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_unless_validation_using_string_true # When the evaluated string returns true - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :unless => "a = 1; a == 1" ) + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => "a = 1; a == 1" ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert t.valid? assert !t.errors.on(:title) @@ -1285,7 +1292,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_if_validation_using_string_false # When the evaluated string returns false - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :if => "false") + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => "false") t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert t.valid? assert !t.errors.on(:title) @@ -1293,7 +1300,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_unless_validation_using_string_false # When the evaluated string returns false - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", :unless => "false") + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => "false") t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert !t.valid? assert t.errors.on(:title) @@ -1302,7 +1309,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_if_validation_using_block_true # When the block returns true - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => Proc.new { |r| r.content.size > 4 } ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert !t.valid? @@ -1312,7 +1319,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_unless_validation_using_block_true # When the block returns true - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => Proc.new { |r| r.content.size > 4 } ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert t.valid? @@ -1321,7 +1328,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_if_validation_using_block_false # When the block returns false - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => Proc.new { |r| r.title != "uhohuhoh"} ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert t.valid? @@ -1330,7 +1337,7 @@ class ValidationsTest < ActiveRecord::TestCase def test_unless_validation_using_block_false # When the block returns false - Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %d", + Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => Proc.new { |r| r.title != "uhohuhoh"} ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") assert !t.valid? @@ -1507,13 +1514,13 @@ class ValidatesNumericalityTest < ActiveRecord::TestCase end def test_validates_numericality_with_numeric_message - Topic.validates_numericality_of :approved, :less_than => 4, :message => "smaller than %d" + Topic.validates_numericality_of :approved, :less_than => 4, :message => "smaller than {{count}}" topic = Topic.new("title" => "numeric test", "approved" => 10) assert !topic.valid? assert_equal "smaller than 4", topic.errors.on(:approved) - Topic.validates_numericality_of :approved, :greater_than => 4, :message => "greater than %d" + Topic.validates_numericality_of :approved, :greater_than => 4, :message => "greater than {{count}}" topic = Topic.new("title" => "numeric test", "approved" => 1) assert !topic.valid? diff --git a/activerecord/test/models/category.rb b/activerecord/test/models/category.rb index 1660c61682..4e9d247a4e 100644 --- a/activerecord/test/models/category.rb +++ b/activerecord/test/models/category.rb @@ -13,6 +13,9 @@ class Category < ActiveRecord::Base has_and_belongs_to_many :post_with_conditions, :class_name => 'Post', :conditions => { :title => 'Yet Another Testing Title' } + + has_and_belongs_to_many :posts_gruoped_by_title, :class_name => "Post", :group => "title", :select => "title" + def self.what_are_you 'a category...' end diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb index cd435948a1..0eb8ae0a15 100644 --- a/activerecord/test/models/company.rb +++ b/activerecord/test/models/company.rb @@ -55,6 +55,8 @@ class Firm < Company has_many :readonly_clients, :class_name => 'Client', :readonly => true has_many :clients_using_primary_key, :class_name => 'Client', :primary_key => 'name', :foreign_key => 'firm_name' + has_many :clients_grouped_by_firm_id, :class_name => "Client", :group => "firm_id", :select => "firm_id" + has_many :clients_grouped_by_name, :class_name => "Client", :group => "name", :select => "name" has_one :account, :foreign_key => "firm_id", :dependent => :destroy, :validate => true has_one :unvalidated_account, :foreign_key => "firm_id", :class_name => 'Account', :validate => false diff --git a/activerecord/test/models/parrot.rb b/activerecord/test/models/parrot.rb index 65191c1aa5..b9431fd1c0 100644 --- a/activerecord/test/models/parrot.rb +++ b/activerecord/test/models/parrot.rb @@ -3,6 +3,7 @@ class Parrot < ActiveRecord::Base has_and_belongs_to_many :pirates has_and_belongs_to_many :treasures has_many :loots, :as => :looter + alias_attribute :title, :name end class LiveParrot < Parrot diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index b38a5061d5..7d7a6920e2 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,5 +1,7 @@ *Edge* +* Fixed Sri Jayawardenepura time zone to map to Asia/Colombo [Jamis Buck] + * Added Inflector#parameterize for easy slug generation ("Donald E. Knuth".parameterize => "donald-e-knuth") #713 [Matt Darby] * Changed cache benchmarking to be reported in milliseconds [DHH] diff --git a/activesupport/lib/active_support/cache/memory_store.rb b/activesupport/lib/active_support/cache/memory_store.rb index f3e4b8c13b..c1a713b4c5 100644 --- a/activesupport/lib/active_support/cache/memory_store.rb +++ b/activesupport/lib/active_support/cache/memory_store.rb @@ -3,63 +3,35 @@ module ActiveSupport class MemoryStore < Store def initialize @data = {} - @guard = Monitor.new - end - - def fetch(key, options = {}) - @guard.synchronize do - super - end end def read(name, options = nil) - @guard.synchronize do - super - @data[name] - end + super + @data[name] end def write(name, value, options = nil) - @guard.synchronize do - super - @data[name] = value.freeze - end + super + @data[name] = value.freeze end def delete(name, options = nil) - @guard.synchronize do - @data.delete(name) - end + super + @data.delete(name) end def delete_matched(matcher, options = nil) - @guard.synchronize do - @data.delete_if { |k,v| k =~ matcher } - end + super + @data.delete_if { |k,v| k =~ matcher } end def exist?(name,options = nil) - @guard.synchronize do - @data.has_key?(name) - end - end - - def increment(key, amount = 1) - @guard.synchronize do - super - end - end - - def decrement(key, amount = 1) - @guard.synchronize do - super - end + super + @data.has_key?(name) end def clear - @guard.synchronize do - @data.clear - end + @data.clear end end end diff --git a/activesupport/lib/active_support/cache/synchronized_memory_store.rb b/activesupport/lib/active_support/cache/synchronized_memory_store.rb new file mode 100644 index 0000000000..d2ff28768f --- /dev/null +++ b/activesupport/lib/active_support/cache/synchronized_memory_store.rb @@ -0,0 +1,46 @@ +module ActiveSupport + module Cache + class SynchronizedMemoryStore < MemoryStore + def initialize + super + @guard = Monitor.new + end + + def fetch(key, options = {}) + @guard.synchronize { super } + end + + def read(name, options = nil) + @guard.synchronize { super } + end + + def write(name, value, options = nil) + @guard.synchronize { super } + end + + def delete(name, options = nil) + @guard.synchronize { super } + end + + def delete_matched(matcher, options = nil) + @guard.synchronize { super } + end + + def exist?(name,options = nil) + @guard.synchronize { super } + end + + def increment(key, amount = 1) + @guard.synchronize { super } + end + + def decrement(key, amount = 1) + @guard.synchronize { super } + end + + def clear + @guard.synchronize { super } + end + end + end +end diff --git a/activesupport/lib/active_support/core_ext/hash/except.rb b/activesupport/lib/active_support/core_ext/hash/except.rb index f26d01553d..949976d741 100644 --- a/activesupport/lib/active_support/core_ext/hash/except.rb +++ b/activesupport/lib/active_support/core_ext/hash/except.rb @@ -10,7 +10,7 @@ module ActiveSupport #:nodoc: module Except # Returns a new hash without the given keys. def except(*keys) - clone.except!(*keys) + dup.except!(*keys) end # Replaces the hash without the given keys. diff --git a/activesupport/lib/active_support/core_ext/string.rb b/activesupport/lib/active_support/core_ext/string.rb index 25386af70a..7ff2f11eff 100644 --- a/activesupport/lib/active_support/core_ext/string.rb +++ b/activesupport/lib/active_support/core_ext/string.rb @@ -6,6 +6,7 @@ require 'active_support/core_ext/string/iterators' require 'active_support/core_ext/string/unicode' require 'active_support/core_ext/string/xchar' require 'active_support/core_ext/string/filters' +require 'active_support/core_ext/string/behavior' class String #:nodoc: include ActiveSupport::CoreExtensions::String::Access @@ -15,4 +16,5 @@ class String #:nodoc: include ActiveSupport::CoreExtensions::String::StartsEndsWith include ActiveSupport::CoreExtensions::String::Iterators include ActiveSupport::CoreExtensions::String::Unicode + include ActiveSupport::CoreExtensions::String::Behavior end diff --git a/activesupport/lib/active_support/core_ext/string/behavior.rb b/activesupport/lib/active_support/core_ext/string/behavior.rb new file mode 100644 index 0000000000..a93ca3027f --- /dev/null +++ b/activesupport/lib/active_support/core_ext/string/behavior.rb @@ -0,0 +1,13 @@ +module ActiveSupport #:nodoc: + module CoreExtensions #:nodoc: + module String #:nodoc: + module Behavior + # Enable more predictable duck-typing on String-like classes. See + # Object#acts_like?. + def acts_like_string? + true + end + end + end + end +end
\ No newline at end of file diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb index e5f0063285..8a917a9eb2 100644 --- a/activesupport/lib/active_support/inflector.rb +++ b/activesupport/lib/active_support/inflector.rb @@ -257,7 +257,7 @@ module ActiveSupport # <%= link_to(@person.name, person_path %> # # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a> def parameterize(string, sep = '-') - string.gsub(/[^a-z0-9]+/i, sep).downcase + string.chars.normalize(:kd).to_s.gsub(/[^\x00-\x7F]+/, '').gsub(/[^a-z0-9_\-]+/i, sep).downcase end # Create the name of a table like Rails does for models to table names. This method diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb index 185d03020c..de2c83f8d1 100644 --- a/activesupport/lib/active_support/multibyte/chars.rb +++ b/activesupport/lib/active_support/multibyte/chars.rb @@ -49,6 +49,11 @@ module ActiveSupport::Multibyte #:nodoc: false end + # Enable more predictable duck-typing on String-like classes. See Object#acts_like?. + def acts_like_string? + true + end + # Create a new Chars instance. def initialize(str) @string = str.respond_to?(:string) ? str.string : str diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 788d40bfa8..a294dd0ba3 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -124,7 +124,7 @@ module ActiveSupport "Kathmandu" => "Asia/Katmandu", "Astana" => "Asia/Dhaka", "Dhaka" => "Asia/Dhaka", - "Sri Jayawardenepura" => "Asia/Dhaka", + "Sri Jayawardenepura" => "Asia/Colombo", "Almaty" => "Asia/Almaty", "Novosibirsk" => "Asia/Novosibirsk", "Rangoon" => "Asia/Rangoon", diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Colombo.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Colombo.rb new file mode 100644 index 0000000000..f6531fa819 --- /dev/null +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Colombo.rb @@ -0,0 +1,30 @@ +require 'tzinfo/timezone_definition' + +module TZInfo + module Definitions + module Asia + module Colombo + include TimezoneDefinition + + timezone 'Asia/Colombo' do |tz| + tz.offset :o0, 19164, 0, :LMT + tz.offset :o1, 19172, 0, :MMT + tz.offset :o2, 19800, 0, :IST + tz.offset :o3, 19800, 1800, :IHST + tz.offset :o4, 19800, 3600, :IST + tz.offset :o5, 23400, 0, :LKT + tz.offset :o6, 21600, 0, :LKT + + tz.transition 1879, 12, :o1, 17335550003, 7200 + tz.transition 1905, 12, :o2, 52211763607, 21600 + tz.transition 1942, 1, :o3, 116657485, 48 + tz.transition 1942, 8, :o4, 9722413, 4 + tz.transition 1945, 10, :o2, 38907909, 16 + tz.transition 1996, 5, :o5, 832962600 + tz.transition 1996, 10, :o6, 846266400 + tz.transition 2006, 4, :o2, 1145039400 + end + end + end + end +end diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index 7a414e946f..44d48e7577 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -341,6 +341,20 @@ class HashExtTest < Test::Unit::TestCase assert_equal expected, original.except!(:c) assert_equal expected, original end + + def test_except_with_original_frozen + original = { :a => 'x', :b => 'y' } + original.freeze + assert_nothing_raised { original.except(:a) } + end + + uses_mocha 'except with expectation' do + def test_except_with_mocha_expectation_on_original + original = { :a => 'x', :b => 'y' } + original.expects(:delete).never + original.except(:a) + end + end end class IWriteMyOwnXML diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index c9f959ef32..c0decf2c3f 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -201,3 +201,9 @@ class StringInflectionsTest < Test::Unit::TestCase end end end + +class StringBehaviourTest < Test::Unit::TestCase + def test_acts_like_string + assert 'Bambi'.acts_like_string? + end +end
\ No newline at end of file diff --git a/activesupport/test/inflector_test_cases.rb b/activesupport/test/inflector_test_cases.rb index d399c90385..8057809dbd 100644 --- a/activesupport/test/inflector_test_cases.rb +++ b/activesupport/test/inflector_test_cases.rb @@ -144,7 +144,10 @@ module InflectorTestCases StringToParameterized = { "Donald E. Knuth" => "donald-e-knuth", - "Random text with *(bad)* characters" => "random-text-with-bad-characters" + "Random text with *(bad)* characters" => "random-text-with-bad-characters", + "Malmö" => "malmo", + "Garçons" => "garcons", + "Allow_Under_Scores" => "allow_under_scores" } UnderscoreToHuman = { diff --git a/activesupport/test/multibyte_chars_test.rb b/activesupport/test/multibyte_chars_test.rb index 63cfadb7ec..a87309b038 100644 --- a/activesupport/test/multibyte_chars_test.rb +++ b/activesupport/test/multibyte_chars_test.rb @@ -167,6 +167,10 @@ class CharsTest < Test::Unit::TestCase assert_equal false, 'test'.chars.respond_to?(:a_method_that_doesnt_exist) end + def test_acts_like_string + assert 'Bambi'.chars.acts_like_string? + end + protected def with_kcode(kcode) diff --git a/railties/lib/commands/console.rb b/railties/lib/commands/console.rb index 2b9d92f647..63df834639 100644 --- a/railties/lib/commands/console.rb +++ b/railties/lib/commands/console.rb @@ -1,11 +1,13 @@ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb' require 'optparse' + options = { :sandbox => false, :irb => irb } OptionParser.new do |opt| opt.banner = "Usage: console [environment] [options]" opt.on('-s', '--sandbox', 'Rollback database modifications on exit.') { |v| options[:sandbox] = v } opt.on("--irb=[#{irb}]", 'Invoke a different irb.') { |v| options[:irb] = v } + opt.on("--debugger", 'Enable ruby-debugging for the console.') { |v| options[:debugger] = v } opt.parse!(ARGV) end @@ -15,6 +17,17 @@ libs << " -r console_app" libs << " -r console_sandbox" if options[:sandbox] libs << " -r console_with_helpers" +if options[:debugger] + begin + require 'ruby-debug' + libs << " -r ruby-debug" + puts "=> Debugger enabled" + rescue Exception + puts "You need to install ruby-debug to run the console in debugging mode. With gems, use 'gem install ruby-debug'" + exit + end +end + ENV['RAILS_ENV'] = case ARGV.first when "p"; "production" when "d"; "development" |