activemodel 5.1.7 → 5.2.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +32 -93
  3. data/README.rdoc +1 -1
  4. data/lib/active_model.rb +6 -1
  5. data/lib/active_model/attribute.rb +243 -0
  6. data/lib/active_model/attribute/user_provided_default.rb +30 -0
  7. data/lib/active_model/attribute_assignment.rb +8 -5
  8. data/lib/active_model/attribute_methods.rb +12 -10
  9. data/lib/active_model/attribute_mutation_tracker.rb +116 -0
  10. data/lib/active_model/attribute_set.rb +113 -0
  11. data/lib/active_model/attribute_set/builder.rb +124 -0
  12. data/lib/active_model/attribute_set/yaml_encoder.rb +41 -0
  13. data/lib/active_model/attributes.rb +108 -0
  14. data/lib/active_model/callbacks.rb +7 -2
  15. data/lib/active_model/conversion.rb +2 -0
  16. data/lib/active_model/dirty.rb +124 -57
  17. data/lib/active_model/errors.rb +32 -21
  18. data/lib/active_model/forbidden_attributes_protection.rb +2 -0
  19. data/lib/active_model/gem_version.rb +5 -3
  20. data/lib/active_model/lint.rb +2 -0
  21. data/lib/active_model/model.rb +2 -0
  22. data/lib/active_model/naming.rb +5 -3
  23. data/lib/active_model/railtie.rb +2 -0
  24. data/lib/active_model/secure_password.rb +5 -3
  25. data/lib/active_model/serialization.rb +2 -0
  26. data/lib/active_model/serializers/json.rb +3 -2
  27. data/lib/active_model/translation.rb +2 -0
  28. data/lib/active_model/type.rb +6 -0
  29. data/lib/active_model/type/big_integer.rb +2 -0
  30. data/lib/active_model/type/binary.rb +2 -0
  31. data/lib/active_model/type/boolean.rb +2 -0
  32. data/lib/active_model/type/date.rb +2 -0
  33. data/lib/active_model/type/date_time.rb +6 -0
  34. data/lib/active_model/type/decimal.rb +2 -0
  35. data/lib/active_model/type/float.rb +2 -0
  36. data/lib/active_model/type/helpers.rb +2 -0
  37. data/lib/active_model/type/helpers/accepts_multiparameter_time.rb +6 -0
  38. data/lib/active_model/type/helpers/mutable.rb +2 -0
  39. data/lib/active_model/type/helpers/numeric.rb +2 -0
  40. data/lib/active_model/type/helpers/time_value.rb +2 -1
  41. data/lib/active_model/type/immutable_string.rb +2 -0
  42. data/lib/active_model/type/integer.rb +3 -1
  43. data/lib/active_model/type/registry.rb +2 -0
  44. data/lib/active_model/type/string.rb +2 -0
  45. data/lib/active_model/type/time.rb +8 -4
  46. data/lib/active_model/type/value.rb +3 -1
  47. data/lib/active_model/validations.rb +7 -3
  48. data/lib/active_model/validations/absence.rb +2 -0
  49. data/lib/active_model/validations/acceptance.rb +2 -0
  50. data/lib/active_model/validations/callbacks.rb +11 -13
  51. data/lib/active_model/validations/clusivity.rb +2 -0
  52. data/lib/active_model/validations/confirmation.rb +3 -1
  53. data/lib/active_model/validations/exclusion.rb +2 -0
  54. data/lib/active_model/validations/format.rb +1 -0
  55. data/lib/active_model/validations/helper_methods.rb +2 -0
  56. data/lib/active_model/validations/inclusion.rb +2 -0
  57. data/lib/active_model/validations/length.rb +10 -2
  58. data/lib/active_model/validations/numericality.rb +3 -1
  59. data/lib/active_model/validations/presence.rb +1 -0
  60. data/lib/active_model/validations/validates.rb +4 -3
  61. data/lib/active_model/validations/with.rb +2 -0
  62. data/lib/active_model/validator.rb +6 -4
  63. data/lib/active_model/version.rb +2 -0
  64. metadata +17 -9
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  # Raised when forbidden attributes are used for mass assignment.
3
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  # Returns the version of the currently loaded \Active \Model as a <tt>Gem::Version</tt>
3
5
  def self.gem_version
@@ -6,9 +8,9 @@ module ActiveModel
6
8
 
7
9
  module VERSION
8
10
  MAJOR = 5
9
- MINOR = 1
10
- TINY = 7
11
- PRE = nil
11
+ MINOR = 2
12
+ TINY = 0
13
+ PRE = "beta1"
12
14
 
13
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
14
16
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  module Lint
3
5
  # == Active \Model \Lint \Tests
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  # == Active \Model \Basic \Model
3
5
  #
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/hash/except"
2
4
  require "active_support/core_ext/module/introspection"
3
- require "active_support/core_ext/module/remove_method"
5
+ require "active_support/core_ext/module/redefine_method"
4
6
 
5
7
  module ActiveModel
6
8
  class Name
@@ -47,7 +49,7 @@ module ActiveModel
47
49
  # :method: <=>
48
50
  #
49
51
  # :call-seq:
50
- # ==(other)
52
+ # <=>(other)
51
53
  #
52
54
  # Equivalent to <tt>String#<=></tt>.
53
55
  #
@@ -216,7 +218,7 @@ module ActiveModel
216
218
  # provided method below, or rolling your own is required.
217
219
  module Naming
218
220
  def self.extended(base) #:nodoc:
219
- base.remove_possible_method :model_name
221
+ base.silence_redefinition_of_method :model_name
220
222
  base.delegate :model_name, to: :class
221
223
  end
222
224
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_model"
2
4
  require "rails"
3
5
 
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  module SecurePassword
3
5
  extend ActiveSupport::Concern
4
6
 
5
- # BCrypt hash function can handle maximum 72 characters, and if we pass
6
- # password of length more than 72 characters it ignores extra characters.
7
+ # BCrypt hash function can handle maximum 72 bytes, and if we pass
8
+ # password of length more than 72 bytes it ignores extra characters.
7
9
  # Hence need to put a restriction on password length.
8
10
  MAX_PASSWORD_LENGTH_ALLOWED = 72
9
11
 
@@ -18,7 +20,7 @@ module ActiveModel
18
20
  #
19
21
  # The following validations are added automatically:
20
22
  # * Password must be present on creation
21
- # * Password length should be less than or equal to 72 characters
23
+ # * Password length should be less than or equal to 72 bytes
22
24
  # * Confirmation of password (using a +password_confirmation+ attribute)
23
25
  #
24
26
  # If password confirmation validation is not needed, simply leave out the
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/hash/except"
2
4
  require "active_support/core_ext/hash/slice"
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/json"
2
4
 
3
5
  module ActiveModel
@@ -10,8 +12,7 @@ module ActiveModel
10
12
  included do
11
13
  extend ActiveModel::Naming
12
14
 
13
- class_attribute :include_root_in_json, instance_writer: false
14
- self.include_root_in_json = false
15
+ class_attribute :include_root_in_json, instance_writer: false, default: false
15
16
  end
16
17
 
17
18
  # Returns a hash representing the model. Some configuration can be
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  # == Active \Model \Translation
3
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_model/type/helpers"
2
4
  require "active_model/type/value"
3
5
 
@@ -30,6 +32,10 @@ module ActiveModel
30
32
  def lookup(*args, **kwargs) # :nodoc:
31
33
  registry.lookup(*args, **kwargs)
32
34
  end
35
+
36
+ def default_value # :nodoc:
37
+ @default_value ||= Value.new
38
+ end
33
39
  end
34
40
 
35
41
  register(:big_integer, Type::BigInteger)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_model/type/integer"
2
4
 
3
5
  module ActiveModel
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  module Type
3
5
  class Binary < Value # :nodoc:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  module Type
3
5
  # == Active \Model \Type \Boolean
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  module Type
3
5
  class Date < Value # :nodoc:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  module Type
3
5
  class DateTime < Value # :nodoc:
@@ -10,6 +12,10 @@ module ActiveModel
10
12
  :datetime
11
13
  end
12
14
 
15
+ def serialize(value)
16
+ super(cast(value))
17
+ end
18
+
13
19
  private
14
20
 
15
21
  def cast_value(value)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bigdecimal/util"
2
4
 
3
5
  module ActiveModel
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  module Type
3
5
  class Float < Value # :nodoc:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_model/type/helpers/accepts_multiparameter_time"
2
4
  require "active_model/type/helpers/numeric"
3
5
  require "active_model/type/helpers/mutable"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  module Type
3
5
  module Helpers # :nodoc: all
@@ -19,6 +21,10 @@ module ActiveModel
19
21
  end
20
22
  end
21
23
 
24
+ define_method(:value_constructed_by_mass_assignment?) do |value|
25
+ value.is_a?(Hash)
26
+ end
27
+
22
28
  define_method(:value_from_multiparameter_assignment) do |values_hash|
23
29
  defaults.each do |k, v|
24
30
  values_hash[k] ||= v
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  module Type
3
5
  module Helpers # :nodoc: all
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  module Type
3
5
  module Helpers # :nodoc: all
@@ -1,4 +1,5 @@
1
- require "active_support/core_ext/string/zones"
1
+ # frozen_string_literal: true
2
+
2
3
  require "active_support/core_ext/time/zones"
3
4
 
4
5
  module ActiveModel
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  module Type
3
5
  class ImmutableString < Value # :nodoc:
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  module Type
3
5
  class Integer < Value # :nodoc:
4
6
  include Helpers::Numeric
5
7
 
6
8
  # Column storage size in bytes.
7
- # 4 bytes means a MySQL int or Postgres integer as opposed to smallint etc.
9
+ # 4 bytes means an integer as opposed to smallint etc.
8
10
  DEFAULT_LIMIT = 4
9
11
 
10
12
  def initialize(*)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  # :stopdoc:
3
5
  module Type
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_model/type/immutable_string"
2
4
 
3
5
  module ActiveModel
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  module Type
3
5
  class Time < Value # :nodoc:
@@ -16,8 +18,6 @@ module ActiveModel
16
18
  case value
17
19
  when ::String
18
20
  value = "2000-01-01 #{value}"
19
- time_hash = ::Date._parse(value)
20
- return if time_hash[:hour].nil?
21
21
  when ::Time
22
22
  value = value.change(year: 2000, day: 1, month: 1)
23
23
  end
@@ -28,10 +28,14 @@ module ActiveModel
28
28
  private
29
29
 
30
30
  def cast_value(value)
31
- return apply_seconds_precision(value) unless value.is_a?(::String)
31
+ return value unless value.is_a?(::String)
32
32
  return if value.empty?
33
33
 
34
- dummy_time_value = value.sub(/\A(\d\d\d\d-\d\d-\d\d |)/, "2000-01-01 ")
34
+ if value.start_with?("2000-01-01")
35
+ dummy_time_value = value
36
+ else
37
+ dummy_time_value = "2000-01-01 #{value}"
38
+ end
35
39
 
36
40
  fast_string_to_time(dummy_time_value) || begin
37
41
  time_hash = ::Date._parse(dummy_time_value)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  module Type
3
5
  class Value
@@ -84,7 +86,7 @@ module ActiveModel
84
86
  false
85
87
  end
86
88
 
87
- def force_equality?(_value) # :nodoc:
89
+ def value_constructed_by_mass_assignment?(_value) # :nodoc:
88
90
  false
89
91
  end
90
92
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/array/extract_options"
2
4
  require "active_support/core_ext/hash/keys"
3
5
  require "active_support/core_ext/hash/except"
@@ -49,8 +51,7 @@ module ActiveModel
49
51
  private :validation_context=
50
52
  define_callbacks :validate, scope: :name
51
53
 
52
- class_attribute :_validators, instance_writer: false
53
- self._validators = Hash.new { |h, k| h[k] = [] }
54
+ class_attribute :_validators, instance_writer: false, default: Hash.new { |h, k| h[k] = [] }
54
55
  end
55
56
 
56
57
  module ClassMethods
@@ -147,6 +148,9 @@ module ActiveModel
147
148
  # or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
148
149
  # method, proc or string should return or evaluate to a +true+ or +false+
149
150
  # value.
151
+ #
152
+ # NOTE: Calling +validate+ multiple times on the same method will overwrite previous definitions.
153
+ #
150
154
  def validate(*args, &block)
151
155
  options = args.extract_options!
152
156
 
@@ -432,4 +436,4 @@ module ActiveModel
432
436
  end
433
437
  end
434
438
 
435
- Dir[File.dirname(__FILE__) + "/validations/*.rb"].each { |file| require file }
439
+ Dir[File.expand_path("validations/*.rb", __dir__)].each { |file| require file }
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  module Validations
3
5
  # == \Active \Model Absence Validator
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  module Validations
3
5
  class AcceptanceValidator < EachValidator # :nodoc:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  module Validations
3
5
  # == Active \Model \Validation \Callbacks
@@ -52,16 +54,14 @@ module ActiveModel
52
54
  # person.valid? # => true
53
55
  # person.name # => "bob"
54
56
  def before_validation(*args, &block)
55
- options = args.extract_options!
56
- options[:if] = Array(options[:if])
57
-
58
- if options.key?(:on)
57
+ options = args.last
58
+ if options.is_a?(Hash) && options[:on]
59
+ options[:if] = Array(options[:if])
60
+ options[:on] = Array(options[:on])
59
61
  options[:if].unshift ->(o) {
60
- !(Array(options[:on]) & Array(o.validation_context)).empty?
62
+ options[:on].include? o.validation_context
61
63
  }
62
64
  end
63
-
64
- args << options
65
65
  set_callback(:validation, :before, *args, &block)
66
66
  end
67
67
 
@@ -95,15 +95,13 @@ module ActiveModel
95
95
  options = args.extract_options!
96
96
  options[:prepend] = true
97
97
  options[:if] = Array(options[:if])
98
-
99
- if options.key?(:on)
98
+ if options[:on]
99
+ options[:on] = Array(options[:on])
100
100
  options[:if].unshift ->(o) {
101
- !(Array(options[:on]) & Array(o.validation_context)).empty?
101
+ options[:on].include? o.validation_context
102
102
  }
103
103
  end
104
-
105
- args << options
106
- set_callback(:validation, :after, *args, &block)
104
+ set_callback(:validation, :after, *(args << options), &block)
107
105
  end
108
106
  end
109
107
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/range"
2
4
 
3
5
  module ActiveModel
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  module Validations
3
5
  class ConfirmationValidator < EachValidator # :nodoc:
@@ -7,7 +9,7 @@ module ActiveModel
7
9
  end
8
10
 
9
11
  def validate_each(record, attribute, value)
10
- if (confirmed = record.send("#{attribute}_confirmation"))
12
+ unless (confirmed = record.send("#{attribute}_confirmation")).nil?
11
13
  unless confirmation_value_equal?(record, attribute, value, confirmed)
12
14
  human_attribute_name = record.class.human_attribute_name(attribute)
13
15
  record.errors.add(:"#{attribute}_confirmation", :confirmation, options.except(:case_sensitive).merge!(attribute: human_attribute_name))