red-arrow 0.4.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,391 @@
1
+ # Copyright 2017 Kouhei Sutou <kou@clear-code.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Arrow
16
+ class Slicer
17
+ def initialize(table)
18
+ @table = table
19
+ end
20
+
21
+ def [](column_name)
22
+ column = @table[column_name]
23
+ return nil if column.nil?
24
+ ColumnCondition.new(column)
25
+ end
26
+
27
+ def respond_to_missing?(name, include_private)
28
+ return true if self[name]
29
+ super
30
+ end
31
+
32
+ def method_missing(name, *args, &block)
33
+ if args.empty?
34
+ column_condition = self[name]
35
+ return column_condition if column_condition
36
+ end
37
+ super
38
+ end
39
+
40
+ class Condition
41
+ def evaluate
42
+ message = "Slicer::Condition must define \#evaluate: #{inspect}"
43
+ raise NotImplementedError.new(message)
44
+ end
45
+
46
+ def &(condition)
47
+ AndCondition.new(self, condition)
48
+ end
49
+
50
+ def |(condition)
51
+ OrCondition.new(self, condition)
52
+ end
53
+
54
+ def ^(condition)
55
+ XorCondition.new(self, condition)
56
+ end
57
+ end
58
+
59
+ class LogicalCondition < Condition
60
+ def initialize(condition1, condition2)
61
+ @condition1 = condition1
62
+ @condition2 = condition2
63
+ end
64
+
65
+ def evaluate
66
+ values1 = @condition1.evaluate.each
67
+ values2 = @condition2.evaluate.each
68
+ raw_array = []
69
+ begin
70
+ loop do
71
+ value1 = values1.next
72
+ value2 = values2.next
73
+ if value1.nil? or value2.nil?
74
+ raw_array << nil
75
+ else
76
+ raw_array << evaluate_value(value1, value2)
77
+ end
78
+ end
79
+ rescue StopIteration
80
+ end
81
+ BooleanArray.new(raw_array)
82
+ end
83
+ end
84
+
85
+ class AndCondition < LogicalCondition
86
+ private
87
+ def evaluate_value(value1, value2)
88
+ value1 and value2
89
+ end
90
+ end
91
+
92
+ class OrCondition < LogicalCondition
93
+ private
94
+ def evaluate_value(value1, value2)
95
+ value1 or value2
96
+ end
97
+ end
98
+
99
+ class XorCondition < LogicalCondition
100
+ private
101
+ def evaluate_value(value1, value2)
102
+ value1 ^ value2
103
+ end
104
+ end
105
+
106
+ class ColumnCondition < Condition
107
+ def initialize(column)
108
+ @column = column
109
+ end
110
+
111
+ def evaluate
112
+ data = @column.data
113
+ if data.n_chunks == 1
114
+ array = data.get_chunk(0)
115
+ if array.is_a?(BooleanArray)
116
+ array
117
+ else
118
+ array.cast(BooleanDataType.new)
119
+ end
120
+ else
121
+ raw_array = []
122
+ data.each_chunk do |chunk|
123
+ if chunk.is_a?(BooleanArray)
124
+ boolean_array = chunk
125
+ else
126
+ boolean_array = chunk.cast(BooleanDataType.new)
127
+ end
128
+ boolean_array.each do |value|
129
+ raw_array << value
130
+ end
131
+ end
132
+ BooleanArray.new(raw_array)
133
+ end
134
+ end
135
+
136
+ def !@
137
+ NotColumnCondition.new(@column)
138
+ end
139
+
140
+ def null?
141
+ self == nil
142
+ end
143
+
144
+ def ==(value)
145
+ EqualCondition.new(@column, value)
146
+ end
147
+
148
+ def !=(value)
149
+ NotEqualCondition.new(@column, value)
150
+ end
151
+
152
+ def <(value)
153
+ LessCondition.new(@column, value)
154
+ end
155
+
156
+ def <=(value)
157
+ LessEqualCondition.new(@column, value)
158
+ end
159
+
160
+ def >(value)
161
+ GreaterCondition.new(@column, value)
162
+ end
163
+
164
+ def >=(value)
165
+ GreaterEqualCondition.new(@column, value)
166
+ end
167
+
168
+ def select(&block)
169
+ SelectCondition.new(@column, block)
170
+ end
171
+
172
+ def reject(&block)
173
+ RejectCondition.new(@column, block)
174
+ end
175
+ end
176
+
177
+ class NotColumnCondition < Condition
178
+ def initialize(column)
179
+ @column = column
180
+ end
181
+
182
+ def evaluate
183
+ data = @column.data
184
+ raw_array = []
185
+ data.each_chunk do |chunk|
186
+ if chunk.is_a?(BooleanArray)
187
+ boolean_array = chunk
188
+ else
189
+ boolean_array = chunk.cast(BooleanDataType.new)
190
+ end
191
+ boolean_array.each do |value|
192
+ if value.nil?
193
+ raw_array << value
194
+ else
195
+ raw_array << !value
196
+ end
197
+ end
198
+ end
199
+ BooleanArray.new(raw_array)
200
+ end
201
+
202
+ def !@
203
+ ColumnCondition.new(@column)
204
+ end
205
+ end
206
+
207
+ class EqualCondition < Condition
208
+ def initialize(column, value)
209
+ @column = column
210
+ @value = value
211
+ end
212
+
213
+ def !@
214
+ NotEqualCondition.new(@column, @value)
215
+ end
216
+
217
+ def evaluate
218
+ case @value
219
+ when nil
220
+ raw_array = @column.collect(&:nil?)
221
+ BooleanArray.new(raw_array)
222
+ else
223
+ raw_array = @column.collect do |value|
224
+ if value.nil?
225
+ nil
226
+ else
227
+ @value == value
228
+ end
229
+ end
230
+ BooleanArray.new(raw_array)
231
+ end
232
+ end
233
+ end
234
+
235
+ class NotEqualCondition < Condition
236
+ def initialize(column, value)
237
+ @column = column
238
+ @value = value
239
+ end
240
+
241
+ def !@
242
+ EqualCondition.new(@column, @value)
243
+ end
244
+
245
+ def evaluate
246
+ case @value
247
+ when nil
248
+ raw_array = @column.collect do |value|
249
+ not value.nil?
250
+ end
251
+ BooleanArray.new(raw_array)
252
+ else
253
+ raw_array = @column.collect do |value|
254
+ if value.nil?
255
+ nil
256
+ else
257
+ @value != value
258
+ end
259
+ end
260
+ BooleanArray.new(raw_array)
261
+ end
262
+ end
263
+ end
264
+
265
+ class LessCondition < Condition
266
+ def initialize(column, value)
267
+ @column = column
268
+ @value = value
269
+ end
270
+
271
+ def !@
272
+ GreaterEqualCondition.new(@column, @value)
273
+ end
274
+
275
+ def evaluate
276
+ raw_array = @column.collect do |value|
277
+ if value.nil?
278
+ nil
279
+ else
280
+ @value > value
281
+ end
282
+ end
283
+ BooleanArray.new(raw_array)
284
+ end
285
+ end
286
+
287
+ class LessEqualCondition < Condition
288
+ def initialize(column, value)
289
+ @column = column
290
+ @value = value
291
+ end
292
+
293
+ def !@
294
+ GreaterCondition.new(@column, @value)
295
+ end
296
+
297
+ def evaluate
298
+ raw_array = @column.collect do |value|
299
+ if value.nil?
300
+ nil
301
+ else
302
+ @value >= value
303
+ end
304
+ end
305
+ BooleanArray.new(raw_array)
306
+ end
307
+ end
308
+
309
+ class GreaterCondition < Condition
310
+ def initialize(column, value)
311
+ @column = column
312
+ @value = value
313
+ end
314
+
315
+ def !@
316
+ LessEqualCondition.new(@column, @value)
317
+ end
318
+
319
+ def evaluate
320
+ raw_array = @column.collect do |value|
321
+ if value.nil?
322
+ nil
323
+ else
324
+ @value < value
325
+ end
326
+ end
327
+ BooleanArray.new(raw_array)
328
+ end
329
+ end
330
+
331
+ class GreaterEqualCondition < Condition
332
+ def initialize(column, value)
333
+ @column = column
334
+ @value = value
335
+ end
336
+
337
+ def !@
338
+ LessCondition.new(@column, @value)
339
+ end
340
+
341
+ def evaluate
342
+ raw_array = @column.collect do |value|
343
+ if value.nil?
344
+ nil
345
+ else
346
+ @value <= value
347
+ end
348
+ end
349
+ BooleanArray.new(raw_array)
350
+ end
351
+ end
352
+
353
+ class SelectCondition < Condition
354
+ def initialize(column, block)
355
+ @column = column
356
+ @block = block
357
+ end
358
+
359
+ def !@
360
+ RejectCondition.new(@column, @block)
361
+ end
362
+
363
+ def evaluate
364
+ BooleanArray.new(@column.collect(&@block))
365
+ end
366
+ end
367
+
368
+ class RejectCondition < Condition
369
+ def initialize(column, block)
370
+ @column = column
371
+ @block = block
372
+ end
373
+
374
+ def !@
375
+ SelectCondition.new(@column, @block)
376
+ end
377
+
378
+ def evaluate
379
+ raw_array = @column.collect do |value|
380
+ evaluated_value = @block.call(value)
381
+ if evaluated_value.nil?
382
+ nil
383
+ else
384
+ not evaluated_value
385
+ end
386
+ end
387
+ BooleanArray.new(raw_array)
388
+ end
389
+ end
390
+ end
391
+ end
@@ -0,0 +1,88 @@
1
+ # Copyright 2017-2018 Kouhei Sutou <kou@clear-code.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require "time"
16
+
17
+ module Arrow
18
+ class TableFormatter
19
+ def initialize(table, options={})
20
+ @table = table
21
+ @options = options
22
+ end
23
+
24
+ def format
25
+ text = ""
26
+ columns = @table.columns
27
+ columns.each do |column|
28
+ text << "\t"
29
+ text << format_column_name(column)
30
+ end
31
+ text << "\n"
32
+
33
+ n_rows = @table.n_rows
34
+ return text if n_rows.zero?
35
+
36
+ border = @options[:border] || 10
37
+ n_digits = (Math.log10(n_rows) + 1).truncate
38
+ [border, n_rows].min.times do |i|
39
+ format_row(text, columns, i, n_digits)
40
+ end
41
+ return text if n_rows <= border
42
+
43
+ text << "...\n"
44
+ [border, n_rows - border].max.upto(n_rows - 1) do |i|
45
+ format_row(text, columns, i, n_digits)
46
+ end
47
+
48
+ text
49
+ end
50
+
51
+ private
52
+ FLOAT_N_DIGITS = 10
53
+ def format_column_name(column)
54
+ case column.data_type
55
+ when TimestampDataType
56
+ "%*s" % [Time.now.iso8601.size, column.name]
57
+ when FloatDataType, DoubleDataType
58
+ "%*s" % [FLOAT_N_DIGITS, column.name]
59
+ else
60
+ column.name
61
+ end
62
+ end
63
+
64
+ def format_row(text, columns, i, n_digits)
65
+ text << ("%*d" % [n_digits, i])
66
+ columns.each do |column|
67
+ text << "\t"
68
+ text << format_column_value(column, i)
69
+ end
70
+ text << "\n"
71
+ text
72
+ end
73
+
74
+ def format_column_value(column, i)
75
+ value = column[i]
76
+ case value
77
+ when Time
78
+ value.iso8601
79
+ when Float
80
+ "%*f" % [[column.name.size, FLOAT_N_DIGITS].max, value]
81
+ when Integer
82
+ "%*d" % [column.name.size, value]
83
+ else
84
+ "%-*s" % [column.name.size, value.to_s]
85
+ end
86
+ end
87
+ end
88
+ end