lib/rubypython.rb in rubypython-0.2.11 vs lib/rubypython.rb in rubypython-0.3.0
- old
+ new
@@ -1,126 +1,130 @@
-require 'rubypython_bridge'
-require 'rubypython/wrapper_extensions'
+require 'rubypython/core_ext/string'
+require 'rubypython/python'
+require 'rubypython/pythonerror'
+require 'rubypython/pyobject'
+require 'rubypython/rubypyproxy'
+require 'rubypython/pymainclass'
-=begin rdoc
-This module provides the direct user interface for the RubyPython extension.
+#This module provides the direct user interface for the RubyPython extension.
+#
+#RubyPython interfaces to the Python C API via the {Python} module using the
+#Ruby FFI gem. However, the end user should only worry about dealing with the
+#methods made avaiable via the RubyPython module.
+#
+#Usage
+#-----
+#It is important to remember that the Python Interpreter must be
+#started before the bridge is functional. This will start the embedded
+#interpreter. If this approach is used, the user should remember to call
+#RubyPython.stop when they are finished with Python.
+#@example
+# RubyPython.start
+# cPickle = RubyPython.import "cPickle"
+# puts cPickle.dumps("RubyPython is awesome!").rubify
+# RubyPython.stop
+#
+#Legacy Mode vs Normal Mode
+#---------------------------
+#By default RubyPython always returns a proxy class which refers method calls to
+#the wrapped Python object. If you instead would like RubyPython to aggressively
+#attempt conversion of return values, as it did in RubyPython 0.2.x, then you
+#should set {RubyPython.legacy_mode} to true. In this case RubyPython will
+#attempt to convert any return value from Python to a native Ruby type, and only
+#return a proxy if conversion is not possible. For further examples see
+#{RubyPython.legacy_mode}.
+module RubyPython
-The majority of the functionality lies in the _RubyPythonBridge_ module, which is provided
-by the C extension. However, the end user should only worry about dealing with the RubyPython
-module as that is designed for user interaction. Furthermore the RubyPythonBridge is somewhat
-bad with memory management and using it directly may result in some strange crashes.
+ class << self
-==Usage
-It is important to remember that the Python Interpreter must be started before the bridge
-is functional. This may be done by two methods. One is to use the +start+ function.
-This will start the embedded interpreter. If this approach is used, the user should
-remember to call RubyPython.stop when they are finished with Python.
-Example:
- RubyPython.start
- cPickle=RubyPython.import "cPickle"
- puts cPickle.dumps "RubyPython is awesome!"
- RubyPython.stop
-
-The other method is preferable if one wants a simpler approach. This other method is to use
-<tt>RubyPython.run</tt>. run takes a block which is evaluated in the scope of the RubyPython module.
-In addition, the interpreter is started before the block is run and halted at its completion.
-This allows one to do something like the following:
- RubyPython.run do
- cPickle=import "cPickle"
- puts cPickle.dumps "RubyPython is still awesome!"
- end
+ #Determines whether RubyPython is operating in Normal Mode or Legacy Mode.
+ #If legacy_mode is true, RubyPython switches into a mode compatible with
+ #versions < 0.3.0. All Python objects returned by method invocations are
+ #automatically converted to natve Ruby Types if RubyPython knows how to do
+ #this. Only if no such conversion is known are the objects wrapped in proxy
+ #objects. Otherwise RubyPython automatically wraps all returned objects as
+ #an instance of {RubyPyProxy} or one of its subclasses.
+ #@return [Boolean]
+ #@example Normal Mode
+ # RubyPython.start
+ # string = RubyPython.import 'string'
+ # ascii_letters = string.ascii_letters # Here ascii_letters is a proxy object
+ # puts ascii_letters.rubify # we use the rubify method to convert it to a
+ # # native type
+ # RubyPython.stop
+ #
+ #@example Legacy Mode
+ # RubyPython.legacy_mode = true
+ # RubyPython.start
+ # string = RubyPython.import 'string'
+ # ascii_letters = string.ascii_letters # Here ascii_letters is a native ruby string
+ # puts ascii_letters # No explicit conversion is neccessary
+ # RubyPython.stop
+ attr_accessor :legacy_mode
-The downside to the above method is that the block has no access to the encompassing scope. An
-alternative is to use <tt>RubyPython.session</tt>. The downside to this approach is that the module
-methods are not available by their unqualified names: i.e.
- irb(main):001:0> RubyPython.session do
- irb(main):002:1* cPickle=import "cPickle"
- irb(main):003:1> end
- NoMethodError: undefined method `import' for main:Object
- from (irb):2
- from ./rubypython.rb:93:in `call'
- from ./rubypython.rb:93:in `session'
- from (irb):1
-
-However:
- irb(main):001:0> RubyPython.session do
- irb(main):002:1* cPickle=RubyPython.import "cPickle"
- irb(main):003:1> puts cPickle.dumps "RubyPython is still awesome!"
- irb(main):004:1> end
- S'RubyPython is still awesome!'
- .
- => nil
+ #Starts ups the Python interpreter. This method **must** be run
+ #before using any Python code. The only alternatives are use of the
+ #{session} and {run} methods.
+ #@return [Boolean] returns true if the interpreter was started here
+ # and false otherwise
+ def start
+ if Python.Py_IsInitialized != 0
+ return false
+ end
+ Python.Py_Initialize
+ true
+ end
-A compromise can be achieved by just including the RubyPython module into the scope you're
-working in.
+ #Stops the Python interpreter if it is running. Returns true if the
+ #intepreter is stopped by this invocation. All wrapped Python objects
+ #should be considered invalid after invocation of this method.
+ #@return [Boolean] returns true if the interpreter was stopped here
+ # and false otherwise
+ def stop
+ if Python.Py_IsInitialized !=0
+ PyMain.main = nil
+ PyMain.builtin = nil
+ RubyPython::Operators.send :class_variable_set, '@@operator', nil
+ Python.Py_Finalize
+ RubyPython::PyObject::AutoPyPointer.current_pointers.clear
+ return true
+ end
+ false
+ end
-If you really wish to be free of dealing with the interpreter, just import 'rubypython/session'.
-This will start the interpreter on import and will halt it when execution ends.
-
-==Errors
-The RubyPythonModule defines a new error object, PythonError. Should any error occur within
-the Python interpreter, the class and value of the error will be passed back into ruby within
-the text of the raised PythonError.
- irb(main):001:0> RubyPython.start
- => true
- irb(main):002:0> RubyPython.import "does not exist"
- PythonError: ImportError:(No module named does not exist)
+ #Import a Python module into the interpreter and return a proxy object
+ #for it. This is the preferred way to gain access to Python object.
+ #@param [String] mod_name the name of the module to import
+ #@return [RubyPyModule] a proxy object wrapping the requested
+ #module
+ def import(mod_name)
+ pModule = Python.PyImport_ImportModule mod_name
+ if(PythonError.error?)
+ raise PythonError.handle_error
+ end
+ pymod = PyObject.new pModule
+ RubyPyModule.new(pymod)
+ end
- from ./rubypython.rb:66:in `initialize'
- from ./rubypython.rb:66:in `import'
- from ./rubypython.rb:66:in `import'
- from (irb):2
-=end
-module RubyPython
-
- # Used to started the python interpreter. Delegates to RubyPythonBridge
- #
- # RubyPython.start
- # --Some python code--
- # RubyPython.stop
- #
- # Also see, _stop_
- def self.start() #=> true||false
- RubyPythonBridge.start
- end
-
-
+ #Execute the given block, starting the Python interperter before its execution
+ #and stopping the interpreter after its execution. The last expression of the
+ #block is returned; be careful that this is not a Python object as it will
+ #become invalid when the interpreter is stopped.
+ #@param [Block] block the code to be executed while the interpreter is running
+ #@return the result of evaluating the given block
+ def session
+ start
+ result = yield
+ stop
+ result
+ end
- # Used to end the python session. Adds some cleanup on top of RubyPythonBridge.stop
- def self.stop() #=> true,false
- ObjectSpace.each_object(RubyPythonBridge::RubyPyObject) do |o|
- o.free_pobj
+ #The same as {session} except that the block is executed within the scope
+ #of the RubyPython module.
+ def run(&block)
+ start
+ result = module_eval(&block)
+ stop
end
- PyMain.main=nil
- PyMain.builtin=nil
- RubyPythonBridge.stop
end
-
- # Import the python module +mod+ and return it wrapped as a ruby object
- def self.import(mod)
- RubyPythonBridge.import(mod)
- end
-
- # Handles the setup and cleanup involved with using the interpreter for you.
- # Note that all Python object will be effectively scope to within the block
- # as the embedded interpreter will be halted at its end. The supplied block is
- # run within the scope of the RubyPython module.
- #
- # Alternatively the user may prefer RubyPython.session which simples handles
- # initialization and cleanup of the interpreter.
- def self.run(&block)
- start
- module_eval(&block)
- stop
- end
-
- # Simply starts the interpreter, runs the supplied block, and stops the interpreter.
- def self.session(&block)
- start
- retval = block.call
- stop
- return retval
- end
end
-
-