Bug #4735 ยป 0001-Adding-documentation-to-scanf.rb.patch
lib/scanf.rb | ||
---|---|---|
# scanf for Ruby
|
||
#
|
||
# $Release Version: 1.1.2 $
|
||
# $Revision$
|
||
# $Id$
|
||
# $Author$
|
||
#
|
||
# A product of the Austin Ruby Codefest (Austin, Texas, August 2002)
|
||
=begin
|
||
scanf for Ruby
|
||
$Release Version: 1.1.2 $
|
||
$Revision$
|
||
$Id$
|
||
$Author$
|
||
=scanf for Ruby
|
||
A product of the Austin Ruby Codefest (Austin, Texas, August 2002)
|
||
==Description
|
||
=scanf for ruby
|
||
scanf for Ruby is an implementation of the C function scanf(3),
|
||
modified as necessary for Ruby compatibility.
|
||
==description
|
||
The methods provided are String#scanf, IO#scanf, and
|
||
Kernel#scanf. Kernel#scanf is a wrapper around STDIN.scanf. IO#scanf
|
||
can be used on any IO stream, including file handles and sockets.
|
||
scanf for ruby is an implementation of the c function scanf(3),
|
||
modified as necessary for ruby compatibility.
|
||
the methods provided are string#scanf, io#scanf, and
|
||
kernel#scanf. kernel#scanf is a wrapper around stdin.scanf. io#scanf
|
||
can be used on any io stream, including file handles and sockets.
|
||
scanf can be called either with or without a block.
|
||
scanf for Ruby scans an input string or stream according to a
|
||
<b>format</b>, as described below ("Conversions"), and returns an
|
||
array of matches between the format and the input. The format is
|
||
scanf for ruby scans an input string or stream according to a
|
||
<b>format</b>, as described below ("conversions"), and returns an
|
||
array of matches between the format and the input. the format is
|
||
defined in a string, and is similar (though not identical) to the
|
||
formats used in Kernel#printf and Kernel#sprintf.
|
||
formats used in kernel#printf and kernel#sprintf.
|
||
The format may contain <b>conversion specifiers</b>, which tell scanf
|
||
the format may contain <b>conversion specifiers</b>, which tell scanf
|
||
what form (type) each particular matched substring should be converted
|
||
to (e.g., decimal integer, floating point number, literal string,
|
||
etc.) The matches and conversions take place from left to right, and
|
||
etc.) the matches and conversions take place from left to right, and
|
||
the conversions themselves are returned as an array.
|
||
The format string may also contain characters other than those in the
|
||
conversion specifiers. White space (blanks, tabs, or newlines) in the
|
||
the format string may also contain characters other than those in the
|
||
conversion specifiers. white space (blanks, tabs, or newlines) in the
|
||
format string matches any amount of white space, including none, in
|
||
the input. Everything else matches only itself.
|
||
the input. everything else matches only itself.
|
||
Scanning stops, and scanf returns, when any input character fails to
|
||
scanning stops, and scanf returns, when any input character fails to
|
||
match the specifications in the format string, or when input is
|
||
exhausted, or when everything in the format string has been
|
||
matched. All matches found up to the stopping point are returned in
|
||
matched. all matches found up to the stopping point are returned in
|
||
the return array (or yielded to the block, if a block was given).
|
||
==Basic usage
|
||
==basic usage
|
||
require 'scanf.rb'
|
||
# String#scanf and IO#scanf take a single argument (a format string)
|
||
array = aString.scanf("%d%s")
|
||
array = anIO.scanf("%d%s")
|
||
# string#scanf and io#scanf take a single argument (a format string)
|
||
array = astring.scanf("%d%s")
|
||
array = anio.scanf("%d%s")
|
||
# Kernel#scanf reads from STDIN
|
||
# kernel#scanf reads from stdin
|
||
array = scanf("%d%s")
|
||
==Block usage
|
||
... | ... | |
in using any of the more complex and/or arcane character class
|
||
idioms.
|
||
==License and copyright
|
||
Copyright:: (c) 2002-2003 David Alan Black
|
||
License:: Distributed on the same licensing terms as Ruby itself
|
||
==Warranty disclaimer
|
||
This software is provided "as is" and without any express or implied
|
||
warranties, including, without limitation, the implied warranties of
|
||
merchantibility and fitness for a particular purpose.
|
||
==Credits and acknowledgements
|
||
scanf for Ruby was developed as the major activity of the Austin
|
||
Ruby Codefest (Austin, Texas, August 2002).
|
||
Principal author:: David Alan Black (mailto:dblack@superlink.net)
|
||
Co-author:: Hal Fulton (mailto:hal9000@hypermetrics.com)
|
||
Project contributors:: Nolan Darilek, Jason Johnston
|
||
Thanks to Hal Fulton for hosting the Codefest.
|
||
Thanks to Matz for suggestions about the class design.
|
||
Thanks to Gavin Sinclair for some feedback on the documentation.
|
||
The text for parts of this document, especially the Description and
|
||
Conversions sections, above, were adapted from the Linux Programmer's
|
||
Manual manpage for scanf(3), dated 1995-11-01.
|
||
==Bugs and bug reports
|
||
scanf for Ruby is based on something of an amalgam of C scanf
|
||
implementations and documentation, rather than on a single canonical
|
||
description. Suggestions for features and behaviors which appear in
|
||
other scanfs, and would be meaningful in Ruby, are welcome, as are
|
||
reports of suspicious behaviors and/or bugs. (Please see "Credits and
|
||
acknowledgements", above, for email addresses.)
|
||
=end
|
||
#:stopdoc:
|
||
module Scanf
|
||
=begin
|
||
==Technical notes
|
||
===Rationale behind scanf for Ruby
|
||
... | ... | |
when the FormatString object runs out of FormatSpecifiers, scanning
|
||
stops and results accumulated so far are returned in an array.
|
||
==License and copyright
|
||
Copyright:: (c) 2002-2003 David Alan Black
|
||
License:: Distributed on the same licensing terms as Ruby itself
|
||
==Warranty disclaimer
|
||
This software is provided "as is" and without any express or implied
|
||
warranties, including, without limitation, the implied warranties of
|
||
merchantibility and fitness for a particular purpose.
|
||
==Credits and acknowledgements
|
||
scanf for Ruby was developed as the major activity of the Austin
|
||
Ruby Codefest (Austin, Texas, August 2002).
|
||
Principal author:: David Alan Black (mailto:dblack@superlink.net)
|
||
Co-author:: Hal Fulton (mailto:hal9000@hypermetrics.com)
|
||
Project contributors:: Nolan Darilek, Jason Johnston
|
||
Thanks to Hal Fulton for hosting the Codefest.
|
||
Thanks to Matz for suggestions about the class design.
|
||
Thanks to Gavin Sinclair for some feedback on the documentation.
|
||
The text for parts of this document, especially the Description and
|
||
Conversions sections, above, were adapted from the Linux Programmer's
|
||
Manual manpage for scanf(3), dated 1995-11-01.
|
||
==Bugs and bug reports
|
||
scanf for Ruby is based on something of an amalgam of C scanf
|
||
implementations and documentation, rather than on a single canonical
|
||
description. Suggestions for features and behaviors which appear in
|
||
other scanfs, and would be meaningful in Ruby, are welcome, as are
|
||
reports of suspicious behaviors and/or bugs. (Please see "Credits and
|
||
acknowledgements", above, for email addresses.)
|
||
=end
|
||
module Scanf
|
||
class FormatSpecifier
|
||
attr_reader :re_string, :matched_string, :conversion, :matched
|
||
... | ... | |
end
|
||
end
|
||
end
|
||
#:startdoc:
|
||
# When required, +scanf.rb+ adds the +scanf+ method to the +IO+
|
||
# class, for reading formatted strings from streams.
|
||
class IO
|
||
# The trick here is doing a match where you grab one *line*
|
||
# of input at a time. The linebreak may or may not occur
|
||
# at the boundary where the string matches a format specifier.
|
||
# And if it does, some rule about whitespace may or may not
|
||
# be in effect...
|
||
#
|
||
# That's why this is much more elaborate than the string
|
||
# version.
|
||
#
|
||
# For each line:
|
||
# Match succeeds (non-emptily)
|
||
# and the last attempted spec/string sub-match succeeded:
|
||
#
|
||
# could the last spec keep matching?
|
||
# yes: save interim results and continue (next line)
|
||
#
|
||
# The last attempted spec/string did not match:
|
||
#
|
||
# are we on the next-to-last spec in the string?
|
||
# yes:
|
||
# is fmt_string.string_left all spaces?
|
||
# yes: does current spec care about input space?
|
||
# yes: fatal failure
|
||
# no: save interim results and continue
|
||
# no: continue [this state could be analyzed further]
|
||
#
|
||
#
|
||
def scanf(str,&b)
|
||
#:stopdoc:
|
||
# The trick here is doing a match where you grab one *line*
|
||
# of input at a time. The linebreak may or may not occur
|
||
# at the boundary where the string matches a format specifier.
|
||
# And if it does, some rule about whitespace may or may not
|
||
# be in effect...
|
||
#
|
||
# That's why this is much more elaborate than the string
|
||
# version.
|
||
#
|
||
# For each line:
|
||
# Match succeeds (non-emptily)
|
||
# and the last attempted spec/string sub-match succeeded:
|
||
#
|
||
# could the last spec keep matching?
|
||
# yes: save interim results and continue (next line)
|
||
#
|
||
# The last attempted spec/string did not match:
|
||
#
|
||
# are we on the next-to-last spec in the string?
|
||
# yes:
|
||
# is fmt_string.string_left all spaces?
|
||
# yes: does current spec care about input space?
|
||
# yes: fatal failure
|
||
# no: save interim results and continue
|
||
# no: continue [this state could be analyzed further]
|
||
#
|
||
#:startdoc:
|
||
# Scans the current string until the match is exhausted,
|
||
# yielding each match as it is encountered in the string.
|
||
# A block is not necessary though, as the results will simply
|
||
# be aggregated into the final array.
|
||
#
|
||
# "123 456".block_scanf("%d")
|
||
# # => [123, 456]
|
||
#
|
||
# If a block is given, the value from that is returned from
|
||
# the yield is added to an output array.
|
||
#
|
||
# "123 456".block_scanf("%d) do |digit,| # Requires a ',' to unpack the Array
|
||
# digit + 100
|
||
# end
|
||
# # => [223, 556]
|
||
#
|
||
def scanf(str,&b) #:yield: +current_match+
|
||
return block_scanf(str,&b) if b
|
||
return [] unless str.size > 0
|
||
... | ... | |
end
|
||
end
|
||
# String has two convenience methods for scanning the contents
|
||
# of a string object into an +Array+. The first is the standard
|
||
# +scanf+ function; the second is the +block_scanf+, which
|
||
# yields a match to the given block, accumulating the output.
|
||
#
|
||
# Note that the String#scanf method will perform in the exact
|
||
# same way as String#block_scanf if passed a block.
|
||
#
|
||
class String
|
||
def scanf(fstr,&b)
|
||
# Scans the current string. If a block is given, it
|
||
# functions exactly like +block_scanf+.
|
||
#
|
||
# arr = "123 456".scanf("%d%d")
|
||
# # => [123, 456]
|
||
#
|
||
# require 'pp'
|
||
#
|
||
# "this 123 read that 456 other".scanf("%s%d%s") {|m| pp m}
|
||
#
|
||
# # ["this", 123, "read"]
|
||
# # ["that", 456, "other"]
|
||
# # => [["this", 123, "read"], ["that", 456, "other"]]
|
||
#
|
||
def scanf(fstr,&b) #:yield: +current_match+ if block_given?
|
||
if b
|
||
block_scanf(fstr,&b)
|
||
else
|
||
... | ... | |
end
|
||
end
|
||
def block_scanf(fstr,&b)
|
||
# Scans the current string until the match is exhausted,
|
||
# yielding each match as it is encountered in the string.
|
||
# A block is not necessary though, as the results will simply
|
||
# be aggregated into the final array.
|
||
#
|
||
# "123 456".block_scanf("%d")
|
||
# # => [123, 456]
|
||
#
|
||
# If a block is given, the value from that is returned from
|
||
# the yield is added to an output array.
|
||
#
|
||
# "123 456".block_scanf("%d) do |digit,| # Requires a ',' to unpack the Array
|
||
# digit + 100
|
||
# end
|
||
# # => [223, 556]
|
||
#
|
||
def block_scanf(fstr,&b) #:yield: +current_match+
|
||
fs = Scanf::FormatString.new(fstr)
|
||
str = self.dup
|
||
final = []
|
||
... | ... | |
end
|
||
end
|
||
module Kernel
|
||
# The Kernel#scanf method is private by default, but because +Kernel+
|
||
# is mixed in the +Object+ inheritance heirarchy, it is thus
|
||
# available everywhere.
|
||
#
|
||
# It reads from +STDIN+.
|
||
#
|
||
module Kernel
|
||
private
|
||
def scanf(fs,&b)
|
||
# Queries +STDIN+ for input.
|
||
def scanf(fs,&b) #:doc:
|
||
STDIN.scanf(fs,&b)
|
||
end
|
||
end
|