64

日付が変わるたびに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 の回答は警告を生成せず、単純に優れています。

4

4 に答える 4

69

次のモジュールはあなたが望むことをするかもしれません。そうでない場合、それはあなたの解決策へのいくつかの指針を提供するかもしれません

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構​​造のいくつかにまだ頭を悩ませているので、ここでルビーのタブーを破った場合は許してください

于 2010-07-31T07:00:57.000 に答える
6

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

アップデート2020/5/6:リンクが切れたというコメントに応えて、古いプロジェクトの例をここに貼り付けていますが、それが良いアプローチであるかどうか、どのような状況であるかはわかりません。

original_verbose = $VERBOSE
$VERBOSE = nil # suppress warnings
# do stuff that raises warnings you don't care about
$VERBOSE = original_verbose
于 2012-08-30T18:11:10.573 に答える
4

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

他のケースでTau = 2 * Pi unless defined?(Tau)は、完全に問題なく、最も読みやすいため、最もエレガントなソリューションです。

于 2010-07-30T21:15:54.033 に答える
2

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

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

于 2010-07-30T21:38:41.890 に答える