odca 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +51 -0
- data/.rspec +3 -0
- data/.travis.yml +12 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +36 -0
- data/LICENSE +21 -0
- data/README.md +32 -0
- data/Rakefile +10 -0
- data/config/overlays_info.yml +35 -0
- data/lib/odca/hashlink_generator.rb +15 -0
- data/lib/odca/headful_overlay.rb +55 -0
- data/lib/odca/null_value.rb +17 -0
- data/lib/odca/overlay.rb +77 -0
- data/lib/odca/overlays/conditional_overlay.rb +18 -0
- data/lib/odca/overlays/encode_overlay.rb +26 -0
- data/lib/odca/overlays/entry_overlay.rb +33 -0
- data/lib/odca/overlays/format_overlay.rb +15 -0
- data/lib/odca/overlays/header.rb +26 -0
- data/lib/odca/overlays/information_overlay.rb +22 -0
- data/lib/odca/overlays/label_overlay.rb +105 -0
- data/lib/odca/overlays/masking_overlay.rb +15 -0
- data/lib/odca/overlays/review_overlay.rb +33 -0
- data/lib/odca/overlays/source_overlay.rb +26 -0
- data/lib/odca/parentful_overlay.rb +30 -0
- data/lib/odca/parser.rb +94 -0
- data/lib/odca/schema_base.rb +86 -0
- data/lib/odca/schema_parser.rb +100 -0
- data/lib/odca/version.rb +3 -0
- data/lib/odca.rb +14 -0
- data/odca.gemspec +32 -0
- metadata +116 -0
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
data/.travis.yml
ADDED
data/Gemfile
ADDED
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,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,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
|
data/lib/odca/overlay.rb
ADDED
@@ -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,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,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
|
data/lib/odca/parser.rb
ADDED
@@ -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
|
data/lib/odca/version.rb
ADDED
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: []
|