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.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.autotest +3 -0
  3. data/.gitignore +18 -0
  4. data/.hgignore +20 -0
  5. data/.hgtags +12 -0
  6. data/.rspec +2 -0
  7. data/Contributors.rdoc +11 -0
  8. data/History.rdoc +214 -0
  9. data/License.rdoc +26 -0
  10. data/Manifest.txt +46 -0
  11. data/PostInstall.txt +16 -0
  12. data/README.rdoc +272 -0
  13. data/Rakefile +118 -0
  14. data/autotest/discover.rb +1 -0
  15. data/lib/rubypython/blankobject.rb +23 -0
  16. data/lib/rubypython/conversion.rb +332 -0
  17. data/lib/rubypython/interpreter.rb +262 -0
  18. data/lib/rubypython/macros.rb +56 -0
  19. data/lib/rubypython/operators.rb +120 -0
  20. data/lib/rubypython/pygenerator.rb +61 -0
  21. data/lib/rubypython/pymainclass.rb +80 -0
  22. data/lib/rubypython/pyobject.rb +189 -0
  23. data/lib/rubypython/python.rb +199 -0
  24. data/lib/rubypython/pythonerror.rb +80 -0
  25. data/lib/rubypython/rubypyproxy.rb +328 -0
  26. data/lib/rubypython/tuple.rb +10 -0
  27. data/lib/rubypython/type.rb +20 -0
  28. data/lib/rubypython.rb +229 -0
  29. data/spec/basic_spec.rb +50 -0
  30. data/spec/callback_spec.rb +53 -0
  31. data/spec/conversion_spec.rb +68 -0
  32. data/spec/pymainclass_spec.rb +24 -0
  33. data/spec/pyobject_spec.rb +202 -0
  34. data/spec/python_helpers/basics.py +23 -0
  35. data/spec/python_helpers/errors.py +2 -0
  36. data/spec/python_helpers/objects.py +48 -0
  37. data/spec/pythonerror_spec.rb +52 -0
  38. data/spec/refcnt_spec.rb +98 -0
  39. data/spec/rubypyclass_spec.rb +10 -0
  40. data/spec/rubypyproxy_spec.rb +261 -0
  41. data/spec/rubypython_spec.rb +59 -0
  42. data/spec/spec_helper.rb +71 -0
  43. data/website/index.rhtml +36 -0
  44. data/website/robots.txt +5 -0
  45. data/website/stylesheets/960.css +549 -0
  46. data/website/stylesheets/border-radius.htc +143 -0
  47. data/website/stylesheets/screen.css +132 -0
  48. metadata +297 -0
data/Rakefile ADDED
@@ -0,0 +1,118 @@
1
+ # -*- ruby encoding: utf-8 -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+
6
+ Hoe.plugin :doofus
7
+ Hoe.plugin :gemspec2
8
+ Hoe.plugin :rubyforge unless ENV['CI'] or ENV['TRAVIS']
9
+ Hoe.plugin :git
10
+ Hoe.plugin :hg
11
+ Hoe.plugin :travis
12
+
13
+ Hoe.spec 'rubypython' do
14
+ self.rubyforge_name = self.name
15
+
16
+ developer('Steeve Morin', 'swiuzzz+rubypython@gmail.com')
17
+ developer('Austin Ziegler', 'austin@rubyforge.org')
18
+ developer('Zach Raines', 'raineszm+rubypython@gmail.com')
19
+
20
+ license 'MIT'
21
+
22
+ self.remote_rdoc_dir = 'rdoc'
23
+ self.rsync_args << ' --exclude=statsvn/'
24
+
25
+ self.history_file = 'History.rdoc'
26
+ self.readme_file = 'README.rdoc'
27
+ self.extra_rdoc_files = FileList["*.rdoc"].to_a
28
+
29
+ self.extra_deps << ['ffi', '~> 1.0.7']
30
+ self.extra_deps << ['blankslate', '>= 2.1.2.3']
31
+
32
+ self.extra_dev_deps << ['hoe-doofus', '~> 1.0']
33
+ self.extra_dev_deps << ['hoe-gemspec2', '~> 1.1']
34
+ self.extra_dev_deps << ['hoe-git', '~> 1.5']
35
+ self.extra_dev_deps << ['hoe-hg', '~> 1.0']
36
+ self.extra_dev_deps << ['hoe-rubygems', '~> 1.0']
37
+ self.extra_dev_deps << ['hoe-travis', '~> 1.2']
38
+
39
+ self.extra_dev_deps << ['rspec', '~> 2.0']
40
+ self.extra_dev_deps << ['tilt', '~> 1.0']
41
+
42
+ self.spec_extras[:requirements] = [ "Python, ~> 2.4" ]
43
+ end
44
+
45
+ namespace :website do
46
+ desc "Build the website files."
47
+ task :build => [ "website/index.html" ]
48
+
49
+ deps = FileList["website/**/*"].exclude { |f| File.directory? f }
50
+ deps.include(*%w(Rakefile))
51
+ deps.include(*FileList["*.rdoc"].to_a)
52
+ deps.exclude(*%w(website/index.html website/images/*))
53
+
54
+ file "website/index.html" => deps do |t|
55
+ require 'tilt'
56
+ require 'rubypython'
57
+
58
+ puts "Generating #{t.name}…"
59
+
60
+ # Let's modify the rdoc for presenation purposes.
61
+ body_rdoc = File.read("README.rdoc")
62
+
63
+ contrib = File.read("Contributors.rdoc")
64
+ body_rdoc.gsub!(/^:include: Contributors.rdoc/, contrib)
65
+
66
+ license = File.read("License.rdoc")
67
+ body_rdoc.sub!(/^:include: License.rdoc/, license)
68
+ toc_elements = body_rdoc.scan(/^(=+) (.*)$/)
69
+ toc_elements.map! { |e| [ e[0].count('='), e[1] ] }
70
+ body_rdoc.gsub!(/^(=.*)/) { "#{$1.downcase}" }
71
+ body = Tilt::RDocTemplate.new(nil) { body_rdoc }.render
72
+
73
+ title = nil
74
+ body.gsub!(%r{<h1>(.*)</h1>}) { title = $1; "" }
75
+
76
+ toc_elements = toc_elements.select { |e| e[0].between?(2, 3) }
77
+
78
+ last_level = 0
79
+ toc = ""
80
+
81
+ toc_elements.each do |element|
82
+ level, text = *element
83
+ ltext = text.downcase
84
+ id = text.downcase.gsub(/[^a-z]+/, '-')
85
+
86
+ body.gsub!(%r{<h#{level}>#{ltext}</h#{level}>}) {
87
+ %Q(<h#{level} id="#{id}">#{ltext}</h#{level}>)
88
+ }
89
+
90
+ if last_level != level
91
+ if level > last_level
92
+ toc << "<ol>"
93
+ else
94
+ toc << "</li></ol></li>"
95
+ end
96
+
97
+ last_level = level
98
+ end
99
+
100
+ toc << %Q(<li><a href="##{id}">#{text}</a>)
101
+ end
102
+ toc << "</li></ol>"
103
+
104
+ template = Tilt.new("website/index.rhtml", :trim => "<>%")
105
+ context = {
106
+ :title => title,
107
+ :toc => toc,
108
+ :body => body,
109
+ :download => "http://rubyforge.org/frs/?group_id=6737",
110
+ :version => RubyPython::VERSION,
111
+ :modified => Time.now
112
+ }
113
+ File.open(t.name, "w") { |f| f.write template.render(self, context) } end
114
+ end
115
+
116
+ task "docs" => "website:build"
117
+
118
+ # vim: syntax=ruby
@@ -0,0 +1 @@
1
+ Autotest.add_discovery { "rspec2" }
@@ -0,0 +1,23 @@
1
+ require 'blankslate'
2
+
3
+ # This document is the basis of the RubyPyProxy precisely because it hides
4
+ # the implementation of so many things that should be forwarded on to the
5
+ # Python object. This class is for internal use only.
6
+ #
7
+ # Note that in Ruby 1.9, BasicObject might be a better choice, but there are
8
+ # some decisions made in the rest of the library that make this harder. I
9
+ # don't see a clean way to integrate both Ruby 1.8 and 1.9 support for this.
10
+ class RubyPython::BlankObject < ::BlankSlate #:nodoc:
11
+ class << self
12
+ def hide(name)
13
+ if instance_methods.include?(name) and
14
+ name.to_s !~ /^(__|instance_eval|object_id)/
15
+ @hidden_methods ||= {}
16
+ @hidden_methods[name.to_sym] = instance_method(name)
17
+ undef_method name
18
+ end
19
+ end
20
+ end
21
+
22
+ instance_methods.each { |m| hide(m) }
23
+ end
@@ -0,0 +1,332 @@
1
+ require 'rubypython/python'
2
+ require 'rubypython/macros'
3
+ require 'numru'
4
+
5
+ # Acts as a namespace for methods to bidirectionally convert between native
6
+ # Ruby types and native \Python types. Unsupported conversions raise
7
+ # UnsupportedConversion.
8
+ #
9
+ # The methods in this module should be considered internal implementation to
10
+ # RubyPython as they all return FFI pointers to \Python objects.
11
+ module RubyPython::Conversion
12
+ # Raised when RubyPython does not know how to convert an object from
13
+ # \Python to Ruby or vice versa.
14
+ class UnsupportedConversion < Exception; end
15
+ class ConversionError < RuntimeError; end
16
+
17
+ # Convert a Ruby string to a \Python string. Returns an FFI::Pointer to
18
+ # a PyStringObject.
19
+ def self.rtopString(rString)
20
+ size = rString.respond_to?(:bytesize) ? rString.bytesize : rString.size
21
+ ptr = RubyPython::Python.PyString_FromStringAndSize(rString, size)
22
+ if ptr.null?
23
+ raise ConversionError.new "Python failed to create a string with contents #{rString}"
24
+ else
25
+ ptr
26
+ end
27
+ end
28
+
29
+ # Convert a Ruby Array to \Python List. Returns an FFI::Pointer to
30
+ # a PyListObject.
31
+ def self.rtopArrayToList(rArray)
32
+ size = rArray.length
33
+ pList = RubyPython::Python.PyList_New size
34
+ if pList.null?
35
+ raise ConversionError.new "Python failed to create list of size #{size}"
36
+ end
37
+ rArray.each_with_index do |el, i|
38
+ # PyList_SetItem steals a reference, but rtopObject creates a new reference
39
+ # So we wind up with giving a new reference to the Python interpreter for every
40
+ # object
41
+ ret = RubyPython::Python.PyList_SetItem pList, i, rtopObject(el)
42
+ raise ConversionError.new "Failed to set item #{el} in array conversion" if ret == -1
43
+ end
44
+ pList
45
+ end
46
+
47
+ # Convert a Ruby Array (including the subclass RubyPython::Tuple) to
48
+ # \Python \tuple. Returns an FFI::Pointer to a PyTupleObject.
49
+ def self.rtopArrayToTuple(rArray)
50
+ pList = rtopArrayToList(rArray)
51
+ pTuple = RubyPython::Python.PyList_AsTuple(pList)
52
+ RubyPython::Python.Py_DecRef(pList)
53
+ if pTuple.null?
54
+ raise Conversion.new "Python failed to convert an intermediate list of #{rArray} to a tuple"
55
+ end
56
+ pTuple
57
+ end
58
+
59
+ # Convert a Ruby Hash to a \Python Dict. Returns an FFI::Pointer to a
60
+ # PyDictObject.
61
+ def self.rtopHash(rHash)
62
+ pDict = RubyPython::Python.PyDict_New
63
+ if pDict.null?
64
+ raise ConversionError.new "Python failed to create new dict"
65
+ end
66
+ rHash.each do |k,v|
67
+ key = rtopObject(k, :key => true)
68
+ value = rtopObject(v)
69
+
70
+ # PyDict_SetItem INCREFS both the key and the value passed to it.
71
+ # Since rtopObject already gives us a new reference, this is not necessary.
72
+ # Thus, we decref the passed in objects to balancy things out
73
+ if RubyPython::Python.PyDict_SetItem(pDict, key, value) == -1
74
+ raise ConversionError.new "Python failed to set #{key}, #{value} in dict conversion"
75
+ end
76
+
77
+ RubyPython::Python.Py_DecRef key
78
+ RubyPython::Python.Py_DecRef value
79
+ end
80
+
81
+ pDict
82
+ end
83
+
84
+ # Convert a Ruby Fixnum to a \Python Int. Returns an FFI::Pointer to a
85
+ # PyIntObject.
86
+ def self.rtopFixnum(rNum)
87
+ num = RubyPython::Python.PyInt_FromLong(rNum)
88
+ raise ConversionError.new "Failed to convert #{rNum}" if num.null?
89
+ num
90
+ end
91
+
92
+ # Convert a Ruby Bignum to a \Python Long. Returns an FFI::Pointer to a
93
+ # PyLongObject.
94
+ def self.rtopBigNum(rNum)
95
+ num = RubyPython::Python.PyLong_FromLongLong(rNum)
96
+ raise ConversionError.new "Failed to convert #{rNum}" if num.null?
97
+ num
98
+ end
99
+
100
+ # Convert a Ruby float to a \Python Float. Returns an FFI::Pointer to a
101
+ # PyFloatObject.
102
+ def self.rtopFloat(rNum)
103
+ num = RubyPython::Python.PyFloat_FromDouble(rNum)
104
+ raise ConversionError.new "Failed to convert #{rNum}" if num.null?
105
+ num
106
+ end
107
+
108
+ # Returns a \Python False value (equivalent to Ruby's +false+). Returns an
109
+ # FFI::Pointer to Py_ZeroStruct.
110
+ def self.rtopFalse
111
+ RubyPython::Macros.Py_RETURN_FALSE
112
+ end
113
+
114
+ # Returns a \Python True value (equivalent to Ruby's +true+). Returns an
115
+ # FFI::Pointer to Py_TrueStruct.
116
+ def self.rtopTrue
117
+ RubyPython::Macros.Py_RETURN_TRUE
118
+ end
119
+
120
+ # Returns a \Python None value (equivalent to Ruby's +nil+). Returns an
121
+ # FFI::Pointer to Py_NoneStruct.
122
+ def self.rtopNone
123
+ RubyPython::Macros.Py_RETURN_NONE
124
+ end
125
+
126
+ # Convert a Ruby Symbol to a \Python String. Returns an FFI::Pointer to a
127
+ # PyStringObject.
128
+ def self.rtopSymbol(rSymbol)
129
+ rtopString rSymbol.to_s
130
+ end
131
+
132
+ # Convert a Ruby Proc to a \Python Function. Returns an FFI::Pointer to a
133
+ # PyCFunction.
134
+ def self.rtopFunction(rObj)
135
+ proc = ::FFI::Function.new(:pointer, [:pointer, :pointer]) do |p_self, p_args|
136
+ retval = rObj.call(*ptorTuple(p_args))
137
+ pObject = retval.is_a?(RubyPython::RubyPyProxy) ? retval.pObject : RubyPython::PyObject.new(retval)
138
+
139
+ # make sure the refcount is >1 when pObject is destroyed
140
+ pObject.xIncref
141
+ pObject.pointer
142
+ end
143
+
144
+ defn = RubyPython::Python::PyMethodDef.new
145
+ defn[:ml_name] = ::FFI::MemoryPointer.from_string("RubyPython::Proc::%s" % rObj.object_id)
146
+ defn[:ml_meth] = proc
147
+ defn[:ml_flags] = RubyPython::Python::METH_VARARGS
148
+ defn[:ml_doc] = nil
149
+
150
+ return RubyPython::Python.PyCFunction_New(defn, nil)
151
+ end
152
+
153
+ # This will attempt to convert a Ruby object to an equivalent \Python
154
+ # native type. Returns an FFI::Pointer to a \Python object (the
155
+ # appropriate Py_Object C structure). If the conversion is unsuccessful,
156
+ # will raise UnsupportedConversion.
157
+ #
158
+ # [rObj] A native Ruby object.
159
+ # [is_key] Set to +true+ if the provided Ruby object will be used as a
160
+ # key in a \Python +dict+. (This primarily matters for Array
161
+ # conversion.)
162
+ def self.rtopObject(rObj, is_key = false)
163
+ case rObj
164
+ when String
165
+ rtopString rObj
166
+ when RubyPython::Tuple
167
+ rtopArrayToTuple rObj
168
+ when Array
169
+ # If this object is going to be used as a hash key we should make it a
170
+ # tuple instead of a list
171
+ if is_key
172
+ rtopArrayToTuple rObj
173
+ else
174
+ rtopArrayToList rObj
175
+ end
176
+ when Hash
177
+ rtopHash rObj
178
+ when Fixnum
179
+ rtopFixnum rObj
180
+ when Bignum
181
+ rtopBignum rObj
182
+ when Float
183
+ rtopFloat rObj
184
+ when true
185
+ rtopTrue
186
+ when false
187
+ rtopFalse
188
+ when Symbol
189
+ rtopSymbol rObj
190
+ when Proc, Method
191
+ rtopFunction rObj
192
+ when nil
193
+ rtopNone
194
+ when RubyPython::PyObject
195
+ rObj.xIncref
196
+ rObj.pointer
197
+ when RubyPython::RubyPyProxy
198
+ rtopObject(rObj.pObject, is_key)
199
+ when NumRu
200
+ rtopObject(rObj.np_obj)
201
+ else
202
+ raise UnsupportedConversion.new("Unsupported type #{rObj.class} for conversion.")
203
+ end
204
+ end
205
+
206
+ # Convert an FFI::Pointer to a \Python String (PyStringObject) to a Ruby
207
+ # String.
208
+ def self.ptorString(pString)
209
+ #strPtr is a pointer to a pointer to the internal character array.
210
+ #FFI will free strPtr when we are done but the internal array MUST
211
+ #not be modified
212
+ strPtr = ::FFI::MemoryPointer.new(:pointer)
213
+ sizePtr = ::FFI::MemoryPointer.new(:ssize_t)
214
+
215
+ RubyPython::Python.PyString_AsStringAndSize(pString, strPtr, sizePtr)
216
+
217
+ size = case ::FFI.find_type(:ssize_t)
218
+ when ::FFI.find_type(:long)
219
+ sizePtr.read_long
220
+ when ::FFI.find_type(:int)
221
+ sizePtr.read_int
222
+ when ::FFI.find_type(:long_long)
223
+ sizePtr.read_long_long
224
+ else
225
+ nil
226
+ end
227
+
228
+ strPtr.read_pointer.read_string(size)
229
+ end
230
+
231
+ # Convert an FFI::Pointer to a \Python List (PyListObject) to a Ruby
232
+ # Array.
233
+ def self.ptorList(pList)
234
+ rb_array = []
235
+ list_size = RubyPython::Python.PyList_Size(pList)
236
+
237
+ list_size.times do |i|
238
+ element = RubyPython::Python.PyList_GetItem(pList, i)
239
+ rObject = ptorObject(element)
240
+ rb_array.push rObject
241
+ end
242
+
243
+ rb_array
244
+ end
245
+
246
+ # Convert an FFI::Pointer to a \Python Int (PyIntObject) to a Ruby Fixnum.
247
+ def self.ptorInt(pNum)
248
+ RubyPython::Python.PyInt_AsLong(pNum)
249
+ end
250
+
251
+ # Convert an FFI::Pointer to a \Python Long (PyLongObject) to a Ruby
252
+ # Fixnum. This version does not do overflow checking, but probably should.
253
+ def self.ptorLong(pNum)
254
+ RubyPython::Python.PyLong_AsLong(pNum)
255
+ # TODO Overflow Checking
256
+ end
257
+
258
+ # Convert an FFI::Pointer to a \Python Float (PyFloatObject) to a Ruby
259
+ # Float.
260
+ def self.ptorFloat(pNum)
261
+ RubyPython::Python.PyFloat_AsDouble(pNum)
262
+ end
263
+
264
+ # Convert an FFI::Pointer to a \Python Tuple (PyTupleObject) to an
265
+ # instance of RubyPython::Tuple, a subclass of the Ruby Array class.
266
+ def self.ptorTuple(pTuple)
267
+ #PySequence_List returns a new list. Since we are only using it as a temporary
268
+ #here, we will have to DecRef it once we are done.
269
+ pList = RubyPython::Python.PySequence_List pTuple
270
+ rArray = ptorList pList
271
+ RubyPython::Python.Py_DecRef pList
272
+ RubyPython::Tuple.tuple(rArray)
273
+ end
274
+
275
+ # Convert an FFI::Pointer to a \Python Dictionary (PyDictObject) to a Ruby
276
+ # Hash.
277
+ def self.ptorDict(pDict)
278
+ rb_hash = {}
279
+
280
+ pos = ::FFI::MemoryPointer.new :ssize_t
281
+ pos.write_int 0
282
+ key = ::FFI::MemoryPointer.new :pointer
283
+ val = ::FFI::MemoryPointer.new :pointer
284
+
285
+ while RubyPython::Python.PyDict_Next(pDict, pos, key, val) != 0
286
+ #PyDict_Next sets key and val to borrowed references. We do not care
287
+ #if we are able to convert them to native ruby types, but if we wind up
288
+ #wrapping either in a proxy we better IncRef it to make sure it stays
289
+ #around.
290
+ pKey = key.read_pointer
291
+ pVal = val.read_pointer
292
+ rKey = ptorObject(pKey)
293
+ rVal = ptorObject(pVal)
294
+ RubyPython.Py_IncRef pKey if rKey.kind_of? ::FFI::Pointer
295
+ RubyPython.Py_IncRef pVal if rVal.kind_of? ::FFI::Pointer
296
+ rb_hash[rKey] = rVal
297
+ end
298
+
299
+ rb_hash
300
+ end
301
+
302
+ # Converts a pointer to a \Python object into a native Ruby type, if
303
+ # possible. If the conversion cannot be done, the Python object will be
304
+ # returned unmodified.
305
+ #
306
+ # [pObj] An FFI::Pointer to a \Python object.
307
+ def self.ptorObject(pObj)
308
+ if RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyString_Type.to_ptr) != 0
309
+ ptorString pObj
310
+ elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyList_Type.to_ptr) != 0
311
+ ptorList pObj
312
+ elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyInt_Type.to_ptr) != 0
313
+ ptorInt pObj
314
+ elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyLong_Type.to_ptr) != 0
315
+ ptorLong pObj
316
+ elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyFloat_Type.to_ptr) != 0
317
+ ptorFloat pObj
318
+ elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyTuple_Type.to_ptr) != 0
319
+ ptorTuple pObj
320
+ elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyDict_Type.to_ptr) != 0
321
+ ptorDict pObj
322
+ elsif pObj == RubyPython::Macros.Py_True
323
+ true
324
+ elsif pObj == RubyPython::Macros.Py_False
325
+ false
326
+ elsif pObj == RubyPython::Macros.Py_None
327
+ nil
328
+ else
329
+ pObj
330
+ end
331
+ end
332
+ end