rubypython-raspi 0.1.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/Rakefile ADDED
@@ -0,0 +1,108 @@
1
+ # -*- ruby encoding: utf-8 -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+
6
+ Hoe.plugin :doofus
7
+ Hoe.plugin :gemspec
8
+ Hoe.plugin :rubyforge
9
+ Hoe.plugin :git
10
+ Hoe.plugin :hg
11
+
12
+ Hoe.spec 'rubypython' do
13
+ self.rubyforge_name = self.name
14
+
15
+ developer('Steeve Morin', 'swiuzzz+rubypython@gmail.com')
16
+ developer('Austin Ziegler', 'austin@rubyforge.org')
17
+ developer('Zach Raines', 'raineszm+rubypython@gmail.com')
18
+
19
+ self.remote_rdoc_dir = 'rdoc'
20
+ self.rsync_args << ' --exclude=statsvn/'
21
+
22
+ self.history_file = 'History.rdoc'
23
+ self.readme_file = 'README.rdoc'
24
+ self.extra_rdoc_files = FileList["*.rdoc"].to_a
25
+
26
+ self.extra_deps << ['ffi', '~> 1.0.7']
27
+ self.extra_deps << ['blankslate', '>= 2.1.2.3']
28
+
29
+ self.extra_dev_deps << ['rspec', '~> 2.0']
30
+ self.extra_dev_deps << ['tilt', '~> 1.0']
31
+
32
+ self.spec_extras[:requirements] = [ "Python, ~> 2.4" ]
33
+ end
34
+
35
+ namespace :website do
36
+ desc "Build the website files."
37
+ task :build => [ "website/index.html" ]
38
+
39
+ deps = FileList["website/**/*"].exclude { |f| File.directory? f }
40
+ deps.include(*%w(Rakefile))
41
+ deps.include(*FileList["*.rdoc"].to_a)
42
+ deps.exclude(*%w(website/index.html website/images/*))
43
+
44
+ file "website/index.html" => deps do |t|
45
+ require 'tilt'
46
+ require 'rubypython'
47
+
48
+ puts "Generating #{t.name}…"
49
+
50
+ # Let's modify the rdoc for presenation purposes.
51
+ body_rdoc = File.read("README.rdoc")
52
+
53
+ contrib = File.read("Contributors.rdoc")
54
+ body_rdoc.gsub!(/^:include: Contributors.rdoc/, contrib)
55
+
56
+ license = File.read("License.rdoc")
57
+ body_rdoc.sub!(/^:include: License.rdoc/, license)
58
+ toc_elements = body_rdoc.scan(/^(=+) (.*)$/)
59
+ toc_elements.map! { |e| [ e[0].count('='), e[1] ] }
60
+ body_rdoc.gsub!(/^(=.*)/) { "#{$1.downcase}" }
61
+ body = Tilt::RDocTemplate.new(nil) { body_rdoc }.render
62
+
63
+ title = nil
64
+ body.gsub!(%r{<h1>(.*)</h1>}) { title = $1; "" }
65
+
66
+ toc_elements = toc_elements.select { |e| e[0].between?(2, 3) }
67
+
68
+ last_level = 0
69
+ toc = ""
70
+
71
+ toc_elements.each do |element|
72
+ level, text = *element
73
+ ltext = text.downcase
74
+ id = text.downcase.gsub(/[^a-z]+/, '-')
75
+
76
+ body.gsub!(%r{<h#{level}>#{ltext}</h#{level}>}) {
77
+ %Q(<h#{level} id="#{id}">#{ltext}</h#{level}>)
78
+ }
79
+
80
+ if last_level != level
81
+ if level > last_level
82
+ toc << "<ol>"
83
+ else
84
+ toc << "</li></ol></li>"
85
+ end
86
+
87
+ last_level = level
88
+ end
89
+
90
+ toc << %Q(<li><a href="##{id}">#{text}</a>)
91
+ end
92
+ toc << "</li></ol>"
93
+
94
+ template = Tilt.new("website/index.rhtml", :trim => "<>%")
95
+ context = {
96
+ :title => title,
97
+ :toc => toc,
98
+ :body => body,
99
+ :download => "http://rubyforge.org/frs/?group_id=6737",
100
+ :version => RubyPython::VERSION,
101
+ :modified => Time.now
102
+ }
103
+ File.open(t.name, "w") { |f| f.write template.render(self, context) } end
104
+ end
105
+
106
+ task "docs" => "website:build"
107
+
108
+ # vim: syntax=ruby
@@ -0,0 +1 @@
1
+ Autotest.add_discovery { "rspec2" }
data/lib/rubypython.rb ADDED
@@ -0,0 +1,284 @@
1
+ # RubyPython is a bridge between the Ruby and \Python interpreters. It
2
+ # embeds a \Python interpreter in the Ruby application's process using FFI
3
+ # and provides a means for wrapping, converting, and calling \Python objects
4
+ # and methods.
5
+ #
6
+ # == Usage
7
+ # The \Python interpreter must be started before the RubyPython bridge is
8
+ # functional. The user can either manually manage the running of the
9
+ # interpreter as shown below, or use the +RubyPython.run+ or
10
+ # +RubyPython.session+ methods to automatically start and stop the
11
+ # interpreter.
12
+ #
13
+ # RubyPython.start
14
+ # cPickle = RubyPython.import "cPickle"
15
+ # puts cPickle.dumps("RubyPython is awesome!").rubify
16
+ # RubyPython.stop
17
+ module RubyPython
18
+ VERSION = '0.6'
19
+ end
20
+
21
+ require 'rubypython/blankobject'
22
+ require 'rubypython/interpreter'
23
+ require 'rubypython/python'
24
+ require 'rubypython/pythonerror'
25
+ require 'rubypython/pyobject'
26
+ require 'rubypython/rubypyproxy'
27
+ require 'rubypython/pymainclass'
28
+ require 'rubypython/pygenerator'
29
+ require 'rubypython/tuple'
30
+ require 'thread'
31
+
32
+ module RubyPython
33
+ class << self
34
+ ##
35
+ # :attr_accessor:
36
+ # Controls whether RubyPython is operating in <em>Proxy Mode</em> or
37
+ # <em>Legacy Mode</em>. This behavioural difference is deprecated as of
38
+ # RubyPython 0.6 and will be removed in a subsequent release.
39
+ #
40
+ # === Proxy Mode
41
+ # By default, +legacy_mode+ is +false+, meaning that any object returned
42
+ # from a \Python function call will be wrapped in a Ruby-Python proxy
43
+ # (an instance of +RubyPyProxy+ or one of its subclasses). This allows
44
+ # \Python method calls to be forwarded to the \Python object, even if it
45
+ # would otherwise be a native Ruby object.
46
+ #
47
+ # RubyPython.session do
48
+ # string = RubyPython.import 'string'
49
+ # ascii_letters = string.ascii_letters
50
+ # puts ascii_letters.isalpha # => True
51
+ # puts ascii_letters.rubify.isalpha # throws NoMethodError
52
+ # end
53
+ #
54
+ # === Legacy Mode
55
+ # If +legacy_mode+ is +true+, RubyPython automatically tries to convert
56
+ # returned objects to native Ruby object types. If there is no such
57
+ # conversion, the object remains wrapped in +RubyPyProxy+. This
58
+ # behaviour is the same as RubyPython 0.2 and earlier. This mode is
59
+ # deprecated as of RubyPython 0.6 and will be removed.
60
+ #
61
+ # RubyPython.legacy_mode = true
62
+ # RubyPython.session do
63
+ # string = RubyPython.import 'string'
64
+ # ascii_letters = string.ascii_letters
65
+ # puts ascii_letters.isalpha # throws NoMethodError
66
+ # end
67
+ def legacy_mode=(value)
68
+ warn_legacy_mode_deprecation unless defined? @legacy_mode
69
+ @legacy_mode = value
70
+ end
71
+
72
+ def legacy_mode
73
+ unless defined? @legacy_mode
74
+ warn_legacy_mode_deprecation
75
+ @legacy_mode = nil
76
+ end
77
+ @legacy_mode
78
+ end
79
+
80
+ def legacy_mode?
81
+ @legacy_mode = nil unless defined? @legacy_mode
82
+ @legacy_mode
83
+ end
84
+ private :legacy_mode?
85
+
86
+ def warn_legacy_mode_deprecation
87
+ warn "RubyPython's Legacy Mode is deprecated and will be removed after version #{VERSION}."
88
+ end
89
+ private :warn_legacy_mode_deprecation
90
+
91
+ ## Starts the \Python interpreter. One of +RubyPython.start+,
92
+ # RubyPython.session+, or +RubyPython.run+ must be run before using any
93
+ # \Python code. Returns +true+ if the interpreter was started; +false+
94
+ # otherwise.
95
+ #
96
+ # [options] Configures the interpreter prior to starting it. Principally
97
+ # used to provide an alternative \Python interpreter to start.
98
+ #
99
+ # With no options provided:
100
+ # RubyPython.start
101
+ # sys = RubyPython.import 'sys'
102
+ # p sys.version # => "2.6.6"
103
+ # RubyPython.stop
104
+ #
105
+ # With an alternative \Python executable:
106
+ # RubyPython.start(:python_exe => 'python2.7')
107
+ # sys = RubyPython.import 'sys'
108
+ # p sys.version # => "2.7.1"
109
+ # RubyPython.stop
110
+ def start(options = {})
111
+ Mutex.new.synchronize do
112
+ # Has the Runtime interpreter been defined?
113
+ if self.const_defined?(:Runtime)
114
+ # If this constant is defined, then yes it is. Since it is, let's
115
+ # see if we should print a warning to the user.
116
+ unless Runtime == options
117
+ warn "The Python interpreter has already been loaded from #{Runtime.python} and cannot be changed in this process. Continuing with the current runtime."
118
+ end
119
+ else
120
+ interp = RubyPython::Interpreter.new(options)
121
+ if interp.valid?
122
+ self.const_set(:Runtime, interp)
123
+ else
124
+ raise RubyPython::InvalidInterpreter, "An invalid interpreter was specified."
125
+ end
126
+ end
127
+
128
+ unless defined? RubyPython::Python.ffi_libraries
129
+ Runtime.__send__(:infect!, RubyPython::Python)
130
+ end
131
+ end
132
+
133
+ return false if RubyPython::Python.Py_IsInitialized != 0
134
+ RubyPython::Python.Py_Initialize
135
+ notify :start
136
+ true
137
+ end
138
+
139
+ # Stops the \Python interpreter if it is running. Returns +true+ if the
140
+ # intepreter is stopped. All wrapped \Python objects are invalid after
141
+ # invocation of this method. If you need the values within the \Python
142
+ # proxy objects, be sure to call +RubyPyProxy#rubify+ on them.
143
+ def stop
144
+ if defined? Python.Py_IsInitialized and Python.Py_IsInitialized != 0
145
+ Python.Py_Finalize
146
+ notify :stop
147
+ true
148
+ else
149
+ false
150
+ end
151
+ end
152
+
153
+ # Import a \Python module into the interpreter and return a proxy object
154
+ # for it.
155
+ #
156
+ # This is the preferred way to gain access to \Python objects.
157
+ #
158
+ # [mod_name] The name of the module to import.
159
+ def import(mod_name)
160
+ if defined? Python.Py_IsInitialized and Python.Py_IsInitialized != 0
161
+ pModule = Python.PyImport_ImportModule mod_name
162
+ raise PythonError.handle_error if PythonError.error?
163
+ pymod = PyObject.new pModule
164
+ RubyPyModule.new(pymod)
165
+ else
166
+ raise "Python has not been started."
167
+ end
168
+ end
169
+
170
+ # Starts the \Python interpreter (optionally with options) and +yields+
171
+ # to the provided block. When the block exits for any reason, the
172
+ # \Python interpreter is stopped automatically.
173
+ #
174
+ # The last executed expression of the block is returned. Be careful that
175
+ # the last expression of the block does not return a RubyPyProxy object,
176
+ # because the proxy object will be invalidated when the interpreter is
177
+ # stopped.
178
+ #
179
+ # [options] Configures the interpreter prior to starting it. Principally
180
+ # used to provide an alternative \Python interpreter to start.
181
+ #
182
+ # *NOTE*: In the current version of RubyPython, it _is_ possible to change
183
+ # \Python interpreters in a single Ruby process execution, but it is
184
+ # *strongly* discouraged as this may lead to segmentation faults. This
185
+ # feature is highly experimental and may be disabled in the future.
186
+ #
187
+ # :call-seq:
188
+ # session(options = {}) { block to execute }
189
+ def session(options = {})
190
+ start(options)
191
+ yield
192
+ ensure
193
+ stop
194
+ end
195
+
196
+ # Starts the \Python interpreter (optionally with options) and executes
197
+ # the provided block in the RubyPython module scope. When the block
198
+ # exits for any reason, the \Python interpreter is stopped
199
+ # automatically.
200
+ #
201
+ # The last executed expression of the block is returned. Be careful that
202
+ # the last expression of the block does not return a RubyPyProxy object,
203
+ # because the proxy object will be invalidated when the interpreter is
204
+ # stopped.
205
+ #
206
+ # [options] Configures the interpreter prior to starting it. Principally
207
+ # used to provide an alternative \Python interpreter to start.
208
+ #
209
+ # *NOTE*: In the current version of RubyPython, it _is_ possible to
210
+ # change \Python interpreters in a single Ruby process execution, but it
211
+ # is *strongly* discouraged as this may lead to segmentation faults.
212
+ # This feature is highly experimental and may be disabled in the future.
213
+ #
214
+ # :call-seq:
215
+ # run(options = {}) { block to execute in RubyPython context }
216
+ def run(options = {}, &block)
217
+ start(options)
218
+ self.module_eval(&block)
219
+ ensure
220
+ stop
221
+ end
222
+
223
+ # Starts the \Python interpreter for a
224
+ # {virtualenv}[http://pypi.python.org/pypi/virtualenv] virtual
225
+ # environment. Returns +true+ if the interpreter was started.
226
+ #
227
+ # [virtualenv] The root path to the virtualenv-installed \Python
228
+ # interpreter.
229
+ #
230
+ # RubyPython.start_from_virtualenv('/path/to/virtualenv')
231
+ # sys = RubyPython.import 'sys'
232
+ # p sys.version # => "2.7.1"
233
+ # RubyPython.stop
234
+ #
235
+ # *NOTE*: In the current version of RubyPython, it _is_ possible to
236
+ # change \Python interpreters in a single Ruby process execution, but it
237
+ # is *strongly* discouraged as this may lead to segmentation faults.
238
+ # This feature is highly experimental and may be disabled in the future.
239
+ def start_from_virtualenv(virtualenv)
240
+ result = start(:python_exe => File.join(virtualenv, "bin", "python"))
241
+ activate_virtualenv
242
+ result
243
+ end
244
+
245
+ # Returns an object describing the active Python interpreter. Returns
246
+ # +nil+ if there is no active interpreter.
247
+ def python
248
+ if self.const_defined? :Runtime
249
+ self::Runtime
250
+ else
251
+ nil
252
+ end
253
+ end
254
+
255
+ # Used to activate the virtualenv.
256
+ def activate_virtualenv
257
+ imp = import("imp")
258
+ imp.load_source("activate_this",
259
+ File.join(File.dirname(RubyPython::Runtime.python),
260
+ "activate_this.py"))
261
+ end
262
+ private :activate_virtualenv
263
+
264
+ def add_observer(object)
265
+ @observers ||= []
266
+ @observers << object
267
+ true
268
+ end
269
+ private :add_observer
270
+
271
+ def notify(status)
272
+ @observers ||= []
273
+ @observers.each do |o|
274
+ next if nil === o
275
+ o.__send__ :python_interpreter_update, status
276
+ end
277
+ end
278
+ private :notify
279
+ end
280
+
281
+ add_observer PyMain
282
+ add_observer Operators
283
+ add_observer PyObject::AutoPyPointer
284
+ end
@@ -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,286 @@
1
+ require 'rubypython/python'
2
+ require 'rubypython/macros'
3
+
4
+ # Acts as a namespace for methods to bidirectionally convert between native
5
+ # Ruby types and native \Python types. Unsupported conversions raise
6
+ # UnsupportedConversion.
7
+ #
8
+ # The methods in this module should be considered internal implementation to
9
+ # RubyPython as they all return FFI pointers to \Python objects.
10
+ module RubyPython::Conversion
11
+ # Raised when RubyPython does not know how to convert an object from
12
+ # \Python to Ruby or vice versa.
13
+ class UnsupportedConversion < Exception; end
14
+
15
+ # Convert a Ruby string to a \Python string. Returns an FFI::Pointer to
16
+ # a PyStringObject.
17
+ def self.rtopString(rString)
18
+ size = rString.respond_to?(:bytesize) ? rString.bytesize : rString.size
19
+ RubyPython::Python.PyString_FromStringAndSize(rString, size)
20
+ end
21
+
22
+ # Convert a Ruby Array to \Python List. Returns an FFI::Pointer to
23
+ # a PyListObject.
24
+ def self.rtopArrayToList(rArray)
25
+ size = rArray.length
26
+ pList = RubyPython::Python.PyList_New size
27
+ rArray.each_with_index do |el, i|
28
+ RubyPython::Python.PyList_SetItem pList, i, rtopObject(el)
29
+ end
30
+ pList
31
+ end
32
+
33
+ # Convert a Ruby Array (including the subclass RubyPython::Tuple) to
34
+ # \Python \tuple. Returns an FFI::Pointer to a PyTupleObject.
35
+ def self.rtopArrayToTuple(rArray)
36
+ pList = rtopArrayToList(rArray)
37
+ pTuple = RubyPython::Python.PySequence_Tuple(pList)
38
+ RubyPython::Python.Py_DecRef(pList)
39
+ pTuple
40
+ end
41
+
42
+ # Convert a Ruby Hash to a \Python Dict. Returns an FFI::Pointer to a
43
+ # PyDictObject.
44
+ def self.rtopHash(rHash)
45
+ pDict = RubyPython::Python.PyDict_New
46
+ rHash.each do |k,v|
47
+ RubyPython::Python.PyDict_SetItem pDict, rtopObject(k, key = true),
48
+ rtopObject(v)
49
+ end
50
+ pDict
51
+ end
52
+
53
+ # Convert a Ruby Fixnum to a \Python Int. Returns an FFI::Pointer to a
54
+ # PyIntObject.
55
+ def self.rtopFixnum(rNum)
56
+ RubyPython::Python.PyInt_FromLong(rNum)
57
+ end
58
+
59
+ # Convert a Ruby Bignum to a \Python Long. Returns an FFI::Pointer to a
60
+ # PyLongObject.
61
+ def self.rtopBigNum(rNum)
62
+ RubyPython::Python.PyLong_FromLong(rNum)
63
+ end
64
+
65
+ # Convert a Ruby float to a \Python Float. Returns an FFI::Pointer to a
66
+ # PyFloatObject.
67
+ def self.rtopFloat(rNum)
68
+ RubyPython::Python.PyFloat_FromDouble(rNum)
69
+ end
70
+
71
+ # Returns a \Python False value (equivalent to Ruby's +false+). Returns an
72
+ # FFI::Pointer to Py_ZeroStruct.
73
+ def self.rtopFalse
74
+ RubyPython::Macros.Py_RETURN_FALSE
75
+ end
76
+
77
+ # Returns a \Python True value (equivalent to Ruby's +true+). Returns an
78
+ # FFI::Pointer to Py_TrueStruct.
79
+ def self.rtopTrue
80
+ RubyPython::Macros.Py_RETURN_TRUE
81
+ end
82
+
83
+ # Returns a \Python None value (equivalent to Ruby's +nil+). Returns an
84
+ # FFI::Pointer to Py_NoneStruct.
85
+ def self.rtopNone
86
+ RubyPython::Macros.Py_RETURN_NONE
87
+ end
88
+
89
+ # Convert a Ruby Symbol to a \Python String. Returns an FFI::Pointer to a
90
+ # PyStringObject.
91
+ def self.rtopSymbol(rSymbol)
92
+ RubyPython::Python.PyString_FromString rSymbol.to_s
93
+ end
94
+
95
+ # Convert a Ruby Proc to a \Python Function. Returns an FFI::Pointer to a
96
+ # PyCFunction.
97
+ def self.rtopFunction(rObj)
98
+ proc = FFI::Function.new(:pointer, [:pointer, :pointer]) do |p_self, p_args|
99
+ retval = rObj.call(*ptorTuple(p_args))
100
+ pObject = retval.is_a?(RubyPython::RubyPyProxy) ? retval.pObject : RubyPython::PyObject.new(retval)
101
+
102
+ # make sure the refcount is >1 when pObject is destroyed
103
+ pObject.xIncref
104
+ pObject.pointer
105
+ end
106
+
107
+ defn = RubyPython::Python::PyMethodDef.new
108
+ defn[:ml_name] = FFI::MemoryPointer.from_string("RubyPython::Proc::%s" % rObj.object_id)
109
+ defn[:ml_meth] = proc
110
+ defn[:ml_flags] = RubyPython::Python::METH_VARARGS
111
+ defn[:ml_doc] = nil
112
+
113
+ return RubyPython::Python.PyCFunction_New(defn, nil)
114
+ end
115
+
116
+ # This will attempt to convert a Ruby object to an equivalent \Python
117
+ # native type. Returns an FFI::Pointer to a \Python object (the
118
+ # appropriate Py…Object C structure). If the conversion is unsuccessful,
119
+ # will raise UnsupportedConversion.
120
+ #
121
+ # [rObj] A native Ruby object.
122
+ # [is_key] Set to +true+ if the provided Ruby object will be used as a
123
+ # key in a \Python +dict+. (This primarily matters for Array
124
+ # conversion.)
125
+ def self.rtopObject(rObj, is_key = false)
126
+ case rObj
127
+ when String
128
+ rtopString rObj
129
+ when RubyPython::Tuple
130
+ rtopArrayToTuple rObj
131
+ when Array
132
+ # If this object is going to be used as a hash key we should make it a
133
+ # tuple instead of a list
134
+ if is_key
135
+ rtopArrayToTuple rObj
136
+ else
137
+ rtopArrayToList rObj
138
+ end
139
+ when Hash
140
+ rtopHash rObj
141
+ when Fixnum
142
+ rtopFixnum rObj
143
+ when Bignum
144
+ rtopBignum rObj
145
+ when Float
146
+ rtopFloat rObj
147
+ when true
148
+ rtopTrue
149
+ when false
150
+ rtopFalse
151
+ when Symbol
152
+ rtopSymbol rObj
153
+ when Proc, Method
154
+ if RubyPython.legacy_mode
155
+ raise UnsupportedConversion.new("Callbacks are not supported in Legacy Mode.")
156
+ end
157
+ rtopFunction rObj
158
+ when Method
159
+ rtopFunction rObj
160
+ when nil
161
+ rtopNone
162
+ when RubyPython::PyObject
163
+ rObj.pointer
164
+ else
165
+ raise UnsupportedConversion.new("Unsupported type #{rObj.class} for conversion.")
166
+ end
167
+ end
168
+
169
+ # Convert an FFI::Pointer to a \Python String (PyStringObject) to a Ruby
170
+ # String.
171
+ def self.ptorString(pString)
172
+ strPtr = FFI::MemoryPointer.new(:pointer)
173
+ sizePtr = FFI::MemoryPointer.new(:ssize_t)
174
+
175
+ RubyPython::Python.PyString_AsStringAndSize(pString, strPtr, sizePtr)
176
+
177
+ size = case FFI.find_type(:ssize_t)
178
+ when FFI.find_type(:long)
179
+ sizePtr.read_long
180
+ when FFI.find_type(:int)
181
+ sizePtr.read_int
182
+ when FFI.find_type(:long_long)
183
+ sizePtr.read_long_long
184
+ else
185
+ nil
186
+ end
187
+
188
+ strPtr.read_pointer.read_string(size)
189
+ end
190
+
191
+ # Convert an FFI::Pointer to a \Python List (PyListObject) to a Ruby
192
+ # Array.
193
+ def self.ptorList(pList)
194
+ rb_array = []
195
+ list_size = RubyPython::Python.PyList_Size(pList)
196
+
197
+ list_size.times do |i|
198
+ element = RubyPython::Python.PyList_GetItem(pList, i)
199
+ # PyList_GetItem returns borrowed ref
200
+ RubyPython::Python.Py_IncRef element
201
+ rObject = ptorObject(element)
202
+ rb_array.push rObject
203
+ end
204
+
205
+ rb_array
206
+ end
207
+
208
+ # Convert an FFI::Pointer to a \Python Int (PyIntObject) to a Ruby Fixnum.
209
+ def self.ptorInt(pNum)
210
+ RubyPython::Python.PyInt_AsLong(pNum)
211
+ end
212
+
213
+ # Convert an FFI::Pointer to a \Python Long (PyLongObject) to a Ruby
214
+ # Fixnum. This version does not do overflow checking, but probably should.
215
+ def self.ptorLong(pNum)
216
+ RubyPython::Python.PyLong_AsLong(pNum)
217
+ # TODO Overflow Checking
218
+ end
219
+
220
+ # Convert an FFI::Pointer to a \Python Float (PyFloatObject) to a Ruby
221
+ # Float.
222
+ def self.ptorFloat(pNum)
223
+ RubyPython::Python.PyFloat_AsDouble(pNum)
224
+ end
225
+
226
+ # Convert an FFI::Pointer to a \Python Tuple (PyTupleObject) to an
227
+ # instance of RubyPython::Tuple, a subclass of the Ruby Array class.
228
+ def self.ptorTuple(pTuple)
229
+ pList = RubyPython::Python.PySequence_List pTuple
230
+ rArray = ptorList pList
231
+ RubyPython::Python.Py_DecRef pList
232
+ RubyPython::Tuple.tuple(rArray)
233
+ end
234
+
235
+ # Convert an FFI::Pointer to a \Python Dictionary (PyDictObject) to a Ruby
236
+ # Hash.
237
+ def self.ptorDict(pDict)
238
+ rb_hash = {}
239
+
240
+ pos = FFI::MemoryPointer.new :ssize_t
241
+ pos.write_int 0
242
+ key = FFI::MemoryPointer.new :pointer
243
+ val = FFI::MemoryPointer.new :pointer
244
+
245
+ while RubyPython::Python.PyDict_Next(pDict, pos, key, val) != 0
246
+ pKey = key.read_pointer
247
+ pVal = val.read_pointer
248
+ rKey = ptorObject(pKey)
249
+ rVal = ptorObject(pVal)
250
+ rb_hash[rKey] = rVal
251
+ end
252
+
253
+ rb_hash
254
+ end
255
+
256
+ # Converts a pointer to a \Python object into a native Ruby type, if
257
+ # possible. If the conversion cannot be done, the Python object will be
258
+ # returned unmodified.
259
+ #
260
+ # [pObj] An FFI::Pointer to a \Python object.
261
+ def self.ptorObject(pObj)
262
+ if RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyString_Type.to_ptr) != 0
263
+ ptorString pObj
264
+ elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyList_Type.to_ptr) != 0
265
+ ptorList pObj
266
+ elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyInt_Type.to_ptr) != 0
267
+ ptorInt pObj
268
+ elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyLong_Type.to_ptr) != 0
269
+ ptorLong pObj
270
+ elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyFloat_Type.to_ptr) != 0
271
+ ptorFloat pObj
272
+ elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyTuple_Type.to_ptr) != 0
273
+ ptorTuple pObj
274
+ elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyDict_Type.to_ptr) != 0
275
+ ptorDict pObj
276
+ elsif pObj == RubyPython::Macros.Py_True
277
+ true
278
+ elsif pObj == RubyPython::Macros.Py_False
279
+ false
280
+ elsif pObj == RubyPython::Macros.Py_None
281
+ nil
282
+ else
283
+ pObj
284
+ end
285
+ end
286
+ end