Commits

Austin Ziegler committed 6203ed3

Modernize RubyPython tests.

- Add travis support (it won't work at first, probably).

  • Participants
  • Parent commits a928ad3

Comments (0)

Files changed (27)

File .gemtest

Empty file added.
 .rake_tasks~
 .rvmrc
 .yardoc/*
+.vagrant/*
 coverage.info
 coverage/*
 doc/*
+---
+language: ruby
+rvm:
+  - 2.1.0
+  - 2.0.0
+  - 1.9.3
+  - 1.9.2
+  - jruby-19mode
+  - rbx
+  - 1.8.7
+  - jruby-18mode
+  - ree
+  - ruby-head
+  - jruby-head
+matrix:
+  allow_failures:
+    - rvm: rbx
+before_script:
+  - gem install hoe-travis --no-rdoc --no-ri
+  - rake travis:before -t
+script: rake travis
+after_script:
+  - rake travis:after -t
+notifications:
+  recipients:
+    - austin@rubyforge.org
+  email:
+    - on_success: change
+    - on_failure: always
+# -*- ruby -*-
+
+# NOTE: This file is present to keep Travis CI happy. Edits to it will not
+# be accepted.
+
+source "https://rubygems.org/"
+gemspec
+
+# vim: syntax=ruby

File Manifest.txt

 .autotest
+.gitignore
+.hgignore
+.hgtags
 .rspec
 Contributors.rdoc
 History.rdoc
 spec/rubypyproxy_spec.rb
 spec/rubypython_spec.rb
 spec/spec_helper.rb
+website/index.rhtml
+website/robots.txt
+website/stylesheets/960.css
+website/stylesheets/border-radius.htc
+website/stylesheets/screen.css
 require 'hoe'
 
 Hoe.plugin :doofus
-Hoe.plugin :gemspec
-Hoe.plugin :rubyforge
+Hoe.plugin :gemspec2
+Hoe.plugin :rubyforge unless ENV['CI'] or ENV['TRAVIS']
 Hoe.plugin :git
 Hoe.plugin :hg
+Hoe.plugin :travis
 
 Hoe.spec 'rubypython' do
   self.rubyforge_name = self.name
   developer('Austin Ziegler', 'austin@rubyforge.org')
   developer('Zach Raines', 'raineszm+rubypython@gmail.com')
 
+  license 'MIT'
+
   self.remote_rdoc_dir = 'rdoc'
   self.rsync_args << ' --exclude=statsvn/'
 
   self.readme_file = 'README.rdoc'
   self.extra_rdoc_files = FileList["*.rdoc"].to_a
 
-  self.extra_deps << ['ffi', '>= 1.0.7']
-  self.extra_deps << ['blankslate', '>= 2.1.2.3']
+  self.extra_deps << ['ffi', ['~> 1.0', '>= 1.0.7']]
+  self.extra_deps << ['blankslate', '~> 3.1']
+
+  self.extra_dev_deps << ['hoe-doofus', '~> 1.0']
+  self.extra_dev_deps << ['hoe-gemspec2', '~> 1.1']
+  self.extra_dev_deps << ['hoe-git', '~> 1.5']
+  self.extra_dev_deps << ['hoe-hg', '~> 1.0']
+  self.extra_dev_deps << ['hoe-rubygems', '~> 1.0']
+  self.extra_dev_deps << ['hoe-travis', '~> 1.2']
 
   self.extra_dev_deps << ['rspec', '~> 2.0']
-  self.extra_dev_deps << ['tilt', '~> 1.0']
+  self.extra_dev_deps << ['tilt', '~> 2.0']
 
   self.spec_extras[:requirements]  = [ "Python, ~> 2.4" ]
 end
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
+VAGRANTFILE_API_VERSION = "2"
+
+provision = <<-EOS
+sudo apt-get install -y git zsh rake ruby-dev
+sudo locale-gen en_CA.UTF-8
+sudo chsh -s/bin/zsh vagrant
+git clone https://github.com/halostatue/dotfiles .dotfiles
+sudo apt-get autoremove -y
+EOS
+
+Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
+  # All Vagrant configuration is done here. The most common configuration
+  # options are documented and commented below. For a complete reference,
+  # please see the online documentation at vagrantup.com.
+
+  # Every Vagrant virtual environment requires a box to build off of.
+  config.vm.box = "saucy64"
+
+  # The url from where the 'config.vm.box' box will be fetched if it doesn't
+  # already exist on the user's system.
+  config.vm.box_url =
+    "http://cloud-images.ubuntu.com/vagrant/saucy/current/saucy-server-cloudimg-amd64-vagrant-disk1.box"
+
+  config.vm.provision :shell, inline: provision
+
+  # Create a forwarded port mapping which allows access to a specific port
+  # within the machine from a port on the host machine. In the example below,
+  # accessing "localhost:8080" will access port 80 on the guest machine.
+  # config.vm.network :forwarded_port, guest: 80, host: 8080
+
+  # Create a private network, which allows host-only access to the machine
+  # using a specific IP.
+  # config.vm.network :private_network, ip: "192.168.33.10"
+
+  # If true, then any SSH connections made will enable agent forwarding.
+  # Default value: false
+  config.ssh.forward_agent = true
+
+  # Share an additional folder to the guest VM. The first argument is
+  # the path on the host to the actual folder. The second argument is
+  # the path on the guest to mount the folder. And the optional third
+  # argument is a set of non-required options.
+  # config.vm.synced_folder "../data", "/vagrant_data"
+end

File lib/rubypython.rb

 #   puts cPickle.dumps("RubyPython is awesome!").rubify
 #   RubyPython.stop
 module RubyPython
-  VERSION = '0.6.3'
+  VERSION = '0.7'
 end
 
 require 'rubypython/blankobject'

File lib/rubypython/conversion.rb

   # Raised when RubyPython does not know how to convert an object from
   # \Python to Ruby or vice versa.
   class UnsupportedConversion < Exception; end
+  # Raised when RubyPython does encounters an error when converting an
+  # object from \Python to Ruby or vice versa.
   class ConversionError < RuntimeError; end
 
-  # Convert a Ruby string to a \Python string. Returns an FFI::Pointer to
-  # a PyStringObject.
-  def self.rtopString(rString)
-    size = rString.respond_to?(:bytesize) ? rString.bytesize : rString.size
-    ptr = RubyPython::Python.PyString_FromStringAndSize(rString, size)
-    if ptr.null?
-      raise ConversionError.new "Python failed to create a string with contents #{rString}"
-    else
-      ptr
+  class << self
+    # Convert a Ruby string to a \Python string. Returns an FFI::Pointer to
+    # a PyStringObject.
+    def rtopString(rString)
+      size = rString.respond_to?(:bytesize) ? rString.bytesize : rString.size
+      ptr = RubyPython::Python.PyString_FromStringAndSize(rString, size)
+      if ptr.null?
+        raise ConversionError, "Python failed to create a string with contents #{rString}"
+      else
+        ptr
+      end
     end
-  end
 
-  # Convert a Ruby Array to \Python List. Returns an FFI::Pointer to
-  # a PyListObject.
-  def self.rtopArrayToList(rArray)
-    size = rArray.length
-    pList = RubyPython::Python.PyList_New size
-    if pList.null?
-      raise ConversionError.new "Python failed to create list of size #{size}"
+    # Convert a Ruby Array to \Python List. Returns an FFI::Pointer to
+    # a PyListObject.
+    def rtopArrayToList(rArray)
+      size = rArray.length
+      pList = RubyPython::Python.PyList_New(size)
+      if pList.null?
+        raise ConversionError, "Python failed to create list of size #{size}"
+      end
+      rArray.each_with_index do |el, i|
+        # PyList_SetItem steals a reference, but rtopObject creates a new
+        # reference. So we wind up with giving a new reference to the Python
+        # interpreter for every object.
+        ret = RubyPython::Python.PyList_SetItem(pList, i, rtopObject(el))
+        if ret == -1
+          raise ConversionError, "Failed to set item #{el} in array conversion"
+        end
+      end
+      pList
     end
-    rArray.each_with_index do |el, i|
-      # PyList_SetItem steals a reference, but rtopObject creates a new reference
-      # So we wind up with giving a new reference to the Python interpreter for every
-      # object
-      ret = RubyPython::Python.PyList_SetItem pList, i, rtopObject(el)
-      raise ConversionError.new "Failed to set item #{el} in array conversion" if ret == -1
+
+    # Convert a Ruby Array (including the subclass RubyPython::Tuple) to
+    # \Python \tuple. Returns an FFI::Pointer to a PyTupleObject.
+    def rtopArrayToTuple(rArray)
+      pList = rtopArrayToList(rArray)
+      pTuple = RubyPython::Python.PyList_AsTuple(pList)
+      RubyPython::Python.Py_DecRef(pList)
+      if pTuple.null?
+        raise Conversion, "Python failed to convert an intermediate list of #{rArray} to a tuple"
+      end
+      pTuple
     end
-    pList
-  end
 
-  # Convert a Ruby Array (including the subclass RubyPython::Tuple) to
-  # \Python \tuple. Returns an FFI::Pointer to a PyTupleObject.
-  def self.rtopArrayToTuple(rArray)
-    pList = rtopArrayToList(rArray)
-    pTuple = RubyPython::Python.PyList_AsTuple(pList)
-    RubyPython::Python.Py_DecRef(pList)
-    if pTuple.null?
-      raise Conversion.new "Python failed to convert an intermediate list of #{rArray} to a tuple"
-    end
-    pTuple
-  end
+    # Convert a Ruby Hash to a \Python Dict. Returns an FFI::Pointer to a
+    # PyDictObject.
+    def rtopHash(rHash)
+      pDict = RubyPython::Python.PyDict_New
+      if pDict.null?
+        raise ConversionError, "Python failed to create new dict"
+      end
+      rHash.each do |k,v|
+        key = rtopObject(k, :key => true)
+        value = rtopObject(v)
 
-  # Convert a Ruby Hash to a \Python Dict. Returns an FFI::Pointer to a
-  # PyDictObject.
-  def self.rtopHash(rHash)
-    pDict = RubyPython::Python.PyDict_New
-    if pDict.null?
-      raise ConversionError.new "Python failed to create new dict"
-    end
-    rHash.each do |k,v|
-      key = rtopObject(k, :key => true)
-      value = rtopObject(v)
+        # PyDict_SetItem INCREFS both the key and the value passed to it.
+        # Since rtopObject already gives us a new reference, this is not necessary.
+        # Thus, we decref the passed in objects to balancy things out
+        if RubyPython::Python.PyDict_SetItem(pDict, key, value) == -1
+          raise ConversionError, "Python failed to set #{key}, #{value} in dict conversion"
+        end
 
-      # PyDict_SetItem INCREFS both the key and the value passed to it.
-      # Since rtopObject already gives us a new reference, this is not necessary.
-      # Thus, we decref the passed in objects to balancy things out
-      if RubyPython::Python.PyDict_SetItem(pDict, key, value) == -1
-        raise ConversionError.new "Python failed to set #{key}, #{value} in dict conversion"
+        RubyPython::Python.Py_DecRef key
+        RubyPython::Python.Py_DecRef value
       end
 
-      RubyPython::Python.Py_DecRef key
-      RubyPython::Python.Py_DecRef value
+      pDict
     end
 
-    pDict
-  end
-
-  # Convert a Ruby Fixnum to a \Python Int. Returns an FFI::Pointer to a
-  # PyIntObject.
-  def self.rtopFixnum(rNum)
-    num = RubyPython::Python.PyInt_FromLong(rNum)
-    raise ConversionError.new "Failed to convert #{rNum}" if num.null?
-    num
-  end
-
-  # Convert a Ruby Bignum to a \Python Long. Returns an FFI::Pointer to a
-  # PyLongObject.
-  def self.rtopBigNum(rNum)
-    num = RubyPython::Python.PyLong_FromLong(rNum)
-    raise ConversionError.new "Failed to convert #{rNum}" if num.null?
-    num
-  end
-
-  # Convert a Ruby float to a \Python Float. Returns an FFI::Pointer to a
-  # PyFloatObject.
-  def self.rtopFloat(rNum)
-    num = RubyPython::Python.PyFloat_FromDouble(rNum)
-    raise ConversionError.new "Failed to convert #{rNum}" if num.null?
-    num
-  end
-
-  # Returns a \Python False value (equivalent to Ruby's +false+). Returns an
-  # FFI::Pointer to Py_ZeroStruct.
-  def self.rtopFalse
-    RubyPython::Macros.Py_RETURN_FALSE
-  end
-
-  # Returns a \Python True value (equivalent to Ruby's +true+). Returns an
-  # FFI::Pointer to Py_TrueStruct.
-  def self.rtopTrue
-    RubyPython::Macros.Py_RETURN_TRUE
-  end
-
-  # Returns a \Python None value (equivalent to Ruby's +nil+). Returns an
-  # FFI::Pointer to Py_NoneStruct.
-  def self.rtopNone
-    RubyPython::Macros.Py_RETURN_NONE
-  end
-
-  # Convert a Ruby Symbol to a \Python String. Returns an FFI::Pointer to a
-  # PyStringObject.
-  def self.rtopSymbol(rSymbol)
-    rtopString rSymbol.to_s
-  end
-
-  # Convert a Ruby Proc to a \Python Function. Returns an FFI::Pointer to a
-  # PyCFunction.
-  def self.rtopFunction(rObj)
-    proc = ::FFI::Function.new(:pointer, [:pointer, :pointer]) do |p_self, p_args|
-      retval = rObj.call(*ptorTuple(p_args))
-      pObject = retval.is_a?(RubyPython::RubyPyProxy) ? retval.pObject : RubyPython::PyObject.new(retval)
-
-      # make sure the refcount is >1 when pObject is destroyed
-      pObject.xIncref
-      pObject.pointer
+    # Convert a Ruby Fixnum to a \Python Int. Returns an FFI::Pointer to a
+    # PyIntObject.
+    def rtopFixnum(rNum)
+      num = RubyPython::Python.PyInt_FromLong(rNum)
+      raise ConversionError, "Failed to convert #{rNum}" if num.null?
+      num
     end
 
-    defn = RubyPython::Python::PyMethodDef.new
-    defn[:ml_name] = ::FFI::MemoryPointer.from_string("RubyPython::Proc::%s" % rObj.object_id)
-    defn[:ml_meth] = proc
-    defn[:ml_flags] = RubyPython::Python::METH_VARARGS
-    defn[:ml_doc] = nil
-
-    return RubyPython::Python.PyCFunction_New(defn, nil)
-  end
-
-  # This will attempt to convert a Ruby object to an equivalent \Python
-  # native type. Returns an FFI::Pointer to a \Python object (the
-  # appropriate Py_Object C structure). If the conversion is unsuccessful,
-  # will raise UnsupportedConversion.
-  #
-  # [rObj]    A native Ruby object.
-  # [is_key]  Set to +true+ if the provided Ruby object will be used as a
-  #           key in a \Python +dict+. (This primarily matters for Array
-  #           conversion.)
-  def self.rtopObject(rObj, is_key = false)
-    case rObj
-    when String
-      rtopString rObj
-    when RubyPython::Tuple
-      rtopArrayToTuple rObj
-    when Array
-      # If this object is going to be used as a hash key we should make it a
-      # tuple instead of a list
-      if is_key
-        rtopArrayToTuple rObj
-      else
-        rtopArrayToList rObj
-      end
-    when Hash
-      rtopHash rObj
-    when Fixnum
-      rtopFixnum rObj
-    when Bignum
-      rtopBignum rObj
-    when Float
-      rtopFloat rObj
-    when true
-      rtopTrue
-    when false
-      rtopFalse
-    when Symbol
-      rtopSymbol rObj
-    when Proc, Method
-      rtopFunction rObj
-    when nil
-      rtopNone
-    when RubyPython::PyObject
-      rObj.xIncref
-      rObj.pointer
-    when RubyPython::RubyPyProxy
-      rtopObject(rObj.pObject, is_key)
-    else
-      raise UnsupportedConversion.new("Unsupported type #{rObj.class} for conversion.")
-    end
-  end
-
-  # Convert an FFI::Pointer to a \Python String (PyStringObject) to a Ruby
-  # String.
-  def self.ptorString(pString)
-    #strPtr is a pointer to a pointer to the internal character array.
-    #FFI will free strPtr when we are done but the internal array MUST
-    #not be modified
-    strPtr  = ::FFI::MemoryPointer.new(:pointer)
-    sizePtr = ::FFI::MemoryPointer.new(:ssize_t)
-
-    RubyPython::Python.PyString_AsStringAndSize(pString, strPtr, sizePtr)
-
-    size = case ::FFI.find_type(:ssize_t)
-           when ::FFI.find_type(:long)
-             sizePtr.read_long
-           when ::FFI.find_type(:int)
-             sizePtr.read_int
-           when ::FFI.find_type(:long_long)
-             sizePtr.read_long_long
-           else
-             nil
-           end
-
-    strPtr.read_pointer.read_string(size)
-  end
-
-  # Convert an FFI::Pointer to a \Python List (PyListObject) to a Ruby
-  # Array.
-  def self.ptorList(pList)
-    rb_array = []
-    list_size = RubyPython::Python.PyList_Size(pList)
-
-    list_size.times do |i|
-      element = RubyPython::Python.PyList_GetItem(pList, i)
-      rObject = ptorObject(element)
-      rb_array.push rObject
+    # Convert a Ruby Bignum to a \Python Long. Returns an FFI::Pointer to a
+    # PyLongObject.
+    def rtopBigNum(rNum)
+      num = RubyPython::Python.PyLong_FromLong(rNum)
+      raise ConversionError, "Failed to convert #{rNum}" if num.null?
+      num
     end
 
-    rb_array
-  end
-
-  # Convert an FFI::Pointer to a \Python Int (PyIntObject) to a Ruby Fixnum.
-  def self.ptorInt(pNum)
-    RubyPython::Python.PyInt_AsLong(pNum)
-  end
-
-  # Convert an FFI::Pointer to a \Python Long (PyLongObject) to a Ruby
-  # Fixnum. This version does not do overflow checking, but probably should.
-  def self.ptorLong(pNum)
-    RubyPython::Python.PyLong_AsLong(pNum)
-    # TODO Overflow Checking
-  end
-
-  # Convert an FFI::Pointer to a \Python Float (PyFloatObject) to a Ruby
-  # Float.
-  def self.ptorFloat(pNum)
-    RubyPython::Python.PyFloat_AsDouble(pNum)
-  end
-
-  # Convert an FFI::Pointer to a \Python Tuple (PyTupleObject) to an
-  # instance of RubyPython::Tuple, a subclass of the Ruby Array class.
-  def self.ptorTuple(pTuple)
-    #PySequence_List returns a new list. Since we are only using it as a temporary
-    #here, we will have to DecRef it once we are done.
-    pList = RubyPython::Python.PySequence_List pTuple
-    rArray = ptorList pList
-    RubyPython::Python.Py_DecRef pList
-    RubyPython::Tuple.tuple(rArray)
-  end
-
-  # Convert an FFI::Pointer to a \Python Dictionary (PyDictObject) to a Ruby
-  # Hash.
-  def self.ptorDict(pDict)
-    rb_hash = {}
-
-    pos = ::FFI::MemoryPointer.new :ssize_t
-    pos.write_int 0
-    key = ::FFI::MemoryPointer.new :pointer
-    val = ::FFI::MemoryPointer.new :pointer
-
-    while RubyPython::Python.PyDict_Next(pDict, pos, key, val) != 0
-      #PyDict_Next sets key and val to borrowed references. We do not care
-      #if we are able to convert them to native ruby types, but if we wind up
-      #wrapping either in a proxy we better IncRef it to make sure it stays
-      #around.
-      pKey = key.read_pointer
-      pVal = val.read_pointer
-      rKey = ptorObject(pKey)
-      rVal = ptorObject(pVal)
-      RubyPython.Py_IncRef pKey if rKey.kind_of? ::FFI::Pointer
-      RubyPython.Py_IncRef pVal if rVal.kind_of? ::FFI::Pointer
-      rb_hash[rKey] = rVal
+    # Convert a Ruby float to a \Python Float. Returns an FFI::Pointer to a
+    # PyFloatObject.
+    def rtopFloat(rNum)
+      num = RubyPython::Python.PyFloat_FromDouble(rNum)
+      raise ConversionError, "Failed to convert #{rNum}" if num.null?
+      num
     end
 
-    rb_hash
-  end
+    # Returns a \Python False value (equivalent to Ruby's +false+). Returns an
+    # FFI::Pointer to Py_ZeroStruct.
+    def rtopFalse
+      RubyPython::Macros.Py_RETURN_FALSE
+    end
 
-  # Converts a pointer to a \Python object into a native Ruby type, if
-  # possible. If the conversion cannot be done, the Python object will be
-  # returned unmodified.
-  #
-  # [pObj]  An FFI::Pointer to a \Python object.
-  def self.ptorObject(pObj)
-    if RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyString_Type.to_ptr) != 0
-      ptorString pObj
-    elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyList_Type.to_ptr) != 0
-      ptorList pObj
-    elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyInt_Type.to_ptr) != 0
-      ptorInt pObj
-    elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyLong_Type.to_ptr) != 0
-      ptorLong pObj
-    elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyFloat_Type.to_ptr) != 0
-      ptorFloat pObj
-    elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyTuple_Type.to_ptr) != 0
-      ptorTuple pObj
-    elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyDict_Type.to_ptr) != 0
-      ptorDict pObj
-    elsif pObj == RubyPython::Macros.Py_True
-      true
-    elsif pObj == RubyPython::Macros.Py_False
-      false
-    elsif pObj == RubyPython::Macros.Py_None
-      nil
-    else
-      pObj
+    # Returns a \Python True value (equivalent to Ruby's +true+). Returns an
+    # FFI::Pointer to Py_TrueStruct.
+    def rtopTrue
+      RubyPython::Macros.Py_RETURN_TRUE
+    end
+
+    # Returns a \Python None value (equivalent to Ruby's +nil+). Returns an
+    # FFI::Pointer to Py_NoneStruct.
+    def rtopNone
+      RubyPython::Macros.Py_RETURN_NONE
+    end
+
+    # Convert a Ruby Symbol to a \Python String. Returns an FFI::Pointer to a
+    # PyStringObject.
+    def rtopSymbol(rSymbol)
+      rtopString rSymbol.to_s
+    end
+
+    # Convert a Ruby Proc to a \Python Function. Returns an FFI::Pointer to a
+    # PyCFunction.
+    def rtopFunction(rObj)
+      proc = ::FFI::Function.new(:pointer, [:pointer, :pointer]) do |p_self, p_args|
+        retval = rObj.call(*ptorTuple(p_args))
+        pObject = retval.is_a?(RubyPython::RubyPyProxy) ? retval.pObject : RubyPython::PyObject.new(retval)
+
+        # make sure the refcount is >1 when pObject is destroyed
+        pObject.xIncref
+        pObject.pointer
+      end
+
+      defn = RubyPython::Python::PyMethodDef.new
+      defn[:ml_name] = ::FFI::MemoryPointer.from_string("RubyPython::Proc::%s" % rObj.object_id)
+      defn[:ml_meth] = proc
+      defn[:ml_flags] = RubyPython::Python::METH_VARARGS
+      defn[:ml_doc] = nil
+
+      return RubyPython::Python.PyCFunction_New(defn, nil)
+    end
+
+    # This will attempt to convert a Ruby object to an equivalent \Python
+    # native type. Returns an FFI::Pointer to a \Python object (the
+    # appropriate Py_Object C structure). If the conversion is unsuccessful,
+    # will raise UnsupportedConversion.
+    #
+    # [rObj]    A native Ruby object.
+    # [is_key]  Set to +true+ if the provided Ruby object will be used as a
+    #           key in a \Python +dict+. (This primarily matters for Array
+    #           conversion.)
+    def rtopObject(rObj, is_key = false)
+      case rObj
+      when String
+        rtopString rObj
+      when RubyPython::Tuple
+        rtopArrayToTuple rObj
+      when Array
+        # If this object is going to be used as a hash key we should make it a
+        # tuple instead of a list
+        if is_key
+          rtopArrayToTuple rObj
+        else
+          rtopArrayToList rObj
+        end
+      when Hash
+        rtopHash rObj
+      when Fixnum
+        rtopFixnum rObj
+      when Bignum
+        rtopBignum rObj
+      when Float
+        rtopFloat rObj
+      when true
+        rtopTrue
+      when false
+        rtopFalse
+      when Symbol
+        rtopSymbol rObj
+      when Proc, Method
+        rtopFunction rObj
+      when nil
+        rtopNone
+      when RubyPython::PyObject
+        rObj.xIncref
+        rObj.pointer
+      when RubyPython::RubyPyProxy
+        rtopObject(rObj.pObject, is_key)
+      else
+        raise UnsupportedConversion.new("Unsupported type #{rObj.class} for conversion.")
+      end
+    end
+
+    # Convert an FFI::Pointer to a \Python String (PyStringObject) to a Ruby
+    # String.
+    def ptorString(pString)
+      #strPtr is a pointer to a pointer to the internal character array.
+      #FFI will free strPtr when we are done but the internal array MUST
+      #not be modified
+      strPtr  = ::FFI::MemoryPointer.new(:pointer)
+      sizePtr = ::FFI::MemoryPointer.new(:ssize_t)
+
+      RubyPython::Python.PyString_AsStringAndSize(pString, strPtr, sizePtr)
+
+      size = case ::FFI.find_type(:ssize_t)
+             when ::FFI.find_type(:long)
+               sizePtr.read_long
+             when ::FFI.find_type(:int)
+               sizePtr.read_int
+             when ::FFI.find_type(:long_long)
+               sizePtr.read_long_long
+             else
+               nil
+             end
+
+      strPtr.read_pointer.read_string(size)
+    end
+
+    # Convert an FFI::Pointer to a \Python List (PyListObject) to a Ruby
+    # Array.
+    def ptorList(pList)
+      rb_array = []
+      list_size = RubyPython::Python.PyList_Size(pList)
+
+      list_size.times do |i|
+        element = RubyPython::Python.PyList_GetItem(pList, i)
+        rObject = ptorObject(element)
+        rb_array.push rObject
+      end
+
+      rb_array
+    end
+
+    # Convert an FFI::Pointer to a \Python Int (PyIntObject) to a Ruby Fixnum.
+    def ptorInt(pNum)
+      RubyPython::Python.PyInt_AsLong(pNum)
+    end
+
+    # Convert an FFI::Pointer to a \Python Long (PyLongObject) to a Ruby
+    # Fixnum. This version does not do overflow checking, but probably should.
+    def ptorLong(pNum)
+      RubyPython::Python.PyLong_AsLong(pNum)
+      # TODO Overflow Checking
+    end
+
+    # Convert an FFI::Pointer to a \Python Float (PyFloatObject) to a Ruby
+    # Float.
+    def ptorFloat(pNum)
+      RubyPython::Python.PyFloat_AsDouble(pNum)
+    end
+
+    # Convert an FFI::Pointer to a \Python Tuple (PyTupleObject) to an
+    # instance of RubyPython::Tuple, a subclass of the Ruby Array class.
+    def ptorTuple(pTuple)
+      #PySequence_List returns a new list. Since we are only using it as a temporary
+      #here, we will have to DecRef it once we are done.
+      pList = RubyPython::Python.PySequence_List pTuple
+      rArray = ptorList pList
+      RubyPython::Python.Py_DecRef pList
+      RubyPython::Tuple.tuple(rArray)
+    end
+
+    # Convert an FFI::Pointer to a \Python Dictionary (PyDictObject) to a Ruby
+    # Hash.
+    def ptorDict(pDict)
+      rb_hash = {}
+
+      pos = ::FFI::MemoryPointer.new :ssize_t
+      pos.write_int 0
+      key = ::FFI::MemoryPointer.new :pointer
+      val = ::FFI::MemoryPointer.new :pointer
+
+      while RubyPython::Python.PyDict_Next(pDict, pos, key, val) != 0
+        #PyDict_Next sets key and val to borrowed references. We do not care
+        #if we are able to convert them to native ruby types, but if we wind up
+        #wrapping either in a proxy we better IncRef it to make sure it stays
+        #around.
+        pKey = key.read_pointer
+        pVal = val.read_pointer
+        rKey = ptorObject(pKey)
+        rVal = ptorObject(pVal)
+        RubyPython.Py_IncRef pKey if rKey.kind_of? ::FFI::Pointer
+        RubyPython.Py_IncRef pVal if rVal.kind_of? ::FFI::Pointer
+        rb_hash[rKey] = rVal
+      end
+
+      rb_hash
+    end
+
+    # Converts a pointer to a \Python object into a native Ruby type, if
+    # possible. If the conversion cannot be done, the Python object will be
+    # returned unmodified.
+    #
+    # [pObj] An FFI::Pointer to a \Python object.
+    def ptorObject(pObj)
+      if RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyString_Type.to_ptr) != 0
+        ptorString pObj
+      elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyList_Type.to_ptr) != 0
+        ptorList pObj
+      elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyInt_Type.to_ptr) != 0
+        ptorInt pObj
+      elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyLong_Type.to_ptr) != 0
+        ptorLong pObj
+      elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyFloat_Type.to_ptr) != 0
+        ptorFloat pObj
+      elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyTuple_Type.to_ptr) != 0
+        ptorTuple pObj
+      elsif RubyPython::Macros.PyObject_TypeCheck(pObj, RubyPython::Python.PyDict_Type.to_ptr) != 0
+        ptorDict pObj
+      elsif pObj == RubyPython::Macros.Py_True
+        true
+      elsif pObj == RubyPython::Macros.Py_False
+        false
+      elsif pObj == RubyPython::Macros.Py_None
+        nil
+      else
+        pObj
+      end
     end
   end
 end

File lib/rubypython/interpreter.rb

 # interpreter (from +RubyPython.python+), but should not directly
 # instantiate this class.
 class RubyPython::Interpreter
-
   ##
   # Compare the current Interpreter to the provided Interpreter or
   # configuration hash. A configuration hash will be converted to an
   def initialize(options = {})
     @python_exe = options[:python_exe]
     # Windows: 'C:\\Python27\python.exe'
-    # Mac OS X: '/usr/bin/
+    # Mac OS X: '/usr/bin/'
 
     # The default interpreter might be python3 on some systems
     rc, majorversion = runpy "import sys; print(sys.version_info[0])"
     end
 
     if ::FFI::Platform.unix?
-      # On Unixes, let's look in some standard alternative places, too.
-      # Just in case. Some Unixes don't include a .so symlink when they
-      # should, so let's look for the base cases of .so.1 and .so.1.0, too.
+      # On Unixes, let's look in some standard alternative places, too. Just
+      # in case. Some Unixes don't include a .so symlink when they should,
+      # so let's look for the base cases of .so.1 and .so.1.0, too.
       [ @libname, "#{@libname}.1", "#{@libname}.1.0" ].each do |name|
         if ::FFI::Platform::ARCH != 'i386'
           @locations << File.join("/opt/local/lib64", name)

File lib/rubypython/pyobject.rb

   # PyObject wrapper around the returned object, which may be +NULL+.
   # [rbPyArgs]  A PyObject wrapping a Tuple of the supplied arguments.
   def callObject(rbPyArgs)
-    pyReturn = RubyPython::Python.PyObject_CallObject(@pointer, rbPyArgs.pointer)
+    pyReturn =
+      RubyPython::Python.PyObject_CallObject(@pointer, rbPyArgs.pointer)
     self.class.new pyReturn
   end
 

File lib/rubypython/rubypyproxy.rb

       end
     end
 
-    #Handles the of calling a wrapped callable Python object at a higher level
-    #than +PyObject#callObject+. For internal use only.
+    # Handles the of calling a wrapped callable Python object at a higher
+    # level than +PyObject#callObject+. For internal use only.
     def _method_call(pFunc, args, pKeywords)
       pTuple = PyObject.buildArgTuple(*args)
       pReturn = if pKeywords

File lib/rubypython/tuple.rb

       value
     end
   end
+
+  # A conversion method.
+  def self.Tuple(array)
+    ::RubyPython::Tuple.tuple(array)
+  end
 end

File rubypython.gemspec

+# -*- encoding: utf-8 -*-
+# stub: rubypython 0.7 ruby lib
+
+Gem::Specification.new do |s|
+  s.name = "rubypython"
+  s.version = "0.7"
+
+  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+  s.require_paths = ["lib"]
+  s.authors = ["Steeve Morin", "Austin Ziegler", "Zach Raines"]
+  s.date = "2014-02-05"
+  s.description = "RubyPython is a bridge between the Ruby and Python interpreters. It embeds a\nrunning Python interpreter in the Ruby application's process using FFI and\nprovides a means for wrapping, converting, and calling Python objects and\nmethods.\n\nRubyPython uses FFI to marshal the data between the Ruby and Python VMs and\nmake Python calls. You can:\n\n* Inherit from Python classes.\n* Configure callbacks from Python.\n* Run Python generators (on Ruby 1.9.2 or later)."
+  s.email = ["swiuzzz+rubypython@gmail.com", "austin@rubyforge.org", "raineszm+rubypython@gmail.com"]
+  s.extra_rdoc_files = ["Contributors.rdoc", "History.rdoc", "License.rdoc", "Manifest.txt", "PostInstall.txt", "README.rdoc", "website/robots.txt", "Contributors.rdoc", "History.rdoc", "License.rdoc", "README.rdoc"]
+  s.files = [".autotest", ".gemtest", ".gitignore", ".hgignore", ".hgtags", ".rspec", "Contributors.rdoc", "History.rdoc", "License.rdoc", "Manifest.txt", "PostInstall.txt", "README.rdoc", "Rakefile", "autotest/discover.rb", "lib/rubypython.rb", "lib/rubypython/blankobject.rb", "lib/rubypython/conversion.rb", "lib/rubypython/interpreter.rb", "lib/rubypython/macros.rb", "lib/rubypython/operators.rb", "lib/rubypython/pygenerator.rb", "lib/rubypython/pymainclass.rb", "lib/rubypython/pyobject.rb", "lib/rubypython/python.rb", "lib/rubypython/pythonerror.rb", "lib/rubypython/rubypyproxy.rb", "lib/rubypython/tuple.rb", "lib/rubypython/type.rb", "spec/basic_spec.rb", "spec/callback_spec.rb", "spec/conversion_spec.rb", "spec/pymainclass_spec.rb", "spec/pyobject_spec.rb", "spec/python_helpers/basics.py", "spec/python_helpers/errors.py", "spec/python_helpers/objects.py", "spec/pythonerror_spec.rb", "spec/refcnt_spec.rb", "spec/rubypyclass_spec.rb", "spec/rubypyproxy_spec.rb", "spec/rubypython_spec.rb", "spec/spec_helper.rb", "website/index.rhtml", "website/robots.txt", "website/stylesheets/960.css", "website/stylesheets/border-radius.htc", "website/stylesheets/screen.css"]
+  s.licenses = ["MIT"]
+  s.rdoc_options = ["--main", "README.rdoc"]
+  s.requirements = ["Python, ~> 2.4"]
+  s.rubyforge_project = "rubypython"
+  s.rubygems_version = "2.2.1"
+  s.summary = "RubyPython is a bridge between the Ruby and Python interpreters"
+
+  if s.respond_to? :specification_version then
+    s.specification_version = 4
+
+    if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
+      s.add_runtime_dependency(%q<ffi>, [">= 1.0.7", "~> 1.0"])
+      s.add_runtime_dependency(%q<blankslate>, ["~> 3.1"])
+      s.add_development_dependency(%q<rubyforge>, [">= 2.0.4"])
+      s.add_development_dependency(%q<rdoc>, ["~> 4.0"])
+      s.add_development_dependency(%q<hoe-doofus>, ["~> 1.0"])
+      s.add_development_dependency(%q<hoe-gemspec2>, ["~> 1.1"])
+      s.add_development_dependency(%q<hoe-git>, ["~> 1.5"])
+      s.add_development_dependency(%q<hoe-hg>, ["~> 1.0"])
+      s.add_development_dependency(%q<hoe-rubygems>, ["~> 1.0"])
+      s.add_development_dependency(%q<hoe-travis>, ["~> 1.2"])
+      s.add_development_dependency(%q<rspec>, ["~> 2.0"])
+      s.add_development_dependency(%q<tilt>, ["~> 2.0"])
+      s.add_development_dependency(%q<hoe>, ["~> 3.8"])
+    else
+      s.add_dependency(%q<ffi>, [">= 1.0.7", "~> 1.0"])
+      s.add_dependency(%q<blankslate>, ["~> 3.1"])
+      s.add_dependency(%q<rubyforge>, [">= 2.0.4"])
+      s.add_dependency(%q<rdoc>, ["~> 4.0"])
+      s.add_dependency(%q<hoe-doofus>, ["~> 1.0"])
+      s.add_dependency(%q<hoe-gemspec2>, ["~> 1.1"])
+      s.add_dependency(%q<hoe-git>, ["~> 1.5"])
+      s.add_dependency(%q<hoe-hg>, ["~> 1.0"])
+      s.add_dependency(%q<hoe-rubygems>, ["~> 1.0"])
+      s.add_dependency(%q<hoe-travis>, ["~> 1.2"])
+      s.add_dependency(%q<rspec>, ["~> 2.0"])
+      s.add_dependency(%q<tilt>, ["~> 2.0"])
+      s.add_dependency(%q<hoe>, ["~> 3.8"])
+    end
+  else
+    s.add_dependency(%q<ffi>, [">= 1.0.7", "~> 1.0"])
+    s.add_dependency(%q<blankslate>, ["~> 3.1"])
+    s.add_dependency(%q<rubyforge>, [">= 2.0.4"])
+    s.add_dependency(%q<rdoc>, ["~> 4.0"])
+    s.add_dependency(%q<hoe-doofus>, ["~> 1.0"])
+    s.add_dependency(%q<hoe-gemspec2>, ["~> 1.1"])
+    s.add_dependency(%q<hoe-git>, ["~> 1.5"])
+    s.add_dependency(%q<hoe-hg>, ["~> 1.0"])
+    s.add_dependency(%q<hoe-rubygems>, ["~> 1.0"])
+    s.add_dependency(%q<hoe-travis>, ["~> 1.2"])
+    s.add_dependency(%q<rspec>, ["~> 2.0"])
+    s.add_dependency(%q<tilt>, ["~> 2.0"])
+    s.add_dependency(%q<hoe>, ["~> 3.8"])
+  end
+end

File spec/basic_spec.rb

-require File.dirname(__FILE__) + '/spec_helper.rb'
+# -*- ruby encoding: utf-8 -*-
 
-include TestConstants
+require 'spec_helper'
 
 describe "RubyPython" do
   it "can import and use a native extension like cPickle" do
     cPickle = RubyPython.import("cPickle")
-    string = cPickle.dumps("Testing RubyPython.")
-    string.should_not be_a_kind_of String
-    string.rubify.should be_a_kind_of String
-    string.rubify.should ~ /S'Testing RubyPython.'\n/
+    string  = cPickle.dumps("Testing RubyPython.")
+    expect(string).not_to be_a_kind_of String
+    expect(string.rubify).to be_a_kind_of String
+    expect(string.rubify).to match /S'Testing RubyPython.'\n/
   end
 
   it "can import and use a pure Python extension like pickle" do
     pickle = RubyPython.import("pickle")
     string = pickle.dumps("Testing RubyPython.")
-    string.should_not be_a_kind_of String
-    string.rubify.should be_a_kind_of String
-    string.rubify.should ~ /S'Testing RubyPython.'\n/
+    expect(string).not_to be_a_kind_of String
+    expect(string.rubify).to be_a_kind_of String
+    expect(string.rubify).to match /S'Testing RubyPython.'\n/
   end
 
   it "can use iterators from Python" do
     items = []
     @basics.iterate_list.to_enum.each { |item| items << item }
-    items.should == [ 1, 2, 3 ]
+    expect(items).to eq [ 1, 2, 3 ]
   end
 
   it "can use Ruby procs as callbacks to Python code" do
-    @basics.simple_callback(lambda { |v| v * v }, 4).should == 16
+    expect(@basics.simple_callback(lambda { |v| v * v }, 4)).to eq 16
   end
 
   it "can use Ruby methods as callbacks to Python code" do
     def triple(v)
       v * 3
     end
-    @basics.simple_callback(method(:triple), 4).should == 12
+    expect(@basics.simple_callback(method(:triple), 4)).to eq 12
   end
 
   it "can feed a Python generator in Ruby 1.9", :ruby_version => '1.9' do
     output = @basics.simple_generator(RubyPython.generator do
       (1..10).each { |i| RubyPython.yield i }
     end)
-    output.should == [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
+    expect(output).to eq [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
   end
 
   it "can use named parameters to functions" do
-    @basics.named_args(2, 1).should == [ 2, 1 ]
-    @basics.named_args!(:arg2 => 2, :arg1 => 1).should == [ 1, 2 ]
+    expect(@basics.named_args(2, 1)).to eq [ 2, 1 ]
+    expect(@basics.named_args!(:arg2 => 2, :arg1 => 1)).to eq [ 1, 2 ]
   end
 end

File spec/callback_spec.rb

-require File.dirname(__FILE__) + '/spec_helper.rb'
+# -*- ruby encoding: utf-8 -*-
 
-include TestConstants
+require 'spec_helper'
 
 describe 'Callbacks' do
   {
-    'procs' => AProc,
-    'methods' => AMethod,
+    'procs'   => RPTest::AProc,
+    'methods' => RPTest::AMethod,
   }.each do |rb_type, rb_object|
-    it "accepts #{rb_type} as functions" do
+    specify "accept #{rb_type} as functions" do
       [
         [2, 2],
         ["a", "Word"],
         [ [1, 2], [3, 4] ]
       ].each do |args|
-        @objects.apply_callback(rb_object, args).should == rb_object.call(*args)
+        @objects.apply_callback(rb_object, args)
+
+        expect(@objects.apply_callback(rb_object, args)).to \
+          eq rb_object.call(*args)
       end
     end
   end
 
   [
-    ["an int", AnInt],
-    ["a float", AFloat],
-    ["a string", AString],
-    ["a string with nulls", AStringWithNULLs],
-    ["an array", AnArray],
-    ["an array", AnArray],
-    ["a hash", AConvertedHash],
+    ["an int", RPTest::AnInt],
+    ["a float", RPTest::AFloat],
+    ["a string", RPTest::AString],
+    ["a string with nulls", RPTest::AStringWithNULLs],
+    ["an array", RPTest::AnArray],
+    ["an array", RPTest::AnArray],
+    ["a hash", RPTest::AConvertedHash],
     ["true", true],
     ["false", false],
     ["nil", nil]
   ].each do |rb_type, rb_value|
     it "is able to return #{rb_type}" do
-      callback = Proc.new do 
+      callback = Proc.new do
         rb_value
       end
 
-      @objects.apply_callback(callback, []).should == rb_value
+      expect(@objects.apply_callback(callback, [])).to eq rb_value
     end
   end
 
   it "is able to be stored by python variables" do
     mockObject = @objects.RubyPythonMockObject.new
-    mockObject.callback = AProc
+    expect {
+      mockObject.callback = RPTest::AProc
+    }.not_to raise_error
   end
 
   it "is callable as a python instance variable" do
     mockObject = @objects.RubyPythonMockObject.new
-    mockObject.callback = AProc
-    mockObject.callback(2, 2).rubify.should == 4
+    mockObject.callback = RPTest::AProc
+    expect(mockObject.callback(2, 2).rubify).to eq 4
   end
-
 end

File spec/conversion_spec.rb

-require File.dirname(__FILE__) + '/spec_helper.rb'
+# -*- ruby encoding: utf-8 -*-
 
-include TestConstants
+require 'spec_helper'
 
 describe RubyPython::Conversion do
-  subject { RubyPython::Conversion }
+  subject { described_class }
 
   context "when converting from Python to Ruby" do
     [
-      ["an int", "an int", AnInt],
-      ["a float", "a float", AFloat],
-      ["a string", "a string", AString],
-      ["a string_with_nulls", "a string_with_nulls", AStringWithNULLs],
-      ["a list", "an array", AnArray],
-      ["a tuple", "a tuple", ATuple],
-      ["a dict", "a hash", AConvertedHash],
+      ["an int", "an int", RPTest::AnInt],
+      ["a float", "a float", RPTest::AFloat],
+      ["a string", "a string", RPTest::AString],
+      ["a string_with_nulls", "a string_with_nulls", RPTest::AStringWithNULLs],
+      ["a list", "an array", RPTest::AnArray],
+      ["a tuple", "a tuple", RPTest::ATuple],
+      ["a dict", "a hash", RPTest::AConvertedHash],
       ["python True", "true", true],
       ["python False", "false", false],
       ["python None", "nil", nil]
     ].each do |py_type, rb_type, output|
-      it "should convert #{py_type} to #{rb_type}" do
-        py_object_ptr = @objects.__send__(py_type.sub(' ', '_')).pObject.pointer
-        obj = subject.ptorObject(py_object_ptr)
-        obj.should == output
-        obj.class.should == output.class
+      it "converts from #{py_type} to #{rb_type}" do
+        py_object_ptr =
+          @objects.__send__(py_type.sub(' ', '_')).pObject.pointer
+        object = subject.ptorObject(py_object_ptr)
+        expect(object).to eq(output)
+        expect(object).to be_an_instance_of(output.class)
       end
     end
 
-    it "should return an FFI::Pointer when it cannot convert" do
+    it "returns an FFI::Pointer when it cannot convert" do
       unconvertable = @objects.RubyPythonMockObject.pObject.pointer
-      subject.ptorObject(unconvertable).should be_a_kind_of(FFI::Pointer)
+      expect(subject.ptorObject(unconvertable)).to \
+        be_a_kind_of FFI::Pointer
     end
   end
 
   context "when converting Ruby to Python" do
     [
-      ["an int", "an int", AnInt],
-      ["a float", "a float", AFloat],
-      ["a string", "a string", AString],
-      ["a string_with_nulls", "a string_with_nulls", AStringWithNULLs],
-      ["a string", "a symbol", ASym],
-      ["a list", "an array", AnArray],
-      ["a tuple", "a tuple", ATuple ],
-      ["a dict", "a hash", AConvertedHash],
+      ["an int", "an int", RPTest::AnInt],
+      ["a float", "a float", RPTest::AFloat],
+      ["a string", "a string", RPTest::AString],
+      ["a string_with_nulls", "a string_with_nulls", RPTest::AStringWithNULLs],
+      ["a string", "a symbol", RPTest::ASym],
+      ["a list", "an array", RPTest::AnArray],
+      ["a tuple", "a tuple", RPTest::ATuple ],
+      ["a dict", "a hash", RPTest::AConvertedHash],
       ["python True", "true", true],
       ["python False", "false", false],
       ["python None", "nil", nil],
-      ["a function", "a proc", AProc, true]
+      ["a function", "a proc", RPTest::AProc, true]
     ].each do |py_type, rb_type, input, no_compare|
-      it "should convert #{rb_type} to #{py_type}" do
+      it "converts from #{rb_type} to #{py_type}" do
         py_object_ptr = subject.rtopObject(input)
         unless no_compare
           output = @objects.__send__(rb_type.sub(' ', '_')).pObject.pointer
-          RubyPython::Python.PyObject_Compare(py_object_ptr, output).should == 0
+          result =
+            RubyPython::Python.PyObject_Compare(py_object_ptr, output)
+          expect(result).to eq 0
         end
       end
     end
 
-    it "should raise an exception when it cannot convert" do
-      lambda { subject.rtopObject(Class) }.should raise_exception(subject::UnsupportedConversion)
+    it "raises an exception when it cannot convert" do
+      expect {
+        subject.rtopObject(Class)
+      }.to raise_error(subject::UnsupportedConversion)
     end
 
-    it "should convert a tuple correctly" do
-      @basics.expects_tuple(AnArray).should == false
-      @basics.expects_tuple(RubyPython::Tuple.tuple(AnArray)).should == true
+    it "converts a tuple correctly" do
+      array_tuple = RubyPython::Tuple(RPTest::AnArray)
+      expect(@basics.expects_tuple(RPTest::AnArray)).to eq false
+      expect(@basics.expects_tuple(array_tuple)).to eq true
     end
   end
 end

File spec/issues/cython/c.pyx

+cdef class C:
+    @classmethod
+    def foo(cls, a=5):
+        print a, cls
+        print cls, a

File spec/issues/cython/test.rb

+require 'rubypython'
+
+def import_cython
+  pyximport = RubyPython.import('pyximport')
+  pyximport.install
+
+  sys = RubyPython.import('sys')
+  sys.path.append File.dirname(__FILE__)
+  sys
+end
+
+def try_cmod
+  RubyPython.start
+  import_cython
+  cmod = RubyPython.import('c')
+  cmod.C.foo
+  RubyPython.stop
+end
+
+try_cmod
+try_cmod

File spec/pymainclass_spec.rb

-require File.dirname(__FILE__) + '/spec_helper.rb'
+# -*- ruby encoding: utf-8 -*-
 
-include TestConstants
+require 'spec_helper'
 
 describe RubyPython::PyMainClass do
   subject { RubyPython::PyMain }
 
-  it "should delegate to builtins" do
-    subject.float(AnInt).rubify.should == AnInt.to_f
+  it "delegates to builtins" do
+    expect(subject.float(RPTest::AnInt).rubify).to eq RPTest::AnInt.to_f
   end
 
-  it "should handle block syntax" do
-    subject.float(AnInt) {|f| f.rubify*2}.should == (AnInt.to_f * 2)
+  it "handles block syntax" do
+    expect(subject.float(RPTest::AnInt) { |f| f.rubify*2 }).to \
+      eq (RPTest::AnInt.to_f * 2)
   end
 
-  it "should allow attribute access" do
-    subject.main.__name__.rubify.should == '__main__'
+  it "allows attribute access" do
+    expect(subject.main.__name__.rubify).to eq '__main__'
   end
 
-  it "should allow global variable setting" do
+  it "allows global variable setting" do
     subject.x = 2
-    subject.x.rubify.should == 2
+    expect(subject.x.rubify).to eq 2
   end
 end

File spec/pyobject_spec.rb

-require File.dirname(__FILE__) + '/spec_helper.rb'
+# -*- ruby encoding: utf-8 -*-
 
-include TestConstants
+require 'spec_helper'
 
 describe RubyPython::PyObject do
   before do
     @urllib2 = RubyPython.import('urllib2').pObject
     @builtin = RubyPython.import("__builtin__")
     sys = RubyPython.import 'sys'
-    sys.path.append './spec/python_helpers/'
+    sys.path.append RPTest::Helpers
     @objects = RubyPython.import('objects')
   end
 
   describe ".new" do
     [
-      ["a string", AString],
-      ["an int", AnInt],
-      ["a float", AFloat],
-      ["an array", AnArray],
-      ["a symbol", ASym],
-      ["a hash", AHash]
+      ["a string", RPTest::AString],
+      ["an int", RPTest::AnInt],
+      ["a float", RPTest::AFloat],
+      ["an array", RPTest::AnArray],
+      ["a symbol", RPTest::ASym],
+      ["a hash", RPTest::AHash]
     ].each do |title, obj|
-      it "should wrap #{title}" do
-        lambda { described_class.new(obj) }.should_not raise_exception
+      it "wraps #{title}" do
+        expect {
+          described_class.new(obj)
+        }.not_to raise_exception
       end
     end
 
       "a dict",
       "a tuple"
     ].each do |title|
-      it "should take #{title} from a Python pointer" do
-        lambda do
+      it "takes #{title} from a Python pointer" do
+        expect {
           py_obj = @objects.__send__(title.gsub(' ','_')).pObject.pointer
           described_class.new(py_obj)
-        end.should_not raise_exception
+        }.not_to raise_exception
       end
     end
-  end #new
+  end
 
   describe "#rubify" do
     [
-      ["a string", AString],
-      ["an int", AnInt],
-      ["a float", AFloat],
-      ["an array", AnArray],
-      ["a symbol", ASym, ASym.to_s],
-      ["a hash", AHash, AConvertedHash]
+      ["a string", RPTest::AString],
+      ["an int", RPTest::AnInt],
+      ["a float", RPTest::AFloat],
+      ["an array", RPTest::AnArray],
+      ["a symbol", RPTest::ASym, RPTest::ASym.to_s],
+      ["a hash", RPTest::AHash, RPTest::AConvertedHash]
     ].each do |arr|
       type, input, output = arr
       output ||= input
 
-      it "should faithfully unwrap #{type}" do
-        described_class.new(input).rubify.should == output
+      it "faithfully unwraps #{type}" do
+        expect(described_class.new(input).rubify).to eq output
       end
     end
-  end #rubify
+  end
 
   describe "#hasAttr" do
-    it "should return true when object has the requested attribute" do
-      @string.hasAttr("ascii_letters").should be_true
+    it "returns true when object has the requested attribute" do
+      expect(@string.hasAttr("ascii_letters")).to eq true
     end
 
-    it "should return false when object does not have the requested attribute" do
-      @string.hasAttr("nonExistentThing").should be_false
+    it "returns false when object is missing the requested attribute" do
+      expect(@string.hasAttr("nonExistentThing")).to eq false
     end
   end
 
   describe "#getAttr" do
-    it "should fetch requested object attribute" do 
+    it "fetches requested object attribute" do
       ascii_letters = @string.getAttr "ascii_letters"
-      ascii_letters.rubify.should == "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+      expect(ascii_letters.rubify).to \
+        eq "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
     end
 
-    it "should return a PyObject instance" do
+    it "returns a PyObject instance" do
       ascii_letters = @string.getAttr "ascii_letters"
-      ascii_letters.should be_kind_of(described_class)
+      expect(ascii_letters).to be_instance_of described_class
     end
   end
 
-  describe "#setAttr" do 
-    it "should modify the specified attribute of the object" do
+  describe "#setAttr" do
+    it "modifies the specified attribute of the object" do
       pyNewLetters = described_class.new "RbPy"
       @string.setAttr "ascii_letters", pyNewLetters
-      @string.getAttr("ascii_letters").rubify.should == pyNewLetters.rubify
+      expect(@string.getAttr("ascii_letters").rubify).to \
+        eq pyNewLetters.rubify
     end
 
-    it "should create the requested attribute if it doesn't exist" do 
+    it "creates the requested attribute if it doesn't exist" do
       pyNewString = described_class.new "python"
       @string.setAttr "ruby", pyNewString
-      @string.getAttr("ruby").rubify.should == pyNewString.rubify
+      expect(@string.getAttr("ruby").rubify).to eq pyNewString.rubify
     end
   end
 
       @less_dup = described_class.new 5
     end
 
-    it "should return 0 when objects are equal" do
-      @less.cmp(@less_dup).should == 0
+    it "returns 0 when objects are equal" do
+      expect(@less.cmp(@less_dup)).to eq 0
     end
 
-    it "should change sign under interchange of arguments" do 
-      @less.cmp(@greater).should == -@greater.cmp(@less)
+    it "changes sign under interchange of arguments" do
+      expect(@less.cmp(@greater)).to eq -@greater.cmp(@less)
     end
 
-    it "should return -1 when first object is less than the second" do
-      @less.cmp(@greater).should == -1
+    it "returns -1 when first object is less than the second" do
+      expect(@less.cmp(@greater)).to eq -1
     end
 
-    it "should return 1 when first object is greater than the second" do
-      @greater.cmp(@less).should == 1
+    it "returns 1 when first object is greater than the second" do
+      expect(@greater.cmp(@less)).to eq 1
     end
   end
 
-
   describe "#callObject" do
-    #Expand coverage types
-    it "should execute wrapped object with supplied arguments" do
-      arg = described_class.new AnInt
+    # Expand coverage types
+    it "executes the wrapped object with supplied arguments" do
+      arg = described_class.new RPTest::AnInt
       argt = described_class.buildArgTuple arg
 
       builtin = @builtin.pObject
       stringClass = builtin.getAttr "str"
-      stringClass.callObject(argt).rubify.should == AnInt.to_s
+      expect(stringClass.callObject(argt).rubify).to eq RPTest::AnInt.to_s
     end
   end
 
   describe "#function_or_method?" do
-    it "should be true given a method" do
+    it "returns true given a method" do
       mockObjClass = @objects.RubyPythonMockObject.pObject
-      mockObjClass.getAttr('square_elements').should be_a_function_or_method
+      expect(mockObjClass.getAttr('square_elements')).to \
+        be_a_function_or_method
     end
 
-    it "should be true given a function" do
-      @objects.pObject.getAttr('identity').should be_a_function_or_method
+    it "returns be true given a function" do
+      expect(@objects.pObject.getAttr('identity')).to \
+        be_a_function_or_method
     end
 
-    it "should return true given a builtin function" do
+    it "returns true given a builtin function" do
       any = @builtin.pObject.getAttr('any')
-      any.should be_a_function_or_method
+      expect(any).to be_a_function_or_method
     end
 
-    it "should return false given a class" do
-      @objects.RubyPythonMockObject.pObject.should_not be_a_function_or_method
+    it "returns false given a class" do
+      expect(@objects.RubyPythonMockObject.pObject).not_to \
+        be_a_function_or_method
     end
   end
 
   describe "#class?" do
-    it "should return true if wrapped object is an old style class" do
-      @objects.RubyPythonMockObject.pObject.should be_a_class
+    it "returns true if wrapped object is an old style class" do
+      expect(@objects.RubyPythonMockObject.pObject).to be_a_class
     end
 
-    it "should return true if wrapped object is an new style class" do
-      @objects.NewStyleClass.pObject.should be_a_class
+    it "returns true if wrapped object is an new style class" do
+      expect(@objects.NewStyleClass.pObject).to be_a_class
     end
 
-    it "should return true if wrapped object is a builtin class" do
+    it "returns true if wrapped object is a builtin class" do
       strClass = @builtin.pObject.getAttr('str')
-      strClass.should be_a_class
+      expect(strClass).to be_a_class
     end
 
-    it "should return false given an object instance" do
-      @objects.RubyPythonMockObject.new.pObject.should_not be_a_class
+    it "returns false given an object instance" do
+      expect(@objects.RubyPythonMockObject.new.pObject).not_to be_a_class
     end
   end
 
   describe "#callable?" do
-    it "should be true given a method" do
+    it "returns true given a method" do
       mockObjClass = @objects.RubyPythonMockObject.pObject
-      mockObjClass.getAttr('square_elements').should be_callable
+      expect(mockObjClass.getAttr('square_elements')).to be_callable
     end
 
-    it "should be true given a function" do
-      @objects.pObject.getAttr('identity').should be_callable
+    it "returns true given a function" do
+      expect(@objects.pObject.getAttr('identity')).to be_callable
     end
 
-    it "should return true given a builtin function" do
+    it "returns true given a builtin function" do
       any = @builtin.pObject.getAttr('any')
-      any.should be_callable
+      expect(any).to be_callable
     end
 
-    it "should return true given a class" do
-      @objects.RubyPythonMockObject.pObject.should be_callable
+    it "returns true given a class" do
+      expect(@objects.RubyPythonMockObject.pObject).to be_callable
     end
 
-    it "should return false given a non-callable instance" do
-      @objects.RubyPythonMockObject.new.pObject.should_not be_callable
+    it "returns false given a non-callable instance" do
+      expect(@objects.RubyPythonMockObject.new.pObject).not_to be_callable
     end
 
-    specify { described_class.new(6).should_not be_callable }
-
+    it "returns false given a non-callable value" do
+      expect(described_class.new(6)).not_to be_callable
+    end
   end
-
 end

File spec/pythonerror_spec.rb

-require File.dirname(__FILE__) + '/spec_helper.rb'
+# -*- ruby encoding: utf-8 -*-
+
+require 'spec_helper'
 
 describe RubyPython::PythonError do
   def cause_error
   end
 
   describe "#error?" do
-    it "should return false when no error has occured" do
-      described_class.error?.should be_false
+    it "returns false when no error has occured" do
+      expect(described_class.error?).to eq false
     end
 
-    it "should return true when an error has occured" do
+    it "returns true when an error has occured" do
       cause_error
-      described_class.error?.should be_true
+      expect(described_class.error?).to eq true
     end
   end
 
   describe "#clear" do
-    it "should reset the Python error flag" do
+    it "resets the Python error flag" do
       cause_error
       described_class.clear
-      described_class.error?.should be_false
+      expect(described_class.error?).to eq false
     end
 
-    it "should not barf when there is no error" do
-      lambda {described_class.clear}.should_not raise_exception
+    it "does not barf when there is no error" do
+      expect {
+        described_class.clear
+      }.not_to raise_exception
     end
   end
 
   describe "#fetch" do
-    it "should make availible Python error type" do
+    it "makes available the Python error type" do
       cause_error
       rbType, rbValue, rbTraceback = described_class.fetch
-      rbType.getAttr("__name__").rubify.should == "ImportError"
+      expect(rbType.getAttr("__name__").rubify).to eq "ImportError"
     end
   end
 
   describe ".last_traceback" do
-    it "should make availble the Python traceback of the last error" do
+    it "makes available the Python traceback of the last error" do
       traceback = RubyPython.import 'traceback'
       errors = RubyPython.import 'errors'
       begin
       rescue RubyPython::PythonError => exc
         tb = exc.traceback
         list = traceback.format_tb(tb)
-        list.rubify[0].should =~ /1 \/ 0/
+        expect(list.rubify[0]).to match %r{1 / 0}
       end
     end
   end

File spec/refcnt_spec.rb

-require File.dirname(__FILE__) + '/spec_helper.rb'
+# -*- ruby encoding: utf-8 -*-
 
-def get_refcnt(pobject)
-  raise 'Cannot work with a nil object' if pobject.nil?
-
-  if pobject.kind_of? RubyPython::RubyPyProxy
-    pobject = pobject.pObject.pointer
-  elsif pobject.kind_of? RubyPython::PyObject
-    pobject = pobject.pointer
-  end
-  RubyPython::Macros.Py_REFCNT pobject
-end
-
-include TestConstants
+require 'spec_helper'
 
 describe 'Reference Counting' do
-  before :all do
-    RubyPython.start
-    @sys = RubyPython.import 'sys'
-    @sys.path.append './spec/python_helpers'
-    @objects = RubyPython.import 'objects'
+  it "is one given a new object" do
+    pyObj = @objects.RubyPythonMockObject.new
+    expect(get_refcnt(pyObj)).to eq 1
   end
 
-  after :all do
-    RubyPython.stop
-  end
-
-  it "should be one given a new object" do
-    pyObj = @objects.RubyPythonMockObject.new
-    get_refcnt(pyObj).should == 1
-  end
-
-  it "should increase when a new reference is passed into Ruby" do
+  it "increases when a new reference is passed into Ruby" do
     pyObj = @objects.RubyPythonMockObject
     refcnt = get_refcnt(pyObj)
     pyObj2 = @objects.RubyPythonMockObject
-    get_refcnt(pyObj).should == (refcnt + 1)
+    expect(get_refcnt(pyObj)).to eq (refcnt + 1)
   end
 
   describe RubyPython::PyObject do
     describe "#xIncref" do
-      it "should increase the reference count" do
+      it "increases the reference count" do
         pyObj = @objects.RubyPythonMockObject.new
         refcnt = get_refcnt(pyObj)
         pyObj.pObject.xIncref
-        get_refcnt(pyObj).should == refcnt + 1
+        expect(get_refcnt(pyObj)).to eq refcnt + 1
       end
     end
 
     describe "#xDecref" do
-      it "should decrease the reference count" do
+      it "decreases the reference count" do
         pyObj = @objects.RubyPythonMockObject.new
         pyObj.pObject.xIncref
         refcnt = get_refcnt(pyObj)
         pointer = pyObj.pObject.pointer
         pyObj.pObject.xDecref
-        get_refcnt(pointer).should == refcnt - 1
+        expect(get_refcnt(pointer)).to eq refcnt - 1
       end
     end
   end
 
   describe RubyPython::Conversion do
     describe ".rtopArrayToList" do
-      it "should incref any wrapped objects in the array" do
-        int = RubyPython::PyObject.new AnInt
+      it "increments the references around wrapped objects in the array" do
+        int = RubyPython::PyObject.new RPTest::AnInt
         refcnt = get_refcnt(int)
-        arr = [int]
+        arr = [ int ]
         pyArr = subject.rtopArrayToList(arr)
-        get_refcnt(int).should == refcnt + 1
+        expect(get_refcnt(int)).to eq refcnt + 1
       end
-
     end
 
     describe ".rtopObject" do
       [
-        ["string", AString],
-        ["float", AFloat],
-        ["array", AnArray],
-        #["symbol", ASym],
-        ["hash", AHash]
+        ["string", RPTest::AString],
+        ["float", RPTest::AFloat],
+        ["array", RPTest::AnArray],
+        #["symbol", RPTest::ASym],
+        ["hash", RPTest::AHash]
       ].each do |arr|
         type, input = arr
 
-        it "should return a refcnt of 1 for newly created #{type}" do
+        it "returns a refcnt of 1 for newly created #{type}" do
           pyObj = subject.rtopObject(input)
-          get_refcnt(pyObj).should == 1
+          expect(get_refcnt(pyObj)).to eq 1
         end
 
-        it "should increment the refcnt each time the same #{type} is passed in" do
+        it "increments the refcnt each time the same #{type} is passed in" do
           pyObj = RubyPython::PyObject.new subject.rtopObject(input)
           refcnt = get_refcnt(pyObj)
           pyObj2 = subject.rtopObject(pyObj)
-          get_refcnt(pyObj2).should == refcnt + 1
+          expect(get_refcnt(pyObj2)).to eq refcnt + 1
         end
       end
     end

File spec/rubypyclass_spec.rb

-require File.dirname(__FILE__) + '/spec_helper.rb'
+# -*- ruby encoding: utf-8 -*-
+
+require 'spec_helper'
 
 describe RubyPython::RubyPyClass do
   describe "#new" do
-    it "should return a RubyPyInstance" do
+    it "returns a RubyPyInstance" do
       urllib2 = RubyPython.import 'urllib2'
-      urllib2.Request.new('google.com').should be_a(RubyPython::RubyPyInstance)
+      expect(urllib2.Request.new('google.com')).to \
+        be_a RubyPython::RubyPyInstance
     end
   end
 end

File spec/rubypyproxy_spec.rb

-require File.dirname(__FILE__) + '/spec_helper.rb'
+# -*- ruby encoding: utf-8 -*-
 
-include TestConstants
+require 'spec_helper'
+
 describe RubyPython::RubyPyProxy do
   before do
     @a = RubyPython::PyObject.new "a"
     @six = described_class.new 6
 
     @sys = RubyPython.import 'sys'
-    @sys.path.append './spec/python_helpers'
+    @sys.path.append RPTest::Helpers
     @objects = RubyPython.import 'objects'
   end
 
   describe "#new" do
-    it "should accept a PyObject instance" do
-      rbPyObject = RubyPython::PyObject.new AString
-      lambda {described_class.new rbPyObject}.should_not raise_exception
+    it "accepts a PyObject instance" do
+      rbPyObject = RubyPython::PyObject.new RPTest::AString
+      expect {
+        described_class.new rbPyObject
+      }.not_to raise_exception
     end
 
     [
-      ["a string", AString],
-      ["an int", AnInt],
-      ["a float", AFloat],
-      ["an array", AnArray],
-      ["a symbol", ASym, ASym.to_s],
-      ["a hash", AHash, AConvertedHash]
+      ["a string", RPTest::AString],
+      ["an int", RPTest::AnInt],
+      ["a float", RPTest::AFloat],
+      ["an array", RPTest::AnArray],
+      ["a symbol", RPTest::ASym, RPTest::ASym.to_s],
+      ["a hash", RPTest::AHash, RPTest::AConvertedHash]
     ].each do |arr|
       type, input, output = arr
       output ||= input
 
-      it "should convert #{type} to wrapped pObject" do
-        described_class.new(input).pObject.rubify.should == output
+      it "converts #{type} to wrapped pObject" do
+        expect(described_class.new(input).pObject.rubify).to eq output
       end
     end
   end
 
   describe "#rubify" do
     [
-      ["a string", AString],
-      ["an int", AnInt],
-      ["a float", AFloat],
-      ["an array", AnArray],
-      ["a symbol", ASym],
-      ["a hash", AHash]
+      ["a string", RPTest::AString],
+      ["an int", RPTest::AnInt],
+      ["a float", RPTest::AFloat],
+      ["an array", RPTest::AnArray],
+      ["a symbol", RPTest::ASym],
+      ["a hash", RPTest::AHash]
     ].each do |title, obj|
-      it "should faithfully unwrap #{title}" do
+      it "faithfully unwraps #{title}" do
         pyObject = RubyPython::PyObject.new obj
         proxy = described_class.new pyObject
-        proxy.rubify.should == pyObject.rubify
+        expect(proxy.rubify).to eq pyObject.rubify
       end
     end
   end
 
   describe "#inspect" do
-    it "should return 'repr' of wrapped object" do
-      @six.inspect.should == '6'
+    it "returns 'repr' of wrapped object" do
+      expect(@six.inspect).to eq '6'
     end
 
-    it "should gracefully handle lack of defined __repr__" do
-      lambda { @objects.RubyPythonMockObject.inspect }.should_not raise_exception
+    it "gracefully handles the lack of a defined __repr__" do
+      expect {
+        @objects.RubyPythonMockObject.inspect
+      }.not_to raise_exception
     end
 
     it "always tries the 'repr' function if __repr__ produces an error" do
-      RubyPython::PyMain.list.inspect.should == run_python_command('print repr(list)').chomp
+      expect(RubyPython::PyMain.list.inspect).to eq run_python_command('print repr(list)').chomp
     end
   end
 
   describe "#to_s" do
-    it "should return 'str' of wrapped object" do
-      @six.to_s.should == '6'
+    it "returns 'str' of wrapped object" do
+      expect(@six.to_s).to eq '6'
     end
 
-    it "should gracefully handle lack of defined __str__" do
-      lambda { @objects.RubyPythonMockObject.to_s }.should_not raise_exception
+    it "gracefully handles the lack of a defined __str__" do
+      expect {
+        @objects.RubyPythonMockObject.to_s
+      }.not_to raise_exception
     end
 
     it "always tries the 'str' function if __repr__ produces an error" do
-      RubyPython::PyMain.list.to_s.should == run_python_command('print str(list)').chomp
+      expect(RubyPython::PyMain.list.to_s).to eq run_python_command('print str(list)').chomp
     end
   end
 
   describe "#to_a" do
-    it "should convert a list to an array of its entries" do
+    it "converts a list to an array of its entries" do
       list = @objects.a_list
-      list.to_a.should == AnArray.map { |x| described_class.new(x) }
+      expect(list.to_a).to \
+        eq RPTest::AnArray.map { |x| described_class.new(x) }
     end
 
-    it "should convert a tuple to an array of its entries" do
+    it "converts a tuple to an array of its entries" do
       tuple = @objects.a_tuple
-      tuple.to_a.should == AnArray.map { |x| described_class.new(x) }
+      expect(tuple.to_a).to \
+        eq RPTest::AnArray.map { |x| described_class.new(x) }
     end
 
-    it "should convert a dict to an array of keys" do
+    it "converts a dict to an array of keys" do
       dict = @objects.a_dict
-      dict.to_a.sort.should == AConvertedHash.keys.map {|x| described_class.new(x)}.sort
+      expect(dict.to_a.sort).to \
+        eq RPTest::AConvertedHash.keys.map { |x|
+          described_class.new(x)
+      }.sort
     end
   end
 
   describe "#respond_to?" do
-    it "should return true given getters" do
-      @objects.should respond_to(:RubyPythonMockObject)
+    it "returns true given getters" do
+      expect(@objects).to respond_to(:RubyPythonMockObject)
     end
 
-    it "should return false given undefined methods" do
-      @objects.should_not respond_to(:undefined_attr)
+    it "returns false given undefined methods" do
+      expect(@objects).to_not respond_to(:undefined_attr)
     end
 
-    it "should return true given any setter" do
-      @objects.should respond_to(:any_variable=)
+    it "returns true given any setter" do
+      expect(@objects).to respond_to(:any_variable=)
     end
 
-    it "should return true given methods on RubyPyProxy instance" do
-      @objects.should respond_to(:inspect)
+    it "returns true given methods on RubyPyProxy instance" do
+      expect(@objects).to respond_to(:inspect)
     end
   end
 
   describe "method delegation" do
-    it "should refer method calls to wrapped object" do
+    it "refers method calls to wrapped objects" do
       aProxy = described_class.new(@a)
       bProxy = described_class.new(@b)
-      aProxy.__add__(bProxy).rubify.should == (@a.rubify + @b.rubify)
+      expect(aProxy.__add__(bProxy).rubify).to eq (@a.rubify + @b.rubify)
     end
 
-    it "should raise NoMethodError when method is undefined" do
+    it "raises NoMethodError when method is undefined" do
       aProxy = described_class.new @a
-      lambda {aProxy.wat}.should raise_exception(NoMethodError)
+      expect {
+        aProxy.wat
+      }.to raise_exception NoMethodError
     end
 
     it "raises NoMethodError when boolean method is undefined" do
       aProxy = described_class.new @a
-      lambda { aProxy.wat? }.should raise_exception(NoMethodError)
+      expect {
+        aProxy.wat?
+      }.to raise_exception NoMethodError
     end
 
-    it "should allow methods to be called with no arguments" do
+    it "allows methods to be called with no arguments" do
       builtinProxy = described_class.new @builtin
       rbStrClass = builtinProxy.str
-      rbStrClass.new.rubify.should == String.new
+      expect(rbStrClass.new.rubify).to eq String.new
     end
 
-    it "should fetch attributes when method name is an attribute" do
+    it "fetches attributes when method name is an attribute" do
       pyLetters = @string.getAttr "ascii_letters"
       stringProxy = described_class.new @string
-      stringProxy.ascii_letters.rubify.should == pyLetters.rubify
+      expect(stringProxy.ascii_letters.rubify).to eq pyLetters.rubify
     end
 
-    it "should set attribute if method call is a setter" do
+    it "sets attribute if method call is a setter" do
       stringProxy = described_class.new @string
-      stringProxy.letters = AString
-      stringProxy.letters.rubify.should == AString
+      stringProxy.letters = RPTest::AString
+      expect(stringProxy.letters.rubify).to eq RPTest::AString
     end
 
-    it "should create nonexistent attirubte if method call is a setter" do
+    it "creates nonexistent attirubte if method call is a setter" do
       stringProxy = described_class.new @string
       stringProxy.nonExistent = 1
-      stringProxy.nonExistent.rubify.should == 1
+      expect(stringProxy.nonExistent.rubify).to eq 1
     end
 
-    it "should return a class as a RubyPyClass" do
+    it "returns a class as a RubyPyClass" do
       urllib2 = RubyPython.import('urllib2')
-      urllib2.Request.should be_a(RubyPython::RubyPyClass)
+      expect(urllib2.Request).to be_a(RubyPython::RubyPyClass)
     end
 
-    it "should pass named args via bang method" do
-      @objects.named_args!(:arg2 => 2, :arg1 => 1).rubify.should == [4,2]
+    it "passes named args via bang method" do
+      expect(@objects.named_args!(:arg2 => 2, :arg1 => 1).rubify).to \
+        eq [ 4, 2 ]
     end
 
-    it "should pass through keyword arguments via bang method" do
+    it "passes through keyword arguments via bang method" do
       builtinProxy = described_class.new @builtin
-      builtinProxy.dict!({'dict'=>'val'}, :keyword=>true).rubify.should == {
-        'dict' => 'val',
-        'keyword' => true
-      }
+      args = [ { 'dict' => 'val' }, { :keyword => true } ]
+      expect(builtinProxy.dict!(*args).rubify).to \
+        eq({ 'dict' => 'val', 'keyword' => true })
     end
   end
 
   describe "when used with an operator" do
     [
-      '+', '-', '/', '*', '&', '^', '%', '**',
-      '>>', '<<', '<=>', '|'
+      '+'