snapshot_aggregate_root 0.5.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 +7 -0
- data/.gitignore +9 -0
- data/Gemfile +4 -0
- data/README.md +34 -0
- data/Rakefile +4 -0
- data/lib/snapshot_aggregate_root.rb +113 -0
- data/lib/snapshot_aggregate_root/configuration.rb +14 -0
- data/lib/snapshot_aggregate_root/default_apply_strategy.rb +25 -0
- data/lib/snapshot_aggregate_root/version.rb +3 -0
- data/snapshot_aggregate_root.gemspec +31 -0
- metadata +167 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA1:
         | 
| 3 | 
            +
              metadata.gz: d356e58389d1bb33fdd4462cb9b2df873d94c83e
         | 
| 4 | 
            +
              data.tar.gz: 558e2953a0d60cbd5880b9d18748e3f33f7a8fd3
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: afbf998b72579cae65db5451109cb5fa8173c0963e2782f2553b1e0adc774ad386f42b665f268344df43a5d4ed59bb150d995738517255807d10028068f9c916
         | 
| 7 | 
            +
              data.tar.gz: 4ba0fda9221166df43c470d99065f4283251626bc5a02700577c9536f06341dbaf1e18a8661c46e35c802fc9df6b20a4865a10456f6a9a6bb58bf42b0d384abb
         | 
    
        data/.gitignore
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,34 @@ | |
| 1 | 
            +
            # SnapshotAggregateRoot
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            An extension of https://github.com/arkency/aggregate_root with support for concurrent writers.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            ## Usage
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            ### Snapshots
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            Snapshots are created automatically as required by the `#store` method.  Implementations of this class must implement
         | 
| 10 | 
            +
            2 methods.
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            * `#build_snapshot`
         | 
| 13 | 
            +
            * `#apply_snapshot(snapshot)`
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            Optionally Implementations may also override
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            * `#snapshot_threshold` - Override how often snapshots are taken
         | 
| 18 | 
            +
            * `#requires_snapshot?`- Provide a custom implementation for when snapshots a required
         | 
| 19 | 
            +
             | 
| 20 | 
            +
             | 
| 21 | 
            +
            ### Concurrent Writers
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            In order to be safe for current writes snapshot aggregate root exposes a `#with_write_context(stream_name, event_store:)` method. This method loads the aggregate, applies the block, then stores the events within a mutex so that only one concurrent writer can execute the block.  Event handlers are triggered after the command is complete
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            The entire command handler for a snapshot aggregate root should be executed within this block eg.
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            ```
         | 
| 28 | 
            +
              def apply_command(command)
         | 
| 29 | 
            +
                SomeAggregate.new.with_write_context(command.aggregate_id) do |aggregate|
         | 
| 30 | 
            +
                  aggregate.do_command(command)
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            ```
         | 
| 34 | 
            +
             | 
    
        data/Rakefile
    ADDED
    
    
| @@ -0,0 +1,113 @@ | |
| 1 | 
            +
            require 'active_support/inflector'
         | 
| 2 | 
            +
            require 'snapshot_aggregate_root/version'
         | 
| 3 | 
            +
            require 'snapshot_aggregate_root/configuration'
         | 
| 4 | 
            +
            require 'snapshot_aggregate_root/default_apply_strategy'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module SnapshotAggregateRoot
         | 
| 7 | 
            +
              attr_accessor :events_since_snapshot
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              def apply(event)
         | 
| 10 | 
            +
                apply_strategy.(self, event)
         | 
| 11 | 
            +
                unpublished_events << event
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              def with_lock(stream_name, event_store: default_event_store, &block)
         | 
| 15 | 
            +
                event_store.with_lock(stream_name, &block)
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              def with_write_context(stream_name, event_store: default_event_store)
         | 
| 19 | 
            +
                with_lock(stream_name, event_store: event_store) do
         | 
| 20 | 
            +
                  load(stream_name, event_store: event_store)
         | 
| 21 | 
            +
                  yield self
         | 
| 22 | 
            +
                  store(stream_name, event_store: event_store)
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
                notify(event_store: event_store)
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              def load(stream_name, event_store: default_event_store)
         | 
| 28 | 
            +
                @loaded_from_stream_name = stream_name
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                snapshot = event_store.last_stream_snapshot(stream_name)
         | 
| 31 | 
            +
                if snapshot
         | 
| 32 | 
            +
                  apply_snapshot(snapshot)
         | 
| 33 | 
            +
                  events = event_store.read_events_forward(stream_name, start: snapshot.event_id, count: 0)
         | 
| 34 | 
            +
                else
         | 
| 35 | 
            +
                  events = event_store.read_events_forward(stream_name, count: 0)
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                events.each(&method(:apply))
         | 
| 39 | 
            +
                self.events_since_snapshot = events.count
         | 
| 40 | 
            +
                @unpublished_events = nil
         | 
| 41 | 
            +
                self
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              def store(stream_name = loaded_from_stream_name, event_store: default_event_store)
         | 
| 45 | 
            +
                self.events_since_snapshot += @unpublished_events.count
         | 
| 46 | 
            +
                unpublished_events.each do |event|
         | 
| 47 | 
            +
                  event_store.append_to_stream(event, stream_name: stream_name)
         | 
| 48 | 
            +
                  unnotified_events.push(event)
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
                @unpublished_events = nil
         | 
| 51 | 
            +
                if requires_snapshot?
         | 
| 52 | 
            +
                  snapshot!(stream_name, event_store: event_store)
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
              end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
              def notify(event_store: )
         | 
| 57 | 
            +
                unnotified_events.each do |event|
         | 
| 58 | 
            +
                  event_store.notify_subscribers(event)
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
                @unnotified_events = nil
         | 
| 61 | 
            +
              end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
              def events_since_snapshot
         | 
| 64 | 
            +
                @events_since_snapshot || 0
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              private
         | 
| 68 | 
            +
             | 
| 69 | 
            +
              attr_reader :loaded_from_stream_name
         | 
| 70 | 
            +
             | 
| 71 | 
            +
              # This method must be implemented by consumers of this module
         | 
| 72 | 
            +
              #
         | 
| 73 | 
            +
              # Returns an Event
         | 
| 74 | 
            +
              def build_snapshot
         | 
| 75 | 
            +
                raise "build_snapshot not implemented in #{self}"
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
              # This method must be implemented by consumers of this module
         | 
| 79 | 
            +
              #
         | 
| 80 | 
            +
              # Returns an Event
         | 
| 81 | 
            +
              def apply_snapshot(snapshot)
         | 
| 82 | 
            +
                raise "apply_snapshot not implemented in #{self}"
         | 
| 83 | 
            +
              end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
              def requires_snapshot?
         | 
| 86 | 
            +
                events_since_snapshot >= snapshot_threshold
         | 
| 87 | 
            +
              end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
              def snapshot_threshold
         | 
| 90 | 
            +
                50
         | 
| 91 | 
            +
              end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
              def snapshot!(stream_name, event_store:)
         | 
| 94 | 
            +
                event = build_snapshot
         | 
| 95 | 
            +
                event_store.publish_snapshot(event, stream_name: stream_name)
         | 
| 96 | 
            +
              end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
              def unpublished_events
         | 
| 99 | 
            +
                @unpublished_events ||= []
         | 
| 100 | 
            +
              end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
              def unnotified_events
         | 
| 103 | 
            +
                @unnotified_events ||= []
         | 
| 104 | 
            +
              end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
              def apply_strategy
         | 
| 107 | 
            +
                DefaultApplyStrategy.new
         | 
| 108 | 
            +
              end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
              def default_event_store
         | 
| 111 | 
            +
                SnapshotAggregateRoot.configuration.default_event_store
         | 
| 112 | 
            +
              end
         | 
| 113 | 
            +
            end
         | 
| @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            module SnapshotAggregateRoot
         | 
| 2 | 
            +
              class << self
         | 
| 3 | 
            +
                attr_accessor :configuration
         | 
| 4 | 
            +
              end
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              def self.configure
         | 
| 7 | 
            +
                self.configuration ||= Configuration.new
         | 
| 8 | 
            +
                yield(configuration)
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              class Configuration
         | 
| 12 | 
            +
                attr_accessor :default_event_store
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            module SnapshotAggregateRoot
         | 
| 2 | 
            +
              MissingHandler = Class.new(StandardError)
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              class DefaultApplyStrategy
         | 
| 5 | 
            +
                def initialize(strict: true)
         | 
| 6 | 
            +
                  @strict = strict
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def call(aggregate, event)
         | 
| 10 | 
            +
                  name = handler_name(event)
         | 
| 11 | 
            +
                  if aggregate.respond_to?(name, true)
         | 
| 12 | 
            +
                    aggregate.method(name).call(event)
         | 
| 13 | 
            +
                  else
         | 
| 14 | 
            +
                    raise MissingHandler.new("Missing handler method #{name} on aggregate #{aggregate.class}") if strict
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                private
         | 
| 19 | 
            +
                attr_reader :strict
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def handler_name(event)
         | 
| 22 | 
            +
                  "apply_#{event.class.name.demodulize.underscore}"
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| @@ -0,0 +1,31 @@ | |
| 1 | 
            +
            # coding: utf-8
         | 
| 2 | 
            +
            lib = File.expand_path('../lib', __FILE__)
         | 
| 3 | 
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         | 
| 4 | 
            +
            require 'snapshot_aggregate_root/version'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Gem::Specification.new do |spec|
         | 
| 7 | 
            +
              spec.name          = 'snapshot_aggregate_root'
         | 
| 8 | 
            +
              spec.version       = SnapshotAggregateRoot::VERSION
         | 
| 9 | 
            +
              spec.licenses      = ['MIT']
         | 
| 10 | 
            +
              spec.authors       = ['Gareth Andrew']
         | 
| 11 | 
            +
              spec.email         = ['gingerhendrix@gmail.com']
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              spec.summary       = %q{Event sourced aggregate root implementation with concurrent writer and snapshot support}
         | 
| 14 | 
            +
              spec.description   = %q{Event sourced aggregate root implementation with concurrent writer and snapshot support}
         | 
| 15 | 
            +
              spec.homepage      = 'https://github.com/gingerhendrix/snapshot_aggregate_root'
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              spec.files         = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
         | 
| 18 | 
            +
              spec.bindir        = 'exe'
         | 
| 19 | 
            +
              spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
         | 
| 20 | 
            +
              spec.require_paths = ['lib']
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              spec.add_development_dependency 'bundler', '~> 1.9'
         | 
| 23 | 
            +
              spec.add_development_dependency 'rake', '~> 10.0'
         | 
| 24 | 
            +
              spec.add_development_dependency 'pry'
         | 
| 25 | 
            +
              spec.add_development_dependency 'rspec'
         | 
| 26 | 
            +
              spec.add_development_dependency 'rails', '~> 4.2.1'
         | 
| 27 | 
            +
              spec.add_development_dependency 'transaction_event_store_mongoid', '~> 0.0.1'
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              spec.add_dependency 'activesupport', '>= 3.0'
         | 
| 30 | 
            +
              spec.add_dependency 'transaction_event_store', '~> 0.0.1'
         | 
| 31 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,167 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: snapshot_aggregate_root
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.5.0
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Gareth Andrew
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: exe
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2017-07-26 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: bundler
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - "~>"
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: '1.9'
         | 
| 20 | 
            +
              type: :development
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - "~>"
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: '1.9'
         | 
| 27 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            +
              name: rake
         | 
| 29 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            +
                requirements:
         | 
| 31 | 
            +
                - - "~>"
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            +
                    version: '10.0'
         | 
| 34 | 
            +
              type: :development
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            +
                requirements:
         | 
| 38 | 
            +
                - - "~>"
         | 
| 39 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            +
                    version: '10.0'
         | 
| 41 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            +
              name: pry
         | 
| 43 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 | 
            +
                requirements:
         | 
| 45 | 
            +
                - - ">="
         | 
| 46 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            +
                    version: '0'
         | 
| 48 | 
            +
              type: :development
         | 
| 49 | 
            +
              prerelease: false
         | 
| 50 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 | 
            +
                requirements:
         | 
| 52 | 
            +
                - - ">="
         | 
| 53 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            +
                    version: '0'
         | 
| 55 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 56 | 
            +
              name: rspec
         | 
| 57 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 | 
            +
                requirements:
         | 
| 59 | 
            +
                - - ">="
         | 
| 60 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            +
                    version: '0'
         | 
| 62 | 
            +
              type: :development
         | 
| 63 | 
            +
              prerelease: false
         | 
| 64 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 | 
            +
                requirements:
         | 
| 66 | 
            +
                - - ">="
         | 
| 67 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 68 | 
            +
                    version: '0'
         | 
| 69 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 70 | 
            +
              name: rails
         | 
| 71 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 72 | 
            +
                requirements:
         | 
| 73 | 
            +
                - - "~>"
         | 
| 74 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 75 | 
            +
                    version: 4.2.1
         | 
| 76 | 
            +
              type: :development
         | 
| 77 | 
            +
              prerelease: false
         | 
| 78 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 79 | 
            +
                requirements:
         | 
| 80 | 
            +
                - - "~>"
         | 
| 81 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 82 | 
            +
                    version: 4.2.1
         | 
| 83 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 84 | 
            +
              name: transaction_event_store_mongoid
         | 
| 85 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 86 | 
            +
                requirements:
         | 
| 87 | 
            +
                - - "~>"
         | 
| 88 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 89 | 
            +
                    version: 0.0.1
         | 
| 90 | 
            +
              type: :development
         | 
| 91 | 
            +
              prerelease: false
         | 
| 92 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 93 | 
            +
                requirements:
         | 
| 94 | 
            +
                - - "~>"
         | 
| 95 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 96 | 
            +
                    version: 0.0.1
         | 
| 97 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 98 | 
            +
              name: activesupport
         | 
| 99 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 100 | 
            +
                requirements:
         | 
| 101 | 
            +
                - - ">="
         | 
| 102 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 103 | 
            +
                    version: '3.0'
         | 
| 104 | 
            +
              type: :runtime
         | 
| 105 | 
            +
              prerelease: false
         | 
| 106 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 107 | 
            +
                requirements:
         | 
| 108 | 
            +
                - - ">="
         | 
| 109 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 110 | 
            +
                    version: '3.0'
         | 
| 111 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 112 | 
            +
              name: transaction_event_store
         | 
| 113 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 114 | 
            +
                requirements:
         | 
| 115 | 
            +
                - - "~>"
         | 
| 116 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 117 | 
            +
                    version: 0.0.1
         | 
| 118 | 
            +
              type: :runtime
         | 
| 119 | 
            +
              prerelease: false
         | 
| 120 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 121 | 
            +
                requirements:
         | 
| 122 | 
            +
                - - "~>"
         | 
| 123 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 124 | 
            +
                    version: 0.0.1
         | 
| 125 | 
            +
            description: Event sourced aggregate root implementation with concurrent writer and
         | 
| 126 | 
            +
              snapshot support
         | 
| 127 | 
            +
            email:
         | 
| 128 | 
            +
            - gingerhendrix@gmail.com
         | 
| 129 | 
            +
            executables: []
         | 
| 130 | 
            +
            extensions: []
         | 
| 131 | 
            +
            extra_rdoc_files: []
         | 
| 132 | 
            +
            files:
         | 
| 133 | 
            +
            - ".gitignore"
         | 
| 134 | 
            +
            - Gemfile
         | 
| 135 | 
            +
            - README.md
         | 
| 136 | 
            +
            - Rakefile
         | 
| 137 | 
            +
            - lib/snapshot_aggregate_root.rb
         | 
| 138 | 
            +
            - lib/snapshot_aggregate_root/configuration.rb
         | 
| 139 | 
            +
            - lib/snapshot_aggregate_root/default_apply_strategy.rb
         | 
| 140 | 
            +
            - lib/snapshot_aggregate_root/version.rb
         | 
| 141 | 
            +
            - snapshot_aggregate_root.gemspec
         | 
| 142 | 
            +
            homepage: https://github.com/gingerhendrix/snapshot_aggregate_root
         | 
| 143 | 
            +
            licenses:
         | 
| 144 | 
            +
            - MIT
         | 
| 145 | 
            +
            metadata: {}
         | 
| 146 | 
            +
            post_install_message: 
         | 
| 147 | 
            +
            rdoc_options: []
         | 
| 148 | 
            +
            require_paths:
         | 
| 149 | 
            +
            - lib
         | 
| 150 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 151 | 
            +
              requirements:
         | 
| 152 | 
            +
              - - ">="
         | 
| 153 | 
            +
                - !ruby/object:Gem::Version
         | 
| 154 | 
            +
                  version: '0'
         | 
| 155 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 156 | 
            +
              requirements:
         | 
| 157 | 
            +
              - - ">="
         | 
| 158 | 
            +
                - !ruby/object:Gem::Version
         | 
| 159 | 
            +
                  version: '0'
         | 
| 160 | 
            +
            requirements: []
         | 
| 161 | 
            +
            rubyforge_project: 
         | 
| 162 | 
            +
            rubygems_version: 2.5.1
         | 
| 163 | 
            +
            signing_key: 
         | 
| 164 | 
            +
            specification_version: 4
         | 
| 165 | 
            +
            summary: Event sourced aggregate root implementation with concurrent writer and snapshot
         | 
| 166 | 
            +
              support
         | 
| 167 | 
            +
            test_files: []
         |