rubypython 0.3.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.autotest +3 -0
- data/.gemtest +0 -0
- data/.gitignore +13 -0
- data/.hgignore +14 -0
- data/.hgtags +7 -0
- data/.rspec +1 -1
- data/Contributors.rdoc +9 -0
- data/History.rdoc +148 -0
- data/{License.txt → License.rdoc} +7 -1
- data/Manifest.txt +15 -10
- data/PostInstall.txt +11 -4
- data/README.rdoc +272 -0
- data/Rakefile +107 -22
- data/autotest/discover.rb +1 -0
- data/lib/rubypython.rb +214 -120
- data/lib/rubypython/blankobject.rb +16 -14
- data/lib/rubypython/conversion.rb +242 -173
- data/lib/rubypython/legacy.rb +30 -31
- data/lib/rubypython/macros.rb +43 -34
- data/lib/rubypython/operators.rb +103 -101
- data/lib/rubypython/options.rb +41 -44
- data/lib/rubypython/pygenerator.rb +61 -0
- data/lib/rubypython/pymainclass.rb +46 -29
- data/lib/rubypython/pyobject.rb +193 -177
- data/lib/rubypython/python.rb +189 -176
- data/lib/rubypython/pythonerror.rb +54 -63
- data/lib/rubypython/pythonexec.rb +123 -0
- data/lib/rubypython/rubypyproxy.rb +213 -137
- data/lib/rubypython/type.rb +20 -0
- data/spec/basic_spec.rb +50 -0
- data/spec/callback_spec.rb +7 -17
- data/spec/conversion_spec.rb +7 -21
- data/spec/legacy_spec.rb +1 -16
- data/spec/pymainclass_spec.rb +6 -15
- data/spec/pyobject_spec.rb +39 -64
- data/spec/python_helpers/basics.py +20 -0
- data/spec/python_helpers/objects.py +24 -20
- data/spec/pythonerror_spec.rb +5 -17
- data/spec/refcnt_spec.rb +4 -10
- data/spec/rubypyclass_spec.rb +1 -11
- data/spec/rubypyproxy_spec.rb +45 -54
- data/spec/rubypython_spec.rb +45 -57
- data/spec/spec_helper.rb +49 -33
- metadata +87 -63
- data.tar.gz.sig +0 -0
- data/History.markdown +0 -97
- data/README.markdown +0 -105
- data/lib/rubypython/core_ext/string.rb +0 -7
- data/lib/rubypython/version.rb +0 -9
- data/spec/python_helpers/objects.pyc +0 -0
- metadata.gz.sig +0 -0
@@ -1,21 +1,23 @@
|
|
1
1
|
require 'blankslate'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
3
|
+
# This document is the basis of the RubyPyProxy precisely because it hides
|
4
|
+
# the implementation of so many things that should be forwarded on to the
|
5
|
+
# Python object. This class is for internal use only.
|
6
|
+
#
|
7
|
+
# Note that in Ruby 1.9, BasicObject might be a better choice, but there are
|
8
|
+
# some decisions made in the rest of the library that make this harder. I
|
9
|
+
# don't see a clean way to integrate both Ruby 1.8 and 1.9 support for this.
|
10
|
+
class RubyPython::BlankObject < ::BlankSlate #:nodoc:
|
11
|
+
class << self
|
12
|
+
def hide(name)
|
13
|
+
if instance_methods.include?(name) and
|
14
|
+
name.to_s !~ /^(__|instance_eval|object_id)/
|
12
15
|
@hidden_methods ||= {}
|
13
|
-
|
14
|
-
|
15
|
-
end
|
16
|
+
@hidden_methods[name.to_sym] = instance_method(name)
|
17
|
+
undef_method name
|
16
18
|
end
|
17
19
|
end
|
18
|
-
|
19
|
-
instance_methods.each { |m| hide(m) }
|
20
20
|
end
|
21
|
+
|
22
|
+
instance_methods.each { |m| hide(m) }
|
21
23
|
end
|
@@ -1,215 +1,284 @@
|
|
1
1
|
require 'rubypython/python'
|
2
2
|
require 'rubypython/macros'
|
3
|
-
module RubyPython
|
4
|
-
#This modules encapsulates the work of converting between native Ruby and
|
5
|
-
#Python types. Unsupported conversions raise {UnsupportedConversion}.
|
6
|
-
module Conversion
|
7
3
|
|
8
|
-
|
9
|
-
|
10
|
-
|
4
|
+
# Acts as a namespace for methods to bidirectionally convert between native
|
5
|
+
# Ruby types and native \Python types. Unsupported conversions raise
|
6
|
+
# UnsupportedConversion.
|
7
|
+
#
|
8
|
+
# The methods in this module should be considered internal implementation to
|
9
|
+
# RubyPython as they all return FFI pointers to \Python objects.
|
10
|
+
module RubyPython::Conversion
|
11
|
+
# Raised when RubyPython does not know how to convert an object from
|
12
|
+
# \Python to Ruby or vice versa.
|
13
|
+
class UnsupportedConversion < Exception; end
|
11
14
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
+
# Convert a Ruby string to a \Python string. Returns an FFI::Pointer to
|
16
|
+
# a PyStringObject.
|
17
|
+
def self.rtopString(rString)
|
18
|
+
size = rString.respond_to?(:bytesize) ? rString.bytesize : rString.size
|
19
|
+
RubyPython::Python.PyString_FromStringAndSize(rString, size)
|
20
|
+
end
|
15
21
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
pList
|
22
|
+
# Convert a Ruby Array to \Python List. Returns an FFI::Pointer to
|
23
|
+
# a PyListObject.
|
24
|
+
def self.rtopArrayToList(rArray)
|
25
|
+
size = rArray.length
|
26
|
+
pList = RubyPython::Python.PyList_New size
|
27
|
+
rArray.each_with_index do |el, i|
|
28
|
+
RubyPython::Python.PyList_SetItem pList, i, rtopObject(el)
|
23
29
|
end
|
30
|
+
pList
|
31
|
+
end
|
24
32
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
33
|
+
# Convert a Ruby Array to \Python Tuple. Returns an FFI::Pointer to a
|
34
|
+
# PyTupleObject.
|
35
|
+
def self.rtopArrayToTuple(rArray)
|
36
|
+
pList = rtopArrayToList(rArray)
|
37
|
+
pTuple = RubyPython::Python.PySequence_Tuple(pList)
|
38
|
+
RubyPython::Python.Py_DecRef(pList)
|
39
|
+
pTuple
|
40
|
+
end
|
31
41
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
pDict
|
42
|
+
# Convert a Ruby Hash to a \Python Dict. Returns an FFI::Pointer to a
|
43
|
+
# PyDictObject.
|
44
|
+
def self.rtopHash(rHash)
|
45
|
+
pDict = RubyPython::Python.PyDict_New
|
46
|
+
rHash.each do |k,v|
|
47
|
+
RubyPython::Python.PyDict_SetItem pDict, rtopObject(k, key = true),
|
48
|
+
rtopObject(v)
|
38
49
|
end
|
50
|
+
pDict
|
51
|
+
end
|
39
52
|
|
40
|
-
|
41
|
-
|
42
|
-
|
53
|
+
# Convert a Ruby Fixnum to a \Python Int. Returns an FFI::Pointer to a
|
54
|
+
# PyIntObject.
|
55
|
+
def self.rtopFixnum(rNum)
|
56
|
+
RubyPython::Python.PyInt_FromLong(rNum)
|
57
|
+
end
|
43
58
|
|
44
|
-
|
45
|
-
|
46
|
-
|
59
|
+
# Convert a Ruby Bignum to a \Python Long. Returns an FFI::Pointer to a
|
60
|
+
# PyLongObject.
|
61
|
+
def self.rtopBigNum(rNum)
|
62
|
+
RubyPython::Python.PyLong_FromLong(rNum)
|
63
|
+
end
|
47
64
|
|
48
|
-
|
49
|
-
|
50
|
-
|
65
|
+
# Convert a Ruby float to a \Python Float. Returns an FFI::Pointer to a
|
66
|
+
# PyFloatObject.
|
67
|
+
def self.rtopFloat(rNum)
|
68
|
+
RubyPython::Python.PyFloat_FromDouble(rNum)
|
69
|
+
end
|
51
70
|
|
52
|
-
|
53
|
-
|
54
|
-
|
71
|
+
# Returns a \Python False value (equivalent to Ruby's +false+). Returns an
|
72
|
+
# FFI::Pointer to Py_ZeroStruct.
|
73
|
+
def self.rtopFalse
|
74
|
+
RubyPython::Macros.Py_RETURN_FALSE
|
75
|
+
end
|
55
76
|
|
56
|
-
|
57
|
-
|
58
|
-
|
77
|
+
# Returns a \Python True value (equivalent to Ruby's +true+). Returns an
|
78
|
+
# FFI::Pointer to Py_TrueStruct.
|
79
|
+
def self.rtopTrue
|
80
|
+
RubyPython::Macros.Py_RETURN_TRUE
|
81
|
+
end
|
59
82
|
|
60
|
-
|
61
|
-
|
62
|
-
|
83
|
+
# Returns a \Python None value (equivalent to Ruby's +nil+). Returns an
|
84
|
+
# FFI::Pointer to Py_NoneStruct.
|
85
|
+
def self.rtopNone
|
86
|
+
RubyPython::Macros.Py_RETURN_NONE
|
87
|
+
end
|
63
88
|
|
64
|
-
|
65
|
-
|
66
|
-
|
89
|
+
# Convert a Ruby Symbol to a \Python String. Returns an FFI::Pointer to a
|
90
|
+
# PyStringObject.
|
91
|
+
def self.rtopSymbol(rSymbol)
|
92
|
+
RubyPython::Python.PyString_FromString rSymbol.to_s
|
93
|
+
end
|
67
94
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
pyMethodDef[:ml_name] = FFI::MemoryPointer.from_string "Proc::#{rObj.object_id}"
|
75
|
-
pyMethodDef[:ml_meth] = callback
|
76
|
-
pyMethodDef[:ml_flags] = Python::METH_VARARGS
|
77
|
-
pyMethodDef[:ml_doc] = nil
|
95
|
+
# Convert a Ruby Proc to a \Python Function. Returns an FFI::Pointer to a
|
96
|
+
# PyCFunction.
|
97
|
+
def self.rtopFunction(rObj)
|
98
|
+
proc = FFI::Function.new(:pointer, [:pointer, :pointer]) do |p_self, p_args|
|
99
|
+
retval = rObj.call(*ptorTuple(p_args))
|
100
|
+
pObject = retval.is_a?(RubyPython::RubyPyProxy) ? retval.pObject : RubyPython::PyObject.new(retval)
|
78
101
|
|
79
|
-
|
102
|
+
# make sure the refcount is >1 when pObject is destroyed
|
103
|
+
pObject.xIncref
|
104
|
+
pObject.pointer
|
80
105
|
end
|
81
106
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
rtopFloat rObj
|
110
|
-
when true
|
111
|
-
rtopTrue
|
112
|
-
when false
|
113
|
-
rtopFalse
|
114
|
-
when Symbol
|
115
|
-
rtopSymbol rObj
|
116
|
-
when nil
|
117
|
-
rtopNone
|
118
|
-
when Proc, Method
|
119
|
-
raise UnsupportedConversion.new("Python to Ruby callbacks not suppported in legacy mode") if RubyPython.legacy_mode
|
120
|
-
rtopProc rObj
|
107
|
+
defn = RubyPython::Python::PyMethodDef.new
|
108
|
+
defn[:ml_name] = FFI::MemoryPointer.from_string("RubyPython::Proc::%s" % rObj.object_id)
|
109
|
+
defn[:ml_meth] = proc
|
110
|
+
defn[:ml_flags] = RubyPython::Python::METH_VARARGS
|
111
|
+
defn[:ml_doc] = nil
|
112
|
+
|
113
|
+
return RubyPython::Python.PyCFunction_New(defn, nil)
|
114
|
+
end
|
115
|
+
|
116
|
+
# This will attempt to convert a Ruby object to an equivalent \Python
|
117
|
+
# native type. Returns an FFI::Pointer to a \Python object (the
|
118
|
+
# appropriate Py…Object C structure). If the conversion is unsuccessful,
|
119
|
+
# will raise UnsupportedConversion.
|
120
|
+
#
|
121
|
+
# [rObj] A native Ruby object.
|
122
|
+
# [is_key] Set to +true+ if the provided Ruby object will be used as a
|
123
|
+
# key in a \Python +dict+. (This primarily matters for Array
|
124
|
+
# conversion.)
|
125
|
+
def self.rtopObject(rObj, is_key = false)
|
126
|
+
case rObj
|
127
|
+
when String
|
128
|
+
rtopString rObj
|
129
|
+
when Array
|
130
|
+
# If this object is going to be used as a hash key we should make it a
|
131
|
+
# tuple instead of a list
|
132
|
+
if is_key
|
133
|
+
rtopArrayToTuple rObj
|
121
134
|
else
|
122
|
-
|
135
|
+
rtopArrayToList rObj
|
123
136
|
end
|
137
|
+
when Hash
|
138
|
+
rtopHash rObj
|
139
|
+
when Fixnum
|
140
|
+
rtopFixnum rObj
|
141
|
+
when Bignum
|
142
|
+
rtopBignum rObj
|
143
|
+
when Float
|
144
|
+
rtopFloat rObj
|
145
|
+
when true
|
146
|
+
rtopTrue
|
147
|
+
when false
|
148
|
+
rtopFalse
|
149
|
+
when Symbol
|
150
|
+
rtopSymbol rObj
|
151
|
+
when Proc, Method
|
152
|
+
if RubyPython.legacy_mode
|
153
|
+
raise UnsupportedConversion.new("Callbacks are not supported in Legacy Mode.")
|
154
|
+
end
|
155
|
+
rtopFunction rObj
|
156
|
+
when Method
|
157
|
+
rtopFunction rObj
|
158
|
+
when nil
|
159
|
+
rtopNone
|
160
|
+
when RubyPython::PyObject
|
161
|
+
rObj.pointer
|
162
|
+
else
|
163
|
+
raise UnsupportedConversion.new("Unsupported type #{rObj.class} for conversion.")
|
124
164
|
end
|
165
|
+
end
|
125
166
|
|
126
|
-
|
127
|
-
|
128
|
-
|
167
|
+
# Convert an FFI::Pointer to a \Python String (PyStringObject) to a Ruby
|
168
|
+
# String.
|
169
|
+
def self.ptorString(pString)
|
170
|
+
strPtr = FFI::MemoryPointer.new(:pointer)
|
171
|
+
sizePtr = FFI::MemoryPointer.new(:ssize_t)
|
129
172
|
|
130
|
-
|
131
|
-
rb_array = []
|
132
|
-
list_size = Python.PyList_Size(pList)
|
173
|
+
RubyPython::Python.PyString_AsStringAndSize(pString, strPtr, sizePtr)
|
133
174
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
175
|
+
size = case FFI.find_type(:ssize_t)
|
176
|
+
when FFI.find_type(:long)
|
177
|
+
sizePtr.read_long
|
178
|
+
when FFI.find_type(:int)
|
179
|
+
sizePtr.read_int
|
180
|
+
when FFI.find_type(:long_long)
|
181
|
+
sizePtr.read_long_long
|
182
|
+
else
|
183
|
+
nil
|
184
|
+
end
|
140
185
|
|
141
|
-
|
142
|
-
|
186
|
+
strPtr.read_pointer.read_string(size)
|
187
|
+
end
|
143
188
|
|
144
|
-
|
145
|
-
|
146
|
-
|
189
|
+
# Convert an FFI::Pointer to a \Python List (PyListObject) to a Ruby
|
190
|
+
# Array.
|
191
|
+
def self.ptorList(pList)
|
192
|
+
rb_array = []
|
193
|
+
list_size = RubyPython::Python.PyList_Size(pList)
|
147
194
|
|
148
|
-
|
149
|
-
Python.
|
150
|
-
#
|
195
|
+
list_size.times do |i|
|
196
|
+
element = RubyPython::Python.PyList_GetItem(pList, i)
|
197
|
+
# PyList_GetItem returns borrowed ref
|
198
|
+
RubyPython::Python.Py_IncRef element
|
199
|
+
rObject = ptorObject(element)
|
200
|
+
rb_array.push rObject
|
151
201
|
end
|
152
202
|
|
153
|
-
|
154
|
-
|
155
|
-
end
|
203
|
+
rb_array
|
204
|
+
end
|
156
205
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
rArray
|
162
|
-
end
|
206
|
+
# Convert an FFI::Pointer to a \Python Int (PyIntObject) to a Ruby Fixnum.
|
207
|
+
def self.ptorInt(pNum)
|
208
|
+
RubyPython::Python.PyInt_AsLong(pNum)
|
209
|
+
end
|
163
210
|
|
164
|
-
|
165
|
-
|
211
|
+
# Convert an FFI::Pointer to a \Python Long (PyLongObject) to a Ruby
|
212
|
+
# Fixnum. This version does not do overflow checking, but probably should.
|
213
|
+
def self.ptorLong(pNum)
|
214
|
+
RubyPython::Python.PyLong_AsLong(pNum)
|
215
|
+
# TODO Overflow Checking
|
216
|
+
end
|
166
217
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
218
|
+
# Convert an FFI::Pointer to a \Python Float (PyFloatObject) to a Ruby
|
219
|
+
# Float.
|
220
|
+
def self.ptorFloat(pNum)
|
221
|
+
RubyPython::Python.PyFloat_AsDouble(pNum)
|
222
|
+
end
|
171
223
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
224
|
+
# Convert an FFI::Pointer to a \Python Tuple (PyTupleObject) to a Ruby
|
225
|
+
# Array.
|
226
|
+
def self.ptorTuple(pTuple)
|
227
|
+
pList = RubyPython::Python.PySequence_List pTuple
|
228
|
+
rArray = ptorList pList
|
229
|
+
RubyPython::Python.Py_DecRef pList
|
230
|
+
rArray
|
231
|
+
end
|
179
232
|
|
180
|
-
|
233
|
+
# Convert an FFI::Pointer to a \Python Dictionary (PyDictObject) to a Ruby
|
234
|
+
# Hash.
|
235
|
+
def self.ptorDict(pDict)
|
236
|
+
rb_hash = {}
|
237
|
+
|
238
|
+
pos = FFI::MemoryPointer.new :ssize_t
|
239
|
+
pos.write_int 0
|
240
|
+
key = FFI::MemoryPointer.new :pointer
|
241
|
+
val = FFI::MemoryPointer.new :pointer
|
242
|
+
|
243
|
+
while RubyPython::Python.PyDict_Next(pDict, pos, key, val) != 0
|
244
|
+
pKey = key.read_pointer
|
245
|
+
pVal = val.read_pointer
|
246
|
+
rKey = ptorObject(pKey)
|
247
|
+
rVal = ptorObject(pVal)
|
248
|
+
rb_hash[rKey] = rVal
|
181
249
|
end
|
182
250
|
|
251
|
+
rb_hash
|
252
|
+
end
|
183
253
|
|
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
|
-
|
212
|
-
end
|
254
|
+
# Converts a pointer to a \Python object into a native Ruby type, if
|
255
|
+
# possible. If the conversion cannot be done, the Python object will be
|
256
|
+
# returned unmodified.
|
257
|
+
#
|
258
|
+
# [pObj] An FFI::Pointer to a \Python object.
|
259
|
+
def self.ptorObject(pObj)
|
260
|
+
if RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyString_Type.to_ptr) != 0
|
261
|
+
ptorString pObj
|
262
|
+
elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyList_Type.to_ptr) != 0
|
263
|
+
ptorList pObj
|
264
|
+
elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyInt_Type.to_ptr) != 0
|
265
|
+
ptorInt pObj
|
266
|
+
elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyLong_Type.to_ptr) != 0
|
267
|
+
ptorLong pObj
|
268
|
+
elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyFloat_Type.to_ptr) != 0
|
269
|
+
ptorFloat pObj
|
270
|
+
elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyTuple_Type.to_ptr) != 0
|
271
|
+
ptorTuple pObj
|
272
|
+
elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyDict_Type.to_ptr) != 0
|
273
|
+
ptorDict pObj
|
274
|
+
elsif pObj == RubyPython::Macros.Py_True
|
275
|
+
true
|
276
|
+
elsif pObj == RubyPython::Macros.Py_False
|
277
|
+
false
|
278
|
+
elsif pObj == RubyPython::Macros.Py_None
|
279
|
+
nil
|
280
|
+
else
|
281
|
+
pObj
|
213
282
|
end
|
214
283
|
end
|
215
284
|
end
|