107107# tools to enable you to read and write to and from Strings or IO objects, as
108108# needed.
109109#
110+ # All examples here assume prior execution of:
111+ # require 'csv'
112+ #
110113# The most generic interface of the library is:
111114#
112115# csv = CSV.new(io, **options)
@@ -752,20 +755,78 @@ def filter(input=nil, output=nil, **options)
752755 end
753756
754757 #
755- # This method is intended as the primary interface for reading CSV files. You
756- # pass a +path+ and any +options+ you wish to set for the read. Each row of
757- # file will be passed to the provided +block+ in turn.
758+ # :call-seq:
759+ # foreach(path, mode='r', **options) {|row| ... ) -> integer or nil
760+ # foreach(io, mode='r', **options {|row| ... ) -> integer or nil
761+ # foreach(path, mode='r', **options) -> new_enumerator
762+ # foreach(io, mode='r', **options -> new_enumerator
758763 #
759- # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
764+ # Calls the block with each row read from source +path+ or +io+.
765+ # Returns an integer, or, if there were no rows, +nil+.
760766 #
761- # The +options+ parameter can be anything CSV::new() understands. This method
762- # also understands an additional <tt>:encoding</tt> parameter that you can use
763- # to specify the Encoding of the data in the file to be read. You must provide
764- # this unless your data is in Encoding::default_external(). CSV will use this
765- # to determine how to parse the data. You may provide a second Encoding to
766- # have the data transcoded as it is read. For example,
767- # <tt>encoding: "UTF-32BE:UTF-8"</tt> would read UTF-32BE data from the file
768- # but transcode it to UTF-8 before CSV parses it.
767+ # * Argument +path+, if given, must be the path to a file.
768+ # * Argument +io+, if given, must be an \IO object opened for reading.
769+ # * Argument +mode+, if given, must be a \File mode
770+ # See {Open Mode}[IO.html#method-c-new-label-Open+Mode].
771+ # * Arguments <tt>**options</tt> must be keyword options.
772+ # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
773+ # * This method optionally accepts an additional <tt>:encoding</tt> option
774+ # that you can use to specify the Encoding of the data read from +path+ or +io+.
775+ # You must provide this unless your data is in the encoding
776+ # given by <tt>Encoding::default_external</tt>.
777+ # Parsing will use this to determine how to parse the data.
778+ # You may provide a second Encoding to
779+ # have the data transcoded as it is read. For example,
780+ # encoding: 'UTF-32BE:UTF-8'
781+ # would read +UTF-32BE+ data from the file
782+ # but transcode it to +UTF-8+ before parsing.
783+ #
784+ # ---
785+ #
786+ # These examples assume prior execution of:
787+ # string = "foo,0\nbar,1\nbaz,2\n"
788+ # path = 't.csv'
789+ # File.write(path, string)
790+ # io = File.open(path)
791+ #
792+ # Read rows from a file at +path+:
793+ # CSV.foreach(path) {|row| p row } # => 21
794+ # Output:
795+ # ["foo", "0"]
796+ # ["bar", "1"]
797+ # ["baz", "2"]
798+ #
799+ # Read rows from an \IO object:
800+ # CSV.foreach(io) {|row| p row } # => 21
801+ # Output:
802+ # ["foo", "0"]
803+ # ["bar", "1"]
804+ # ["baz", "2"]
805+ #
806+ # Returns a new \Enumerator if no block given:
807+ # CSV.foreach(path) # => #<Enumerator: CSV:foreach("t.csv", "r")>
808+ # CSV.foreach(io) # => #<Enumerator: CSV:foreach(#<File:t.csv>, "r")>
809+ #
810+ # Issues a warning if an encoding is unsupported:
811+ # CSV.foreach(io, encoding: 'foo:bar') {|row| } # => 21
812+ # Output:
813+ # warning: Unsupported encoding foo ignored
814+ # warning: Unsupported encoding bar ignored
815+ #
816+ # ---
817+ #
818+ # Raises an exception if +path+ is a \String, but not the path to a readable file:
819+ # # Raises Errno::ENOENT (No such file or directory @ rb_sysopen - nosuch.csv):
820+ # CSV.foreach('nosuch.csv') {|row| }
821+ #
822+ # Raises an exception if +io+ is an \IO object, but not open for reading:
823+ # io = File.open(path, 'w') {|row| }
824+ # # Raises TypeError (no implicit conversion of nil into String):
825+ # CSV.foreach(io) {|row| }
826+ #
827+ # Raises an exception if +mode+ is invalid:
828+ # # Raises IOError (not opened for reading):
829+ # CSV.foreach(path, 'w') {|row| }
769830 #
770831 def foreach ( path , mode = "r" , **options , &block )
771832 return to_enum ( __method__ , path , mode , **options ) unless block_given?
@@ -776,23 +837,63 @@ def foreach(path, mode="r", **options, &block)
776837
777838 #
778839 # :call-seq:
779- # generate( str , **options ) { |csv| ... }
780- # generate( **options ) { |csv| ... }
840+ # generate(csv_string , **options) {|csv| ... }
841+ # generate(**options) {|csv| ... }
781842 #
782- # This method wraps a String you provide, or an empty default String, in a
783- # CSV object which is passed to the provided block. You can use the block to
784- # append CSV rows to the String and when the block exits, the final String
785- # will be returned .
843+ # * Argument +csv_string+, if given, must be a \ String object;
844+ # defaults to a new empty \String.
845+ # * Arguments +options+, if given, should be parsing options.
846+ # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing] .
786847 #
787- # Note that a passed String *is* modified by this method. Call dup() before
788- # passing if you need a new String.
848+ # ---
789849 #
790- # See {Options for Generating}[#class-CSV-label-Options+for+Generating].
850+ # Creates a new \CSV object via <tt>CSV.new(csv_string, **options)</tt>;
851+ # calls the block with the \CSV object, which the block may modify;
852+ # returns the \String generated from the \CSV object.
853+ #
854+ # Note that a passed \String *is* modified by this method.
855+ # Pass <tt>csv_string</tt>.dup if the \String must be preserved.
791856 #
792857 # This method has one additional option: <tt>:encoding</tt>,
793858 # which sets the base Encoding for the output if no no +str+ is specified.
794859 # CSV needs this hint if you plan to output non-ASCII compatible data.
795860 #
861+ # ---
862+ #
863+ # Add lines:
864+ # input_string = "foo,0\nbar,1\nbaz,2\n"
865+ # output_string = CSV.generate(input_string) do |csv|
866+ # csv << ['bat', 3]
867+ # csv << ['bam', 4]
868+ # end
869+ # output_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n"
870+ # input_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n"
871+ # output_string.equal?(input_string) # => true # Same string, modified
872+ #
873+ # Add lines into new string, preserving old string:
874+ # input_string = "foo,0\nbar,1\nbaz,2\n"
875+ # output_string = CSV.generate(input_string.dup) do |csv|
876+ # csv << ['bat', 3]
877+ # csv << ['bam', 4]
878+ # end
879+ # output_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n"
880+ # input_string # => "foo,0\nbar,1\nbaz,2\n"
881+ # output_string.equal?(input_string) # => false # Different strings
882+ #
883+ # Create lines from nothing:
884+ # output_string = CSV.generate do |csv|
885+ # csv << ['foo', 0]
886+ # csv << ['bar', 1]
887+ # csv << ['baz', 2]
888+ # end
889+ # output_string # => "foo,0\nbar,1\nbaz,2\n"
890+ #
891+ # ---
892+ #
893+ # Raises an exception if +csv_string+ is not a \String object:
894+ # # Raises TypeError (no implicit conversion of Integer into String)
895+ # CSV.generate(0)
896+ #
796897 def generate ( str = nil , **options )
797898 encoding = options [ :encoding ]
798899 # add a default empty String, if none was given
@@ -865,7 +966,7 @@ def generate_line(row, **options)
865966 # You must pass a +filename+ and may optionally add a +mode+ for Ruby's
866967 # open().
867968 #
868- # See {Options for Generating }[#class-CSV-label-Options+for+Generating ].
969+ # See {Options for Parsing }[#class-CSV-label-Options+for+Parsing ].
869970 #
870971 # This method works like Ruby's open() call, in that it will pass a CSV object
871972 # to a provided block and close it when the block terminates, or it will
0 commit comments