table_structure 0.3.20 → 0.3.21
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +1 -1
- data/README.md +53 -52
- data/lib/table_structure.rb +7 -5
- data/lib/table_structure/iterator.rb +97 -12
- data/lib/table_structure/schema.rb +64 -85
- data/lib/table_structure/schema/column_converter.rb +48 -0
- data/lib/table_structure/schema/columns/schema.rb +3 -2
- data/lib/table_structure/schema/{keys_generator.rb → key_converter.rb} +2 -2
- data/lib/table_structure/schema/row_builder.rb +22 -0
- data/lib/table_structure/table.rb +72 -0
- data/lib/table_structure/table/column_converter.rb +46 -0
- data/lib/table_structure/table/context_builder.rb +49 -0
- data/lib/table_structure/table/iterator.rb +13 -15
- data/lib/table_structure/table/row_builder.rb +38 -0
- data/lib/table_structure/version.rb +1 -1
- data/lib/table_structure/writer.rb +7 -33
- metadata +9 -7
- data/lib/table_structure/schema/column_converters.rb +0 -83
- data/lib/table_structure/schema/context_builders.rb +0 -55
- data/lib/table_structure/schema/row_builders.rb +0 -58
- data/lib/table_structure/schema/table.rb +0 -61
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c8d52660a94da1c1fbcc8a14a8332214c32ba1627a50239ee72f9916e12c8502
|
4
|
+
data.tar.gz: 2156f6ebaa0ee6fd88dfb282a3c339e20101da8bf33cd250355eff7557915921
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e5091c8a9c362a09b563e608cf78b74fddb53526ebd53ef30700f4c975429689c5ab8e27f72918d7c4fbdcd798b7911f20dd70593a313fe59bdb88d5deb8e35
|
7
|
+
data.tar.gz: 6ae2d481a839d63271009435173250f929009bd2273a59f3aaa974cc14e7612d7cb55258c82c2fe189f304277249d298e0eaaa7d15d1d20b6acc53cee3bb02f9
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
# 0.3.21
|
2
|
+
Changes:
|
3
|
+
- Add `TableStructure::Table`
|
4
|
+
- This provides methods for converting data with the schema.
|
5
|
+
- Use `TableStructure::Table.new` instead of `TableStructure::Schema#create_table`.
|
6
|
+
- `TableStructure::Schema`
|
7
|
+
- `TableStructure::Schema#create_table` has been deprecated. Use `TableStructure::Table.new` instead.
|
8
|
+
|
1
9
|
# 0.3.20
|
2
10
|
Changes:
|
3
11
|
- `TableStructure::Schema`
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -8,6 +8,8 @@
|
|
8
8
|
- Converts data with the schema, and outputs table structured data.
|
9
9
|
- `TableStructure::Iterator`
|
10
10
|
- Converts data with the schema, and enumerates table structured data.
|
11
|
+
- `TableStructure::Table`
|
12
|
+
- Provides methods for converting data with the schema.
|
11
13
|
|
12
14
|
## Installation
|
13
15
|
|
@@ -127,7 +129,6 @@ response_body = Enumerator.new do |y|
|
|
127
129
|
writer.write(items, to: CSV.new(y))
|
128
130
|
end
|
129
131
|
```
|
130
|
-
[Sample with docker](https://github.com/jsmmr/ruby_table_structure_sample)
|
131
132
|
|
132
133
|
You can also convert CSV character code:
|
133
134
|
```ruby
|
@@ -147,27 +148,31 @@ end
|
|
147
148
|
```
|
148
149
|
|
149
150
|
#### TableStructure::Iterator
|
150
|
-
|
151
|
-
To use this option, define `column(s)
|
151
|
+
If you want to convert the item to row as Hash instead of Array, specify `row_type: :hash`.
|
152
|
+
To use this option, define `:key` on `column(s)`.
|
152
153
|
|
153
154
|
Define a schema:
|
154
155
|
```ruby
|
155
156
|
class SampleTableSchema
|
156
157
|
include TableStructure::Schema
|
157
158
|
|
158
|
-
# If header is
|
159
|
-
column
|
159
|
+
# If `:header` is set to `false`, `:name` is optional.
|
160
|
+
column name: 'ID',
|
161
|
+
key: :id,
|
160
162
|
value: ->(row, *) { row[:id] }
|
161
163
|
|
162
|
-
column
|
164
|
+
column name: 'Name',
|
165
|
+
key: :name,
|
163
166
|
value: ->(row, *) { row[:name] }
|
164
167
|
|
165
|
-
columns
|
168
|
+
columns name: ['Pet 1', 'Pet 2', 'Pet 3'],
|
169
|
+
key: %i[pet1 pet2 pet3],
|
166
170
|
value: ->(row, *) { row[:pets] }
|
167
171
|
|
168
172
|
columns ->(table) {
|
169
173
|
table[:questions].map do |question|
|
170
174
|
{
|
175
|
+
name: question[:id],
|
171
176
|
key: question[:id].downcase.to_sym,
|
172
177
|
value: ->(row, *) { row[:answers][question[:id]] }
|
173
178
|
}
|
@@ -175,7 +180,7 @@ class SampleTableSchema
|
|
175
180
|
}
|
176
181
|
|
177
182
|
## If the schemas are nested, :key must be unique in parent and child schemas.
|
178
|
-
## This can also be avoided by
|
183
|
+
## This can also be avoided by using :key_prefix or :key_suffix option.
|
179
184
|
# columns ->(table) { NestedTableSchema.new(context: table, key_prefix: 'foo_', key_suffix: '_bar') }
|
180
185
|
end
|
181
186
|
```
|
@@ -191,7 +196,7 @@ context = {
|
|
191
196
|
}
|
192
197
|
|
193
198
|
schema = SampleTableSchema.new(context: context)
|
194
|
-
iterator = TableStructure::Iterator.new(schema,
|
199
|
+
iterator = TableStructure::Iterator.new(schema, header: false, row_type: :hash)
|
195
200
|
```
|
196
201
|
|
197
202
|
Enumerate the items converted by the schema:
|
@@ -225,6 +230,33 @@ enum.lazy.select { |item| item[:q1] == '⭕️' }.take(1).force
|
|
225
230
|
# => [{:id=>1, :name=>"Taro", :pet1=>"🐱", :pet2=>"🐶", :pet3=>nil, :q1=>"⭕️", :q2=>"❌", :q3=>"⭕️"}]
|
226
231
|
```
|
227
232
|
|
233
|
+
#### TableStructure::Table
|
234
|
+
|
235
|
+
Initialize a table with the schema and render the table:
|
236
|
+
```erb
|
237
|
+
<% TableStructure::Table.new(schema, row_type: :hash) do |table| %>
|
238
|
+
<table>
|
239
|
+
<thead>
|
240
|
+
<tr>
|
241
|
+
<% table.header.each do |key, value| %>
|
242
|
+
<th class="<%= key %>"><%= value %></th>
|
243
|
+
<% end %>
|
244
|
+
</tr>
|
245
|
+
</thead>
|
246
|
+
|
247
|
+
<tbody>
|
248
|
+
<% table.body(@items).each do |row| %>
|
249
|
+
<tr>
|
250
|
+
<% row.each do |key, value| %>
|
251
|
+
<td class="<%= key %>"><%= value %></td>
|
252
|
+
<% end %>
|
253
|
+
</tr>
|
254
|
+
<% end %>
|
255
|
+
</tbody>
|
256
|
+
</table>
|
257
|
+
<% end %>
|
258
|
+
```
|
259
|
+
|
228
260
|
### Advanced
|
229
261
|
|
230
262
|
You can add definitions when initializing the schema.
|
@@ -244,7 +276,7 @@ schema = UserTableSchema.new do
|
|
244
276
|
end
|
245
277
|
```
|
246
278
|
|
247
|
-
You can also omit columns by
|
279
|
+
You can also omit columns by using `:omitted`.
|
248
280
|
```ruby
|
249
281
|
class UserTableSchema
|
250
282
|
include TableStructure::Schema
|
@@ -265,7 +297,7 @@ context = { admin: true }
|
|
265
297
|
schema = UserTableSchema.new(context: context)
|
266
298
|
```
|
267
299
|
|
268
|
-
You can also omit columns by
|
300
|
+
You can also omit columns by using `:nil_definitions_ignored` option.
|
269
301
|
If this option is set to `true` and `column(s)` difinition returns `nil`, the difinition is ignored.
|
270
302
|
```ruby
|
271
303
|
class SampleTableSchema
|
@@ -327,37 +359,27 @@ end
|
|
327
359
|
class SampleTableSchema
|
328
360
|
include TableStructure::Schema
|
329
361
|
|
330
|
-
columns
|
362
|
+
columns UserTableSchema
|
331
363
|
## or
|
332
|
-
# columns UserTableSchema
|
364
|
+
# columns ->(table) { UserTableSchema.new(context: table) }
|
333
365
|
|
334
|
-
columns
|
366
|
+
columns PetTableSchema
|
335
367
|
## or
|
336
|
-
# columns PetTableSchema
|
368
|
+
# columns ->(table) { PetTableSchema.new(context: table) }
|
337
369
|
|
338
|
-
columns
|
370
|
+
columns QuestionTableSchema
|
339
371
|
## or
|
340
|
-
# columns QuestionTableSchema
|
372
|
+
# columns ->(table) { QuestionTableSchema.new(context: table) }
|
341
373
|
end
|
342
|
-
|
343
|
-
context = {
|
344
|
-
questions: [
|
345
|
-
{ id: 'Q1', text: 'Do you like sushi?' },
|
346
|
-
{ id: 'Q2', text: 'Do you like yakiniku?' },
|
347
|
-
{ id: 'Q3', text: 'Do you like ramen?' }
|
348
|
-
]
|
349
|
-
}
|
350
|
-
|
351
|
-
schema = SampleTableSchema.new(context: context)
|
352
374
|
```
|
353
375
|
|
354
376
|
You can also concatenate or merge the schema classes.
|
355
377
|
Both create a schema class, with a few differences.
|
356
378
|
- `+`
|
357
379
|
- Similar to nesting the schemas.
|
358
|
-
`column_converter`
|
380
|
+
`column_converter` works only to columns in the schema that they was defined.
|
359
381
|
- `merge`
|
360
|
-
- If there are some definitions of `column_converter`
|
382
|
+
- If there are some definitions of `column_converter` with the same name in the schemas to be merged, the one in the schema that is merged last will work to all columns.
|
361
383
|
|
362
384
|
```ruby
|
363
385
|
class UserTableSchema
|
@@ -444,30 +466,9 @@ class SampleTableSchema
|
|
444
466
|
end
|
445
467
|
```
|
446
468
|
|
447
|
-
|
448
|
-
```erb
|
449
|
-
<% @schema.create_table(row_type: :hash) do |table| %>
|
450
|
-
<table>
|
451
|
-
<thead>
|
452
|
-
<tr>
|
453
|
-
<% table.header.each do |key, value| %>
|
454
|
-
<th class="<%= key %>"><%= value %></th>
|
455
|
-
<% end %>
|
456
|
-
</tr>
|
457
|
-
</thead>
|
469
|
+
## Sample with docker
|
458
470
|
|
459
|
-
|
460
|
-
<% table.body(@items).each do |row| %>
|
461
|
-
<tr>
|
462
|
-
<% row.each do |key, value| %>
|
463
|
-
<td class="<%= key %>"><%= value %></td>
|
464
|
-
<% end %>
|
465
|
-
</tr>
|
466
|
-
<% end %>
|
467
|
-
</tbody>
|
468
|
-
</table>
|
469
|
-
<% end %>
|
470
|
-
```
|
471
|
+
https://github.com/jsmmr/ruby_table_structure_sample
|
471
472
|
|
472
473
|
## Contributing
|
473
474
|
|
data/lib/table_structure.rb
CHANGED
@@ -21,14 +21,16 @@ module TableStructure
|
|
21
21
|
require 'table_structure/schema/definition/columns/attributes'
|
22
22
|
require 'table_structure/schema/definition/columns/schema_class'
|
23
23
|
require 'table_structure/schema/definition/columns/schema_instance'
|
24
|
-
require 'table_structure/schema/
|
25
|
-
require 'table_structure/schema/
|
26
|
-
require 'table_structure/schema/
|
27
|
-
require 'table_structure/schema/keys_generator'
|
28
|
-
require 'table_structure/schema/table'
|
24
|
+
require 'table_structure/schema/column_converter'
|
25
|
+
require 'table_structure/schema/row_builder'
|
26
|
+
require 'table_structure/schema/key_converter'
|
29
27
|
require 'table_structure/schema/columns/attributes'
|
30
28
|
require 'table_structure/schema/columns/schema'
|
31
29
|
require 'table_structure/schema/utils'
|
30
|
+
require 'table_structure/table'
|
31
|
+
require 'table_structure/table/column_converter'
|
32
|
+
require 'table_structure/table/context_builder'
|
33
|
+
require 'table_structure/table/row_builder'
|
32
34
|
require 'table_structure/table/iterator'
|
33
35
|
require 'table_structure/writer'
|
34
36
|
require 'table_structure/csv/writer'
|
@@ -2,21 +2,106 @@
|
|
2
2
|
|
3
3
|
module TableStructure
|
4
4
|
class Iterator
|
5
|
-
def initialize(
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
5
|
+
def initialize(
|
6
|
+
schema,
|
7
|
+
header: { context: nil },
|
8
|
+
row_type: :array,
|
9
|
+
**deprecated_options
|
10
|
+
)
|
11
|
+
if deprecated_options.key?(:header_omitted)
|
12
|
+
header_omitted = deprecated_options[:header_omitted]
|
13
|
+
warn "[TableStructure] `header_omitted: #{!!header_omitted}` option has been deprecated. Use `header: #{!header_omitted}` option instead."
|
14
|
+
header = !header_omitted
|
15
|
+
end
|
16
|
+
|
17
|
+
if deprecated_options.key?(:header_context)
|
18
|
+
header_context = deprecated_options[:header_context]
|
19
|
+
warn '[TableStructure] `:header_context` option has been deprecated. Use `header: { context: ... }` option instead.'
|
20
|
+
header = { context: header_context }
|
21
|
+
end
|
22
|
+
|
23
|
+
if deprecated_options.key?(:result_type)
|
24
|
+
warn '[TableStructure] `:result_type` option has been deprecated. Use `:row_type` option instead.'
|
25
|
+
row_type = deprecated_options[:result_type]
|
26
|
+
end
|
27
|
+
|
28
|
+
unless schema.is_a?(Schema)
|
29
|
+
raise ::TableStructure::Error, "Must be use Schema. #{schema}"
|
30
|
+
end
|
31
|
+
|
32
|
+
@schema = schema
|
33
|
+
@options = {
|
34
|
+
header: header,
|
35
|
+
row_type: row_type
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
def iterate(
|
40
|
+
items,
|
41
|
+
**deprecated_options,
|
42
|
+
&block
|
43
|
+
)
|
44
|
+
header = @options[:header]
|
45
|
+
row_type = @options[:row_type]
|
46
|
+
|
47
|
+
if deprecated_options.key?(:header)
|
48
|
+
header = deprecated_options[:header]
|
49
|
+
warn '[TableStructure] Use :header option on initialize method.'
|
50
|
+
end
|
51
|
+
|
52
|
+
if deprecated_options.key?(:header_omitted)
|
53
|
+
header_omitted = deprecated_options[:header_omitted]
|
54
|
+
warn "[TableStructure] `header_omitted: #{!!header_omitted}` option has been deprecated. Use `header: #{!header_omitted}` option instead."
|
55
|
+
header = !header_omitted
|
14
56
|
end
|
57
|
+
|
58
|
+
if deprecated_options.key?(:header_context)
|
59
|
+
header_context = deprecated_options[:header_context]
|
60
|
+
warn '[TableStructure] `:header_context` option has been deprecated. Use `header: { context: ... }` option instead.'
|
61
|
+
header = { context: header_context }
|
62
|
+
end
|
63
|
+
|
64
|
+
if deprecated_options.key?(:row_type)
|
65
|
+
row_type = deprecated_options[:row_type]
|
66
|
+
warn '[TableStructure] Use :row_type option on initialize method.'
|
67
|
+
end
|
68
|
+
|
69
|
+
if deprecated_options.key?(:result_type)
|
70
|
+
warn '[TableStructure] `:result_type` option has been deprecated. Use `:row_type` option instead.'
|
71
|
+
row_type = deprecated_options[:result_type]
|
72
|
+
end
|
73
|
+
|
74
|
+
items = enumerize(items)
|
75
|
+
|
76
|
+
enum =
|
77
|
+
Table::Iterator
|
78
|
+
.new(
|
79
|
+
Table.new(@schema, row_type: row_type),
|
80
|
+
header: header
|
81
|
+
)
|
82
|
+
.iterate(items)
|
83
|
+
|
84
|
+
if block_given?
|
85
|
+
enum =
|
86
|
+
enum
|
87
|
+
.lazy
|
88
|
+
.map { |row| block.call(row) }
|
89
|
+
end
|
90
|
+
|
91
|
+
enum
|
15
92
|
end
|
16
93
|
|
17
|
-
|
18
|
-
|
19
|
-
|
94
|
+
private
|
95
|
+
|
96
|
+
def enumerize(items)
|
97
|
+
if items.respond_to?(:each)
|
98
|
+
items
|
99
|
+
elsif items.respond_to?(:call)
|
100
|
+
warn "[TableStructure] Use `Enumerator` to wrap items instead of `lambda`. The use of `lambda` has been deprecated. #{items}"
|
101
|
+
Enumerator.new { |y| items.call(y) }
|
102
|
+
else
|
103
|
+
raise ::TableStructure::Error, "Must be enumerable. #{items}"
|
104
|
+
end
|
20
105
|
end
|
21
106
|
end
|
22
107
|
end
|
@@ -21,15 +21,12 @@ module TableStructure
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
:context,
|
31
|
-
:options
|
32
|
-
)
|
24
|
+
attr_reader :columns,
|
25
|
+
:context_builders,
|
26
|
+
:column_converters,
|
27
|
+
:key_converter,
|
28
|
+
:row_builders,
|
29
|
+
:context
|
33
30
|
|
34
31
|
def initialize(
|
35
32
|
name: self.class.name,
|
@@ -42,20 +39,27 @@ module TableStructure
|
|
42
39
|
**deprecated_options,
|
43
40
|
&block
|
44
41
|
)
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
42
|
+
if deprecated_options.key?(:row_type)
|
43
|
+
raise ::TableStructure::Error, 'Use :row_type option with Table, Writer or Iterator.'
|
44
|
+
end
|
45
|
+
|
46
|
+
if deprecated_options.key?(:result_type)
|
47
|
+
raise ::TableStructure::Error, ':result_type option has been deprecated. Use :row_type option instead.'
|
50
48
|
end
|
51
49
|
|
52
|
-
options =
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
50
|
+
options =
|
51
|
+
[
|
52
|
+
self.class.options,
|
53
|
+
{
|
54
|
+
name_prefix: name_prefix,
|
55
|
+
name_suffix: name_suffix,
|
56
|
+
key_prefix: key_prefix,
|
57
|
+
key_suffix: key_suffix,
|
58
|
+
nil_definitions_ignored: nil_definitions_ignored
|
59
|
+
},
|
60
|
+
deprecated_options
|
61
|
+
]
|
62
|
+
.reduce({}, &:merge!)
|
59
63
|
|
60
64
|
schema_classes = [self.class]
|
61
65
|
|
@@ -63,90 +67,65 @@ module TableStructure
|
|
63
67
|
schema_classes << ::TableStructure::Schema.create_class(&block)
|
64
68
|
end
|
65
69
|
|
66
|
-
context_builders =
|
67
|
-
schema_classes
|
68
|
-
|
70
|
+
@context_builders =
|
71
|
+
schema_classes
|
72
|
+
.map(&:context_builders)
|
73
|
+
.reduce({}, &:merge!)
|
69
74
|
|
70
|
-
|
71
|
-
|
72
|
-
)
|
75
|
+
table_context_builder = @context_builders.delete(:table)
|
76
|
+
|
77
|
+
@context = table_context_builder ? table_context_builder.call(context) : context
|
73
78
|
|
74
|
-
|
75
|
-
schema_classes
|
79
|
+
@column_converters =
|
80
|
+
schema_classes
|
81
|
+
.map(&:column_converters)
|
82
|
+
.reduce({}, &:merge!)
|
83
|
+
.merge(
|
84
|
+
ColumnConverter.create_optional_converters(
|
85
|
+
name_prefix: options.delete(:name_prefix),
|
86
|
+
name_suffix: options.delete(:name_suffix)
|
87
|
+
)
|
88
|
+
)
|
89
|
+
|
90
|
+
@key_converter = KeyConverter.new(
|
91
|
+
prefix: options.delete(:key_prefix),
|
92
|
+
suffix: options.delete(:key_suffix)
|
76
93
|
)
|
77
94
|
|
78
|
-
|
95
|
+
@row_builders =
|
96
|
+
RowBuilder.prepend_default_builders(
|
97
|
+
schema_classes
|
98
|
+
.map(&:row_builders)
|
99
|
+
.reduce({}, &:merge!)
|
100
|
+
)
|
79
101
|
|
80
|
-
columns =
|
102
|
+
@columns =
|
81
103
|
Definition::Columns::Compiler
|
82
104
|
.new(
|
83
105
|
name,
|
84
106
|
schema_classes.map(&:column_definitions).reduce([], &:concat),
|
85
|
-
options
|
107
|
+
{ nil_definitions_ignored: options.delete(:nil_definitions_ignored) }
|
86
108
|
)
|
87
|
-
.compile(
|
109
|
+
.compile(@context)
|
88
110
|
|
89
|
-
@
|
90
|
-
MyDefinition.new(
|
91
|
-
name,
|
92
|
-
columns,
|
93
|
-
context_builders,
|
94
|
-
column_converters,
|
95
|
-
row_builders,
|
96
|
-
table_context,
|
97
|
-
options
|
98
|
-
)
|
111
|
+
@options = options
|
99
112
|
end
|
100
113
|
|
101
|
-
def create_table(row_type: :array, **deprecated_options)
|
102
|
-
|
114
|
+
def create_table(row_type: :array, **deprecated_options, &block)
|
115
|
+
warn '[TableStructure] `TableStructure::Schema#create_table` has been deprecated. Use `TableStructure::Table.new` instead.'
|
116
|
+
|
117
|
+
options = @options.merge(deprecated_options)
|
103
118
|
|
104
119
|
if options.key?(:result_type)
|
105
120
|
warn '[TableStructure] `:result_type` option has been deprecated. Use `:row_type` option instead.'
|
106
121
|
options[:row_type] = options[:result_type]
|
107
122
|
end
|
108
123
|
|
109
|
-
|
110
|
-
|
111
|
-
suffix: options[:key_suffix]
|
112
|
-
}
|
113
|
-
|
114
|
-
keys_generator = KeysGenerator.new(
|
115
|
-
**keys_generator_options
|
116
|
-
)
|
117
|
-
|
118
|
-
table = Table.new(
|
119
|
-
columns: @_definition_.columns,
|
120
|
-
context: @_definition_.context,
|
121
|
-
keys_generator: keys_generator
|
122
|
-
)
|
123
|
-
|
124
|
-
@_definition_
|
125
|
-
.context_builders
|
126
|
-
.extend_methods_for(table)
|
127
|
-
|
128
|
-
column_converters_options = {
|
129
|
-
name_prefix: options[:name_prefix],
|
130
|
-
name_suffix: options[:name_suffix]
|
131
|
-
}
|
132
|
-
|
133
|
-
@_definition_
|
134
|
-
.column_converters
|
135
|
-
.extend_methods_for(table, **column_converters_options)
|
136
|
-
|
137
|
-
row_builders_options = {
|
138
|
-
row_type: options[:row_type] || row_type
|
139
|
-
}
|
140
|
-
|
141
|
-
@_definition_
|
142
|
-
.row_builders
|
143
|
-
.extend_methods_for(table, **row_builders_options)
|
124
|
+
::TableStructure::Table.new(self, row_type: options[:row_type] || row_type, &block)
|
125
|
+
end
|
144
126
|
|
145
|
-
|
146
|
-
|
147
|
-
else
|
148
|
-
table
|
149
|
-
end
|
127
|
+
def contain_callable?(attribute)
|
128
|
+
@columns.any? { |column| column.contain_callable?(attribute) }
|
150
129
|
end
|
151
130
|
end
|
152
131
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TableStructure
|
4
|
+
module Schema
|
5
|
+
module ColumnConverter
|
6
|
+
class << self
|
7
|
+
def create_optional_converters(
|
8
|
+
name_prefix: nil,
|
9
|
+
name_suffix: nil
|
10
|
+
)
|
11
|
+
column_converters = {}
|
12
|
+
|
13
|
+
if name_prefix
|
14
|
+
column_converters[:_name_prepender_] =
|
15
|
+
create_prepender(name_prefix, header: true, body: false)
|
16
|
+
end
|
17
|
+
|
18
|
+
if name_suffix
|
19
|
+
column_converters[:_name_appender_] =
|
20
|
+
create_appender(name_suffix, header: true, body: false)
|
21
|
+
end
|
22
|
+
|
23
|
+
column_converters
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def create_prepender(string, **options)
|
29
|
+
Definition::ColumnConverter.new(
|
30
|
+
lambda { |val, *|
|
31
|
+
val.nil? ? val : "#{string}#{val}"
|
32
|
+
},
|
33
|
+
**options
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
def create_appender(string, **options)
|
38
|
+
Definition::ColumnConverter.new(
|
39
|
+
lambda { |val, *|
|
40
|
+
val.nil? ? val : "#{val}#{string}"
|
41
|
+
},
|
42
|
+
**options
|
43
|
+
)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -5,7 +5,8 @@ module TableStructure
|
|
5
5
|
module Columns
|
6
6
|
class Schema
|
7
7
|
def initialize(schema)
|
8
|
-
@
|
8
|
+
@schema = schema
|
9
|
+
@table = ::TableStructure::Table.new(schema)
|
9
10
|
end
|
10
11
|
|
11
12
|
def names(header_context, _table_context)
|
@@ -25,7 +26,7 @@ module TableStructure
|
|
25
26
|
end
|
26
27
|
|
27
28
|
def contain_callable?(attribute)
|
28
|
-
@
|
29
|
+
@schema.contain_callable?(attribute)
|
29
30
|
end
|
30
31
|
end
|
31
32
|
end
|
@@ -2,13 +2,13 @@
|
|
2
2
|
|
3
3
|
module TableStructure
|
4
4
|
module Schema
|
5
|
-
class
|
5
|
+
class KeyConverter
|
6
6
|
def initialize(prefix: nil, suffix: nil)
|
7
7
|
@prefix = prefix
|
8
8
|
@suffix = suffix
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
11
|
+
def convert(keys)
|
12
12
|
return keys unless has_any_options?
|
13
13
|
|
14
14
|
keys.map do |key|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TableStructure
|
4
|
+
module Schema
|
5
|
+
module RowBuilder
|
6
|
+
DEFAULT_ROW_BUILDERS = {
|
7
|
+
_to_hash_: Definition::RowBuilder.new(
|
8
|
+
lambda { |values, keys, *|
|
9
|
+
keys.map.with_index { |key, i| [key || i, values[i]] }.to_h
|
10
|
+
},
|
11
|
+
enabled_row_types: [:hash]
|
12
|
+
)
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def prepend_default_builders(builders)
|
17
|
+
DEFAULT_ROW_BUILDERS.merge(builders)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TableStructure
|
4
|
+
class Table
|
5
|
+
def initialize(schema, row_type: :array)
|
6
|
+
@columns = schema.columns
|
7
|
+
@context = schema.context
|
8
|
+
@key_converter = schema.key_converter
|
9
|
+
|
10
|
+
ContextBuilder.create_module(
|
11
|
+
schema.context_builders,
|
12
|
+
apply_to_name: schema.contain_callable?(:name),
|
13
|
+
apply_to_value: schema.contain_callable?(:value),
|
14
|
+
context: schema.context
|
15
|
+
) { |mod| extend mod }
|
16
|
+
|
17
|
+
ColumnConverter.create_module(
|
18
|
+
schema.column_converters,
|
19
|
+
context: schema.context
|
20
|
+
) { |mod| extend mod }
|
21
|
+
|
22
|
+
RowBuilder.create_module(
|
23
|
+
schema.row_builders,
|
24
|
+
row_type: row_type,
|
25
|
+
keys: keys,
|
26
|
+
context: schema.context
|
27
|
+
) { |mod| extend mod }
|
28
|
+
|
29
|
+
yield self if block_given?
|
30
|
+
end
|
31
|
+
|
32
|
+
def header(context: nil)
|
33
|
+
row_values(:names, context)
|
34
|
+
end
|
35
|
+
|
36
|
+
def body(items)
|
37
|
+
Enumerator.new do |y|
|
38
|
+
items.each { |item| y << data(context: item) }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def rows(items)
|
43
|
+
warn '[TableStructure] `TableStructure::Table#rows(items)` has been deprecated. Use `TableStructure::Table#body(items)` instead.'
|
44
|
+
body(items)
|
45
|
+
end
|
46
|
+
|
47
|
+
def row(context: nil)
|
48
|
+
warn '[TableStructure] `TableStructure::Table#row(context: ...)` has been deprecated. Use `TableStructure::Table#body(items)` instead.'
|
49
|
+
data(context: context)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def data(context: nil)
|
55
|
+
row_values(:values, context)
|
56
|
+
end
|
57
|
+
|
58
|
+
def keys
|
59
|
+
@keys ||= @key_converter.convert(@columns.map(&:keys).flatten)
|
60
|
+
end
|
61
|
+
|
62
|
+
def size
|
63
|
+
@size ||= @columns.map(&:size).reduce(0, &:+)
|
64
|
+
end
|
65
|
+
|
66
|
+
def row_values(method, context)
|
67
|
+
@columns
|
68
|
+
.map { |column| column.send(method, context, @context) }
|
69
|
+
.flatten
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TableStructure
|
4
|
+
class Table::ColumnConverter
|
5
|
+
class ColumnConvertible < Module
|
6
|
+
def initialize(methods)
|
7
|
+
methods.each do |name, method|
|
8
|
+
define_method(name, &method)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def create_module(converters, context:)
|
15
|
+
return if converters.empty?
|
16
|
+
|
17
|
+
header_converters = converters.select { |_k, v| v.applicable_to_header? }
|
18
|
+
body_converters = converters.select { |_k, v| v.applicable_to_body? }
|
19
|
+
|
20
|
+
methods = {}
|
21
|
+
|
22
|
+
unless header_converters.empty?
|
23
|
+
methods[:header] = create_method(header_converters, context)
|
24
|
+
end
|
25
|
+
|
26
|
+
unless body_converters.empty?
|
27
|
+
methods[:data] = create_method(body_converters, context)
|
28
|
+
end
|
29
|
+
|
30
|
+
yield ColumnConvertible.new(methods)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def create_method(converters, table_context)
|
36
|
+
proc do |context: nil|
|
37
|
+
super(context: context).map do |val|
|
38
|
+
converters.reduce(val) do |val, (_, converter)|
|
39
|
+
converter.call(val, context, table_context)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TableStructure
|
4
|
+
class Table::ContextBuilder
|
5
|
+
class ContextBuildable < Module
|
6
|
+
def initialize(methods)
|
7
|
+
methods.each do |name, method|
|
8
|
+
define_method(name, &method)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def create_module(
|
15
|
+
builders,
|
16
|
+
apply_to_name: true,
|
17
|
+
apply_to_value: true,
|
18
|
+
context:
|
19
|
+
)
|
20
|
+
return if builders.empty?
|
21
|
+
|
22
|
+
header_builder = builders[:header] # will remove
|
23
|
+
row_builder = builders[:row]
|
24
|
+
|
25
|
+
methods = {}
|
26
|
+
|
27
|
+
if apply_to_name && builders.key?(:header)
|
28
|
+
methods[:header] = create_method(builders[:header])
|
29
|
+
end
|
30
|
+
|
31
|
+
if apply_to_value && builders.key?(:row)
|
32
|
+
methods[:data] = create_method(builders[:row])
|
33
|
+
end
|
34
|
+
|
35
|
+
yield ContextBuildable.new(methods)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def create_method(builder)
|
41
|
+
return if builder.nil?
|
42
|
+
|
43
|
+
proc do |context: nil|
|
44
|
+
super(context: builder.call(context))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -1,23 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module TableStructure
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
end
|
4
|
+
class Table::Iterator
|
5
|
+
def initialize(table, header: { context: nil })
|
6
|
+
@table = table
|
7
|
+
@header_options = header
|
8
|
+
end
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
17
|
-
@table
|
18
|
-
.body(items)
|
19
|
-
.each { |row| y << row }
|
10
|
+
def iterate(items)
|
11
|
+
::Enumerator.new do |y|
|
12
|
+
if @header_options
|
13
|
+
header_context = @header_options.is_a?(Hash) ? @header_options[:context] : nil
|
14
|
+
y << @table.header(context: header_context)
|
20
15
|
end
|
16
|
+
@table
|
17
|
+
.body(items)
|
18
|
+
.each { |row| y << row }
|
21
19
|
end
|
22
20
|
end
|
23
21
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TableStructure
|
4
|
+
class Table::RowBuilder
|
5
|
+
class ResultBuildable < Module
|
6
|
+
def initialize(methods)
|
7
|
+
methods.each do |name, method|
|
8
|
+
define_method(name, &method)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def create_module(builders, row_type:, keys:, context:)
|
15
|
+
return if builders.empty?
|
16
|
+
|
17
|
+
builders = builders.select { |_k, v| v.enabled?(row_type) }
|
18
|
+
return if builders.empty?
|
19
|
+
|
20
|
+
yield ResultBuildable.new(
|
21
|
+
header: create_method(builders, keys, context),
|
22
|
+
data: create_method(builders, keys, context)
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def create_method(builders, table_keys, table_context)
|
29
|
+
proc do |context: nil|
|
30
|
+
builders
|
31
|
+
.reduce(super(context: context)) do |vals, (_, builder)|
|
32
|
+
builder.call(vals, table_keys, context, table_context)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -46,7 +46,7 @@ module TableStructure
|
|
46
46
|
|
47
47
|
if deprecated_options.key?(:header)
|
48
48
|
header = deprecated_options[:header]
|
49
|
-
warn '[TableStructure]
|
49
|
+
warn '[TableStructure] Use :header option on initialize method.'
|
50
50
|
end
|
51
51
|
|
52
52
|
if deprecated_options.key?(:header_omitted)
|
@@ -63,7 +63,7 @@ module TableStructure
|
|
63
63
|
|
64
64
|
if deprecated_options.key?(:row_type)
|
65
65
|
row_type = deprecated_options[:row_type]
|
66
|
-
warn '[TableStructure]
|
66
|
+
warn '[TableStructure] Use :row_type option on initialize method.'
|
67
67
|
end
|
68
68
|
|
69
69
|
if deprecated_options.key?(:result_type)
|
@@ -71,28 +71,13 @@ module TableStructure
|
|
71
71
|
row_type = deprecated_options[:result_type]
|
72
72
|
end
|
73
73
|
|
74
|
-
|
74
|
+
output = Output.new(to, method: method)
|
75
75
|
|
76
|
-
|
77
|
-
|
76
|
+
Iterator
|
77
|
+
.new(@schema, header: header, row_type: row_type)
|
78
|
+
.iterate(items, &block)
|
79
|
+
.each { |row| output.write(row) }
|
78
80
|
|
79
|
-
enum =
|
80
|
-
Table::Iterator
|
81
|
-
.new(
|
82
|
-
table,
|
83
|
-
header: header
|
84
|
-
)
|
85
|
-
.iterate(items)
|
86
|
-
|
87
|
-
if block_given?
|
88
|
-
enum =
|
89
|
-
enum
|
90
|
-
.lazy
|
91
|
-
.map { |row| block.call(row) }
|
92
|
-
end
|
93
|
-
|
94
|
-
enum.each { |row| output.write(row) }
|
95
|
-
end
|
96
81
|
nil
|
97
82
|
end
|
98
83
|
|
@@ -108,16 +93,5 @@ module TableStructure
|
|
108
93
|
@output.send(@method, values)
|
109
94
|
end
|
110
95
|
end
|
111
|
-
|
112
|
-
def enumerize(items)
|
113
|
-
if items.respond_to?(:each)
|
114
|
-
items
|
115
|
-
elsif items.respond_to?(:call)
|
116
|
-
warn "[TableStructure] Use `Enumerator` to wrap items instead of `lambda`. The use of `lambda` has been deprecated. #{items}"
|
117
|
-
Enumerator.new { |y| items.call(y) }
|
118
|
-
else
|
119
|
-
raise ::TableStructure::Error, "Must be enumerable. #{items}"
|
120
|
-
end
|
121
|
-
end
|
122
96
|
end
|
123
97
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: table_structure
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jsmmr
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-03-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -75,10 +75,9 @@ files:
|
|
75
75
|
- lib/table_structure/iterator.rb
|
76
76
|
- lib/table_structure/schema.rb
|
77
77
|
- lib/table_structure/schema/class_methods.rb
|
78
|
-
- lib/table_structure/schema/
|
78
|
+
- lib/table_structure/schema/column_converter.rb
|
79
79
|
- lib/table_structure/schema/columns/attributes.rb
|
80
80
|
- lib/table_structure/schema/columns/schema.rb
|
81
|
-
- lib/table_structure/schema/context_builders.rb
|
82
81
|
- lib/table_structure/schema/definition/column_converter.rb
|
83
82
|
- lib/table_structure/schema/definition/columns/attributes.rb
|
84
83
|
- lib/table_structure/schema/definition/columns/compiler.rb
|
@@ -93,11 +92,14 @@ files:
|
|
93
92
|
- lib/table_structure/schema/dsl/context_builder.rb
|
94
93
|
- lib/table_structure/schema/dsl/option.rb
|
95
94
|
- lib/table_structure/schema/dsl/row_builder.rb
|
96
|
-
- lib/table_structure/schema/
|
97
|
-
- lib/table_structure/schema/
|
98
|
-
- lib/table_structure/schema/table.rb
|
95
|
+
- lib/table_structure/schema/key_converter.rb
|
96
|
+
- lib/table_structure/schema/row_builder.rb
|
99
97
|
- lib/table_structure/schema/utils.rb
|
98
|
+
- lib/table_structure/table.rb
|
99
|
+
- lib/table_structure/table/column_converter.rb
|
100
|
+
- lib/table_structure/table/context_builder.rb
|
100
101
|
- lib/table_structure/table/iterator.rb
|
102
|
+
- lib/table_structure/table/row_builder.rb
|
101
103
|
- lib/table_structure/version.rb
|
102
104
|
- lib/table_structure/writer.rb
|
103
105
|
- table_structure.gemspec
|
@@ -1,83 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module TableStructure
|
4
|
-
module Schema
|
5
|
-
class ColumnConverters
|
6
|
-
def initialize(converters)
|
7
|
-
@header_converters = converters.select { |_k, v| v.applicable_to_header? }
|
8
|
-
@body_converterss = converters.select { |_k, v| v.applicable_to_body? }
|
9
|
-
end
|
10
|
-
|
11
|
-
def extend_methods_for(table, name_prefix:, name_suffix:)
|
12
|
-
table_context = table.instance_variable_get(:@context)
|
13
|
-
|
14
|
-
header_converters =
|
15
|
-
@header_converters
|
16
|
-
.merge(
|
17
|
-
_prepend_prefix_: create_prepender(name_prefix),
|
18
|
-
_append_suffix_: create_appender(name_suffix)
|
19
|
-
)
|
20
|
-
.reject { |_k, v| v.nil? }
|
21
|
-
|
22
|
-
body_converterss = @body_converterss
|
23
|
-
|
24
|
-
methods =
|
25
|
-
{
|
26
|
-
header: create_method(header_converters, table_context),
|
27
|
-
data: create_method(body_converterss, table_context)
|
28
|
-
}
|
29
|
-
.reject { |_k, v| v.nil? }
|
30
|
-
|
31
|
-
return if methods.empty?
|
32
|
-
|
33
|
-
table.extend ColumnConvertible.new(methods)
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
def create_prepender(prefix)
|
39
|
-
return unless prefix
|
40
|
-
|
41
|
-
Definition::ColumnConverter.new(
|
42
|
-
lambda { |val, *|
|
43
|
-
val.nil? ? val : "#{prefix}#{val}"
|
44
|
-
},
|
45
|
-
header: true,
|
46
|
-
body: false
|
47
|
-
)
|
48
|
-
end
|
49
|
-
|
50
|
-
def create_appender(suffix)
|
51
|
-
return unless suffix
|
52
|
-
|
53
|
-
Definition::ColumnConverter.new(
|
54
|
-
lambda { |val, *|
|
55
|
-
val.nil? ? val : "#{val}#{suffix}"
|
56
|
-
},
|
57
|
-
header: true,
|
58
|
-
body: false
|
59
|
-
)
|
60
|
-
end
|
61
|
-
|
62
|
-
def create_method(converters, table_context)
|
63
|
-
return if converters.empty?
|
64
|
-
|
65
|
-
proc do |context: nil|
|
66
|
-
super(context: context).map do |val|
|
67
|
-
converters.reduce(val) do |val, (_, converter)|
|
68
|
-
converter.call(val, context, table_context)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
class ColumnConvertible < Module
|
76
|
-
def initialize(methods)
|
77
|
-
methods.each do |name, method|
|
78
|
-
define_method(name, &method)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module TableStructure
|
4
|
-
module Schema
|
5
|
-
class ContextBuilders
|
6
|
-
def initialize(builders)
|
7
|
-
@table_builder = builders[:table]
|
8
|
-
@header_builder = builders[:header]
|
9
|
-
@row_builder = builders[:row]
|
10
|
-
end
|
11
|
-
|
12
|
-
def build_for_table(context)
|
13
|
-
if @table_builder
|
14
|
-
@table_builder.call(context)
|
15
|
-
else
|
16
|
-
context
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def extend_methods_for(table)
|
21
|
-
methods = {}
|
22
|
-
|
23
|
-
if table.send(:contain_callable?, :name)
|
24
|
-
methods[:header] = create_method(@header_builder)
|
25
|
-
end
|
26
|
-
if table.send(:contain_callable?, :value)
|
27
|
-
methods[:data] = create_method(@row_builder)
|
28
|
-
end
|
29
|
-
|
30
|
-
methods.reject! { |_k, v| v.nil? }
|
31
|
-
return if methods.empty?
|
32
|
-
|
33
|
-
table.extend ContextBuildable.new(methods)
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
def create_method(builder)
|
39
|
-
return if builder.nil?
|
40
|
-
|
41
|
-
proc do |context: nil|
|
42
|
-
super(context: builder.call(context))
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
class ContextBuildable < Module
|
48
|
-
def initialize(methods)
|
49
|
-
methods.each do |name, method|
|
50
|
-
define_method(name, &method)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
@@ -1,58 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module TableStructure
|
4
|
-
module Schema
|
5
|
-
class RowBuilders
|
6
|
-
DEFAULT_BUILDERS = {
|
7
|
-
_to_hash_: ::TableStructure::Schema::Definition::RowBuilder.new(
|
8
|
-
lambda { |values, keys, *|
|
9
|
-
keys.map.with_index { |key, i| [key || i, values[i]] }.to_h
|
10
|
-
},
|
11
|
-
enabled_row_types: [:hash]
|
12
|
-
)
|
13
|
-
}.freeze
|
14
|
-
|
15
|
-
def initialize(builders)
|
16
|
-
@builders = builders
|
17
|
-
end
|
18
|
-
|
19
|
-
def extend_methods_for(table, row_type: :array)
|
20
|
-
builders =
|
21
|
-
DEFAULT_BUILDERS
|
22
|
-
.merge(@builders)
|
23
|
-
.select { |_k, v| v.enabled?(row_type) }
|
24
|
-
|
25
|
-
return if builders.empty?
|
26
|
-
|
27
|
-
table_context = table.instance_variable_get(:@context)
|
28
|
-
table_keys = table.send(:keys)
|
29
|
-
|
30
|
-
table.extend ResultBuildable.new(
|
31
|
-
header: create_method(builders, table_keys, table_context),
|
32
|
-
data: create_method(builders, table_keys, table_context)
|
33
|
-
)
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
def create_method(builders, table_keys, table_context)
|
39
|
-
return if builders.empty?
|
40
|
-
|
41
|
-
proc do |context: nil|
|
42
|
-
builders
|
43
|
-
.reduce(super(context: context)) do |vals, (_, builder)|
|
44
|
-
builder.call(vals, table_keys, context, table_context)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
class ResultBuildable < Module
|
51
|
-
def initialize(methods)
|
52
|
-
methods.each do |name, method|
|
53
|
-
define_method(name, &method)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
@@ -1,61 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module TableStructure
|
4
|
-
module Schema
|
5
|
-
class Table
|
6
|
-
def initialize(
|
7
|
-
columns:,
|
8
|
-
context:,
|
9
|
-
keys_generator:
|
10
|
-
)
|
11
|
-
@columns = columns
|
12
|
-
@context = context
|
13
|
-
@keys_generator = keys_generator
|
14
|
-
end
|
15
|
-
|
16
|
-
def header(context: nil)
|
17
|
-
row_values(:names, context)
|
18
|
-
end
|
19
|
-
|
20
|
-
def row(context: nil)
|
21
|
-
warn '[TableStructure] `TableStructure::Schema::Table#row(context:)` has been deprecated. Use `TableStructure::Schema::Table#body(items)` instead.'
|
22
|
-
data(context: context)
|
23
|
-
end
|
24
|
-
|
25
|
-
def body(items)
|
26
|
-
Enumerator.new do |y|
|
27
|
-
items.each { |item| y << data(context: item) }
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def rows(items)
|
32
|
-
warn '[TableStructure] `TableStructure::Schema::Table#rows(items)` has been deprecated. Use `TableStructure::Schema::Table#body(items)` instead.'
|
33
|
-
body(items)
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
def data(context: nil)
|
39
|
-
row_values(:values, context)
|
40
|
-
end
|
41
|
-
|
42
|
-
def keys
|
43
|
-
@keys ||= @keys_generator.generate(@columns.map(&:keys).flatten)
|
44
|
-
end
|
45
|
-
|
46
|
-
def size
|
47
|
-
@size ||= @columns.map(&:size).reduce(0, &:+)
|
48
|
-
end
|
49
|
-
|
50
|
-
def row_values(method, context)
|
51
|
-
@columns
|
52
|
-
.map { |column| column.send(method, context, @context) }
|
53
|
-
.flatten
|
54
|
-
end
|
55
|
-
|
56
|
-
def contain_callable?(attribute)
|
57
|
-
@columns.any? { |column| column.contain_callable?(attribute) }
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|