rggen-core 0.28.0 → 0.30.0

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