rggen-core 0.27.0 → 0.29.0

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