Class: WineOLE::Proxy

Inherits:
Object
  • Object
show all
Defined in:
lib/wineole/proxy.rb

Constant Summary collapse

IMPLICIT_CONVERSIONS =

Ruby's implicit-conversion protocol. The interpreter probes these on arbitrary objects behind the scenes — puts/p and Array() look for to_ary/to_a, multiple assignment looks for to_ary, string interpolation and Kernel#String look for to_str, IO methods look for to_io, &obj looks for to_proc, Integer()/format('%d', _)/ "ab" * _/array indexing look for to_int/to_i, Float() looks for to_f, File.open looks for to_path, and 1 + _ looks for coerce. Forwarding these to the remote object turns every puts proxy into a round trip that ends in DISP_E_UNKNOWNNAME, so they must behave exactly as they would on a plain Ruby object that doesn't define them: NoMethodError, and respond_to? == false (which is what stops the interpreter calling them at all).

%i[
  to_ary to_a to_hash to_str to_io to_proc
  to_int to_i to_f to_path coerce
].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(client, session_id:, handle:, created:) ⇒ Proxy

Returns a new instance of Proxy.



44
45
46
47
48
49
# File 'lib/wineole/proxy.rb', line 44

def initialize(client, session_id:, handle:, created:)
  @client = client
  @ole_session_id = session_id
  @ole_handle = handle
  @created = created
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object



51
52
53
54
55
56
57
# File 'lib/wineole/proxy.rb', line 51

def method_missing(name, *args)
  return super if IMPLICIT_CONVERSIONS.include?(name)

  check_live!
  named = args.last.is_a?(Hash) ? args.pop : {}
  invoke(name.to_s, args, named)
end

Instance Attribute Details

#ole_handleObject (readonly)

Returns the value of attribute ole_handle.



42
43
44
# File 'lib/wineole/proxy.rb', line 42

def ole_handle
  @ole_handle
end

#ole_session_idObject (readonly)

Returns the value of attribute ole_session_id.



42
43
44
# File 'lib/wineole/proxy.rb', line 42

def ole_session_id
  @ole_session_id
end

Class Method Details

.connect(class_name, client) ⇒ Object



11
12
13
14
# File 'lib/wineole/proxy.rb', line 11

def self.connect(class_name, client)
  handle = client.call('connect', {class_name: class_name})['$ole_ref']
  new(client, session_id: client.object_id, handle: handle, created: false)
end

.connect_or_create(class_name, client) ⇒ Object



16
17
18
19
# File 'lib/wineole/proxy.rb', line 16

def self.connect_or_create(class_name, client)
  result = client.call('connect_or_create', {class_name: class_name})
  new(client, session_id: client.object_id, handle: result['$ole_ref'], created: result['created'])
end

.create(class_name, client) ⇒ Object



6
7
8
9
# File 'lib/wineole/proxy.rb', line 6

def self.create(class_name, client)
  handle = client.call('create', {class_name: class_name})['$ole_ref']
  new(client, session_id: client.object_id, handle: handle, created: true)
end

.wrap(client, session_id, ole_ref) ⇒ Object



21
22
23
# File 'lib/wineole/proxy.rb', line 21

def self.wrap(client, session_id, ole_ref)
  new(client, session_id: session_id, handle: ole_ref, created: nil)
end

Instance Method Details

#[](*args) ⇒ Object



63
64
65
66
# File 'lib/wineole/proxy.rb', line 63

def [](*args)
  check_live!
  invoke('', args, {})
end

#invoke(name, args, named) ⇒ Object

Deliberately bare and public, unlike every other meta-method here (which are ole_-prefixed to avoid shadowing a same-named remote COM member): an explicit escape hatch for the rare case a COM object really does define e.g. an ole_handle member, matching real Ruby WIN32OLE's own choice to keep invoke public and unprefixed.



96
97
98
99
100
101
102
103
104
105
# File 'lib/wineole/proxy.rb', line 96

def invoke(name, args, named)
  check_live!
  params = {
    handle: @ole_handle,
    name: name,
    args: args.map { |a| encode(a) },
    named: named.transform_values { |v| encode(v) },
  }
  decode(@client.call('invoke', params))
end

#marshal_dumpObject



87
88
89
# File 'lib/wineole/proxy.rb', line 87

def marshal_dump
  raise NotSerializableError, 'WineOLE::Proxy references are connection-scoped and cannot be persisted'
end

#ole_const_loadObject



82
83
84
85
# File 'lib/wineole/proxy.rb', line 82

def ole_const_load
  check_live!
  @client.call('const_load', {handle: @ole_handle})
end

#ole_created?Boolean

Was this instance freshly created by connect_or_create's fallback, or attached to something already running? true for .create, false for .connect, whatever the bridge reported for .connect_or_create, and nil for anything derived from another Proxy (e.g. xl.Worksheets) — attach-vs-create isn't a meaningful question for those.

Returns:

  • (Boolean)


74
75
76
# File 'lib/wineole/proxy.rb', line 74

def ole_created?
  @created
end

#ole_releaseObject



78
79
80
# File 'lib/wineole/proxy.rb', line 78

def ole_release
  @client.call('release', {handle: @ole_handle})
end

#respond_to_missing?(name, _include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


59
60
61
# File 'lib/wineole/proxy.rb', line 59

def respond_to_missing?(name, _include_private = false)
  !IMPLICIT_CONVERSIONS.include?(name)
end