rggen-core 0.20.0 → 0.24.0

Sign up to get free protection for your applications and to get access to all the features.
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