Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/azure/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 宏和类级访问器方法的最佳实践和实现?_Ruby_Macros_Metaprogramming_Class Design_Accessor - Fatal编程技术网

Ruby 宏和类级访问器方法的最佳实践和实现?

Ruby 宏和类级访问器方法的最佳实践和实现?,ruby,macros,metaprogramming,class-design,accessor,Ruby,Macros,Metaprogramming,Class Design,Accessor,我正在设计/构建一个类系统,所有这些类都派生自一个基类 目标是使继承的宏方法易于使用,如下所示: class Something < A::Base full_name 'Something that goes bump in the night.' end module MacroMethods private def full_name(full_name) # non-trivial, one-time-only set-up code exists here

我正在设计/构建一个类系统,所有这些类都派生自一个基类

目标是使继承的宏方法易于使用,如下所示:

class Something < A::Base
  full_name 'Something that goes bump in the night.'
end
module MacroMethods
  private
  def full_name(full_name)
    # non-trivial, one-time-only set-up code exists here in actual usage
  end
end
module AccessorMethods
  public
  def full_name
    # a non-trivial, runtime-calculated value is returned here in actual usage
  end
end
> Thing.full_name = 'Thing Class'
=> "Thing Class"
> Thing.full_name
=> "My full name is Thing Class"
module MacroMethods
  private
  def full_name(full_name)
    # non-trivial, one-time-only set-up code exists here in actual usage
    # this method can only be called once in the definition of any given class,
    #   because after the first call, it will be redefined!
    extend AccessorMethods
  end
end

module AccessorMethods
  public
  def full_name
    # a non-trivial, runtime-calculated value is returned here in actual usage
  end
end

class Base
  extend MacroMethods
end

class Something < Base
  full_name 'after this call, I will get a new full_name method!'
end

class SomethingElse < Base
  full_name 'so will I!'
end

鉴于
A::Base
包含/扩展/以某种方式混合了模块和宏方法,其工作原理如下:

class Something < A::Base
  full_name 'Something that goes bump in the night.'
end
module MacroMethods
  private
  def full_name(full_name)
    # non-trivial, one-time-only set-up code exists here in actual usage
  end
end
module AccessorMethods
  public
  def full_name
    # a non-trivial, runtime-calculated value is returned here in actual usage
  end
end
> Thing.full_name = 'Thing Class'
=> "Thing Class"
> Thing.full_name
=> "My full name is Thing Class"
module MacroMethods
  private
  def full_name(full_name)
    # non-trivial, one-time-only set-up code exists here in actual usage
    # this method can only be called once in the definition of any given class,
    #   because after the first call, it will be redefined!
    extend AccessorMethods
  end
end

module AccessorMethods
  public
  def full_name
    # a non-trivial, runtime-calculated value is returned here in actual usage
  end
end

class Base
  extend MacroMethods
end

class Something < Base
  full_name 'after this call, I will get a new full_name method!'
end

class SomethingElse < Base
  full_name 'so will I!'
end
以及一个具有类级访问器方法的模块,其工作原理如下:

class Something < A::Base
  full_name 'Something that goes bump in the night.'
end
module MacroMethods
  private
  def full_name(full_name)
    # non-trivial, one-time-only set-up code exists here in actual usage
  end
end
module AccessorMethods
  public
  def full_name
    # a non-trivial, runtime-calculated value is returned here in actual usage
  end
end
> Thing.full_name = 'Thing Class'
=> "Thing Class"
> Thing.full_name
=> "My full name is Thing Class"
module MacroMethods
  private
  def full_name(full_name)
    # non-trivial, one-time-only set-up code exists here in actual usage
    # this method can only be called once in the definition of any given class,
    #   because after the first call, it will be redefined!
    extend AccessorMethods
  end
end

module AccessorMethods
  public
  def full_name
    # a non-trivial, runtime-calculated value is returned here in actual usage
  end
end

class Base
  extend MacroMethods
end

class Something < Base
  full_name 'after this call, I will get a new full_name method!'
end

class SomethingElse < Base
  full_name 'so will I!'
end
无论我如何将它们混合在一起,我都会不断地在两者之间遇到命名冲突(即“错误数量的参数(1代表0)(ArgumentError)”)

注意:
全名
是所需内容的最简单示例;其他更复杂的宏/访问器确保宏方法的非灵活约束需要在类内声明,并且只需要设置一次


我的问题有两个方面:

  • 有没有一种方法可以让这些都在
    a::Base
    类中工作?
  • 在Ruby中这是正确的方法吗?有没有更好的方法来实现同样的结果
  • 已考虑的备选方案:

    • 调用宏或访问器方法或其他方法。
      (例如,在某物类中:
      设置“某物的全名…”

      缺点是命名混乱且不符合常规

    • 将访问器方法设置为实例级而不是类级。
      (例如,
      放一个“某物.全名”

      缺点是宏设置的特性是类固有的,而不是每个实例固有的(在某些情况下,可能只有对类的引用可用,而不是实例)

    • 创建处理宏和访问器功能的单一方法。
      (例如,在A::基类中:
      def self.full_name(*args).

      缺点是宏方法不再是私有的,RDoc看起来像sh*t

    • 改用absact/virtual-ish方法。
      (例如,在Something类中:
      def self.full_name;'Something that…';end

      缺点是,这是子类中的更多代码,而不是一个好的Ruby范例,它是Objul-C(或C++,或java,…)的东西。


    如果您希望某些类可以使用类宏,那么公共基类不是Ruby解决方案。相反,您可以创建一个模块,该模块使用希望基类具有的功能扩展基类:

    module Extensions
      def self.included(base_class)
        base_class.extend ClassMethods
      end
    
      module ClassMethods
        attr_accessor :full_name
      end
    end
    
    class Something
      include Extensions
    
      self.full_name = "Something that goes bump in the night"
    end
    
    puts Something.full_name    # => Something that goes bump in the night
    thing = Something.new
    puts thing.full_name        # Error
    

    这将覆盖
    扩展
    中名为
    Module#included
    的钩子方法,该方法将包含该模块的任何类作为参数传递。然后,新方法调用基类上的
    Object#extend
    ,将
    ClassMethods
    中可用的方法作为类方法直接放到该类上。这与定义类方法的方式相同,但它是动态运行的。这使您无需在提供宏的类上使用唯一的基类。请注意,这些方法没有在包含模块的类的实例上定义。

    这似乎不必要地复杂。为什么不在父类上使用属性呢

    class Base
      class << self
        attr_accessor :full_name
      end
    end
    
    class A < Base; end
    
    class B < Base; end
    
    A.full_name = "The full name of A"
    B.full_name = "The full name of B"
    
    puts A.full_name # "The full name of A"
    puts B.full_name # "The full name of B"
    
    类基
    
    类看起来大多数其他答案都有正确的想法,但缺少
    #全名
    的getter方法。此示例可能就是您正在寻找的:

    class Thing
      class << self
        attr_writer :full_name
    
        def full_name
          "My full name is #{@full_name}"
        end
      end
    end
    

    拖鞋,我仔细阅读了你的问题。无法在同一对象上同时定义名为
    full\u name
    的两种不同方法。但是,你可以这样做:

    class Something < A::Base
      full_name 'Something that goes bump in the night.'
    end
    
    module MacroMethods
      private
      def full_name(full_name)
        # non-trivial, one-time-only set-up code exists here in actual usage
      end
    end
    
    module AccessorMethods
      public
      def full_name
        # a non-trivial, runtime-calculated value is returned here in actual usage
      end
    end
    
    > Thing.full_name = 'Thing Class'
    => "Thing Class"
    > Thing.full_name
    => "My full name is Thing Class"
    
    module MacroMethods
      private
      def full_name(full_name)
        # non-trivial, one-time-only set-up code exists here in actual usage
        # this method can only be called once in the definition of any given class,
        #   because after the first call, it will be redefined!
        extend AccessorMethods
      end
    end
    
    module AccessorMethods
      public
      def full_name
        # a non-trivial, runtime-calculated value is returned here in actual usage
      end
    end
    
    class Base
      extend MacroMethods
    end
    
    class Something < Base
      full_name 'after this call, I will get a new full_name method!'
    end
    
    class SomethingElse < Base
      full_name 'so will I!'
    end
    
    模块宏方法
    私有的
    def全名(全名)
    #在实际使用中,这里存在非常重要的一次性设置代码
    #此方法在任何给定类的定义中只能调用一次,
    #因为在第一次调用之后,它将被重新定义!
    扩展辅助方法
    结束
    结束
    模块辅助方法
    公众的
    def全名
    #在实际使用中,这里返回一个非平凡的运行时计算值
    结束
    结束
    阶级基础
    扩展宏方法
    结束
    将某物分类为
    这基本上就是我正在做的事情;如果有兴趣,你可以查看我正在使用的实际代码。不过,也许我遗漏了一些东西。我不知道这如何解决类级访问器方法的名称与类级宏方法的名称冲突的问题。从您的示例来看,似乎没有访问器方法(调用
    Something.full\u name
    会引发ArgumentError)。我通过添加更多示例代码澄清了这个问题。希望这有助于澄清我在寻找什么。我更新了我的答案。如果您还不了解Ruby元编程,那么您可能需要对Ruby元编程进行一些研究,然后才能完全理解解决方案,但这应该是可行的。感谢您更新您的答案,但它仍然没有解决我的问题(请参阅“注:全名是所需内容的最简单示例…”“全名”宏/访问器只是最简单的例子;需要做更多的事情。此外,其目的是创建一个固化的模型,该模型可以在以后的代码中依赖;允许琐碎的重新定义违背了目的。我已经澄清了一个问题,即给定的代码是我正在尝试的一个示例,不是我的确切代码,而且给定的约束也不灵活。@Refactor和@Jimmy:我删除了特定于简单的
    full_name
    的代码位,以澄清问题不是简单地设置和获取静态值,而是Ruby中最好的范例,考虑到只需一次的宏方法和类级访问器的需要,不管v