5

Ruby では、初期化中に指定された値に基づいて、次のモジュールのいずれかから継承されるクラスを作成しようとしています。これらのモジュールの両方が継承し、それを継承するモジュールで定義された定数を使用する共通のメソッドを含む基本モジュールを作成したいと思います。例:

module BaseMod
  def what_am_i
    puts OUTPUT
  end
end

module Tall
  OUTPUT = "I am tall"
  include BaseMod
end

module Short
  OUTPUT = "I am short"
  include BaseMod
end

class Person
  def initialize type
    if type =~ /short/i
      extend Short
    else
      extend Tall
    end
  end
end

p = Person.new "short"
p.what_am_i

私の問題は、「p.what_am_i」が呼び出されると、次のエラーが発生することです。

NameError: uninitialized constant BaseMod::OUTPUT
  const_missing at org/jruby/RubyModule.java:2642
      what_am_i at test_logic2.rb:3
         (root) at test_logic2.rb:28

また、これを行うためのより良い方法があるかどうかも疑問に思っています。

4

4 に答える 4

4
module BaseMod
  def what_am_i
    puts self.class::OUTPUT
  end
end

module Tall
  OUTPUT = "I am tall"
  include BaseMod
end

module Short
  OUTPUT = "I am short"
  include BaseMod
end

class Person
  def initialize(type)
    if type =~ /short/i
      self.class.send(:include, Short)
    else
      self.class.send(:include, Tall)
    end
  end
end

p = Person.new "short"
p.what_am_i

編集:上記のコードは実際には機能しません:

p = Person.new "short"
p.what_am_i
>> I am short
p = Person.new "tall"
p.what_am_i
>> I am tall
p = Person.new "short"
p.what_am_i
>> I am tall

別の試みを次に示します。

module BaseMod
  def self.included(base)
    base.send(:define_method, :what_am_i) do
      puts base::OUTPUT
    end
  end
end

module Tall
  OUTPUT = "I am tall"
  include BaseMod
end

module Short
  OUTPUT = "I am short"
  include BaseMod
end

class Person
  def initialize type
    if type =~ /short/i
      extend Short
    else
      extend Tall
    end
  end
end

p = Person.new "short"
p.what_am_i
p = Person.new "tall"
p.what_am_i
p = Person.new "short"
p.what_am_i
于 2012-07-17T22:30:53.130 に答える
2

あなたの状況で定数を取得するには、次のように書く必要があります。

module Tall
 ::OUTPUT = "I am tall"
 include BaseMod
end

ただし、Short モジュールの宣言で定数を再定義していることに注意してください。そのため、常に「I am short」が表示されます。

したがって、正しく行うには、次のことを試してください。

module BaseMod
 OUTPUT="Before"
 def what_am_i
  puts OUTPUT
 end
end

module Tall
 def self.extended(k)
  OUTPUT.replace  "I am tall"
 end
 include BaseMod
end

module Short
 def self.extended(k)
  OUTPUT.replace "I am short"
 end
 include BaseMod
end

K

于 2012-07-17T01:00:08.670 に答える
1

もう1つのオプションをテーブルに持ってきます。あなたの複雑な実世界のケースが何であるかはよくわからないので、ここに私の選択があります:

module BaseMod
  def what_am_i
    puts output
  end
end

module Tall
  include BaseMod
  def self.extended klass
    define_method :output do
      "I am tall"
    end
  end
end

module Short
  include BaseMod
  def self.extended klass
    define_method :output do
      "I am short"
    end
  end
end

class Person
  def initialize type
    extend (type =~ /short/i ? Short : Tall ) # Because I didn't wanna type all those lines
  end
end

p = Person.new "short"
p.what_am_i

この状況では、これを同じように簡単に実行できることに注意してください。

module Tall
  include BaseMod
  def output
    "I am tall"
  end
end

しかし、それが本当にあなたを助けるかどうかはわかりません。

于 2012-07-17T15:39:35.277 に答える
0

人 p に #what_am_i メッセージを送信すると、インタープリターはクラスの祖先の上位にあるメソッドの実装を探し、最終的に BaseMod でそれを見つけますが、そのレベルでは OUTPUT 定数はもう定義されていません。だから、Ruby は OUTPUT 定数を階層の上に向かって探し続けていると思いますが、それが定義されている Tall および Short モジュールでは、下に向かって調べることは考えていません。士気は、多くのサブモジュールを含めたとしても、すべての定数にすべての人がアクセスできる 1 つのヒープに入るのではなく、それらの階層を含める順序と逆の順序で維持することです (Tall.Ancestors を参照)。どのレベルでも、同じレベルまたはそれ以上のレベルの定数のみにアクセスできます。私は次の方法であなたの問題を解決します:

module Personhood
  def what_am_i; @output end
end

class Tall
  include Personhood
    def initialize
      @output = "I am tall"
    end
  end
end

class Short
  include Personhood
    def initialize
      @output = "I am short"
    end
  end
end

def Person( type )
  if type =~ /short/i
    Short.new
  else
    Tall.new
  end
end

pete = Person "short"
pete.what_am_i
=> I am short

インスタンス変数を優先して定数を破棄しました。とにかく、Rubyには実際の定数はありません。Tall と Short をクラスにし、Person をコンストラクタ メソッドにして、入力に応じて Tall または Short クラスを返します。そうすべきだと感じています。

于 2012-07-17T03:19:57.813 に答える