table_transform 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +6 -1
- data/CHANGELOG.md +10 -8
- data/README.md +31 -1
- data/lib/table_transform/excel_creator.rb +24 -3
- data/lib/table_transform/table.rb +71 -29
- data/lib/table_transform/version.rb +1 -1
- data/table_transform.gemspec +9 -7
- metadata +20 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 91c96009ab39b8d65825644044ebd64e75b85994
|
4
|
+
data.tar.gz: 7f6c16447953380214f627ce735bbe90bedcd1dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3cf48bcd2ed716bc0c0c2c00d43f8d6d2bd6165f790c75bfb20e496a2aa7afe223012f1a91495d0d77c36973c42c9f6ccfcb5620efc5e7f79a72ae57a1427bf3
|
7
|
+
data.tar.gz: f3e61219d7987ef67a8070cd6e11228c0ab138a7475d2890e20a12e2c03737bf0fca5522b44804ab21f22505d0ad805b40f951d672cf2853217ced602481764c
|
data/.travis.yml
CHANGED
@@ -1,3 +1,8 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
|
3
|
+
- 2.1.2
|
4
|
+
- 2.2.2
|
5
|
+
addons:
|
6
|
+
code_climate:
|
7
|
+
repo_token:
|
8
|
+
secure: G4bpiNUwVTTksk5nncmXcjMWh84uB3YbZwZsCqBROpjHOwaWcHDDID7OPWbl8Yp3x23Q9tj5oEI1i8+zei+jsk1AM5nB30XgAbIVQtv0qcahnDLrMNpWs4ubvBEw3yjwKRslqCD7WDC/lk8eYYmjJ6GyaIDeW8rJbITIkHTk4tKCjXFQRinUClWFfgg+rJSTyUqNqo3+aPaxDUvSeermOKK3jTQp9y1IsRFEbwtLUqliZ3rCgvhj43H4pQ0gDqsmtDqnuHgKBikm9D7+Gf6SbFyAMfy+XpHWlEXLjwwUVlTcSASB6cQ/v0ilJlLSzgaGoTgb6nBbLA3q/cvWTS3O5QEYfWnhzIlmoDBZXVRHWTcR1WpIXF10J5KT/UH+nHCOFGIefriMPWr6LZou1LMZrjY5hJLCeXxgM5xBF3MTAgiQd9cLlzzirCGzN9GGBOZsdDENG74IZPGpmKUPBm7OXjsrLc7rRIoPg92bMuDlBejU0RUWMDTjmrLvgLJM6R6ZdWQ6Ahf9YkLM7apDtVj3DFjOBX2oQuynq9ZuZ9dfhu49MME/7qeIQZD6HQqZixq9Zn8n2tFFvAMrIbeZKc5lZz5TumHiukouh6Jmq9e4issca9J4hV/hFlQ30Ds2plabbgzliISQlQEGh0oUBog3sW1prNnxkcfN+gO7uCHTBaI=
|
data/CHANGELOG.md
CHANGED
@@ -6,18 +6,20 @@ TableTransform is still in pre-release state. This means that its APIs and behav
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
-
## [0.
|
9
|
+
## [0.3.0][] (2016-02-29)
|
10
|
+
* Added format capability for columns when published as Excel
|
11
|
+
* CodeClimate and test coverage added
|
12
|
+
* Ruby >= 2.1 verified with TravisCI
|
13
|
+
* Improved documentation
|
10
14
|
|
15
|
+
## [0.2.0][] (2016-02-16)
|
11
16
|
* Added ability to publish Tables in *Microsoft Excel* format
|
12
|
-
|
13
|
-
Fixes:
|
14
|
-
|
15
|
-
* Require at least non empty header row to be present in Table
|
17
|
+
* [FIX] Require at least non empty header row to be present in Table
|
16
18
|
|
17
19
|
## 0.1.0 (2016-02-10)
|
18
|
-
|
19
20
|
* Initial release including Table
|
20
21
|
|
21
22
|
[Semver]: http://semver.org
|
22
|
-
[Unreleased]: https://github.com/jonas-lantto/table_transform/compare/v0.
|
23
|
-
[0.
|
23
|
+
[Unreleased]: https://github.com/jonas-lantto/table_transform/compare/v0.3.0...HEAD
|
24
|
+
[0.3.0]: https://github.com/jonas-lantto/table_transform/compare/v0.2.0...v0.3.0
|
25
|
+
[0.2.0]: https://github.com/jonas-lantto/table_transform/compare/v0.1.0...v0.2.0
|
data/README.md
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
[![Gem Version](https://badge.fury.io/rb/table_transform.svg)](http://badge.fury.io/rb/table_transform)
|
3
3
|
[![Build Status](https://travis-ci.org/jonas-lantto/table_transform.svg)](https://travis-ci.org/jonas-lantto/table_transform)
|
4
4
|
[![Code Climate](https://codeclimate.com/github/jonas-lantto/table_transform/badges/gpa.svg)](https://codeclimate.com/github/jonas-lantto/table_transform)
|
5
|
+
[![Test Coverage](https://codeclimate.com/github/jonas-lantto/table_transform/badges/coverage.svg)](https://codeclimate.com/github/jonas-lantto/table_transform/coverage)
|
6
|
+
[![Issue Count](https://codeclimate.com/github/jonas-lantto/table_transform/badges/issue_count.svg)](https://codeclimate.com/github/jonas-lantto/table_transform)
|
5
7
|
|
6
8
|
Utility to work with csv type data in a name safe environment with utilities to transform data
|
7
9
|
|
@@ -54,8 +56,36 @@ Or install it yourself as:
|
|
54
56
|
t1 = TableTransform::Table::create_empty(%w(Col1 Col2))
|
55
57
|
t2 = TableTransform::Table::create_empty(%w(Col1 Col2))
|
56
58
|
t3 = t1 + t2
|
57
|
-
|
59
|
+
|
60
|
+
### Inspect and traverse
|
61
|
+
# Loop through all rows
|
62
|
+
t.each_row{|row| puts row['Rebate'].to_f * row['Price'].to_f}
|
63
|
+
|
64
|
+
#### Table::Row
|
65
|
+
`Table::each_row` return a `Table::Row`<br/>
|
66
|
+
A row can access its values by column name e.g. `row['Name']`
|
67
|
+
|
68
|
+
#### Table:Cell
|
69
|
+
# Table::Cell < String
|
70
|
+
row['operating_system'].downcase == 'centos'
|
71
|
+
|
72
|
+
# include_any?
|
73
|
+
c = row['Col1'] # c = 'CHECK'
|
74
|
+
c.include_any?(%w(AA EC DD))) # true
|
75
|
+
|
76
|
+
### Meta data
|
77
|
+
# Set format for one column
|
78
|
+
t.set_metadata('Tax', {format: '0.0%'})
|
58
79
|
|
80
|
+
# Extract metadata
|
81
|
+
t.metadata['Tax'] # {format: '0.0%'}
|
82
|
+
|
83
|
+
# Set format for multiple columns
|
84
|
+
t.set_metadata(*%w(Income Tax Dept), {format: '#,##0'})
|
85
|
+
|
86
|
+
# Add meta data during add_column
|
87
|
+
t.add_column('Tax', {format: '0.0%'}){|row| 0.25}
|
88
|
+
|
59
89
|
### Publish
|
60
90
|
# Export as array
|
61
91
|
t.to_a
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'write_xlsx'
|
2
|
+
require_relative 'table'
|
2
3
|
|
3
4
|
|
4
5
|
module TableTransform
|
@@ -7,6 +8,7 @@ module TableTransform
|
|
7
8
|
class ExcelCreator
|
8
9
|
def initialize(filename)
|
9
10
|
@workbook = WriteXLSX.new(filename)
|
11
|
+
@formats = {}
|
10
12
|
end
|
11
13
|
|
12
14
|
def create!
|
@@ -14,7 +16,8 @@ module TableTransform
|
|
14
16
|
end
|
15
17
|
|
16
18
|
def add_tab(name, table)
|
17
|
-
|
19
|
+
set_formats(table.metadata) if table.is_a?(TableTransform::Table)
|
20
|
+
create_table(name, table)
|
18
21
|
end
|
19
22
|
|
20
23
|
#################################
|
@@ -35,8 +38,26 @@ module TableTransform
|
|
35
38
|
res.map! { |x| [x, max_width].min }
|
36
39
|
end
|
37
40
|
|
38
|
-
def
|
41
|
+
def set_formats(metadata)
|
42
|
+
metadata.each{|_,v|
|
43
|
+
f = v[:format]
|
44
|
+
@formats[f] ||= @workbook.add_format(:num_format => f) unless f.nil?
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def create_column_metadata(metadata, formats)
|
49
|
+
res = []
|
50
|
+
metadata.each{ |header_name, data|
|
51
|
+
data_dup = data.dup
|
52
|
+
data_dup[:format] = formats[data_dup[:format]] unless data_dup[:format].nil? #replace str format with excel representation
|
53
|
+
res << {header: header_name}.merge(data_dup)
|
54
|
+
}
|
55
|
+
res
|
56
|
+
end
|
57
|
+
|
58
|
+
def create_table(name, table)
|
39
59
|
worksheet = @workbook.add_worksheet(name)
|
60
|
+
data = table.to_a
|
40
61
|
return if data.nil? or data.empty? # Create empty worksheet if no data
|
41
62
|
|
42
63
|
auto_filter = true
|
@@ -51,7 +72,7 @@ module TableTransform
|
|
51
72
|
:name => name.tr(' ', '_'),
|
52
73
|
:data => data,
|
53
74
|
:autofilter => auto_filter ? 1 : 0,
|
54
|
-
:columns =>
|
75
|
+
:columns => create_column_metadata(table.metadata, @formats)
|
55
76
|
}
|
56
77
|
)
|
57
78
|
|
@@ -25,25 +25,43 @@ module TableTransform
|
|
25
25
|
# @throws if column size for each row match
|
26
26
|
def initialize(rows)
|
27
27
|
raise 'Table required to have at least a header row' if (rows.nil? or rows.empty?)
|
28
|
+
|
28
29
|
@data_rows = rows.clone
|
29
|
-
|
30
|
-
@column_indexes = create_column_name_binding(
|
30
|
+
header = @data_rows.shift
|
31
|
+
@column_indexes = create_column_name_binding(header)
|
32
|
+
@metadata = header.zip( Array.new(header.size){{}} ).to_h
|
31
33
|
|
32
|
-
validate_header_uniqueness
|
34
|
+
validate_header_uniqueness(header)
|
33
35
|
validate_column_size
|
34
36
|
end
|
35
37
|
|
38
|
+
# Sets metadata for given columns
|
39
|
+
# Example:
|
40
|
+
# set_metadata('Col1', {format: '#,##0'})
|
41
|
+
def set_metadata(*columns, metadata)
|
42
|
+
validate_column_names(*columns)
|
43
|
+
validate_metadata_tags(metadata)
|
44
|
+
|
45
|
+
columns.each{|col| @metadata[col] = metadata.clone}
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns meta data as Hash with header name as key
|
49
|
+
def metadata
|
50
|
+
@metadata.clone
|
51
|
+
end
|
52
|
+
|
36
53
|
def << (hash_values)
|
37
54
|
@data_rows << create_row(hash_values)
|
38
55
|
self
|
39
56
|
end
|
40
57
|
|
41
58
|
# Add two tables
|
42
|
-
# @throws if header do not match
|
59
|
+
# @throws if header or meta data do not match
|
43
60
|
def +(table)
|
44
61
|
t2 = table.to_a
|
45
62
|
t2_header = t2.shift
|
46
|
-
raise 'Tables cannot be added due to header mismatch' if @
|
63
|
+
raise 'Tables cannot be added due to header mismatch' if @metadata.keys != t2_header
|
64
|
+
raise 'Tables cannot be added due to meta data mismatch' if @metadata != table.metadata
|
47
65
|
TableTransform::Table.new(self.to_a + t2)
|
48
66
|
end
|
49
67
|
|
@@ -56,29 +74,33 @@ module TableTransform
|
|
56
74
|
# @returns array of data arrays including header row
|
57
75
|
def to_a
|
58
76
|
res = @data_rows.clone
|
59
|
-
res.unshift @
|
77
|
+
res.unshift @metadata.keys.clone
|
60
78
|
end
|
61
79
|
|
62
80
|
# @returns new table with specified columns specified in given header
|
63
81
|
def extract(header)
|
64
|
-
|
65
|
-
|
82
|
+
validate_column_names(*header)
|
83
|
+
selected_cols = @column_indexes.values_at(*header)
|
84
|
+
t = Table.new( @data_rows.inject([header]) {|res, row| (res << row.values_at(*selected_cols))} )
|
85
|
+
t.metadata = t.metadata.keys.zip(@metadata.values_at(*header)).to_h
|
86
|
+
t
|
66
87
|
end
|
67
88
|
|
68
89
|
# @returns new table with rows that match given block
|
69
90
|
def filter
|
70
|
-
Table.new( @data_rows.select {|row| yield Row.new(@column_indexes, row)}.unshift @
|
91
|
+
Table.new( @data_rows.select {|row| yield Row.new(@column_indexes, row)}.unshift @metadata.keys.clone )
|
71
92
|
end
|
72
93
|
|
73
94
|
#adds a column with given name to the far right of the table
|
74
95
|
#@throws if given column name already exists
|
75
|
-
def add_column(name)
|
76
|
-
raise "Column '#{name}' already exists" if @
|
77
|
-
@
|
96
|
+
def add_column(name, metadata = {})
|
97
|
+
raise "Column '#{name}' already exists" if @metadata.keys.include?(name)
|
98
|
+
@metadata[name] = {}
|
78
99
|
@data_rows.each{|x|
|
79
100
|
x << (yield Row.new(@column_indexes, x))
|
80
101
|
}
|
81
102
|
@column_indexes[name] = @column_indexes.size
|
103
|
+
set_metadata(name, metadata)
|
82
104
|
self # enable chaining
|
83
105
|
end
|
84
106
|
|
@@ -87,32 +109,21 @@ module TableTransform
|
|
87
109
|
@data_rows.each{|r|
|
88
110
|
r[index] = yield Row.new(@column_indexes, r)
|
89
111
|
}
|
112
|
+
|
90
113
|
self # enable chaining
|
91
114
|
end
|
92
115
|
|
93
116
|
def delete_column(*names)
|
94
|
-
|
95
|
-
|
96
|
-
delete_indexes.each{|i| @header.delete_at(i)}
|
117
|
+
validate_column_names(*names)
|
118
|
+
names.each{|n| @metadata.delete(n)}
|
97
119
|
|
98
|
-
selected_cols = @
|
120
|
+
selected_cols = @column_indexes.values_at(*@metadata.keys)
|
99
121
|
@data_rows.map!{|row| row.values_at(*selected_cols)}
|
100
122
|
|
101
|
-
@column_indexes = create_column_name_binding(@
|
123
|
+
@column_indexes = create_column_name_binding(@metadata.keys)
|
102
124
|
self
|
103
125
|
end
|
104
126
|
|
105
|
-
# @throws unless all header names are unique
|
106
|
-
private def validate_header_uniqueness
|
107
|
-
dup = @header.select{ |e| @header.count(e) > 1 }.uniq
|
108
|
-
raise "Column #{dup.map{|x| "'#{x}'"}.join(' and ')} not unique" if dup.size > 0
|
109
|
-
end
|
110
|
-
|
111
|
-
# @throws unless all rows have same number of elements
|
112
|
-
private def validate_column_size
|
113
|
-
@data_rows.each_with_index {|x, index| raise "Column size mismatch. On row #{index+1}. Size #{x.size} expected to be #{@header.size}" if @header.size != x.size}
|
114
|
-
end
|
115
|
-
|
116
127
|
class Row
|
117
128
|
|
118
129
|
def initialize(cols, row)
|
@@ -136,13 +147,44 @@ module TableTransform
|
|
136
147
|
end
|
137
148
|
end
|
138
149
|
|
150
|
+
protected
|
151
|
+
attr_writer :metadata
|
152
|
+
|
139
153
|
private
|
140
154
|
def create_column_name_binding(header_row)
|
141
155
|
header_row.map.with_index{ |x, i| [x, i] }.to_h
|
142
156
|
end
|
143
157
|
|
144
158
|
def create_row(hash_values)
|
145
|
-
@
|
159
|
+
@metadata.keys.inject([]) { |row, col| row << hash_values.fetch(col){raise "Value for column '#{col}' could not be found"} }
|
160
|
+
end
|
161
|
+
|
162
|
+
# @throws unless all header names are unique
|
163
|
+
def validate_header_uniqueness(header)
|
164
|
+
dup = header.select{ |e| header.count(e) > 1 }.uniq
|
165
|
+
raise "Column(s) not unique: #{dup.map{|x| "'#{x}'"}.join(', ')}" if dup.size > 0
|
166
|
+
end
|
167
|
+
|
168
|
+
# @throws unless all rows have same number of elements
|
169
|
+
def validate_column_size
|
170
|
+
@data_rows.each_with_index {|x, index| raise "Column size mismatch. On row #{index+1}. Size #{x.size} expected to be #{@metadata.size}" if @metadata.size != x.size}
|
171
|
+
end
|
172
|
+
|
173
|
+
def validate_column_names(*names)
|
174
|
+
diff = names - @metadata.keys
|
175
|
+
raise raise "No column with name '#{diff.first}' exists" if diff.size > 0
|
176
|
+
end
|
177
|
+
|
178
|
+
def validate_metadata_tags(metadata)
|
179
|
+
raise 'Metadata must be a hash' unless metadata.is_a?(Hash)
|
180
|
+
metadata.each { |k, v|
|
181
|
+
case k
|
182
|
+
when :format
|
183
|
+
raise "Meta tag 'format' expected to be a non-empty string" unless v.is_a?(String) && !v.empty?
|
184
|
+
else
|
185
|
+
raise "Unknown meta data tag '#{k}'"
|
186
|
+
end
|
187
|
+
}
|
146
188
|
end
|
147
189
|
end
|
148
190
|
end
|
data/table_transform.gemspec
CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ['Jonas Lantto']
|
10
10
|
spec.email = ['j@lantto.net']
|
11
11
|
|
12
|
-
spec.summary = %q{
|
13
|
-
spec.description = %q{}
|
12
|
+
spec.summary = %q{Transforms csv like data to Excel}
|
13
|
+
spec.description = %q{Utility to work with csv type data in a name safe environment with utilities to transform data}
|
14
14
|
spec.homepage = 'https://github.com/jonas-lantto/table_transform'
|
15
15
|
spec.license = 'MIT'
|
16
16
|
|
@@ -19,9 +19,11 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ['lib']
|
21
21
|
|
22
|
-
spec.
|
23
|
-
|
24
|
-
spec.add_development_dependency '
|
25
|
-
spec.add_development_dependency '
|
26
|
-
spec.add_development_dependency '
|
22
|
+
spec.required_ruby_version = '>= 2.1'
|
23
|
+
|
24
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
25
|
+
spec.add_development_dependency 'minitest', '~> 5.0'
|
26
|
+
spec.add_development_dependency 'write_xlsx', '~> 0.83'
|
27
|
+
spec.add_development_dependency 'roo', '~> 2.3'
|
28
|
+
spec.add_development_dependency 'codeclimate-test-reporter','~> 0.5.0'
|
27
29
|
end
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: table_transform
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.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-02-
|
11
|
+
date: 2016-02-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: bundler
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '1.10'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '1.10'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: rake
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,7 +66,22 @@ dependencies:
|
|
80
66
|
- - "~>"
|
81
67
|
- !ruby/object:Gem::Version
|
82
68
|
version: '2.3'
|
83
|
-
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: codeclimate-test-reporter
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.5.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.5.0
|
83
|
+
description: Utility to work with csv type data in a name safe environment with utilities
|
84
|
+
to transform data
|
84
85
|
email:
|
85
86
|
- j@lantto.net
|
86
87
|
executables: []
|
@@ -115,7 +116,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
115
116
|
requirements:
|
116
117
|
- - ">="
|
117
118
|
- !ruby/object:Gem::Version
|
118
|
-
version: '
|
119
|
+
version: '2.1'
|
119
120
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
121
|
requirements:
|
121
122
|
- - ">="
|
@@ -126,6 +127,5 @@ rubyforge_project:
|
|
126
127
|
rubygems_version: 2.4.8
|
127
128
|
signing_key:
|
128
129
|
specification_version: 4
|
129
|
-
summary:
|
130
|
-
to transform data
|
130
|
+
summary: Transforms csv like data to Excel
|
131
131
|
test_files: []
|