Inheriting constants inside a Ruby module

In Ruby, I am trying to create a class that inherits one of the following modules based on the value specified during initialization. I would like to make a base module that both of these modules inherit from that which contains common methods that use the constants defined in the modules that inherit it. Example:

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

My problem is that when p.what_am_i is called, I get the following error:

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

I am also wondering if there is a better way to do this.

+5
source share
4 answers
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

Edit: The above code does not work:

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

Here is another attempt:

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
+4
source

To get a constant in your situation, you should write something like this:

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

, 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

+2

. , , , :

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

, .

+1

, p #what_am_i, , , BaseMod, OUTPUT . , Ruby OUTPUT, , , , Tall Short, . , , , , (. 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

I chose a constant in favor of instance variables. There are no real constants in Ruby. Tall and Short are classes, and Person is a constructor method that returns the Tall or Short class depending on its input. This is how I feel it should be done.

0
source

All Articles