def write(*args)
    # Check for a cell reference in A1 notation and substitute row and column
    args = row_col_notation(args)

    token = args[2]

    # Handle undefs as blanks
    token ||= ''

    # First try user defined matches.
    @write_match.each do |aref|
      re  = aref[0]
      sub = aref[1]

      if token =~ Regexp.new(re)
        match = eval("#{sub} self, args")
        return match if match
      end
    end

    # Match an array ref.
    if token.respond_to?(:to_ary)
      write_row(*args)
    elsif token.respond_to?(:coerce)  # Numeric
      write_number(*args)
      # Match http, https or ftp URL
    elsif token =~ %r|^[fh]tt?ps?://|
      write_url(*args)
      # Match mailto:
    elsif token =~ %r|^mailto:|
      write_url(*args)
      # Match internal or external sheet link
    elsif token =~ %r!^(?:in|ex)ternal:!
      write_url(*args)
      # Match formula
    elsif token =~ /^=/
      write_formula(*args)
      # Match blank
    elsif token == ''
      args.delete_at(2)     # remove the empty string from the parameter list
      write_blank(*args)
    else
      write_string(*args)
    end
  end
def write(*args)
    # Check for a cell reference in A1 notation and substitute row and column
    args = row_col_notation(args)

    token = args[2]

    # Handle undefs as blanks
    token ||= ''

    # First try user defined matches.
    @write_match.each do |aref|
      re  = aref[0]
      sub = aref[1]

      if token =~ Regexp.new(re)
        match = eval("#{sub} self, args")
        return match if match
      end
    end

    # Match an array ref.
    if token.respond_to?(:to_ary)
      write_row(*args)
    elsif token.respond_to?(:coerce)  # Numeric
      write_number(*args)
      # Match http, https or ftp URL
    elsif token =~ %r|^[fh]tt?ps?://|
      write_url(*args)
      # Match mailto:
    elsif token =~ %r|^mailto:|
      write_url(*args)
      # Match internal or external sheet link
    elsif token =~ %r!^(?:in|ex)ternal:!
      write_url(*args)
      # Match formula
    elsif token =~ /^=/
      write_formula(*args)
      # Match blank
    elsif token == ''
      args.delete_at(2)     # remove the empty string from the parameter list
      write_blank(*args)
    else
      write_string(*args)
    end
  end
--

 Allow the user to add their own matches and handlers to the write() method.

 This method is used to extend the WriteExcel write() method to handle user
 defined data.

 If you refer to the section on write() above you will see that it acts as an
 alias for several more specific write_* methods. However, it doesn't always
 act in exactly the way that you would like it to.

 One solution is to filter the input data yourself and call the appropriate
 write_* method. Another approach is to use the add_write_handler() method
 to add your own automated behaviour to write().

 The add_write_handler() method take two arguments, _re_, a regular
 expression to match incoming data and _code_ a callback function to handle
 the matched data:

     worksheet.add_write_handler(qr/^\d\d\d\d$/, \&my_write)

 (In the these examples the qr operator is used to quote the regular expression
 strings, see perlop for more details).

 The method is used as follows. say you wished to write 7 digit ID numbers as
 a string so that any leading zeros were preserved*, you could do something
 like the following:

     worksheet.add_write_handler(qr/^\d{7}$/, \&write_my_id)

     sub write_my_id {
         my $worksheet = shift;
         return $worksheet->write_string(@_);
     }

 * You could also use the keep_leading_zeros() method for this.

 Then if you call write() with an appropriate string it will be handled automatically:

     # Writes 0000000. It would normally be written as a number; 0.
     $worksheet->write('A1', '0000000');

 The callback function will receive a reference to the calling worksheet
 and all of the other arguments that were passed to write(). The callback
 will see an @_ argument list that looks like the following:

     $_[0]   A ref to the calling worksheet. *
     $_[1]   Zero based row number.
     $_[2]   Zero based column number.
     $_[3]   A number or string or token.
     $_[4]   A format ref if any.
     $_[5]   Any other arguments.
     ...

     *  It is good style to shift this off the list so the @_ is the same
        as the argument list seen by write().

 Your callback should return() the return value of the write_* method that
 was called or undef to indicate that you rejected the match and want
 write() to continue as normal.

 So for example if you wished to apply the previous filter only to ID
 values that occur in the first column you could modify your callback
 function as follows:

     sub write_my_id {
         my $worksheet = shift;
         my $col       = $_[1];

         if ($col == 0) {
             return $worksheet->write_string(@_);
         }
         else {
             # Reject the match and return control to write()
             return undef;
         }
     }

 Now, you will get different behaviour for the first column and other
 columns:

     $worksheet->write('A1', '0000000'); # Writes 0000000
     $worksheet->write('B1', '0000000'); # Writes 0

 You may add more than one handler in which case they will be called in the
 order that they were added.

 Note, the add_write_handler() method is particularly suited for handling
 dates.

 See the write_handler 1-4 programs in the examples directory for further
 examples.

++
  def add_write_handler(regexp, code_ref)
    #       return unless ref $_[1] eq 'CODE';

    @write_match.push([regexp, code_ref])
  end

 :call-seq:
   write(row, col,    token, format)
   write(A1_notation, token, format)

 Parse token and call appropriate write method. row and column are zero
 indexed. format is optional.

 The write_url() methods have a flag to prevent recursion when writing a
 string that looks like a url.

 Returns: return value of called subroutine


 Excel makes a distinction between data types such as strings, numbers,
 blanks, formulas and hyperlinks. To simplify the process of writing
 data the write() method acts as a general alias for several more
 specific methods:
    write_string()
    write_number()
    write_blank()
    write_formula()
    write_url()
    write_row()
    write_col()

 The general rule is that if the data looks like a something then a
 something is written. Here are some examples in both row-column
 and A1 notation:
                                                         # Same as:
    worksheet.write(0, 0, 'Hello'                     )  # write_string()
    worksheet.write(1, 0, 'One'                       )  # write_string()
    worksheet.write(2, 0,  2                          )  # write_number()
    worksheet.write(3, 0,  3.00001                    )  # write_number()
    worksheet.write(4, 0,  ""                         )  # write_blank()
    worksheet.write(5, 0,  ''                         )  # write_blank()
    worksheet.write(6, 0,  nil                        )  # write_blank()
    worksheet.write(7, 0                              )  # write_blank()
    worksheet.write(8, 0,  'http://www.ruby-lang.org/')  # write_url()
    worksheet.write('A9',  'ftp://ftp.ruby-lang.org/' )  # write_url()
    worksheet.write('A10', 'internal:Sheet1!A1'       )  # write_url()
    worksheet.write('A11', 'external:c:\foo.xls'      )  # write_url()
    worksheet.write('A12', '=A3 + 3*A4'               )  # write_formula()
    worksheet.write('A13', '=SIN(PI()/4)'             )  # write_formula()
    worksheet.write('A14', ['name', 'company']        )  # write_row()
    worksheet.write('A15', [ ['name', 'company'] ]    )  # write_col()

 And if the keep_leading_zeros property is set:
  $worksheet.write('A16,  2                     ); # write_number()
    $worksheet.write('A17,  02                    ); # write_string()
    $worksheet.write('A18,  00002                 ); # write_string()

 The "looks like" rule is defined by regular expressions:

 * write_number() if _token_ is a number based on the following regex:
   token =~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/.

 * write_string() if keep_leading_zeros() is set and _token_ is an integer
   with leading zeros based on the following regex: token =~ /^0\d+$/.

 * write_blank() if _token_ is undef or a blank string: undef, "" or ''.

 * write_url() if _token_ is a http, https, ftp or mailto URL based on the
   following regexes: token =~ m|^[fh]tt?ps?://| or $token =~ m|^mailto:|.

 * write_url() if _token_ is an internal or external sheet reference based
   on the following regex: token =~ m[^(in|ex)ternal:].

 * write_formula() if the first character of _token_ is "=".

 * write_row() if _token_ is an array.

 * write_col() if _token+ is an array of array.

 * write_string() if none of the previous conditions apply.

 The format parameter is optional. It should be a valid Format object, see
 "CELL FORMATTING":

    format = workbook.add_format
    format.set_bold
    format.set_color('red')
    format.set_align('center')

    worksheet.write(4, 0, 'Hello', format)   # Formatted string

 The write() method will ignore empty strings or undef tokens unless a
 format is also supplied. As such you needn't worry about special
 handling for empty or undef values in your data. See also the
 write_blank() method.

 One problem with the write() method is that occasionally data looks like a
 number but you don't want it treated as a number. For example, zip codes or
 ID numbers often start with a leading zero. If you write this data as a
 number then the leading zero(s) will be stripped. You can change this
 default behaviour by using the keep_leading_zeros() method. While this
 property is in place any integers with leading zeros will be treated as
 strings and the zeros will be preserved. See the keep_leading_zeros()
 section for a full discussion of this issue.

 You can also add your own data handlers to the write() method using
 add_write_handler().

 The write methods return:

    0 for success.
   -1 for insufficient number of arguments.
   -2 for row or column out of bounds.
   -3 for string too long.