fibril 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cf7d153b66e754a9c54176ad4aed2f7b6e5b0055
4
+ data.tar.gz: 57d3036405946c6c82bfce1cea816c119d5f71fd
5
+ SHA512:
6
+ metadata.gz: 75bb606b9261c086109e971235f29fc624371db80f428e653b9918766d2346f674b4ce03e1a16ebb76239c8e22377a37b9a4b5ab3ef6e2b433eb5717f06b6479
7
+ data.tar.gz: d104f2d54afe2eeef3da5caae50b4d782576b7bb396caca58fd0986213c29eb0d9c87a45ce5844f3630b43dc5d67037546ba6d2ab5d1d9546af3ad5d1da47e96
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.0
4
+ before_install: gem install bundler -v 1.10.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fibril.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Wouter Coppieters
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # Fibril
2
+
3
+
4
+ ## Installation
5
+
6
+ Add this line to your application's Gemfile:
7
+
8
+ ```ruby
9
+ gem 'fibril'
10
+ ```
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install fibril
19
+
20
+ ## Usage
21
+
22
+ TODO: Write usage instructions here
23
+
24
+ ## Development
25
+
26
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
27
+
28
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
29
+
30
+ ## Contributing
31
+
32
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/fibril.
33
+
34
+
35
+ ## License
36
+
37
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
38
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
data/bin/fibril ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "fibril"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ require "pry"
11
+ if ARGV[0]
12
+ require_relative "../#{ARGV[0]}"
13
+ else
14
+ Pry.start
15
+ end
16
+
17
+
18
+ # require "irb"
19
+ # IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,71 @@
1
+ require_relative '../lib/fibril'
2
+
3
+ require 'benchmark'
4
+
5
+
6
+ def get_5
7
+ 5.tap{ async.sleep 0.5 }
8
+ end
9
+
10
+ def get_res
11
+ starts = Time.now
12
+ res = get_5
13
+ ends = Time.now
14
+ puts "Get res took #{ends - starts}"
15
+ res
16
+ end
17
+ Benchmark.bm do |bm|
18
+ # bm.report{
19
+ # Fibril do
20
+ # i = 0
21
+ # await fibril{ i = get_5 + 20 + i }.until{ i > 260 },
22
+ # fibril{ i = get_5 + 100 + i }.loop(2) do
23
+ # puts "Final i is #{i}"
24
+ # end
25
+ # end
26
+ # }
27
+
28
+ # puts "Done"
29
+ # sleep 2
30
+ bm.report{
31
+
32
+ Fibril do
33
+ i = 0
34
+ await(
35
+ fibril{ starts = Time.now; res = get_res;i = res + 20 + i; puts "Weave 1 took #{Time.now - starts}" }.until{ i > 260 },
36
+ fibril{ starts = Time.now; res = get_res;i = res + 100 + i; puts "Weave 2 took #{Time.now - starts}" }.loop(2)
37
+ ) do
38
+ puts "Final i is #{i}"
39
+ end
40
+ end
41
+ }
42
+ end
43
+
44
+
45
+ # Fibril do
46
+ # await fibril{ puts 1; tick; puts 3 },
47
+ # fibril{ puts 2; tick; puts 4 } do
48
+ # puts "Finished"
49
+ # end
50
+ # end
51
+ # }
52
+ # end
53
+
54
+
55
+
56
+ # Thread.new do
57
+ # [
58
+ # Thread.new do
59
+ # puts "Big very very very very long message 1"
60
+ # puts "Big very very very very long message 2"
61
+ # puts "Big very very very very long message 5"
62
+ # puts "Big very very very very long message 6"
63
+ # end,
64
+ # Thread.new do
65
+ # puts "Big very very very very long message 3"
66
+ # puts "Big very very very very long message 4"
67
+ # puts "Big very very very very long message 7"
68
+ # puts "Big very very very very long message 8"
69
+ # end
70
+ # ].each(&:join)
71
+ # end.join
@@ -0,0 +1,80 @@
1
+ require_relative 'fibril'
2
+ require "benchmark"
3
+
4
+ Benchmark.bm do |bm|
5
+ bm.report{
6
+ i = 0
7
+ 100.times do
8
+ puts "A very long output statement : #{1}. Current thread: #{Thread.current}"
9
+ puts "A very long output statement : #{2}. Current thread: #{Thread.current}"
10
+ puts "A very long output statement : #{3}. Current thread: #{Thread.current}"
11
+ puts "A very long output statement : #{4}. Current thread: #{Thread.current}"
12
+ puts "A very long output statement : #{5}. Current thread: #{Thread.current}"
13
+ puts "A very long output statement : #{6}. Current thread: #{Thread.current}"
14
+ puts "A very long output statement : #{7}. Current thread: #{Thread.current}"
15
+ puts "A very long output statement : #{8}. Current thread: #{Thread.current}"
16
+ end
17
+ }
18
+ bm.report{
19
+ i = 0
20
+
21
+ 100.times do
22
+ Fibril do
23
+ Fibril do
24
+ puts "A very long output statement : #{1}. Current thread: #{Thread.current}"
25
+ puts "A very long output statement : #{2}. Current thread: #{Thread.current}"
26
+ tick
27
+ puts "A very long output statement : #{3}. Current thread: #{Thread.current}"
28
+ puts "A very long output statement : #{4}. Current thread: #{Thread.current}"
29
+ end
30
+
31
+ Fibril do
32
+ puts "A very long output statement : #{5}. Current thread: #{Thread.current}"
33
+ puts "A very long output statement : #{6}. Current thread: #{Thread.current}"
34
+ tick
35
+ puts "A very long output statement : #{7}. Current thread: #{Thread.current}"
36
+ puts "A very long output statement : #{8}. Current thread: #{Thread.current}"
37
+ Fibril.stop
38
+ end
39
+ end
40
+ end
41
+ }
42
+ bm.report{
43
+ i = 0
44
+ 100.times do
45
+ Thread.new do
46
+ [
47
+ Thread.new do
48
+ puts "A very long output statement : #{1}. Current thread: #{Thread.current}"
49
+ puts "A very long output statement : #{2}. Current thread: #{Thread.current}"
50
+ puts "A very long output statement : #{3}. Current thread: #{Thread.current}"
51
+ puts "A very long output statement : #{4}. Current thread: #{Thread.current}"
52
+ end,
53
+ Thread.new do
54
+ puts "A very long output statement : #{5}. Current thread: #{Thread.current}"
55
+ puts "A very long output statement : #{6}. Current thread: #{Thread.current}"
56
+ puts "A very long output statement : #{7}. Current thread: #{Thread.current}"
57
+ puts "A very long output statement : #{8}. Current thread: #{Thread.current}"
58
+ end
59
+ ].each(&:join)
60
+ end.join
61
+ end
62
+ }
63
+ end
64
+
65
+ # Thread.new do
66
+ # [
67
+ # Thread.new do
68
+ # puts "Big very very very very long message 1"
69
+ # puts "Big very very very very long message 2"
70
+ # puts "Big very very very very long message 5"
71
+ # puts "Big very very very very long message 6"
72
+ # end,
73
+ # Thread.new do
74
+ # puts "Big very very very very long message 3"
75
+ # puts "Big very very very very long message 4"
76
+ # puts "Big very very very very long message 7"
77
+ # puts "Big very very very very long message 8"
78
+ # end
79
+ # ].each(&:join)
80
+ # end.join
@@ -0,0 +1,82 @@
1
+ require_relative '../lib/fibril'
2
+ require "benchmark"
3
+
4
+ Benchmark.bm do |bm|
5
+ bm.report{
6
+ i = 0
7
+ 1_000.times do
8
+ print "\rA very long output statement : #{1}. Current thread: #{Thread.current}"
9
+ print "\rA very long output statement : #{2}. Current thread: #{Thread.current}"
10
+ print "\rA very long output statement : #{3}. Current thread: #{Thread.current}"
11
+ print "\rA very long output statement : #{4}. Current thread: #{Thread.current}"
12
+ print "\rA very long output statement : #{5}. Current thread: #{Thread.current}"
13
+ print "\rA very long output statement : #{6}. Current thread: #{Thread.current}"
14
+ print "\rA very long output statement : #{7}. Current thread: #{Thread.current}"
15
+ print "\rA very long output statement : #{8}. Current thread: #{Thread.current}"
16
+ end
17
+ puts
18
+ }
19
+ bm.report{
20
+ i = 0
21
+
22
+ 1_000.times do
23
+ Fibril do
24
+ Fibril do
25
+ print "\rA very long output statement : #{1}. Current thread: #{Thread.current}"
26
+ print "\rA very long output statement : #{2}. Current thread: #{Thread.current}"
27
+ tick
28
+ print "\rA very long output statement : #{3}. Current thread: #{Thread.current}"
29
+ print "\rA very long output statement : #{4}. Current thread: #{Thread.current}"
30
+ end
31
+
32
+ Fibril do
33
+ print "\rA very long output statement : #{5}. Current thread: #{Thread.current}"
34
+ print "\rA very long output statement : #{6}. Current thread: #{Thread.current}"
35
+ tick
36
+ print "\rA very long output statement : #{7}. Current thread: #{Thread.current}"
37
+ print "\rA very long output statement : #{8}. Current thread: #{Thread.current}"
38
+ end
39
+ end
40
+ end
41
+ puts
42
+ }
43
+ bm.report{
44
+ i = 0
45
+ 1_000.times do
46
+ Thread.new do
47
+ [
48
+ Thread.new do
49
+ print "\rA very long output statement : #{1}. Current thread: #{Thread.current}"
50
+ print "\rA very long output statement : #{2}. Current thread: #{Thread.current}"
51
+ print "\rA very long output statement : #{3}. Current thread: #{Thread.current}"
52
+ print "\rA very long output statement : #{4}. Current thread: #{Thread.current}"
53
+ end,
54
+ Thread.new do
55
+ print "\rA very long output statement : #{5}. Current thread: #{Thread.current}"
56
+ print "\rA very long output statement : #{6}. Current thread: #{Thread.current}"
57
+ print "\rA very long output statement : #{7}. Current thread: #{Thread.current}"
58
+ print "\rA very long output statement : #{8}. Current thread: #{Thread.current}"
59
+ end
60
+ ].each(&:join)
61
+ end.join
62
+ end
63
+ puts
64
+ }
65
+ end
66
+
67
+ # Thread.new do
68
+ # [
69
+ # Thread.new do
70
+ # print "\rBig very very very very long message 1"
71
+ # print "\rBig very very very very long message 2"
72
+ # print "\rBig very very very very long message 5"
73
+ # print "\rBig very very very very long message 6"
74
+ # end,
75
+ # Thread.new do
76
+ # print "\rBig very very very very long message 3"
77
+ # print "\rBig very very very very long message 4"
78
+ # print "\rBig very very very very long message 7"
79
+ # print "\rBig very very very very long message 8"
80
+ # end
81
+ # ].each(&:join)
82
+ # end.join
@@ -0,0 +1,27 @@
1
+ require_relative "../lib/fibril/loop"
2
+
3
+ fibril{
4
+ [1,2,3].async.each do |i|
5
+ puts i
6
+ end
7
+ }
8
+
9
+ fibril{
10
+ [4,5,6].async.each do |i|
11
+ puts i
12
+ end
13
+ }
14
+ # Kernel.send :alias_method, :old_puts, :puts
15
+ # Fibril::async :puts
16
+
17
+ # puts 1
18
+ # puts 2
19
+ # puts 3
20
+
21
+ # puts 4
22
+ # puts 5
23
+ # puts 6
24
+
25
+ # sleep
26
+
27
+ # old_puts "Done!"
@@ -0,0 +1,15 @@
1
+ require_relative "../lib/fibril/loop"
2
+
3
+ fibril{
4
+ variables.guard.await
5
+ puts "First finished"
6
+ }
7
+
8
+ variables.guard = fibril{
9
+ sleep 0.2
10
+ puts "Second finished"
11
+ }.until{ true }
12
+
13
+ await(variables.guard){
14
+ puts "Guard depleted"
15
+ }
@@ -0,0 +1,13 @@
1
+ require_relative "../lib/fibril/loop"
2
+
3
+ fibril{
4
+ puts 1
5
+ tick
6
+ puts 3
7
+ }
8
+
9
+ fibril{
10
+ puts 2
11
+ tick
12
+ puts 4
13
+ }
@@ -0,0 +1,23 @@
1
+ require_relative "../lib/fibril/loop"
2
+
3
+ pending = promise{ sleep 1; 3 }
4
+ pending2 = promise{ sleep 0.1; 4 }
5
+
6
+ fibril{
7
+ puts "First"
8
+ puts async.await(pending)
9
+ puts "First"
10
+ }
11
+
12
+ fibril{
13
+ puts "Second"
14
+ result = async.await_all pending, pending2
15
+ puts "Second"
16
+ puts "Result is #{result}"
17
+ }
18
+
19
+ fibril{
20
+ puts "Third"
21
+ puts async.await(pending2)
22
+ puts "Third"
23
+ }
data/fibril.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'fibril/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "fibril"
8
+ spec.version = Fibril::VERSION
9
+ spec.authors = ["Wouter Coppieters"]
10
+ spec.email = ["wouter.coppieters@youdo.co.nz"]
11
+
12
+ spec.summary = "Fibril"
13
+ spec.description = "Fibril"
14
+ spec.homepage = "https://github.com/wouterken/Fibril"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
+ # delete this section to allow pushing this gem to any host.
19
+
20
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
+ spec.bindir = "exe"
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ["lib"]
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.10"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ spec.add_development_dependency "byebug", "~> 8.2.1"
28
+ spec.add_development_dependency "pry-byebug", "~> 3.3.0"
29
+ spec.add_development_dependency 'pry', '~> 0.10.2', '>= 0.10.0'
30
+ spec.add_development_dependency "minitest"
31
+ end
data/fibril.todo ADDED
@@ -0,0 +1,39 @@
1
+ ✔ Guard becomes event driven - no polling @done (16-02-18 09:28)
2
+ ✔ Fibrils return single count guards @done (16-02-18 09:28)
3
+ ✔ Can await one or more guards @done (16-02-18 09:28)
4
+ ✔ Use semaphore type object for synchronising multiple async calls @done (16-02-18 19:03)
5
+ ✔ Use counter to determine if any work left to do, if not auto-stop @done (16-02-18 19:03)
6
+ ✔ Create event loop import @done (16-02-18 21:15)
7
+ ✔ Create continous and counting loop construct @done (16-02-18 21:15)
8
+ ✔ Create async object @done (16-02-19 07:35)
9
+ ✔ Create promises @done (16-02-19 07:49)
10
+ ✔ Turn into gem @done (16-02-19 07:49)
11
+
12
+ ☐ Add keywords syntax highlighting in Sublime
13
+ - promise, async, fibril, await, await_all
14
+
15
+ ☐ Create smarter loop importer. Finds import statement and only evals everything past itself
16
+
17
+ ☐ Write performance tests
18
+ ☐ Use efficient ring buffer as queue and block when full
19
+
20
+ ☐ Examples:
21
+
22
+ ☐ Weave with tick
23
+ ☐ Weave with async IO
24
+ ☐ Weave external await
25
+ ☐ Weave with internal await
26
+ ☐ Promises
27
+
28
+ ☐ Disk read + write
29
+ ☐ Database queries using AR
30
+ ☐ Network IO
31
+ ☐ Asyncifying common functions
32
+ ☐ Asyncifying class methods
33
+ ☐ Asyncifying instance methods
34
+ ☐ Asyncifying module methods
35
+ ☐ Comparison to thread
36
+ ☐ Comparison to event machine
37
+
38
+ ☐ Rename to Weave
39
+ ☐ Refactor
@@ -0,0 +1,11 @@
1
+ require_relative '../fibril'
2
+ require 'pry'
3
+
4
+ call_stack = caller
5
+ lines = IO.read(call_stack[0][/.*?(?=\:)/,0]).split("\n")
6
+
7
+ if %r{require.*".*?fibril/loop"} =~ lines[0].gsub("'",?").gsub(/\s+/,' ').strip
8
+ $LOAD_PATH << '.'
9
+ fibril{ eval lines[1..-1].join("\n") }
10
+ exit(0)
11
+ end
@@ -0,0 +1,3 @@
1
+ class Fibril < Fiber
2
+ VERSION = "0.0.1"
3
+ end
data/lib/fibril.rb ADDED
@@ -0,0 +1,241 @@
1
+ require "fibril/version"
2
+ require 'ostruct'
3
+
4
+
5
+ class Fibril < Fiber
6
+ class << self
7
+ attr_accessor :running, :stopped, :queue, :task_count, :guards, :current, :id_seq
8
+ end
9
+
10
+ self.queue = []
11
+ self.guards = Hash.new{|h,k| }
12
+ self.id_seq = 0
13
+
14
+ attr_accessor :fiber, :guards, :block, :id
15
+
16
+ def self.log(msg)
17
+ # puts msg
18
+ end
19
+
20
+ def variables
21
+ @@variables ||= OpenStruct.new
22
+ end
23
+
24
+ def initialize(&blk)
25
+ self.id = Fibril.id_seq += 1
26
+ self.block = blk
27
+ self.guards = []
28
+ define_singleton_method :execute_fibril, self.block
29
+ super(&method(:execute))
30
+ Fibril.queue << self
31
+ end
32
+
33
+ def reset(guard)
34
+ copy = Fibril.new(&self.block)
35
+ copy.guards << guard
36
+ return copy
37
+ end
38
+
39
+ def execute
40
+ Fibril.task_count += 1
41
+ execute_fibril
42
+ self.guards.each(&:visit)
43
+ Fibril.task_count -= 1
44
+ Fibril.log "Ending #{id}"
45
+ end
46
+
47
+ def tick
48
+ Fibril.enqueue self
49
+ self.yield
50
+ end
51
+
52
+ def self.enqueue(fibril)
53
+ Fibril.log "Enqueing fibril #{fibril.id}"
54
+ Fibril.queue << fibril
55
+ end
56
+
57
+ def yield
58
+ Fibril.log "Yielding #{id}"
59
+ Fiber.yield
60
+ end
61
+
62
+ def current
63
+ self
64
+ end
65
+
66
+ def self.deplete_guard(guard)
67
+ return unless waiters = guards[guard.id]
68
+ switches = waiters[:switches]
69
+ switches[guard.id] = true
70
+ waiters[:block][] if switches.values.all?
71
+ end
72
+
73
+ def await(*guards, &block)
74
+
75
+ if guards.length == 1 && guards[0].kind_of?(Promise)
76
+ return await_promise(guards[0])
77
+ end
78
+
79
+ await_block = {
80
+ switches: Hash[guards.map{|guard| [guard.id, false]}],
81
+ block: block
82
+ }
83
+ guards.each do |guard|
84
+ Fibril.guards[guard.id] = await_block
85
+ end
86
+ end
87
+
88
+ def promise(&blk)
89
+ return Promise.new(&blk)
90
+ end
91
+
92
+ def await_promise(promise)
93
+ promise.await
94
+ end
95
+
96
+ def await_all(*promises)
97
+ promises.map(&:await)
98
+ end
99
+
100
+ def self.stop
101
+ Fibril do
102
+ Fibril.stopped = true
103
+ end
104
+ end
105
+
106
+ def resume
107
+ Fibril.current = self
108
+ Fibril.log "Resuming #{id}"
109
+ super
110
+ end
111
+
112
+ def self.start
113
+ self.task_count = 0
114
+ self.stopped = false
115
+ self.running = true
116
+ if queue.any?
117
+ queue.shift.resume
118
+ self.loop if queue.any? || Fibril.task_count > 0
119
+ end
120
+ self.running = false
121
+ end
122
+
123
+ def self.loop
124
+ Fibril.log "Starting loop inside #{Fibril.current}"
125
+ while ((Fibril.task_count > 0 || queue.any?) && !Fibril.stopped)
126
+ Fibril.queue.shift.resume if Fibril.queue.any?
127
+ end
128
+ end
129
+
130
+ def Guard(i, fibril)
131
+ return Guard.new(i, fibril)
132
+ end
133
+
134
+ class AsyncProxy
135
+ attr_accessor :target
136
+
137
+ def initialize(target)
138
+ self.target = target
139
+ end
140
+
141
+ def method_missing(name, *args, &block)
142
+ waiting = Fibril.current
143
+ Thread.new do
144
+ target.send(name, *args, &block).tap{ Fibril.enqueue waiting }
145
+ end.tap{
146
+ Fibril.current.yield
147
+ }.value
148
+ end
149
+ end
150
+
151
+
152
+ class Guard
153
+ class << self
154
+ attr_accessor :guard_seq
155
+ end
156
+
157
+ attr_accessor :fibril, :id, :break_condition, :depleted
158
+
159
+ self.guard_seq = 0
160
+
161
+ def self.create(fibril, counter=1)
162
+ self.guard_seq += 1
163
+ guard = Fibril::Guard.new(self.guard_seq, counter, fibril)
164
+ fibril.guards << guard
165
+ return guard
166
+ end
167
+
168
+ def await
169
+ Fibril.current.tick while !self.depleted
170
+ end
171
+
172
+ def initialize(id, counter, fibril)
173
+ self.id = id
174
+ self.fibril = fibril
175
+ self.break_condition = 1
176
+ end
177
+
178
+ def visit
179
+ case self.break_condition
180
+ when Proc
181
+ if self.break_condition[]
182
+ self.depleted = true
183
+ Fibril.deplete_guard(self)
184
+ else
185
+ self.fibril = self.fibril.reset(self)
186
+ end
187
+ else
188
+ self.break_condition -= 1
189
+ if self.break_condition.zero?
190
+ self.depleted = true
191
+ Fibril.deplete_guard(self)
192
+ else
193
+ self.fibril = self.fibril.reset(self)
194
+ end
195
+ end
196
+ end
197
+
198
+ def loop(break_condition=-1, &blck)
199
+ self.break_condition = block_given? ? blck : break_condition
200
+ self
201
+ end
202
+
203
+ def while(&blk)
204
+ loop{ !blk[] }
205
+ end
206
+
207
+ def until(&blk)
208
+ loop{ blk[] }
209
+ end
210
+ end
211
+
212
+ class Promise
213
+ attr_accessor :promise_thread
214
+ def initialize(&blk)
215
+ self.promise_thread = Thread.new(&blk)
216
+ end
217
+
218
+ def await
219
+ self.promise_thread.join.value
220
+ end
221
+ end
222
+
223
+ end
224
+
225
+ class ::BasicObject
226
+ def async
227
+ @async_proxy ||= ::Fibril::AsyncProxy.new(self)
228
+ end
229
+ end
230
+
231
+
232
+ def Fibril(&block)
233
+ fibril = Fibril.new(&block).tap do |t|
234
+ Fibril.start unless Fibril.running
235
+ end
236
+ guard = Fibril::Guard.create(fibril)
237
+ end
238
+
239
+
240
+
241
+ Kernel.send :alias_method, :fibril, :Fibril
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fibril
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Wouter Coppieters
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-02-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: byebug
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 8.2.1
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 8.2.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry-byebug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 3.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.3.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.10.2
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: 0.10.0
79
+ type: :development
80
+ prerelease: false
81
+ version_requirements: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - "~>"
84
+ - !ruby/object:Gem::Version
85
+ version: 0.10.2
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 0.10.0
89
+ - !ruby/object:Gem::Dependency
90
+ name: minitest
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ description: Fibril
104
+ email:
105
+ - wouter.coppieters@youdo.co.nz
106
+ executables: []
107
+ extensions: []
108
+ extra_rdoc_files: []
109
+ files:
110
+ - ".gitignore"
111
+ - ".travis.yml"
112
+ - Gemfile
113
+ - LICENSE.txt
114
+ - README.md
115
+ - Rakefile
116
+ - bin/fibril
117
+ - bin/setup
118
+ - examples/example_1.rb
119
+ - examples/example_2.rb
120
+ - examples/example_3.rb
121
+ - examples/example_async.rb
122
+ - examples/example_guard.rb
123
+ - examples/example_loop.rb
124
+ - examples/example_promise.rb
125
+ - fibril.gemspec
126
+ - fibril.todo
127
+ - lib/fibril.rb
128
+ - lib/fibril/loop.rb
129
+ - lib/fibril/version.rb
130
+ homepage: https://github.com/wouterken/Fibril
131
+ licenses:
132
+ - MIT
133
+ metadata: {}
134
+ post_install_message:
135
+ rdoc_options: []
136
+ require_paths:
137
+ - lib
138
+ required_ruby_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ required_rubygems_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ requirements: []
149
+ rubyforge_project:
150
+ rubygems_version: 2.4.5
151
+ signing_key:
152
+ specification_version: 4
153
+ summary: Fibril
154
+ test_files: []