แนวทางปฏิบัติที่ดีที่สุดในการทำเครื่องหมายรหัสที่เลิกใช้แล้วใน Ruby?


127

ฉันต้องการทำเครื่องหมายวิธีการว่าเลิกใช้งานแล้วเพื่อให้ผู้ใช้สามารถตรวจสอบโค้ดและติดตามได้อย่างง่ายดาย ใน Java คุณตั้งค่า @Deprecated และทุกคนรู้ว่านี่หมายถึงอะไร

จึงมีวิธีที่ต้องการ (หรือแม้แต่เครื่องมือ) ในการทำเครื่องหมายและตรวจสอบการเลิกใช้งานใน Ruby หรือไม่?


เพื่อความเป็นธรรมคำอธิบายประกอบของ 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
รหัสเป็นความรับผิด รหัสน้อยคุณต้องรักษาให้ดีขึ้น การเลิกใช้งานเป็นสิ่งที่ดีสำหรับความเข้ากันได้แบบย้อนกลับชั่วคราว แต่เมื่อเวลาผ่านไปมันก็กลายเป็นสิ่งที่ไม่ดี หากผู้คนจำเป็นต้องใช้วิธีเลิกใช้ก็ควรใช้ไลบรารีเวอร์ชันเก่าแทน
Ryan McGeary

2
การตอบสนองที่ยอดเยี่ยม ฉันแค่ต้องการเพิ่มลิงก์ไปยังการตอบกลับที่ฉันแสดงวิธีการที่ฉันใช้เมื่อเร็ว ๆ นี้ซึ่งอาศัย Ruby Std Lib: stackoverflow.com/questions/293981/…
Ricardo Valeriano

1
@RicardoValeriano ฉันเห็นด้วยคำตอบของคุณควรรวม (หรือได้รับการโหวตสูงกว่าหรือทั้งสองอย่าง :))
เฟลิกซ์

54

ทับทิมมาตรฐานห้องสมุดมีโมดูลกับตรรกะคำเตือน: 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 มาตรฐาน
Kris

2
นำหน้า0สำหรับลิเทอรัลตัวเลขทำให้เป็นเลขฐานแปดดังนั้นจึงควรลบออก
Matt Whipple

3
ขอบคุณสำหรับทิป. ฉันเลิกใช้งานทั้งชั้นเรียนและแนะนำให้ใช้คลาสใหม่กว่านี้:deprecate :initialize, UseThisClassInstead, 2017, 5
Jon Kern

ตัวอย่างการใช้งานที่ยอดเยี่ยมจอน ดีจริงๆ
Ricardo Valeriano

5
คำตอบที่ถูกต้องก่อนหน้านี้เลิกใช้แล้วและควรใช้คำตอบโดย Ricardo Valueriano
simon

14

หากคุณต้องการเป็นคนใจร้าย (ภายใต้อุบายของการเป็นประโยชน์) คุณสามารถพิมพ์บรรทัดแรกของ callstack ในระหว่างคำเตือนเพื่อให้ผู้พัฒนาทราบว่าพวกเขากำลังใช้การโทรที่เลิกใช้งานอยู่ที่ไหน

นี่เป็นความหมายเพราะฉันค่อนข้างมั่นใจว่าเป็นผลงานที่ได้รับความนิยม

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

เมื่อใช้อย่างถูกต้องสิ่งนี้จะรวมเส้นทางสัมบูรณ์ไปยังไฟล์และบรรทัดที่ใช้การเรียกที่เลิกใช้แล้ว ข้อมูลเพิ่มเติมเกี่ยวกับ Kernel :: caller มีอยู่ที่นี่


5
ฉันไม่พิจารณาค่าเฉลี่ยนี้ การตีที่มีประสิทธิภาพเพียงเล็กน้อยนั้นดีกว่าการไล่ตามตำแหน่งที่เลิกใช้งานและดีกว่าสิ่งที่ทำลายเมื่อวิธีการถูกลบออกในที่สุด
Nathan Long

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 ไม่สามารถใช้ได้อีกต่อไปใน Rubygem ในปี 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
Benjamin Oakes

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


2

Caniveteเป็นอัญมณีที่ช่วยให้คุณเลิกใช้วิธีการของคุณได้อย่างเรียบง่ายและสวยงาม เล็ก ๆ น้อย ๆ เพิ่มเติมเกี่ยวกับมันนี่


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

มันค่อนข้างเปิดเผยและให้การบันทึกข้อมูลที่เกี่ยวข้อง ฉันไม่ได้เป็น Rubyist มากนักดังนั้นอาจต้องมีการปรับแต่ง / 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) 

สิ้นสุด

เลิกใช้: a,: get_a เลิกใช้: b,: get_b เลิกใช้: c,: get_c end

o = Foo.new p oa

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.