rggen-core 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/CODE_OF_CONDUCT.md +46 -0
  3. data/LICENSE +21 -0
  4. data/README.md +46 -0
  5. data/exe/rggen +13 -0
  6. data/lib/rggen/core.rb +101 -0
  7. data/lib/rggen/core/base/component.rb +54 -0
  8. data/lib/rggen/core/base/component_factory.rb +84 -0
  9. data/lib/rggen/core/base/feature.rb +46 -0
  10. data/lib/rggen/core/base/feature_factory.rb +37 -0
  11. data/lib/rggen/core/base/hierarchical_accessors.rb +91 -0
  12. data/lib/rggen/core/base/hierarchical_feature_accessors.rb +83 -0
  13. data/lib/rggen/core/base/internal_struct.rb +21 -0
  14. data/lib/rggen/core/base/shared_context.rb +18 -0
  15. data/lib/rggen/core/builder.rb +13 -0
  16. data/lib/rggen/core/builder/builder.rb +150 -0
  17. data/lib/rggen/core/builder/category.rb +116 -0
  18. data/lib/rggen/core/builder/component_entry.rb +29 -0
  19. data/lib/rggen/core/builder/component_registry.rb +47 -0
  20. data/lib/rggen/core/builder/feature_registry.rb +126 -0
  21. data/lib/rggen/core/builder/input_component_registry.rb +35 -0
  22. data/lib/rggen/core/builder/list_feature_entry.rb +98 -0
  23. data/lib/rggen/core/builder/output_component_registry.rb +10 -0
  24. data/lib/rggen/core/builder/simple_feature_entry.rb +39 -0
  25. data/lib/rggen/core/cli.rb +29 -0
  26. data/lib/rggen/core/configuration.rb +19 -0
  27. data/lib/rggen/core/configuration/component.rb +10 -0
  28. data/lib/rggen/core/configuration/component_factory.rb +19 -0
  29. data/lib/rggen/core/configuration/error.rb +16 -0
  30. data/lib/rggen/core/configuration/feature.rb +13 -0
  31. data/lib/rggen/core/configuration/feature_factory.rb +11 -0
  32. data/lib/rggen/core/configuration/hash_loader.rb +15 -0
  33. data/lib/rggen/core/configuration/json_loader.rb +18 -0
  34. data/lib/rggen/core/configuration/loader.rb +11 -0
  35. data/lib/rggen/core/configuration/ruby_loader.rb +15 -0
  36. data/lib/rggen/core/configuration/yaml_loader.rb +18 -0
  37. data/lib/rggen/core/core_extensions/casecmp.rb +12 -0
  38. data/lib/rggen/core/core_extensions/forwardable.rb +12 -0
  39. data/lib/rggen/core/core_extensions/forwardable_workaround.rb +22 -0
  40. data/lib/rggen/core/core_extensions/object.rb +14 -0
  41. data/lib/rggen/core/dsl.rb +30 -0
  42. data/lib/rggen/core/exceptions.rb +29 -0
  43. data/lib/rggen/core/facets.rb +7 -0
  44. data/lib/rggen/core/generator.rb +51 -0
  45. data/lib/rggen/core/input_base/component.rb +30 -0
  46. data/lib/rggen/core/input_base/component_factory.rb +88 -0
  47. data/lib/rggen/core/input_base/feature.rb +130 -0
  48. data/lib/rggen/core/input_base/feature_factory.rb +80 -0
  49. data/lib/rggen/core/input_base/input_data.rb +98 -0
  50. data/lib/rggen/core/input_base/input_matcher.rb +79 -0
  51. data/lib/rggen/core/input_base/input_value.rb +34 -0
  52. data/lib/rggen/core/input_base/json_loader.rb +16 -0
  53. data/lib/rggen/core/input_base/loader.rb +44 -0
  54. data/lib/rggen/core/input_base/property.rb +76 -0
  55. data/lib/rggen/core/input_base/verifier.rb +41 -0
  56. data/lib/rggen/core/input_base/yaml_loader.rb +34 -0
  57. data/lib/rggen/core/options.rb +181 -0
  58. data/lib/rggen/core/output_base/code_generator.rb +59 -0
  59. data/lib/rggen/core/output_base/component.rb +100 -0
  60. data/lib/rggen/core/output_base/component_factory.rb +35 -0
  61. data/lib/rggen/core/output_base/erb_engine.rb +21 -0
  62. data/lib/rggen/core/output_base/feature.rb +147 -0
  63. data/lib/rggen/core/output_base/feature_factory.rb +13 -0
  64. data/lib/rggen/core/output_base/file_writer.rb +40 -0
  65. data/lib/rggen/core/output_base/template_engine.rb +27 -0
  66. data/lib/rggen/core/printers.rb +53 -0
  67. data/lib/rggen/core/register_map.rb +21 -0
  68. data/lib/rggen/core/register_map/component.rb +20 -0
  69. data/lib/rggen/core/register_map/component_factory.rb +19 -0
  70. data/lib/rggen/core/register_map/error.rb +16 -0
  71. data/lib/rggen/core/register_map/feature.rb +22 -0
  72. data/lib/rggen/core/register_map/feature_factory.rb +11 -0
  73. data/lib/rggen/core/register_map/hash_loader.rb +47 -0
  74. data/lib/rggen/core/register_map/input_data.rb +34 -0
  75. data/lib/rggen/core/register_map/json_loader.rb +18 -0
  76. data/lib/rggen/core/register_map/loader.rb +15 -0
  77. data/lib/rggen/core/register_map/ruby_loader.rb +15 -0
  78. data/lib/rggen/core/register_map/yaml_loader.rb +18 -0
  79. data/lib/rggen/core/utility/attribute_setter.rb +53 -0
  80. data/lib/rggen/core/utility/code_utility.rb +64 -0
  81. data/lib/rggen/core/utility/code_utility/code_block.rb +88 -0
  82. data/lib/rggen/core/utility/code_utility/line.rb +51 -0
  83. data/lib/rggen/core/utility/code_utility/source_file.rb +104 -0
  84. data/lib/rggen/core/utility/code_utility/structure_definition.rb +54 -0
  85. data/lib/rggen/core/utility/regexp_patterns.rb +38 -0
  86. data/lib/rggen/core/version.rb +10 -0
  87. metadata +188 -0
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module InputBase
6
+ class Feature < Base::Feature
7
+ include Utility::RegexpPatterns
8
+
9
+ class << self
10
+ def property(name, **options, &body)
11
+ Property.define(self, name, **options, &body)
12
+ properties.include?(name) || properties << name
13
+ end
14
+
15
+ alias_method :field, :property
16
+
17
+ def properties
18
+ @properties ||= []
19
+ end
20
+
21
+ def ignore_empty_value(value = nil)
22
+ @ignore_empty_value = value unless value.nil?
23
+ @ignore_empty_value
24
+ end
25
+
26
+ def ignore_empty_value?
27
+ @ignore_empty_value.nil? || @ignore_empty_value
28
+ end
29
+
30
+ def build(&block)
31
+ @builders ||= []
32
+ @builders << block
33
+ end
34
+
35
+ attr_reader :builders
36
+
37
+ def active_feature?
38
+ !passive_feature?
39
+ end
40
+
41
+ def passive_feature?
42
+ builders.nil?
43
+ end
44
+
45
+ def input_pattern(pattern_or_patterns, **options, &converter)
46
+ @input_matcher =
47
+ InputMatcher.new(pattern_or_patterns, options, &converter)
48
+ end
49
+
50
+ attr_reader :input_matcher
51
+
52
+ def verify(scope, &block)
53
+ @verifiers ||= {}
54
+ (@verifiers[scope] ||= []) << Verifier.new(&block)
55
+ end
56
+
57
+ attr_reader :verifiers
58
+
59
+ def inherited(subclass)
60
+ super
61
+ export_instance_variable(:@properties, subclass, &:dup)
62
+ export_instance_variable(:@ignore_empty_value, subclass)
63
+ export_instance_variable(:@builders, subclass, &:dup)
64
+ export_instance_variable(:@input_matcher, subclass)
65
+ export_verifiers(subclass) if @verifiers
66
+ end
67
+
68
+ private
69
+
70
+ def export_verifiers(subclass)
71
+ copied_verifiers =
72
+ @verifiers.map { |scope, blocks| [scope, blocks.dup] }.to_h
73
+ subclass.instance_variable_set(:@verifiers, copied_verifiers)
74
+ end
75
+ end
76
+
77
+ delegate_to_class [
78
+ :properties, :active_feature?, :passive_feature?, :ignore_empty_value?
79
+ ]
80
+
81
+ def build(*args)
82
+ self.class.builders && do_build(args)
83
+ end
84
+
85
+ def verify(scope)
86
+ verified?(scope) || do_verify(scope)
87
+ end
88
+
89
+ private
90
+
91
+ def do_build(args)
92
+ @position = args.last.position
93
+ args = [*args[0..-2], args.last.value]
94
+ match_automatically? && match_pattern(args.last)
95
+ Array(self.class.builders)
96
+ .each { |builder| instance_exec(*args, &builder) }
97
+ end
98
+
99
+ attr_reader :position
100
+
101
+ def match_automatically?
102
+ matcher = self.class.input_matcher
103
+ matcher&.match_automatically?
104
+ end
105
+
106
+ def match_pattern(rhs)
107
+ matcher = self.class.input_matcher
108
+ @match_data, @match_index = matcher&.match(rhs)
109
+ end
110
+
111
+ attr_reader :match_data
112
+ attr_reader :match_index
113
+
114
+ def pattern_matched?
115
+ !match_data.nil?
116
+ end
117
+
118
+ def verified?(scope)
119
+ @verified && @verified[scope]
120
+ end
121
+
122
+ def do_verify(scope)
123
+ Array(self.class.verifiers&.at(scope))
124
+ .each { |verifier| verifier.verify(self) }
125
+ (@verified ||= {})[scope] = true
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module InputBase
6
+ class FeatureFactory < Base::FeatureFactory
7
+ class << self
8
+ def convert_value(&block)
9
+ @value_converter = block
10
+ end
11
+
12
+ attr_reader :value_converter
13
+
14
+ def default_value(&block)
15
+ @default_value = block if block_given?
16
+ @default_value
17
+ end
18
+ end
19
+
20
+ def create(component, *args)
21
+ input_value = preprocess(args.last)
22
+ create_feature(component, *args[0..-2], input_value) do |feature|
23
+ build_feature(feature, input_value)
24
+ feature.verify(:feature)
25
+ end
26
+ end
27
+
28
+ def active_feature_factory?
29
+ !passive_feature_factory?
30
+ end
31
+
32
+ def passive_feature_factory?
33
+ @target_features.nil? && @target_feature.passive_feature?
34
+ end
35
+
36
+ private
37
+
38
+ def preprocess(input_value)
39
+ converted_value =
40
+ active_feature_factory? && convert_value(input_value)
41
+ converted_value || input_value
42
+ end
43
+
44
+ def convert_value(input_value)
45
+ new_value =
46
+ if input_value.empty_value?
47
+ evaluate_defalt_value(input_value.position)
48
+ else
49
+ convert(input_value.value, input_value.position)
50
+ end
51
+ new_value && InputValue.new(new_value, input_value.position)
52
+ end
53
+
54
+ def evaluate_defalt_value(position)
55
+ block = self.class.default_value
56
+ block && instance_exec(position, &block)
57
+ end
58
+
59
+ def convert(value, position)
60
+ block = self.class.value_converter
61
+ block && instance_exec(value, position, &block)
62
+ end
63
+
64
+ def build_feature(feature, input_value)
65
+ build?(feature, input_value) && feature.build(input_value)
66
+ end
67
+
68
+ def build?(feature, input_value)
69
+ active_feature_factory? &&
70
+ input_value.available? &&
71
+ !ignore_empty_value?(feature, input_value)
72
+ end
73
+
74
+ def ignore_empty_value?(feature, input_value)
75
+ feature.ignore_empty_value? && input_value.empty_value?
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module InputBase
6
+ class InputData
7
+ def initialize(valid_value_lists)
8
+ @valid_value_lists = valid_value_lists
9
+ @values = Hash.new(NAValue)
10
+ @children = []
11
+ define_setter_methods
12
+ block_given? && yield(self)
13
+ end
14
+
15
+ def value(value_name, value, position = nil)
16
+ symbolized_name = value_name.to_sym
17
+ return unless valid_value?(symbolized_name)
18
+ @values[symbolized_name] =
19
+ case value
20
+ when InputValue
21
+ value
22
+ else
23
+ InputValue.new(value, position)
24
+ end
25
+ end
26
+
27
+ def []=(value_name, position = nil, value)
28
+ value(value_name, value, position)
29
+ end
30
+
31
+ def [](value_name)
32
+ @values[value_name]
33
+ end
34
+
35
+ def values(value_list = nil, position = nil)
36
+ value_list && Hash(value_list).each { |n, v| value(n, v, position) }
37
+ @values
38
+ end
39
+
40
+ attr_reader :children
41
+
42
+ def child(value_list = nil, &block)
43
+ create_child_data do |child_data|
44
+ child_data.build_by_block(block)
45
+ child_data.values(value_list)
46
+ @children << child_data
47
+ end
48
+ end
49
+
50
+ def load_file(file)
51
+ build_by_block(
52
+ instance_eval("-> { #{File.binread(file)} }", file, 1)
53
+ )
54
+ end
55
+
56
+ private
57
+
58
+ def valid_value?(value_name)
59
+ @valid_value_lists.first.include?(value_name)
60
+ end
61
+
62
+ def define_setter_methods
63
+ @valid_value_lists.first.each(&method(:define_setter_method))
64
+ end
65
+
66
+ def define_setter_method(value_name)
67
+ define_singleton_method(value_name) do |value, position = nil|
68
+ value_setter(value_name, value, position)
69
+ end
70
+ end
71
+
72
+ def value_setter(value_name, value, position)
73
+ position ||= position_from_caller
74
+ value(value_name, value, position)
75
+ end
76
+
77
+ def position_from_caller
78
+ locations = caller_locations(3, 2)
79
+ locations[0].path.include?('docile') ? locations[1] : locations[0]
80
+ end
81
+
82
+ def create_child_data(&block)
83
+ child_data_class.new(@valid_value_lists[1..-1], &block)
84
+ end
85
+
86
+ def child_data_class
87
+ InputData
88
+ end
89
+
90
+ protected
91
+
92
+ def build_by_block(block)
93
+ block && Docile.dsl_eval(self, &block)
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module InputBase
6
+ class InputMatcher
7
+ def initialize(pattern_or_patterns, options, &converter)
8
+ @options = options
9
+ @converter = converter
10
+ @patterns = format_patterns(pattern_or_patterns)
11
+ end
12
+
13
+ def match(rhs)
14
+ rhs = rhs.to_s
15
+ rhs = delete_blanks(rhs) if ignore_blanks?
16
+ match_patterns(rhs)
17
+ end
18
+
19
+ def match_automatically?
20
+ @options.fetch(:match_automatically, true)
21
+ end
22
+
23
+ private
24
+
25
+ def format_patterns(patterns)
26
+ if @options.fetch(:match_wholly, true)
27
+ patterns_hash(patterns)
28
+ .map { |i, pattern| [i, /\A#{pattern}\z/] }
29
+ .to_h
30
+ else
31
+ patterns_hash(patterns)
32
+ end
33
+ end
34
+
35
+ def patterns_hash(patterns)
36
+ if patterns.is_a?(Hash)
37
+ patterns
38
+ else
39
+ Array(patterns)
40
+ .map.with_index { |pattern, i| [i, pattern] }
41
+ .to_h
42
+ end
43
+ end
44
+
45
+ def ignore_blanks?
46
+ @options.fetch(:ignore_blanks, true)
47
+ end
48
+
49
+ DELETE_BLANK_PATTERN =
50
+ Regexp.union(
51
+ /(?<=\w)[[:blank:]]+(?=[[:punct:]&&[^_]])/,
52
+ /(?<=[[:punct:]&&[^_]])[[:blank:]]+(?=\w)/
53
+ ).freeze
54
+
55
+ COMPRESS_BLANK_PATTERN = /[[:blank:]]+/.freeze
56
+
57
+ def delete_blanks(rhs)
58
+ rhs
59
+ .strip
60
+ .gsub(DELETE_BLANK_PATTERN, '')
61
+ .gsub(COMPRESS_BLANK_PATTERN, ' ')
62
+ end
63
+
64
+ def match_patterns(rhs)
65
+ match_data, index =
66
+ @patterns
67
+ .map { |i, pattern| pattern.match(rhs) { |m| [m, i] } }
68
+ .compact
69
+ .max { |m| m[0].length }
70
+ match_data && [convert_match_data(match_data), index]
71
+ end
72
+
73
+ def convert_match_data(match_data)
74
+ @converter&.call(match_data) || match_data
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module InputBase
6
+ class InputValue
7
+ def initialize(value, position)
8
+ @value = (value.is_a?(String) && value.strip) || value
9
+ @position = position
10
+ end
11
+
12
+ attr_accessor :value
13
+ attr_reader :position
14
+
15
+ def empty_value?
16
+ return true if @value.nil?
17
+ return true if @value.respond_to?(:empty?) && @value.empty?
18
+ false
19
+ end
20
+
21
+ def available?
22
+ true
23
+ end
24
+ end
25
+
26
+ NAValue = InputValue.new(nil, nil).instance_eval do
27
+ def available?
28
+ false
29
+ end
30
+ freeze
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module InputBase
6
+ module JSONLoader
7
+ private
8
+
9
+ def load_json(file)
10
+ json = File.binread(file)
11
+ JSON.parse(json, symbolize_names: true)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module InputBase
6
+ class Loader
7
+ class << self
8
+ def support_types(types)
9
+ @support_types = types.map(&:to_sym)
10
+ end
11
+
12
+ def support?(file)
13
+ file_ext = File.ext(file).to_sym
14
+ @support_types.any? { |type| type.casecmp?(file_ext) }
15
+ end
16
+
17
+ def load_file(file, input_data, valid_value_list)
18
+ new(input_data, valid_value_list).load_file(file)
19
+ end
20
+ end
21
+
22
+ def initialize(input_data, valid_value_lists)
23
+ @input_data = input_data
24
+ @valid_value_lists = valid_value_lists
25
+ end
26
+
27
+ def load_file(file)
28
+ File.readable?(file) || (
29
+ raise Core::LoadError.new('cannot load such file', file)
30
+ )
31
+ format(read_file(file), file)
32
+ end
33
+
34
+ private
35
+
36
+ def format(_read_data, _file)
37
+ end
38
+
39
+ attr_reader :input_data
40
+ attr_reader :valid_value_lists
41
+ end
42
+ end
43
+ end
44
+ end