table_transform 0.5.0 → 0.6.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: 18bd452f05254c417d3deb30c03d61c9595d3494
4
- data.tar.gz: d998ab542023204734aca739c5caf91538307e91
3
+ metadata.gz: 49ec7d69f22f2697f744cbfde782c2d5bdf176ec
4
+ data.tar.gz: 9528fc0373c003fb1be323e00cea5718328e4a9e
5
5
  SHA512:
6
- metadata.gz: fb3c761f20419bccf2a954c05ee50b0baf01886bc87df0808071cf44147e6c8050bee7b8d0613b058a7f152dbe8ce6e02b4cd74ac08164e0dff3590028060bad
7
- data.tar.gz: 55bf3224205284a9b32904fa7f5d507be845878bd4eaf0f983a17e26456d6cccb24f1420a7df697866223b2df2964150404285e1db6497efe7904464172bcc1c
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.5.0...HEAD
32
- [0.4.0]: https://github.com/jonas-lantto/table_transform/compare/v0.4.0...v0.5.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
- ### Table properties
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
- ### Meta data
105
+ #### Column properties
84
106
  # Set format for one column
85
- t.set_metadata('Tax', {format: '0.0%'})
107
+ t.column_properties['Tax'].update({format: '0.0%'})
86
108
 
87
- # Extract metadata
88
- t.metadata['Tax'] # {format: '0.0%'}
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.metadata) if table.is_a?(TableTransform::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.metadata[name][:format])].max
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(metadata)
60
- metadata.each{|_,v|
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(metadata, formats, formulas)
67
+ def create_column_metadata(column_properties, formats, formulas)
67
68
  res = []
68
- metadata.each{ |header_name, data|
69
- data_dup = data.dup
70
- data_dup[:format] = formats[data_dup[:format]] unless data_dup[:format].nil? #replace str format with excel representation
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
- data_dup.merge!({formula: formula}) unless formula.nil?
73
- res << {header: header_name}.merge(data_dup)
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
- properties = ExcelCreator::default_properties(name).update(table.table_properties.to_h)
84
- col_width = ExcelCreator::column_width(table, properties[:auto_filter])
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 => properties[:name],
100
+ :name => table_properties[:name],
93
101
  :data => data,
94
- :autofilter => properties[:auto_filter] ? 1 : 0,
95
- :columns => create_column_metadata(table.metadata, @formats, table.formulas)
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
- validate_column_names(*columns)
49
- validate_metadata_tags(metadata)
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
- @metadata.clone
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, metadata = {})
60
- add_column(column, metadata){nil}
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 meta data do not match
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 @metadata.keys == t2_header
76
- raise 'Tables cannot be added due to meta data mismatch' unless @metadata == table.metadata
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 @metadata.keys.clone
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
- validate_column_names(*header)
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
- t.metadata = t.metadata.keys.zip(@metadata.values_at(*header)).to_h
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 @metadata.keys.clone), @table_properties.to_h )
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, metadata = {})
111
- raise "Column '#{name}' already exists" if @metadata.keys.include?(name)
112
- @metadata[name] = {}
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
- validate_column_names(*names)
136
+ validate_column_exist(*names)
133
137
  names.each{|n|
134
- @metadata.delete(n)
138
+ @column_properties.delete(n)
135
139
  @formulas.delete(n)
136
140
  }
137
141
 
138
- selected_cols = @column_indexes.values_at(*@metadata.keys)
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(@metadata.keys)
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
- @metadata.keys.inject([]) { |row, col| row << hash_values.fetch(col){raise "Value for column '#{col}' could not be found"} }
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 #{@metadata.size}" if @metadata.size != x.size}
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 validate_column_names(*names)
214
- diff = names - @metadata.keys
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 validate_metadata_tags(metadata)
219
- raise 'Metadata must be a hash' unless metadata.is_a?(Hash)
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
@@ -1,3 +1,3 @@
1
1
  module TableTransform
2
- VERSION = '0.5.0'
2
+ VERSION = '0.6.0'
3
3
  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.5.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-13 00:00:00.000000000 Z
11
+ date: 2016-03-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake