rggen-core 0.20.0 → 0.24.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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +2 -1
  4. data/exe/rggen +2 -2
  5. data/lib/rggen/core.rb +9 -1
  6. data/lib/rggen/core/builder/builder.rb +30 -36
  7. data/lib/rggen/core/builder/component_registry.rb +8 -9
  8. data/lib/rggen/core/builder/feature_registry.rb +6 -9
  9. data/lib/rggen/core/builder/input_component_registry.rb +43 -10
  10. data/lib/rggen/core/builder/layer.rb +44 -29
  11. data/lib/rggen/core/builder/loader_registry.rb +48 -0
  12. data/lib/rggen/core/builder/plugin_manager.rb +122 -0
  13. data/lib/rggen/core/builder/plugin_spec.rb +83 -0
  14. data/lib/rggen/core/configuration.rb +5 -3
  15. data/lib/rggen/core/configuration/hash_loader.rb +4 -2
  16. data/lib/rggen/core/configuration/toml_loader.rb +18 -0
  17. data/lib/rggen/core/dsl.rb +3 -1
  18. data/lib/rggen/core/exceptions.rb +9 -4
  19. data/lib/rggen/core/facets.rb +0 -1
  20. data/lib/rggen/core/generator.rb +3 -3
  21. data/lib/rggen/core/input_base/feature.rb +2 -2
  22. data/lib/rggen/core/input_base/input_data.rb +8 -4
  23. data/lib/rggen/core/input_base/input_value_extractor.rb +34 -0
  24. data/lib/rggen/core/input_base/loader.rb +64 -20
  25. data/lib/rggen/core/input_base/toml_loader.rb +16 -0
  26. data/lib/rggen/core/input_base/yaml_loader.rb +12 -8
  27. data/lib/rggen/core/options.rb +18 -14
  28. data/lib/rggen/core/output_base/code_generator.rb +1 -1
  29. data/lib/rggen/core/plugin.rb +16 -0
  30. data/lib/rggen/core/printers.rb +11 -7
  31. data/lib/rggen/core/register_map.rb +6 -6
  32. data/lib/rggen/core/register_map/hash_loader.rb +58 -17
  33. data/lib/rggen/core/register_map/toml_loader.rb +18 -0
  34. data/lib/rggen/core/utility/attribute_setter.rb +5 -0
  35. data/lib/rggen/core/utility/error_utility.rb +33 -6
  36. data/lib/rggen/core/version.rb +2 -4
  37. metadata +32 -5
  38. data/lib/rggen/core/builder/plugins.rb +0 -79
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module Builder
6
+ class LoaderRegistry
7
+ def initialize
8
+ @loaders = []
9
+ @extractors = []
10
+ @ignore_values = {}
11
+ end
12
+
13
+ def register_loader(loader)
14
+ register_loaders([loader])
15
+ end
16
+
17
+ def register_loaders(loaders)
18
+ @loaders.concat(Array(loaders))
19
+ end
20
+
21
+ def define_value_extractor(layers, value, &body)
22
+ @extractors <<
23
+ create_extractor(layers, value, &body)
24
+ end
25
+
26
+ def ignore_value(layers, value)
27
+ ignore_values(layers, [value])
28
+ end
29
+
30
+ def ignore_values(layers, values)
31
+ [layers].flatten.each do |layer|
32
+ (@ignore_values[layer] ||= []).concat(Array(values))
33
+ end
34
+ end
35
+
36
+ def create_loaders
37
+ @loaders.map { |loader| loader.new(@extractors, @ignore_values) }
38
+ end
39
+
40
+ private
41
+
42
+ def create_extractor(layers, value, &body)
43
+ Class.new(Core::InputBase::InputValueExtractor, &body).new(layers, value)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module Builder
6
+ class PluginRegistry
7
+ def initialize(plugin_module, &block)
8
+ @plugin_module = plugin_module
9
+ @block = block
10
+ end
11
+
12
+ def default_setup(builder)
13
+ @plugin_module.plugin_spec.activate(builder)
14
+ end
15
+
16
+ def optional_setup(builder)
17
+ @block && @plugin_module.instance_exec(builder, &@block)
18
+ end
19
+
20
+ def version_info
21
+ @plugin_module.plugin_spec.version_info
22
+ end
23
+ end
24
+
25
+ class PluginManager
26
+ def initialize(builder)
27
+ @builder = builder
28
+ @plugins = []
29
+ end
30
+
31
+ def load_plugin(setup_path_or_name)
32
+ setup_path_or_name = setup_path_or_name.to_s.strip
33
+ setup_path =
34
+ if setup_file_directly_given?(setup_path_or_name)
35
+ setup_path_or_name
36
+ else
37
+ get_setup_path(setup_path_or_name)
38
+ end
39
+ read_setup_file(setup_path, setup_path_or_name)
40
+ end
41
+
42
+ def load_plugins(plugins, no_default_plugins, activation = true)
43
+ RgGen.builder(@builder)
44
+ merge_plugins(plugins, no_default_plugins).each(&method(:load_plugin))
45
+ activation && activate_plugins
46
+ end
47
+
48
+ def register_plugin(plugin_module, &block)
49
+ plugin?(plugin_module) ||
50
+ (raise Core::PluginError.new('no plugin spec is given'))
51
+ @plugins << PluginRegistry.new(plugin_module, &block)
52
+ end
53
+
54
+ def activate_plugins(**options)
55
+ options[:no_default_setup] ||
56
+ @plugins.each { |plugin| plugin.default_setup(@builder) }
57
+ options[:no_optional_setup] ||
58
+ @plugins.each { |plugin| plugin.optional_setup(@builder) }
59
+ end
60
+
61
+ def version_info
62
+ @plugins.map(&:version_info)
63
+ end
64
+
65
+ private
66
+
67
+ def setup_file_directly_given?(setup_path_or_name)
68
+ File.ext(setup_path_or_name) == 'rb' ||
69
+ File.basename(setup_path_or_name, '.*') == 'setup'
70
+ end
71
+
72
+ def get_setup_path(name)
73
+ base, sub_directory = name.split('/', 2)
74
+ base = base.sub(/^rggen[-_]/, '').tr('-', '_')
75
+ File.join(*['rggen', base, sub_directory, 'setup'].compact)
76
+ end
77
+
78
+ def read_setup_file(setup_path, setup_path_or_name)
79
+ require setup_path
80
+ rescue ::LoadError
81
+ message =
82
+ if setup_path_or_name == setup_path
83
+ "cannot load such plugin: #{setup_path_or_name}"
84
+ else
85
+ "cannot load such plugin: #{setup_path_or_name} (#{setup_path})"
86
+ end
87
+ raise Core::PluginError.new(message)
88
+ end
89
+
90
+ def merge_plugins(plugins, no_default_plugins)
91
+ [
92
+ *default_plugins(no_default_plugins),
93
+ *plugins_from_env,
94
+ *plugins
95
+ ]
96
+ end
97
+
98
+ DEFAULT_PLUGSINS = 'rggen/setup'
99
+
100
+ def default_plugins(no_default_plugins)
101
+ load_default_plugins?(no_default_plugins) && DEFAULT_PLUGSINS || nil
102
+ end
103
+
104
+ def load_default_plugins?(no_default_plugins)
105
+ return false if no_default_plugins
106
+ return false if ENV.key?('RGGEN_NO_DEFAULT_PLUGINS')
107
+ return false if Gem.find_files(DEFAULT_PLUGSINS).empty?
108
+ true
109
+ end
110
+
111
+ def plugins_from_env
112
+ ENV['RGGEN_PLUGINS']
113
+ &.split(':')&.map(&:strip)&.reject(&:empty?)
114
+ end
115
+
116
+ def plugin?(plugin_module)
117
+ plugin_module.respond_to?(:plugin_spec) && plugin_module.plugin_spec
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module Builder
6
+ class PluginSpec
7
+ def initialize(name, plugin_module)
8
+ @name = name
9
+ @plugin_module = plugin_module
10
+ @component_registrations = []
11
+ @loader_registrations = []
12
+ @files = []
13
+ end
14
+
15
+ def version(value = nil)
16
+ @version = value if value
17
+ version_value
18
+ end
19
+
20
+ def version_info
21
+ "#{@name} #{version}"
22
+ end
23
+
24
+ def register_component(component, layers = nil, &body)
25
+ @component_registrations << [component, layers, body]
26
+ end
27
+
28
+ def register_loader(component, loader_type, loader)
29
+ @loader_registrations << [component, loader_type, loader]
30
+ end
31
+
32
+ def register_loaders(component, loader_type, loaders)
33
+ Array(loaders)
34
+ .each { |loader| register_loader(component, loader_type, loader) }
35
+ end
36
+
37
+ def register_files(files)
38
+ root = File.dirname(caller_locations(1, 1).first.path)
39
+ files.each { |file| @files << File.join(root, file) }
40
+ end
41
+
42
+ alias_method :files, :register_files
43
+
44
+ def activate(builder)
45
+ activate_components(builder)
46
+ activate_loaders(builder)
47
+ load_files
48
+ end
49
+
50
+ private
51
+
52
+ DEFAULT_VERSION = '0.0.0'
53
+
54
+ def version_value
55
+ @version || const_version || DEFAULT_VERSION
56
+ end
57
+
58
+ def const_version
59
+ @plugin_module.const_defined?(:VERSION) &&
60
+ @plugin_module.const_get(:VERSION)
61
+ end
62
+
63
+ def activate_components(builder)
64
+ @component_registrations.each do |component, layers, body|
65
+ builder
66
+ .output_component_registry(component)
67
+ .register_component(layers, &body)
68
+ end
69
+ end
70
+
71
+ def activate_loaders(builder)
72
+ @loader_registrations.each do |component, loader_type, loader|
73
+ builder.register_loader(component, loader_type, loader)
74
+ end
75
+ end
76
+
77
+ def load_files
78
+ @files.each(&method(:require))
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -5,13 +5,15 @@ module RgGen
5
5
  module Configuration
6
6
  def self.setup(builder)
7
7
  builder.input_component_registry(:configuration) do
8
- register_component do
8
+ register_global_component do
9
9
  component Component, ComponentFactory
10
10
  feature Feature, FeatureFactory
11
11
  end
12
12
 
13
- base_loader Loader
14
- register_loaders [RubyLoader, JSONLoader, YAMLLoader]
13
+ register_loader :ruby, RubyLoader
14
+ register_loader :json, JSONLoader
15
+ register_loader :toml, TOMLLoader
16
+ register_loader :yaml, YAMLLoader
15
17
  end
16
18
  end
17
19
  end
@@ -4,8 +4,10 @@ module RgGen
4
4
  module Core
5
5
  module Configuration
6
6
  module HashLoader
7
- def format(read_data, file)
8
- input_data.values(Hash(read_data), file)
7
+ private
8
+
9
+ def format_layer_data(read_data, _layer, file)
10
+ Hash(read_data)
9
11
  rescue TypeError => e
10
12
  raise Core::LoadError.new(e.message, file)
11
13
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module Configuration
6
+ class TOMLLoader < Loader
7
+ include HashLoader
8
+ include InputBase::TOMLLoader
9
+
10
+ support_types [:toml]
11
+
12
+ def read_file(file)
13
+ load_toml(file)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -15,11 +15,13 @@ module RgGen
15
15
  :define_simple_feature,
16
16
  :define_list_feature,
17
17
  :define_list_item_feature,
18
+ :define_value_extractor,
18
19
  :enable,
19
20
  :disable_all,
20
21
  :disable,
21
22
  :delete,
22
- :setup
23
+ :register_plugin,
24
+ :load_plugin
23
25
  ].each do |method_name|
24
26
  def_delegator :'RgGen.builder', method_name
25
27
  end
@@ -3,23 +3,28 @@
3
3
  module RgGen
4
4
  module Core
5
5
  class RgGenError < StandardError
6
- def initialize(message, additional_info = nil)
6
+ def initialize(message, location_info = nil, verbose_info = nil)
7
7
  super(message)
8
8
  @error_message = message
9
- @additional_info = additional_info
9
+ @location_info = location_info
10
+ @verbose_info = verbose_info
10
11
  end
11
12
 
12
13
  attr_reader :error_message
13
- attr_reader :additional_info
14
+ attr_reader :location_info
15
+ attr_reader :verbose_info
14
16
 
15
17
  def to_s
16
- additional_info ? "#{super} -- #{additional_info}" : super
18
+ location_info && "#{super} -- #{location_info}" || super
17
19
  end
18
20
  end
19
21
 
20
22
  class BuilderError < RgGenError
21
23
  end
22
24
 
25
+ class PluginError < RgGenError
26
+ end
27
+
23
28
  class RuntimeError < RgGenError
24
29
  end
25
30
 
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'facets/array/merge'
4
4
  require 'facets/file/ext'
5
- require 'facets/hash/at'
6
5
  require 'facets/pathname/to_path'
7
6
  require 'facets/module/attr_setter'
8
7
  require 'facets/module/lastname'
@@ -4,7 +4,7 @@ module RgGen
4
4
  module Core
5
5
  class Generator
6
6
  def run(builder, options)
7
- load_setup_file(builder, options[:setup])
7
+ load_plugins(builder, options)
8
8
  load_configuration(builder, options[:configuration])
9
9
  load_register_map(builder, options.register_map_files)
10
10
  write_files(builder, options)
@@ -15,8 +15,8 @@ module RgGen
15
15
  attr_reader :configuration
16
16
  attr_reader :register_map
17
17
 
18
- def load_setup_file(builder, file)
19
- builder.load_setup_file(file)
18
+ def load_plugins(builder, options)
19
+ builder.load_plugins(options[:plugins], options[:no_default_plugins])
20
20
  end
21
21
 
22
22
  def load_configuration(builder, file)
@@ -149,8 +149,8 @@ module RgGen
149
149
  end
150
150
 
151
151
  def do_verify(scope)
152
- Array(self.class.verifiers&.at(scope))
153
- .each { |verifier| verifier.verify(self) }
152
+ self.class.verifiers&.[](scope)
153
+ &.each { |verifier| verifier.verify(self) }
154
154
  (@verified ||= {})[scope] = true
155
155
  end
156
156
 
@@ -51,9 +51,9 @@ module RgGen
51
51
  end
52
52
 
53
53
  def load_file(file)
54
- build_by_block(
55
- instance_eval("-> { #{File.binread(file)} }", file, 1)
56
- )
54
+ build_by_block(instance_eval(<<~BODY, file, 1))
55
+ -> { #{File.binread(file)} } # -> { File.binread(file) }
56
+ BODY
57
57
  end
58
58
 
59
59
  private
@@ -79,7 +79,11 @@ module RgGen
79
79
 
80
80
  def position_from_caller
81
81
  locations = caller_locations(3, 2)
82
- locations[0].path.include?('docile') ? locations[1] : locations[0]
82
+ include_docile_path?(locations[0]) && locations[1] || locations[0]
83
+ end
84
+
85
+ def include_docile_path?(caller_location)
86
+ caller_location.path.include?('docile')
83
87
  end
84
88
 
85
89
  def create_child_data(layer, &block)
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module InputBase
6
+ class InputValueExtractor
7
+ def initialize(target_layers, target_value)
8
+ @target_layers = Array(target_layers)
9
+ @target_value = target_value
10
+ end
11
+
12
+ class << self
13
+ attr_reader :extractor
14
+
15
+ private
16
+
17
+ def extract(&body)
18
+ @extractor = body
19
+ end
20
+ end
21
+
22
+ def target_value?(layer, value)
23
+ value == @target_value &&
24
+ (@target_layers.empty? || @target_layers.include?(layer))
25
+ end
26
+
27
+ def extract(input_data)
28
+ body = self.class.extractor
29
+ instance_exec(input_data, &body)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end