table_transform 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +35 -0
- data/lib/table_transform/excel_creator.rb +18 -7
- data/lib/table_transform/formula_helper.rb +36 -0
- data/lib/table_transform/table.rb +19 -1
- data/lib/table_transform/version.rb +1 -1
- data/lib/table_transform.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9eeed52b5a7aa9db9eea7f0e0f27a40ff2b932be
|
4
|
+
data.tar.gz: bad8620c79b09929f105d54894b4df931a8b778b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7837639dace38af311b85547f997b138812c3bba8d969a356936896f0b1a0be9e12ec22e7b86fbaa705f93a6efd55122d6a739339ad732a619965dfb6d058eaf
|
7
|
+
data.tar.gz: aa40106dd2c8e0c18129a60e50965a1e4e09eaf3d8305bb367aeab79166d6dc540636e9d0b771e9a4fb6f4e4c1c812593338a4309a2f10251a03f7f9d5b794a2
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,11 @@ TableTransform is still in pre-release state. This means that its APIs and behav
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
## [0.4.0][] (2016-03-05)
|
10
|
+
* Supports formulas in columns
|
11
|
+
* Helper functions to create formulas
|
12
|
+
* Column width estimates format size in calculation
|
13
|
+
|
9
14
|
## [0.3.0][] (2016-02-29)
|
10
15
|
* Added format capability for columns when published as Excel
|
11
16
|
* CodeClimate and test coverage added
|
@@ -21,5 +26,6 @@ TableTransform is still in pre-release state. This means that its APIs and behav
|
|
21
26
|
|
22
27
|
[Semver]: http://semver.org
|
23
28
|
[Unreleased]: https://github.com/jonas-lantto/table_transform/compare/v0.3.0...HEAD
|
29
|
+
[0.4.0]: https://github.com/jonas-lantto/table_transform/compare/v0.3.0...v0.4.0
|
24
30
|
[0.3.0]: https://github.com/jonas-lantto/table_transform/compare/v0.2.0...v0.3.0
|
25
31
|
[0.2.0]: https://github.com/jonas-lantto/table_transform/compare/v0.1.0...v0.2.0
|
data/README.md
CHANGED
@@ -86,6 +86,41 @@ A row can access its values by column name e.g. `row['Name']`
|
|
86
86
|
# Add meta data during add_column
|
87
87
|
t.add_column('Tax', {format: '0.0%'}){|row| 0.25}
|
88
88
|
|
89
|
+
### Formula
|
90
|
+
Formulas can be added to columns. They have to be in US locale.
|
91
|
+
Column values will be nil if inspected
|
92
|
+
|
93
|
+
# Add formula to column
|
94
|
+
t.add_column_formula('OnePlusOne', '1+1')
|
95
|
+
|
96
|
+
# Add formula to column with meta data
|
97
|
+
t.add_column_formula('OnePlusOne', '1+1' {format: '0.0'})
|
98
|
+
|
99
|
+
#### Formula helper
|
100
|
+
To aid when creating formulas there are a few helpers available
|
101
|
+
|
102
|
+
f = TableTransform::FormulaHelper # Namespace alias
|
103
|
+
|
104
|
+
# Column
|
105
|
+
f::column('price') # <=> [price]
|
106
|
+
t.add_column_formula('Total value', "#{f::column('price')}*f::column('volume')}")
|
107
|
+
|
108
|
+
# Table
|
109
|
+
f::table('Table1') # <=> Table1[]
|
110
|
+
|
111
|
+
# Text (will avoid the clutter of protecting " character)
|
112
|
+
f::text('No') # <=> "No"
|
113
|
+
|
114
|
+
# VLOOKUP, convenience function to extract values from another table
|
115
|
+
# Finds the street name in table Address for name specified in column Name
|
116
|
+
f::vlookup(f::column('Name'), 'Address', 'Street'))
|
117
|
+
f::vlookup('[Name]', 'Address', 'Street'))
|
118
|
+
|
119
|
+
# Finds the number of pets in Table Pets for name specified in column Name. If name does not exist it defaults to 0
|
120
|
+
f::vlookup(f::column('Name'), 'Pets', 'nPets', 0))
|
121
|
+
f::vlookup('[Name]', 'Pets', 'nPets', 0))
|
122
|
+
|
123
|
+
|
89
124
|
### Publish
|
90
125
|
# Export as array
|
91
126
|
t.to_a
|
@@ -23,13 +23,22 @@ module TableTransform
|
|
23
23
|
#################################
|
24
24
|
private
|
25
25
|
|
26
|
+
# estimated column width of format
|
27
|
+
def self.format_column_size(format)
|
28
|
+
return 0 if format.nil?
|
29
|
+
f = format.gsub(/\[.*?\]/, '').split(';')
|
30
|
+
f.map{|x| x.size}.max
|
31
|
+
end
|
32
|
+
|
26
33
|
# @return array with column width per column
|
27
|
-
def self.column_width(
|
28
|
-
return []
|
34
|
+
def self.column_width(table, auto_filter_correct = true, max_width = 100)
|
35
|
+
return [] unless table.is_a? TableTransform::Table
|
36
|
+
data = table.to_a
|
29
37
|
|
30
38
|
auto_filter_size_correction = auto_filter_correct ? 3 : 0
|
31
|
-
|
32
|
-
|
39
|
+
res = Array.new(data.first.map { |name|
|
40
|
+
[name.to_s.size + auto_filter_size_correction, format_column_size(table.metadata[name][:format])].max
|
41
|
+
})
|
33
42
|
data.each { |row|
|
34
43
|
row.each_with_index { |cell, column_no|
|
35
44
|
res[column_no] = [cell.to_s.size, res[column_no]].max
|
@@ -45,11 +54,13 @@ module TableTransform
|
|
45
54
|
}
|
46
55
|
end
|
47
56
|
|
48
|
-
def create_column_metadata(metadata, formats)
|
57
|
+
def create_column_metadata(metadata, formats, formulas)
|
49
58
|
res = []
|
50
59
|
metadata.each{ |header_name, data|
|
51
60
|
data_dup = data.dup
|
52
61
|
data_dup[:format] = formats[data_dup[:format]] unless data_dup[:format].nil? #replace str format with excel representation
|
62
|
+
formula = formulas[header_name]
|
63
|
+
data_dup.merge!({formula: formula}) unless formula.nil?
|
53
64
|
res << {header: header_name}.merge(data_dup)
|
54
65
|
}
|
55
66
|
res
|
@@ -61,7 +72,7 @@ module TableTransform
|
|
61
72
|
return if data.nil? or data.empty? # Create empty worksheet if no data
|
62
73
|
|
63
74
|
auto_filter = true
|
64
|
-
col_width = ExcelCreator::column_width(
|
75
|
+
col_width = ExcelCreator::column_width(table, auto_filter)
|
65
76
|
|
66
77
|
header = data.shift
|
67
78
|
data << [nil] * header.count if data.empty? # Add extra row if empty
|
@@ -72,7 +83,7 @@ module TableTransform
|
|
72
83
|
:name => name.tr(' ', '_'),
|
73
84
|
:data => data,
|
74
85
|
:autofilter => auto_filter ? 1 : 0,
|
75
|
-
:columns => create_column_metadata(table.metadata, @formats)
|
86
|
+
:columns => create_column_metadata(table.metadata, @formats, table.formulas)
|
76
87
|
}
|
77
88
|
)
|
78
89
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module TableTransform
|
2
|
+
|
3
|
+
# Help functions to create formulas
|
4
|
+
module FormulaHelper
|
5
|
+
# Reference a table
|
6
|
+
def self.table(name)
|
7
|
+
"#{name}[]"
|
8
|
+
end
|
9
|
+
|
10
|
+
# Reference a column in same table
|
11
|
+
def self.column(name)
|
12
|
+
"[#{name}]"
|
13
|
+
end
|
14
|
+
|
15
|
+
# Quotes text to be used inside formulas
|
16
|
+
def self.text(txt)
|
17
|
+
"\"#{txt}\""
|
18
|
+
end
|
19
|
+
|
20
|
+
# vlookup helper, search for a value in another table with return column specified by name
|
21
|
+
# Use other help functions to create an excel expression
|
22
|
+
#
|
23
|
+
# @param [excel expression] search_value, value to lookup
|
24
|
+
# @param [string] table_name, name of the table to search in
|
25
|
+
# @param [string] return_col_name, name of the return column in given table
|
26
|
+
# @param [excel expression] default, value if nothing was found, otherwise Excel will show N/A
|
27
|
+
def self.vlookup(search_value, table_name, return_col_name, default = nil)
|
28
|
+
vlookup = "VLOOKUP(#{search_value},#{table(table_name)},COLUMN(#{table_name}[[#Headers],#{column(return_col_name)}]),FALSE)"
|
29
|
+
|
30
|
+
# Workaround
|
31
|
+
# Should be possible to write "IFNA(#{vlookup},#{default})"
|
32
|
+
# but Excel will error with #Name? until formula is updated by hand
|
33
|
+
default.nil? ? vlookup : "IF(ISNA(#{vlookup}),#{default},#{vlookup})"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -8,6 +8,8 @@ module TableTransform
|
|
8
8
|
end
|
9
9
|
|
10
10
|
class Table
|
11
|
+
attr_reader :formulas
|
12
|
+
|
11
13
|
def self.create_from_file(file_name, sep = ',')
|
12
14
|
rows = CSV.read(file_name, { :col_sep => sep })
|
13
15
|
raise "'#{file_name}' contains no data" if rows.empty?
|
@@ -30,6 +32,7 @@ module TableTransform
|
|
30
32
|
header = @data_rows.shift
|
31
33
|
@column_indexes = create_column_name_binding(header)
|
32
34
|
@metadata = header.zip( Array.new(header.size){{}} ).to_h
|
35
|
+
@formulas = {}
|
33
36
|
|
34
37
|
validate_header_uniqueness(header)
|
35
38
|
validate_column_size
|
@@ -50,6 +53,12 @@ module TableTransform
|
|
50
53
|
@metadata.clone
|
51
54
|
end
|
52
55
|
|
56
|
+
def add_column_formula(column, formula, metadata = {})
|
57
|
+
add_column(column, metadata){nil}
|
58
|
+
@formulas[column] = formula
|
59
|
+
self # self chaining
|
60
|
+
end
|
61
|
+
|
53
62
|
def << (hash_values)
|
54
63
|
@data_rows << create_row(hash_values)
|
55
64
|
self
|
@@ -83,6 +92,7 @@ module TableTransform
|
|
83
92
|
selected_cols = @column_indexes.values_at(*header)
|
84
93
|
t = Table.new( @data_rows.inject([header]) {|res, row| (res << row.values_at(*selected_cols))} )
|
85
94
|
t.metadata = t.metadata.keys.zip(@metadata.values_at(*header)).to_h
|
95
|
+
t.formulas = header.zip(@formulas.values_at(*header)).to_h
|
86
96
|
t
|
87
97
|
end
|
88
98
|
|
@@ -105,6 +115,7 @@ module TableTransform
|
|
105
115
|
end
|
106
116
|
|
107
117
|
def change_column(name)
|
118
|
+
raise "Column with formula('#{name}') cannot be changed" if @formulas[name]
|
108
119
|
index = Util::get_col_index(name, @column_indexes)
|
109
120
|
@data_rows.each{|r|
|
110
121
|
r[index] = yield Row.new(@column_indexes, r)
|
@@ -115,7 +126,10 @@ module TableTransform
|
|
115
126
|
|
116
127
|
def delete_column(*names)
|
117
128
|
validate_column_names(*names)
|
118
|
-
names.each{|n|
|
129
|
+
names.each{|n|
|
130
|
+
@metadata.delete(n)
|
131
|
+
@formulas.delete(n)
|
132
|
+
}
|
119
133
|
|
120
134
|
selected_cols = @column_indexes.values_at(*@metadata.keys)
|
121
135
|
@data_rows.map!{|row| row.values_at(*selected_cols)}
|
@@ -124,6 +138,8 @@ module TableTransform
|
|
124
138
|
self
|
125
139
|
end
|
126
140
|
|
141
|
+
# Table row
|
142
|
+
# Columns within row can be referenced by name, e.g. row['name']
|
127
143
|
class Row
|
128
144
|
|
129
145
|
def initialize(cols, row)
|
@@ -140,6 +156,7 @@ module TableTransform
|
|
140
156
|
|
141
157
|
end
|
142
158
|
|
159
|
+
# Cell within Table::Row
|
143
160
|
class Cell < String
|
144
161
|
# @returns true if this cell includes any of the given values in list
|
145
162
|
def include_any?(list)
|
@@ -149,6 +166,7 @@ module TableTransform
|
|
149
166
|
|
150
167
|
protected
|
151
168
|
attr_writer :metadata
|
169
|
+
attr_writer :formulas
|
152
170
|
|
153
171
|
private
|
154
172
|
def create_column_name_binding(header_row)
|
data/lib/table_transform.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: table_transform
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonas Lantto
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-03-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -101,6 +101,7 @@ files:
|
|
101
101
|
- Rakefile
|
102
102
|
- lib/table_transform.rb
|
103
103
|
- lib/table_transform/excel_creator.rb
|
104
|
+
- lib/table_transform/formula_helper.rb
|
104
105
|
- lib/table_transform/table.rb
|
105
106
|
- lib/table_transform/version.rb
|
106
107
|
- table_transform.gemspec
|