Найкраща практика позначення застарілого коду в Ruby?


127

Я хотів би позначити метод як застарілий, тому люди, які використовують його, можуть легко перевірити свій код і наздогнати його. На Java ви встановлюєте @Deprecated, і всі знають, що це означає.

Тож чи є кращий спосіб (або навіть інструменти) для маркування та перевірки на застарілі в Рубі?


Якщо чесно, анотація Java підходить, оскільки вона не має значення вказувати на потенційну заміну
Heiko Rupp

Відповіді:


160

Майже у всіх випадках залежно від бібліотеки чи метапрограмування депрекація є надмірною. Просто додайте коментар до rdoc та зателефонуйте до Kernel#warnметоду. Наприклад:

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

Якщо ви використовуєте Yard замість rdoc , коментар до документа повинен виглядати так:

# @deprecated Please use {#useful} instead

І нарешті, якщо ви дотримуєтеся Tomdoc , зробіть ваш коментар таким чином:

# Deprecated: Please use `useful` instead

Застаріле: Позначає, що метод застарілий і буде видалений у наступній версії. Ви повинні використовувати це для документування методів, які були загальнодоступними, але будуть видалені в наступній основній версії.


Крім того, не забудьте видалити застарілий метод у майбутньому (і належним чином semver 'd) релізі . Не робіть тих самих помилок, які робили бібліотеки Java.


4
Я не впевнена , що це так «помилка» з боку Java, а величезна проблема забезпечення сумісності (див stackoverflow.com/questions/314540 ), що blindgaenger неможливо , потрібно розглянути його коду Ruby.
VonC

38
Кодекс - це відповідальність. Чим менше коду вам доведеться підтримувати, тим краще. Позбавлення часу корисні для тимчасової зворотної сумісності, але з часом вона стає суворою. Якщо людям потрібно використовувати пенсійні методи, вони повинні використовувати старіші версії ваших бібліотек.
Райан Макгірі

2
Відмінна відповідь. Я просто хочу додати посилання на відповідь, де я показую підхід, який я використовував останнім часом, який спирається на Ruby Std Lib: stackoverflow.com/questions/293981/…
Рікардо Валеріано

1
@RicardoValeriano Я згоден, ваша відповідь має бути інтегрованою (або проголосували вище, або обидва :)).
Фелікс

53

Стандартна бібліотека Ruby має модуль з логікою попередження: https://ruby-doc.org/stdlib/libdoc/rubygems/rdoc/Gem/Deprecate.html . Я, як правило, вважаю за краще підтримувати свої повідомлення про депресію "стандартним" способом:

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

Зауважте, що при такому підході ви отримаєте безкоштовну інформацію про те, де відбувся дзвінок.


Приємно, не знав про це в стандартній lib.
Кріс

2
провідний 0для числового букваря робить його восьмеричним, тому його, ймовірно, слід видалити.
Метт Віппл

3
Дякую за пораду. Я застарів увесь клас і запропонував використовувати новіший клас:deprecate :initialize, UseThisClassInstead, 2017, 5
Джон Керн,

Прекрасний приклад використання, Джон. Дійсно приємний.
Рікардо Валеріано

5
Попередній правильну відповідь був застарілі і відповідь Рікардо Valueriano повинен тепер бути використаний
SIMON

14

Якщо ви хочете бути підступними (під видом корисності), ви можете роздрукувати перший рядок стовпчика дзвінка під час попередження, щоб повідомити розробникам, де вони використовують застарілий виклик.

Це означає, тому що я майже впевнений, що це хіт на виставу.

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

При правильному використанні це буде включати абсолютний шлях до файла та рядка, де використовувався застарілий виклик. Більше інформації про Kernel :: caller можна отримати тут


5
Я не вважаю це означає. Невеликий хіт на продуктивність приємніший, ніж домагатися того, де був застарілий виклик, і набагато приємніше, ніж щось зламається, коли метод врешті-решт видаляється.
Натан Лонг

13

Використання ActiveSupport:

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

Попередження вимикаються у виробничих умовах за замовчуванням


12

Ви також можете використовувати ActiveSupport::Deprecation(доступний у версії 4.0+) як такий:

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

У вас є libdeprecated-ruby (2010-2012 рр., Більше не доступний на рубігемі у 2015 році)

Невелика бібліотека призначена для допомоги розробникам, які працюють із застарілим кодом.
Ідея походить від Dмови програмування, де розробники можуть позначити певний код як застарілий, а потім дозволити / заборонити можливість виконувати застарілий код.

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

Посилання переносить мене на сторінку про пакет Debian. Це схоже (якщо не те саме) і є RubyGem: rubygems.org/gems/deprecated
Бенджамін Оукс

3

Ви можете використовувати шаблон класу макросів і написати щось подібне:

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



1

Я закінчила співати легкий метод:

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

Потім для знецінення методу вставте виклик у тіло методу (або конструктор для класу)

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

Це досить декларативно і забезпечує ведення журналу з відповідною інформацією. Я не сильно рубіст, тому це може знадобитися певного налаштування / YMMV.


0

Ми можемо використовувати внутрішні методи макросів. Приклад:

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) 

кінцевий кінець

deprecate: a,: get_a deprecate: b,: get_b deprecate: c,: get_c кінець

o = Foo.новий p oa

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.