web-dev-qa-db-ja.com

警告なしでRuby定数を再定義するには?

日付が変わるたびにRubyファイルを評価するRubyコードを実行しています。ファイルには、次のような定数の定義があります

Tau = 2 * Pi

そして、もちろん、インタープリターに不要な「すでに初期化された定数」警告を毎回表示させるので、次の機能が必要です。

def_if_not_defined(:Tau, 2 * Pi)
redef_without_warning(:Tau, 2 * Pi)

このような定数定義をすべて書くことで、警告を回避できます。

Tau = 2 * Pi unless defined?(Tau)

しかし、それはエレガントではなく、少し濡れています( [〜#〜] dry [〜#〜] ではありません)。

def_if_not_definedへのより良い方法はありますか?そして、どのようにredef_without_warning

-

スティーブのおかげで解決策:

class Object
  def def_if_not_defined(const, value)
    mod = self.is_a?(Module) ? self : self.class
    mod.const_set(const, value) unless mod.const_defined?(const)
  end

  def redef_without_warning(const, value)
    mod = self.is_a?(Module) ? self : self.class
    mod.send(:remove_const, const) if mod.const_defined?(const)
    mod.const_set(const, value)
  end
end

A = 1
redef_without_warning :A, 2
fail 'unit test' unless A == 2
module M
  B = 10
  redef_without_warning :B, 20
end
fail 'unit test' unless M::B == 20

-

この質問は古いです。上記のコードはRuby 1.8にのみ必要です。 Ruby 1.9では、P3t3rU5の答えは警告を出さず、単に優れています。

55

次のモジュールはあなたが望むことをするかもしれません。そうでない場合、ソリューションへのポインタを提供する可能性があります

module RemovableConstants

  def def_if_not_defined(const, value)
    self.class.const_set(const, value) unless self.class.const_defined?(const)
  end

  def redef_without_warning(const, value)
    self.class.send(:remove_const, const) if self.class.const_defined?(const)
    self.class.const_set(const, value)
  end
end

そして、それを使用する例として

class A
  include RemovableConstants

  def initialize
    def_if_not_defined("Foo", "ABC")
    def_if_not_defined("Bar", "DEF")
  end

  def show_constants
    puts "Foo is #{Foo}"
    puts "Bar is #{Bar}"
  end

  def reload
    redef_without_warning("Foo", "GHI")
    redef_without_warning("Bar", "JKL")
  end

end

a = A.new
a.show_constants
a.reload
a.show_constants

次の出力を提供します

Foo is ABC
Bar is DEF
Foo is GHI
Bar is JKL

Ruby内のModule:Class:Eigenclass構​​造のいくつかについてまだ頭を悩ませているので、ここでRubyタブーを破った場合はご容赦ください

60
Steve Weet

値を再定義し、定数を使用しない場合は、代わりにグローバル変数($ tau = 2 * Pi)を使用しますが、これも良い方法ではありません。適切なクラスのインスタンス変数にする必要があります。

その他の場合、Tau = 2 * Pi unless defined?(Tau)は完全に問題なく、最も読みやすく、したがって最もエレガントなソリューションです。

4
Leventix

警告を抑制するために$ VERBOSEを使用する別のアプローチについては、ここで説明します。 http://mentalized.net/journal/2010/04/02/suppress_warnings_from_Ruby/

3
Paul Lynch

定数の値が非常に奇妙でない限り(つまり、nilまたはfalseに設定された定数がある場合)、最良の選択は条件付き代入演算子を使用することです:Tau ||= 2*Pi

これにより、Tauがnilfalse、または未定義の場合は2πに設定され、それ以外の場合はそのままになります。

2
Chuck