konfig-config 1.0.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 +7 -0
- data/lib/konfig/config.rb +26 -0
- data/lib/konfig/config_hash.rb +14 -0
- data/lib/konfig/deep_merge.rb +1 -0
- data/lib/konfig/error.rb +20 -0
- data/lib/konfig/schema.rb +52 -0
- data/lib/konfig/schema_attribute.rb +71 -0
- data/lib/konfig/schema_dsl.rb +22 -0
- data/lib/konfig/schema_group.rb +44 -0
- data/lib/konfig/schema_group_dsl.rb +19 -0
- data/lib/konfig/sources/abstract.rb +19 -0
- data/lib/konfig/sources/directory.rb +35 -0
- data/lib/konfig/sources/environment.rb +34 -0
- data/lib/konfig/sources/yaml.rb +28 -0
- data/lib/konfig/version.rb +12 -0
- data/lib/konfig-config.rb +3 -0
- data/lib/konfig.rb +4 -0
- metadata +73 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 75a53b2df0604086dbbec0e28d797572149247f999d16875948c0ceec940ccb5
|
4
|
+
data.tar.gz: 5dcc54bb9a313c53c26ce7b3070ef69e3a9ea9a805aa9a3513d5406be7297c64
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6536edc14535469c53978a368ddc3fb8e73dbf8058c7c79cb4737894e73645d30275e86551a16fcfc5374acc8eb40e94c1c0af64ab5c45ab8775d341c8971273
|
7
|
+
data.tar.gz: c0f45ef59ea643d7d1a1d1342d6bda7ff88edb4e50530e53a009eb46efdbf6f3d64c42ece69d98cf959150fc74f0abedf6422d8f249815e5ff8370c5635cbec8
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Konfig
|
4
|
+
class Config
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def build(schema, sources: [])
|
9
|
+
@schema = schema
|
10
|
+
@sources = sources
|
11
|
+
|
12
|
+
values = Hashie::Mash.new(@schema.create_hash(nil))
|
13
|
+
|
14
|
+
# Override all defaults with values from the sources
|
15
|
+
# in the reverse order they are given.
|
16
|
+
sources.reverse.each do |source|
|
17
|
+
values.deep_merge!(@schema.create_hash(source))
|
18
|
+
end
|
19
|
+
|
20
|
+
values
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'hashie'
|
4
|
+
|
5
|
+
module Konfig
|
6
|
+
class ConfigHash < ::Hash
|
7
|
+
|
8
|
+
include Hashie::Extensions::MethodAccess
|
9
|
+
include Hashie::Extensions::DeepMerge
|
10
|
+
include Hashie::Extensions::MergeInitializer
|
11
|
+
include Hashie::Extensions::IndifferentAccess
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
# frozen_string_literal: true
|
data/lib/konfig/error.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Konfig
|
4
|
+
|
5
|
+
class Error < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
class GroupNotFoundError < Error
|
9
|
+
end
|
10
|
+
|
11
|
+
class AttributeNotFoundError < Error
|
12
|
+
end
|
13
|
+
|
14
|
+
class InvalidAttributeTypeError < Error
|
15
|
+
end
|
16
|
+
|
17
|
+
class ValueNotPresentError < Error
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'konfig/error'
|
4
|
+
require 'konfig/schema_group'
|
5
|
+
require 'konfig/schema_dsl'
|
6
|
+
require 'konfig/config_hash'
|
7
|
+
|
8
|
+
module Konfig
|
9
|
+
class Schema
|
10
|
+
|
11
|
+
attr_reader :groups
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@groups = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def group(name)
|
18
|
+
@groups[name] || raise(GroupNotFoundError, "Group '#{name}' not found in schema")
|
19
|
+
end
|
20
|
+
|
21
|
+
def group?(name)
|
22
|
+
@groups.key?(name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_group(name)
|
26
|
+
group = SchemaGroup.new
|
27
|
+
@groups[name] = group
|
28
|
+
yield group if block_given?
|
29
|
+
group
|
30
|
+
end
|
31
|
+
|
32
|
+
def create_hash(source)
|
33
|
+
@groups.each_with_object({}) do |(name, group), hash|
|
34
|
+
hash[name] = group.create_hash([name], source)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class << self
|
39
|
+
|
40
|
+
def draw(&block)
|
41
|
+
schema = new
|
42
|
+
if block
|
43
|
+
dsl = SchemaDSL.new(schema)
|
44
|
+
dsl.instance_eval(&block)
|
45
|
+
end
|
46
|
+
schema
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Konfig
|
4
|
+
class SchemaAttribute
|
5
|
+
|
6
|
+
TYPES = [:string, :integer, :float, :boolean].freeze
|
7
|
+
|
8
|
+
attr_reader :name
|
9
|
+
attr_reader :type
|
10
|
+
attr_reader :default
|
11
|
+
attr_reader :transformer
|
12
|
+
|
13
|
+
def initialize(name, type: :string, array: false, default: nil, transformer: nil)
|
14
|
+
@name = name
|
15
|
+
@type = type
|
16
|
+
@array = array
|
17
|
+
@default = default
|
18
|
+
@transformer = transformer
|
19
|
+
|
20
|
+
raise InvalidAttributeTypeError, "Invalid type #{type} for attribute #{name}" unless TYPES.include?(type)
|
21
|
+
end
|
22
|
+
|
23
|
+
def array?
|
24
|
+
@array == true
|
25
|
+
end
|
26
|
+
|
27
|
+
def cast(value)
|
28
|
+
return value.map { |v| cast(v) } if value.is_a?(Array)
|
29
|
+
|
30
|
+
return nil if value.nil?
|
31
|
+
return nil if value.is_a?(String) && value.empty?
|
32
|
+
|
33
|
+
send("cast_#{type}", value)
|
34
|
+
end
|
35
|
+
|
36
|
+
def transform(value)
|
37
|
+
casted = cast(value)
|
38
|
+
return casted if transformer.nil?
|
39
|
+
|
40
|
+
transformer.call(casted)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def cast_string(input)
|
46
|
+
input.to_s
|
47
|
+
end
|
48
|
+
|
49
|
+
def cast_integer(input)
|
50
|
+
return 1 if input == true
|
51
|
+
return 0 if input == false
|
52
|
+
|
53
|
+
input.to_i
|
54
|
+
end
|
55
|
+
|
56
|
+
def cast_float(input)
|
57
|
+
return 1.0 if input == true
|
58
|
+
return 0.0 if input == false
|
59
|
+
|
60
|
+
input.to_f
|
61
|
+
end
|
62
|
+
|
63
|
+
def cast_boolean(input)
|
64
|
+
return true if input == true
|
65
|
+
return false if input == false
|
66
|
+
|
67
|
+
%w[true 1 1.0].include?(input.to_s)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'konfig/schema_group_dsl'
|
4
|
+
|
5
|
+
module Konfig
|
6
|
+
class SchemaDSL
|
7
|
+
|
8
|
+
def initialize(schema)
|
9
|
+
@schema = schema
|
10
|
+
end
|
11
|
+
|
12
|
+
def group(name, &block)
|
13
|
+
group = @schema.add_group(name)
|
14
|
+
if block
|
15
|
+
group_dsl = SchemaGroupDSL.new(group)
|
16
|
+
group_dsl.instance_eval(&block)
|
17
|
+
end
|
18
|
+
group
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'konfig/config_hash'
|
4
|
+
require 'konfig/schema_attribute'
|
5
|
+
|
6
|
+
module Konfig
|
7
|
+
class SchemaGroup
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@attributes = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def attribute(name)
|
14
|
+
@attributes[name] || raise(AttributeNotFoundError, "Attribute '#{name}' not found in schema")
|
15
|
+
end
|
16
|
+
|
17
|
+
def attribute?(name)
|
18
|
+
@attributes.key?(name)
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_attribute(name, **kwargs, &block)
|
22
|
+
kwargs[:transformer] = block if block && !kwargs.key?(:transformer)
|
23
|
+
@attributes[name] = SchemaAttribute.new(name, **kwargs)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Create a hash of the all the values for this group from the given source.
|
27
|
+
def create_hash(path, source = nil)
|
28
|
+
@attributes.each_with_object({}) do |(name, attribute), hash|
|
29
|
+
attribute_path = path + [name]
|
30
|
+
if source.nil?
|
31
|
+
hash[name] = attribute.cast(attribute.default)
|
32
|
+
else
|
33
|
+
begin
|
34
|
+
source_value = source.get(attribute_path, attribute: attribute)
|
35
|
+
hash[name] = attribute.transform(source_value)
|
36
|
+
rescue ValueNotPresentError
|
37
|
+
# This is OK
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'konfig/schema_attribute'
|
4
|
+
|
5
|
+
module Konfig
|
6
|
+
class SchemaGroupDSL
|
7
|
+
|
8
|
+
def initialize(group)
|
9
|
+
@group = group
|
10
|
+
end
|
11
|
+
|
12
|
+
SchemaAttribute::TYPES.each do |type|
|
13
|
+
define_method type do |name, **kwargs, &block|
|
14
|
+
@group.add_attribute(name, type: type, **kwargs, &block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Konfig
|
4
|
+
module Sources
|
5
|
+
class Abstract
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
end
|
9
|
+
|
10
|
+
# The get method will return the give value for the given path.
|
11
|
+
# The path will contain the full path to the value, including the
|
12
|
+
# groups which lead up to it.
|
13
|
+
def get(path, attribute: nil)
|
14
|
+
raise NotImplementedError
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'konfig/error'
|
4
|
+
require 'konfig/sources/abstract'
|
5
|
+
|
6
|
+
module Konfig
|
7
|
+
module Sources
|
8
|
+
class Directory < Abstract
|
9
|
+
|
10
|
+
def initialize(root, strip_contents: true, array_separator: /\n/)
|
11
|
+
super()
|
12
|
+
@root = root
|
13
|
+
@strip_contents = strip_contents
|
14
|
+
@array_separator = array_separator
|
15
|
+
end
|
16
|
+
|
17
|
+
def get(path, attribute: nil)
|
18
|
+
file_path = File.join(@root, path.join('.'))
|
19
|
+
raise ValueNotPresentError unless File.exist?(file_path)
|
20
|
+
|
21
|
+
result = File.read(file_path)
|
22
|
+
result = result.strip if @strip_contents
|
23
|
+
result = handle_array(result) if attribute&.array?
|
24
|
+
result
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def handle_array(value)
|
30
|
+
value.split(@array_separator).map(&:strip)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'konfig/error'
|
4
|
+
require 'konfig/sources/abstract'
|
5
|
+
|
6
|
+
module Konfig
|
7
|
+
module Sources
|
8
|
+
class Environment < Abstract
|
9
|
+
|
10
|
+
def initialize(env, array_separator: /\s*,\s*/)
|
11
|
+
super()
|
12
|
+
@env = env
|
13
|
+
@array_separator = array_separator
|
14
|
+
end
|
15
|
+
|
16
|
+
def get(path, attribute: nil)
|
17
|
+
key = path.map { |p| p.to_s.upcase }.join('_')
|
18
|
+
raise ValueNotPresentError unless @env.key?(key)
|
19
|
+
|
20
|
+
value = @env[key]
|
21
|
+
|
22
|
+
value = handle_array(value) if attribute&.array?
|
23
|
+
value
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def handle_array(value)
|
29
|
+
value.split(@array_separator).map(&:strip)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'konfig/error'
|
4
|
+
require 'konfig/sources/abstract'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
module Konfig
|
8
|
+
module Sources
|
9
|
+
class YAML < Abstract
|
10
|
+
|
11
|
+
def initialize(source)
|
12
|
+
super()
|
13
|
+
@source = ::YAML.safe_load(source)
|
14
|
+
end
|
15
|
+
|
16
|
+
def get(path, _attribute: nil)
|
17
|
+
source = @source
|
18
|
+
path.each do |p|
|
19
|
+
raise ValueNotPresentError unless source.key?(p.to_s)
|
20
|
+
|
21
|
+
source = source[p.to_s]
|
22
|
+
end
|
23
|
+
source
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Konfig
|
4
|
+
|
5
|
+
VERSION_FILE_ROOT = File.expand_path('../../VERSION', __dir__)
|
6
|
+
if File.file?(VERSION_FILE_ROOT)
|
7
|
+
VERSION = File.read(VERSION_FILE_ROOT).strip.sub(/\Av/, '')
|
8
|
+
else
|
9
|
+
VERSION = '0.0.0.dev'
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
data/lib/konfig.rb
ADDED
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: konfig-config
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Adam Cooke
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-03-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: hashie
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: A config schema generator
|
28
|
+
email:
|
29
|
+
- adam@krystal.uk
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- lib/konfig-config.rb
|
35
|
+
- lib/konfig.rb
|
36
|
+
- lib/konfig/config.rb
|
37
|
+
- lib/konfig/config_hash.rb
|
38
|
+
- lib/konfig/deep_merge.rb
|
39
|
+
- lib/konfig/error.rb
|
40
|
+
- lib/konfig/schema.rb
|
41
|
+
- lib/konfig/schema_attribute.rb
|
42
|
+
- lib/konfig/schema_dsl.rb
|
43
|
+
- lib/konfig/schema_group.rb
|
44
|
+
- lib/konfig/schema_group_dsl.rb
|
45
|
+
- lib/konfig/sources/abstract.rb
|
46
|
+
- lib/konfig/sources/directory.rb
|
47
|
+
- lib/konfig/sources/environment.rb
|
48
|
+
- lib/konfig/sources/yaml.rb
|
49
|
+
- lib/konfig/version.rb
|
50
|
+
homepage: https://github.com/krystal/konfig
|
51
|
+
licenses:
|
52
|
+
- MIT
|
53
|
+
metadata: {}
|
54
|
+
post_install_message:
|
55
|
+
rdoc_options: []
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '2.6'
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
requirements: []
|
69
|
+
rubygems_version: 3.3.26
|
70
|
+
signing_key:
|
71
|
+
specification_version: 4
|
72
|
+
summary: A config schema generator
|
73
|
+
test_files: []
|