File: reporting.rb

package info (click to toggle)
rails 2%3A7.2.2.1%2Bdfsg-7
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 43,352 kB
  • sloc: ruby: 349,799; javascript: 30,703; yacc: 46; sql: 43; sh: 29; makefile: 27
file content (179 lines) | stat: -rw-r--r-- 6,707 bytes parent folder | download | duplicates (2)
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# frozen_string_literal: true

require "rbconfig"

module ActiveSupport
  class Deprecation
    module Reporting
      # Whether to print a message (silent mode)
      attr_writer :silenced
      # Name of gem where method is deprecated
      attr_accessor :gem_name

      # Outputs a deprecation warning to the output configured by
      # ActiveSupport::Deprecation#behavior.
      #
      #   ActiveSupport::Deprecation.new.warn('something broke!')
      #   # => "DEPRECATION WARNING: something broke! (called from your_code.rb:1)"
      def warn(message = nil, callstack = nil)
        return if silenced

        callstack ||= caller_locations(2)
        deprecation_message(callstack, message).tap do |full_message|
          if deprecation_disallowed?(message)
            disallowed_behavior.each { |b| b.call(full_message, callstack, self) }
          else
            behavior.each { |b| b.call(full_message, callstack, self) }
          end
        end
      end

      # Silence deprecation warnings within the block.
      #
      #   deprecator = ActiveSupport::Deprecation.new
      #   deprecator.warn('something broke!')
      #   # => "DEPRECATION WARNING: something broke! (called from your_code.rb:1)"
      #
      #   deprecator.silence do
      #     deprecator.warn('something broke!')
      #   end
      #   # => nil
      def silence(&block)
        begin_silence
        block.call
      ensure
        end_silence
      end

      def begin_silence # :nodoc:
        @silence_counter.value += 1
      end

      def end_silence # :nodoc:
        @silence_counter.value -= 1
      end

      def silenced
        @silenced || @silence_counter.value.nonzero?
      end

      # Allow previously disallowed deprecation warnings within the block.
      # <tt>allowed_warnings</tt> can be an array containing strings, symbols, or regular
      # expressions. (Symbols are treated as strings). These are compared against
      # the text of deprecation warning messages generated within the block.
      # Matching warnings will be exempt from the rules set by
      # ActiveSupport::Deprecation#disallowed_warnings.
      #
      # The optional <tt>if:</tt> argument accepts a truthy/falsy value or an object that
      # responds to <tt>.call</tt>. If truthy, then matching warnings will be allowed.
      # If falsey then the method yields to the block without allowing the warning.
      #
      #   deprecator = ActiveSupport::Deprecation.new
      #   deprecator.disallowed_behavior = :raise
      #   deprecator.disallowed_warnings = [
      #     "something broke"
      #   ]
      #
      #   deprecator.warn('something broke!')
      #   # => ActiveSupport::DeprecationException
      #
      #   deprecator.allow ['something broke'] do
      #     deprecator.warn('something broke!')
      #   end
      #   # => nil
      #
      #   deprecator.allow ['something broke'], if: Rails.env.production? do
      #     deprecator.warn('something broke!')
      #   end
      #   # => ActiveSupport::DeprecationException for dev/test, nil for production
      def allow(allowed_warnings = :all, if: true, &block)
        conditional = binding.local_variable_get(:if)
        conditional = conditional.call if conditional.respond_to?(:call)
        if conditional
          @explicitly_allowed_warnings.bind(allowed_warnings, &block)
        else
          yield
        end
      end

      def deprecation_warning(deprecated_method_name, message = nil, caller_backtrace = nil)
        caller_backtrace ||= caller_locations(2)
        deprecated_method_warning(deprecated_method_name, message).tap do |msg|
          warn(msg, caller_backtrace)
        end
      end

      private
        # Outputs a deprecation warning message
        #
        #   deprecated_method_warning(:method_name)
        #   # => "method_name is deprecated and will be removed from Rails #{deprecation_horizon}"
        #   deprecated_method_warning(:method_name, :another_method)
        #   # => "method_name is deprecated and will be removed from Rails #{deprecation_horizon} (use another_method instead)"
        #   deprecated_method_warning(:method_name, "Optional message")
        #   # => "method_name is deprecated and will be removed from Rails #{deprecation_horizon} (Optional message)"
        def deprecated_method_warning(method_name, message = nil)
          warning = "#{method_name} is deprecated and will be removed from #{gem_name} #{deprecation_horizon}"
          case message
          when Symbol then "#{warning} (use #{message} instead)"
          when String then "#{warning} (#{message})"
          else warning
          end
        end

        def deprecation_message(callstack, message = nil)
          message ||= "You are using deprecated behavior which will be removed from the next major or minor release."
          "DEPRECATION WARNING: #{message} #{deprecation_caller_message(callstack)}"
        end

        def deprecation_caller_message(callstack)
          file, line, method = extract_callstack(callstack)
          if file
            if line && method
              "(called from #{method} at #{file}:#{line})"
            else
              "(called from #{file}:#{line})"
            end
          end
        end

        def extract_callstack(callstack)
          return [] if callstack.empty?
          return _extract_callstack(callstack) if callstack.first.is_a? String

          offending_line = callstack.find { |frame|
            # Code generated with `eval` doesn't have an `absolute_path`, e.g. templates.
            path = frame.absolute_path || frame.path
            path && !ignored_callstack?(path)
          } || callstack.first

          [offending_line.path, offending_line.lineno, offending_line.label]
        end

        def _extract_callstack(callstack)
          ActiveSupport.deprecator.warn(<<~MESSAGE)
            Passing the result of `caller` to ActiveSupport::Deprecation#warn is deprecated and will be removed in Rails 8.0.

            Please pass the result of `caller_locations` instead.
          MESSAGE

          offending_line = callstack.find { |line| !ignored_callstack?(line) } || callstack.first

          if offending_line
            if md = offending_line.match(/^(.+?):(\d+)(?::in `(.*?)')?/)
              md.captures
            else
              offending_line
            end
          end
        end

        RAILS_GEM_ROOT = File.expand_path("../../../..", __dir__) + "/" # :nodoc:
        LIB_DIR = RbConfig::CONFIG["libdir"] # :nodoc:

        def ignored_callstack?(path)
          path.start_with?(RAILS_GEM_ROOT, LIB_DIR) || path.include?("<internal:")
        end
    end
  end
end