Class: RubyPython::RubyPyProxy

Inherits:
BlankObject
  • Object
show all
Includes:
Operators
Defined in:
lib/rubypython/rubypyproxy.rb

Overview

This is the object that the end user will most often be interacting with. It holds a reference to an object in the Python VM an delegates method calls to it, wrapping and returning the results. The user should not worry about reference counting of this object an instance will decrement its objects reference count when it is garbage collected.

Note: All RubyPyProxy objects become invalid when the Python interpreter is halted.

Calling Methods With Blocks


Any method which is forwarded to a Python object may be called with a block. The result of the method will passed as the argument to that block.

Passing Procs and Methods to methods


RubyPython now supports passing Proc and Method objects to Python methods. The Proc or Method object must be passed explicitly. As seen above, supplying a block to a method will result in the return value of the method call being passed to the block.

When a Proc or Method is supplied as a callback, then arguments that it will be called with will be wrapped Python objects.

Examples:

Supplying a block to a method call

irb(main):001:0> RubyPython.start
=> true
irb(main):002:0> RubyPython::PyMain.float(10) do |f|
irb(main):003:1*     2*f.rubify
irb(main):004:1> end
=> 20.0
irb(main):005:0> RubyPython.stop
=> true

Passing a Proc to Python

#Python Code
def apply_callback(callback, argument):
  return callback(argument)

#IRB Session
irb(main):001:0> RubyPython.start
=> true
irb(main):002:0> sys = RubyPython.import 'sys'
=> <module 'sys' (built-in)>
irb(main):003:0> sys.path.append('.')
=> None
irb(main):004:0> sample = RubyPython.import 'sample'
=> <module 'sample' from './sample.pyc'>
irb(main):005:0> callback = Proc.new do |arg|
irb(main):006:1*   arg * 2
irb(main):007:1> end
=> #<Proc:0x000001018df490@(irb):5>
irb(main):008:0> sample.apply_callback(callback, 21).rubify
=> 42
irb(main):009:0> RubyPython.stop

Direct Known Subclasses

RubyPyClass, RubyPyInstance, RubyPyModule

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Operators

#<=>, #[], #[]=, bin_op, #include?, operator_, rel_op, unary_op, update

Methods inherited from BlankObject

hide

Constructor Details

#initialize(pObject) ⇒ RubyPyProxy

Returns a new instance of RubyPyProxy.



71
72
73
74
75
76
77
# File 'lib/rubypython/rubypyproxy.rb', line 71

def initialize(pObject)
  if pObject.kind_of? PyObject
    @pObject = pObject
  else
    @pObject = PyObject.new pObject
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object

Implements the method call delegation.



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/rubypython/rubypyproxy.rb', line 114

def method_missing(name, *args, &block)
  name = name.to_s

  if(name.end_with? "?")
    begin
      RubyPyProxy.reveal(name.to_sym)
      return self.__send__(name.to_sym, *args, &block)
    rescue RuntimeError => exc
      raise NoMethodError.new(name) if exc.message =~ /Don't know how to reveal/
      raise
    end
  end


  if(name.end_with? "=")
    setter = true
    name.chomp! "="
  else
    setter=false
  end

  if(!@pObject.hasAttr(name) and !setter)
    raise NoMethodError.new(name)
  end


  args = PyObject.convert(*args)

  if setter
    return @pObject.setAttr(name, args[0]) 
  end

  pFunc = @pObject.getAttr(name)

  if pFunc.callable?
    if args.empty? and pFunc.class?
      pReturn = pFunc
    else
      pTuple = PyObject.buildArgTuple(*args)
      pReturn = pFunc.callObject(pTuple)
      if(PythonError.error?)
        raise PythonError.handle_error
      end
    end
  else
    pReturn = pFunc
  end

  return _wrap(pReturn)
end

Instance Attribute Details

#pObjectObject (readonly)

Returns the value of attribute pObject.



69
70
71
# File 'lib/rubypython/rubypyproxy.rb', line 69

def pObject
  @pObject
end

Instance Method Details

#_wrap(pyobject) ⇒ Object

Handles the job of wrapping up anything returned by a RubyPython::RubyPyProxy instance. The behavior differs depending on the value of RubyPython.legacy_mode. If legacy mode is inactive, every returned object is wrapped by an instance of RubyPython::RubyPyProxy. If legacy mode is active, RubyPython first attempts to convert the returned object to a native Ruby type, and then only wraps the object if this fails.



85
86
87
88
89
90
91
92
93
94
95
# File 'lib/rubypython/rubypyproxy.rb', line 85

def _wrap(pyobject)
  if pyobject.class?
    RubyPyClass.new(pyobject)
  elsif RubyPython.legacy_mode
    pyobject.rubify
  else
    RubyPyProxy.new(pyobject)
  end
rescue Conversion::UnsupportedConversion => exc
  RubyPyProxy.new pyobject
end

#inspectString

Returns the string representation of the wrapped object via a call to the object’s _repr_ method.

Returns:



175
176
177
178
179
# File 'lib/rubypython/rubypyproxy.rb', line 175

def inspect
  self.__repr__.rubify
rescue PythonError, NoMethodError
  RubyPython::PyMain.repr(self).rubify
end

#is_real_method?Object

Moves the old respond_to? method to is_real_method?



100
# File 'lib/rubypython/rubypyproxy.rb', line 100

alias :is_real_method? :respond_to?

#respond_to?(mname) ⇒ Boolean

RubyPython checks the attribute dictionary of the wrapped object to check whether it will respond to a method call. This should not return false positives but it may return false negatives. The builitin Ruby respond_to? method has been aliased to is_real_method?.

Returns:

  • (Boolean)


106
107
108
109
110
111
# File 'lib/rubypython/rubypyproxy.rb', line 106

def respond_to?(mname)
  return true if is_real_method?(mname)
  mname = mname.to_s
  return true if mname.end_with? '='
  @pObject.hasAttr(mname)
end

#rubifyObject

RubyPython will attempt to translate the wrapped object into a native Ruby object. This will only succeed for simple builtin type.



167
168
169
# File 'lib/rubypython/rubypyproxy.rb', line 167

def rubify
  @pObject.rubify
end

#to_aArray<RubyPyProxy>

Converts the wrapped Python object to a Ruby Array. Note that this only converts one level, so a nested array will remain a proxy object. Only wrapped objects which have an _iter_ method may be converted using to_a.

Note that for Dict objects, this method returns what you would get in Python, not in Ruby i.e. a_dict.to_a returns an array of the dictionary’s keys.

Examples:

List

irb(main):001:0> RubyPython.start
=> true
irb(main):002:0> a_list = RubyPython::RubyPyProxy.new [1, 'a', 2, 'b']
=> [1, 'a', 2, 'b']
irb(main):003:0> a_list.kind_of? RubyPython::RubyPyProxy
=> true
irb(main):004:0> a_list.to_a
=> [1, 'a', 2, 'b']
irb(main):005:0> RubyPython.stop
=> true

Dict

irb(main):001:0> RubyPython.start
=> true
irb(main):002:0> a_dict = RubyPython::RubyPyProxy.new({1 => '2', :three => [4,5]})
=> {1: '2', 'three': [4, 5]}
irb(main):003:0> a_dict.kind_of? RubyPython::RubyPyProxy
=> true
irb(main):004:0> a_dict.to_a
=> [1, 'three']
irb(main):005:0> RubyPython.stop
=> true

Returns:



223
224
225
226
227
228
229
230
231
232
# File 'lib/rubypython/rubypyproxy.rb', line 223

def to_a
  iter = self.__iter__
  ary = []
  loop do
    ary << iter.next()
  end
rescue PythonError => exc
  raise if exc.message !~ /StopIteration/
  ary
end

#to_sString

Returns the string representation of the wrapped object via a call to the object’s _str_ method.

Returns:



185
186
187
188
189
# File 'lib/rubypython/rubypyproxy.rb', line 185

def to_s
  self.__str__.rubify
rescue PythonError, NoMethodError
  RubyPython::PyMain.str(self).rubify
end