table_structure 0.3.22 → 0.4.3
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/.travis.yml +1 -1
- data/CHANGELOG.md +33 -0
- data/Gemfile.lock +7 -7
- data/README.md +30 -31
- data/lib/table_structure.rb +6 -12
- data/lib/table_structure/csv/writer.rb +4 -41
- data/lib/table_structure/iterator.rb +48 -89
- data/lib/table_structure/schema.rb +63 -76
- data/lib/table_structure/schema/class_methods.rb +9 -28
- 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/column_definition.rb +12 -2
- data/lib/table_structure/schema/dsl/context_builder.rb +2 -11
- data/lib/table_structure/schema/dsl/row_builder.rb +2 -9
- data/lib/table_structure/schema/{key_converter.rb → keys_builder.rb} +2 -2
- data/lib/table_structure/schema/row_context_builder_factory.rb +26 -0
- data/lib/table_structure/table.rb +31 -56
- data/lib/table_structure/utils.rb +40 -0
- data/lib/table_structure/version.rb +1 -1
- data/lib/table_structure/writer.rb +7 -54
- metadata +8 -14
- 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 -41
- data/lib/table_structure/schema/dsl/option.rb +0 -19
- 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/iterator.rb +0 -22
- data/lib/table_structure/table/row_builder.rb +0 -38
@@ -3,29 +3,25 @@
|
|
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
|
-
klass.extend(DSL::Option)
|
10
9
|
klass.extend(DSL::RowBuilder)
|
11
10
|
klass.extend(ClassMethods)
|
12
11
|
end
|
13
12
|
|
14
13
|
def self.create_class(&block)
|
15
|
-
raise ::TableStructure::Error, 'No block given.' unless block
|
14
|
+
raise ::TableStructure::Error, 'No block has been given.' unless block
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
include schema_module
|
16
|
+
::Class.new do
|
17
|
+
include Schema
|
20
18
|
class_eval(&block)
|
21
19
|
end
|
22
20
|
end
|
23
21
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
:key_converter,
|
28
|
-
:row_builders,
|
22
|
+
Row = ::Struct.new(:keys, :values, :context)
|
23
|
+
|
24
|
+
attr_reader :row_builders,
|
29
25
|
:context
|
30
26
|
|
31
27
|
def initialize(
|
@@ -36,96 +32,87 @@ module TableStructure
|
|
36
32
|
key_prefix: nil,
|
37
33
|
key_suffix: nil,
|
38
34
|
nil_definitions_ignored: false,
|
39
|
-
**deprecated_options,
|
40
35
|
&block
|
41
36
|
)
|
42
|
-
|
43
|
-
|
44
|
-
end
|
37
|
+
schema_class = CompositeClass.new.compose(self.class)
|
38
|
+
schema_class.compose(Schema.create_class(&block)) if block
|
45
39
|
|
46
|
-
|
47
|
-
raise ::TableStructure::Error, ':result_type option has been deprecated. Use :row_type option instead.'
|
48
|
-
end
|
49
|
-
|
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!)
|
63
|
-
|
64
|
-
schema_classes = [self.class]
|
65
|
-
|
66
|
-
if block_given?
|
67
|
-
schema_classes << ::TableStructure::Schema.create_class(&block)
|
68
|
-
end
|
40
|
+
context_builders = schema_class.context_builders
|
69
41
|
|
70
|
-
|
71
|
-
schema_classes
|
72
|
-
.map(&:context_builders)
|
73
|
-
.reduce({}, &:merge!)
|
74
|
-
|
75
|
-
table_context_builder = @context_builders.delete(:table)
|
42
|
+
table_context_builder = context_builders.delete(:table)
|
76
43
|
|
77
44
|
@context = table_context_builder ? table_context_builder.call(context) : context
|
78
45
|
|
79
|
-
@
|
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
|
-
)
|
46
|
+
@row_context_builder_factory = RowContextBuilderFactory.new(self, context_builders)
|
89
47
|
|
90
|
-
@
|
91
|
-
|
92
|
-
|
48
|
+
@column_builder_factory = ColumnBuilderFactory.new(
|
49
|
+
schema_class.column_builders,
|
50
|
+
context: @context,
|
51
|
+
name_prefix: name_prefix,
|
52
|
+
name_suffix: name_suffix
|
93
53
|
)
|
94
54
|
|
95
|
-
@
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
55
|
+
@keys_builder = KeysBuilder.new(
|
56
|
+
prefix: key_prefix,
|
57
|
+
suffix: key_suffix
|
58
|
+
)
|
59
|
+
|
60
|
+
@row_builders = schema_class.row_builders
|
101
61
|
|
102
62
|
@columns =
|
103
63
|
Definition::Columns::Compiler
|
104
64
|
.new(
|
105
65
|
name,
|
106
|
-
|
107
|
-
|
66
|
+
schema_class.column_definitions,
|
67
|
+
nil_definitions_ignored: nil_definitions_ignored
|
108
68
|
)
|
109
69
|
.compile(@context)
|
70
|
+
end
|
110
71
|
|
111
|
-
|
72
|
+
def columns_keys
|
73
|
+
@columns_keys ||= @keys_builder.build(@columns.map(&:keys).flatten)
|
112
74
|
end
|
113
75
|
|
114
|
-
def
|
115
|
-
|
76
|
+
def columns_size
|
77
|
+
@columns.map(&:size).reduce(0, &:+)
|
78
|
+
end
|
116
79
|
|
117
|
-
|
80
|
+
def contain_name_callable?
|
81
|
+
@columns.any? { |column| column.name_callable? }
|
82
|
+
end
|
118
83
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
end
|
84
|
+
def contain_value_callable?
|
85
|
+
@columns.any? { |column| column.value_callable? }
|
86
|
+
end
|
123
87
|
|
124
|
-
|
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
|
+
)
|
125
101
|
end
|
126
102
|
|
127
|
-
def
|
128
|
-
|
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
|
+
)
|
129
116
|
end
|
130
117
|
end
|
131
118
|
end
|
@@ -4,13 +4,11 @@ module TableStructure
|
|
4
4
|
module Schema
|
5
5
|
module ClassMethods
|
6
6
|
def +(other)
|
7
|
-
|
8
|
-
raise ::TableStructure::Error, "Must be a schema class. #{other}"
|
9
|
-
end
|
7
|
+
raise ::TableStructure::Error, "Must be a schema class. [#{other}]" unless Utils.schema_class?(other)
|
10
8
|
|
11
9
|
self_class = self
|
12
10
|
|
13
|
-
|
11
|
+
Schema.create_class do
|
14
12
|
columns self_class
|
15
13
|
columns other
|
16
14
|
end
|
@@ -18,33 +16,16 @@ module TableStructure
|
|
18
16
|
|
19
17
|
def merge(*others)
|
20
18
|
others.each do |other|
|
21
|
-
|
22
|
-
raise ::TableStructure::Error, "Must be a schema class. #{other}"
|
23
|
-
end
|
19
|
+
raise ::TableStructure::Error, "Must be a schema class. [#{other}]" unless Utils.schema_class?(other)
|
24
20
|
end
|
25
21
|
|
26
|
-
|
27
|
-
|
28
|
-
::TableStructure::Schema.create_class do
|
29
|
-
@__column_definitions__ =
|
30
|
-
schema_classes
|
31
|
-
.map(&:column_definitions)
|
32
|
-
.flatten
|
33
|
-
|
34
|
-
@__context_builders__ =
|
35
|
-
schema_classes
|
36
|
-
.map(&:context_builders)
|
37
|
-
.reduce({}, &:merge!)
|
38
|
-
|
39
|
-
@__column_converters__ =
|
40
|
-
schema_classes
|
41
|
-
.map(&:column_converters)
|
42
|
-
.reduce({}, &:merge!)
|
22
|
+
schema_class = CompositeClass.new.compose(self, *others)
|
43
23
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
24
|
+
Schema.create_class do
|
25
|
+
@__column_definitions__ = schema_class.column_definitions
|
26
|
+
@__context_builders__ = schema_class.context_builders
|
27
|
+
@__column_builders__ = schema_class.column_builders
|
28
|
+
@__row_builders__ = schema_class.row_builders
|
48
29
|
end
|
49
30
|
end
|
50
31
|
end
|
@@ -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
|
+
.flatten
|
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)
|