定义类声明的方法调用,la Rails

时间:2016-06-14 20:16:20

标签: ruby-on-rails ruby inheritance

我正在构建一个类似于ActiveRecord的特定于域的层次结构继承结构,即我有一个Base类,然后在n下声明了Base个子类。

我目前正在将子项中的细节声明为常量,然后从Base类中的共享方法中调用它们,但它变得笨拙。我想通过方法调用实现Rails样式来声明特定于类的实例化值

如果您熟悉Rails,我实际上是在尝试从ActiveRecord复制has_many / belongs_to的通用结构,或者从ActionPack复制before_action

我想要完成的一个简单的,人为的例子......

class Widget < Base

  important_value :foo, :bar

end

widget = Widget.new
widget.foo
# => :bar

如果有人可以向我解释在课程Base中要实现上述目标的内容,我将会顺利开展。

2 个答案:

答案 0 :(得分:1)

class Base 
  class << self
    def important_value(key, value)
      # define method named `key` which returns `value`
      define_method(key) { value } 
    end 
  end 
end 

class Widget < Base 
  important_value :foo, :bar 
end 

Widget.new.foo # => :bar

或者,如果“重要值”方法的数量很少且事先已知:

class Base 
  def foo 
    self.class.foo 
  end 

  class << self
    attr_reader :foo 

    def important_value(key, value)
      self.instance_variable_set(:"@#{key}", value)
    end 
  end 
end 

class Widget < Base 
  important_value :foo, :bar 
end 

Widget.new.foo # => :bar

答案 1 :(得分:0)

这与我原来问题的条件并不完全一致,但它对我的推动非常有帮助。

class Base

  # defining variables happens at the class level
  # the first line allows us to set a sane default (skip for a nil value)
  # the second line makes the method a getter as well as a setter (this is required)
  def self.title(val = nil)
    @title ||= 'DEFAULT TITLE'
    return @title if val.nil?
    @title = val.upcase
  end

  # the instance-level reader
  # if you want to change the values from the child, use attr_accessor
  # in either case, the visibility of @title in the child is unchanged (we assume its not accessed directly)
  attr_reader :title

  # set the instance variable when the class is instantiated
  def initialize
    instance_variable_set("@title", self.class.title)
  end

end

class Foo < Base
  title "foo title"
end

class Bar < Base
  # if left commented out, the value will be set to 'DEFAULT TITLE'
  # title "BAR TITLE" 
end

f = Foo.new
f.title
# => "FOO TITLE"

b = Bar.new
b.title
# => "DEFAULT TITLE"