rggen-core 0.22.0 → 0.25.1

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 (48) 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 +8 -1
  6. data/lib/rggen/core/base/component.rb +5 -6
  7. data/lib/rggen/core/base/component_factory.rb +8 -5
  8. data/lib/rggen/core/builder/builder.rb +23 -17
  9. data/lib/rggen/core/builder/component_registry.rb +8 -9
  10. data/lib/rggen/core/builder/feature_registry.rb +15 -15
  11. data/lib/rggen/core/builder/layer.rb +44 -29
  12. data/lib/rggen/core/builder/list_feature_entry.rb +5 -9
  13. data/lib/rggen/core/builder/loader_registry.rb +1 -2
  14. data/lib/rggen/core/builder/plugin_manager.rb +38 -43
  15. data/lib/rggen/core/builder/plugin_spec.rb +83 -0
  16. data/lib/rggen/core/builder/simple_feature_entry.rb +4 -4
  17. data/lib/rggen/core/configuration.rb +3 -2
  18. data/lib/rggen/core/configuration/toml_loader.rb +18 -0
  19. data/lib/rggen/core/core_extensions/object.rb +4 -4
  20. data/lib/rggen/core/dsl.rb +1 -1
  21. data/lib/rggen/core/exceptions.rb +6 -4
  22. data/lib/rggen/core/facets.rb +1 -1
  23. data/lib/rggen/core/input_base/component.rb +12 -0
  24. data/lib/rggen/core/input_base/component_factory.rb +1 -0
  25. data/lib/rggen/core/input_base/feature.rb +22 -8
  26. data/lib/rggen/core/input_base/input_data.rb +24 -17
  27. data/lib/rggen/core/input_base/input_matcher.rb +5 -5
  28. data/lib/rggen/core/input_base/loader.rb +15 -15
  29. data/lib/rggen/core/input_base/property.rb +17 -11
  30. data/lib/rggen/core/input_base/toml_loader.rb +16 -0
  31. data/lib/rggen/core/input_base/yaml_loader.rb +1 -18
  32. data/lib/rggen/core/options.rb +6 -0
  33. data/lib/rggen/core/output_base/code_generator.rb +5 -6
  34. data/lib/rggen/core/output_base/document_component_factory.rb +10 -0
  35. data/lib/rggen/core/output_base/feature.rb +15 -11
  36. data/lib/rggen/core/output_base/file_writer.rb +1 -1
  37. data/lib/rggen/core/output_base/source_file_component_factory.rb +15 -0
  38. data/lib/rggen/core/output_base/template_engine.rb +4 -5
  39. data/lib/rggen/core/plugin.rb +16 -0
  40. data/lib/rggen/core/register_map.rb +4 -5
  41. data/lib/rggen/core/register_map/hash_loader.rb +6 -9
  42. data/lib/rggen/core/register_map/toml_loader.rb +18 -0
  43. data/lib/rggen/core/utility/attribute_setter.rb +5 -0
  44. data/lib/rggen/core/utility/code_utility/code_block.rb +11 -5
  45. data/lib/rggen/core/utility/error_utility.rb +33 -6
  46. data/lib/rggen/core/version.rb +2 -4
  47. metadata +32 -6
  48. data/lib/rggen/core/base/proxy_call.rb +0 -18
@@ -15,11 +15,11 @@ module RgGen
15
15
  attr_reader :registry
16
16
  attr_reader :name
17
17
 
18
- def setup(base_feature, base_factory, context, body)
18
+ def setup(base_feature, base_factory, context, &body)
19
19
  @base_feature = Class.new(base_feature)
20
20
  @factory = Class.new(base_factory)
21
21
  context && attach_shared_context(context)
22
- body && Docile.dsl_eval(self, @name, &body)
22
+ block_given? && Docile.dsl_eval(self, @name, &body)
23
23
  end
24
24
 
25
25
  def match_entry_type?(entry_type)
@@ -49,9 +49,8 @@ module RgGen
49
49
  @features[feature_name] ||= Class.new(@base_feature)
50
50
  feature = @features[feature_name]
51
51
  if context
52
- feature.method_defined?(:shared_context) && (
53
- raise BuilderError.new('shared context has already been set')
54
- )
52
+ feature.method_defined?(:shared_context) &&
53
+ (raise BuilderError.new('shared context has already been set'))
55
54
  feature.attach_context(context)
56
55
  end
57
56
  body && feature.class_exec(feature_name, &body)
@@ -87,10 +86,7 @@ module RgGen
87
86
  end
88
87
 
89
88
  def target_features(enabled_features)
90
- enabled_features
91
- .select { |n| @features.key?(n) }
92
- .map { |n| [n, @features[n]] }
93
- .to_h
89
+ @features.slice(*enabled_features)
94
90
  end
95
91
  end
96
92
  end
@@ -19,8 +19,7 @@ module RgGen
19
19
  end
20
20
 
21
21
  def define_value_extractor(layers, value, &body)
22
- @extractors <<
23
- create_extractor(layers, value, &body)
22
+ @extractors << create_extractor(layers, value, &body)
24
23
  end
25
24
 
26
25
  def ignore_value(layers, value)
@@ -3,46 +3,22 @@
3
3
  module RgGen
4
4
  module Core
5
5
  module Builder
6
- class Plugin
7
- DEFAULT_PLUGIN_VERSION = '0.0.0'
8
-
6
+ class PluginRegistry
9
7
  def initialize(plugin_module, &block)
10
8
  @plugin_module = plugin_module
11
9
  @block = block
12
- plugin_name # check if plugin name is given
13
10
  end
14
11
 
15
12
  def default_setup(builder)
16
- @plugin_module.respond_to?(:default_setup) &&
17
- @plugin_module.default_setup(builder)
13
+ @plugin_module.plugin_spec.activate(builder)
18
14
  end
19
15
 
20
16
  def optional_setup(builder)
21
17
  @block && @plugin_module.instance_exec(builder, &@block)
22
18
  end
23
19
 
24
- def plugin_name
25
- if @plugin_module.const_defined?(:PLUGIN_NAME)
26
- @plugin_module.const_get(:PLUGIN_NAME)
27
- elsif @plugin_module.respond_to?(:plugin_name)
28
- @plugin_module.plugin_name
29
- else
30
- raise Core::PluginError.new('no plugin name is given')
31
- end
32
- end
33
-
34
- def version
35
- if @plugin_module.const_defined?(:VERSION)
36
- @plugin_module.const_get(:VERSION)
37
- elsif @plugin_module.respond_to?(:version)
38
- @plugin_module.version
39
- else
40
- DEFAULT_PLUGIN_VERSION
41
- end
42
- end
43
-
44
20
  def version_info
45
- "#{plugin_name} #{version}"
21
+ @plugin_module.plugin_spec.version_info
46
22
  end
47
23
  end
48
24
 
@@ -54,24 +30,25 @@ module RgGen
54
30
 
55
31
  def load_plugin(setup_path_or_name)
56
32
  setup_path_or_name = setup_path_or_name.to_s.strip
57
- setup_path =
33
+ setup_path, root_dir =
58
34
  if setup_file_directly_given?(setup_path_or_name)
59
- setup_path_or_name
35
+ [setup_path_or_name, extract_root_dir(setup_path_or_name)]
60
36
  else
61
- get_setup_path(setup_path_or_name)
37
+ [get_setup_path(setup_path_or_name), nil]
62
38
  end
63
- read_setup_file(setup_path, setup_path_or_name)
39
+ read_setup_file(setup_path, setup_path_or_name, root_dir)
64
40
  end
65
41
 
66
42
  def load_plugins(plugins, no_default_plugins, activation = true)
67
43
  RgGen.builder(@builder)
68
- merge_plugins(plugins, no_default_plugins)
69
- .each { |plugin| load_plugin(*plugin) }
44
+ merge_plugins(plugins, no_default_plugins).each(&method(:load_plugin))
70
45
  activation && activate_plugins
71
46
  end
72
47
 
73
- def setup(plugin_module, &block)
74
- @plugins << Plugin.new(plugin_module, &block)
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)
75
52
  end
76
53
 
77
54
  def activate_plugins(**options)
@@ -92,21 +69,35 @@ module RgGen
92
69
  File.basename(setup_path_or_name, '.*') == 'setup'
93
70
  end
94
71
 
72
+ def extract_root_dir(setup_path)
73
+ Pathname
74
+ .new(setup_path)
75
+ .ascend.find(&method(:rggen_dir?))
76
+ &.parent
77
+ &.to_s
78
+ end
79
+
80
+ def rggen_dir?(path)
81
+ path.each_filename.to_a[-2..-1] == ['lib', 'rggen']
82
+ end
83
+
95
84
  def get_setup_path(name)
96
85
  base, sub_directory = name.split('/', 2)
97
86
  base = base.sub(/^rggen[-_]/, '').tr('-', '_')
98
- File.join(*[
99
- 'rggen', base, sub_directory || '', 'setup'
100
- ].reject(&:empty?))
87
+ File.join(*['rggen', base, sub_directory, 'setup'].compact)
101
88
  end
102
89
 
103
- def read_setup_file(setup_path, setup_path_or_name)
90
+ def read_setup_file(setup_path, setup_path_or_name, root_dir)
91
+ root_dir && $LOAD_PATH.unshift(root_dir)
104
92
  require setup_path
105
93
  rescue ::LoadError
106
- raise Core::PluginError.new([
107
- "cannot load such plugin: #{setup_path_or_name}",
108
- setup_path_or_name != setup_path && " (#{setup_path})" || ''
109
- ].join)
94
+ message =
95
+ if setup_path_or_name == setup_path
96
+ "cannot load such plugin: #{setup_path_or_name}"
97
+ else
98
+ "cannot load such plugin: #{setup_path_or_name} (#{setup_path})"
99
+ end
100
+ raise Core::PluginError.new(message)
110
101
  end
111
102
 
112
103
  def merge_plugins(plugins, no_default_plugins)
@@ -134,6 +125,10 @@ module RgGen
134
125
  ENV['RGGEN_PLUGINS']
135
126
  &.split(':')&.map(&:strip)&.reject(&:empty?)
136
127
  end
128
+
129
+ def plugin?(plugin_module)
130
+ plugin_module.respond_to?(:plugin_spec) && plugin_module.plugin_spec
131
+ end
137
132
  end
138
133
  end
139
134
  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
@@ -12,8 +12,8 @@ module RgGen
12
12
  attr_reader :registry
13
13
  attr_reader :name
14
14
 
15
- def setup(base_feature, factory, context, body)
16
- @feature = define_feature(base_feature, context, body)
15
+ def setup(base_feature, factory, context, &body)
16
+ @feature = define_feature(base_feature, context, &body)
17
17
  @factory = factory
18
18
  end
19
19
 
@@ -27,10 +27,10 @@ module RgGen
27
27
 
28
28
  private
29
29
 
30
- def define_feature(base, context, body)
30
+ def define_feature(base, context, &body)
31
31
  feature = Class.new(base)
32
32
  context && feature.attach_context(context)
33
- body && feature.class_exec(@name, &body)
33
+ block_given? && feature.class_exec(@name, &body)
34
34
  feature
35
35
  end
36
36
  end
@@ -5,14 +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
13
  register_loader :ruby, RubyLoader
14
- register_loader :yaml, YAMLLoader
15
14
  register_loader :json, JSONLoader
15
+ register_loader :toml, TOMLLoader
16
+ register_loader :yaml, YAMLLoader
16
17
  end
17
18
  end
18
19
  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
@@ -2,10 +2,10 @@
2
2
 
3
3
  class Object
4
4
  def export_instance_variable(variable, to)
5
- return unless instance_variable_defined?(variable)
6
- v = instance_variable_get(variable)
7
- v = yield(v) if block_given?
8
- to.instance_variable_set(variable, v)
5
+ instance_variable_defined?(variable) &&
6
+ instance_variable_get(variable)
7
+ .yield_self { |v| block_given? ? yield(v) : v }
8
+ .yield_self { |v| to.instance_variable_set(variable, v) }
9
9
  end
10
10
 
11
11
  def singleton_exec(*args, &block)
@@ -20,7 +20,7 @@ module RgGen
20
20
  :disable_all,
21
21
  :disable,
22
22
  :delete,
23
- :setup,
23
+ :register_plugin,
24
24
  :load_plugin
25
25
  ].each do |method_name|
26
26
  def_delegator :'RgGen.builder', method_name
@@ -3,17 +3,19 @@
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
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'facets/array/merge'
4
4
  require 'facets/file/ext'
5
- require 'facets/hash/at'
5
+ require 'facets/hash/except' if RUBY_VERSION < '3.0.0'
6
6
  require 'facets/pathname/to_path'
7
7
  require 'facets/module/attr_setter'
8
8
  require 'facets/module/lastname'
@@ -9,10 +9,22 @@ module RgGen
9
9
  define_proxy_calls(feature, feature.properties)
10
10
  end
11
11
 
12
+ def document_only
13
+ @document_only = true
14
+ end
15
+
16
+ def document_only?
17
+ instance_variable_defined?(:@document_only) && @document_only
18
+ end
19
+
12
20
  def properties
13
21
  features.flat_map(&:properties)
14
22
  end
15
23
 
24
+ def post_build
25
+ features.each(&:post_build)
26
+ end
27
+
16
28
  def verify(scope)
17
29
  features.each { |feature| feature.verify(scope) }
18
30
  children.each { |child| child.verify(scope) } if scope == :all
@@ -79,6 +79,7 @@ module RgGen
79
79
  def post_build(component)
80
80
  exist_no_children?(component) &&
81
81
  raise_no_children_error(component)
82
+ component.post_build
82
83
  component.verify(:component)
83
84
  end
84
85
 
@@ -34,6 +34,13 @@ module RgGen
34
34
 
35
35
  attr_reader :builders
36
36
 
37
+ def post_build(&block)
38
+ @post_builders ||= []
39
+ @post_builders << block
40
+ end
41
+
42
+ attr_reader :post_builders
43
+
37
44
  def active_feature?
38
45
  !passive_feature?
39
46
  end
@@ -68,6 +75,7 @@ module RgGen
68
75
  export_instance_variable(:@properties, subclass, &:dup)
69
76
  export_instance_variable(:@ignore_empty_value, subclass)
70
77
  export_instance_variable(:@builders, subclass, &:dup)
78
+ export_instance_variable(:@post_builders, subclass, &:dup)
71
79
  export_instance_variable(:@input_matcher, subclass)
72
80
  export_instance_variable(:@printables, subclass, &:dup)
73
81
  export_verifiers(subclass) if @verifiers
@@ -95,6 +103,12 @@ module RgGen
95
103
  self.class.builders && do_build(args)
96
104
  end
97
105
 
106
+ def post_build
107
+ self.class.post_builders&.each do |post_builder|
108
+ instance_exec(&post_builder)
109
+ end
110
+ end
111
+
98
112
  def verify(scope)
99
113
  verified?(scope) || do_verify(scope)
100
114
  end
@@ -102,7 +116,7 @@ module RgGen
102
116
  def printables
103
117
  helper
104
118
  .printables
105
- &.map { |name, body| [name, printable(name, body)] }
119
+ &.map { |name, body| [name, printable(name, &body)] }
106
120
  end
107
121
 
108
122
  def printable?
@@ -119,10 +133,10 @@ module RgGen
119
133
 
120
134
  def do_build(args)
121
135
  @position = args.last.position
122
- args = [*args[0..-2], args.last.value]
123
- match_automatically? && match_pattern(args.last)
136
+ value = args.last.value
137
+ match_automatically? && match_pattern(value)
124
138
  Array(self.class.builders)
125
- .each { |builder| instance_exec(*args, &builder) }
139
+ .each { |builder| instance_exec(*args[0..-2], value, &builder) }
126
140
  end
127
141
 
128
142
  attr_reader :position
@@ -149,13 +163,13 @@ module RgGen
149
163
  end
150
164
 
151
165
  def do_verify(scope)
152
- Array(self.class.verifiers&.at(scope))
153
- .each { |verifier| verifier.verify(self) }
166
+ self.class.verifiers&.[](scope)
167
+ &.each { |verifier| verifier.verify(self) }
154
168
  (@verified ||= {})[scope] = true
155
169
  end
156
170
 
157
- def printable(name, body)
158
- body ? instance_exec(&body) : __send__(name)
171
+ def printable(name, &body)
172
+ block_given? ? instance_exec(&body) : __send__(name)
159
173
  end
160
174
  end
161
175
  end