true_table 0.1.2 → 0.2.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
  SHA256:
3
- metadata.gz: 9c778d54af435cbd53a4dfc45df1026d954dd79fda06c12ca7de9c5203054bd5
4
- data.tar.gz: ecb8c574d6f53b7936cf7c668e55050f4effee32063922b92605200f48569d94
3
+ metadata.gz: 53e26ebda846b40d7f2399e318b3be09ce49c71ddebbab97bfc34fbd64d664b4
4
+ data.tar.gz: 1427d9de17b647d15469522ea5483b268ca41ef82a325b286617dc72ada93ad9
5
5
  SHA512:
6
- metadata.gz: 9cc7983ee8202a8ce1c1e4414dc5e5a2c34f5ed4e70c2789e2c940c325431cb1034d99ddaaae6c11e7771b993b8f0f747c3e3a7a792445b22f6376573e02b638
7
- data.tar.gz: 3f2e42e7b50716d0e93e0676fd7c161a8e6bab1962c50358b734fb301d7b967785acaa7db79382a1b70fffce28c54d6ed9e1e27a88e45c237db717c2ddca6ed5
6
+ metadata.gz: b2aa85ebfd3c93611bcd499fa1c551dfac70b552353e89e60e0a68362763c9e8e5663d9557d310d36fb488409aaf3fac46234dc95fe18644422fc7654ec05155
7
+ data.tar.gz: 9c8d9423738e0724c3bbcac5fc93187c8bd8c2e68cd5cb8a481324bd0b2080b3087ff9dad498b024ec41f0784a061afc0988c5654f177073c2a1334ec9cb78e1
data/README.md CHANGED
@@ -16,6 +16,9 @@ each row is a `Hash`.
16
16
  $ gem install true_table
17
17
  ```
18
18
 
19
- ## Usage
19
+ ## Documentation
20
20
 
21
- TODO
21
+ [Documentation on RubyDoc][docs]
22
+
23
+
24
+ [docs]: https://rubydoc.info/gems/true_table
@@ -1,2 +1,236 @@
1
- require 'true_table/table'
2
- require 'byebug' if ENV['BYEBUG']
1
+ require 'csv'
2
+
3
+ class TrueTable < Array
4
+ class << self
5
+ # Loads a CSV string
6
+ #
7
+ # @example
8
+ # csv = "id,name\n1,Harry\n2,Lloyd"
9
+ # table = TrueTable.load_csv csv, converters: [:date, :numeric]
10
+ #
11
+ # @param [String] csv_string CSV string.
12
+ # @param [Hash] options options to forward to the CSV class.
13
+ #
14
+ # @return [TrueTable] the new table object
15
+ def from_csv(csv_string, options = {})
16
+ default_options = { headers: true, converters: :numeric, header_converters: :symbol }
17
+ csv = CSV.new csv_string, **default_options.merge(options)
18
+ new.tap do |table|
19
+ csv.each { |row| table << row.to_h }
20
+ end
21
+ end
22
+
23
+ # Loads a CSV file
24
+ #
25
+ # @example
26
+ # table = TrueTable.from_csv "sample.csv", converters: [:date, :numeric]
27
+ #
28
+ # @param [String] path the path to the CSV file.
29
+ # @param [Hash] options options to forward to the CSV class.
30
+ #
31
+ # @return [TrueTable] the new table object
32
+ def load_csv(path, options = {})
33
+ from_csv File.read(path), options
34
+ end
35
+ end
36
+
37
+ # Combines table with other and returns a new one
38
+ def +(other)
39
+ result = self.class.new
40
+ each_row { |row, i| result << row.merge(other[i]) }
41
+ result
42
+ end
43
+
44
+ # Returns a new table without the specified columns
45
+ def -(cols)
46
+ keep_keys = headers - cols
47
+ result = self.class.new
48
+ each_row { |row, i| result << row.slice(*keep_keys) }
49
+ result
50
+ end
51
+
52
+ # Returns a row or a column
53
+ def [](key)
54
+ key.is_a?(Symbol) ? col(key) : super
55
+ end
56
+
57
+ # Adds or updates a row or a column
58
+ def []=(key, value)
59
+ key.is_a?(Symbol) ? add_col(key.to_sym, value) : super
60
+ end
61
+
62
+ # Returns a deep copy of self
63
+ def clone
64
+ self.class.new map(&:clone)
65
+ end
66
+
67
+ # Returns a column as Array
68
+ def col(key)
69
+ map { |row| row[key] }
70
+ end
71
+
72
+ # Returns a hash of columns
73
+ def cols
74
+ result = {}
75
+ each_col { |col, header| result[header] = col }
76
+ result
77
+ end
78
+
79
+ # Returns a copy of self without rows that contain nil in any column
80
+ def compact
81
+ dup.compact!
82
+ end
83
+
84
+ # Removes rows with nil in any column
85
+ def compact!
86
+ delete_if { |row| row.values.include? nil }
87
+ end
88
+
89
+ # Delete a row or a column in place and returns the deleted row/column
90
+ def delete_at(index)
91
+ if index.is_a?(Symbol) || index.is_a?(String)
92
+ result = self[index]
93
+ return nil unless result
94
+ each_row { |row, i| row.delete index }
95
+ result
96
+ else
97
+ super
98
+ end
99
+ end
100
+ alias delete_col delete_at
101
+ alias delete_row delete_at
102
+
103
+ # Returns a table with different rows
104
+ def difference(*others)
105
+ self.class.new super
106
+ end
107
+
108
+ # Extracts nested value. Accepts row, column or column, row
109
+ def dig(*indexes)
110
+ key = indexes.shift
111
+ if key.is_a?(Symbol)
112
+ col(key.to_sym).dig *indexes
113
+ else
114
+ row(key).dig *indexes
115
+ end
116
+ end
117
+
118
+ # Iterates over columns
119
+ def each_col
120
+ headers.each { |header| yield col(header), header }
121
+ end
122
+
123
+ # Iterates over rows
124
+ alias each_row each_with_index
125
+
126
+ def fetch(key, *default)
127
+ if key.is_a?(Symbol)
128
+ if headers.include? key
129
+ col(key.to_sym)
130
+ elsif default.any?
131
+ default.first
132
+ elsif block_given?
133
+ yield key
134
+ else
135
+ raise IndexError, "row :#{key} does not exist"
136
+ end
137
+ else
138
+ super
139
+ end
140
+ end
141
+
142
+ # Returns an array of column headers
143
+ def headers
144
+ first.keys
145
+ end
146
+
147
+ # Returns a new table with intersecting rows
148
+ def intersection(*others)
149
+ self.class.new super
150
+ end
151
+
152
+ # Returns a string with joined rows and columns
153
+ def join(row_separator = $,, col_separator = nil, with_headers: false)
154
+ if col_separator
155
+ result = map { |row| row.values.join col_separator }.join(row_separator)
156
+ with_headers ? headers.join(col_separator) + row_separator + result : result
157
+ else
158
+ super row_separator
159
+ end
160
+ end
161
+
162
+ # Returns the last row or a new table with the last N rows
163
+ def last(*args)
164
+ args.empty? ? super : self.class.new(super)
165
+ end
166
+
167
+ # Returns a new table without rejected rows
168
+ def reject
169
+ self.class.new super
170
+ end
171
+
172
+ # Returns a reversed copy
173
+ def reverse
174
+ self.class.new super
175
+ end
176
+
177
+ # Returns a new table with the element at `count` as the first element
178
+ def rotate(count = 1)
179
+ self.class.new super
180
+ end
181
+
182
+ # Returns a row
183
+ alias row []
184
+
185
+ # Saves the table as a CSV file
186
+ def save_csv(path)
187
+ File.write path, to_csv
188
+ end
189
+
190
+ # Returns a new table with selected rows
191
+ def select
192
+ self.class.new super
193
+ end
194
+ alias filter select
195
+
196
+ # Returns a new shuffled tables
197
+ def shuffle(*args)
198
+ self.class.new super
199
+ end
200
+
201
+ # Returns a new sorted table
202
+ def sort
203
+ self.class.new super
204
+ end
205
+
206
+ # Returns a new sorted table
207
+ def sort_by
208
+ self.class.new super
209
+ end
210
+
211
+ # Returns a CSV string
212
+ def to_csv(row_separator = "\n", col_separator = ",")
213
+ join(row_separator, col_separator, with_headers: true)
214
+ end
215
+
216
+ # Returns a hash representation of the table using the values of the
217
+ # first column as hash keys
218
+ def to_h
219
+ map { |row| [row.values.first, row] }.to_h
220
+ end
221
+
222
+ # Returns only values, without any headers (array of arrays)
223
+ def values
224
+ map { |row| row.values }
225
+ end
226
+
227
+ protected
228
+
229
+ def add_col(key, values)
230
+ values.each_with_index do |value, i|
231
+ self[i] ||= {}
232
+ self[i][key] = value
233
+ end
234
+ end
235
+
236
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: true_table
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danny Ben Shitrit
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-06 00:00:00.000000000 Z
11
+ date: 2020-09-09 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Simple and intuitive tabular data type
14
14
  email: db@dannyben.com
@@ -18,8 +18,6 @@ extra_rdoc_files: []
18
18
  files:
19
19
  - README.md
20
20
  - lib/true_table.rb
21
- - lib/true_table/table.rb
22
- - lib/true_table/version.rb
23
21
  homepage: https://github.com/dannyben/true_table
24
22
  licenses:
25
23
  - MIT
@@ -1,198 +0,0 @@
1
- module TrueTable
2
- class Table < Array
3
- # Combines table with other and returns a new one
4
- def +(other)
5
- result = self.class.new
6
- each_row { |row, i| result << row.merge(other[i]) }
7
- result
8
- end
9
-
10
- # Returns a new table without the specified columns
11
- def -(cols)
12
- keep_keys = headers - cols
13
- result = self.class.new
14
- each_row { |row, i| result << row.slice(*keep_keys) }
15
- result
16
- end
17
-
18
- # Returns a row or a column
19
- def [](key)
20
- key.is_a?(Symbol) ? col(key) : super
21
- end
22
-
23
- # Adds or updates a row or a column
24
- def []=(key, value)
25
- key.is_a?(Symbol) ? add_col(key.to_sym, value) : super
26
- end
27
-
28
- # Returns a deep copy of self
29
- def clone
30
- self.class.new map(&:clone)
31
- end
32
-
33
- # Returns a column as Array
34
- def col(key)
35
- map { |row| row[key] }
36
- end
37
-
38
- # Returns a hash of columns
39
- def cols
40
- result = {}
41
- each_col { |col, header| result[header] = col }
42
- result
43
- end
44
-
45
- # Returns a copy of self without rows that contain nil in any column
46
- def compact
47
- dup.compact!
48
- end
49
-
50
- # Removes rows with nil in any column
51
- def compact!
52
- delete_if { |row| row.values.include? nil }
53
- end
54
-
55
- # Delete a row or a column in place and returns the deleted row/column
56
- def delete_at(index)
57
- if index.is_a?(Symbol) || index.is_a?(String)
58
- result = self[index]
59
- return nil unless result
60
- each_row { |row, i| row.delete index }
61
- result
62
- else
63
- super
64
- end
65
- end
66
- alias delete_col delete_at
67
- alias delete_row delete_at
68
-
69
- # Returns a table with different rows
70
- def difference(*others)
71
- self.class.new super
72
- end
73
-
74
- # Extracts nested value. Accepts row, column or column, row
75
- def dig(*indexes)
76
- key = indexes.shift
77
- if key.is_a?(Symbol)
78
- col(key.to_sym).dig *indexes
79
- else
80
- row(key).dig *indexes
81
- end
82
- end
83
-
84
- # Iterates over columns
85
- def each_col
86
- headers.each { |header| yield col(header), header }
87
- end
88
-
89
- # Iterates over rows
90
- alias each_row each_with_index
91
-
92
- def fetch(key, *default)
93
- if key.is_a?(Symbol)
94
- if headers.include? key
95
- col(key.to_sym)
96
- elsif default.any?
97
- default.first
98
- elsif block_given?
99
- yield key
100
- else
101
- raise IndexError, "row :#{key} does not exist"
102
- end
103
- else
104
- super
105
- end
106
- end
107
-
108
- # Returns an array of column headers
109
- def headers
110
- first.keys
111
- end
112
-
113
- # Returns a new table with intersecting rows
114
- def intersection(*others)
115
- self.class.new super
116
- end
117
-
118
- # Returns a string with joined rows and columns
119
- def join(row_separator = $,, col_separator = nil, with_headers: false)
120
- if col_separator
121
- result = map { |row| row.values.join col_separator }.join(row_separator)
122
- with_headers ? headers.join(col_separator) + row_separator + result : result
123
- else
124
- super row_separator
125
- end
126
- end
127
-
128
- # Returns the last row or a new table with the last N rows
129
- def last(*args)
130
- args.empty? ? super : self.class.new(super)
131
- end
132
-
133
- # Returns a new table without rejected rows
134
- def reject
135
- self.class.new super
136
- end
137
-
138
- # Returns a reversed copy
139
- def reverse
140
- self.class.new super
141
- end
142
-
143
- # Returns a new table with the element at `count` as the first element
144
- def rotate(count = 1)
145
- self.class.new super
146
- end
147
-
148
- # Returns a row
149
- alias row []
150
-
151
- # Returns a new table with selected rows
152
- def select
153
- self.class.new super
154
- end
155
- alias filter select
156
-
157
- # Returns a new shuffled tables
158
- def shuffle(*args)
159
- self.class.new super
160
- end
161
-
162
- # Returns a new sorted table
163
- def sort
164
- self.class.new super
165
- end
166
-
167
- # Returns a new sorted table
168
- def sort_by
169
- self.class.new super
170
- end
171
-
172
- # Returns a CSV string
173
- def to_csv(row_separator = "\n", col_separator = ",")
174
- join(row_separator, col_separator, with_headers: true)
175
- end
176
-
177
- # Returns a hash representation of the table using the values of the
178
- # first column as hash keys
179
- def to_h
180
- map { |row| [row.values.first, row] }.to_h
181
- end
182
-
183
- # Returns only values, without any headers (array of arrays)
184
- def values
185
- map { |row| row.values }
186
- end
187
-
188
- protected
189
-
190
- def add_col(key, values)
191
- values.each_with_index do |value, i|
192
- self[i] ||= {}
193
- self[i][key] = value
194
- end
195
- end
196
-
197
- end
198
- end
@@ -1,3 +0,0 @@
1
- module TrueTable
2
- VERSION = "0.1.2"
3
- end