activemodel 5.1.7 → 5.2.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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))