Class: Philiprehberger::CsvBuilder::Builder
- Inherits:
-
Object
- Object
- Philiprehberger::CsvBuilder::Builder
- Defined in:
- lib/philiprehberger/csv_builder/builder.rb
Overview
DSL builder for constructing CSV output from records
Instance Attribute Summary collapse
-
#columns ⇒ Array<Column>
readonly
The defined columns.
-
#records ⇒ Array
readonly
The source records.
Instance Method Summary collapse
-
#column(name, header: nil) {|record| ... } ⇒ self
Define a column.
-
#filter {|record| ... } ⇒ self
Add a filter to exclude records.
-
#filtered_records ⇒ Array
Return the filtered records.
-
#footer {|Array| ... } ⇒ self
Append a computed footer row after all data rows.
-
#headers ⇒ Array<String>
Return the header row.
-
#initialize(records, delimiter: ',', quote_char: '"', bom: false, encoding: 'UTF-8') ⇒ Builder
constructor
A new instance of Builder.
-
#limit(n) ⇒ self
Limit the number of output rows.
-
#offset(n) ⇒ self
Skip the first N filtered/sorted records.
-
#row_number(header: '#') ⇒ self
Add an auto-incrementing row number as the first column.
-
#sort_by(direction: :asc) {|record| ... } ⇒ self
Sort records before CSV output.
-
#to_csv ⇒ String
Generate the CSV as a string.
-
#to_file(path) ⇒ void
Write the CSV to a file.
-
#to_io(io) ⇒ void
Stream CSV to any IO object.
-
#total(column_name) {|values| ... } ⇒ self
Shorthand for adding a footer row with a computed total for the named column.
-
#transform_header {|name| ... } ⇒ self
Register a proc applied to all column headers during rendering.
-
#validate {|row| ... } ⇒ self
Register a validation block for rows.
Constructor Details
#initialize(records, delimiter: ',', quote_char: '"', bom: false, encoding: 'UTF-8') ⇒ Builder
Returns a new instance of Builder.
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/philiprehberger/csv_builder/builder.rb', line 21 def initialize(records, delimiter: ',', quote_char: '"', bom: false, encoding: 'UTF-8') @records = records @columns = [] @filters = [] @validations = [] @row_number_header = nil @delimiter = delimiter @quote_char = quote_char @sort_by = nil @sort_direction = :asc @limit_count = nil @offset_count = nil @footer_block = nil @header_transform = nil @bom = bom @encoding = encoding end |
Instance Attribute Details
#columns ⇒ Array<Column> (readonly)
Returns the defined columns.
11 12 13 |
# File 'lib/philiprehberger/csv_builder/builder.rb', line 11 def columns @columns end |
#records ⇒ Array (readonly)
Returns the source records.
14 15 16 |
# File 'lib/philiprehberger/csv_builder/builder.rb', line 14 def records @records end |
Instance Method Details
#column(name, header: nil) {|record| ... } ⇒ self
Define a column
131 132 133 134 |
# File 'lib/philiprehberger/csv_builder/builder.rb', line 131 def column(name, header: nil, &block) @columns << Column.new(name, header: header, &block) self end |
#filter {|record| ... } ⇒ self
Add a filter to exclude records
141 142 143 144 |
# File 'lib/philiprehberger/csv_builder/builder.rb', line 141 def filter(&block) @filters << block self end |
#filtered_records ⇒ Array
Return the filtered records
167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/philiprehberger/csv_builder/builder.rb', line 167 def filtered_records result = @records @filters.each do |f| result = result.select(&f) end if @sort_by result = result.sort_by(&@sort_by) result = result.reverse if @sort_direction == :desc end result = result.drop(@offset_count) if @offset_count result = result.first(@limit_count) if @limit_count result end |
#footer {|Array| ... } ⇒ self
Append a computed footer row after all data rows
79 80 81 82 |
# File 'lib/philiprehberger/csv_builder/builder.rb', line 79 def (&block) @footer_block = block self end |
#headers ⇒ Array<String>
Return the header row
158 159 160 161 162 |
# File 'lib/philiprehberger/csv_builder/builder.rb', line 158 def headers base = @columns.map(&:header) base = base.map { |h| @header_transform.call(h) } if @header_transform @row_number_header ? [@row_number_header] + base : base end |
#limit(n) ⇒ self
Limit the number of output rows
60 61 62 63 |
# File 'lib/philiprehberger/csv_builder/builder.rb', line 60 def limit(n) @limit_count = n self end |
#offset(n) ⇒ self
Skip the first N filtered/sorted records
69 70 71 72 |
# File 'lib/philiprehberger/csv_builder/builder.rb', line 69 def offset(n) @offset_count = n self end |
#row_number(header: '#') ⇒ self
Add an auto-incrementing row number as the first column
150 151 152 153 |
# File 'lib/philiprehberger/csv_builder/builder.rb', line 150 def row_number(header: '#') @row_number_header = header self end |
#sort_by(direction: :asc) {|record| ... } ⇒ self
Sort records before CSV output
46 47 48 49 50 51 52 53 54 |
# File 'lib/philiprehberger/csv_builder/builder.rb', line 46 def sort_by(direction: :asc, &block) raise Error, 'A block is required for sort_by' unless block raise Error, "direction must be :asc or :desc (got #{direction.inspect})" unless %i[asc desc].include?(direction) @sort_by = block @sort_direction = direction self end |
#to_csv ⇒ String
Generate the CSV as a string
185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/philiprehberger/csv_builder/builder.rb', line 185 def to_csv recs = filtered_records validate_rows!(recs) unless @validations.empty? csv_string = CSV.generate(**) do |csv| csv << headers recs.each_with_index do |record, index| csv << build_row(record, index) end csv << @footer_block.call(recs) if @footer_block end csv_string = csv_string.encode(@encoding) unless @encoding == 'UTF-8' @bom ? "\xEF\xBB\xBF#{csv_string}" : csv_string end |
#to_file(path) ⇒ void
This method returns an undefined value.
Write the CSV to a file
203 204 205 |
# File 'lib/philiprehberger/csv_builder/builder.rb', line 203 def to_file(path) File.binwrite(path, to_csv) end |
#to_io(io) ⇒ void
This method returns an undefined value.
Stream CSV to any IO object
212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/philiprehberger/csv_builder/builder.rb', line 212 def to_io(io) io.write("\xEF\xBB\xBF") if @bom recs = filtered_records validate_rows!(recs) unless @validations.empty? csv = CSV.new(io, **) csv << headers recs.each_with_index do |record, index| csv << build_row(record, index) end csv << @footer_block.call(recs) if @footer_block end |
#total(column_name) {|values| ... } ⇒ self
Shorthand for adding a footer row with a computed total for the named column
109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/philiprehberger/csv_builder/builder.rb', line 109 def total(column_name, &block) col_name = column_name.to_sym @footer_block = lambda do |recs| columns.map do |col| if col.name == col_name values = recs.map { |r| col.extract(r).to_f } block ? block.call(values) : values.sum else '' end end end self end |
#transform_header {|name| ... } ⇒ self
Register a proc applied to all column headers during rendering
99 100 101 102 |
# File 'lib/philiprehberger/csv_builder/builder.rb', line 99 def transform_header(&block) @header_transform = block self end |
#validate {|row| ... } ⇒ self
Register a validation block for rows
89 90 91 92 |
# File 'lib/philiprehberger/csv_builder/builder.rb', line 89 def validate(&block) @validations << block self end |