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