rubypython 0.2.11 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data.tar.gz.sig +0 -0
  2. data/{History.txt → History.markdown} +34 -28
  3. data/Manifest.txt +26 -40
  4. data/PostInstall.txt +2 -1
  5. data/README.markdown +103 -0
  6. data/Rakefile +19 -3
  7. data/lib/rubypython.rb +118 -114
  8. data/lib/rubypython/blankobject.rb +21 -0
  9. data/lib/rubypython/conversion.rb +198 -0
  10. data/lib/rubypython/core_ext/string.rb +7 -0
  11. data/lib/rubypython/legacy.rb +15 -0
  12. data/lib/rubypython/macros.rb +47 -0
  13. data/lib/rubypython/operators.rb +111 -0
  14. data/lib/rubypython/pymainclass.rb +51 -0
  15. data/lib/rubypython/pyobject.rb +203 -0
  16. data/lib/rubypython/python.rb +111 -0
  17. data/lib/rubypython/pythonerror.rb +78 -0
  18. data/lib/rubypython/rubypyproxy.rb +214 -0
  19. data/lib/rubypython/version.rb +4 -3
  20. data/spec/conversion_spec.rb +66 -0
  21. data/spec/legacy_spec.rb +22 -0
  22. data/spec/pymainclass_spec.rb +26 -0
  23. data/spec/pyobject_spec.rb +264 -0
  24. data/spec/python_helpers/objects.py +41 -0
  25. data/spec/pythonerror_spec.rb +43 -0
  26. data/spec/refcnt_spec.rb +68 -0
  27. data/spec/rubypyclass_spec.rb +13 -0
  28. data/spec/rubypyproxy_spec.rb +249 -0
  29. data/spec/rubypython_spec.rb +62 -0
  30. data/spec/spec.opts +2 -0
  31. data/spec/spec_helper.rb +51 -0
  32. metadata +79 -73
  33. metadata.gz.sig +0 -0
  34. data/README.txt +0 -60
  35. data/ext/rubypython_bridge/cbridge.c +0 -150
  36. data/ext/rubypython_bridge/cbridge.h +0 -15
  37. data/ext/rubypython_bridge/config.h +0 -14
  38. data/ext/rubypython_bridge/extconf.rb +0 -43
  39. data/ext/rubypython_bridge/ptor.c +0 -242
  40. data/ext/rubypython_bridge/ptor.h +0 -15
  41. data/ext/rubypython_bridge/rp_blankobject.c +0 -42
  42. data/ext/rubypython_bridge/rp_blankobject.h +0 -11
  43. data/ext/rubypython_bridge/rp_class.c +0 -56
  44. data/ext/rubypython_bridge/rp_class.h +0 -7
  45. data/ext/rubypython_bridge/rp_error.c +0 -34
  46. data/ext/rubypython_bridge/rp_error.h +0 -11
  47. data/ext/rubypython_bridge/rp_function.c +0 -31
  48. data/ext/rubypython_bridge/rp_function.h +0 -7
  49. data/ext/rubypython_bridge/rp_instance.c +0 -164
  50. data/ext/rubypython_bridge/rp_instance.h +0 -7
  51. data/ext/rubypython_bridge/rp_module.c +0 -160
  52. data/ext/rubypython_bridge/rp_module.h +0 -8
  53. data/ext/rubypython_bridge/rp_object.c +0 -194
  54. data/ext/rubypython_bridge/rp_object.h +0 -23
  55. data/ext/rubypython_bridge/rp_util.c +0 -63
  56. data/ext/rubypython_bridge/rp_util.h +0 -11
  57. data/ext/rubypython_bridge/rtop.c +0 -212
  58. data/ext/rubypython_bridge/rtop.h +0 -17
  59. data/ext/rubypython_bridge/rubypython_bridge.c +0 -125
  60. data/ext/rubypython_bridge/rubypython_bridge.h +0 -10
  61. data/lib/rubypython/session.rb +0 -4
  62. data/lib/rubypython/wrapper_extensions.rb +0 -83
  63. data/setup.rb +0 -1585
  64. data/tasks/environment.rake +0 -7
  65. data/tasks/extconf.rake +0 -13
  66. data/tasks/extconf/rubypython_bridge.rake +0 -49
  67. data/test/python_helpers/objects.py +0 -12
  68. data/test/test.wav +0 -0
  69. data/test/test_helper.rb +0 -2
  70. data/test/test_rubypython.rb +0 -215
  71. data/test/test_rubypython_bridge_extn.rb +0 -133
  72. data/test/test_session.rb +0 -6
@@ -0,0 +1,21 @@
1
+ require 'blankslate'
2
+
3
+ module RubyPython
4
+ #An object to be used as a base class for Proxy classes.
5
+ #It is necessary to define this because no such class exists in Ruby
6
+ #1.8.x
7
+ class BlankObject < BlankSlate
8
+ class << self
9
+ def hide(name)
10
+ if instance_methods.include?(name) and
11
+ name.to_s !~ /^(__|instance_eval|object_id)/
12
+ @hidden_methods ||= {}
13
+ @hidden_methods[name.to_sym] = instance_method(name)
14
+ undef_method name
15
+ end
16
+ end
17
+ end
18
+
19
+ instance_methods.each { |m| hide(m) }
20
+ end
21
+ end
@@ -0,0 +1,198 @@
1
+ require 'rubypython/python'
2
+ require 'rubypython/macros'
3
+ module RubyPython
4
+ #This modules encapsulates the work of converting between native Ruby and
5
+ #Python types. Unsupported conversions raise {UnsupportedConversion}.
6
+ module Conversion
7
+
8
+ #Raised when RubyPython does not know how to convert an object from Python
9
+ #to Ruby or vice versa
10
+ class UnsupportedConversion < Exception; end
11
+
12
+ def self.rtopString(rString)
13
+ Python.PyString_FromString(rString)
14
+ end
15
+
16
+ def self.rtopArrayToList(rArray)
17
+ size = rArray.length
18
+ pList = Python.PyList_New size
19
+ rArray.each_with_index do |el, i|
20
+ Python.PyList_SetItem pList, i, rtopObject(el)
21
+ end
22
+ pList
23
+ end
24
+
25
+ def self.rtopArrayToTuple(rArray)
26
+ pList = rtopArrayToList(rArray)
27
+ pTuple = Python.PySequence_Tuple(pList)
28
+ Python.Py_DecRef(pList)
29
+ pTuple
30
+ end
31
+
32
+ def self.rtopHash(rHash)
33
+ pDict = Python.PyDict_New
34
+ rHash.each do |k,v|
35
+ Python.PyDict_SetItem pDict, rtopObject(k, key=true), rtopObject(v)
36
+ end
37
+ pDict
38
+ end
39
+
40
+ def self.rtopFixnum(rNum)
41
+ Python.PyInt_FromLong(rNum)
42
+ end
43
+
44
+ def self.rtopBigNum(rNum)
45
+ Python.PyLong_FromLong(rNum)
46
+ end
47
+
48
+ def self.rtopFloat(rNum)
49
+ Python.PyFloat_FromDouble(rNum)
50
+ end
51
+
52
+ def self.rtopFalse
53
+ Macros.Py_RETURN_FALSE
54
+ end
55
+
56
+ def self.rtopTrue
57
+ Macros.Py_RETURN_TRUE
58
+ end
59
+
60
+ def self.rtopNone
61
+ Macros.Py_RETURN_NONE
62
+ end
63
+
64
+ def self.rtopSymbol(rSymbol)
65
+ Python.PyString_FromString rSymbol.to_s
66
+ end
67
+
68
+ #If possible converts a ruby type to an equivalent
69
+ #python native type.
70
+ #@param rObj a native ruby type
71
+ #@param [Boolean] is_key whether this object will be used as a key in a
72
+ # python dict.
73
+ #@return [FFI::Pointer] a to a C PyObject\*
74
+ #@raise [UnsupportedConversion]
75
+ def self.rtopObject(rObj, is_key=false)
76
+ case rObj
77
+ when String
78
+ rtopString rObj
79
+ when Array
80
+ # If this object is going to be used as a
81
+ # hash key we should make it a tuple instead
82
+ # of a list
83
+ if is_key
84
+ rtopArrayToTuple rObj
85
+ else
86
+ rtopArrayToList rObj
87
+ end
88
+ when Hash
89
+ rtopHash rObj
90
+ when Fixnum
91
+ rtopFixnum rObj
92
+ when Bignum
93
+ rtopBignum rObj
94
+ when Float
95
+ rtopFloat rObj
96
+ when true
97
+ rtopTrue
98
+ when false
99
+ rtopFalse
100
+ when Symbol
101
+ rtopSymbol rObj
102
+ when nil
103
+ rtopNone
104
+ else
105
+ raise UnsupportedConversion.new("Unsupported type for RTOP conversion." )
106
+ end
107
+ end
108
+
109
+ def self.ptorString(pString)
110
+ Python.PyString_AsString(pString)
111
+ end
112
+
113
+ def self.ptorList(pList)
114
+ rb_array = []
115
+ list_size = Python.PyList_Size(pList)
116
+
117
+ list_size.times do |i|
118
+ element = Python.PyList_GetItem(pList, i)
119
+ Python.Py_IncRef element
120
+ rObject = ptorObject(element)
121
+ rb_array.push rObject
122
+ end
123
+
124
+ rb_array
125
+ end
126
+
127
+ def self.ptorInt(pNum)
128
+ Python.PyInt_AsLong pNum
129
+ end
130
+
131
+ def self.ptorLong(pNum)
132
+ Python.PyLong_AsLong(pNum)
133
+ #TODO Overflow Checking
134
+ end
135
+
136
+ def self.ptorFloat(pNum)
137
+ Python.PyFloat_AsDouble(pNum)
138
+ end
139
+
140
+ def self.ptorTuple(pTuple)
141
+ pList = Python.PySequence_List pTuple
142
+ rArray = ptorList pList
143
+ Python.Py_DecRef pList
144
+ rArray
145
+ end
146
+
147
+ def self.ptorDict(pDict)
148
+ rb_hash = {}
149
+
150
+ pos = FFI::MemoryPointer.new :ssize_t
151
+ pos.write_int 0
152
+ key = FFI::MemoryPointer.new :pointer
153
+ val = FFI::MemoryPointer.new :pointer
154
+
155
+ while Python.PyDict_Next(pDict, pos, key, val) != 0
156
+ pKey = key.read_pointer
157
+ pVal = val.read_pointer
158
+ rKey = ptorObject(pKey)
159
+ rVal = ptorObject(pVal)
160
+ rb_hash[rKey] = rVal
161
+ end
162
+
163
+ rb_hash
164
+ end
165
+
166
+
167
+ #Converts a pointer to a Python object into a native ruby type, if
168
+ #possible. Otherwise raises an error.
169
+ #@param [FFI::Pointer] pObj a pointer to a Python object
170
+ #@return a native ruby object.
171
+ #@raise {UnsupportedConversion}
172
+ def self.ptorObject(pObj)
173
+ if Macros.PyObject_TypeCheck(pObj, Python.PyString_Type.to_ptr) != 0
174
+ ptorString pObj
175
+ elsif Macros.PyObject_TypeCheck(pObj, Python.PyList_Type.to_ptr) != 0
176
+ ptorList pObj
177
+ elsif Macros.PyObject_TypeCheck(pObj, Python.PyInt_Type.to_ptr) != 0
178
+ ptorInt pObj
179
+ elsif Macros.PyObject_TypeCheck(pObj, Python.PyLong_Type.to_ptr) != 0
180
+ ptorLong pObj
181
+ elsif Macros.PyObject_TypeCheck(pObj, Python.PyFloat_Type.to_ptr) != 0
182
+ ptorFloat pObj
183
+ elsif Macros.PyObject_TypeCheck(pObj, Python.PyTuple_Type.to_ptr) != 0
184
+ ptorTuple pObj
185
+ elsif Macros.PyObject_TypeCheck(pObj, Python.PyDict_Type.to_ptr) != 0
186
+ ptorDict pObj
187
+ elsif pObj == Macros.Py_True
188
+ true
189
+ elsif pObj == Macros.Py_False
190
+ false
191
+ elsif pObj == Macros.Py_None
192
+ nil
193
+ else
194
+ pObj
195
+ end
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,7 @@
1
+ class String
2
+ #This is necessary for Ruby versions 1.8.6 and below as
3
+ #String#end_with? is not defined in this case.
4
+ def end_with?(c)
5
+ self[-1].chr == c
6
+ end
7
+ end unless String.respond_to? :end_with?
@@ -0,0 +1,15 @@
1
+ require 'rubypython'
2
+
3
+ module RubyPython::LegacyMode
4
+ class << self
5
+ def setup_legacy
6
+ RubyPython.legacy_mode = true
7
+ end
8
+
9
+ def teardown_legacy
10
+ RubyPython.legacy_mode = false
11
+ end
12
+ end
13
+ end
14
+
15
+ RubyPython::LegacyMode.setup_legacy
@@ -0,0 +1,47 @@
1
+ require 'ffi'
2
+ require 'rubypython/python'
3
+
4
+ module RubyPython
5
+ #Contains Python C API macros reimplmented in Ruby. For internal use only.
6
+ module Macros
7
+ def self.Py_TYPE(pObjPointer)
8
+ pStruct = Python::PyObjectStruct.new pObjPointer
9
+ pStruct[:ob_type]
10
+ end
11
+
12
+ def self.PyObject_TypeCheck(pObject, pTypePointer)
13
+ if Py_TYPE(pObject) == pTypePointer
14
+ 1
15
+ else
16
+ 0
17
+ end
18
+ end
19
+
20
+ def self.Py_True
21
+ Python.Py_TrueStruct.to_ptr
22
+ end
23
+
24
+ def self.Py_False
25
+ Python.Py_ZeroStruct.to_ptr
26
+ end
27
+
28
+ def self.Py_None
29
+ Python.Py_NoneStruct.to_ptr
30
+ end
31
+
32
+ def self.Py_RETURN_FALSE
33
+ Python.Py_IncRef(self.Py_False)
34
+ self.Py_False
35
+ end
36
+
37
+ def self.Py_RETURN_TRUE
38
+ Python.Py_IncRef(self.Py_True)
39
+ self.Py_True
40
+ end
41
+
42
+ def self.Py_RETURN_NONE
43
+ Python.Py_IncRef(self.Py_None)
44
+ self.Py_None
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,111 @@
1
+ module RubyPython
2
+ #A mixin module to provide method delegation to a proxy class. This is done
3
+ #either by delegating to methods defined on the wrapped object or by using the
4
+ #Python _operator_ module. A large number of the methods are dynamically
5
+ #generated and so their documentation is not provided here. In general all
6
+ #operators that can be overloaded are delegated.
7
+ module Operators
8
+ #Provides access to the Python _operator_ module.
9
+ #@return[RubyPython::RubyPyModule]
10
+ def self.operator_
11
+ @@operator ||= RubyPython.import('operator')
12
+ end
13
+
14
+ #Creates a method to delegate a binary operation. The result of the
15
+ #operation will follow the conversion rules appropriate to the current mode
16
+ #of operation as set by {RubyPython.legacy_mode}.
17
+ #@param[Symbol, String] rname The name of the Ruby method for this operation
18
+ #@param[String] pname The name of the Python magic method to which this
19
+ #method should be delegated.
20
+ def self.bin_op rname, pname
21
+ define_method rname.to_sym do |other|
22
+ self.__send__ pname, other
23
+ end
24
+ end
25
+
26
+ #Creates a method to delegate a relational operator. The result of the
27
+ #delegated method will always be converted to a Ruby type so that simple
28
+ #boolean testing may occur. These methods are implemented with calls the
29
+ #_operator_ module.
30
+ #@param[Symbol, String] rname The name of the Ruby method for this operation
31
+ #@param[String] pname The name of the Python magic method to which this
32
+ #method should be delegated.
33
+ def self.rel_op rname, pname
34
+ define_method rname.to_sym do |other|
35
+ Operators.operator_.__send__(pname, self, other).rubify
36
+ end
37
+ end
38
+
39
+ #Creates a method to delegate a relational operator. The result of the
40
+ #operation will follow the conversion rules appropriate to the current mode
41
+ #of operation as set by {RubyPython.legacy_mode}. These methods are
42
+ #implemented with calls the _operator_ module.
43
+ #@param[Symbol, String] rname The name of the Ruby method for this operation
44
+ #@param[String] pname The name of the Python magic method to which this
45
+ #method should be delegated.
46
+ def self.unary_op rname, pname
47
+ define_method rname.to_sym do
48
+ Operators.operator_.__send__(pname, self)
49
+ end
50
+ end
51
+
52
+
53
+ [
54
+ [:+, '__add__'],
55
+ [:-, '__sub__'],
56
+ [:*, '__mul__'],
57
+ [:/, '__div__'],
58
+ [:&, '__and__'],
59
+ [:^, '__xor__'],
60
+ [:%, '__mod__'],
61
+ [:**, '__pow__'],
62
+ [:>>, '__rshift__'],
63
+ [:<<, '__lshift__'],
64
+ [:|, '__or__']
65
+ ].each do |args|
66
+ bin_op *args
67
+ end
68
+
69
+ [
70
+ [:~, :__invert__],
71
+ [:+@, :__pos__],
72
+ [:-@, :__neg__]
73
+ ].each do |args|
74
+ unary_op *args
75
+ end
76
+
77
+ [
78
+ [:==, 'eq'],
79
+ [:<, 'lt'],
80
+ [:<=, 'le'],
81
+ [:>, 'gt'],
82
+ [:>=, 'ge'],
83
+ [:equal?, 'is_']
84
+ ].each do |args|
85
+ rel_op *args
86
+ end
87
+
88
+ alias :eql? :==
89
+
90
+ #Delegates object indexed access to the wrapped Python object.
91
+ def [](index)
92
+ self.__getitem__ index
93
+ end
94
+
95
+ #Delegates setting of various indices to the wrapped Python object.
96
+ def []=(index, value)
97
+ self.__setitem__ index, value
98
+ end
99
+
100
+ #Delegates membership testing to Python.
101
+ def include?(item)
102
+ self.__contains__(item).rubify
103
+ end
104
+
105
+ #Delegates Comparison to Python.
106
+ def <=>(other)
107
+ PyMain.cmp(self, other)
108
+ end
109
+
110
+ end
111
+ end
@@ -0,0 +1,51 @@
1
+ require 'rubypython/blankobject'
2
+ require 'singleton'
3
+
4
+ module RubyPython
5
+ # A singleton object providing access to the python \_\_main\_\_ and
6
+ # \_\_builtin\_\_ modules. This can be conveniently accessed through the
7
+ # already instaniated PyMain constant. The \_\_main\_\_ namespace is
8
+ # searched before the \_\_builtin\_\_ namespace. As such, naming clashes will
9
+ # be resolved in that order.
10
+ #
11
+ # ## Block Syntax
12
+ # The PyMainClass object provides somewhat experimental block support. A
13
+ # block may be passed to a method call and the object returned by the
14
+ # function call will be passed as an argument to the block.
15
+ class PyMainClass < BlankObject
16
+ include Singleton
17
+ attr_writer :main, :builtin
18
+
19
+ #@return [RubyPyModule] a proxy object wrapping the Python \__main\__
20
+ #namespace.
21
+ def main
22
+ @main||=RubyPython.import "__main__"
23
+ end
24
+
25
+ #@return [RubyPyModule] a proxy object wrapping the Python \__builtin\__
26
+ #namespace.
27
+ def builtin
28
+ @builtin||=RubyPython.import "__builtin__"
29
+ end
30
+
31
+ #Delegates any method calls on this object to the Python \__main\__ or
32
+ #\__builtin\__ namespaces. Method call resolution occurs in that order.
33
+ def method_missing(name,*args,&block)
34
+ proxy = if main.respond_to?(name)
35
+ main
36
+ elsif builtin.respond_to?(name)
37
+ builtin
38
+ else
39
+ super(name, *args)
40
+ end
41
+ result = if proxy.is_real_method?(name)
42
+ proxy.__send__(name, *args)
43
+ else
44
+ proxy.__send__(:method_missing, name,*args)
45
+ end
46
+ block ? block.call(result) : result
47
+ end
48
+ end
49
+
50
+ PyMain = PyMainClass.instance
51
+ end