Add quantity explosion to xlsx and csv

Closes #78
dev
Andy Meneely 2015-10-20 18:20:53 -04:00
parent dd1148d68f
commit 08381b86f0
12 changed files with 528 additions and 6 deletions

View File

@ -484,6 +484,10 @@ Squib supports importing data from `xlsx` files and `csv` files. These methods a
Of course, you can always import your game data other ways using just Ruby. There's nothing special about Squib's methods other than their convenience.
###Quantity Explosion
If you want more than one copy of a card, then have a column called `Qty` and fill it with counts. Squib's `xlsx` and `csv` methods will automatically expand those rows according to those counts. You can also customize that "Qty" to anything you like by setting the `explode` option (e.g. `explode: 'Quantity'`). See the `excel.rb` and the `csv_import.rb` samples found [here](https://github.com/andymeneely/squib/tree/master/samples/) for an example.
## Making Squib Verbose
By default, Squib's logger is set to WARN, but more fine-grained logging is embedded in the code. To set the logger, just put this at the top of your script:

View File

@ -22,7 +22,7 @@ module Squib
# @option opts file [String] the file to open. Must end in `.xlsx`. Opens relative to the current directory.
# @option opts sheet [Integer] (0) The zero-based index of the sheet from which to read.
# @option opts strip [Boolean] (true) When true, strips leading and trailing whitespace on values and headers
# @option opts qty_header [String] ('qty']) Quantity explosion will be applied to the column this name
# @option opts explode [String] ('qty') Quantity explosion will be applied to the column this name. See README for example.
# @return [Hash] a hash of arrays based on columns in the spreadsheet
# @api public
def xlsx(opts = {})
@ -44,7 +44,7 @@ module Squib
data[header] << cell
end#row
end#col
data
explode_quantities(data, import.explode)
end#xlsx
module_function :xlsx
@ -66,7 +66,7 @@ module Squib
#
# @option opts file [String] the CSV-formatted file to open. Opens relative to the current directory.
# @option opts strip [Boolean] (true) When true, strips leading and trailing whitespace on values and headers
# @option opts qty_header [String] ('qty']) Quantity explosion will be applied to the column this name
# @option opts explode [String] ('qty') Quantity explosion will be applied to the column this name. See README for example.
# @return [Hash] a hash of arrays based on columns in the table
# @api public
def csv(opts = {})
@ -87,7 +87,7 @@ module Squib
end
hash = new_hash
end
return hash
return explode_quantities(hash, import.explode)
end
module_function :csv
@ -101,6 +101,20 @@ module Squib
end
module_function :check_duplicate_csv_headers
def explode_quantities(data, qty)
return data unless data.key? qty.to_s.strip
qtys = data[qty]
new_data = {}
data.each do |col, arr|
new_data[col] = []
qtys.each_with_index do |qty, index|
qty.to_i.times { new_data[col] << arr[index] }
end
end
return new_data
end
module_function :explode_quantities
class Deck
# Convenience call on deck goes to the module function

View File

@ -8,7 +8,9 @@ module Squib
include ArgLoader
def self.parameters
{ strip: true }
{ strip: true,
explode: 'Qty'
}
end
def self.expanding_parameters
@ -24,6 +26,10 @@ module Squib
arg
end
def validate_explode(arg)
arg
end
def strip?
strip
end

View File

@ -15,4 +15,12 @@ Squib::Deck.new(cards: 2) do
end
# CSV is also a Squib-module-level function, so this also works:
data = Squib.csv file: 'sample.csv'
data = Squib.csv file: 'quantity_explosion.csv' # 2 rows...
num_cards = data['Name'].size # ...but 4 cards!
Squib::Deck.new(cards: num_cards) do
background color: :white
rect # card border
text str: data['Name'], font: 'Arial 54'
save_sheet prefix: 'sample_csv_qty_', columns: 4
end

View File

@ -14,6 +14,18 @@ Squib::Deck.new(cards: 3) do
save format: :png, prefix: 'sample_excel_' #save to individual pngs
end
# xlsx is also a Squib-module-level function, so this also works:
data = Squib.xlsx file: 'explode_quantities.xlsx' # 2 rows...
num_cards = data['Name'].size # ...but 4 cards!
Squib::Deck.new(cards: num_cards) do
background color: :white
rect # card border
text str: data['Name'], font: 'Arial 54'
save_sheet prefix: 'sample_xlsx_qty_', columns: 4
end
# Here's another example, a bit more realistic. Here's what's going on:
# * We call xlsx from Squib directly - BEFORE Squib::Deck creation. This
# allows us to infer the number of cards based on the size of the "Name"

Binary file not shown.

View File

@ -0,0 +1,3 @@
Name,Qty
Basilisk,3
High Templar,1
1 Name Qty
2 Basilisk 3
3 High Templar 1

View File

@ -36,6 +36,20 @@ describe Squib::Deck do
})
end
it 'explodes quantities' do
expect(Squib.csv(file: csv_file('qty.csv'))).to eq({
'Name' => %w(Ha Ha Ha Ho),
'Qty' => [3, 3, 3, 1],
})
end
it 'explodes quantities on specified header' do
expect(Squib.csv(explode: 'Quantity', file: csv_file('qty_named.csv'))).to eq({
'Name' => %w(Ha Ha Ha Ho),
'Quantity' => [3, 3, 3, 1],
})
end
end
context '#xlsx' do

3
spec/data/csv/qty.csv Normal file
View File

@ -0,0 +1,3 @@
Name,Qty
Ha, 3
Ho, 1
1 Name Qty
2 Ha 3
3 Ho 1

View File

@ -0,0 +1,3 @@
Name,Quantity
Ha, 3
Ho, 1
1 Name Quantity
2 Ha 3
3 Ho 1

View File

@ -74,3 +74,140 @@ pango: ellipsized?([])
cairo: restore([])
surface: write_to_png(["_output/sample_csv_00.png"])
surface: write_to_png(["_output/sample_csv_01.png"])
cairo: antialias=(["subpixel"])
cairo: antialias=(["subpixel"])
cairo: antialias=(["subpixel"])
cairo: antialias=(["subpixel"])
cairo: save([])
cairo: set_source_color(["white"])
cairo: paint([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["white"])
cairo: paint([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["white"])
cairo: paint([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["white"])
cairo: paint([])
cairo: restore([])
cairo: save([])
cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0])
cairo: set_source_color(["#0000"])
cairo: fill_preserve([])
cairo: set_source_color(["black"])
cairo: set_line_width([2.0])
cairo: set_line_join([0])
cairo: set_line_cap([0])
cairo: set_dash([[]])
cairo: stroke([])
cairo: restore([])
cairo: save([])
cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0])
cairo: set_source_color(["#0000"])
cairo: fill_preserve([])
cairo: set_source_color(["black"])
cairo: set_line_width([2.0])
cairo: set_line_join([0])
cairo: set_line_cap([0])
cairo: set_dash([[]])
cairo: stroke([])
cairo: restore([])
cairo: save([])
cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0])
cairo: set_source_color(["#0000"])
cairo: fill_preserve([])
cairo: set_source_color(["black"])
cairo: set_line_width([2.0])
cairo: set_line_join([0])
cairo: set_line_cap([0])
cairo: set_dash([[]])
cairo: stroke([])
cairo: restore([])
cairo: save([])
cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0])
cairo: set_source_color(["#0000"])
cairo: fill_preserve([])
cairo: set_source_color(["black"])
cairo: set_line_width([2.0])
cairo: set_line_join([0])
cairo: set_line_cap([0])
cairo: set_dash([[]])
cairo: stroke([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["black"])
cairo: translate([0, 0])
cairo: rotate([0])
cairo: move_to([0, 0])
pango: font_description=([MockDouble])
pango: text=(["Basilisk"])
pango: wrap=([#<Pango::Layout::WrapMode word-char>])
pango: ellipsize=([#<Pango::Layout::EllipsizeMode end>])
pango: alignment=([#<Pango::Layout::Alignment left>])
pango: justify=([false])
cairo: move_to([0, 0])
cairo: move_to([0, 0])
cairo: show_pango_layout([MockDouble])
pango: ellipsized?([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["black"])
cairo: translate([0, 0])
cairo: rotate([0])
cairo: move_to([0, 0])
pango: font_description=([MockDouble])
pango: text=(["Basilisk"])
pango: wrap=([#<Pango::Layout::WrapMode word-char>])
pango: ellipsize=([#<Pango::Layout::EllipsizeMode end>])
pango: alignment=([#<Pango::Layout::Alignment left>])
pango: justify=([false])
cairo: move_to([0, 0])
cairo: move_to([0, 0])
cairo: show_pango_layout([MockDouble])
pango: ellipsized?([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["black"])
cairo: translate([0, 0])
cairo: rotate([0])
cairo: move_to([0, 0])
pango: font_description=([MockDouble])
pango: text=(["Basilisk"])
pango: wrap=([#<Pango::Layout::WrapMode word-char>])
pango: ellipsize=([#<Pango::Layout::EllipsizeMode end>])
pango: alignment=([#<Pango::Layout::Alignment left>])
pango: justify=([false])
cairo: move_to([0, 0])
cairo: move_to([0, 0])
cairo: show_pango_layout([MockDouble])
pango: ellipsized?([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["black"])
cairo: translate([0, 0])
cairo: rotate([0])
cairo: move_to([0, 0])
pango: font_description=([MockDouble])
pango: text=(["High Templar"])
pango: wrap=([#<Pango::Layout::WrapMode word-char>])
pango: ellipsize=([#<Pango::Layout::EllipsizeMode end>])
pango: alignment=([#<Pango::Layout::Alignment left>])
pango: justify=([false])
cairo: move_to([0, 0])
cairo: move_to([0, 0])
cairo: show_pango_layout([MockDouble])
pango: ellipsized?([])
cairo: restore([])
cairo: set_source([MockDouble, 0, 0])
cairo: paint([])
cairo: set_source([MockDouble, 100, 0])
cairo: paint([])
cairo: set_source([MockDouble, 200, 0])
cairo: paint([])
cairo: set_source([MockDouble, 300, 0])
cairo: paint([])
surface: write_to_png(["_output/sample_csv_qty_00.png"])

View File

@ -163,6 +163,7 @@ surface: write_to_png(["_output/sample_excel_02.png"])
cairo: antialias=(["subpixel"])
cairo: antialias=(["subpixel"])
cairo: antialias=(["subpixel"])
cairo: antialias=(["subpixel"])
cairo: save([])
cairo: set_source_color(["white"])
cairo: paint([])
@ -176,6 +177,190 @@ cairo: set_source_color(["white"])
cairo: paint([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["white"])
cairo: paint([])
cairo: restore([])
cairo: save([])
cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0])
cairo: set_source_color(["#0000"])
cairo: fill_preserve([])
cairo: set_source_color(["black"])
cairo: set_line_width([2.0])
cairo: set_line_join([0])
cairo: set_line_cap([0])
cairo: set_dash([[]])
cairo: stroke([])
cairo: restore([])
cairo: save([])
cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0])
cairo: set_source_color(["#0000"])
cairo: fill_preserve([])
cairo: set_source_color(["black"])
cairo: set_line_width([2.0])
cairo: set_line_join([0])
cairo: set_line_cap([0])
cairo: set_dash([[]])
cairo: stroke([])
cairo: restore([])
cairo: save([])
cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0])
cairo: set_source_color(["#0000"])
cairo: fill_preserve([])
cairo: set_source_color(["black"])
cairo: set_line_width([2.0])
cairo: set_line_join([0])
cairo: set_line_cap([0])
cairo: set_dash([[]])
cairo: stroke([])
cairo: restore([])
cairo: save([])
cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0])
cairo: set_source_color(["#0000"])
cairo: fill_preserve([])
cairo: set_source_color(["black"])
cairo: set_line_width([2.0])
cairo: set_line_join([0])
cairo: set_line_cap([0])
cairo: set_dash([[]])
cairo: stroke([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["black"])
cairo: translate([0, 0])
cairo: rotate([0])
cairo: move_to([0, 0])
pango: font_description=([MockDouble])
pango: text=(["Zergling"])
pango: wrap=([#<Pango::Layout::WrapMode word-char>])
pango: ellipsize=([#<Pango::Layout::EllipsizeMode end>])
pango: alignment=([#<Pango::Layout::Alignment left>])
pango: justify=([false])
cairo: move_to([0, 0])
cairo: move_to([0, 0])
cairo: show_pango_layout([MockDouble])
pango: ellipsized?([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["black"])
cairo: translate([0, 0])
cairo: rotate([0])
cairo: move_to([0, 0])
pango: font_description=([MockDouble])
pango: text=(["Zergling"])
pango: wrap=([#<Pango::Layout::WrapMode word-char>])
pango: ellipsize=([#<Pango::Layout::EllipsizeMode end>])
pango: alignment=([#<Pango::Layout::Alignment left>])
pango: justify=([false])
cairo: move_to([0, 0])
cairo: move_to([0, 0])
cairo: show_pango_layout([MockDouble])
pango: ellipsized?([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["black"])
cairo: translate([0, 0])
cairo: rotate([0])
cairo: move_to([0, 0])
pango: font_description=([MockDouble])
pango: text=(["Zergling"])
pango: wrap=([#<Pango::Layout::WrapMode word-char>])
pango: ellipsize=([#<Pango::Layout::EllipsizeMode end>])
pango: alignment=([#<Pango::Layout::Alignment left>])
pango: justify=([false])
cairo: move_to([0, 0])
cairo: move_to([0, 0])
cairo: show_pango_layout([MockDouble])
pango: ellipsized?([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["black"])
cairo: translate([0, 0])
cairo: rotate([0])
cairo: move_to([0, 0])
pango: font_description=([MockDouble])
pango: text=(["High Templar"])
pango: wrap=([#<Pango::Layout::WrapMode word-char>])
pango: ellipsize=([#<Pango::Layout::EllipsizeMode end>])
pango: alignment=([#<Pango::Layout::Alignment left>])
pango: justify=([false])
cairo: move_to([0, 0])
cairo: move_to([0, 0])
cairo: show_pango_layout([MockDouble])
pango: ellipsized?([])
cairo: restore([])
cairo: set_source([MockDouble, 0, 0])
cairo: paint([])
cairo: set_source([MockDouble, 100, 0])
cairo: paint([])
cairo: set_source([MockDouble, 200, 0])
cairo: paint([])
cairo: set_source([MockDouble, 300, 0])
cairo: paint([])
surface: write_to_png(["_output/sample_xlsx_qty_00.png"])
cairo: antialias=(["subpixel"])
cairo: antialias=(["subpixel"])
cairo: antialias=(["subpixel"])
cairo: antialias=(["subpixel"])
cairo: antialias=(["subpixel"])
cairo: antialias=(["subpixel"])
cairo: save([])
cairo: set_source_color(["white"])
cairo: paint([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["white"])
cairo: paint([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["white"])
cairo: paint([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["white"])
cairo: paint([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["white"])
cairo: paint([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["white"])
cairo: paint([])
cairo: restore([])
cairo: save([])
cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0])
cairo: set_source_color(["#0000"])
cairo: fill_preserve([])
cairo: set_source_color(["black"])
cairo: set_line_width([2.0])
cairo: set_line_join([0])
cairo: set_line_cap([0])
cairo: set_dash([[]])
cairo: stroke([])
cairo: restore([])
cairo: save([])
cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0])
cairo: set_source_color(["#0000"])
cairo: fill_preserve([])
cairo: set_source_color(["black"])
cairo: set_line_width([2.0])
cairo: set_line_join([0])
cairo: set_line_cap([0])
cairo: set_dash([[]])
cairo: stroke([])
cairo: restore([])
cairo: save([])
cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0])
cairo: set_source_color(["#0000"])
cairo: fill_preserve([])
cairo: set_source_color(["black"])
cairo: set_line_width([2.0])
cairo: set_line_join([0])
cairo: set_line_cap([0])
cairo: set_dash([[]])
cairo: stroke([])
cairo: restore([])
cairo: save([])
cairo: rounded_rectangle([0, 0, 825, 1125, 0, 0])
cairo: set_source_color(["#0000"])
cairo: fill_preserve([])
@ -235,6 +420,69 @@ cairo: translate([0, 0])
cairo: rotate([0])
cairo: move_to([0, 0])
pango: font_description=([MockDouble])
pango: text=(["Wood"])
pango: width=([844800])
pango: wrap=([#<Pango::Layout::WrapMode word-char>])
pango: ellipsize=([#<Pango::Layout::EllipsizeMode end>])
pango: alignment=([#<Pango::Layout::Alignment center>])
pango: justify=([false])
cairo: move_to([0, 0])
cairo: move_to([0, 0])
cairo: show_pango_layout([MockDouble])
cairo: rounded_rectangle([0, 0, 0, 0, 0, 0])
cairo: set_source_color(["red"])
cairo: set_line_width([2.0])
cairo: stroke([])
pango: ellipsized?([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["black"])
cairo: translate([0, 0])
cairo: rotate([0])
cairo: move_to([0, 0])
pango: font_description=([MockDouble])
pango: text=(["Wood"])
pango: width=([844800])
pango: wrap=([#<Pango::Layout::WrapMode word-char>])
pango: ellipsize=([#<Pango::Layout::EllipsizeMode end>])
pango: alignment=([#<Pango::Layout::Alignment center>])
pango: justify=([false])
cairo: move_to([0, 0])
cairo: move_to([0, 0])
cairo: show_pango_layout([MockDouble])
cairo: rounded_rectangle([0, 0, 0, 0, 0, 0])
cairo: set_source_color(["red"])
cairo: set_line_width([2.0])
cairo: stroke([])
pango: ellipsized?([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["black"])
cairo: translate([0, 0])
cairo: rotate([0])
cairo: move_to([0, 0])
pango: font_description=([MockDouble])
pango: text=(["Metal"])
pango: width=([844800])
pango: wrap=([#<Pango::Layout::WrapMode word-char>])
pango: ellipsize=([#<Pango::Layout::EllipsizeMode end>])
pango: alignment=([#<Pango::Layout::Alignment center>])
pango: justify=([false])
cairo: move_to([0, 0])
cairo: move_to([0, 0])
cairo: show_pango_layout([MockDouble])
cairo: rounded_rectangle([0, 0, 0, 0, 0, 0])
cairo: set_source_color(["red"])
cairo: set_line_width([2.0])
cairo: stroke([])
pango: ellipsized?([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["black"])
cairo: translate([0, 0])
cairo: rotate([0])
cairo: move_to([0, 0])
pango: font_description=([MockDouble])
pango: text=(["Metal"])
pango: width=([844800])
pango: wrap=([#<Pango::Layout::WrapMode word-char>])
@ -298,6 +546,69 @@ cairo: translate([0, 0])
cairo: rotate([0])
cairo: move_to([0, 0])
pango: font_description=([MockDouble])
pango: text=(["$2k"])
pango: width=([844800])
pango: wrap=([#<Pango::Layout::WrapMode word-char>])
pango: ellipsize=([#<Pango::Layout::EllipsizeMode end>])
pango: alignment=([#<Pango::Layout::Alignment right>])
pango: justify=([false])
cairo: move_to([0, 0])
cairo: move_to([0, 0])
cairo: show_pango_layout([MockDouble])
cairo: rounded_rectangle([0, 0, 0, 0, 0, 0])
cairo: set_source_color(["red"])
cairo: set_line_width([2.0])
cairo: stroke([])
pango: ellipsized?([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["black"])
cairo: translate([0, 0])
cairo: rotate([0])
cairo: move_to([0, 0])
pango: font_description=([MockDouble])
pango: text=(["$2k"])
pango: width=([844800])
pango: wrap=([#<Pango::Layout::WrapMode word-char>])
pango: ellipsize=([#<Pango::Layout::EllipsizeMode end>])
pango: alignment=([#<Pango::Layout::Alignment right>])
pango: justify=([false])
cairo: move_to([0, 0])
cairo: move_to([0, 0])
cairo: show_pango_layout([MockDouble])
cairo: rounded_rectangle([0, 0, 0, 0, 0, 0])
cairo: set_source_color(["red"])
cairo: set_line_width([2.0])
cairo: stroke([])
pango: ellipsized?([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["black"])
cairo: translate([0, 0])
cairo: rotate([0])
cairo: move_to([0, 0])
pango: font_description=([MockDouble])
pango: text=(["$3k"])
pango: width=([844800])
pango: wrap=([#<Pango::Layout::WrapMode word-char>])
pango: ellipsize=([#<Pango::Layout::EllipsizeMode end>])
pango: alignment=([#<Pango::Layout::Alignment right>])
pango: justify=([false])
cairo: move_to([0, 0])
cairo: move_to([0, 0])
cairo: show_pango_layout([MockDouble])
cairo: rounded_rectangle([0, 0, 0, 0, 0, 0])
cairo: set_source_color(["red"])
cairo: set_line_width([2.0])
cairo: stroke([])
pango: ellipsized?([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["black"])
cairo: translate([0, 0])
cairo: rotate([0])
cairo: move_to([0, 0])
pango: font_description=([MockDouble])
pango: text=(["$3k"])
pango: width=([844800])
pango: wrap=([#<Pango::Layout::WrapMode word-char>])
@ -340,4 +651,11 @@ cairo: set_source([MockDouble, 100, 0])
cairo: paint([])
cairo: set_source([MockDouble, 200, 0])
cairo: paint([])
cairo: set_source([MockDouble, 300, 0])
cairo: paint([])
cairo: set_source([MockDouble, 400, 0])
cairo: paint([])
surface: write_to_png(["_output/sample_excel_resources_00.png"])
cairo: set_source([MockDouble, 0, 0])
cairo: paint([])
surface: write_to_png(["_output/sample_excel_resources_01.png"])