Module: Proxeze

Defined in:
lib/proxeze.rb,
lib/proxeze/class_methods.rb,
lib/proxeze/instance_methods.rb

Defined Under Namespace

Modules: ClassHooks, Copying, Hooks

Class Method Summary collapse

Class Method Details

.class_defined?(name) ⇒ Boolean

Returns:

  • (Boolean)


7
8
9
# File 'lib/proxeze.rb', line 7

def self.class_defined? name
  const_defined? name, false
end

.class_methods_from(target_class) ⇒ Object



15
16
17
# File 'lib/proxeze.rb', line 15

def self.class_methods_from target_class
  target_class.methods
end

.default_proxy_optionsObject



84
85
86
# File 'lib/proxeze.rb', line 84

def self.default_proxy_options
  {:redefine_new_method => true, :exclude_class_methods => [], :include_class_methods => []}
end

.for(object, &callback_blk) ⇒ Object

create a proxy object for the given object



89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/proxeze.rb', line 89

def self.for object, &callback_blk
  proxy = self.proxy( object.class, :redefine_new_method => false ).new( object )
  proxy.class.hooks.clear
  cls = (class << proxy; self; end)
  cls.send :include, Copying unless cls.ancestors.include?(Copying)
  cls.send :include, Hooks unless cls.ancestors.include?(Hooks)
  cls.send :extend, ClassHooks unless cls.ancestors.include?(ClassHooks)
  unless callback_blk.nil?
    proxy.instance_eval &callback_blk
  end
  proxy
end

.object_methodsObject



11
12
13
# File 'lib/proxeze.rb', line 11

def self.object_methods
  Object.methods
end

.proxy(target_class, opts = {}, &callback_blk) ⇒ Object

Create a proxy class for the given target class. If the :redefine_new_method option is false, the target class’ #new method will not be reimplemented.

When the target class’ #new method is reimplemented, all subsequent calls to #new on that class will return an instance of a proxied class (in the Proxeze namespace), thereby allowing seemless integration with existing classes and object creation.

Typically, only the Proxeze>>#for method should pass in :redefine_new_method => false here.



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/proxeze.rb', line 44

def self.proxy target_class, opts = {}, &callback_blk
  options = default_proxy_options.merge opts
  cls_name = class_name_for(target_class)
  unless self.class_defined? cls_name
    cls = DelegateClass target_class
    cls.send :include, Copying
    cls.send :include, Hooks
    cls.send :extend, ClassHooks
    self.const_set cls_name, cls
    
    excluded_class_methods = object_methods + [:new, :public_api, :delegating_block] + options[:exclude_class_methods]
    (class_methods_from(target_class) - excluded_class_methods + options[:include_class_methods]).each do |method|
      blk = Delegator.delegating_block_for_method_and_target(method, target_class)
      (class << cls; self; end).instance_eval do
        define_method(method, &blk)
      end
    end
  end

  # we have to collect the methods as Strings here because
  # 1.9 changed the implementation to return Symbols instead of Strings
  if options[:redefine_new_method] && !target_class.methods.collect{|e| e.to_s}.include?('new_with_extra_behavior')
    meta = class << target_class; self; end
    meta.class_eval %Q{
      def new_with_extra_behavior *args, &blk
        #{cls_name}.new( self.new_without_extra_behavior(*args, &blk) )
      end
      alias_method :new_without_extra_behavior, :new
      alias_method :new, :new_with_extra_behavior
    }, __FILE__, __LINE__
  end
  
  cls = self.const_get cls_name
  unless callback_blk.nil?
    # (class << cls; self; end).instance_eval &callback_blk
    cls.instance_eval &callback_blk
  end
  cls
end