table_structure 0.2.2 → 0.3.0

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: 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