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
类中工作?- 调用宏或访问器方法或其他方法。
(例如,在某物类中:
)设置“某物的全名…”
缺点是命名混乱且不符合常规 - 将访问器方法设置为实例级而不是类级。
(例如,
)放一个“某物.全名”
缺点是宏设置的特性是类固有的,而不是每个实例固有的(在某些情况下,可能只有对类的引用可用,而不是实例) - 创建处理宏和访问器功能的单一方法。
(例如,在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,…)的东西。
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