deimos-ruby 1.9.2 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 32eb1834570b6a1ea7d61274bf35be7365f16f1bb818c5c1148459bbc5a0b87a
4
- data.tar.gz: eb1ea3e922b947c631f05c0e1a41ce65a3c7a366b42e9b5884de499fff14817b
3
+ metadata.gz: a614febc556860a51e870e89beb90fde63201fffae3ba7ca78c53d423a65a7b6
4
+ data.tar.gz: e4676b33fbaf9c105ffd12b89a0090a86b8befd7cf0e09b39078a70e213f72dc
5
5
  SHA512:
6
- metadata.gz: f9d27f061f4ddcc3db165c08aaa09c02d80471cfa8b815cb2fc91909a6992615a49697870f517e70fae958d8bd8fa022b2369310f839c5bcba60a415c9a95750
7
- data.tar.gz: '0578c18592f11f646ae89b44a12c712ef86403b282ce9624c7e3127f5d54ba9f20faa634fd463e03b1287dd84d4bfddbecc2ee20e503a76b2f83a700c491b72e'
6
+ metadata.gz: 0d418e1d0b27008392da829980c6bdf754111a1f103965dce6882f97d3a02f0220d58756f6f1f0682df12944eac1a012516b0a3612c257342509b6e0b4c3da57
7
+ data.tar.gz: 1be3de2310297dc6b75a8f98b6c3f84483c6c401d6395dc6752cc57c342f8935911ba1ad11e8eb69e6bfcb19720e8540985c42976033401c39e137a3ab8fbc40
data/CHANGELOG.md CHANGED
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## UNRELEASED
9
9
 
10
+ ## 1.10.0 - 2021-03-22
11
+
12
+ - ### Roadmap :car:
13
+
14
+ - Extracted the configuration piece into a separate gem, [fig_tree](https://www.github.com/flipp-oss/fig_tree).
15
+ - Added a `save_record` method to ActiveRecordConsumer in case calling code wants to work with the record before saving.
16
+
17
+ - ### Fixes :wrench:
18
+
19
+ - Fixed a regression where the default values for consumer / Phobos listener configs were not correct (they were all nil). This is technically a breaking change, but it puts the configs back the way they were at version 1.4 and matches the documentation.
10
20
 
11
21
  ## 1.9.2 - 2021-01-29
12
22
 
data/Gemfile.lock CHANGED
@@ -1,71 +1,72 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- deimos-ruby (1.9.1)
4
+ deimos-ruby (1.9.2)
5
5
  avro_turf (~> 0.11)
6
+ fig_tree (~> 0.0.2)
6
7
  phobos (>= 1.9, < 3.0)
7
8
  ruby-kafka (< 2)
8
- sigurd (= 0.0.1)
9
+ sigurd (~> 0.0.1)
9
10
 
10
11
  GEM
11
12
  remote: https://rubygems.org/
12
13
  specs:
13
- actioncable (6.1.1)
14
- actionpack (= 6.1.1)
15
- activesupport (= 6.1.1)
14
+ actioncable (6.1.3)
15
+ actionpack (= 6.1.3)
16
+ activesupport (= 6.1.3)
16
17
  nio4r (~> 2.0)
17
18
  websocket-driver (>= 0.6.1)
18
- actionmailbox (6.1.1)
19
- actionpack (= 6.1.1)
20
- activejob (= 6.1.1)
21
- activerecord (= 6.1.1)
22
- activestorage (= 6.1.1)
23
- activesupport (= 6.1.1)
19
+ actionmailbox (6.1.3)
20
+ actionpack (= 6.1.3)
21
+ activejob (= 6.1.3)
22
+ activerecord (= 6.1.3)
23
+ activestorage (= 6.1.3)
24
+ activesupport (= 6.1.3)
24
25
  mail (>= 2.7.1)
25
- actionmailer (6.1.1)
26
- actionpack (= 6.1.1)
27
- actionview (= 6.1.1)
28
- activejob (= 6.1.1)
29
- activesupport (= 6.1.1)
26
+ actionmailer (6.1.3)
27
+ actionpack (= 6.1.3)
28
+ actionview (= 6.1.3)
29
+ activejob (= 6.1.3)
30
+ activesupport (= 6.1.3)
30
31
  mail (~> 2.5, >= 2.5.4)
31
32
  rails-dom-testing (~> 2.0)
32
- actionpack (6.1.1)
33
- actionview (= 6.1.1)
34
- activesupport (= 6.1.1)
33
+ actionpack (6.1.3)
34
+ actionview (= 6.1.3)
35
+ activesupport (= 6.1.3)
35
36
  rack (~> 2.0, >= 2.0.9)
36
37
  rack-test (>= 0.6.3)
37
38
  rails-dom-testing (~> 2.0)
38
39
  rails-html-sanitizer (~> 1.0, >= 1.2.0)
39
- actiontext (6.1.1)
40
- actionpack (= 6.1.1)
41
- activerecord (= 6.1.1)
42
- activestorage (= 6.1.1)
43
- activesupport (= 6.1.1)
40
+ actiontext (6.1.3)
41
+ actionpack (= 6.1.3)
42
+ activerecord (= 6.1.3)
43
+ activestorage (= 6.1.3)
44
+ activesupport (= 6.1.3)
44
45
  nokogiri (>= 1.8.5)
45
- actionview (6.1.1)
46
- activesupport (= 6.1.1)
46
+ actionview (6.1.3)
47
+ activesupport (= 6.1.3)
47
48
  builder (~> 3.1)
48
49
  erubi (~> 1.4)
49
50
  rails-dom-testing (~> 2.0)
50
51
  rails-html-sanitizer (~> 1.1, >= 1.2.0)
51
- activejob (6.1.1)
52
- activesupport (= 6.1.1)
52
+ activejob (6.1.3)
53
+ activesupport (= 6.1.3)
53
54
  globalid (>= 0.3.6)
54
- activemodel (6.1.1)
55
- activesupport (= 6.1.1)
56
- activerecord (6.1.1)
57
- activemodel (= 6.1.1)
58
- activesupport (= 6.1.1)
59
- activerecord-import (1.0.7)
55
+ activemodel (6.1.3)
56
+ activesupport (= 6.1.3)
57
+ activerecord (6.1.3)
58
+ activemodel (= 6.1.3)
59
+ activesupport (= 6.1.3)
60
+ activerecord-import (1.0.8)
60
61
  activerecord (>= 3.2)
61
- activestorage (6.1.1)
62
- actionpack (= 6.1.1)
63
- activejob (= 6.1.1)
64
- activerecord (= 6.1.1)
65
- activesupport (= 6.1.1)
62
+ activestorage (6.1.3)
63
+ actionpack (= 6.1.3)
64
+ activejob (= 6.1.3)
65
+ activerecord (= 6.1.3)
66
+ activesupport (= 6.1.3)
66
67
  marcel (~> 0.3.1)
67
68
  mimemagic (~> 0.3.2)
68
- activesupport (6.1.1)
69
+ activesupport (6.1.3)
69
70
  concurrent-ruby (~> 1.0, >= 1.0.2)
70
71
  i18n (>= 1.6, < 2)
71
72
  minitest (>= 5.1)
@@ -83,17 +84,19 @@ GEM
83
84
  concurrent-ruby-ext (1.1.8)
84
85
  concurrent-ruby (= 1.1.8)
85
86
  crass (1.0.6)
86
- database_cleaner (1.8.5)
87
- ddtrace (0.45.0)
87
+ database_cleaner (1.99.0)
88
+ ddtrace (0.46.0)
88
89
  msgpack
89
90
  diff-lcs (1.4.4)
90
91
  digest-crc (0.6.3)
91
92
  rake (>= 12.0.0, < 14.0.0)
92
- dogstatsd-ruby (4.8.2)
93
+ dogstatsd-ruby (4.8.3)
93
94
  erubi (1.10.0)
94
- excon (0.78.1)
95
+ excon (0.79.0)
95
96
  exponential-backoff (0.0.4)
96
- ffi (1.14.2)
97
+ ffi (1.15.0)
98
+ fig_tree (0.0.2)
99
+ activesupport (>= 3.0.0)
97
100
  formatador (0.2.5)
98
101
  globalid (0.4.2)
99
102
  activesupport (>= 4.2.0)
@@ -114,7 +117,7 @@ GEM
114
117
  guard-rubocop (1.4.0)
115
118
  guard (~> 2.0)
116
119
  rubocop (< 2.0)
117
- i18n (1.8.7)
120
+ i18n (1.8.9)
118
121
  concurrent-ruby (~> 1.0)
119
122
  listen (3.4.1)
120
123
  rb-fsevent (~> 0.10, >= 0.10.3)
@@ -135,12 +138,12 @@ GEM
135
138
  mimemagic (0.3.5)
136
139
  mini_mime (1.0.2)
137
140
  mini_portile2 (2.5.0)
138
- minitest (5.14.3)
139
- msgpack (1.4.1)
141
+ minitest (5.14.4)
142
+ msgpack (1.4.2)
140
143
  multi_json (1.15.0)
141
144
  mysql2 (0.5.3)
142
145
  nenv (0.3.0)
143
- nio4r (2.5.4)
146
+ nio4r (2.5.7)
144
147
  nokogiri (1.11.1)
145
148
  mini_portile2 (~> 2.5.0)
146
149
  racc (~> 1.4)
@@ -159,36 +162,36 @@ GEM
159
162
  logging
160
163
  ruby-kafka
161
164
  thor
162
- pry (0.13.1)
165
+ pry (0.14.0)
163
166
  coderay (~> 1.1)
164
167
  method_source (~> 1.0)
165
168
  racc (1.5.2)
166
169
  rack (2.2.3)
167
170
  rack-test (1.1.0)
168
171
  rack (>= 1.0, < 3)
169
- rails (6.1.1)
170
- actioncable (= 6.1.1)
171
- actionmailbox (= 6.1.1)
172
- actionmailer (= 6.1.1)
173
- actionpack (= 6.1.1)
174
- actiontext (= 6.1.1)
175
- actionview (= 6.1.1)
176
- activejob (= 6.1.1)
177
- activemodel (= 6.1.1)
178
- activerecord (= 6.1.1)
179
- activestorage (= 6.1.1)
180
- activesupport (= 6.1.1)
172
+ rails (6.1.3)
173
+ actioncable (= 6.1.3)
174
+ actionmailbox (= 6.1.3)
175
+ actionmailer (= 6.1.3)
176
+ actionpack (= 6.1.3)
177
+ actiontext (= 6.1.3)
178
+ actionview (= 6.1.3)
179
+ activejob (= 6.1.3)
180
+ activemodel (= 6.1.3)
181
+ activerecord (= 6.1.3)
182
+ activestorage (= 6.1.3)
183
+ activesupport (= 6.1.3)
181
184
  bundler (>= 1.15.0)
182
- railties (= 6.1.1)
185
+ railties (= 6.1.3)
183
186
  sprockets-rails (>= 2.0.0)
184
187
  rails-dom-testing (2.0.3)
185
188
  activesupport (>= 4.2.0)
186
189
  nokogiri (>= 1.6)
187
190
  rails-html-sanitizer (1.3.0)
188
191
  loofah (~> 2.3)
189
- railties (6.1.1)
190
- actionpack (= 6.1.1)
191
- activesupport (= 6.1.1)
192
+ railties (6.1.3)
193
+ actionpack (= 6.1.3)
194
+ activesupport (= 6.1.3)
192
195
  method_source
193
196
  rake (>= 0.8.7)
194
197
  thor (~> 1.0)
@@ -197,7 +200,7 @@ GEM
197
200
  rb-fsevent (0.10.4)
198
201
  rb-inotify (0.10.1)
199
202
  ffi (~> 1.0)
200
- regexp_parser (2.0.3)
203
+ regexp_parser (2.1.1)
201
204
  rexml (3.2.4)
202
205
  rspec (3.10.0)
203
206
  rspec-core (~> 3.10.0)
@@ -208,10 +211,10 @@ GEM
208
211
  rspec-expectations (3.10.1)
209
212
  diff-lcs (>= 1.2.0, < 2.0)
210
213
  rspec-support (~> 3.10.0)
211
- rspec-mocks (3.10.1)
214
+ rspec-mocks (3.10.2)
212
215
  diff-lcs (>= 1.2.0, < 2.0)
213
216
  rspec-support (~> 3.10.0)
214
- rspec-rails (4.0.2)
217
+ rspec-rails (4.1.1)
215
218
  actionpack (>= 4.2)
216
219
  activesupport (>= 4.2)
217
220
  railties (>= 4.2)
@@ -219,7 +222,7 @@ GEM
219
222
  rspec-expectations (~> 3.10)
220
223
  rspec-mocks (~> 3.10)
221
224
  rspec-support (~> 3.10)
222
- rspec-support (3.10.1)
225
+ rspec-support (3.10.2)
223
226
  rspec_junit_formatter (0.4.1)
224
227
  rspec-core (>= 2, < 4, != 2.12.0)
225
228
  rubocop (0.88.0)
@@ -239,7 +242,7 @@ GEM
239
242
  digest-crc
240
243
  ruby-progressbar (1.11.0)
241
244
  shellany (0.0.1)
242
- sigurd (0.0.1)
245
+ sigurd (0.0.3)
243
246
  concurrent-ruby (~> 1)
244
247
  exponential-backoff
245
248
  sprockets (4.0.2)
data/deimos-ruby.gemspec CHANGED
@@ -21,7 +21,8 @@ Gem::Specification.new do |spec|
21
21
  spec.add_runtime_dependency('avro_turf', '~> 0.11')
22
22
  spec.add_runtime_dependency('phobos', '>= 1.9', '< 3.0')
23
23
  spec.add_runtime_dependency('ruby-kafka', '< 2')
24
- spec.add_runtime_dependency('sigurd', '0.0.1')
24
+ spec.add_runtime_dependency('sigurd', '~> 0.0.1')
25
+ spec.add_runtime_dependency('fig_tree', '~> 0.0.2')
25
26
 
26
27
  spec.add_development_dependency('activerecord-import')
27
28
  spec.add_development_dependency('avro', '~> 1.9')
data/docs/ARCHITECTURE.md CHANGED
@@ -74,11 +74,7 @@ must define methods such as:
74
74
 
75
75
  ### Configuration
76
76
 
77
- Deimos has its own `Configurable` module that makes heavy use of `method_missing`
78
- to provide a very succinct but powerful configuration format (including
79
- default values, procs, print out as hash, reset, etc.). It also
80
- allows for multiple blocks to define different objects of the same time
81
- (like producers, consumers, pollers etc.).
77
+ Deimos uses the [https://www.github.com/flipp_oss/fig_tree](fig_tree) gem for configuration.
82
78
 
83
79
  The configuration definition for Deimos is in `config/configuration.rb`. In
84
80
  addition, there are methods in `config/phobos_config.rb` which translate to/from
@@ -91,6 +91,7 @@ delivery|`:batch`|The delivery mode for the consumer. Possible values: `:message
91
91
  session_timeout|300|Number of seconds after which, if a client hasn't contacted the Kafka cluster, it will be kicked out of the group.
92
92
  offset_commit_interval|10|Interval between offset commits, in seconds.
93
93
  offset_commit_threshold|0|Number of messages that can be processed before their offsets are committed. If zero, offset commits are not triggered by message processing
94
+ offset_retention_time|nil|The time period that committed offsets will be retained, in seconds. Defaults to the broker setting.
94
95
  heartbeat_interval|10|Interval between heartbeats; must be less than the session window.
95
96
  backoff|`(1000..60_000)`|Range representing the minimum and maximum number of milliseconds to back off after a consumer error.
96
97
 
@@ -58,6 +58,11 @@ module Deimos
58
58
  attrs.each do |k, v|
59
59
  record.send("#{k}=", v)
60
60
  end
61
+ save_record(record)
62
+ end
63
+
64
+ # @param record [ActiveRecord::Base]
65
+ def save_record(record)
61
66
  record.created_at ||= Time.zone.now if record.respond_to?(:created_at)
62
67
  record.updated_at = Time.zone.now if record.respond_to?(:updated_at)
63
68
  record.save!
@@ -1,17 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'fig_tree'
3
4
  require_relative 'phobos_config'
4
- require_relative 'configurable'
5
5
  require_relative '../metrics/mock'
6
6
  require_relative '../tracing/mock'
7
7
  require 'active_support/core_ext/numeric'
8
8
 
9
9
  # :nodoc:
10
10
  module Deimos
11
- include Configurable
11
+ include FigTree
12
12
 
13
13
  # :nodoc:
14
- class Configurable::ConfigStruct
14
+ class FigTree::ConfigStruct
15
15
  include Deimos::PhobosConfig
16
16
  end
17
17
 
@@ -60,7 +60,7 @@ module Deimos
60
60
  end
61
61
  end
62
62
 
63
- # @param kafka_config [Configurable::ConfigStruct]
63
+ # @param kafka_config [FigTree::ConfigStruct]
64
64
  def self.configure_producer_or_consumer(kafka_config)
65
65
  klass = kafka_config.class_name.constantize
66
66
  klass.class_eval do
@@ -327,19 +327,19 @@ module Deimos
327
327
  # These are the phobos "listener" configs. See CONFIGURATION.md for more
328
328
  # info.
329
329
  setting :group_id
330
- setting :max_concurrency
331
- setting :start_from_beginning
330
+ setting :max_concurrency, 1
331
+ setting :start_from_beginning, true
332
332
  setting :max_bytes_per_partition, 500.kilobytes
333
- setting :min_bytes
334
- setting :max_wait_time
333
+ setting :min_bytes, 1
334
+ setting :max_wait_time, 5
335
335
  setting :force_encoding
336
- setting :delivery
336
+ setting :delivery, :batch
337
337
  setting :backoff
338
- setting :session_timeout
339
- setting :offset_commit_interval
340
- setting :offset_commit_threshold
338
+ setting :session_timeout, 300
339
+ setting :offset_commit_interval, 10
340
+ setting :offset_commit_threshold, 0
341
341
  setting :offset_retention_time
342
- setting :heartbeat_interval
342
+ setting :heartbeat_interval, 10
343
343
  end
344
344
 
345
345
  setting_object :db_poller do
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Deimos
4
- VERSION = '1.9.2'
4
+ VERSION = '1.10.0'
5
5
  end
@@ -74,34 +74,34 @@ describe Deimos, 'configuration' do
74
74
  {
75
75
  topic: 'my_consume_topic',
76
76
  group_id: 'my_group_id',
77
- max_concurrency: nil,
78
- start_from_beginning: nil,
77
+ max_concurrency: 1,
78
+ start_from_beginning: true,
79
79
  max_bytes_per_partition: 524_288,
80
- min_bytes: nil,
81
- max_wait_time: nil,
80
+ min_bytes: 1,
81
+ max_wait_time: 5,
82
82
  force_encoding: nil,
83
- delivery: nil,
84
- session_timeout: nil,
85
- offset_commit_interval: nil,
86
- offset_commit_threshold: nil,
83
+ delivery: 'batch',
84
+ session_timeout: 300,
85
+ offset_commit_interval: 10,
86
+ offset_commit_threshold: 0,
87
87
  offset_retention_time: nil,
88
- heartbeat_interval: nil,
88
+ heartbeat_interval: 10,
89
89
  handler: 'ConsumerTest::MyConsumer'
90
90
  }, {
91
91
  topic: 'my_batch_consume_topic',
92
92
  group_id: 'my_batch_group_id',
93
- max_concurrency: nil,
94
- start_from_beginning: nil,
93
+ max_concurrency: 1,
94
+ start_from_beginning: true,
95
95
  max_bytes_per_partition: 500.kilobytes,
96
- min_bytes: nil,
97
- max_wait_time: nil,
96
+ min_bytes: 1,
97
+ max_wait_time: 5,
98
98
  force_encoding: nil,
99
99
  delivery: 'inline_batch',
100
- session_timeout: nil,
101
- offset_commit_interval: nil,
102
- offset_commit_threshold: nil,
100
+ session_timeout: 300,
101
+ offset_commit_interval: 10,
102
+ offset_commit_threshold: 0,
103
103
  offset_retention_time: nil,
104
- heartbeat_interval: nil,
104
+ heartbeat_interval: 10,
105
105
  handler: 'ConsumerTest::MyBatchConsumer'
106
106
  }
107
107
  ],
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deimos-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.2
4
+ version: 1.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Orner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-29 00:00:00.000000000 Z
11
+ date: 2021-03-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: avro_turf
@@ -62,16 +62,30 @@ dependencies:
62
62
  name: sigurd
63
63
  requirement: !ruby/object:Gem::Requirement
64
64
  requirements:
65
- - - '='
65
+ - - "~>"
66
66
  - !ruby/object:Gem::Version
67
67
  version: 0.0.1
68
68
  type: :runtime
69
69
  prerelease: false
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
- - - '='
72
+ - - "~>"
73
73
  - !ruby/object:Gem::Version
74
74
  version: 0.0.1
75
+ - !ruby/object:Gem::Dependency
76
+ name: fig_tree
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: 0.0.2
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: 0.0.2
75
89
  - !ruby/object:Gem::Dependency
76
90
  name: activerecord-import
77
91
  requirement: !ruby/object:Gem::Requirement
@@ -370,7 +384,6 @@ files:
370
384
  - lib/deimos/backends/kafka_async.rb
371
385
  - lib/deimos/backends/test.rb
372
386
  - lib/deimos/batch_consumer.rb
373
- - lib/deimos/config/configurable.rb
374
387
  - lib/deimos/config/configuration.rb
375
388
  - lib/deimos/config/phobos_config.rb
376
389
  - lib/deimos/consume/batch_consumption.rb
@@ -428,7 +441,6 @@ files:
428
441
  - spec/backends/kafka_async_spec.rb
429
442
  - spec/backends/kafka_spec.rb
430
443
  - spec/batch_consumer_spec.rb
431
- - spec/config/configurable_spec.rb
432
444
  - spec/config/configuration_spec.rb
433
445
  - spec/consumer_spec.rb
434
446
  - spec/deimos_spec.rb
@@ -512,7 +524,6 @@ test_files:
512
524
  - spec/backends/kafka_async_spec.rb
513
525
  - spec/backends/kafka_spec.rb
514
526
  - spec/batch_consumer_spec.rb
515
- - spec/config/configurable_spec.rb
516
527
  - spec/config/configuration_spec.rb
517
528
  - spec/consumer_spec.rb
518
529
  - spec/deimos_spec.rb
@@ -1,278 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/concern'
4
- require 'active_support/callbacks'
5
-
6
- module Deimos
7
- # Module to allow configuration. Loosely based off of the dry-configuration
8
- # gem but with several advantages:
9
- # - Works with Ruby 2.3.
10
- # - More succinct syntax using method_missing so you do not need to write
11
- # "config.whatever" and can just write "whatever".
12
- # - Use nested blocks:
13
- # Deimos.configure do
14
- # config.kafka.ssl do
15
- # enabled true
16
- # ca_cert_file 'my_file'
17
- # end
18
- # config.kafka do
19
- # ssl do
20
- # enabled true
21
- # end
22
- # end
23
- # end
24
- # - Allows for arrays of configurations:
25
- # Deimos.configure do |config|
26
- # config.producer do
27
- # class_name 'MyProducer'
28
- # topic 'MyTopic'
29
- # end
30
- # end
31
- # - Allows to call `configure` multiple times without crashing.
32
- # - Allows to lazy-set default values by passing a proc as a default:
33
- # Deimos.define_settings do |config|
34
- # setting :my_val, default_proc: proc { MyDefault.calculated_value }
35
- # end
36
- # - Support for setting up and automatically calling deprecated configurations.
37
- # - Support for configuration callbacks.
38
- module Configurable
39
- extend ActiveSupport::Concern
40
-
41
- ConfigValue = Struct.new(:value, :default_value, :default_proc, :deprecation) do
42
-
43
- # Reset value back to default.
44
- def reset!
45
- if self.value.is_a?(ConfigStruct)
46
- self.value.reset!
47
- else
48
- self.value = self.default_value
49
- end
50
- end
51
-
52
- # :nodoc:
53
- def clone_and_reset
54
- setting = ConfigValue.new(self.value, self.default_value,
55
- self.default_proc, self.deprecation)
56
- setting.reset!
57
- setting
58
- end
59
-
60
- end
61
-
62
- # Class that defines and keeps the configuration values.
63
- class ConfigStruct
64
- include ActiveSupport::Callbacks
65
-
66
- define_callbacks :configure
67
-
68
- # @param name [String]
69
- def initialize(name)
70
- @name = name
71
- @settings = {}
72
- @setting_objects = {}
73
- @setting_templates = {}
74
- end
75
-
76
- # Reset config back to default values.
77
- def reset!
78
- @setting_objects = @setting_templates.map { |k, _| [k, []] }.to_h
79
- @settings.values.each(&:reset!)
80
- end
81
-
82
- # Mark a configuration as deprecated and replaced with the new config.
83
- # @param old_config [String]
84
- # @param new_config [String]
85
- def deprecate(old_config, new_config)
86
- @settings[old_config.to_sym] ||= ConfigValue.new
87
- @settings[old_config.to_sym].deprecation = new_config
88
- end
89
-
90
- # :nodoc:
91
- def inspect
92
- "#{@name}: #{@settings.inspect} #{@setting_objects.inspect}"
93
- end
94
-
95
- # @return [Hash]
96
- def to_h
97
- @settings.map { |k, v| [k, v.value] }.to_h
98
- end
99
-
100
- # :nodoc:
101
- def clone_and_reset
102
- new_config = self.clone
103
- new_config.setting_objects = new_config.setting_objects.clone
104
- new_config.settings = new_config.settings.map { |k, v| [k, v.clone_and_reset] }.to_h
105
- new_config
106
- end
107
-
108
- # Define a setting template for an array of objects via a block:
109
- # setting_object :producer do
110
- # setting :topic
111
- # setting :class_name
112
- # end
113
- # This will create the `producer` method to define these values as well
114
- # as the `producer_objects` method to retrieve them.
115
- # @param name [Symbol]
116
- def setting_object(name, &block)
117
- new_config = ConfigStruct.new("#{@name}.#{name}")
118
- @setting_objects[name] = []
119
- @setting_templates[name] = new_config
120
- new_config.instance_eval(&block)
121
- end
122
-
123
- # Define a setting with the given name.
124
- # @param name [Symbol]
125
- # @param default_value [Object]
126
- # @param default_proc [Proc]
127
- def setting(name, default_value=nil, default_proc: nil, &block)
128
- if block_given?
129
- # Create a nested setting
130
- setting_config = @settings[name]&.value || ConfigStruct.new("#{@name}.#{name}")
131
- setting = ConfigValue.new
132
- setting.value = setting_config
133
- @settings[name] = setting
134
- setting_config.instance_eval(&block)
135
- else
136
- setting = ConfigValue.new
137
- setting.default_proc = default_proc
138
- setting.default_value = default_value
139
- setting.reset!
140
- @settings[name] = setting
141
- end
142
- end
143
-
144
- # :nodoc:
145
- def respond_to_missing?(method, include_all=true)
146
- method = method.to_s.sub(/=$/, '')
147
- method.ends_with?('objects') ||
148
- @setting_templates.key?(method.to_sym) ||
149
- @settings.key?(method.to_sym) ||
150
- super
151
- end
152
-
153
- # :nodoc:
154
- def method_missing(method, *args, &block)
155
- config_key = method.to_s.sub(/=$/, '').to_sym
156
-
157
- # Return the list of setting objects with the given name
158
- if config_key.to_s.end_with?('objects')
159
- return _setting_object_method(config_key)
160
- end
161
-
162
- # Define a new setting object with the given name
163
- if @setting_templates.key?(config_key) && block_given?
164
- return _new_setting_object_method(config_key, &block)
165
- end
166
-
167
- setting = @settings[config_key]
168
-
169
- if setting&.deprecation
170
- return _deprecated_config_method(method, *args)
171
- end
172
-
173
- return super unless setting
174
-
175
- if block_given?
176
- return _block_config_method(config_key, &block)
177
- end
178
-
179
- _default_config_method(config_key, *args)
180
- end
181
-
182
- protected
183
-
184
- # Only for the clone method
185
- attr_accessor :settings, :setting_objects
186
-
187
- private
188
-
189
- def _deprecated_config_method(method, *args)
190
- config_key = method.to_s.sub(/=$/, '').to_sym
191
- new_config = @settings[config_key].deprecation
192
- equals = method.to_s.end_with?('=') ? '=' : ''
193
- ActiveSupport::Deprecation.warn("config.#{config_key}#{equals} is deprecated - use config.#{new_config}#{equals}")
194
- obj = self
195
- messages = new_config.split('.')
196
- messages[0..-2].each do |message|
197
- obj = obj.send(message)
198
- end
199
- if args.length.positive?
200
- obj.send(messages[-1], args[0])
201
- else
202
- obj.send(messages[-1])
203
- end
204
- end
205
-
206
- # Get or set a value.
207
- def _default_config_method(config_key, *args)
208
- if args.length.positive?
209
- # Set the value
210
- @settings[config_key].value = args[0]
211
- else
212
- # Get the value
213
- setting = @settings[config_key]
214
- if setting.default_proc && setting.value.nil?
215
- setting.value = setting.default_proc.call
216
- end
217
- setting.value
218
- end
219
- end
220
-
221
- # Define a new setting object and use the passed block to define values.
222
- def _new_setting_object_method(config_key, &block)
223
- new_config = @setting_templates[config_key].clone_and_reset
224
- new_config.instance_eval(&block)
225
- @setting_objects[config_key] << new_config
226
- end
227
-
228
- # Return a setting object.
229
- def _setting_object_method(config_key)
230
- key = config_key.to_s.sub(/_objects$/, '').to_sym
231
- @setting_objects[key]
232
- end
233
-
234
- # Define new values inside a block.
235
- def _block_config_method(config_key, &block)
236
- unless @settings[config_key].value.is_a?(ConfigStruct)
237
- raise "Block called for #{config_key} but it is not a nested config!"
238
- end
239
-
240
- @settings[config_key].value.instance_eval(&block)
241
- end
242
- end
243
-
244
- # :nodoc:
245
- module ClassMethods
246
- # Define and redefine settings.
247
- def define_settings(&block)
248
- config.instance_eval(&block)
249
- end
250
-
251
- # Configure the settings with values.
252
- def configure(&block)
253
- if defined?(Rake) && defined?(Rake.application)
254
- tasks = Rake.application.top_level_tasks
255
- if tasks.any? { |t| %w(assets webpacker yarn).include?(t.split(':').first) }
256
- puts 'Skipping Deimos configuration since we are in JS/CSS compilation'
257
- return
258
- end
259
- end
260
- config.run_callbacks(:configure) do
261
- config.instance_eval(&block)
262
- end
263
- end
264
-
265
- # @return [ConfigStruct]
266
- def config
267
- @config ||= ConfigStruct.new('config')
268
- end
269
-
270
- # Pass a block to run after configuration is done.
271
- def after_configure(&block)
272
- mod = self
273
- config.class.set_callback(:configure, :after,
274
- proc { mod.instance_eval(&block) })
275
- end
276
- end
277
- end
278
- end
@@ -1,136 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # :nodoc:
4
- class MyConfig
5
- include Deimos::Configurable
6
-
7
- define_settings do
8
- setting :set1
9
- setting :set2, 'hi mom'
10
- setting :group do
11
- setting :set3, default_proc: proc { false }
12
- setting :set5, (proc { 5 })
13
- end
14
-
15
- setting_object :listy do
16
- setting :list1, 10
17
- setting :list2, 5
18
- end
19
- end
20
- end
21
-
22
- describe Deimos::Configurable do
23
- it 'should configure correctly with default values' do
24
- expect(MyConfig.config.set1).to be_nil
25
- expect(MyConfig.config.set2).to eq('hi mom')
26
- expect(MyConfig.config.group.set3).to eq(false)
27
- expect(MyConfig.config.listy_objects).to be_empty
28
- expect { MyConfig.config.blah }.to raise_error(NameError)
29
- expect { MyConfig.config.group.set4 }.to raise_error(NameError)
30
- end
31
-
32
- it 'should not call the proc until it has to' do
33
- num_calls = 0
34
- value_proc = proc do
35
- num_calls += 1
36
- num_calls
37
- end
38
- MyConfig.define_settings do
39
- setting :set_with_proc, default_proc: value_proc
40
- end
41
- expect(num_calls).to eq(0)
42
- expect(MyConfig.config.set_with_proc).to eq(1)
43
- # calling twice should not call the proc again
44
- expect(MyConfig.config.set_with_proc).to eq(1)
45
- expect(num_calls).to eq(1)
46
- end
47
-
48
- it "should raise error when setting configs that don't exist" do
49
- expect { MyConfig.configure { set15 'some_value' } }.to raise_error(NameError)
50
- end
51
-
52
- it 'should add values' do
53
- MyConfig.configure do |config|
54
- config.set1 = 5 # config.x syntax
55
- set2 nil # method_missing syntax
56
- config.group.set3 = true
57
- end
58
-
59
- # second configure should not blow anything away
60
- MyConfig.configure do
61
- listy do
62
- list1 0
63
- list2 1
64
- end
65
- listy do
66
- list1 100
67
- list2 200
68
- end
69
- end
70
-
71
- expect(MyConfig.config.set1).to eq(5)
72
- expect(MyConfig.config.set2).to be_nil
73
- expect(MyConfig.config.group.set3).to eq(true)
74
- expect(MyConfig.config.listy_objects.map(&:to_h)).
75
- to eq([
76
- { list1: 0, list2: 1 },
77
- { list1: 100, list2: 200 }
78
- ])
79
-
80
- # test reset!
81
- MyConfig.config.reset!
82
- expect(MyConfig.config.set1).to be_nil
83
- expect(MyConfig.config.set2).to eq('hi mom')
84
- expect(MyConfig.config.group.set3).to eq(false)
85
- expect(MyConfig.config.listy_objects).to be_empty
86
- end
87
-
88
- it 'should add with block syntax' do
89
- MyConfig.configure do
90
- group do
91
- set5(proc { 10 })
92
- end
93
- end
94
- expect(MyConfig.config.group.set5.call).to eq(10)
95
- end
96
-
97
- it 'should add or redefine settings' do
98
- MyConfig.define_settings do
99
- setting :group do
100
- setting :set6, 15
101
- setting :set5, (proc { 15 })
102
- end
103
- setting_object :notey do
104
- setting :note_title, 'some-title'
105
- end
106
- end
107
-
108
- expect(MyConfig.config.group.set6).to eq(15)
109
- expect(MyConfig.config.group.set5.call).to eq(15)
110
- expect(MyConfig.config.listy_objects).to be_empty
111
- expect(MyConfig.config.notey_objects).to be_empty
112
-
113
- MyConfig.configure do
114
- notey do
115
- note_title 'hi mom'
116
- end
117
- listy do
118
- list1 0
119
- end
120
- end
121
- expect(MyConfig.config.notey_objects.size).to eq(1)
122
- expect(MyConfig.config.notey_objects.first.note_title).to eq('hi mom')
123
- expect(MyConfig.config.listy_objects.size).to eq(1)
124
- expect(MyConfig.config.listy_objects.first.list1).to eq(0)
125
-
126
- # This should not remove any keys
127
- MyConfig.define_settings do
128
- setting :group do
129
- setting :set6, 20
130
- end
131
- end
132
- expect(MyConfig.config.group.set6).to eq(20)
133
- expect(MyConfig.config.group.set5.call).to eq(15)
134
- end
135
-
136
- end