table_structure 0.3.20 → 0.3.21
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 +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
|