Skip to content

Instantly share code, notes, and snippets.

@sancarn
Last active May 30, 2018 17:47
Show Gist options
  • Select an option

  • Save sancarn/d84a76e36a94c8dbcb5244caede45bd0 to your computer and use it in GitHub Desktop.

Select an option

Save sancarn/d84a76e36a94c8dbcb5244caede45bd0 to your computer and use it in GitHub Desktop.
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)
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
=begin
DEFINITION:
I want a simple wrapper which will wrap the Application class and down.
Criterium:
* Each class must be extendable directly via the proxy class:
class ProxyApplication
def method()
#...
end
end
class ProxyCurrent
def method()
#...
end
end
#...
* All methods of delegated class should be accessible from Proxy<<Class>>
* No proxy class can be predefined, new instances are created on-the-fly.
* All methods of proxy class should return proxied objects,i.e.
ProxyApplication.open_current #=> ProxyCurrent instance
#<ProxyCurrent>.get_row(1) #=> ProxyRow instance
#...
* Must not call the initialisation methods of the classes themselves.
* Ideally would work even if within console
=end
#class Proxy
# def initialize(obj)
#
# end
#end
class Proxy < SimpleDelegator
def initialize(obj)
# #Work around for
@delegate_class = (obj.is_a? Class) ? obj : obj.class
super(obj)
end
def to_s
#Define to_s to show that class is proxied
#return "PROXY:" + @delegate_class.to_s
end
def method_missing(m,*args,&block)
begin
#Try to get return value from class method
retVal = @delegate_class.__send__(m,*args,&block)
rescue
#Get return value from instance method if available
retVal = super.__send__(m,*args,&block)
end
#Enwrap return value
return Proxy.enwrap(retVal)
end
def Proxy.enwrap(retVal)
#Extension class name
newClassName = "Proxy" + retVal.class.to_s
if !(::Object.constants.include?(newClassName.to_sym))
#Define a class dynamically
classDef = ::Object.const_set newClassName, Class.new(Proxy)
else
classDef = ::Object.const_get(newClassName.to_sym)
end
#Return new instance of retVal
return classDef.new(retVal)
end
end
=begin ::OLD CODE::
Proxy.enwrap:
classDef = <<-EOF
class #{newClassName} < Proxy
end
return #{newClassName}.new(retVal)
EOF
return eval(classDef)
Initialize:
@delegate_class.singleton_methods.each do |name|
self.class.send(:define_method,name) do |*args|
retVal = @delegate_class.__send__(name, *args)
return Proxy.enwrap(retVal)
end
end
=end
#----------------------------------------------------------------------
# TEST SCRIPT
#----------------------------------------------------------------------
PApplication = Proxy.new(Application)
puts PApplication
current = PApplication.open_current()
puts current
#Try to extend ProxyApplication and ProxyCurrent.
class ProxyApplication
def self.test()
return true
end
end
class ProxyCurrent
def test()
return true
end
end
puts PApplication.test()
puts current.test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment