diff --git a/CHANGELOG.md b/CHANGELOG.md index d89c0c6..8d2d08d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +### deprecations 2.0.0 +- supports custom behavior +- supports temporary behavior change +- supports inheritance of deprecated methods +- `Deprecations#configure` and `Deprecations#configuration` are obsolete (use `Deprecations#behavior`) + ### deprecations 1.0.6 - support for textual alternative of deprecated methods diff --git a/README.md b/README.md index 8a367b9..113e04d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Deprecations -This gem provides transparent declaration of deprecated methods and classes. +This gem provides transparent declaration of deprecated methods and classes. It's easy, small, has no dependencies and no overhead. [![Code Climate](https://codeclimate.com/github/mblumtritt/deprecations.png)](https://codeclimate.com/github/mblumtritt/deprecations) @@ -46,6 +46,7 @@ class MySample def clean clear end + deprecated :clean, :clear, 'next version' end @@ -55,27 +56,43 @@ Whenever the method `MySample#clean` is called this warning appears: > [DEPRECATION] `MySample#clean` is deprecated and will be outdated next version. Please use `MySample#clear` instead. -You can change this behavior by configure the Deprecations gem: +Marking a complete class as deprecated will present the deprecation warning whenever this class is instantiated: ```ruby -Deprecations.configure do |config| - config.behavior = :raise +class MySample + deprecated! + + # some more code here... end ``` -Valid behaviors are: +You can change the behavior of notifying: + +```ruby +Deprecations.behavior = :raise +``` + +There are 3 pre-defined behaviors: - `:raise` will raise an `DeprecationException` when a deprecated method is called -- `:silence` will do nothing +- `:silence` will do nothing (ignore the deprecation) - `:warn` will print a warning (default behavior) -Marking a complete class as deprecated will present the deprecation warning (or exception) whenever this class is instantiated: +Besides this you can implement your own: ```ruby -class MySample - deprecated! - - # some more code here... +Deprecations.behavior = proc do |subject, _alternative, _outdated| + SuperLogger.warning "deprecated: #{subject}" +end +``` + +Any object responding to `#call` will be accepted as a valid handler. + +Whenever you need to temporary change the standard behavior (like e.g. in your specs) you can do this like + +```ruby +Deprecations.set_behavior(:silent) do + MyDeprecatedClass.new.do_some_magic end ``` diff --git a/Rakefile b/Rakefile index 498c294..cc00642 100644 --- a/Rakefile +++ b/Rakefile @@ -1,7 +1,6 @@ -ENV.key?('NO_RUBYGEMS') or require('rubygems') require 'bundler/gem_tasks' - require 'rspec/core/rake_task' + RSpec::Core::RakeTask.new(:test) do |t| t.pattern = ['spec/*_spec.rb', 'spec/**/*/*_spec.rb'] t.rspec_opts = '-w' diff --git a/deprecations.gemspec b/deprecations.gemspec index e1fbb7c..c59f6a9 100644 --- a/deprecations.gemspec +++ b/deprecations.gemspec @@ -1,6 +1,6 @@ require File.expand_path('../lib/deprecations/version', __FILE__) -GemSpec= Gem::Specification.new do |spec| +GemSpec = Gem::Specification.new do |spec| spec.required_rubygems_version = Gem::Requirement.new('>= 1.3.6') spec.platform = Gem::Platform::RUBY spec.required_ruby_version = '>= 2.0.0' @@ -9,13 +9,14 @@ GemSpec= Gem::Specification.new do |spec| spec.authors = ['Mike Blumtritt'] spec.email = %w[mike.blumtritt@injixo.com] spec.summary = 'Deprecation support for your project.' - spec.description = 'This gem provides transparent declaration of deprecated methods and classes.' + spec.description = "This gem provides transparent declaration of deprecated methods and classes. "\ + "It's easy, small, has no dependencies and no overhead." spec.homepage = 'https://github.com/mblumtritt/deprecations' spec.date = Time.now.strftime('%Y-%m-%d') spec.require_paths = %w[lib] spec.files = %x[git ls-files].split($/) - spec.test_files = spec.files.grep(%r[^test/]) - spec.extra_rdoc_files = %w[README.md] + spec.test_files = spec.files.grep(%r[^spec/]) + spec.extra_rdoc_files = %w[README.md CHANGELOG.md] spec.has_rdoc = false # TODO! spec.add_development_dependency 'rake' spec.add_development_dependency 'rspec', '>= 3.0.0' @@ -23,6 +24,7 @@ GemSpec= Gem::Specification.new do |spec| spec.add_development_dependency 'guard-rspec' if /darwin|mac os/i =~ RUBY_PLATFORM spec.add_development_dependency 'rb-fsevent' + spec.add_development_dependency 'terminal-notifier' spec.add_development_dependency 'terminal-notifier-guard' end end diff --git a/lib/deprecations.rb b/lib/deprecations.rb index c0d47cf..efddf9b 100644 --- a/lib/deprecations.rb +++ b/lib/deprecations.rb @@ -1,40 +1,14 @@ - -DeprecationError = Class.new(ScriptError) - module Deprecations autoload(:VERSION, "#{__FILE__[/.*(?=\..+$)/]}/version") - require_relative 'deprecations/configuration' require_relative 'deprecations/extension' + require_relative 'deprecations/behavior' - class << self - - def call(subject, alternative, outdated) - case configuration.behavior - when :warn - warn(subject, alternative, outdated) - when :raise - throw!(subject, alternative) - end - self - end - - private - - def throw!(subject, alternative) - msg = "`#{subject}` is deprecated" - alternative and msg << " - use #{alternative} instead" - ex = DeprecationError.new(msg) - ex.set_backtrace(caller(3)) - raise(ex) - end - - def warn(subject, alternative, outdated) - location = ::Kernel.caller_locations(3,1).last and location = "#{location.path}:#{location.lineno}: " - msg = "#{location}[DEPRECATION] `#{subject}` is deprecated" - msg << (outdated ? " and will be outdated #{outdated}." : '.') - alternative and msg << " Please use `#{alternative}` instead." - ::Kernel.warn(msg) - end - + def self.call(subject, alternative, outdated) + @behavior.call(subject, alternative, outdated) + self end + + self.behavior = :warn end + +DeprecationError = Class.new(ScriptError) diff --git a/lib/deprecations/behavior.rb b/lib/deprecations/behavior.rb new file mode 100644 index 0000000..2309559 --- /dev/null +++ b/lib/deprecations/behavior.rb @@ -0,0 +1,55 @@ +module Deprecations + class << self + + def behavior + BEHAVIOR.key(@behavior) || @behavior + end + + def behavior=(behavior) + @behavior = as_behavior(behavior) + end + + def set_behavior(behavior) + behavior = as_behavior(behavior) + block_given? or raise(ArgumentError, 'block expected') + current_behavior = @behavior + begin + @behavior = behavior + yield + ensure + @behavior = current_behavior + end + end + + private + + def as_behavior(arg) + defined?(arg.call) ? arg : BEHAVIOR.fetch(arg) do + raise(ArgumentError, "invalid parameter - behavior has to be #{valid_behavior} or need to respond to `call`") + end + end + + def valid_behavior + BEHAVIOR.keys.map(&:inspect).join(' | ') + end + + BEHAVIOR = { + silence: ->(*){}, + raise: proc do |subject, alternative| + msg = "`#{subject}` is deprecated" + alternative and msg << " - use #{alternative} instead" + ex = ::DeprecationError.new(msg) + ex.set_backtrace(caller(4)) + raise(ex) + end, + warn: proc do |subject, alternative, outdated | + location = caller_locations(4, 1).last and location = "#{location.path}:#{location.lineno}: " + msg = "#{location}[DEPRECATION] `#{subject}` is deprecated" + msg << (outdated ? " and will be outdated #{outdated}." : '.') + alternative and msg << " Please use `#{alternative}` instead." + ::Kernel.warn(msg) + end + } + + end +end diff --git a/lib/deprecations/configuration.rb b/lib/deprecations/configuration.rb deleted file mode 100644 index 0214fc5..0000000 --- a/lib/deprecations/configuration.rb +++ /dev/null @@ -1,35 +0,0 @@ - -module Deprecations - class << self - - def configure - yield(@@cfg = Cfg.new) - end - - def configuration - @@cfg - end - - BEHAVIORS = [:warn, :raise, :silence] - - private - - class Cfg < BasicObject - attr_reader :behavior - - def initialize - @behavior = :warn - end - - def behavior=(how) - BEHAVIORS.include?(how) and return @behavior = how - ::Kernel.raise( - ::ArgumentError, "invalid parameter `#{how}` - have to be #{BEHAVIORS.map(&:inspect).join(' | ')}" - ) - end - - end - - @@cfg = Cfg.new - end -end diff --git a/lib/deprecations/extension.rb b/lib/deprecations/extension.rb index 9cbbc5d..3acd191 100644 --- a/lib/deprecations/extension.rb +++ b/lib/deprecations/extension.rb @@ -14,10 +14,11 @@ def __method(method_name) end def __method_deprecated!(method, alternative, outdated) + defining_context = self define_method(method.name) do |*a, &b| - decorated = Class === self ? "#{self}." : "#{self.class}#" + decorated = Class === self ? "#{self}." : "#{defining_context}#" Deprecations.call( - "#{decorated}#{__method__}", + "#{decorated}#{::Kernel.__method__}", UnboundMethod === alternative ? "#{decorated}#{alternative.name}" : alternative, outdated ) @@ -29,6 +30,9 @@ def __method_not_found!(method_name) raise(NameError, "undefined method `#{method_name}` for class `#{self}`") end + def __method_alternative(alternative) + Symbol === alternative ? (__method(alternative) or __method_not_found!(alternative)) : alternative + end end module ClassMethods @@ -36,9 +40,11 @@ module ClassMethods include Helper def deprecated(method_name, alternative = nil, outdated = nil) - m = __method(method_name) or __method_not_found!(method_name) - a = Symbol === alternative ? (__method(alternative) or __method_not_found!(alternative)) : alternative - __method_deprecated!(m, a, outdated) + __method_deprecated!( + (__method(method_name) or __method_not_found!(method_name)), + __method_alternative(alternative), + outdated + ) end end @@ -48,8 +54,7 @@ module InstanceMethods def deprecated(method_name, alternative = nil, outdated = nil) m = __method(method_name) or return singleton_class.send(:deprecated, method_name, alternative, outdated) - a = Symbol === alternative ? (__method(alternative) or __method_not_found!(alternative)) : alternative - __method_deprecated!(m, a, outdated) + __method_deprecated!(m, __method_alternative(alternative), outdated) end def deprecated!(alternative = nil, outdated = nil) diff --git a/lib/deprecations/version.rb b/lib/deprecations/version.rb index 593076d..ee8326d 100644 --- a/lib/deprecations/version.rb +++ b/lib/deprecations/version.rb @@ -1,3 +1,3 @@ module Deprecations - VERSION = '1.0.6' + VERSION = '2.0.0pre' end diff --git a/spec/deprecations/behavior_spec.rb b/spec/deprecations/behavior_spec.rb new file mode 100644 index 0000000..941310c --- /dev/null +++ b/spec/deprecations/behavior_spec.rb @@ -0,0 +1,98 @@ +require 'spec_helper' + +RSpec.describe Deprecations do + context 'behavior' do + + it 'is possible to configure the behavior with a pre-defined value' do + %i(silence raise warn).each do |behavior| + Deprecations.behavior = behavior + expect(Deprecations.behavior).to be(behavior) + end + end + + it 'is possible to configure a custom behavior' do + custom = proc do |*args| + FantasticLogger.log(*args) + end + Deprecations.behavior = custom + expect(Deprecations.behavior).to be(custom) + end + + context 'standard behavior :silence' do + before do + Deprecations.behavior = :silence + end + + it 'does simply nothing' do + expect(subject.call(*%w(should be silent))).to be(subject) + end + end + + context 'standard behavior :warn' do + before do + Deprecations.behavior = :warn + end + after do + Deprecations.call('Bad#method', 'Bad#alternative', 'after next version') + end + + it 'warns about the deprecation' do + expect(Kernel).to receive(:warn).once.with(/DEPRECATION/) + end + + it 'points to the deprecated method' do + expect(Kernel).to receive(:warn).once.with(/Bad#method.*deprecated/) + end + + it 'suggests the alternative method' do + expect(Kernel).to receive(:warn).once.with(/Bad#alternative.*instead/) + end + + it 'contains information about when it will not longer supported' do + expect(Kernel).to receive(:warn).once.with(/outdated after next version/) + end + end + + context 'standard behavior :raise' do + before do + Deprecations.behavior = :raise + end + subject{ Deprecations.call('Bad#method', 'Bad#alternative', 'after next version') } + + it 'raises a Deprecations::Error' do + expect{ subject }.to raise_error(DeprecationError) + end + + it 'points to the deprecated method' do + expect{ subject }.to raise_error(DeprecationError, /Bad#method.*deprecated/) + end + + it 'suggests the alternative method' do + expect{ subject }.to raise_error(DeprecationError, /Bad#alternative.*instead/) + end + end + + context 'change behavior temporary' do + let(:sample_class) do + Class.new(BasicObject) do + deprecated! + end + end + + before do + Deprecations.behavior = :raise + end + + after do + Deprecations.set_behavior(:warn) do + sample_class.new.__id__ + end + end + + it 'is possible to temporary use a different behavior' do + expect(Kernel).to receive(:warn).once + end + + end + end +end diff --git a/spec/deprecations/configuration_spec.rb b/spec/deprecations/configuration_spec.rb deleted file mode 100644 index 69f2a5d..0000000 --- a/spec/deprecations/configuration_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -require 'spec_helper' - -RSpec.describe 'Deprecations::Configuration' do - it 'is possible to configure the module' do - Deprecations.configure do |config| - config.behavior = :silence - end - expect(Deprecations.configuration.behavior).to be :silence - end - - context 'when invalid arguments are given' do - it 'raises an error' do - expect do - Deprecations.configure do |config| - config.behavior = :invalid_value - end - end.to raise_error(ArgumentError, /invalid_value/) - end - end -end diff --git a/spec/deprecations/version_spec.rb b/spec/deprecations/version_spec.rb index fcf91e5..bdea92e 100644 --- a/spec/deprecations/version_spec.rb +++ b/spec/deprecations/version_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' -RSpec.describe Deprecations::VERSION do +RSpec.describe 'Deprecations::VERSION' do it 'has format ..' do - expect(subject).to match(/^\d{1,2}\.\d{1,2}\.\d{1,3}/) + expect(Deprecations::VERSION).to match(/^\d{1,2}\.\d{1,2}\.\d{1,3}/) end end diff --git a/spec/deprecations_spec.rb b/spec/deprecations_spec.rb index 36b911c..a90e319 100644 --- a/spec/deprecations_spec.rb +++ b/spec/deprecations_spec.rb @@ -1,380 +1,229 @@ require 'spec_helper' -module DeprecationsSamples # samples how to use - - # mixin with some methods for demonstration - module MethodSamples - def foo(*parameters) - block_given? ? yield(parameters) : {foo: parameters} - end - - def alt - :nop - end - end - - # mixin with initializer method for demonstration - module InitializerSample - attr_reader :parameters - def initialize(*parameters) - @parameters = block_given? ? yield(parameters) : {foo: parameters} - end - end - - # here we go: - - class Sample1 - include MethodSamples - deprecated :foo # Sample1#foo is deprecated - end - - class Sample2 - include MethodSamples - deprecated :foo, :alt # Sample2#foo is deprecated, Sample2#alt should be used - end - - class Sample3 - include MethodSamples - deprecated :foo, :alt, 'next version' # Sample3#foo is deprecated and will be outdated in next version, Sample3#alt should be used - end - - class Sample4 - extend MethodSamples - deprecated :foo # class method Sample4::foo is deprecated - end - - class Sample5 - extend MethodSamples - deprecated :foo, :alt # class method Sample5::foo is deprecated, Sample5::alt should be used - end - - class Sample6 - extend MethodSamples - deprecated :foo, :alt, 'next version' # class method Sample6::foo is deprecated and will be outdated in next version, Sample6::alt should be used - end - - class Sample7 - deprecated! # class Sample7 is deprecated - include InitializerSample - end - - class Sample8 - deprecated! Sample1 # class Sample8 is deprecated, class Sample1 should be used - include InitializerSample - end - - class Sample9 - deprecated! Sample1, 'in 2.0.0' # class Sample9 is deprecated and will be outdated in version 2.0.0, class Sample1 should be used - include InitializerSample - end - - module AnonymousDefined - AnnoSample7 = Class.new do - deprecated! # class AnonymousDefined::AnnoSample7 is deprecated - include InitializerSample - end - - AnnoSample8 = Class.new do - deprecated! Sample1 # class AnonymousDefined::AnnoSample8 is deprecated, class Sample1 should be used - include InitializerSample - end - - AnnoSample9 = Class.new do - deprecated! Sample1, 'in 2.0.0' # class AnonymousDefined::AnnoSample9 is deprecated and will be outdated in version 2.0.0, class Sample1 should be used - include InitializerSample - end - end - -end - -RSpec.shared_examples_for 'a transparent deprecated method' do - it 'forwards all parameter and returns the original method`s result' do - allow(Kernel).to receive(:warn) - expect(sample.foo(:arg1, :arg2, 42)).to eq(foo: [:arg1, :arg2, 42]) - end - - it 'forwards a given Proc to the original method' do - allow(Kernel).to receive(:warn) - expect(sample.foo(:arg1, 'test', 42){ |p| {via_block: p} }).to eq(via_block: [:arg1, 'test', 42]) - end -end - -RSpec.shared_examples_for 'a deprecated method (warnings enabled)' do - it_should_behave_like 'a transparent deprecated method' - - it 'warns about the deprecation' do - expect(Kernel).to receive(:warn).once.with(/\bDeprecationsSamples::Sample\d[\.#]foo\b.*\bdeprecated\b/) - sample.foo - end - - it 'points to the calling line' do - expect(Kernel).to receive(:warn).with(/#{__FILE__}:#{__LINE__ + 1}/) - sample.foo - end - -end - -RSpec.shared_examples_for 'a deprecated method (should throw)' do - it 'raises an DeprecationError' do - expect{ sample.foo }.to raise_error(DeprecationError, /\bDeprecationsSamples::Sample\d[\.#]foo\b.*\bdeprecated\b/) - end - - it 'has a helpful backtrace' do - backtrace = nil - begin - sample.foo - rescue DeprecationError => err - backtrace = err.backtrace - end - expect(backtrace.first).to match(/#{__FILE__}:#{__LINE__ - 4}/) - end -end - -RSpec.shared_examples_for 'a transparent deprecated class' do - it 'calls the original initializer with all parameters' do - allow(Kernel).to receive(:warn) - instance = sample.new(:arg1, :arg2, 42) - expect(instance.parameters).to eq(foo: [:arg1, :arg2, 42]) - end - - it 'forwards a given Proc to the original initializer' do - allow(Kernel).to receive(:warn) - instance = sample.new(:arg1, 'test', 42){ |p| {via_block: p} } - expect(instance.parameters).to eq(via_block: [:arg1, 'test', 42]) - end -end - -RSpec.shared_examples_for 'a deprecated class (warnings enabled)' do - it_should_behave_like 'a transparent deprecated class' - - it 'warns about the deprecation' do - expect(Kernel).to receive(:warn).once.with(/\b#{sample}\b.*\bdeprecated\b/) - sample.new - end - - it 'points to the calling line' do - expect(Kernel).to receive(:warn).with(/#{__FILE__}:#{__LINE__ + 1}/) - sample.new - end -end - -RSpec.shared_examples_for 'a deprecated class (should throw)' do - it 'raises an DeprecationError' do - expect{ sample.new }.to raise_error(DeprecationError, /\bDeprecationsSamples::Sample\d\b.*\bdeprecated\b/) - end - - it 'has a helpful backtrace' do - backtrace = nil - begin - sample.new - rescue DeprecationError => err - backtrace = err.backtrace - end - expect(backtrace.first).to match(/#{__FILE__}:#{__LINE__ - 4}/) - end -end - RSpec.describe Deprecations do - context 'when configured as silent' do - before :all do - Deprecations.configuration.behavior = :silence - end - - context 'when an instance method is marked as deprecated' do - let(:sample){ DeprecationsSamples::Sample1.new } - it_should_behave_like 'a transparent deprecated method' + context 'policy' do + before do + Deprecations.behavior = :silence end - context 'when a class method is marked as deprecated' do - let(:sample){ DeprecationsSamples::Sample4 } - it_should_behave_like 'a transparent deprecated method' - end - - context 'when a class is marked as deprecated' do - let(:sample){ DeprecationsSamples::Sample7 } - it_should_behave_like 'a transparent deprecated class' - end - end + context 'parameter forwarding' do - context 'when configured to warn' do - before :all do - Deprecations.configuration.behavior = :warn - end - - context 'when an instance method is marked as deprecated' do - let(:sample){ DeprecationsSamples::Sample1.new } - - it_should_behave_like 'a deprecated method (warnings enabled)' - - context 'when an optional alternative method is given' do - let(:sample){ DeprecationsSamples::Sample2.new } - - it_should_behave_like 'a deprecated method (warnings enabled)' - - it 'suggests the alternative method' do - expect(Kernel).to receive(:warn).with(/DeprecationsSamples::Sample2#alt.*instead/) - sample.foo + context 'when an instance method is marked as deprecated' do + subject do + Class.new(BasicObject) do + def foo(*args) + {foo: args} + end + deprecated :foo + end end - end - context 'when an optional comment is given' do - let(:sample){ DeprecationsSamples::Sample3.new } - - it_should_behave_like 'a deprecated method (warnings enabled)' - - it 'informs about when it will become outdated' do - expect(Kernel).to receive(:warn).with(/outdated next version/) - sample.foo + it 'forwards all parameters and returns the original method`s result' do + result = subject.new.foo(:arg1, :arg2, 42) + expect(result).to eq(foo: [:arg1, :arg2, 42]) end end - end - - context 'when a class method is marked as deprecated' do - let(:sample){ DeprecationsSamples::Sample4 } - - it_should_behave_like 'a deprecated method (warnings enabled)' - context 'when an optional alternative method is given' do - let(:sample){ DeprecationsSamples::Sample5 } - - it_should_behave_like 'a deprecated method (warnings enabled)' + context 'when a class method is marked as deprecated' do + subject do + Class.new(BasicObject) do + def self.foo(*args) + {foo: args} + end + deprecated :foo + end + end - it 'suggests the alternative method' do - expect(Kernel).to receive(:warn).with(/\bDeprecationsSamples::Sample5\.alt\b.*\binstead\b/) - sample.foo + it 'forwards all parameters and returns the original method`s result' do + result = subject.foo(:arg1, :arg2, 42) + expect(result).to eq(foo: [:arg1, :arg2, 42]) end end - context 'when an optional comment is given' do - let(:sample){ DeprecationsSamples::Sample6 } - - it_should_behave_like 'a deprecated method (warnings enabled)' + context 'when a class is marked as deprecated' do + subject do + Class.new(BasicObject) do + attr_reader :parameters + def initialize(*parameters) + @parameters = parameters + end + deprecated! + end + end - it 'informs about when it will become outdated' do - expect(Kernel).to receive(:warn).with(/outdated next version/) - sample.foo + it 'forwards all parameters to the initializer and returns the original method`s result' do + expect(subject.new(:arg1, :arg2, 42).parameters).to eq([:arg1, :arg2, 42]) end end end - context 'when a class is marked as deprecated' do - let(:sample){ DeprecationsSamples::Sample7 } + context 'block forwarding' do - it_should_behave_like 'a deprecated class (warnings enabled)' + context 'when an instance method is marked as deprecated' do + subject do + Class.new(BasicObject) do + def foo(arg) + yield(arg) + end + deprecated :foo + end + end - context 'when an optional alternative class is given' do - let(:sample){ DeprecationsSamples::Sample8 } + it 'forwards a given Proc to the original method' do + result = subject.new.foo(41) do |arg| + {my_blocks_result: arg + 1} + end + expect(result).to eq(my_blocks_result: 42) + end + end - it_should_behave_like 'a deprecated class (warnings enabled)' + context 'when a class method is marked as deprecated' do + subject do + Class.new(BasicObject) do + def self.foo(arg) + yield(arg) + end + deprecated :foo + end + end - it 'suggests the alternative class' do - expect(Kernel).to receive(:warn).with(/\bDeprecationsSamples::Sample1\b.*\binstead\b/) - sample.new + it 'forwards a given Proc to the original method' do + result = subject.foo(665) do |arg| + {my_blocks_result: arg + 1} + end + expect(result).to eq(my_blocks_result: 666) end end - context 'when an optional comment is given' do - let(:sample){ DeprecationsSamples::Sample9 } - - it_should_behave_like 'a deprecated class (warnings enabled)' + context 'when a class is marked as deprecated' do + subject do + Class.new(BasicObject) do + attr_reader :value + def initialize(arg) + @value = yield(arg) + end + deprecated! + end + end - it 'informs about when it will become outdated' do - expect(Kernel).to receive(:warn).with(/outdated in 2.0.0/) - sample.new + it 'forwards a given Proc to the initializer' do + instance = subject.new(41) do |arg| + {my_blocks_result: arg + 1} + end + expect(instance.value).to eq(my_blocks_result: 42) end end - end - context 'when a anonymous class is marked as deprecated' do - let(:sample){ DeprecationsSamples::AnonymousDefined::AnnoSample7 } + end - it_should_behave_like 'a deprecated class (warnings enabled)' + end - context 'when an optional alternative class is given' do - let(:sample){ DeprecationsSamples::AnonymousDefined::AnnoSample8 } + context 'handling' do - it_should_behave_like 'a deprecated class (warnings enabled)' + context 'when a method is marked as deprecated' do - it 'suggests the alternative class' do - expect(Kernel).to receive(:warn).with(/\bDeprecationsSamples::Sample1\b.*\binstead\b/) - sample.new + context 'when an alternative method and a comment are present ' do + subject do + Class.new(BasicObject) do + def foo + end + def bar + end + deprecated :foo, :bar, 'next version' + end end - end - context 'when an optional comment is given' do - let(:sample){ DeprecationsSamples::AnonymousDefined::AnnoSample9 } - - it_should_behave_like 'a deprecated class (warnings enabled)' + after do + subject.new.foo + end - it 'informs about when it will become outdated' do - expect(Kernel).to receive(:warn).with(/outdated in 2.0.0/) - sample.new + it 'calls the handler with correct subject' do + expect(Deprecations).to receive(:call).once.with("#{subject}#foo", anything, anything) + end + it 'calls the handler with correct alternative method' do + expect(Deprecations).to receive(:call).once.with(anything, "#{subject}#bar", anything) + end + it 'calls the handler with a comment' do + expect(Deprecations).to receive(:call).once.with(anything, anything, 'next version') end end - end - - context 'error cases' do - context 'when the method to mark as deprecated does not exist' do - it 'raises a NameError' do - expect do - Class.new do - deprecated :does_not_exist + context 'when no alternative method and no comment are present' do + subject do + Class.new(BasicObject) do + def bar end - end.to raise_error(NameError, /undefined method.*does_not_exist/) + deprecated :bar + end end - end - context 'when the alternative method does not exist' do - it 'raises a NameError' do - expect do - Class.new do - def foo; end - deprecated :foo, :not_existing_alternative - end - end.to raise_error(NameError, /undefined method.*not_existing_alternative/) + after do + subject.new.bar end - end - end - end + it 'calls handler without an alternative method' do + expect(Deprecations).to receive(:call).once.with(anything, nil, anything) + end + it 'calls handler without a comment' do + expect(Deprecations).to receive(:call).once.with(anything, anything, nil) + end + end - context 'when configured to raise' do - before :all do - Deprecations.configuration.behavior = :raise end - context 'when an instance method is marked as deprecated' do - let(:sample){ DeprecationsSamples::Sample1.new } - - it_should_behave_like 'a deprecated method (should throw)' - - context 'when an optional alternative method is given' do - let(:sample){ DeprecationsSamples::Sample2.new } - - it_should_behave_like 'a deprecated method (should throw)' + context 'when a class is anonymous defined' do + module Samples + AnonymousDefined = Class.new(::BasicObject) do + def clean; end + def clear; end + deprecated :clean, :clear - it 'suggests the alternative method' do - expect{ sample.foo }.to raise_error(DeprecationError, /DeprecationsSamples::Sample2#alt.*instead/) + def self.create; end + def self.make; end + deprecated :create, :make end end - end - context 'when a class method is marked as deprecated' do - let(:sample){ DeprecationsSamples::Sample7 } + it 'uses correct decorated instance method names' do + expect(Deprecations).to receive(:call).once.with( + 'Samples::AnonymousDefined#clean', + 'Samples::AnonymousDefined#clear', + nil + ) + Samples::AnonymousDefined.new.clean + end - it_should_behave_like 'a deprecated class (should throw)' + it 'uses correct decorated singleton method names' do + expect(Deprecations).to receive(:call).once.with( + 'Samples::AnonymousDefined.create', + 'Samples::AnonymousDefined.make', + nil + ) + Samples::AnonymousDefined.create + end + end - context 'when an optional alternative class is given' do - let(:sample){ DeprecationsSamples::Sample8 } + context 'when a sub-class is used' do + module Samples + class Parent < ::BasicObject + def clean; end + def clear; end + deprecated :clean, :clear + end - it_should_behave_like 'a deprecated class (should throw)' + class Child < Parent; end + end - it 'suggests the alternative class' do - expect{ sample.new }.to raise_error(DeprecationError, /\bDeprecationsSamples::Sample8\b.*\binstead\b/) - end + it 'uses correct decorated method names' do + expect(Deprecations).to receive(:call).once.with( + 'Samples::Parent#clean', + 'Samples::Parent#clear', + nil + ) + Samples::Child.new.clean end end + end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 214ecc8..c4f4f50 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,4 +1,3 @@ -# configure RSpec RSpec.configure do |config| config.raise_errors_for_deprecations! config.disable_monkey_patching! @@ -6,5 +5,4 @@ config.expect_with(:rspec){ |c| c.syntax = :expect } config.mock_with(:rspec){ |c| c.syntax = :expect } end - require 'deprecations'