dim-toolkit 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/dim +9 -0
- data/lib/dim/commands/check.rb +13 -0
- data/lib/dim/commands/export.rb +145 -0
- data/lib/dim/commands/format.rb +198 -0
- data/lib/dim/commands/stats.rb +64 -0
- data/lib/dim/consistency.rb +187 -0
- data/lib/dim/dimmain.rb +28 -0
- data/lib/dim/encoding.rb +4 -0
- data/lib/dim/exit_helper.rb +23 -0
- data/lib/dim/exporter/csv.rb +25 -0
- data/lib/dim/exporter/exporterInterface.rb +37 -0
- data/lib/dim/exporter/json.rb +32 -0
- data/lib/dim/exporter/rst.rb +142 -0
- data/lib/dim/ext/psych.rb +63 -0
- data/lib/dim/ext/string.rb +85 -0
- data/lib/dim/globals.rb +12 -0
- data/lib/dim/helpers/attribute_helper.rb +126 -0
- data/lib/dim/helpers/file_helper.rb +25 -0
- data/lib/dim/loader.rb +581 -0
- data/lib/dim/options.rb +116 -0
- data/lib/dim/requirement.rb +236 -0
- data/lib/dim/ver.rb +7 -0
- data/lib/dim.rb +1 -0
- data/license.txt +205 -0
- data/version.txt +1 -0
- metadata +98 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative '../globals'
|
2
|
+
require_relative '../requirement'
|
3
|
+
|
4
|
+
module Dim
|
5
|
+
class Csv < ExporterInterface
|
6
|
+
EXPORTER['csv'] = self
|
7
|
+
|
8
|
+
def header(content)
|
9
|
+
@keys = @loader.all_attributes.keys
|
10
|
+
@keys.delete('test_setups')
|
11
|
+
content.puts 'Sep=,'
|
12
|
+
content.puts "id,document_name,originator,#{@keys.join(',')}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def requirement(content, req)
|
16
|
+
vals = [req.id, req.document, req.origin]
|
17
|
+
@keys.each { |k| vals << req.data[k] }
|
18
|
+
# These values will never be nil.
|
19
|
+
# ID cannot be nil in Dim file, so as origin (default is "") and
|
20
|
+
# document cannot be missing in Dim files.
|
21
|
+
# Which leaves with data and YAML file cannot define nil value.
|
22
|
+
content.puts(vals.map { |a| "\"#{a.gsub('"', '""')}\"" }.join(','))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Dim
|
2
|
+
# This is how the interface is used by the Dim::Export:
|
3
|
+
#
|
4
|
+
# initialize()
|
5
|
+
#
|
6
|
+
# for every module:
|
7
|
+
# header()
|
8
|
+
# document()
|
9
|
+
# metadata()
|
10
|
+
# for every requirement in module:
|
11
|
+
# requirement()
|
12
|
+
# footer()
|
13
|
+
#
|
14
|
+
# if hasIndex:
|
15
|
+
# for every originator/category combination:
|
16
|
+
# index()
|
17
|
+
class ExporterInterface
|
18
|
+
attr_reader :hasIndex
|
19
|
+
|
20
|
+
def initialize(loader)
|
21
|
+
@hasIndex = false
|
22
|
+
@loader = loader
|
23
|
+
end
|
24
|
+
|
25
|
+
def header(f); end
|
26
|
+
|
27
|
+
def document(f, name); end
|
28
|
+
|
29
|
+
def metadata(f, metadata); end
|
30
|
+
|
31
|
+
def requirement(f, r); end
|
32
|
+
|
33
|
+
def footer(f); end
|
34
|
+
|
35
|
+
def index(f, category, origin, modules); end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
require_relative '../globals'
|
4
|
+
require_relative '../requirement'
|
5
|
+
|
6
|
+
module Dim
|
7
|
+
class Json < ExporterInterface
|
8
|
+
EXPORTER['json'] = self
|
9
|
+
|
10
|
+
def header(_f)
|
11
|
+
@content = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def requirement(_f, r)
|
15
|
+
vals = { 'id' => r.id, 'document_name' => r.document, 'originator' => r.origin }
|
16
|
+
|
17
|
+
@loader.all_attributes.keys.each do |k|
|
18
|
+
next if k == 'test_setups'
|
19
|
+
|
20
|
+
v = r.data[k]
|
21
|
+
v = v.cleanUniqArray.join(',') if k == 'refs'
|
22
|
+
vals[k] = v.strip
|
23
|
+
end
|
24
|
+
|
25
|
+
@content << vals
|
26
|
+
end
|
27
|
+
|
28
|
+
def footer(f)
|
29
|
+
f.puts(JSON.pretty_generate(@content))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Dim
|
4
|
+
class Rst < ExporterInterface
|
5
|
+
EXPORTER['rst'] = self
|
6
|
+
|
7
|
+
def initialize(loader)
|
8
|
+
super(loader)
|
9
|
+
@hasIndex = true
|
10
|
+
end
|
11
|
+
|
12
|
+
def document(f, name)
|
13
|
+
raw_html_name = ':raw-html:`' + name + '`'
|
14
|
+
f.puts raw_html_name
|
15
|
+
f.puts '=' * raw_html_name.length
|
16
|
+
@lastHeadingLevel = 0
|
17
|
+
@moduleName = name
|
18
|
+
end
|
19
|
+
|
20
|
+
def metadata(f, meta)
|
21
|
+
f.puts ''
|
22
|
+
f.puts html(meta.strip.escape_html, with_space: false)
|
23
|
+
end
|
24
|
+
|
25
|
+
def level2char(level)
|
26
|
+
{ 0 => '=',
|
27
|
+
1 => '-',
|
28
|
+
2 => '+',
|
29
|
+
3 => '~',
|
30
|
+
4 => '^',
|
31
|
+
5 => '"' }.fetch(level, '"')
|
32
|
+
end
|
33
|
+
|
34
|
+
def html(elem, with_space: true)
|
35
|
+
return if elem.empty?
|
36
|
+
|
37
|
+
with_space ? " :raw-html:`#{elem}`" : ":raw-html:`#{elem}`"
|
38
|
+
end
|
39
|
+
|
40
|
+
def handle_empty_value(value)
|
41
|
+
return '' if value.empty?
|
42
|
+
|
43
|
+
' ' + (value.is_a?(Array) ? value.join(', ') : value)
|
44
|
+
end
|
45
|
+
|
46
|
+
def createMultiLanguageElement(r, name)
|
47
|
+
lang_elems = r.data.keys.select { |k| k.start_with?("#{name}_") && !r.data[k].empty? }.sort
|
48
|
+
if lang_elems.empty?
|
49
|
+
return r.data[name].empty? ? '' : r.data[name]
|
50
|
+
end
|
51
|
+
|
52
|
+
str = (r.data[name].empty? ? '-' : r.data[name])
|
53
|
+
lang_elems.each do |l|
|
54
|
+
str << "<br><br><b>#{l.split('_').map(&:capitalize).join(' ')}: </b>"
|
55
|
+
str << r.data[l]
|
56
|
+
end
|
57
|
+
str
|
58
|
+
end
|
59
|
+
|
60
|
+
def requirement(f, r)
|
61
|
+
r.data.each { |k, v| r.data[k] = v.strip.escape_html }
|
62
|
+
|
63
|
+
if r.data['type'].start_with?('heading')
|
64
|
+
(@lastHeadingLevel + 1...r.depth).each do |l|
|
65
|
+
str = '<Skipped Heading Level>'
|
66
|
+
f.puts ''
|
67
|
+
f.puts str
|
68
|
+
f.puts level2char(l) * str.length
|
69
|
+
end
|
70
|
+
f.puts ''
|
71
|
+
str = ':raw-html:`' + r.data['text'] + '`'
|
72
|
+
f.puts str
|
73
|
+
f.puts level2char(r.depth) * str.length
|
74
|
+
@lastHeadingLevel = r.depth
|
75
|
+
return
|
76
|
+
end
|
77
|
+
|
78
|
+
r.data['tester'].gsub!('<br>', ' ')
|
79
|
+
r.data['developer'].gsub!('<br>', ' ')
|
80
|
+
text = createMultiLanguageElement(r, 'text')
|
81
|
+
comment = createMultiLanguageElement(r, 'comment')
|
82
|
+
refs = r.data['refs'].cleanUniqArray.select do |ref|
|
83
|
+
!@loader.requirements.has_key?(ref) || !@loader.requirements[ref].type.start_with?('heading')
|
84
|
+
end
|
85
|
+
tags = r.data['tags'].cleanUniqString
|
86
|
+
sources = r.data['sources'].cleanUniqString
|
87
|
+
|
88
|
+
f.puts ''
|
89
|
+
f.puts ".. #{r.data['type']}:: #{r.id}"
|
90
|
+
f.puts " :category: #{r.category}"
|
91
|
+
f.puts " :status: #{r.data['status']}"
|
92
|
+
f.puts " :review_status: #{r.data['review_status']}"
|
93
|
+
f.puts " :asil: #{r.data['asil']}"
|
94
|
+
f.puts " :cal: #{r.data['cal']}"
|
95
|
+
f.puts " :tags:#{handle_empty_value(tags)}"
|
96
|
+
f.puts " :comment:#{html(comment)}"
|
97
|
+
f.puts " :miscellaneous:#{html(r.data['miscellaneous'])}"
|
98
|
+
f.puts " :refs:#{handle_empty_value(refs)}"
|
99
|
+
@loader.custom_attributes.each_key do |custom_attribute|
|
100
|
+
f.puts " :#{custom_attribute}:#{handle_empty_value(r.data[custom_attribute])}"
|
101
|
+
end
|
102
|
+
if r.data['type'] == 'requirement'
|
103
|
+
vc = createMultiLanguageElement(r, 'verification_criteria')
|
104
|
+
|
105
|
+
f.puts " :sources:#{handle_empty_value(sources)}"
|
106
|
+
f.puts " :feature:#{html(r.data['feature'])}"
|
107
|
+
f.puts " :change_request:#{html(r.data['change_request'])}"
|
108
|
+
f.puts " :developer:#{handle_empty_value(r.data['developer'])}"
|
109
|
+
f.puts " :tester:#{handle_empty_value(r.data['tester'])}"
|
110
|
+
f.puts " :verification_methods:#{handle_empty_value(r.data['verification_methods'])}"
|
111
|
+
f.puts " :verification_criteria:#{html(vc)}"
|
112
|
+
end
|
113
|
+
|
114
|
+
f.puts "\n #{html(text)}" unless text.empty?
|
115
|
+
end
|
116
|
+
|
117
|
+
def footer(f)
|
118
|
+
files = @loader.module_data[@moduleName][:files].values.flatten
|
119
|
+
return if files.empty?
|
120
|
+
|
121
|
+
f.puts ''
|
122
|
+
f.puts '.. enclosed::'
|
123
|
+
f.puts ''
|
124
|
+
files.each do |file|
|
125
|
+
f.puts " #{file}"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def index(f, category, origin, modules)
|
130
|
+
caption = category.capitalize + ' (' + origin + ')'
|
131
|
+
f.puts caption
|
132
|
+
f.puts '=' * caption.length
|
133
|
+
f.puts ''
|
134
|
+
f.puts '.. toctree::'
|
135
|
+
f.puts ' :maxdepth: 1'
|
136
|
+
f.puts ''
|
137
|
+
modules.sort.each do |m|
|
138
|
+
f.puts " #{m.sanitize}/Requirements"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require_relative '../exit_helper'
|
2
|
+
|
3
|
+
module Dim
|
4
|
+
module Refinements
|
5
|
+
refine Psych::Nodes::Document do
|
6
|
+
def line_numbers
|
7
|
+
hash = {}
|
8
|
+
children[0].children.each do |node|
|
9
|
+
if node.is_a?(Psych::Nodes::Scalar)
|
10
|
+
hash[node.value] = node.start_line + 1
|
11
|
+
end
|
12
|
+
end
|
13
|
+
hash
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module Psych
|
20
|
+
module Visitors
|
21
|
+
class ToRuby
|
22
|
+
alias revive_hash_org revive_hash
|
23
|
+
|
24
|
+
def patched_revive_hash(hash, o)
|
25
|
+
test_hash = {}
|
26
|
+
o.children.each_slice(2) do |k, _v|
|
27
|
+
key = accept(k)
|
28
|
+
if test_hash.has_key?(key)
|
29
|
+
line = "line #{k.start_line + 1}: "
|
30
|
+
Dim::ExitHelper.exit(code: 1, msg: "#{line}found \"#{key}\" twice which must be unique.")
|
31
|
+
end
|
32
|
+
test_hash[key] = k
|
33
|
+
end
|
34
|
+
revive_hash_org hash, o
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.add_patch
|
38
|
+
alias revive_hash patched_revive_hash
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.revert_patch
|
42
|
+
alias revive_hash revive_hash_org
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module Nodes
|
48
|
+
class Scalar
|
49
|
+
alias initialize_org initialize
|
50
|
+
def quoted_initialize(value, anchor = nil, tag = nil, plain = true, _quoted = false, style = ANY)
|
51
|
+
initialize_org(value, anchor, tag, plain, true, style)
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.add_patch
|
55
|
+
alias initialize quoted_initialize
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.revert_patch
|
59
|
+
alias initialize initialize_org
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
class String
|
2
|
+
def cleanString
|
3
|
+
cleanArray.join(', ')
|
4
|
+
end
|
5
|
+
|
6
|
+
def cleanUniqString
|
7
|
+
cleanUniqArray.join(', ')
|
8
|
+
end
|
9
|
+
|
10
|
+
def cleanUniqArray
|
11
|
+
cleanArray.uniq
|
12
|
+
end
|
13
|
+
|
14
|
+
def cleanArray
|
15
|
+
cleanSplit.select { |s| !s.empty? }
|
16
|
+
end
|
17
|
+
|
18
|
+
def cleanSplit
|
19
|
+
split(/(?<!\\),/).map(&:strip)
|
20
|
+
end
|
21
|
+
|
22
|
+
def addEnum(e)
|
23
|
+
replace((cleanArray << e).uniq.join(', '))
|
24
|
+
end
|
25
|
+
|
26
|
+
def removeEnum(e)
|
27
|
+
arr = cleanArray
|
28
|
+
arr.delete(e)
|
29
|
+
replace(arr.join(', '))
|
30
|
+
end
|
31
|
+
|
32
|
+
def escapeHtmlOutside
|
33
|
+
gsub(/&(?!(amp|lt|gt|quot|apos|emsp);)/, '&')
|
34
|
+
.gsub('<', '<')
|
35
|
+
.gsub('>', '>')
|
36
|
+
.gsub('"', '"')
|
37
|
+
.gsub("'", ''')
|
38
|
+
.gsub("\t", ' ')
|
39
|
+
.gsub("\n", '<br>')
|
40
|
+
.gsub('`', '`')
|
41
|
+
.gsub(/(?<= ) /, ' ')
|
42
|
+
end
|
43
|
+
|
44
|
+
def escape_html_inside
|
45
|
+
gsub('`', '`')
|
46
|
+
.gsub("\t", ' ')
|
47
|
+
.gsub("\n", ' ')
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_next_escape_token(pos)
|
51
|
+
ind = index(%r{<\s*(\/?)\s*html\s*>}, pos)
|
52
|
+
return [:none, length - pos, -1] if ind.nil?
|
53
|
+
|
54
|
+
type = Regexp.last_match(1).empty? ? :start : :end
|
55
|
+
[type, ind - pos, ind + Regexp.last_match(0).length]
|
56
|
+
end
|
57
|
+
|
58
|
+
def escape_html
|
59
|
+
str = ''
|
60
|
+
search_pos = 0
|
61
|
+
nested = 0
|
62
|
+
while true
|
63
|
+
next_token, token_pos, after_token_pos = get_next_escape_token(search_pos)
|
64
|
+
if nested == 0
|
65
|
+
str << self[search_pos, token_pos].escapeHtmlOutside
|
66
|
+
nested = 1 if next_token == :start
|
67
|
+
else
|
68
|
+
str << self[search_pos, token_pos].escape_html_inside
|
69
|
+
nested += (next_token == :start ? +1 : -1)
|
70
|
+
end
|
71
|
+
break if next_token == :none
|
72
|
+
|
73
|
+
search_pos = after_token_pos
|
74
|
+
end
|
75
|
+
str.strip
|
76
|
+
end
|
77
|
+
|
78
|
+
def sanitize
|
79
|
+
gsub(/[^a-zA-Z0-9.\-_]/, '_')
|
80
|
+
end
|
81
|
+
|
82
|
+
def universal_newline
|
83
|
+
encode(encoding, universal_newline: true)
|
84
|
+
end
|
85
|
+
end
|
data/lib/dim/globals.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
OPTIONS ||= {}
|
2
|
+
SUBCOMMANDS ||= {}
|
3
|
+
EXPORTER ||= {}
|
4
|
+
CATEGORY_ORDER = {
|
5
|
+
'input' => 1,
|
6
|
+
'system' => 2,
|
7
|
+
'software' => 3,
|
8
|
+
'architecture' => 4,
|
9
|
+
'module' => 5,
|
10
|
+
}.freeze
|
11
|
+
ALLOWED_CATEGORIES = CATEGORY_ORDER.keys.each_with_object({}) { |k, obj| obj[k.to_sym] = k }.freeze
|
12
|
+
SRS_NAME_REGEX = /[^a-zA-Z0-9-]+/.freeze
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'file_helper'
|
4
|
+
|
5
|
+
module Dim
|
6
|
+
module Helpers
|
7
|
+
module AttributeHelper
|
8
|
+
include FileHelper
|
9
|
+
|
10
|
+
CHECK_SINGLE_ENUM = :check_single_enum
|
11
|
+
CHECK_MULTI_ENUM = :check_multi_enum
|
12
|
+
FORMAT_STYLES = {
|
13
|
+
'list' => 'list',
|
14
|
+
'multi' => 'multi',
|
15
|
+
'single' => 'single',
|
16
|
+
'split' => 'split',
|
17
|
+
'text' => 'text'
|
18
|
+
}.freeze
|
19
|
+
@filepath = ''
|
20
|
+
|
21
|
+
def resolve_attributes(folder:, filename:)
|
22
|
+
@filepath = "#{folder}/#{filename}"
|
23
|
+
attributes = open_yml_file(folder, filename, allow_empty_file: true)
|
24
|
+
unless attributes
|
25
|
+
puts "Warning: empty file detected; skipped loading of #{filename}"
|
26
|
+
return
|
27
|
+
end
|
28
|
+
|
29
|
+
check_for_default_attributes(attributes, filename)
|
30
|
+
|
31
|
+
attributes.each do |attribute, attr_config|
|
32
|
+
attr_config.transform_keys!(&:to_sym)
|
33
|
+
|
34
|
+
change_type_to_format_style(attr_config)
|
35
|
+
validate_format_style(attribute, attr_config)
|
36
|
+
add_check_value(attr_config)
|
37
|
+
validate_default(attribute, attr_config)
|
38
|
+
validate_allowed(attribute, attr_config)
|
39
|
+
validate_allowed_for_enum(attribute, attr_config)
|
40
|
+
validate_default_for_enum(attribute, attr_config)
|
41
|
+
|
42
|
+
symbolize_values(attr_config)
|
43
|
+
end
|
44
|
+
|
45
|
+
attributes
|
46
|
+
end
|
47
|
+
|
48
|
+
def check_for_default_attributes(attributes, filename)
|
49
|
+
common_values = Requirement::SYNTAX.keys & attributes.keys
|
50
|
+
return if common_values.empty?
|
51
|
+
|
52
|
+
Dim::ExitHelper.exit(
|
53
|
+
code: 1,
|
54
|
+
filename: @filepath,
|
55
|
+
msg: 'Defining standard attributes as a custom attributes is not allowed; ' \
|
56
|
+
"#{common_values.join(',')} in #{filename}"
|
57
|
+
)
|
58
|
+
end
|
59
|
+
|
60
|
+
# TODO: change "format_style" to "type" in requirements syntax and then remove this conversion
|
61
|
+
def change_type_to_format_style(config)
|
62
|
+
config[:format_style] = config.delete(:type)
|
63
|
+
end
|
64
|
+
|
65
|
+
def validate_format_style(attribute, config)
|
66
|
+
return if FORMAT_STYLES.values.include?(config[:format_style])
|
67
|
+
|
68
|
+
exit_with_error(config: 'type', config_value: config[:format_style], attribute: attribute)
|
69
|
+
end
|
70
|
+
|
71
|
+
def add_check_value(config)
|
72
|
+
config[:check] = CHECK_SINGLE_ENUM if config[:format_style] == FORMAT_STYLES['single']
|
73
|
+
config[:check] = CHECK_MULTI_ENUM if config[:format_style] == FORMAT_STYLES['multi']
|
74
|
+
end
|
75
|
+
|
76
|
+
def validate_default(attribute, config)
|
77
|
+
return unless config[:default] == 'auto'
|
78
|
+
|
79
|
+
exit_with_error(config: 'default', config_value: config[:default], attribute: attribute)
|
80
|
+
end
|
81
|
+
|
82
|
+
def validate_allowed(attribute, config)
|
83
|
+
return if config[:allowed].nil? || config[:allowed].is_a?(Array)
|
84
|
+
|
85
|
+
exit_with_error(config: 'allowed', config_value: config[:allowed], attribute: attribute)
|
86
|
+
end
|
87
|
+
|
88
|
+
def validate_allowed_for_enum(attribute, config)
|
89
|
+
return unless FORMAT_STYLES.fetch_values('single', 'multi').include?(config[:format_style])
|
90
|
+
|
91
|
+
return if config[:allowed].is_a?(Array) && config[:allowed].map { |val| val.is_a?(String) }.all?
|
92
|
+
|
93
|
+
Dim::ExitHelper.exit(
|
94
|
+
code: 1,
|
95
|
+
filename: @filepath,
|
96
|
+
msg: "Allowed value must be list of strings; invalid allowed value for #{attribute}"
|
97
|
+
)
|
98
|
+
end
|
99
|
+
|
100
|
+
def validate_default_for_enum(attribute, config)
|
101
|
+
return unless FORMAT_STYLES.fetch_values('single', 'multi').include?(config[:format_style])
|
102
|
+
|
103
|
+
return if config[:allowed].include?(config[:default])
|
104
|
+
|
105
|
+
Dim::ExitHelper.exit(
|
106
|
+
code: 1,
|
107
|
+
filename: @filepath,
|
108
|
+
msg: "default value for #{attribute} must be from allowed list of #{config[:allowed]}"
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
def symbolize_values(config)
|
113
|
+
config[:format_style] = config[:format_style].to_sym if config[:format_style]
|
114
|
+
config[:format_shift] = config[:format_shift].to_i
|
115
|
+
config[:default] = '' unless config[:default]
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def exit_with_error(config:, config_value:, attribute:)
|
121
|
+
msg = "Invalid value \"#{config_value}\" for #{config} detected for attribute #{attribute}"
|
122
|
+
Dim::ExitHelper.exit(code: 1, filename: @filepath, msg: msg)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../exit_helper'
|
4
|
+
|
5
|
+
module Dim::Helpers
|
6
|
+
module FileHelper
|
7
|
+
def open_yml_file(folder, filename, allow_empty_file: false)
|
8
|
+
file_path = Pathname.new(File.join(folder, filename)).cleanpath.to_s
|
9
|
+
binary_data = File.binread(file_path).chomp
|
10
|
+
begin
|
11
|
+
data = YAML.parse(
|
12
|
+
binary_data.encode('utf-8', invalid: :replace, undef: :replace, replace: '?'),
|
13
|
+
filename: file_path
|
14
|
+
)
|
15
|
+
rescue Psych::SyntaxError => e
|
16
|
+
Dim::ExitHelper.exit(code: 1, filename: filename, msg: e.message)
|
17
|
+
end
|
18
|
+
|
19
|
+
Dim::ExitHelper.exit(code: 1, filename: filename, msg: 'not a valid yaml file') unless data || allow_empty_file
|
20
|
+
return unless data
|
21
|
+
|
22
|
+
data.to_ruby
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|