shinsei_config 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6af621e538e6ba8146f4ba7814770563595b1c522baa0010055e6c93d17641f0
4
+ data.tar.gz: b79735e216a52f3a899b4c395dda017df9da3cd5b829ea329937baf2857ce234
5
+ SHA512:
6
+ metadata.gz: d0e96f8135a98c3c61781c75a25e6af63d43a7ad67c6e7055b06933181149cbd9db7709f6a74cb305580c24c422003d41840514c81de61a8d4b414519278fc82
7
+ data.tar.gz: 718a2a75ffc48008cbf3726417a54c90304958f8264952524dab6af375bac0254cc657046417328cebfe459e7d9a09e6b15058183e5ae043be6e594be13c92d8
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,46 @@
1
+ plugins:
2
+ - rubocop-rake
3
+ - rubocop-rspec
4
+
5
+ AllCops:
6
+ TargetRubyVersion: 3.3
7
+ NewCops: enable
8
+
9
+ Style/StringLiterals:
10
+ EnforcedStyle: single_quotes
11
+
12
+ Style/StringLiteralsInInterpolation:
13
+ EnforcedStyle: single_quotes
14
+
15
+ Metrics/MethodLength:
16
+ Max: 20
17
+ Exclude:
18
+ - 'spec/**/*.rb'
19
+
20
+ Metrics/BlockLength:
21
+ Exclude:
22
+ - 'spec/**/*.rb'
23
+
24
+ Metrics/ClassLength:
25
+ Max: 200
26
+
27
+ Metrics/ParameterLists:
28
+ CountKeywordArgs: false
29
+
30
+ Layout/LeadingCommentSpace:
31
+ AllowRBSInlineAnnotation: true
32
+
33
+ RSpec/NamedSubject:
34
+ Enabled: false
35
+
36
+ RSpec/MultipleExpectations:
37
+ Enabled: false
38
+
39
+ RSpec/MultipleMemoizedHelpers:
40
+ Enabled: false
41
+
42
+ RSpec/NestedGroups:
43
+ Max: 4
44
+
45
+ RSpec/ExampleLength:
46
+ Enabled: false
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2025-11-17
4
+
5
+ - Initial release
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Denis Talakevich
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,171 @@
1
+ # ShinseiConfig
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/shinsei_config.svg)](https://rubygems.org/gems/shinsei_config)
4
+ [![CI](https://github.com/senid231/shinsei_config/actions/workflows/main.yml/badge.svg)](https://github.com/senid231/shinsei_config/actions/workflows/main.yml)
5
+ [![CodeQL](https://github.com/senid231/shinsei_config/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/senid231/shinsei_config/actions/workflows/github-code-scanning/codeql)
6
+
7
+ Shinsei (真正 — "genuine, correct, authentic")
8
+
9
+ A Ruby gem for loading configuration from YAML files with schema validation, ERB interpolation, and environment-specific settings.
10
+
11
+ ## Features
12
+
13
+ - **Schema Validation**: Uses [dry-schema](https://dry-rb.org/gems/dry-schema/) for robust configuration validation
14
+ - **ERB Interpolation**: Process ERB templates before YAML parsing
15
+ - **Environment Splitting**: Load environment-specific configurations
16
+ - **Immutable Config Objects**: Uses Ruby 3.2+ `Data.define` for frozen, immutable configuration objects
17
+ - **Type-Safe Access**: Access configuration values with dot notation
18
+ - **Custom YAML Options**: Pass custom options to YAML parser
19
+
20
+ ## Installation
21
+
22
+ Install the gem and add to the application's Gemfile by executing:
23
+
24
+ ```bash
25
+ bundle add shinsei_config
26
+ ```
27
+
28
+ If bundler is not being used to manage dependencies, install the gem by executing:
29
+
30
+ ```bash
31
+ gem install shinsei_config
32
+ ```
33
+
34
+ ## Usage
35
+
36
+ ### Basic Example
37
+
38
+ ```ruby
39
+ require 'shinsei_config'
40
+
41
+ class MyAppConfig < ShinseiConfig::RootConfig
42
+ settings do |s|
43
+ s.config_path = Rails.root.join('config/my_app_config.yml').to_s # required
44
+ s.env = Rails.env.to_s # optional, default nil which means no env splitting
45
+ s.yaml_opts = { aliases: true } # optional, default {}
46
+ end
47
+
48
+ schema do
49
+ required(:write_account_stats).value(:bool?)
50
+ required(:api_keys).hash do
51
+ required(:service_a).filled(:string)
52
+ required(:service_b).filled(:string)
53
+ end
54
+ end
55
+
56
+ def self.service_a_test?
57
+ # custom methods to access config values
58
+ api_keys.service_a.start_with?('test-')
59
+ end
60
+ end
61
+
62
+ # When application starts
63
+ MyAppConfig.load! # may raise ShinseiConfig::ValidationError if config is invalid
64
+
65
+ # Somewhere in the app
66
+ MyAppConfig.api_keys.service_a # => "actual-key"
67
+ MyAppConfig.write_account_stats # => true
68
+ MyAppConfig.service_a_test? # => false
69
+ ```
70
+
71
+ ### YAML File Examples
72
+
73
+ #### Simple Configuration (config/my_app_config.yml)
74
+
75
+ ```yaml
76
+ write_account_stats: true
77
+ api_keys:
78
+ service_a: <%= ENV['SERVICE_A_KEY'] %>
79
+ service_b: production-key-b
80
+ ```
81
+
82
+ #### Environment-Specific Configuration
83
+
84
+ ```yaml
85
+ development:
86
+ write_account_stats: false
87
+ api_keys:
88
+ service_a: test-key-a
89
+ service_b: test-key-b
90
+
91
+ production:
92
+ write_account_stats: true
93
+ api_keys:
94
+ service_a: <%= ENV['SERVICE_A_KEY'] %>
95
+ service_b: <%= ENV['SERVICE_B_KEY'] %>
96
+ ```
97
+
98
+ ### Features in Detail
99
+
100
+ #### ERB Interpolation
101
+
102
+ ERB is processed on the raw YAML content before parsing:
103
+
104
+ ```yaml
105
+ # config.yml
106
+ database_url: <%= ENV.fetch('DATABASE_URL', 'postgres://localhost/mydb') %>
107
+ max_connections: <%= 2 * 5 %>
108
+ ```
109
+
110
+ #### Schema Validation
111
+
112
+ The gem uses [dry-schema](https://dry-rb.org/gems/dry-schema/) for validation:
113
+
114
+ ```ruby
115
+ schema do
116
+ required(:database).hash do
117
+ required(:host).filled(:string)
118
+ required(:port).filled(:integer)
119
+ end
120
+
121
+ optional(:features).array(:string)
122
+
123
+ required(:timeout).value(:integer, gt?: 0)
124
+ end
125
+ ```
126
+
127
+ #### Custom YAML Options
128
+
129
+ Pass custom options to the YAML parser:
130
+
131
+ ```ruby
132
+ settings do |s|
133
+ s.config_path = 'config/app.yml'
134
+ s.yaml_opts = {
135
+ aliases: true,
136
+ permitted_classes: [Date, Time],
137
+ permitted_symbols: []
138
+ }
139
+ end
140
+ ```
141
+
142
+ #### Immutable Configuration
143
+
144
+ All configuration objects are deeply frozen and immutable:
145
+
146
+ ```ruby
147
+ MyAppConfig.api_keys.frozen? # => true
148
+ MyAppConfig.api_keys.service_a.frozen? # => true
149
+ ```
150
+
151
+ #### Reloading Configuration
152
+
153
+ You can reload the configuration at runtime (useful for development):
154
+
155
+ ```ruby
156
+ MyAppConfig.reload!
157
+ ```
158
+
159
+ ## Development
160
+
161
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
162
+
163
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
164
+
165
+ ## Contributing
166
+
167
+ Bug reports and pull requests are welcome on GitHub at https://github.com/senid231/shinsei_config.
168
+
169
+ ## License
170
+
171
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require 'rubocop/rake_task'
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShinseiConfig
4
+ # Recursively builds Data.define objects from hash with deep freezing
5
+ class ConfigBuilder
6
+ # @rbs hash: Hash[untyped, untyped] -- return: Data
7
+ def self.build(hash)
8
+ new(hash).build
9
+ end
10
+
11
+ # @rbs @hash: Hash[untyped, untyped]
12
+
13
+ # @rbs attr_reader hash: Hash[untyped, untyped]
14
+ attr_reader :hash
15
+
16
+ # @rbs hash: Hash[untyped, untyped] -- return: void
17
+ def initialize(hash)
18
+ @hash = hash
19
+ end
20
+
21
+ # @rbs return: Data
22
+ def build
23
+ raise Error, "Expected Hash, got #{hash.class}" unless hash.is_a?(Hash)
24
+
25
+ # Create a Data.define class with all keys as symbols
26
+ config_class = Data.define(*hash.keys.map(&:to_sym))
27
+
28
+ # Build values, recursively converting nested hashes
29
+ # Convert keys to symbols for Data.define
30
+ values = hash.transform_keys(&:to_sym).transform_values { |v| build_value(v) }
31
+
32
+ # Create instance and freeze
33
+ config_class.new(**values).freeze
34
+ end
35
+
36
+ private
37
+
38
+ # @rbs value: untyped -- return: untyped
39
+ def build_value(value)
40
+ case value
41
+ when Hash
42
+ ConfigBuilder.build(value)
43
+ when Array
44
+ value.map { |v| build_value(v) }.freeze
45
+ else
46
+ value
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+ require 'erb'
5
+
6
+ module ShinseiConfig
7
+ # Handles loading YAML files with ERB interpolation and environment splitting
8
+ class Loader
9
+ # @rbs @config_path: String
10
+ # @rbs @env: String?
11
+ # @rbs @yaml_opts: Hash[Symbol, untyped]
12
+
13
+ # @rbs attr_reader config_path: String
14
+ # @rbs attr_reader env: String?
15
+ # @rbs attr_reader yaml_opts: Hash[Symbol, untyped]
16
+ attr_reader :config_path, :env, :yaml_opts
17
+
18
+ # @rbs config_path: String, env: String?, **yaml_opts: untyped -- return: void
19
+ def initialize(config_path:, env: nil, **yaml_opts)
20
+ @config_path = config_path
21
+ @env = env
22
+ @yaml_opts = yaml_opts
23
+ end
24
+
25
+ # @rbs return: Hash[String, untyped]
26
+ def load
27
+ raise Error, "Config file not found: #{config_path}" unless File.exist?(config_path)
28
+
29
+ # Read raw content
30
+ raw_content = File.read(config_path)
31
+
32
+ # Process ERB on raw content before YAML parsing
33
+ erb_processed = ERB.new(raw_content).result
34
+
35
+ # Parse YAML with provided options
36
+ parsed_yaml = YAML.safe_load(erb_processed, **yaml_opts)
37
+
38
+ # Extract environment section if env is set
39
+ extract_env_section(parsed_yaml)
40
+ end
41
+
42
+ private
43
+
44
+ # @rbs parsed_yaml: Hash[String, untyped] -- return: Hash[String, untyped]
45
+ def extract_env_section(parsed_yaml)
46
+ return parsed_yaml unless env
47
+
48
+ unless parsed_yaml.is_a?(Hash) && parsed_yaml.key?(env)
49
+ raise Error, "Environment '#{env}' not found in config file"
50
+ end
51
+
52
+ parsed_yaml[env]
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShinseiConfig
4
+ # Base class for configuration. Users inherit from this class.
5
+ class RootConfig
6
+ class << self
7
+ # @rbs @settings: Settings?
8
+ # @rbs @schema_validator: SchemaValidator?
9
+ # @rbs @config: Data?
10
+
11
+ # Configure settings for this config class
12
+ # @rbs () { (Settings) -> void } -> Settings
13
+ def settings(&block)
14
+ @settings ||= Settings.new
15
+ block&.call(@settings)
16
+ @settings
17
+ end
18
+
19
+ # Define validation schema
20
+ # @rbs () { () -> void } -> SchemaValidator?
21
+ def schema(&block)
22
+ @schema_validator = SchemaValidator.new(&block) if block
23
+ @schema_validator
24
+ end
25
+
26
+ # Load and validate configuration
27
+ # @rbs return: singleton(RootConfig)
28
+ def load!
29
+ validate_setup!
30
+
31
+ # Load YAML with ERB and env splitting
32
+ loader = Loader.new(
33
+ config_path: settings.config_path,
34
+ env: settings.env,
35
+ **settings.yaml_opts
36
+ )
37
+ config_hash = loader.load
38
+
39
+ # Validate against schema if defined
40
+ schema&.validate!(config_hash)
41
+
42
+ # Build config object
43
+ @config = ConfigBuilder.build(config_hash)
44
+
45
+ self
46
+ end
47
+
48
+ # Reload configuration
49
+ # @rbs return: singleton(RootConfig)
50
+ def reload!
51
+ @config = nil
52
+ load!
53
+ end
54
+
55
+ # Access config instance
56
+ # @rbs return: Data
57
+ def config
58
+ raise Error, "Config not loaded. Call #{name}.load! first" unless @config
59
+
60
+ @config
61
+ end
62
+
63
+ # Delegate method calls to config instance
64
+ # @rbs method_name: Symbol, *args: untyped, **kwargs: untyped -- return: untyped
65
+ def method_missing(method_name, *, &)
66
+ if config.respond_to?(method_name)
67
+ config.public_send(method_name, *, &)
68
+ else
69
+ super
70
+ end
71
+ end
72
+
73
+ # @rbs method_name: Symbol, include_private: bool -- return: bool
74
+ def respond_to_missing?(method_name, include_private = false)
75
+ config.respond_to?(method_name) || super
76
+ end
77
+
78
+ private
79
+
80
+ # @rbs return: void
81
+ def validate_setup!
82
+ settings.validate!
83
+
84
+ return if schema
85
+
86
+ raise Error, "Schema not defined. Call #{name}.schema { ... } in class body"
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry-schema'
4
+
5
+ module ShinseiConfig
6
+ # Wraps dry-schema for validating configuration
7
+ class SchemaValidator
8
+ # @rbs @schema: Dry::Schema::Processor
9
+
10
+ # @rbs attr_reader schema: Dry::Schema::Processor
11
+ attr_reader :schema
12
+
13
+ # @rbs **opts: untyped -- return: void
14
+ def initialize(**, &)
15
+ @schema = Dry::Schema.define(processor_type: Dry::Schema::JSON, **, &)
16
+ end
17
+
18
+ # @rbs config_hash: Hash[untyped, untyped] -- return: void
19
+ def validate!(config_hash)
20
+ result = schema.call(config_hash)
21
+
22
+ return if result.success?
23
+
24
+ raise ValidationError, result.errors
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShinseiConfig
4
+ # Stores settings for RootConfig that are not part of the schema
5
+ class Settings
6
+ # @rbs @config_path: String?
7
+ # @rbs @env: String?
8
+ # @rbs @yaml_opts: Hash[Symbol, untyped]
9
+
10
+ # @rbs attr_accessor config_path: String?
11
+ # @rbs attr_accessor env: String?
12
+ # @rbs attr_accessor yaml_opts: Hash[Symbol, untyped]
13
+ attr_accessor :config_path, :env, :yaml_opts
14
+
15
+ # @rbs return: void
16
+ def initialize
17
+ @config_path = nil
18
+ @env = nil
19
+ @yaml_opts = {}
20
+ end
21
+
22
+ # @rbs return: void
23
+ def validate!
24
+ raise Error, 'config_path is required' if config_path.nil? || config_path.empty?
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShinseiConfig
4
+ # Raised when config validation fails
5
+ class ValidationError < Error
6
+ # @rbs @errors: Hash[Symbol, Array[String]]
7
+
8
+ # @rbs attr_reader errors: Hash[Symbol, Array[String]]
9
+ attr_reader :errors
10
+
11
+ # @rbs errors: Hash[Symbol, Array[String]] -- return: void
12
+ def initialize(errors)
13
+ @errors = errors
14
+ super(format_errors)
15
+ end
16
+
17
+ private
18
+
19
+ # @rbs return: String
20
+ def format_errors
21
+ return 'Validation failed' if errors.empty?
22
+
23
+ formatted = errors.to_h.map do |key, messages|
24
+ " #{key}: #{messages.join(', ')}"
25
+ end
26
+
27
+ "Validation failed:\n#{formatted.join("\n")}"
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShinseiConfig
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'shinsei_config/version'
4
+
5
+ module ShinseiConfig
6
+ class Error < StandardError; end
7
+ end
8
+
9
+ require_relative 'shinsei_config/settings'
10
+ require_relative 'shinsei_config/validation_error'
11
+ require_relative 'shinsei_config/loader'
12
+ require_relative 'shinsei_config/schema_validator'
13
+ require_relative 'shinsei_config/config_builder'
14
+ require_relative 'shinsei_config/root_config'
data/manifest.yaml ADDED
@@ -0,0 +1,2 @@
1
+ dependencies:
2
+ - name: dry-schema
@@ -0,0 +1,25 @@
1
+ # Generated from lib/shinsei_config/config_builder.rb with RBS::Inline
2
+
3
+ module ShinseiConfig
4
+ # Recursively builds Data.define objects from hash with deep freezing
5
+ class ConfigBuilder
6
+ # @rbs hash: Hash[untyped, untyped] -- return: Data
7
+ def self.build: (Hash[untyped, untyped] hash) -> untyped
8
+
9
+ @hash: Hash[untyped, untyped]
10
+
11
+ # @rbs attr_reader hash: Hash[untyped, untyped]
12
+ attr_reader hash: untyped
13
+
14
+ # @rbs hash: Hash[untyped, untyped] -- return: void
15
+ def initialize: (Hash[untyped, untyped] hash) -> untyped
16
+
17
+ # @rbs return: Data
18
+ def build: () -> Data
19
+
20
+ private
21
+
22
+ # @rbs value: untyped -- return: untyped
23
+ def build_value: (untyped value) -> untyped
24
+ end
25
+ end
@@ -0,0 +1,38 @@
1
+ # Generated from lib/shinsei_config/loader.rb with RBS::Inline
2
+
3
+ module ShinseiConfig
4
+ # Handles loading YAML files with ERB interpolation and environment splitting
5
+ class Loader
6
+ @config_path: String
7
+
8
+ @env: String?
9
+
10
+ @yaml_opts: Hash[Symbol, untyped]
11
+
12
+ # @rbs attr_reader config_path: String
13
+ # @rbs attr_reader env: String?
14
+ # @rbs attr_reader yaml_opts: Hash[Symbol, untyped]
15
+ attr_reader config_path: untyped
16
+
17
+ # @rbs attr_reader config_path: String
18
+ # @rbs attr_reader env: String?
19
+ # @rbs attr_reader yaml_opts: Hash[Symbol, untyped]
20
+ attr_reader env: untyped
21
+
22
+ # @rbs attr_reader config_path: String
23
+ # @rbs attr_reader env: String?
24
+ # @rbs attr_reader yaml_opts: Hash[Symbol, untyped]
25
+ attr_reader yaml_opts: untyped
26
+
27
+ # @rbs config_path: String, env: String?, **yaml_opts: untyped -- return: void
28
+ def initialize: (config_path: String, ?env: untyped, **untyped yaml_opts) -> untyped
29
+
30
+ # @rbs return: Hash[String, untyped]
31
+ def load: () -> Hash[String, untyped]
32
+
33
+ private
34
+
35
+ # @rbs parsed_yaml: Hash[String, untyped] -- return: Hash[String, untyped]
36
+ def extract_env_section: (Hash[String, untyped] parsed_yaml) -> untyped
37
+ end
38
+ end
@@ -0,0 +1,42 @@
1
+ # Generated from lib/shinsei_config/root_config.rb with RBS::Inline
2
+
3
+ module ShinseiConfig
4
+ # Base class for configuration. Users inherit from this class.
5
+ class RootConfig
6
+ @settings: Settings?
7
+
8
+ @schema_validator: SchemaValidator?
9
+
10
+ @config: Data?
11
+
12
+ # Configure settings for this config class
13
+ # @rbs () { (Settings) -> void } -> Settings
14
+ def self.settings: () { (Settings) -> void } -> Settings
15
+
16
+ # Define validation schema
17
+ # @rbs () { () -> void } -> SchemaValidator?
18
+ def self.schema: () { () -> void } -> SchemaValidator?
19
+
20
+ # Load and validate configuration
21
+ # @rbs return: singleton(RootConfig)
22
+ def self.load!: () -> singleton(RootConfig)
23
+
24
+ # Reload configuration
25
+ # @rbs return: singleton(RootConfig)
26
+ def self.reload!: () -> singleton(RootConfig)
27
+
28
+ # Access config instance
29
+ # @rbs return: Data
30
+ def self.config: () -> Data
31
+
32
+ # Delegate method calls to config instance
33
+ # @rbs method_name: Symbol, *args: untyped, **kwargs: untyped -- return: untyped
34
+ def self.method_missing: (Symbol method_name, *untyped) ?{ (?) -> untyped } -> untyped
35
+
36
+ # @rbs method_name: Symbol, include_private: bool -- return: bool
37
+ def self.respond_to_missing?: (Symbol method_name, ?untyped include_private) -> untyped
38
+
39
+ # @rbs return: void
40
+ private def self.validate_setup!: () -> void
41
+ end
42
+ end
@@ -0,0 +1,17 @@
1
+ # Generated from lib/shinsei_config/schema_validator.rb with RBS::Inline
2
+
3
+ module ShinseiConfig
4
+ # Wraps dry-schema for validating configuration
5
+ class SchemaValidator
6
+ @schema: Dry::Schema::Processor
7
+
8
+ # @rbs attr_reader schema: Dry::Schema::Processor
9
+ attr_reader schema: untyped
10
+
11
+ # @rbs **opts: untyped -- return: void
12
+ def initialize: (**untyped) ?{ (?) -> untyped } -> untyped
13
+
14
+ # @rbs config_hash: Hash[untyped, untyped] -- return: void
15
+ def validate!: (Hash[untyped, untyped] config_hash) -> untyped
16
+ end
17
+ end
@@ -0,0 +1,33 @@
1
+ # Generated from lib/shinsei_config/settings.rb with RBS::Inline
2
+
3
+ module ShinseiConfig
4
+ # Stores settings for RootConfig that are not part of the schema
5
+ class Settings
6
+ @config_path: String?
7
+
8
+ @env: String?
9
+
10
+ @yaml_opts: Hash[Symbol, untyped]
11
+
12
+ # @rbs attr_accessor config_path: String?
13
+ # @rbs attr_accessor env: String?
14
+ # @rbs attr_accessor yaml_opts: Hash[Symbol, untyped]
15
+ attr_accessor config_path: untyped
16
+
17
+ # @rbs attr_accessor config_path: String?
18
+ # @rbs attr_accessor env: String?
19
+ # @rbs attr_accessor yaml_opts: Hash[Symbol, untyped]
20
+ attr_accessor env: untyped
21
+
22
+ # @rbs attr_accessor config_path: String?
23
+ # @rbs attr_accessor env: String?
24
+ # @rbs attr_accessor yaml_opts: Hash[Symbol, untyped]
25
+ attr_accessor yaml_opts: untyped
26
+
27
+ # @rbs return: void
28
+ def initialize: () -> void
29
+
30
+ # @rbs return: void
31
+ def validate!: () -> void
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ # Generated from lib/shinsei_config/validation_error.rb with RBS::Inline
2
+
3
+ module ShinseiConfig
4
+ # Raised when config validation fails
5
+ class ValidationError < Error
6
+ @errors: Hash[Symbol, Array[String]]
7
+
8
+ # @rbs attr_reader errors: Hash[Symbol, Array[String]]
9
+ attr_reader errors: untyped
10
+
11
+ # @rbs errors: Hash[Symbol, Array[String]] -- return: void
12
+ def initialize: (Hash[Symbol, Array[String]] errors) -> untyped
13
+
14
+ private
15
+
16
+ # @rbs return: String
17
+ def format_errors: () -> String
18
+ end
19
+ end
@@ -0,0 +1,5 @@
1
+ # Generated from lib/shinsei_config/version.rb with RBS::Inline
2
+
3
+ module ShinseiConfig
4
+ VERSION: ::String
5
+ end
@@ -0,0 +1,6 @@
1
+ # Generated from lib/shinsei_config.rb with RBS::Inline
2
+
3
+ module ShinseiConfig
4
+ class Error < StandardError
5
+ end
6
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: shinsei_config
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Denis Talakevich
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-11-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dry-schema
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.13'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.13'
27
+ description: ShinseiConfig (真正 — genuine, correct, authentic) loads configuration
28
+ from YAML files, supports ERB interpolation, per-environment splitting, and validates
29
+ structure using dry-schema.
30
+ email:
31
+ - senid231@gmail.com
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - ".rspec"
37
+ - ".rubocop.yml"
38
+ - CHANGELOG.md
39
+ - LICENSE.txt
40
+ - README.md
41
+ - Rakefile
42
+ - lib/shinsei_config.rb
43
+ - lib/shinsei_config/config_builder.rb
44
+ - lib/shinsei_config/loader.rb
45
+ - lib/shinsei_config/root_config.rb
46
+ - lib/shinsei_config/schema_validator.rb
47
+ - lib/shinsei_config/settings.rb
48
+ - lib/shinsei_config/validation_error.rb
49
+ - lib/shinsei_config/version.rb
50
+ - manifest.yaml
51
+ - sig/shinsei_config.rbs
52
+ - sig/shinsei_config/config_builder.rbs
53
+ - sig/shinsei_config/loader.rbs
54
+ - sig/shinsei_config/root_config.rbs
55
+ - sig/shinsei_config/schema_validator.rbs
56
+ - sig/shinsei_config/settings.rbs
57
+ - sig/shinsei_config/validation_error.rbs
58
+ - sig/shinsei_config/version.rbs
59
+ homepage: https://github.com/senid231/shinsei_config
60
+ licenses:
61
+ - MIT
62
+ metadata:
63
+ homepage_uri: https://github.com/senid231/shinsei_config
64
+ source_code_uri: https://github.com/senid231/shinsei_config
65
+ changelog_uri: https://github.com/senid231/shinsei_config/blob/master/CHANGELOG.md
66
+ rubygems_mfa_required: 'true'
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 3.3.0
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubygems_version: 3.5.22
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: Loads and validates configuration from YAML files with schema validation
86
+ test_files: []