ucfg 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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +35 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/ucfg.rb +56 -0
- data/lib/ucfg/variable_substitution.rb +90 -0
- data/lib/ucfg/version.rb +5 -0
- data/ucfg.gemspec +31 -0
- metadata +99 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8bbf3f2b08b59481c9ec0f4575399514acac9e446b99440c4599d6fa70f4cf76
|
4
|
+
data.tar.gz: f17dbf0b390389951bb295f1a23e42a79e0a4bd5efc641e3c6f2d6aa32f9a1eb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b098e6e239820fd2f75e108d7173dd29c5054adf103b31d84879c3503df6b23979d9c26722457f8029f95927b3d00f5dc09d28d321daab35e99519431a93c76d
|
7
|
+
data.tar.gz: c725cb25678c117cfc0b839b4ef20cf6305b67e3809e420369e1bca07d0061e026948b054a233e072b406c720629690c5e07dba783b17ccdd77093ff46a78293
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ucfg (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.3)
|
10
|
+
rake (10.5.0)
|
11
|
+
rspec (3.8.0)
|
12
|
+
rspec-core (~> 3.8.0)
|
13
|
+
rspec-expectations (~> 3.8.0)
|
14
|
+
rspec-mocks (~> 3.8.0)
|
15
|
+
rspec-core (3.8.2)
|
16
|
+
rspec-support (~> 3.8.0)
|
17
|
+
rspec-expectations (3.8.4)
|
18
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
19
|
+
rspec-support (~> 3.8.0)
|
20
|
+
rspec-mocks (3.8.1)
|
21
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
22
|
+
rspec-support (~> 3.8.0)
|
23
|
+
rspec-support (3.8.2)
|
24
|
+
|
25
|
+
PLATFORMS
|
26
|
+
ruby
|
27
|
+
|
28
|
+
DEPENDENCIES
|
29
|
+
bundler (~> 2.0)
|
30
|
+
rake (~> 10.0)
|
31
|
+
rspec (~> 3.0)
|
32
|
+
ucfg!
|
33
|
+
|
34
|
+
BUNDLED WITH
|
35
|
+
2.0.2
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "ucfg"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/lib/ucfg.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ucfg/version"
|
4
|
+
require "ucfg/variable_substitution"
|
5
|
+
require "yaml"
|
6
|
+
|
7
|
+
module Ucfg
|
8
|
+
class Error < StandardError; end
|
9
|
+
class InvalidYAMLSyntax < Error; end
|
10
|
+
class InvalidSubstitution < Error; end
|
11
|
+
|
12
|
+
# This is a modified version of Hash#deep_merge! from ActiveSupport: https://github.com/rails/rails/blob/b9ca94caea2ca6a6cc09abaffaad67b447134079/activesupport/lib/active_support/core_ext/hash/deep_merge.rb
|
13
|
+
module DeepMergeableHash
|
14
|
+
refine Hash do
|
15
|
+
def deep_merge!(other_hash, &block)
|
16
|
+
merge!(other_hash) do |key, this_val, other_val|
|
17
|
+
if this_val.is_a?(Hash) && other_val.is_a?(Hash)
|
18
|
+
this_val.dup.deep_merge!(other_val, &block)
|
19
|
+
elsif block_given?
|
20
|
+
block.call(key, this_val, other_val)
|
21
|
+
else
|
22
|
+
other_val
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
using DeepMergeableHash
|
30
|
+
|
31
|
+
class << self
|
32
|
+
def parse(raw, options = ENV)
|
33
|
+
value = YAML.safe_load(raw)
|
34
|
+
dot_nested_value = dot_to_nested(value)
|
35
|
+
VariableSubstitution.new(dot_nested_value, options).substitute
|
36
|
+
rescue Psych::SyntaxError
|
37
|
+
raise InvalidYAMLSyntax, "Invalid YAML"
|
38
|
+
end
|
39
|
+
|
40
|
+
def dot_to_nested(value)
|
41
|
+
case value
|
42
|
+
when Array
|
43
|
+
value.map { |v| dot_to_nested(v) }
|
44
|
+
when Hash
|
45
|
+
value.each_with_object({}) do |(k, v), out|
|
46
|
+
keys_in_path = k.split(".")
|
47
|
+
transformed_value = dot_to_nested(v)
|
48
|
+
dot_nested_hash = keys_in_path.reverse_each.reduce(transformed_value) { |memo, part| { part => memo } }
|
49
|
+
out.deep_merge!(dot_nested_hash)
|
50
|
+
end
|
51
|
+
else
|
52
|
+
value
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "yaml"
|
4
|
+
|
5
|
+
module Ucfg
|
6
|
+
class VariableSubstitution
|
7
|
+
PREFIX = "${"
|
8
|
+
SUFFIX = "}"
|
9
|
+
|
10
|
+
def initialize(full_config, options = {})
|
11
|
+
@full_config = full_config
|
12
|
+
@options = options
|
13
|
+
end
|
14
|
+
|
15
|
+
def substitute
|
16
|
+
substitute_variables(full_config)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
attr_reader :full_config, :options
|
22
|
+
|
23
|
+
def substitute_variables(config)
|
24
|
+
case config
|
25
|
+
when Hash
|
26
|
+
config.transform_values { |val| substitute_variables(val) }
|
27
|
+
when Array
|
28
|
+
config.map { |val| substitute_variables(val) }
|
29
|
+
when String
|
30
|
+
final_value = variable_substitutions(config)
|
31
|
+
Psych::ScalarScanner.new(Psych::ClassLoader.new).tokenize(final_value)
|
32
|
+
else
|
33
|
+
config
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def variable_substitutions(string, visited_placeholders = Set.new)
|
38
|
+
while (start_index = string.index(PREFIX))
|
39
|
+
break unless (end_index = find_placeholder_end_index(string, start_index))
|
40
|
+
|
41
|
+
placeholder = string[(start_index + PREFIX.length)..(end_index - SUFFIX.length)]
|
42
|
+
if visited_placeholders.include?(placeholder)
|
43
|
+
raise InvalidSubstitution, "Circular placeholder reference '#{placeholder}' in property definitions"
|
44
|
+
end
|
45
|
+
|
46
|
+
visited_placeholders.add(placeholder)
|
47
|
+
|
48
|
+
placeholder = variable_substitutions(placeholder, visited_placeholders)
|
49
|
+
placeholder, _, default_value = placeholder.partition(":")
|
50
|
+
if !options.key?(placeholder) && default_value.to_s.empty?
|
51
|
+
raise InvalidSubstitution, "Could not resolve placeholder '#{placeholder}'"
|
52
|
+
end
|
53
|
+
|
54
|
+
unquoted_default_value =
|
55
|
+
if default_value.start_with?('"') && default_value.end_with?('"')
|
56
|
+
default_value[1..-2]
|
57
|
+
elsif default_value.start_with?("'") && default_value.end_with?("'")
|
58
|
+
default_value[1..-2]
|
59
|
+
else
|
60
|
+
default_value
|
61
|
+
end
|
62
|
+
property_value = options.key?(placeholder) ? options.fetch(placeholder) : unquoted_default_value
|
63
|
+
final_value = variable_substitutions(property_value, visited_placeholders)
|
64
|
+
string = string[0...start_index] + final_value + string[(end_index + 1)..-1]
|
65
|
+
|
66
|
+
visited_placeholders.delete(placeholder)
|
67
|
+
end
|
68
|
+
|
69
|
+
string
|
70
|
+
end
|
71
|
+
|
72
|
+
def find_placeholder_end_index(config, start_index)
|
73
|
+
index = start_index + PREFIX.length
|
74
|
+
within_nested_placedholder = 0
|
75
|
+
while index < config.length
|
76
|
+
if config[index...(index + SUFFIX.length)] == SUFFIX
|
77
|
+
return index unless within_nested_placedholder > 0
|
78
|
+
|
79
|
+
within_nested_placedholder -= 1
|
80
|
+
index += SUFFIX.length
|
81
|
+
elsif config[index...(index + PREFIX.length)] == PREFIX
|
82
|
+
within_nested_placedholder += 1
|
83
|
+
index += PREFIX.length
|
84
|
+
else
|
85
|
+
index += 1
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/lib/ucfg/version.rb
ADDED
data/ucfg.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
lib = File.expand_path("lib", __dir__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "ucfg/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "ucfg"
|
7
|
+
spec.version = Ucfg::VERSION
|
8
|
+
spec.authors = ["Orhan Toy"]
|
9
|
+
spec.email = ["toyorhan@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = %q{Ruby universal configuration}
|
12
|
+
spec.description = %q{This library is the Ruby variant of https://github.com/elastic/go-ucfg}
|
13
|
+
spec.homepage = "https://github.com/orhantoy/ucfg"
|
14
|
+
|
15
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
16
|
+
spec.metadata["source_code_uri"] = "https://github.com/orhantoy/ucfg"
|
17
|
+
spec.metadata["changelog_uri"] = "https://github.com/orhantoy/ucfg"
|
18
|
+
|
19
|
+
# Specify which files should be added to the gem when it is released.
|
20
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
21
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
22
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
23
|
+
end
|
24
|
+
spec.bindir = "exe"
|
25
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
26
|
+
spec.require_paths = ["lib"]
|
27
|
+
|
28
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
29
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
30
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ucfg
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Orhan Toy
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-08-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
description: This library is the Ruby variant of https://github.com/elastic/go-ucfg
|
56
|
+
email:
|
57
|
+
- toyorhan@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- ".rspec"
|
64
|
+
- ".travis.yml"
|
65
|
+
- Gemfile
|
66
|
+
- Gemfile.lock
|
67
|
+
- Rakefile
|
68
|
+
- bin/console
|
69
|
+
- bin/setup
|
70
|
+
- lib/ucfg.rb
|
71
|
+
- lib/ucfg/variable_substitution.rb
|
72
|
+
- lib/ucfg/version.rb
|
73
|
+
- ucfg.gemspec
|
74
|
+
homepage: https://github.com/orhantoy/ucfg
|
75
|
+
licenses: []
|
76
|
+
metadata:
|
77
|
+
homepage_uri: https://github.com/orhantoy/ucfg
|
78
|
+
source_code_uri: https://github.com/orhantoy/ucfg
|
79
|
+
changelog_uri: https://github.com/orhantoy/ucfg
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options: []
|
82
|
+
require_paths:
|
83
|
+
- lib
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
requirements: []
|
95
|
+
rubygems_version: 3.0.4
|
96
|
+
signing_key:
|
97
|
+
specification_version: 4
|
98
|
+
summary: Ruby universal configuration
|
99
|
+
test_files: []
|