Browse Source

Add quantity explosion to xlsx and csv

Closes #78
dev
Andy Meneely 10 years ago
parent
commit
08381b86f0
  1. 4
      README.md
  2. 22
      lib/squib/api/data.rb
  3. 8
      lib/squib/args/import.rb
  4. 10
      samples/csv_import.rb
  5. 12
      samples/excel.rb
  6. BIN
      samples/explode_quantities.xlsx
  7. 3
      samples/quantity_explosion.csv
  8. 14
      spec/api/api_data_spec.rb
  9. 3
      spec/data/csv/qty.csv
  10. 3
      spec/data/csv/qty_named.csv
  11. 137
      spec/data/samples/csv_import.rb.txt
  12. 318
      spec/data/samples/excel.rb.txt

4
README.md

@ -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:

22
lib/squib/api/data.rb

@ -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

8
lib/squib/args/import.rb

@ -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

10
samples/csv_import.rb

@ -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

12
samples/excel.rb

@ -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"

BIN
samples/explode_quantities.xlsx

Binary file not shown.

3
samples/quantity_explosion.csv

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

14
spec/api/api_data_spec.rb

@ -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

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

3
spec/data/csv/qty_named.csv

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

137
spec/data/samples/csv_import.rb.txt

@ -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"])

318
spec/data/samples/excel.rb.txt

@ -163,6 +163,11 @@ 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([])
cairo: restore([])
cairo: save([])
cairo: set_source_color(["white"])
cairo: paint([])
@ -209,6 +214,186 @@ 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([])
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])
@ -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"])

Loading…
Cancel
Save