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.
Files changed (51) hide show
  1. data/.autotest +3 -0
  2. data/.gemtest +0 -0
  3. data/.gitignore +13 -0
  4. data/.hgignore +14 -0
  5. data/.hgtags +7 -0
  6. data/.rspec +1 -1
  7. data/Contributors.rdoc +9 -0
  8. data/History.rdoc +148 -0
  9. data/{License.txt → License.rdoc} +7 -1
  10. data/Manifest.txt +15 -10
  11. data/PostInstall.txt +11 -4
  12. data/README.rdoc +272 -0
  13. data/Rakefile +107 -22
  14. data/autotest/discover.rb +1 -0
  15. data/lib/rubypython.rb +214 -120
  16. data/lib/rubypython/blankobject.rb +16 -14
  17. data/lib/rubypython/conversion.rb +242 -173
  18. data/lib/rubypython/legacy.rb +30 -31
  19. data/lib/rubypython/macros.rb +43 -34
  20. data/lib/rubypython/operators.rb +103 -101
  21. data/lib/rubypython/options.rb +41 -44
  22. data/lib/rubypython/pygenerator.rb +61 -0
  23. data/lib/rubypython/pymainclass.rb +46 -29
  24. data/lib/rubypython/pyobject.rb +193 -177
  25. data/lib/rubypython/python.rb +189 -176
  26. data/lib/rubypython/pythonerror.rb +54 -63
  27. data/lib/rubypython/pythonexec.rb +123 -0
  28. data/lib/rubypython/rubypyproxy.rb +213 -137
  29. data/lib/rubypython/type.rb +20 -0
  30. data/spec/basic_spec.rb +50 -0
  31. data/spec/callback_spec.rb +7 -17
  32. data/spec/conversion_spec.rb +7 -21
  33. data/spec/legacy_spec.rb +1 -16
  34. data/spec/pymainclass_spec.rb +6 -15
  35. data/spec/pyobject_spec.rb +39 -64
  36. data/spec/python_helpers/basics.py +20 -0
  37. data/spec/python_helpers/objects.py +24 -20
  38. data/spec/pythonerror_spec.rb +5 -17
  39. data/spec/refcnt_spec.rb +4 -10
  40. data/spec/rubypyclass_spec.rb +1 -11
  41. data/spec/rubypyproxy_spec.rb +45 -54
  42. data/spec/rubypython_spec.rb +45 -57
  43. data/spec/spec_helper.rb +49 -33
  44. metadata +87 -63
  45. data.tar.gz.sig +0 -0
  46. data/History.markdown +0 -97
  47. data/README.markdown +0 -105
  48. data/lib/rubypython/core_ext/string.rb +0 -7
  49. data/lib/rubypython/version.rb +0 -9
  50. data/spec/python_helpers/objects.pyc +0 -0
  51. metadata.gz.sig +0 -0
@@ -0,0 +1,20 @@
1
+ module RubyPython
2
+ # Creates a Ruby class that inherits from a proxied Python object.
3
+ def self.Type(name)
4
+ mod, match, klass = name.rpartition(".")
5
+ pymod = RubyPython.import(mod)
6
+ pyclass = pymod.pObject.getAttr(klass)
7
+ rclass = Class.new(RubyPyProxy) do
8
+ define_method(:initialize) do |*args|
9
+ args = PyObject.convert(*args)
10
+ pTuple = PyObject.buildArgTuple(*args)
11
+ pReturn = pyclass.callObject(pTuple)
12
+ if PythonError.error?
13
+ raise PythonError.handle_error
14
+ end
15
+ @pObject = pReturn
16
+ end
17
+ end
18
+ return rclass
19
+ end
20
+ end
@@ -0,0 +1,50 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ include TestConstants
4
+
5
+ describe "RubyPython" do
6
+ it "can import and use a native extension like cPickle" do
7
+ cPickle = RubyPython.import("cPickle")
8
+ string = cPickle.dumps("Testing RubyPython.")
9
+ string.should_not be_a_kind_of String
10
+ string.rubify.should be_a_kind_of String
11
+ string.rubify.should == "S'Testing RubyPython.'\np1\n."
12
+ end
13
+
14
+ it "can import and use a pure Python extension like pickle" do
15
+ pickle = RubyPython.import("pickle")
16
+ string = pickle.dumps("Testing RubyPython.")
17
+ string.should_not be_a_kind_of String
18
+ string.rubify.should be_a_kind_of String
19
+ string.rubify.should == "S'Testing RubyPython.'\np0\n."
20
+ end
21
+
22
+ it "can use iterators from Python" do
23
+ items = []
24
+ @basics.iterate_list.to_enum.each { |item| items << item }
25
+ items.should == [ 1, 2, 3 ]
26
+ end
27
+
28
+ it "can use Ruby procs as callbacks to Python code" do
29
+ @basics.simple_callback(lambda { |v| v * v }, 4).should == 16
30
+ end
31
+
32
+ it "can use Ruby methods as callbacks to Python code" do
33
+ def triple(v)
34
+ v * 3
35
+ end
36
+ @basics.simple_callback(method(:triple), 4).should == 12
37
+ end
38
+
39
+ it "can feed a Python generator in Ruby 1.9", :ruby_version => '1.9' do
40
+ output = @basics.simple_generator(RubyPython.generator do
41
+ (1..10).each { |i| RubyPython.yield i }
42
+ end)
43
+ output.should == [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
44
+ end
45
+
46
+ it "can use named parameters to functions" do
47
+ @basics.named_args(2, 1).should == [ 2, 1 ]
48
+ @basics.named_args!(:arg2 => 2, :arg1 => 1).should == [ 1, 2 ]
49
+ end
50
+ end
@@ -1,23 +1,12 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper.rb'
2
2
 
3
- describe 'Callbacks' do
4
- include TestConstants
5
-
6
- before do
7
- RubyPython.start
8
- @sys = RubyPython.import 'sys'
9
- @sys.path.append './spec/python_helpers'
10
- @objects = RubyPython.import 'objects'
11
- end
12
-
13
- after do
14
- RubyPython.start
15
- end
3
+ include TestConstants
16
4
 
17
- [
18
- [ 'procs', AProc ],
19
- [ 'methods', AMethod]
20
- ].each do |rb_type, rb_object|
5
+ describe 'Callbacks' do
6
+ {
7
+ 'procs' => AProc,
8
+ 'methods' => AMethod,
9
+ }.each do |rb_type, rb_object|
21
10
  it "accepts #{rb_type} as functions" do
22
11
  [
23
12
  [2, 2],
@@ -33,6 +22,7 @@ describe 'Callbacks' do
33
22
  ["an int", AnInt],
34
23
  ["a float", AFloat],
35
24
  ["a string", AString],
25
+ ["a string with nulls", AStringWithNULLs],
36
26
  ["an array", AnArray],
37
27
  ["an array", AnArray],
38
28
  ["a hash", AConvertedHash],
@@ -1,26 +1,16 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper.rb'
2
2
 
3
3
  include TestConstants
4
- describe RubyPython::Conversion do
5
4
 
5
+ describe RubyPython::Conversion do
6
6
  subject { RubyPython::Conversion }
7
7
 
8
- before do
9
- RubyPython.start
10
- sys = RubyPython.import 'sys'
11
- sys.path.append './spec/python_helpers'
12
- @objects = RubyPython.import 'objects'
13
- end
14
-
15
- after do
16
- RubyPython.stop
17
- end
18
-
19
8
  context "when converting from Python to Ruby" do
20
9
  [
21
10
  ["an int", "an int", AnInt],
22
11
  ["a float", "a float", AFloat],
23
12
  ["a string", "a string", AString],
13
+ ["a string_with_nulls", "a string_with_nulls", AStringWithNULLs],
24
14
  ["a list", "an array", AnArray],
25
15
  ["a tuple", "an array", AnArray],
26
16
  ["a dict", "a hash", AConvertedHash],
@@ -28,24 +18,24 @@ describe RubyPython::Conversion do
28
18
  ["python False", "false", false],
29
19
  ["python None", "nil", nil]
30
20
  ].each do |py_type, rb_type, output|
31
- it "converts #{py_type} to #{rb_type}" do
21
+ it "should convert #{py_type} to #{rb_type}" do
32
22
  py_object_ptr = @objects.__send__(py_type.sub(' ', '_')).pObject.pointer
33
23
  subject.ptorObject(py_object_ptr).should == output
34
24
  end
35
25
  end
36
26
 
37
- it "returns an FFI::Pointer when it cannot convert" do
27
+ it "should return an FFI::Pointer when it cannot convert" do
38
28
  unconvertable = @objects.RubyPythonMockObject.pObject.pointer
39
29
  subject.ptorObject(unconvertable).should be_a_kind_of(FFI::Pointer)
40
30
  end
41
31
  end
42
32
 
43
-
44
33
  context "when converting Ruby to Python" do
45
34
  [
46
35
  ["an int", "an int", AnInt],
47
36
  ["a float", "a float", AFloat],
48
37
  ["a string", "a string", AString],
38
+ ["a string_with_nulls", "a string_with_nulls", AStringWithNULLs],
49
39
  ["a string", "a symbol", ASym],
50
40
  ["a list", "an array", AnArray],
51
41
  ["a dict", "a hash", AConvertedHash],
@@ -54,8 +44,7 @@ describe RubyPython::Conversion do
54
44
  ["python None", "nil", nil],
55
45
  ["a function", "a proc", AProc, true]
56
46
  ].each do |py_type, rb_type, input, no_compare|
57
-
58
- it "converts #{rb_type} to #{py_type}" do
47
+ it "should convert #{rb_type} to #{py_type}" do
59
48
  py_object_ptr = subject.rtopObject(input)
60
49
  unless no_compare
61
50
  output = @objects.__send__(rb_type.sub(' ', '_')).pObject.pointer
@@ -64,11 +53,8 @@ describe RubyPython::Conversion do
64
53
  end
65
54
  end
66
55
 
67
- it "raises an exception when it cannot convert" do
56
+ it "should raise an exception when it cannot convert" do
68
57
  lambda { subject.rtopObject(Class) }.should raise_exception(subject::UnsupportedConversion)
69
58
  end
70
-
71
59
  end
72
-
73
-
74
60
  end
data/spec/legacy_spec.rb CHANGED
@@ -3,20 +3,6 @@ require File.dirname(__FILE__) + '/spec_helper.rb'
3
3
  include TestConstants
4
4
 
5
5
  describe 'RubyPython Legacy Mode Module' do
6
-
7
- before do
8
- RubyPython.start
9
- sys = RubyPython.import 'sys'
10
- path = sys.path
11
- path.push './spec/python_helpers'
12
- sys.path = path
13
- @objects = RubyPython.import 'objects'
14
- end
15
-
16
- after do
17
- RubyPython.stop
18
- end
19
-
20
6
  before :all do
21
7
  require 'rubypython/legacy'
22
8
  end
@@ -26,7 +12,7 @@ describe 'RubyPython Legacy Mode Module' do
26
12
  end
27
13
 
28
14
  describe "when required" do
29
- it "enables legacy mode" do
15
+ it "should enable legacy mode" do
30
16
  RubyPython.legacy_mode.should == true
31
17
  end
32
18
 
@@ -57,5 +43,4 @@ describe 'RubyPython Legacy Mode Module' do
57
43
  end
58
44
  end
59
45
  end
60
-
61
46
  end
@@ -1,33 +1,24 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper.rb'
2
2
 
3
- describe RubyPython::PyMainClass do
4
- include TestConstants
5
-
6
- before do
7
- RubyPython.start
8
- end
9
-
10
- after do
11
- RubyPython.stop
12
- end
3
+ include TestConstants
13
4
 
5
+ describe RubyPython::PyMainClass do
14
6
  subject { RubyPython::PyMain }
15
7
 
16
- it "delegates to builtins" do
8
+ it "should delegate to builtins" do
17
9
  subject.float(AnInt).rubify.should == AnInt.to_f
18
10
  end
19
11
 
20
- it "handles block syntax" do
12
+ it "should handle block syntax" do
21
13
  subject.float(AnInt) {|f| f.rubify*2}.should == (AnInt.to_f * 2)
22
14
  end
23
15
 
24
- it "allows attribute access" do
16
+ it "should allow attribute access" do
25
17
  subject.main.__name__.rubify.should == '__main__'
26
18
  end
27
19
 
28
- it "allows global variable modification" do
20
+ it "should allow global variable setting" do
29
21
  subject.x = 2
30
22
  subject.x.rubify.should == 2
31
23
  end
32
-
33
24
  end
@@ -1,16 +1,8 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper.rb'
2
2
 
3
- describe RubyPython::PyObject do
4
- include TestConstants
5
-
6
- before do
7
- RubyPython.start
8
- end
9
-
10
- after do
11
- RubyPython.start
12
- end
3
+ include TestConstants
13
4
 
5
+ describe RubyPython::PyObject do
14
6
  before do
15
7
  @string = RubyPython.import('string').pObject
16
8
  @urllib2 = RubyPython.import('urllib2').pObject
@@ -29,8 +21,7 @@ describe RubyPython::PyObject do
29
21
  ["a symbol", ASym],
30
22
  ["a hash", AHash]
31
23
  ].each do |title, obj|
32
-
33
- it "wraps #{title}" do
24
+ it "should wrap #{title}" do
34
25
  lambda { described_class.new(obj) }.should_not raise_exception
35
26
  end
36
27
  end
@@ -41,20 +32,17 @@ describe RubyPython::PyObject do
41
32
  "a list",
42
33
  "a dict",
43
34
  "a tuple"
44
- ].each do |type|
45
- it "accepts a Python pointer to a #{type}" do
35
+ ].each do |title|
36
+ it "should take #{title} from a Python pointer" do
46
37
  lambda do
47
- py_obj = @objects.__send__(type.gsub(' ','_')).pObject.pointer
38
+ py_obj = @objects.__send__(title.gsub(' ','_')).pObject.pointer
48
39
  described_class.new(py_obj)
49
40
  end.should_not raise_exception
50
41
  end
51
42
  end
52
-
53
-
54
43
  end #new
55
44
 
56
45
  describe "#rubify" do
57
-
58
46
  [
59
47
  ["a string", AString],
60
48
  ["an int", AnInt],
@@ -66,44 +54,42 @@ describe RubyPython::PyObject do
66
54
  type, input, output = arr
67
55
  output ||= input
68
56
 
69
- it "faithfully unwraps #{type}" do
57
+ it "should faithfully unwrap #{type}" do
70
58
  described_class.new(input).rubify.should == output
71
59
  end
72
-
73
60
  end
74
-
75
61
  end #rubify
76
62
 
77
63
  describe "#hasAttr" do
78
- it "is true when wrapped object has the requested attribute" do
64
+ it "should return true when object has the requested attribute" do
79
65
  @string.hasAttr("ascii_letters").should be_true
80
66
  end
81
67
 
82
- it "is false when wrapped object does not have the requested attribute" do
68
+ it "should return false when object does not have the requested attribute" do
83
69
  @string.hasAttr("nonExistentThing").should be_false
84
70
  end
85
71
  end
86
72
 
87
73
  describe "#getAttr" do
88
- it "fetchs a pointer to the requested object attribute" do
74
+ it "should fetch requested object attribute" do
89
75
  ascii_letters = @string.getAttr "ascii_letters"
90
76
  ascii_letters.rubify.should == "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
91
77
  end
92
78
 
93
- it "returns a PyObject instance" do
79
+ it "should return a PyObject instance" do
94
80
  ascii_letters = @string.getAttr "ascii_letters"
95
81
  ascii_letters.should be_kind_of(described_class)
96
82
  end
97
83
  end
98
84
 
99
85
  describe "#setAttr" do
100
- it "modifies the specified attribute of the object" do
86
+ it "should modify the specified attribute of the object" do
101
87
  pyNewLetters = described_class.new "RbPy"
102
88
  @string.setAttr "ascii_letters", pyNewLetters
103
89
  @string.getAttr("ascii_letters").rubify.should == pyNewLetters.rubify
104
90
  end
105
91
 
106
- it "creates the requested attribute if it doesn't exist" do
92
+ it "should create the requested attribute if it doesn't exist" do
107
93
  pyNewString = described_class.new "python"
108
94
  @string.setAttr "ruby", pyNewString
109
95
  @string.getAttr("ruby").rubify.should == pyNewString.rubify
@@ -111,53 +97,51 @@ describe RubyPython::PyObject do
111
97
  end
112
98
 
113
99
  describe "#cmp" do
114
-
115
100
  before do
116
101
  @less = described_class.new 5
117
102
  @greater = described_class.new 10
118
103
  @less_dup = described_class.new 5
119
104
  end
120
105
 
121
- it "returns 0 when objects are equal" do
106
+ it "should return 0 when objects are equal" do
122
107
  @less.cmp(@less_dup).should == 0
123
108
  end
124
109
 
125
- it "changes sign under interchange of arguments" do
110
+ it "should change sign under interchange of arguments" do
126
111
  @less.cmp(@greater).should == -@greater.cmp(@less)
127
112
  end
128
113
 
129
- it "returns -1 when first object is less than the second" do
114
+ it "should return -1 when first object is less than the second" do
130
115
  @less.cmp(@greater).should == -1
131
116
  end
132
-
133
- it "returns 1 when first object is greater than the second" do
117
+
118
+ it "should return 1 when first object is greater than the second" do
134
119
  @greater.cmp(@less).should == 1
135
120
  end
136
121
  end
137
122
 
138
123
  describe "#makeTuple" do
139
- it "wraps single arguments in a tuple" do
124
+ it "should wrap single arguments in a tuple" do
140
125
  arg = described_class.new AString
141
126
  described_class.makeTuple(arg).rubify.should == [AString]
142
127
  end
143
128
 
144
- it "turns a Python list into a tuple" do
129
+ it "should turn a Python list into a tuple" do
145
130
  arg = @objects.a_list.pObject
146
131
  converted = described_class.makeTuple(arg)
147
132
  converted.rubify.should == AnArray
148
133
  end
149
134
 
150
- it "returns the given argument if it is a tuple" do
135
+ it "should return the given argument if it is a tuple" do
151
136
  arg = @objects.a_tuple.pObject
152
137
  converted = described_class.makeTuple(arg)
153
138
  converted.pointer.address.should == arg.pointer.address
154
139
  end
155
-
156
140
  end
157
141
 
158
142
  describe "#callObject" do
159
143
  #Expand coverage types
160
- it "executes wrapped object with supplied arguments" do
144
+ it "should execute wrapped object with supplied arguments" do
161
145
  arg = described_class.new AnInt
162
146
  argt = described_class.buildArgTuple arg
163
147
 
@@ -168,7 +152,7 @@ describe RubyPython::PyObject do
168
152
  end
169
153
 
170
154
  describe "#newList" do
171
- it "wraps supplied args in a Python list" do
155
+ it "should wrap supplied args in a Python list" do
172
156
  args = AnArray.map do |obj|
173
157
  described_class.new obj
174
158
  end
@@ -177,69 +161,64 @@ describe RubyPython::PyObject do
177
161
  end
178
162
 
179
163
  describe "#function_or_method?" do
180
-
181
- it "is true for a method" do
164
+ it "should be true given a method" do
182
165
  mockObjClass = @objects.RubyPythonMockObject.pObject
183
166
  mockObjClass.getAttr('square_elements').should be_a_function_or_method
184
167
  end
185
168
 
186
- it "is true for a function" do
169
+ it "should be true given a function" do
187
170
  @objects.pObject.getAttr('identity').should be_a_function_or_method
188
171
  end
189
172
 
190
- it "is true for a builtin function" do
173
+ it "should return true given a builtin function" do
191
174
  any = @builtin.pObject.getAttr('any')
192
175
  any.should be_a_function_or_method
193
176
  end
194
177
 
195
- it "is false for a class" do
178
+ it "should return false given a class" do
196
179
  @objects.RubyPythonMockObject.pObject.should_not be_a_function_or_method
197
180
  end
198
-
199
181
  end
200
182
 
201
183
  describe "#class?" do
202
-
203
- it "is true if wrapped object is an old style class" do
184
+ it "should return true if wrapped object is an old style class" do
204
185
  @objects.RubyPythonMockObject.pObject.should be_a_class
205
186
  end
206
187
 
207
- it "is true if wrapped object is an new style class" do
188
+ it "should return true if wrapped object is an new style class" do
208
189
  @objects.NewStyleClass.pObject.should be_a_class
209
190
  end
210
191
 
211
- it "is true if wrapped object is a builtin class" do
192
+ it "should return true if wrapped object is a builtin class" do
212
193
  strClass = @builtin.pObject.getAttr('str')
213
194
  strClass.should be_a_class
214
195
  end
215
196
 
216
- it "is false for an object instance" do
197
+ it "should return false given an object instance" do
217
198
  @objects.RubyPythonMockObject.new.pObject.should_not be_a_class
218
199
  end
219
-
220
200
  end
221
201
 
222
202
  describe "#callable?" do
223
-
224
- it "is true for a method" do
203
+ it "should be true given a method" do
225
204
  mockObjClass = @objects.RubyPythonMockObject.pObject
226
205
  mockObjClass.getAttr('square_elements').should be_callable
227
206
  end
228
207
 
229
- it "is true for a function" do
208
+ it "should be true given a function" do
230
209
  @objects.pObject.getAttr('identity').should be_callable
231
210
  end
232
211
 
233
- it "is true for a builtin function" do
212
+ it "should return true given a builtin function" do
234
213
  any = @builtin.pObject.getAttr('any')
235
214
  any.should be_callable
236
215
  end
237
216
 
238
- it "is true for a class" do
217
+ it "should return true given a class" do
239
218
  @objects.RubyPythonMockObject.pObject.should be_callable
240
219
  end
241
220
 
242
- it "is false for a non-callable instance" do
221
+ it "should return false given a non-callable instance" do
243
222
  @objects.RubyPythonMockObject.new.pObject.should_not be_callable
244
223
  end
245
224
 
@@ -248,24 +227,20 @@ describe RubyPython::PyObject do
248
227
  end
249
228
 
250
229
  describe ".convert" do
251
-
252
- it "does not modify PyObjects passed to it" do
230
+ it "should not modify PyObjects passed to it" do
253
231
  args = AnArray.map { |x| described_class.new(x) }
254
232
  described_class.convert(*args).should == args
255
233
  end
256
234
 
257
- it "pulls PyObjects out of RubyPyProxy instances" do
235
+ it "should pull PyObjects out of RubyPyProxy instances" do
258
236
  args = @objects.an_array.to_a
259
237
  described_class.convert(*args).should == args.map {|x| x.pObject}
260
238
  end
261
239
 
262
- it "creates new PyObject instances of simple Ruby types" do
240
+ it "should create new PyObject instances of simple Ruby types" do
263
241
  described_class.convert(*AnArray).each do |x|
264
242
  x.should be_a_kind_of described_class
265
243
  end
266
244
  end
267
-
268
245
  end
269
-
270
246
  end
271
-