green 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.
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "eventmachine", "~> 1.0.0.beta.4"
4
+ gem "em-http-request"
5
+ gem "unicorn"
6
+
7
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,34 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ green (0.0.1)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ addressable (2.2.7)
10
+ em-http-request (1.0.0)
11
+ addressable (>= 2.2.3)
12
+ em-socksify
13
+ eventmachine (>= 1.0.0.beta.3)
14
+ http_parser.rb (>= 0.5.2)
15
+ em-socksify (0.2.0)
16
+ eventmachine (>= 1.0.0.beta.4)
17
+ eventmachine (1.0.0.mail.7)
18
+ http_parser.rb (0.5.3)
19
+ kgio (2.7.4)
20
+ rack (1.4.1)
21
+ raindrops (0.8.0)
22
+ unicorn (4.2.1)
23
+ kgio (~> 2.6)
24
+ rack
25
+ raindrops (~> 0.7)
26
+
27
+ PLATFORMS
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ em-http-request
32
+ eventmachine (~> 1.0.0.beta.4)
33
+ green!
34
+ unicorn
data/README.md ADDED
@@ -0,0 +1,55 @@
1
+ Cooperative multitasking for Ruby. Proof of concept.
2
+
3
+ Based on Ruby 1.9 Fibers, but unlike EM::Synchrony it uses symmetric coroutines (only #current and #transfer used) and HUB-orientend architecture. So coroutines transfer control to HUB and HUB transfer control to coroutines. Coroutines never tranfer control to each other.
4
+
5
+ In comparison with EM-Synchrony it allows:
6
+ - develop real complex cooperative multitasking apps;
7
+ - timeouts. Yes, in common case you cannot add timeout with EM-Synchrony;
8
+ - kill greens. And it safe unlike kill Threads;
9
+ - works with REPL and debugger. EM-Synchrony uses Fiber.yield, so you cannot run nothing in REPL;
10
+ - works with every environment. You can run nonblock web-applications with Unicorn;
11
+ - compatible with Ruby's Enumerator and with any other uses of Fibers themself (see https://github.com/igrigorik/em-synchrony/issues/114)
12
+
13
+ ```ruby
14
+ require 'green'
15
+ require 'green/group'
16
+ require 'green-em/em-http'
17
+
18
+ g = Green::Pool.new(size: 2)
19
+
20
+ urls = ['http://google.com', 'http://yandex.ru']
21
+
22
+ results = g.enumerator(urls) do |url|
23
+ EventMachine::HttpRequest.new(url).get
24
+ end.map { |i| i.response }
25
+
26
+ p results
27
+ ```
28
+
29
+ You can run it from Irb! ;)
30
+
31
+ You can add timeout:
32
+
33
+ ```ruby
34
+ require 'green'
35
+ require 'green/group'
36
+ require 'green-em/em-http'
37
+
38
+ g = Green::Pool.new(size: 2)
39
+
40
+ urls = ['http://google.com', 'http://yandex.ru']
41
+
42
+ begin
43
+ Green.timeout(1) do
44
+ results = g.enumerator(urls) do |url|
45
+ EventMachine::HttpRequest.new(url).get
46
+ end.map { |i| i.response }
47
+ p results
48
+ end
49
+ rescue Timeout::Error
50
+ p "Timeout!"
51
+ end
52
+ ```
53
+
54
+ And much more soon ;)
55
+
data/Rakefile ADDED
@@ -0,0 +1,131 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'date'
4
+
5
+ #############################################################################
6
+ #
7
+ # Helper functions
8
+ #
9
+ #############################################################################
10
+
11
+ def name
12
+ @name ||= Dir['*.gemspec'].first.split('.').first
13
+ end
14
+
15
+ def version
16
+ line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
17
+ line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
18
+ end
19
+
20
+ def date
21
+ Date.today.to_s
22
+ end
23
+
24
+ def rubyforge_project
25
+ name
26
+ end
27
+
28
+ def gemspec_file
29
+ "#{name}.gemspec"
30
+ end
31
+
32
+ def gem_file
33
+ "#{name}-#{version}.gem"
34
+ end
35
+
36
+ def replace_header(head, header_name)
37
+ head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
38
+ end
39
+
40
+ #############################################################################
41
+ #
42
+ # Standard tasks
43
+ #
44
+ #############################################################################
45
+
46
+
47
+ task :default => :spec
48
+ require 'rake/testtask'
49
+ Rake::TestTask.new(:spec) do |t|
50
+ t.libs << 'spec'
51
+ t.pattern = 'spec/**/*_spec.rb'
52
+ t.verbose = false
53
+ end
54
+
55
+ desc "Generate RCov test coverage and open in your browser"
56
+ task :coverage do
57
+ require 'rcov'
58
+ sh "rm -fr coverage"
59
+ sh "rcov test/test_*.rb"
60
+ sh "open coverage/index.html"
61
+ end
62
+
63
+ desc "Open an irb session preloaded with this library"
64
+ task :console do
65
+ sh "irb -rubygems -r ./lib/#{name}.rb"
66
+ end
67
+
68
+
69
+ #############################################################################
70
+ #
71
+ # Packaging tasks
72
+ #
73
+ #############################################################################
74
+
75
+ desc "Create tag v#{version} and build and push #{gem_file} to Rubygems"
76
+ task :release => :build do
77
+ unless `git branch` =~ /^\* master$/
78
+ puts "You must be on the master branch to release!"
79
+ exit!
80
+ end
81
+ sh "git commit --allow-empty -m 'Release #{version}'"
82
+ sh "git tag v#{version}"
83
+ sh "git push origin master"
84
+ sh "git push origin v#{version}"
85
+ sh "gem push pkg/#{name}-#{version}.gem"
86
+ end
87
+
88
+ desc "Build #{gem_file} into the pkg directory"
89
+ task :build => :gemspec do
90
+ sh "mkdir -p pkg"
91
+ sh "gem build #{gemspec_file}"
92
+ sh "mv #{gem_file} pkg"
93
+ end
94
+
95
+ desc "Generate #{gemspec_file}"
96
+ task :gemspec => :validate do
97
+ # read spec file and split out manifest section
98
+ spec = File.read(gemspec_file)
99
+ head, manifest, tail = spec.split(" # = MANIFEST =\n")
100
+
101
+ # replace name version and date
102
+ replace_header(head, :name)
103
+ replace_header(head, :version)
104
+ replace_header(head, :date)
105
+ #comment this out if your rubyforge_project has a different name
106
+ replace_header(head, :rubyforge_project)
107
+
108
+ # determine file list from git ls-files
109
+ files = `git ls-files`.
110
+ split("\n").
111
+ sort.
112
+ reject { |file| file =~ /^\./ }.
113
+ reject { |file| file =~ /^(rdoc|pkg)/ }.
114
+ map { |file| " #{file}" }.
115
+ join("\n")
116
+
117
+ # piece file back together and write
118
+ manifest = " s.files = %w[\n#{files}\n ]\n"
119
+ spec = [head, manifest, tail].join(" # = MANIFEST =\n")
120
+ File.open(gemspec_file, 'w') { |io| io.write(spec) }
121
+ puts "Updated #{gemspec_file}"
122
+ end
123
+
124
+ desc "Validate #{gemspec_file}"
125
+ task :validate do
126
+ libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
127
+ unless Dir['VERSION*'].empty?
128
+ puts "A `VERSION` file at root level violates Gem best practices."
129
+ exit!
130
+ end
131
+ end
data/Readme.md ADDED
@@ -0,0 +1,55 @@
1
+ Cooperative multitasking for Ruby. Proof of concept.
2
+
3
+ Based on Ruby 1.9 Fibers, but unlike EM::Synchrony it uses symmetric coroutines (only #current and #transfer used) and HUB-orientend architecture. So coroutines transfer control to HUB and HUB transfer control to coroutines. Coroutines never tranfer control to each other.
4
+
5
+ In comparison with EM-Synchrony it allows:
6
+ - develop real complex cooperative multitasking apps;
7
+ - timeouts. Yes, in common case you cannot add timeout with EM-Synchrony;
8
+ - kill greens. And it safe unlike kill Threads;
9
+ - works with REPL and debugger. EM-Synchrony uses Fiber.yield, so you cannot run nothing in REPL;
10
+ - works with every environment. You can run nonblock web-applications with Unicorn;
11
+ - compatible with Ruby's Enumerator and with any other uses of Fibers themself (see https://github.com/igrigorik/em-synchrony/issues/114)
12
+
13
+ ```ruby
14
+ require 'green'
15
+ require 'green/group'
16
+ require 'green-em/em-http'
17
+
18
+ g = Green::Pool.new(size: 2)
19
+
20
+ urls = ['http://google.com', 'http://yandex.ru']
21
+
22
+ results = g.enumerator(urls) do |url|
23
+ EventMachine::HttpRequest.new(url).get
24
+ end.map { |i| i.response }
25
+
26
+ p results
27
+ ```
28
+
29
+ You can run it from Irb! ;)
30
+
31
+ You can add timeout:
32
+
33
+ ```ruby
34
+ require 'green'
35
+ require 'green/group'
36
+ require 'green-em/em-http'
37
+
38
+ g = Green::Pool.new(size: 2)
39
+
40
+ urls = ['http://google.com', 'http://yandex.ru']
41
+
42
+ begin
43
+ Green.timeout(1) do
44
+ results = g.enumerator(urls) do |url|
45
+ EventMachine::HttpRequest.new(url).get
46
+ end.map { |i| i.response }
47
+ p results
48
+ end
49
+ rescue Timeout::Error
50
+ p "Timeout!"
51
+ end
52
+ ```
53
+
54
+ And much more soon ;)
55
+
data/app.ru ADDED
@@ -0,0 +1,24 @@
1
+ require 'bundler'
2
+
3
+ Bundler.setup
4
+
5
+ require 'green'
6
+ require 'green/group'
7
+
8
+ app = proc do |env|
9
+ start = Time.now
10
+ g = Green::Group.new
11
+ results = []
12
+ g.spawn do
13
+ Green.sleep 1
14
+ results << :fiz
15
+ end
16
+ g.spawn do
17
+ Green.sleep 1
18
+ results << :buz
19
+ end
20
+ g.join
21
+ [200, {"Content-Type" => 'plain/text'}, ["Execution time: #{Time.now - start}; Results: #{results.inspect}"]]
22
+ end
23
+
24
+ run app
data/green.gemspec ADDED
@@ -0,0 +1,48 @@
1
+ Gem::Specification.new do |s|
2
+ s.specification_version = 2 if s.respond_to? :specification_version=
3
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
4
+ s.rubygems_version = '1.3.5'
5
+
6
+ s.name = 'green'
7
+ s.version = '0.0.1'
8
+ s.date = '2012-05-09'
9
+ s.rubyforge_project = 'green'
10
+
11
+ s.summary = "Cooperative multitasking fo Ruby"
12
+ s.description = "Cooperative multitasking fo Ruby"
13
+
14
+ s.authors = ["Andrew Rudenko"]
15
+ s.email = 'ceo@prepor.ru'
16
+ s.homepage = 'http://github.com/prepor/green'
17
+
18
+ s.require_paths = %w[lib]
19
+
20
+ s.rdoc_options = ["--charset=UTF-8"]
21
+ s.extra_rdoc_files = %w[README.md]
22
+
23
+
24
+ # = MANIFEST =
25
+ s.files = %w[
26
+ Gemfile
27
+ Gemfile.lock
28
+ Rakefile
29
+ Readme.md
30
+ app.ru
31
+ green.gemspec
32
+ lib/green-em/em-http.rb
33
+ lib/green.rb
34
+ lib/green/event.rb
35
+ lib/green/ext.rb
36
+ lib/green/group.rb
37
+ lib/green/hub.rb
38
+ lib/green/hub/em.rb
39
+ lib/green/monkey.rb
40
+ lib/green/semaphore.rb
41
+ lib/green/tcp_socket.rb
42
+ ]
43
+ # = MANIFEST =
44
+
45
+ ## Test files will be grabbed from the file list. Make sure the path glob
46
+ ## matches what you actually use.
47
+ s.test_files = s.files.select { |path| path =~ /^spec\/.*_spec\.rb/ }
48
+ end
@@ -0,0 +1,29 @@
1
+ class Green
2
+ class Event
3
+ include Green::Waiter
4
+ attr_reader :waiters
5
+ def initialize
6
+ @waiters = []
7
+ @setted = false
8
+ end
9
+
10
+ def set(result = nil)
11
+ @setted = true
12
+ @result = result
13
+ waiters.each { |v| Green.hub.callback { v.switch } }
14
+ end
15
+
16
+ def wait
17
+ if @setted
18
+ @result
19
+ else
20
+ waiters << Green.current
21
+ Green.hub.wait self, Green.current
22
+ end
23
+ end
24
+
25
+ def green_cancel(waiter)
26
+ waiters.delete waiter
27
+ end
28
+ end
29
+ end
data/lib/green/ext.rb ADDED
@@ -0,0 +1,25 @@
1
+ class Fiber
2
+
3
+ # def self.new
4
+ # super.tap { |o| o[:green] = Green.current }
5
+ # end
6
+
7
+ #Attribute Reference--Returns the value of a fiber-local variable, using
8
+ #either a symbol or a string name. If the specified variable does not exist,
9
+ #returns nil.
10
+ def [](key)
11
+ local_fiber_variables[key]
12
+ end
13
+
14
+ #Attribute Assignment--Sets or creates the value of a fiber-local variable,
15
+ #using either a symbol or a string. See also Fiber#[].
16
+ def []=(key,value)
17
+ local_fiber_variables[key] = value
18
+ end
19
+
20
+ private
21
+
22
+ def local_fiber_variables
23
+ @local_fiber_variables ||= {}
24
+ end
25
+ end
@@ -0,0 +1,78 @@
1
+ require 'green/event'
2
+ require 'green/semaphore'
3
+ class Green
4
+ class Group
5
+ attr_reader :options, :greens
6
+ def initialize(options = {})
7
+ @options = options
8
+ @greens = []
9
+ end
10
+
11
+ def spawn(*args, &blk)
12
+ g = Green.spawn do
13
+ blk.call(*args)
14
+ end
15
+ add g
16
+ g.callback { discard g }
17
+ g
18
+ end
19
+
20
+ def apply(&blk)
21
+ spawn(&blk).join
22
+ end
23
+
24
+ def add(green)
25
+ greens << green
26
+ end
27
+
28
+ def discard(green)
29
+ greens.delete green
30
+ end
31
+
32
+ def join
33
+ while (g = greens.pop)
34
+ g.join
35
+ end
36
+ end
37
+
38
+ def enumerator(iterable, &blk)
39
+ iter = iterable.each
40
+ Enumerator.new do |y|
41
+ e = Event.new
42
+ begin
43
+ waiting = 0
44
+ while true
45
+ i = iter.next
46
+ waiting += 1
47
+ spawn(i) do |item|
48
+ y << blk.call(item)
49
+ waiting -= 1
50
+ e.set if waiting == 0
51
+ end
52
+ end
53
+ rescue StopIteration
54
+ e.wait
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ class Pool < Group
61
+ attr_reader :semaphore
62
+ def initialize(*args)
63
+ super
64
+ @semaphore = Semaphore.new(options[:size])
65
+ end
66
+
67
+ def spawn(*args, &blk)
68
+ semaphore.acquire
69
+ super() do
70
+ begin
71
+ blk.call(*args)
72
+ ensure
73
+ semaphore.release
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,44 @@
1
+ require 'eventmachine'
2
+
3
+ class ::EM::Timer
4
+ include Green::Waiter
5
+
6
+ def green_cancel
7
+ cancel
8
+ end
9
+ end
10
+
11
+ module ::EM::Deferrable
12
+ include Green::Waiter
13
+
14
+ def green_cancel
15
+ # instance_variable_get(:@callbacks).each { |c| cancel_callback c }
16
+ # instance_variable_get(:@errbacks).each { |c| cancel_errback c }
17
+ # cancel_timeout
18
+ end
19
+ end
20
+
21
+ class Green
22
+ class Hub
23
+ class EM < Hub
24
+ # если мы запускаем приложение внутри thin или rainbows с EM, то значит мы уже внутри EM-реактора, а hub должен переключиться в main тред.
25
+ def run
26
+ if ::EM.reactor_running?
27
+ loop do
28
+ Green.main.switch
29
+ end
30
+ else
31
+ ::EM.run
32
+ end
33
+ end
34
+
35
+ def timer(n, &blk)
36
+ ::EM::Timer.new(n, &blk)
37
+ end
38
+
39
+ def callback(&blk)
40
+ ::EM.next_tick(&blk)
41
+ end
42
+ end
43
+ end
44
+ end
data/lib/green/hub.rb ADDED
@@ -0,0 +1,42 @@
1
+ class Green
2
+ class Hub
3
+ attr_reader :g
4
+ def initialize
5
+ c = Green.current
6
+ callback { c.switch }
7
+ @g = Green.new do
8
+ run
9
+ end
10
+ g.switch
11
+ end
12
+
13
+ def switch
14
+ g.switch
15
+ end
16
+
17
+ def wait(waiter, *args)
18
+ switch
19
+ rescue => e
20
+ waiter.green_cancel(*args)
21
+ raise e
22
+ end
23
+
24
+ def sleep(n)
25
+ g = Green.current
26
+ t = timer(n) { g.switch }
27
+ wait t
28
+ end
29
+
30
+ def run
31
+ raise "override"
32
+ end
33
+
34
+ def timer(n, &blk)
35
+ raise "override"
36
+ end
37
+
38
+ def callback(&blk)
39
+ raise "override"
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,13 @@
1
+ class Green
2
+ module Monkey
3
+ extend self
4
+
5
+ def patch_constants
6
+
7
+ end
8
+
9
+ def patch_socket
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,44 @@
1
+ class Green
2
+ class Semaphore
3
+ include Green::Waiter
4
+ attr_accessor :counter
5
+ def initialize(value = 1)
6
+ @counter = value
7
+ @links = []
8
+ end
9
+
10
+ def acquire
11
+ if counter > 0
12
+ self.counter -= 1
13
+ true
14
+ else
15
+ g = Green.current
16
+ clb = rawlink { g.switch }
17
+ Green.hub.wait self, clb
18
+ self.counter -= 1
19
+ true
20
+ end
21
+ end
22
+
23
+ def release
24
+ self.counter += 1
25
+ if @links.size > 0
26
+ l = @links.pop
27
+ Green.hub.callback { l.call }
28
+ end
29
+ end
30
+
31
+ def rawlink(&clb)
32
+ @links << clb
33
+ clb
34
+ end
35
+
36
+ def unlink(clb)
37
+ @links.delete clb
38
+ end
39
+
40
+ def green_cancel(clb)
41
+ unlink clb
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,25 @@
1
+ class Green
2
+ class Socket < ::Socket
3
+ def accept
4
+ accept_nonblock
5
+ end
6
+
7
+ def connect(sock_addr)
8
+ connect_nonblock(sock_addr)
9
+ end
10
+
11
+ def send(mesg, flags = 0, dest_sockaddr = nil)
12
+ super(mesg, flags, dest_sockaddr)
13
+ rescue Errno::EAGAIN => e
14
+ wait_write
15
+ retry
16
+ end
17
+
18
+ def recv(maxlen, flags = 0)
19
+ super(maxlen, flags = 0)
20
+ rescue Errno::EAGAIN => e
21
+ wait_read
22
+ retry
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,29 @@
1
+ begin
2
+ require "em-http-request"
3
+ rescue LoadError => error
4
+ raise "Missing EM-Synchrony dependency: gem install em-http-request"
5
+ end
6
+
7
+ module EventMachine
8
+ class HTTPException < RuntimeError; end
9
+ module HTTPMethods
10
+ %w[get head post delete put].each do |type|
11
+ class_eval %[
12
+ alias :a#{type} :#{type}
13
+ def #{type}(options = {}, &blk)
14
+ g = Green.current
15
+
16
+ conn = setup_request(:#{type}, options, &blk)
17
+ if conn.error.nil?
18
+ conn.callback { g.switch(conn) }
19
+ conn.errback { g.throw(HTTPException.new(conn)) }
20
+
21
+ Green.hub.wait(conn)
22
+ else
23
+ raise HTTPException.new(conn)
24
+ end
25
+ end
26
+ ]
27
+ end
28
+ end
29
+ end
data/lib/green.rb ADDED
@@ -0,0 +1,117 @@
1
+ require 'fiber'
2
+ require 'pp'
3
+ require 'thread'
4
+
5
+ class Green
6
+ VERSION = "0.0.1"
7
+ class Proxy
8
+ attr_reader :f
9
+ def initialize
10
+ @f = Fiber.current
11
+ end
12
+
13
+ def switch(*args)
14
+ f.transfer(*args)
15
+ end
16
+ end
17
+
18
+ module Waiter
19
+ def green_cancel
20
+ raise "override"
21
+ end
22
+ end
23
+
24
+ class << self
25
+
26
+ def thread_locals
27
+ @thread_locals ||= {}
28
+ @thread_locals[Thread.current] ||= {}
29
+ end
30
+
31
+ def sleep(n)
32
+ Green.hub.sleep(n)
33
+ end
34
+
35
+ def main
36
+ MAIN
37
+ end
38
+
39
+ def current
40
+ Fiber.current[:green] || Proxy.new
41
+ end
42
+
43
+ def make_hub
44
+ Hub::EM.new
45
+ end
46
+
47
+ def hub
48
+ # thread_locals[:hub] ||= make_hub
49
+ @hub ||= make_hub
50
+ end
51
+
52
+ def spawn(&blk)
53
+ Green.new(&blk).tap { |o| o.start }
54
+ end
55
+
56
+ def timeout(n, &blk)
57
+ g = current
58
+ timer = hub.timer(n) do
59
+ g.switch Timeout::Error.new
60
+ end
61
+ res = blk.call
62
+ timer.cancel
63
+ res
64
+ end
65
+ end
66
+
67
+ # class GreenError < StandardError; end
68
+ # class GreenKill < GreenError; end
69
+
70
+ require 'green/ext'
71
+ require 'green/hub'
72
+
73
+ require 'green/hub/em'
74
+
75
+ attr_reader :f, :callbacks
76
+ def initialize()
77
+ @callbacks = []
78
+ @f = Fiber.new do
79
+ res = yield
80
+ @callbacks.each { |c| c.call(*res) }
81
+ Green.hub.switch
82
+ end
83
+ @f[:green] = self
84
+ end
85
+
86
+
87
+ def switch(*args)
88
+ return unless f.alive?
89
+ f.transfer(*args).tap do |*res|
90
+ res.size == 1 && res.first.is_a?(Exception) && raise(res.first)
91
+ end
92
+ end
93
+
94
+ def throw(exc = RuntimeException.new)
95
+ switch(exc)
96
+ end
97
+
98
+ def start
99
+ Green.hub.callback { self.switch }
100
+ end
101
+
102
+ def callback(&blk)
103
+ callbacks << blk
104
+ end
105
+
106
+ def join
107
+ g = Green.current
108
+ callback { |*res| g.switch(*res) }
109
+ Green.hub.switch
110
+ end
111
+
112
+ # def kill
113
+ # self.throw(GreenKill.new)
114
+ # end
115
+
116
+ MAIN = Fiber.current[:green] = Proxy.new
117
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: green
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Andrew Rudenko
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-05-09 00:00:00.000000000Z
13
+ dependencies: []
14
+ description: Cooperative multitasking fo Ruby
15
+ email: ceo@prepor.ru
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files:
19
+ - README.md
20
+ files:
21
+ - Gemfile
22
+ - Gemfile.lock
23
+ - Rakefile
24
+ - Readme.md
25
+ - app.ru
26
+ - green.gemspec
27
+ - lib/green-em/em-http.rb
28
+ - lib/green.rb
29
+ - lib/green/event.rb
30
+ - lib/green/ext.rb
31
+ - lib/green/group.rb
32
+ - lib/green/hub.rb
33
+ - lib/green/hub/em.rb
34
+ - lib/green/monkey.rb
35
+ - lib/green/semaphore.rb
36
+ - lib/green/tcp_socket.rb
37
+ - README.md
38
+ homepage: http://github.com/prepor/green
39
+ licenses: []
40
+ post_install_message:
41
+ rdoc_options:
42
+ - --charset=UTF-8
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ none: false
47
+ requirements:
48
+ - - ! '>='
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubyforge_project: green
59
+ rubygems_version: 1.8.10
60
+ signing_key:
61
+ specification_version: 2
62
+ summary: Cooperative multitasking fo Ruby
63
+ test_files: []
64
+ has_rdoc: