miner_mover 0.1.0.1 → 0.1.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7d6d5e0e85b066dc78e4e6c7b86d751245f1e2b3809ab176f9b69e7047c2d330
4
- data.tar.gz: cd0f57ea360871fefdb7927eddef3651a277c8e8116d41a2da085dcf02a3ed73
3
+ metadata.gz: d6d1e4d4ee9ab3ff3dedcd283b94f1c089dd6478657f215d0903a18bcbaa576f
4
+ data.tar.gz: b0d0a6fc768ede45676fa68545379e915d98e9c9f8d6416c48b7bd564b8b09fc
5
5
  SHA512:
6
- metadata.gz: 1a8d2759692483f004c0d512a17b2b4ec6a10e6d26b3e66b8785b28a0510cc3eaf7ad029b95f0a11a37b0264dc028e3c65a5cbccffbc64e5446365cdaf9ae2ce
7
- data.tar.gz: d88946c92b88073fc01f4b57ae0f13ba157ca7a72c85ae6ad405a0569b311e5420689d76014c5cda88c709b2dfbfa2dbed6b090e2c001894fdf4267686cbd87d
6
+ metadata.gz: a3f7e4cffe3a1bc9805097a11f6490a7de4d64daa5c893e3341b569e89296d8dde97185a89f6cd5eabbcb4d9f1156d41c913fa33365601a6bb9cdacb4d8fbf6f
7
+ data.tar.gz: ae1292dfb2249203ad53a0860900dc49b6b46cd618f586fae8fa549700195448824d29347fb19460ff191164420113c687711a8dbbf1b101b71f9154395824b9
data/README.md CHANGED
@@ -18,7 +18,7 @@ results as well. Ore is gathered at each depth; either a fixed amount or
18
18
  randomized, based on depth. The amount of time spent mining each level is
19
19
  independent and may be randomized.
20
20
 
21
- https://github.com/rickhull/miner_mover/blob/bd76ea400944aab8eab9e3ffcac85d1e28353eff/lib/miner_mover/worker.rb#L85-L99
21
+ https://github.com/rickhull/miner_mover/blob/4f2a62f6d77316e780c7c13248698d4c57bb392e/lib/miner_mover/worker.rb#L96-L104
22
22
 
23
23
  In this case, miners are rewarded by calculating `fibonacci(depth)`, using
24
24
  classic, inefficient fibonacci.
@@ -31,7 +31,7 @@ A mover has a batch size, say 10. As the mover accumulates ore over time,
31
31
  once the batch size is reached, the mover delivers the ore to the destination.
32
32
  Larger batches take longer. The delivery time can be randomized.
33
33
 
34
- https://github.com/rickhull/miner_mover/blob/bd76ea400944aab8eab9e3ffcac85d1e28353eff/lib/miner_mover/worker.rb#L135-L162
34
+ https://github.com/rickhull/miner_mover/blob/4f2a62f6d77316e780c7c13248698d4c57bb392e/lib/miner_mover/worker.rb#L152-L183
35
35
 
36
36
  The time and work spent delivering ore can be simulated three ways,
37
37
  configured via `:work_type`
@@ -44,18 +44,22 @@ configured via `:work_type`
44
44
 
45
45
  ## Install
46
46
 
47
- You'll want to use **Ruby 3.x** to make the most of Fibers.
47
+ You'll want to use **Ruby 3.x** (CRuby) to make the most of Fibers.
48
48
 
49
49
  ### Dependencies
50
50
 
51
- * rake
52
- * minitest
53
51
  * dotcfg
54
- * fiber_scheduler
55
52
 
56
- `gem install miner_mover` will take care of the following:
53
+ `gem install dotcfg`
54
+
55
+ #### Additionally
56
+
57
+ To use Fiber::Scheduler and kqueue / epoll / io_uring:
58
+
59
+ * fiber_scheduler
60
+ * io-event
57
61
 
58
- `gem install rake minitest dotcfg fiber_scheduler`
62
+ `gem install fiber_scheduler io-event`
59
63
 
60
64
  ### Clone
61
65
 
@@ -71,20 +75,21 @@ Try: `rake -T` to see available [Rake tasks](Rakefile)
71
75
  ```
72
76
  $ rake -T
73
77
 
74
- rake alt_demo # run all demos minus fiber_scheduler / ractor / process
75
- rake config # run demo/config
76
- rake default # rake test
77
- rake demo # run all demos
78
- rake fiber # run demo/fiber
79
- rake fiber_scheduler # run demo/fiber_scheduler
80
- rake process_pipe # run demo/process_pipe
81
- rake process_socket # run demo/process_socket
82
- rake ractor # run demo/ractor
83
- rake serial # run demo/serial
78
+ rake config # Run demo/config.rb
79
+ rake demo # Run all demos
80
+ rake fiber # Run demo/fiber.rb
81
+ rake fiber_scheduler # Run demo/fiber_scheduler.rb
82
+ rake jvm_demo # Run JVM compatible demos
83
+ rake process_pipe # Run demo/process_pipe.rb
84
+ rake process_socket # Run demo/process_socket.rb
85
+ rake ractor # Run demo/ractor.rb
86
+ rake serial # Run demo/serial.rb
84
87
  rake test # Run tests
85
- rake thread # run demo/thread
88
+ rake thread # Run demo/thread.rb
86
89
  ```
87
90
 
91
+ Try: `rake test`
92
+
88
93
  ## Rake Tasks
89
94
 
90
95
  Included demonstration scripts can be executed via Rake tasks.
@@ -113,36 +118,76 @@ Rake tasks take care of `LOAD_PATH`, so the following is
113
118
 
114
119
  ## Exploration in `irb`
115
120
 
116
- `$ irb -Ilib -rminer_mover/worker`
121
+ `$ irb -I lib`
117
122
 
118
123
  ```
119
- irb(main):001:0> include MinerMover
124
+ irb(main):001:0> require 'miner_mover/worker'
125
+ => true
126
+
127
+ irb(main):002:0> include MinerMover
120
128
  => Object
121
129
 
122
- irb(main):002:0> miner = Miner.new
130
+ irb(main):003:0> miner = Miner.new
123
131
  =>
124
- #<MinerMover::Miner:0x00007fdd649754e8
132
+ #<MinerMover::Miner:0x00007fbee8a3a080
125
133
  ...
126
134
 
127
- irb(main):003:0> miner.mine_ore
128
- => 0
129
-
130
- irb(main):004:0> miner.mine_ore 5
131
- => 3
132
-
133
- irb(main):005:0> miner.mine_ore 20
134
- => 6483
135
-
136
- irb(main):006:0> mover = Mover.new
135
+ irb(main):004:0> mover = Mover.new
137
136
  =>
138
- #<MinerMover::Mover:0x00007fdd64979930
137
+ #<MinerMover::Mover:0x00007fbee8a8a6c0
139
138
  ...
140
139
 
141
- irb(main):007:0> mover.load_ore 6483
142
- => 6483
143
-
144
- irb(main):008:0> mover.status
145
- => "Batch 6483 / 10M 0% | Moved 0x (0M)"
140
+ irb(main):005:0> miner.state
141
+ =>
142
+ {:id=>"00050720",
143
+ :logging=>false,
144
+ :debugging=>false,
145
+ :timer=>10200,
146
+ :variance=>0,
147
+ :depth=>5,
148
+ :partial_reward=>false}
149
+
150
+ irb(main):006:0> mover.state
151
+ =>
152
+ {:id=>"00057860",
153
+ :logging=>false,
154
+ :debugging=>false,
155
+ :timer=>10456,
156
+ :variance=>0,
157
+ :work_type=>:cpu,
158
+ :batch_size=>10000000,
159
+ :batch=>0,
160
+ :batches=>0,
161
+ :ore_moved=>0}
162
+
163
+ irb(main):007:0> miner.mine_ore
164
+ => 7
165
+
166
+ irb(main):008:0> mover.load_ore 7
167
+ => 7
168
+
169
+ irb(main):009:0> miner.state
170
+ =>
171
+ {:id=>"00050720",
172
+ :logging=>false,
173
+ :debugging=>false,
174
+ :timer=>28831,
175
+ :variance=>0,
176
+ :depth=>5,
177
+ :partial_reward=>false}
178
+
179
+ irb(main):010:0> mover.state
180
+ =>
181
+ {:id=>"00057860",
182
+ :logging=>false,
183
+ :debugging=>false,
184
+ :timer=>27959,
185
+ :variance=>0,
186
+ :work_type=>:cpu,
187
+ :batch_size=>10000000,
188
+ :batch=>7,
189
+ :batches=>0,
190
+ :ore_moved=>0}
146
191
  ```
147
192
 
148
193
  ## Included scripts
@@ -165,6 +210,46 @@ multiple miners or movers.
165
210
 
166
211
  Execute via e.g. `ruby -Ilib demo/thread.rb`
167
212
 
213
+ ### Approaches
214
+
215
+ #### [Serial](demo/serial.rb)
216
+
217
+ One miner, one mover. The miner mines to a depth, then loads the ore.
218
+ When the mover has a full batch, the batch is moved while the miner waits.
219
+
220
+ #### [Fibers](demo/fiber.rb)
221
+
222
+ Without a Fiber Scheduler, this just changes some organizational things.
223
+ Again, one miner, one mover. The mover has its own fiber, and the mining
224
+ fiber can pass ore to the moving fiber. There is no concurrency, so the
225
+ performance is roughly the same as before.
226
+
227
+ #### [Fiber Scheduler](demo/fiber_scheduler.rb)
228
+
229
+ TBD
230
+
231
+ #### [Threads](demo/thread.rb)
232
+
233
+ An array of mining threads and an array of moving threads.
234
+ A single shared queue for loading ore from miners to movers.
235
+ All threads contend for the same execution lock (GVL).
236
+
237
+ #### [Ractors](demo/ractor.rb)
238
+
239
+ Moving threads execute in their own ractor.
240
+ Mining threads contend against mining threads. Moving threads, likewise.
241
+
242
+ #### [Processes with pipes](demo/process_pipe.rb)
243
+
244
+ Similar to ractors, but using `Process.fork` for movers, using a pipe to send
245
+ ore from the parent mining process.
246
+
247
+ #### [Processes with sockets](demo/process_socket.rb)
248
+
249
+ As above, but with Unix sockets (*not* network sockets), using any of
250
+ `SOCK_STREAM` `SOCK_DGRAM` `SOCK_SEQPACKET` socket types.
251
+ In all cases, ore amounts are 4 bytes so the types behave roughly equivalently.
252
+
168
253
  # Multitasking
169
254
 
170
255
  *Multitasking* here means "the most general sense of performing several tasks
@@ -379,11 +464,15 @@ others. My favorites:
379
464
 
380
465
  * `Process.fork` - when called with a block, the block is only executed in the
381
466
  child subprocess
382
- * `Process.spawn` - extensive options, nonblocking, call Process.wait(pid)
467
+ * `Process.spawn` - extensive options, nonblocking, call `Process.wait(pid)`
383
468
  to get the result
384
- * `Open3.popen3` - for access to STDIN, STDOUT, STDERR
469
+ * `Open3.popen3` - for access to `STDIN` `STDOUT` `STDERR`
385
470
 
386
471
  ### IPC
387
472
 
388
- * Pipes - streaming bytes: `IO.pipe`
389
- * Unix sockets - messages with datagrams: `Socket.pair(:UNIX, :DGRAM, 0)`
473
+ * Pipes
474
+ - `IO.pipe` (streaming / bytes / unidirectional)
475
+ * Unix sockets
476
+ - `UNIXSocket.pair :RAW`
477
+ - `UNIXSocket.pair :DGRAM` (datagram / message / "like UDP")
478
+ - `UNIXSocket.pair :STREAM` (streaming / bytes / "like TCP")
data/Rakefile CHANGED
@@ -1,27 +1,43 @@
1
- require 'rake/testtask'
1
+ #
2
+ # test task
3
+ #
2
4
 
5
+ require 'rake/testtask'
3
6
  Rake::TestTask.new :test do |t|
4
7
  t.pattern = "test/*.rb"
5
8
  t.warning = true
6
9
  end
7
-
8
- desc "rake test"
9
10
  task default: :test
10
11
 
12
+ #
13
+ # demo tasks
14
+ #
15
+
16
+ if ENV['RUBYOPT'].nil? or ENV['RUBYOPT'].empty?
17
+ flags = ['-I', File.join(__dir__, 'lib')]
18
+ else
19
+ flags = nil # subprocesses will have RUBYOPT
20
+ end
21
+
22
+ # create a rake task to run each script in demo/
11
23
  Dir['demo/*.rb'].each { |demo_path|
12
24
  name = File.basename(demo_path, '.rb')
13
- desc "run demo/#{name}"
14
- task(name) { sh "ruby -Ilib #{demo_path}" }
25
+ desc "Run #{demo_path}"
26
+ task(name) { ruby *flags, demo_path }
15
27
  }
16
28
 
17
29
  # jruby / truffleruby lack fiber_scheduler, Ractor, and Process#fork
18
- desc "run all demos minus fiber_scheduler / ractor / process"
30
+ desc "Run JVM compatible demos"
19
31
  task jvm_demo: [:serial, :fiber, :thread]
20
32
 
21
- desc "run all demos"
33
+ desc "Run all demos"
22
34
  task demo: [:serial, :fiber, :fiber_scheduler,
23
35
  :thread, :ractor, :process_pipe, :process_socket]
24
36
 
37
+ #
38
+ # release tasks
39
+ #
40
+
25
41
  begin
26
42
  require 'buildar'
27
43
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0.1
1
+ 0.1.2.1
@@ -15,7 +15,7 @@ Signal.trap("INT") {
15
15
  stop_mining = true
16
16
  }
17
17
 
18
- socktype = [:DGRAM, :STREAM, :RAW].sample
18
+ socktype = [:DGRAM, :STREAM, :SEQPACKET].sample
19
19
  run.log "SOCK #{socktype}"
20
20
  csock, psock = UNIXSocket.pair(socktype)
21
21
 
@@ -44,22 +44,22 @@ module MinerMover
44
44
  t.strftime "%Y-%m-%d %H:%M:%S.%L"
45
45
  end
46
46
 
47
- def restart(t = Time.now)
48
- @start = t
47
+ def restart(f = Timer.now)
48
+ @start = f
49
49
  self
50
50
  end
51
51
  alias_method :initialize, :restart
52
52
 
53
- def elapsed(t = Time.now)
54
- t - @start
53
+ def elapsed(f = Timer.now)
54
+ f - @start
55
55
  end
56
56
 
57
- def elapsed_ms(t = Time.now)
58
- elapsed(t) * 1000
57
+ def elapsed_ms(f = Timer.now)
58
+ elapsed(f) * 1000
59
59
  end
60
60
 
61
- def elapsed_display(t = Time.now)
62
- Timer.elapsed_display(elapsed_ms(t))
61
+ def elapsed_display(f = Timer.now)
62
+ Timer.elapsed_display(elapsed_ms(f))
63
63
  end
64
64
  alias_method :to_s, :elapsed_display
65
65
  alias_method :inspect, :elapsed_display
@@ -77,32 +77,36 @@ module MinerMover
77
77
  class Miner < Worker
78
78
  attr_accessor :depth, :partial_reward
79
79
 
80
- def initialize(depth: 10,
81
- partial_reward: true,
80
+ def initialize(depth: 5,
81
+ partial_reward: false,
82
82
  variance: 0,
83
83
  logging: false,
84
84
  debugging: false,
85
85
  timer: nil)
86
86
  @partial_reward = partial_reward
87
87
  @depth = depth
88
- super(variance: variance, logging: logging,
89
- debugging: debugging, timer: timer)
88
+ super(variance: variance, timer: timer,
89
+ logging: logging, debugging: debugging)
90
90
  end
91
91
 
92
92
  def state
93
93
  super.merge(depth: @depth, partial_reward: @partial_reward)
94
94
  end
95
95
 
96
+ # return an array of integers representing ore mined at each depth
97
+ def mine_ores(depth = @depth)
98
+ # every new depth is a new mining operation
99
+ Array.new(depth) { |d|
100
+ # mine ore by calculating fibonacci for that depth
101
+ mined = MinerMover.fib(self.varied(d).round)
102
+ @partial_reward ? rand(1 + mined) : mined
103
+ }
104
+ end
105
+
106
+ # wrap the above method with logging, timing, and summing
96
107
  def mine_ore(depth = @depth)
97
108
  log format("MINE Depth %i", depth)
98
- ores, elapsed = Timer.elapsed {
99
- # every new depth is a new mining operation
100
- Array.new(depth) { |d|
101
- # mine ore by calculating fibonacci for that depth
102
- mined = MinerMover.fib self.varied(d).round
103
- @partial_reward ? rand(1 + mined) : mined
104
- }
105
- }
109
+ ores, elapsed = Timer.elapsed { self.mine_ores(depth) }
106
110
  total = ores.sum
107
111
  log format("MIND %s %s (%.2f s)",
108
112
  Ore.display(total), ores.inspect, elapsed)
@@ -124,8 +128,8 @@ module MinerMover
124
128
  @rate = rate.to_f * Ore::BLOCK
125
129
  @work_type = work_type
126
130
  @batch, @batches, @ore_moved = 0, 0, 0
127
- super(variance: variance, logging: logging,
128
- debugging: debugging, timer: timer)
131
+ super(variance: variance, timer: timer,
132
+ logging: logging, debugging: debugging)
129
133
  end
130
134
 
131
135
  def state
@@ -145,33 +149,37 @@ module MinerMover
145
149
  ].join(' | ')
146
150
  end
147
151
 
148
- def load_ore(amt)
149
- @batch += amt
152
+ # accept some ore for moving; just accumulate unless we have a full batch
153
+ def load_ore amount
154
+ log format("LOAD %s | %s", Ore.display(amount), self.status)
155
+ @batch += amount
150
156
  move_batch if @batch >= @batch_size
151
- log format("LOAD %s", self.status)
157
+ log format("LDED %s | %s", Ore.display(amount), self.status)
152
158
  @batch
153
159
  end
154
160
 
155
- def move(duration)
156
- MinerMover.work(duration, @work_type)
157
- end
158
-
161
+ # return the amount moved
159
162
  def move_batch
160
163
  raise "unexpected batch: #{@batch}" if @batch <= 0
161
- amt = [@batch, @batch_size].min
162
- duration = self.varied(amt / @rate)
164
+ amount = [@batch, @batch_size].min
163
165
 
164
- log format("MOVE %s (%.2f s)", Ore.display(amt), duration)
165
- _, elapsed = Timer.elapsed { self.move(duration) }
166
- log format("MOVD %s (%.2f s)", Ore.display(amt), elapsed)
166
+ self.move amount
167
167
 
168
168
  # accounting
169
- @ore_moved += amt
170
- @batch -= amt
169
+ @ore_moved += amount
170
+ @batch -= amount
171
171
  @batches += 1
172
172
 
173
- # what moved
174
- amt
173
+ amount
174
+ end
175
+
176
+ # perform the work of moving the amount of ore
177
+ def move amount
178
+ duration = self.varied(amount / @rate)
179
+ log format("MOVE %s (%.2f s)", Ore.display(amount), duration)
180
+ _, elapsed = Timer.elapsed { MinerMover.work(duration, @work_type) }
181
+ log format("MOVD %s (%.2f s)", Ore.display(amount), elapsed)
182
+ self
175
183
  end
176
184
  end
177
185
  end
data/lib/miner_mover.rb CHANGED
@@ -3,20 +3,22 @@ module MinerMover
3
3
 
4
4
  # $/ is the default line separator: "\n"
5
5
  def self.puts(str, io = $stdout, separator = LINE_SEP)
6
- self.write_nonblock(io, str + separator)
6
+ self.write(io, str + separator)
7
7
  end
8
8
 
9
- def self.write_nonblock(io, str)
9
+ def self.write(io, str)
10
+ # nonblocking write attempt; ensure the full string is written
10
11
  begin
11
- # nonblocking write attempt; ensure the full string is written
12
- size = str.bytesize
13
12
  num_bytes = io.write_nonblock(str)
14
- # blocking write if nonblocking write comes up short
15
- io.write str.byteslice(num_bytes, size - num_bytes) if num_bytes < size
16
13
  rescue IO::WaitWritable, Errno::EINTR
17
14
  IO.select([], [io]) # wait until writable
18
15
  retry
19
16
  end
17
+ # blocking write if nonblocking write comes up short
18
+ if num_bytes < str.bytesize
19
+ io.write str.byteslice(num_bytes, str.bytesize - num_bytes)
20
+ end
21
+ nil
20
22
  end
21
23
 
22
24
  def self.log_fmt(timer, id, msg)
data/miner_mover.gemspec CHANGED
@@ -5,11 +5,11 @@ Gem::Specification.new do |s|
5
5
  s.description = <<EOF
6
6
  Fundamentally, we have a set of miners and a set of movers. A miner takes some amount of time to mine ore, which is given to a mover. When a mover has enough ore for a full batch, the delivery takes some amount of time before more ore can be loaded.
7
7
  EOF
8
- s.authors = ["Rick Hull"]
8
+ s.authors = ["Rick Hull"]
9
9
  s.homepage = "https://github.com/rickhull/miner_mover"
10
10
  s.license = "LGPL-3.0"
11
11
 
12
- s.required_ruby_version = "~> 2"
12
+ s.required_ruby_version = "> 2"
13
13
 
14
14
  s.version = File.read(File.join(__dir__, 'VERSION')).chomp
15
15
 
@@ -18,16 +18,5 @@ EOF
18
18
  s.files += Dir['test/**/*.rb']
19
19
  s.files += Dir['demo/**/*.rb']
20
20
 
21
- s.add_dependency "dotcfg", "~> 1.0"
22
-
23
- s.requirements << "For all features and best performance:"
24
- s.requirements << "gem install rake minitest fiber_scheduler"
25
- s.requirements << "For dev tools:"
26
- s.requirements << "gem install buildar flog flay"
27
-
28
- s.add_development_dependency "rake", "~> 13.0" # CVE-2020-8130
29
- s.add_development_dependency "minitest", "~> 5.0"
30
- s.add_development_dependency "buildar", "~> 3.0"
31
- s.add_development_dependency "flog", "~> 0"
32
- s.add_development_dependency "flay", "~> 0"
21
+ s.add_runtime_dependency "dotcfg", "~> 1.0"
33
22
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: miner_mover
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.1
4
+ version: 0.1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rick Hull
@@ -24,76 +24,6 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.0'
27
- - !ruby/object:Gem::Dependency
28
- name: rake
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '13.0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '13.0'
41
- - !ruby/object:Gem::Dependency
42
- name: minitest
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '5.0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '5.0'
55
- - !ruby/object:Gem::Dependency
56
- name: buildar
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '3.0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '3.0'
69
- - !ruby/object:Gem::Dependency
70
- name: flog
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: flay
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
27
  description: 'Fundamentally, we have a set of miners and a set of movers. A miner
98
28
  takes some amount of time to mine ore, which is given to a mover. When a mover has
99
29
  enough ore for a full batch, the delivery takes some amount of time before more
@@ -133,7 +63,7 @@ require_paths:
133
63
  - lib
134
64
  required_ruby_version: !ruby/object:Gem::Requirement
135
65
  requirements:
136
- - - "~>"
66
+ - - ">"
137
67
  - !ruby/object:Gem::Version
138
68
  version: '2'
139
69
  required_rubygems_version: !ruby/object:Gem::Requirement
@@ -141,12 +71,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
141
71
  - - ">="
142
72
  - !ruby/object:Gem::Version
143
73
  version: '0'
144
- requirements:
145
- - 'For all features and best performance:'
146
- - gem install rake minitest fiber_scheduler
147
- - 'For dev tools:'
148
- - gem install buildar flog flay
149
- rubygems_version: 3.3.20
74
+ requirements: []
75
+ rubygems_version: 3.4.4
150
76
  signing_key:
151
77
  specification_version: 4
152
78
  summary: This project provides a basic concurrency problem useful for exploring different