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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a1f210944b382bc0260157f164e45025db904802
4
- data.tar.gz: 9d0d655fbb1a219b3bb22ce320b2fd0480dde335
3
+ metadata.gz: 6a2b88cc897a3961acfe0506efeae2215de462b8
4
+ data.tar.gz: 0478ac34202073124995fd797b082bbcfa609551
5
5
  SHA512:
6
- metadata.gz: 2bd33c114f0cbcb09f70f8aacf9b9ffff28757a20a5d8039e0888d0f8575887d9d2c282c34d703fa39d77aa786c9d01b5a76d623004ce55cf2588231f0364f94
7
- data.tar.gz: 7526b42e798652f771d0c094ee574ecab591811bfadd26b5446d333fcd5e62f7e22107cb50c672270ba754a590954d65fe20a9340703cb3f6ebb380359064c76
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 concrete config classes without
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
- ## Example
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
- The abstract configuration factory declares a `key`, which is used to look up the concrete
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
- In the example below, the `SourceConfig` abstract factory declares the key `:protocol`; the
19
- concrete classes `OAISourceConfig` and `ResyncSourceConfig` register themselves with
20
- `protocol: 'OAI'` and `protocol: 'Resync'`, respectively. `SourceConfig.for_environment()`
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
- class OAISourceConfig < SourceConfig
31
- protocol 'OAI'
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
- ### Single-environment example
46
-
47
- Configuration file:
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
- environment = Environment.load_file('spec/data/single-environment.yml')
62
- # => #<Config::Factory::Environment:0x007fe8d3883240 @name=:production, @configs={"source"=>{"protocol"=>"OAI", "oai_base_url"=>"http://oai.example.org/oai", "metadata_prefix"=>"some_prefix", "set"=>"some_set", "seconds_granularity"=>true}}>
63
- source_config = SourceConfig.for_environment(environment, :source)
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
- ### Multiple-environment example
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
- Configuration file:
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
- test:
73
- source:
74
- protocol: Resync
75
- capability_list_url: http://localhost:8888/capabilitylist.xml
116
+ persistence:
117
+ adapter: sqlite3
118
+ database: db/development.sqlite3
119
+ pool: 5
120
+ timeout: 5000
121
+ ```
76
122
 
77
- production:
78
- source:
79
- protocol: OAI
80
- oai_base_url: http://oai.example.org/oai
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
- Loading:
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
- environments = Environments.load_file('spec/data/multiple_environments.yml')
90
- # => {:test=>#<Config::Factory::Environment:0x007fe8d3863dc8 @name=:test, @configs={"source"=>{"protocol"=>"Resync", "capability_list_url"=>"http://localhost:8888/capabilitylist.xml"}}>, :production=>#<Config::Factory::Environment:0x007fe8d3863be8 @name=:production, @configs={"source"=>{"protocol"=>"OAI", "oai_base_url"=>"http://oai.example.org/oai", "metadata_prefix"=>"some_prefix", "set"=>"some_set", "seconds_granularity"=>true}}>}
91
- test_env = environments[:test]
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
- ## Config classes with only one implementation
142
+ ### Instantiating implementations directly
98
143
 
99
- `config-factory` also supports instantiating concrete configuration classes directly.
100
- In this case, we simply don't declare a `key` for the class, and the configuration hash
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 DBConfig
148
+ class SolrConfig
105
149
  include Config::Factory
106
150
 
107
- def initialize(connection_info)
108
- @connection_info = connection_info
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
- db:
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
- db:
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 :product_key
8
+ attr_reader :impl_key
9
9
 
10
10
  def key(k)
11
- @product_key = k
12
- registry = products
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
- product_class = find_product_class(args)
33
- product_class.new(args)
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 find_product_class(args)
39
- return self unless product_key
40
- fail ArgumentError, "product key #{product_key} not found in argument hash #{args}" unless args.key?(product_key)
41
- key_value = args.delete(product_key)
42
- product_class = products[key_value]
43
- fail ArgumentError, "No #{name} product class found for #{product_key}: #{key_value}" unless product_class
44
- product_class
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 products
55
- @products ||= {}
71
+ def impls_by_key
72
+ @impls_by_key ||= {}
56
73
  end
74
+
57
75
  end
58
76
  end
59
77
  end
@@ -4,7 +4,7 @@ module Config
4
4
  NAME = 'config-factory'
5
5
 
6
6
  # The version of this gem
7
- VERSION = '0.0.7'
7
+ VERSION = '0.0.8'
8
8
 
9
9
  # The copyright notice for this gem
10
10
  COPYRIGHT = 'Copyright (c) 2016 The Regents of the University of California'
@@ -18,7 +18,7 @@ development:
18
18
  adapter: mysql2
19
19
  encoding: utf8
20
20
  pool: 5
21
- database: example_pord
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: example_pord
50
+ database: example_prod
51
51
  host: mysql.example.org
52
52
  port: 3306
@@ -0,0 +1,5 @@
1
+ persistence:
2
+ adapter: sqlite3
3
+ database: db/production.sqlite3
4
+ pool: 5
5
+ timeout: 5000
@@ -1,8 +1,8 @@
1
- db:
1
+ persistence:
2
2
  adapter: mysql2
3
3
  encoding: utf8
4
4
  pool: 5
5
- database: example_pord
5
+ database: example_prod
6
6
  host: mysql-dev.example.org
7
7
  port: 3306
8
8
  source:
@@ -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
- product = SourceConfig.build_from(config_hash)
11
- expect(product).to be_an(OAISourceConfig)
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(product.send(k)).to eq(v)
14
+ expect(impl.send(k)).to eq(v)
15
15
  end
16
16
  end
17
17
 
18
- it 'raises a sensible exception if no product found for the key' do
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 concrete factories without product keys' do
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: 'example_pord',
28
+ database: 'example_prod',
29
29
  host: 'mysql-dev.example.org',
30
30
  port: 3306
31
31
  }
32
- product = DBConfig.build_from(config_hash)
33
- expect(product).to be_a(DBConfig)
34
- expect(product.connection_info).to eq(config_hash)
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
- product = SourceConfig.for_environment(env, :source)
45
- expect(product).to be_an(OAISourceConfig)
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(product.send(k)).to eq(v)
76
+ expect(impl.send(k)).to eq(v)
49
77
  end
50
78
  end
51
79
 
52
- it 'raises a sensible exception if no product found for the key' do
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
- product = SourceConfig.from_file('spec/data/single-environment.yml', :source)
63
- expect(product).to be_an(OAISourceConfig)
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(product.send(k)).to eq(v)
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' => 'example_pord',
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(url: capability_list_url)
39
+ super(source_url: capability_list_url)
40
40
  @capability_list_url = source_uri
41
41
  end
42
42
  end
43
43
 
44
- class DBConfig
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 'Solr'
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.7
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-03-31 00:00:00.000000000 Z
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