fast-tcpn 0.0.5

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 (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +40 -0
  6. data/LICENSE.txt +674 -0
  7. data/README.md +453 -0
  8. data/fast-tcpn.gemspec +40 -0
  9. data/fast-tcpn.rb +192 -0
  10. data/lib/fast-tcpn.rb +25 -0
  11. data/lib/fast-tcpn/clone.rb +7 -0
  12. data/lib/fast-tcpn/clone/using_code_from_stack.rb +50 -0
  13. data/lib/fast-tcpn/clone/using_deep_clone.rb +10 -0
  14. data/lib/fast-tcpn/clone/using_deep_dive.rb +25 -0
  15. data/lib/fast-tcpn/clone/using_marshal.rb +8 -0
  16. data/lib/fast-tcpn/dsl.rb +177 -0
  17. data/lib/fast-tcpn/hash_marking.rb +220 -0
  18. data/lib/fast-tcpn/place.rb +70 -0
  19. data/lib/fast-tcpn/tcpn.rb +288 -0
  20. data/lib/fast-tcpn/timed_hash_marking.rb +87 -0
  21. data/lib/fast-tcpn/timed_place.rb +44 -0
  22. data/lib/fast-tcpn/timed_token.rb +27 -0
  23. data/lib/fast-tcpn/token.rb +30 -0
  24. data/lib/fast-tcpn/transition.rb +224 -0
  25. data/lib/fast-tcpn/version.rb +3 -0
  26. data/spec/callbacks_spec.rb +164 -0
  27. data/spec/dsl/page_spec.rb +195 -0
  28. data/spec/dsl/transition_spec.rb +41 -0
  29. data/spec/hash_marking_spec.rb +9 -0
  30. data/spec/place_spec.rb +10 -0
  31. data/spec/spec_helper.rb +101 -0
  32. data/spec/support/hash_marking_shared.rb +274 -0
  33. data/spec/support/place_shared.rb +66 -0
  34. data/spec/support/token_shared.rb +27 -0
  35. data/spec/support/uses_temp_files.rb +31 -0
  36. data/spec/tcpn_binding_spec.rb +54 -0
  37. data/spec/tcpn_sim_spec.rb +323 -0
  38. data/spec/tcpn_spec.rb +150 -0
  39. data/spec/timed_hash_marking_spec.rb +132 -0
  40. data/spec/timed_place_spec.rb +38 -0
  41. data/spec/timed_token_spec.rb +50 -0
  42. data/spec/token_spec.rb +13 -0
  43. data/spec/transition_spec.rb +236 -0
  44. metadata +156 -0
@@ -0,0 +1,195 @@
1
+ require 'spec_helper'
2
+
3
+ describe FastTCPN::DSL::PageDSL do
4
+ shared_examples "error handler" do
5
+ it "wraps error in DSLError " do
6
+ expect {
7
+ load_model
8
+ }.to raise_error FastTCPN::DSL::DSLError
9
+ end
10
+
11
+ it "includes page name in exception" do
12
+ expect {
13
+ load_model
14
+ }.to raise_error FastTCPN::DSL::DSLError, /Example TCPN Page/
15
+ end
16
+
17
+ it "includes original message in exception" do
18
+ expect {
19
+ load_model
20
+ }.to raise_error FastTCPN::DSL::DSLError, /An error occured/
21
+ end
22
+ end
23
+
24
+ shared_examples "nested error handler" do
25
+ it "includes subpage name in exception" do
26
+ expect {
27
+ load_model
28
+ }.to raise_error FastTCPN::DSL::DSLError, /A sub page/
29
+ end
30
+ end
31
+
32
+ describe "Error handling" do
33
+
34
+
35
+ describe "simple page" do
36
+ let :load_model do
37
+ FastTCPN.model do
38
+ page "Example TCPN Page" do
39
+ raise "An error occured"
40
+ end
41
+ end
42
+ end
43
+
44
+ it_behaves_like "error handler"
45
+ end
46
+
47
+ describe "nested page" do
48
+ let :load_model do
49
+ FastTCPN.model do
50
+ page "Example TCPN Page" do
51
+ page "A sub page" do
52
+ raise "An error occured"
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ it_behaves_like "error handler"
59
+ it_behaves_like "nested error handler"
60
+
61
+ end
62
+
63
+ end
64
+
65
+ describe "#place" do
66
+ let :model do
67
+ FastTCPN.model do
68
+ page "First page" do
69
+ p1 = place "input"
70
+ end
71
+ end
72
+ end
73
+ it "defines place in model" do
74
+ expect(model.find_place "input").to be_kind_of FastTCPN::Place
75
+ end
76
+ end
77
+
78
+ describe "#timed_place" do
79
+ let :model do
80
+ FastTCPN.model do
81
+ page "First page" do
82
+ p1 = timed_place "input"
83
+ end
84
+ end
85
+ end
86
+ it "defines timed place in model" do
87
+ expect(model.find_place "input").to be_kind_of FastTCPN::TimedPlace
88
+ end
89
+ end
90
+
91
+ describe "created by #read" do
92
+ include UsesTempFiles
93
+
94
+ in_directory_with_file "models/example.rb"
95
+
96
+ before do
97
+ content_for_file "models/example.rb", <<-EOF
98
+ page "Example page" do
99
+ p1 = place "input"
100
+ p2 = place "output"
101
+ end
102
+ EOF
103
+ end
104
+
105
+ let :model do
106
+ FastTCPN.read "models/example.rb"
107
+ end
108
+
109
+ it "has places defined in file" do
110
+ expect(model.find_place("input")).to be_kind_of FastTCPN::Place
111
+ expect(model.find_place("output")).to be_kind_of FastTCPN::Place
112
+ end
113
+
114
+ end
115
+
116
+ describe "#sub_page" do
117
+ describe "correctly handles errors" do
118
+ include UsesTempFiles
119
+
120
+ in_directory_with_file "models/top_page.rb"
121
+ in_directory_with_file "models/a_subpage.rb"
122
+
123
+ before do
124
+ content_for_file "models/top_page.rb", <<-EOF
125
+ page "Example TCPN Page" do
126
+ sub_page "a_subpage.rb"
127
+ end
128
+ EOF
129
+
130
+ content_for_file "models/a_subpage.rb", <<-EOF
131
+ page "A sub page" do
132
+ p1 = place "subpage place"
133
+ raise "An error occured"
134
+ end
135
+ EOF
136
+ end
137
+
138
+ let :load_model do
139
+ FastTCPN.read 'models/top_page.rb'
140
+ end
141
+
142
+ it_behaves_like "error handler"
143
+ it_behaves_like "nested error handler"
144
+ end
145
+
146
+ describe "correctly loads pages" do
147
+ include UsesTempFiles
148
+
149
+ in_directory_with_file "models/top_page.rb"
150
+ in_directory_with_file "models/a_subpage.rb"
151
+
152
+ before do
153
+ content_for_file "models/top_page.rb", <<-EOF
154
+ page "Example TCPN Page" do
155
+ sub_page "a_subpage.rb"
156
+ p1 = place "top page place"
157
+ transition "send" do
158
+ input p1
159
+ end
160
+ end
161
+ EOF
162
+
163
+ content_for_file "models/a_subpage.rb", <<-EOF
164
+ page "A sub page" do
165
+ p1 = place "sub page place"
166
+ transition "work" do
167
+ input p1
168
+ end
169
+ end
170
+ EOF
171
+ end
172
+
173
+ let :model do
174
+ FastTCPN.read 'models/top_page.rb'
175
+ end
176
+
177
+ it "has place from top page" do
178
+ expect(model.find_place("top page place")).to be_kind_of FastTCPN::Place
179
+ end
180
+
181
+ it "has place from sub page" do
182
+ expect(model.find_place("sub page place")).to be_kind_of FastTCPN::Place
183
+ end
184
+
185
+ it "has transition from top page" do
186
+ expect(model.find_transition("send")).to be_kind_of FastTCPN::Transition
187
+ end
188
+
189
+ it "has transition from sub page" do
190
+ expect(model.find_transition("work")).to be_kind_of FastTCPN::Transition
191
+ end
192
+ end
193
+
194
+ end
195
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe FastTCPN::DSL::TransitionDSL do
4
+ let :model do
5
+
6
+ FastTCPN.model do
7
+ page "Test TCPN page" do
8
+ p1 = place :in
9
+ p2 = place :out
10
+ transition "work" do
11
+ input p1
12
+ output p2 do |binding, clock|
13
+ binding[:in]
14
+ end
15
+ sentry do |marking_for, clock, result|
16
+ result << { out: marking_for[:in] }
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ end
23
+
24
+ describe "defines transition" do
25
+ it "with name `work`" do
26
+ expect(model.find_transition("work")).not_to be_nil
27
+ end
28
+
29
+ it "with one input place" do
30
+ expect(model.find_transition("work").inputs_size).to eq 1
31
+ end
32
+ it "with out output place" do
33
+ expect(model.find_transition("work").outputs_size).to eq 1
34
+ end
35
+
36
+ it "with sentry" do
37
+ expect(model.find_transition("work").default_sentry?).to be false
38
+ end
39
+ end
40
+
41
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe FastTCPN::HashMarking do
4
+
5
+ let(:marking_class) { FastTCPN::HashMarking }
6
+
7
+ it_behaves_like 'hash marking'
8
+
9
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe "FastTCPN::Place" do
4
+
5
+ let(:place_class) { FastTCPN::Place }
6
+ let(:marking_class) { FastTCPN::HashMarking }
7
+ let(:keys) { { name: :name, valid: :valid? } }
8
+
9
+ it_behaves_like 'valid place'
10
+ end
@@ -0,0 +1,101 @@
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_filter '/spec/'
4
+ end
5
+
6
+
7
+ require 'fast-tcpn'
8
+ Dir["./spec/support/**/*.rb"].sort.each { |f| require f }
9
+
10
+ # In specs we need full backtraces from simulation
11
+ FastTCPN.debug = true
12
+
13
+ # This file was generated by the `rspec --init` command. Conventionally, all
14
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
15
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this
16
+ # file to always be loaded, without a need to explicitly require it in any files.
17
+ #
18
+ # Given that it is always loaded, you are encouraged to keep this file as
19
+ # light-weight as possible. Requiring heavyweight dependencies from this file
20
+ # will add to the boot time of your test suite on EVERY test run, even for an
21
+ # individual file that may not need all of that loaded. Instead, consider making
22
+ # a separate helper file that requires the additional dependencies and performs
23
+ # the additional setup, and require it from the spec files that actually need it.
24
+ #
25
+ # The `.rspec` file also contains a few flags that are not defaults but that
26
+ # users commonly want.
27
+ #
28
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
29
+ RSpec.configure do |config|
30
+ # rspec-expectations config goes here. You can use an alternate
31
+ # assertion/expectation library such as wrong or the stdlib/minitest
32
+ # assertions if you prefer.
33
+ config.expect_with :rspec do |expectations|
34
+ # This option will default to `true` in RSpec 4. It makes the `description`
35
+ # and `failure_message` of custom matchers include text for helper methods
36
+ # defined using `chain`, e.g.:
37
+ # be_bigger_than(2).and_smaller_than(4).description
38
+ # # => "be bigger than 2 and smaller than 4"
39
+ # ...rather than:
40
+ # # => "be bigger than 2"
41
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
42
+ end
43
+
44
+ # rspec-mocks config goes here. You can use an alternate test double
45
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
46
+ config.mock_with :rspec do |mocks|
47
+ # Prevents you from mocking or stubbing a method that does not exist on
48
+ # a real object. This is generally recommended, and will default to
49
+ # `true` in RSpec 4.
50
+ mocks.verify_partial_doubles = true
51
+ end
52
+
53
+ # The settings below are suggested to provide a good initial experience
54
+ # with RSpec, but feel free to customize to your heart's content.
55
+ # These two settings work together to allow you to limit a spec run
56
+ # to individual examples or groups you care about by tagging them with
57
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
58
+ # get run.
59
+ config.filter_run :focus
60
+ config.run_all_when_everything_filtered = true
61
+
62
+ =begin
63
+ # Limits the available syntax to the non-monkey patched syntax that is recommended.
64
+ # For more details, see:
65
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
66
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
67
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
68
+ config.disable_monkey_patching!
69
+
70
+ # This setting enables warnings. It's recommended, but in some cases may
71
+ # be too noisy due to issues in dependencies.
72
+ config.warnings = true
73
+
74
+ # Many RSpec users commonly either run the entire suite or an individual
75
+ # file, and it's useful to allow more verbose output when running an
76
+ # individual spec file.
77
+ if config.files_to_run.one?
78
+ # Use the documentation formatter for detailed output,
79
+ # unless a formatter has already been configured
80
+ # (e.g. via a command-line flag).
81
+ config.default_formatter = 'doc'
82
+ end
83
+
84
+ # Print the 10 slowest examples and example groups at the
85
+ # end of the spec run, to help surface which specs are running
86
+ # particularly slow.
87
+ config.profile_examples = 10
88
+
89
+ # Run specs in random order to surface order dependencies. If you find an
90
+ # order dependency and want to debug it, you can fix the order by providing
91
+ # the seed, which is printed after each run.
92
+ # --seed 1234
93
+ config.order = :random
94
+
95
+ # Seed global randomization in this process using the `--seed` CLI option.
96
+ # Setting this allows you to use `--seed` to deterministically reproduce
97
+ # test failures related to randomization by passing the same `--seed` value
98
+ # as the one that triggered the failure.
99
+ Kernel.srand config.seed
100
+ =end
101
+ end
@@ -0,0 +1,274 @@
1
+ class Worker
2
+ attr_accessor :name
3
+ def initialize(name, finished, cpu = nil)
4
+ @name, @finished, @cpu = name, finished, cpu
5
+ end
6
+ def finished?
7
+ @finished
8
+ end
9
+
10
+ def cpu(value)
11
+ if @cpu == value
12
+ "yes"
13
+ else
14
+ "no"
15
+ end
16
+ end
17
+ end
18
+
19
+ shared_examples 'hash marking' do
20
+
21
+ describe "keys with params" do
22
+ let :marking do
23
+ marking_class.new name: :name, finished: :finished?, cpu_intel: [ :cpu, "intel" ]
24
+ end
25
+
26
+ subject { marking }
27
+
28
+ it "iterates over selected tokens" do
29
+ subject.add Worker.new("intel1", true, 'intel')
30
+ subject.add Worker.new("intel2", true, 'intel')
31
+ subject.add Worker.new("amd", true, 'amd')
32
+ expect(subject.each(:cpu_intel, 'yes').map { |t| t.value.name }).to match_array ["intel1", "intel2"]
33
+ end
34
+
35
+ it "works for empty marking" do
36
+ expect {
37
+ subject.each(:cpu_intel, 'yes') do
38
+
39
+ end
40
+ }.not_to raise_error
41
+ end
42
+
43
+
44
+ end
45
+
46
+ let :marking do
47
+ marking_class.new name: :name, finished: :finished?
48
+ end
49
+
50
+ describe "without tokens" do
51
+ describe "#keys" do
52
+ shared_examples "keys defined in constructor" do
53
+ it "returns keys defined in constructor" do
54
+ expect(subject.keys[:name]).to eq :name
55
+ expect(subject.keys[:finished]).to eq :finished?
56
+ end
57
+ end
58
+ context "for just created marking" do
59
+ subject { marking }
60
+
61
+ include_examples "keys defined in constructor"
62
+
63
+ it "has 2 keys" do
64
+ expect(subject.keys.size).to eq 2
65
+ end
66
+
67
+ end
68
+
69
+ context "for marking with keys added later" do
70
+ subject do
71
+ marking.add_keys val: :something, valid: :valid?
72
+ marking
73
+ end
74
+
75
+ include_examples "keys defined in constructor"
76
+
77
+ it "has 4 keys" do
78
+ expect(subject.keys.size).to eq 4
79
+ end
80
+
81
+ it "returns the added keys" do
82
+ expect(subject.keys[:val]).to eq :something
83
+ expect(subject.keys[:valid]).to eq :valid?
84
+ end
85
+
86
+ end
87
+ end
88
+ end
89
+
90
+ describe "with tokens" do
91
+
92
+ let(:wget1) { Worker.new :wget1, true }
93
+ let(:wget2) { Worker.new :wget2, true }
94
+ let(:wget3) { Worker.new :wget3, false }
95
+
96
+ subject do
97
+ marking.add wget1
98
+ marking.add wget2
99
+ marking.add wget3
100
+ marking
101
+ end
102
+
103
+ it "iterates over all tokens" do
104
+ expect(subject.map { |t| t.value.name }).to match_array [wget1.name, wget2.name, wget3.name]
105
+ end
106
+
107
+ it "shuffles tokens for each iteration" do
108
+ list1 = subject.map { |t| t.value.name }
109
+ equal_lists = 0
110
+ 10.times do
111
+ list2 = subject.map { |t| t.value.name }
112
+ expect(list1).to match_array list2
113
+ if list1 == list2
114
+ equal_lists += 1
115
+ end
116
+ end
117
+ expect(equal_lists).to be < 10
118
+ end
119
+
120
+ it "iterates over selected tokens" do
121
+ expect(subject.each(:finished, true).map { |t| t.value.name }).to match_array [wget1.name, wget2.name]
122
+ end
123
+
124
+ it "clones tokens before they are returned" do
125
+ expect(subject.each(:name, wget1.name).first.object_id).not_to eq(wget1.object_id)
126
+ end
127
+
128
+
129
+ describe "#add_keys" do
130
+ it "raises error" do
131
+ expect {
132
+ subject.add_keys val: :something, valid: :valid?
133
+ }.to raise_error FastTCPN::HashMarking::CannotAddKeys
134
+ end
135
+ end
136
+
137
+
138
+ describe "#delete" do
139
+ it "deletes tokens from 'name' list" do
140
+ expect {
141
+ subject.delete subject.each(:name, wget1.name).first
142
+ }.to change(subject, :size).by(-1)
143
+ expect(subject.each(:name, wget1.name).map { |t| t.value }).not_to include(wget1)
144
+ end
145
+
146
+ it "deletes from 'finished' list" do
147
+ expect {
148
+ subject.delete subject.each(:name, wget1.name).first
149
+ }.to change(subject, :size).by(-1)
150
+ expect(subject.each(:finished, wget1.finished?)).not_to include(wget1)
151
+ end
152
+
153
+ it "returns deleted token" do
154
+ to_delete = subject.each(:name, wget1.name).first
155
+ expect(subject.delete to_delete).to eq to_delete
156
+ end
157
+
158
+ it "returns nil if nothing was deleted" do
159
+ already_deleted = subject.delete subject.each(:name, wget1.name).first
160
+ expect(subject.delete already_deleted).to eq nil
161
+ end
162
+
163
+ context "with Array" do
164
+ it "deletes all tokens in the Array" do
165
+ tokens = []
166
+ tokens << subject.each(:name, wget1.name).first
167
+ tokens << subject.each(:name, wget2.name).first
168
+ expect {
169
+ subject.delete tokens
170
+ }.to change(subject, :size).by(-2)
171
+ expect(subject.each).not_to include(wget1)
172
+ expect(subject.each).not_to include(wget2)
173
+ end
174
+ end
175
+
176
+ end
177
+
178
+ describe "#get gets token from marking" do
179
+ let(:token) { subject.each.first }
180
+
181
+ it "equal to given token" do
182
+ expect(subject.get(token)).to eq token
183
+ end
184
+
185
+ it "clone of given token" do
186
+ expect(subject.get(token).object_id).not_to eq token.object_id
187
+ end
188
+
189
+ it "even if token value changed" do
190
+ token.value.name = "asdasd"
191
+ expect(subject.get(token)).to eq token
192
+ end
193
+
194
+ it "every time a new clone" do
195
+ token2 = subject.get(token)
196
+ expect(subject.get(token).object_id).not_to eq token2.object_id
197
+ end
198
+
199
+ end
200
+ end
201
+
202
+ describe "#add" do
203
+ it "extracts value from tokens of class extending this class" do
204
+ value = Worker.new("intel1", true, 'intel')
205
+ extended_token_class = Class.new subject.token_type
206
+ token = extended_token_class.new(value)
207
+ subject.add token
208
+ expect(subject.each.first.value.name).to eq value.name
209
+ end
210
+
211
+ describe "with Hash" do
212
+ it "adds token with value from :val key" do
213
+ value = Worker.new("intel1", true, 'intel')
214
+ subject.add val: value
215
+ expect(subject.each.first.value.name).to eq value.name
216
+ end
217
+ end
218
+
219
+ describe "with Array" do
220
+ it "adds all tokens from array" do
221
+ value1 = Worker.new("intel1", true, 'intel')
222
+ value2 = Worker.new("intel2", true, 'intel')
223
+ subject.add [ value1, value2 ]
224
+ expect(subject.map { |t| t.value.name }).to match_array ['intel1', 'intel2']
225
+ end
226
+ describe "of Hashes" do
227
+ it "adds all tokens from all Hashes in array" do
228
+ value1 = Worker.new("intel1", true, 'intel')
229
+ value2 = Worker.new("intel2", true, 'intel')
230
+ subject.add [ {val: value1}, {val: value2} ]
231
+ expect(subject.map { |t| t.value.name }).to match_array ['intel1', 'intel2']
232
+ end
233
+ end
234
+ end
235
+ end
236
+
237
+ it "works for Symbols" do
238
+ expect {
239
+ marking_class.new.add :asd
240
+ }.not_to raise_error
241
+ end
242
+
243
+ it "works for Procs" do
244
+ expect {
245
+ marking_class.new.add(proc {})
246
+ }.not_to raise_error
247
+ end
248
+
249
+ it "works for Fixnums" do
250
+ expect {
251
+ marking_class.new.add(123)
252
+ }.not_to raise_error
253
+ end
254
+
255
+ Klazz = Struct.new(:name, :id)
256
+ it "works for Structs" do
257
+ expect {
258
+ marking_class.new.add(Klazz.new)
259
+ }.not_to raise_error
260
+ end
261
+
262
+ it "works for anonymous Structs" do
263
+ expect {
264
+ marking_class.new.add(Struct.new(:name, :id).new)
265
+ }.not_to raise_error
266
+ end
267
+
268
+ it "works for nil" do
269
+ expect {
270
+ marking_class.new.add(nil)
271
+ }.not_to raise_error
272
+ end
273
+ end
274
+