metacosm 0.1.3 → 0.1.4

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
  SHA1:
3
- metadata.gz: c77a542532dce2178b3a6e3c879924724ab83eab
4
- data.tar.gz: 1df7e65cbec1a351789896f8814340c7d0b2ba6f
3
+ metadata.gz: 052e0d6b334fd7502342b5facd9cc6925a466df1
4
+ data.tar.gz: e00f5d01027be65e8f91ff04c8b48665d664eeea
5
5
  SHA512:
6
- metadata.gz: f526c542c046c94a6768a32e9cdd4b4003fe1809dd124978919d781bb6d1f2c17127b34a6c6dda5900f2e6b01127aaef1a6d8b0dc9edbb58aee399502048bc4b
7
- data.tar.gz: efec11ddcc904437cabe20fee6c4f385ff2d197d2d46e648b6853930945ac47582a119de6d89ce47b698e0b06f2036942b0f4f99a0b6ba3148ed181240fb0ac8
6
+ metadata.gz: 4087a92a6eee8aa00cfb280ac6dd2cdba64bdef2b1fda60e29ae5c31d26ebff3a9b2a66c8bcd3c21e3bd5f4b7214c6c3ef2b2007ef897c36ff3710b5cfff5dd2
7
+ data.tar.gz: b008d3c6409925ad9f1d601079dd2805b42fd5709b0245a512e1c183d194f8a8032d5407a465592f909e19359512c2734006efbcd26b3953d5f9a65db7fc8f21
data/README.md CHANGED
@@ -50,16 +50,16 @@ A Fizzbuzz implementation contrived enough to show off many of the features of t
50
50
 
51
51
  protected
52
52
  def fizz
53
- FizzEvent.create(value: @counter, counter_id: @id)
53
+ FizzEvent.create
54
54
  end
55
55
 
56
56
  def buzz
57
- BuzzEvent.create(value: @counter, counter_id: @id)
57
+ BuzzEvent.create
58
58
  end
59
59
 
60
60
  def counter_incremented
61
61
  CounterIncrementedEvent.create(
62
- value: @counter,
62
+ value: @counter,
63
63
  counter_id: @id
64
64
  )
65
65
  end
@@ -73,13 +73,14 @@ A Fizzbuzz implementation contrived enough to show off many of the features of t
73
73
  end
74
74
  end
75
75
 
76
- class IncrementCounterCommand < Struct.new(:increment, :counter_id)
76
+ class IncrementCounterCommand < Command
77
+ attr_accessor :increment, :counter_id
77
78
  end
78
79
 
79
80
  class IncrementCounterCommandHandler
80
- def handle(command)
81
- counter = Counter.find_by(command.counter_id)
82
- counter.increment!(command.increment)
81
+ def handle(increment:,counter_id:)
82
+ counter = Counter.find(counter_id)
83
+ counter.increment!(increment)
83
84
  end
84
85
  end
85
86
 
@@ -97,61 +98,89 @@ A Fizzbuzz implementation contrived enough to show off many of the features of t
97
98
 
98
99
  def update_counter_view(counter_id, value)
99
100
  counter_view = CounterView.where(counter_id: counter_id).first_or_create
100
- counter_view.value = value
101
+ counter_view.update value: value
101
102
  end
102
103
 
103
104
  private
104
105
  def fizz_buzz!(counter_id, n)
105
- fire(FizzCommand.new(counter_id, n)) if fizz?(n)
106
- fire(BuzzCommand.new(counter_id, n)) if buzz?(n)
106
+ fire(FizzCommand.create(counter_id: counter_id)) if fizz?(n)
107
+ fire(BuzzCommand.create(counter_id: counter_id)) if buzz?(n)
107
108
  end
108
109
 
109
110
  def fizz?(n); n % 3 == 0 end
110
111
  def buzz?(n); n % 5 == 0 end
111
112
  end
112
113
 
113
- class FizzCommand < Struct.new(:counter_id, :value); end
114
+ class FizzCommand < Command
115
+ attr_accessor :counter_id
116
+ end
117
+
114
118
  class FizzCommandHandler
115
- def handle(command)
116
- counter = Counter.find_by(command.counter_id)
119
+ def handle(counter_id:)
120
+ counter = Counter.find(counter_id)
117
121
  counter.fizz!
118
122
  end
119
123
  end
120
124
 
121
- class BuzzCommand < Struct.new(:counter_id, :value); end
125
+ class BuzzCommand < Command
126
+ attr_accessor :counter_id
127
+ end
128
+
122
129
  class BuzzCommandHandler
123
- def handle(command)
124
- counter = Counter.find_by(command.counter_id)
130
+ def handle(counter_id:)
131
+ counter = Counter.find(counter_id)
125
132
  counter.buzz!
126
133
  end
127
134
  end
128
135
 
129
136
  class FizzEvent < Event
130
- attr_accessor :value, :counter_id
131
137
  end
132
138
 
133
139
  class FizzEventListener < EventListener
134
- def receive(event)
140
+ def receive
135
141
  puts "fizz"
136
142
  end
137
143
  end
138
144
 
139
145
  class BuzzEvent < Event
140
- attr_accessor :value, :counter_id
141
146
  end
142
147
 
143
148
  class BuzzEventListener < EventListener
144
- def receive(event)
149
+ def receive
145
150
  puts "buzz"
146
151
  end
147
152
  end
153
+ ````
154
+
155
+ Given all this prelude we can run a fizzbuzz "simulation":
156
+
157
+ ````ruby
158
+ sim = Simulation.current
159
+ counter_model = Counter.create
160
+ counter_view = CounterView.find_by(counter_id: counter_model.id)
148
161
 
149
- class CounterValueQuery
150
- def execute(counter_id:)
151
- counter = CounterView.find_by(counter_id: counter_id)
152
- counter.value
153
- end
154
- end
162
+ counter_view.value # => 0
163
+
164
+ increment_counter_command = IncrementCounterCommand.create(
165
+ increment: 1, counter_id: counter_model.id
166
+ )
167
+
168
+ sim.apply(increment_counter_command)
169
+
170
+ counter_view.value # => 1
171
+
172
+ 100.times { sim.apply(increment_counter_command) }
173
+
174
+ sim.events.take(10)
175
+ # => [CounterCreatedEvent (id: 1, counter_id: 1),
176
+ # CounterIncrementedEvent (id: 1, value: 1, counter_id: 1),
177
+ # CounterIncrementedEvent (id: 2, value: 2, counter_id: 1),
178
+ # CounterIncrementedEvent (id: 3, value: 3, counter_id: 1),
179
+ # FizzEvent (id: 1),
180
+ # CounterIncrementedEvent (id: 4, value: 4, counter_id: 1),
181
+ # CounterIncrementedEvent (id: 5, value: 5, counter_id: 1),
182
+ # BuzzEvent (id: 1),
183
+ # CounterIncrementedEvent (id: 6, value: 6, counter_id: 1)]
155
184
  ````
156
185
 
157
186
  ## Requirements
data/gemspec.yml CHANGED
@@ -6,8 +6,8 @@ authors: Joseph Weissman
6
6
  email: jweissman1986@gmail.com
7
7
  homepage: https://rubygems.org/gems/metacosm
8
8
  dependencies:
9
- passive_record: ~> 0.2
10
- frappuccino: ~> 0.3
9
+ passive_record: ~> 0.3
10
+ frappuccino: ~> 0.3
11
11
  development_dependencies:
12
12
  bundler: ~> 1.10
13
13
  codeclimate-test-reporter: ~> 0.1
data/lib/metacosm.rb CHANGED
@@ -6,16 +6,9 @@ module Metacosm
6
6
  class Model
7
7
  include PassiveRecord
8
8
  after_create :register_observer, :emit_creation_event
9
+ after_update :emit_updation_event
9
10
 
10
- def update(attrs={})
11
- attrs.each do |k,v|
12
- send("#{k}=",v)
13
- end
14
-
15
- emit(updation_event(attrs)) if updated_event_class
16
- end
17
-
18
- protected
11
+ private
19
12
  def register_observer
20
13
  Simulation.current.watch(self)
21
14
  end
@@ -24,6 +17,10 @@ module Metacosm
24
17
  emit(creation_event) if created_event_class
25
18
  end
26
19
 
20
+ def emit_updation_event
21
+ emit(updation_event) if updated_event_class
22
+ end
23
+
27
24
  def attributes_with_external_id
28
25
  attrs = to_h
29
26
  if attrs.key?(:id)
@@ -34,7 +31,7 @@ module Metacosm
34
31
  end
35
32
 
36
33
  # trim down extenralized attrs for evt
37
- def attributes_for_event(klass, additional_attrs={})
34
+ def attributes_for_event(klass)
38
35
  # assume evts attrs are attr_accessible?
39
36
  keys_to_keep = klass.instance_methods.find_all do |method|
40
37
  method != :== &&
@@ -43,8 +40,7 @@ module Metacosm
43
40
  end
44
41
 
45
42
  attributes_with_external_id.
46
- delete_if {|k,v| !keys_to_keep.include?(k) }.
47
- merge(additional_attrs)
43
+ delete_if {|k,v| !keys_to_keep.include?(k) }
48
44
  end
49
45
 
50
46
  def assemble_event(klass, addl_attrs={})
@@ -52,7 +48,11 @@ module Metacosm
52
48
  end
53
49
 
54
50
  def creation_event
55
- assemble_event(created_event_class)
51
+ assemble_event created_event_class
52
+ end
53
+
54
+ def updation_event
55
+ assemble_event updated_event_class
56
56
  end
57
57
 
58
58
  def created_event_class
@@ -60,10 +60,6 @@ module Metacosm
60
60
  Object.const_get(created_event_name) rescue nil
61
61
  end
62
62
 
63
- def updation_event(changed_attrs={})
64
- assemble_event(updated_event_class, changed_attrs)
65
- end
66
-
67
63
  def updated_event_class
68
64
  updated_event_name = self.class.name + "UpdatedEvent"
69
65
  Object.const_get(updated_event_name) rescue nil
@@ -0,0 +1,104 @@
1
+ module Metacosm
2
+ module TestHarness
3
+ class GivenWhenThen < Struct.new(:given_events,:when_command,:then_event_class)
4
+ include RSpec::Matchers
5
+
6
+ def when(*commands)
7
+ @when_commands ||= []
8
+ commands.each do |command|
9
+ @when_commands.push command
10
+ end
11
+ self
12
+ end
13
+
14
+ def expect_events(evts)
15
+ @then_events = evts
16
+ verify!
17
+ self
18
+ end
19
+
20
+ def expect_query(query, to_find:)
21
+ @query = query
22
+ @expected_query_results = to_find
23
+ verify!
24
+ self
25
+ end
26
+
27
+ protected
28
+
29
+ def verify!
30
+ clean_slate!
31
+ receive_events!
32
+ fire_commands!
33
+
34
+ validate_events!
35
+ validate_query!
36
+
37
+ self
38
+ end
39
+
40
+ private
41
+
42
+ def clean_slate!
43
+ PassiveRecord.drop_all
44
+ Simulation.current.clear!
45
+ self
46
+ end
47
+
48
+ def receive_events!
49
+ unless self.given_events.nil?
50
+ self.given_events.each do |evt|
51
+ sim.receive(evt, record: false)
52
+ end
53
+ end
54
+ self
55
+ end
56
+
57
+ def fire_commands!
58
+ unless @when_commands.nil?
59
+ @when_commands.each do |cmd|
60
+ sim.apply(cmd)
61
+ end
62
+ end
63
+ self
64
+ end
65
+
66
+ def validate_events!
67
+ if @then_event_class
68
+ expect(@then_event_class).to eq(sim.events.last.class)
69
+ end
70
+
71
+ if @then_events
72
+ expect(@then_events).to match_array(sim.events)
73
+ end
74
+
75
+ if @then_event_attrs
76
+ @then_event_attrs.each do |k,v|
77
+ expect(sim.events.last.send(k)).to eq(v)
78
+ end
79
+ end
80
+
81
+ self
82
+ end
83
+
84
+ def validate_query!
85
+ if @query
86
+ expect(@query.execute).to eq(@expected_query_results)
87
+ end
88
+ self
89
+ end
90
+
91
+ def sim
92
+ @sim ||= Simulation.current
93
+ end
94
+ end
95
+
96
+ def given_no_activity
97
+ GivenWhenThen.new
98
+ end
99
+
100
+ def given_events(events)
101
+ GivenWhenThen.new(events)
102
+ end
103
+ end
104
+ end
@@ -1,4 +1,4 @@
1
1
  module Metacosm
2
2
  # metacosm version
3
- VERSION = "0.1.3"
3
+ VERSION = "0.1.4"
4
4
  end
@@ -12,6 +12,37 @@ describe "a simple simulation (fizzbuzz)" do
12
12
  )
13
13
  end
14
14
 
15
+ it 'should run the linearized test for the README' do
16
+ sim = Simulation.current
17
+ counter_model = Counter.create
18
+ counter_view = CounterView.find_by(counter_id: counter_model.id)
19
+
20
+ expect(counter_view.value).to eq(0) # => 0
21
+
22
+ increment_counter_command = IncrementCounterCommand.create(
23
+ increment: 1, counter_id: counter_model.id
24
+ )
25
+
26
+ sim.apply(increment_counter_command)
27
+
28
+ # model is updated which triggers view changes
29
+ expect(counter_view.value).to eq(1) # => 1
30
+
31
+ 100.times { sim.apply(increment_counter_command) }
32
+
33
+ expect(sim.events.take(10).map(&:class)).to eq(
34
+ [CounterCreatedEvent,
35
+ CounterCreatedEvent,
36
+ CounterIncrementedEvent,
37
+ CounterIncrementedEvent,
38
+ CounterIncrementedEvent,
39
+ FizzEvent,
40
+ CounterIncrementedEvent,
41
+ CounterIncrementedEvent,
42
+ BuzzEvent,
43
+ CounterIncrementedEvent])
44
+ end
45
+
15
46
  context "one command once" do
16
47
  before { simulation.apply(increment_counter) }
17
48
 
data/spec/spec_helper.rb CHANGED
@@ -4,117 +4,13 @@ require 'rspec/its'
4
4
  require 'pry'
5
5
  require 'ostruct'
6
6
  require 'metacosm'
7
+ require 'metacosm/support/test_harness'
7
8
 
8
9
  include Metacosm
9
10
 
10
11
  require 'support/fizz_buzz'
11
12
  require 'support/village'
12
13
 
13
- class GivenWhenThen < Struct.new(:given_events,:when_command,:then_event_class)
14
- include RSpec::Matchers
15
-
16
- def when(*commands)
17
- @when_commands ||= []
18
- commands.each do |command|
19
- @when_commands.push command
20
- end
21
- self
22
- end
23
-
24
- def expect_events(evts)
25
- @then_events = evts
26
- verify!
27
- self
28
- end
29
-
30
- def expect_query(query, to_find:)
31
- @query = query
32
- @expected_query_results = to_find
33
- verify!
34
- self
35
- end
36
-
37
- protected
38
-
39
- def verify!
40
- clean_slate!
41
- receive_events!
42
- fire_commands!
43
-
44
- validate_events!
45
- validate_query!
46
-
47
- self
48
- end
49
-
50
- private
51
-
52
- def clean_slate!
53
- PassiveRecord.drop_all
54
- Simulation.current.clear!
55
- self
56
- end
57
-
58
- def receive_events!
59
- unless self.given_events.nil?
60
- self.given_events.each do |evt|
61
- sim.receive(evt, record: false)
62
- end
63
- end
64
- self
65
- end
66
-
67
- def fire_commands!
68
- unless @when_commands.nil?
69
- @when_commands.each do |cmd|
70
- sim.apply(cmd)
71
- end
72
- end
73
- self
74
- end
75
-
76
- def validate_events!
77
- if @then_event_class
78
- expect(@then_event_class).to eq(sim.events.last.class)
79
- end
80
-
81
- if @then_events
82
- expect(@then_events).to match_array(sim.events)
83
- end
84
-
85
- if @then_event_attrs
86
- @then_event_attrs.each do |k,v|
87
- expect(sim.events.last.send(k)).to eq(v)
88
- end
89
- end
90
-
91
- self
92
- end
93
-
94
- def validate_query!
95
- if @query
96
- expect(@query.execute).to eq(@expected_query_results)
97
- end
98
- self
99
- end
100
-
101
- def sim
102
- @sim ||= Simulation.current
103
- end
104
- end
105
-
106
- module Metacosm
107
- module SpecHelpers
108
- def given_no_activity
109
- GivenWhenThen.new
110
- end
111
-
112
- def given_events(events)
113
- GivenWhenThen.new(events)
114
- end
115
- end
116
- end
117
-
118
14
  RSpec.configure do |c|
119
- c.include Metacosm::SpecHelpers
15
+ c.include Metacosm::TestHarness
120
16
  end
@@ -36,9 +36,15 @@ end
36
36
 
37
37
  class CounterView < View
38
38
  attr_accessor :value, :counter_id
39
- def update_value(new_value)
40
- @value = new_value
41
- self
39
+ end
40
+
41
+ class CounterCreatedEvent < Event
42
+ attr_accessor :counter_id #, :value
43
+ end
44
+
45
+ class CounterCreatedEventListener < EventListener
46
+ def receive(counter_id:)
47
+ CounterView.create(counter_id: counter_id, value: 0)
42
48
  end
43
49
  end
44
50
 
@@ -67,7 +73,7 @@ class CounterIncrementedEventListener < EventListener
67
73
 
68
74
  def update_counter_view(counter_id, value)
69
75
  counter_view = CounterView.where(counter_id: counter_id).first_or_create
70
- counter_view.value = value
76
+ counter_view.update value: value
71
77
  end
72
78
 
73
79
  private
@@ -102,8 +108,7 @@ class BuzzCommandHandler
102
108
  end
103
109
  end
104
110
 
105
- class FizzEvent < Event
106
- end
111
+ class FizzEvent < Event; end
107
112
 
108
113
  class FizzEventListener < EventListener
109
114
  def receive
@@ -111,8 +116,7 @@ class FizzEventListener < EventListener
111
116
  end
112
117
  end
113
118
 
114
- class BuzzEvent < Event
115
- end
119
+ class BuzzEvent < Event; end
116
120
 
117
121
  class BuzzEventListener < EventListener
118
122
  def receive
@@ -80,7 +80,6 @@ class VillageUpdatedEventListener < EventListener
80
80
  end
81
81
  end
82
82
 
83
-
84
83
  class CreatePersonCommand < Command
85
84
  attr_accessor :world_id, :village_id, :person_id, :person_name
86
85
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metacosm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joseph Weissman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-23 00:00:00.000000000 Z
11
+ date: 2016-02-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: passive_record
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.2'
19
+ version: '0.3'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.2'
26
+ version: '0.3'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: frappuccino
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -162,6 +162,7 @@ files:
162
162
  - features/step_definitions/metacosm_steps.rb
163
163
  - gemspec.yml
164
164
  - lib/metacosm.rb
165
+ - lib/metacosm/support/test_harness.rb
165
166
  - lib/metacosm/version.rb
166
167
  - metacosm.gemspec
167
168
  - schema.png