Class: RubyPython::RubyPyProxy
- Inherits:
-
BlankObject
- Object
- BlankSlate
- BlankObject
- RubyPython::RubyPyProxy
- Includes:
- Operators
- Defined in:
- lib/rubypython/rubypyproxy.rb
Overview
In most cases, users will interact with RubyPyProxy objects that hold references to active objects in the Python interpreter. RubyPyProxy delegates method calls to Python objects, wrapping and returning the results as RubyPyProxy objects.
The allocation, deallocation, and reference counting on RubyPyProxy objects is automatic: RubyPython takes care of it all. When the object is garbage collected, the instance will automatically decrement its object reference count.
- 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.
RubyPython.run do
sys = RubyPython.import 'sys'
sys.version { |v| v.rubify.split(' ') }
end
# => [ "2.6.1", … ]
Passing Procs and Methods to Python Methods
RubyPython 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. It will therefore typically be necessary to write a wrapper around any Ruby callback that requires native Ruby objects.
# Python Code: sample.py
def apply_callback(callback, argument):
return callback(argument)
# IRB Session
>> RubyPython.start
=> true
>> sys = RubyPython.import 'sys'
=> <module 'sys' (built-in)>
>> sys.path.append('.')
=> None
>> sample = RubyPython.import 'sample'
=> <module 'sample' from './sample.pyc'>
>> callback = Proc.new { |arg| arg * 2 }
=> # <Proc:0x000001018df490@(irb):5>
>> sample.apply_callback(callback, 21).rubify
=> 42
>> RubyPython.stop
=> true
Direct Known Subclasses
Instance Attribute Summary collapse
-
#pObject ⇒ Object
readonly
Returns the value of attribute pObject.
Instance Method Summary collapse
-
#initialize(pObject) ⇒ RubyPyProxy
constructor
Creates a Python proxy for the provided Ruby object.
-
#inspect ⇒ Object
Returns the String representation of the wrapped object via a call to the object’s
__repr__
method, or therepr
method in PyMain. -
#is_real_method? ⇒ Object
The standard Ruby
#respond_to?
method has been renamed to allow RubyPython to query if the proxied Python object supports the method desired. -
#method_missing(name, *args, &block) ⇒ Object
Delegates method calls to proxied Python objects.
-
#methods ⇒ Object
Returns the methods on the Python object by calling the
dir
built-in. -
#respond_to?(mname) ⇒ Boolean
RubyPython checks the attribute dictionary of the wrapped object to check whether it will respond to a method call.
-
#rubify ⇒ Object
RubyPython will attempt to translate the wrapped object into a native Ruby object.
-
#to_a ⇒ Object
Converts the wrapped Python object to a Ruby Array.
-
#to_enum ⇒ Object
Creates a PyEnumerable for this object.
-
#to_s ⇒ Object
Returns the string representation of the wrapped object via a call to the object’s
__str__
method or thestr
method in PyMain.
Methods included from Operators
#<=>, #[], #[]=, bin_op, #include?, operator_, rel_op, unary_op, update
Methods inherited from BlankObject
Constructor Details
#initialize(pObject) ⇒ RubyPyProxy
Creates a Python proxy for the provided Ruby object.
Only the following Ruby types can be represented in Python:
-
String
-
Array
-
Hash
-
Fixnum
-
Bignum
-
Float
-
Symbol (as a String)
-
Proc
-
Method
-
true
(as True) -
false
(as False) -
nil
(as None)
82 83 84 85 86 87 88 |
# File 'lib/rubypython/rubypyproxy.rb', line 82 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
Delegates method calls to proxied Python objects.
Delegation Rules
-
If the method ends with a question-mark (e.g.,
nil?
), it can only be a Ruby method on RubyPyProxy. Attempt to reveal it (RubyPyProxy is a BlankObject) and call it. -
If the method ends with equals signs (e.g.,
value=
) it’s a setter and we can always set an attribute on a Python object. -
If the method ends with an exclamation point (e.g.,
foo!
) we are attempting to call a method with keyword arguments. -
The Python method or value will be called, if it’s callable.
-
RubyPython will wrap the return value in a RubyPyProxy object (unless legacy_mode has been turned on).
-
If a block has been provided, the wrapped return value will be passed into the block.
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/rubypython/rubypyproxy.rb', line 142 def method_missing(name, *args, &block) name = name.to_s if name =~ /\?$/ begin RubyPyProxy.reveal(name.to_sym) return self.__send__(name.to_sym, *args, &block) rescue RuntimeError => exc raise NoMethodError.new(name) if exc. =~ /Don't know how to reveal/ raise end end kwargs = false if name =~ /=$/ return @pObject.setAttr(name.chomp('='), PyObject.convert(*args).first) elsif name =~ /!$/ kwargs = true name.chomp! "!" end raise NoMethodError.new(name) if !@pObject.hasAttr(name) pFunc = @pObject.getAttr(name) if pFunc.callable? if args.empty? and pFunc.class? pReturn = pFunc else if kwargs and args.last.is_a?(Hash) pKeywords = PyObject.convert(args.pop).first end orig_args = args args = PyObject.convert(*args) pTuple = PyObject.buildArgTuple(*args) pReturn = if pKeywords pFunc.callObjectKeywords(pTuple, pKeywords) else pFunc.callObject(pTuple) end # Clean up unused Python vars instead of waiting on Ruby's GC to # do it. pFunc.xDecref pTuple.xDecref pKeywords.xDecref if pKeywords orig_args.each_with_index do |arg, i| # Only decref objects that were created in PyObject.convert. if !arg.kind_of?(RubyPython::PyObject) and !arg.kind_of?(RubyPython::RubyPyProxy) args[i].xDecref end end raise PythonError.handle_error if PythonError.error? end else pReturn = pFunc end result = _wrap(pReturn) if block block.call(result) else result end end |
Instance Attribute Details
#pObject ⇒ Object (readonly)
Returns the value of attribute pObject.
65 66 67 |
# File 'lib/rubypython/rubypyproxy.rb', line 65 def pObject @pObject end |
Instance Method Details
#inspect ⇒ Object
Returns the String representation of the wrapped object via a call to the object’s __repr__
method, or the repr
method in PyMain.
221 222 223 224 225 |
# File 'lib/rubypython/rubypyproxy.rb', line 221 def inspect self.__repr__.rubify rescue PythonError, NoMethodError RubyPython::PyMain.repr(self).rubify end |
#is_real_method? ⇒ Object
The standard Ruby #respond_to?
method has been renamed to allow RubyPython to query if the proxied Python object supports the method desired. Setter methods (e.g., foo=
) are always supported.
114 |
# File 'lib/rubypython/rubypyproxy.rb', line 114 alias :is_real_method? :respond_to? |
#methods ⇒ Object
Returns the methods on the Python object by calling the dir
built-in.
288 289 290 |
# File 'lib/rubypython/rubypyproxy.rb', line 288 def methods pObject.dir.map { |x| x.to_sym } end |
#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 built-in Ruby respond_to? method has been aliased to is_real_method?.
120 121 122 123 124 125 |
# File 'lib/rubypython/rubypyproxy.rb', line 120 def respond_to?(mname) return true if is_real_method?(mname) mname = mname.to_s return true if mname =~ /=$/ @pObject.hasAttr(mname) end |
#rubify ⇒ Object
RubyPython will attempt to translate the wrapped object into a native Ruby object. This will only succeed for simple built-in type.
215 216 217 |
# File 'lib/rubypython/rubypyproxy.rb', line 215 def rubify @pObject.rubify end |
#to_a ⇒ Object
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 Python Dict objects, this method returns what you would get in Python, not in Ruby: a_dict.to_a
returns an array of the dictionary’s keys.
List #to_a Returns an Array
>> RubyPython.start
=> true
>> list = RubyPython::RubyPyProxy.new([1, 'a', 2, 'b'])
=> [1, 'a', 2, 'b']
>> list.kind_of? RubyPython::RubyPyProxy
=> true
>> list.to_a
=> [1, 'a', 2, 'b']
>> RubyPython.stop
=> true
Dict #to_a Returns An Array of Keys
>> RubyPython.start
=> true
>> dict = RubyPython::RubyPyProxy.new({1 => '2', :three => [4,5]})
=> {1: '2', 'three': [4, 5]}
>> dict.kind_of? RubyPython::RubyPyProxy
=> true
>> dict.to_a
=> [1, 'three']
>> RubyPython.stop
=> true
Non-Array Values Do Not Convert
>> RubyPython.start
=> true
>> item = RubyPython::RubyPyProxy.new(42)
=> 42
>> item.to_a
NoMethodError: __iter__
275 276 277 278 279 280 281 282 283 284 |
# File 'lib/rubypython/rubypyproxy.rb', line 275 def to_a iter = self.__iter__ ary = [] loop do ary << iter.next() end rescue PythonError => exc raise if exc. !~ /StopIteration/ ary end |
#to_enum ⇒ Object
Creates a PyEnumerable for this object. The object must have the __iter__
method.
294 295 296 |
# File 'lib/rubypython/rubypyproxy.rb', line 294 def to_enum PyEnumerable.new(@pObject) end |
#to_s ⇒ Object
Returns the string representation of the wrapped object via a call to the object’s __str__
method or the str
method in PyMain.
229 230 231 232 233 |
# File 'lib/rubypython/rubypyproxy.rb', line 229 def to_s self.__str__.rubify rescue PythonError, NoMethodError RubyPython::PyMain.str(self).rubify end |