patch from Steven Jenkins -------
authorFrank Mori Hess <fmhess@speakeasy.net>
Sat, 6 Mar 2004 22:13:37 +0000 (22:13 +0000)
committerFrank Mori Hess <fmhess@speakeasy.net>
Sat, 6 Mar 2004 22:13:37 +0000 (22:13 +0000)
The attached patch updates files in comedilib/swig/ruby. lib/comedi.rb is
updated to raise Ruby exceptions as indicated by the comedilib API
documentation. README and demo/cmd are updated accordingly.

swig/ruby/README
swig/ruby/demo/cmd
swig/ruby/lib/comedi.rb

index f1e0092b836b2e187bdd978db7ece0cc9e98ad65..56fffd04770c9e4dae6c29ce3ef0831b383f0c9c 100644 (file)
@@ -12,7 +12,7 @@ Instructions for building by hand (you shouldn't need to do this):
         library and the file lib/comedi.rb, which provides more
         Ruby-like method syntax.
 
-The file 'lib/comedi.rb' provides syntactic sugar in three forms:
+The file 'lib/comedi.rb' provides syntactic sugar in four forms:
 
 1.  Method names without the 'comedi_' prefix. The Comedi module
     disambiguates the namespace. For example, you can say
@@ -26,6 +26,10 @@ The file 'lib/comedi.rb' provides syntactic sugar in three forms:
     reading from the file descriptor associated with the comedi device.
     Data from comedi device 'dev' can be read by 'dev.ios.read'.
 
+4.  A ComediError exception class. If the underlying comedi
+    function returns an error indication, the ruby method will raise
+    ComediError.
+
 The file 'demo/cmd' is a straight port of 'cmd.c' from the
 Comedilib 'demo' directory. It illustrates the basics of programming
 Comedi commands using Ruby.
@@ -44,4 +48,4 @@ omitted from the parameter list. For example:
 
 Steven Jenkins
 steven.jenkins@ieee.org
-2004-01-12
+2004-03-02
index 861bb3cc524ce839f5ff2dde0e61a2fec31d2b91..b6408145827268f00e2ca9a2ac04675595218a25 100755 (executable)
@@ -51,16 +51,18 @@ ret, cmd = dev.prepare_cmd_lib($subdevice, $freq, Comedi_cmd_struct.new)
 $stderr.printf("command before testing:\n")
 dump_cmd($stderr, cmd)
 
-ret, cmd = dev.command_test(cmd)
-if ret < 0
+begin
+    ret, cmd = dev.command_test(cmd)
+rescue
     comedi_perror("comedi_command_test")
     exit 1
 end
 $stderr.printf("first test returned %d (%s)\n", ret, cmdtest_messages[ret])
 dump_cmd($stderr, cmd)
 
-ret, cmd = dev.command_test(cmd)
-if ret < 0
+begin
+    ret, cmd = dev.command_test(cmd)
+rescue
     comedi_perror("comedi_command_test")
     exit 1
 end
@@ -70,8 +72,9 @@ dump_cmd($stderr, cmd)
 tstart = Time.new
 $stderr.printf("start time: %d.%06d\n", tstart.tv_sec, tstart.tv_usec)
 
-ret = dev.command(cmd)
-if ret < 0
+begin
+    ret = dev.command(cmd)
+rescue
     comedi_perror("comedi_command")
     exit 1
 end
index ef38f6f3fd60c621dff50d724ae886452e6ea843..f769d18c32c5cb31b514ae686596ea0ddeaed141 100644 (file)
@@ -13,7 +13,7 @@
 
 # This file is syntactic sugar for accessing the Ruby comedilib
 # extension library generated by SWIG. The syntactic sugar is in
-# three forms:
+# four forms:
 #
 # (1)  Method names without the 'comedi_' prefix. The Comedi module
 # disambiguates the namespace.
 # (3)  A pre-defined IO object and an accessor method to simplify
 # reading from the file descriptor associated with the comedi device.
 # Data from comedi device dev can be accessed with dev.ios.read.
+#
+# (4)  A ComediError exception class. If the underlying comedi
+# function returns an error indication, the ruby method will raise
+# ComediError.
 
 require 'comedi.so'
 
 include Comedi
-include SWIG
-
-module SWIG
 
-# TYPE_p_comedi_t is returned by Comedi::open
+# SWIG::TYPE_p_comedi_t is returned by Comedi::open
 
-class TYPE_p_comedi_t
+class SWIG::TYPE_p_comedi_t
 
     # create an IO object to access the comedi_t fileno
 
     def ios
-       @ios = IO.new(fileno, 'r') if @ios.nil?
-       @ios
+       def self.ios
+           @ios
+       end
+       @ios = IO.new(fileno, 'r')
     end
 end
 
+# ComediError is raised by methods whose underlying comedi functions return
+# indication of an error.
+
+class ComediError < SystemCallError
+
+    def initialize
+       @comedi_errno = Comedi::errno
+    end
+
+    attr_reader :comedi_errno
 end
 
 module Comedi
 
 private
 
-    # wrap_module_method defines Comedi module methods without the
-    # unnecessary comedi_ prefix.
+    # wrap_method is the basis for wrap_module_method and
+    # wrap_instance_method.
 
-    def wrap_module_method(mod, name)
-       mod.module_eval <<-EOF
+    def wrap_method(mod, name, err, arglist)
+       wrap_def = %Q{
            def #{name}(*args)
-               comedi_#{name}(*args)
+               ret = comedi_#{name}(#{arglist})
+       }
+       unless err == :none
+           wrap_def << %Q{ raise ComediError.new if }
+           case err
+               when :neg
+                   wrap_def << %Q{ ret < 0 }
+               when nil
+                   wrap_def << %Q{ ret.nil?  }
+               else
+                   wrap_def << %Q{ ret == #{err} }
+           end
+       end
+       wrap_def << %Q{
+               ret
            end
-       EOF
+       }
+       mod.module_eval wrap_def
+    end
+
+    # wrap_module_method defines Comedi module methods without the
+    # unnecessary comedi_ prefix. The wrapped method raises
+    # ComediError if the return value equals a specified value.
+
+    def wrap_module_method(mod, name, err)
+       wrap_method(mod, name, err, '*args')
     end
 
     # wrap_instance_method defines instance methods for any of several
     # classes. It removes the comedi_ prefix and allows use of an
-    # explicit receiver.
+    # explicit receiver.  The wrapped method raises ComediError
+    # if the return value equals a specified value.
 
-    def wrap_instance_method(mod, name)
-       mod.module_eval <<-EOF
-           def #{name}(*args)
-               comedi_#{name}(self, *args)
-           end
-       EOF
+    def wrap_instance_method(mod, name, err)
+       wrap_method(mod, name, err, 'self, *args')
     end
 
-    # Comedi module methods
+    # This struct holds information for methods with return class and
+    # error indication.
 
-    %w{ open loglevel perror strerrno errno to_phys from_phys
-       set_global_oor_behavior parse_calibration_file
-    }.each do |name|
-       wrap_module_method(Comedi, name)
-    end
+    Method_group = Struct.new(:class, :err, :names)
 
-    # Comedi_t_struct instance methods
-
-    %w{ close fileno get_n_subdevices get_version_code
-       get_driver_name get_board_name get_subdevice_type
-       find_subdevice_by_type get_read_subdevice get_write_device
-       get_subdevice_flags get_n_channels range_is_chan_specific
-       maxdata_is_chan_specific get_maxdata get_n_ranges
-       get_range find_range get_buffer size
-       get_max_buffer_size set_buffer_size trigger
-       do_insnlist do_insn lock unlock data_read
-       data_read_delayed data_read_hint data_write dio_config
-       dio_read dio_write dio_bitfield get_cmd_src_mask
-       get_cmd_generic_timed cancel command command_test poll
-       set_max_buffer_size get_buffer_contents
-       mark_buffer_read get_buffer_offset apply_calibration
-       apply_parsed_calibration get_default_calibration_path
-    }.each do |name|
-       wrap_instance_method(SWIG::TYPE_p_comedi_t, name)
-    end
+    # Wrap Comedi module methods
 
-    # Comedi_sv_t instance methods
+    [   
+       # Comedi module methods that return nil on error.
 
-    %w{ sv_init sv_update sv_measure
-    }.each do |name|
-       wrap_instance_method(Comedi_sv_t, name)
-    end
+       Method_group.new(Comedi, nil, %w{
+           open
+           parse_calibration_file
+       }),
 
-    # Comedi_calibration_t instance methods
+       # Comedi module methods that do not indicate errors.
+
+       Method_group.new(Comedi, :none, %w{
+           loglevel
+           perror
+           strerrno
+           errno
+           to_phys
+           from_phys
+           set_global_oor_behavior
+       }),
+    ].each do |d|
+       d.names.each do |n|
+           wrap_module_method(d.class, n, d.err)
+       end
+    end
 
-    %w{ cleanup_calibration_file
-    }.each do |name|
-       wrap_instance_method(Comedi_calibration_t, name)
+    # Wrap Instance methods
+
+    [   
+       # SWIG::TYPE_p_comedi_t methods that return -1 on error.
+
+       Method_group.new(SWIG::TYPE_p_comedi_t, -1, %w{
+           close
+           fileno
+           get_subdevice_type
+           find_subdevice_by_type
+           get_read_subdevice
+           get_write_device
+           get_subdevice_flags
+           get_n_channels
+           range_is_chan_specific
+           maxdata_is_chan_specific
+           get_n_ranges
+           find_range
+           get_buffer_size
+           get_max_buffer_size
+           set_buffer_size
+           trigger
+           do_insnlist
+           do_insn
+           lock
+           unlock
+           data_read
+           data_read_delayed
+           data_write
+           dio_config
+           dio_read
+           dio_write
+           dio_bitfield
+           get_cmd_src_mask
+           get_cmd_generic_timed
+           cancel
+           command
+           command_test
+           poll
+           set_max_buffer_size
+           get_buffer_contents
+           mark_buffer_read
+           get_buffer_offset
+       }),
+
+       # SWIG::TYPE_p_comedi_t methods that return 0 on error.
+
+       Method_group.new(SWIG::TYPE_p_comedi_t, 0, %w{
+           get_maxdata
+       }),
+
+       # SWIG::TYPE_p_comedi_t methods that return <0 on error.
+
+       Method_group.new(SWIG::TYPE_p_comedi_t, :neg, %w{
+           apply_calibration
+           apply_parsed_calibration
+       }),
+
+       # SWIG::TYPE_p_comedi_t methods that return nil on error.
+
+       Method_group.new(SWIG::TYPE_p_comedi_t, nil, %w{
+           get_driver_name
+           get_board_name
+           get_range
+           get_default_calibration_path
+       }),
+
+       # SWIG::TYPE_p_comedi_t methods that do not indicate errors.
+
+       Method_group.new(SWIG::TYPE_p_comedi_t, :none, %w{
+           get_n_subdevices
+           get_version_code
+           data_read_hint
+       }),
+
+       # Comedi_sv_t methods that return -1 on errors.
+
+       Method_group.new(Comedi_sv_t, -1, %w{
+           sv_init
+           sv_update
+           sv_measure
+       }),
+
+       # Comedi_calibration_t methods that do not indicate errors.
+
+       Method_group.new(Comedi_calibration_t, :none, %w{
+           cleanup_calibration_file
+       })
+    ].each do |d|
+       d.names.each do |n|
+           wrap_instance_method(d.class, n, d.err)
+       end
     end
 end