lib/pycall/pyobject.rb in pycall-0.1.0.alpha.20170307 vs lib/pycall/pyobject.rb in pycall-0.1.0.alpha.20170308

- old
+ new

@@ -1,173 +1,17 @@ module PyCall - Py_LT = 0 - Py_LE = 1 - Py_EQ = 2 - Py_NE = 3 - Py_GT = 4 - Py_GE = 5 + class PyObject + include PyObjectWrapper - RICH_COMPARISON_OPCODES = { - :< => Py_LT, - :<= => Py_LE, - :== => Py_EQ, - :!= => Py_NE, - :> => Py_GT, - :>= => Py_GE - }.freeze - - module PyObjectMethods - def rich_compare(other, op) - opcode = RICH_COMPARISON_OPCODES[op] - raise ArgumentError, "Unknown comparison op: #{op}" unless opcode - - other = Conversions.from_ruby(other) unless other.kind_of?(PyObject) - return other.null? if self.null? - return false if other.null? - - value = LibPython.PyObject_RichCompare(self, other, opcode) - raise "Unable to compare: #{self} #{op} #{other}" if value.null? - value.to_ruby - end - - RICH_COMPARISON_OPCODES.keys.each do |op| - define_method(op) {|other| rich_compare(other, op) } - end - - def py_none? - to_ptr == PyCall.None.to_ptr - end - - def kind_of?(klass) - case klass - when PyObject, PyTypeObject - Types.pyisinstance(self, klass) - else - super - end - end - end - - class PyObject < FFI::Struct - include PyObjectMethods - def self.null - new(FFI::Pointer::NULL) + new(LibPython::PyObjectStruct.new(FFI::Pointer::NULL)) end - - alias __aref__ [] - alias __aset__ []= - - def [](*indices) - if indices.length == 1 - indices = indices[0] - else - indices = PyCall.tuple(*indices) - end - PyCall.getitem(self, indices) - end - - def []=(*indices_and_value) - value = indices_and_value.pop - indices = indices_and_value - if indices.length == 1 - indices = indices[0] - else - indices = PyCall.tuple(*indices) - end - PyCall.setitem(self, indices, value) - end - - def +(other) - other = Conversions.from_ruby(other) - value = LibPython.PyNumber_Add(self, other) - return value.to_ruby unless value.null? - raise PyError.fetch - end - - def -(other) - other = Conversions.from_ruby(other) - value = LibPython.PyNumber_Subtract(self, other) - return value.to_ruby unless value.null? - raise PyError.fetch - end - - def *(other) - other = Conversions.from_ruby(other) - value = LibPython.PyNumber_Multiply(self, other) - return value.to_ruby unless value.null? - raise PyError.fetch - end - - def /(other) - other = Conversions.from_ruby(other) - value = LibPython.PyNumber_TrueDivide(self, other) - return value.to_ruby unless value.null? - raise PyError.fetch - end - - def **(other) - other = Conversions.from_ruby(other) - value = LibPython.PyNumber_Power(self, other, PyCall.None) - return value.to_ruby unless value.null? - raise PyError.fetch - end - - def coerce(other) - [Conversions.from_ruby(other), self] - end - - def call(*args, **kwargs) - args = PyCall::Tuple[*args] - kwargs = kwargs.empty? ? PyObject.null : PyCall::Dict.new(kwargs).__pyobj__ - res = LibPython.PyObject_Call(self, args.__pyobj__, kwargs) - return res.to_ruby if LibPython.PyErr_Occurred().null? - raise PyError.fetch - end - - def method_missing(name, *args, **kwargs) - if PyCall.hasattr?(self, name) - PyCall.getattr(self, name) - else - super - end - end - - def to_s - s = LibPython.PyObject_Repr(self) - if s.null? - LibPython.PyErr_Clear() - s = LibPython.PyObject_Str(self) - if s.null? - LibPython.PyErr_Clear() - return super - end - end - s.to_ruby - end - - alias inspect to_s - - def type - LibPython.PyObject_Type(self) - end end - class PyTypeObject < FFI::Struct - include PyObjectMethods - - def ===(obj) - obj.kind_of? self - end - - def inspect - "pytype(#{self[:tp_name]})" - end - end - def self.getattr(pyobj, name, default=nil) name = check_attr_name(name) + pyobj = pyobj.__pyobj__ unless pyobj.kind_of? LibPython::PyObjectStruct value = LibPython.PyObject_GetAttrString(pyobj, name) if value.null? return default if default raise PyError.fetch end @@ -175,16 +19,19 @@ end def self.setattr(pyobj, name, value) name = check_attr_name(name) value = Conversions.from_ruby(value) + value = value.__pyobj__ unless pyobj.kind_of? LibPython::PyObjectStruct + pyobj = pyobj.__pyobj__ unless pyobj.kind_of? LibPython::PyObjectStruct return self unless LibPython.PyObject_SetAttrString(pyobj, name, value) == -1 raise PyError.fetch end def self.hasattr?(pyobj, name) name = check_attr_name(name) + pyobj = pyobj.__pyobj__ unless pyobj.kind_of? LibPython::PyObjectStruct 1 == LibPython.PyObject_HasAttrString(pyobj, name) end def self.check_attr_name(name) return name.to_str if name.respond_to? :to_str @@ -192,16 +39,18 @@ raise TypeError, "attribute name must be a String or a Symbol: #{name.inspect}" end private_class_method :check_attr_name def self.getitem(pyobj, key) + pyobj = pyobj.__pyobj__ unless pyobj.kind_of? LibPython::PyObjectStruct pykey = Conversions.from_ruby(key) value = LibPython.PyObject_GetItem(pyobj, pykey) return value.to_ruby unless value.null? raise PyError.fetch end def self.setitem(pyobj, key, value) + pyobj = pyobj.__pyobj__ unless pyobj.kind_of? LibPython::PyObjectStruct pykey = Conversions.from_ruby(key) value = Conversions.from_ruby(value) return self unless LibPython.PyObject_SetItem(pyobj, pykey, value) == -1 raise PyError.fetch end