Передача всего, но возможность предварительного расширения наших прокси-классов - PullRequest
0 голосов
/ 30 мая 2018

Учитывая набор определений классов:

class Application
    def self.open_current
        return Current.new()
    end
end
class Current
    def get_row(row)
        Row.new(row)
    end
end
class Row
    def get_col(row)
        #...
    end
end

Разработка прокси-класса, который будет:

  • Создание Proxy<<Class>> версий каждого класса, которые можно расширять с помощью

    class ProxyApplication
        def myMethod()
            #...
        end
    end
    #...
    
  • Обернуть все возвращаемые значения всех методов в каждом классе так, чтобы прокси-класс всегда использовался вместо стандартного класса.IE

    app = Proxy.new(Application) #app == ProxyApplication
    current = app.open_current   #current == #<ProxyCurrent>
    

В конечном счете, определение Proxy должно быть динамическим, а не статическим определением.

Я работаю над этой проблемой уже около 6 часов.У меня следующий код .Это включает 3 раздела:

  • Начальная настройка класса
  • Определение класса прокси
  • Тестирование класса прокси

В настоящее время я долженточка, в которой pApplication=Proxy.new(Application) возвращает #<Proxy>, а pApplication.open_current возвращает #<ProxyCurrent>, что, кажется, находится на правильной строке.Однако в настоящее время происходит ошибка, когда Delegate.rb пытается вызвать test() с 2,3 аргументами вместо 0 ...

Но мой вопрос, реально ли я об этом правильно?Использование SimpleDelegator самый простой способ сделать это?Одна из текущих проблем заключается в том, что мне нужно добавить новую функциональность в существующий SimpleDelegator.Я также рассмотрел использование Forwardable, но, если возможно, я не хочу использовать этот проект для делегирования методов вручную.

Есть идеи?

1 Ответ

0 голосов
/ 30 мая 2018

Из-за многочисленных ограничений, связанных с первоначальной идеей упаковки всех вызовов в один класс, я немного переработал его, но он работает точно так же.

def proxy__enwrap(obj)
    isClass = obj.is_a?(Class)
    oldClass = isClass ? obj : obj.class
    sNewClass = "Proxy#{oldClass.to_s}"
    code = <<-EOF
        class #{sNewClass}
            include InstanceProxy
            def self.__cinit__(obj)
                @@__cobj__ = obj
            end
            def self.__cget__
                @@__cobj__
            end
            def self.method_missing(m,*args,&block)
                if @@__cobj__.respond_to? m
                    retVal = @@__cobj__.public_send(m,*args,*block)
                    return proxy__enwrap(retVal)
                else
                    puts "ERROR " + m.to_s + "(" + args.to_s + ") + block?"
                    #Throw error
                end
            end
        end
        #{sNewClass}.__cinit__(#{oldClass.to_s})
        if isClass
            return #{sNewClass}
        else
            return #{sNewClass}.new(obj)
        end
    EOF

    ::Kernel.eval(code)
end

module InstanceProxy
    def method_missing(m,*args,&block)
        retVal = @__obj__.__send__(m,*args,&block)
        return proxy__enwrap(retVal)
    end
    def initialize(obj)
        @__obj__ = obj
    end
end

XXApplication = Application
::Object.const_set "Application", proxy__enwrap(Application)

В настоящее время единственной проблемой являетсячто объект неправильно оборачивается вокруг получаемых объектов ... Хотя я не уверен, что это вообще возможно.

Редактировать:

Я улучшилсистема также для переноса объектов, переданных в виде блоков:

def proxy__enwrap(obj)
    isClass = obj.is_a?(Class)
    oldClass = isClass ? obj : obj.class
    sNewClass = "Proxy#{oldClass.to_s}"
    code = <<-EOF
        class #{sNewClass}
            include InstanceProxy
            def self.__cinit__(obj)
                @@__cobj__ = obj
            end
            def self.__cget__
                @@__cobj__
            end
            def self.to_ary
                #fix for puts (puts calls to_ary. see: /6704898/ruby-pochemu-stavit-vyzov-toary)
                [self.to_s]
            end
            def self.method_missing(m,*args,&block)
                #Wrap block arguments:
                newBlock = Proc.new {}
                if block_given?
                    newBlock = Proc.new do |*args|
                        args = args.map {|arg| proxy__enwrap(arg)}
                        block.call(*args)
                    end
                end

                #Call delegated functions. Raise error if object doesn't respond to method.
                #Return wrapped value
                if @@__cobj__.respond_to? m
                    retVal = @@__cobj__.public_send(m,*args,*block)
                    return proxy__enwrap(retVal)
                else
                    raise ArgumentError.new("Method '\#\{m.to_s}' doesn't exist.")
                end
            end
        end
        #{sNewClass}.__cinit__(#{oldClass.to_s})
        if isClass
            return #{sNewClass}
        else
            return #{sNewClass}.new(obj)
        end
    EOF

    ::Kernel.eval(code)
end

module InstanceProxy
    def method_missing(m,*args,&block)
        #Wrap block arguments:
        newBlock = Proc.new {}
        if block_given?
            newBlock = Proc.new do |*args|
                args = args.map {|arg| proxy__enwrap(arg)}
                block.call(*args)
            end
        end

        #Call delegated functions. Raise error if object doesn't respond to method.
        #Return wrapped value
        if @__obj__.respond_to? m
            retVal = @__obj__.__send__(m,*args,&newBlock)
            return proxy__enwrap(retVal)
        else
            raise ArgumentError.new("Method '#{m.to_s}' doesn't exist.")
        end
    end
    def initialize(obj)
        @__obj__ = obj
    end
    def to_ary
        #fix for puts (puts calls to_ary. see: /6704898/ruby-pochemu-stavit-vyzov-toary)
        [self.to_s]
    end
end

#
XXApplication = Application

#Silence warnings of overwriting constant
original_verbosity = $VERBOSE
$VERBOSE = nil
    ::Object.const_set "Application", proxy__enwrap(Application)
$VERBOSE = original_verbosity
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...