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,262 @@
|
|
|
1
|
+
# -*- ruby encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
class RubyPython::InvalidInterpreter < Exception
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
# An instance of this class represents information about a particular
|
|
8
|
+
# \Python interpreter.
|
|
9
|
+
#
|
|
10
|
+
# This class represents the current Python interpreter.
|
|
11
|
+
# A class that represents a \Python executable.
|
|
12
|
+
#
|
|
13
|
+
# End users may get the instance that represents the current running \Python
|
|
14
|
+
# interpreter (from +RubyPython.python+), but should not directly
|
|
15
|
+
# instantiate this class.
|
|
16
|
+
class RubyPython::Interpreter
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
# Compare the current Interpreter to the provided Interpreter or
|
|
20
|
+
# configuration hash. A configuration hash will be converted to an
|
|
21
|
+
# Interpreter object before being compared.
|
|
22
|
+
# :python_exe basename is used. If comparing against another Interpreter
|
|
23
|
+
# object, the Interpreter basename and version are used.
|
|
24
|
+
def ==(other)
|
|
25
|
+
other = self.class.new(other) if other.kind_of? Hash
|
|
26
|
+
return false unless other.kind_of? self.class
|
|
27
|
+
(self.version == other.version) && (self.version_name == other.version_name)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
##
|
|
31
|
+
# Create a new instance of an Interpreter instance describing a particular
|
|
32
|
+
# \Python executable and shared library.
|
|
33
|
+
#
|
|
34
|
+
# Expects a hash that matches the configuration options provided to
|
|
35
|
+
# RubyPython.start; currently only one value is recognized in that hash:
|
|
36
|
+
#
|
|
37
|
+
# * <tt>:python_exe</tt>: Specifies the name of the python executable to
|
|
38
|
+
# run.
|
|
39
|
+
def initialize(options = {})
|
|
40
|
+
@python_exe = options[:python_exe]
|
|
41
|
+
# Windows: 'C:\\Python27\python.exe'
|
|
42
|
+
# Mac OS X: '/usr/bin/
|
|
43
|
+
|
|
44
|
+
# The default interpreter might be python3 on some systems
|
|
45
|
+
rc, majorversion = runpy "import sys; print(sys.version_info[0])"
|
|
46
|
+
if majorversion == "3"
|
|
47
|
+
warn "The python interpreter is python 3, switching to python2"
|
|
48
|
+
@python_exe = "python2"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
rc, @python = runpy "import sys; print sys.executable"
|
|
52
|
+
if rc.exitstatus.nonzero?
|
|
53
|
+
raise RubyPython::InvalidInterpreter, "An invalid interpreter was specified."
|
|
54
|
+
end
|
|
55
|
+
rc, @version = runpy "import sys; print '%d.%d' % sys.version_info[:2]"
|
|
56
|
+
rc, @sys_prefix = runpy "import sys; print sys.prefix"
|
|
57
|
+
|
|
58
|
+
if ::FFI::Platform.windows?
|
|
59
|
+
flat_version = @version.tr('.', '')
|
|
60
|
+
basename = File.basename(@python, '.exe')
|
|
61
|
+
|
|
62
|
+
if basename =~ /(?:#{@version}|#{flat_version})$/
|
|
63
|
+
@version_name = basename
|
|
64
|
+
else
|
|
65
|
+
@version_name = "#{basename}#{flat_version}"
|
|
66
|
+
end
|
|
67
|
+
else
|
|
68
|
+
basename = File.basename(@python)
|
|
69
|
+
if basename =~ /#{@version}/
|
|
70
|
+
@version_name = basename
|
|
71
|
+
elsif basename.end_with?("2")
|
|
72
|
+
@version_name = "#{basename[0..-2]}#{@version}"
|
|
73
|
+
else
|
|
74
|
+
@version_name = "#{basename}#{@version}"
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
@library = find_python_lib
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def find_python_lib
|
|
82
|
+
# By default, the library name will be something like
|
|
83
|
+
# libpython2.6.so, but that won't always work.
|
|
84
|
+
@libbase = "#{::FFI::Platform::LIBPREFIX}#{@version_name}"
|
|
85
|
+
@libext = ::FFI::Platform::LIBSUFFIX
|
|
86
|
+
@libname = "#{@libbase}.#{@libext}"
|
|
87
|
+
|
|
88
|
+
# We may need to look in multiple locations for Python, so let's
|
|
89
|
+
# build this as an array.
|
|
90
|
+
@locations = [ File.join(@sys_prefix, "lib", @libname) ]
|
|
91
|
+
|
|
92
|
+
if ::FFI::Platform.mac?
|
|
93
|
+
# On the Mac, let's add a special case that has even a different
|
|
94
|
+
# @libname. This may not be fully useful on future versions of OS
|
|
95
|
+
# X, but it should work on 10.5 and 10.6. Even if it doesn't, the
|
|
96
|
+
# next step will (/usr/lib/libpython<version>.dylib is a symlink
|
|
97
|
+
# to the correct location).
|
|
98
|
+
@locations << File.join(@sys_prefix, "Python")
|
|
99
|
+
# Let's also look in the location that was originally set in this
|
|
100
|
+
# library:
|
|
101
|
+
File.join(@sys_prefix, "lib", "#{@realname}", "config", @libname)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
if ::FFI::Platform.unix?
|
|
105
|
+
# On Unixes, let's look in some standard alternative places, too.
|
|
106
|
+
# Just in case. Some Unixes don't include a .so symlink when they
|
|
107
|
+
# should, so let's look for the base cases of .so.1 and .so.1.0, too.
|
|
108
|
+
[ @libname, "#{@libname}.1", "#{@libname}.1.0" ].each do |name|
|
|
109
|
+
if ::FFI::Platform::ARCH != 'i386'
|
|
110
|
+
@locations << File.join("/opt/local/lib64", name)
|
|
111
|
+
@locations << File.join("/opt/lib64", name)
|
|
112
|
+
@locations << File.join("/usr/local/lib64", name)
|
|
113
|
+
@locations << File.join("/usr/lib64", name)
|
|
114
|
+
@locations << File.join("/usr/lib/x86_64-linux-gnu", name)
|
|
115
|
+
end
|
|
116
|
+
@locations << File.join("/opt/local/lib", name)
|
|
117
|
+
@locations << File.join("/opt/lib", name)
|
|
118
|
+
@locations << File.join("/usr/local/lib", name)
|
|
119
|
+
@locations << File.join("/usr/lib", name)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
if ::FFI::Platform.windows?
|
|
124
|
+
# On Windows, the appropriate DLL is usually be found in
|
|
125
|
+
# %SYSTEMROOT%\system or %SYSTEMROOT%\system32; as a fallback we'll
|
|
126
|
+
# use C:\Windows\system{,32} as well as the install directory and the
|
|
127
|
+
# install directory + libs.
|
|
128
|
+
system_root = File.expand_path(ENV['SYSTEMROOT']).gsub(/\\/, '/')
|
|
129
|
+
@locations << File.join(system_root, 'system', @libname)
|
|
130
|
+
@locations << File.join(system_root, 'system32', @libname)
|
|
131
|
+
@locations << File.join("C:/WINDOWS", "System", @libname)
|
|
132
|
+
@locations << File.join("C:/WINDOWS", "System32", @libname)
|
|
133
|
+
@locations << File.join(sys_prefix, @libname)
|
|
134
|
+
@locations << File.join(sys_prefix, 'libs', @libname)
|
|
135
|
+
@locations << File.join(system_root, "SysWOW64", @libname)
|
|
136
|
+
@locations << File.join("C:/WINDOWS", "SysWOW64", @libname)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Let's add alternative extensions; again, just in case.
|
|
140
|
+
@locations.dup.each do |location|
|
|
141
|
+
path = File.dirname(location)
|
|
142
|
+
base = File.basename(location, ".#{@libext}")
|
|
143
|
+
@locations << File.join(path, "#{base}.so") # Standard Unix
|
|
144
|
+
@locations << File.join(path, "#{base}.dylib") # Mac OS X
|
|
145
|
+
@locations << File.join(path, "#{base}.dll") # Windows
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Remove redundant locations
|
|
149
|
+
@locations.uniq!
|
|
150
|
+
|
|
151
|
+
library = nil
|
|
152
|
+
|
|
153
|
+
@locations.each do |location|
|
|
154
|
+
if File.exists? location
|
|
155
|
+
library = location
|
|
156
|
+
break
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
library
|
|
161
|
+
end
|
|
162
|
+
private :find_python_lib
|
|
163
|
+
|
|
164
|
+
def valid?
|
|
165
|
+
if @python.nil? or @python.empty?
|
|
166
|
+
false
|
|
167
|
+
elsif @library.nil? or @library.empty?
|
|
168
|
+
false
|
|
169
|
+
else
|
|
170
|
+
true
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
##
|
|
175
|
+
# The name of the \Python executable that is used. This is the value of
|
|
176
|
+
# 'sys.executable' for the \Python interpreter provided in
|
|
177
|
+
# <tt>:python_exe</tt> or 'python' if it is not provided.
|
|
178
|
+
#
|
|
179
|
+
# On Mac OS X Lion (10.7), this value is '/usr/bin/python' for 'python'.
|
|
180
|
+
attr_reader :python
|
|
181
|
+
##
|
|
182
|
+
# The version of the \Python interpreter. This is a decimalized version of
|
|
183
|
+
# 'sys.version_info[:2]' (such that \Python 2.7.1 is reported as '2.7').
|
|
184
|
+
attr_reader :version
|
|
185
|
+
##
|
|
186
|
+
# The system prefix for the \Python interpreter. This is the value of
|
|
187
|
+
# 'sys.prefix'.
|
|
188
|
+
attr_reader :sys_prefix
|
|
189
|
+
##
|
|
190
|
+
# The basename of the \Python interpreter with a version number. This is
|
|
191
|
+
# mostly an intermediate value used to find the shared \Python library,
|
|
192
|
+
# but /usr/bin/python is often a link to /usr/bin/python2.7 so it may be
|
|
193
|
+
# of value. Note that this does *not* include the full path to the
|
|
194
|
+
# interpreter.
|
|
195
|
+
attr_reader :version_name
|
|
196
|
+
|
|
197
|
+
# The \Python library.
|
|
198
|
+
attr_reader :library
|
|
199
|
+
|
|
200
|
+
# Run a Python command-line command.
|
|
201
|
+
def runpy(command)
|
|
202
|
+
i = @python || @python_exe || 'python'
|
|
203
|
+
if ::FFI::Platform.windows?
|
|
204
|
+
o = %x(#{i} -c "#{command}" 2> NUL:)
|
|
205
|
+
else
|
|
206
|
+
o = %x(#{i} -c "#{command}" 2> /dev/null)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
[ $?, o.chomp ]
|
|
210
|
+
end
|
|
211
|
+
private :runpy
|
|
212
|
+
|
|
213
|
+
def inspect(debug = false)
|
|
214
|
+
if debug
|
|
215
|
+
debug_s
|
|
216
|
+
elsif @python
|
|
217
|
+
"#<#{self.class}: #{python} v#{version} #{sys_prefix} #{version_name}>"
|
|
218
|
+
else
|
|
219
|
+
"#<#{self.class}: invalid interpreter>"
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def debug_s(format = nil)
|
|
224
|
+
system = ""
|
|
225
|
+
system << "windows " if ::FFI::Platform.windows?
|
|
226
|
+
system << "mac " if ::FFI::Platform.mac?
|
|
227
|
+
system << "unix " if ::FFI::Platform.unix?
|
|
228
|
+
system << "unknown " if system.empty?
|
|
229
|
+
|
|
230
|
+
case format
|
|
231
|
+
when :report
|
|
232
|
+
s = <<-EOS
|
|
233
|
+
python_exe: #{@python_exe}
|
|
234
|
+
python: #{@python}
|
|
235
|
+
version: #{@version}
|
|
236
|
+
sys_prefix: #{@sys_prefix}
|
|
237
|
+
version_name: #{@version_name}
|
|
238
|
+
platform: #{system.chomp}
|
|
239
|
+
library: #{@library.inspect}
|
|
240
|
+
libbase: #{@libbase}
|
|
241
|
+
libext: #{@libext}
|
|
242
|
+
libname: #{@libname}
|
|
243
|
+
locations: #{@locations.inspect}
|
|
244
|
+
EOS
|
|
245
|
+
else
|
|
246
|
+
s = "#<#{self.class}: "
|
|
247
|
+
s << "python_exe=#{@python_exe.inspect} "
|
|
248
|
+
s << "python=#{@python.inspect} "
|
|
249
|
+
s << "version=#{@version.inspect} "
|
|
250
|
+
s << "sys_prefix=#{@sys_prefix.inspect} "
|
|
251
|
+
s << "version_name=#{@version_name.inspect} "
|
|
252
|
+
s << system
|
|
253
|
+
s << "library=#{@library.inspect} "
|
|
254
|
+
s << "libbase=#{@libbase.inspect} "
|
|
255
|
+
s << "libext=#{@libext.inspect} "
|
|
256
|
+
s << "libname=#{@libname.inspect} "
|
|
257
|
+
s << "locations=#{@locations.inspect}"
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
s
|
|
261
|
+
end
|
|
262
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require 'ffi'
|
|
2
|
+
require 'rubypython/python'
|
|
3
|
+
|
|
4
|
+
# Contains Python C API macros reimplemented in Ruby. For internal use only.
|
|
5
|
+
module RubyPython::Macros #:nodoc:
|
|
6
|
+
# Returns the reference count for the provided pointer.
|
|
7
|
+
def self.Py_REFCNT(pObjPointer)
|
|
8
|
+
pStruct = RubyPython::Python::PyObjectStruct.new pObjPointer
|
|
9
|
+
pStruct[:ob_refcnt]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Returns the object type for the provided pointer.
|
|
13
|
+
def self.Py_TYPE(pObjPointer)
|
|
14
|
+
pStruct = RubyPython::Python::PyObjectStruct.new pObjPointer
|
|
15
|
+
pStruct[:ob_type]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# This has been modified from the C API macro to allow for multiple
|
|
19
|
+
# pointer objects to be passed. It simplifies a number of checks.
|
|
20
|
+
def self.PyObject_TypeCheck(pObject, pTypePointer)
|
|
21
|
+
type = self.Py_TYPE(pObject)
|
|
22
|
+
|
|
23
|
+
[ pTypePointer ].flatten.each do |pointer|
|
|
24
|
+
return 1 if type == pointer
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
return 0
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.Py_True
|
|
31
|
+
RubyPython::Python.Py_TrueStruct.to_ptr
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.Py_False
|
|
35
|
+
RubyPython::Python.Py_ZeroStruct.to_ptr
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.Py_None
|
|
39
|
+
RubyPython::Python.Py_NoneStruct.to_ptr
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.Py_RETURN_FALSE
|
|
43
|
+
RubyPython::Python.Py_IncRef(self.Py_False)
|
|
44
|
+
self.Py_False
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.Py_RETURN_TRUE
|
|
48
|
+
RubyPython::Python.Py_IncRef(self.Py_True)
|
|
49
|
+
self.Py_True
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def self.Py_RETURN_NONE
|
|
53
|
+
RubyPython::Python.Py_IncRef(self.Py_None)
|
|
54
|
+
self.Py_None
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# A mixin module to provide method delegation to a proxy class. This is done
|
|
2
|
+
# either by delegating to methods defined on the wrapped object or by using
|
|
3
|
+
# the \Python _operator_ module. A large number of the methods are
|
|
4
|
+
# dynamically generated and so their documentation is not provided here. In
|
|
5
|
+
# general all operators that can be overloaded are delegated.
|
|
6
|
+
module RubyPython::Operators
|
|
7
|
+
# Provides access to the \Python _operator_ module.
|
|
8
|
+
def self.operator_
|
|
9
|
+
@@operator ||= RubyPython.import('operator')
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Creates a method to delegate a binary operation.
|
|
13
|
+
# [rname] The name of the Ruby method for this operation. Can be either a
|
|
14
|
+
# Symbol or a String.
|
|
15
|
+
# [pname] The name of the \Python magic method to which this method should
|
|
16
|
+
# be delegated.
|
|
17
|
+
def self.bin_op(rname, pname)
|
|
18
|
+
define_method rname.to_sym do |other|
|
|
19
|
+
self.__send__(pname, other)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Creates a method to delegate a relational operator. The result of the
|
|
24
|
+
# delegated method will always be converted to a Ruby type so that simple
|
|
25
|
+
# boolean testing may occur. These methods are implemented with calls the
|
|
26
|
+
# _operator_ module.
|
|
27
|
+
#
|
|
28
|
+
# [rname] The name of the Ruby method for this operation. Can be a Symbol
|
|
29
|
+
# or a String.
|
|
30
|
+
# [pname] The name of the \Python magic method to which this method should
|
|
31
|
+
# be delegated.
|
|
32
|
+
def self.rel_op(rname, pname)
|
|
33
|
+
define_method rname.to_sym do |other|
|
|
34
|
+
RubyPython::Operators.operator_.__send__(pname, self, other).rubify
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Creates a method to delegate a relational operator.
|
|
39
|
+
# These methods are implemented with calls the _operator_ module.
|
|
40
|
+
# [rname] The name of the Ruby method for this operation. Can be a Symbol
|
|
41
|
+
# or a String.
|
|
42
|
+
# [pname] The name of the \Python magic method to which this method should
|
|
43
|
+
# be delegated.
|
|
44
|
+
def self.unary_op(rname, pname)
|
|
45
|
+
define_method rname.to_sym do
|
|
46
|
+
RubyPython::Operators.operator_.__send__(pname, self)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
[
|
|
51
|
+
[:+, '__add__'],
|
|
52
|
+
[:-, '__sub__'],
|
|
53
|
+
[:*, '__mul__'],
|
|
54
|
+
[:/, '__div__'],
|
|
55
|
+
[:&, '__and__'],
|
|
56
|
+
[:^, '__xor__'],
|
|
57
|
+
[:%, '__mod__'],
|
|
58
|
+
[:**, '__pow__'],
|
|
59
|
+
[:>>, '__rshift__'],
|
|
60
|
+
[:<<, '__lshift__'],
|
|
61
|
+
[:|, '__or__']
|
|
62
|
+
].each do |args|
|
|
63
|
+
bin_op *args
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
[
|
|
67
|
+
[:~, :__invert__],
|
|
68
|
+
[:+@, :__pos__],
|
|
69
|
+
[:-@, :__neg__]
|
|
70
|
+
].each do |args|
|
|
71
|
+
unary_op *args
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
[
|
|
75
|
+
[:==, 'eq'],
|
|
76
|
+
[:<, 'lt'],
|
|
77
|
+
[:<=, 'le'],
|
|
78
|
+
[:>, 'gt'],
|
|
79
|
+
[:>=, 'ge'],
|
|
80
|
+
[:equal?, 'is_']
|
|
81
|
+
].each do |args|
|
|
82
|
+
rel_op *args
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Delegates object indexed access to the wrapped \Python object.
|
|
86
|
+
def [](index)
|
|
87
|
+
self.__getitem__ index
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Delegates setting of various indices to the wrapped \Python object.
|
|
91
|
+
def []=(index, value)
|
|
92
|
+
self.__setitem__ index, value
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Delegates membership testing to \Python.
|
|
96
|
+
def include?(item)
|
|
97
|
+
self.__contains__(item).rubify
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Delegates Comparison to \Python.
|
|
101
|
+
def <=>(other)
|
|
102
|
+
RubyPython::PyMain.cmp(self, other)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
class << self
|
|
106
|
+
# Called by RubyPython when the interpreter is started or stopped so
|
|
107
|
+
# that the necessary preparation or cleanup can be done. For internal
|
|
108
|
+
# use only.
|
|
109
|
+
def python_interpreter_update(status)
|
|
110
|
+
case status
|
|
111
|
+
when :stop
|
|
112
|
+
@@operator = nil
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
private :python_interpreter_update
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Aliases eql? to == for Python objects.
|
|
119
|
+
alias_method :eql?, :==
|
|
120
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require "rubypython/python"
|
|
2
|
+
require "rubypython/conversion"
|
|
3
|
+
require 'rubypython/macros'
|
|
4
|
+
require 'rubypython/conversion'
|
|
5
|
+
require 'rubypython/pyobject'
|
|
6
|
+
require "rubypython/pymainclass"
|
|
7
|
+
require "rubypython/rubypyproxy"
|
|
8
|
+
|
|
9
|
+
if defined? Fiber
|
|
10
|
+
module RubyPython
|
|
11
|
+
class << self
|
|
12
|
+
# Creates a \Python generator object called +rubypython_generator+
|
|
13
|
+
# that accepts a callback and yields to it.
|
|
14
|
+
#
|
|
15
|
+
# *Note*: This method only exists in the RubyPython if the Fiber
|
|
16
|
+
# exists.
|
|
17
|
+
def generator_type
|
|
18
|
+
@generator_type ||= lambda do
|
|
19
|
+
code = <<-EOM
|
|
20
|
+
def rubypython_generator(callback):
|
|
21
|
+
while True:
|
|
22
|
+
yield callback()
|
|
23
|
+
EOM
|
|
24
|
+
|
|
25
|
+
globals = PyObject.new({ "__builtins__" => PyMain.builtin.pObject, })
|
|
26
|
+
empty_hash = PyObject.new({})
|
|
27
|
+
ptr = Python.PyRun_String(code, Python::PY_FILE_INPUT, globals.pointer, empty_hash.pointer)
|
|
28
|
+
ptr = Python.PyRun_String("rubypython_generator", Python::PY_EVAL_INPUT, globals.pointer, empty_hash.pointer)
|
|
29
|
+
raise PythonError.handle_error if PythonError.error?
|
|
30
|
+
RubyPyProxy.new(PyObject.new(ptr))
|
|
31
|
+
end.call
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Creates a Ruby lambda that acts like a \Python generator. Uses
|
|
35
|
+
# +RubyPython.generator_type+ and Fiber to work the generator as a
|
|
36
|
+
# coroutine.
|
|
37
|
+
#
|
|
38
|
+
# *Note*: This method only exists in the RubyPython if the Fiber
|
|
39
|
+
# exists.
|
|
40
|
+
def generator
|
|
41
|
+
return lambda do |*args|
|
|
42
|
+
fib = Fiber.new do
|
|
43
|
+
yield *args
|
|
44
|
+
Python.PyErr_SetNone(Python.PyExc_StopIteration)
|
|
45
|
+
::FFI::Pointer::NULL
|
|
46
|
+
end
|
|
47
|
+
generator_type.__call__(lambda { fib.resume })
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Performs a +Fiber.yield+ with the provided arguments, continuing the
|
|
52
|
+
# coroutine execution of the generator.
|
|
53
|
+
#
|
|
54
|
+
# *Note*: This method only exists in the RubyPython if the Fiber
|
|
55
|
+
# exists.
|
|
56
|
+
def yield(*args)
|
|
57
|
+
Fiber.yield(*args)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
require 'rubypython/blankobject'
|
|
2
|
+
require 'singleton'
|
|
3
|
+
|
|
4
|
+
module RubyPython
|
|
5
|
+
# A singleton object providing access to the \Python <tt>__main__</tt> and
|
|
6
|
+
# <tt>__builtin__</tt> modules. This can be conveniently accessed through
|
|
7
|
+
# +PyMain+. The <tt>__main__</tt> namespace is searched before the
|
|
8
|
+
# <tt>__builtin__</tt> namespace. As such, naming clashes will be resolved
|
|
9
|
+
# in that order.
|
|
10
|
+
#
|
|
11
|
+
# RubyPython::PyMain.dir("dir") # => ['__add__', '__class__', … ]
|
|
12
|
+
#
|
|
13
|
+
# === Block Syntax
|
|
14
|
+
# PyMainClass provides experimental block support for called methods. A
|
|
15
|
+
# block may be passed to a method call and the object returned by the
|
|
16
|
+
# function call will be passed as an argument to the block.
|
|
17
|
+
#
|
|
18
|
+
# RubyPython::PyMain.dir("dir") { |a| a.rubify.map { |e| e.to_sym } }
|
|
19
|
+
# # => [:__add__, :__class__, :__contains__, … ]
|
|
20
|
+
class PyMainClass < RubyPython::BlankObject
|
|
21
|
+
include Singleton
|
|
22
|
+
|
|
23
|
+
# Returns a proxy object wrapping the \Python <tt>__main__</tt> namespace.
|
|
24
|
+
def main
|
|
25
|
+
@main ||= RubyPython.import "__main__"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Returns a proxy object wrapping the \Python <tt>__builtin__</tt>
|
|
29
|
+
# namespace.
|
|
30
|
+
def builtin
|
|
31
|
+
@builtin ||= RubyPython.import "__builtin__"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Delegates any method calls on this object to the \Python
|
|
35
|
+
# <tt>__main__</tt> or <tt>__builtin__</tt> namespaces, in that order. If
|
|
36
|
+
# a block is provided, the result of calling the \Python method will be
|
|
37
|
+
# yielded as an argument to the block.
|
|
38
|
+
#
|
|
39
|
+
# [name] The name of the \Python method or function to call.
|
|
40
|
+
# [args] The arguments to pass to the \Python method.
|
|
41
|
+
# [block] A block to execute with the result of calling the \Python
|
|
42
|
+
# method. If a block is provided, the result of the block is returned,
|
|
43
|
+
# not the result of the \Python method.
|
|
44
|
+
def method_missing(name, *args, &block)
|
|
45
|
+
proxy = if main.respond_to?(name)
|
|
46
|
+
main
|
|
47
|
+
elsif builtin.respond_to?(name)
|
|
48
|
+
builtin
|
|
49
|
+
else
|
|
50
|
+
super(name, *args)
|
|
51
|
+
end
|
|
52
|
+
result = if proxy.is_real_method?(name)
|
|
53
|
+
proxy.__send__(name, *args)
|
|
54
|
+
else
|
|
55
|
+
proxy.__send__(:method_missing, name, *args)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
if block
|
|
59
|
+
block.call(result)
|
|
60
|
+
else
|
|
61
|
+
result
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Called by RubyPython when the interpreter is started or stopped so
|
|
66
|
+
# that the neccesary preparation or cleanup can be done. For internal
|
|
67
|
+
# use only.
|
|
68
|
+
def python_interpreter_update(status)
|
|
69
|
+
case status
|
|
70
|
+
when :stop
|
|
71
|
+
@main = nil
|
|
72
|
+
@builtin = nil
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
private :python_interpreter_update
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# The accessible instance of PyMainClass.
|
|
79
|
+
PyMain = RubyPython::PyMainClass.instance
|
|
80
|
+
end
|