table_structure 0.3.14 → 0.3.15

Sign up to get free protection for your applications and to get access to all the features.
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