table_structure 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/CHANGELOG.md +10 -0
- data/Gemfile.lock +7 -7
- data/README.md +3 -3
- data/lib/table_structure.rb +6 -10
- data/lib/table_structure/iterator.rb +13 -4
- data/lib/table_structure/schema.rb +67 -41
- data/lib/table_structure/schema/class_methods.rb +2 -2
- data/lib/table_structure/schema/column_builder_factory.rb +75 -0
- data/lib/table_structure/schema/columns/attributes.rb +14 -9
- data/lib/table_structure/schema/columns/schema.rb +14 -9
- data/lib/table_structure/schema/composite_class.rb +40 -0
- data/lib/table_structure/schema/definition/columns/compiler.rb +7 -3
- data/lib/table_structure/schema/definition/columns/validator.rb +2 -6
- data/lib/table_structure/schema/dsl/column_builder.rb +29 -0
- data/lib/table_structure/schema/dsl/context_builder.rb +1 -4
- data/lib/table_structure/schema/dsl/row_builder.rb +2 -2
- data/lib/table_structure/schema/{key_converter.rb → keys_builder.rb} +2 -2
- data/lib/table_structure/schema/row_context_builder_factory.rb +30 -0
- data/lib/table_structure/table.rb +31 -46
- data/lib/table_structure/utils.rb +40 -0
- data/lib/table_structure/version.rb +1 -1
- data/lib/table_structure/writer.rb +0 -2
- metadata +8 -12
- data/lib/table_structure/schema/column_converter.rb +0 -46
- data/lib/table_structure/schema/definition/column_converter.rb +0 -31
- data/lib/table_structure/schema/definition/context_builder.rb +0 -17
- data/lib/table_structure/schema/definition/row_builder.rb +0 -25
- data/lib/table_structure/schema/dsl/column_converter.rb +0 -28
- data/lib/table_structure/schema/row_builder.rb +0 -21
- data/lib/table_structure/table/column_converter.rb +0 -46
- data/lib/table_structure/table/context_builder.rb +0 -49
- data/lib/table_structure/table/row_builder.rb +0 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 06f36abaa1bc4478901ea51a27e0e22b00ecf70ecbfd18b4c785c2e86e08ca1d
|
4
|
+
data.tar.gz: 26990e2f8ac30764a3d571dbf8a35e422ce163989f9eda5e92aa3c2b9e5cf498
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 288ea6944e5efa303a3c39e4502dce7b0d2994504796a7de0b69b28d8b0cd91f878670db9846a51cbb57d16797bb8124e50f2162db00ec89b49d83de3a345030
|
7
|
+
data.tar.gz: 72d983aef1de40282befe38d230806b1fb3deec4ecf08801822867d43ea656a6a307ad53c46ae87f2661bcc90ef5c6f0b3d8c5ea515eb80ddeb78e559b552585
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
# 0.4.2
|
2
|
+
Changes:
|
3
|
+
- `TableStructure::Schema`
|
4
|
+
- Improve performance.
|
5
|
+
- `TableStructure::Iterator`
|
6
|
+
- `TableStructure::Writer`
|
7
|
+
- `TableStructure::CSV::Writer`
|
8
|
+
- Add validation for `header: { step: n }` option.
|
9
|
+
- `n` is allowed positive number or `nil`(default).
|
10
|
+
|
1
11
|
# 0.4.1
|
2
12
|
Changes:
|
3
13
|
- `TableStructure::Iterator`
|
data/Gemfile.lock
CHANGED
@@ -1,26 +1,26 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
table_structure (0.4.
|
4
|
+
table_structure (0.4.2)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
-
diff-lcs (1.
|
9
|
+
diff-lcs (1.4.4)
|
10
10
|
rake (13.0.1)
|
11
11
|
rspec (3.9.0)
|
12
12
|
rspec-core (~> 3.9.0)
|
13
13
|
rspec-expectations (~> 3.9.0)
|
14
14
|
rspec-mocks (~> 3.9.0)
|
15
|
-
rspec-core (3.9.
|
16
|
-
rspec-support (~> 3.9.
|
17
|
-
rspec-expectations (3.9.
|
15
|
+
rspec-core (3.9.2)
|
16
|
+
rspec-support (~> 3.9.3)
|
17
|
+
rspec-expectations (3.9.2)
|
18
18
|
diff-lcs (>= 1.2.0, < 2.0)
|
19
19
|
rspec-support (~> 3.9.0)
|
20
20
|
rspec-mocks (3.9.1)
|
21
21
|
diff-lcs (>= 1.2.0, < 2.0)
|
22
22
|
rspec-support (~> 3.9.0)
|
23
|
-
rspec-support (3.9.
|
23
|
+
rspec-support (3.9.3)
|
24
24
|
|
25
25
|
PLATFORMS
|
26
26
|
ruby
|
@@ -32,4 +32,4 @@ DEPENDENCIES
|
|
32
32
|
table_structure!
|
33
33
|
|
34
34
|
BUNDLED WITH
|
35
|
-
2.1.
|
35
|
+
2.1.4
|
data/README.md
CHANGED
@@ -106,10 +106,10 @@ items = [
|
|
106
106
|
## or
|
107
107
|
# items = Enumerator.new { |y| Item.find_each { |item| y << item } }
|
108
108
|
|
109
|
-
|
110
|
-
writer.write(items, to:
|
109
|
+
array = []
|
110
|
+
writer.write(items, to: array)
|
111
111
|
|
112
|
-
#
|
112
|
+
# array
|
113
113
|
# => [["ID", "Name", "Pet 1", "Pet 2", "Pet 3", "Q1", "Q2", "Q3"], ["1", "Taro", "🐱", "🐶", "", "⭕️", "❌", "⭕️"], ["2", "Hanako", "🐇", "🐢", "🐿", "⭕️", "⭕️", "❌"]]
|
114
114
|
```
|
115
115
|
|
data/lib/table_structure.rb
CHANGED
@@ -5,31 +5,27 @@ module TableStructure
|
|
5
5
|
|
6
6
|
require 'table_structure/version'
|
7
7
|
require 'forwardable'
|
8
|
+
require 'table_structure/utils'
|
8
9
|
require 'table_structure/schema'
|
9
10
|
require 'table_structure/schema/class_methods'
|
10
|
-
require 'table_structure/schema/
|
11
|
+
require 'table_structure/schema/composite_class'
|
12
|
+
require 'table_structure/schema/dsl/column_builder'
|
11
13
|
require 'table_structure/schema/dsl/column_definition'
|
12
14
|
require 'table_structure/schema/dsl/context_builder'
|
13
15
|
require 'table_structure/schema/dsl/row_builder'
|
14
|
-
require 'table_structure/schema/definition/column_converter'
|
15
|
-
require 'table_structure/schema/definition/context_builder'
|
16
|
-
require 'table_structure/schema/definition/row_builder'
|
17
16
|
require 'table_structure/schema/definition/columns/compiler'
|
18
17
|
require 'table_structure/schema/definition/columns/error'
|
19
18
|
require 'table_structure/schema/definition/columns/validator'
|
20
19
|
require 'table_structure/schema/definition/columns/attributes'
|
21
20
|
require 'table_structure/schema/definition/columns/schema_class'
|
22
21
|
require 'table_structure/schema/definition/columns/schema_instance'
|
23
|
-
require 'table_structure/schema/
|
24
|
-
require 'table_structure/schema/
|
25
|
-
require 'table_structure/schema/
|
22
|
+
require 'table_structure/schema/column_builder_factory'
|
23
|
+
require 'table_structure/schema/keys_builder'
|
24
|
+
require 'table_structure/schema/row_context_builder_factory'
|
26
25
|
require 'table_structure/schema/columns/attributes'
|
27
26
|
require 'table_structure/schema/columns/schema'
|
28
27
|
require 'table_structure/schema/utils'
|
29
28
|
require 'table_structure/table'
|
30
|
-
require 'table_structure/table/column_converter'
|
31
|
-
require 'table_structure/table/context_builder'
|
32
|
-
require 'table_structure/table/row_builder'
|
33
29
|
require 'table_structure/writer'
|
34
30
|
require 'table_structure/csv/writer'
|
35
31
|
require 'table_structure/iterator'
|
@@ -12,6 +12,17 @@ module TableStructure
|
|
12
12
|
@context = options[:context]
|
13
13
|
@step = options[:step]
|
14
14
|
end
|
15
|
+
|
16
|
+
validate
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def validate
|
22
|
+
if @step
|
23
|
+
raise ::TableStructure::Error, ':step must be numeric.' unless @step.is_a?(Numeric)
|
24
|
+
raise ::TableStructure::Error, ':step must be positive number.' unless @step.positive?
|
25
|
+
end
|
15
26
|
end
|
16
27
|
end
|
17
28
|
|
@@ -25,9 +36,7 @@ module TableStructure
|
|
25
36
|
end
|
26
37
|
|
27
38
|
def iterate(items, &block)
|
28
|
-
unless items.respond_to?(:each)
|
29
|
-
raise ::TableStructure::Error, "Must be enumerable. #{items}"
|
30
|
-
end
|
39
|
+
raise ::TableStructure::Error, "Must be enumerable. #{items}" unless items.respond_to?(:each)
|
31
40
|
|
32
41
|
table_enum = ::Enumerator.new do |y|
|
33
42
|
body_enum = @table.body(items)
|
@@ -36,7 +45,7 @@ module TableStructure
|
|
36
45
|
header_row = @table.header(context: @header_options.context)
|
37
46
|
y << header_row
|
38
47
|
|
39
|
-
if @header_options.step
|
48
|
+
if @header_options.step
|
40
49
|
loop do
|
41
50
|
@header_options.step.times { y << body_enum.next }
|
42
51
|
y << header_row
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module TableStructure
|
4
4
|
module Schema
|
5
5
|
def self.included(klass)
|
6
|
-
klass.extend(DSL::
|
6
|
+
klass.extend(DSL::ColumnBuilder)
|
7
7
|
klass.extend(DSL::ColumnDefinition)
|
8
8
|
klass.extend(DSL::ContextBuilder)
|
9
9
|
klass.extend(DSL::RowBuilder)
|
@@ -11,20 +11,17 @@ module TableStructure
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def self.create_class(&block)
|
14
|
-
raise ::TableStructure::Error, 'No block given.' unless block
|
14
|
+
raise ::TableStructure::Error, 'No block has been given.' unless block
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
include schema_module
|
16
|
+
::Class.new do
|
17
|
+
include Schema
|
19
18
|
class_eval(&block)
|
20
19
|
end
|
21
20
|
end
|
22
21
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
:key_converter,
|
27
|
-
:row_builders,
|
22
|
+
Row = ::Struct.new(:keys, :values, :context)
|
23
|
+
|
24
|
+
attr_reader :row_builders,
|
28
25
|
:context
|
29
26
|
|
30
27
|
def initialize(
|
@@ -37,56 +34,85 @@ module TableStructure
|
|
37
34
|
nil_definitions_ignored: false,
|
38
35
|
&block
|
39
36
|
)
|
40
|
-
|
41
|
-
|
42
|
-
if block_given?
|
43
|
-
schema_classes << ::TableStructure::Schema.create_class(&block)
|
44
|
-
end
|
37
|
+
schema_class = CompositeClass.new.compose(self.class)
|
38
|
+
schema_class.compose(Schema.create_class(&block)) if block
|
45
39
|
|
46
|
-
|
47
|
-
schema_classes
|
48
|
-
.map(&:context_builders)
|
49
|
-
.reduce({}, &:merge!)
|
40
|
+
context_builders = schema_class.context_builders
|
50
41
|
|
51
|
-
table_context_builder =
|
42
|
+
table_context_builder = context_builders.delete(:table)
|
52
43
|
|
53
44
|
@context = table_context_builder ? table_context_builder.call(context) : context
|
54
45
|
|
55
|
-
@
|
56
|
-
|
57
|
-
|
58
|
-
.
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
)
|
64
|
-
)
|
46
|
+
@row_context_builder_factory = RowContextBuilderFactory.new(self, context_builders)
|
47
|
+
|
48
|
+
@column_builder_factory = ColumnBuilderFactory.new(
|
49
|
+
schema_class.column_builders,
|
50
|
+
context: @context,
|
51
|
+
name_prefix: name_prefix,
|
52
|
+
name_suffix: name_suffix
|
53
|
+
)
|
65
54
|
|
66
|
-
@
|
55
|
+
@keys_builder = KeysBuilder.new(
|
67
56
|
prefix: key_prefix,
|
68
57
|
suffix: key_suffix
|
69
58
|
)
|
70
59
|
|
71
|
-
@row_builders =
|
72
|
-
RowBuilder.prepend_default_builders(
|
73
|
-
schema_classes
|
74
|
-
.map(&:row_builders)
|
75
|
-
.reduce({}, &:merge!)
|
76
|
-
)
|
60
|
+
@row_builders = schema_class.row_builders
|
77
61
|
|
78
62
|
@columns =
|
79
63
|
Definition::Columns::Compiler
|
80
64
|
.new(
|
81
65
|
name,
|
82
|
-
|
83
|
-
|
66
|
+
schema_class.column_definitions,
|
67
|
+
nil_definitions_ignored: nil_definitions_ignored
|
84
68
|
)
|
85
69
|
.compile(@context)
|
86
70
|
end
|
87
71
|
|
88
|
-
def
|
89
|
-
@
|
72
|
+
def columns_keys
|
73
|
+
@columns_keys ||= @keys_builder.build(@columns.map(&:keys).flatten)
|
74
|
+
end
|
75
|
+
|
76
|
+
def columns_size
|
77
|
+
@columns.map(&:size).reduce(0, &:+)
|
78
|
+
end
|
79
|
+
|
80
|
+
def contain_name_callable?
|
81
|
+
@columns.any? { |column| column.name_callable? }
|
82
|
+
end
|
83
|
+
|
84
|
+
def contain_value_callable?
|
85
|
+
@columns.any? { |column| column.value_callable? }
|
86
|
+
end
|
87
|
+
|
88
|
+
def create_header_row_generator
|
89
|
+
::TableStructure::Utils::CompositeCallable.new.compose(
|
90
|
+
@row_context_builder_factory.create_header_builder,
|
91
|
+
proc do |context|
|
92
|
+
values =
|
93
|
+
@columns
|
94
|
+
.map { |column| column.names(context, @context) }
|
95
|
+
.flatten
|
96
|
+
|
97
|
+
Row.new(columns_keys, values, context)
|
98
|
+
end,
|
99
|
+
@column_builder_factory.create_header_builder
|
100
|
+
)
|
101
|
+
end
|
102
|
+
|
103
|
+
def create_data_row_generator
|
104
|
+
::TableStructure::Utils::CompositeCallable.new.compose(
|
105
|
+
@row_context_builder_factory.create_data_builder,
|
106
|
+
proc do |context|
|
107
|
+
values =
|
108
|
+
@columns
|
109
|
+
.map { |column| column.values(context, @context) }
|
110
|
+
.flatten
|
111
|
+
|
112
|
+
Row.new(columns_keys, values, context)
|
113
|
+
end,
|
114
|
+
@column_builder_factory.create_data_builder
|
115
|
+
)
|
90
116
|
end
|
91
117
|
end
|
92
118
|
end
|
@@ -36,9 +36,9 @@ module TableStructure
|
|
36
36
|
.map(&:context_builders)
|
37
37
|
.reduce({}, &:merge!)
|
38
38
|
|
39
|
-
@
|
39
|
+
@__column_builders__ =
|
40
40
|
schema_classes
|
41
|
-
.map(&:
|
41
|
+
.map(&:column_builders)
|
42
42
|
.reduce({}, &:merge!)
|
43
43
|
|
44
44
|
@__row_builders__ =
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TableStructure
|
4
|
+
module Schema
|
5
|
+
class ColumnBuilderFactory
|
6
|
+
def initialize(
|
7
|
+
builders,
|
8
|
+
context: nil,
|
9
|
+
name_prefix: nil,
|
10
|
+
name_suffix: nil
|
11
|
+
)
|
12
|
+
@builders = builders
|
13
|
+
@context = context
|
14
|
+
|
15
|
+
optional_builders = {}
|
16
|
+
|
17
|
+
if name_prefix
|
18
|
+
optional_builders[:_name_prepender_] =
|
19
|
+
::TableStructure::Utils::TypedProc.new(
|
20
|
+
types: :header
|
21
|
+
) do |val, *|
|
22
|
+
val.nil? ? val : "#{name_prefix}#{val}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
if name_suffix
|
27
|
+
optional_builders[:_name_appender_] =
|
28
|
+
::TableStructure::Utils::TypedProc.new(
|
29
|
+
types: :header
|
30
|
+
) do |val, *|
|
31
|
+
val.nil? ? val : "#{val}#{name_suffix}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
@builders.merge!(optional_builders) unless optional_builders.empty?
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_header_builder
|
39
|
+
builders =
|
40
|
+
@builders
|
41
|
+
.select { |_k, v| v.typed?(:header) }
|
42
|
+
.values
|
43
|
+
|
44
|
+
return if builders.empty?
|
45
|
+
|
46
|
+
proc do |row|
|
47
|
+
row.values = row.values.map do |value|
|
48
|
+
builders.reduce(value) do |value, builder|
|
49
|
+
builder.call(value, row.context, @context)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
row
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def create_data_builder
|
57
|
+
builders =
|
58
|
+
@builders
|
59
|
+
.select { |_k, v| v.typed?(:body) }
|
60
|
+
.values
|
61
|
+
|
62
|
+
return if builders.empty?
|
63
|
+
|
64
|
+
proc do |row|
|
65
|
+
row.values = row.values.map do |value|
|
66
|
+
builders.reduce(value) do |value, builder|
|
67
|
+
builder.call(value, row.context, @context)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
row
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -7,25 +7,30 @@ module TableStructure
|
|
7
7
|
attr_reader :keys, :size
|
8
8
|
|
9
9
|
def initialize(name:, key:, value:, size:)
|
10
|
-
@
|
10
|
+
@name_callable = Utils.callable?(name)
|
11
|
+
@name = @name_callable ? name : proc { name }
|
11
12
|
@keys = optimize_size([key].flatten, size)
|
12
|
-
@
|
13
|
+
@value_callable = Utils.callable?(value)
|
14
|
+
@value = @value_callable ? value : proc { value }
|
13
15
|
@size = size
|
14
16
|
end
|
15
17
|
|
16
18
|
def names(context, table_context)
|
17
|
-
|
18
|
-
optimize_size(
|
19
|
+
names = @name.call(context, table_context)
|
20
|
+
optimize_size(names, @size)
|
19
21
|
end
|
20
22
|
|
21
23
|
def values(context, table_context)
|
22
|
-
|
23
|
-
optimize_size(
|
24
|
+
values = @value.call(context, table_context)
|
25
|
+
optimize_size(values, @size)
|
24
26
|
end
|
25
27
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
28
|
+
def name_callable?
|
29
|
+
@name_callable
|
30
|
+
end
|
31
|
+
|
32
|
+
def value_callable?
|
33
|
+
@value_callable
|
29
34
|
end
|
30
35
|
|
31
36
|
private
|
@@ -6,27 +6,32 @@ module TableStructure
|
|
6
6
|
class Schema
|
7
7
|
def initialize(schema)
|
8
8
|
@schema = schema
|
9
|
-
@
|
9
|
+
@header_row_generator = schema.create_header_row_generator
|
10
|
+
@data_row_generator = schema.create_data_row_generator
|
10
11
|
end
|
11
12
|
|
12
|
-
def names(
|
13
|
-
@
|
13
|
+
def names(row_context, *)
|
14
|
+
@header_row_generator.call(row_context).values
|
14
15
|
end
|
15
16
|
|
16
17
|
def keys
|
17
|
-
@
|
18
|
+
@schema.columns_keys
|
18
19
|
end
|
19
20
|
|
20
|
-
def values(row_context,
|
21
|
-
@
|
21
|
+
def values(row_context, *)
|
22
|
+
@data_row_generator.call(row_context).values
|
22
23
|
end
|
23
24
|
|
24
25
|
def size
|
25
|
-
@
|
26
|
+
@schema.columns_size
|
26
27
|
end
|
27
28
|
|
28
|
-
def
|
29
|
-
@schema.
|
29
|
+
def name_callable?
|
30
|
+
@schema.contain_name_callable?
|
31
|
+
end
|
32
|
+
|
33
|
+
def value_callable?
|
34
|
+
@schema.contain_value_callable?
|
30
35
|
end
|
31
36
|
end
|
32
37
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TableStructure
|
4
|
+
module Schema
|
5
|
+
class CompositeClass
|
6
|
+
def initialize
|
7
|
+
@classes = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def compose(*classes)
|
11
|
+
@classes.concat(classes.flatten.compact)
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
def column_definitions
|
16
|
+
@classes
|
17
|
+
.map(&:column_definitions)
|
18
|
+
.reduce([], &:concat)
|
19
|
+
end
|
20
|
+
|
21
|
+
def context_builders
|
22
|
+
@classes
|
23
|
+
.map(&:context_builders)
|
24
|
+
.reduce({}, &:merge!)
|
25
|
+
end
|
26
|
+
|
27
|
+
def column_builders
|
28
|
+
@classes
|
29
|
+
.map(&:column_builders)
|
30
|
+
.reduce({}, &:merge!)
|
31
|
+
end
|
32
|
+
|
33
|
+
def row_builders
|
34
|
+
@classes
|
35
|
+
.map(&:row_builders)
|
36
|
+
.reduce({}, &:merge!)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -5,10 +5,14 @@ module TableStructure
|
|
5
5
|
module Definition
|
6
6
|
module Columns
|
7
7
|
class Compiler
|
8
|
-
def initialize(
|
8
|
+
def initialize(
|
9
|
+
schema_name,
|
10
|
+
definitions,
|
11
|
+
nil_definitions_ignored: false
|
12
|
+
)
|
9
13
|
@schema_name = schema_name
|
10
14
|
@definitions = definitions
|
11
|
-
@
|
15
|
+
@nil_definitions_ignored = !!nil_definitions_ignored
|
12
16
|
end
|
13
17
|
|
14
18
|
def compile(context = nil)
|
@@ -26,7 +30,7 @@ module TableStructure
|
|
26
30
|
SchemaInstance.new(definition)
|
27
31
|
elsif Utils.schema_class?(definition)
|
28
32
|
SchemaClass.new(definition)
|
29
|
-
elsif definition.nil? && @
|
33
|
+
elsif definition.nil? && @nil_definitions_ignored
|
30
34
|
next
|
31
35
|
else
|
32
36
|
raise Error.new('Invalid definition.', @schema_name, i)
|
@@ -13,15 +13,11 @@ module TableStructure
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def validate(name:, key:, size:, **)
|
16
|
-
if key.respond_to?(:call)
|
17
|
-
raise Error.new('"key" must not be lambda.', @name, @index)
|
18
|
-
end
|
16
|
+
raise Error.new('"key" must not be lambda.', @name, @index) if key.respond_to?(:call)
|
19
17
|
if !key && name.respond_to?(:call) && !size
|
20
18
|
raise Error.new('"size" must be defined, because column size cannot be determined.', @name, @index)
|
21
19
|
end
|
22
|
-
if size && size < DEFAULT_SIZE
|
23
|
-
raise Error.new('"size" must be positive.', @name, @index)
|
24
|
-
end
|
20
|
+
raise Error.new('"size" must be positive.', @name, @index) if size && size < DEFAULT_SIZE
|
25
21
|
if key && size && [key].flatten.size < size
|
26
22
|
raise Error.new('"key" size must not be less than specified "size".', @name, @index)
|
27
23
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TableStructure
|
4
|
+
module Schema
|
5
|
+
module DSL
|
6
|
+
module ColumnBuilder
|
7
|
+
def column_builder(
|
8
|
+
name,
|
9
|
+
header: true,
|
10
|
+
body: true,
|
11
|
+
&block
|
12
|
+
)
|
13
|
+
column_builders[name] =
|
14
|
+
::TableStructure::Utils::TypedProc.new(
|
15
|
+
types: { header: !!header, body: !!body }.select { |_k, v| v }.keys,
|
16
|
+
&block
|
17
|
+
)
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def column_builders
|
22
|
+
@__column_builders__ ||= {}
|
23
|
+
end
|
24
|
+
|
25
|
+
alias column_converter column_builder
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -6,10 +6,7 @@ module TableStructure
|
|
6
6
|
module ContextBuilder
|
7
7
|
# TODO: Change definition style
|
8
8
|
def context_builder(name, &block)
|
9
|
-
context_builders[name] =
|
10
|
-
::TableStructure::Schema::Definition::ContextBuilder.new(
|
11
|
-
&block
|
12
|
-
)
|
9
|
+
context_builders[name] = block
|
13
10
|
nil
|
14
11
|
end
|
15
12
|
|
@@ -2,13 +2,13 @@
|
|
2
2
|
|
3
3
|
module TableStructure
|
4
4
|
module Schema
|
5
|
-
class
|
5
|
+
class KeysBuilder
|
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 build(keys)
|
12
12
|
return keys unless has_any_options?
|
13
13
|
|
14
14
|
keys.map do |key|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TableStructure
|
4
|
+
module Schema
|
5
|
+
class RowContextBuilderFactory
|
6
|
+
def initialize(schema, builders)
|
7
|
+
@schema = schema
|
8
|
+
@builders = builders
|
9
|
+
end
|
10
|
+
|
11
|
+
def create_header_builder
|
12
|
+
return unless @schema.contain_name_callable?
|
13
|
+
return unless @builders.key?(:header)
|
14
|
+
|
15
|
+
proc do |context|
|
16
|
+
@builders[:header].call(context)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def create_data_builder
|
21
|
+
return unless @schema.contain_value_callable?
|
22
|
+
return unless @builders.key?(:row)
|
23
|
+
|
24
|
+
proc do |context|
|
25
|
+
@builders[:row].call(context)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -2,61 +2,46 @@
|
|
2
2
|
|
3
3
|
module TableStructure
|
4
4
|
class Table
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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 }
|
5
|
+
DEFAULT_ROW_BUILDERS = {
|
6
|
+
_to_hash_: Utils::TypedProc.new(
|
7
|
+
types: :hash
|
8
|
+
) do |values, keys, *|
|
9
|
+
keys.map.with_index { |key, i| [key || i, values[i]] }.to_h
|
10
|
+
end
|
11
|
+
}.freeze
|
21
12
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
13
|
+
def initialize(schema, row_type: :array)
|
14
|
+
@header_row_generator = schema.create_header_row_generator
|
15
|
+
@data_row_generator = schema.create_data_row_generator
|
16
|
+
|
17
|
+
row_builders =
|
18
|
+
DEFAULT_ROW_BUILDERS
|
19
|
+
.merge(schema.row_builders)
|
20
|
+
.select { |_k, v| v.typed?(row_type) }
|
21
|
+
.values
|
22
|
+
|
23
|
+
unless row_builders.empty?
|
24
|
+
row_build_task = proc do |row|
|
25
|
+
row.values = row_builders.reduce(row.values) do |values, builder|
|
26
|
+
builder.call(values, row.keys, row.context, schema.context)
|
27
|
+
end
|
28
|
+
row
|
29
|
+
end
|
30
|
+
@header_row_generator.compose(row_build_task)
|
31
|
+
@data_row_generator.compose(row_build_task)
|
32
|
+
end
|
28
33
|
|
29
34
|
yield self if block_given?
|
30
35
|
end
|
31
36
|
|
32
37
|
def header(context: nil)
|
33
|
-
|
38
|
+
@header_row_generator.call(context).values
|
34
39
|
end
|
35
40
|
|
36
|
-
def body(
|
37
|
-
Enumerator.new do |y|
|
38
|
-
|
41
|
+
def body(contexts)
|
42
|
+
::Enumerator.new do |y|
|
43
|
+
contexts.each { |context| y << @data_row_generator.call(context).values }
|
39
44
|
end
|
40
45
|
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def data(context: nil)
|
45
|
-
row_values(:values, context)
|
46
|
-
end
|
47
|
-
|
48
|
-
def keys
|
49
|
-
@keys ||= @key_converter.convert(@columns.map(&:keys).flatten)
|
50
|
-
end
|
51
|
-
|
52
|
-
def size
|
53
|
-
@size ||= @columns.map(&:size).reduce(0, &:+)
|
54
|
-
end
|
55
|
-
|
56
|
-
def row_values(method, context)
|
57
|
-
@columns
|
58
|
-
.map { |column| column.send(method, context, @context) }
|
59
|
-
.flatten
|
60
|
-
end
|
61
46
|
end
|
62
47
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TableStructure
|
4
|
+
module Utils
|
5
|
+
class Proc < ::Proc
|
6
|
+
attr_reader :options
|
7
|
+
|
8
|
+
def initialize(**options, &block)
|
9
|
+
@options = options
|
10
|
+
super(&block)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class TypedProc < Proc
|
15
|
+
def initialize(types:, **options, &block)
|
16
|
+
@types = [types].flatten.compact
|
17
|
+
super(**options, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def typed?(type)
|
21
|
+
@types.include?(type)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class CompositeCallable
|
26
|
+
def initialize
|
27
|
+
@callables = []
|
28
|
+
end
|
29
|
+
|
30
|
+
def compose(*callables)
|
31
|
+
@callables.concat(callables.flatten.compact)
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def call(source)
|
36
|
+
@callables.reduce(source) { |memo, callable| callable.call(memo) }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
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.4.
|
4
|
+
version: 0.4.2
|
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-07-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -75,29 +75,25 @@ 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_builder_factory.rb
|
79
79
|
- lib/table_structure/schema/columns/attributes.rb
|
80
80
|
- lib/table_structure/schema/columns/schema.rb
|
81
|
-
- lib/table_structure/schema/
|
81
|
+
- lib/table_structure/schema/composite_class.rb
|
82
82
|
- lib/table_structure/schema/definition/columns/attributes.rb
|
83
83
|
- lib/table_structure/schema/definition/columns/compiler.rb
|
84
84
|
- lib/table_structure/schema/definition/columns/error.rb
|
85
85
|
- lib/table_structure/schema/definition/columns/schema_class.rb
|
86
86
|
- lib/table_structure/schema/definition/columns/schema_instance.rb
|
87
87
|
- lib/table_structure/schema/definition/columns/validator.rb
|
88
|
-
- lib/table_structure/schema/
|
89
|
-
- lib/table_structure/schema/definition/row_builder.rb
|
90
|
-
- lib/table_structure/schema/dsl/column_converter.rb
|
88
|
+
- lib/table_structure/schema/dsl/column_builder.rb
|
91
89
|
- lib/table_structure/schema/dsl/column_definition.rb
|
92
90
|
- lib/table_structure/schema/dsl/context_builder.rb
|
93
91
|
- lib/table_structure/schema/dsl/row_builder.rb
|
94
|
-
- lib/table_structure/schema/
|
95
|
-
- lib/table_structure/schema/
|
92
|
+
- lib/table_structure/schema/keys_builder.rb
|
93
|
+
- lib/table_structure/schema/row_context_builder_factory.rb
|
96
94
|
- lib/table_structure/schema/utils.rb
|
97
95
|
- lib/table_structure/table.rb
|
98
|
-
- lib/table_structure/
|
99
|
-
- lib/table_structure/table/context_builder.rb
|
100
|
-
- lib/table_structure/table/row_builder.rb
|
96
|
+
- lib/table_structure/utils.rb
|
101
97
|
- lib/table_structure/version.rb
|
102
98
|
- lib/table_structure/writer.rb
|
103
99
|
- table_structure.gemspec
|
@@ -1,46 +0,0 @@
|
|
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
|
-
**options
|
31
|
-
) do |val, *|
|
32
|
-
val.nil? ? val : "#{string}#{val}"
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def create_appender(string, **options)
|
37
|
-
Definition::ColumnConverter.new(
|
38
|
-
**options
|
39
|
-
) do |val, *|
|
40
|
-
val.nil? ? val : "#{val}#{string}"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module TableStructure
|
4
|
-
module Schema
|
5
|
-
module Definition
|
6
|
-
class ColumnConverter
|
7
|
-
extend Forwardable
|
8
|
-
|
9
|
-
def_delegator :@callable, :call
|
10
|
-
|
11
|
-
def initialize(
|
12
|
-
header: true,
|
13
|
-
body: true,
|
14
|
-
&block
|
15
|
-
)
|
16
|
-
@applicable_to_header = header
|
17
|
-
@applicable_to_body = body
|
18
|
-
@callable = block
|
19
|
-
end
|
20
|
-
|
21
|
-
def applicable_to_header?
|
22
|
-
!!@applicable_to_header
|
23
|
-
end
|
24
|
-
|
25
|
-
def applicable_to_body?
|
26
|
-
!!@applicable_to_body
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module TableStructure
|
4
|
-
module Schema
|
5
|
-
module Definition
|
6
|
-
class ContextBuilder
|
7
|
-
extend Forwardable
|
8
|
-
|
9
|
-
def_delegator :@callable, :call
|
10
|
-
|
11
|
-
def initialize(&block)
|
12
|
-
@callable = block
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module TableStructure
|
4
|
-
module Schema
|
5
|
-
module Definition
|
6
|
-
class RowBuilder
|
7
|
-
extend Forwardable
|
8
|
-
|
9
|
-
def_delegator :@callable, :call
|
10
|
-
|
11
|
-
def initialize(
|
12
|
-
enabled_row_types: %i[array hash],
|
13
|
-
&block
|
14
|
-
)
|
15
|
-
@enabled_row_types = [enabled_row_types].flatten
|
16
|
-
@callable = block
|
17
|
-
end
|
18
|
-
|
19
|
-
def enabled?(row_type)
|
20
|
-
@enabled_row_types.include?(row_type)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module TableStructure
|
4
|
-
module Schema
|
5
|
-
module DSL
|
6
|
-
module ColumnConverter
|
7
|
-
def column_converter(
|
8
|
-
name,
|
9
|
-
header: true,
|
10
|
-
body: true,
|
11
|
-
&block
|
12
|
-
)
|
13
|
-
column_converters[name] =
|
14
|
-
::TableStructure::Schema::Definition::ColumnConverter.new(
|
15
|
-
header: header,
|
16
|
-
body: body,
|
17
|
-
&block
|
18
|
-
)
|
19
|
-
nil
|
20
|
-
end
|
21
|
-
|
22
|
-
def column_converters
|
23
|
-
@__column_converters__ ||= {}
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,21 +0,0 @@
|
|
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
|
-
enabled_row_types: [:hash]
|
9
|
-
) do |values, keys, *|
|
10
|
-
keys.map.with_index { |key, i| [key || i, values[i]] }.to_h
|
11
|
-
end
|
12
|
-
}.freeze
|
13
|
-
|
14
|
-
class << self
|
15
|
-
def prepend_default_builders(builders)
|
16
|
-
DEFAULT_ROW_BUILDERS.merge(builders)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,46 +0,0 @@
|
|
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
|
@@ -1,49 +0,0 @@
|
|
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] # TODO: Change not to use keyword of `header`
|
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,38 +0,0 @@
|
|
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
|