rggen-core 0.28.0 → 0.30.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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +1 -1
  4. data/lib/rggen/core/base/component.rb +2 -2
  5. data/lib/rggen/core/builder/builder.rb +10 -1
  6. data/lib/rggen/core/builder/feature_entry_base.rb +42 -0
  7. data/lib/rggen/core/builder/feature_registry.rb +26 -24
  8. data/lib/rggen/core/builder/general_feature_entry.rb +40 -0
  9. data/lib/rggen/core/builder/input_component_registry.rb +2 -2
  10. data/lib/rggen/core/builder/layer.rb +18 -4
  11. data/lib/rggen/core/builder/list_feature_entry.rb +10 -23
  12. data/lib/rggen/core/builder/loader_registry.rb +3 -6
  13. data/lib/rggen/core/builder/simple_feature_entry.rb +9 -17
  14. data/lib/rggen/core/configuration/error.rb +6 -3
  15. data/lib/rggen/core/core_extensions/object.rb +2 -2
  16. data/lib/rggen/core/dsl.rb +1 -0
  17. data/lib/rggen/core/input_base/conversion_utility.rb +24 -0
  18. data/lib/rggen/core/input_base/error.rb +41 -0
  19. data/lib/rggen/core/input_base/feature.rb +20 -16
  20. data/lib/rggen/core/input_base/feature_factory.rb +24 -36
  21. data/lib/rggen/core/input_base/hash_list_parser.rb +38 -0
  22. data/lib/rggen/core/input_base/input_data.rb +2 -2
  23. data/lib/rggen/core/input_base/input_value.rb +3 -7
  24. data/lib/rggen/core/input_base/input_vaue_parser.rb +31 -0
  25. data/lib/rggen/core/input_base/option_array_parser.rb +33 -0
  26. data/lib/rggen/core/input_base/option_hash_parser.rb +104 -0
  27. data/lib/rggen/core/input_base/property.rb +6 -6
  28. data/lib/rggen/core/input_base/yaml_loader.rb +13 -16
  29. data/lib/rggen/core/register_map/error.rb +6 -3
  30. data/lib/rggen/core/utility/code_utility/source_file.rb +25 -0
  31. data/lib/rggen/core/version.rb +1 -1
  32. data/lib/rggen/core.rb +8 -0
  33. metadata +13 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 30286c1aefc400e1d6cda52dddc797fca2ad3a35fcf3a43578371a5b9a8fc4b0
4
- data.tar.gz: e7bb012b70a143c1412eab481febce79e7083ab83c22136f3e52540a41e67c69
3
+ metadata.gz: 977e436971681e3425cdb967c6a86d7debeb89fac6ab33db6e7ab1d831102b8f
4
+ data.tar.gz: 9d49db2290dfdc7b5c7dfc4a0369a2428ed9606f6487cad4c956c7144d46319f
5
5
  SHA512:
6
- metadata.gz: a14bd1ce40c782d0628e55f23a6acffa1578598a421bae4a7127c4464800078ac3181504e0a53b829581cfba4820b56fbc07803cf3fe338097479f4d3aca646a
7
- data.tar.gz: 524360603dae2839afe73e23a8c2cbedac3e2373e70a24e671d006977caf08dea6a5813d50a99a1724b3ab1a098b38134b0f653cbde2f9c6ee341d12596a73d0
6
+ metadata.gz: 999522157b4878363182b31f22a3a12c73c6908409b043c972df3885e9908df66b7093b27bfbe90da30b5dfcebffdcbcdc2ccb1b11da87ebed244f071c991134
7
+ data.tar.gz: 61149e6066502b04f73f525304745b7e555355c141944fb3e03a1043a6ab6761cd0637ffa90ca22c7d3e330d65020831031f525fa4a189b54c9834b78eccc551
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2017-2022 Taichi Ishitani
3
+ Copyright (c) 2017-2023 Taichi Ishitani
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -45,7 +45,7 @@ Feedbacks, bug reports, questions and etc. are wellcome! You can post them by us
45
45
 
46
46
  ## Copyright & License
47
47
 
48
- Copyright © 2017-2022 Taichi Ishitani. RgGen::Core is licensed under the [MIT License](https://opensource.org/licenses/MIT), see [LICENSE](LICENSE) for futher details.
48
+ Copyright © 2017-2023 Taichi Ishitani. RgGen::Core is licensed under the [MIT License](https://opensource.org/licenses/MIT), see [LICENSE](LICENSE) for futher details.
49
49
 
50
50
  ## Code of Conduct
51
51
 
@@ -75,9 +75,9 @@ module RgGen
75
75
 
76
76
  def define_proxy_call(receiver, method_name)
77
77
  (@proxy_receivers ||= {})[method_name.to_sym] = receiver
78
- define_singleton_method(method_name) do |*args, &block|
78
+ define_singleton_method(method_name) do |*args, **keywords, &block|
79
79
  name = __method__
80
- @proxy_receivers[name].__send__(name, *args, &block)
80
+ @proxy_receivers[name].__send__(name, *args, **keywords, &block)
81
81
  end
82
82
  end
83
83
  end
@@ -47,6 +47,7 @@ module RgGen
47
47
  end
48
48
 
49
49
  [
50
+ :define_feature,
50
51
  :define_simple_feature,
51
52
  :define_list_feature,
52
53
  :define_list_item_feature
@@ -73,7 +74,7 @@ module RgGen
73
74
  if targets.empty?
74
75
  @component_registries[type]
75
76
  else
76
- @component_registries[type].slice(*targets)
77
+ collect_component_factories(type, targets)
77
78
  end
78
79
  registries.each_value.map(&:build_factory)
79
80
  end
@@ -127,6 +128,14 @@ module RgGen
127
128
  (registries[name] = COMPONENT_REGISTRIES[type].new(name, self))
128
129
  body && Docile.dsl_eval(registries[name], &body) || registries[name]
129
130
  end
131
+
132
+ def collect_component_factories(type, targets)
133
+ unknown_components = targets - @component_registries[type].keys
134
+ unknown_components.empty? ||
135
+ (raise BuilderError.new("unknown component: #{unknown_components.first}"))
136
+
137
+ @component_registries[type].slice(*targets)
138
+ end
130
139
  end
131
140
  end
132
141
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module Builder
6
+ class FeatureEntryBase
7
+ def initialize(registry, name)
8
+ @registry = registry
9
+ @name = name
10
+ end
11
+
12
+ attr_reader :registry
13
+ attr_reader :name
14
+
15
+ def match_entry_type?(entry_type)
16
+ entry_type == entry_type_name
17
+ end
18
+
19
+ def build_factory(targets)
20
+ @factory.new(name) do |f|
21
+ f.target_features(target_features(targets))
22
+ f.target_feature(target_feature)
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def attach_shared_context(context, *targets)
29
+ (context && targets)&.each do |target|
30
+ target.attach_context(context)
31
+ end
32
+ end
33
+
34
+ def target_features(_tergets)
35
+ end
36
+
37
+ def target_feature
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -11,6 +11,10 @@ module RgGen
11
11
  @enabled_features = {}
12
12
  end
13
13
 
14
+ def define_feature(name, context = nil, &body)
15
+ create_new_entry(:general, name, context, &body)
16
+ end
17
+
14
18
  def define_simple_feature(name, context = nil, &body)
15
19
  create_new_entry(:simple, name, context, &body)
16
20
  end
@@ -26,12 +30,11 @@ module RgGen
26
30
  entry.define_feature(feature_name, context, &body)
27
31
  end
28
32
 
29
- def enable(feature_or_list_names, feature_names = nil)
30
- if feature_names
31
- list_name = feature_or_list_names
33
+ def enable(list_name = nil, feature_names)
34
+ if list_name
32
35
  (@enabled_features[list_name] ||= []).merge!(Array(feature_names))
33
36
  else
34
- Array(feature_or_list_names).each do |name|
37
+ Array(feature_names).each do |name|
35
38
  @enabled_features.key?(name) || (@enabled_features[name] = nil)
36
39
  end
37
40
  end
@@ -41,31 +44,23 @@ module RgGen
41
44
  @enabled_features.clear
42
45
  end
43
46
 
44
- def delete(feature_or_list_names = nil, feature_names = nil)
45
- if feature_names
46
- @feature_entries[feature_or_list_names]&.delete(feature_names)
47
- elsif feature_or_list_names
48
- Array(feature_or_list_names).each(&@feature_entries.method(:delete))
47
+ def delete(list_name = nil, feature_names)
48
+ if list_name
49
+ @feature_entries[list_name]&.delete(feature_names)
49
50
  else
50
- @feature_entries.clear
51
+ Array(feature_names).each(&@feature_entries.method(:delete))
51
52
  end
52
53
  end
53
54
 
54
- def simple_feature?(feature_name)
55
- @feature_entries[feature_name]&.match_entry_type?(:simple) || false
55
+ def delete_all
56
+ @feature_entries.clear
56
57
  end
57
58
 
58
- def list_feature?(list_name, feature_name = nil)
59
- return false unless @feature_entries[list_name]&.match_entry_type?(:list)
60
- return true unless feature_name
61
- @feature_entries[list_name].feature?(feature_name)
62
- end
63
-
64
- def feature?(feature_or_list_name, feature_name = nil)
65
- if feature_name
66
- list_feature?(feature_or_list_name, feature_name)
59
+ def feature?(list_name = nil, feature_name)
60
+ if list_name
61
+ list_feature?(list_name, feature_name)
67
62
  else
68
- simple_feature?(feature_or_list_name) || list_feature?(feature_or_list_name)
63
+ @feature_entries.key?(feature_name)
69
64
  end
70
65
  end
71
66
 
@@ -89,7 +84,9 @@ module RgGen
89
84
  private
90
85
 
91
86
  FEATURE_ENTRIES = {
92
- simple: SimpleFeatureEntry, list: ListFeatureEntry
87
+ general: GeneralFeatureEntry,
88
+ simple: SimpleFeatureEntry,
89
+ list: ListFeatureEntry
93
90
  }.freeze
94
91
 
95
92
  def create_new_entry(type, name, context, &body)
@@ -105,7 +102,7 @@ module RgGen
105
102
  end
106
103
 
107
104
  def enabled_list?(list_name)
108
- return false unless list_feature?(list_name)
105
+ return false unless @feature_entries[list_name]&.match_entry_type?(:list)
109
106
  return true if @enabled_features.empty?
110
107
  return true if @enabled_features.key?(list_name)
111
108
  false
@@ -114,6 +111,11 @@ module RgGen
114
111
  def build_factory(entry)
115
112
  entry.build_factory(@enabled_features[entry.name])
116
113
  end
114
+
115
+ def list_feature?(list_name, feature_name)
116
+ @feature_entries[list_name]&.match_entry_type?(:list) &&
117
+ @feature_entries[list_name]&.feature?(feature_name) || false
118
+ end
117
119
  end
118
120
  end
119
121
  end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module Builder
6
+ class GeneralFeatureEntry < FeatureEntryBase
7
+ include Base::SharedContext
8
+
9
+ def setup(base_feature, base_factory, context, &body)
10
+ @feature = Class.new(base_feature)
11
+ @factory = Class.new(base_factory)
12
+ attach_shared_context(context, @feature, @factory, self)
13
+ block_given? && Docile.dsl_eval(self, @name, &body)
14
+ end
15
+
16
+ def define_factory(&body)
17
+ @factory.class_exec(&body)
18
+ end
19
+
20
+ alias_method :factory, :define_factory
21
+
22
+ def define_feature(&body)
23
+ @feature.class_exec(&body)
24
+ end
25
+
26
+ alias_method :feature, :define_feature
27
+
28
+ private
29
+
30
+ def entry_type_name
31
+ :general
32
+ end
33
+
34
+ def target_feature
35
+ @feature
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -23,9 +23,9 @@ module RgGen
23
23
  block_given? && yield(@loader_registries[loader_type])
24
24
  end
25
25
 
26
- def define_value_extractor(loader_type, layers_or_value, value = nil, &body)
26
+ def define_value_extractor(loader_type, layers = nil, value, &body)
27
27
  @loader_registries[loader_type]
28
- .define_value_extractor(layers_or_value, value, &body)
28
+ .define_value_extractor(layers, value, &body)
29
29
  end
30
30
 
31
31
  def build_factory
@@ -53,6 +53,16 @@ module RgGen
53
53
  current_shared_context(false)
54
54
  end
55
55
 
56
+ def define_feature(feature_names, &body)
57
+ Array(feature_names).each do |feature_name|
58
+ do_proxy_call do |proxy|
59
+ proxy.body(body)
60
+ proxy.method_name(__method__)
61
+ proxy.feature_name(feature_name)
62
+ end
63
+ end
64
+ end
65
+
56
66
  def define_simple_feature(feature_names, &body)
57
67
  Array(feature_names).each do |feature_name|
58
68
  do_proxy_call do |proxy|
@@ -84,9 +94,9 @@ module RgGen
84
94
  end
85
95
  end
86
96
 
87
- def enable(feature_or_list_names, feature_names = nil)
97
+ def enable(...)
88
98
  @feature_registries.each_value do |registry|
89
- registry.enable(feature_or_list_names, feature_names)
99
+ registry.enable(...)
90
100
  end
91
101
  end
92
102
 
@@ -94,12 +104,16 @@ module RgGen
94
104
  @feature_registries.each_value(&:enable_all)
95
105
  end
96
106
 
97
- def delete(feature_or_list_names = nil, feature_names = nil)
107
+ def delete(...)
98
108
  @feature_registries.each_value do |registry|
99
- registry.delete(*[feature_or_list_names, feature_names].compact)
109
+ registry.delete(...)
100
110
  end
101
111
  end
102
112
 
113
+ def delete_all
114
+ @feature_registries.each_value(&:delete_all)
115
+ end
116
+
103
117
  private
104
118
 
105
119
  def define_proxy_call(name)
@@ -3,42 +3,27 @@
3
3
  module RgGen
4
4
  module Core
5
5
  module Builder
6
- class ListFeatureEntry
6
+ class ListFeatureEntry < FeatureEntryBase
7
7
  include Base::SharedContext
8
8
 
9
9
  def initialize(registry, name)
10
- @registry = registry
11
- @name = name
10
+ super(registry, name)
12
11
  @features = {}
13
12
  end
14
13
 
15
- attr_reader :registry
16
- attr_reader :name
17
-
18
14
  def setup(base_feature, base_factory, context, &body)
19
15
  @base_feature = Class.new(base_feature)
20
16
  @factory = Class.new(base_factory)
21
- context && attach_shared_context(context)
17
+ attach_shared_context(context, @base_feature, @factory, self)
22
18
  block_given? && Docile.dsl_eval(self, @name, &body)
23
19
  end
24
20
 
25
- def match_entry_type?(entry_type)
26
- entry_type == :list
27
- end
28
-
29
21
  def define_factory(&body)
30
22
  @factory.class_exec(&body)
31
23
  end
32
24
 
33
25
  alias_method :factory, :define_factory
34
26
 
35
- def build_factory(targets)
36
- @factory.new(@name) do |f|
37
- f.target_features(target_features(targets))
38
- f.target_feature(@default_feature)
39
- end
40
- end
41
-
42
27
  def define_base_feature(&body)
43
28
  body && @base_feature.class_exec(&body)
44
29
  end
@@ -51,7 +36,7 @@ module RgGen
51
36
  if context
52
37
  feature.method_defined?(:shared_context) &&
53
38
  (raise BuilderError.new('shared context has already been set'))
54
- feature.attach_context(context)
39
+ attach_shared_context(context, feature)
55
40
  end
56
41
  body && feature.class_exec(feature_name, &body)
57
42
  end
@@ -83,15 +68,17 @@ module RgGen
83
68
 
84
69
  private
85
70
 
86
- def attach_shared_context(context)
87
- [@factory, @base_feature, self].each do |target|
88
- target.attach_context(context)
89
- end
71
+ def entry_type_name
72
+ :list
90
73
  end
91
74
 
92
75
  def target_features(targets)
93
76
  targets && @features.slice(*targets) || @features
94
77
  end
78
+
79
+ def target_feature
80
+ @default_feature
81
+ end
95
82
  end
96
83
  end
97
84
  end
@@ -18,18 +18,15 @@ module RgGen
18
18
  @loaders.concat(Array(loaders))
19
19
  end
20
20
 
21
- def define_value_extractor(layers_or_value, value = nil, &body)
22
- value, layers = [value, layers_or_value].compact
21
+ def define_value_extractor(layers = nil, value, &body)
23
22
  @extractors << create_extractor(layers, value, &body)
24
23
  end
25
24
 
26
- def ignore_value(layers_or_value, value = nil)
27
- value, layers = [value, layers_or_value].compact
25
+ def ignore_value(layers = nil, value)
28
26
  ignore_values(layers, [value])
29
27
  end
30
28
 
31
- def ignore_values(layers_or_values, values = nil)
32
- values, layers = [values, layers_or_values].compact
29
+ def ignore_values(layers = nil, values)
33
30
  [layers].flatten.each do |layer|
34
31
  (@ignore_values[layer] ||= []).concat(Array(values))
35
32
  end
@@ -3,36 +3,28 @@
3
3
  module RgGen
4
4
  module Core
5
5
  module Builder
6
- class SimpleFeatureEntry
7
- def initialize(registry, name)
8
- @registry = registry
9
- @name = name
10
- end
11
-
12
- attr_reader :registry
13
- attr_reader :name
14
-
6
+ class SimpleFeatureEntry < FeatureEntryBase
15
7
  def setup(base_feature, factory, context, &body)
16
8
  @feature = define_feature(base_feature, context, &body)
17
9
  @factory = factory
18
10
  end
19
11
 
20
- def match_entry_type?(entry_type)
21
- entry_type == :simple
22
- end
12
+ private
23
13
 
24
- def build_factory(_enabled_features)
25
- @factory.new(@name) { |f| f.target_feature(@feature) }
14
+ def entry_type_name
15
+ :simple
26
16
  end
27
17
 
28
- private
29
-
30
18
  def define_feature(base, context, &body)
31
19
  feature = Class.new(base)
32
- context && feature.attach_context(context)
20
+ attach_shared_context(context, feature)
33
21
  block_given? && feature.class_exec(@name, &body)
34
22
  feature
35
23
  end
24
+
25
+ def target_feature
26
+ @feature
27
+ end
36
28
  end
37
29
  end
38
30
  end
@@ -7,9 +7,12 @@ module RgGen
7
7
  end
8
8
 
9
9
  module RaiseError
10
- def error(message, input_value = nil)
11
- position = input_value.position if input_value.respond_to?(:position)
12
- raise ConfigurationError.new(message, position || @position)
10
+ include InputBase::RaiseError
11
+
12
+ private
13
+
14
+ def error_exception
15
+ ConfigurationError
13
16
  end
14
17
  end
15
18
  end
@@ -8,7 +8,7 @@ class Object
8
8
  .then { |v| to.instance_variable_set(variable, v) }
9
9
  end
10
10
 
11
- def singleton_exec(*args, &block)
12
- singleton_class.class_exec(*args, &block)
11
+ def singleton_exec(...)
12
+ singleton_class.class_exec(...)
13
13
  end
14
14
  end
@@ -14,6 +14,7 @@ module RgGen
14
14
  :setup_loader,
15
15
  :load_plugin,
16
16
  :define_loader,
17
+ :define_feature,
17
18
  :define_simple_feature,
18
19
  :define_list_feature,
19
20
  :define_list_item_feature,
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module InputBase
6
+ module ConversionUtility
7
+ private
8
+
9
+ def to_int(value, position = nil)
10
+ v, pos =
11
+ if value.is_a?(InputValue)
12
+ [value.value, value.position]
13
+ else
14
+ [value, position]
15
+ end
16
+ Integer(v)
17
+ rescue ArgumentError, TypeError
18
+ message = yield(v)
19
+ error message, pos
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module InputBase
6
+ ApproximatelyErrorPosition = Struct.new(:position) do
7
+ def self.create(position)
8
+ position && new(position)
9
+ end
10
+
11
+ def to_s
12
+ "#{position} (approximately)"
13
+ end
14
+ end
15
+
16
+ module RaiseError
17
+ private
18
+
19
+ def error(message, position = nil)
20
+ pos = extract_error_position(position)
21
+ raise error_exception.new(message, pos)
22
+ end
23
+
24
+ def extract_error_position(position)
25
+ pos =
26
+ if position.respond_to?(:position)
27
+ position.position
28
+ else
29
+ position
30
+ end
31
+ pos ||
32
+ if respond_to?(:error_position)
33
+ error_position
34
+ else
35
+ @position
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -6,6 +6,7 @@ module RgGen
6
6
  class Feature < Base::Feature
7
7
  include Utility::RegexpPatterns
8
8
  include Utility::TypeChecker
9
+ include ConversionUtility
9
10
 
10
11
  class << self
11
12
  def property(name, **options, &body)
@@ -29,15 +30,13 @@ module RgGen
29
30
  end
30
31
 
31
32
  def build(&block)
32
- @builders ||= []
33
- @builders << block
33
+ (@builders ||= []) << block
34
34
  end
35
35
 
36
36
  attr_reader :builders
37
37
 
38
38
  def post_build(&block)
39
- @post_builders ||= []
40
- @post_builders << block
39
+ (@post_builders ||= []) << block
41
40
  end
42
41
 
43
42
  attr_reader :post_builders
@@ -64,8 +63,7 @@ module RgGen
64
63
  attr_reader :verifiers
65
64
 
66
65
  def printable(name, &body)
67
- @printables ||= {}
68
- @printables[name] = body
66
+ (@printables ||= {})[name] = body
69
67
  end
70
68
 
71
69
  attr_reader :printables
@@ -119,11 +117,22 @@ module RgGen
119
117
  end
120
118
 
121
119
  def inspect
122
- printable_values =
123
- printables&.map { |name, value| "#{name}: #{value.inspect}" }
120
+ printable_values = printables&.map { |name, value| "#{name}: #{value.inspect}" }
124
121
  (printable_values && "#{super}[#{printable_values.join(', ')}]") || super
125
122
  end
126
123
 
124
+ attr_reader :position
125
+
126
+ def error_position
127
+ if position
128
+ position
129
+ else
130
+ approximate_position =
131
+ component.features.map(&:position).find(&:itself)
132
+ ApproximatelyErrorPosition.create(approximate_position)
133
+ end
134
+ end
135
+
127
136
  private
128
137
 
129
138
  def do_build(args)
@@ -137,16 +146,12 @@ module RgGen
137
146
  self.class.builders.each { |builder| instance_exec(*args, &builder) }
138
147
  end
139
148
 
140
- attr_reader :position
141
-
142
149
  def match_automatically?
143
- matcher = self.class.input_matcher
144
- matcher&.match_automatically?
150
+ self.class.input_matcher&.match_automatically?
145
151
  end
146
152
 
147
153
  def match_pattern(rhs)
148
- matcher = self.class.input_matcher
149
- @match_data, @match_index = matcher&.match(rhs)
154
+ @match_data, @match_index = self.class.input_matcher&.match(rhs)
150
155
  end
151
156
 
152
157
  attr_reader :match_data
@@ -161,8 +166,7 @@ module RgGen
161
166
  end
162
167
 
163
168
  def do_verify(scope)
164
- self.class.verifiers&.[](scope)
165
- &.each { |verifier| verifier.verify(self) }
169
+ self.class.verifiers&.[](scope)&.each { |verifier| verifier.verify(self) }
166
170
  (@verified ||= {})[scope] = true
167
171
  end
168
172
 
@@ -18,12 +18,9 @@ module RgGen
18
18
  @default_value
19
19
  end
20
20
 
21
- def allow_options
22
- @allow_options = true
23
- end
24
-
25
- def allow_options?
26
- @allow_options || false
21
+ def value_format(format = nil, **options)
22
+ @value_format = [format, options] if format
23
+ @value_format
27
24
  end
28
25
  end
29
26
 
@@ -48,50 +45,41 @@ module RgGen
48
45
  def process_input_value(input_value)
49
46
  if passive_feature_factory?
50
47
  input_value
51
- elsif self.class.allow_options?
52
- process_input_value_with_options(input_value)
53
48
  else
54
- process_input_value_without_options(input_value)
49
+ process_active_input_value(input_value)
55
50
  end
56
51
  end
57
52
 
58
- def process_input_value_with_options(input_value)
59
- value, options =
60
- if string?(input_value)
61
- parse_string_value(input_value)
62
- else
63
- Array(input_value).then { |values| [values.first, values[1..]] }
53
+ def process_active_input_value(input_value)
54
+ parsed_value, options =
55
+ if self.class.value_format
56
+ parse_input_value(input_value, self.class.value_format)
64
57
  end
65
- value = convert_value(value, input_value.position) || value
66
- InputValue.new(value, options || [], input_value.position)
67
- end
68
-
69
- def parse_string_value(input_value)
70
- value, options = split_string(input_value, ':', 2)
71
- [value, parse_option_string(options)]
58
+ override_input_value(input_value, parsed_value, options) || input_value
72
59
  end
73
60
 
74
- def parse_option_string(option_string)
75
- split_string(option_string, /[,\n]/, 0)&.map do |option|
76
- name, value = split_string(option, ':', 2)
77
- value && [name, value] || name
78
- end
79
- end
61
+ VALUE_PARSERS = {
62
+ option_array: OptionArrayParser,
63
+ option_hash: OptionHashParser,
64
+ hash_list: HashListParser
65
+ }.freeze
80
66
 
81
- def split_string(string, separator, limit)
82
- string&.split(separator, limit)&.map(&:strip)
67
+ def parse_input_value(input_value, value_format)
68
+ format, options = value_format
69
+ VALUE_PARSERS[format].new(error_exception, **options).parse(input_value)
83
70
  end
84
71
 
85
- def process_input_value_without_options(input_value)
86
- value = convert_value(input_value.value, input_value.position)
87
- value && InputValue.new(value, input_value.position) || input_value
72
+ def override_input_value(input_value, parsed_value, options)
73
+ (convert_value(input_value, parsed_value) || parsed_value)
74
+ &.then { |v| InputValue.new(v, options, input_value.position) }
88
75
  end
89
76
 
90
- def convert_value(value, position)
77
+ def convert_value(input_value, parsed_value)
78
+ value = parsed_value || input_value.value
91
79
  if empty_value?(value)
92
- evaluate_defalt_value(position)
80
+ evaluate_defalt_value(input_value.position)
93
81
  else
94
- convert(value, position)
82
+ convert(value, input_value.position)
95
83
  end
96
84
  end
97
85
 
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module InputBase
6
+ class HashListParser < InputValueParser
7
+ def parse(input_value)
8
+ list =
9
+ if string?(input_value)
10
+ split_string(input_value, /^\s*$/, 0)
11
+ elsif hash?(input_value) && !input_value.empty?
12
+ [input_value]
13
+ else
14
+ Array(input_value)
15
+ end
16
+ [list.map { |item| parse_hash(item, input_value) }]
17
+ end
18
+
19
+ private
20
+
21
+ def parse_hash(item, input_value)
22
+ if string?(item)
23
+ parse_string_hash(item)
24
+ else
25
+ Hash(item)
26
+ end
27
+ rescue TypeError, ArgumentError
28
+ error "cannot convert #{item.inspect} into hash", input_value
29
+ end
30
+
31
+ def parse_string_hash(item)
32
+ split_string(item, /[,\n]/, 0)
33
+ .to_h { |element| split_string(element, ':', 2) }
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -21,8 +21,8 @@ module RgGen
21
21
  assign_value(symbolized_name, value, position)
22
22
  end
23
23
 
24
- def []=(value_name, position_or_value, value = nil)
25
- value(value_name, value || position_or_value, position_or_value)
24
+ def []=(value_name, position = nil, value)
25
+ value(value_name, value, position)
26
26
  end
27
27
 
28
28
  def [](value_name)
@@ -6,14 +6,10 @@ module RgGen
6
6
  class InputValue < ::SimpleDelegator
7
7
  NoValue = Object.new
8
8
 
9
- def initialize(value, options_or_position, position = NoValue)
9
+ def initialize(value, options = NoValue, position)
10
10
  super((value.is_a?(String) && value.strip) || value)
11
- @options, @position =
12
- if position.equal?(NoValue)
13
- [NoValue, options_or_position]
14
- else
15
- [options_or_position, position]
16
- end
11
+ @options = options
12
+ @position = position
17
13
  end
18
14
 
19
15
  alias_method :value, :__getobj__
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module InputBase
6
+ class InputValueParser
7
+ include Utility::TypeChecker
8
+
9
+ def initialize(exception, **_option)
10
+ @exception = exception
11
+ end
12
+
13
+ private
14
+
15
+ def split_string(string, separator, limit)
16
+ string&.split(separator, limit)&.map(&:strip)
17
+ end
18
+
19
+ def error(message, position_or_input_value = nil)
20
+ position =
21
+ if position_or_input_value.respond_to?(:position)
22
+ position_or_input_value.position
23
+ else
24
+ position_or_input_value
25
+ end
26
+ raise @exception.new(message, position)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module InputBase
6
+ class OptionArrayParser < InputValueParser
7
+ def parse(input_value)
8
+ value, options =
9
+ if string?(input_value)
10
+ parse_string_value(input_value)
11
+ else
12
+ Array(input_value).then { |v| [v.first, v[1..]] }
13
+ end
14
+ [value, options || []]
15
+ end
16
+
17
+ private
18
+
19
+ def parse_string_value(input_value)
20
+ value, option_string = split_string(input_value, ':', 2)
21
+ [value, parse_option_string(option_string)]
22
+ end
23
+
24
+ def parse_option_string(option_string)
25
+ split_string(option_string, /[,\n]/, 0)&.map do |option|
26
+ name_value = split_string(option, ':', 2)
27
+ name_value.size == 2 && name_value || name_value.first
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module InputBase
6
+ class OptionHashParser < InputValueParser
7
+ def initialize(exception, allowed_options: nil, multiple_values: false)
8
+ super
9
+ @allowed_options = allowed_options
10
+ @multiple_values = multiple_values
11
+ end
12
+
13
+ def parse(input_value)
14
+ values, options = parse_input_value(input_value)
15
+ check_result(values, options, input_value)
16
+ pack_result(values, options)
17
+ end
18
+
19
+ private
20
+
21
+ def parse_input_value(input_value)
22
+ values, options =
23
+ if string?(input_value)
24
+ parse_string_value(input_value)
25
+ elsif array?(input_value)
26
+ parse_array_value(input_value)
27
+ elsif hash?(input_value)
28
+ [nil, input_value]
29
+ elsif !input_value.empty_value?
30
+ [[input_value.value]]
31
+ end
32
+ [values || [], symbolize_keys(options) || {}]
33
+ end
34
+
35
+ def parse_string_value(input_value)
36
+ value_string, option_string = split_string(input_value, ':', 2)
37
+ values = split_string(value_string, /[,\n]/, 0)
38
+ options = parse_option_string(option_string, input_value.position)
39
+ [values, options]
40
+ end
41
+
42
+ def parse_option_string(option_string, position)
43
+ split_string(option_string, /[,\n]/, 0)
44
+ &.to_h { |option| split_string(option, ':', 2) }
45
+ rescue ArgumentError, TypeError
46
+ error "invalid options are given: #{option_string.inspect}", position
47
+ end
48
+
49
+ def parse_array_value(input_value)
50
+ input_value.each_with_object([[], {}]) do |item, (values, options)|
51
+ if value_item?(item, values)
52
+ values << item
53
+ else
54
+ update_option_hash(options, item, input_value.position)
55
+ end
56
+ end
57
+ end
58
+
59
+ def value_item?(item, values)
60
+ !hash?(item) && (@multiple_values || values.empty?)
61
+ end
62
+
63
+ def update_option_hash(option_hash, item, position)
64
+ option_hash.update(item)
65
+ rescue ArgumentError, TypeError
66
+ error "invalid option is given: #{item.inspect}", position
67
+ end
68
+
69
+ def symbolize_keys(options)
70
+ options&.transform_keys { |k| string?(k) && k.to_sym || k }
71
+ end
72
+
73
+ def check_result(values, options, input_value)
74
+ no_values?(values, options) &&
75
+ (error "no input values are given: #{input_value.inspect}", input_value)
76
+ illegal_value_size?(values) &&
77
+ (error "multiple input values are given: #{values}", input_value)
78
+ check_option(options, input_value.position)
79
+ end
80
+
81
+ def no_values?(values, options)
82
+ values.empty? && !options.empty?
83
+ end
84
+
85
+ def illegal_value_size?(values)
86
+ !@multiple_values && values.size > 1
87
+ end
88
+
89
+ def check_option(options, position)
90
+ return if @allowed_options.nil? || @allowed_options.empty?
91
+ return if options.nil? || options.empty?
92
+
93
+ unknown_options = options.keys - @allowed_options
94
+ unknown_options.empty? ||
95
+ (error "unknown options are given: #{unknown_options}", position)
96
+ end
97
+
98
+ def pack_result(values, options)
99
+ [@multiple_values && values || values.first, options]
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -23,16 +23,16 @@ module RgGen
23
23
 
24
24
  def define(feature)
25
25
  feature.class_exec(self) do |property|
26
- define_method(property.name) do |*args, &block|
27
- property.evaluate(self, args, &block)
26
+ define_method(property.name) do |*args, **keywords, &block|
27
+ property.evaluate(self, *args, **keywords, &block)
28
28
  end
29
29
  end
30
30
  end
31
31
 
32
- def evaluate(feature, args, &block)
32
+ def evaluate(feature, *args, **keywords, &block)
33
33
  feature.verify(@options[:verify]) if @options.key?(:verify)
34
34
  if proxy_property?
35
- proxy_property(feature, args, &block)
35
+ proxy_property(feature, *args, **keywords, &block)
36
36
  else
37
37
  default_property(feature)
38
38
  end
@@ -55,7 +55,7 @@ module RgGen
55
55
  ].any?
56
56
  end
57
57
 
58
- def proxy_property(feature, args, &block)
58
+ def proxy_property(feature, *args, **keywords, &block)
59
59
  receiver, method =
60
60
  if @costom_property
61
61
  [@costom_property.bind(feature), :call]
@@ -64,7 +64,7 @@ module RgGen
64
64
  else
65
65
  [feature, @options[:forward_to]]
66
66
  end
67
- receiver.__send__(method, *args, &block)
67
+ receiver.__send__(method, *args, **keywords, &block)
68
68
  end
69
69
 
70
70
  def default_property(feature)
@@ -55,18 +55,16 @@ module RgGen
55
55
  end
56
56
  end
57
57
 
58
- def register(node, object)
59
- obj =
60
- if override_object?(node)
61
- file = node.filename
62
- line = node.start_line + 1
63
- column = node.start_column + 1
64
- position = Position.new(file, line, column)
65
- InputValue.new(object, position)
66
- else
67
- object
68
- end
69
- super(node, obj)
58
+ def accept(node)
59
+ object = super
60
+ if override_object?(node)
61
+ file = node.filename
62
+ line = node.start_line + 1
63
+ column = node.start_column + 1
64
+ InputValue.new(object, Position.new(file, line, column))
65
+ else
66
+ object
67
+ end
70
68
  end
71
69
 
72
70
  private
@@ -100,10 +98,9 @@ module RgGen
100
98
  return result if ::Psych::VERSION >= '3.2.0'
101
99
 
102
100
  if result.match_class?(Hash)
103
- keys = result.keys
104
- keys.each do |key|
105
- result[key.to_sym] = symbolize_names(result.delete(key))
106
- end
101
+ result
102
+ .transform_keys!(&:to_sym)
103
+ .transform_values!(&method(:symbolize_names))
107
104
  elsif result.match_class?(Array)
108
105
  result.map! { |value| symbolize_names(value) }
109
106
  end
@@ -7,9 +7,12 @@ module RgGen
7
7
  end
8
8
 
9
9
  module RaiseError
10
- def error(message, input_value = nil)
11
- position = input_value.position if input_value.respond_to?(:position)
12
- raise RegisterMapError.new(message, position || @position)
10
+ include InputBase::RaiseError
11
+
12
+ private
13
+
14
+ def error_exception
15
+ RegisterMapError
13
16
  end
14
17
  end
15
18
  end
@@ -4,6 +4,8 @@ module RgGen
4
4
  module Core
5
5
  module Utility
6
6
  module CodeUtility
7
+ MacroDefinition = Struct.new(:name, :value)
8
+
7
9
  class SourceFile
8
10
  include CodeUtility
9
11
 
@@ -43,6 +45,15 @@ module RgGen
43
45
  include_files([file])
44
46
  end
45
47
 
48
+ def macro_definitions(macros)
49
+ @macro_definitions ||= []
50
+ @macro_definitions.concat(Array(macros))
51
+ end
52
+
53
+ def macro_definition(macro)
54
+ macro_definitions([macro])
55
+ end
56
+
46
57
  def body(&block)
47
58
  @bodies ||= []
48
59
  @bodies << block
@@ -65,6 +76,7 @@ module RgGen
65
76
  @file_header,
66
77
  include_guard_header,
67
78
  include_file_block,
79
+ macro_definition_block,
68
80
  *Array(@bodies),
69
81
  include_guard_footer
70
82
  ].compact
@@ -94,6 +106,19 @@ module RgGen
94
106
  end
95
107
  end
96
108
 
109
+ def macro_definition_block
110
+ @macro_definitions && lambda do
111
+ keyword = self.class.define_keyword
112
+ @macro_definitions.flat_map do |macro|
113
+ if macro.value.nil?
114
+ [keyword, space, macro.name, nl]
115
+ else
116
+ [keyword, space, macro.name, space, macro.value, nl]
117
+ end
118
+ end
119
+ end
120
+ end
121
+
97
122
  def include_guard_footer
98
123
  @guard_macro && (-> { self.class.endif_keyword })
99
124
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RgGen
4
4
  module Core
5
- VERSION = '0.28.0'
5
+ VERSION = '0.30.0'
6
6
  MAJOR, MINOR, PATCH = VERSION.split('.').map(&:to_i)
7
7
  end
8
8
  end
data/lib/rggen/core.rb CHANGED
@@ -42,6 +42,8 @@ require_relative 'core/base/feature_layer_extension'
42
42
  require_relative 'core/input_base/input_value'
43
43
  require_relative 'core/input_base/input_data'
44
44
  require_relative 'core/input_base/input_value_extractor'
45
+ require_relative 'core/input_base/error'
46
+ require_relative 'core/input_base/conversion_utility'
45
47
  require_relative 'core/input_base/loader'
46
48
  require_relative 'core/input_base/json_loader'
47
49
  require_relative 'core/input_base/toml_loader'
@@ -52,6 +54,10 @@ require_relative 'core/input_base/input_matcher'
52
54
  require_relative 'core/input_base/verifier'
53
55
  require_relative 'core/input_base/property'
54
56
  require_relative 'core/input_base/feature'
57
+ require_relative 'core/input_base/input_vaue_parser'
58
+ require_relative 'core/input_base/option_array_parser'
59
+ require_relative 'core/input_base/option_hash_parser'
60
+ require_relative 'core/input_base/hash_list_parser'
55
61
  require_relative 'core/input_base/feature_factory'
56
62
 
57
63
  require_relative 'core/configuration/input_data'
@@ -99,6 +105,8 @@ require_relative 'core/builder/component_registry'
99
105
  require_relative 'core/builder/loader_registry'
100
106
  require_relative 'core/builder/input_component_registry'
101
107
  require_relative 'core/builder/output_component_registry'
108
+ require_relative 'core/builder/feature_entry_base'
109
+ require_relative 'core/builder/general_feature_entry'
102
110
  require_relative 'core/builder/simple_feature_entry'
103
111
  require_relative 'core/builder/list_feature_entry'
104
112
  require_relative 'core/builder/feature_registry'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rggen-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.28.0
4
+ version: 0.30.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Taichi Ishitani
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-10-10 00:00:00.000000000 Z
11
+ date: 2023-04-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: docile
@@ -111,7 +111,9 @@ files:
111
111
  - lib/rggen/core/builder/builder.rb
112
112
  - lib/rggen/core/builder/component_entry.rb
113
113
  - lib/rggen/core/builder/component_registry.rb
114
+ - lib/rggen/core/builder/feature_entry_base.rb
114
115
  - lib/rggen/core/builder/feature_registry.rb
116
+ - lib/rggen/core/builder/general_feature_entry.rb
115
117
  - lib/rggen/core/builder/input_component_registry.rb
116
118
  - lib/rggen/core/builder/layer.rb
117
119
  - lib/rggen/core/builder/list_feature_entry.rb
@@ -142,14 +144,20 @@ files:
142
144
  - lib/rggen/core/generator.rb
143
145
  - lib/rggen/core/input_base/component.rb
144
146
  - lib/rggen/core/input_base/component_factory.rb
147
+ - lib/rggen/core/input_base/conversion_utility.rb
148
+ - lib/rggen/core/input_base/error.rb
145
149
  - lib/rggen/core/input_base/feature.rb
146
150
  - lib/rggen/core/input_base/feature_factory.rb
151
+ - lib/rggen/core/input_base/hash_list_parser.rb
147
152
  - lib/rggen/core/input_base/input_data.rb
148
153
  - lib/rggen/core/input_base/input_matcher.rb
149
154
  - lib/rggen/core/input_base/input_value.rb
150
155
  - lib/rggen/core/input_base/input_value_extractor.rb
156
+ - lib/rggen/core/input_base/input_vaue_parser.rb
151
157
  - lib/rggen/core/input_base/json_loader.rb
152
158
  - lib/rggen/core/input_base/loader.rb
159
+ - lib/rggen/core/input_base/option_array_parser.rb
160
+ - lib/rggen/core/input_base/option_hash_parser.rb
153
161
  - lib/rggen/core/input_base/property.rb
154
162
  - lib/rggen/core/input_base/toml_loader.rb
155
163
  - lib/rggen/core/input_base/verifier.rb
@@ -207,15 +215,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
207
215
  requirements:
208
216
  - - ">="
209
217
  - !ruby/object:Gem::Version
210
- version: '2.6'
218
+ version: '2.7'
211
219
  required_rubygems_version: !ruby/object:Gem::Requirement
212
220
  requirements:
213
221
  - - ">="
214
222
  - !ruby/object:Gem::Version
215
223
  version: '0'
216
224
  requirements: []
217
- rubygems_version: 3.3.7
225
+ rubygems_version: 3.4.10
218
226
  signing_key:
219
227
  specification_version: 4
220
- summary: rggen-core-0.28.0
228
+ summary: rggen-core-0.30.0
221
229
  test_files: []