-
Notifications
You must be signed in to change notification settings - Fork 68
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implemented a whole new class to represent the data that comes in from CSV and XLSX. See docs for more info. Closes #153
- Loading branch information
1 parent
935040b
commit f4d9424
Showing
9 changed files
with
484 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
Squib::DataFrame | ||
================ | ||
|
||
As described in :doc:`/data`, the ``Squib::DataFrame`` is what is returned by Squib's data import methods (:doc:`/dsl/csv` and :doc:`/dsl/xlsx`). | ||
|
||
It behaves like a ``Hash`` of ``Arrays``, so acessing an individual column can be done via the square brackets, e.g. ``data['title']``. | ||
|
||
Here are some other convenience methods in ``Squib::DataFrame`` | ||
|
||
columns become methods | ||
---------------------- | ||
|
||
Through magic of Ruby metaprogramming, every column also becomes a method on the data frame. So these two are equivalent: | ||
|
||
.. code-block:: irb | ||
irb(main):002:0> data = Squib.csv file: 'basic.csv' | ||
=> #<Squib::DataFrame:0x00000003764550 @hash={"h1"=>[1, 3], "h2"=>[2, 4]}> | ||
irb(main):003:0> data.h1 | ||
=> [1, 3] | ||
irb(main):004:0> data['h1'] | ||
=> [1, 3] | ||
#columns | ||
-------- | ||
|
||
Returns an array of the column names in the data frame | ||
|
||
#ncolumns | ||
--------- | ||
|
||
Returns the number of columns in the data frame | ||
|
||
#col?(name) | ||
----------- | ||
|
||
Returns ``true`` if there is column ``name``. | ||
|
||
#row(i) | ||
------- | ||
|
||
Returns a hash of values across all columns in the ``i``th row of the dataframe. Represents a single card. | ||
#nrows | ||
------ | ||
Returns the number of rows the data frame has, computed by the maximum length of any column array. | ||
#to_json | ||
-------- | ||
Returns a ``json`` representation of the entire data frame. | ||
|
||
#to_pretty_json | ||
--------------- | ||
|
||
Returns a ``json`` representation of the entire data frame, formatted with indentation for human viewing. | ||
|
||
#to_pretty_text | ||
--------------- | ||
|
||
Returns a textual representation of the dataframe that emulates what the information looks like on an individual card. Here's an example: | ||
|
||
.. code-block:: text | ||
╭------------------------------------╮ | ||
Name | Mage | | ||
Cost | 1 | | ||
Description | You may cast 1 spell per turn | | ||
Snark | Magic, dude. | | ||
╰------------------------------------╯ | ||
╭------------------------------------╮ | ||
Name | Rogue | | ||
Cost | 2 | | ||
Description | You always take the first turn. | | ||
Snark | I like to be sneaky | | ||
╰------------------------------------╯ | ||
╭------------------------------------╮ | ||
Name | Warrior | | ||
Cost | 3 | | ||
Description | | ||
Snark | I have a long story to tell to tes | | ||
| t the word-wrapping ability of pre | | ||
| tty text formatting. | | ||
╰------------------------------------╯ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
# encoding: UTF-8 | ||
|
||
require 'json' | ||
require 'forwardable' | ||
|
||
module Squib | ||
class DataFrame | ||
include Enumerable | ||
|
||
def initialize(hash = {}, def_columns = true) | ||
@hash = hash | ||
columns.each { |col| def_column(col) } if def_columns | ||
end | ||
|
||
def each(&block) | ||
@hash.each(&block) | ||
end | ||
|
||
def [](i) | ||
@hash[i] | ||
end | ||
|
||
def []=(col, v) | ||
@hash[col] = v | ||
def_column(col) | ||
return v | ||
end | ||
|
||
def columns | ||
@hash.keys | ||
end | ||
|
||
def ncolumns | ||
@hash.keys.size | ||
end | ||
|
||
def col?(col) | ||
@hash.key? col | ||
end | ||
|
||
def row(i) | ||
@hash.inject(Hash.new) { |ret, (name, arr)| ret[name] = arr[i]; ret } | ||
end | ||
|
||
def nrows | ||
@hash.inject(0) { |max, (_n, col)| col.size > max ? col.size : max } | ||
end | ||
|
||
def to_json | ||
@hash.to_json | ||
end | ||
|
||
def to_pretty_json | ||
JSON.pretty_generate(@hash) | ||
end | ||
|
||
def to_h | ||
@hash | ||
end | ||
|
||
def to_pretty_text | ||
max_col = columns.inject(0) { |max, c | c.length > max ? c.length : max } | ||
top = " ╭#{'-' * 36}╮\n" | ||
bottom = " ╰#{'-' * 36}╯\n" | ||
str = '' | ||
0.upto(nrows - 1) do | i | | ||
str += (' ' * max_col) + top | ||
row(i).each do |col, data| | ||
str += "#{col.rjust(max_col)} #{wrap_n_pad(data, max_col)}" | ||
end | ||
str += (' ' * max_col) + bottom | ||
end | ||
return str | ||
end | ||
|
||
private | ||
|
||
def snake_case(str) | ||
str.to_s. | ||
strip. | ||
gsub(/\s+/,'_'). | ||
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). | ||
gsub(/([a-z]+)([A-Z])/,'\1_\2'). | ||
downcase. | ||
to_sym | ||
end | ||
|
||
def wrap_n_pad(str, max_col) | ||
str.to_s. | ||
concat(' '). # handle nil & empty strings | ||
scan(/.{1,34}/). | ||
map { |s| (' ' * max_col) + " | " + s.ljust(34) }. | ||
join(" |\n"). | ||
lstrip. # initially no whitespace next to key | ||
concat(" |\n") | ||
end | ||
|
||
def def_column(col) | ||
raise "Column #{col} - does not exist" unless @hash.key? col | ||
method_name = snake_case(col) | ||
return if self.class.method_defined?(method_name) #warn people? or skip? | ||
define_singleton_method method_name do | ||
@hash[col] | ||
end | ||
end | ||
|
||
end | ||
end |
Oops, something went wrong.