aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel/lib
diff options
context:
space:
mode:
authorJosé Valim <jose.valim@gmail.com>2011-11-23 20:43:06 +0000
committerJosé Valim <jose.valim@gmail.com>2011-11-23 20:43:06 +0000
commite62de52aa398341a29b7ecef4ec9f9df8e1743e2 (patch)
tree3a87677e000259ecc0ced6bc93afc03fea73493b /activemodel/lib
parentafd7140b66e7cb32e1be58d9e44489e6bcbde0dc (diff)
parentfd86a1b6b068df87164d5763bdcd4a323a1e76f4 (diff)
downloadrails-e62de52aa398341a29b7ecef4ec9f9df8e1743e2.tar.gz
rails-e62de52aa398341a29b7ecef4ec9f9df8e1743e2.tar.bz2
rails-e62de52aa398341a29b7ecef4ec9f9df8e1743e2.zip
Merge branch 'master' into serializers
Diffstat (limited to 'activemodel/lib')
-rw-r--r--activemodel/lib/active_model/attribute_methods.rb59
-rw-r--r--activemodel/lib/active_model/dirty.rb2
-rw-r--r--activemodel/lib/active_model/errors.rb47
-rw-r--r--activemodel/lib/active_model/naming.rb24
-rw-r--r--activemodel/lib/active_model/observing.rb3
-rw-r--r--activemodel/lib/active_model/secure_password.rb4
-rw-r--r--activemodel/lib/active_model/validations/validates.rb2
-rw-r--r--activemodel/lib/active_model/validator.rb2
8 files changed, 84 insertions, 59 deletions
diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb
index ef0b95424e..e69cb5c459 100644
--- a/activemodel/lib/active_model/attribute_methods.rb
+++ b/activemodel/lib/active_model/attribute_methods.rb
@@ -57,7 +57,8 @@ module ActiveModel
module AttributeMethods
extend ActiveSupport::Concern
- COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?=]?\z/
+ NAME_COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?=]?\z/
+ CALL_COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?]?\z/
included do
class_attribute :attribute_method_matchers, :instance_writer => false
@@ -112,7 +113,7 @@ module ActiveModel
# If we can compile the method name, do it. Otherwise use define_method.
# This is an important *optimization*, please don't change it. define_method
# has slower dispatch and consumes more memory.
- if name =~ COMPILABLE_REGEXP
+ if name =~ NAME_COMPILABLE_REGEXP
sing.class_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{name}; #{value.nil? ? 'nil' : value.to_s.inspect}; end
RUBY
@@ -240,18 +241,7 @@ module ActiveModel
attribute_method_matchers.each do |matcher|
matcher_new = matcher.method_name(new_name).to_s
matcher_old = matcher.method_name(old_name).to_s
-
- if matcher_new =~ COMPILABLE_REGEXP && matcher_old =~ COMPILABLE_REGEXP
- module_eval <<-RUBY, __FILE__, __LINE__ + 1
- def #{matcher_new}(*args)
- send(:#{matcher_old}, *args)
- end
- RUBY
- else
- define_method(matcher_new) do |*args|
- send(matcher_old, *args)
- end
- end
+ define_optimized_call self, matcher_new, matcher_old
end
end
@@ -293,17 +283,7 @@ module ActiveModel
if respond_to?(generate_method)
send(generate_method, attr_name)
else
- if method_name =~ COMPILABLE_REGEXP
- defn = "def #{method_name}(*args)"
- else
- defn = "define_method(:'#{method_name}') do |*args|"
- end
-
- generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
- #{defn}
- send(:#{matcher.method_missing_target}, '#{attr_name}', *args)
- end
- RUBY
+ define_optimized_call generated_attribute_methods, method_name, matcher.method_missing_target, attr_name.to_s
end
end
end
@@ -342,11 +322,11 @@ module ActiveModel
# used to alleviate the GC, which ultimately also speeds up the app
# significantly (in our case our test suite finishes 10% faster with
# this cache).
- def attribute_method_matchers_cache
+ def attribute_method_matchers_cache #:nodoc:
@attribute_method_matchers_cache ||= {}
end
- def attribute_method_matcher(method_name)
+ def attribute_method_matcher(method_name) #:nodoc:
if attribute_method_matchers_cache.key?(method_name)
attribute_method_matchers_cache[method_name]
else
@@ -359,6 +339,31 @@ module ActiveModel
end
end
+ # Define a method `name` in `mod` that dispatches to `send`
+ # using the given `extra` args. This fallbacks `define_method`
+ # and `send` if the given names cannot be compiled.
+ def define_optimized_call(mod, name, send, *extra) #:nodoc:
+ if name =~ NAME_COMPILABLE_REGEXP
+ defn = "def #{name}(*args)"
+ else
+ defn = "define_method(:'#{name}') do |*args|"
+ end
+
+ extra = (extra.map(&:inspect) << "*args").join(", ")
+
+ if send =~ CALL_COMPILABLE_REGEXP
+ target = "#{send}(#{extra})"
+ else
+ target = "send(:'#{send}', #{extra})"
+ end
+
+ mod.module_eval <<-RUBY, __FILE__, __LINE__ + 1
+ #{defn}
+ #{target}
+ end
+ RUBY
+ end
+
class AttributeMethodMatcher
attr_reader :prefix, :suffix, :method_missing_target
diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb
index 166cccf161..026f077ee7 100644
--- a/activemodel/lib/active_model/dirty.rb
+++ b/activemodel/lib/active_model/dirty.rb
@@ -98,7 +98,7 @@ module ActiveModel
# person.name = 'bob'
# person.changed? # => true
def changed?
- !changed_attributes.empty?
+ changed_attributes.any?
end
# List of attributes with unsaved changes.
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index d91e4a2b6a..8337b04c0d 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -205,21 +205,14 @@ module ActiveModel
messages.dup
end
- # 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>.
+ # Adds +message+ to the error messages on +attribute+. More than one error can be added to the same
+ # +attribute+.
# 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 <tt>Time.now</tt> to be used within an error.
def add(attribute, message = nil, options = {})
- message ||= :invalid
-
- if message.is_a?(Symbol)
- message = generate_message(attribute, message, options.except(*CALLBACKS_OPTIONS))
- elsif message.is_a?(Proc)
- message = message.call
- end
+ message = normalize_message(attribute, message, options)
if options[:strict]
raise ActiveModel::StrictValidationFailed, message
end
@@ -244,6 +237,15 @@ module ActiveModel
end
end
+ # Returns true if an error on the attribute with the given message is present, false otherwise.
+ # +message+ is treated the same as for +add+.
+ # p.errors.add :name, :blank
+ # p.errors.added? :name, :blank # => true
+ def added?(attribute, message = nil, options = {})
+ message = normalize_message(attribute, message, options)
+ self[attribute].include? message
+ end
+
# Returns all the full error messages in an array.
#
# class Company
@@ -300,13 +302,17 @@ module ActiveModel
def generate_message(attribute, type = :invalid, options = {})
type = options.delete(:message) if options[:message].is_a?(Symbol)
- defaults = @base.class.lookup_ancestors.map do |klass|
- [ :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.i18n_key}.attributes.#{attribute}.#{type}",
- :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.i18n_key}.#{type}" ]
+ if @base.class.respond_to?(:i18n_scope)
+ defaults = @base.class.lookup_ancestors.map do |klass|
+ [ :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.i18n_key}.attributes.#{attribute}.#{type}",
+ :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.i18n_key}.#{type}" ]
+ end
+ else
+ defaults = []
end
defaults << options.delete(:message)
- defaults << :"#{@base.class.i18n_scope}.errors.messages.#{type}"
+ defaults << :"#{@base.class.i18n_scope}.errors.messages.#{type}" if @base.class.respond_to?(:i18n_scope)
defaults << :"errors.attributes.#{attribute}.#{type}"
defaults << :"errors.messages.#{type}"
@@ -325,6 +331,19 @@ module ActiveModel
I18n.translate(key, options)
end
+
+ private
+ def normalize_message(attribute, message, options)
+ message ||= :invalid
+
+ if message.is_a?(Symbol)
+ generate_message(attribute, message, options.except(*CALLBACKS_OPTIONS))
+ elsif message.is_a?(Proc)
+ message.call
+ else
+ message
+ end
+ end
end
class StrictValidationFailed < StandardError
diff --git a/activemodel/lib/active_model/naming.rb b/activemodel/lib/active_model/naming.rb
index f16459ede2..2566920d63 100644
--- a/activemodel/lib/active_model/naming.rb
+++ b/activemodel/lib/active_model/naming.rb
@@ -13,18 +13,18 @@ module ActiveModel
def initialize(klass, namespace = nil, name = nil)
name ||= klass.name
super(name)
- @unnamespaced = self.sub(/^#{namespace.name}::/, '') if namespace
- @klass = klass
- @singular = _singularize(self).freeze
- @plural = ActiveSupport::Inflector.pluralize(@singular).freeze
- @element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self)).freeze
- @human = ActiveSupport::Inflector.humanize(@element).freeze
- @collection = ActiveSupport::Inflector.tableize(self).freeze
+ @unnamespaced = self.sub(/^#{namespace.name}::/, '') if namespace
+ @klass = klass
+ @singular = _singularize(self).freeze
+ @plural = ActiveSupport::Inflector.pluralize(@singular).freeze
+ @element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self)).freeze
+ @human = ActiveSupport::Inflector.humanize(@element).freeze
+ @collection = ActiveSupport::Inflector.tableize(self).freeze
@partial_path = "#{@collection}/#{@element}".freeze
- @param_key = (namespace ? _singularize(@unnamespaced) : @singular).freeze
- @route_key = (namespace ? ActiveSupport::Inflector.pluralize(@param_key) : @plural).freeze
- @i18n_key = self.underscore.to_sym
+ @param_key = (namespace ? _singularize(@unnamespaced) : @singular).freeze
+ @route_key = (namespace ? ActiveSupport::Inflector.pluralize(@param_key) : @plural).freeze
+ @i18n_key = self.underscore.to_sym
end
# Transform the model name into a more humane format, using I18n. By default,
@@ -79,7 +79,9 @@ module ActiveModel
# used to retrieve all kinds of naming-related information.
def model_name
@_model_name ||= begin
- namespace = self.parents.detect { |n| n.respond_to?(:_railtie) }
+ namespace = self.parents.detect do |n|
+ n.respond_to?(:use_relative_model_naming?) && n.use_relative_model_naming?
+ end
ActiveModel::Name.new(self, namespace)
end
end
diff --git a/activemodel/lib/active_model/observing.rb b/activemodel/lib/active_model/observing.rb
index 7a910d18e7..cd8eb357de 100644
--- a/activemodel/lib/active_model/observing.rb
+++ b/activemodel/lib/active_model/observing.rb
@@ -187,8 +187,7 @@ module ActiveModel
def observe(*models)
models.flatten!
models.collect! { |model| model.respond_to?(:to_sym) ? model.to_s.camelize.constantize : model }
- remove_possible_method(:observed_classes)
- define_method(:observed_classes) { models }
+ redefine_method(:observed_classes) { models }
end
# Returns an array of Classes to observe.
diff --git a/activemodel/lib/active_model/secure_password.rb b/activemodel/lib/active_model/secure_password.rb
index 7a109d9a52..db78864c67 100644
--- a/activemodel/lib/active_model/secure_password.rb
+++ b/activemodel/lib/active_model/secure_password.rb
@@ -32,8 +32,8 @@ module ActiveModel
# User.find_by_name("david").try(:authenticate, "notright") # => nil
# User.find_by_name("david").try(:authenticate, "mUc3m00RsqyRe") # => user
def has_secure_password
- # Load bcrypt-ruby only when has_secured_password is used to avoid make ActiveModel
- # (and by extension the entire framework) dependent on a binary library.
+ # Load bcrypt-ruby only when has_secure_password is used.
+ # This is to avoid ActiveModel (and by extension the entire framework) being dependent on a binary library.
gem 'bcrypt-ruby', '~> 3.0.0'
require 'bcrypt'
diff --git a/activemodel/lib/active_model/validations/validates.rb b/activemodel/lib/active_model/validations/validates.rb
index fbceb81e8f..8e09f6ac35 100644
--- a/activemodel/lib/active_model/validations/validates.rb
+++ b/activemodel/lib/active_model/validations/validates.rb
@@ -57,7 +57,7 @@ module ActiveModel
#
# Additionally validator classes may be in another namespace and still used within any class.
#
- # validates :name, :'file/title' => true
+ # validates :name, :'film/title' => true
#
# The validators hash can also handle regular expressions, ranges,
# arrays and strings in shortcut form, e.g.
diff --git a/activemodel/lib/active_model/validator.rb b/activemodel/lib/active_model/validator.rb
index 0e444738ba..35ec98c822 100644
--- a/activemodel/lib/active_model/validator.rb
+++ b/activemodel/lib/active_model/validator.rb
@@ -57,7 +57,7 @@ module ActiveModel #:nodoc:
# To add behavior to the initialize method, use the following signature:
#
# class MyValidator < ActiveModel::Validator
- # def initialize(record, options)
+ # def initialize(options)
# super
# @my_custom_field = options[:field_name] || :first_name
# end