Ruby では
Class.new
で無名のクラスオブジェクトは生成することができる。
このとき
- クラス名
- クラス本体
通常のクラス定義
class Foo
では、識別子のレベルでクラスの名前 (定数) が与えられていなければならない。Class.new
では、無名のクラス・オブジェクトを作れるが、今回の目的を果たすには命名が必要である。
だから、どうすればいいかというと
- 無名のクラス・オブジェクトを作ってから、それにクラス名を与える
- この無名のクラス・オブジェクトは、クラスの中身 (これから作ろうとしているクラスで評価されるコードブロック) を持つ
ことができればよい。
class_define
以下のコードで作ってみた。
#
# file: class_define.rb
#
# create nameless class object with code block.
# ==== Args
# &block :: code block
# ==== Return
# a class object.
# ==== See Also
# * class_define
def create_class( &block )
class_obj = Class.new
class_obj.class_eval(&block) # self will be bound at designation.
class_obj
end
# name a nameless class object.
# ==== Args
# name :: class name in symbol.
# class_obj :: class object.
# parent :: current class.
# ==== Return
# const value (class name)
# ==== See Also
# * class_define
def designate_class( name, class_obj, parent=self )
#eval "#{name.to_s}=class_obj"
parent.const_set(name, class_obj)
end
# generate a class with code block.
# ==== Usage
# in top-level or class definition scope,
# class_define :Foo do
# def foo; "#{__method__} #{self}"
# end
# ==== Args
# const_sym :: a name of class in symbol.
# parent :: current class.
# &block :: body of class.
# ==== Return
#
def class_define( const_sym, parent=self, &block )
parent = parent.class unless parent.to_s =~ /^[A-Z]/
class_obj = create_class(&block)
designate_class(const_sym, class_obj, parent)
end
#### end of filename: class_define.rb
テスト
require "class_define"
class_define :Foo do
def foo; "#{__method__} #{self}"; end
end
class_define :Car do
def foo; "#{__method__} #{self}"; end
end
p Foo.new.foo
p Car.new.foo
begin
foo
rescue => e
puts e.message
end
# class in class (Foo::Bar)
class Foo
class_define :Bar do
def foo; "#{__method__} #{self}"; end
end
end
# class in class (Car::Cdr)
class_define :Cdr, Car do
def foo; "#{__method__} #{self}"; end
end
p Foo::Bar.new.foo
p Car::Cdr.new.foo
実行すると、
$ ruby -I. test-class_define.rb
"foo #<Foo:0x000001011679c8>"
"foo #<Car:0x00000101167838>"
undefined local variable or method `foo' for main:Object
"foo #<Foo::Bar:0x00000101167180>"
"foo #<Car::Cdr:0x00000101166ff0>"
となり、いい感じである。
0 件のコメント:
コメントを投稿
何かありましたら、どうぞ: