table_transform 0.5.0 → 0.6.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 +8 -2
- data/README.md +27 -8
- data/lib/table_transform/excel_creator.rb +23 -15
- data/lib/table_transform/properties.rb +6 -9
- data/lib/table_transform/table.rb +67 -38
- data/lib/table_transform/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 49ec7d69f22f2697f744cbfde782c2d5bdf176ec
|
4
|
+
data.tar.gz: 9528fc0373c003fb1be323e00cea5718328e4a9e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d4001db9c5ccb63aedf406320d0e5accec5b8f788a247dc75f6981a1dbbdf205d29d56667bee5d0575302635177cba0b47beb863f6c44f57977fb9dd9762a2fc
|
7
|
+
data.tar.gz: 0e1697d357bcb66f417102b049d02bdd0d6ceb68d8fe1d4f60112d0a5c01746f9bba1a8c9edcd8dd1d71ef690fbd34cf206850020fabb5d0cd242dcae1834e55
|
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.6.0][] (2016-03-20)
|
10
|
+
* Added rename table column
|
11
|
+
* Harmonization of how to work with properties, Table and Column
|
12
|
+
* Deprecated old metadata functions (to be removed)
|
13
|
+
|
9
14
|
## [0.5.0][] (2016-03-13)
|
10
15
|
* Table properties added
|
11
16
|
|
@@ -28,8 +33,9 @@ TableTransform is still in pre-release state. This means that its APIs and behav
|
|
28
33
|
* Initial release including Table
|
29
34
|
|
30
35
|
[Semver]: http://semver.org
|
31
|
-
[Unreleased]: https://github.com/jonas-lantto/table_transform/compare/v0.
|
32
|
-
[0.
|
36
|
+
[Unreleased]: https://github.com/jonas-lantto/table_transform/compare/v0.6.0...HEAD
|
37
|
+
[0.6.0]: https://github.com/jonas-lantto/table_transform/compare/v0.5.0...v0.6.0
|
38
|
+
[0.5.0]: https://github.com/jonas-lantto/table_transform/compare/v0.4.0...v0.5.0
|
33
39
|
[0.4.0]: https://github.com/jonas-lantto/table_transform/compare/v0.3.0...v0.4.0
|
34
40
|
[0.3.0]: https://github.com/jonas-lantto/table_transform/compare/v0.2.0...v0.3.0
|
35
41
|
[0.2.0]: https://github.com/jonas-lantto/table_transform/compare/v0.1.0...v0.2.0
|
data/README.md
CHANGED
@@ -46,6 +46,9 @@ Or install it yourself as:
|
|
46
46
|
# Will remove given columns. One or several can be specified.
|
47
47
|
t.delete_column('Name', 'Address')
|
48
48
|
|
49
|
+
# Rename column
|
50
|
+
r.rename_column('Age', 'Years')
|
51
|
+
|
49
52
|
# Create a new Table with given column in specified order
|
50
53
|
t.extract(%w(Length Name))
|
51
54
|
|
@@ -73,22 +76,38 @@ A row can access its values by column name e.g. `row['Name']`
|
|
73
76
|
c = row['Col1'] # c = 'CHECK'
|
74
77
|
c.include_any?(%w(AA EC DD))) # true
|
75
78
|
|
76
|
-
###
|
79
|
+
### Properties
|
80
|
+
There are two categories of properties, Table and Column<br/>
|
81
|
+
Same interface for interacting with properties
|
82
|
+
|
83
|
+
# Update - add or update :name property in existing p
|
84
|
+
p.update({name: 'xxx'})
|
85
|
+
|
86
|
+
# Reset - resets p with given property, clearing previous properties
|
87
|
+
p.reset({name: 'xxx'})
|
88
|
+
|
89
|
+
# Delete
|
90
|
+
p.delete(:name)
|
91
|
+
|
92
|
+
# Each
|
93
|
+
p.each{|x| ...}
|
94
|
+
|
95
|
+
# Access
|
96
|
+
p[:name]
|
97
|
+
|
98
|
+
#### Table properties
|
77
99
|
# Set table name - override default name
|
78
100
|
t.table_properties.update({name: 'Table1'})
|
79
101
|
|
80
102
|
# Set turn on/off auto filter button
|
81
103
|
t.table_properties.update({auto_filter: false})
|
82
104
|
|
83
|
-
|
105
|
+
#### Column properties
|
84
106
|
# Set format for one column
|
85
|
-
t.
|
107
|
+
t.column_properties['Tax'].update({format: '0.0%'})
|
86
108
|
|
87
|
-
# Extract
|
88
|
-
t.
|
89
|
-
|
90
|
-
# Set format for multiple columns
|
91
|
-
t.set_metadata(*%w(Income Tax Dept), {format: '#,##0'})
|
109
|
+
# Extract properties
|
110
|
+
t.column_properties['Tax'] # {format: '0.0%'}
|
92
111
|
|
93
112
|
# Add meta data during add_column
|
94
113
|
t.add_column('Tax', {format: '0.0%'}){|row| 0.25}
|
@@ -16,7 +16,7 @@ module TableTransform
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def add_tab(name, table)
|
19
|
-
set_formats(table.
|
19
|
+
set_formats(table.column_properties) if table.is_a?(TableTransform::Table)
|
20
20
|
create_table(name, table)
|
21
21
|
end
|
22
22
|
|
@@ -46,7 +46,7 @@ module TableTransform
|
|
46
46
|
|
47
47
|
auto_filter_size_correction = auto_filter_correct ? 3 : 0
|
48
48
|
res = Array.new(data.first.map { |name|
|
49
|
-
[name.to_s.size + auto_filter_size_correction, format_column_size(table.
|
49
|
+
[name.to_s.size + auto_filter_size_correction, format_column_size(table.column_properties[name][:format])].max
|
50
50
|
})
|
51
51
|
data.each { |row|
|
52
52
|
row.each_with_index { |cell, column_no|
|
@@ -56,21 +56,29 @@ module TableTransform
|
|
56
56
|
res.map! { |x| [x, max_width].min }
|
57
57
|
end
|
58
58
|
|
59
|
-
def set_formats(
|
60
|
-
|
59
|
+
def set_formats(column_properties)
|
60
|
+
# find all :formats across all columns
|
61
|
+
column_properties.each{|_,v|
|
61
62
|
f = v[:format]
|
62
63
|
@formats[f] ||= @workbook.add_format(:num_format => f) unless f.nil?
|
63
64
|
}
|
64
65
|
end
|
65
66
|
|
66
|
-
def create_column_metadata(
|
67
|
+
def create_column_metadata(column_properties, formats, formulas)
|
67
68
|
res = []
|
68
|
-
|
69
|
-
|
70
|
-
|
69
|
+
column_properties.each{ |header_name, data|
|
70
|
+
col_props = TableTransform::Properties.new data.to_h
|
71
|
+
|
72
|
+
#format (replace str format with excel representation)
|
73
|
+
col_props.update({format: formats[col_props[:format]]}) unless col_props[:format].nil?
|
74
|
+
|
75
|
+
#formula
|
71
76
|
formula = formulas[header_name]
|
72
|
-
|
73
|
-
|
77
|
+
col_props.update({formula: formula}) unless formula.nil?
|
78
|
+
|
79
|
+
#header
|
80
|
+
col_props.update({header: header_name})
|
81
|
+
res << col_props.to_h
|
74
82
|
}
|
75
83
|
res
|
76
84
|
end
|
@@ -80,8 +88,8 @@ module TableTransform
|
|
80
88
|
data = table.to_a
|
81
89
|
return if data.nil? or data.empty? # Create empty worksheet if no data
|
82
90
|
|
83
|
-
|
84
|
-
col_width = ExcelCreator::column_width(table,
|
91
|
+
table_properties = ExcelCreator::default_properties(name).update(table.table_properties.to_h)
|
92
|
+
col_width = ExcelCreator::column_width(table, table_properties[:auto_filter])
|
85
93
|
|
86
94
|
header = data.shift
|
87
95
|
data << [nil] * header.count if data.empty? # Add extra row if empty
|
@@ -89,10 +97,10 @@ module TableTransform
|
|
89
97
|
worksheet.add_table(
|
90
98
|
0, 0, data.count, header.count - 1,
|
91
99
|
{
|
92
|
-
:name =>
|
100
|
+
:name => table_properties[:name],
|
93
101
|
:data => data,
|
94
|
-
:autofilter =>
|
95
|
-
:columns => create_column_metadata(table.
|
102
|
+
:autofilter => table_properties[:auto_filter] ? 1 : 0,
|
103
|
+
:columns => create_column_metadata(table.column_properties, @formats, table.formulas)
|
96
104
|
}
|
97
105
|
)
|
98
106
|
|
@@ -1,10 +1,14 @@
|
|
1
|
+
require 'forwardable'
|
1
2
|
|
2
3
|
module TableTransform
|
3
4
|
|
4
5
|
class Properties
|
6
|
+
extend Forwardable
|
7
|
+
def_delegators :@props, :delete, :each, :[]
|
8
|
+
|
5
9
|
def initialize(init_properties = {})
|
6
10
|
validate(init_properties)
|
7
|
-
@props = init_properties
|
11
|
+
@props = init_properties.clone
|
8
12
|
end
|
9
13
|
|
10
14
|
def validate(properties)
|
@@ -20,18 +24,11 @@ module TableTransform
|
|
20
24
|
@props.merge! properties
|
21
25
|
end
|
22
26
|
|
23
|
-
def delete(prop_key)
|
24
|
-
@props.delete(prop_key)
|
25
|
-
end
|
26
|
-
|
27
27
|
def reset(properties)
|
28
28
|
validate(properties)
|
29
29
|
@props = properties
|
30
30
|
end
|
31
31
|
|
32
|
-
def [](prop_key)
|
33
|
-
raise "Property '#{prop_key}' does not exist" unless @props.include? prop_key
|
34
|
-
@props[prop_key]
|
35
|
-
end
|
36
32
|
end
|
33
|
+
|
37
34
|
end
|
@@ -11,6 +11,7 @@ module TableTransform
|
|
11
11
|
class Table
|
12
12
|
attr_reader :formulas
|
13
13
|
attr_reader :table_properties
|
14
|
+
attr_reader :column_properties
|
14
15
|
|
15
16
|
def self.create_from_file(file_name, sep = ',')
|
16
17
|
rows = CSV.read(file_name, { :col_sep => sep })
|
@@ -33,9 +34,10 @@ module TableTransform
|
|
33
34
|
@data_rows = rows.clone
|
34
35
|
header = @data_rows.shift
|
35
36
|
@column_indexes = create_column_name_binding(header)
|
36
|
-
@metadata = header.zip( Array.new(header.size){{}} ).to_h
|
37
37
|
@formulas = {}
|
38
38
|
@table_properties = TableProperties.new(table_properties)
|
39
|
+
@column_properties = Hash.new{|hash, key| raise "No column with name '#{key}' exists"}
|
40
|
+
create_column_properties(*header,{})
|
39
41
|
|
40
42
|
validate_header_uniqueness(header)
|
41
43
|
validate_column_size
|
@@ -45,19 +47,22 @@ module TableTransform
|
|
45
47
|
# Example:
|
46
48
|
# set_metadata('Col1', {format: '#,##0'})
|
47
49
|
def set_metadata(*columns, metadata)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
columns.each{|col| @metadata[col] = metadata.clone}
|
50
|
+
warn 'set_metadata is deprecated. Use column_properties[] instead'
|
51
|
+
columns.each{|c| @column_properties[c].reset(metadata)}
|
52
52
|
end
|
53
53
|
|
54
54
|
# Returns meta data as Hash with header name as key
|
55
55
|
def metadata
|
56
|
-
|
56
|
+
warn 'metadata is deprecated. Use column_properties[] instead'
|
57
|
+
res = Hash.new
|
58
|
+
@column_properties.each{|k, v|
|
59
|
+
res.merge! ({k => v.to_h})
|
60
|
+
}
|
61
|
+
res
|
57
62
|
end
|
58
63
|
|
59
|
-
def add_column_formula(column, formula,
|
60
|
-
add_column(column,
|
64
|
+
def add_column_formula(column, formula, column_properties = {})
|
65
|
+
add_column(column, column_properties){nil}
|
61
66
|
@formulas[column] = formula
|
62
67
|
self # self chaining
|
63
68
|
end
|
@@ -68,12 +73,12 @@ module TableTransform
|
|
68
73
|
end
|
69
74
|
|
70
75
|
# Add two tables
|
71
|
-
# @throws if header or
|
76
|
+
# @throws if header or properties do not match
|
72
77
|
def +(table)
|
73
78
|
t2 = table.to_a
|
74
79
|
t2_header = t2.shift
|
75
|
-
raise 'Tables cannot be added due to header mismatch' unless @
|
76
|
-
raise 'Tables cannot be added due to
|
80
|
+
raise 'Tables cannot be added due to header mismatch' unless @column_properties.keys == t2_header
|
81
|
+
raise 'Tables cannot be added due to column properties mismatch' unless column_properties_eql? table.column_properties
|
77
82
|
raise 'Tables cannot be added due to table properties mismatch' unless @table_properties.to_h == table.table_properties.to_h
|
78
83
|
TableTransform::Table.new(self.to_a + t2)
|
79
84
|
end
|
@@ -87,34 +92,33 @@ module TableTransform
|
|
87
92
|
# @returns array of data arrays including header row
|
88
93
|
def to_a
|
89
94
|
res = @data_rows.clone
|
90
|
-
res.unshift @
|
95
|
+
res.unshift @column_properties.keys.clone
|
91
96
|
end
|
92
97
|
|
93
98
|
# @returns new table with specified columns specified in given header
|
94
99
|
def extract(header)
|
95
|
-
|
100
|
+
validate_column_exist(*header)
|
96
101
|
selected_cols = @column_indexes.values_at(*header)
|
97
102
|
t = Table.new( @data_rows.inject([header]) {|res, row| (res << row.values_at(*selected_cols))}, @table_properties.to_h )
|
98
|
-
|
103
|
+
header.each{|h| t.column_properties[h].reset(@column_properties[h].to_h)}
|
99
104
|
t.formulas = header.zip(@formulas.values_at(*header)).to_h
|
100
105
|
t
|
101
106
|
end
|
102
107
|
|
103
108
|
# @returns new table with rows that match given block
|
104
109
|
def filter
|
105
|
-
Table.new( (@data_rows.select {|row| yield Row.new(@column_indexes, row)}.unshift @
|
110
|
+
Table.new( (@data_rows.select {|row| yield Row.new(@column_indexes, row)}.unshift @column_properties.keys.clone), @table_properties.to_h )
|
106
111
|
end
|
107
112
|
|
108
113
|
#adds a column with given name to the far right of the table
|
109
114
|
#@throws if given column name already exists
|
110
|
-
def add_column(name,
|
111
|
-
|
112
|
-
|
115
|
+
def add_column(name, column_properties = {})
|
116
|
+
validate_column_absence(name)
|
117
|
+
create_column_properties(name, column_properties)
|
113
118
|
@data_rows.each{|x|
|
114
119
|
x << (yield Row.new(@column_indexes, x))
|
115
120
|
}
|
116
121
|
@column_indexes[name] = @column_indexes.size
|
117
|
-
set_metadata(name, metadata)
|
118
122
|
self # enable chaining
|
119
123
|
end
|
120
124
|
|
@@ -129,19 +133,28 @@ module TableTransform
|
|
129
133
|
end
|
130
134
|
|
131
135
|
def delete_column(*names)
|
132
|
-
|
136
|
+
validate_column_exist(*names)
|
133
137
|
names.each{|n|
|
134
|
-
@
|
138
|
+
@column_properties.delete(n)
|
135
139
|
@formulas.delete(n)
|
136
140
|
}
|
137
141
|
|
138
|
-
selected_cols = @column_indexes.values_at(*@
|
142
|
+
selected_cols = @column_indexes.values_at(*@column_properties.keys)
|
139
143
|
@data_rows.map!{|row| row.values_at(*selected_cols)}
|
140
144
|
|
141
|
-
@column_indexes = create_column_name_binding(@
|
145
|
+
@column_indexes = create_column_name_binding(@column_properties.keys)
|
142
146
|
self
|
143
147
|
end
|
144
148
|
|
149
|
+
def rename_column(from, to)
|
150
|
+
validate_column_exist(from)
|
151
|
+
validate_column_absence(to)
|
152
|
+
|
153
|
+
@column_properties = @column_properties.map{|k,v| [k == from ? to : k, v] }.to_h
|
154
|
+
@formulas = @formulas.map{|k,v| [k == from ? to : k, v] }.to_h
|
155
|
+
@column_indexes = create_column_name_binding(@column_properties.keys)
|
156
|
+
end
|
157
|
+
|
145
158
|
# Table row
|
146
159
|
# Columns within row can be referenced by name, e.g. row['name']
|
147
160
|
class Row
|
@@ -185,9 +198,23 @@ module TableTransform
|
|
185
198
|
end
|
186
199
|
end
|
187
200
|
|
201
|
+
# Column properties
|
202
|
+
class ColumnProperties < TableTransform::Properties
|
203
|
+
def validate(properties)
|
204
|
+
super
|
205
|
+
properties.each { |k, v|
|
206
|
+
case k
|
207
|
+
when :format
|
208
|
+
raise "Column property 'format' expected to be a non-empty string" unless v.is_a?(String) && !v.empty?
|
209
|
+
else
|
210
|
+
raise "Unknown column property '#{k}'"
|
211
|
+
end
|
212
|
+
}
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
188
216
|
|
189
217
|
protected
|
190
|
-
attr_writer :metadata
|
191
218
|
attr_writer :formulas
|
192
219
|
|
193
220
|
private
|
@@ -196,7 +223,16 @@ module TableTransform
|
|
196
223
|
end
|
197
224
|
|
198
225
|
def create_row(hash_values)
|
199
|
-
@
|
226
|
+
@column_properties.keys.inject([]) { |row, col| row << hash_values.fetch(col){raise "Value for column '#{col}' could not be found"} }
|
227
|
+
end
|
228
|
+
|
229
|
+
def create_column_properties(*header, properties)
|
230
|
+
header.each{|key| @column_properties.store(key, TableTransform::Table::ColumnProperties.new(properties))}
|
231
|
+
end
|
232
|
+
|
233
|
+
def column_properties_eql?(column_properties)
|
234
|
+
return false unless @column_properties.size == column_properties.size
|
235
|
+
@column_properties.each{|key, prop| return false unless prop.to_h == column_properties[key].to_h}
|
200
236
|
end
|
201
237
|
|
202
238
|
# @throws unless all header names are unique
|
@@ -207,24 +243,17 @@ module TableTransform
|
|
207
243
|
|
208
244
|
# @throws unless all rows have same number of elements
|
209
245
|
def validate_column_size
|
210
|
-
@data_rows.each_with_index {|x, index| raise "Column size mismatch. On row #{index+1}. Size #{x.size} expected to be #{@
|
246
|
+
@data_rows.each_with_index {|x, index| raise "Column size mismatch. On row #{index+1}. Size #{x.size} expected to be #{@column_properties.size}" if @column_properties.size != x.size}
|
211
247
|
end
|
212
248
|
|
213
|
-
def
|
214
|
-
diff = names - @
|
249
|
+
def validate_column_exist(*names)
|
250
|
+
diff = names - @column_properties.keys
|
215
251
|
raise raise "No column with name '#{diff.first}' exists" if diff.size > 0
|
216
252
|
end
|
217
253
|
|
218
|
-
def
|
219
|
-
raise '
|
220
|
-
metadata.each { |k, v|
|
221
|
-
case k
|
222
|
-
when :format
|
223
|
-
raise "Meta tag 'format' expected to be a non-empty string" unless v.is_a?(String) && !v.empty?
|
224
|
-
else
|
225
|
-
raise "Unknown meta data tag '#{k}'"
|
226
|
-
end
|
227
|
-
}
|
254
|
+
def validate_column_absence(name)
|
255
|
+
raise "Column '#{name}' already exists" if @column_properties.keys.include?(name)
|
228
256
|
end
|
257
|
+
|
229
258
|
end
|
230
259
|
end
|
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.6.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-03-
|
11
|
+
date: 2016-03-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|