rubypython 0.2.11 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|