ellington 0.0.1 → 0.0.2

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.
@@ -0,0 +1,51 @@
1
+ require_relative "test_helper"
2
+
3
+ class RouteTest < MicroTest::Test
4
+
5
+ before do
6
+ @route = BasicMath.new
7
+ end
8
+
9
+ test "lines on class" do
10
+ assert @route.lines.length == 3
11
+ assert @route.lines[0].is_a?(Addition)
12
+ assert @route.lines[1].is_a?(Division)
13
+ assert @route.lines[2].is_a?(Multiplication)
14
+ end
15
+
16
+ test "type of lines must be unique" do
17
+ begin
18
+ @route.lines << Addition.new
19
+ rescue Ellington::ListAlreadyContainsType => e
20
+ end
21
+ assert !e.nil?
22
+ end
23
+
24
+ test "lines are assigned route" do
25
+ @route.lines.each do |line|
26
+ assert line.route == BasicMath
27
+ end
28
+ end
29
+
30
+ test "goal" do
31
+ goals = @route.goal & [@route.lines[1].goal, @route.lines[2].goal].flatten
32
+ assert @route.goal.length == goals.length
33
+ end
34
+
35
+ test "fail_target" do
36
+ assert !@route.fail_target.empty?
37
+ assert((@route.fail_target & @route.pass_target).empty?)
38
+ expected = (@route.states.keys - @route.pass_target).delete_if do |state|
39
+ state.to_s =~ /\AERROR/
40
+ end
41
+ assert @route.fail_target == expected
42
+ end
43
+
44
+ test "connections" do
45
+ assert @route.connections.first.line == @route.lines[1]
46
+ assert @route.connections.first.states == @route.lines[0].pass_target
47
+ assert @route.connections.last.line == @route.lines[2]
48
+ assert @route.connections.last.states == @route.lines[0].fail_target
49
+ end
50
+
51
+ end
@@ -0,0 +1,115 @@
1
+ require_relative "test_helper"
2
+
3
+ class StationTest < MicroTest::Test
4
+
5
+ before do
6
+ @route = BasicMath.new
7
+ @line = @route.lines.first
8
+ @station = @line.stations.first
9
+ @passenger = Ellington::Passenger.new(NumberWithHistory.new(0), @route)
10
+ @passenger.current_state = @route.initial_state
11
+ @passenger.lock
12
+ end
13
+
14
+ test "name" do
15
+ assert @station.name == "Add10::Addition"
16
+ end
17
+
18
+ test "state_name" do
19
+ assert @station.state_name(:foo) == "FOO Add10::Addition"
20
+ end
21
+
22
+ test "passed" do
23
+ assert @station.passed == "PASS Add10::Addition"
24
+ end
25
+
26
+ test "failed" do
27
+ assert @station.failed == "FAIL Add10::Addition"
28
+ end
29
+
30
+ test "errored" do
31
+ assert @station.errored == "ERROR Add10::Addition"
32
+ end
33
+
34
+ test "states keys" do
35
+ assert @station.states.keys == [
36
+ @station.passed,
37
+ @station.failed,
38
+ @station.errored
39
+ ]
40
+ end
41
+
42
+ test "error state can transition to passed" do
43
+ assert @station.states.can_transition?(@station.errored => @station.passed)
44
+ end
45
+
46
+ test "error state can transition to failed" do
47
+ assert @station.states.can_transition?(@station.errored => @station.failed)
48
+ end
49
+
50
+ test "pass state is terminating" do
51
+ assert @station.states[@station.passed].nil?
52
+ assert !@station.states.can_transition?(@station.passed => @station.failed)
53
+ assert !@station.states.can_transition?(@station.passed => @station.errored)
54
+ end
55
+
56
+ test "fail state is terminating" do
57
+ assert @station.states[@station.failed].nil?
58
+ assert !@station.states.can_transition?(@station.failed => @station.passed)
59
+ assert !@station.states.can_transition?(@station.failed => @station.errored)
60
+ end
61
+
62
+ test "pass properly transitions passenger's state" do
63
+ @passenger.current_state = @route.initial_state
64
+ @station.pass @passenger
65
+ assert @passenger.current_state == @station.passed
66
+ end
67
+
68
+ test "fail properly transitions passenger's state" do
69
+ @passenger.current_state = @route.initial_state
70
+ @station.fail @passenger
71
+ assert @passenger.current_state == @station.failed
72
+ end
73
+
74
+ test "error properly transitions passenger's state" do
75
+ @passenger.current_state = @route.initial_state
76
+ @station.error @passenger
77
+ assert @passenger.current_state == @station.errored
78
+ end
79
+
80
+ test "can_engage? returns true for the expected inital state" do
81
+ @passenger.current_state = @route.initial_state
82
+ assert @station.can_engage?(@passenger)
83
+ end
84
+
85
+ test "can_engage? returns false for unexpected inital states" do
86
+ @passenger.current_state = @line.stations.last.passed
87
+ assert !@station.can_engage?(@passenger)
88
+ @passenger.current_state = :unexpected
89
+ assert !@station.can_engage?(@passenger)
90
+ end
91
+
92
+ test "engage" do
93
+ @passenger.current_state = @route.initial_state
94
+ @station.engage(@passenger, :pass => true)
95
+ assert @passenger.current_state == @station.passed
96
+ end
97
+
98
+ test "observers are notified after a station completes" do
99
+ observer = MicroMock.make.new
100
+ observer.attr :callbacks, []
101
+ observer.def :update do |info|
102
+ callbacks << info
103
+ end
104
+ @station.add_observer observer
105
+ @passenger.current_state = @route.initial_state
106
+ @station.call(@passenger, :pass => true)
107
+ assert observer.callbacks.length == 1
108
+ info = observer.callbacks.first
109
+ assert info.station == @station
110
+ assert info.passenger == @passenger
111
+ assert info.transition.old_state == @route.initial_state
112
+ assert info.transition.new_state == @station.passed
113
+ end
114
+
115
+ end
@@ -0,0 +1,54 @@
1
+ require_relative "test_helper"
2
+
3
+ class TargetTest < MicroTest::Test
4
+
5
+ before do
6
+ @number = NumberWithHistory.new(0)
7
+ end
8
+
9
+ test "basic goal" do
10
+ goal = Ellington::Target.new(:finished)
11
+ assert goal.include?(:finished)
12
+ end
13
+
14
+ test "multiple states" do
15
+ goal = Ellington::Target.new(:one, :two, :three)
16
+ assert goal.include?(:one)
17
+ assert goal.include?(:two)
18
+ assert goal.include?(:three)
19
+ end
20
+
21
+ test "not satisfied for nil passenger" do
22
+ goal = Ellington::Target.new(:finished)
23
+ assert !goal.satisfied?(nil)
24
+ end
25
+
26
+ test "not satisfied for passenger in the wrong state" do
27
+ passenger = Ellington::Passenger.new(@number, Ellington::Ticket.new, StateJacket::Catalog.new)
28
+ passenger.current_state = :open
29
+ goal = Ellington::Target.new(:closed)
30
+ assert !goal.satisfied?(passenger)
31
+ end
32
+
33
+ test "satisfied for passenger in the right state" do
34
+ passenger = Ellington::Passenger.new(@number, Ellington::Ticket.new, StateJacket::Catalog.new)
35
+ passenger.current_state = :closed
36
+ goal = Ellington::Target.new(:closed)
37
+ assert goal.satisfied?(passenger)
38
+ end
39
+
40
+ test "satisfied for passenger in an expected state" do
41
+ passenger = Ellington::Passenger.new(@number, Ellington::Ticket.new, StateJacket::Catalog.new)
42
+ passenger.current_state = :two
43
+ goal = Ellington::Target.new(:one, :two, :three)
44
+ assert goal.satisfied?(passenger)
45
+ end
46
+
47
+ test "not satisfied for passenger not in an expected state" do
48
+ passenger = Ellington::Passenger.new(@number, Ellington::Ticket.new, StateJacket::Catalog.new)
49
+ passenger.current_state = :four
50
+ goal = Ellington::Target.new(:one, :two, :three)
51
+ assert !goal.satisfied?(passenger)
52
+ end
53
+
54
+ end
@@ -0,0 +1,6 @@
1
+ require "logger"
2
+ require "delegate"
3
+ require 'pry-exception_explorer'
4
+ require_relative "../lib/ellington"
5
+ require_relative "example"
6
+
@@ -0,0 +1,39 @@
1
+ require_relative "test_helper"
2
+ require "digest"
3
+
4
+ class TicketTest < MicroTest::Test
5
+
6
+ before do
7
+ @route = BasicMath.new
8
+ @ticket = Ellington::Ticket.new(Ellington::Target.new(:closed),
9
+ :user_id => "458e9710-c1c4-495b-b25a-c622e893f6f7",
10
+ :debit_id => "b834fb69-2eb3-4e57-b313-16b863e91f74",
11
+ :credit_id => "9a670fce-4826-4a90-aaf7-a58738a4ce5b"
12
+ )
13
+ @passenger = Ellington::Passenger.new(0, @route, @ticket)
14
+ end
15
+
16
+ test "basic ticket" do
17
+ assert @ticket[:user_id] == "458e9710-c1c4-495b-b25a-c622e893f6f7"
18
+ assert @ticket[:debit_id] == "b834fb69-2eb3-4e57-b313-16b863e91f74"
19
+ assert @ticket[:credit_id] == "9a670fce-4826-4a90-aaf7-a58738a4ce5b"
20
+ end
21
+
22
+ test "ticket id" do
23
+ assert @ticket.id == Digest::SHA256.hexdigest(@ticket.values.map(&:to_s).join)
24
+ end
25
+
26
+ test "goal" do
27
+ assert @ticket.goal.to_a == [:closed]
28
+ end
29
+
30
+ test "goal is not achieved when passenger is not in the correct state" do
31
+ assert !@ticket.goal.satisfied?(@passenger)
32
+ end
33
+
34
+ test "goal is achieved when passenger is in the correct state" do
35
+ @passenger.current_state = :closed
36
+ assert @ticket.goal.satisfied?(@passenger)
37
+ end
38
+
39
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ellington
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,24 +9,92 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-16 00:00:00.000000000 Z
13
- dependencies: []
14
- description: Write a gem description
12
+ date: 2013-02-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: hero
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.1.7
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.1.7
30
+ - !ruby/object:Gem::Dependency
31
+ name: state_jacket
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.0.7
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.0.7
46
+ description: ! "\n Ellington is a collection of simple concepts designed to bring
47
+ discipline, organization, and modularity to a project.\n\n The nomenclature is
48
+ taken from New York's subway system.\n We've found that using cohesive physical
49
+ metaphors helps people reason more clearly about the complexities of software.\n
50
+ \ The subway analogy isn't perfect but gets pretty close.\n\n The Ellington
51
+ architecture should only be applied after a good understanding of the problem domain
52
+ has been established.\n We recommend spiking a solution to learn your project's
53
+ requirements and then coming back to Ellington.\n "
15
54
  email:
16
55
  - natehop@gmail.com
17
56
  executables: []
18
57
  extensions: []
19
58
  extra_rdoc_files: []
20
59
  files:
21
- - .gitignore
60
+ - lib/ellington/attendant.rb
61
+ - lib/ellington/conductor.rb
62
+ - lib/ellington/connection.rb
63
+ - lib/ellington/connection_list.rb
64
+ - lib/ellington/errros.rb
65
+ - lib/ellington/has_targets.rb
66
+ - lib/ellington/line.rb
67
+ - lib/ellington/line_info.rb
68
+ - lib/ellington/line_list.rb
69
+ - lib/ellington/logger.rb
70
+ - lib/ellington/passenger.rb
71
+ - lib/ellington/route.rb
72
+ - lib/ellington/route_info.rb
73
+ - lib/ellington/station.rb
74
+ - lib/ellington/station_info.rb
75
+ - lib/ellington/station_list.rb
76
+ - lib/ellington/target.rb
77
+ - lib/ellington/ticket.rb
78
+ - lib/ellington/transition_info.rb
79
+ - lib/ellington/unique_type_array.rb
80
+ - lib/ellington/version.rb
81
+ - lib/ellington.rb
22
82
  - Gemfile
83
+ - Gemfile.lock
23
84
  - LICENSE.txt
24
- - README.md
25
85
  - Rakefile
26
- - ellington.gemspec
27
- - lib/ellington.rb
28
- - lib/ellington/version.rb
29
- homepage: ''
86
+ - README.md
87
+ - test/attendant_test.rb
88
+ - test/conductor_test.rb
89
+ - test/example.rb
90
+ - test/line_test.rb
91
+ - test/passenger_test.rb
92
+ - test/route_test.rb
93
+ - test/station_test.rb
94
+ - test/target_test.rb
95
+ - test/test_helper.rb
96
+ - test/ticket_test.rb
97
+ homepage: https://github.com/hopsoft/ellington
30
98
  licenses: []
31
99
  post_install_message:
32
100
  rdoc_options: []
@@ -46,9 +114,19 @@ required_rubygems_version: !ruby/object:Gem::Requirement
46
114
  version: '0'
47
115
  requirements: []
48
116
  rubyforge_project:
49
- rubygems_version: 1.8.23
117
+ rubygems_version: 1.8.25
50
118
  signing_key:
51
119
  specification_version: 3
52
- summary: Write a gem summary
53
- test_files: []
54
- has_rdoc:
120
+ summary: A framework for moving stateful objects through a complex series of business
121
+ rules.
122
+ test_files:
123
+ - test/attendant_test.rb
124
+ - test/conductor_test.rb
125
+ - test/example.rb
126
+ - test/line_test.rb
127
+ - test/passenger_test.rb
128
+ - test/route_test.rb
129
+ - test/station_test.rb
130
+ - test/target_test.rb
131
+ - test/test_helper.rb
132
+ - test/ticket_test.rb
data/.gitignore DELETED
@@ -1,17 +0,0 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .yardoc
6
- Gemfile.lock
7
- InstalledFiles
8
- _yardoc
9
- coverage
10
- doc/
11
- lib/bundler/man
12
- pkg
13
- rdoc
14
- spec/reports
15
- test/tmp
16
- test/version_tmp
17
- tmp
data/ellington.gemspec DELETED
@@ -1,19 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'ellington/version'
5
-
6
- Gem::Specification.new do |gem|
7
- gem.name = "ellington"
8
- gem.version = Ellington::VERSION
9
- gem.authors = ["Nathan Hopkins"]
10
- gem.email = ["natehop@gmail.com"]
11
- gem.description = %q{Write a gem description}
12
- gem.summary = %q{Write a gem summary}
13
- gem.homepage = ""
14
-
15
- gem.files = `git ls-files`.split($/)
16
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
- gem.require_paths = ["lib"]
19
- end