rggen-core 0.22.0 → 0.25.1

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