abide_dev_utils 0.10.1 → 0.11.2
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 +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +7 -1
- data/Gemfile.lock +25 -19
- data/Rakefile +28 -0
- data/abide_dev_utils.gemspec +1 -0
- data/lib/abide_dev_utils/cem/benchmark.rb +490 -0
- data/lib/abide_dev_utils/cem/generate/coverage_report.rb +380 -0
- data/lib/abide_dev_utils/cem/generate/reference.rb +319 -0
- data/lib/abide_dev_utils/cem/generate.rb +11 -0
- data/lib/abide_dev_utils/cem/hiera_data/mapping_data/map_data.rb +110 -0
- data/lib/abide_dev_utils/cem/hiera_data/mapping_data/mixins.rb +46 -0
- data/lib/abide_dev_utils/cem/hiera_data/mapping_data.rb +146 -0
- data/lib/abide_dev_utils/cem/hiera_data/resource_data/control.rb +127 -0
- data/lib/abide_dev_utils/cem/hiera_data/resource_data/parameters.rb +90 -0
- data/lib/abide_dev_utils/cem/hiera_data/resource_data/resource.rb +102 -0
- data/lib/abide_dev_utils/cem/hiera_data/resource_data.rb +310 -0
- data/lib/abide_dev_utils/cem/hiera_data.rb +7 -0
- data/lib/abide_dev_utils/cem/mapping/mapper.rb +282 -0
- data/lib/abide_dev_utils/cem/validate/resource_data.rb +33 -0
- data/lib/abide_dev_utils/cem/validate.rb +10 -0
- data/lib/abide_dev_utils/cem.rb +1 -0
- data/lib/abide_dev_utils/cli/cem.rb +98 -0
- data/lib/abide_dev_utils/dot_number_comparable.rb +75 -0
- data/lib/abide_dev_utils/errors/cem.rb +32 -0
- data/lib/abide_dev_utils/errors/general.rb +8 -2
- data/lib/abide_dev_utils/errors/ppt.rb +4 -0
- data/lib/abide_dev_utils/errors.rb +6 -0
- data/lib/abide_dev_utils/markdown.rb +104 -0
- data/lib/abide_dev_utils/ppt/class_utils.rb +1 -1
- data/lib/abide_dev_utils/ppt/code_gen/data_types.rb +64 -0
- data/lib/abide_dev_utils/ppt/code_gen/generate.rb +15 -0
- data/lib/abide_dev_utils/ppt/code_gen/resource.rb +59 -0
- data/lib/abide_dev_utils/ppt/code_gen/resource_types/base.rb +93 -0
- data/lib/abide_dev_utils/ppt/code_gen/resource_types/class.rb +17 -0
- data/lib/abide_dev_utils/ppt/code_gen/resource_types/manifest.rb +16 -0
- data/lib/abide_dev_utils/ppt/code_gen/resource_types/parameter.rb +16 -0
- data/lib/abide_dev_utils/ppt/code_gen/resource_types/strings.rb +13 -0
- data/lib/abide_dev_utils/ppt/code_gen/resource_types.rb +6 -0
- data/lib/abide_dev_utils/ppt/code_gen.rb +15 -0
- data/lib/abide_dev_utils/ppt/code_introspection.rb +102 -0
- data/lib/abide_dev_utils/ppt/facter_utils.rb +140 -0
- data/lib/abide_dev_utils/ppt/hiera.rb +300 -0
- data/lib/abide_dev_utils/ppt/puppet_module.rb +75 -0
- data/lib/abide_dev_utils/ppt.rb +6 -5
- data/lib/abide_dev_utils/validate.rb +14 -0
- data/lib/abide_dev_utils/version.rb +1 -1
- data/lib/abide_dev_utils/xccdf/parser/helpers.rb +146 -0
- data/lib/abide_dev_utils/xccdf/parser/objects.rb +87 -144
- data/lib/abide_dev_utils/xccdf/parser.rb +5 -0
- data/lib/abide_dev_utils/xccdf/utils.rb +89 -0
- data/lib/abide_dev_utils/xccdf.rb +3 -0
- metadata +50 -3
- data/lib/abide_dev_utils/ppt/coverage.rb +0 -86
@@ -15,10 +15,108 @@ module Abide
|
|
15
15
|
CMD_LONG = 'Namespace for commands related to Puppet CEM'
|
16
16
|
def initialize
|
17
17
|
super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: true)
|
18
|
+
add_command(CemGenerate.new)
|
18
19
|
add_command(CemUpdateConfig.new)
|
19
20
|
end
|
20
21
|
end
|
21
22
|
|
23
|
+
class CemGenerate < AbideCommand
|
24
|
+
CMD_NAME = 'generate'
|
25
|
+
CMD_SHORT = 'Holds subcommands for generating objects / files'
|
26
|
+
CMD_LONG = 'Holds subcommands for generating objects / files'
|
27
|
+
def initialize
|
28
|
+
super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: true)
|
29
|
+
add_command(CemGenerateCoverageReport.new)
|
30
|
+
add_command(CemGenerateReference.new)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class CemGenerateCoverageReport < AbideCommand
|
35
|
+
CMD_NAME = 'coverage-report'
|
36
|
+
CMD_SHORT = 'Generates control coverage report'
|
37
|
+
CMD_LONG = <<-EOLC.chomp
|
38
|
+
Generates report of resources that are associated with controls in mapping data. This command must
|
39
|
+
be run from a module directory.
|
40
|
+
EOLC
|
41
|
+
def initialize
|
42
|
+
super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: false)
|
43
|
+
options.on('-o [FILE]', '--out-file [FILE]', 'Path to save the coverage report') { |f| @data[:file] = f }
|
44
|
+
options.on('-f [FORMAT]', '--format [FORMAT]', 'The format to output the report in (hash, json, yaml)') do |f|
|
45
|
+
@data[:format] = f
|
46
|
+
end
|
47
|
+
options.on('-B [BENCHMARK]', '--benchmark [BENCHMARK]', 'Specify the benchmark to show coverage for') do |x|
|
48
|
+
@data[:benchmark] = x
|
49
|
+
end
|
50
|
+
options.on('-P [PROFILE]', '--profile [PROFILE]', 'Specifiy the profile to show coverage for') do |x|
|
51
|
+
@data[:profile] = x
|
52
|
+
end
|
53
|
+
options.on('-L [LEVEL]', '--level [LEVEL]', 'Specify the level to show coverage for') do |l|
|
54
|
+
@data[:profile] = l
|
55
|
+
end
|
56
|
+
options.on('-I', '--ignore-benchmark-errors', 'Ignores errors while generating benchmark reports') do
|
57
|
+
@data[:ignore_all] = true
|
58
|
+
end
|
59
|
+
options.on('-X [XCCDF_DIR]', '--xccdf-dir [XCCDF_DIR]', 'If specified, the coverage report will be correlated with info from the benchmark XCCDF files') do |d|
|
60
|
+
@data[:xccdf_dir] = d
|
61
|
+
end
|
62
|
+
options.on('-v', '--verbose', 'Will output the report to the console') { @data[:verbose] = true }
|
63
|
+
options.on('-q', '--quiet', 'Will not output anything to the console') { @data[:quiet] = true }
|
64
|
+
end
|
65
|
+
|
66
|
+
def execute
|
67
|
+
file_name = @data.fetch(:file, 'coverage_report')
|
68
|
+
out_format = @data.fetch(:format, 'yaml')
|
69
|
+
quiet = @data.fetch(:quiet, false)
|
70
|
+
console = @data.fetch(:verbose, false) && !quiet
|
71
|
+
generate_opts = {
|
72
|
+
benchmark: @data.fetch(:benchmark),
|
73
|
+
profile: @data.fetch(:profile),
|
74
|
+
level: @data.fetch(:level),
|
75
|
+
ignore_benchmark_errors: @data.fetch(:ignore_all, false),
|
76
|
+
xccdf_dir: @data.fetch(:xccdf_dir),
|
77
|
+
}
|
78
|
+
AbideDevUtils::Output.simple('Generating coverage report...') unless quiet
|
79
|
+
coverage = AbideDevUtils::CEM::Generate::CoverageReport.generate(format_func: :to_h, opts: generate_opts)
|
80
|
+
AbideDevUtils::Output.simple("Saving coverage report to #{file_name}...")
|
81
|
+
case out_format
|
82
|
+
when /yaml/i
|
83
|
+
AbideDevUtils::Output.yaml(coverage, console: console, file: file_name)
|
84
|
+
when /json/i
|
85
|
+
AbideDevUtils::Output.json(coverage, console: console, file: file_name)
|
86
|
+
else
|
87
|
+
File.open(file_name, 'w') do |f|
|
88
|
+
AbideDevUtils::Output.simple(coverage.to_s, stream: f)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class CemGenerateReference < AbideCommand
|
95
|
+
CMD_NAME = 'reference'
|
96
|
+
CMD_SHORT = 'Generates a reference doc for the module'
|
97
|
+
CMD_LONG = 'Generates a reference doc for the module'
|
98
|
+
def initialize
|
99
|
+
super(CMD_NAME, CMD_SHORT, CMD_LONG, takes_commands: false)
|
100
|
+
options.on('-o [FILE]', '--out-file [FILE]', 'Path to save the updated config file') do |o|
|
101
|
+
@data[:out_file] = o
|
102
|
+
end
|
103
|
+
options.on('-f [FORMAT]', '--format [FORMAT]', 'Format to save reference as') do |f|
|
104
|
+
@data[:format] = f
|
105
|
+
end
|
106
|
+
options.on('-v', '--verbose', 'Verbose output') do
|
107
|
+
@data[:verbose] = true
|
108
|
+
end
|
109
|
+
options.on('-q', '--quiet', 'Quiet output') do
|
110
|
+
@data[:quiet] = true
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def execute
|
115
|
+
AbideDevUtils::Validate.puppet_module_directory
|
116
|
+
AbideDevUtils::CEM::Generate::Reference.generate(@data)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
22
120
|
class CemUpdateConfig < AbideCommand
|
23
121
|
CMD_NAME = 'update-config'
|
24
122
|
CMD_SHORT = 'Updates the Puppet CEM config'
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AbideDevUtils
|
4
|
+
# Module provides comparison methods for "dot numbers", numbers that
|
5
|
+
# take the form of "1.1.1" as found in CIS benchmarks. Classes that
|
6
|
+
# include this module must implement a method "number" that returns
|
7
|
+
# their dot number representation.
|
8
|
+
module DotNumberComparable
|
9
|
+
include ::Comparable
|
10
|
+
|
11
|
+
def <=>(other)
|
12
|
+
return 0 if number_eq(number, other.number)
|
13
|
+
return 1 if number_gt(number, other.number)
|
14
|
+
return -1 if number_lt(number, other.number)
|
15
|
+
end
|
16
|
+
|
17
|
+
def number_eq(this_num, other_num)
|
18
|
+
this_num == other_num
|
19
|
+
end
|
20
|
+
|
21
|
+
def number_parent_of?(this_num, other_num)
|
22
|
+
return false if number_eq(this_num, other_num)
|
23
|
+
|
24
|
+
# We split the numbers into parts and compare the resulting arrays
|
25
|
+
num1_parts = this_num.to_s.split('.')
|
26
|
+
num2_parts = other_num.to_s.split('.')
|
27
|
+
# For this_num to be a parent of other_num, the number of parts in
|
28
|
+
# this_num must be less than the number of parts in other_num.
|
29
|
+
# Additionally, each part of this_num must be equal to the parts of
|
30
|
+
# other_num at the same index.
|
31
|
+
# Example: this_num = '1.2.3' and other_num = '1.2.3.4'
|
32
|
+
# In this case, num1_parts = ['1', '2', '3'] and num2_parts = ['1', '2', '3', '4']
|
33
|
+
# So, this_num is a parent of other_num because at indexes 0, 1, and 2
|
34
|
+
# of num1_parts and num2_parts, the parts are equal.
|
35
|
+
num1_parts.length < num2_parts.length &&
|
36
|
+
num2_parts[0..(num1_parts.length - 1)] == num1_parts
|
37
|
+
end
|
38
|
+
|
39
|
+
def number_child_of?(this_num, other_num)
|
40
|
+
number_parent_of?(other_num, this_num)
|
41
|
+
end
|
42
|
+
|
43
|
+
def number_gt(this_num, other_num)
|
44
|
+
return false if number_eq(this_num, other_num)
|
45
|
+
return true if number_parent_of?(this_num, other_num)
|
46
|
+
|
47
|
+
num1_parts = this_num.to_s.split('.')
|
48
|
+
num2_parts = other_num.to_s.split('.')
|
49
|
+
num1_parts.zip(num2_parts).each do |num1_part, num2_part|
|
50
|
+
next if num1_part == num2_part # we skip past equal parts
|
51
|
+
|
52
|
+
# If num1_part is nil that means that we've had equal numbers so far.
|
53
|
+
# Therfore, this_num is greater than other num because of the
|
54
|
+
# hierarchical nature of the numbers.
|
55
|
+
# Example: this_num = '1.2' and other_num = '1.2.3'
|
56
|
+
# In this case, num1_part is nil and num2_part is '3'
|
57
|
+
# So, this_num is greater than other_num
|
58
|
+
return true if num1_part.nil?
|
59
|
+
# If num2_part is nil that means that we've had equal numbers so far.
|
60
|
+
# Therfore, this_num is less than other num because of the
|
61
|
+
# hierarchical nature of the numbers.
|
62
|
+
# Example: this_num = '1.2.3' and other_num = '1.2'
|
63
|
+
# In this case, num1_part is '3' and num2_part is nil
|
64
|
+
# So, this_num is less than other_num
|
65
|
+
return false if num2_part.nil?
|
66
|
+
|
67
|
+
return num1_part.to_i > num2_part.to_i
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def number_lt(this_num, other_num)
|
72
|
+
number_gt(other_num, this_num)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'abide_dev_utils/errors/base'
|
4
|
+
|
5
|
+
module AbideDevUtils
|
6
|
+
module Errors
|
7
|
+
# Raised by Benchmark when mapping data cannot be loaded
|
8
|
+
class MappingFilesNotFoundError < GenericError
|
9
|
+
@default = 'Mapping files not found using facts:'
|
10
|
+
end
|
11
|
+
|
12
|
+
# Raised by Benchmark when mapping files are not found for the specified framework
|
13
|
+
class MappingDataFrameworkMismatchError < GenericError
|
14
|
+
@default = 'Mapping data could not be found for the specified framework:'
|
15
|
+
end
|
16
|
+
|
17
|
+
# Raised by Benchmark when resource data cannot be loaded
|
18
|
+
class ResourceDataNotFoundError < GenericError
|
19
|
+
@default = 'Resource data not found using facts:'
|
20
|
+
end
|
21
|
+
|
22
|
+
# Raised by Control when it can't find mapping data for itself
|
23
|
+
class NoMappingDataForControlError < GenericError
|
24
|
+
@default = 'No mapping data found for control:'
|
25
|
+
end
|
26
|
+
|
27
|
+
# Raised by a control when it's given ID and framework are incompatible
|
28
|
+
class ControlIdFrameworkMismatchError < GenericError
|
29
|
+
@default = 'Control ID is invalid with the given framework:'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -9,7 +9,12 @@ module AbideDevUtils
|
|
9
9
|
@default = 'Object is empty and should not be:'
|
10
10
|
end
|
11
11
|
|
12
|
-
# Raised when a
|
12
|
+
# Raised when something is not a string, or is an empty string
|
13
|
+
class NotPopulatedStringError < GenericError
|
14
|
+
@default = 'Object is either not a String or is empty:'
|
15
|
+
end
|
16
|
+
|
17
|
+
# Raised when an object is initialized with a nil param
|
13
18
|
class NewObjectParamNilError < GenericError
|
14
19
|
@default = 'Object init parameter is nil and should not be:'
|
15
20
|
end
|
@@ -54,8 +59,9 @@ module AbideDevUtils
|
|
54
59
|
@default = 'Object does not respond to #to_hash or #to_h:'
|
55
60
|
end
|
56
61
|
|
62
|
+
# Raised when conflicting CLI options are specified for a command
|
57
63
|
class CliOptionsConflict < GenericError
|
58
|
-
@default =
|
64
|
+
@default = 'Console options conflict:'
|
59
65
|
end
|
60
66
|
end
|
61
67
|
end
|
@@ -5,6 +5,10 @@ require 'abide_dev_utils/errors/base'
|
|
5
5
|
module AbideDevUtils
|
6
6
|
module Errors
|
7
7
|
module Ppt
|
8
|
+
class NotModuleDirError < GenericError
|
9
|
+
@default = 'Path is not a Puppet module directory:'
|
10
|
+
end
|
11
|
+
|
8
12
|
class ObjClassPathError < GenericError
|
9
13
|
@default = 'Invalid path for class:'
|
10
14
|
end
|
@@ -1,9 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'abide_dev_utils/errors/base'
|
4
|
+
require 'abide_dev_utils/errors/cem'
|
4
5
|
require 'abide_dev_utils/errors/comply'
|
5
6
|
require 'abide_dev_utils/errors/gcloud'
|
6
7
|
require 'abide_dev_utils/errors/general'
|
7
8
|
require 'abide_dev_utils/errors/jira'
|
8
9
|
require 'abide_dev_utils/errors/xccdf'
|
9
10
|
require 'abide_dev_utils/errors/ppt'
|
11
|
+
|
12
|
+
module AbideDevUtils
|
13
|
+
# Namespace for Error objects
|
14
|
+
module Errors; end
|
15
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AbideDevUtils
|
4
|
+
# Formats text for output in markdown
|
5
|
+
class Markdown
|
6
|
+
def initialize(file, with_toc: true)
|
7
|
+
@file = file
|
8
|
+
@with_toc = with_toc
|
9
|
+
@toc = ["## Table of Contents\n"]
|
10
|
+
@body = []
|
11
|
+
@title = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_markdown
|
15
|
+
toc = @toc.join("\n")
|
16
|
+
body = @body.join("\n")
|
17
|
+
"#{@title}\n#{toc}\n\n#{body}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_file
|
21
|
+
File.write(@file, to_markdown)
|
22
|
+
end
|
23
|
+
|
24
|
+
def method_missing(name, *args, &block)
|
25
|
+
if name.to_s.start_with?('add_')
|
26
|
+
add(name.to_s.sub('add_', '').to_sym, *args, &block)
|
27
|
+
else
|
28
|
+
super
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def respond_to_missing?(name, include_private = false)
|
33
|
+
name.to_s.start_with?('add_') || super
|
34
|
+
end
|
35
|
+
|
36
|
+
def title(text)
|
37
|
+
"# #{text}\n"
|
38
|
+
end
|
39
|
+
|
40
|
+
def h1(text)
|
41
|
+
"## #{text}\n"
|
42
|
+
end
|
43
|
+
|
44
|
+
def h2(text)
|
45
|
+
"### #{text}\n"
|
46
|
+
end
|
47
|
+
|
48
|
+
def h3(text)
|
49
|
+
"#### #{text}\n"
|
50
|
+
end
|
51
|
+
|
52
|
+
def ul(text, indent: 0)
|
53
|
+
indented_text = []
|
54
|
+
indent.times { indented_text << ' ' } if indent.positive?
|
55
|
+
|
56
|
+
indented_text << "* #{text}"
|
57
|
+
indented_text.join
|
58
|
+
end
|
59
|
+
|
60
|
+
def bold(text)
|
61
|
+
"**#{text}**"
|
62
|
+
end
|
63
|
+
|
64
|
+
def italic(text)
|
65
|
+
"*#{text}*"
|
66
|
+
end
|
67
|
+
|
68
|
+
def link(text, url, anchor: false)
|
69
|
+
url = anchor(url) if anchor
|
70
|
+
"[#{text}](#{url.downcase})"
|
71
|
+
end
|
72
|
+
|
73
|
+
def code(text)
|
74
|
+
"\`#{text}\`"
|
75
|
+
end
|
76
|
+
|
77
|
+
def code_block(text, language: nil)
|
78
|
+
language.nil? ? "```\n#{text}\n```" : "```#{language}\n#{text}\n```"
|
79
|
+
end
|
80
|
+
|
81
|
+
def anchor(text)
|
82
|
+
"##{text.downcase.gsub(%r{\s|_}, '-').tr('.,\'"()', '')}"
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def add(type, text, *args, **kwargs)
|
88
|
+
@toc << ul(link(text, text, anchor: true), indent: 0) if @with_toc && type == :h1
|
89
|
+
|
90
|
+
case type.to_sym
|
91
|
+
when :title
|
92
|
+
@title = title(text)
|
93
|
+
when :ul
|
94
|
+
@body << ul(text, indent: kwargs.fetch(:indent, 0))
|
95
|
+
when :link
|
96
|
+
@body << link(text, args.first, anchor: kwargs.fetch(:anchor, false))
|
97
|
+
when :code_block
|
98
|
+
@body << code_block(text, language: kwargs.fetch(:language, nil))
|
99
|
+
else
|
100
|
+
@body << send(type, text)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -27,7 +27,7 @@ module AbideDevUtils
|
|
27
27
|
def self.path_from_class_name(class_name)
|
28
28
|
parts = class_name.split('::')
|
29
29
|
parts[-1] = "#{parts[-1]}.pp"
|
30
|
-
File.expand_path(File.join('manifests', parts[1
|
30
|
+
File.expand_path(File.join('manifests', parts[1..]))
|
31
31
|
end
|
32
32
|
|
33
33
|
# Returns the namespaced class name from a file path
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'puppet'
|
4
|
+
|
5
|
+
module AbideDevUtils
|
6
|
+
module Ppt
|
7
|
+
module CodeGen
|
8
|
+
module DataTypes
|
9
|
+
def infer_data_type(data)
|
10
|
+
Puppet::Pops::Types::TypeCalculator.infer(data).to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
# Displays a Puppet type value as a string
|
14
|
+
def display_value(val)
|
15
|
+
if val.is_a?(Puppet::Pops::Model::LiteralUndef)
|
16
|
+
'undef'
|
17
|
+
elsif val.respond_to?(:value)
|
18
|
+
display_value(val.value)
|
19
|
+
elsif val.respond_to?(:cased_value)
|
20
|
+
display_value(val.cased_value)
|
21
|
+
else
|
22
|
+
val
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Displays a Puppet type expression (type signature) as a string
|
27
|
+
# @param param [Puppet::Pops::Model::Parameter] AST Parameter node of a parsed Puppet manifest
|
28
|
+
def display_type_expr(param)
|
29
|
+
te = param.respond_to?(:type_expr) ? param.type_expr : param
|
30
|
+
if te.respond_to? :left_expr
|
31
|
+
display_type_expr_with_left_expr(te)
|
32
|
+
elsif te.respond_to? :entries
|
33
|
+
display_type_expr_with_entries(te)
|
34
|
+
elsif te.respond_to? :cased_value
|
35
|
+
te.cased_value
|
36
|
+
elsif te.respond_to? :value
|
37
|
+
te.value
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Used by #display_type_expr
|
42
|
+
def display_type_expr_with_left_expr(te)
|
43
|
+
cased = nil
|
44
|
+
keys = nil
|
45
|
+
cased = te.left_expr.cased_value if te.left_expr.respond_to? :cased_value
|
46
|
+
keys = te.keys.map { |x| display_type_expr(x) }.to_s if te.respond_to? :keys
|
47
|
+
keys.tr!('"', '') unless cased == 'Enum'
|
48
|
+
"#{cased}#{keys}"
|
49
|
+
end
|
50
|
+
|
51
|
+
# Used by #display_type_expr
|
52
|
+
def display_type_expr_with_entries(te)
|
53
|
+
te.entries.each_with_object({}) do |x, hsh|
|
54
|
+
key = nil
|
55
|
+
val = nil
|
56
|
+
key = display_value(x.key) if x.respond_to? :key
|
57
|
+
val = display_type_expr(x.value) if x.respond_to? :value
|
58
|
+
hsh[key] = val if key
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'abide_dev_utils/ppt/code_gen/resource_types'
|
4
|
+
|
5
|
+
module AbideDevUtils
|
6
|
+
module Ppt
|
7
|
+
module CodeGen
|
8
|
+
module Generate
|
9
|
+
def self.a_manifest
|
10
|
+
AbideDevUtils::Ppt::CodeGen::Manifest.new
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AbideDevUtils
|
4
|
+
module Ppt
|
5
|
+
module CodeGen
|
6
|
+
class Resource
|
7
|
+
attr_reader :type, :title
|
8
|
+
|
9
|
+
def initialize(type, title, **attributes)
|
10
|
+
validate_type_and_title(type, title)
|
11
|
+
@type = type
|
12
|
+
@title = title
|
13
|
+
@attributes = attributes
|
14
|
+
end
|
15
|
+
|
16
|
+
def reference
|
17
|
+
"#{title.split('::').map(&:capitalize).join('::')}['#{title}']"
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
return "#{type} { '#{title}': }" if @attributes.empty?
|
22
|
+
|
23
|
+
str_array = ["#{type} { '#{title}':"]
|
24
|
+
@attributes.each do |key, val|
|
25
|
+
str_array << " #{pad_attribute(key)} => #{val},"
|
26
|
+
end
|
27
|
+
str_array << '}'
|
28
|
+
str_array.join("\n")
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def validate_type_and_title(type, title)
|
34
|
+
raise 'Type / title must be String' unless type.is_a?(String) && title.is_a?(String)
|
35
|
+
raise 'Type / title must not be empty' if type.empty? || title.empty?
|
36
|
+
end
|
37
|
+
|
38
|
+
def longest_attribute_length
|
39
|
+
return @longest_attribute_length if defined?(@longest_attribute_length)
|
40
|
+
|
41
|
+
longest = ''
|
42
|
+
@attributes.each_key do |k|
|
43
|
+
longest = k if k.length > longest.length
|
44
|
+
end
|
45
|
+
@longest_attribute_length = longest.length
|
46
|
+
@longest_attribute_length
|
47
|
+
end
|
48
|
+
|
49
|
+
def pad_attribute(attribute)
|
50
|
+
return attribute if attribute.length == longest_attribute_length
|
51
|
+
|
52
|
+
attr_array = [attribute]
|
53
|
+
(longest_attribute_length - attribute.length).times { attr_array << ' ' }
|
54
|
+
attr_array.join
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'securerandom'
|
4
|
+
|
5
|
+
module AbideDevUtils
|
6
|
+
module Ppt
|
7
|
+
module CodeGen
|
8
|
+
# Base class for all code gen objects
|
9
|
+
class Base
|
10
|
+
attr_accessor :title, :id
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@id = SecureRandom.hex(10)
|
14
|
+
@supports_value = false
|
15
|
+
@supports_children = false
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
"#{type} : value: #{@value}; children: #{@children}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def reference
|
23
|
+
raise NotImplementedError, "#{type} does not support having a reference"
|
24
|
+
end
|
25
|
+
|
26
|
+
def type
|
27
|
+
self.class.to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
def value
|
31
|
+
raise NotImplementedError, "#{type} does not support having a value" unless @supports_value
|
32
|
+
|
33
|
+
@value
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_my(t, named: nil)
|
37
|
+
if named.nil?
|
38
|
+
children.each_with_object([]) do |(k, v), arr|
|
39
|
+
arr << v if k.start_with?("#{t.to_s.capitalize}_")
|
40
|
+
end
|
41
|
+
else
|
42
|
+
children["#{t.to_s.capitalize}_#{named}"]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Creates a new object of the given type and adds it to the current objects children
|
47
|
+
# if the current object supports children.
|
48
|
+
# Returns `self`. If a block is given, the new
|
49
|
+
# object will be yielded before adding to children.
|
50
|
+
def with_a(t, named: nil)
|
51
|
+
obj = Object.const_get("AbideDevUtils::Ppt::CodeGen::#{t.to_s.capitalize}").new
|
52
|
+
obj.title = named unless named.nil? || named.empty?
|
53
|
+
|
54
|
+
yield obj if block_given?
|
55
|
+
|
56
|
+
children["#{t.to_s.capitalize}_#{obj.id}"] = obj
|
57
|
+
self
|
58
|
+
end
|
59
|
+
alias and_a with_a
|
60
|
+
|
61
|
+
def has_a(t, named: nil)
|
62
|
+
obj = Object.const_get("AbideDevUtils::Ppt::CodeGen::#{t.to_s.capitalize}").new
|
63
|
+
obj.title = named unless named.nil? || named.empty?
|
64
|
+
children["#{t.to_s.capitalize}_#{obj.id}"] = obj
|
65
|
+
obj
|
66
|
+
end
|
67
|
+
alias and_has_a has_a
|
68
|
+
alias that_has_a has_a
|
69
|
+
|
70
|
+
# Sets the explicit value of the current object if the current object has an explicit value.
|
71
|
+
def that_equals(val)
|
72
|
+
self.value = val
|
73
|
+
self
|
74
|
+
end
|
75
|
+
alias and_assign_a_value_of that_equals
|
76
|
+
alias has_a_value_of that_equals
|
77
|
+
alias that_has_a_value_of that_equals
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def children
|
82
|
+
raise NotImplementedError, "#{type} does not support children" unless @supports_children
|
83
|
+
|
84
|
+
@children ||= {}
|
85
|
+
end
|
86
|
+
|
87
|
+
def value=(val)
|
88
|
+
@value = val if @supports_value
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'abide_dev_utils/ppt/code_gen/resource_types/base'
|
4
|
+
|
5
|
+
module AbideDevUtils
|
6
|
+
module Ppt
|
7
|
+
module CodeGen
|
8
|
+
class Class < Base
|
9
|
+
def initialize
|
10
|
+
super
|
11
|
+
@supports_children = true
|
12
|
+
@supports_value = true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'abide_dev_utils/ppt/code_gen/resource_types/base'
|
4
|
+
|
5
|
+
module AbideDevUtils
|
6
|
+
module Ppt
|
7
|
+
module CodeGen
|
8
|
+
class Manifest < Base
|
9
|
+
def initialize
|
10
|
+
super
|
11
|
+
@supports_children = true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'abide_dev_utils/ppt/code_gen/resource_types/base'
|
4
|
+
|
5
|
+
module AbideDevUtils
|
6
|
+
module Ppt
|
7
|
+
module CodeGen
|
8
|
+
class Parameter < Base
|
9
|
+
def initialize
|
10
|
+
@supports_children = true
|
11
|
+
@supports_value = true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|