Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

root/trunk/activesupport/lib/active_support/deprecation.rb

Revision 7474, 6.3 kB (checked in by bitsweat, 1 year ago)

Some 1.9 forward compatibility

Line 
1 require 'yaml'
2
3 module ActiveSupport
4   module Deprecation #:nodoc:
5     mattr_accessor :debug
6     self.debug = false
7
8     # Choose the default warn behavior according to RAILS_ENV.
9     # Ignore deprecation warnings in production.
10     DEFAULT_BEHAVIORS = {
11       'test'        => Proc.new { |message, callstack|
12                          $stderr.puts(message)
13                          $stderr.puts callstack.join("\n  ") if debug
14                        },
15       'development' => Proc.new { |message, callstack|
16                          logger = defined?(::RAILS_DEFAULT_LOGGER) ? ::RAILS_DEFAULT_LOGGER : Logger.new($stderr)
17                          logger.warn message
18                          logger.debug callstack.join("\n  ") if debug
19                        }
20     }
21
22     class << self
23       def warn(message = nil, callstack = caller)
24         behavior.call(deprecation_message(callstack, message), callstack) if behavior && !silenced?
25       end
26
27       def default_behavior
28         if defined?(RAILS_ENV)
29           DEFAULT_BEHAVIORS[RAILS_ENV.to_s]
30         else
31           DEFAULT_BEHAVIORS['test']
32         end
33       end
34
35       # Have deprecations been silenced?
36       def silenced?
37         @silenced = false unless defined?(@silenced)
38         @silenced
39       end
40
41       # Silence deprecation warnings within the block.
42       def silence
43         old_silenced, @silenced = @silenced, true
44         yield
45       ensure
46         @silenced = old_silenced
47       end
48
49       attr_writer :silenced
50
51
52       private
53         def deprecation_message(callstack, message = nil)
54           message ||= "You are using deprecated behavior which will be removed from Rails 2.0."
55           "DEPRECATION WARNING: #{message}  See http://www.rubyonrails.org/deprecation for details. #{deprecation_caller_message(callstack)}"
56         end
57
58         def deprecation_caller_message(callstack)
59           file, line, method = extract_callstack(callstack)
60           if file
61             if line && method
62               "(called from #{method} at #{file}:#{line})"
63             else
64               "(called from #{file}:#{line})"
65             end
66           end
67         end
68
69         def extract_callstack(callstack)
70           if md = callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/)
71             md.captures
72           else
73             callstack.first
74           end
75         end
76     end
77
78     # Behavior is a block that takes a message argument.
79     mattr_accessor :behavior
80     self.behavior = default_behavior
81
82     # Warnings are not silenced by default.
83     self.silenced = false
84
85     module ClassMethods #:nodoc:
86       # Declare that a method has been deprecated.
87       def deprecate(*method_names)
88         options = method_names.extract_options!
89         method_names = method_names + options.keys
90         method_names.each do |method_name|
91           alias_method_chain(method_name, :deprecation) do |target, punctuation|
92             class_eval(<<-EOS, __FILE__, __LINE__)
93               def #{target}_with_deprecation#{punctuation}(*args, &block)
94                 ::ActiveSupport::Deprecation.warn(self.class.deprecated_method_warning(:#{method_name}, #{options[method_name].inspect}), caller)
95                 #{target}_without_deprecation#{punctuation}(*args, &block)
96               end
97             EOS
98           end
99         end
100       end
101
102       def deprecated_method_warning(method_name, message=nil)
103         warning = "#{method_name} is deprecated and will be removed from Rails #{deprecation_horizon}"
104         case message
105           when Symbol then "#{warning} (use #{message} instead)"
106           when String then "#{warning} (#{message})"
107           else warning
108         end
109       end
110
111       def deprecation_horizon
112         '2.0'
113       end
114     end
115
116     module Assertions #:nodoc:
117       def assert_deprecated(match = nil, &block)
118         result, warnings = collect_deprecations(&block)
119         assert !warnings.empty?, "Expected a deprecation warning within the block but received none"
120         if match
121           match = Regexp.new(Regexp.escape(match)) unless match.is_a?(Regexp)
122           assert warnings.any? { |w| w =~ match }, "No deprecation warning matched #{match}: #{warnings.join(', ')}"
123         end
124         result
125       end
126
127       def assert_not_deprecated(&block)
128         result, deprecations = collect_deprecations(&block)
129         assert deprecations.empty?, "Expected no deprecation warning within the block but received #{deprecations.size}: \n  #{deprecations * "\n  "}"
130         result
131       end
132
133       private
134         def collect_deprecations
135           old_behavior = ActiveSupport::Deprecation.behavior
136           deprecations = []
137           ActiveSupport::Deprecation.behavior = Proc.new do |message, callstack|
138             deprecations << message
139           end
140           result = yield
141           [result, deprecations]
142         ensure
143           ActiveSupport::Deprecation.behavior = old_behavior
144         end
145     end
146
147     # Stand-in for @request, @attributes, @params, etc which emits deprecation
148     # warnings on any method call (except #inspect).
149     class DeprecatedInstanceVariableProxy #:nodoc:
150       silence_warnings do
151         instance_methods.each { |m| undef_method m unless m =~ /^__/ }
152       end
153
154       def initialize(instance, method, var = "@#{method}")
155         @instance, @method, @var = instance, method, var
156       end
157
158       # Don't give a deprecation warning on inspect since test/unit and error
159       # logs rely on it for diagnostics.
160       def inspect
161         target.inspect
162       end
163
164       private
165         def method_missing(called, *args, &block)
166           warn caller, called, args
167           target.__send__(called, *args, &block)
168         end
169
170         def target
171           @instance.__send__(@method)
172         end
173
174         def warn(callstack, called, args)
175           ActiveSupport::Deprecation.warn("#{@var} is deprecated! Call #{@method}.#{called} instead of #{@var}.#{called}. Args: #{args.inspect}", callstack)
176         end
177     end
178   end
179 end
180
181 class Module
182   include ActiveSupport::Deprecation::ClassMethods
183 end
184
185 require 'test/unit/error'
186
187 module Test
188   module Unit
189     class TestCase
190       include ActiveSupport::Deprecation::Assertions
191     end
192
193     class Error # :nodoc:
194       # Silence warnings when reporting test errors.
195       def message_with_silenced_deprecation
196         ActiveSupport::Deprecation.silence do
197           message_without_silenced_deprecation
198         end
199       end
200
201       alias_method_chain :message, :silenced_deprecation
202     end
203   end
204 end
Note: See TracBrowser for help on using the browser.