rubypython 0.2.11 → 0.3.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.
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