rggen-core 0.27.0 → 0.29.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 (34) 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 +14 -13
  8. data/lib/rggen/core/builder/general_feature_entry.rb +40 -0
  9. data/lib/rggen/core/builder/layer.rb +10 -0
  10. data/lib/rggen/core/builder/list_feature_entry.rb +10 -23
  11. data/lib/rggen/core/builder/plugin_manager.rb +11 -3
  12. data/lib/rggen/core/builder/simple_feature_entry.rb +9 -17
  13. data/lib/rggen/core/configuration/error.rb +8 -1
  14. data/lib/rggen/core/core_extensions/kernel.rb +13 -0
  15. data/lib/rggen/core/core_extensions/object.rb +4 -4
  16. data/lib/rggen/core/dsl.rb +1 -0
  17. data/lib/rggen/core/input_base/feature.rb +13 -15
  18. data/lib/rggen/core/input_base/feature_factory.rb +48 -12
  19. data/lib/rggen/core/input_base/hash_list_parser.rb +38 -0
  20. data/lib/rggen/core/input_base/input_matcher.rb +2 -2
  21. data/lib/rggen/core/input_base/input_value.rb +29 -7
  22. data/lib/rggen/core/input_base/input_vaue_parser.rb +26 -0
  23. data/lib/rggen/core/input_base/property.rb +8 -8
  24. data/lib/rggen/core/input_base/value_with_options_parser.rb +33 -0
  25. data/lib/rggen/core/input_base/yaml_loader.rb +99 -6
  26. data/lib/rggen/core/options.rb +1 -1
  27. data/lib/rggen/core/register_map/error.rb +8 -1
  28. data/lib/rggen/core/register_map/hash_loader.rb +4 -2
  29. data/lib/rggen/core/utility/code_utility/source_file.rb +25 -0
  30. data/lib/rggen/core/utility/regexp_patterns.rb +12 -0
  31. data/lib/rggen/core/utility/type_checker.rb +22 -0
  32. data/lib/rggen/core/version.rb +1 -1
  33. data/lib/rggen/core.rb +8 -0
  34. metadata +12 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 87457243bd057e719ca35386df5b23f6c0cc72a86029e93998b51d8436f0b184
4
- data.tar.gz: 96a4fd969fd9399e3a1bffdbc9319315bcd9a4df1f45827eb31517eb942bb489
3
+ metadata.gz: 18a9718f8b5e18dc5fff8f27e29df34c94017f3964cd63d2f6fa09eb5627a7de
4
+ data.tar.gz: 21993e58645d31298ec8a8044f1eb05d436a2a05b10215b8f93f5e91443daf03
5
5
  SHA512:
6
- metadata.gz: ab5f4642ecd2d47c88dfffe5432733c7c91320dace927c84d537cdc12be2e54ab70cf9e4ee32f47bd03f7ec044090f13e1b4a4efab6fa1f2549f6e99d3f05d5d
7
- data.tar.gz: 1faf35891545834a2ba9df954b15d818c65ea6910859c4987c8e587d495dcfd167fbbb0a5a9206d060fca16c817a004474d721298ac0f6fa9eecbef2dccb04dc
6
+ metadata.gz: 92e3f06ffd5182911e805c145b08ebea4e74e2e07e618eb7311be527b2abc8e2fdc41b50f82e1565d38798b109d12d325ce15da3262b4ac9aabcad0df077b824
7
+ data.tar.gz: fc15825417a32f84cddcc5b776b24a51c2f2bc495e82001ca3912a4e7f992e5bfa0b366a19d6ae37f080d3bad9258213a8701c9b9c5b8bff1332f0835fde4377
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
@@ -51,21 +55,11 @@ module RgGen
51
55
  end
52
56
  end
53
57
 
54
- def simple_feature?(feature_name)
55
- @feature_entries[feature_name]&.match_entry_type?(:simple) || false
56
- end
57
-
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
58
  def feature?(feature_or_list_name, feature_name = nil)
65
59
  if feature_name
66
60
  list_feature?(feature_or_list_name, feature_name)
67
61
  else
68
- simple_feature?(feature_or_list_name) || list_feature?(feature_or_list_name)
62
+ @feature_entries.key?(feature_or_list_name)
69
63
  end
70
64
  end
71
65
 
@@ -89,7 +83,9 @@ module RgGen
89
83
  private
90
84
 
91
85
  FEATURE_ENTRIES = {
92
- simple: SimpleFeatureEntry, list: ListFeatureEntry
86
+ general: GeneralFeatureEntry,
87
+ simple: SimpleFeatureEntry,
88
+ list: ListFeatureEntry
93
89
  }.freeze
94
90
 
95
91
  def create_new_entry(type, name, context, &body)
@@ -105,7 +101,7 @@ module RgGen
105
101
  end
106
102
 
107
103
  def enabled_list?(list_name)
108
- return false unless list_feature?(list_name)
104
+ return false unless @feature_entries[list_name]&.match_entry_type?(:list)
109
105
  return true if @enabled_features.empty?
110
106
  return true if @enabled_features.key?(list_name)
111
107
  false
@@ -114,6 +110,11 @@ module RgGen
114
110
  def build_factory(entry)
115
111
  entry.build_factory(@enabled_features[entry.name])
116
112
  end
113
+
114
+ def list_feature?(list_name, feature_name)
115
+ @feature_entries[list_name]&.match_entry_type?(:list) &&
116
+ @feature_entries[list_name]&.feature?(feature_name) || false
117
+ end
117
118
  end
118
119
  end
119
120
  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
@@ -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|
@@ -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
@@ -47,7 +47,7 @@ module RgGen
47
47
  def find_gemspec_by_path(path)
48
48
  Gem::Specification
49
49
  .each.find { |spec| match_gemspec_path?(spec, path) }
50
- .yield_self { |spec| spec && [spec.name, spec.version] }
50
+ .then { |spec| spec && [spec.name, spec.version] }
51
51
  end
52
52
 
53
53
  def match_gemspec_path?(gemspec, path)
@@ -88,8 +88,8 @@ module RgGen
88
88
  end
89
89
 
90
90
  def activate_plugins
91
- @plugins.each { |plugin| plugin.activate(@builder) }
92
- @plugins.each { |plugin| plugin.activate_additionally(@builder) }
91
+ do_normal_activation
92
+ do_addtional_activation
93
93
  end
94
94
 
95
95
  def activate_plugin_by_name(plugin_name)
@@ -136,6 +136,14 @@ module RgGen
136
136
  &.reject(&:blank?)
137
137
  &.map { |entry| entry.split(',', 2) }
138
138
  end
139
+
140
+ def do_normal_activation
141
+ @plugins.each { |plugin| plugin.activate(@builder) }
142
+ end
143
+
144
+ def do_addtional_activation
145
+ @plugins.each { |plugin| plugin.activate_additionally(@builder) }
146
+ end
139
147
  end
140
148
  end
141
149
  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,7 +7,14 @@ module RgGen
7
7
  end
8
8
 
9
9
  module RaiseError
10
- def error(message, position = nil)
10
+ private
11
+
12
+ def error_exception
13
+ ConfigurationError
14
+ end
15
+
16
+ def error(message, input_value = nil)
17
+ position = input_value.position if input_value.respond_to?(:position)
11
18
  raise ConfigurationError.new(message, position || @position)
12
19
  end
13
20
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kernel
4
+ alias_method :__orignal_Integer, :Integer
5
+
6
+ def Integer(arg, base = 0, exception: true)
7
+ arg = arg.__getobj__ if arg.is_a?(::Delegator)
8
+ __orignal_Integer(arg, base, exception: exception)
9
+ end
10
+
11
+ module_function :__orignal_Integer
12
+ module_function :Integer
13
+ end
@@ -4,11 +4,11 @@ class Object
4
4
  def export_instance_variable(variable, to)
5
5
  instance_variable_defined?(variable) &&
6
6
  instance_variable_get(variable)
7
- .yield_self { |v| block_given? ? yield(v) : v }
8
- .yield_self { |v| to.instance_variable_set(variable, v) }
7
+ .then { |v| block_given? ? yield(v) : v }
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,
@@ -5,6 +5,7 @@ module RgGen
5
5
  module InputBase
6
6
  class Feature < Base::Feature
7
7
  include Utility::RegexpPatterns
8
+ include Utility::TypeChecker
8
9
 
9
10
  class << self
10
11
  def property(name, **options, &body)
@@ -50,8 +51,7 @@ module RgGen
50
51
  end
51
52
 
52
53
  def input_pattern(pattern_or_patterns, **options, &converter)
53
- @input_matcher =
54
- InputMatcher.new(pattern_or_patterns, **options, &converter)
54
+ @input_matcher = InputMatcher.new(pattern_or_patterns, **options, &converter)
55
55
  end
56
56
 
57
57
  attr_reader :input_matcher
@@ -88,9 +88,8 @@ module RgGen
88
88
  end
89
89
 
90
90
  def export_verifiers(subclass)
91
- subclass.instance_variable_set(
92
- :@verifiers, @verifiers.transform_values(&:dup)
93
- )
91
+ subclass
92
+ .instance_variable_set(:@verifiers, @verifiers.transform_values(&:dup))
94
93
  end
95
94
  end
96
95
 
@@ -104,9 +103,7 @@ module RgGen
104
103
  end
105
104
 
106
105
  def post_build
107
- self.class.post_builders&.each do |post_builder|
108
- instance_exec(&post_builder)
109
- end
106
+ self.class.post_builders&.each { |block| instance_exec(&block) }
110
107
  end
111
108
 
112
109
  def verify(scope)
@@ -114,9 +111,7 @@ module RgGen
114
111
  end
115
112
 
116
113
  def printables
117
- helper
118
- .printables
119
- &.map { |name, body| [name, printable(name, &body)] }
114
+ helper.printables&.map { |name, body| [name, printable(name, &body)] }
120
115
  end
121
116
 
122
117
  def printable?
@@ -133,10 +128,13 @@ module RgGen
133
128
 
134
129
  def do_build(args)
135
130
  @position = args.last.position
136
- value = args.last.value
137
- match_automatically? && match_pattern(value)
138
- Array(self.class.builders)
139
- .each { |builder| instance_exec(*args[0..-2], value, &builder) }
131
+ match_automatically? && match_pattern(args.last)
132
+ execute_build_blocks(args)
133
+ end
134
+
135
+ def execute_build_blocks(args)
136
+ args = [*args, args.last.options] if args.last.with_options?
137
+ self.class.builders.each { |builder| instance_exec(*args, &builder) }
140
138
  end
141
139
 
142
140
  attr_reader :position
@@ -4,6 +4,8 @@ module RgGen
4
4
  module Core
5
5
  module InputBase
6
6
  class FeatureFactory < Base::FeatureFactory
7
+ include Utility::TypeChecker
8
+
7
9
  class << self
8
10
  def convert_value(&block)
9
11
  @value_converter = block
@@ -15,10 +17,15 @@ module RgGen
15
17
  @default_value = block if block_given?
16
18
  @default_value
17
19
  end
20
+
21
+ def value_format(format = nil)
22
+ @value_format = format if format
23
+ @value_format
24
+ end
18
25
  end
19
26
 
20
27
  def create(component, *args)
21
- input_value = preprocess(args.last)
28
+ input_value = process_input_value(args.last)
22
29
  create_feature(component, *args[0..-2], input_value) do |feature|
23
30
  build_feature(feature, input_value)
24
31
  feature.verify(:feature)
@@ -35,20 +42,49 @@ module RgGen
35
42
 
36
43
  private
37
44
 
38
- def preprocess(input_value)
39
- converted_value =
40
- active_feature_factory? && convert_value(input_value)
41
- converted_value || input_value
45
+ def process_input_value(input_value)
46
+ if passive_feature_factory?
47
+ input_value
48
+ else
49
+ process_active_input_value(input_value)
50
+ end
42
51
  end
43
52
 
44
- def convert_value(input_value)
45
- new_value =
46
- if input_value.empty_value?
47
- evaluate_defalt_value(input_value.position)
48
- else
49
- convert(input_value.value, input_value.position)
53
+ def process_active_input_value(input_value)
54
+ parseed_value, options =
55
+ if self.class.value_format
56
+ parse_input_value(input_value, self.class.value_format)
50
57
  end
51
- new_value && InputValue.new(new_value, input_value.position)
58
+ override_input_value(input_value, parseed_value, options) || input_value
59
+ end
60
+
61
+ VALUE_PARSERS = {
62
+ value_with_options: ValueWithOptionsParser,
63
+ hash_list: HashListParser
64
+ }.freeze
65
+
66
+ def parse_input_value(input_value, value_format)
67
+ VALUE_PARSERS[value_format].new(error_exception).parse(input_value)
68
+ end
69
+
70
+ def override_input_value(input_value, parseed_value, options)
71
+ (convert_value(input_value, parseed_value) || parseed_value)
72
+ &.then { |v| InputValue.new(v, options, input_value.position) }
73
+ end
74
+
75
+ def convert_value(input_value, parseed_value)
76
+ value = parseed_value || input_value.value
77
+ if empty_value?(value)
78
+ evaluate_defalt_value(input_value.position)
79
+ else
80
+ convert(value, input_value.position)
81
+ end
82
+ end
83
+
84
+ def empty_value?(value)
85
+ return true if value.nil?
86
+ return value.empty? if value.respond_to?(:empty?)
87
+ false
52
88
  end
53
89
 
54
90
  def evaluate_defalt_value(position)
@@ -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
@@ -13,8 +13,8 @@ module RgGen
13
13
  def match(rhs)
14
14
  rhs
15
15
  .to_s
16
- .yield_self { |s| ignore_blanks? && delete_blanks(s) || s }
17
- .yield_self(&method(:match_patterns))
16
+ .then { |s| ignore_blanks? && delete_blanks(s) || s }
17
+ .then(&method(:match_patterns))
18
18
  end
19
19
 
20
20
  def match_automatically?
@@ -3,21 +3,43 @@
3
3
  module RgGen
4
4
  module Core
5
5
  module InputBase
6
- class InputValue
7
- def initialize(value, position)
8
- @value = (value.is_a?(String) && value.strip) || value
9
- @position = position
6
+ class InputValue < ::SimpleDelegator
7
+ NoValue = Object.new
8
+
9
+ def initialize(value, options_or_position, position = NoValue)
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
10
17
  end
11
18
 
12
- attr_accessor :value
19
+ alias_method :value, :__getobj__
20
+
13
21
  attr_reader :position
22
+ attr_reader :options
23
+
24
+ def ==(other)
25
+ __getobj__ == other ||
26
+ other.is_a?(InputValue) && __getobj__ == other.__getobj__
27
+ end
28
+
29
+ def match_class?(klass)
30
+ __getobj__.is_a?(klass)
31
+ end
14
32
 
15
33
  def empty_value?
16
- return true if @value.nil?
17
- return true if @value.respond_to?(:empty?) && @value.empty?
34
+ return true if value.nil?
35
+ return true if value.respond_to?(:empty?) && value.empty?
18
36
  false
19
37
  end
20
38
 
39
+ def with_options?
40
+ !@options.equal?(NoValue)
41
+ end
42
+
21
43
  def available?
22
44
  true
23
45
  end
@@ -0,0 +1,26 @@
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)
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, input_value = nil)
20
+ position = input_value.position if input_value.respond_to?(:position)
21
+ raise @exception.new(message, position)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ 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)
@@ -80,8 +80,8 @@ module RgGen
80
80
 
81
81
  def set_initial_value(feature, varible_name)
82
82
  @options[:initial]
83
- .yield_self { |v| evaluate_default_initial_value(feature, v) }
84
- .yield_self { |v| feature.instance_variable_set(varible_name, v) }
83
+ .then { |v| evaluate_default_initial_value(feature, v) }
84
+ .then { |v| feature.instance_variable_set(varible_name, v) }
85
85
  end
86
86
 
87
87
  def evaluate_default_initial_value(feature, value)
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module InputBase
6
+ class ValueWithOptionsParser < 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
@@ -4,15 +4,108 @@ module RgGen
4
4
  module Core
5
5
  module InputBase
6
6
  module YAMLLoader
7
+ Position = Struct.new(:file, :line, :column) do
8
+ def to_s
9
+ "file #{file} line #{line} column #{column}"
10
+ end
11
+ end
12
+
13
+ module PsychExtension
14
+ refine ::Psych::Nodes::Node do
15
+ attr_accessor :filename
16
+
17
+ attr_writer :mapping_key
18
+
19
+ def mapping_key?
20
+ @mapping_key || false
21
+ end
22
+ end
23
+ end
24
+
25
+ using PsychExtension
26
+
27
+ class TreeBuilder < ::Psych::TreeBuilder
28
+ def initialize(filename)
29
+ super()
30
+ @filename = filename
31
+ end
32
+
33
+ def set_start_location(node)
34
+ super
35
+ node.filename = @filename
36
+ end
37
+
38
+ def scalar(value, anchor, tag, plain, quated, style)
39
+ node = super
40
+ node.mapping_key = mapping_key?
41
+ node
42
+ end
43
+
44
+ private
45
+
46
+ def mapping_key?
47
+ @last.mapping? && @last.children.size.odd?
48
+ end
49
+ end
50
+
51
+ class Visitor < ::Psych::Visitors::ToRuby
52
+ if ::Psych::VERSION >= '3.2.0'
53
+ def initialize(scalar_scanner, class_loader)
54
+ super(scalar_scanner, class_loader, symbolize_names: true)
55
+ end
56
+ end
57
+
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
68
+ end
69
+
70
+ private
71
+
72
+ def override_object?(node)
73
+ node.mapping? || node.sequence? || (node.scalar? && !node.mapping_key?)
74
+ end
75
+ end
76
+
7
77
  private
8
78
 
9
79
  def load_yaml(file)
10
- yaml = File.binread(file)
11
- YAML.safe_load(
12
- yaml,
13
- permitted_classes: [Symbol], aliases: true,
14
- filename: file, symbolize_names: true
15
- )
80
+ parse_yaml(File.binread(file), file)
81
+ .then { |result| to_ruby(result) }
82
+ .then { |result| symbolize_names(result) }
83
+ end
84
+
85
+ def parse_yaml(yaml, file)
86
+ parser = ::Psych::Parser.new(TreeBuilder.new(file))
87
+ parser.parse(yaml, file)
88
+ parser.handler.root.children.first
89
+ end
90
+
91
+ def to_ruby(result)
92
+ cl = ::Psych::ClassLoader::Restricted.new(['Symbol'], [])
93
+ ss = ::Psych::ScalarScanner.new(cl)
94
+ Visitor.new(ss, cl).accept(result)
95
+ end
96
+
97
+ def symbolize_names(result)
98
+ return result if ::Psych::VERSION >= '3.2.0'
99
+
100
+ if result.match_class?(Hash)
101
+ result
102
+ .transform_keys!(&:to_sym)
103
+ .transform_values!(&method(:symbolize_names))
104
+ elsif result.match_class?(Array)
105
+ result.map! { |value| symbolize_names(value) }
106
+ end
107
+
108
+ result
16
109
  end
17
110
  end
18
111
  end
@@ -119,7 +119,7 @@ module RgGen
119
119
  Options.add_option(:configuration) do |option|
120
120
  option.short_option '-c'
121
121
  option.long_option '--configuration FILE'
122
- option.default { ENV['RGGEN_DEFAULT_CONFIGURATION_FILE'] }
122
+ option.default { ENV.fetch('RGGEN_DEFAULT_CONFIGURATION_FILE', nil) }
123
123
  option.description 'Specify a configuration file'
124
124
  end
125
125
 
@@ -7,7 +7,14 @@ module RgGen
7
7
  end
8
8
 
9
9
  module RaiseError
10
- def error(message, position = nil)
10
+ private
11
+
12
+ def error_exception
13
+ RegisterMapError
14
+ end
15
+
16
+ def error(message, input_value = nil)
17
+ position = input_value.position if input_value.respond_to?(:position)
11
18
  raise RegisterMapError.new(message, position || @position)
12
19
  end
13
20
  end
@@ -4,6 +4,8 @@ module RgGen
4
4
  module Core
5
5
  module RegisterMap
6
6
  module HashLoader
7
+ include Utility::TypeChecker
8
+
7
9
  private
8
10
 
9
11
  SUB_LAYER_KEYS = {
@@ -21,7 +23,7 @@ module RgGen
21
23
  }.freeze
22
24
 
23
25
  def format_layer_data(read_data, layer, file)
24
- if read_data.is_a?(Array)
26
+ if array?(read_data)
25
27
  format_array_layer_data(read_data, layer, file)
26
28
  else
27
29
  fomrat_hash_layer_data(read_data, layer, file)
@@ -39,7 +41,7 @@ module RgGen
39
41
  end
40
42
 
41
43
  def format_sub_layer_data(read_data, layer, file)
42
- if read_data.is_a?(Array)
44
+ if array?(read_data)
43
45
  format_array_sub_layer_data(read_data, layer, file)
44
46
  else
45
47
  format_hash_sub_layer_data(read_data, layer, file)
@@ -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
@@ -32,6 +32,18 @@ module RgGen
32
32
  def integer
33
33
  INTEGER_PATTERN
34
34
  end
35
+
36
+ TRUTHY_PATTERN = /true|on|yes/i.freeze
37
+
38
+ def truthy_pattern
39
+ TRUTHY_PATTERN
40
+ end
41
+
42
+ FALSEY_PATTERN = /false|off|no/i.freeze
43
+
44
+ def falsey_pattern
45
+ FALSEY_PATTERN
46
+ end
35
47
  end
36
48
  end
37
49
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module Utility
6
+ module TypeChecker
7
+ [String, Symbol, Integer, Array, Hash].each do |klass|
8
+ module_eval(<<~DEFINE_METHOD, __FILE__, __LINE__ + 1)
9
+ # module_function def string?(value)
10
+ # return value.match_class?(String) if value.respond_to?(:match_class?)
11
+ # value.is_a?(String)
12
+ # end
13
+ module_function def #{klass.to_s.downcase}?(value)
14
+ return value.match_class?(#{klass}) if value.respond_to?(:match_class?)
15
+ value.is_a?(#{klass})
16
+ end
17
+ DEFINE_METHOD
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RgGen
4
4
  module Core
5
- VERSION = '0.27.0'
5
+ VERSION = '0.29.0'
6
6
  MAJOR, MINOR, PATCH = VERSION.split('.').map(&:to_i)
7
7
  end
8
8
  end
data/lib/rggen/core.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'delegate'
3
4
  require 'docile'
4
5
  require 'erubi'
5
6
  require 'fileutils'
@@ -14,6 +15,7 @@ require 'yaml'
14
15
  require_relative 'core/version'
15
16
 
16
17
  require_relative 'core/facets'
18
+ require_relative 'core/core_extensions/kernel'
17
19
  require_relative 'core/core_extensions/object'
18
20
 
19
21
  require_relative 'core/utility/attribute_setter'
@@ -24,6 +26,7 @@ require_relative 'core/utility/code_utility/structure_definition'
24
26
  require_relative 'core/utility/code_utility'
25
27
  require_relative 'core/utility/error_utility'
26
28
  require_relative 'core/utility/regexp_patterns'
29
+ require_relative 'core/utility/type_checker'
27
30
 
28
31
  require_relative 'core/exceptions'
29
32
 
@@ -49,6 +52,9 @@ require_relative 'core/input_base/input_matcher'
49
52
  require_relative 'core/input_base/verifier'
50
53
  require_relative 'core/input_base/property'
51
54
  require_relative 'core/input_base/feature'
55
+ require_relative 'core/input_base/input_vaue_parser'
56
+ require_relative 'core/input_base/value_with_options_parser'
57
+ require_relative 'core/input_base/hash_list_parser'
52
58
  require_relative 'core/input_base/feature_factory'
53
59
 
54
60
  require_relative 'core/configuration/input_data'
@@ -96,6 +102,8 @@ require_relative 'core/builder/component_registry'
96
102
  require_relative 'core/builder/loader_registry'
97
103
  require_relative 'core/builder/input_component_registry'
98
104
  require_relative 'core/builder/output_component_registry'
105
+ require_relative 'core/builder/feature_entry_base'
106
+ require_relative 'core/builder/general_feature_entry'
99
107
  require_relative 'core/builder/simple_feature_entry'
100
108
  require_relative 'core/builder/list_feature_entry'
101
109
  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.27.0
4
+ version: 0.29.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-07-05 00:00:00.000000000 Z
11
+ date: 2023-01-02 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
@@ -134,6 +136,7 @@ files:
134
136
  - lib/rggen/core/configuration/ruby_loader.rb
135
137
  - lib/rggen/core/configuration/toml_loader.rb
136
138
  - lib/rggen/core/configuration/yaml_loader.rb
139
+ - lib/rggen/core/core_extensions/kernel.rb
137
140
  - lib/rggen/core/core_extensions/object.rb
138
141
  - lib/rggen/core/dsl.rb
139
142
  - lib/rggen/core/exceptions.rb
@@ -143,14 +146,17 @@ files:
143
146
  - lib/rggen/core/input_base/component_factory.rb
144
147
  - lib/rggen/core/input_base/feature.rb
145
148
  - lib/rggen/core/input_base/feature_factory.rb
149
+ - lib/rggen/core/input_base/hash_list_parser.rb
146
150
  - lib/rggen/core/input_base/input_data.rb
147
151
  - lib/rggen/core/input_base/input_matcher.rb
148
152
  - lib/rggen/core/input_base/input_value.rb
149
153
  - lib/rggen/core/input_base/input_value_extractor.rb
154
+ - lib/rggen/core/input_base/input_vaue_parser.rb
150
155
  - lib/rggen/core/input_base/json_loader.rb
151
156
  - lib/rggen/core/input_base/loader.rb
152
157
  - lib/rggen/core/input_base/property.rb
153
158
  - lib/rggen/core/input_base/toml_loader.rb
159
+ - lib/rggen/core/input_base/value_with_options_parser.rb
154
160
  - lib/rggen/core/input_base/verifier.rb
155
161
  - lib/rggen/core/input_base/yaml_loader.rb
156
162
  - lib/rggen/core/options.rb
@@ -187,6 +193,7 @@ files:
187
193
  - lib/rggen/core/utility/code_utility/structure_definition.rb
188
194
  - lib/rggen/core/utility/error_utility.rb
189
195
  - lib/rggen/core/utility/regexp_patterns.rb
196
+ - lib/rggen/core/utility/type_checker.rb
190
197
  - lib/rggen/core/version.rb
191
198
  homepage: https://github.com/rggen/rggen-core
192
199
  licenses:
@@ -205,15 +212,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
205
212
  requirements:
206
213
  - - ">="
207
214
  - !ruby/object:Gem::Version
208
- version: '2.6'
215
+ version: '2.7'
209
216
  required_rubygems_version: !ruby/object:Gem::Requirement
210
217
  requirements:
211
218
  - - ">="
212
219
  - !ruby/object:Gem::Version
213
220
  version: '0'
214
221
  requirements: []
215
- rubygems_version: 3.3.3
222
+ rubygems_version: 3.4.1
216
223
  signing_key:
217
224
  specification_version: 4
218
- summary: rggen-core-0.27.0
225
+ summary: rggen-core-0.29.0
219
226
  test_files: []