table_structure 0.2.2 → 0.3.0

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: 90d27cfdc8700ffb57706bcde59f1aee9786af31fd132478befc8081b0f7cb4c
4
- data.tar.gz: 5b7e60df0bc67c276cf4f95d70aba5b13a6a5be46004d8eb974c7182ee1261e6
3
+ metadata.gz: 4e966906136bf9907efb5bf1ad6fc1f2181ded3e4c6bbd6f76c19750198ecadd
4
+ data.tar.gz: c1f11210056449c18d31c693e758872659d603b1e9d1a28013cf0e35baff8776
5
5
  SHA512:
6
- metadata.gz: 228a500f8c1e842dbfed09939b95c0af27237f3ef56e2e2a4c526c0b89fafd73d8a99a9ea1b9ee64f4f3610966f9717c829c2447d2c479f69c09877929f67a65
7
- data.tar.gz: 44afa3c28a9ad5260361fdea2dcf85ac57b8799735305332bec3e3963b2d770f87fe06f73614e3b2645fe68c9579cbbc1a6e4256bbd39811046d1762db5878f1
6
+ metadata.gz: a98e9de6bd5d32941ee5730a8f34294d459a04ebc5e22a547887225421f7f91fcbbce59b026c6af5a96fa6215e38f0be6ed03b6155e04365418576f982d15873
7
+ data.tar.gz: b57d5dc8e40f0937ea14c06c08fb54d720bbd3215186b9357fc0f9f28705ea905938f238157999ecb62221ae84fd41d28872c63653557919b2be92a2162bc468
data/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ # 0.3.0
2
+ Changes:
3
+ - `TableStructure::Schema`
4
+ - Add `:omitted` key for column(s) DSL.
5
+ - Support nested schema.
6
+ - Add following options for schema initialization:
7
+ - `:key_prefix`
8
+ - `:key_suffix`
9
+
10
+ # 0.2.0
11
+ Changes:
12
+ - Add `TableStructure::Iterator`.
13
+
14
+ # 0.1.0
15
+ - First version
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- table_structure (0.2.2)
4
+ table_structure (0.3.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![Build Status](https://travis-ci.org/jsmmr/ruby_table_structure.svg?branch=master)](https://travis-ci.org/jsmmr/ruby_table_structure)
4
4
 
5
5
  `TableStructure` has two major functions.
6
- The functions are `TableStructure::Schema` that defines the schema of a table using DSL and ` TableStructure::Writer` that converts and outputs data with that schema.
6
+ The functions are `TableStructure::Schema` that defines the schema of a table using DSL and ` TableStructure::Writer` that converts and outputs data with the schema.
7
7
 
8
8
  ## Installation
9
9
 
@@ -132,6 +132,10 @@ class SampleTableSchema
132
132
  end
133
133
  }
134
134
 
135
+ ## When nesting schemas, same key must not exist in parent and child schemas.
136
+ ## This can also be avoided by specifying :key_prefix or :key_suffix option.
137
+ # columns ->(table) { NestedSchema.new(context: table, key_prefix: 'foo_', key_suffix: '_bar') }
138
+
135
139
  column_converter :to_s, ->(val, *) { val.to_s }
136
140
  end
137
141
 
@@ -180,6 +184,76 @@ enum.lazy.select { |item| item[:q1] == '⭕️' }.take(1).force
180
184
 
181
185
  ### Advanced
182
186
 
187
+ You can also omit columns by defining `:omitted`.
188
+ ```ruby
189
+ class SampleTableSchema
190
+ include TableStructure::Schema
191
+
192
+ column name: 'ID',
193
+ value: ->(row, _table) { row[:id] }
194
+
195
+ column name: 'Name',
196
+ value: ->(row, *) { row[:name] }
197
+
198
+ column name: 'Secret',
199
+ value: ->(row, *) { row[:secret] },
200
+ omitted: ->(table) { !table[:admin] }
201
+ end
202
+
203
+ context = { admin: true }
204
+
205
+ schema = SampleTableSchema.new(context: context)
206
+ ```
207
+
208
+ You can also nest schemas.
209
+ ```ruby
210
+ class PetsSchema
211
+ include TableStructure::Schema
212
+
213
+ columns name: ['Pet 1', 'Pet 2', 'Pet 3'],
214
+ value: ->(row, *) { row[:pets] }
215
+ end
216
+
217
+ class QuestionsSchema
218
+ include TableStructure::Schema
219
+
220
+ columns ->(table) {
221
+ table[:questions].map do |question|
222
+ {
223
+ name: question[:id],
224
+ value: ->(row, *) { row[:answers][question[:id]] }
225
+ }
226
+ end
227
+ }
228
+ end
229
+
230
+ class SampleTableSchema
231
+ include TableStructure::Schema
232
+
233
+ column name: 'ID',
234
+ value: ->(row, _table) { row[:id] }
235
+
236
+ column name: 'Name',
237
+ value: ->(row, *) { row[:name] }
238
+
239
+ columns ->(table) { PetsSchema.new(context: table) }
240
+
241
+ columns ->(table) { QuestionsSchema.new(context: table) }
242
+
243
+ column_converter :to_s, ->(val, *) { val.to_s }
244
+ end
245
+
246
+ context = {
247
+ questions: [
248
+ { id: 'Q1', text: 'Do you like sushi?' },
249
+ { id: 'Q2', text: 'Do you like yakiniku?' },
250
+ { id: 'Q3', text: 'Do you like ramen?' }
251
+ ]
252
+ }
253
+
254
+ schema = SampleTableSchema.new(context: context)
255
+ ```
256
+
183
257
  You can also use `context_builder`.
184
258
  This may be useful when `column` definition lambda is complicated.
185
259
  ```ruby
@@ -219,7 +293,7 @@ class SampleTableSchema
219
293
  end
220
294
  ```
221
295
 
222
- If you want to convert CSV character code, see the code below.
296
+ If you want to convert CSV character code, you do so within block of `write` method.
223
297
  ```ruby
224
298
  File.open('sample.csv', 'w') do |f|
225
299
  writer.write(items, to: CSV.new(f)) do |row_values|
@@ -16,6 +16,8 @@ module TableStructure
16
16
  require 'table_structure/schema/definition/validator'
17
17
  require 'table_structure/schema/table'
18
18
  require 'table_structure/schema/column'
19
+ require 'table_structure/schema/column/attrs'
20
+ require 'table_structure/schema/column/schema'
19
21
  require 'table_structure/schema/utils'
20
22
  require 'table_structure/writer'
21
23
  require 'table_structure/iterator'
@@ -10,7 +10,11 @@ module TableStructure
10
10
  klass.extend(DSL::ResultBuilder)
11
11
  end
12
12
 
13
- DEFAULT_OPTIONS = { result_type: :array }.freeze
13
+ DEFAULT_OPTIONS = {
14
+ result_type: :array,
15
+ key_prefix: nil,
16
+ key_suffix: nil
17
+ }.freeze
14
18
 
15
19
  def initialize(context: nil, **options)
16
20
  column_definitions = self.class.column_definitions
@@ -30,12 +34,12 @@ module TableStructure
30
34
 
31
35
  def header(context: nil)
32
36
  context = self.class.context_builders[:header].call(context)
33
- @table_structure_schema_table_.header(context)
37
+ @table_structure_schema_table_.header_values(context)
34
38
  end
35
39
 
36
40
  def row(context: nil)
37
41
  context = self.class.context_builders[:row].call(context)
38
- @table_structure_schema_table_.row(context)
42
+ @table_structure_schema_table_.row_values(context)
39
43
  end
40
44
 
41
45
  def column_converters
@@ -2,44 +2,12 @@
2
2
 
3
3
  module TableStructure
4
4
  module Schema
5
- class Column
6
- attr_reader :name, :key, :vlaue, :size
7
-
8
- def initialize(name:, key:, value:, size:)
9
- @name = name
10
- @key = key
11
- @value = value
12
- @size = size
13
- end
14
-
15
- def name(header_context, table_context)
16
- name = Utils.evaluate_callable(@name, header_context, table_context)
17
- optimize_size(name)
18
- end
19
-
20
- def key
21
- optimize_size(@key)
22
- end
23
-
24
- def value(row_context, table_context)
25
- value = Utils.evaluate_callable(@value, row_context, table_context)
26
- optimize_size(value)
27
- end
28
-
29
- private
30
-
31
- def optimize_size(value)
32
- return value if @size == 1 && !value.is_a?(Array)
33
-
34
- values = [value].flatten
35
- actual_size = values.size
36
- expected_size = @size
37
- if actual_size > expected_size
38
- values[0, expected_size]
39
- elsif actual_size < expected_size
40
- [].concat(values).fill(nil, actual_size, (expected_size - actual_size))
5
+ module Column
6
+ def self.create(definition, options)
7
+ if definition.is_a?(Hash)
8
+ Attrs.new(definition, options)
41
9
  else
42
- values
10
+ Schema.new(definition)
43
11
  end
44
12
  end
45
13
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TableStructure
4
+ module Schema
5
+ module Column
6
+ class Attrs
7
+ attr_reader :name, :key, :vlaue, :size
8
+
9
+ def initialize(definition, options)
10
+ @name = definition[:name]
11
+ @key = definition[:key]
12
+ @value = definition[:value]
13
+ @size = definition[:size]
14
+ @options = options
15
+ end
16
+
17
+ def name(header_context, table_context)
18
+ name = Utils.evaluate_callable(@name, header_context, table_context)
19
+ optimize_size(name)
20
+ end
21
+
22
+ def key
23
+ key = optimize_size(@key)
24
+ decorate_key(key)
25
+ end
26
+
27
+ def value(row_context, table_context)
28
+ value = Utils.evaluate_callable(@value, row_context, table_context)
29
+ optimize_size(value)
30
+ end
31
+
32
+ private
33
+
34
+ def optimize_size(value)
35
+ return value if @size == 1 && !value.is_a?(Array)
36
+
37
+ values = [value].flatten
38
+ actual_size = values.size
39
+ expected_size = @size
40
+ if actual_size > expected_size
41
+ values[0, expected_size]
42
+ elsif actual_size < expected_size
43
+ [].concat(values).fill(nil, actual_size, (expected_size - actual_size))
44
+ else
45
+ values
46
+ end
47
+ end
48
+
49
+ def decorate_key(key)
50
+ return key unless @options[:key_prefix] || @options[:key_suffix]
51
+
52
+ [key].flatten.map do |key|
53
+ next key unless key
54
+
55
+ decorated_key = "#{@options[:key_prefix]}#{key}#{@options[:key_suffix]}"
56
+ decorated_key = decorated_key.to_sym if key.is_a?(Symbol)
57
+ decorated_key
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TableStructure
4
+ module Schema
5
+ module Column
6
+ class Schema
7
+ attr_reader :schema
8
+
9
+ def initialize(schema)
10
+ @schema = schema
11
+ end
12
+
13
+ def name(header_context, _table_context)
14
+ schema.header(context: header_context)
15
+ end
16
+
17
+ def key
18
+ schema
19
+ .instance_variable_get(:@table_structure_schema_table_)
20
+ .send(:keys)
21
+ end
22
+
23
+ def value(row_context, _table_context)
24
+ schema.row(context: row_context)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -7,7 +7,8 @@ module TableStructure
7
7
  name: nil,
8
8
  key: nil,
9
9
  value: nil,
10
- size: nil
10
+ size: nil,
11
+ omitted: false
11
12
  }.freeze
12
13
 
13
14
  DEFAULT_SIZE = 1
@@ -26,13 +27,24 @@ module TableStructure
26
27
  [definition]
27
28
  .flatten
28
29
  .map do |definition|
29
- definition = DEFAULT_ATTRS.merge(definition)
30
- validator.validate(definition)
31
- definition[:size] = determine_size(definition)
32
- definition
30
+ if definition.is_a?(Hash)
31
+ definition = DEFAULT_ATTRS.merge(definition)
32
+ omitted = definition.delete(:omitted)
33
+ next if Utils.evaluate_callable(omitted, context)
34
+
35
+ validator.validate(definition)
36
+ definition[:size] = determine_size(definition)
37
+ definition
38
+ elsif Utils.schema_instance?(definition)
39
+ definition
40
+ # elsif Utils.schema_class?(definition)
41
+ # # TODO: This doesn't work as expected when result_type: :hash is specified.
42
+ # definition.new(context: context, **@options)
43
+ end
33
44
  end
34
45
  end
35
46
  .flatten
47
+ .compact
36
48
  end
37
49
 
38
50
  private
@@ -10,23 +10,28 @@ module TableStructure
10
10
  @column_converters = default_column_converters.merge(column_converters)
11
11
  @result_builders = default_result_builders(options).merge(result_builders)
12
12
  @context = context
13
+ @options = options
13
14
  end
14
15
 
15
- def header(context)
16
+ def header_values(context)
16
17
  values(:name, context)
17
18
  end
18
19
 
19
- def row(context)
20
+ def row_values(context)
20
21
  values(:value, context)
21
22
  end
22
23
 
24
+ def keys
25
+ @columns.map(&:key).flatten
26
+ end
27
+
23
28
  private
24
29
 
25
30
  def build_columns(definitions, context, options)
26
31
  Definition
27
32
  .new(definitions, options)
28
33
  .compile(context)
29
- .map { |attrs| Column.new(attrs) }
34
+ .map { |definition| Column.create(definition, options) }
30
35
  end
31
36
 
32
37
  def default_column_converters
@@ -41,10 +46,6 @@ module TableStructure
41
46
  result_builders
42
47
  end
43
48
 
44
- def keys
45
- @columns.map(&:key).flatten
46
- end
47
-
48
49
  def values(method, context)
49
50
  columns = @columns
50
51
  .map { |column| column.send(method, context, @context) }
@@ -6,6 +6,24 @@ module TableStructure
6
6
  def self.evaluate_callable(val, *params)
7
7
  val.respond_to?(:call) ? val.call(*params) : val
8
8
  end
9
+
10
+ def self.concat_key(key, prefix, suffix)
11
+ case key
12
+ when Symbol
13
+ "#{prefix}#{key}#{suffix}".to_sym
14
+ else
15
+ "#{prefix}#{key}#{suffix}"
16
+ end
17
+ end
18
+
19
+ def self.schema_class?(val)
20
+ val.is_a?(Class) &&
21
+ val.included_modules.include?(::TableStructure::Schema)
22
+ end
23
+
24
+ def self.schema_instance?(val)
25
+ val.is_a?(::TableStructure::Schema)
26
+ end
9
27
  end
10
28
  end
11
29
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TableStructure
4
- VERSION = '0.2.2'
4
+ VERSION = '0.3.0'
5
5
  end
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
11
11
  spec.email = ['jsmmr@icloud.com']
12
12
 
13
13
  spec.summary = 'Creates and outputs table structured data.'
14
- spec.description = 'This gem creates and outputs table structured data. Useful for creating CSV.'
14
+ spec.description = 'Creates and outputs table structured data. Useful for creating CSV.'
15
15
  spec.homepage = 'https://github.com/jsmmr/ruby_table_structure'
16
16
  spec.license = 'MIT'
17
17
 
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.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - jsmmr
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-08-25 00:00:00.000000000 Z
11
+ date: 2019-08-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,8 +52,7 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
- description: This gem creates and outputs table structured data. Useful for creating
56
- CSV.
55
+ description: Creates and outputs table structured data. Useful for creating CSV.
57
56
  email:
58
57
  - jsmmr@icloud.com
59
58
  executables: []
@@ -63,6 +62,7 @@ files:
63
62
  - ".gitignore"
64
63
  - ".rspec"
65
64
  - ".travis.yml"
65
+ - CHANGELOG.md
66
66
  - Gemfile
67
67
  - Gemfile.lock
68
68
  - LICENSE.txt
@@ -74,6 +74,8 @@ files:
74
74
  - lib/table_structure/iterator.rb
75
75
  - lib/table_structure/schema.rb
76
76
  - lib/table_structure/schema/column.rb
77
+ - lib/table_structure/schema/column/attrs.rb
78
+ - lib/table_structure/schema/column/schema.rb
77
79
  - lib/table_structure/schema/definition.rb
78
80
  - lib/table_structure/schema/definition/error.rb
79
81
  - lib/table_structure/schema/definition/validator.rb