table_transform 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2d6d8a8e87390799ac51635a6889032993ab424f
4
- data.tar.gz: 118f7f5592a983ee5ff77cad1e7960d73e032de8
3
+ metadata.gz: 91c96009ab39b8d65825644044ebd64e75b85994
4
+ data.tar.gz: 7f6c16447953380214f627ce735bbe90bedcd1dd
5
5
  SHA512:
6
- metadata.gz: 320bd9c7eccdcf26649d717c3f254e7fcaa39f6cd88f256e6b91355c0d5f631a85ad5fe4a107af90f40bc3a6c755e670ee3dceb53d83c98e0fb8ae4f0d4fb899
7
- data.tar.gz: 574420f128ca4cfc4b54db2a6a7058f562c5201294db8954c0965fde1850d05021198761376c7d7e07eb5c36633a39ca885b01e09a8c6bafd50936351dc3648b
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
- - 2.2.2
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.2.0][] (2016-02-16)
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.2.0...HEAD
23
- [0.2.0]: https://github.com/jonas-lantto/table_transform/compare/v0.1.0...0.2.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
- create_table(name, table.to_a)
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 create_table(name, data)
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 => header.map { |v| {:header => v} }
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
- @header = @data_rows.shift
30
- @column_indexes = create_column_name_binding(@header)
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 @header != t2_header
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 @header
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
- selected_cols = header.inject([]) { |res, c| res << Util::get_col_index(c, @column_indexes) }
65
- Table.new( @data_rows.inject([header]) {|res, row| (res << row.values_at(*selected_cols))} )
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 @header.clone )
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 @header.include?(name)
77
- @header << name
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
- delete_indexes = names.inject([]){|res, n| res << Util::get_col_index(n, @column_indexes)}
95
- delete_indexes.sort!.reverse!
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 = @header.inject([]) { |res, c| res << Util::get_col_index(c, @column_indexes) }
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(@header)
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
- @header.inject([]) { |row, col| row << hash_values.fetch(col){raise "Value for column '#{col}' could not be found"} }
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
@@ -1,3 +1,3 @@
1
1
  module TableTransform
2
- VERSION = '0.2.0'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -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{Utility to work with csv type data in a name safe environment with utilities to transform data}
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.add_development_dependency 'bundler', '~> 1.10'
23
- spec.add_development_dependency 'rake', '~> 10.0'
24
- spec.add_development_dependency 'minitest', '~> 5.0'
25
- spec.add_development_dependency 'write_xlsx', '~> 0.83'
26
- spec.add_development_dependency 'roo', '~> 2.3'
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.2.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-15 00:00:00.000000000 Z
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
- description: ''
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: '0'
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: Utility to work with csv type data in a name safe environment with utilities
130
- to transform data
130
+ summary: Transforms csv like data to Excel
131
131
  test_files: []