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

root/branches/1-2-stable/activesupport/lib/active_support/deprecation.rb

Revision 6141, 6.3 kB (checked in by bitsweat, 2 years ago)

Merge [6140] from trunk.

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.last.is_a?(Hash) ? method_names.pop : {}
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       instance_methods.each { |m| undef_method m unless m =~ /^__/ }
151
152       def initialize(instance, method, var = "@#{method}")
153         @instance, @method, @var = instance, method, var
154       end
155
156       # Don't give a deprecation warning on inspect since test/unit and error
157       # logs rely on it for diagnostics.
158       def inspect
159         target.inspect
160       end
161
162       private
163         def method_missing(called, *args, &block)
164           warn caller, called, args
165           target.__send__(called, *args, &block)
166         end
167
168         def target
169           @instance.__send__(@method)
170         end
171
172         def warn(callstack, called, args)
173           ActiveSupport::Deprecation.warn("#{@var} is deprecated! Call #{@method}.#{called} instead of #{@var}.#{called}. Args: #{args.inspect}", callstack)
174         end
175     end
176   end
177 end
178
179 class Module
180   include ActiveSupport::Deprecation::ClassMethods
181 end
182
183 require 'test/unit/error'
184
185 module Test
186   module Unit
187     class TestCase
188       include ActiveSupport::Deprecation::Assertions
189     end
190
191     class Error # :nodoc:
192       # Silence warnings when reporting test errors.
193       def message_with_silenced_deprecation
194         ActiveSupport::Deprecation.silence do
195           message_without_silenced_deprecation
196         end
197       end
198
199       alias_method_chain :message, :silenced_deprecation
200     end
201   end
202 end
Note: See TracBrowser for help on using the browser.