devise 4.7.1 → 4.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -4
  3. data/MIT-LICENSE +2 -1
  4. data/README.md +68 -61
  5. data/app/controllers/devise_controller.rb +2 -2
  6. data/app/helpers/devise_helper.rb +18 -6
  7. data/app/mailers/devise/mailer.rb +5 -5
  8. data/app/views/devise/shared/_links.html.erb +1 -1
  9. data/config/locales/en.yml +2 -2
  10. data/lib/devise.rb +1 -5
  11. data/lib/devise/controllers/helpers.rb +7 -7
  12. data/lib/devise/controllers/sign_in_out.rb +6 -4
  13. data/lib/devise/controllers/url_helpers.rb +1 -1
  14. data/lib/devise/failure_app.rb +2 -3
  15. data/lib/devise/hooks/lockable.rb +2 -5
  16. data/lib/devise/hooks/timeoutable.rb +2 -2
  17. data/lib/devise/mapping.rb +1 -1
  18. data/lib/devise/models/authenticatable.rb +12 -7
  19. data/lib/devise/models/confirmable.rb +2 -2
  20. data/lib/devise/models/database_authenticatable.rb +5 -1
  21. data/lib/devise/models/lockable.rb +10 -2
  22. data/lib/devise/models/recoverable.rb +2 -2
  23. data/lib/devise/models/rememberable.rb +1 -1
  24. data/lib/devise/models/trackable.rb +1 -1
  25. data/lib/devise/omniauth.rb +2 -5
  26. data/lib/devise/rails/deprecated_constant_accessor.rb +39 -0
  27. data/lib/devise/rails/routes.rb +4 -4
  28. data/lib/devise/test/controller_helpers.rb +3 -1
  29. data/lib/devise/test/integration_helpers.rb +1 -1
  30. data/lib/devise/version.rb +1 -1
  31. data/lib/generators/active_record/devise_generator.rb +17 -2
  32. data/lib/generators/devise/devise_generator.rb +1 -1
  33. data/lib/generators/devise/install_generator.rb +1 -5
  34. data/lib/generators/devise/views_generator.rb +1 -1
  35. data/lib/generators/templates/README +9 -1
  36. data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +1 -1
  37. data/lib/generators/templates/devise.rb +15 -3
  38. metadata +9 -8
@@ -20,6 +20,6 @@
20
20
 
21
21
  <%- if devise_mapping.omniauthable? %>
22
22
  <%- resource_class.omniauth_providers.each do |provider| %>
23
- <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) %><br />
23
+ <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), method: :post %><br />
24
24
  <% end %>
25
25
  <% end %>
@@ -1,4 +1,4 @@
1
- # Additional translations at https://github.com/plataformatec/devise/wiki/I18n
1
+ # Additional translations at https://github.com/heartcombo/devise/wiki/I18n
2
2
 
3
3
  en:
4
4
  devise:
@@ -44,7 +44,7 @@ en:
44
44
  signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account."
45
45
  update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirmation link to confirm your new email address."
46
46
  updated: "Your account has been updated successfully."
47
- updated_but_not_signed_in: "Your account has been updated successfully, but since your password was changed, you need to sign in again"
47
+ updated_but_not_signed_in: "Your account has been updated successfully, but since your password was changed, you need to sign in again."
48
48
  sessions:
49
49
  signed_in: "Signed in successfully."
50
50
  signed_out: "Signed out successfully."
data/lib/devise.rb CHANGED
@@ -71,7 +71,7 @@ module Devise
71
71
 
72
72
  # The number of times to hash the password.
73
73
  mattr_accessor :stretches
74
- @@stretches = 11
74
+ @@stretches = 12
75
75
 
76
76
  # The default key used when authenticating over http auth.
77
77
  mattr_accessor :http_authentication_key
@@ -297,10 +297,6 @@ module Devise
297
297
  mattr_accessor :sign_in_after_change_password
298
298
  @@sign_in_after_change_password = true
299
299
 
300
- def self.rails51? # :nodoc:
301
- Rails.gem_version >= Gem::Version.new("5.1.x")
302
- end
303
-
304
300
  def self.activerecord51? # :nodoc:
305
301
  defined?(ActiveRecord) && ActiveRecord.gem_version >= Gem::Version.new("5.1.x")
306
302
  end
@@ -36,14 +36,14 @@ module Devise
36
36
  # before_action ->{ authenticate_blogger! :admin } # Redirects to the admin login page
37
37
  # current_blogger :user # Preferably returns a User if one is signed in
38
38
  #
39
- def devise_group(group_name, opts={})
39
+ def devise_group(group_name, opts = {})
40
40
  mappings = "[#{ opts[:contains].map { |m| ":#{m}" }.join(',') }]"
41
41
 
42
42
  class_eval <<-METHODS, __FILE__, __LINE__ + 1
43
- def authenticate_#{group_name}!(favourite=nil, opts={})
43
+ def authenticate_#{group_name}!(favorite = nil, opts = {})
44
44
  unless #{group_name}_signed_in?
45
45
  mappings = #{mappings}
46
- mappings.unshift mappings.delete(favourite.to_sym) if favourite
46
+ mappings.unshift mappings.delete(favorite.to_sym) if favorite
47
47
  mappings.each do |mapping|
48
48
  opts[:scope] = mapping
49
49
  warden.authenticate!(opts) if !devise_controller? || opts.delete(:force)
@@ -57,9 +57,9 @@ module Devise
57
57
  end
58
58
  end
59
59
 
60
- def current_#{group_name}(favourite=nil)
60
+ def current_#{group_name}(favorite = nil)
61
61
  mappings = #{mappings}
62
- mappings.unshift mappings.delete(favourite.to_sym) if favourite
62
+ mappings.unshift mappings.delete(favorite.to_sym) if favorite
63
63
  mappings.each do |mapping|
64
64
  current = warden.authenticate(scope: mapping)
65
65
  return current if current
@@ -113,7 +113,7 @@ module Devise
113
113
  mapping = mapping.name
114
114
 
115
115
  class_eval <<-METHODS, __FILE__, __LINE__ + 1
116
- def authenticate_#{mapping}!(opts={})
116
+ def authenticate_#{mapping}!(opts = {})
117
117
  opts[:scope] = :#{mapping}
118
118
  warden.authenticate!(opts) if !devise_controller? || opts.delete(:force)
119
119
  end
@@ -252,7 +252,7 @@ module Devise
252
252
  # Overwrite Rails' handle unverified request to sign out all scopes,
253
253
  # clear run strategies and remove cached variables.
254
254
  def handle_unverified_request
255
- super # call the default behaviour which resets/nullifies/raises
255
+ super # call the default behavior which resets/nullifies/raises
256
256
  request.env["devise.skip_storage"] = true
257
257
  sign_out_all_scopes(false)
258
258
  end
@@ -10,7 +10,7 @@ module Devise
10
10
  # cause exceptions to be thrown from this method; if you simply want to check
11
11
  # if a scope has already previously been authenticated without running
12
12
  # authentication hooks, you can directly call `warden.authenticated?(scope: scope)`
13
- def signed_in?(scope=nil)
13
+ def signed_in?(scope = nil)
14
14
  [scope || Devise.mappings.keys].flatten.any? do |_scope|
15
15
  warden.authenticate?(scope: _scope)
16
16
  end
@@ -21,7 +21,7 @@ module Devise
21
21
  # to the set_user method in warden.
22
22
  # If you are using a custom warden strategy and the timeoutable module, you have to
23
23
  # set `env["devise.skip_timeout"] = true` in the request to use this method, like we do
24
- # in the sessions controller: https://github.com/plataformatec/devise/blob/master/app/controllers/devise/sessions_controller.rb#L7
24
+ # in the sessions controller: https://github.com/heartcombo/devise/blob/master/app/controllers/devise/sessions_controller.rb#L7
25
25
  #
26
26
  # Examples:
27
27
  #
@@ -77,7 +77,7 @@ module Devise
77
77
  # sign_out :user # sign_out(scope)
78
78
  # sign_out @user # sign_out(resource)
79
79
  #
80
- def sign_out(resource_or_scope=nil)
80
+ def sign_out(resource_or_scope = nil)
81
81
  return sign_out_all_scopes unless resource_or_scope
82
82
  scope = Devise::Mapping.find_scope!(resource_or_scope)
83
83
  user = warden.user(scope: scope, run_callbacks: false) # If there is no user
@@ -92,7 +92,7 @@ module Devise
92
92
  # Sign out all active users or scopes. This helper is useful for signing out all roles
93
93
  # in one click. This signs out ALL scopes in warden. Returns true if there was at least one logout
94
94
  # and false if there was no user logged in on all scopes.
95
- def sign_out_all_scopes(lock=true)
95
+ def sign_out_all_scopes(lock = true)
96
96
  users = Devise.mappings.keys.map { |s| warden.user(scope: s, run_callbacks: false) }
97
97
 
98
98
  warden.logout
@@ -106,10 +106,12 @@ module Devise
106
106
  private
107
107
 
108
108
  def expire_data_after_sign_in!
109
+ # TODO: remove once Rails 5.2+ and forward are only supported.
109
110
  # session.keys will return an empty array if the session is not yet loaded.
110
111
  # This is a bug in both Rack and Rails.
111
112
  # A call to #empty? forces the session to be loaded.
112
113
  session.empty?
114
+
113
115
  session.keys.grep(/^devise\./).each { |k| session.delete(k) }
114
116
  end
115
117
 
@@ -34,7 +34,7 @@ module Devise
34
34
  end
35
35
  end
36
36
 
37
- def self.generate_helpers!(routes=nil)
37
+ def self.generate_helpers!(routes = nil)
38
38
  routes ||= begin
39
39
  mappings = Devise.mappings.values.map(&:used_helpers).flatten.uniq
40
40
  Devise::URL_HELPERS.slice(*mappings)
@@ -71,7 +71,6 @@ module Devise
71
71
  end
72
72
 
73
73
  flash.now[:alert] = i18n_message(:invalid) if is_flashing_format?
74
- # self.response = recall_app(warden_options[:recall]).call(env)
75
74
  self.response = recall_app(warden_options[:recall]).call(request.env)
76
75
  end
77
76
 
@@ -107,7 +106,7 @@ module Devise
107
106
  options[:authentication_keys] = keys.join(I18n.translate(:"support.array.words_connector"))
108
107
  options = i18n_options(options)
109
108
 
110
- I18n.t(:"#{scope}.#{message}", options)
109
+ I18n.t(:"#{scope}.#{message}", **options)
111
110
  else
112
111
  message.to_s
113
112
  end
@@ -152,7 +151,7 @@ module Devise
152
151
 
153
152
  # We need to add the rootpath to `script_name` manually for applications that use a Rails
154
153
  # version lower than 5.1. Otherwise, it is going to generate a wrong path for Engines
155
- # that use Devise. Remove it when the support of Rails 5.0 is droped.
154
+ # that use Devise. Remove it when the support of Rails 5.0 is dropped.
156
155
  elsif root_path_defined?(context) && !rails_51_and_up?
157
156
  rootpath = context.routes.url_helpers.root_path
158
157
  opts[:script_name] = rootpath.chomp('/') if rootpath.length > 1
@@ -3,10 +3,7 @@
3
3
  # After each sign in, if resource responds to failed_attempts, sets it to 0
4
4
  # This is only triggered when the user is explicitly set (with set_user)
5
5
  Warden::Manager.after_set_user except: :fetch do |record, warden, options|
6
- if record.respond_to?(:failed_attempts) && warden.authenticated?(options[:scope])
7
- unless record.failed_attempts.to_i.zero?
8
- record.failed_attempts = 0
9
- record.save(validate: false)
10
- end
6
+ if record.respond_to?(:reset_failed_attempts!) && warden.authenticated?(options[:scope])
7
+ record.reset_failed_attempts!
11
8
  end
12
9
  end
@@ -21,8 +21,8 @@ Warden::Manager.after_set_user do |record, warden, options|
21
21
 
22
22
  proxy = Devise::Hooks::Proxy.new(warden)
23
23
 
24
- if record.timedout?(last_request_at) &&
25
- !env['devise.skip_timeout'] &&
24
+ if !env['devise.skip_timeout'] &&
25
+ record.timedout?(last_request_at) &&
26
26
  !proxy.remember_me_is_active?(record)
27
27
  Devise.sign_out_all_scopes ? proxy.sign_out : proxy.sign_out(scope)
28
28
  throw :warden, scope: scope, message: :timeout
@@ -46,7 +46,7 @@ module Devise
46
46
  raise "Could not find a valid mapping for #{obj.inspect}"
47
47
  end
48
48
 
49
- def self.find_by_path!(path, path_type=:fullpath)
49
+ def self.find_by_path!(path, path_type = :fullpath)
50
50
  Devise.mappings.each_value { |m| return m if path.include?(m.send(path_type)) }
51
51
  raise "Could not find a valid mapping for path #{path.inspect}"
52
52
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'devise/hooks/activatable'
4
4
  require 'devise/hooks/csrf_cleaner'
5
+ require 'devise/rails/deprecated_constant_accessor'
5
6
 
6
7
  module Devise
7
8
  module Models
@@ -55,11 +56,14 @@ module Devise
55
56
  module Authenticatable
56
57
  extend ActiveSupport::Concern
57
58
 
58
- BLACKLIST_FOR_SERIALIZATION = [:encrypted_password, :reset_password_token, :reset_password_sent_at,
59
+ UNSAFE_ATTRIBUTES_FOR_SERIALIZATION = [:encrypted_password, :reset_password_token, :reset_password_sent_at,
59
60
  :remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip,
60
61
  :last_sign_in_ip, :password_salt, :confirmation_token, :confirmed_at, :confirmation_sent_at,
61
62
  :remember_token, :unconfirmed_email, :failed_attempts, :unlock_token, :locked_at]
62
63
 
64
+ include Devise::DeprecatedConstantAccessor
65
+ deprecate_constant "BLACKLIST_FOR_SERIALIZATION", "Devise::Models::Authenticatable::UNSAFE_ATTRIBUTES_FOR_SERIALIZATION"
66
+
63
67
  included do
64
68
  class_attribute :devise_modules, instance_writer: false
65
69
  self.devise_modules ||= []
@@ -104,12 +108,12 @@ module Devise
104
108
  # given to :except will simply add names to exempt to Devise internal list.
105
109
  def serializable_hash(options = nil)
106
110
  options = options.try(:dup) || {}
107
- options[:except] = Array(options[:except])
111
+ options[:except] = Array(options[:except]).dup
108
112
 
109
113
  if options[:force_except]
110
114
  options[:except].concat Array(options[:force_except])
111
115
  else
112
- options[:except].concat BLACKLIST_FOR_SERIALIZATION
116
+ options[:except].concat UNSAFE_ATTRIBUTES_FOR_SERIALIZATION
113
117
  end
114
118
 
115
119
  super(options)
@@ -152,7 +156,8 @@ module Devise
152
156
  # # If the record is new or changed then delay the
153
157
  # # delivery until the after_commit callback otherwise
154
158
  # # send now because after_commit will not be called.
155
- # if new_record? || changed?
159
+ # # For Rails < 6 use `changed?` instead of `saved_changes?`.
160
+ # if new_record? || saved_changes?
156
161
  # pending_devise_notifications << [notification, args]
157
162
  # else
158
163
  # render_and_send_devise_message(notification, *args)
@@ -271,17 +276,17 @@ module Devise
271
276
  find_first_by_auth_conditions(tainted_conditions)
272
277
  end
273
278
 
274
- def find_first_by_auth_conditions(tainted_conditions, opts={})
279
+ def find_first_by_auth_conditions(tainted_conditions, opts = {})
275
280
  to_adapter.find_first(devise_parameter_filter.filter(tainted_conditions).merge(opts))
276
281
  end
277
282
 
278
283
  # Find or initialize a record setting an error if it can't be found.
279
- def find_or_initialize_with_error_by(attribute, value, error=:invalid) #:nodoc:
284
+ def find_or_initialize_with_error_by(attribute, value, error = :invalid) #:nodoc:
280
285
  find_or_initialize_with_errors([attribute], { attribute => value }, error)
281
286
  end
282
287
 
283
288
  # Find or initialize a record with group of attributes based on a list of required attributes.
284
- def find_or_initialize_with_errors(required_attributes, attributes, error=:invalid) #:nodoc:
289
+ def find_or_initialize_with_errors(required_attributes, attributes, error = :invalid) #:nodoc:
285
290
  attributes.try(:permit!)
286
291
  attributes = attributes.to_h.with_indifferent_access
287
292
  .slice(*required_attributes)
@@ -76,7 +76,7 @@ module Devise
76
76
  # Confirm a user by setting it's confirmed_at to actual time. If the user
77
77
  # is already confirmed, add an error to email field. If the user is invalid
78
78
  # add errors
79
- def confirm(args={})
79
+ def confirm(args = {})
80
80
  pending_any_confirmation do
81
81
  if confirmation_period_expired?
82
82
  self.errors.add(:email, :confirmation_period_expired,
@@ -334,7 +334,7 @@ module Devise
334
334
  # confirmation instructions to it. If not, try searching for a user by unconfirmed_email
335
335
  # field. If no user is found, returns a new user with an email not found error.
336
336
  # Options must contain the user email
337
- def send_confirmation_instructions(attributes={})
337
+ def send_confirmation_instructions(attributes = {})
338
338
  confirmable = find_by_unconfirmed_email_with_errors(attributes) if reconfirmable
339
339
  unless confirmable.try(:persisted?)
340
340
  confirmable = find_or_initialize_with_errors(confirmation_keys, attributes, :not_found)
@@ -7,6 +7,10 @@ module Devise
7
7
  # Authenticatable Module, responsible for hashing the password and
8
8
  # validating the authenticity of a user while signing in.
9
9
  #
10
+ # This module defines a `password=` method. This method will hash the argument
11
+ # and store it in the `encrypted_password` column, bypassing any pre-existing
12
+ # `password` column if it exists.
13
+ #
10
14
  # == Options
11
15
  #
12
16
  # DatabaseAuthenticatable adds the following options to devise_for:
@@ -195,7 +199,7 @@ module Devise
195
199
  # Hashes the password using bcrypt. Custom hash functions should override
196
200
  # this method to apply their own algorithm.
197
201
  #
198
- # See https://github.com/plataformatec/devise-encryptable for examples
202
+ # See https://github.com/heartcombo/devise-encryptable for examples
199
203
  # of other hashing engines.
200
204
  def password_digest(password)
201
205
  Devise::Encryptor.digest(self.class, password)
@@ -57,6 +57,14 @@ module Devise
57
57
  save(validate: false)
58
58
  end
59
59
 
60
+ # Resets failed attempts counter to 0.
61
+ def reset_failed_attempts!
62
+ if respond_to?(:failed_attempts) && !failed_attempts.to_i.zero?
63
+ self.failed_attempts = 0
64
+ save(validate: false)
65
+ end
66
+ end
67
+
60
68
  # Verifies whether a user is locked or not.
61
69
  def access_locked?
62
70
  !!locked_at && !lock_expired?
@@ -110,7 +118,7 @@ module Devise
110
118
  false
111
119
  end
112
120
  end
113
-
121
+
114
122
  def increment_failed_attempts
115
123
  self.class.increment_counter(:failed_attempts, id)
116
124
  reload
@@ -168,7 +176,7 @@ module Devise
168
176
  # unlock instructions to it. If not user is found, returns a new user
169
177
  # with an email not found error.
170
178
  # Options must contain the user's unlock keys
171
- def send_unlock_instructions(attributes={})
179
+ def send_unlock_instructions(attributes = {})
172
180
  lockable = find_or_initialize_with_errors(unlock_keys, attributes, :not_found)
173
181
  lockable.resend_unlock_instructions if lockable.persisted?
174
182
  lockable
@@ -131,7 +131,7 @@ module Devise
131
131
  # password instructions to it. If user is not found, returns a new user
132
132
  # with an email not found error.
133
133
  # Attributes must contain the user's email
134
- def send_reset_password_instructions(attributes={})
134
+ def send_reset_password_instructions(attributes = {})
135
135
  recoverable = find_or_initialize_with_errors(reset_password_keys, attributes, :not_found)
136
136
  recoverable.send_reset_password_instructions if recoverable.persisted?
137
137
  recoverable
@@ -142,7 +142,7 @@ module Devise
142
142
  # try saving the record. If not user is found, returns a new user
143
143
  # containing an error in reset_password_token attribute.
144
144
  # Attributes must contain reset_password_token, password and confirmation
145
- def reset_password_by_token(attributes={})
145
+ def reset_password_by_token(attributes = {})
146
146
  original_token = attributes[:reset_password_token]
147
147
  reset_password_token = Devise.token_generator.digest(self, :reset_password_token, original_token)
148
148
 
@@ -102,7 +102,7 @@ module Devise
102
102
 
103
103
  def remember_me?(token, generated_at)
104
104
  # TODO: Normalize the JSON type coercion along with the Timeoutable hook
105
- # in a single place https://github.com/plataformatec/devise/blob/ffe9d6d406e79108cf32a2c6a1d0b3828849c40b/lib/devise/hooks/timeoutable.rb#L14-L18
105
+ # in a single place https://github.com/heartcombo/devise/blob/ffe9d6d406e79108cf32a2c6a1d0b3828849c40b/lib/devise/hooks/timeoutable.rb#L14-L18
106
106
  if generated_at.is_a?(String)
107
107
  generated_at = time_from_json(generated_at)
108
108
  end
@@ -33,7 +33,7 @@ module Devise
33
33
  def update_tracked_fields!(request)
34
34
  # We have to check if the user is already persisted before running
35
35
  # `save` here because invalid users can be saved if we don't.
36
- # See https://github.com/plataformatec/devise/issues/4673 for more details.
36
+ # See https://github.com/heartcombo/devise/issues/4673 for more details.
37
37
  return if new_record?
38
38
 
39
39
  update_tracked_fields(request)
@@ -1,17 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  begin
4
+ gem "omniauth", ">= 1.0.0"
5
+
4
6
  require "omniauth"
5
- require "omniauth/version"
6
7
  rescue LoadError
7
8
  warn "Could not load 'omniauth'. Please ensure you have the omniauth gem >= 1.0.0 installed and listed in your Gemfile."
8
9
  raise
9
10
  end
10
11
 
11
- unless OmniAuth::VERSION =~ /^1\./
12
- raise "You are using an old OmniAuth version, please ensure you have 1.0.0.pr2 version or later installed."
13
- end
14
-
15
12
  # Clean up the default path_prefix. It will be automatically set by Devise.
16
13
  OmniAuth.config.path_prefix = nil
17
14
 
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'active_support/deprecation/constant_accessor'
5
+
6
+ module Devise
7
+ DeprecatedConstantAccessor = ActiveSupport::Deprecation::DeprecatedConstantAccessor #:nodoc:
8
+ end
9
+ rescue LoadError
10
+
11
+ # Copy of constant deprecation module from Rails / Active Support version 6, so we can use it
12
+ # with Rails <= 5.0 versions. This can be removed once we support only Rails 5.1 or greater.
13
+ module Devise
14
+ module DeprecatedConstantAccessor #:nodoc:
15
+ def self.included(base)
16
+ require "active_support/inflector/methods"
17
+
18
+ extension = Module.new do
19
+ def const_missing(missing_const_name)
20
+ if class_variable_defined?(:@@_deprecated_constants)
21
+ if (replacement = class_variable_get(:@@_deprecated_constants)[missing_const_name.to_s])
22
+ replacement[:deprecator].warn(replacement[:message] || "#{name}::#{missing_const_name} is deprecated! Use #{replacement[:new]} instead.", Rails::VERSION::MAJOR == 4 ? caller : caller_locations)
23
+ return ActiveSupport::Inflector.constantize(replacement[:new].to_s)
24
+ end
25
+ end
26
+ super
27
+ end
28
+
29
+ def deprecate_constant(const_name, new_constant, message: nil, deprecator: ActiveSupport::Deprecation.instance)
30
+ class_variable_set(:@@_deprecated_constants, {}) unless class_variable_defined?(:@@_deprecated_constants)
31
+ class_variable_get(:@@_deprecated_constants)[const_name.to_s] = { new: new_constant, message: message, deprecator: deprecator }
32
+ end
33
+ end
34
+ base.singleton_class.prepend extension
35
+ end
36
+ end
37
+ end
38
+
39
+ end