config-factory 0.0.7 → 0.0.8
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 +4 -4
- data/CHANGES.md +6 -1
- data/README.md +233 -58
- data/lib/config/factory/abstract_factory.rb +33 -15
- data/lib/config/factory/module_info.rb +1 -1
- data/spec/data/multiple-environments.yml +2 -2
- data/spec/data/raw-section.yml +5 -0
- data/spec/data/single-environment.yml +2 -2
- data/spec/unit/config/factory/abstract_factory_spec.rb +44 -16
- data/spec/unit/config/factory/environment_spec.rb +4 -1
- data/spec/unit/config/factory/environments_spec.rb +48 -0
- data/spec/unit/config/factory/fixtures.rb +33 -3
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a2b88cc897a3961acfe0506efeae2215de462b8
|
4
|
+
data.tar.gz: 0478ac34202073124995fd797b082bbcfa609551
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac4f9910a57c0cdb78c9052f773cbef06ca811f881af87418103a2861ad5c9c17db8687f9cba42cdc465cb3092e713443ee039cae30705860e0f487692660d94
|
7
|
+
data.tar.gz: 971e76011a0ff96b3607392261bb88f48e708e0745406c7a28067932e8553bbd354690b396177e46a3040be0aa35837c20c96867d4322491f07305d59676a666
|
data/CHANGES.md
CHANGED
@@ -1,6 +1,11 @@
|
|
1
|
+
## 0.0.8 (4 April 2016)
|
2
|
+
|
3
|
+
- Support looking up implementation classes based on an argument
|
4
|
+
filter
|
5
|
+
|
1
6
|
## 0.0.7 (31 March 2016)
|
2
7
|
|
3
|
-
- Support direct instantiation of
|
8
|
+
- Support direct instantiation of implementation classes without
|
4
9
|
product keys
|
5
10
|
|
6
11
|
## 0.0.6 (16 March 2016)
|
data/README.md
CHANGED
@@ -9,122 +9,297 @@ A gem for creating configuration classes using the
|
|
9
9
|
[Abstract Factory](https://web.archive.org/web/20111109224959/http://www.informit.com/articles/article.aspx?p=1398599),
|
10
10
|
pattern, with run-time configuration provided by hashes or YAML files.
|
11
11
|
|
12
|
-
|
12
|
+
- [Factory lookup patterns](#factory-lookup-patterns)
|
13
|
+
- [Looking up concrete factory classes based on a key value](#looking-up-concrete-factory-classes-based-on-a-key-value)
|
14
|
+
- [Finding concrete factory classes based on an argument filter](#finding-concrete-factory-classes-based-on-an-argument-filter)
|
15
|
+
- [Instantiating implementations directly](#instantiating-implementations-directly)
|
16
|
+
- [Environments](#environments)
|
17
|
+
- [Multiple environments](#multiple-environments)
|
18
|
+
- [Single environment](#single-environment)
|
13
19
|
|
14
|
-
|
15
|
-
config class for a given configuration. Concrete implementations register themselves with a
|
16
|
-
DSL method named after the `key` value.
|
20
|
+
## Factory lookup patterns
|
17
21
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
will then look for a `protocol:` line in the configuration file to determine which
|
22
|
-
registered concrete class to instantiate.
|
22
|
+
### Looking up concrete factory classes based on a key value
|
23
|
+
|
24
|
+
In the basic use case, an abstract factory class defines a configuration key:
|
23
25
|
|
24
26
|
```ruby
|
25
27
|
class SourceConfig
|
26
28
|
include Config::Factory
|
27
|
-
key :protocol
|
29
|
+
key :protocol # <- configuration key
|
28
30
|
end
|
31
|
+
```
|
29
32
|
|
30
|
-
|
31
|
-
|
33
|
+
This creates a corresponding DSL method (here `:protocol`), which implementation
|
34
|
+
classes use to register themselves.
|
32
35
|
|
36
|
+
```ruby
|
37
|
+
class OAISourceConfig < SourceConfig
|
38
|
+
protocol 'OAI' # <- registers OAISourceConfig as implementation
|
39
|
+
# for the "OAI" protocol
|
33
40
|
def initialize(oai_base_url:, metadata_prefix:, set: nil, seconds_granularity: false)
|
41
|
+
# ...
|
34
42
|
end
|
35
43
|
end
|
36
44
|
|
37
45
|
class ResyncSourceConfig < SourceConfig
|
38
|
-
protocol 'Resync'
|
39
|
-
|
46
|
+
protocol 'Resync' # <- registers ResyncSourceConfig as implementation
|
47
|
+
# for the "Resync" protocol
|
40
48
|
def initialize(capability_list_url:)
|
49
|
+
# ...
|
41
50
|
end
|
42
51
|
end
|
43
52
|
```
|
44
53
|
|
45
|
-
|
46
|
-
|
47
|
-
|
54
|
+
At run time, `SourceConfig` finds the `protocol:` key in the configuration, and
|
55
|
+
based on the value `'OAI'`, instantiates an `OAISourceConfig`, passing the remaining
|
56
|
+
arguments to the `OAISourceConfig` initializer.
|
48
57
|
|
49
58
|
```YAML
|
50
59
|
source:
|
51
|
-
protocol: OAI
|
60
|
+
protocol: OAI # <- indicates we want an OAISourceConfig
|
61
|
+
|
62
|
+
# these arguments will be passed to the OAISourceConfig initializer
|
52
63
|
oai_base_url: http://oai.example.org/oai
|
53
64
|
metadata_prefix: some_prefix
|
54
65
|
set: some_set
|
55
66
|
seconds_granularity: true
|
56
67
|
```
|
57
68
|
|
58
|
-
Loading:
|
59
|
-
|
60
69
|
```ruby
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
# => #<OAISourceConfig:0x007fe8d38b3990 @oai_base_url="http://oai.example.org/oai", @metadata_prefix="some_prefix", @set="some_set", @seconds_granularity=true>
|
70
|
+
config = YAML.load_file('config.yml')
|
71
|
+
SourceConfig.build_from(config, :source)
|
72
|
+
# => #<OAISourceConfig:0x007fc8f14a58f0>
|
65
73
|
```
|
66
74
|
|
67
|
-
###
|
75
|
+
### Finding concrete factory classes based on an argument filter
|
76
|
+
|
77
|
+
In some cases (e.g., compatibility with existing configuration files), it may
|
78
|
+
be necessary to have the implementation class examine the entire configuration
|
79
|
+
hash to determine whether it can support a given configuration.
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
class PersistenceConfig
|
83
|
+
include Config::Factory
|
84
|
+
# note no configuration key given
|
85
|
+
end
|
86
|
+
|
87
|
+
class DBPersistenceConfig < PersistenceConfig
|
88
|
+
attr_reader :connection_info
|
68
89
|
|
69
|
-
|
90
|
+
# Applies if we find 'adapter:' in the config file
|
91
|
+
can_build_if { |config| config.key?(:adapter) }
|
92
|
+
|
93
|
+
def initialize(connection_info)
|
94
|
+
@connection_info = connection_info
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class XMLPersistenceConfig < PersistenceConfig
|
99
|
+
attr_reader :connection_info
|
100
|
+
|
101
|
+
# Applies if we find 'path:' in the config file
|
102
|
+
# and its value ends in '.xml'
|
103
|
+
can_build_if do |config|
|
104
|
+
config[:path] && config[:path].end_with?('.xml')
|
105
|
+
end
|
106
|
+
|
107
|
+
def initialize(connection_info)
|
108
|
+
@connection_info = connection_info
|
109
|
+
end
|
110
|
+
end
|
111
|
+
```
|
112
|
+
|
113
|
+
This configuration will build a `DBPersistenceConfig`:
|
70
114
|
|
71
115
|
```YAML
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
116
|
+
persistence:
|
117
|
+
adapter: sqlite3
|
118
|
+
database: db/development.sqlite3
|
119
|
+
pool: 5
|
120
|
+
timeout: 5000
|
121
|
+
```
|
76
122
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
metadata_prefix: some_prefix
|
82
|
-
set: some_set
|
83
|
-
seconds_granularity: true
|
123
|
+
```ruby
|
124
|
+
config = YAML.load_file('config.yml')
|
125
|
+
PersistenceConfig.build_from(config, :persistence)
|
126
|
+
# => #<DBPersistenceConfig:0x007fc8f14c4d18>
|
84
127
|
```
|
85
128
|
|
86
|
-
|
129
|
+
Whereas this configuration will build an `XMLConfig`:
|
130
|
+
|
131
|
+
```YAML
|
132
|
+
persistence:
|
133
|
+
path: config/persistence.xml
|
134
|
+
```
|
87
135
|
|
88
136
|
```ruby
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
# => #<Config::Factory::Environment:0x007fe8d383a400 @name=:test, @configs={"source"=>{"protocol"=>"Resync", "capability_list_url"=>"http://localhost:8888/capabilitylist.xml"}}>
|
93
|
-
source_config = SourceConfig.for_environment(test_env, :source)
|
94
|
-
# => #<ResyncSourceConfig:0x007fe8d48180c0 @capability_list_url="http://localhost:8888/capabilitylist.xml">
|
137
|
+
config = YAML.load_file('config.yml')
|
138
|
+
PersistenceConfig.build_from(config, :persistence)
|
139
|
+
# => #<XMLPersistenceConfig:0x007fc8f14ed420>
|
95
140
|
```
|
96
141
|
|
97
|
-
|
142
|
+
### Instantiating implementations directly
|
98
143
|
|
99
|
-
|
100
|
-
|
101
|
-
will be passed directly to the initializer of the concrete class.
|
144
|
+
Finally, you may have a mix of abstract and concrete factories, so that some factories
|
145
|
+
don't need any lookup and can just be instantiated directly.
|
102
146
|
|
103
147
|
```ruby
|
104
|
-
class
|
148
|
+
class SolrConfig
|
105
149
|
include Config::Factory
|
106
150
|
|
107
|
-
def initialize(
|
108
|
-
|
151
|
+
def initialize(url:, proxy: nil, open_timeout: 60, read_timeout: 120)
|
152
|
+
# ...
|
109
153
|
end
|
110
154
|
end
|
111
155
|
```
|
112
156
|
|
113
157
|
```YAML
|
158
|
+
solr:
|
159
|
+
url: http://solr.example.org/
|
160
|
+
proxy: http://foo:bar@proxy.example.com/
|
161
|
+
open_timeout: 120
|
162
|
+
read_timeout: 300
|
163
|
+
```
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
config = YAML.load_file('config.yml')
|
167
|
+
SolrConfig.build_from(config, :solr)
|
168
|
+
# => #<SolrConfig:0x007fc8f1504f08>
|
169
|
+
```
|
170
|
+
|
171
|
+
## Environments
|
172
|
+
|
173
|
+
The YAML examples above each show only the configuration for a single factory. However,
|
174
|
+
`Config::Factory` also supports a structured configuration file with configurations for
|
175
|
+
multiple factories, optionally organized into environments.
|
176
|
+
|
177
|
+
### Multiple environments
|
178
|
+
|
179
|
+
The `Environments.load_file()` method loads a multi-environment config file as a hash
|
180
|
+
of `Environment` instances.
|
181
|
+
|
182
|
+
```ruby
|
183
|
+
envs = Environments.load_file('config.yml')
|
184
|
+
# => {:defaults=>#<Environment:0x007f8e9a578818>,
|
185
|
+
# :development=>#<Environment:0x007f8e9a578728>,
|
186
|
+
# :test=>#<Environment:0x007f8e9a578660>,
|
187
|
+
# :production=>#<Environment:0x007f8e9a578520>}
|
188
|
+
test = envs[:test]
|
189
|
+
# => #<Environment:0x007f8e9a578660>
|
190
|
+
```
|
191
|
+
|
192
|
+
The `AbstractFactory.for_environment()` method takes an environment instance and a
|
193
|
+
configuration section name.
|
194
|
+
|
195
|
+
```ruby
|
196
|
+
source = SourceConfig.for_environment(test, :source)
|
197
|
+
# => #<ResyncSourceConfig:0x007f8e9a54a878>
|
198
|
+
index = IndexConfig.for_environment(test, :index)
|
199
|
+
# => #<SolrConfig:0x007f8e9a5383a8>
|
200
|
+
persistence = PersistenceConfig.for_environment(test, :persistence)
|
201
|
+
# => #<DBConfig:0x007f8e9a5019e8>
|
202
|
+
```
|
203
|
+
|
204
|
+
The configuration file for the examples above. Note that standard YAML features such
|
205
|
+
as references are supported.
|
206
|
+
|
207
|
+
```YAML
|
208
|
+
defaults: &defaults
|
209
|
+
source:
|
210
|
+
protocol: OAI
|
211
|
+
oai_base_url: http://oai.example.org/oai
|
212
|
+
metadata_prefix: some_prefix
|
213
|
+
set: some_set
|
214
|
+
seconds_granularity: true
|
215
|
+
index:
|
216
|
+
adapter: solr
|
217
|
+
url: http://solr.example.org/
|
218
|
+
proxy: http://foo:bar@proxy.example.com/
|
219
|
+
open_timeout: 120
|
220
|
+
read_timeout: 300
|
221
|
+
|
222
|
+
development:
|
223
|
+
<<: *defaults
|
224
|
+
persistence:
|
225
|
+
adapter: mysql2
|
226
|
+
encoding: utf8
|
227
|
+
pool: 5
|
228
|
+
database: example_dev
|
229
|
+
host: mysql-dev.example.org
|
230
|
+
port: 3306
|
231
|
+
index:
|
232
|
+
adapter: solr
|
233
|
+
url: http://solr-dev.example.org/
|
234
|
+
proxy: http://foo:bar@proxy.example.com/
|
235
|
+
open_timeout: 120
|
236
|
+
read_timeout: 300
|
237
|
+
|
114
238
|
test:
|
115
|
-
|
239
|
+
persistence:
|
116
240
|
adapter: sqlite3
|
117
241
|
database: ':memory:'
|
118
242
|
pool: 5
|
119
243
|
timeout: 5000
|
244
|
+
source:
|
245
|
+
protocol: Resync
|
246
|
+
capability_list_url: http://localhost:8888/capabilitylist.xml
|
247
|
+
index:
|
248
|
+
adapter: solr
|
249
|
+
url: http://localhost:8000/solr/
|
120
250
|
|
121
251
|
production:
|
122
|
-
|
252
|
+
<<: *defaults
|
253
|
+
persistence:
|
123
254
|
adapter: mysql2
|
124
|
-
host: mydb.example.org
|
125
|
-
database: myapp
|
126
|
-
username: myuser
|
127
|
-
password: blank
|
128
|
-
port: 3306
|
129
255
|
encoding: utf8
|
256
|
+
pool: 5
|
257
|
+
database: example_prod
|
258
|
+
host: mysql.example.org
|
259
|
+
port: 3306
|
130
260
|
```
|
261
|
+
|
262
|
+
The `Environments` module supports arbitrary environment names, but the standard ones
|
263
|
+
are `:defaults`, `:development`, `:test`, `:stage`, `:staging,` and `:production`. The
|
264
|
+
`Environments.load_file` method will warn if none of these are present, as this might
|
265
|
+
indicate loading a single-environment config file as multiple by mistake.
|
266
|
+
|
267
|
+
### Single environment
|
268
|
+
|
269
|
+
For a single-environment config file, use the `load_file()` method on the `Environment`
|
270
|
+
class itself (not the `Environments` module, plural):
|
271
|
+
|
272
|
+
```ruby
|
273
|
+
env = Environment.load_file('config.yml')
|
274
|
+
# => #<Environment:0x007f8e9a49b1c0>
|
275
|
+
persistence = PersistenceConfig.for_environment(env, :persistence)
|
276
|
+
# => #<DBConfig:0x007f8e9a45abe8>
|
277
|
+
source = SourceConfig.for_environment(env, :source)
|
278
|
+
# => #<OAISourceConfig:0x007f8e9a482fa8>
|
279
|
+
index = IndexConfig.for_environment(env, :index)
|
280
|
+
# => #<SolrConfig:0x007f8e9a4438a8>
|
281
|
+
```
|
282
|
+
|
283
|
+
```YAML
|
284
|
+
persistence:
|
285
|
+
adapter: mysql2
|
286
|
+
encoding: utf8
|
287
|
+
pool: 5
|
288
|
+
database: example_prod
|
289
|
+
host: mysql-dev.example.org
|
290
|
+
port: 3306
|
291
|
+
source:
|
292
|
+
protocol: OAI
|
293
|
+
oai_base_url: http://oai.example.org/oai
|
294
|
+
metadata_prefix: some_prefix
|
295
|
+
set: some_set
|
296
|
+
seconds_granularity: true
|
297
|
+
index:
|
298
|
+
adapter: solr
|
299
|
+
url: http://solr.example.org/
|
300
|
+
proxy: http://foo:bar@proxy.example.com/
|
301
|
+
open_timeout: 120
|
302
|
+
read_timeout: 300
|
303
|
+
```
|
304
|
+
|
305
|
+
By default, a single environment uses the environment name `:production`.
|
@@ -5,16 +5,24 @@ module Config
|
|
5
5
|
end
|
6
6
|
|
7
7
|
module AbstractFactory
|
8
|
-
attr_reader :
|
8
|
+
attr_reader :impl_key
|
9
9
|
|
10
10
|
def key(k)
|
11
|
-
@
|
12
|
-
registry =
|
11
|
+
@impl_key = k
|
12
|
+
registry = impls_by_key
|
13
13
|
define_singleton_method(k) do |v|
|
14
14
|
registry[v] = self
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
+
def self.extended(mod)
|
19
|
+
filter_registry = {}
|
20
|
+
mod.define_singleton_method(:can_build_if) do |&block|
|
21
|
+
filter_registry[self] = block
|
22
|
+
end
|
23
|
+
mod.define_singleton_method(:filters_by_impl_class) { filter_registry }
|
24
|
+
end
|
25
|
+
|
18
26
|
def for_environment(env, config_name)
|
19
27
|
arg_hash = env.args_for(config_name)
|
20
28
|
fail ArgumentError, "no #{self} arguments found for config #{config_name} in environment #{env}" unless arg_hash
|
@@ -26,22 +34,31 @@ module Config
|
|
26
34
|
for_environment(env, config_name)
|
27
35
|
end
|
28
36
|
|
29
|
-
def build_from(arg_hash)
|
37
|
+
def build_from(arg_hash, section_name = nil)
|
30
38
|
fail ArgumentError, "nil argument hash passed to #{self}.build_from" unless arg_hash
|
31
39
|
args = deep_symbolize_keys(arg_hash)
|
32
|
-
|
33
|
-
|
40
|
+
args = args[section_name] if section_name
|
41
|
+
impl_class = find_impl_class(args)
|
42
|
+
impl_class.new(args)
|
34
43
|
end
|
35
44
|
|
36
45
|
private
|
37
46
|
|
38
|
-
def
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
47
|
+
def find_impl_class(args)
|
48
|
+
pk = impl_key
|
49
|
+
return impl_for_key(pk, args) if pk
|
50
|
+
filters_by_impl_class.each_pair do |impl_class, filter|
|
51
|
+
return impl_class if filter.call(args)
|
52
|
+
end
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
def impl_for_key(key_sym, args)
|
57
|
+
fail ArgumentError, "implementation key #{key_sym} not found in argument hash #{args}" unless args.key?(key_sym)
|
58
|
+
key_value = args.delete(key_sym)
|
59
|
+
impl_class = impls_by_key[key_value]
|
60
|
+
fail ArgumentError, "No #{name} implementation found for #{key_sym}: #{key_value}" unless impl_class
|
61
|
+
impl_class
|
45
62
|
end
|
46
63
|
|
47
64
|
def deep_symbolize_keys(val)
|
@@ -51,9 +68,10 @@ module Config
|
|
51
68
|
end.to_h
|
52
69
|
end
|
53
70
|
|
54
|
-
def
|
55
|
-
@
|
71
|
+
def impls_by_key
|
72
|
+
@impls_by_key ||= {}
|
56
73
|
end
|
74
|
+
|
57
75
|
end
|
58
76
|
end
|
59
77
|
end
|
@@ -18,7 +18,7 @@ development:
|
|
18
18
|
adapter: mysql2
|
19
19
|
encoding: utf8
|
20
20
|
pool: 5
|
21
|
-
database:
|
21
|
+
database: example_dev
|
22
22
|
host: mysql-dev.example.org
|
23
23
|
port: 3306
|
24
24
|
index:
|
@@ -47,6 +47,6 @@ production:
|
|
47
47
|
adapter: mysql2
|
48
48
|
encoding: utf8
|
49
49
|
pool: 5
|
50
|
-
database:
|
50
|
+
database: example_prod
|
51
51
|
host: mysql.example.org
|
52
52
|
port: 3306
|
@@ -7,31 +7,59 @@ module Config
|
|
7
7
|
describe '#build_from' do
|
8
8
|
it 'builds the correct class with the correct config' do
|
9
9
|
config_hash = { protocol: 'OAI', oai_base_url: 'http://oai.example.org/oai', metadata_prefix: 'some_prefix', set: 'some_set', seconds_granularity: true }
|
10
|
-
|
11
|
-
expect(
|
10
|
+
impl = SourceConfig.build_from(config_hash)
|
11
|
+
expect(impl).to be_an(OAISourceConfig)
|
12
12
|
args = { oai_base_url: URI('http://oai.example.org/oai'), metadata_prefix: 'some_prefix', set: 'some_set', seconds_granularity: true }
|
13
13
|
args.each do |k, v|
|
14
|
-
expect(
|
14
|
+
expect(impl.send(k)).to eq(v)
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
it 'raises a sensible exception if no
|
18
|
+
it 'raises a sensible exception if no impl found for the key' do
|
19
19
|
config_hash = { protocol: 'Elvis' }
|
20
20
|
expect { SourceConfig.build_from(config_hash) }.to raise_error(ArgumentError, /SourceConfig.*protocol.*Elvis/)
|
21
21
|
end
|
22
22
|
|
23
|
-
it 'supports
|
23
|
+
it 'supports implementation factories without impl keys' do
|
24
24
|
config_hash = {
|
25
25
|
adapter: 'mysql2',
|
26
26
|
encoding: 'utf8',
|
27
27
|
pool: 5,
|
28
|
-
database: '
|
28
|
+
database: 'example_prod',
|
29
29
|
host: 'mysql-dev.example.org',
|
30
30
|
port: 3306
|
31
31
|
}
|
32
|
-
|
33
|
-
expect(
|
34
|
-
expect(
|
32
|
+
impl = MysqlConfig.build_from(config_hash)
|
33
|
+
expect(impl).to be_a(MysqlConfig)
|
34
|
+
expect(impl.connection_info).to eq(config_hash)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "can build a class without a declared key, so long as it's registered" do
|
38
|
+
config_hash = {
|
39
|
+
adapter: 'mysql2',
|
40
|
+
encoding: 'utf8',
|
41
|
+
pool: 5,
|
42
|
+
database: 'example_prod',
|
43
|
+
host: 'mysql-dev.example.org',
|
44
|
+
port: 3306
|
45
|
+
}
|
46
|
+
impl = PersistenceConfig.build_from(config_hash)
|
47
|
+
expect(impl).to be_a(DBConfig)
|
48
|
+
expect(impl.connection_info).to eq(config_hash)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'works with section headers' do
|
52
|
+
expected_info = {
|
53
|
+
adapter: 'sqlite3',
|
54
|
+
database: 'db/production.sqlite3',
|
55
|
+
pool: 5,
|
56
|
+
timeout: 5000
|
57
|
+
}
|
58
|
+
|
59
|
+
hash = YAML.load_file('spec/data/raw-section.yml')
|
60
|
+
impl = PersistenceConfig.build_from(hash, :persistence)
|
61
|
+
expect(impl).to be_a(DBConfig)
|
62
|
+
expect(impl.connection_info).to eq(expected_info)
|
35
63
|
end
|
36
64
|
end
|
37
65
|
|
@@ -41,15 +69,15 @@ module Config
|
|
41
69
|
env = instance_double(Environment)
|
42
70
|
expect(env).to receive(:args_for).with(:source) { config_hash }
|
43
71
|
|
44
|
-
|
45
|
-
expect(
|
72
|
+
impl = SourceConfig.for_environment(env, :source)
|
73
|
+
expect(impl).to be_an(OAISourceConfig)
|
46
74
|
args = { oai_base_url: URI('http://oai.example.org/oai'), metadata_prefix: 'some_prefix', set: 'some_set', seconds_granularity: true }
|
47
75
|
args.each do |k, v|
|
48
|
-
expect(
|
76
|
+
expect(impl.send(k)).to eq(v)
|
49
77
|
end
|
50
78
|
end
|
51
79
|
|
52
|
-
it 'raises a sensible exception if no
|
80
|
+
it 'raises a sensible exception if no impl found for the key' do
|
53
81
|
config_hash = { protocol: 'Elvis' }
|
54
82
|
env = instance_double(Environment)
|
55
83
|
expect(env).to receive(:args_for).with(:source) { config_hash }
|
@@ -59,11 +87,11 @@ module Config
|
|
59
87
|
|
60
88
|
describe '#from_file' do
|
61
89
|
it 'builds the correct class with the correct config' do
|
62
|
-
|
63
|
-
expect(
|
90
|
+
impl = SourceConfig.from_file('spec/data/single-environment.yml', :source)
|
91
|
+
expect(impl).to be_an(OAISourceConfig)
|
64
92
|
args = { oai_base_url: URI('http://oai.example.org/oai'), metadata_prefix: 'some_prefix', set: 'some_set', seconds_granularity: true }
|
65
93
|
args.each do |k, v|
|
66
|
-
expect(
|
94
|
+
expect(impl.send(k)).to eq(v)
|
67
95
|
end
|
68
96
|
end
|
69
97
|
end
|
@@ -44,6 +44,9 @@ module Config
|
|
44
44
|
env = Environment.load_file('spec/data/single-environment.yml')
|
45
45
|
expect(env).to be_an(Environment)
|
46
46
|
expect(env.name).to eq(Environments::DEFAULT_ENVIRONMENT)
|
47
|
+
|
48
|
+
pers = PersistenceConfig.for_environment(env, :persistence)
|
49
|
+
expect(pers).to be_a(DBConfig)
|
47
50
|
end
|
48
51
|
|
49
52
|
it 'raises an error for malformed files' do
|
@@ -70,7 +73,7 @@ module Config
|
|
70
73
|
'adapter' => 'mysql2',
|
71
74
|
'encoding' => 'utf8',
|
72
75
|
'pool' => 5,
|
73
|
-
'database' => '
|
76
|
+
'database' => 'example_prod',
|
74
77
|
'host' => 'mysql-dev.example.org',
|
75
78
|
'port' => 3306
|
76
79
|
},
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require_relative 'fixtures'
|
2
3
|
|
3
4
|
module Config
|
4
5
|
module Factory
|
@@ -16,6 +17,53 @@ module Config
|
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
20
|
+
it 'supports YAML references' do
|
21
|
+
envs = Environments.load_file('spec/data/multiple-environments.yml')
|
22
|
+
|
23
|
+
defaults = envs[:defaults]
|
24
|
+
source_default = SourceConfig.for_environment(defaults, :source)
|
25
|
+
expect(source_default).to be_an(OAISourceConfig)
|
26
|
+
expect(source_default.source_uri).to eq(URI('http://oai.example.org/oai'))
|
27
|
+
index_default = IndexConfig.for_environment(defaults, :index)
|
28
|
+
expect(index_default).to be_a(SolrConfig)
|
29
|
+
expect(index_default.uri).to eq(URI('http://solr.example.org/'))
|
30
|
+
|
31
|
+
development = envs[:development]
|
32
|
+
source_dev = SourceConfig.for_environment(development, :source)
|
33
|
+
expect(source_dev).to be_an(OAISourceConfig)
|
34
|
+
expect(source_dev.source_uri).to eq(URI('http://oai.example.org/oai'))
|
35
|
+
persistence_dev = PersistenceConfig.for_environment(development, :db)
|
36
|
+
expect(persistence_dev).to be_a(DBConfig)
|
37
|
+
expect(persistence_dev.connection_info[:adapter]).to eq('mysql2')
|
38
|
+
expect(persistence_dev.connection_info[:database]).to eq('example_dev')
|
39
|
+
index_dev = IndexConfig.for_environment(development, :index)
|
40
|
+
expect(index_dev).to be_a(SolrConfig)
|
41
|
+
expect(index_dev.uri).to eq(URI('http://solr-dev.example.org/'))
|
42
|
+
|
43
|
+
test = envs[:test]
|
44
|
+
persistence_test = PersistenceConfig.for_environment(test, :db)
|
45
|
+
expect(persistence_test).to be_a(DBConfig)
|
46
|
+
expect(persistence_test.connection_info[:adapter]).to eq('sqlite3')
|
47
|
+
source_test = SourceConfig.for_environment(test, :source)
|
48
|
+
expect(source_test).to be_a(ResyncSourceConfig)
|
49
|
+
expect(source_test.source_uri).to eq(URI('http://localhost:8888/capabilitylist.xml'))
|
50
|
+
index_test = IndexConfig.for_environment(test, :index)
|
51
|
+
expect(index_test).to be_a(SolrConfig)
|
52
|
+
expect(index_test.uri).to eq(URI('http://localhost:8000/solr/'))
|
53
|
+
|
54
|
+
production = envs[:production]
|
55
|
+
source_production = SourceConfig.for_environment(production, :source)
|
56
|
+
expect(source_production).to be_an(OAISourceConfig)
|
57
|
+
expect(source_production.source_uri).to eq(URI('http://oai.example.org/oai'))
|
58
|
+
index_production = IndexConfig.for_environment(production, :index)
|
59
|
+
expect(index_production).to be_a(SolrConfig)
|
60
|
+
expect(index_production.uri).to eq(URI('http://solr.example.org/'))
|
61
|
+
persistence_production = PersistenceConfig.for_environment(production, :db)
|
62
|
+
expect(persistence_production).to be_a(DBConfig)
|
63
|
+
expect(persistence_production.connection_info[:adapter]).to eq('mysql2')
|
64
|
+
expect(persistence_production.connection_info[:database]).to eq('example_prod')
|
65
|
+
end
|
66
|
+
|
19
67
|
it 'reads a standard ActiveRecord DB config' do
|
20
68
|
envs = Environments.load_file('spec/data/db-config.yml')
|
21
69
|
expect(envs).to be_a(Hash)
|
@@ -36,12 +36,42 @@ class ResyncSourceConfig < SourceConfig
|
|
36
36
|
attr_reader :capability_list_url
|
37
37
|
|
38
38
|
def initialize(capability_list_url:)
|
39
|
-
super(
|
39
|
+
super(source_url: capability_list_url)
|
40
40
|
@capability_list_url = source_uri
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
|
44
|
+
# PersistenceConfig
|
45
|
+
|
46
|
+
class PersistenceConfig
|
47
|
+
include Config::Factory
|
48
|
+
end
|
49
|
+
|
50
|
+
class DBConfig < PersistenceConfig
|
51
|
+
attr_reader :connection_info
|
52
|
+
|
53
|
+
can_build_if { |config| config.key?(:adapter) }
|
54
|
+
|
55
|
+
def initialize(connection_info)
|
56
|
+
@connection_info = connection_info
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class XMLConfig < PersistenceConfig
|
61
|
+
attr_reader :connection_info
|
62
|
+
|
63
|
+
can_build_if do |config|
|
64
|
+
config[:path] && config[:path].end_with?('.xml')
|
65
|
+
end
|
66
|
+
|
67
|
+
def initialize(connection_info)
|
68
|
+
@connection_info = connection_info
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# MysqlConfig
|
73
|
+
|
74
|
+
class MysqlConfig
|
45
75
|
include Config::Factory
|
46
76
|
|
47
77
|
attr_reader :connection_info
|
@@ -66,7 +96,7 @@ class IndexConfig
|
|
66
96
|
end
|
67
97
|
|
68
98
|
class SolrConfig < IndexConfig
|
69
|
-
adapter '
|
99
|
+
adapter 'solr'
|
70
100
|
|
71
101
|
attr_reader :url
|
72
102
|
attr_reader :proxy
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: config-factory
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Moles
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-04-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -122,6 +122,7 @@ files:
|
|
122
122
|
- spec/.rubocop.yml
|
123
123
|
- spec/data/db-config.yml
|
124
124
|
- spec/data/multiple-environments.yml
|
125
|
+
- spec/data/raw-section.yml
|
125
126
|
- spec/data/single-environment.yml
|
126
127
|
- spec/spec_helper.rb
|
127
128
|
- spec/unit/config/factory/abstract_factory_spec.rb
|
@@ -157,6 +158,7 @@ test_files:
|
|
157
158
|
- spec/.rubocop.yml
|
158
159
|
- spec/data/db-config.yml
|
159
160
|
- spec/data/multiple-environments.yml
|
161
|
+
- spec/data/raw-section.yml
|
160
162
|
- spec/data/single-environment.yml
|
161
163
|
- spec/spec_helper.rb
|
162
164
|
- spec/unit/config/factory/abstract_factory_spec.rb
|