summaryrefslogtreecommitdiff
path: root/lib/rubygems/deprecate.rb
blob: 56505512c30e2a882c0d88c71d44a56fd4da8354 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# frozen_string_literal: true
##
# Provides 3 methods for declaring when something is going away.
#
# +deprecate(name, repl, year, month)+:
#     Indicate something may be removed on/after a certain date.
#
# +rubygems_deprecate(name, replacement=:none)+:
#     Indicate something will be removed in the next major RubyGems version,
#     and (optionally) a replacement for it.
#
# +rubygems_deprecate_command+:
#     Indicate a RubyGems command (in +lib/rubygems/commands/*.rb+) will be
#     removed in the next RubyGems version.
#
# Also provides +skip_during+ for temporarily turning off deprecation warnings.
# This is intended to be used in the test suite, so deprecation warnings
# don't cause test failures if you need to make sure stderr is otherwise empty.
#
#
# Example usage of +deprecate+ and +rubygems_deprecate+:
#
#     class Legacy
#       def self.some_class_method
#         # ...
#       end
#
#       def some_instance_method
#         # ...
#       end
#
#       def some_old_method
#         # ...
#       end
#
#       extend Gem::Deprecate
#       deprecate :some_instance_method, "X.z", 2011, 4
#       rubygems_deprecate :some_old_method, "Modern#some_new_method"
#
#       class << self
#         extend Gem::Deprecate
#         deprecate :some_class_method, :none, 2011, 4
#       end
#     end
#
#
# Example usage of +rubygems_deprecate_command+:
#
#     class Gem::Commands::QueryCommand < Gem::Command
#       extend Gem::Deprecate
#       rubygems_deprecate_command
#
#       # ...
#     end
#
#
# Example usage of +skip_during+:
#
#     class TestSomething < Gem::Testcase
#       def test_some_thing_with_deprecations
#         Gem::Deprecate.skip_during do
#           actual_stdout, actual_stderr = capture_output do
#             Gem.something_deprecated
#           end
#           assert_empty actual_stdout
#           assert_equal(expected, actual_stderr)
#         end
#       end
#     end

module Gem::Deprecate

  def self.skip # :nodoc:
    @skip ||= false
  end

  def self.skip=(v) # :nodoc:
    @skip = v
  end

  ##
  # Temporarily turn off warnings. Intended for tests only.

  def skip_during
    Gem::Deprecate.skip, original = true, Gem::Deprecate.skip
    yield
  ensure
    Gem::Deprecate.skip = original
  end

  def self.next_rubygems_major_version # :nodoc:
    Gem::Version.new(Gem.rubygems_version.segments.first).bump
  end

  ##
  # Simple deprecation method that deprecates +name+ by wrapping it up
  # in a dummy method. It warns on each call to the dummy method
  # telling the user of +repl+ (unless +repl+ is :none) and the
  # year/month that it is planned to go away.

  def deprecate(name, repl, year, month)
    class_eval do
      old = "_deprecated_#{name}"
      alias_method old, name
      define_method name do |*args, &block|
        klass = self.kind_of? Module
        target = klass ? "#{self}." : "#{self.class}#"
        msg = [ "NOTE: #{target}#{name} is deprecated",
                repl == :none ? " with no replacement" : "; use #{repl} instead",
                ". It will be removed on or after %4d-%02d." % [year, month],
                "\n#{target}#{name} called from #{Gem.location_of_caller.join(":")}",
        ]
        warn "#{msg.join}." unless Gem::Deprecate.skip
        send old, *args, &block
      end
      ruby2_keywords name if respond_to?(:ruby2_keywords, true)
    end
  end

  ##
  # Simple deprecation method that deprecates +name+ by wrapping it up
  # in a dummy method. It warns on each call to the dummy method
  # telling the user of +repl+ (unless +repl+ is :none) and the
  # Rubygems version that it is planned to go away.

  def rubygems_deprecate(name, replacement=:none)
    class_eval do
      old = "_deprecated_#{name}"
      alias_method old, name
      define_method name do |*args, &block|
        klass = self.kind_of? Module
        target = klass ? "#{self}." : "#{self.class}#"
        msg = [ "NOTE: #{target}#{name} is deprecated",
                replacement == :none ? " with no replacement" : "; use #{replacement} instead",
                ". It will be removed in Rubygems #{Gem::Deprecate.next_rubygems_major_version}",
                "\n#{target}#{name} called from #{Gem.location_of_caller.join(":")}",
        ]
        warn "#{msg.join}." unless Gem::Deprecate.skip
        send old, *args, &block
      end
      ruby2_keywords name if respond_to?(:ruby2_keywords, true)
    end
  end

  # Deprecation method to deprecate Rubygems commands
  def rubygems_deprecate_command(version = Gem::Deprecate.next_rubygems_major_version)
    class_eval do
      define_method "deprecated?" do
        true
      end

      define_method "deprecation_warning" do
        msg = [ "#{self.command} command is deprecated",
                ". It will be removed in Rubygems #{version}.\n",
        ]

        alert_warning "#{msg.join}" unless Gem::Deprecate.skip
      end
    end
  end

  module_function :rubygems_deprecate, :rubygems_deprecate_command, :skip_during

end