stepmod-utils 0.3.23 → 0.3.25
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test-concept-generation.yml +38 -0
- data/.gitignore +3 -0
- data/.rubocop.yml +3 -0
- data/exe/stepmod-annotate-all +27 -14
- data/exe/stepmod-extract-changes +57 -0
- data/exe/stepmod-extract-concepts +165 -0
- data/lib/stepmod/utils/change.rb +74 -0
- data/lib/stepmod/utils/change_collection.rb +50 -0
- data/lib/stepmod/utils/change_edition.rb +60 -0
- data/lib/stepmod/utils/change_edition_collection.rb +38 -0
- data/lib/stepmod/utils/changes_extractor.rb +194 -0
- data/lib/stepmod/utils/concept.rb +40 -10
- data/lib/stepmod/utils/converters/description.rb +22 -0
- data/lib/stepmod/utils/express_bibdata.rb +111 -0
- data/lib/stepmod/utils/smrl_description_converter.rb +1 -0
- data/lib/stepmod/utils/stepmod_file_annotator.rb +215 -14
- data/lib/stepmod/utils/term.rb +18 -5
- data/lib/stepmod/utils/terms_extractor.rb +253 -292
- data/lib/stepmod/utils/version.rb +1 -1
- data/stepmod-utils.gemspec +2 -1
- metadata +31 -11
- data/exe/stepmod-build-resource-docs-cache +0 -20
- data/exe/stepmod-extract-terms +0 -237
- data/exe/stepmod-find-express-files +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 46ea2364546e11b067f0d3d21e78d0a1df701ec5189aeb94d08461d551b22786
|
4
|
+
data.tar.gz: ab5adf48414ca093c86ff2fbe12155ff7eab79102412f1c1f9949ee5e7eac591
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16eb837cff97033e742a20f2513ca426f69d41bb49cce9956c450f41c90290bd3404083c378a40b0ac6c35a68c974c57db1b11e5919cc6a1d5da9b65845b310b
|
7
|
+
data.tar.gz: c3df83672ebda912b592c487698b61e1e19e91cc31da78959dae7d3f4d3836b6a1940d78e33eec34dca92815fe7385e0289f3170303f989187132e1ef21ebc82
|
@@ -0,0 +1,38 @@
|
|
1
|
+
name: test-concept-generation
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ main ]
|
6
|
+
tags: [ v* ]
|
7
|
+
pull_request:
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
generate_yaml_concepts:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
steps:
|
13
|
+
- name: Checkout
|
14
|
+
uses: actions/checkout@v3
|
15
|
+
|
16
|
+
- name: Setup Ruby
|
17
|
+
uses: ruby/setup-ruby@v1
|
18
|
+
with:
|
19
|
+
ruby-version: '3.1'
|
20
|
+
bundler-cache: true
|
21
|
+
|
22
|
+
- name: Check out iso-10303-stepmod-wg12 repo
|
23
|
+
uses: actions/checkout@v3
|
24
|
+
with:
|
25
|
+
repository: metanorma/iso-10303-stepmod-wg12
|
26
|
+
token: ${{ secrets.METANORMA_CI_PAT_TOKEN }}
|
27
|
+
path: iso-10303-stepmod-wg12
|
28
|
+
|
29
|
+
- name: Generate Annotated EXPRESS files
|
30
|
+
run: bundle exec stepmod-annotate-all ./iso-10303-stepmod-wg12
|
31
|
+
|
32
|
+
- name: Generate Concept YAML files
|
33
|
+
working-directory: iso-10303-stepmod-wg12
|
34
|
+
run: |
|
35
|
+
bundle exec stepmod-extract-concepts \
|
36
|
+
-p ./data \
|
37
|
+
-i ./repository_index.xml \
|
38
|
+
-o ./output-yaml
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/exe/stepmod-annotate-all
CHANGED
@@ -5,14 +5,28 @@ require "stepmod/utils/stepmod_file_annotator"
|
|
5
5
|
|
6
6
|
stepmod_dir = ARGV.first || Dir.pwd
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
files
|
15
|
-
|
8
|
+
def all_express_files(stepmod_dir)
|
9
|
+
index_file = File.read(File.join(stepmod_dir, "repository_index.xml"))
|
10
|
+
index = Nokogiri::XML(index_file).root
|
11
|
+
|
12
|
+
files = []
|
13
|
+
index.xpath("modules/module").each do |item|
|
14
|
+
files << "#{stepmod_dir}/data/modules/#{item['name']}/arm.exp"
|
15
|
+
files << "#{stepmod_dir}/data/modules/#{item['name']}/mim.exp"
|
16
|
+
end
|
17
|
+
|
18
|
+
index.xpath("resources/resource").each do |item|
|
19
|
+
files << "#{stepmod_dir}/data/resources/#{item['name']}/#{item['name']}.exp"
|
20
|
+
end
|
21
|
+
|
22
|
+
index.xpath("business_object_models/business_object_model").each do |item|
|
23
|
+
files << "#{stepmod_dir}/data/business_object_models/#{item['name']}/bom.exp"
|
24
|
+
files << "#{stepmod_dir}/data/business_object_models/#{item['name']}/DomainModel.exp"
|
25
|
+
end
|
26
|
+
|
27
|
+
files.filter { |file| File.exist?(file) }
|
28
|
+
end
|
29
|
+
|
16
30
|
MAX_THREADS = 1 #[2, Concurrent.processor_count].max * 2
|
17
31
|
MAX_QUEUE_SIZE = MAX_THREADS * 4
|
18
32
|
# https://github.com/ruby-concurrency/concurrent-ruby/blob/master/docs-source/thread_pools.md
|
@@ -22,14 +36,16 @@ pool = Concurrent::ThreadPoolExecutor.new(
|
|
22
36
|
max_queue: MAX_QUEUE_SIZE,
|
23
37
|
fallback_policy: :caller_runs,
|
24
38
|
)
|
39
|
+
|
40
|
+
files = all_express_files(stepmod_dir)
|
41
|
+
|
25
42
|
files.each_slice(MAX_QUEUE_SIZE) do |batch|
|
26
43
|
puts("Queueing next batch")
|
27
44
|
batch.each do |file|
|
28
45
|
pool.post do
|
29
|
-
puts
|
46
|
+
puts "#{Thread.current.object_id}: Queued processing #{file}"
|
30
47
|
annotated = Stepmod::Utils::StepmodFileAnnotator.new(
|
31
48
|
express_file: file,
|
32
|
-
resource_docs_cache_file: resource_docs_cache_file,
|
33
49
|
stepmod_dir: stepmod_dir
|
34
50
|
).call
|
35
51
|
|
@@ -40,11 +56,8 @@ files.each_slice(MAX_QUEUE_SIZE) do |batch|
|
|
40
56
|
file.puts(annotated)
|
41
57
|
end
|
42
58
|
|
43
|
-
puts
|
59
|
+
puts "#{Thread.current.object_id}: Done processing #{File.basename(file)} => #{annotated_file_path}."
|
44
60
|
end
|
45
61
|
end
|
46
62
|
pool.shutdown
|
47
63
|
end
|
48
|
-
|
49
|
-
# cleanup
|
50
|
-
`rm "#{resource_docs_cache_file}"`
|
@@ -0,0 +1,57 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# resolve bin path, ignoring symlinks
|
4
|
+
require "pathname"
|
5
|
+
bin_file = Pathname.new(__FILE__).realpath
|
6
|
+
|
7
|
+
# add self to libpath
|
8
|
+
$:.unshift File.expand_path("../../lib", bin_file)
|
9
|
+
|
10
|
+
# Fixes https://github.com/rubygems/rubygems/issues/1420
|
11
|
+
require "rubygems/specification"
|
12
|
+
|
13
|
+
module Gem
|
14
|
+
class Specification
|
15
|
+
def this; self; end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
require "bundler/setup"
|
20
|
+
require "stepmod/utils/changes_extractor"
|
21
|
+
require "optparse"
|
22
|
+
|
23
|
+
def log(message)
|
24
|
+
puts "[stepmod-utils] #{message}"
|
25
|
+
end
|
26
|
+
|
27
|
+
options = {}
|
28
|
+
OptionParser.new do |opts|
|
29
|
+
opts.banner = "Usage: #{$0} [options]"
|
30
|
+
|
31
|
+
opts.on(
|
32
|
+
"-p",
|
33
|
+
"--path STEPMOD_DATA_PATH",
|
34
|
+
String,
|
35
|
+
"Path to STEPmod data directory",
|
36
|
+
) do |path|
|
37
|
+
options[:stepmod_dir] = path
|
38
|
+
end
|
39
|
+
|
40
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
41
|
+
puts opts
|
42
|
+
exit
|
43
|
+
end
|
44
|
+
end.parse!
|
45
|
+
|
46
|
+
stepmod_dir = options[:stepmod_dir]
|
47
|
+
if stepmod_dir.nil?
|
48
|
+
raise StandardError.new("STEPmod data path not set, set with the `-p` option")
|
49
|
+
else
|
50
|
+
log "STEPmod data path: `#{stepmod_dir}`"
|
51
|
+
end
|
52
|
+
|
53
|
+
changes = Stepmod::Utils::ChangesExtractor.call(
|
54
|
+
stepmod_dir: Pathname.new(stepmod_dir).realpath,
|
55
|
+
)
|
56
|
+
|
57
|
+
changes.save_to_files
|
@@ -0,0 +1,165 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
require "fileutils"
|
5
|
+
# resolve bin path, ignoring symlinks
|
6
|
+
require "pathname"
|
7
|
+
bin_file = Pathname.new(__FILE__).realpath
|
8
|
+
|
9
|
+
# add self to libpath
|
10
|
+
$:.unshift File.expand_path("../../lib", bin_file)
|
11
|
+
|
12
|
+
# Fixes https://github.com/rubygems/rubygems/issues/1420
|
13
|
+
require "rubygems/specification"
|
14
|
+
|
15
|
+
module Gem
|
16
|
+
class Specification
|
17
|
+
def this; self; end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
require "bundler/setup"
|
22
|
+
require_relative "../lib/stepmod/utils/terms_extractor"
|
23
|
+
require "optparse"
|
24
|
+
|
25
|
+
def log(message)
|
26
|
+
puts "[stepmod-utils] #{message}"
|
27
|
+
end
|
28
|
+
|
29
|
+
options = {}
|
30
|
+
OptionParser.new do |opts|
|
31
|
+
opts.banner = "Usage: #{$0} [options]"
|
32
|
+
|
33
|
+
opts.on(
|
34
|
+
"-p",
|
35
|
+
"--path STEPMOD_DATA_PATH",
|
36
|
+
String,
|
37
|
+
"Path to STEPmod data directory",
|
38
|
+
) do |path|
|
39
|
+
options[:stepmod_dir] = path
|
40
|
+
end
|
41
|
+
|
42
|
+
opts.on(
|
43
|
+
"-i",
|
44
|
+
"--index INDEX_PATH",
|
45
|
+
String,
|
46
|
+
"Path to repository_index.xml",
|
47
|
+
) do |path|
|
48
|
+
unless path.nil?
|
49
|
+
options[:index_path] = Pathname.new(path).to_s
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
opts.on(
|
54
|
+
"-o",
|
55
|
+
"--output INDEX_PATH",
|
56
|
+
String,
|
57
|
+
"Path to output directory",
|
58
|
+
) do |path|
|
59
|
+
unless path.nil?
|
60
|
+
options[:output_dir] = Pathname.new(path).to_s
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
65
|
+
puts opts
|
66
|
+
exit
|
67
|
+
end
|
68
|
+
end.parse!
|
69
|
+
|
70
|
+
stepmod_dir = options[:stepmod_dir]
|
71
|
+
if stepmod_dir.nil?
|
72
|
+
raise StandardError.new(
|
73
|
+
"STEPmod data path not set, set with the `-p` option.",
|
74
|
+
)
|
75
|
+
else
|
76
|
+
log "STEPmod data path: `#{stepmod_dir}`"
|
77
|
+
end
|
78
|
+
|
79
|
+
default_index_path = File.join(stepmod_dir, "repository_index.xml")
|
80
|
+
index_path = options[:index_path] || default_index_path
|
81
|
+
if File.exist?(index_path)
|
82
|
+
log "Repository index path: `#{index_path}`"
|
83
|
+
else
|
84
|
+
raise StandardError.new(
|
85
|
+
"Index file not present at #{index_path}, set with the `-i` option.",
|
86
|
+
)
|
87
|
+
end
|
88
|
+
|
89
|
+
default_output_dir = File.join(stepmod_dir, "output_yaml")
|
90
|
+
output_dir = options[:output_dir] || default_output_dir
|
91
|
+
unless File.directory?(output_dir)
|
92
|
+
FileUtils.mkdir_p(output_dir)
|
93
|
+
end
|
94
|
+
log "Output directory path: `#{output_dir}`"
|
95
|
+
|
96
|
+
_general_concepts,
|
97
|
+
resource_concepts,
|
98
|
+
_parsed_bibliography,
|
99
|
+
_part_concepts,
|
100
|
+
part_resources,
|
101
|
+
part_modules = Stepmod::Utils::TermsExtractor.call(stepmod_dir, index_path)
|
102
|
+
|
103
|
+
def part_to_title(bibdata)
|
104
|
+
{
|
105
|
+
41 => "Fundamentals of product description and support",
|
106
|
+
42 => "Geometric and topological representation",
|
107
|
+
43 => "Foundation representation",
|
108
|
+
44 => "Product structure, concept and configuration",
|
109
|
+
45 => "Material and other engineering properties",
|
110
|
+
46 => "Visual presentation",
|
111
|
+
47 => "Shape tolerance",
|
112
|
+
51 => "Mathematical representation",
|
113
|
+
}[bibdata.part.to_i] || bibdata.title_en
|
114
|
+
end
|
115
|
+
|
116
|
+
# rubocop:disable Layout/LineLength
|
117
|
+
IMAGE_REPLACEMENTS = {
|
118
|
+
"image::eq01.gif[]" => "stem:[H(A,B) = max {h(A, B), h(B,A)}]",
|
119
|
+
"image::eq02.gif[]" => "stem:[max_{a in A} { min_{b in B} d(a,b) }]",
|
120
|
+
"image::vector_z_c.gif[]" => "stem:[bar z_{c}]",
|
121
|
+
"image::one_direction_repeat_factor_expression.gif[]" => "stem:[I + k cdot R; k = -1, 1]",
|
122
|
+
"image::two_direction_repeat_factor_expression.gif[]" => "stem:[I + k_1 cdot R_1 + k_2 cdot R_2; k_1, k_2 = -1, 0, 1, k^2_1 + k^2_2 != 0]",
|
123
|
+
}.freeze
|
124
|
+
|
125
|
+
TEXT_REPLACEMENTS = {
|
126
|
+
' (see <module_ref linkend="ply_orientation_specification:4_entities:figure:f2"> Figure 2</module_ref>)' => "",
|
127
|
+
' (see <module_ref linkend="ply_orientation_specification:4_entities:figure:f3"> Figure 3</module_ref>)' => "",
|
128
|
+
}.freeze
|
129
|
+
# rubocop:enable Layout/LineLength
|
130
|
+
|
131
|
+
def replace_content(content)
|
132
|
+
IMAGE_REPLACEMENTS.each_pair do |k, v|
|
133
|
+
content.gsub!(k, v)
|
134
|
+
end
|
135
|
+
TEXT_REPLACEMENTS.each_pair do |k, v|
|
136
|
+
content.gsub!(k, v)
|
137
|
+
end
|
138
|
+
|
139
|
+
content
|
140
|
+
end
|
141
|
+
|
142
|
+
part_resources.each do |(_bibdata, current_part_resources)|
|
143
|
+
current_part_resources.save_to_files(output_dir)
|
144
|
+
end
|
145
|
+
log "INFO: part_resources written to yaml files"
|
146
|
+
|
147
|
+
part_modules.sort_by do |(bibdata, _part_modules_arm, _part_modules_mim)|
|
148
|
+
bibdata.part.to_i
|
149
|
+
end.each do |(_bibdata, part_modules_arm, part_modules_mim)|
|
150
|
+
unless part_modules_arm.empty?
|
151
|
+
part_modules_arm.values.map do |managed_concept|
|
152
|
+
managed_concept.save_to_files(output_dir)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
unless part_modules_mim.empty?
|
157
|
+
part_modules_mim.values.map do |managed_concept|
|
158
|
+
managed_concept.save_to_files(output_dir)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
log "INFO: part_modules written to yaml files"
|
163
|
+
|
164
|
+
resource_concepts.save_to_files(output_dir)
|
165
|
+
log "INFO: resource_concepts written to yaml files"
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require "psych"
|
2
|
+
require "stepmod/utils/change_edition"
|
3
|
+
require "stepmod/utils/change_edition_collection"
|
4
|
+
|
5
|
+
module Stepmod
|
6
|
+
module Utils
|
7
|
+
class Change
|
8
|
+
attr_accessor :schema_name
|
9
|
+
attr_reader :change_editions
|
10
|
+
|
11
|
+
MODULE_TYPES = {
|
12
|
+
arm: "arm",
|
13
|
+
mim: "mim",
|
14
|
+
arm_longform: "arm_lf",
|
15
|
+
mim_longform: "mim_lf",
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
def initialize(stepmod_dir:, schema_name:, type:)
|
19
|
+
@stepmod_dir = stepmod_dir
|
20
|
+
@change_editions = Stepmod::Utils::ChangeEditionCollection.new
|
21
|
+
@schema_name = schema_name
|
22
|
+
@type = type
|
23
|
+
end
|
24
|
+
|
25
|
+
def resource?
|
26
|
+
!module?
|
27
|
+
end
|
28
|
+
|
29
|
+
def module?
|
30
|
+
MODULE_TYPES.key?(@type.to_sym) || MODULE_TYPES.value?(@type.to_s)
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_change_edition(change_edition)
|
34
|
+
@change_editions[change_edition[:version]] = change_edition
|
35
|
+
end
|
36
|
+
|
37
|
+
def fetch_change_edition(version)
|
38
|
+
@change_editions[version]
|
39
|
+
end
|
40
|
+
alias_method :[], :fetch_change_edition
|
41
|
+
|
42
|
+
def save_to_file
|
43
|
+
File.write(filepath(@type), Psych.dump(to_h))
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_h
|
47
|
+
{
|
48
|
+
"schema" => schema_name,
|
49
|
+
"change_edition" => change_editions.to_h,
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def filepath(type)
|
56
|
+
File.join(
|
57
|
+
@stepmod_dir,
|
58
|
+
"data",
|
59
|
+
base_folder,
|
60
|
+
schema_name,
|
61
|
+
"#{MODULE_TYPES[type.to_sym] || schema_name}.changes.yaml",
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
def base_folder
|
66
|
+
if resource?
|
67
|
+
"resources"
|
68
|
+
else
|
69
|
+
"modules"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "stepmod/utils/change"
|
2
|
+
|
3
|
+
module Stepmod
|
4
|
+
module Utils
|
5
|
+
class ChangeCollection
|
6
|
+
def initialize(stepmod_dir:)
|
7
|
+
@stepmod_dir = stepmod_dir
|
8
|
+
@changes = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def fetch_or_initialize(change, type)
|
12
|
+
schema = schema_name(change)
|
13
|
+
|
14
|
+
@changes[schema_identifier(schema, type)] ||= Change.new(
|
15
|
+
type: type,
|
16
|
+
stepmod_dir: @stepmod_dir,
|
17
|
+
schema_name: schema,
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
def fetch(change, type)
|
22
|
+
schema = schema_name(change)
|
23
|
+
@changes[schema_identifier(schema, type)]
|
24
|
+
end
|
25
|
+
|
26
|
+
def save_to_files
|
27
|
+
@changes.values.each(&:save_to_file)
|
28
|
+
end
|
29
|
+
|
30
|
+
def count
|
31
|
+
@changes.keys.count
|
32
|
+
end
|
33
|
+
alias_method :size, :count
|
34
|
+
|
35
|
+
def each(&block)
|
36
|
+
@changes.values.each(&block)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def schema_name(change)
|
42
|
+
change.is_a?(Stepmod::Utils::Change) ? change.schema_name : change
|
43
|
+
end
|
44
|
+
|
45
|
+
def schema_identifier(schema_name, type)
|
46
|
+
"#{schema_name}_#{type}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Stepmod
|
2
|
+
module Utils
|
3
|
+
class ChangeEdition
|
4
|
+
attr_accessor :version, :description
|
5
|
+
attr_reader :additions, :modifications, :deletions, :mapping
|
6
|
+
|
7
|
+
def initialize(options)
|
8
|
+
@version = options[:version]
|
9
|
+
@description = options[:description]
|
10
|
+
self.additions = options[:additions] || []
|
11
|
+
self.modifications = options[:modifications] || []
|
12
|
+
self.deletions = options[:deletions] || []
|
13
|
+
self.mapping = options[:mapping] || []
|
14
|
+
end
|
15
|
+
|
16
|
+
def additions=(additions)
|
17
|
+
validate_type("additions", additions, Array)
|
18
|
+
|
19
|
+
@additions = additions
|
20
|
+
end
|
21
|
+
|
22
|
+
def modifications=(modifications)
|
23
|
+
validate_type("modifications", modifications, Array)
|
24
|
+
|
25
|
+
@modifications = modifications
|
26
|
+
end
|
27
|
+
|
28
|
+
def deletions=(deletions)
|
29
|
+
validate_type("deletions", deletions, Array)
|
30
|
+
|
31
|
+
@deletions = deletions
|
32
|
+
end
|
33
|
+
|
34
|
+
def mapping=(mapping)
|
35
|
+
validate_type("mapping", mapping, Array)
|
36
|
+
|
37
|
+
@mapping = mapping
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_h
|
41
|
+
{
|
42
|
+
"version" => version,
|
43
|
+
"description" => description,
|
44
|
+
"additions" => additions,
|
45
|
+
"modifications" => modifications,
|
46
|
+
"deletions" => deletions,
|
47
|
+
"mapping" => mapping,
|
48
|
+
}.reject { |_k, v| v.nil? || v.empty? }
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def validate_type(column, value, type)
|
54
|
+
error = "#{column} must be of type ::#{type}, Got ::#{value.class}"
|
55
|
+
|
56
|
+
raise error unless value.is_a?(type)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "stepmod/utils/change_edition"
|
2
|
+
|
3
|
+
module Stepmod
|
4
|
+
module Utils
|
5
|
+
class ChangeEditionCollection
|
6
|
+
def initialize
|
7
|
+
@collection = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def fetch_or_initialize(version)
|
11
|
+
@collection[version] ||=
|
12
|
+
Stepmod::Utils::ChangeEdition.new(version: version)
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_h
|
16
|
+
@collection.values.map(&:to_h)
|
17
|
+
end
|
18
|
+
|
19
|
+
def []=(version, change_edition)
|
20
|
+
klass = Stepmod::Utils::ChangeEdition
|
21
|
+
@collection[version] = if change_edition.is_a?(klass)
|
22
|
+
change_edition
|
23
|
+
else
|
24
|
+
klass.new(change_edition)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def [](version)
|
29
|
+
@collection[version]
|
30
|
+
end
|
31
|
+
|
32
|
+
def count
|
33
|
+
@collection.values.count
|
34
|
+
end
|
35
|
+
alias_method :size, :count
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|