A melhor prática para marca obsoleto código em Ruby?
-
08-07-2019 - |
Pergunta
Eu gostaria de marcar um método como obsoleto, por isso as pessoas que usam ele pode facilmente verificar o seu código e apanhar. Em Java você definir @deprecated e todo mundo sabe o que isso significa.
Então, há uma maneira preferida (ou até mesmo ferramentas) para marcar e verificar se há reprovações em Ruby?
Solução
Para quase todos os casos, dependendo de uma biblioteca ou metaprogramming para uma depreciação é um exagero. Basta adicionar um comentário ao rdoc e chamar o método Kernel#warn
. Por exemplo:
class Foo
# <b>DEPRECATED:</b> Please use <tt>useful</tt> instead.
def useless
warn "[DEPRECATION] `useless` is deprecated. Please use `useful` instead."
useful
end
def useful
# ...
end
end
Se você estiver usando Quintal em vez de rdoc , o seu comentário doc deve ficar assim:
# @deprecated Please use {#useful} instead
Por último, se você aderir a tomdoc , o seu comentário parecido com este:
# Deprecated: Please use `useful` instead
Deprecated: Indica que o método é obsoleto e será removido em uma versão futura. Você deve usar isso para métodos de documentos que eram públicos, mas serão removidas na próxima versão principal.
Além disso, não se esqueça de remover o método obsoleto em algum futuro (e devidamente semver 'd ) liberação . Não cometer os mesmos erros que as bibliotecas Java fez.
Outras dicas
Biblioteca Padrão Ruby tem um módulo com a lógica aviso: http://ruby-doc.org/stdlib-1.9.3/libdoc/rubygems/rdoc/Gem/Deprecate.html . I tendem a preferir-lo a manter as minhas mensagens de descontinuação de uma forma "padrão":
# my_file.rb
class MyFile
extend Gem::Deprecate
def no_more
close
end
deprecate :no_more, :close, 2015, 5
def close
# new logic here
end
end
MyFile.new.no_more
# => NOTE: MyFile#no_more is deprecated; use close instead. It will be removed on or after 2015-05-01.
# => MyFile#no_more called from my_file.rb:16.
Note que, com essa abordagem, você vai ganhar gratuitamente informações sobre onde a chamada ocorreu.
Se você quer ser média (sob o engano de ser útil) você pode imprimir a primeira linha da pilha de chamadas durante um aviso para deixar devs saber onde eles estão usando uma chamada obsoleta.
Esta é média porque eu tenho certeza que é um desempenho de sucesso.
warn Kernel.caller.first + " whatever deprecation message here"
Quando usado corretamente, isso vai incluir o caminho absoluto para o arquivo e linha onde a chamada obsoleta foi usado. Mais informações sobre Kernel :: chamador está disponível aqui
Usando ActiveSupport:
class Player < ActiveRecord::Base
def to_s
ActiveSupport::Deprecation.warn('Use presenter instead')
partner_uid
end
end
Os avisos são desligadas em ambiente de produção por padrão
Você também pode usar ActiveSupport::Deprecation
(disponível na versão 4.0+), tais como:
require 'active_support/deprecation'
require 'active_support/core_ext/module/deprecation'
class MyGem
def self.deprecator
ActiveSupport::Deprecation.new('2.0', 'MyGem')
end
def old_method
end
def new_method
end
deprecate old_method: :new_method, deprecator: deprecator
end
MyGem.new.old_method
# => DEPRECATION WARNING: old_method is deprecated and will be removed from MyGem 2.0 (use new_method instead). (called from <main> at file.rb:18)
Você tem libdeprecated-ruby
(2010-2012, não está mais disponível no rubygem em 2015)
Uma pequena biblioteca destina a ajudar os desenvolvedores que trabalham com código obsoleto.
A idéia vem do 'D
' linguagem de programação, onde os desenvolvedores podem marcar determinado código como obsoleto, e em seguida, permitir / não permitir a capacidade de executar código obsoleto.
require 'lib/deprecated.rb'
require 'test/unit'
# this class is used to test the deprecate functionality
class DummyClass
def monkey
return true
end
deprecate :monkey
end
# we want exceptions for testing here.
Deprecate.set_action(:throw)
class DeprecateTest < Test::Unit::TestCase
def test_set_action
assert_raise(DeprecatedError) { raise StandardError.new unless DummyClass.new.monkey }
Deprecate.set_action(proc { |msg| raise DeprecatedError.new("#{msg} is deprecated.") })
assert_raise(DeprecatedError) { raise StandardError.new unless DummyClass.new.monkey }
# set to warn and make sure our return values are getting through.
Deprecate.set_action(:warn)
assert_nothing_raised(DeprecatedError) { raise StandardError.new unless DummyClass.new.monkey }
end
end
Você pode usar o padrão Classe Macros e escrever algo como isto:
class Module
def deprecate(old_method, new_method)
define_method(old_method) do |*args, &block|
warn "Method #{old_method}() depricated. Use #{new_method}() instead"
send(new_method, *args, &block)
end
end
end
class Test
def my_new_method
p "My method"
end
deprecate :my_old_method, :my_method
end
Ao usar rails, você tem o método # deprecate Module.
acabei jogando juntos um método leve:
def deprecate(msg)
method = caller_locations(1, 1).first.label
source = caller(2, 1).first
warn "#{method} is deprecated: #{msg}\ncalled at #{source}"
end
Em seguida, a deprecate um método de inserção de uma chamada no corpo do método (ou um construtor de uma classe)
def foo
deprecate 'prefer bar, will be removed in version 3'
...
end
É bastante declarativa e fornece log com informações relevantes. Eu não sou muito de um Rubyist por isso pode precisar de alguns ajustes / YMMV.