synapse-core 0.1.2 → 0.2.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.
Files changed (57) hide show
  1. data/lib/synapse/auditing/audit_logger.rb +28 -0
  2. data/lib/synapse/auditing/data_provider.rb +42 -0
  3. data/lib/synapse/auditing/dispatch_interceptor.rb +29 -0
  4. data/lib/synapse/auditing/unit_listener.rb +53 -0
  5. data/lib/synapse/auditing.rb +4 -0
  6. data/lib/synapse/command.rb +34 -0
  7. data/lib/synapse/{duplication.rb → common/duplication.rb} +0 -0
  8. data/lib/synapse/{errors.rb → common/errors.rb} +0 -0
  9. data/lib/synapse/{identifier.rb → common/identifier.rb} +2 -1
  10. data/lib/synapse/{message.rb → common/message.rb} +0 -0
  11. data/lib/synapse/{message_builder.rb → common/message_builder.rb} +0 -0
  12. data/lib/synapse/domain.rb +5 -0
  13. data/lib/synapse/event_bus.rb +5 -0
  14. data/lib/synapse/event_sourcing/conflict_resolver.rb +4 -6
  15. data/lib/synapse/event_sourcing/member.rb +11 -2
  16. data/lib/synapse/event_sourcing/snapshot/taker.rb +0 -18
  17. data/lib/synapse/event_sourcing.rb +13 -0
  18. data/lib/synapse/event_store/mongo/cursor_event_stream.rb +3 -3
  19. data/lib/synapse/event_store/mongo.rb +8 -0
  20. data/lib/synapse/event_store.rb +11 -0
  21. data/lib/synapse/partitioning/amqp/amqp_queue_reader.rb +50 -0
  22. data/lib/synapse/partitioning/amqp/amqp_queue_writer.rb +31 -0
  23. data/lib/synapse/partitioning/amqp/key_resolver.rb +26 -0
  24. data/lib/synapse/partitioning/amqp.rb +3 -0
  25. data/lib/synapse/partitioning/memory_queue_reader.rb +31 -0
  26. data/lib/synapse/partitioning/memory_queue_writer.rb +19 -0
  27. data/lib/synapse/partitioning/message_receipt.rb +25 -0
  28. data/lib/synapse/partitioning/packing/json_packer.rb +93 -0
  29. data/lib/synapse/partitioning/packing/json_unpacker.rb +83 -0
  30. data/lib/synapse/partitioning/packing.rb +27 -0
  31. data/lib/synapse/partitioning/queue_reader.rb +32 -0
  32. data/lib/synapse/partitioning/queue_writer.rb +17 -0
  33. data/lib/synapse/partitioning.rb +20 -0
  34. data/lib/synapse/process_manager.rb +4 -0
  35. data/lib/synapse/repository/locking.rb +3 -8
  36. data/lib/synapse/repository.rb +7 -0
  37. data/lib/synapse/serialization/converter/bson.rb +28 -0
  38. data/lib/synapse/serialization/serializer/attribute.rb +48 -0
  39. data/lib/synapse/serialization/serializer.rb +1 -1
  40. data/lib/synapse/serialization.rb +46 -0
  41. data/lib/synapse/uow/factory.rb +5 -5
  42. data/lib/synapse/uow/uow.rb +13 -13
  43. data/lib/synapse/uow.rb +8 -0
  44. data/lib/synapse/upcasting/chain.rb +1 -1
  45. data/lib/synapse/upcasting.rb +5 -0
  46. data/lib/synapse/version.rb +1 -1
  47. data/lib/synapse/wiring.rb +3 -0
  48. data/lib/synapse.rb +26 -338
  49. data/test/auditing/data_provider_test.rb +30 -0
  50. data/test/auditing/dispatch_interceptor_test.rb +25 -0
  51. data/test/auditing/unit_listener_test.rb +70 -0
  52. data/test/partitioning/memory_test.rb +34 -0
  53. data/test/partitioning/packing/json_test.rb +61 -0
  54. data/test/test_ext.rb +14 -0
  55. data/test/test_helper.rb +4 -0
  56. metadata +45 -24
  57. data/test/event_sourcing/snapshot/deferred_taker_test.rb +0 -19
data/lib/synapse.rb CHANGED
@@ -1,351 +1,39 @@
1
1
  require 'active_support'
2
2
  require 'active_support/core_ext'
3
- require 'eventmachine'
4
3
  require 'logging'
5
4
  require 'set'
6
5
 
7
6
  require 'synapse/version'
8
7
 
8
+ require 'synapse/common/errors'
9
+ require 'synapse/common/identifier'
10
+ require 'synapse/common/message'
11
+ require 'synapse/common/message_builder'
12
+
9
13
  module Synapse
10
14
  extend ActiveSupport::Autoload
11
15
 
12
- eager_autoload do
13
- autoload_at 'synapse/errors' do
14
- autoload :SynapseError
15
- autoload :ConfigurationError
16
- autoload :NonTransientError
17
- autoload :TransientError
18
- end
19
-
20
- autoload_at 'synapse/identifier' do
21
- autoload :IdentifierFactory
22
- autoload :GuidIdentifierFactory
23
- end
24
-
25
- autoload :Message
26
- autoload :MessageBuilder
27
-
28
- autoload_at 'synapse/duplication' do
29
- autoload :DuplicationError
30
- autoload :DuplicationRecorder
31
- end
32
- end
33
-
34
- module Command
35
- extend ActiveSupport::Autoload
36
-
37
- eager_autoload do
38
- autoload :CommandBus
39
- autoload :SimpleCommandBus
40
-
41
- autoload :CommandCallback
42
- autoload :CommandFilter
43
- autoload :CommandHandler
44
-
45
- autoload_at 'synapse/command/message' do
46
- autoload :CommandMessage
47
- autoload :CommandMessageBuilder
48
- end
49
-
50
- autoload :CommandGateway, 'synapse/command/gateway'
51
-
52
- autoload :DispatchInterceptor
53
- autoload :InterceptorChain
54
-
55
- autoload_at 'synapse/command/duplication' do
56
- autoload :DuplicationFilter
57
- autoload :DuplicationCleanupInterceptor
58
- end
59
-
60
- autoload_at 'synapse/command/errors' do
61
- autoload :CommandExecutionError
62
- autoload :CommandValidationError
63
- autoload :NoHandlerError
64
- end
65
-
66
- autoload_at 'synapse/command/filters/validation' do
67
- autoload :ActiveModelValidationFilter
68
- autoload :ActiveModelValidationError
69
- end
70
-
71
- autoload_at 'synapse/command/interceptors/serialization' do
72
- autoload :SerializationOptimizingInterceptor
73
- autoload :SerializationOptimizingListener
74
- end
75
-
76
- autoload_at 'synapse/command/rollback_policy' do
77
- autoload :RollbackPolicy
78
- autoload :RollbackOnAnyExceptionPolicy
79
- end
80
-
81
- autoload :WiringCommandHandler, 'synapse/command/wiring'
82
- end
16
+ autoload_at 'synapse/common/duplication' do
17
+ autoload :DuplicationError
18
+ autoload :DuplicationRecorder
83
19
  end
84
20
 
85
- module Domain
86
- extend ActiveSupport::Autoload
87
-
88
- eager_autoload do
89
- autoload_at 'synapse/domain/aggregate_root' do
90
- autoload :AggregateRoot
91
- autoload :AggregateIdentifierNotInitializedError
92
- end
93
-
94
- autoload :EventContainer
95
-
96
- autoload_at 'synapse/domain/message' do
97
- autoload :EventMessage
98
- autoload :DomainEventMessage
99
- end
100
-
101
- autoload_at 'synapse/domain/message_builder' do
102
- autoload :EventMessageBuilder
103
- autoload :DomainEventMessageBuilder
104
- end
105
-
106
- autoload_at 'synapse/domain/stream' do
107
- autoload :DomainEventStream
108
- autoload :EndOfStreamError
109
- autoload :SimpleDomainEventStream
110
- end
111
- end
112
- end
113
-
114
- module EventBus
115
- extend ActiveSupport::Autoload
116
-
117
- eager_autoload do
118
- autoload_at 'synapse/event_bus/event_bus' do
119
- autoload :EventBus
120
- autoload :SubscriptionFailedError
121
- end
122
-
123
- autoload :EventListener
124
- autoload :EventListenerProxy
125
- autoload :SimpleEventBus
126
- autoload :WiringEventListener, 'synapse/event_bus/wiring'
127
- end
128
- end
129
-
130
- module EventSourcing
131
- extend ActiveSupport::Autoload
132
-
133
- eager_autoload do
134
- autoload_at 'synapse/event_sourcing/aggregate_factory' do
135
- autoload :AggregateFactory
136
- autoload :GenericAggregateFactory
137
- end
138
-
139
- autoload :AggregateRoot
140
- autoload :Entity
141
- autoload :Member
142
-
143
- autoload :EventSourcingRepository, 'synapse/event_sourcing/repository'
144
- autoload :EventSourcedStorageListener, 'synapse/event_sourcing/storage_listener'
145
- autoload :EventStreamDecorator, 'synapse/event_sourcing/stream_decorator'
146
-
147
- autoload_at 'synapse/event_sourcing/conflict_resolver' do
148
- autoload :ConflictResolver
149
- autoload :ConflictResolvingUnitOfWorkListener
150
- autoload :CapturingEventStream
151
- end
152
-
153
- autoload_at 'synapse/event_sourcing/snapshot/taker' do
154
- autoload :AggregateSnapshotTaker
155
- autoload :DeferredSnapshotTaker
156
- autoload :SnapshotTaker
157
- end
158
-
159
- autoload_at 'synapse/event_sourcing/snapshot/count_stream' do
160
- autoload :CountingEventStream
161
- autoload :TriggeringEventStream
162
- autoload :SnapshotUnitOfWorkListener
163
- end
164
-
165
- autoload :EventCountSnapshotTrigger, 'synapse/event_sourcing/snapshot/count_trigger'
166
- end
167
- end
168
-
169
- module EventStore
170
- extend ActiveSupport::Autoload
171
-
172
- eager_autoload do
173
- autoload_at 'synapse/event_store/errors' do
174
- autoload :EventStoreError
175
- autoload :StreamNotFoundError
176
- end
177
-
178
- autoload_at 'synapse/event_store/event_store' do
179
- autoload :EventStore
180
- autoload :SnapshotEventStore
181
- end
182
- end
183
-
184
- autoload :InMemoryEventStore, 'synapse/event_store/in_memory'
185
-
186
- module Mongo
187
- extend ActiveSupport::Autoload
188
-
189
- autoload :CursorDomainEventStream, 'synapse/event_store/mongo/cursor_event_stream'
190
- autoload :MongoEventStore, 'synapse/event_store/mongo/event_store'
191
- autoload :DocumentPerEventStrategy, 'synapse/event_store/mongo/per_event_strategy'
192
- autoload :DocumentPerCommitStrategy, 'synapse/event_store/mongo/per_commit_strategy'
193
- autoload :StorageStrategy, 'synapse/event_store/mongo/storage_strategy'
194
-
195
- autoload_at 'synapse/event_store/mongo/template' do
196
- autoload :MongoTemplate
197
- autoload :DefaultMongoTemplate
198
- end
199
- end
200
- end
201
-
202
- module ProcessManager
203
- extend ActiveSupport::Autoload
204
-
205
- autoload :Correlation
206
- autoload :CorrelationResolver
207
- autoload :CorrelationSet
208
-
209
- autoload :Process
210
- end
211
-
212
- module Repository
213
- extend ActiveSupport::Autoload
214
-
215
- eager_autoload do
216
- autoload_at 'synapse/repository/errors' do
217
- autoload :AggregateNotFoundError
218
- autoload :ConcurrencyError
219
- autoload :ConflictingAggregateVersionError
220
- autoload :ConflictingModificationError
221
- end
222
-
223
- autoload :LockManager
224
- autoload :PessimisticLockManager
225
-
226
- autoload_at 'synapse/repository/locking' do
227
- autoload :LockingRepository
228
- autoload :LockCleaningUnitOfWorkListener
229
- end
230
-
231
- autoload :Repository
232
- end
233
- end
234
-
235
- module Serialization
236
- extend ActiveSupport::Autoload
237
-
238
- eager_autoload do
239
- autoload :Converter
240
- autoload :ConverterFactory, 'synapse/serialization/converter/factory'
241
- autoload :IdentityConverter, 'synapse/serialization/converter/identity'
242
-
243
- autoload_at 'synapse/serialization/errors' do
244
- autoload :ConversionError
245
- autoload :SerializationError
246
- autoload :UnknownSerializedTypeError
247
- end
248
-
249
- autoload_at 'synapse/serialization/lazy_object' do
250
- autoload :DeserializedObject
251
- autoload :LazyObject
252
- end
253
-
254
- autoload_at 'synapse/serialization/revision_resolver' do
255
- autoload :RevisionResolver
256
- autoload :FixedRevisionResolver
257
- end
258
-
259
- autoload :SerializedDomainEventData, 'synapse/serialization/message/data'
260
- autoload :MessageSerializer, 'synapse/serialization/message/serializer'
261
- autoload :SerializedMetadata, 'synapse/serialization/message/metadata'
262
- autoload :SerializationAware, 'synapse/serialization/message/serialization_aware'
263
- autoload :SerializedObjectCache, 'synapse/serialization/message/serialized_object_cache'
264
-
265
- autoload_at 'synapse/serialization/message/serialization_aware_message' do
266
- autoload :SerializationAwareEventMessage
267
- autoload :SerializationAwareDomainEventMessage
268
- end
269
-
270
- autoload_at 'synapse/serialization/message/serialized_message' do
271
- autoload :SerializedMessage
272
- autoload :SerializedEventMessage
273
- autoload :SerializedDomainEventMessage
274
- end
275
-
276
- autoload_at 'synapse/serialization/message/serialized_message_builder' do
277
- autoload :SerializedMessageBuilder
278
- autoload :SerializedEventMessageBuilder
279
- autoload :SerializedDomainEventMessageBuilder
280
- end
281
-
282
- autoload :Serializer
283
- autoload :SerializedObject
284
- autoload :SerializedType
285
- end
286
-
287
- autoload_at 'synapse/serialization/converter/json' do
288
- autoload :JsonToObjectConverter
289
- autoload :ObjectToJsonConverter
290
- end
291
-
292
- autoload_at 'synapse/serialization/converter/ox' do
293
- autoload :XmlToOxDocumentConverter
294
- autoload :OxDocumentToXmlConverter
295
- end
296
-
297
- autoload :OjSerializer, 'synapse/serialization/serializer/oj'
298
- autoload :OxSerializer, 'synapse/serialization/serializer/ox'
299
- autoload :MarshalSerializer, 'synapse/serialization/serializer/marshal'
300
- end
301
-
302
- module UnitOfWork
303
- extend ActiveSupport::Autoload
304
-
305
- eager_autoload do
306
- autoload_at 'synapse/uow/nesting' do
307
- autoload :NestableUnitOfWork
308
- autoload :OuterCommitUnitOfWorkListener
309
- end
310
-
311
- autoload :StorageListener, 'synapse/uow/storage_listener'
312
- autoload :TransactionManager, 'synapse/uow/transaction_manager'
313
- autoload :UnitOfWork, 'synapse/uow/uow'
314
- autoload :UnitOfWorkFactory, 'synapse/uow/factory'
315
- autoload :UnitOfWorkListener, 'synapse/uow/listener'
316
- autoload :UnitOfWorkListenerCollection, 'synapse/uow/listener_collection'
317
- autoload :UnitOfWorkProvider, 'synapse/uow/provider'
318
- end
319
- end
320
-
321
- module Upcasting
322
- extend ActiveSupport::Autoload
323
-
324
- autoload :SingleUpcaster
325
- autoload :Upcaster
326
- autoload :UpcasterChain, 'synapse/upcasting/chain'
327
-
328
- autoload_at 'synapse/upcasting/context' do
329
- autoload :UpcastingContext
330
- autoload :SerializedDomainEventUpcastingContext
331
- end
332
-
333
- autoload :UpcastSerializedDomainEventData, 'synapse/upcasting/data'
334
- end
335
-
336
- module Wiring
337
- extend ActiveSupport::Autoload
338
-
339
- autoload :MessageWiring
340
- autoload :Wire
341
- autoload :WireRegistry
342
- end
343
-
344
- # TODO this is more of an application call
345
- ActiveSupport::Autoload.eager_autoload!
346
-
347
- # Setup the default identifier factory
348
- ActiveSupport.on_load :identifier_factory do
349
- IdentifierFactory.instance = GuidIdentifierFactory.new
350
- end
21
+ eager_autoload do
22
+ # Common components
23
+ autoload :Command
24
+ autoload :Domain
25
+ autoload :EventBus
26
+ autoload :Repository
27
+ autoload :Serialization
28
+ autoload :UnitOfWork, 'synapse/uow'
29
+ autoload :Wiring
30
+ end
31
+
32
+ # Optional components
33
+ autoload :Auditing
34
+ autoload :EventSourcing
35
+ autoload :EventStore
36
+ autoload :Partitioning
37
+ autoload :ProcessManager
38
+ autoload :Upcasting
351
39
  end
@@ -0,0 +1,30 @@
1
+ require 'test_helper'
2
+
3
+ module Synapse
4
+ module Auditing
5
+
6
+ class CommandMetadataProviderTest < Test::Unit::TestCase
7
+ def test_provide_data_for
8
+ data = { foo: 0 }
9
+
10
+ provider = CommandMetadataProvider.new
11
+ command = Command::CommandMessage.build do |builder|
12
+ builder.metadata = data
13
+ end
14
+
15
+ assert_equal data, provider.provide_data_for(command)
16
+ end
17
+ end
18
+
19
+ class CorrelationDataProviderTest < Test::Unit::TestCase
20
+ def test_provide_data_for
21
+ provider = CorrelationDataProvider.new
22
+ command = Command::CommandMessage.build
23
+
24
+ expected = { :command_id => command.id }
25
+ assert_equal expected, provider.provide_data_for(command)
26
+ end
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ module Synapse
4
+ module Auditing
5
+
6
+ class AuditingDispatchInterceptorTest < Test::Unit::TestCase
7
+ def test_intercept
8
+ return_value = Object.new
9
+ chain = Object.new
10
+ command = Object.new
11
+ unit = Object.new
12
+
13
+ interceptor = AuditingDispatchInterceptor.new
14
+
15
+ mock(unit).register_listener(is_a(AuditingUnitOfWorkListener))
16
+ mock(chain).proceed(command) do
17
+ return_value
18
+ end
19
+
20
+ assert_equal return_value, interceptor.intercept(command, unit, chain)
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,70 @@
1
+ require 'test_helper'
2
+
3
+ module Synapse
4
+ module Auditing
5
+
6
+ class AuditingUnitOfWorkListenerTest < Test::Unit::TestCase
7
+ def test_on_event_registered
8
+ data_provider_a = Object.new
9
+ data_provider_b = Object.new
10
+
11
+ command = Object.new
12
+ data_providers = [data_provider_a, data_provider_b]
13
+ loggers = []
14
+
15
+ listener = AuditingUnitOfWorkListener.new command, data_providers, loggers
16
+
17
+ event = Object.new
18
+
19
+ data_a = { foo: 0 }
20
+ data_b = { bar: 1 }
21
+
22
+ mock(data_provider_a).provide_data_for(command) { data_a }
23
+ mock(data_provider_b).provide_data_for(command) { data_b }
24
+
25
+ mock(event).and_metadata(data_a.merge(data_b)) { event }
26
+
27
+ out = listener.on_event_registered(Object.new, event)
28
+
29
+ assert_same event, out
30
+ assert listener.recorded_events.include? event
31
+ end
32
+
33
+ def test_after_commit
34
+ logger = Object.new
35
+
36
+ command = Object.new
37
+ return_value = Object.new
38
+ data_providers = []
39
+ loggers = [logger]
40
+ event = Object.new
41
+
42
+ mock(logger).on_success(command, return_value, [event])
43
+
44
+ listener = AuditingUnitOfWorkListener.new command, data_providers, loggers
45
+ listener.return_value = return_value
46
+ listener.recorded_events.push event
47
+
48
+ listener.after_commit Object.new
49
+ end
50
+
51
+ def test_on_rollback
52
+ logger = Object.new
53
+
54
+ command = Object.new
55
+ exception = Exception.new
56
+ data_providers = []
57
+ loggers = [logger]
58
+ event = Object.new
59
+
60
+ mock(logger).on_success(command, exception, [event])
61
+
62
+ listener = AuditingUnitOfWorkListener.new command, data_providers, loggers
63
+ listener.recorded_events.push event
64
+
65
+ listener.on_rollback Object.new, exception
66
+ end
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,34 @@
1
+ require 'test_helper'
2
+
3
+ module Synapse
4
+ module Partitioning
5
+
6
+ class MemoryQueueTest < Test::Unit::TestCase
7
+ def test_queuing
8
+ message = MessageBuilder.build
9
+
10
+ queue = Queue.new
11
+
12
+ reader = MemoryQueueReader.new queue, :test
13
+ writer = MemoryQueueWriter.new queue
14
+
15
+ count = 0
16
+
17
+ Thread.new do
18
+ reader.subscribe do |receipt|
19
+ assert_equal message, receipt.packed
20
+ assert_equal :test, receipt.queue_name
21
+
22
+ count = count.next
23
+ end
24
+ end
25
+
26
+ writer.put_message message, message
27
+ writer.put_message message, message
28
+
29
+ wait_until { count == 2 }
30
+ end
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,61 @@
1
+ require 'test_helper'
2
+
3
+ module Synapse
4
+ module Partitioning
5
+
6
+ class JsonPackingTest < Test::Unit::TestCase
7
+ def setup
8
+ @serializer = Serialization::MarshalSerializer.new
9
+ @packer = JsonMessagePacker.new @serializer
10
+ @unpacker = JsonMessageUnpacker.new @serializer
11
+ end
12
+
13
+ def test_packing
14
+ message = Domain::DomainEventMessage.build do |builder|
15
+ builder.metadata = { foo: 0 }
16
+ builder.payload = { bar: 1 }
17
+ builder.aggregate_id = '123'
18
+ builder.sequence_number = 1
19
+ end
20
+
21
+ packed = @packer.pack_message message
22
+ unpacked = @unpacker.unpack_message packed
23
+
24
+ assert_equal message.id, unpacked.id
25
+ assert_equal message.metadata, unpacked.metadata
26
+ assert_equal message.payload, unpacked.payload
27
+ assert_equal message.timestamp.to_i, unpacked.timestamp.to_i
28
+ assert_equal message.aggregate_id, unpacked.aggregate_id
29
+ assert_equal message.sequence_number, unpacked.sequence_number
30
+ end
31
+
32
+ def test_type_packing
33
+ [Command::CommandMessage, Domain::EventMessage, Domain::DomainEventMessage].each do |type|
34
+ message = type.build
35
+ packed = @packer.pack_message message
36
+ unpacked = @unpacker.unpack_message packed
37
+
38
+ assert type === unpacked
39
+ end
40
+ end
41
+
42
+ def test_unknown_type
43
+ message = Message.build
44
+
45
+ assert_raise ArgumentError do
46
+ @packer.pack_message message
47
+ end
48
+
49
+ packed = {
50
+ message_type: :message
51
+ }
52
+ packed = JSON.dump packed
53
+
54
+ assert_raise ArgumentError do
55
+ @unpacker.unpack_message packed
56
+ end
57
+ end
58
+ end
59
+
60
+ end
61
+ end
data/test/test_ext.rb ADDED
@@ -0,0 +1,14 @@
1
+ class Test::Unit::TestCase
2
+ # Blocks until a condition is met or a timeout occurs
3
+ #
4
+ # @param [Integer] timeout In seconds
5
+ # @param [Float] retry_interval In seconds
6
+ # @return [undefined]
7
+ def wait_until(timeout = 2, retry_interval = 0.1, &block)
8
+ start = Time.now
9
+ until !!block.call
10
+ raise if (Time.now - start).to_i >= timeout
11
+ sleep retry_interval
12
+ end
13
+ end
14
+ end
data/test/test_helper.rb CHANGED
@@ -14,6 +14,10 @@ require 'rr'
14
14
  require 'timecop'
15
15
  require 'synapse'
16
16
 
17
+ require 'test_ext'
18
+
17
19
  class Test::Unit::TestCase
18
20
  include RR::Adapters::TestUnit
19
21
  end
22
+
23
+ ActiveSupport::Autoload.eager_autoload!