euston-projections 1.0.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.
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,161 @@
1
+ require 'date'
2
+ require 'rspec/core/rake_task'
3
+
4
+ #############################################################################
5
+ #
6
+ # Helper functions
7
+ #
8
+ #############################################################################
9
+
10
+ def name
11
+ @name ||= Dir['*.gemspec'].first.split('.').first
12
+ end
13
+
14
+ def version
15
+ line = File.read("lib/#{name}/version.rb")[/^\s*VERSION\s*=\s*.*/]
16
+ line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
17
+ end
18
+
19
+ def date
20
+ Date.today.to_s
21
+ end
22
+
23
+ def rubyforge_project
24
+ name
25
+ end
26
+
27
+ def gemspec_file
28
+ "#{name}.gemspec"
29
+ end
30
+
31
+ def gem_file
32
+ "#{name}-#{version}.gem"
33
+ end
34
+
35
+ def replace_header(head, header_name, provider = nil)
36
+ if provider
37
+ value = send(provider)
38
+ else
39
+ value = "'#{send(header_name)}'"
40
+ end
41
+
42
+ provider ||= header_name
43
+ head.sub!(/(\.#{header_name}\s*= ).*/) { "#{$1}#{value}"}
44
+ end
45
+
46
+ def platform
47
+ jruby? ? '-java' : ''
48
+ end
49
+
50
+ def platform_dependant_gem_file
51
+ "#{name}-#{version}#{platform}.gem"
52
+ end
53
+
54
+ def platform_dependent_version
55
+ "'#{version}#{platform}'"
56
+ end
57
+
58
+ def jruby?
59
+ RUBY_PLATFORM.to_s == 'java'
60
+ end
61
+
62
+ def trim_array_ends array
63
+ array.shift
64
+ array.pop
65
+ array
66
+ end
67
+
68
+ #############################################################################
69
+ #
70
+ # Custom tasks
71
+ #
72
+ #############################################################################
73
+
74
+ default_rspec_opts = %w[--colour --format Fuubar]
75
+
76
+ desc "Run all examples"
77
+ RSpec::Core::RakeTask.new(:spec) do |t|
78
+ t.rspec_opts = default_rspec_opts
79
+ end
80
+
81
+ #############################################################################
82
+ #
83
+ # Packaging tasks
84
+ #
85
+ #############################################################################
86
+
87
+ def built_gem
88
+ @built_gem ||= Dir["#{name}*.gem"].first
89
+ end
90
+
91
+ desc "Create tag v#{platform_dependent_version} and build and push #{platform_dependant_gem_file} to Rubygems"
92
+ task :release => :build do
93
+ unless `git branch` =~ /^\* master$/
94
+ puts "You must be on the master branch to release!"
95
+ exit!
96
+ end
97
+
98
+ sh "git commit --allow-empty -a -m 'Release #{platform_dependent_version}'"
99
+ sh "git tag v#{platform_dependent_version}"
100
+ sh "git push origin master"
101
+ sh "git push origin v#{platform_dependent_version}"
102
+
103
+ command = "gem push pkg/#{platform_dependant_gem_file}"
104
+
105
+ if jruby?
106
+ puts "--------------------------------------------------------------------------------------"
107
+ puts "can't push to rubygems using jruby at the moment, so switch to mri and run: #{command}"
108
+ puts "--------------------------------------------------------------------------------------"
109
+ else
110
+ sh command
111
+ end
112
+ end
113
+
114
+ desc "Build #{platform_dependant_gem_file} into the pkg directory"
115
+ task :build => :gemspec do
116
+ sh "mkdir -p pkg"
117
+ sh "gem build #{gemspec_file}"
118
+ sh "mv #{built_gem} pkg"
119
+ end
120
+
121
+ desc "Generate #{gemspec_file}"
122
+ task :gemspec => :validate do
123
+ # read spec file and split out manifest section
124
+ spec = File.read(gemspec_file)
125
+ head, manifest, tail = spec.split(" # = MANIFEST =\n")
126
+
127
+ # replace name version and date
128
+ replace_header(head, :name)
129
+ replace_header(head, :version)
130
+ replace_header(head, :date)
131
+ #comment this out if your rubyforge_project has a different name
132
+ #replace_header(head, :rubyforge_project)
133
+
134
+ # determine file list from git ls-files
135
+ files = `git ls-files`.
136
+ split("\n").
137
+ sort.
138
+ reject { |file| file =~ /^\./ }.
139
+ reject { |file| file =~ /^(rdoc|pkg)/ }.
140
+ map { |file| " #{file}" }.
141
+ join("\n")
142
+
143
+ # piece file back together and write
144
+ manifest = " s.files = %w[\n#{files}\n ]\n"
145
+ spec = [head, manifest, tail].join(" # = MANIFEST =\n")
146
+ File.open(gemspec_file, 'w') { |io| io.write(spec) }
147
+ puts "Updated #{gemspec_file}"
148
+ end
149
+
150
+ desc "Validate #{gemspec_file}"
151
+ task :validate do
152
+ libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
153
+ unless libfiles.empty?
154
+ puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
155
+ exit!
156
+ end
157
+ unless Dir['VERSION*'].empty?
158
+ puts "A `VERSION` file at root level violates Gem best practices."
159
+ exit!
160
+ end
161
+ end
@@ -0,0 +1,34 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'euston-projections'
3
+ s.version = '1.0.0'
4
+ s.platform = RUBY_PLATFORM.to_s == 'java' ? 'java' : Gem::Platform::RUBY
5
+ s.authors = ['Lee Henson', 'Guy Boertje']
6
+ s.email = ['lee.m.henson@gmail.com', 'guyboertje@gmail.com']
7
+ s.summary = %q{Default projection classes for Euston.}
8
+ s.description = ""
9
+ s.homepage = 'http://github.com/leemhenson/euston-projections'
10
+
11
+ # = MANIFEST =
12
+ s.files = %w[
13
+ Gemfile
14
+ Rakefile
15
+ euston-projections.gemspec
16
+ lib/euston-projections.rb
17
+ lib/euston-projections/idempotence.rb
18
+ lib/euston-projections/mongo_projection.rb
19
+ lib/euston-projections/mongo_projection_event_handler.rb
20
+ lib/euston-projections/version.rb
21
+ ]
22
+ # = MANIFEST =
23
+
24
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
+
27
+ s.add_dependency 'activesupport', '~> 3.0.10'
28
+ s.add_dependency 'euston-eventstore', '~> 1.2.0'
29
+ s.add_dependency 'mongoid', '~> 2.1.0'
30
+
31
+ s.add_development_dependency 'awesome_print', '~> 0.4.0'
32
+ s.add_development_dependency 'fuubar', '~> 0.0.0'
33
+ s.add_development_dependency 'rspec', '~> 2.6.0'
34
+ end
@@ -0,0 +1,5 @@
1
+ require 'mongoid'
2
+
3
+ require 'euston-projections/idempotence'
4
+ require 'euston-projections/mongo_projection'
5
+ require 'euston-projections/mongo_projection_event_handler'
@@ -0,0 +1,39 @@
1
+ module Euston
2
+ module Projections
3
+ module Idempotence
4
+ extend ActiveSupport::Concern
5
+
6
+ module InstanceMethods
7
+ def if_unhandled obj, headers
8
+ return if obj.already_processed_message? headers.id
9
+
10
+ obj.add_to_history headers.id
11
+
12
+ unless headers.source_message.nil? || obj.already_processed_message?(headers.source_message[:headers][:id])
13
+ obj.add_to_history headers.source_message[:headers][:id]
14
+ end
15
+
16
+ yield
17
+ end
18
+
19
+ def if_unhandled_or_new document_type, id, headers
20
+ document = document_type.find(id) || document_type.new(_id: id)
21
+
22
+ if_unhandled document, headers do
23
+ yield document
24
+ end
25
+ end
26
+
27
+ def if_exists_and_unhandled document_type, id, headers
28
+ document = document_type.find id
29
+
30
+ raise ArgumentError, "Expected to find a #{document_type} with id #{id}, but none exists." if document.nil?
31
+
32
+ if_unhandled document, headers do
33
+ yield document
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,28 @@
1
+ module Euston
2
+ module Projections
3
+ module MongoProjection
4
+ extend ActiveSupport::Concern
5
+ include Mongoid::Document
6
+
7
+ included do
8
+ field :_history, :type => Hash, :default => {}
9
+ end
10
+
11
+ def add_to_history message_id
12
+ _history[message_id] = Time.now.to_f unless already_processed_message? message_id
13
+ end
14
+
15
+ def already_processed_message? message_id
16
+ _history.has_key? message_id
17
+ end
18
+
19
+ def processed_message_ids
20
+ _history.keys
21
+ end
22
+
23
+ def prune_history_older_than time
24
+ _history.reject! { |id, timestamp| timestamp < time }
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,21 @@
1
+ module Euston
2
+ module Projections
3
+ module MongoProjectionEventHandler
4
+ extend ActiveSupport::Concern
5
+
6
+ include EventHandler
7
+ include Idempotence
8
+ include EventStore::Persistence::Mongodb::MongoConcurrencyDetection
9
+
10
+ module ClassMethods
11
+ def concurrent_subscribes *args, &consumer
12
+ subscribes *args do |*block_args|
13
+ detect_mongo_concurrency do
14
+ instance_exec *block_args, &consumer
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ module Euston
2
+ module Projections
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: euston-projections
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Lee Henson
9
+ - Guy Boertje
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2011-10-13 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activesupport
17
+ requirement: &83034820 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: 3.0.10
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *83034820
26
+ - !ruby/object:Gem::Dependency
27
+ name: euston-eventstore
28
+ requirement: &83032120 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 1.2.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: *83032120
37
+ - !ruby/object:Gem::Dependency
38
+ name: mongoid
39
+ requirement: &83030940 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: 2.1.0
45
+ type: :runtime
46
+ prerelease: false
47
+ version_requirements: *83030940
48
+ - !ruby/object:Gem::Dependency
49
+ name: awesome_print
50
+ requirement: &83029740 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: 0.4.0
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: *83029740
59
+ - !ruby/object:Gem::Dependency
60
+ name: fuubar
61
+ requirement: &83028500 !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ~>
65
+ - !ruby/object:Gem::Version
66
+ version: 0.0.0
67
+ type: :development
68
+ prerelease: false
69
+ version_requirements: *83028500
70
+ - !ruby/object:Gem::Dependency
71
+ name: rspec
72
+ requirement: &83027570 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 2.6.0
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: *83027570
81
+ description: ''
82
+ email:
83
+ - lee.m.henson@gmail.com
84
+ - guyboertje@gmail.com
85
+ executables: []
86
+ extensions: []
87
+ extra_rdoc_files: []
88
+ files:
89
+ - Gemfile
90
+ - Rakefile
91
+ - euston-projections.gemspec
92
+ - lib/euston-projections.rb
93
+ - lib/euston-projections/idempotence.rb
94
+ - lib/euston-projections/mongo_projection.rb
95
+ - lib/euston-projections/mongo_projection_event_handler.rb
96
+ - lib/euston-projections/version.rb
97
+ homepage: http://github.com/leemhenson/euston-projections
98
+ licenses: []
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ! '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ! '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubyforge_project:
117
+ rubygems_version: 1.8.10
118
+ signing_key:
119
+ specification_version: 3
120
+ summary: Default projection classes for Euston.
121
+ test_files: []