flight_config 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/flight_config/accessor.rb +89 -0
- data/lib/flight_config/core.rb +68 -32
- data/lib/flight_config/deleter.rb +1 -2
- data/lib/flight_config/globber.rb +6 -5
- data/lib/flight_config/links.rb +54 -0
- data/lib/flight_config/reader.rb +22 -13
- data/lib/flight_config/updater.rb +3 -4
- data/lib/flight_config/version.rb +1 -1
- data/lib/flight_config.rb +2 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f8c36bdbe520695cb9d379d6038699c3529fb1fb8938af728fa50452ec0414ae
|
4
|
+
data.tar.gz: 58bf550037f38ede9db72516a5a70afd1b2fa1a47f1be8e7a3d7b95144d9d768
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf01421b86b937cfd4df7180398a81578723391cd26ac0f54e8c98d7ad741cc1315ff23f257460cb6e7474c652285e67cc5ffabf739fb1d3fda6e826847d6d21
|
7
|
+
data.tar.gz: 17768019155bd3e1621f0d597c89010b1403fe11f280ccec08f9e27c5685bb0435b0dbfdbc888b59bfcc84772146ebb153c2f624330505979d7c3b61b1bdbdc0
|
@@ -0,0 +1,89 @@
|
|
1
|
+
#==============================================================================
|
2
|
+
# Copyright (C) 2019-present Alces Flight Ltd.
|
3
|
+
#
|
4
|
+
# This file is part of FlightConfig.
|
5
|
+
#
|
6
|
+
# This program and the accompanying materials are made available under
|
7
|
+
# the terms of the Eclipse Public License 2.0 which is available at
|
8
|
+
# <https://www.eclipse.org/legal/epl-2.0>, or alternative license
|
9
|
+
# terms made available by Alces Flight Ltd - please direct inquiries
|
10
|
+
# about licensing to licensing@alces-flight.com.
|
11
|
+
#
|
12
|
+
# FlightConfig is distributed in the hope that it will be useful, but
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
|
14
|
+
# IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS
|
15
|
+
# OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A
|
16
|
+
# PARTICULAR PURPOSE. See the Eclipse Public License 2.0 for more
|
17
|
+
# details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the Eclipse Public License 2.0
|
20
|
+
# along with FlightConfig. If not, see:
|
21
|
+
#
|
22
|
+
# https://opensource.org/licenses/EPL-2.0
|
23
|
+
#
|
24
|
+
# For more information on FlightConfig, please visit:
|
25
|
+
# https://github.com/openflighthpc/flight_config
|
26
|
+
#==============================================================================
|
27
|
+
|
28
|
+
# NOTE: This is compatibility layer between the accessor and TTY::Config.
|
29
|
+
# TTY::Config isn't a good match with FlightConfig as they both try and preform
|
30
|
+
# the file handling. Instead a Hashie type object should be used.
|
31
|
+
#
|
32
|
+
# To facilitate the transition, the accessors use the standard [] and []= methods
|
33
|
+
# as these will be defined on most hashie objects. TTY::Config does not implement
|
34
|
+
# them however. Hence the need for the compatibility layer
|
35
|
+
|
36
|
+
module FlightConfig
|
37
|
+
module TTYConfigAccessor
|
38
|
+
def [](key)
|
39
|
+
fetch(key)
|
40
|
+
end
|
41
|
+
|
42
|
+
def []=(key, value)
|
43
|
+
if value.nil?
|
44
|
+
delete(key)
|
45
|
+
else
|
46
|
+
set(key, value: value)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
TTY::Config.include(TTYConfigAccessor)
|
52
|
+
end
|
53
|
+
|
54
|
+
module FlightConfig
|
55
|
+
module Accessor
|
56
|
+
def self.included(base)
|
57
|
+
base.extend(ClassMethods)
|
58
|
+
end
|
59
|
+
|
60
|
+
module ClassMethods
|
61
|
+
def data_accessor(key)
|
62
|
+
data_reader(key)
|
63
|
+
data_writer(key)
|
64
|
+
end
|
65
|
+
|
66
|
+
def data_reader(key, &b)
|
67
|
+
self.define_method(key) do
|
68
|
+
raw = __data__[key]
|
69
|
+
b ? instance_exec(raw, &b) : raw
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def data_writer(key, &b)
|
74
|
+
self.define_method("#{key}=") do |raw|
|
75
|
+
__data__[key] = b ? instance_exec(raw, &b) : raw
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def define_input_methods_from_path_parameters
|
80
|
+
self.method(:path)
|
81
|
+
.parameters
|
82
|
+
.select { |type, _| type == :req }
|
83
|
+
.each_with_index do |(_, arg), idx|
|
84
|
+
define_method(arg) { __inputs__[idx] }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/lib/flight_config/core.rb
CHANGED
@@ -24,6 +24,7 @@
|
|
24
24
|
# For more information on FlightConfig, please visit:
|
25
25
|
# https://github.com/openflighthpc/flight_config
|
26
26
|
#==============================================================================
|
27
|
+
|
27
28
|
require 'flight_config/exceptions'
|
28
29
|
require 'flight_config/log'
|
29
30
|
require 'flight_config/patches/tty_config'
|
@@ -43,7 +44,8 @@ module FlightConfig
|
|
43
44
|
|
44
45
|
# Deprecated: The mode can be switched directly on the object
|
45
46
|
def self.read(obj)
|
46
|
-
obj.
|
47
|
+
obj.instance_variable_set(:@__read_mode__, true)
|
48
|
+
obj.instance_variable_set(:@__data__, nil)
|
47
49
|
obj.__data__
|
48
50
|
end
|
49
51
|
|
@@ -76,12 +78,32 @@ module FlightConfig
|
|
76
78
|
end
|
77
79
|
end
|
78
80
|
|
79
|
-
|
81
|
+
module ClassMethods
|
82
|
+
# NOTE: The _path method acts as adaptation layer to the two ways the path
|
83
|
+
# could be defined: on the class or instance. Moving forward, the path method
|
84
|
+
# should be defined on the class
|
85
|
+
# NOTE: DO NOT USE THIS METHOD PUBLICLY. Define a `path` method instead
|
86
|
+
def _path(*args)
|
87
|
+
if self.respond_to?(:path)
|
88
|
+
self.path(*args)
|
89
|
+
else
|
90
|
+
msg = <<~WARN.gsub("\n", ' ').chomp
|
91
|
+
FlightConfig Deprecation: #{self}.path is not defined. Falling back to
|
92
|
+
the instance method
|
93
|
+
WARN
|
94
|
+
Log.warn msg
|
95
|
+
$stderr.puts msg
|
96
|
+
self.new(*args).path
|
97
|
+
end
|
98
|
+
end
|
80
99
|
|
81
|
-
|
82
|
-
|
100
|
+
# *READ ME*: Hack Alart
|
101
|
+
# NOTE: Override this method in your class, and it should just work
|
102
|
+
# TODO: Eventually replace the _path method with this
|
103
|
+
# def path(*_args)
|
104
|
+
# raise NotImplementedError
|
105
|
+
# end
|
83
106
|
|
84
|
-
module ClassMethods
|
85
107
|
def allow_missing_read(fetch: false)
|
86
108
|
if fetch
|
87
109
|
@allow_missing_read ||= false
|
@@ -90,48 +112,62 @@ module FlightConfig
|
|
90
112
|
end
|
91
113
|
end
|
92
114
|
|
93
|
-
def
|
94
|
-
|
115
|
+
def data_core(klass = nil, &b)
|
116
|
+
@data_core ||= -> do
|
117
|
+
obj = (klass || TTY::Config).new
|
118
|
+
b ? b.call(obj) : obj
|
119
|
+
end
|
120
|
+
@data_core.call
|
95
121
|
end
|
96
122
|
end
|
97
123
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
Core.log(self, 'missing (skip read)')
|
107
|
-
else
|
108
|
-
raise MissingFile, "The file does not exist: #{path}"
|
109
|
-
end
|
124
|
+
attr_reader :__inputs__, :__read_mode__
|
125
|
+
|
126
|
+
def initialize(*input_args, registry: nil, read_mode: nil)
|
127
|
+
@__inputs__ = input_args
|
128
|
+
# TODO: Make this @path = self.class.path(*__inputs__)
|
129
|
+
self.path # Ensure the path can be established with the __inputs__
|
130
|
+
@__registry__ = registry
|
131
|
+
@__read_mode__ = read_mode
|
110
132
|
end
|
111
133
|
|
112
|
-
def
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
ERROR
|
118
|
-
else
|
119
|
-
@__data__mode = :read
|
120
|
-
end
|
134
|
+
def __registry__
|
135
|
+
@__registry__ ||= FlightConfig::Registry.new
|
136
|
+
end
|
137
|
+
|
138
|
+
def __data__initialize(_tty_config)
|
121
139
|
end
|
122
140
|
|
123
141
|
def __data__
|
124
|
-
@__data__ ||= self.class.
|
125
|
-
if
|
126
|
-
|
142
|
+
@__data__ ||= self.class.data_core.tap do |core|
|
143
|
+
if __read_mode__ && File.exists?(path)
|
144
|
+
Core.log(self, 'read')
|
145
|
+
str = File.read(path)
|
146
|
+
yaml_h = (str == Core::PLACEHOLDER ? nil : YAML.load(str))
|
147
|
+
core.merge(yaml_h) if yaml_h
|
148
|
+
elsif __read_mode__ && self.class.allow_missing_read(fetch: true)
|
149
|
+
Core.log(self, 'missing (skip read)')
|
150
|
+
elsif __read_mode__
|
151
|
+
raise MissingFile, "The file does not exist: #{path}"
|
127
152
|
else
|
128
153
|
__data__initialize(core)
|
129
154
|
end
|
130
155
|
end
|
131
156
|
end
|
132
157
|
|
158
|
+
# TODO: Eventually remove the error section as all the configs will have a
|
159
|
+
# class path method
|
160
|
+
# TODO: Set the path in initialize
|
133
161
|
def path
|
134
|
-
|
162
|
+
@path ||= begin
|
163
|
+
if self.class.respond_to?(:path)
|
164
|
+
self.class.path(*__inputs__)
|
165
|
+
else
|
166
|
+
raise FlightConfigError, <<~ERROR.chomp
|
167
|
+
#{self.class}.path has not been defined!
|
168
|
+
ERROR
|
169
|
+
end
|
170
|
+
end
|
135
171
|
end
|
136
172
|
end
|
137
173
|
end
|
@@ -42,11 +42,10 @@ module FlightConfig
|
|
42
42
|
|
43
43
|
module ClassMethods
|
44
44
|
def delete(*a)
|
45
|
-
new!(*a) do |config|
|
45
|
+
new!(*a, read_mode: true) do |config|
|
46
46
|
Deleter.delete_error_if_missing(config)
|
47
47
|
Core.log(config, 'delete')
|
48
48
|
Core.lock(config) do
|
49
|
-
config.__data__set_read_mode
|
50
49
|
config.__data__
|
51
50
|
if block_given? && !(yield config)
|
52
51
|
Core.log(config, 'delete (failed)')
|
@@ -29,11 +29,12 @@ require 'flight_config/reader'
|
|
29
29
|
module FlightConfig
|
30
30
|
module Globber
|
31
31
|
class Matcher
|
32
|
-
attr_reader :klass, :arity
|
32
|
+
attr_reader :klass, :arity, :registry
|
33
33
|
|
34
|
-
def initialize(klass, arity)
|
34
|
+
def initialize(klass, arity, registry)
|
35
35
|
@klass = klass
|
36
36
|
@arity = arity
|
37
|
+
@registry = (registry || FlightConfig::Registry.new)
|
37
38
|
end
|
38
39
|
|
39
40
|
def keys
|
@@ -50,7 +51,7 @@ module FlightConfig
|
|
50
51
|
def read(path)
|
51
52
|
data = regex.match(path)
|
52
53
|
init_args = keys.map { |key| data[key] }
|
53
|
-
klass.read(*init_args)
|
54
|
+
klass.read(*init_args, registry: registry)
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
@@ -59,8 +60,8 @@ module FlightConfig
|
|
59
60
|
end
|
60
61
|
|
61
62
|
module ClassMethods
|
62
|
-
def glob_read(*a)
|
63
|
-
matcher = Globber::Matcher.new(self, a.length)
|
63
|
+
def glob_read(*a, registry: nil)
|
64
|
+
matcher = Globber::Matcher.new(self, a.length, registry)
|
64
65
|
glob_regex = self.new(*a).path
|
65
66
|
Dir.glob(glob_regex)
|
66
67
|
.map { |path| matcher.read(path) }
|
@@ -0,0 +1,54 @@
|
|
1
|
+
#==============================================================================
|
2
|
+
# Copyright (C) 2019-present Alces Flight Ltd.
|
3
|
+
#
|
4
|
+
# This file is part of FlightConfig.
|
5
|
+
#
|
6
|
+
# This program and the accompanying materials are made available under
|
7
|
+
# the terms of the Eclipse Public License 2.0 which is available at
|
8
|
+
# <https://www.eclipse.org/legal/epl-2.0>, or alternative license
|
9
|
+
# terms made available by Alces Flight Ltd - please direct inquiries
|
10
|
+
# about licensing to licensing@alces-flight.com.
|
11
|
+
#
|
12
|
+
# FlightConfig is distributed in the hope that it will be useful, but
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
|
14
|
+
# IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS
|
15
|
+
# OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A
|
16
|
+
# PARTICULAR PURPOSE. See the Eclipse Public License 2.0 for more
|
17
|
+
# details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the Eclipse Public License 2.0
|
20
|
+
# along with FlightConfig. If not, see:
|
21
|
+
#
|
22
|
+
# https://opensource.org/licenses/EPL-2.0
|
23
|
+
#
|
24
|
+
# For more information on FlightConfig, please visit:
|
25
|
+
# https://github.com/openflighthpc/flight_config
|
26
|
+
#==============================================================================
|
27
|
+
|
28
|
+
module FlightConfig
|
29
|
+
module Links
|
30
|
+
def self.included(base)
|
31
|
+
base.extend(ClassMethods)
|
32
|
+
end
|
33
|
+
|
34
|
+
module ClassMethods
|
35
|
+
include Globber::ClassMethods
|
36
|
+
|
37
|
+
def define_link(key, klass, glob: false, &b)
|
38
|
+
links_class.define_method(key) do
|
39
|
+
args = config.instance_exec(&b)
|
40
|
+
method = (glob ? :glob_read : :read)
|
41
|
+
klass.public_send(method, *args, registry: config.__registry__)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def links_class
|
46
|
+
@links_class ||= Struct.new(:config)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def links
|
51
|
+
@links ||= self.class.links_class.new(self)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/flight_config/reader.rb
CHANGED
@@ -24,9 +24,26 @@
|
|
24
24
|
# For more information on FlightConfig, please visit:
|
25
25
|
# https://github.com/openflighthpc/flight_config
|
26
26
|
#==============================================================================
|
27
|
+
|
27
28
|
require 'flight_config/core'
|
28
29
|
|
29
30
|
module FlightConfig
|
31
|
+
class Registry
|
32
|
+
def read(klass, *args)
|
33
|
+
class_hash = (cache[klass] ||= {})
|
34
|
+
arity_hash = (class_hash[args.length] ||= {})
|
35
|
+
last_arg = args.pop
|
36
|
+
last_hash = args.reduce(arity_hash) { |hash, arg| hash[arg] ||= {} }
|
37
|
+
last_hash[last_arg] ||= klass.new(*args, last_arg, registry: self, read_mode: true)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def cache
|
43
|
+
@cache ||= {}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
30
47
|
module Reader
|
31
48
|
include Core
|
32
49
|
|
@@ -37,27 +54,19 @@ module FlightConfig
|
|
37
54
|
module ClassMethods
|
38
55
|
include Core::ClassMethods
|
39
56
|
|
40
|
-
def new!(*a)
|
41
|
-
new(*a).tap do |config|
|
57
|
+
def new!(*a, **h)
|
58
|
+
new(*a, **h).tap do |config|
|
42
59
|
yield config if block_given?
|
43
60
|
end
|
44
61
|
end
|
45
62
|
|
46
|
-
def read(*a)
|
47
|
-
new
|
48
|
-
config.__data__set_read_mode
|
49
|
-
config.__data__
|
50
|
-
end
|
63
|
+
def read(*a, registry: nil)
|
64
|
+
(registry || Registry.new).read(self, *a)
|
51
65
|
end
|
52
66
|
alias_method :load, :read
|
53
67
|
|
54
68
|
def read_or_new(*a)
|
55
|
-
|
56
|
-
if File.exists?(config.path)
|
57
|
-
config.__data__set_read_mode
|
58
|
-
config.__data__
|
59
|
-
end
|
60
|
-
end
|
69
|
+
File.exists?(_path(*a)) ? read(*a) : new(*a)
|
61
70
|
end
|
62
71
|
end
|
63
72
|
end
|
@@ -64,16 +64,15 @@ module FlightConfig
|
|
64
64
|
include Reader::ClassMethods
|
65
65
|
|
66
66
|
def update(*a, &b)
|
67
|
-
new!(*a) do |config|
|
67
|
+
new!(*a, read_mode: true) do |config|
|
68
68
|
Updater.update_error_if_missing(config)
|
69
|
-
config.__data__set_read_mode
|
70
69
|
Updater.create_or_update(config, action: 'update', &b)
|
71
70
|
end
|
72
71
|
end
|
73
72
|
|
74
73
|
def create_or_update(*a, &b)
|
75
|
-
|
76
|
-
|
74
|
+
mode = File.exists?(_path(*a))
|
75
|
+
new!(*a, read_mode: mode) do |config|
|
77
76
|
Updater.create_or_update(config, action: 'create_or_update', &b)
|
78
77
|
end
|
79
78
|
end
|
data/lib/flight_config.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flight_config
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alces Flight Ltd
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-06-
|
11
|
+
date: 2019-06-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tty-config
|
@@ -112,10 +112,12 @@ files:
|
|
112
112
|
- Rakefile
|
113
113
|
- flight_config.gemspec
|
114
114
|
- lib/flight_config.rb
|
115
|
+
- lib/flight_config/accessor.rb
|
115
116
|
- lib/flight_config/core.rb
|
116
117
|
- lib/flight_config/deleter.rb
|
117
118
|
- lib/flight_config/exceptions.rb
|
118
119
|
- lib/flight_config/globber.rb
|
120
|
+
- lib/flight_config/links.rb
|
119
121
|
- lib/flight_config/log.rb
|
120
122
|
- lib/flight_config/patches/tty_config.rb
|
121
123
|
- lib/flight_config/reader.rb
|