From 204200b92adb78a43725be15ca8a5800e35235fb Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Sat, 7 Nov 2015 00:11:56 +0200 Subject: [PATCH] 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 --- lib/parfait.rb | 1 + lib/parfait/layout.rb | 8 +---- lib/parfait/meta_class.rb | 68 +++++++++++++++++++++++++++++++++++++++ lib/register/boot.rb | 5 ++- test/parfait/test_meta.rb | 10 +----- 5 files changed, 73 insertions(+), 19 deletions(-) create mode 100644 lib/parfait/meta_class.rb diff --git a/lib/parfait.rb b/lib/parfait.rb index f9874260..13dcb572 100644 --- a/lib/parfait.rb +++ b/lib/parfait.rb @@ -7,6 +7,7 @@ require "parfait/list" require "parfait/word" require "parfait/binary_code" require "parfait/method" +require "parfait/meta_class" require "parfait/variable" require "parfait/dictionary" require "parfait/layout" diff --git a/lib/parfait/layout.rb b/lib/parfait/layout.rb index d5445b04..0b9c269d 100644 --- a/lib/parfait/layout.rb +++ b/lib/parfait/layout.rb @@ -80,7 +80,7 @@ module Parfait has = super_index(name) return nil unless has 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 def inspect @@ -96,11 +96,5 @@ module Parfait nil # stop resolve recursing up metaclasses 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 diff --git a/lib/parfait/meta_class.rb b/lib/parfait/meta_class.rb new file mode 100644 index 00000000..e5a65063 --- /dev/null +++ b/lib/parfait/meta_class.rb @@ -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 diff --git a/lib/register/boot.rb b/lib/register/boot.rb index a1477ad6..a86587d5 100644 --- a/lib/register/boot.rb +++ b/lib/register/boot.rb @@ -114,15 +114,14 @@ module Register def layout_names { :Word => {:char_length => :Integer} , :List => {:indexed_length => :Integer} , - # Assumtion is that name is the last of message :Message => { :next_message => :Message, :receiver => :Object, :frame => :Frame , :return_address => :Integer, :return_value => :Integer, :caller => :Message , :name => :Word , :indexed_length => :Integer }, - :MetaClass => {:me => :Class}, + :MetaClass => {:object => :Object}, :Integer => {}, :Object => {}, :Kernel => {}, #fix, kernel is a class, but should be a module - :BinaryCode => {}, + :BinaryCode => {:name => :Word}, :Space => {:classes => :Dictionary , :first_message => :Message}, :Frame => {:next_frame => :Frame, :indexed_length => :Integer}, :Layout => {:object_class => :Class, :instance_methods => :List , :indexed_length => :Integer} , diff --git a/test/parfait/test_meta.rb b/test/parfait/test_meta.rb index 54a7da41..98c66579 100644 --- a/test/parfait/test_meta.rb +++ b/test/parfait/test_meta.rb @@ -20,17 +20,9 @@ class TestMeta < MiniTest::Test end 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 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 @try.create_instance_method :bar, Register.new_list( [ Parfait::Variable.new(:Integer , :bar )]) assert_equal ":bar" , @try.method_names.inspect @@ -38,7 +30,7 @@ class TestMeta < MiniTest::Test def test_add_method foo = foo_method 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 end def test_remove_method