table_structure 0.3.14 → 0.3.15

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: de3f99fed2d954963668ab10f28a330023e28e8a8c41039544c6f961bb3ab539
4
- data.tar.gz: 0e012e4fbcb5fff523418b6c3bfd3762fb3ee53460d4ddefc8ae91cf3a68a950
3
+ metadata.gz: 77197fdbfa164e9f532b190b4e94750354595f9e51d155b91ed36ea2f43aeef2
4
+ data.tar.gz: 52ab0ab962584d0d7e8e10788a6c949369926ec8869577e797a462e90eb76487
5
5
  SHA512:
6
- metadata.gz: b913207c2199fe5436fca4e4b894443fe6aa0d07f9b78d7c76da11ad752a45432340baed1feb07176088e95ebc56f2ac8917e2a66f4523dfcb45fbbd6fd91dd6
7
- data.tar.gz: c96ad294ebc1f7f0e8d23ef3de3b17cdb9fd4546792ce3b8bba80d9d9ae1305c00155cf9f19623efa4b40b2723f71d01a0575c60cc1fbd42d4842a29c7c9256c
6
+ metadata.gz: 99774b00f0260b64ed8a3ea670cf24d79e222c8b75fab7545932fbb248516561078f2908a081bae925e7baf44502d115711974d5b7458937e6db1e0961be0152
7
+ data.tar.gz: ca70303e5f5ec9ae437e9dccd9554b027c48aa68b7cb9c0f0239f6fa1ca0259321c9ea942310ac7a320e8d80ef6b996ef02a1cfb5ac0afa3a317534b351ecd85
data/.travis.yml CHANGED
@@ -8,4 +8,4 @@ rvm:
8
8
  - 2.5
9
9
  - 2.4
10
10
  - 2.3
11
- before_install: gem install bundler:2.0.2
11
+ before_install: gem install bundler:2.1.1
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ # 0.3.15
2
+ Changes:
3
+ - `TableStructure::Schema`
4
+ - Add `+` as class method. this method concatenates the schemas.
5
+
1
6
  # 0.3.14
2
7
  Changes:
3
8
  - Support Ruby 2.7.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- table_structure (0.3.14)
4
+ table_structure (0.3.15)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -32,4 +32,4 @@ DEPENDENCIES
32
32
  table_structure!
33
33
 
34
34
  BUNDLED WITH
35
- 2.0.2
35
+ 2.1.1
data/README.md CHANGED
@@ -76,7 +76,7 @@ schema = SampleTableSchema.new(context: context)
76
76
  Initialize a writer with the schema:
77
77
  ```ruby
78
78
  writer = TableStructure::Writer.new(schema)
79
- ## When omitting header line
79
+ ## To omit header, write:
80
80
  # writer = TableStructure::Writer.new(schema, header_omitted: true)
81
81
  ```
82
82
 
@@ -97,8 +97,9 @@ items = [
97
97
  }
98
98
  ]
99
99
 
100
- ## When using `find_each` method of Rails
100
+ ## To use Rails `find_each` method, write:
101
101
  # items = Item.enum_for(:find_each)
102
+ ## or
102
103
  # items = Enumerator.new { |y| Item.find_each { |item| y << item } }
103
104
 
104
105
  table = []
@@ -117,7 +118,7 @@ end
117
118
 
118
119
  Writes the items converted by the schema to stream as CSV with Rails:
119
120
  ```ruby
120
- # response.headers['X-Accel-Buffering'] = 'no' # When using Nginx for reverse proxy
121
+ # response.headers['X-Accel-Buffering'] = 'no' # Required if Nginx is used for reverse proxy
121
122
  response.headers['Cache-Control'] = 'no-cache'
122
123
  response.headers['Content-Type'] = 'text/csv'
123
124
  response.headers['Content-Disposition'] = 'attachment; filename="sample.csv"'
@@ -164,7 +165,7 @@ class SampleTableSchema
164
165
  end
165
166
  }
166
167
 
167
- ## When nesting schemas, :key must be unique in parent and child schemas.
168
+ ## If the schemas are nested, :key must be unique in parent and child schemas.
168
169
  ## This can also be avoided by specifying :key_prefix or :key_suffix option.
169
170
  # columns ->(table) { NestedSchema.new(context: table, key_prefix: 'foo_', key_suffix: '_bar') }
170
171
 
@@ -318,8 +319,56 @@ context = {
318
319
  schema = SampleTableSchema.new(context: context)
319
320
  ```
320
321
 
322
+ You can also concatenate schemas.
323
+ If there are some definitions of `column_converter` with the same name in the schemas to be concatenated, the one in the schema that is concatenated last will be used.
324
+ ```ruby
325
+ class UserTableSchema
326
+ include TableStructure::Schema
327
+
328
+ column name: 'ID',
329
+ value: ->(row, _table) { row[:id] }
330
+
331
+ column name: 'Name',
332
+ value: ->(row, *) { row[:name] }
333
+ end
334
+
335
+ class PetTableSchema
336
+ include TableStructure::Schema
337
+
338
+ columns name: ['Pet 1', 'Pet 2', 'Pet 3'],
339
+ value: ->(row, *) { row[:pets] }
340
+
341
+ column_converter :same_name, ->(val, *) { 'This definition will not be used.' }
342
+ end
343
+
344
+ class QuestionTableSchema
345
+ include TableStructure::Schema
346
+
347
+ columns ->(table) {
348
+ table[:questions].map do |question|
349
+ {
350
+ name: question[:id],
351
+ value: ->(row, *) { row[:answers][question[:id]] }
352
+ }
353
+ end
354
+ }
355
+
356
+ column_converter :same_name, ->(val, *) { 'This definition will be used.' }
357
+ end
358
+
359
+ context = {
360
+ questions: [
361
+ { id: 'Q1', text: 'Do you like sushi?' },
362
+ { id: 'Q2', text: 'Do you like yakiniku?' },
363
+ { id: 'Q3', text: 'Do you like ramen?' }
364
+ ]
365
+ }
366
+
367
+ schema = (UserTableSchema + PetTableSchema + QuestionTableSchema).new(context: context)
368
+ ```
369
+
321
370
  You can also use `context_builder`.
322
- This may be useful when `column(s)` lambda is complicated.
371
+ This may be useful if `column(s)` lambda is complicated.
323
372
  ```ruby
324
373
  class SampleTableSchema
325
374
  include TableStructure::Schema
@@ -359,7 +408,7 @@ If you want to convert CSV character code, you can do so within block of `write`
359
408
  ```ruby
360
409
  File.open('sample.csv', 'w') do |f|
361
410
  writer.write(items, to: CSV.new(f)) do |row_values|
362
- row_values.map { |val| val&.to_s&.encode('Shift_JIS', invalid: :replace, undef: :replace) }
411
+ row_values.map { |val| val.to_s.encode('Shift_JIS', invalid: :replace, undef: :replace) }
363
412
  end
364
413
  end
365
414
  ```
@@ -3,53 +3,47 @@
3
3
  module TableStructure
4
4
  module CSV
5
5
  class Writer
6
- DEFAULT_OPTIONS = {
7
- bom: false,
8
- csv_options: {}
9
- }.freeze
10
-
11
- INNER_WRITER_DEFAULT_OPTIONS = ::TableStructure::Writer::DEFAULT_OPTIONS
12
- INNER_WRITER_IGNORED_OPTION_KEYS = %i[
13
- result_type
14
- method
15
- ].freeze
16
-
17
6
  BOM = "\uFEFF"
18
7
 
19
- def initialize(schema, **options)
8
+ def initialize(
9
+ schema,
10
+ bom: false,
11
+ csv_options: {},
12
+ header_omitted: false,
13
+ header_context: nil
14
+ )
20
15
  require 'csv'
21
- @options = DEFAULT_OPTIONS.merge(select_csv_writer_options(options))
22
- inner_writer_options = select_inner_writer_options(options)
23
- @writer = ::TableStructure::Writer.new(schema, **inner_writer_options)
24
- end
25
-
26
- def write(items, to:, **options, &block)
27
- csv_writer_options = @options.merge(select_csv_writer_options(options))
28
- inner_writer_options = select_inner_writer_options(options)
29
- if csv_writer_options[:bom]
30
- to.send(INNER_WRITER_DEFAULT_OPTIONS[:method], BOM)
31
- end
32
- csv = ::CSV.new(to, **csv_writer_options[:csv_options])
33
- @writer.write(items, to: csv, **inner_writer_options, &block)
34
- end
35
16
 
36
- private
17
+ @options = {
18
+ bom: bom,
19
+ csv_options: csv_options
20
+ }
21
+ @inner_options = {
22
+ header_omitted: header_omitted,
23
+ header_context: header_context
24
+ }
37
25
 
38
- def select_csv_writer_options(options)
39
- options
40
- .select { |k, _v| DEFAULT_OPTIONS.include?(k) }
26
+ @writer = ::TableStructure::Writer.new(schema, **@inner_options)
41
27
  end
42
28
 
43
- def select_inner_writer_options(options)
44
- options
45
- .select { |k, _v| INNER_WRITER_DEFAULT_OPTIONS.include?(k) }
46
- .reject do |k, v|
47
- ignored = INNER_WRITER_IGNORED_OPTION_KEYS.include?(k)
48
- if ignored
49
- warn "[TableStructure] #{self.class.name} ignores `#{k}:#{v}` option."
50
- end
51
- ignored
52
- end
29
+ def write(
30
+ items,
31
+ to:,
32
+ bom: @options[:bom],
33
+ csv_options: @options[:csv_options],
34
+ header_omitted: @inner_options[:header_omitted],
35
+ header_context: @inner_options[:header_context],
36
+ &block
37
+ )
38
+ inner_options = {
39
+ header_omitted: header_omitted,
40
+ header_context: header_context
41
+ }
42
+
43
+ to << BOM if bom
44
+
45
+ csv = ::CSV.new(to, **csv_options)
46
+ @writer.write(items, to: csv, **inner_options, &block)
53
47
  end
54
48
  end
55
49
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TableStructure
4
+ module Schema
5
+ module ClassMethods
6
+ def +(schema)
7
+ self_schema = self
8
+ Class.new do
9
+ include ::TableStructure::Schema
10
+
11
+ @__column_definitions__ = [
12
+ self_schema.column_definitions,
13
+ schema.column_definitions
14
+ ].flatten
15
+
16
+ @__context_builders__ =
17
+ {}
18
+ .merge!(self_schema.context_builders)
19
+ .merge!(schema.context_builders)
20
+
21
+ @__column_converters__ =
22
+ {}
23
+ .merge!(self_schema.column_converters)
24
+ .merge!(schema.column_converters)
25
+
26
+ @__result_builders__ =
27
+ {}
28
+ .merge!(self_schema.result_builders)
29
+ .merge!(schema.result_builders)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -6,19 +6,19 @@ module TableStructure
6
6
  class Attrs
7
7
  attr_reader :keys, :size
8
8
 
9
- def initialize(definition)
10
- @name = definition[:name]
11
- @keys = optimize_size([definition[:key]].flatten, definition[:size])
12
- @value = definition[:value]
13
- @size = definition[:size]
9
+ def initialize(name:, key:, value:, size:)
10
+ @name = name
11
+ @keys = optimize_size([key].flatten, size)
12
+ @value = value
13
+ @size = size
14
14
  end
15
15
 
16
- def name(context, table_context)
16
+ def names(context, table_context)
17
17
  name = Utils.evaluate_callable(@name, context, table_context)
18
18
  optimize_size(name, @size)
19
19
  end
20
20
 
21
- def value(context, table_context)
21
+ def values(context, table_context)
22
22
  value = Utils.evaluate_callable(@value, context, table_context)
23
23
  optimize_size(value, @size)
24
24
  end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TableStructure
4
+ module Schema
5
+ module Column
6
+ module Definition
7
+ class Compiler
8
+ DEFAULT_ATTRS = {
9
+ name: nil,
10
+ key: nil,
11
+ value: nil,
12
+ size: nil,
13
+ omitted: false
14
+ }.freeze
15
+
16
+ DEFAULT_SIZE = 1
17
+
18
+ def initialize(name, definitions, options)
19
+ @name = name
20
+ @definitions = definitions
21
+ @options = options
22
+ end
23
+
24
+ def compile(context = nil)
25
+ @definitions
26
+ .map { |definition| Utils.evaluate_callable(definition, context) }
27
+ .map.with_index do |definition, i|
28
+ validator = Validator.new(@name, i)
29
+
30
+ [definition]
31
+ .flatten
32
+ .map do |definition|
33
+ if definition.is_a?(Hash)
34
+ definition = DEFAULT_ATTRS.merge(definition)
35
+ omitted = definition.delete(:omitted)
36
+ next if Utils.evaluate_callable(omitted, context)
37
+
38
+ definition = evaluate_attrs(definition, context)
39
+ validator.validate(**definition)
40
+ definition[:size] = determine_size(**definition)
41
+ definition
42
+ elsif Utils.schema_instance?(definition)
43
+ definition
44
+ elsif Utils.schema_class?(definition)
45
+ definition.new(context: context)
46
+ elsif definition.nil? && @options[:nil_definitions_ignored]
47
+ next
48
+ else
49
+ raise Error.new('Invalid definition.', @name, i)
50
+ end
51
+ end
52
+ end
53
+ .flatten
54
+ .compact
55
+ end
56
+
57
+ private
58
+
59
+ def evaluate_attrs(definition, context)
60
+ size = Utils.evaluate_callable(definition[:size], context)
61
+ definition.merge(size: size)
62
+ end
63
+
64
+ def determine_size(name:, key:, size:, **)
65
+ return size if size
66
+
67
+ [calculate_size(name), calculate_size(key)].max
68
+ end
69
+
70
+ def calculate_size(val)
71
+ if val.is_a?(Array)
72
+ return val.empty? ? DEFAULT_SIZE : val.size
73
+ end
74
+
75
+ DEFAULT_SIZE
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TableStructure
4
+ module Schema
5
+ module Column
6
+ module Definition
7
+ class Error < ::TableStructure::Error
8
+ attr_reader :schema_name, :definition_index
9
+
10
+ def initialize(error_message, schema_name, definition_index)
11
+ @schema_name = schema_name
12
+ @definition_index = definition_index
13
+ super("#{error_message} [#{schema_name}] defined position of column(s): #{definition_index + 1}")
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TableStructure
4
+ module Schema
5
+ module Column
6
+ module Definition
7
+ class Validator
8
+ DEFAULT_SIZE = 1
9
+
10
+ def initialize(name, index)
11
+ @name = name
12
+ @index = index
13
+ end
14
+
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
19
+ if !key && name.respond_to?(:call) && !size
20
+ raise Error.new('"size" must be defined, because column size cannot be determined.', @name, @index)
21
+ end
22
+ if size && size < DEFAULT_SIZE
23
+ raise Error.new('"size" must be positive.', @name, @index)
24
+ end
25
+ if key && size && [key].flatten.size < size
26
+ raise Error.new('"key" size must not be less than specified "size".', @name, @index)
27
+ end
28
+
29
+ true
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TableStructure
4
+ module Schema
5
+ module Column
6
+ module Factory
7
+ def self.create(name, definitions, context, options)
8
+ Definition::Compiler
9
+ .new(name, definitions, options)
10
+ .compile(context)
11
+ .map do |definition|
12
+ if definition.is_a?(Hash)
13
+ Attrs.new(**definition)
14
+ else
15
+ Schema.new(definition)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -10,7 +10,7 @@ module TableStructure
10
10
  @table = schema.create_table
11
11
  end
12
12
 
13
- def name(header_context, _table_context)
13
+ def names(header_context, _table_context)
14
14
  @table.header(context: header_context)
15
15
  end
16
16
 
@@ -18,7 +18,7 @@ module TableStructure
18
18
  @table.send(:keys)
19
19
  end
20
20
 
21
- def value(row_context, _table_context)
21
+ def values(row_context, _table_context)
22
22
  @table.row(context: row_context)
23
23
  end
24
24
 
@@ -8,11 +8,12 @@ module TableStructure
8
8
  @row_converters = select_converters_for(:row, converters)
9
9
  end
10
10
 
11
- def extend_methods_for(table)
11
+ def extend_methods_for(table, name_prefix:, name_suffix:)
12
12
  table_context = table.instance_variable_get(:@context)
13
- table_options = table.instance_variable_get(:@options)
14
13
 
15
- header_converters = @header_converters.merge(optional_header_converters(table_options))
14
+ header_converters = @header_converters.merge(
15
+ optional_header_converters(name_prefix: name_prefix, name_suffix: name_suffix)
16
+ )
16
17
  row_converters = @row_converters
17
18
 
18
19
  methods = {}
@@ -37,15 +38,15 @@ module TableStructure
37
38
  .to_h
38
39
  end
39
40
 
40
- def optional_header_converters(options)
41
+ def optional_header_converters(name_prefix:, name_suffix:)
41
42
  converters = {}
42
- if options[:name_prefix]
43
+ if name_prefix
43
44
  converters[:_prepend_prefix_] =
44
- create_prefix_converter(options[:name_prefix])
45
+ create_prefix_converter(name_prefix)
45
46
  end
46
- if options[:name_suffix]
47
+ if name_suffix
47
48
  converters[:_append_suffix_] =
48
- create_suffix_converter(options[:name_suffix])
49
+ create_suffix_converter(name_suffix)
49
50
  end
50
51
 
51
52
  converters
@@ -19,7 +19,7 @@ module TableStructure
19
19
  end
20
20
 
21
21
  def column_converters
22
- @table_structure_schema_column_converters__ ||= {}
22
+ @__column_converters__ ||= {}
23
23
  end
24
24
  end
25
25
  end
@@ -14,7 +14,7 @@ module TableStructure
14
14
  end
15
15
 
16
16
  def column_definitions
17
- @table_structure_schema_column_definitions__ ||= []
17
+ @__column_definitions__ ||= []
18
18
  end
19
19
  end
20
20
  end
@@ -10,7 +10,7 @@ module TableStructure
10
10
  end
11
11
 
12
12
  def context_builders
13
- @table_structure_schema_context_builders__ ||= {}
13
+ @__context_builders__ ||= {}
14
14
  end
15
15
  end
16
16
  end
@@ -11,7 +11,7 @@ module TableStructure
11
11
  end
12
12
 
13
13
  def options
14
- @table_structure_schema_options__ ||= {}
14
+ @__options__ ||= {}
15
15
  end
16
16
  end
17
17
  end
@@ -19,7 +19,7 @@ module TableStructure
19
19
  end
20
20
 
21
21
  def result_builders
22
- @table_structure_schema_result_builders__ ||= {}
22
+ @__result_builders__ ||= {}
23
23
  end
24
24
  end
25
25
  end
@@ -18,15 +18,14 @@ module TableStructure
18
18
  @builders = builders
19
19
  end
20
20
 
21
- def extend_methods_for(table)
22
- table_context = table.instance_variable_get(:@context)
23
- table_options = table.instance_variable_get(:@options)
24
- table_keys = table.send(:keys)
25
-
26
- builders = select_builders(table_options[:result_type])
21
+ def extend_methods_for(table, result_type: :array)
22
+ builders = select_builders(result_type)
27
23
 
28
24
  methods = {}
29
25
  unless builders.empty?
26
+ table_context = table.instance_variable_get(:@context)
27
+ table_keys = table.send(:keys)
28
+
30
29
  methods[:header] = create_method(builders, table_keys, table_context)
31
30
  methods[:row] = create_method(builders, table_keys, table_context)
32
31
  end
@@ -3,10 +3,6 @@
3
3
  module TableStructure
4
4
  module Schema
5
5
  class Table
6
- DEFAULT_OPTIONS = {
7
- result_type: :array
8
- }.freeze
9
-
10
6
  def initialize(
11
7
  columns,
12
8
  context,
@@ -14,15 +10,15 @@ module TableStructure
14
10
  )
15
11
  @columns = columns
16
12
  @context = context
17
- @options = DEFAULT_OPTIONS.merge(options)
13
+ @options = options
18
14
  end
19
15
 
20
16
  def header(context: nil)
21
- values(:name, context)
17
+ values(:names, context)
22
18
  end
23
19
 
24
20
  def row(context: nil)
25
- values(:value, context)
21
+ values(:values, context)
26
22
  end
27
23
 
28
24
  def rows(items)
@@ -8,8 +8,20 @@ module TableStructure
8
8
  klass.extend(DSL::ContextBuilder)
9
9
  klass.extend(DSL::Option)
10
10
  klass.extend(DSL::ResultBuilder)
11
+ klass.extend(ClassMethods)
11
12
  end
12
13
 
14
+ Definition = Struct.new(
15
+ 'Definition',
16
+ :name,
17
+ :columns,
18
+ :context_builders,
19
+ :column_converters,
20
+ :result_builders,
21
+ :context,
22
+ :options
23
+ )
24
+
13
25
  def initialize(
14
26
  name: self.class.name,
15
27
  context: nil,
@@ -23,14 +35,10 @@ module TableStructure
23
35
  unless deprecated_options.empty?
24
36
  caller_location = caller_locations(1, 1)
25
37
  deprecated_options.keys.each do |k|
26
- warn "[TableStructure] Specify #{k} option on the writer or the iterator. #{caller_location}"
38
+ warn "[TableStructure] Specify :#{k} option on the writer or the iterator. #{caller_location}"
27
39
  end
28
40
  end
29
41
 
30
- column_definitions = [].concat(self.class.column_definitions)
31
- context_builders = {}.merge!(self.class.context_builders)
32
- column_converters = {}.merge!(self.class.column_converters)
33
- result_builders = {}.merge!(self.class.result_builders)
34
42
  options = {
35
43
  name_prefix: name_prefix,
36
44
  name_suffix: name_suffix,
@@ -39,10 +47,17 @@ module TableStructure
39
47
  nil_definitions_ignored: nil_definitions_ignored
40
48
  }.merge!(self.class.options).merge!(deprecated_options)
41
49
 
42
- @table_structure_schema_definition_ =
50
+ context_builders = ContextBuilders.new({}.merge!(self.class.context_builders))
51
+ column_converters = ColumnConverters.new({}.merge!(self.class.column_converters))
52
+ result_builders = ResultBuilders.new({}.merge!(self.class.result_builders))
53
+
54
+ context = context_builders.build_for_table(context)
55
+ columns = Column::Factory.create(name, self.class.column_definitions, context, options)
56
+
57
+ @_definition_ =
43
58
  Definition.new(
44
59
  name,
45
- column_definitions,
60
+ columns,
46
61
  context_builders,
47
62
  column_converters,
48
63
  result_builders,
@@ -51,8 +66,36 @@ module TableStructure
51
66
  )
52
67
  end
53
68
 
54
- def create_table(**options, &block)
55
- @table_structure_schema_definition_.create_table(**options, &block)
69
+ # TODO: Specify options using keyword arguments.
70
+ def create_table(**options)
71
+ options = @_definition_.options.merge(options)
72
+
73
+ table = Table.new(
74
+ @_definition_.columns,
75
+ @_definition_.context,
76
+ options
77
+ )
78
+
79
+ @_definition_.context_builders.extend_methods_for(table)
80
+
81
+ column_converters_options = {
82
+ name_prefix: options[:name_prefix],
83
+ name_suffix: options[:name_suffix]
84
+ }
85
+
86
+ @_definition_.column_converters.extend_methods_for(table, **column_converters_options)
87
+
88
+ result_builders_options = {
89
+ result_type: options[:result_type]
90
+ }
91
+
92
+ @_definition_.result_builders.extend_methods_for(table, **result_builders_options)
93
+
94
+ if block_given?
95
+ yield table
96
+ else
97
+ table
98
+ end
56
99
  end
57
100
  end
58
101
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TableStructure
4
- VERSION = '0.3.14'
4
+ VERSION = '0.3.15'
5
5
  end
@@ -6,15 +6,12 @@ module TableStructure
6
6
  require 'table_structure/version'
7
7
 
8
8
  require 'table_structure/schema'
9
+ require 'table_structure/schema/class_methods'
9
10
  require 'table_structure/schema/dsl/column_converter'
10
11
  require 'table_structure/schema/dsl/column_definition'
11
12
  require 'table_structure/schema/dsl/context_builder'
12
13
  require 'table_structure/schema/dsl/option'
13
14
  require 'table_structure/schema/dsl/result_builder'
14
- require 'table_structure/schema/definition'
15
- require 'table_structure/schema/definition/compiler'
16
- require 'table_structure/schema/definition/error'
17
- require 'table_structure/schema/definition/validator'
18
15
  require 'table_structure/schema/column_converters'
19
16
  require 'table_structure/schema/context_builders'
20
17
  require 'table_structure/schema/result_builders'
@@ -22,6 +19,10 @@ module TableStructure
22
19
  require 'table_structure/schema/table/key_decorator'
23
20
  require 'table_structure/schema/column/attrs'
24
21
  require 'table_structure/schema/column/schema'
22
+ require 'table_structure/schema/column/factory'
23
+ require 'table_structure/schema/column/definition/compiler'
24
+ require 'table_structure/schema/column/definition/error'
25
+ require 'table_structure/schema/column/definition/validator'
25
26
  require 'table_structure/schema/utils'
26
27
  require 'table_structure/writer'
27
28
  require 'table_structure/csv/writer'
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.14
4
+ version: 0.3.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - jsmmr
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-12-15 00:00:00.000000000 Z
11
+ date: 2019-12-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -74,14 +74,15 @@ files:
74
74
  - lib/table_structure/csv/writer.rb
75
75
  - lib/table_structure/iterator.rb
76
76
  - lib/table_structure/schema.rb
77
+ - lib/table_structure/schema/class_methods.rb
77
78
  - lib/table_structure/schema/column/attrs.rb
79
+ - lib/table_structure/schema/column/definition/compiler.rb
80
+ - lib/table_structure/schema/column/definition/error.rb
81
+ - lib/table_structure/schema/column/definition/validator.rb
82
+ - lib/table_structure/schema/column/factory.rb
78
83
  - lib/table_structure/schema/column/schema.rb
79
84
  - lib/table_structure/schema/column_converters.rb
80
85
  - lib/table_structure/schema/context_builders.rb
81
- - lib/table_structure/schema/definition.rb
82
- - lib/table_structure/schema/definition/compiler.rb
83
- - lib/table_structure/schema/definition/error.rb
84
- - lib/table_structure/schema/definition/validator.rb
85
86
  - lib/table_structure/schema/dsl/column_converter.rb
86
87
  - lib/table_structure/schema/dsl/column_definition.rb
87
88
  - lib/table_structure/schema/dsl/context_builder.rb
@@ -113,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
114
  - !ruby/object:Gem::Version
114
115
  version: '0'
115
116
  requirements: []
116
- rubygems_version: 3.0.6
117
+ rubygems_version: 3.1.2
117
118
  signing_key:
118
119
  specification_version: 4
119
120
  summary: Generates and outputs table structured data.
@@ -1,79 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module TableStructure
4
- module Schema
5
- class Definition
6
- class Compiler
7
- DEFAULT_ATTRS = {
8
- name: nil,
9
- key: nil,
10
- value: nil,
11
- size: nil,
12
- omitted: false
13
- }.freeze
14
-
15
- DEFAULT_SIZE = 1
16
-
17
- def initialize(name, definitions, options)
18
- @name = name
19
- @definitions = definitions
20
- @options = options
21
- end
22
-
23
- def compile(context = nil)
24
- @definitions
25
- .map { |definition| Utils.evaluate_callable(definition, context) }
26
- .map.with_index do |definition, i|
27
- validator = Validator.new(@name, i)
28
-
29
- [definition]
30
- .flatten
31
- .map do |definition|
32
- if definition.is_a?(Hash)
33
- definition = DEFAULT_ATTRS.merge(definition)
34
- omitted = definition.delete(:omitted)
35
- next if Utils.evaluate_callable(omitted, context)
36
-
37
- definition = evaluate_attrs(definition, context)
38
- validator.validate(**definition)
39
- definition[:size] = determine_size(**definition)
40
- definition
41
- elsif Utils.schema_instance?(definition)
42
- definition
43
- elsif Utils.schema_class?(definition)
44
- definition.new(context: context)
45
- elsif definition.nil? && @options[:nil_definitions_ignored]
46
- next
47
- else
48
- raise Error.new('Invalid definition.', @name, i)
49
- end
50
- end
51
- end
52
- .flatten
53
- .compact
54
- end
55
-
56
- private
57
-
58
- def evaluate_attrs(definition, context)
59
- size = Utils.evaluate_callable(definition[:size], context)
60
- definition.merge(size: size)
61
- end
62
-
63
- def determine_size(name:, key:, size:, **)
64
- return size if size
65
-
66
- [calculate_size(name), calculate_size(key)].max
67
- end
68
-
69
- def calculate_size(val)
70
- if val.is_a?(Array)
71
- return val.empty? ? DEFAULT_SIZE : val.size
72
- end
73
-
74
- DEFAULT_SIZE
75
- end
76
- end
77
- end
78
- end
79
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module TableStructure
4
- module Schema
5
- class Definition
6
- class Error < ::TableStructure::Error
7
- attr_reader :schema_name, :definition_index
8
-
9
- def initialize(error_message, schema_name, definition_index)
10
- @schema_name = schema_name
11
- @definition_index = definition_index
12
- super("#{error_message} [#{schema_name}] defined position of column(s): #{definition_index + 1}")
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module TableStructure
4
- module Schema
5
- class Definition
6
- class Validator
7
- DEFAULT_SIZE = 1
8
-
9
- def initialize(name, index)
10
- @name = name
11
- @index = index
12
- end
13
-
14
- def validate(name:, key:, size:, **)
15
- if key.respond_to?(:call)
16
- raise Error.new('"key" must not be lambda.', @name, @index)
17
- end
18
- if !key && name.respond_to?(:call) && !size
19
- raise Error.new('"size" must be defined, because column size cannot be determined.', @name, @index)
20
- end
21
- if size && size < DEFAULT_SIZE
22
- raise Error.new('"size" must be positive.', @name, @index)
23
- end
24
- if key && size && [key].flatten.size < size
25
- raise Error.new('"key" size must not be less than specified "size".', @name, @index)
26
- end
27
-
28
- true
29
- end
30
- end
31
- end
32
- end
33
- end
@@ -1,63 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module TableStructure
4
- module Schema
5
- class Definition
6
- attr_reader :options
7
-
8
- def initialize(
9
- name,
10
- column_definitions,
11
- context_builders,
12
- column_converters,
13
- result_builders,
14
- context,
15
- options
16
- )
17
- @name = name
18
- @context_builders = ContextBuilders.new(context_builders)
19
- @column_converters = ColumnConverters.new(column_converters)
20
- @result_builders = ResultBuilders.new(result_builders)
21
- @context = @context_builders.build_for_table(context)
22
- @options = options
23
-
24
- @columns = create_columns(@name, column_definitions, @context, @options)
25
- end
26
-
27
- def create_table(**options)
28
- options = @options.merge(options)
29
-
30
- table = Table.new(
31
- @columns,
32
- @context,
33
- options
34
- )
35
-
36
- @context_builders.extend_methods_for(table)
37
- @column_converters.extend_methods_for(table)
38
- @result_builders.extend_methods_for(table)
39
-
40
- if block_given?
41
- yield table
42
- else
43
- table
44
- end
45
- end
46
-
47
- private
48
-
49
- def create_columns(name, definitions, context, options)
50
- Compiler
51
- .new(name, definitions, options)
52
- .compile(context)
53
- .map do |definition|
54
- if definition.is_a?(Hash)
55
- Column::Attrs.new(definition)
56
- else
57
- Column::Schema.new(definition)
58
- end
59
- end
60
- end
61
- end
62
- end
63
- end