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 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: []