odca 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ea45a8bb4326d3bb97747fdde2032ddbd9d5b3c8
4
+ data.tar.gz: fb018551fd8ebb9d80843d9e3cebfa004cbc7c5f
5
+ SHA512:
6
+ metadata.gz: d7abee9e0ec677f92df208b70e3720a951730e3840cf01c5a01b6754d7e27abb1a45cb43094cb34cbe1876243c027fe35d3355b456a6b77f152ff1d82d782d0a
7
+ data.tar.gz: 10d3c7e7b7aab51893a671993caecbe04a9c705f61d56b903e2f4a1c7309dab1bb3eae9e87f30140e17e54b305ff473557a39e562315a8f17b4fe68e9db1bcab
data/.gitignore ADDED
@@ -0,0 +1,51 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+ output
13
+
14
+ # Used by dotenv library to load environment variables.
15
+ # .env
16
+
17
+ ## Specific to RubyMotion:
18
+ .dat*
19
+ .repl_history
20
+ build/
21
+ *.bridgesupport
22
+ build-iPhoneOS/
23
+ build-iPhoneSimulator/
24
+
25
+ ## Specific to RubyMotion (use of CocoaPods):
26
+ #
27
+ # We recommend against adding the Pods directory to your .gitignore. However
28
+ # you should judge for yourself, the pros and cons are mentioned at:
29
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
30
+ #
31
+ # vendor/Pods/
32
+
33
+ ## Documentation cache and generated files:
34
+ /.yardoc/
35
+ /_yardoc/
36
+ /doc/
37
+ /rdoc/
38
+
39
+ ## Environment normalization:
40
+ /.bundle/
41
+ /vendor/bundle
42
+ /lib/bundler/man/
43
+
44
+ # for a library or gem, you might want to ignore these files since the code is
45
+ # intended to run in multiple environments; otherwise, check them in:
46
+ # Gemfile.lock
47
+ # .ruby-version
48
+ # .ruby-gemset
49
+
50
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
51
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --require spec_helper
3
+ --order random
data/.travis.yml ADDED
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ cache: bundler
3
+ script:
4
+ - bundle exec rake
5
+ rvm:
6
+ - 2.4.9
7
+ - ruby-head
8
+ matrix:
9
+ allow_failures:
10
+ - rvm: ruby-head
11
+ notifications:
12
+ email: false
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,36 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ odca (0.1.0)
5
+ base58 (~> 0.2)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ base58 (0.2.3)
11
+ diff-lcs (1.3)
12
+ rake (13.0.0)
13
+ rspec (3.9.0)
14
+ rspec-core (~> 3.9.0)
15
+ rspec-expectations (~> 3.9.0)
16
+ rspec-mocks (~> 3.9.0)
17
+ rspec-core (3.9.0)
18
+ rspec-support (~> 3.9.0)
19
+ rspec-expectations (3.9.0)
20
+ diff-lcs (>= 1.2.0, < 2.0)
21
+ rspec-support (~> 3.9.0)
22
+ rspec-mocks (3.9.0)
23
+ diff-lcs (>= 1.2.0, < 2.0)
24
+ rspec-support (~> 3.9.0)
25
+ rspec-support (3.9.0)
26
+
27
+ PLATFORMS
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ odca!
32
+ rake (~> 13.0)
33
+ rspec (~> 3.0)
34
+
35
+ BUNDLED WITH
36
+ 1.16.2
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 The Human Colossus Lab
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,32 @@
1
+ [![Build Status](https://travis-ci.com/THCLab/odca-ruby.svg?branch=master)](https://travis-ci.com/THCLab/odca-ruby)
2
+
3
+ # ODCA ruby tooling
4
+
5
+
6
+ to parse pre-prepared csv file just trigger it with:
7
+
8
+ ruby parser.rb <FILENAME>
9
+
10
+ It will create `output` directory within which you will find sorted per schema base generated overlays.
11
+
12
+ For information about the format of the csv take a look into `examples`
13
+
14
+ ## How to build input for parser
15
+
16
+ Parser is using csv files as an input. To make sure that the parser will be able to deal with the files you need to keep proper structure within those files. Parser use ';' as a column separator.
17
+
18
+ The flow of the parser is pretty simple:
19
+
20
+ 1) scan third row and look for overlays. The name of the overlay needs to match with the class e.g "LabelOverlay"
21
+ 2) scan each row and create schema base and specify overlays for each object. Rows should be in order sorted by schema base name. As soon as the schema base name change it is saved to the disk with all overlays and new object is created. It continues that process until eaching end of file.
22
+
23
+ All files are stored within output directory. Each time parser will override all files (in most of the case it will just create new one as the name iclude hash link)
24
+
25
+ For more details take a look on the examples or template in 'template/example.csv'
26
+
27
+
28
+ # Development
29
+
30
+ ## Run test
31
+
32
+ rake spec
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env rake
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler'
5
+ require 'rspec/core/rake_task'
6
+
7
+ desc 'Run all specs in spec directory'
8
+ RSpec::Core::RakeTask.new(:spec)
9
+
10
+ task default: :spec
@@ -0,0 +1,35 @@
1
+ label:
2
+ type_v1: spec/overlay/label/1.0
3
+ description: Category and attribute labels for %{schema_name}
4
+
5
+ format:
6
+ type_v1: spec/overlay/format/1.0
7
+ description: Attribute formats for %{schema_name}
8
+
9
+ encode:
10
+ type_v1: spec/overlay/encode/1.0
11
+ description: Character set encoding for %{schema_name}
12
+
13
+ entry:
14
+ type_v1: spec/overlay/entry/1.0
15
+ description: Field entries for %{schema_name}
16
+
17
+ information:
18
+ type_v1: spec/overlay/information/1.0
19
+ description: Informational items for %{schema_name}
20
+
21
+ conditional:
22
+ type_v1: spec/overlay/conditional/1.0
23
+ description:
24
+
25
+ source:
26
+ type_v1: spec/overlay/source/1.0
27
+ description: Source endpoints for %{schema_name}
28
+
29
+ review:
30
+ type_v1: spec/overlay/review/1.0
31
+ description: Field entry review comments for %{schema_name}
32
+
33
+ masking:
34
+ type_v1: spec/overlay/masking/1.0
35
+ description: Masking attributes for %{schema_name}
@@ -0,0 +1,15 @@
1
+ require 'digest/sha2'
2
+ require 'base58'
3
+ require 'json'
4
+
5
+ module Odca
6
+ class HashlinkGenerator
7
+ def self.call(schema)
8
+ Base58.encode(
9
+ Digest::SHA2.hexdigest(
10
+ JSON.pretty_generate(schema)
11
+ ).to_i(16)
12
+ )
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,55 @@
1
+ require 'yaml'
2
+ require 'forwardable'
3
+ require 'odca/overlays/header'
4
+
5
+ module Odca
6
+ class HeadfulOverlay
7
+ extend Forwardable
8
+ attr_reader :parentful_overlay, :role, :purpose
9
+
10
+ OVERLAYS_INFO = 'config/overlays_info.yml'.freeze
11
+
12
+ def_delegators :parentful_overlay, :overlay, :empty?
13
+
14
+ def initialize(parentful_overlay:, role:, purpose:)
15
+ @parentful_overlay = parentful_overlay
16
+ @role = role
17
+ @purpose = purpose
18
+ @overlays_info = overlays_info
19
+ end
20
+
21
+ def to_json(options = {})
22
+ to_h.to_json(*options)
23
+ end
24
+
25
+ def to_h
26
+ header.to_h
27
+ .merge(parentful_overlay.to_h)
28
+ end
29
+
30
+ def header
31
+ @header ||=
32
+ Odca::Overlays::Header.new(
33
+ role: role,
34
+ purpose: purpose,
35
+ type: overlay_info['type_v1'],
36
+ description: format(
37
+ overlay_info['description'],
38
+ schema_name: parentful_overlay.parent.name
39
+ )
40
+ )
41
+ end
42
+
43
+ def overlays_info
44
+ @overlays_info ||= YAML.safe_load(File.open(OVERLAYS_INFO))
45
+ end
46
+
47
+ def overlay_info
48
+ overlay_class_name = overlay.class.name.split('::').last
49
+ overlay_key = overlay_class_name.gsub('Overlay', '').downcase
50
+ overlays_info.fetch(overlay_key) do
51
+ raise "Not found specific information about #{overlay_class_name}"
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,17 @@
1
+ module Odca
2
+ class NullValue
3
+ %i[to_s to_str].each do |method|
4
+ define_method method do
5
+ ''
6
+ end
7
+ end
8
+
9
+ def empty?
10
+ true
11
+ end
12
+
13
+ def nil?
14
+ true
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,77 @@
1
+ require 'odca/null_value'
2
+
3
+ module Odca
4
+ module Overlay
5
+ def self.extended(overlay)
6
+ overlay_class_name = overlay.name.split('::').last
7
+
8
+ overlay.class_eval do
9
+ attr_reader :attributes
10
+
11
+ def _initialize
12
+ @attributes = []
13
+ end
14
+
15
+ alias_method :initialize, :_initialize
16
+
17
+ def empty?
18
+ attributes.empty?
19
+ end
20
+
21
+ def add_attribute(attr)
22
+ return if attr.nil? || attr.value.nil?
23
+ attributes << attr
24
+ end
25
+
26
+ def attr_values
27
+ attributes.each_with_object({}) do |attr, memo|
28
+ memo[attr.attr_name] = attr.value
29
+ end
30
+ end
31
+
32
+ overlay.const_set(
33
+ overlay_class_name.gsub('Overlay', '') << 'Attribute',
34
+ Class.new do
35
+ attr_reader :attr_name, :value
36
+
37
+ def initialize(attr_name:, value:)
38
+ @attr_name = attr_name
39
+ @value = value
40
+ end
41
+ end
42
+ )
43
+
44
+ overlay.const_set(
45
+ 'InputValidator',
46
+ Class.new do
47
+ attr_reader :attr_name, :value
48
+
49
+ def initialize(attr_name:, value:)
50
+ if attr_name.strip.empty?
51
+ raise 'Attribute name is expected to be non empty String'
52
+ end
53
+
54
+ @attr_name = attr_name
55
+ @value = value
56
+ end
57
+
58
+ define_method :call do
59
+ {
60
+ attr_name: attr_name.strip,
61
+ value: validate(value)
62
+ }
63
+ end
64
+
65
+ def validate(input_value)
66
+ if input_value.nil? || input_value.strip.empty?
67
+ Odca::NullValue.new
68
+ else
69
+ input_value.strip
70
+ end
71
+ end
72
+ end
73
+ )
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,18 @@
1
+ module Odca
2
+ module Overlays
3
+ class ConditionalOverlay
4
+ attr_accessor :hidden_attributes, :required_attributes
5
+
6
+ def to_h
7
+ {
8
+ hidden_attributes: hidden_attributes,
9
+ required_attributes: required_attributes
10
+ }
11
+ end
12
+
13
+ def empty?
14
+ hidden_attributes.empty? || required_attributes.empty?
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,26 @@
1
+ require 'odca/overlay'
2
+ require 'odca/null_value'
3
+
4
+ module Odca
5
+ module Overlays
6
+ class EncodeOverlay
7
+ extend Overlay
8
+ attr_reader :language
9
+
10
+ DEFAULT_ENCODING = 'utf-8'.freeze
11
+
12
+ def initialize(language:)
13
+ _initialize
14
+ @language = language
15
+ end
16
+
17
+ def to_h
18
+ {
19
+ language: language,
20
+ default_encoding: DEFAULT_ENCODING,
21
+ attr_encoding: attr_values
22
+ }
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,33 @@
1
+ require 'odca/overlay'
2
+ require 'odca/null_value'
3
+
4
+ module Odca
5
+ module Overlays
6
+ class EntryOverlay
7
+ extend Overlay
8
+ attr_reader :language
9
+
10
+ def initialize(language:)
11
+ _initialize
12
+ @language = language
13
+ end
14
+
15
+ def to_h
16
+ {
17
+ language: language,
18
+ attr_entries: attr_values
19
+ }
20
+ end
21
+
22
+ class InputValidator
23
+ def validate(value)
24
+ if value.nil? || value.strip.empty?
25
+ Odca::NullValue.new
26
+ else
27
+ value.split('|').map(&:strip)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,15 @@
1
+ require 'odca/overlay'
2
+
3
+ module Odca
4
+ module Overlays
5
+ class FormatOverlay
6
+ extend Overlay
7
+
8
+ def to_h
9
+ {
10
+ attr_formats: attr_values
11
+ }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ module Odca
2
+ module Overlays
3
+ class Header
4
+ attr_reader :issued_by, :role, :purpose, :description, :type
5
+
6
+ def initialize(role:, purpose:, description:, type:, issued_by: '')
7
+ @issued_by = issued_by
8
+ @role = role
9
+ @purpose = purpose
10
+ @description = description
11
+ @type = type
12
+ end
13
+
14
+ def to_h
15
+ {
16
+ '@context' => 'https://odca.tech/overlays/v1',
17
+ type: type,
18
+ description: description,
19
+ issued_by: issued_by,
20
+ role: role || '',
21
+ purpose: purpose || ''
22
+ }
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,22 @@
1
+ require 'odca/overlay'
2
+
3
+ module Odca
4
+ module Overlays
5
+ class InformationOverlay
6
+ extend Overlay
7
+ attr_reader :language
8
+
9
+ def initialize(language:)
10
+ _initialize
11
+ @language = language
12
+ end
13
+
14
+ def to_h
15
+ {
16
+ language: language,
17
+ attr_information: attr_values
18
+ }
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,105 @@
1
+ require 'odca/null_value'
2
+
3
+ module Odca
4
+ module Overlays
5
+ class LabelOverlay
6
+ attr_reader :attributes, :language
7
+
8
+ def initialize(language:)
9
+ @attributes = []
10
+ @language = language
11
+ end
12
+
13
+ def to_h
14
+ {
15
+ language: language,
16
+ attr_labels: attr_labels,
17
+ attr_categories: attr_categories,
18
+ category_labels: category_labels,
19
+ category_attributes: category_attributes
20
+ }
21
+ end
22
+
23
+ def empty?
24
+ attributes.empty?
25
+ end
26
+
27
+ def add_attribute(attribute)
28
+ return if attribute.nil? || attribute.attr_name.strip.empty?
29
+ attributes << attribute
30
+ end
31
+
32
+ private def attr_labels
33
+ attributes.each_with_object({}) do |attr, memo|
34
+ memo[attr.attr_name] = attr.label
35
+ end
36
+ end
37
+
38
+ private def attr_categories
39
+ attributes.map(&:category).uniq.map do |cat|
40
+ next if cat.empty?
41
+ cat.downcase.gsub(/\s+/, '_').to_sym
42
+ end.compact
43
+ end
44
+
45
+ private def category_labels
46
+ attributes.map(&:category).uniq
47
+ .each_with_object({}) do |cat, memo|
48
+ next if cat.empty?
49
+ memo[cat.downcase.gsub(/\s+/, '_').to_sym] = cat
50
+ end
51
+ end
52
+
53
+ private def category_attributes
54
+ attributes.each_with_object({}) do |attr, memo|
55
+ next if attr.category.empty?
56
+ category_attr = attr.category.downcase.gsub(/\s+/, '_').to_sym
57
+ (memo[category_attr] ||= []) << attr.attr_name
58
+ end
59
+ end
60
+
61
+ class LabelAttribute
62
+ attr_reader :attr_name, :category, :label
63
+
64
+ def initialize(attr_name:, category:, label:)
65
+ @attr_name = attr_name
66
+ @category = category
67
+ @label = label
68
+ end
69
+ end
70
+
71
+ class InputValidator
72
+ attr_reader :attr_name, :value
73
+
74
+ def initialize(attr_name:, value:)
75
+ if attr_name.strip.empty?
76
+ raise 'Attribute name is expected to be non empty String'
77
+ end
78
+
79
+ @attr_name = attr_name
80
+ @value = value
81
+ end
82
+
83
+ def call
84
+ category = Odca::NullValue.new
85
+ label = Odca::NullValue.new
86
+
87
+ splited = value.split('|')
88
+ case splited.length
89
+ when 1
90
+ label = value.strip
91
+ when 2
92
+ category = splited[0].strip
93
+ label = splited[1].strip
94
+ end
95
+
96
+ {
97
+ attr_name: attr_name.strip,
98
+ category: category,
99
+ label: label
100
+ }
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,15 @@
1
+ require 'odca/overlay'
2
+
3
+ module Odca
4
+ module Overlays
5
+ class MaskingOverlay
6
+ extend Overlay
7
+
8
+ def to_h
9
+ {
10
+ attr_masks: attr_values
11
+ }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,33 @@
1
+ require 'odca/overlay'
2
+ require 'odca/null_value'
3
+
4
+ module Odca
5
+ module Overlays
6
+ class ReviewOverlay
7
+ extend Overlay
8
+ attr_reader :language
9
+
10
+ def initialize(language:)
11
+ _initialize
12
+ @language = language
13
+ end
14
+
15
+ def to_h
16
+ {
17
+ language: language,
18
+ attr_comments: attr_values
19
+ }
20
+ end
21
+
22
+ class InputValidator
23
+ def validate(value)
24
+ if value.nil? || value.strip.empty?
25
+ Odca::NullValue.new
26
+ else
27
+ ''
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,26 @@
1
+ require 'odca/overlay'
2
+ require 'odca/null_value'
3
+
4
+ module Odca
5
+ module Overlays
6
+ class SourceOverlay
7
+ extend Overlay
8
+
9
+ def to_h
10
+ {
11
+ attr_sources: attr_values
12
+ }
13
+ end
14
+
15
+ class InputValidator
16
+ def validate(value)
17
+ if value.nil? || value.strip.empty?
18
+ Odca::NullValue.new
19
+ else
20
+ ''
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,30 @@
1
+ require 'forwardable'
2
+ require 'odca/hashlink_generator'
3
+
4
+ module Odca
5
+ class ParentfulOverlay
6
+ extend Forwardable
7
+ attr_reader :parent, :overlay
8
+
9
+ def_delegator :overlay, :empty?
10
+
11
+ def initialize(parent:, overlay:)
12
+ @parent = parent
13
+ @overlay = overlay
14
+ end
15
+
16
+ def to_json(options = {})
17
+ to_h.to_json(*options)
18
+ end
19
+
20
+ def to_h
21
+ { schema_base: parent_id }.merge(
22
+ overlay.to_h
23
+ )
24
+ end
25
+
26
+ private def parent_id
27
+ "hl:#{HashlinkGenerator.call(parent)}"
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,94 @@
1
+ require 'fileutils'
2
+ require 'odca/hashlink_generator'
3
+ require 'odca/schema_parser'
4
+ require 'json'
5
+ require 'pp'
6
+
7
+ module Odca
8
+ class Parser
9
+ attr_reader :records, :output_dir, :overlay_dtos
10
+
11
+ def initialize(records, output_dir)
12
+ @overlay_dtos = []
13
+ @records = records
14
+ @output_dir = output_dir
15
+ end
16
+
17
+ def call
18
+ columns_number = records[0].size
19
+
20
+ (6..columns_number - 1).each do |i|
21
+ overlay_dtos << OverlayDto.new(
22
+ index: i,
23
+ name: records[2][i],
24
+ role: records[0][i],
25
+ purpose: records[1][i],
26
+ language: records[3][i]
27
+ )
28
+ end
29
+ records.slice!(0, 4)
30
+
31
+ schemas = separate_schemas(records)
32
+ schemas.each do |schema|
33
+ schema_base, overlays = schema.call
34
+ save(schema_base: schema_base, overlays: overlays)
35
+ end
36
+ end
37
+
38
+ private def separate_schemas(records)
39
+ schema_name = ''
40
+ schema_first_row = 0
41
+ records.each_with_object([]).with_index do |(row, memo), i|
42
+ schema_name = row[0] if i.zero?
43
+ next_record = records[i + 1]
44
+ next if next_record && schema_name == next_record[0]
45
+ memo << Odca::SchemaParser.new(
46
+ records[schema_first_row..i], overlay_dtos
47
+ )
48
+ schema_name = next_record[0] if next_record
49
+ schema_first_row = i + 1
50
+ end
51
+ end
52
+
53
+ def save(schema_base:, overlays:)
54
+ path = "#{output_dir}/#{schema_base.name}"
55
+
56
+ save_schema_base(schema_base, path: path)
57
+
58
+ overlays.each do |overlay|
59
+ next if overlay.empty?
60
+ save_overlay(overlay, path: path)
61
+ end
62
+ end
63
+
64
+ def save_schema_base(schema_base, path:)
65
+ FileUtils.mkdir_p(path) unless Dir.exist?(path)
66
+
67
+ File.open("#{path}.json", 'w') do |f|
68
+ f.write(JSON.pretty_generate(schema_base))
69
+ end
70
+ end
71
+
72
+ def save_overlay(headful_overlay, path:)
73
+ overlay_class_name = headful_overlay.overlay.class
74
+ .name.split('::').last
75
+ hl = 'hl:' + HashlinkGenerator.call(headful_overlay)
76
+
77
+ File.open("#{path}/#{overlay_class_name}-#{hl}.json", 'w') do |f|
78
+ f.write(JSON.pretty_generate(headful_overlay))
79
+ end
80
+ end
81
+
82
+ class OverlayDto
83
+ attr_reader :index, :name, :role, :purpose, :language
84
+
85
+ def initialize(index:, name:, role:, purpose:, language:)
86
+ @index = index
87
+ @name = name
88
+ @role = role
89
+ @purpose = purpose
90
+ @language = language
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,86 @@
1
+ require 'forwardable'
2
+
3
+ module Odca
4
+ class SchemaBase
5
+ extend Forwardable
6
+ attr_reader :attributes, :header
7
+
8
+ def_delegators :header, :name, :description, :classification
9
+
10
+ def initialize(header)
11
+ @attributes = []
12
+ @header = header
13
+ end
14
+
15
+ def to_h
16
+ header.to_h.merge(
17
+ attributes: attributes.each_with_object({}) do |attr, memo|
18
+ memo[attr.name] = attr.type
19
+ end,
20
+ pii_attributes: pii_attributes.map(&:name)
21
+ )
22
+ end
23
+
24
+ def add_attribute(attribute)
25
+ attributes << attribute
26
+ end
27
+
28
+ def pii_attributes
29
+ attributes.select(&:pii?)
30
+ end
31
+
32
+ def to_json(*options)
33
+ to_h.to_json(*options)
34
+ end
35
+
36
+ class Header
37
+ attr_reader :name, :description, :classification
38
+
39
+ def initialize(name:, description:, classification:)
40
+ @name = name
41
+ @description = description
42
+ @classification = classification
43
+ end
44
+
45
+ def to_h
46
+ {
47
+ '@context' => 'https://odca.tech/v1',
48
+ name: name,
49
+ type: 'spec/schame_base/1.0',
50
+ description: description,
51
+ classification: classification || '',
52
+ issued_by: ''
53
+ }
54
+ end
55
+ end
56
+
57
+ class Attribute
58
+ attr_reader :name, :type, :pii
59
+
60
+ def self.new(**args)
61
+ super(
62
+ name: args[:name],
63
+ type: args[:type],
64
+ pii: args[:pii].to_s.strip
65
+ )
66
+ end
67
+
68
+ def initialize(name:, type:, pii:)
69
+ @name = name
70
+ @type = type
71
+ @pii = pii
72
+ end
73
+
74
+ def pii?
75
+ case pii
76
+ when 'Y'
77
+ true
78
+ when ''
79
+ false
80
+ else
81
+ raise RuntimeError.new("Unrecognized character: #{pii}")
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,100 @@
1
+ module Odca
2
+ class SchemaParser
3
+ attr_reader :records, :overlay_dtos
4
+
5
+ def initialize(records, overlay_dtos)
6
+ @records = records
7
+ @overlay_dtos = overlay_dtos
8
+ end
9
+
10
+ def call
11
+ schema_base = Odca::SchemaBase.new(
12
+ Odca::SchemaBase::Header.new(
13
+ name: records.first[0],
14
+ description: records.first[1],
15
+ classification: records.first[2]
16
+ )
17
+ )
18
+
19
+ overlay_attrs = {}
20
+ overlay_indexes = overlay_dtos.map(&:index)
21
+
22
+ records.each do |row|
23
+ attr_name = row[3]
24
+ schema_base.add_attribute(
25
+ SchemaBase::Attribute.new(
26
+ name: attr_name,
27
+ type: row[4],
28
+ pii: row[5]
29
+ )
30
+ )
31
+ overlay_indexes.each do |ov_index|
32
+ next unless row[ov_index]
33
+ (overlay_attrs[ov_index] ||= []) << {
34
+ name: attr_name,
35
+ value: row[ov_index]
36
+ }
37
+ end
38
+ end
39
+
40
+ overlays = []
41
+ overlay_dtos.each do |overlay_dto|
42
+ attrs = overlay_attrs[overlay_dto.index]
43
+ next unless attrs
44
+
45
+ overlay = create_overlay(overlay_dto)
46
+ attrs.each do |attr|
47
+ add_attribute(
48
+ to: overlay,
49
+ attr_name: attr[:name],
50
+ value: attr[:value]
51
+ )
52
+ end
53
+ overlays << Odca::HeadfulOverlay.new(
54
+ parentful_overlay: Odca::ParentfulOverlay.new(
55
+ parent: schema_base, overlay: overlay
56
+ ),
57
+ role: overlay_dto.role,
58
+ purpose: overlay_dto.purpose
59
+ )
60
+ end
61
+
62
+ [schema_base, overlays]
63
+ end
64
+
65
+ def add_attribute(to:, attr_name:, value:)
66
+ overlay = to
67
+ overlay_name = overlay.class.name.split('::').last
68
+ begin
69
+ attribute_class = overlay.class
70
+ .const_get(overlay_name.gsub('Overlay', 'Attribute'))
71
+ validator_class = overlay.class
72
+ .const_get('InputValidator')
73
+ rescue => e
74
+ raise "Not found Attribute Class for '#{overlay_name}': #{e}"
75
+ end
76
+
77
+ overlay.add_attribute(
78
+ attribute_class.new(
79
+ validator_class.new(
80
+ attr_name: attr_name,
81
+ value: value
82
+ ).call
83
+ )
84
+ )
85
+ end
86
+
87
+ private def create_overlay(overlay_dto)
88
+ overlay_class = Odca::Overlays.const_get(
89
+ overlay_dto.name.delete(' ')
90
+ )
91
+ if overlay_class.method_defined? 'language'
92
+ overlay_class.new(language: overlay_dto.language)
93
+ else
94
+ overlay_class.new
95
+ end
96
+ rescue => e
97
+ raise "Not found Overlay Class for '#{overlay_dto.name}': #{e}"
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,3 @@
1
+ module Odca
2
+ VERSION = '0.1.0'.freeze
3
+ end
data/lib/odca.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'odca/version'
2
+ require 'odca/parser'
3
+ require 'odca/schema_base'
4
+ require 'odca/headful_overlay'
5
+ require 'odca/parentful_overlay'
6
+ require 'odca/overlays/format_overlay'
7
+ require 'odca/overlays/label_overlay'
8
+ require 'odca/overlays/encode_overlay'
9
+ require 'odca/overlays/entry_overlay'
10
+ require 'odca/overlays/information_overlay'
11
+ require 'odca/overlays/conditional_overlay'
12
+ require 'odca/overlays/source_overlay'
13
+ require 'odca/overlays/review_overlay'
14
+ require 'odca/overlays/masking_overlay'
data/odca.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'odca/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'odca'
7
+ spec.version = Odca::VERSION
8
+ spec.authors = ['THCLab']
9
+ spec.email = ['olichwiruk@gmail.pl']
10
+
11
+ spec.summary = 'ODCA implementation in ruby'
12
+ spec.homepage = 'https://github.com/THCLab/odca-ruby'
13
+ spec.license = 'MIT'
14
+
15
+ # Specify which files should be added to the gem when it is released.
16
+ # The `git ls-files -z` loads the files in the RubyGem that
17
+ # have been added into git.
18
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
19
+ `git ls-files -z`.split("\x0").reject do |f|
20
+ f.match(%r{^(test|spec|features|examples|templates)/}) ||
21
+ f == 'parser.rb'
22
+ end
23
+ end
24
+ spec.bindir = 'exe'
25
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
+ spec.require_paths = ['lib']
27
+
28
+ spec.add_dependency 'base58', '~> 0.2'
29
+
30
+ spec.add_development_dependency 'rake', '~> 13.0'
31
+ spec.add_development_dependency 'rspec', '~> 3.0'
32
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: odca
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - THCLab
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-10-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: base58
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description:
56
+ email:
57
+ - olichwiruk@gmail.pl
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".rspec"
64
+ - ".travis.yml"
65
+ - Gemfile
66
+ - Gemfile.lock
67
+ - LICENSE
68
+ - README.md
69
+ - Rakefile
70
+ - config/overlays_info.yml
71
+ - lib/odca.rb
72
+ - lib/odca/hashlink_generator.rb
73
+ - lib/odca/headful_overlay.rb
74
+ - lib/odca/null_value.rb
75
+ - lib/odca/overlay.rb
76
+ - lib/odca/overlays/conditional_overlay.rb
77
+ - lib/odca/overlays/encode_overlay.rb
78
+ - lib/odca/overlays/entry_overlay.rb
79
+ - lib/odca/overlays/format_overlay.rb
80
+ - lib/odca/overlays/header.rb
81
+ - lib/odca/overlays/information_overlay.rb
82
+ - lib/odca/overlays/label_overlay.rb
83
+ - lib/odca/overlays/masking_overlay.rb
84
+ - lib/odca/overlays/review_overlay.rb
85
+ - lib/odca/overlays/source_overlay.rb
86
+ - lib/odca/parentful_overlay.rb
87
+ - lib/odca/parser.rb
88
+ - lib/odca/schema_base.rb
89
+ - lib/odca/schema_parser.rb
90
+ - lib/odca/version.rb
91
+ - odca.gemspec
92
+ homepage: https://github.com/THCLab/odca-ruby
93
+ licenses:
94
+ - MIT
95
+ metadata: {}
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubyforge_project:
112
+ rubygems_version: 2.6.8
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: ODCA implementation in ruby
116
+ test_files: []