lokeshh_rubypython 0.7
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.
- checksums.yaml +7 -0
- data/.autotest +3 -0
- data/.gitignore +18 -0
- data/.hgignore +20 -0
- data/.hgtags +12 -0
- data/.rspec +2 -0
- data/Contributors.rdoc +11 -0
- data/History.rdoc +214 -0
- data/License.rdoc +26 -0
- data/Manifest.txt +46 -0
- data/PostInstall.txt +16 -0
- data/README.rdoc +272 -0
- data/Rakefile +118 -0
- data/autotest/discover.rb +1 -0
- data/lib/rubypython/blankobject.rb +23 -0
- data/lib/rubypython/conversion.rb +332 -0
- data/lib/rubypython/interpreter.rb +262 -0
- data/lib/rubypython/macros.rb +56 -0
- data/lib/rubypython/operators.rb +120 -0
- data/lib/rubypython/pygenerator.rb +61 -0
- data/lib/rubypython/pymainclass.rb +80 -0
- data/lib/rubypython/pyobject.rb +189 -0
- data/lib/rubypython/python.rb +199 -0
- data/lib/rubypython/pythonerror.rb +80 -0
- data/lib/rubypython/rubypyproxy.rb +328 -0
- data/lib/rubypython/tuple.rb +10 -0
- data/lib/rubypython/type.rb +20 -0
- data/lib/rubypython.rb +229 -0
- data/spec/basic_spec.rb +50 -0
- data/spec/callback_spec.rb +53 -0
- data/spec/conversion_spec.rb +68 -0
- data/spec/pymainclass_spec.rb +24 -0
- data/spec/pyobject_spec.rb +202 -0
- data/spec/python_helpers/basics.py +23 -0
- data/spec/python_helpers/errors.py +2 -0
- data/spec/python_helpers/objects.py +48 -0
- data/spec/pythonerror_spec.rb +52 -0
- data/spec/refcnt_spec.rb +98 -0
- data/spec/rubypyclass_spec.rb +10 -0
- data/spec/rubypyproxy_spec.rb +261 -0
- data/spec/rubypython_spec.rb +59 -0
- data/spec/spec_helper.rb +71 -0
- data/website/index.rhtml +36 -0
- data/website/robots.txt +5 -0
- data/website/stylesheets/960.css +549 -0
- data/website/stylesheets/border-radius.htc +143 -0
- data/website/stylesheets/screen.css +132 -0
- metadata +297 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
include TestConstants
|
|
4
|
+
describe RubyPython::RubyPyProxy do
|
|
5
|
+
before do
|
|
6
|
+
@a = RubyPython::PyObject.new "a"
|
|
7
|
+
@b = RubyPython::PyObject.new "b"
|
|
8
|
+
@builtin = RubyPython.import("__builtin__").pObject
|
|
9
|
+
@string = RubyPython.import("string").pObject
|
|
10
|
+
|
|
11
|
+
@two = described_class.new 2
|
|
12
|
+
@six = described_class.new 6
|
|
13
|
+
|
|
14
|
+
@sys = RubyPython.import 'sys'
|
|
15
|
+
@sys.path.append './spec/python_helpers'
|
|
16
|
+
@objects = RubyPython.import 'objects'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe "#new" do
|
|
20
|
+
it "should accept a PyObject instance" do
|
|
21
|
+
rbPyObject = RubyPython::PyObject.new AString
|
|
22
|
+
lambda {described_class.new rbPyObject}.should_not raise_exception
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
[
|
|
26
|
+
["a string", AString],
|
|
27
|
+
["an int", AnInt],
|
|
28
|
+
["a float", AFloat],
|
|
29
|
+
["an array", AnArray],
|
|
30
|
+
["a symbol", ASym, ASym.to_s],
|
|
31
|
+
["a hash", AHash, AConvertedHash]
|
|
32
|
+
].each do |arr|
|
|
33
|
+
type, input, output = arr
|
|
34
|
+
output ||= input
|
|
35
|
+
|
|
36
|
+
it "should convert #{type} to wrapped pObject" do
|
|
37
|
+
described_class.new(input).pObject.rubify.should == output
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe "#rubify" do
|
|
43
|
+
[
|
|
44
|
+
["a string", AString],
|
|
45
|
+
["an int", AnInt],
|
|
46
|
+
["a float", AFloat],
|
|
47
|
+
["an array", AnArray],
|
|
48
|
+
["a symbol", ASym],
|
|
49
|
+
["a hash", AHash]
|
|
50
|
+
].each do |title, obj|
|
|
51
|
+
it "should faithfully unwrap #{title}" do
|
|
52
|
+
pyObject = RubyPython::PyObject.new obj
|
|
53
|
+
proxy = described_class.new pyObject
|
|
54
|
+
proxy.rubify.should == pyObject.rubify
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
describe "#inspect" do
|
|
60
|
+
it "should return 'repr' of wrapped object" do
|
|
61
|
+
@six.inspect.should == '6'
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "should gracefully handle lack of defined __repr__" do
|
|
65
|
+
lambda { @objects.RubyPythonMockObject.inspect }.should_not raise_exception
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "always tries the 'repr' function if __repr__ produces an error" do
|
|
69
|
+
RubyPython::PyMain.list.inspect.should == run_python_command('print repr(list)').chomp
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
describe "#to_s" do
|
|
74
|
+
it "should return 'str' of wrapped object" do
|
|
75
|
+
@six.to_s.should == '6'
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "should gracefully handle lack of defined __str__" do
|
|
79
|
+
lambda { @objects.RubyPythonMockObject.to_s }.should_not raise_exception
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it "always tries the 'str' function if __repr__ produces an error" do
|
|
83
|
+
RubyPython::PyMain.list.to_s.should == run_python_command('print str(list)').chomp
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
describe "#to_a" do
|
|
88
|
+
it "should convert a list to an array of its entries" do
|
|
89
|
+
list = @objects.a_list
|
|
90
|
+
list.to_a.should == AnArray.map { |x| described_class.new(x) }
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "should convert a tuple to an array of its entries" do
|
|
94
|
+
tuple = @objects.a_tuple
|
|
95
|
+
tuple.to_a.should == AnArray.map { |x| described_class.new(x) }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "should convert a dict to an array of keys" do
|
|
99
|
+
dict = @objects.a_dict
|
|
100
|
+
dict.to_a.sort.should == AConvertedHash.keys.map {|x| described_class.new(x)}.sort
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
describe "#respond_to?" do
|
|
105
|
+
it "should return true given getters" do
|
|
106
|
+
@objects.should respond_to(:RubyPythonMockObject)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "should return false given undefined methods" do
|
|
110
|
+
@objects.should_not respond_to(:undefined_attr)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "should return true given any setter" do
|
|
114
|
+
@objects.should respond_to(:any_variable=)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "should return true given methods on RubyPyProxy instance" do
|
|
118
|
+
@objects.should respond_to(:inspect)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
describe "method delegation" do
|
|
123
|
+
it "should refer method calls to wrapped object" do
|
|
124
|
+
aProxy = described_class.new(@a)
|
|
125
|
+
bProxy = described_class.new(@b)
|
|
126
|
+
aProxy.__add__(bProxy).rubify.should == (@a.rubify + @b.rubify)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it "should raise NoMethodError when method is undefined" do
|
|
130
|
+
aProxy = described_class.new @a
|
|
131
|
+
lambda {aProxy.wat}.should raise_exception(NoMethodError)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it "raises NoMethodError when boolean method is undefined" do
|
|
135
|
+
aProxy = described_class.new @a
|
|
136
|
+
lambda { aProxy.wat? }.should raise_exception(NoMethodError)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it "should allow methods to be called with no arguments" do
|
|
140
|
+
builtinProxy = described_class.new @builtin
|
|
141
|
+
rbStrClass = builtinProxy.str
|
|
142
|
+
rbStrClass.new.rubify.should == String.new
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it "should fetch attributes when method name is an attribute" do
|
|
146
|
+
pyLetters = @string.getAttr "ascii_letters"
|
|
147
|
+
stringProxy = described_class.new @string
|
|
148
|
+
stringProxy.ascii_letters.rubify.should == pyLetters.rubify
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
it "should set attribute if method call is a setter" do
|
|
152
|
+
stringProxy = described_class.new @string
|
|
153
|
+
stringProxy.letters = AString
|
|
154
|
+
stringProxy.letters.rubify.should == AString
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
it "should create nonexistent attirubte if method call is a setter" do
|
|
158
|
+
stringProxy = described_class.new @string
|
|
159
|
+
stringProxy.nonExistent = 1
|
|
160
|
+
stringProxy.nonExistent.rubify.should == 1
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
it "should return a class as a RubyPyClass" do
|
|
164
|
+
urllib2 = RubyPython.import('urllib2')
|
|
165
|
+
urllib2.Request.should be_a(RubyPython::RubyPyClass)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
it "should pass named args via bang method" do
|
|
169
|
+
@objects.named_args!(:arg2 => 2, :arg1 => 1).rubify.should == [4,2]
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it "should pass through keyword arguments via bang method" do
|
|
173
|
+
builtinProxy = described_class.new @builtin
|
|
174
|
+
builtinProxy.dict!({'dict'=>'val'}, :keyword=>true).rubify.should == {
|
|
175
|
+
'dict' => 'val',
|
|
176
|
+
'keyword' => true
|
|
177
|
+
}
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
describe "when used with an operator" do
|
|
182
|
+
[
|
|
183
|
+
'+', '-', '/', '*', '&', '^', '%', '**',
|
|
184
|
+
'>>', '<<', '<=>', '|'
|
|
185
|
+
].each do |op|
|
|
186
|
+
it "should delegate #{op}" do
|
|
187
|
+
@six.__send__(op, @two).rubify.should == 6.__send__(op, 2)
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
[
|
|
192
|
+
'~', '-@', '+@'
|
|
193
|
+
].each do |op|
|
|
194
|
+
it "should delegate #{op}" do
|
|
195
|
+
@six.__send__(op).rubify.should == 6.__send__(op)
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
['==', '<', '>', '<=', '>='].each do |op|
|
|
200
|
+
it "should delegate #{op}" do
|
|
201
|
+
@six.__send__(op, @two).should == 6.__send__(op, 2)
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
describe "#equal?" do
|
|
206
|
+
it "be true given proxies representing the same object" do
|
|
207
|
+
obj1 = @objects.RubyPythonMockObject
|
|
208
|
+
obj2 = @objects.RubyPythonMockObject
|
|
209
|
+
obj1.should equal(obj2)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
it "should be false given objects which are different" do
|
|
213
|
+
@two.should_not equal(@six)
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
it "should allow list indexing" do
|
|
218
|
+
array = described_class.new(AnArray)
|
|
219
|
+
array[1].rubify.should == AnArray[1]
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
it "should allow dict access" do
|
|
223
|
+
dict = described_class.new(AHash)
|
|
224
|
+
key = AConvertedHash.keys[0]
|
|
225
|
+
dict[key].rubify.should == AConvertedHash[key]
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
it "should allow list index assignment" do
|
|
229
|
+
array = described_class.new(AnArray)
|
|
230
|
+
val = AString*2
|
|
231
|
+
array[1] = val
|
|
232
|
+
array[1].rubify.should == val
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
it "should allow dict value modification" do
|
|
236
|
+
dict = described_class.new(AHash)
|
|
237
|
+
key = AConvertedHash.keys[0]
|
|
238
|
+
val = AString*2
|
|
239
|
+
dict[key] = val
|
|
240
|
+
dict[key].rubify.should == val
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
it "should allow creation of new dict key-val pair" do
|
|
244
|
+
dict = described_class.new(AHash)
|
|
245
|
+
key = AString*2
|
|
246
|
+
dict[key] = AString
|
|
247
|
+
dict[key].rubify.should == AString
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
it "should allow membership tests with include?" do
|
|
251
|
+
list = described_class.new(AnArray)
|
|
252
|
+
list.include?(AnArray[0]).should be_true
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
it "should delegate object equality" do
|
|
257
|
+
urllib_a = RubyPython.import('urllib')
|
|
258
|
+
urllib_b = RubyPython.import('urllib')
|
|
259
|
+
urllib_a.should == urllib_b
|
|
260
|
+
end
|
|
261
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
describe RubyPython do
|
|
4
|
+
describe "#import" do
|
|
5
|
+
it "should handle multiple imports" do
|
|
6
|
+
lambda do
|
|
7
|
+
RubyPython.import 'cPickle'
|
|
8
|
+
RubyPython.import 'urllib'
|
|
9
|
+
end.should_not raise_exception
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "should propagate Python errors" do
|
|
13
|
+
lambda do
|
|
14
|
+
RubyPython.import 'nonExistentModule'
|
|
15
|
+
end.should raise_exception(RubyPython::PythonError)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "should return a RubyPyModule" do
|
|
19
|
+
RubyPython.import('urllib2').should be_a(RubyPython::RubyPyModule)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe RubyPython, :self_start => true do
|
|
25
|
+
|
|
26
|
+
describe "#session" do
|
|
27
|
+
it "should start interpreter" do
|
|
28
|
+
RubyPython.session do
|
|
29
|
+
cPickle = RubyPython.import "cPickle"
|
|
30
|
+
cPickle.loads("(dp1\nS'a'\nS'n'\ns(I1\nS'2'\ntp2\nI4\ns.").rubify.should == {"a"=>"n", [1, "2"]=>4}
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "should stop the interpreter" do
|
|
35
|
+
RubyPython.session do
|
|
36
|
+
cPickle = RubyPython.import "cPickle"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
RubyPython.stop.should be_false
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe "#run" do
|
|
44
|
+
it "should start interpreter" do
|
|
45
|
+
RubyPython.run do
|
|
46
|
+
cPickle = import "cPickle"
|
|
47
|
+
cPickle.loads("(dp1\nS'a'\nS'n'\ns(I1\nS'2'\ntp2\nI4\ns.").rubify.should == {"a"=>"n", [1, "2"]=>4}
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "should stop the interpreter" do
|
|
52
|
+
RubyPython.run do
|
|
53
|
+
cPickle = import "cPickle"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
RubyPython.stop.should be_false
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require 'rspec'
|
|
3
|
+
rescue LoadError
|
|
4
|
+
require 'rubygems' unless ENV['NO_RUBYGEMS']
|
|
5
|
+
require 'rspec'
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
dir = File.dirname(__FILE__)
|
|
9
|
+
|
|
10
|
+
$:.unshift(File.join(dir, '..', 'lib'))
|
|
11
|
+
require 'rubypython'
|
|
12
|
+
|
|
13
|
+
module TestConstants
|
|
14
|
+
AString = "STRING"
|
|
15
|
+
AStringWithNULLs = "STRING\0WITH\0NULLS"
|
|
16
|
+
AnInt = 1
|
|
17
|
+
AChar = 'a'
|
|
18
|
+
AFloat = 1.0
|
|
19
|
+
AnArray = [AnInt, AChar, AFloat, AString]
|
|
20
|
+
ATuple = RubyPython::Tuple.tuple(AnArray)
|
|
21
|
+
# ATuple << AnInt << AChar << AFloat << AString
|
|
22
|
+
ASym = :sym
|
|
23
|
+
AHash = {
|
|
24
|
+
AnInt => AnInt,
|
|
25
|
+
AChar.to_sym => AChar,
|
|
26
|
+
ASym => AFloat,
|
|
27
|
+
AString => AString
|
|
28
|
+
}
|
|
29
|
+
AConvertedHash = Hash[*AHash.map do |k, v|
|
|
30
|
+
key = k.is_a?(Symbol) ? k.to_s : k
|
|
31
|
+
[key, v]
|
|
32
|
+
end.flatten]
|
|
33
|
+
AProc = Proc.new { |a1, a2| a1 + a2 }
|
|
34
|
+
def self.a_method(a1, a2)
|
|
35
|
+
a1 + a2
|
|
36
|
+
end
|
|
37
|
+
AMethod = method(:a_method)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def run_python_command(cmd)
|
|
41
|
+
%x(python -c '#{cmd}').chomp
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
RSpec.configure do |config|
|
|
45
|
+
if RUBY_VERSION < '1.9.2'
|
|
46
|
+
config.filter_run_excluding :ruby_version => '1.9'
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
config.before(:all) do
|
|
50
|
+
class RubyPython::RubyPyProxy
|
|
51
|
+
[:should, :should_not, :class].each { |m| reveal(m) }
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
config.before(:all) do
|
|
56
|
+
RubyPython.start
|
|
57
|
+
|
|
58
|
+
@sys = RubyPython.import 'sys'
|
|
59
|
+
@sys.path.append File.join(dir, 'python_helpers')
|
|
60
|
+
@objects = RubyPython.import 'objects'
|
|
61
|
+
@basics = RubyPython.import 'basics'
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
config.before(:all, :self_start => true) do
|
|
65
|
+
RubyPython.stop
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
config.after(:all) do
|
|
69
|
+
RubyPython.stop
|
|
70
|
+
end
|
|
71
|
+
end
|
data/website/index.rhtml
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
<link rel="stylesheet" href="stylesheets/960.css" type="text/css" media="screen">
|
|
4
|
+
<link rel="stylesheet" href="stylesheets/screen.css" type="text/css" media="screen">
|
|
5
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
6
|
+
<link href='http://fonts.googleapis.com/css?family=Inconsolata' rel='stylesheet' type='text/css'>
|
|
7
|
+
<link href='http://fonts.googleapis.com/css?family=Cabin' rel='stylesheet' type='text/css'>
|
|
8
|
+
<title><%= title %></title>
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<div id="header" class="container_24">
|
|
12
|
+
<h1 id="title" class="grid_16"><%= title %></h1>
|
|
13
|
+
<div id="version" class="grid_4 push_3 clickable teardrop-corners" onclick='document.location="<%= download %>"; return false'>
|
|
14
|
+
<p>Get Version</p>
|
|
15
|
+
<a href="<%= download %>" class="numbers"><%= version %></a>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
<div id="content" class="container_24">
|
|
19
|
+
<div id="toc" class="grid_7 push_16">
|
|
20
|
+
<h1>contents</h1>
|
|
21
|
+
<%= toc %>
|
|
22
|
+
</div>
|
|
23
|
+
<div id="body" class="grid_16 pull_7">
|
|
24
|
+
<%= body %>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
<div id="footer" class="container_24">
|
|
28
|
+
<p class="coda push_18 grid_8">
|
|
29
|
+
<a href="mailto:achatesavc+rubypython@gmail.com">Zach Raines</a>,
|
|
30
|
+
<%= modified %><br>
|
|
31
|
+
Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
|
|
32
|
+
</p>
|
|
33
|
+
</div>
|
|
34
|
+
<!-- insert site tracking codes here, like Google Urchin -->
|
|
35
|
+
</body>
|
|
36
|
+
</html>
|
data/website/robots.txt
ADDED