fibril 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []