Le migliori pratiche per contrassegnare il codice obsoleto in Ruby?


127

Vorrei contrassegnare un metodo come obsoleto, in modo che le persone che lo utilizzano possano facilmente controllare il proprio codice e recuperarlo. In Java hai impostato @Deprecated e tutti sanno cosa significa.

Quindi c'è un modo preferito (o persino strumenti) per contrassegnare e verificare le deprecazioni in Ruby?


Ad essere onesti, l'annotazione di Java fa schifo, in quanto non ha alcun valore per indicare una potenziale sostituzione
Heiko Rupp,

Risposte:


160

Per quasi tutti i casi, dipendere da una libreria o metaprogrammazione per un deprezzamento è eccessivo. Basta aggiungere un commento a rdoc e chiamare il Kernel#warnmetodo. Per esempio:

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 stai usando Yard invece di rdoc , il tuo commento doc dovrebbe apparire così:

# @deprecated Please use {#useful} instead

Infine, se aderisci a tomdoc , fai in modo che il tuo commento assomigli a questo:

# Deprecated: Please use `useful` instead

Obsoleto: indica che il metodo è obsoleto e verrà rimosso in una versione futura. Dovresti utilizzarlo per documentare metodi che erano pubblici ma che verranno rimossi alla prossima versione principale.


Inoltre, non dimenticare di rimuovere il metodo obsoleto in alcune versioni future (e correttamente semver 'd) . Non commettere gli stessi errori delle librerie Java.


4
Io non sono sicuro che è così tanto un "errore" da parte di Java, piuttosto un enorme problema di compatibilità all'indietro (vedi stackoverflow.com/questions/314540 ), che blindgaenger potrebbe non essere necessario prendere in considerazione per il suo codice Ruby.
VonC

38
Il codice è una responsabilità. Meno codice devi mantenere, meglio è. Le deprecazioni sono buone per la compatibilità temporanea con le versioni precedenti, ma col passare del tempo diventa instabile. Se le persone devono utilizzare metodi ritirati, dovrebbero invece utilizzare versioni precedenti delle librerie.
Ryan McGeary,

2
Risposta eccellente. Voglio solo aggiungere un link alla risposta in cui mostro l'approccio che ho usato di recente, che si basa sul Ruby Std Lib: stackoverflow.com/questions/293981/…
Ricardo Valeriano,

1
@RicardoValeriano Sono d'accordo, la tua risposta dovrebbe essere integrata (o votata più in alto, o entrambe :)).
Felix,

54

La Ruby Standard Library ha un modulo con la logica di avviso: https://ruby-doc.org/stdlib/libdoc/rubygems/rdoc/Gem/Deprecate.html . Tendo a preferirlo per mantenere i miei messaggi di deprecazione in modo "standard":

# 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.

Nota che con questo approccio otterrai informazioni gratuite su dove è avvenuta la chiamata.


Bello, non lo sapevo in lib standard.
Kris

2
il primo 0per un letterale numerico lo rende ottale e quindi dovrebbe essere rimosso.
Matt Whipple,

3
Grazie per il consiglio. Ho deprecato un'intera classe e ho suggerito di utilizzare la nuova classe:deprecate :initialize, UseThisClassInstead, 2017, 5
Jon Kern,

Ottimo esempio di utilizzo, Jon. Davvero bello.
Ricardo Valeriano,

5
La precedente risposta corretta è stata deprecata e la risposta di Ricardo Valueriano dovrebbe ora essere utilizzata
simon

14

Se vuoi essere cattivo (con il pretesto di essere d'aiuto) puoi stampare la prima riga del callstack durante un avviso per far sapere agli sviluppatori dove stanno usando una chiamata deprecata.

Questo è cattivo perché sono abbastanza sicuro che sia un successo.

warn Kernel.caller.first + " whatever deprecation message here"

Se utilizzato correttamente, includerà il percorso assoluto del file e della linea in cui è stata utilizzata la chiamata obsoleta. Maggiori informazioni su Kernel :: caller sono disponibili qui


5
Non considero questo cattivo. Un piccolo calo delle prestazioni è più bello che dover inseguire dove era la chiamata deprecata e molto più bello di qualcosa che si interrompe quando il metodo viene infine rimosso.
Nathan Long,

13

Utilizzando ActiveSupport:

class Player < ActiveRecord::Base
  def to_s
    ActiveSupport::Deprecation.warn('Use presenter instead')
    partner_uid
  end
end

Gli avvisi sono disattivati ​​nell'ambiente di produzione per impostazione predefinita


12

Puoi anche usare ActiveSupport::Deprecation(disponibile nella versione 4.0+), come tale:

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)

8

You have have libdeprecated-ruby(2010-2012, non più disponibile su rubygem nel 2015)

Una piccola libreria destinata ad aiutare gli sviluppatori che lavorano con codice deprecato.
L'idea viene dal ' D' linguaggio di programmazione, in cui gli sviluppatori possono contrassegnare un determinato codice come deprecato, quindi consentire / impedire la possibilità di eseguire codice deprecato.

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

Il link mi porta a una pagina su un pacchetto Debian. Sembra simile (se non uguale) ed è un RubyGem: rubygems.org/gems/deprecated
Benjamin Oakes,

3

Puoi usare il modello Class Mac e scrivere qualcosa del genere:

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

3

Quando si usano le rotaie, si ha il metodo deprecate Module #.


2

Canivete è un gioiello che ti consente di deprecare i tuoi metodi in modo semplice ed elegante. Un po 'di più qui .


1

Ho finito per mettere insieme un metodo leggero:

def deprecate(msg)
  method = caller_locations(1, 1).first.label
  source = caller(2, 1).first
  warn "#{method} is deprecated: #{msg}\ncalled at #{source}"
end

Quindi per deprecare un metodo inserire una chiamata nel corpo del metodo (o un costruttore per una classe)

def foo
  deprecate 'prefer bar, will be removed in version 3'
  ...
end

È abbastanza dichiarativo e fornisce la registrazione con informazioni pertinenti. Non sono un gran rubino, quindi potrebbe essere necessario modificare / YMMV.


0

Possiamo usare metodi di macro interne. Esempio:

class Foo def get_a; puts "I'm an A" end def get_b; puts "I'm an B" end def get_c; puts "I'm an C" end

def self.deprecate(old_method, new_method)
  define_method(old_method) do |*args, &block|
     puts "Warning: #{old_method} is deprecated! Use #{new_method} instead"
     send(new_method, *args, &block) 

fine fine

deprecate: a,: get_a deprecate: b,: get_b deprecate: c,: get_c end

o = Foo.new p o

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.