import: data frames are here!
Implemented a whole new class to represent the data that comes in from CSV and XLSX. See docs for more info. Closes #153
This commit is contained in:
+18
-18
@@ -3,7 +3,7 @@ require 'spec_helper'
|
||||
describe Squib::Deck do
|
||||
context '#csv' do
|
||||
it 'loads basic csv data' do
|
||||
expect(Squib.csv(file: csv_file('basic.csv'))).to eq({
|
||||
expect(Squib.csv(file: csv_file('basic.csv')).to_h.to_h).to eq({
|
||||
'h1' => [1, 3],
|
||||
'h2' => [2, 4]
|
||||
})
|
||||
@@ -12,7 +12,7 @@ describe Squib::Deck do
|
||||
it 'collapses duplicate columns and warns' do
|
||||
expect(Squib.logger).to receive(:warn)
|
||||
.with('CSV duplicated the following column keys: h1,h1')
|
||||
expect(Squib.csv(file: csv_file('dup_cols.csv'))).to eq({
|
||||
expect(Squib.csv(file: csv_file('dup_cols.csv')).to_h.to_h).to eq({
|
||||
'h1' => [1, 3],
|
||||
'h2' => [5, 7],
|
||||
'H2' => [6, 8],
|
||||
@@ -21,7 +21,7 @@ describe Squib::Deck do
|
||||
end
|
||||
|
||||
it 'strips spaces by default' do
|
||||
expect(Squib.csv(file: csv_file('with_spaces.csv'))).to eq({
|
||||
expect(Squib.csv(file: csv_file('with_spaces.csv')).to_h).to eq({
|
||||
'With Spaces' => ['a b c', 3],
|
||||
'h2' => [2, 4],
|
||||
'h3' => [3, nil]
|
||||
@@ -29,7 +29,7 @@ describe Squib::Deck do
|
||||
end
|
||||
|
||||
it 'skips space stripping if told to' do
|
||||
expect(Squib.csv(strip: false, file: csv_file('with_spaces.csv'))).to eq({
|
||||
expect(Squib.csv(strip: false, file: csv_file('with_spaces.csv')).to_h).to eq({
|
||||
' With Spaces ' => ['a b c ', 3],
|
||||
'h2' => [2, 4],
|
||||
'h3' => [3, nil]
|
||||
@@ -37,14 +37,14 @@ describe Squib::Deck do
|
||||
end
|
||||
|
||||
it 'explodes quantities' do
|
||||
expect(Squib.csv(file: csv_file('qty.csv'))).to eq({
|
||||
expect(Squib.csv(file: csv_file('qty.csv')).to_h).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({
|
||||
expect(Squib.csv(explode: 'Quantity', file: csv_file('qty_named.csv')).to_h).to eq({
|
||||
'Name' => %w(Ha Ha Ha Ho),
|
||||
'Quantity' => [3, 3, 3, 1],
|
||||
})
|
||||
@@ -52,7 +52,7 @@ describe Squib::Deck do
|
||||
|
||||
it 'loads inline data' do
|
||||
hash = Squib.csv(data: "h1,h2\n1,2\n3,4")
|
||||
expect(hash).to eq({
|
||||
expect(hash.to_h).to eq({
|
||||
'h1' => [1, 3],
|
||||
'h2' => [2, 4]
|
||||
})
|
||||
@@ -60,7 +60,7 @@ describe Squib::Deck do
|
||||
|
||||
it 'loads csv with newlines' do
|
||||
hash = Squib.csv(file: csv_file('newline.csv'))
|
||||
expect(hash).to eq({
|
||||
expect(hash.to_h).to eq({
|
||||
'title' => ['Foo'],
|
||||
'level' => [1],
|
||||
'notes' => ["a\nb"]
|
||||
@@ -70,7 +70,7 @@ describe Squib::Deck do
|
||||
it 'loads custom CSV options' do
|
||||
hash = Squib.csv(file: csv_file('custom_opts.csv'),
|
||||
col_sep: '-', quote_char: '|')
|
||||
expect(hash).to eq({
|
||||
expect(hash.to_h).to eq({
|
||||
'x' => ['p'],
|
||||
'y' => ['q-r']
|
||||
})
|
||||
@@ -85,7 +85,7 @@ describe Squib::Deck do
|
||||
'ha'
|
||||
end
|
||||
end
|
||||
expect(data).to eq({
|
||||
expect(data.to_h).to eq({
|
||||
'h1' => [2, 6],
|
||||
'h2' => %w(ha ha),
|
||||
})
|
||||
@@ -99,7 +99,7 @@ describe Squib::Deck do
|
||||
value
|
||||
end
|
||||
end
|
||||
expect(data).to eq({
|
||||
expect(data.to_h).to eq({
|
||||
'a' => ["foo\nbar", 1],
|
||||
'b' => [1, "blah\n"],
|
||||
})
|
||||
@@ -109,7 +109,7 @@ describe Squib::Deck do
|
||||
|
||||
context '#xlsx' do
|
||||
it 'loads basic xlsx data' do
|
||||
expect(Squib.xlsx(file: xlsx_file('basic.xlsx'))).to eq({
|
||||
expect(Squib.xlsx(file: xlsx_file('basic.xlsx')).to_h).to eq({
|
||||
'Name' => %w(Larry Curly Mo),
|
||||
'General Number' => %w(1 2 3), # general types always get loaded as strings with no conversion
|
||||
'Actual Number' => [4.0, 5.0, 6.0], # numbers get auto-converted to integers
|
||||
@@ -117,7 +117,7 @@ describe Squib::Deck do
|
||||
end
|
||||
|
||||
it 'loads xlsx with formulas' do
|
||||
expect(Squib.xlsx(file: xlsx_file('formulas.xlsx'))).to eq({
|
||||
expect(Squib.xlsx(file: xlsx_file('formulas.xlsx')).to_h).to eq({
|
||||
'A' => %w(1 2),
|
||||
'B' => %w(3 4),
|
||||
'Sum' => %w(4 6),
|
||||
@@ -125,20 +125,20 @@ describe Squib::Deck do
|
||||
end
|
||||
|
||||
it 'loads xlsm files with macros' do
|
||||
expect(Squib.xlsx(file: xlsx_file('with_macros.xlsm'))).to eq({
|
||||
expect(Squib.xlsx(file: xlsx_file('with_macros.xlsm')).to_h).to eq({
|
||||
'foo' => %w(8 10),
|
||||
'bar' => %w(9 11),
|
||||
})
|
||||
end
|
||||
|
||||
it 'strips whitespace by default' do
|
||||
expect(Squib.xlsx(file: xlsx_file('whitespace.xlsx'))).to eq({
|
||||
expect(Squib.xlsx(file: xlsx_file('whitespace.xlsx')).to_h).to eq({
|
||||
'With Whitespace' => ['foo', 'bar', 'baz'],
|
||||
})
|
||||
end
|
||||
|
||||
it 'does not strip whitespace when specified' do
|
||||
expect(Squib.xlsx(file: xlsx_file('whitespace.xlsx'), strip: false)).to eq({
|
||||
expect(Squib.xlsx(file: xlsx_file('whitespace.xlsx'), strip: false).to_h).to eq({
|
||||
' With Whitespace ' => ['foo ', ' bar', ' baz '],
|
||||
})
|
||||
end
|
||||
@@ -154,7 +154,7 @@ describe Squib::Deck do
|
||||
'ha'
|
||||
end
|
||||
end
|
||||
expect(data).to eq({
|
||||
expect(data.to_h).to eq({
|
||||
'Name' => %w(he he he),
|
||||
'General Number' => %w(ha ha ha),
|
||||
'Actual Number' => [8.0, 10.0, 12.0],
|
||||
@@ -162,7 +162,7 @@ describe Squib::Deck do
|
||||
end
|
||||
|
||||
it 'explodes quantities' do
|
||||
expect(Squib.xlsx(explode: 'Qty', file: xlsx_file('explode_quantities.xlsx'))).to eq({
|
||||
expect(Squib.xlsx(explode: 'Qty', file: xlsx_file('explode_quantities.xlsx')).to_h).to eq({
|
||||
'Name' => ['Zergling', 'Zergling', 'Zergling', 'High Templar'],
|
||||
'Qty' => %w(3 3 3 1),
|
||||
})
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
require 'spec_helper'
|
||||
require 'squib/import/data_frame'
|
||||
|
||||
describe Squib::DataFrame do
|
||||
let(:basic) do
|
||||
{
|
||||
'Name' => ['Mage', 'Rogue', 'Warrior'],
|
||||
'Cost' => [1, 2, 3],
|
||||
}
|
||||
end
|
||||
|
||||
let(:uneven) do
|
||||
{
|
||||
'Name' => ['Mage', 'Rogue', 'Warrior'],
|
||||
'Cost' => [1, 2],
|
||||
}
|
||||
end
|
||||
|
||||
let(:whitespace) do
|
||||
{
|
||||
'Name \n\r\t' => [' Mage \t\r\n'],
|
||||
}
|
||||
end
|
||||
|
||||
let(:defined) do
|
||||
{
|
||||
'nrows' => [1,2,3],
|
||||
}
|
||||
end
|
||||
|
||||
context 'is Enumerable and like a hash, so it' do
|
||||
it 'responds to each' do
|
||||
expect(subject).to respond_to(:each)
|
||||
end
|
||||
|
||||
it 'responds to any?' do
|
||||
expect(subject.any?).to be false
|
||||
end
|
||||
|
||||
it 'responds to []' do
|
||||
data = Squib::DataFrame.new basic
|
||||
expect(data['Cost']).to eq([1, 2, 3])
|
||||
end
|
||||
|
||||
it 'responds to []=' do
|
||||
data = Squib::DataFrame.new basic
|
||||
data[:a] = 2
|
||||
expect(data[:a]).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
context :columns do
|
||||
it 'provides a list of columns' do
|
||||
data = Squib::DataFrame.new basic
|
||||
expect(data.columns).to eq %w(Name Cost)
|
||||
end
|
||||
end
|
||||
|
||||
context :ncolumns do
|
||||
it 'provides column count' do
|
||||
data = Squib::DataFrame.new basic
|
||||
expect(data.ncolumns).to eq 2
|
||||
end
|
||||
end
|
||||
|
||||
context :row do
|
||||
it 'returns a hash of each row' do
|
||||
data = Squib::DataFrame.new basic
|
||||
expect(data.row(0)).to eq ({'Name' => 'Mage', 'Cost' => 1})
|
||||
expect(data.row(1)).to eq ({'Name' => 'Rogue', 'Cost' => 2})
|
||||
end
|
||||
|
||||
it 'returns nil for uneven data' do
|
||||
data = Squib::DataFrame.new uneven
|
||||
expect(data.row(2)).to eq ({'Name' => 'Warrior', 'Cost' => nil})
|
||||
end
|
||||
end
|
||||
|
||||
context :nrows do
|
||||
it 'returns a row count on even data' do
|
||||
data = Squib::DataFrame.new basic
|
||||
expect(data.nrows).to eq 3
|
||||
end
|
||||
|
||||
it 'returns largest row count on uneven data' do
|
||||
data = Squib::DataFrame.new basic
|
||||
expect(data.nrows).to eq 3
|
||||
end
|
||||
end
|
||||
|
||||
context :json do
|
||||
it 'returns quoty json' do
|
||||
data = Squib::DataFrame.new basic
|
||||
expect(data.to_json).to eq "{\"Name\":[\"Mage\",\"Rogue\",\"Warrior\"],\"Cost\":[1,2,3]}"
|
||||
end
|
||||
|
||||
it 'returns pretty json' do
|
||||
data = Squib::DataFrame.new basic
|
||||
str = <<-EOS
|
||||
{
|
||||
"Name": [
|
||||
"Mage",
|
||||
"Rogue",
|
||||
"Warrior"
|
||||
],
|
||||
"Cost": [
|
||||
1,
|
||||
2,
|
||||
3
|
||||
]
|
||||
}
|
||||
EOS
|
||||
expect(data.to_pretty_json).to eq str.chomp
|
||||
end
|
||||
end
|
||||
|
||||
context :def_column do
|
||||
it 'creates name for Name column' do
|
||||
data = Squib::DataFrame.new basic
|
||||
expect(data).to respond_to(:name)
|
||||
expect(data.name).to eq %w(Mage Rogue Warrior)
|
||||
expect(data.cost).to eq [1, 2, 3]
|
||||
end
|
||||
|
||||
it 'does not redefine methods' do
|
||||
data = Squib::DataFrame.new defined
|
||||
expect(data).to respond_to(:nrows)
|
||||
expect(data.nrows).to eq 3
|
||||
end
|
||||
|
||||
it 'defines a new column from empty data frame' do
|
||||
data = Squib::DataFrame.new
|
||||
expect(data).not_to respond_to(:snark)
|
||||
data['snark'] = [1,2,3]
|
||||
expect(data.snark).to eq [1,2,3]
|
||||
end
|
||||
end
|
||||
|
||||
context :snake_case do
|
||||
subject { Squib::DataFrame.new }
|
||||
it 'strips leading & trailing whitespace' do
|
||||
expect(subject.send(:snake_case, ' A ')).to eq :a
|
||||
end
|
||||
|
||||
it 'converts space to _' do
|
||||
expect(subject.send(:snake_case, 'A b')).to eq :a_b
|
||||
end
|
||||
|
||||
it 'handles multiwhitespace' do
|
||||
expect(subject.send(:snake_case, 'A b')).to eq :a_b
|
||||
end
|
||||
|
||||
it 'handles camelcase' do
|
||||
expect(subject.send(:snake_case, 'fooBar')).to eq :foo_bar
|
||||
end
|
||||
|
||||
it 'handles camelcase with multiple capitals' do
|
||||
expect(subject.send(:snake_case, 'FOOBar')).to eq :foo_bar
|
||||
end
|
||||
end
|
||||
|
||||
context :col? do
|
||||
it 'returns true if a column exists' do
|
||||
data = Squib::DataFrame.new basic
|
||||
expect(data.col? 'Name').to be true
|
||||
end
|
||||
|
||||
it 'returns false if a column does not exist' do
|
||||
data = Squib::DataFrame.new basic
|
||||
expect(data.col? 'ROUS').to be false
|
||||
end
|
||||
end
|
||||
|
||||
context :wrap_n_pad do
|
||||
subject { Squib::DataFrame.new basic }
|
||||
|
||||
it 'returns a handles a single line' do
|
||||
expect(subject.send(:wrap_n_pad, 'a', 3)).
|
||||
to eq "| a |\n"
|
||||
end
|
||||
|
||||
it 'wraps multiple a lines at 34 characters' do
|
||||
expect(subject.send(:wrap_n_pad, 'a' * 40, 3)).
|
||||
to eq <<-EOS
|
||||
| aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
|
||||
| aaaaaa |
|
||||
EOS
|
||||
end
|
||||
end
|
||||
|
||||
context :to_pretty_text do
|
||||
|
||||
let(:verbose) do
|
||||
{
|
||||
'Name' => ['Mage', 'Rogue', 'Warrior'],
|
||||
'Cost' => [1, 2, 3],
|
||||
'Description' => [
|
||||
'Magic, dude.',
|
||||
'I like to be sneaky',
|
||||
'I have a long story to tell to test the word-wrapping ability of pretty text formatting.'
|
||||
],
|
||||
'Snark' => [nil, '', ' ']
|
||||
}
|
||||
end
|
||||
|
||||
it 'returns fun ascii art of the card' do
|
||||
data = Squib::DataFrame.new verbose
|
||||
expect(data.to_pretty_text).to eq <<-EOS
|
||||
╭------------------------------------╮
|
||||
Name | Mage |
|
||||
Cost | 1 |
|
||||
Description | Magic, dude. |
|
||||
Snark | |
|
||||
╰------------------------------------╯
|
||||
╭------------------------------------╮
|
||||
Name | Rogue |
|
||||
Cost | 2 |
|
||||
Description | I like to be sneaky |
|
||||
Snark | |
|
||||
╰------------------------------------╯
|
||||
╭------------------------------------╮
|
||||
Name | Warrior |
|
||||
Cost | 3 |
|
||||
Description | I have a long story to tell to tes |
|
||||
| t the word-wrapping ability of pre |
|
||||
| tty text formatting. |
|
||||
Snark | |
|
||||
╰------------------------------------╯
|
||||
EOS
|
||||
end
|
||||
|
||||
let(:utf8_fun) do
|
||||
{
|
||||
'Fun with UTF8!' => ['👊'],
|
||||
}
|
||||
end
|
||||
|
||||
it 'is admittedly janky with multibyte chars' do
|
||||
# I hate how Ruby handles multibyte chars. Blech!
|
||||
data = Squib::DataFrame.new utf8_fun
|
||||
expect(data.to_pretty_text).to eq <<-EOS
|
||||
╭------------------------------------╮
|
||||
Fun with UTF8! | 👊 |
|
||||
╰------------------------------------╯
|
||||
EOS
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
Reference in New Issue
Block a user