ace-config 0.1.0.beta.rc1b
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE +21 -0
- data/README.md +382 -0
- data/ace-config.gemspec +37 -0
- data/lib/ace_config/configuration.rb +175 -0
- data/lib/ace_config/errors.rb +54 -0
- data/lib/ace_config/setting.rb +231 -0
- data/lib/ace_config/type_checker.rb +93 -0
- data/lib/ace_config/type_map.rb +70 -0
- data/lib/ace_config/version.rb +5 -0
- data/lib/ace_config.rb +8 -0
- metadata +76 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 673610da9904345d9482fa26d53c0717ef5bb3aa5a5bd7124d2ff5cf64b36a2f
|
4
|
+
data.tar.gz: 1b7036dcfba77239068380f9912b7a2efe0fb596e0534eebcfb329dbef58bad8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 96a2009741d8ce31cc20fb5a9a1ac22874ef9d1b67170f720826896fb364799cf7986231cd2d9a9babf3cfe07b594e67277197527eb5858661e7cbd2370e8675
|
7
|
+
data.tar.gz: 0d32fe09d35a104bc697a8e3e2d84286215ab7a15409ee0c54cbb4e7326a9aab7ba5e2f9afa8910b3cb66d1e0b75f3d679c929fee7c42f1d53e5067d1573a2b0
|
data/CHANGELOG.md
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2024 yurigitsu
|
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 all
|
13
|
+
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 THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,382 @@
|
|
1
|
+
# ace-config
|
2
|
+
|
3
|
+
Ruby gem created to simplify managing application configurations and enhance the development of other gems that require configuration management. It offers a simple interface for defining, setting, and retrieving configuration options with type validation, helping ensure configurations are correct and reliable.
|
4
|
+
|
5
|
+
- **ace-config** provides built-in support for importing and exporting configurations in JSON, YAML, and Hash formats, enhancing versatility.
|
6
|
+
|
7
|
+
- **ace-config** offers various built-in types like basic types, data structures, numeric types, and time types.
|
8
|
+
|
9
|
+
- **ace-config** supports infinite nested configurations and 'classy' access providing a flexible and powerful configuration management solution.
|
10
|
+
|
11
|
+
|
12
|
+
## Features
|
13
|
+
|
14
|
+
- **Simple Configuration Management**: Easily define, set, and retrieve configuration options.
|
15
|
+
- **Type Validation**: Ensure configurations are correct with built-in type validation.
|
16
|
+
- **Multiple Formats**: Import and export configurations in JSON, YAML, and Hash formats.
|
17
|
+
- **Nested Configurations**: Support for infinite nested configurations for complex applications.
|
18
|
+
- **Classy Access**: Access configurations in a 'classy' manner for better organization and readability.
|
19
|
+
- **Built-in Types**: Utilize various built-in types including basic types, data structures, numeric types, and time types.
|
20
|
+
- **Extensible**: Easily extendable to accommodate custom configuration needs.
|
21
|
+
|
22
|
+
## Table of Contents
|
23
|
+
- [Installation](#installation)
|
24
|
+
- [Basic Usage](#basic-usage)
|
25
|
+
- [Configuration Container Usage](#configuration-container-usage)
|
26
|
+
- [DSL Syntax](#dsl-syntax)
|
27
|
+
- Typing
|
28
|
+
- [Define Configuration Validation](#set-configuration-type-validation)
|
29
|
+
- [Declaring Validation](#configure-type-validation)
|
30
|
+
- [Type Schema](#type_schema)
|
31
|
+
- [Built-in Types](#built-in-types)
|
32
|
+
- Import:
|
33
|
+
- [Loading Configurations](#loading-configuration-data)
|
34
|
+
- [Loading from a JSON String](#loading-from-a-json-string)
|
35
|
+
- [Loading from a YAML File](#loading-from-a-yaml-file)
|
36
|
+
- Export:
|
37
|
+
- [Exporting Configurations](#exporting-configuration-data)
|
38
|
+
- [to_h](#to_h)
|
39
|
+
- [to_json](#to_json)
|
40
|
+
- [to_yaml](#to_yaml)
|
41
|
+
- OSS
|
42
|
+
- [Development](#development)
|
43
|
+
- [Contributing](#contributing)
|
44
|
+
- [License](#license)
|
45
|
+
- [Code of Conduct](#code-of-conduct)
|
46
|
+
|
47
|
+
## Installation
|
48
|
+
|
49
|
+
Install the gem and add to the application's Gemfile by executing:
|
50
|
+
|
51
|
+
```bash
|
52
|
+
bundle add ace-config
|
53
|
+
```
|
54
|
+
|
55
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
56
|
+
|
57
|
+
```bash
|
58
|
+
gem install ace-config
|
59
|
+
```
|
60
|
+
|
61
|
+
## Basic Usage
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
require 'ace_config'
|
65
|
+
|
66
|
+
module MyApp
|
67
|
+
include AceConfig
|
68
|
+
end
|
69
|
+
|
70
|
+
MyApp.configure :settings do
|
71
|
+
config option: 42
|
72
|
+
config.int typed_opt_one: 42
|
73
|
+
config typed_opt_two: 4.2, type: :float
|
74
|
+
end
|
75
|
+
|
76
|
+
MyApp.settings.option # => 42
|
77
|
+
MyApp.settings.typed_opt_one # => 42
|
78
|
+
MyApp.settings.typed_opt_two # => 4.2
|
79
|
+
```
|
80
|
+
|
81
|
+
### Basic Syntax
|
82
|
+
```ruby
|
83
|
+
MyApp.configure :settings do
|
84
|
+
config option: 42
|
85
|
+
end
|
86
|
+
```
|
87
|
+
|
88
|
+
## Namespacing
|
89
|
+
```ruby
|
90
|
+
MyApp.configure :app do
|
91
|
+
configure :lvl_one do
|
92
|
+
config opt: 100
|
93
|
+
configure :lvl_two do
|
94
|
+
config opt: 200
|
95
|
+
configure :lvl_three do
|
96
|
+
config opt: 300
|
97
|
+
configure :lvl_four do
|
98
|
+
config opt: 400
|
99
|
+
configure :lvl_five do
|
100
|
+
config opt: 500
|
101
|
+
# NOTE: as deep as you want
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
MyApp.app.lvl_one.opt # => 100
|
110
|
+
MyApp.app.lvl_one.lvl_two.opt # => 200
|
111
|
+
MyApp.app.lvl_one.lvl_two.lvl_three.opt # => 300
|
112
|
+
MyApp.app.lvl_one.lvl_two.lvl_three.lvl_four.opt # => 400
|
113
|
+
MyApp.app.lvl_one.lvl_two.lvl_three.lvl_four.lvl_five.opt # => 500
|
114
|
+
```
|
115
|
+
|
116
|
+
### Configure Type Validation
|
117
|
+
```ruby
|
118
|
+
MyApp.configure :settings do
|
119
|
+
config custom_typed_opt_one: '42', type: :float
|
120
|
+
end
|
121
|
+
# => AceConfig::SettingTypeError
|
122
|
+
```
|
123
|
+
|
124
|
+
## Configuration Container Usage
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
require 'ace_config'
|
128
|
+
|
129
|
+
module MyGem
|
130
|
+
include AceConfig
|
131
|
+
end
|
132
|
+
```
|
133
|
+
|
134
|
+
### Declare configurations
|
135
|
+
```ruby
|
136
|
+
MyGem.configure :settings do
|
137
|
+
config :option
|
138
|
+
config.int :typed_opt_one
|
139
|
+
config :typed_opt_two, type: Integer
|
140
|
+
# NOTE: declare nested namespace with configure <symbol arg>
|
141
|
+
configure :nested do
|
142
|
+
config :option
|
143
|
+
end
|
144
|
+
end
|
145
|
+
```
|
146
|
+
|
147
|
+
### Define configurations
|
148
|
+
```ruby
|
149
|
+
MyGem.settings do
|
150
|
+
config option: 1
|
151
|
+
config typed_opt_one: 2
|
152
|
+
config typed_opt_two: 3
|
153
|
+
# NOTE: access namespace via <.dot_access>
|
154
|
+
config.nested do
|
155
|
+
config option: 4
|
156
|
+
end
|
157
|
+
end
|
158
|
+
```
|
159
|
+
|
160
|
+
### Define with DSL Syntax
|
161
|
+
```ruby
|
162
|
+
MyGem.settings do
|
163
|
+
option 1
|
164
|
+
typed_opt_one 2
|
165
|
+
typed_opt_two 3
|
166
|
+
# NOTE: access namespace via <block>
|
167
|
+
nested do
|
168
|
+
option 1
|
169
|
+
end
|
170
|
+
end
|
171
|
+
```
|
172
|
+
|
173
|
+
### Get configurations
|
174
|
+
```ruby
|
175
|
+
MyGem.settings.option # => 1
|
176
|
+
MyGem.settings.typed_opt_one # => 2
|
177
|
+
MyGem.settings.typed_opt_two # => 3
|
178
|
+
MyGem.settings.nested.option # => 4
|
179
|
+
```
|
180
|
+
|
181
|
+
### Define Configuration Type Validation
|
182
|
+
```ruby
|
183
|
+
MyGem.settings do
|
184
|
+
config.typed_opt_two: '1'
|
185
|
+
end
|
186
|
+
# => AceConfig::SettingTypeError
|
187
|
+
|
188
|
+
MyGem.settings do
|
189
|
+
typed_opt_two '1'
|
190
|
+
end
|
191
|
+
# => AceConfig::SettingTypeError
|
192
|
+
```
|
193
|
+
|
194
|
+
## Loading Configuration Data
|
195
|
+
|
196
|
+
The `AceConfig` module allows you to load configuration data from various sources, including YAML and JSON. Below are the details for each option.
|
197
|
+
|
198
|
+
- `json` (String)
|
199
|
+
- `yaml` (String)
|
200
|
+
- `hash` (Hash)
|
201
|
+
- `schema` (Hash) (Optional) See: [Type Schema](#type_schema) and [Built-in Types](#built-in-types)
|
202
|
+
|
203
|
+
### Loading from a JSON String
|
204
|
+
|
205
|
+
You can load configuration data from a JSON string by passing the `json` option to the `configure` method.
|
206
|
+
|
207
|
+
#### Parameters
|
208
|
+
|
209
|
+
- `json` (String): A JSON string containing the configuration data.
|
210
|
+
- `schema` (Hash) (Optional): A hash representing the type schema for the configuration data.
|
211
|
+
|
212
|
+
#### Error Handling
|
213
|
+
|
214
|
+
- If the JSON format is invalid, a `LoadDataError` will be raised with the message "Invalid JSON format".
|
215
|
+
|
216
|
+
#### Example 1
|
217
|
+
```ruby
|
218
|
+
MyGem.configure(:settings, json: '{"opt_one":1,"opt_two":2}').settings
|
219
|
+
# => #<MyGem::Setting:0x00007f8c1c0b2a80 @options={:opt_one=>1, :opt_two=>2}>
|
220
|
+
```
|
221
|
+
|
222
|
+
#### Example 2
|
223
|
+
```ruby
|
224
|
+
MyGem.configure(:settings, json: '{"opt_one":1,"opt_two":2}', schema: { opt_one: :int, opt_two: :str })
|
225
|
+
# => AceConfig::SettingTypeError: Expected: <str>. Given: 2 which is <Integer> class.
|
226
|
+
```
|
227
|
+
|
228
|
+
#### Example 3
|
229
|
+
```ruby
|
230
|
+
MyGem.configure(:settings, json: '{"opt_one":1,"opt_two":2}', schema: { opt_one: :int, opt_two: :int })
|
231
|
+
|
232
|
+
MyGem.settings do
|
233
|
+
opt_one 1
|
234
|
+
opt_two "2"
|
235
|
+
end
|
236
|
+
# => AceConfig::SettingTypeError: Expected: <intstr>. Given: \"2\" which is <String> class.
|
237
|
+
```
|
238
|
+
|
239
|
+
### Loading from a YAML File
|
240
|
+
|
241
|
+
You can also load configuration data from a YAML file by passing the `yaml` option to the `configure` method.
|
242
|
+
|
243
|
+
#### Parameters
|
244
|
+
|
245
|
+
- `yaml` (String): A file path to a YAML file containing the configuration data.
|
246
|
+
- `schema` (Hash) (Optional): A hash representing the type schema for the configuration data.
|
247
|
+
|
248
|
+
#### Error Handling
|
249
|
+
|
250
|
+
- If the specified YAML file is not found, a `LoadDataError` will be raised with the message "YAML file not found".
|
251
|
+
|
252
|
+
##### YAML File
|
253
|
+
```yaml
|
254
|
+
# settings.yml
|
255
|
+
|
256
|
+
opt_one: 1
|
257
|
+
opt_two: 2
|
258
|
+
```
|
259
|
+
|
260
|
+
#### Example 1
|
261
|
+
```ruby
|
262
|
+
MyGem.configure :settings, yaml: 'settings.yml'
|
263
|
+
# => #<MyGem::Setting:0x00006f8c1c0b2a80 @options={:opt_one=>1, :opt_two=>2}>
|
264
|
+
```
|
265
|
+
|
266
|
+
#### Example 2
|
267
|
+
```ruby
|
268
|
+
MyGem.configure :settings, yaml: 'settings.yml', schema: { opt_one: :int, opt_two: :str }
|
269
|
+
# => AceConfig::SettingTypeError: Expected: <str>. Given: 2 which is <Integer> class.
|
270
|
+
```
|
271
|
+
|
272
|
+
#### Example 3
|
273
|
+
```ruby
|
274
|
+
MyGem.configure :settings, yaml: 'settings.yml', schema: { opt_one: :int, opt_two: :int }
|
275
|
+
|
276
|
+
MyGem.settings do
|
277
|
+
opt_one 1
|
278
|
+
opt_two "2"
|
279
|
+
end
|
280
|
+
# => AceConfig::SettingTypeError: Expected: <intstr>. Given: \"2\" which is <String> class.
|
281
|
+
```
|
282
|
+
|
283
|
+
## Exporting Configuration Data
|
284
|
+
|
285
|
+
You can dump the configuration data in various formats using the following methods:
|
286
|
+
|
287
|
+
### to_h
|
288
|
+
```ruby
|
289
|
+
MyGem.configure :settings do
|
290
|
+
config opt_one: 1
|
291
|
+
config opt_two: 2
|
292
|
+
end
|
293
|
+
|
294
|
+
MyGem.settings.to_json # => '{"opt_one":1,"opt_two":2}'
|
295
|
+
```
|
296
|
+
|
297
|
+
### to_json
|
298
|
+
```ruby
|
299
|
+
MyGem.configure :settings do
|
300
|
+
config opt_one: 1
|
301
|
+
config opt_two: 2
|
302
|
+
end
|
303
|
+
|
304
|
+
MyGem.settings.to_json # => '{"opt_one":1,"opt_two":2}'
|
305
|
+
```
|
306
|
+
|
307
|
+
### to_yaml
|
308
|
+
```ruby
|
309
|
+
MyGem.configure :settings do
|
310
|
+
config opt_one: 1
|
311
|
+
config opt_two: 2
|
312
|
+
end
|
313
|
+
|
314
|
+
MyGem.settings.to_yaml # => "---\nopt_one: 1\nopt_two: 2\n"
|
315
|
+
```
|
316
|
+
|
317
|
+
### type_schema
|
318
|
+
```ruby
|
319
|
+
MyGem.configure :settings do
|
320
|
+
config.int opt_one: 1
|
321
|
+
config.str opt_two: "2"
|
322
|
+
end
|
323
|
+
|
324
|
+
MyGem.settings.type_schema # => {:opt_one=>:int, :opt_two=>:str}
|
325
|
+
```
|
326
|
+
|
327
|
+
## Built-in Types
|
328
|
+
|
329
|
+
### Base Types
|
330
|
+
```ruby
|
331
|
+
:int => Integer
|
332
|
+
:str => String
|
333
|
+
:sym => Symbol
|
334
|
+
:null => NilClass
|
335
|
+
:any => Object
|
336
|
+
:true_class => TrueClass
|
337
|
+
:false_class => FalseClass
|
338
|
+
```
|
339
|
+
|
340
|
+
### Data Structures
|
341
|
+
```ruby
|
342
|
+
:hash => Hash
|
343
|
+
:array => Array
|
344
|
+
```
|
345
|
+
### Numeric
|
346
|
+
```ruby
|
347
|
+
:big_decimal => BigDecimal,
|
348
|
+
:float => Float,
|
349
|
+
:complex => Complex,
|
350
|
+
:rational => Rational,
|
351
|
+
```
|
352
|
+
### Time
|
353
|
+
```ruby
|
354
|
+
:date => Date,
|
355
|
+
:date_time => DateTime,
|
356
|
+
:time => Time,
|
357
|
+
```
|
358
|
+
### Composite
|
359
|
+
```ruby
|
360
|
+
:bool => [TrueClass, FalseClass],
|
361
|
+
:numeric => [Integer, Float, BigDecimal],
|
362
|
+
:kernel_num => [Integer, Float, BigDecimal, Complex, Rational],
|
363
|
+
:chrono => [Date, DateTime, Time]
|
364
|
+
```
|
365
|
+
|
366
|
+
## Development
|
367
|
+
|
368
|
+
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.
|
369
|
+
|
370
|
+
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).
|
371
|
+
|
372
|
+
## Contributing
|
373
|
+
|
374
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/yurigitsu/ace-config. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/yurigitsu/ace-config/blob/main/CODE_OF_CONDUCT.md).
|
375
|
+
|
376
|
+
## License
|
377
|
+
|
378
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
379
|
+
|
380
|
+
## Code of Conduct
|
381
|
+
|
382
|
+
Everyone interacting in the AceConfig project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/yurigitsu/ace-config/blob/main/CODE_OF_CONDUCT.md).
|
data/ace-config.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
|
6
|
+
require "ace_config/version"
|
7
|
+
|
8
|
+
Gem::Specification.new do |spec|
|
9
|
+
spec.name = "ace-config"
|
10
|
+
spec.version = "0.1.0.beta.rc1b"
|
11
|
+
spec.authors = ["yurigitsu"]
|
12
|
+
spec.email = ["yurigi.pro@gmail.com"]
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.summary = "A flexible and easy-to-use configuration handling gem."
|
16
|
+
spec.description = "Managing, configurations with type validation, configirations load and export support."
|
17
|
+
spec.homepage = "https://github.com/yurigitsu/#{spec.name}"
|
18
|
+
|
19
|
+
spec.required_ruby_version = ">= 3.0.0"
|
20
|
+
|
21
|
+
spec.files = Dir["CHANGELOG.md", "LICENSE", "README.md", "ace-config.gemspec", "lib/**/*"]
|
22
|
+
spec.bindir = "bin"
|
23
|
+
spec.executables = []
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
|
26
|
+
spec.metadata["repo_homepage"] = "https://github.com/yurigitsu/"
|
27
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
28
|
+
|
29
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
30
|
+
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
31
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
32
|
+
spec.metadata["bug_tracker_uri"] = "#{spec.homepage}/issues"
|
33
|
+
|
34
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
35
|
+
|
36
|
+
spec.add_dependency "bigdecimal", "~> 3.0"
|
37
|
+
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# AceConfig module provides functionality for managing configuration features.
|
4
|
+
#
|
5
|
+
# @example Using AceConfig in a class
|
6
|
+
# class MyApp
|
7
|
+
# include AceConfig
|
8
|
+
#
|
9
|
+
# configure :settings do
|
10
|
+
# config api_key: "default_key"
|
11
|
+
# config max_retries: 3
|
12
|
+
# end
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# MyApp.settings.api_key # => "default_key"
|
16
|
+
# MyApp.settings.max_retries # => 3
|
17
|
+
module AceConfig
|
18
|
+
# Extends the base class with Configuration module methods
|
19
|
+
def self.included(base)
|
20
|
+
base.extend(Configuration)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Isolated module handles isolated configurations.
|
24
|
+
#
|
25
|
+
# @example Using Isolated configurations
|
26
|
+
# class ParentApp
|
27
|
+
# include AceConfig::Isolated
|
28
|
+
#
|
29
|
+
# configure :parent_settings do
|
30
|
+
# config timeout: 30
|
31
|
+
# config tries: 3
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# class ChildApp < ParentApp
|
36
|
+
# parent_settings do
|
37
|
+
# config tries: 4
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# ChildApp.parent_settings.timeout # => 30
|
42
|
+
# ChildApp.parent_settings.tries # => 4
|
43
|
+
# ParentApp.parent_settings.tries # => 3
|
44
|
+
module Isolated
|
45
|
+
# Extends the base class with Configuration and Configuration::Isolated module methods
|
46
|
+
def self.included(base)
|
47
|
+
base.extend(Configuration)
|
48
|
+
base.extend(Configuration::Isolated)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# This module handles configuration trees and loading data from various sources.
|
53
|
+
module Configuration
|
54
|
+
# Isolated module provides methods for handling isolated configurations.
|
55
|
+
module Isolated
|
56
|
+
# Configures an isolated config tree and tracks it
|
57
|
+
#
|
58
|
+
# @param config_tree_name [Symbol] The name of the configuration tree
|
59
|
+
# @param opts [Hash] Options for configuration
|
60
|
+
# @yield The configuration block
|
61
|
+
# @return [self]
|
62
|
+
#
|
63
|
+
# @example
|
64
|
+
# configure :isolated_settings do
|
65
|
+
# config api_url: "https://api.example.com"
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# # Example of accessing the configuration
|
69
|
+
# puts MyApp.isolated_settings.api_url # => "https://api.example.com"
|
70
|
+
def configure(config_tree_name, opts = {}, &block)
|
71
|
+
super
|
72
|
+
|
73
|
+
@isolated_configs ||= []
|
74
|
+
@isolated_configs << config_tree_name
|
75
|
+
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
# Inherits isolated configurations to the base class
|
80
|
+
#
|
81
|
+
# @param base [Class] The inheriting class
|
82
|
+
#
|
83
|
+
# @example
|
84
|
+
# class ChildClass < ParentClass
|
85
|
+
# # Automatically inherits isolated configurations
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# # Example of accessing inherited configurations
|
89
|
+
# puts ChildClass.parent_settings.timeout # => 30
|
90
|
+
def inherited(base)
|
91
|
+
super
|
92
|
+
|
93
|
+
@isolated_configs.each do |parent_config|
|
94
|
+
hash = __send__(parent_config).to_h
|
95
|
+
schema = __send__(parent_config).type_schema
|
96
|
+
|
97
|
+
base.configure parent_config, hash: hash, schema: schema
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Creates a class-level method for the configuration tree.
|
103
|
+
#
|
104
|
+
# This method allows you to define a configuration tree using a block
|
105
|
+
# or load configuration data from a hash, JSON, or YAML file.
|
106
|
+
#
|
107
|
+
# @param config_tree_name [Symbol, String] The name of the configuration method to be defined.
|
108
|
+
# @param opts [Hash] Optional options for loading configuration data.
|
109
|
+
# @option opts [Hash] :hash A hash containing configuration data.
|
110
|
+
# @option opts [String] :json A JSON string containing configuration data.
|
111
|
+
# @option opts [String] :yaml A file path to a YAML file containing configuration data.
|
112
|
+
# @option opts [Hash] :schema A hash representing the type schema for the configuration.
|
113
|
+
# @yield [Setting] A block that builds the configuration tree.
|
114
|
+
#
|
115
|
+
# @example Configuring with a block
|
116
|
+
# configure :app_config do
|
117
|
+
# config :username, value: "admin"
|
118
|
+
# config :max_connections, type: :int, value: 10
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# @example Loading from a hash
|
122
|
+
# configure :app_config, hash: { username: "admin", max_connections: 10 }
|
123
|
+
#
|
124
|
+
# @example Loading from a JSON string
|
125
|
+
# configure :app_config, json: '{"username": "admin", "max_connections": 10}'
|
126
|
+
#
|
127
|
+
# @example Loading from a YAML file
|
128
|
+
# configure :app_config, yaml: 'config/settings.yml'
|
129
|
+
#
|
130
|
+
# @example Loading with a schema
|
131
|
+
# configure :app_config, hash: { name: "admin", policy: "allow" }, schema: { name: :str, policy: :str }
|
132
|
+
def configure(config_tree_name, opts = {}, &block)
|
133
|
+
settings = block ? AceConfig::Setting.new(&block) : AceConfig::Setting.new
|
134
|
+
|
135
|
+
load_configs = load_data(opts) unless opts.empty?
|
136
|
+
settings.load_from_hash(load_configs, schema: opts[:schema]) if load_configs
|
137
|
+
|
138
|
+
define_singleton_method(config_tree_name) do |&tree_block|
|
139
|
+
tree_block ? settings.instance_eval(&tree_block) : settings
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
module_function
|
144
|
+
|
145
|
+
# Loads configuration data from various sources based on the provided options.
|
146
|
+
#
|
147
|
+
# @param opts [Hash] Optional options for loading configuration data.
|
148
|
+
# @option opts [Hash] :hash A hash containing configuration data.
|
149
|
+
# @option opts [String] :json A JSON string containing configuration data.
|
150
|
+
# @option opts [String] :yaml A file path to a YAML file containing configuration data.
|
151
|
+
# @return [Hash] The loaded configuration data.
|
152
|
+
# @raise [LoadDataError] If no valid data is found.
|
153
|
+
#
|
154
|
+
# @example Loading from a hash
|
155
|
+
# load_data(hash: { key: "value" })
|
156
|
+
#
|
157
|
+
# @example Loading from a JSON string
|
158
|
+
# load_data(json: '{"key": "value"}')
|
159
|
+
#
|
160
|
+
# @example Loading from a YAML file
|
161
|
+
# load_data(yaml: 'config/settings.yml')
|
162
|
+
def load_data(opts = {})
|
163
|
+
data = opts[:hash] if opts[:hash]
|
164
|
+
data = JSON.parse(opts[:json]) if opts[:json]
|
165
|
+
data = YAML.load_file(opts[:yaml]) if opts[:yaml]
|
166
|
+
raise AceConfig::LoadDataError, "Invalid load source type" unless data
|
167
|
+
|
168
|
+
data
|
169
|
+
rescue JSON::ParserError
|
170
|
+
raise AceConfig::LoadDataError, "Invalid JSON format"
|
171
|
+
rescue Errno::ENOENT
|
172
|
+
raise AceConfig::LoadDataError, "YAML file not found"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# AceConfig module provides functionality for managing AceConfig features.
|
4
|
+
module AceConfig
|
5
|
+
# Custom error raised when a setting type does not match the expected type.
|
6
|
+
#
|
7
|
+
# @example Raising an SettingTypeError
|
8
|
+
# raise SettingTypeError.new(:int, "string")
|
9
|
+
# # => raises SettingTypeError with message
|
10
|
+
# # "Expected: <int>. Given: \"string\" which is <String> class."
|
11
|
+
class SettingTypeError < TypeError
|
12
|
+
# Initializes a new SettingTypeError.
|
13
|
+
#
|
14
|
+
# @param type [Symbol] The expected type.
|
15
|
+
# @param val [Object] The value that was provided.
|
16
|
+
def initialize(type, val)
|
17
|
+
super(type_error_msg(type, val))
|
18
|
+
end
|
19
|
+
|
20
|
+
# Generates the error message for the exception.
|
21
|
+
#
|
22
|
+
# @param type [Symbol] The expected type.
|
23
|
+
# @param val [Object] The value that was provided.
|
24
|
+
# @return [String] The formatted error message.
|
25
|
+
def type_error_msg(type, val)
|
26
|
+
"Expected: <#{type}>. Given: #{val.inspect} which is <#{val.class}> class."
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Custom error raised when a type definition is missing.
|
31
|
+
#
|
32
|
+
# @example Raising a TypeCheckerError
|
33
|
+
# raise TypeCheckerError.new(:unknown_type)
|
34
|
+
# # => raises TypeCheckerError with message "No type Definition for: <unknown_type> type"
|
35
|
+
class TypeCheckerError < StandardError
|
36
|
+
# Initializes a new TypeCheckerError.
|
37
|
+
#
|
38
|
+
# @param type [Symbol] The type that is missing a definition.
|
39
|
+
def initialize(type)
|
40
|
+
super(definition_error_msg(type))
|
41
|
+
end
|
42
|
+
|
43
|
+
# Generates the error message for the exception.
|
44
|
+
#
|
45
|
+
# @param type [Symbol] The type that is missing a definition.
|
46
|
+
# @return [String] The formatted error message.
|
47
|
+
def definition_error_msg(type)
|
48
|
+
"No type Definition for: <#{type}> type"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Custom error raised when data loading fails.
|
53
|
+
class LoadDataError < StandardError; end
|
54
|
+
end
|
@@ -0,0 +1,231 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "yaml"
|
4
|
+
require "json"
|
5
|
+
|
6
|
+
# AceConfig module provides functionality for managing AceConfig features.
|
7
|
+
module AceConfig
|
8
|
+
# Setting class provides a configuration tree structure for managing settings.
|
9
|
+
#
|
10
|
+
# This class allows for dynamic configuration management, enabling
|
11
|
+
# the loading of settings from hashes, YAML, or JSON formats.
|
12
|
+
#
|
13
|
+
# @example Basic usage
|
14
|
+
# settings = Setting.new do
|
15
|
+
# config(:key1, value: "example")
|
16
|
+
# config(:key2, type: :int)
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
class Setting
|
20
|
+
# Dynamically define methods for each type in TypeMap.
|
21
|
+
#
|
22
|
+
# @!method int(value)
|
23
|
+
# Sets an integer configuration value.
|
24
|
+
# @param value [Integer] The integer value to set.
|
25
|
+
#
|
26
|
+
# @!method string(value)
|
27
|
+
# Sets a string configuration value.
|
28
|
+
# @param value [String] The string value to set.
|
29
|
+
#
|
30
|
+
# ... (other type methods)
|
31
|
+
AceConfig::TypeMap.list_types.each do |type|
|
32
|
+
define_method(type.downcase) { |stng| config(stng, type: type) }
|
33
|
+
end
|
34
|
+
|
35
|
+
# Initializes a new Setting instance.
|
36
|
+
#
|
37
|
+
# @yield [self] Configures the instance upon creation if a block is given.
|
38
|
+
def initialize(&block)
|
39
|
+
@schema = {}
|
40
|
+
@config_tree = {}
|
41
|
+
|
42
|
+
instance_eval(&block) if block_given?
|
43
|
+
end
|
44
|
+
|
45
|
+
# Loads configuration from a hash with an optional schema.
|
46
|
+
#
|
47
|
+
# @param data [Hash] The hash containing configuration data.
|
48
|
+
# @param schema [Hash] Optional schema for type validation.
|
49
|
+
# @raise [NoMethodError] If a method corresponding to a key is not defined.
|
50
|
+
# @raise [SettingTypeError] If a value doesn't match the specified type in the schema.
|
51
|
+
#
|
52
|
+
# @example Loading from a hash with type validation
|
53
|
+
# settings.load_from_hash({ name: "admin", max_connections: 10 }, schema: { name: :str, max_connections: :int })
|
54
|
+
def load_from_hash(data, schema: {})
|
55
|
+
data.each do |key, value|
|
56
|
+
key = key.to_sym
|
57
|
+
type = schema[key] if schema
|
58
|
+
|
59
|
+
if value.is_a?(Hash) || value.is_a?(Setting)
|
60
|
+
configure(key) { load_from_hash(value, schema: schema[key]) }
|
61
|
+
else
|
62
|
+
validate_setting!(value, type) if type
|
63
|
+
|
64
|
+
config(key => value, type: type)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Configures a node of the configuration tree.
|
70
|
+
#
|
71
|
+
# @param node [Symbol, String] The name of the config node key.
|
72
|
+
# @yield [Setting] A block that configures the new node.
|
73
|
+
#
|
74
|
+
# @example Configuring a new node
|
75
|
+
# settings.configure(:database) do
|
76
|
+
# config(:host, value: "localhost")
|
77
|
+
# config(:port, value: 5432)
|
78
|
+
# end
|
79
|
+
def configure(node, &block)
|
80
|
+
if config_tree[node]
|
81
|
+
config_tree[node].instance_eval(&block)
|
82
|
+
else
|
83
|
+
create_new_node(node, &block)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Configures a setting with a given name and type.
|
88
|
+
#
|
89
|
+
# @param setting [Symbol, Hash, nil] The name of the setting or a hash of settings.
|
90
|
+
# @param type [Symbol, nil] The expected type of the setting.
|
91
|
+
# @param opt [Hash] Additional options for configuration.
|
92
|
+
# @return [self] The current instance for method chaining.
|
93
|
+
# @raise [SettingTypeError] If the value does not match the expected type.
|
94
|
+
#
|
95
|
+
# @example Configuring a setting
|
96
|
+
# settings.config(max_connections: 10, type: :int)
|
97
|
+
def config(setting = nil, type: nil, **opt)
|
98
|
+
return self if !setting && opt.empty?
|
99
|
+
|
100
|
+
stngs = setting || opt
|
101
|
+
stng = extract_setting_info(stngs)
|
102
|
+
|
103
|
+
stng_type = type || schema[stng[:name]] || :any
|
104
|
+
validate_setting!(stng[:value], stng_type)
|
105
|
+
|
106
|
+
set_configuration(stng[:name], stng[:value], stng_type)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns the type schema of the configuration.
|
110
|
+
#
|
111
|
+
# @return [Hash] A hash representing the type schema.
|
112
|
+
# @example Retrieving the type schema
|
113
|
+
# schema = settings.type_schema
|
114
|
+
def type_schema
|
115
|
+
{}.tap do |hsh|
|
116
|
+
config_tree.each do |k, v|
|
117
|
+
v.is_a?(AceConfig::Setting) ? (hsh[k] = v.type_schema) : hsh.merge!(schema)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Converts the configuration tree into a hash.
|
123
|
+
#
|
124
|
+
# @return [Hash] The config tree as a hash.
|
125
|
+
# @example Converting to hash
|
126
|
+
# hash = settings.to_h
|
127
|
+
def to_h
|
128
|
+
{}.tap do |hsh|
|
129
|
+
config_tree.each do |k, v|
|
130
|
+
hsh[k] = v.is_a?(AceConfig::Setting) ? v.to_h : v
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# Converts the configuration tree into YAML format.
|
136
|
+
#
|
137
|
+
# @param dump [String, nil] Optional file path to dump the YAML.
|
138
|
+
# @return [String, nil] The YAML string or nil if dumped to a file.
|
139
|
+
# @example Converting to YAML
|
140
|
+
# yaml_string = settings.to_yaml
|
141
|
+
# settings.to_yaml(dump: "config.yml") # Dumps to a file
|
142
|
+
def to_yaml(dump: nil)
|
143
|
+
yaml = to_h.to_yaml
|
144
|
+
dump ? File.write(dump, yaml) : yaml
|
145
|
+
end
|
146
|
+
|
147
|
+
# Converts the configuration tree into JSON format.
|
148
|
+
#
|
149
|
+
# @return [String] The JSON representation of the configuration tree.
|
150
|
+
# @example Converting to JSON
|
151
|
+
# json_string = settings.to_json
|
152
|
+
def to_json(*_args)
|
153
|
+
to_h.to_json
|
154
|
+
end
|
155
|
+
|
156
|
+
protected
|
157
|
+
|
158
|
+
# @return [Hash] The schema of configuration types.
|
159
|
+
attr_reader :schema
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
# @return [Hash] The tree structure of configuration settings.
|
164
|
+
attr_reader :config_tree
|
165
|
+
|
166
|
+
# Creates a new node in the configuration tree.
|
167
|
+
#
|
168
|
+
# @param node [Symbol] The name of the node to create.
|
169
|
+
# @yield [Setting] A block to configure the new setting.
|
170
|
+
# @return [Setting] The newly created setting node.
|
171
|
+
def create_new_node(node, &block)
|
172
|
+
new_node = AceConfig::Setting.new(&block)
|
173
|
+
config_tree[node] = new_node
|
174
|
+
define_node_methods(node)
|
175
|
+
end
|
176
|
+
|
177
|
+
# Defines singleton methods for the given node.
|
178
|
+
#
|
179
|
+
# @param node [Symbol] The name of the node to define methods for.
|
180
|
+
def define_node_methods(node)
|
181
|
+
define_singleton_method(node) do |*_args, &node_block|
|
182
|
+
if node_block
|
183
|
+
config_tree[node].instance_eval(&node_block)
|
184
|
+
else
|
185
|
+
config_tree[node]
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# Extracts the setting information from the provided input.
|
191
|
+
#
|
192
|
+
# @param stngs [Symbol, Hash] The setting name or a hash containing the setting name and value.
|
193
|
+
# @return [Hash] A hash containing the setting name and its corresponding value.
|
194
|
+
def extract_setting_info(stngs)
|
195
|
+
val = nil
|
196
|
+
name = stngs if stngs.is_a?(Symbol)
|
197
|
+
name, val = stngs.to_a.first if stngs.is_a?(Hash)
|
198
|
+
|
199
|
+
{ name: name, value: val }
|
200
|
+
end
|
201
|
+
|
202
|
+
# Validates the setting value against the expected type.
|
203
|
+
#
|
204
|
+
# @param stng_val [Object] The value of the setting to validate.
|
205
|
+
# @param stng_type [Symbol] The expected type of the setting.
|
206
|
+
# @raise [SettingTypeError] If the setting value does not match the expected type.
|
207
|
+
def validate_setting!(stng_val, stng_type)
|
208
|
+
is_valid = AceConfig::TypeChecker.call(stng_val, type: stng_type)
|
209
|
+
raise AceConfig::SettingTypeError.new(stng_type, stng_val) unless !stng_val || is_valid
|
210
|
+
end
|
211
|
+
|
212
|
+
# Sets the configuration for a given setting name, value, and type.
|
213
|
+
#
|
214
|
+
# @param stng_name [Symbol] The name of the setting to configure.
|
215
|
+
# @param stng_val [Object] The value to assign to the setting.
|
216
|
+
# @param stng_type [Symbol] The type of the setting.
|
217
|
+
def set_configuration(stng_name, stng_val, stng_type)
|
218
|
+
schema[stng_name] = stng_type
|
219
|
+
config_tree[stng_name] = stng_val
|
220
|
+
return if respond_to?(stng_name)
|
221
|
+
|
222
|
+
define_singleton_method(stng_name) do |value = nil, type: nil|
|
223
|
+
if value
|
224
|
+
config(**{ stng_name => value, type: type })
|
225
|
+
else
|
226
|
+
config_tree[stng_name]
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# AceConfig module provides functionality for managing AceConfig features.
|
4
|
+
module AceConfig
|
5
|
+
# This class is responsible for type checking in the Ace configuration.
|
6
|
+
class TypeChecker
|
7
|
+
class << self
|
8
|
+
# Calls the appropriate validation method based on the type.
|
9
|
+
#
|
10
|
+
# @param value [Object] The value to validate.
|
11
|
+
# @param type [Symbol, Array<Symbol, Class>, Class] The type(s) to validate against.
|
12
|
+
# @return [Boolean] True if the value matches the type, false otherwise.
|
13
|
+
# @raise [TypeCheckerError] if the type is unsupported or not defined.
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# TypeChecker.call(1, type: :int) # => true
|
17
|
+
# TypeChecker.call(1, type: :numeric) # => true
|
18
|
+
# TypeChecker.call("hello", type: [:str, Integer]) # => true
|
19
|
+
# TypeChecker.call(CustomClass.new, type: CustomClass) # => true
|
20
|
+
def call(value, type:, **_opts)
|
21
|
+
case type
|
22
|
+
when Symbol
|
23
|
+
base_type(value, fetch_type(type))
|
24
|
+
when Array
|
25
|
+
one_of(value, type)
|
26
|
+
else
|
27
|
+
custom_type(value, type)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Validates if value matches the base type.
|
32
|
+
#
|
33
|
+
# @param value [Object] the value to validate
|
34
|
+
# @param type [Class] the type to validate against
|
35
|
+
# @return [Boolean] true if the value matches the base type
|
36
|
+
# @raise [TypeCheckerError] if the type is unsupported or not defined.
|
37
|
+
#
|
38
|
+
# @example
|
39
|
+
# TypeChecker.base_type(1, Integer) # => true
|
40
|
+
# TypeChecker.base_type(1, [:int, :float, :big_decimal]) # => true
|
41
|
+
def base_type(value, type)
|
42
|
+
type = fetch_type(type) if type.is_a?(Symbol)
|
43
|
+
|
44
|
+
type.is_a?(Array) ? one_of(value, type) : value.is_a?(type)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Checks if value matches any type in the array.
|
48
|
+
#
|
49
|
+
# @param value [Object] the value to validate
|
50
|
+
# @param array_type [Array<Symbol, Class>] the array of types to validate against
|
51
|
+
# @return [Boolean] true if the value matches any type in the array
|
52
|
+
#
|
53
|
+
# @example
|
54
|
+
# TypeChecker.one_of(1, [Integer, :str]) # => true
|
55
|
+
# TypeChecker.one_of("hello", [Integer, String, :sym]) # => true
|
56
|
+
# TypeChecker.one_of(nil, [:null, Integer, String]) # => true
|
57
|
+
# TypeChecker.one_of(1.5, [:int, :float, :big_decimal]) # => true
|
58
|
+
def one_of(value, array_type)
|
59
|
+
array_type.any? { |type| type.is_a?(Symbol) ? base_type(value, type) : custom_type(value, type) }
|
60
|
+
end
|
61
|
+
|
62
|
+
# Validates if value is of the specified custom type.
|
63
|
+
#
|
64
|
+
# @param value [Object] the value to validate
|
65
|
+
# @param type [Class] the custom type to validate against
|
66
|
+
# @return [Boolean] true if the value is of the specified custom type
|
67
|
+
#
|
68
|
+
# @example
|
69
|
+
# TypeChecker.custom_type(1, Integer) # => true
|
70
|
+
# TypeChecker.custom_type(CustomClass.new, CustomClass) # => true
|
71
|
+
def custom_type(value, type)
|
72
|
+
value.is_a?(type)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Fetches the basic type from the type map.
|
76
|
+
#
|
77
|
+
# @param type [Symbol] the type to fetch
|
78
|
+
# @return [Class] the corresponding basic type
|
79
|
+
# @raise [TypeCheckerError] if the type does not exist in TYPE_MAP
|
80
|
+
#
|
81
|
+
# @example
|
82
|
+
# TypeChecker.fetch_type(:int) # => Integer
|
83
|
+
# TypeChecker.fetch_type(:null) # => NilClass
|
84
|
+
# TypeChecker.fetch_type(:bool) # => [:truthy, :falsy]
|
85
|
+
def fetch_type(type)
|
86
|
+
basic_type = TypeMap.get(type)
|
87
|
+
raise AceConfig::TypeCheckerError, type unless basic_type
|
88
|
+
|
89
|
+
basic_type
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bigdecimal"
|
4
|
+
require "date"
|
5
|
+
|
6
|
+
# AceConfig module provides functionality for managing AceConfig features.
|
7
|
+
module AceConfig
|
8
|
+
# A class that maps type symbols to their corresponding Ruby classes and provides
|
9
|
+
# predefined collections of type symbols for various categories.
|
10
|
+
#
|
11
|
+
# This class allows retrieval of Ruby classes based on type symbols and provides
|
12
|
+
# methods to access collections of specific type symbols such as booleans, numerics,
|
13
|
+
# and chronological types.
|
14
|
+
class TypeMap
|
15
|
+
TYPE_MAP = {
|
16
|
+
# base types
|
17
|
+
int: Integer,
|
18
|
+
str: String,
|
19
|
+
sym: Symbol,
|
20
|
+
null: NilClass,
|
21
|
+
true_class: TrueClass,
|
22
|
+
false_class: FalseClass,
|
23
|
+
# data structures
|
24
|
+
hash: Hash,
|
25
|
+
array: Array,
|
26
|
+
# numeric types
|
27
|
+
big_decimal: BigDecimal,
|
28
|
+
float: Float,
|
29
|
+
complex: Complex,
|
30
|
+
rational: Rational,
|
31
|
+
# time types
|
32
|
+
date: Date,
|
33
|
+
date_time: DateTime,
|
34
|
+
time: Time,
|
35
|
+
# any type
|
36
|
+
any: Object,
|
37
|
+
# composite types
|
38
|
+
bool: %i[true_class false_class],
|
39
|
+
numeric: %i[int float big_decimal],
|
40
|
+
kernel_num: %i[int float big_decimal complex rational],
|
41
|
+
chrono: %i[date date_time time]
|
42
|
+
}.freeze
|
43
|
+
|
44
|
+
# Retrieves the Ruby class associated with a given type symbol.
|
45
|
+
#
|
46
|
+
# @param type [Symbol] The type symbol to look up. Must be one of the keys in TYPE_MAP.
|
47
|
+
# @return [Class, nil] The corresponding Ruby class or nil if the type symbol is not found.
|
48
|
+
#
|
49
|
+
# @example
|
50
|
+
# TypeMap.get(:int) # => Integer
|
51
|
+
# TypeMap.get(:str) # => String
|
52
|
+
# TypeMap.get(:unknown) # => nil
|
53
|
+
def self.get(type)
|
54
|
+
TYPE_MAP[type]
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns an array of all type symbols defined in TYPE_MAP.
|
58
|
+
#
|
59
|
+
# @return [Array<Symbol>] An array containing all keys from TYPE_MAP.
|
60
|
+
#
|
61
|
+
# @example
|
62
|
+
# TypeMap.list_types # => [:int, :str, :sym, :null, :true_class, :false_class,
|
63
|
+
# :hash, :array, :big_decimal, :float, :complex,
|
64
|
+
# :rational, :date, :date_time, :time, :any,
|
65
|
+
# :bool, :numeric, :kernel_num, :chrono]
|
66
|
+
def self.list_types
|
67
|
+
TYPE_MAP.keys
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/ace_config.rb
ADDED
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ace-config
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0.beta.rc1b
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- yurigitsu
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-09-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bigdecimal
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.0'
|
27
|
+
description: Managing, configurations with type validation, configirations load and
|
28
|
+
export support.
|
29
|
+
email:
|
30
|
+
- yurigi.pro@gmail.com
|
31
|
+
executables: []
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- CHANGELOG.md
|
36
|
+
- LICENSE
|
37
|
+
- README.md
|
38
|
+
- ace-config.gemspec
|
39
|
+
- lib/ace_config.rb
|
40
|
+
- lib/ace_config/configuration.rb
|
41
|
+
- lib/ace_config/errors.rb
|
42
|
+
- lib/ace_config/setting.rb
|
43
|
+
- lib/ace_config/type_checker.rb
|
44
|
+
- lib/ace_config/type_map.rb
|
45
|
+
- lib/ace_config/version.rb
|
46
|
+
homepage: https://github.com/yurigitsu/ace-config
|
47
|
+
licenses:
|
48
|
+
- MIT
|
49
|
+
metadata:
|
50
|
+
repo_homepage: https://github.com/yurigitsu/
|
51
|
+
allowed_push_host: https://rubygems.org
|
52
|
+
homepage_uri: https://github.com/yurigitsu/ace-config
|
53
|
+
changelog_uri: https://github.com/yurigitsu/ace-config/blob/main/CHANGELOG.md
|
54
|
+
source_code_uri: https://github.com/yurigitsu/ace-config
|
55
|
+
bug_tracker_uri: https://github.com/yurigitsu/ace-config/issues
|
56
|
+
rubygems_mfa_required: 'true'
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options: []
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 3.0.0
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
requirements: []
|
72
|
+
rubygems_version: 3.5.20
|
73
|
+
signing_key:
|
74
|
+
specification_version: 4
|
75
|
+
summary: A flexible and easy-to-use configuration handling gem.
|
76
|
+
test_files: []
|