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
data/lib/rubypython/version.rb
CHANGED
@@ -0,0 +1,66 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
include TestConstants
|
4
|
+
describe RubyPython::Conversion do
|
5
|
+
include RubyPythonStartStop
|
6
|
+
|
7
|
+
subject { RubyPython::Conversion }
|
8
|
+
|
9
|
+
before do
|
10
|
+
sys = RubyPython.import 'sys'
|
11
|
+
sys.path.append './spec/python_helpers'
|
12
|
+
@objects = RubyPython.import 'objects'
|
13
|
+
end
|
14
|
+
|
15
|
+
context "when converting from Python to Ruby" do
|
16
|
+
[
|
17
|
+
["an int", "an int", AnInt],
|
18
|
+
["a float", "a float", AFloat],
|
19
|
+
["a string", "a string", AString],
|
20
|
+
["a list", "an array", AnArray],
|
21
|
+
["a tuple", "an array", AnArray],
|
22
|
+
["a dict", "a hash", AConvertedHash],
|
23
|
+
["python True", "true", true],
|
24
|
+
["python False", "false", false],
|
25
|
+
["python None", "nil", nil]
|
26
|
+
].each do |py_type, rb_type, output|
|
27
|
+
it "should convert #{py_type} to #{rb_type}" do
|
28
|
+
py_object_ptr = @objects.__send__(py_type.sub(' ', '_')).pObject.pointer
|
29
|
+
subject.ptorObject(py_object_ptr).should == output
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should return an FFI::Pointer when it cannot convert" do
|
34
|
+
unconvertable = @objects.RubyPythonMockObject.pObject.pointer
|
35
|
+
subject.ptorObject(unconvertable).should be_a_kind_of(FFI::Pointer)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
context "when converting Ruby to Python" do
|
41
|
+
[
|
42
|
+
["an int", "an int", AnInt],
|
43
|
+
["a float", "a float", AFloat],
|
44
|
+
["a string", "a string", AString],
|
45
|
+
["a string", "a symbol", ASym],
|
46
|
+
["a list", "an array", AnArray],
|
47
|
+
["a dict", "a hash", AConvertedHash],
|
48
|
+
["python True", "true", true],
|
49
|
+
["python False", "false", false],
|
50
|
+
["python None", "nil", nil]
|
51
|
+
].each do |py_type, rb_type, input|
|
52
|
+
|
53
|
+
it "should convert #{rb_type} to #{py_type}" do
|
54
|
+
py_object_ptr = subject.rtopObject(input)
|
55
|
+
output = @objects.__send__(rb_type.sub(' ', '_')).pObject.pointer
|
56
|
+
RubyPython::Python.PyObject_Compare(py_object_ptr, output).should == 0
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should raise an exception when it cannot convert" do
|
61
|
+
lambda { subject.rtopObject(Class) }.should raise_exception(subject::UnsupportedConversion)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
data/spec/legacy_spec.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
include TestConstants
|
4
|
+
|
5
|
+
describe 'RubyPython Legacy Mode Module' do
|
6
|
+
include RubyPythonStartStop
|
7
|
+
|
8
|
+
before :all do
|
9
|
+
require 'rubypython/legacy'
|
10
|
+
end
|
11
|
+
|
12
|
+
after :all do
|
13
|
+
RubyPython::LegacyMode.teardown_legacy
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "when required" do
|
17
|
+
it "should enable legacy mode" do
|
18
|
+
RubyPython.legacy_mode.should == true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe RubyPython::PyMainClass do
|
4
|
+
include TestConstants
|
5
|
+
include RubyPythonStartStop
|
6
|
+
|
7
|
+
subject { RubyPython::PyMain }
|
8
|
+
|
9
|
+
it "should delegate to builtins" do
|
10
|
+
subject.float(AnInt).rubify.should == AnInt.to_f
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should handle block syntax" do
|
14
|
+
subject.float(AnInt) {|f| f.rubify*2}.should == (AnInt.to_f * 2)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should allow attribute access" do
|
18
|
+
subject.main.__name__.rubify.should == '__main__'
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should allow global variable setting" do
|
22
|
+
subject.x = 2
|
23
|
+
subject.x.rubify.should == 2
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,264 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe RubyPython::PyObject do
|
4
|
+
include RubyPythonStartStop
|
5
|
+
include TestConstants
|
6
|
+
|
7
|
+
before do
|
8
|
+
@string = RubyPython.import('string').pObject
|
9
|
+
@urllib2 = RubyPython.import('urllib2').pObject
|
10
|
+
@builtin = RubyPython.import("__builtin__")
|
11
|
+
sys = RubyPython.import 'sys'
|
12
|
+
sys.path.append './spec/python_helpers/'
|
13
|
+
@objects = RubyPython.import('objects')
|
14
|
+
end
|
15
|
+
|
16
|
+
describe ".new" do
|
17
|
+
[
|
18
|
+
["a string", AString],
|
19
|
+
["an int", AnInt],
|
20
|
+
["a float", AFloat],
|
21
|
+
["an array", AnArray],
|
22
|
+
["a symbol", ASym],
|
23
|
+
["a hash", AHash]
|
24
|
+
].each do |title, obj|
|
25
|
+
|
26
|
+
it "should wrap #{title}" do
|
27
|
+
lambda { described_class.new(obj) }.should_not raise_exception
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
[
|
32
|
+
"a string",
|
33
|
+
"an int",
|
34
|
+
"a list",
|
35
|
+
"a dict",
|
36
|
+
"a tuple"
|
37
|
+
].each do |title|
|
38
|
+
it "should take #{title} from a Python pointer" do
|
39
|
+
lambda do
|
40
|
+
py_obj = @objects.__send__(title.gsub(' ','_')).pObject.pointer
|
41
|
+
described_class.new(py_obj)
|
42
|
+
end.should_not raise_exception
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
end #new
|
48
|
+
|
49
|
+
describe "#rubify" do
|
50
|
+
|
51
|
+
[
|
52
|
+
["a string", AString],
|
53
|
+
["an int", AnInt],
|
54
|
+
["a float", AFloat],
|
55
|
+
["an array", AnArray],
|
56
|
+
["a symbol", ASym, ASym.to_s],
|
57
|
+
["a hash", AHash, AConvertedHash]
|
58
|
+
].each do |arr|
|
59
|
+
type, input, output = arr
|
60
|
+
output ||= input
|
61
|
+
|
62
|
+
it "should faithfully unwrap #{type}" do
|
63
|
+
described_class.new(input).rubify.should == output
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end #rubify
|
69
|
+
|
70
|
+
describe "#hasAttr" do
|
71
|
+
it "should return true when object has the requested attribute" do
|
72
|
+
@string.hasAttr("ascii_letters").should be_true
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should return false when object does not have the requested attribute" do
|
76
|
+
@string.hasAttr("nonExistentThing").should be_false
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "#getAttr" do
|
81
|
+
it "should fetch requested object attribute" do
|
82
|
+
ascii_letters = @string.getAttr "ascii_letters"
|
83
|
+
ascii_letters.rubify.should == "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should return a PyObject instance" do
|
87
|
+
ascii_letters = @string.getAttr "ascii_letters"
|
88
|
+
ascii_letters.should be_kind_of(described_class)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "#setAttr" do
|
93
|
+
it "should modify the specified attribute of the object" do
|
94
|
+
pyNewLetters = described_class.new "RbPy"
|
95
|
+
@string.setAttr "ascii_letters", pyNewLetters
|
96
|
+
@string.getAttr("ascii_letters").rubify.should == pyNewLetters.rubify
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should create the requested attribute if it doesn't exist" do
|
100
|
+
pyNewString = described_class.new "python"
|
101
|
+
@string.setAttr "ruby", pyNewString
|
102
|
+
@string.getAttr("ruby").rubify.should == pyNewString.rubify
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "#cmp" do
|
107
|
+
|
108
|
+
before do
|
109
|
+
@less = described_class.new 5
|
110
|
+
@greater = described_class.new 10
|
111
|
+
@less_dup = described_class.new 5
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should return 0 when objects are equal" do
|
115
|
+
@less.cmp(@less_dup).should == 0
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should change sign under interchange of arguments" do
|
119
|
+
@less.cmp(@greater).should == -@greater.cmp(@less)
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should return -1 when first object is less than the second" do
|
123
|
+
@less.cmp(@greater).should == -1
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should return 1 when first object is greater than the second" do
|
127
|
+
@greater.cmp(@less).should == 1
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "#makeTuple" do
|
132
|
+
it "should wrap single arguments in a tuple" do
|
133
|
+
arg = described_class.new AString
|
134
|
+
described_class.makeTuple(arg).rubify.should == [AString]
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should turn a Python list into a tuple" do
|
138
|
+
arg = @objects.a_list.pObject
|
139
|
+
converted = described_class.makeTuple(arg)
|
140
|
+
converted.rubify.should == AnArray
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should return the given argument if it is a tuple" do
|
144
|
+
arg = @objects.a_tuple.pObject
|
145
|
+
converted = described_class.makeTuple(arg)
|
146
|
+
converted.pointer.address.should == arg.pointer.address
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
describe "#callObject" do
|
152
|
+
#Expand coverage types
|
153
|
+
it "should execute wrapped object with supplied arguments" do
|
154
|
+
arg = described_class.new AnInt
|
155
|
+
argt = described_class.buildArgTuple arg
|
156
|
+
|
157
|
+
builtin = @builtin.pObject
|
158
|
+
stringClass = builtin.getAttr "str"
|
159
|
+
stringClass.callObject(argt).rubify.should == AnInt.to_s
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
describe "#newList" do
|
164
|
+
it "should wrap supplied args in a Python list" do
|
165
|
+
args = AnArray.map do |obj|
|
166
|
+
described_class.new obj
|
167
|
+
end
|
168
|
+
described_class.newList(*args).rubify.should == AnArray
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
describe "#function_or_method?" do
|
173
|
+
|
174
|
+
it "should be true for a method" do
|
175
|
+
mockObjClass = @objects.RubyPythonMockObject.pObject
|
176
|
+
mockObjClass.getAttr('square_elements').should be_a_function_or_method
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should be true for a function" do
|
180
|
+
@objects.pObject.getAttr('identity').should be_a_function_or_method
|
181
|
+
end
|
182
|
+
|
183
|
+
xit "should return true for a builtin function" do
|
184
|
+
any = @builtin.pObject.getAttr('any')
|
185
|
+
any.should be_a_function_or_method
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should return false for a class" do
|
189
|
+
@objects.RubyPythonMockObject.pObject.should_not be_a_function_or_method
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
describe "#class?" do
|
195
|
+
|
196
|
+
it "should return true if wrapped object is an old style class" do
|
197
|
+
@objects.RubyPythonMockObject.pObject.should be_a_class
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should return true if wrapped object is an new style class" do
|
201
|
+
@objects.NewStyleClass.pObject.should be_a_class
|
202
|
+
end
|
203
|
+
|
204
|
+
it "should return true if wrapped object is a builtin class" do
|
205
|
+
strClass = @builtin.pObject.getAttr('str')
|
206
|
+
strClass.should be_a_class
|
207
|
+
end
|
208
|
+
|
209
|
+
it "should return false for an object instance" do
|
210
|
+
@objects.RubyPythonMockObject.new.pObject.should_not be_a_class
|
211
|
+
end
|
212
|
+
|
213
|
+
end
|
214
|
+
|
215
|
+
describe "#callable?" do
|
216
|
+
|
217
|
+
it "should be true for a method" do
|
218
|
+
mockObjClass = @objects.RubyPythonMockObject.pObject
|
219
|
+
mockObjClass.getAttr('square_elements').should be_callable
|
220
|
+
end
|
221
|
+
|
222
|
+
it "should be true for a function" do
|
223
|
+
@objects.pObject.getAttr('identity').should be_callable
|
224
|
+
end
|
225
|
+
|
226
|
+
it "should return true for a builtin function" do
|
227
|
+
any = @builtin.pObject.getAttr('any')
|
228
|
+
any.should be_callable
|
229
|
+
end
|
230
|
+
|
231
|
+
it "should return true for a class" do
|
232
|
+
@objects.RubyPythonMockObject.pObject.should be_callable
|
233
|
+
end
|
234
|
+
|
235
|
+
it "should return false for a non-callable instance" do
|
236
|
+
@objects.RubyPythonMockObject.new.pObject.should_not be_callable
|
237
|
+
end
|
238
|
+
|
239
|
+
specify { described_class.new(6).should_not be_callable }
|
240
|
+
|
241
|
+
end
|
242
|
+
|
243
|
+
describe ".convert" do
|
244
|
+
|
245
|
+
it "should not modify PyObjects passed to it" do
|
246
|
+
args = AnArray.map { |x| described_class.new(x) }
|
247
|
+
described_class.convert(*args).should == args
|
248
|
+
end
|
249
|
+
|
250
|
+
it "should pull PyObjects out of RubyPyProxy instances" do
|
251
|
+
args = @objects.an_array.to_a
|
252
|
+
described_class.convert(*args).should == args.map {|x| x.pObject}
|
253
|
+
end
|
254
|
+
|
255
|
+
it "should create new PyObject instances of simple Ruby types" do
|
256
|
+
described_class.convert(*AnArray).each do |x|
|
257
|
+
x.should be_a_kind_of described_class
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
end
|
262
|
+
|
263
|
+
end
|
264
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
|
3
|
+
def identity(object):
|
4
|
+
return object
|
5
|
+
|
6
|
+
class RubyPythonMockObject:
|
7
|
+
STRING = "STRING"
|
8
|
+
STRING_LIST = ["STRING1", "STRING2"]
|
9
|
+
INT = 1
|
10
|
+
INT_LIST = [1,1]
|
11
|
+
FLOAT = 1.0
|
12
|
+
FLOAT_LIST = [1.0,1.0]
|
13
|
+
|
14
|
+
def square_elements(self, aList):
|
15
|
+
return [x**2 for x in aList]
|
16
|
+
|
17
|
+
def sum_elements(self, aList):
|
18
|
+
return sum(aList)
|
19
|
+
|
20
|
+
def __eq__(self, other):
|
21
|
+
if type(self) == type(other):
|
22
|
+
return True
|
23
|
+
else:
|
24
|
+
return False
|
25
|
+
|
26
|
+
class NewStyleClass(object):
|
27
|
+
def a_method(self):
|
28
|
+
pass
|
29
|
+
|
30
|
+
an_int = 1
|
31
|
+
a_char = 'a'
|
32
|
+
a_float = 1.0
|
33
|
+
a_symbol = 'sym'
|
34
|
+
a_string = "STRING"
|
35
|
+
an_array = a_list = [an_int, a_char, a_float, a_string]
|
36
|
+
a_hash = a_dict = { an_int: an_int, a_char: a_char, a_symbol: a_float, a_string:
|
37
|
+
a_string}
|
38
|
+
true = python_True = True
|
39
|
+
false = python_False = False
|
40
|
+
nil = python_None = None
|
41
|
+
a_tuple = tuple(a_list)
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe RubyPython::PythonError do
|
4
|
+
include RubyPythonStartStop
|
5
|
+
|
6
|
+
def cause_error
|
7
|
+
RubyPython::Python.PyImport_ImportModule("wat")
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#error?" do
|
11
|
+
it "should return false when no error has occured" do
|
12
|
+
described_class.error?.should be_false
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should return true when an error has occured" do
|
16
|
+
cause_error
|
17
|
+
described_class.error?.should be_true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#clear" do
|
22
|
+
it "should reset the Python error flag" do
|
23
|
+
cause_error
|
24
|
+
described_class.clear
|
25
|
+
described_class.error?.should be_false
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should not barf when there is no error" do
|
29
|
+
lambda {described_class.clear}.should_not raise_exception
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
describe "#fetch" do
|
35
|
+
it "should make availible Python error type" do
|
36
|
+
cause_error
|
37
|
+
rbType, rbValue, rbTraceback = described_class.fetch
|
38
|
+
rbType.getAttr("__name__").rubify.should == "ImportError"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|