metaclass is back
this time with a real purpose and implementation as the intermediary As the interface to the layout and for replacing an edited layout
This commit is contained in:
parent
ebcc15d314
commit
204200b92a
@ -7,6 +7,7 @@ require "parfait/list"
|
|||||||
require "parfait/word"
|
require "parfait/word"
|
||||||
require "parfait/binary_code"
|
require "parfait/binary_code"
|
||||||
require "parfait/method"
|
require "parfait/method"
|
||||||
|
require "parfait/meta_class"
|
||||||
require "parfait/variable"
|
require "parfait/variable"
|
||||||
require "parfait/dictionary"
|
require "parfait/dictionary"
|
||||||
require "parfait/layout"
|
require "parfait/layout"
|
||||||
|
@ -80,7 +80,7 @@ module Parfait
|
|||||||
has = super_index(name)
|
has = super_index(name)
|
||||||
return nil unless has
|
return nil unless has
|
||||||
raise "internal error #{name}:#{has}" if has < 1
|
raise "internal error #{name}:#{has}" if has < 1
|
||||||
(1 + has / 2).to_i # to_i for opal
|
(1 + has / 2).to_i # to_i for opal
|
||||||
end
|
end
|
||||||
|
|
||||||
def inspect
|
def inspect
|
||||||
@ -96,11 +96,5 @@ module Parfait
|
|||||||
nil # stop resolve recursing up metaclasses
|
nil # stop resolve recursing up metaclasses
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_instance_method method_name , arguments
|
|
||||||
raise "create_instance_method #{method_name}.#{method_name.class}" unless method_name.is_a?(Symbol)
|
|
||||||
#puts "Self: #{self.class} clazz: #{clazz.name}"
|
|
||||||
add_instance_method Method.new( self , method_name , arguments )
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
68
lib/parfait/meta_class.rb
Normal file
68
lib/parfait/meta_class.rb
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
module Parfait
|
||||||
|
|
||||||
|
# class that acts like a class, but is really the object
|
||||||
|
|
||||||
|
# described in the ruby language book as the eigenclass, what you get with
|
||||||
|
# class MyClass
|
||||||
|
# class << self <--- this is called the eigenclass, or metaclass, and really is just
|
||||||
|
# .... the class object but gives us the ability to use the
|
||||||
|
# syntax as if it were a class
|
||||||
|
|
||||||
|
# While the "real" metaclass is the layout, we need to honor the constancy of the layout
|
||||||
|
# So the layout needs to be copied and replaced anytime it is edited.
|
||||||
|
# And then changed in the original object, and thus we need this level of indirection
|
||||||
|
|
||||||
|
# Basically we implement the Behaviour protocol, by forwarding to the layout
|
||||||
|
|
||||||
|
class MetaClass < Object
|
||||||
|
include Logging
|
||||||
|
|
||||||
|
attribute :object
|
||||||
|
|
||||||
|
def initialize(object)
|
||||||
|
super()
|
||||||
|
self.object = object
|
||||||
|
end
|
||||||
|
|
||||||
|
def name
|
||||||
|
self.object.get_layout.name
|
||||||
|
end
|
||||||
|
# first part of the protocol is read, just forward to self.object.layout
|
||||||
|
def methods
|
||||||
|
self.object.get_layout.methods
|
||||||
|
end
|
||||||
|
def method_names
|
||||||
|
self.object.get_layout.method_names
|
||||||
|
end
|
||||||
|
def get_instance_method fname
|
||||||
|
self.object.get_layout.get_instance_method fname
|
||||||
|
end
|
||||||
|
def resolve_method m_name
|
||||||
|
self.object.get_layout.resolve_method m_name
|
||||||
|
end
|
||||||
|
|
||||||
|
# the modifying part creates a new layout
|
||||||
|
# forwards the action and replaces the layout
|
||||||
|
def add_instance_method method
|
||||||
|
layout = self.object.get_layout.dup
|
||||||
|
ret = layout.add_instance_method(method)
|
||||||
|
self.object.set_layout layout
|
||||||
|
ret
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_instance_method method_name
|
||||||
|
layout = self.object.get_layout.dup
|
||||||
|
ret = layout.remove_instance_method(method_name)
|
||||||
|
self.object.set_layout layout
|
||||||
|
ret
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_instance_method method_name , arguments
|
||||||
|
raise "create_instance_method #{method_name}.#{method_name.class}" unless method_name.is_a?(Symbol)
|
||||||
|
log.debug "Add_method: #{method_name} clazz: #{self.name}"
|
||||||
|
add_instance_method Method.new( self , method_name , arguments )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
@ -114,15 +114,14 @@ module Register
|
|||||||
def layout_names
|
def layout_names
|
||||||
{ :Word => {:char_length => :Integer} ,
|
{ :Word => {:char_length => :Integer} ,
|
||||||
:List => {:indexed_length => :Integer} ,
|
:List => {:indexed_length => :Integer} ,
|
||||||
# Assumtion is that name is the last of message
|
|
||||||
:Message => { :next_message => :Message, :receiver => :Object, :frame => :Frame ,
|
:Message => { :next_message => :Message, :receiver => :Object, :frame => :Frame ,
|
||||||
:return_address => :Integer, :return_value => :Integer,
|
:return_address => :Integer, :return_value => :Integer,
|
||||||
:caller => :Message , :name => :Word , :indexed_length => :Integer },
|
:caller => :Message , :name => :Word , :indexed_length => :Integer },
|
||||||
:MetaClass => {:me => :Class},
|
:MetaClass => {:object => :Object},
|
||||||
:Integer => {},
|
:Integer => {},
|
||||||
:Object => {},
|
:Object => {},
|
||||||
:Kernel => {}, #fix, kernel is a class, but should be a module
|
:Kernel => {}, #fix, kernel is a class, but should be a module
|
||||||
:BinaryCode => {},
|
:BinaryCode => {:name => :Word},
|
||||||
:Space => {:classes => :Dictionary , :first_message => :Message},
|
:Space => {:classes => :Dictionary , :first_message => :Message},
|
||||||
:Frame => {:next_frame => :Frame, :indexed_length => :Integer},
|
:Frame => {:next_frame => :Frame, :indexed_length => :Integer},
|
||||||
:Layout => {:object_class => :Class, :instance_methods => :List , :indexed_length => :Integer} ,
|
:Layout => {:object_class => :Class, :instance_methods => :List , :indexed_length => :Integer} ,
|
||||||
|
@ -20,17 +20,9 @@ class TestMeta < MiniTest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_new_methods
|
def test_new_methods
|
||||||
assert_equal @try.method_names.class, @try.instance_methods.class
|
|
||||||
assert_equal @try.method_names.get_length , @try.instance_methods.get_length
|
|
||||||
assert_equal 0 , @try.method_names.get_length
|
assert_equal 0 , @try.method_names.get_length
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_init_methods
|
|
||||||
assert_equal 3 , @try.get_layout.variable_index(:instance_methods)
|
|
||||||
@try.instance_methods = Parfait::List.new
|
|
||||||
assert_equal @try.instance_methods , @try.internal_object_get(3)
|
|
||||||
assert @try.instance_methods
|
|
||||||
end
|
|
||||||
def test_create_method
|
def test_create_method
|
||||||
@try.create_instance_method :bar, Register.new_list( [ Parfait::Variable.new(:Integer , :bar )])
|
@try.create_instance_method :bar, Register.new_list( [ Parfait::Variable.new(:Integer , :bar )])
|
||||||
assert_equal ":bar" , @try.method_names.inspect
|
assert_equal ":bar" , @try.method_names.inspect
|
||||||
@ -38,7 +30,7 @@ class TestMeta < MiniTest::Test
|
|||||||
def test_add_method
|
def test_add_method
|
||||||
foo = foo_method
|
foo = foo_method
|
||||||
assert_equal foo , @try.add_instance_method(foo)
|
assert_equal foo , @try.add_instance_method(foo)
|
||||||
assert_equal 1 , @try.instance_methods.get_length
|
assert_equal 1 , @try.method_names.get_length
|
||||||
assert_equal ":foo" , @try.method_names.inspect
|
assert_equal ":foo" , @try.method_names.inspect
|
||||||
end
|
end
|
||||||
def test_remove_method
|
def test_remove_method
|
||||||
|
Loading…
Reference in New Issue
Block a user