true_table 0.1.2 → 0.2.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
  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