rubypython 0.2.11 → 0.3.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.tar.gz.sig +0 -0
- data/{History.txt → History.markdown} +34 -28
- data/Manifest.txt +26 -40
- data/PostInstall.txt +2 -1
- data/README.markdown +103 -0
- data/Rakefile +19 -3
- data/lib/rubypython.rb +118 -114
- data/lib/rubypython/blankobject.rb +21 -0
- data/lib/rubypython/conversion.rb +198 -0
- data/lib/rubypython/core_ext/string.rb +7 -0
- data/lib/rubypython/legacy.rb +15 -0
- data/lib/rubypython/macros.rb +47 -0
- data/lib/rubypython/operators.rb +111 -0
- data/lib/rubypython/pymainclass.rb +51 -0
- data/lib/rubypython/pyobject.rb +203 -0
- data/lib/rubypython/python.rb +111 -0
- data/lib/rubypython/pythonerror.rb +78 -0
- data/lib/rubypython/rubypyproxy.rb +214 -0
- data/lib/rubypython/version.rb +4 -3
- data/spec/conversion_spec.rb +66 -0
- data/spec/legacy_spec.rb +22 -0
- data/spec/pymainclass_spec.rb +26 -0
- data/spec/pyobject_spec.rb +264 -0
- data/spec/python_helpers/objects.py +41 -0
- data/spec/pythonerror_spec.rb +43 -0
- data/spec/refcnt_spec.rb +68 -0
- data/spec/rubypyclass_spec.rb +13 -0
- data/spec/rubypyproxy_spec.rb +249 -0
- data/spec/rubypython_spec.rb +62 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +51 -0
- metadata +79 -73
- metadata.gz.sig +0 -0
- data/README.txt +0 -60
- data/ext/rubypython_bridge/cbridge.c +0 -150
- data/ext/rubypython_bridge/cbridge.h +0 -15
- data/ext/rubypython_bridge/config.h +0 -14
- data/ext/rubypython_bridge/extconf.rb +0 -43
- data/ext/rubypython_bridge/ptor.c +0 -242
- data/ext/rubypython_bridge/ptor.h +0 -15
- data/ext/rubypython_bridge/rp_blankobject.c +0 -42
- data/ext/rubypython_bridge/rp_blankobject.h +0 -11
- data/ext/rubypython_bridge/rp_class.c +0 -56
- data/ext/rubypython_bridge/rp_class.h +0 -7
- data/ext/rubypython_bridge/rp_error.c +0 -34
- data/ext/rubypython_bridge/rp_error.h +0 -11
- data/ext/rubypython_bridge/rp_function.c +0 -31
- data/ext/rubypython_bridge/rp_function.h +0 -7
- data/ext/rubypython_bridge/rp_instance.c +0 -164
- data/ext/rubypython_bridge/rp_instance.h +0 -7
- data/ext/rubypython_bridge/rp_module.c +0 -160
- data/ext/rubypython_bridge/rp_module.h +0 -8
- data/ext/rubypython_bridge/rp_object.c +0 -194
- data/ext/rubypython_bridge/rp_object.h +0 -23
- data/ext/rubypython_bridge/rp_util.c +0 -63
- data/ext/rubypython_bridge/rp_util.h +0 -11
- data/ext/rubypython_bridge/rtop.c +0 -212
- data/ext/rubypython_bridge/rtop.h +0 -17
- data/ext/rubypython_bridge/rubypython_bridge.c +0 -125
- data/ext/rubypython_bridge/rubypython_bridge.h +0 -10
- data/lib/rubypython/session.rb +0 -4
- data/lib/rubypython/wrapper_extensions.rb +0 -83
- data/setup.rb +0 -1585
- data/tasks/environment.rake +0 -7
- data/tasks/extconf.rake +0 -13
- data/tasks/extconf/rubypython_bridge.rake +0 -49
- data/test/python_helpers/objects.py +0 -12
- data/test/test.wav +0 -0
- data/test/test_helper.rb +0 -2
- data/test/test_rubypython.rb +0 -215
- data/test/test_rubypython_bridge_extn.rb +0 -133
- data/test/test_session.rb +0 -6
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'blankslate'
|
2
|
+
|
3
|
+
module RubyPython
|
4
|
+
#An object to be used as a base class for Proxy classes.
|
5
|
+
#It is necessary to define this because no such class exists in Ruby
|
6
|
+
#1.8.x
|
7
|
+
class BlankObject < BlankSlate
|
8
|
+
class << self
|
9
|
+
def hide(name)
|
10
|
+
if instance_methods.include?(name) and
|
11
|
+
name.to_s !~ /^(__|instance_eval|object_id)/
|
12
|
+
@hidden_methods ||= {}
|
13
|
+
@hidden_methods[name.to_sym] = instance_method(name)
|
14
|
+
undef_method name
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
instance_methods.each { |m| hide(m) }
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require 'rubypython/python'
|
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
|
+
|
8
|
+
#Raised when RubyPython does not know how to convert an object from Python
|
9
|
+
#to Ruby or vice versa
|
10
|
+
class UnsupportedConversion < Exception; end
|
11
|
+
|
12
|
+
def self.rtopString(rString)
|
13
|
+
Python.PyString_FromString(rString)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.rtopArrayToList(rArray)
|
17
|
+
size = rArray.length
|
18
|
+
pList = Python.PyList_New size
|
19
|
+
rArray.each_with_index do |el, i|
|
20
|
+
Python.PyList_SetItem pList, i, rtopObject(el)
|
21
|
+
end
|
22
|
+
pList
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.rtopArrayToTuple(rArray)
|
26
|
+
pList = rtopArrayToList(rArray)
|
27
|
+
pTuple = Python.PySequence_Tuple(pList)
|
28
|
+
Python.Py_DecRef(pList)
|
29
|
+
pTuple
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.rtopHash(rHash)
|
33
|
+
pDict = Python.PyDict_New
|
34
|
+
rHash.each do |k,v|
|
35
|
+
Python.PyDict_SetItem pDict, rtopObject(k, key=true), rtopObject(v)
|
36
|
+
end
|
37
|
+
pDict
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.rtopFixnum(rNum)
|
41
|
+
Python.PyInt_FromLong(rNum)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.rtopBigNum(rNum)
|
45
|
+
Python.PyLong_FromLong(rNum)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.rtopFloat(rNum)
|
49
|
+
Python.PyFloat_FromDouble(rNum)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.rtopFalse
|
53
|
+
Macros.Py_RETURN_FALSE
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.rtopTrue
|
57
|
+
Macros.Py_RETURN_TRUE
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.rtopNone
|
61
|
+
Macros.Py_RETURN_NONE
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.rtopSymbol(rSymbol)
|
65
|
+
Python.PyString_FromString rSymbol.to_s
|
66
|
+
end
|
67
|
+
|
68
|
+
#If possible converts a ruby type to an equivalent
|
69
|
+
#python native type.
|
70
|
+
#@param rObj a native ruby type
|
71
|
+
#@param [Boolean] is_key whether this object will be used as a key in a
|
72
|
+
# python dict.
|
73
|
+
#@return [FFI::Pointer] a to a C PyObject\*
|
74
|
+
#@raise [UnsupportedConversion]
|
75
|
+
def self.rtopObject(rObj, is_key=false)
|
76
|
+
case rObj
|
77
|
+
when String
|
78
|
+
rtopString rObj
|
79
|
+
when Array
|
80
|
+
# If this object is going to be used as a
|
81
|
+
# hash key we should make it a tuple instead
|
82
|
+
# of a list
|
83
|
+
if is_key
|
84
|
+
rtopArrayToTuple rObj
|
85
|
+
else
|
86
|
+
rtopArrayToList rObj
|
87
|
+
end
|
88
|
+
when Hash
|
89
|
+
rtopHash rObj
|
90
|
+
when Fixnum
|
91
|
+
rtopFixnum rObj
|
92
|
+
when Bignum
|
93
|
+
rtopBignum rObj
|
94
|
+
when Float
|
95
|
+
rtopFloat rObj
|
96
|
+
when true
|
97
|
+
rtopTrue
|
98
|
+
when false
|
99
|
+
rtopFalse
|
100
|
+
when Symbol
|
101
|
+
rtopSymbol rObj
|
102
|
+
when nil
|
103
|
+
rtopNone
|
104
|
+
else
|
105
|
+
raise UnsupportedConversion.new("Unsupported type for RTOP conversion." )
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.ptorString(pString)
|
110
|
+
Python.PyString_AsString(pString)
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.ptorList(pList)
|
114
|
+
rb_array = []
|
115
|
+
list_size = Python.PyList_Size(pList)
|
116
|
+
|
117
|
+
list_size.times do |i|
|
118
|
+
element = Python.PyList_GetItem(pList, i)
|
119
|
+
Python.Py_IncRef element
|
120
|
+
rObject = ptorObject(element)
|
121
|
+
rb_array.push rObject
|
122
|
+
end
|
123
|
+
|
124
|
+
rb_array
|
125
|
+
end
|
126
|
+
|
127
|
+
def self.ptorInt(pNum)
|
128
|
+
Python.PyInt_AsLong pNum
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.ptorLong(pNum)
|
132
|
+
Python.PyLong_AsLong(pNum)
|
133
|
+
#TODO Overflow Checking
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.ptorFloat(pNum)
|
137
|
+
Python.PyFloat_AsDouble(pNum)
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.ptorTuple(pTuple)
|
141
|
+
pList = Python.PySequence_List pTuple
|
142
|
+
rArray = ptorList pList
|
143
|
+
Python.Py_DecRef pList
|
144
|
+
rArray
|
145
|
+
end
|
146
|
+
|
147
|
+
def self.ptorDict(pDict)
|
148
|
+
rb_hash = {}
|
149
|
+
|
150
|
+
pos = FFI::MemoryPointer.new :ssize_t
|
151
|
+
pos.write_int 0
|
152
|
+
key = FFI::MemoryPointer.new :pointer
|
153
|
+
val = FFI::MemoryPointer.new :pointer
|
154
|
+
|
155
|
+
while Python.PyDict_Next(pDict, pos, key, val) != 0
|
156
|
+
pKey = key.read_pointer
|
157
|
+
pVal = val.read_pointer
|
158
|
+
rKey = ptorObject(pKey)
|
159
|
+
rVal = ptorObject(pVal)
|
160
|
+
rb_hash[rKey] = rVal
|
161
|
+
end
|
162
|
+
|
163
|
+
rb_hash
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
#Converts a pointer to a Python object into a native ruby type, if
|
168
|
+
#possible. Otherwise raises an error.
|
169
|
+
#@param [FFI::Pointer] pObj a pointer to a Python object
|
170
|
+
#@return a native ruby object.
|
171
|
+
#@raise {UnsupportedConversion}
|
172
|
+
def self.ptorObject(pObj)
|
173
|
+
if Macros.PyObject_TypeCheck(pObj, Python.PyString_Type.to_ptr) != 0
|
174
|
+
ptorString pObj
|
175
|
+
elsif Macros.PyObject_TypeCheck(pObj, Python.PyList_Type.to_ptr) != 0
|
176
|
+
ptorList pObj
|
177
|
+
elsif Macros.PyObject_TypeCheck(pObj, Python.PyInt_Type.to_ptr) != 0
|
178
|
+
ptorInt pObj
|
179
|
+
elsif Macros.PyObject_TypeCheck(pObj, Python.PyLong_Type.to_ptr) != 0
|
180
|
+
ptorLong pObj
|
181
|
+
elsif Macros.PyObject_TypeCheck(pObj, Python.PyFloat_Type.to_ptr) != 0
|
182
|
+
ptorFloat pObj
|
183
|
+
elsif Macros.PyObject_TypeCheck(pObj, Python.PyTuple_Type.to_ptr) != 0
|
184
|
+
ptorTuple pObj
|
185
|
+
elsif Macros.PyObject_TypeCheck(pObj, Python.PyDict_Type.to_ptr) != 0
|
186
|
+
ptorDict pObj
|
187
|
+
elsif pObj == Macros.Py_True
|
188
|
+
true
|
189
|
+
elsif pObj == Macros.Py_False
|
190
|
+
false
|
191
|
+
elsif pObj == Macros.Py_None
|
192
|
+
nil
|
193
|
+
else
|
194
|
+
pObj
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
require 'rubypython/python'
|
3
|
+
|
4
|
+
module RubyPython
|
5
|
+
#Contains Python C API macros reimplmented in Ruby. For internal use only.
|
6
|
+
module Macros
|
7
|
+
def self.Py_TYPE(pObjPointer)
|
8
|
+
pStruct = Python::PyObjectStruct.new pObjPointer
|
9
|
+
pStruct[:ob_type]
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.PyObject_TypeCheck(pObject, pTypePointer)
|
13
|
+
if Py_TYPE(pObject) == pTypePointer
|
14
|
+
1
|
15
|
+
else
|
16
|
+
0
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.Py_True
|
21
|
+
Python.Py_TrueStruct.to_ptr
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.Py_False
|
25
|
+
Python.Py_ZeroStruct.to_ptr
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.Py_None
|
29
|
+
Python.Py_NoneStruct.to_ptr
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.Py_RETURN_FALSE
|
33
|
+
Python.Py_IncRef(self.Py_False)
|
34
|
+
self.Py_False
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.Py_RETURN_TRUE
|
38
|
+
Python.Py_IncRef(self.Py_True)
|
39
|
+
self.Py_True
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.Py_RETURN_NONE
|
43
|
+
Python.Py_IncRef(self.Py_None)
|
44
|
+
self.Py_None
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module RubyPython
|
2
|
+
#A mixin module to provide method delegation to a proxy class. This is done
|
3
|
+
#either by delegating to methods defined on the wrapped object or by using the
|
4
|
+
#Python _operator_ module. A large number of the methods are dynamically
|
5
|
+
#generated and so their documentation is not provided here. In general all
|
6
|
+
#operators that can be overloaded are delegated.
|
7
|
+
module Operators
|
8
|
+
#Provides access to the Python _operator_ module.
|
9
|
+
#@return[RubyPython::RubyPyModule]
|
10
|
+
def self.operator_
|
11
|
+
@@operator ||= RubyPython.import('operator')
|
12
|
+
end
|
13
|
+
|
14
|
+
#Creates a method to delegate a binary operation. The result of the
|
15
|
+
#operation will follow the conversion rules appropriate to the current mode
|
16
|
+
#of operation as set by {RubyPython.legacy_mode}.
|
17
|
+
#@param[Symbol, String] rname The name of the Ruby method for this operation
|
18
|
+
#@param[String] pname The name of the Python magic method to which this
|
19
|
+
#method should be delegated.
|
20
|
+
def self.bin_op rname, pname
|
21
|
+
define_method rname.to_sym do |other|
|
22
|
+
self.__send__ pname, other
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
#Creates a method to delegate a relational operator. The result of the
|
27
|
+
#delegated method will always be converted to a Ruby type so that simple
|
28
|
+
#boolean testing may occur. These methods are implemented with calls the
|
29
|
+
#_operator_ module.
|
30
|
+
#@param[Symbol, String] rname The name of the Ruby method for this operation
|
31
|
+
#@param[String] pname The name of the Python magic method to which this
|
32
|
+
#method should be delegated.
|
33
|
+
def self.rel_op rname, pname
|
34
|
+
define_method rname.to_sym do |other|
|
35
|
+
Operators.operator_.__send__(pname, self, other).rubify
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
#Creates a method to delegate a relational operator. The result of the
|
40
|
+
#operation will follow the conversion rules appropriate to the current mode
|
41
|
+
#of operation as set by {RubyPython.legacy_mode}. These methods are
|
42
|
+
#implemented with calls the _operator_ module.
|
43
|
+
#@param[Symbol, String] rname The name of the Ruby method for this operation
|
44
|
+
#@param[String] pname The name of the Python magic method to which this
|
45
|
+
#method should be delegated.
|
46
|
+
def self.unary_op rname, pname
|
47
|
+
define_method rname.to_sym do
|
48
|
+
Operators.operator_.__send__(pname, self)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
[
|
54
|
+
[:+, '__add__'],
|
55
|
+
[:-, '__sub__'],
|
56
|
+
[:*, '__mul__'],
|
57
|
+
[:/, '__div__'],
|
58
|
+
[:&, '__and__'],
|
59
|
+
[:^, '__xor__'],
|
60
|
+
[:%, '__mod__'],
|
61
|
+
[:**, '__pow__'],
|
62
|
+
[:>>, '__rshift__'],
|
63
|
+
[:<<, '__lshift__'],
|
64
|
+
[:|, '__or__']
|
65
|
+
].each do |args|
|
66
|
+
bin_op *args
|
67
|
+
end
|
68
|
+
|
69
|
+
[
|
70
|
+
[:~, :__invert__],
|
71
|
+
[:+@, :__pos__],
|
72
|
+
[:-@, :__neg__]
|
73
|
+
].each do |args|
|
74
|
+
unary_op *args
|
75
|
+
end
|
76
|
+
|
77
|
+
[
|
78
|
+
[:==, 'eq'],
|
79
|
+
[:<, 'lt'],
|
80
|
+
[:<=, 'le'],
|
81
|
+
[:>, 'gt'],
|
82
|
+
[:>=, 'ge'],
|
83
|
+
[:equal?, 'is_']
|
84
|
+
].each do |args|
|
85
|
+
rel_op *args
|
86
|
+
end
|
87
|
+
|
88
|
+
alias :eql? :==
|
89
|
+
|
90
|
+
#Delegates object indexed access to the wrapped Python object.
|
91
|
+
def [](index)
|
92
|
+
self.__getitem__ index
|
93
|
+
end
|
94
|
+
|
95
|
+
#Delegates setting of various indices to the wrapped Python object.
|
96
|
+
def []=(index, value)
|
97
|
+
self.__setitem__ index, value
|
98
|
+
end
|
99
|
+
|
100
|
+
#Delegates membership testing to Python.
|
101
|
+
def include?(item)
|
102
|
+
self.__contains__(item).rubify
|
103
|
+
end
|
104
|
+
|
105
|
+
#Delegates Comparison to Python.
|
106
|
+
def <=>(other)
|
107
|
+
PyMain.cmp(self, other)
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'rubypython/blankobject'
|
2
|
+
require 'singleton'
|
3
|
+
|
4
|
+
module RubyPython
|
5
|
+
# A singleton object providing access to the python \_\_main\_\_ and
|
6
|
+
# \_\_builtin\_\_ modules. This can be conveniently accessed through the
|
7
|
+
# already instaniated PyMain constant. The \_\_main\_\_ namespace is
|
8
|
+
# searched before the \_\_builtin\_\_ namespace. As such, naming clashes will
|
9
|
+
# be resolved in that order.
|
10
|
+
#
|
11
|
+
# ## Block Syntax
|
12
|
+
# The PyMainClass object provides somewhat experimental block support. A
|
13
|
+
# block may be passed to a method call and the object returned by the
|
14
|
+
# function call will be passed as an argument to the block.
|
15
|
+
class PyMainClass < BlankObject
|
16
|
+
include Singleton
|
17
|
+
attr_writer :main, :builtin
|
18
|
+
|
19
|
+
#@return [RubyPyModule] a proxy object wrapping the Python \__main\__
|
20
|
+
#namespace.
|
21
|
+
def main
|
22
|
+
@main||=RubyPython.import "__main__"
|
23
|
+
end
|
24
|
+
|
25
|
+
#@return [RubyPyModule] a proxy object wrapping the Python \__builtin\__
|
26
|
+
#namespace.
|
27
|
+
def builtin
|
28
|
+
@builtin||=RubyPython.import "__builtin__"
|
29
|
+
end
|
30
|
+
|
31
|
+
#Delegates any method calls on this object to the Python \__main\__ or
|
32
|
+
#\__builtin\__ namespaces. Method call resolution occurs in that order.
|
33
|
+
def method_missing(name,*args,&block)
|
34
|
+
proxy = if main.respond_to?(name)
|
35
|
+
main
|
36
|
+
elsif builtin.respond_to?(name)
|
37
|
+
builtin
|
38
|
+
else
|
39
|
+
super(name, *args)
|
40
|
+
end
|
41
|
+
result = if proxy.is_real_method?(name)
|
42
|
+
proxy.__send__(name, *args)
|
43
|
+
else
|
44
|
+
proxy.__send__(:method_missing, name,*args)
|
45
|
+
end
|
46
|
+
block ? block.call(result) : result
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
PyMain = PyMainClass.instance
|
51
|
+
end
|