Praktik terbaik untuk menandai kode usang di Ruby?

127

Saya ingin menandai metode yang sudah usang, sehingga orang yang menggunakannya dapat dengan mudah memeriksa kode mereka dan mengejar ketinggalan. Di Java Anda mengatur @Deprecated dan semua orang tahu apa artinya ini.

Jadi apakah ada cara yang disukai (atau bahkan alat) untuk menandai dan memeriksa penghentian di Ruby?

blindgaenger
sumber
Agar adil, anotasi Java menyebalkan, karena tidak memiliki nilai untuk menunjuk pada pengganti potensial
Heiko Rupp

Jawaban:

160

Untuk hampir semua kasus, tergantung pada pustaka atau metaprogramming untuk penghentian berlebihan. Cukup tambahkan komentar ke rdoc dan panggil Kernel#warnmetode tersebut. Sebagai contoh:

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

Jika Anda menggunakan Yard, bukan rdoc , komentar dokumen Anda akan terlihat seperti ini:

# @deprecated Please use {#useful} instead

Terakhir, jika Anda mematuhi tomdoc , buat komentar Anda terlihat seperti ini:

# Deprecated: Please use `useful` instead

Sudah usang: Menunjukkan bahwa metode ini sudah usang dan akan dihapus dalam versi yang akan datang. Anda HARUS menggunakannya untuk mendokumentasikan metode yang bersifat Publik tetapi akan dihapus pada versi utama berikutnya.


Juga, jangan lupa untuk menghapus metode yang sudah usang dalam beberapa rilis mendatang (dan semver 'd) dengan benar . Jangan membuat kesalahan yang sama seperti yang dilakukan perpustakaan Java.

Ryan McGeary
sumber
4
Saya tidak yakin ini merupakan "kesalahan" dari bagian Java, lebih merupakan masalah kompatibilitas ke belakang yang besar (lihat stackoverflow.com/questions/314540 ), sehingga blindgaenger mungkin tidak perlu mempertimbangkan kode Ruby-nya.
VonC
38
Kode adalah kewajiban. Semakin sedikit kode yang Anda miliki untuk mempertahankan yang lebih baik. Penghentian bagus untuk kompatibilitas mundur sementara, tetapi seiring berjalannya waktu akan menjadi cacat. Jika orang perlu menggunakan metode pensiun, mereka harus menggunakan versi pustaka Anda yang lebih lama.
Ryan McGeary
2
Respons yang luar biasa. Saya hanya ingin menambahkan tautan ke respons tempat saya menunjukkan pendekatan yang saya gunakan akhir-akhir ini, yang bergantung pada Ruby Std Lib: stackoverflow.com/questions/293981/…
Ricardo Valeriano
1
@ RicardoValeriano Saya setuju, respons Anda harus diintegrasikan (atau lebih tinggi, atau keduanya :)).
Felix
53

Perpustakaan Ruby Standar memiliki modul dengan logika peringatan: https://ruby-doc.org/stdlib/libdoc/rubygems/rdoc/Gem/Deprecate.html . Saya cenderung lebih suka mempertahankan pesan penghinaan saya dengan cara "standar":

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

Perhatikan bahwa dengan pendekatan ini Anda akan memperoleh informasi gratis tentang di mana panggilan berlangsung.

Ricardo Valeriano
sumber
Bagus, tidak tahu tentang ini di lib standar.
Kris
2
yang memimpin 0untuk literal numerik membuatnya menjadi oktal dan karenanya harus dihapus.
Matt Whipple
3
Terima kasih atas tipnya. Saya menghentikan seluruh kelas, dan menyarankan kelas yang lebih baru untuk digunakan:deprecate :initialize, UseThisClassInstead, 2017, 5
Jon Kern
Contoh penggunaan yang bagus, Jon. Sangat bagus.
Ricardo Valeriano
5
Jawaban yang benar sebelumnya telah ditinggalkan dan jawaban oleh Ricardo Valueriano sekarang harus digunakan
simon
14

Jika Anda ingin menjadi kejam (dalam tipu muslihat membantu) Anda dapat mencetak baris pertama dari callstack selama peringatan untuk memberi tahu para dev di mana mereka menggunakan panggilan yang sudah tidak digunakan lagi.

Ini berarti karena saya cukup yakin ini adalah hit kinerja.

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

Ketika digunakan dengan benar, ini akan mencakup jalur absolut ke file dan baris tempat panggilan yang sudah usang digunakan. Informasi lebih lanjut tentang Kernel :: caller tersedia di sini

Adam French
sumber
5
Saya tidak menganggap ini berarti. Hit kinerja kecil lebih baik daripada harus mengejar di mana panggilan yang sudah ditinggalkan itu, dan jauh lebih bagus daripada sesuatu yang melanggar ketika metode ini akhirnya dihapus.
Nathan Long
13

Menggunakan ActiveSupport:

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

Peringatan dinonaktifkan di lingkungan produksi secara default

Artur Beljajev
sumber
12

Anda juga dapat menggunakan ActiveSupport::Deprecation(tersedia dalam versi 4.0+), seperti:

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)
Keris
sumber
8

Anda punya libdeprecated-ruby(2010-2012, tidak tersedia lagi di rubygem pada 2015)

Perpustakaan kecil yang dimaksudkan untuk membantu pengembang yang bekerja dengan kode yang sudah usang.
Idenya berasal dari Dbahasa pemrograman ' ', di mana pengembang dapat menandai kode tertentu sebagai usang, dan kemudian memungkinkan / melarang kemampuan untuk mengeksekusi kode usang.

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
VONC
sumber
Tautan membawa saya ke halaman tentang paket Debian. Ini tampaknya mirip (jika tidak sama) dan merupakan RubyGem: rubygems.org/gems/deprecated
Benjamin Oakes
3

Anda dapat menggunakan pola Kelas Macro dan menulis sesuatu seperti ini:

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
Alex Djioev
sumber
3

Saat menggunakan rails, Anda memiliki metode Modul # deprecate.

Pedro Rolo
sumber
2

Canivete adalah permata yang memungkinkan Anda mencela metode Anda dengan cara yang sederhana dan elegan. Sedikit lagi di sini .

skalee
sumber
1

Saya akhirnya menggunakan metode ringan:

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

Kemudian untuk menghentikan metode masukkan panggilan dalam tubuh metode (atau konstruktor untuk kelas)

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

Ini cukup deklaratif dan memberikan info yang relevan dengan logging. Saya tidak terlalu Rubyist jadi mungkin perlu sedikit penyesuaian / YMMV.

Matt Whipple
sumber
0

Kita dapat menggunakan metode makro internal. Contoh:

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) 

ujung akhir

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

o = Foo.n baru p oa

EVN Raja
sumber