config-factory 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|