async 1.15.5 → 1.16.0

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: 9054b68547d0e94b18941009bd5027671653e5b13c9e02ef5cecc02660d03b64
4
- data.tar.gz: 9c2ef872af0bcb90a0bcbfcb757fb4eb1c5a416c52d93176fab13ade58894b2a
3
+ metadata.gz: d32f66a08662551d096e73d45b968db7ba3c1faac364dd30a6727e6b987fc060
4
+ data.tar.gz: daaecb80e3223b8fbd31798c6d45f8c7a03ec45544fceea966ffd1cdc075264a
5
5
  SHA512:
6
- metadata.gz: 0f4b0338a5cda22e46ffff913033d76092225dbec527d35985c477c6bdfa46fda4f38ccb36257994ae675088091abbdc2c1d6bc73a951ecea5d743dfc7c5f007
7
- data.tar.gz: f81dc50f4e9933aacf9132e59651238e5bd40889fdd022551fff024731129d1ea5c5cc07fae03a12594705e941353e5ddb18baec36ad17d40b646fae2e8cfa5e
6
+ metadata.gz: 138843f67fa5d3d700a64d034d8ca70b826f26d48392e2f7bfd404bc77d6045ee7c492f823fb33263a1896a03988e57f9d6d0ba78c6ce7ab48ba48ee29a9460a
7
+ data.tar.gz: 3040bffa50775ca7fa3fde5dd1a6d6c4cde77ffcfd079fddc5118310ff9cf0057842b1525b8c9c0ec1b07192af56baf20e6298efaa359b2bb2c0e55bed948e5a
@@ -19,11 +19,12 @@ Gem::Specification.new do |spec|
19
19
  spec.executables = spec.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
20
20
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
21
  spec.require_paths = ["lib"]
22
-
22
+
23
23
  spec.required_ruby_version = ">= 2.2.7"
24
-
24
+
25
25
  spec.add_runtime_dependency "nio4r", "~> 2.3"
26
26
  spec.add_runtime_dependency "timers", "~> 4.1"
27
+ spec.add_runtime_dependency "event", "~> 1.1"
27
28
 
28
29
  spec.add_development_dependency "async-rspec", "~> 1.1"
29
30
 
@@ -18,191 +18,8 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- require_relative 'terminal'
22
-
23
- # Downstream gems often use `Logger:::LEVEL` constants, so we pull this in so they are available. That being said, the code should be fixed.
24
- require 'logger'
21
+ require 'event/console'
25
22
 
26
23
  module Async
27
- class Logger
28
- class Buffer < StringIO
29
- def initialize(prefix = nil)
30
- @prefix = prefix
31
-
32
- super()
33
- end
34
-
35
- def puts(*args, prefix: @prefix)
36
- args.each do |arg|
37
- self.write(prefix) if prefix
38
-
39
- super(arg)
40
- end
41
- end
42
- end
43
-
44
- LEVELS = {debug: 0, info: 1, warn: 2, error: 3, fatal: 4}
45
-
46
- LEVELS.each do |name, level|
47
- const_set(name.to_s.upcase, level)
48
-
49
- define_method(name) do |subject = nil, *arguments, &block|
50
- enabled = @subjects[subject.class]
51
-
52
- if enabled == true or (enabled != false and level >= @level)
53
- self.format(subject, *arguments, &block)
54
- end
55
- end
56
-
57
- define_method("#{name}!") do
58
- @level = level
59
- end
60
- end
61
-
62
- def initialize(output, level: 1)
63
- @output = output
64
- @level = level
65
- @start = Time.now
66
-
67
- @terminal = Terminal.new(output)
68
- @reset_style = @terminal.reset
69
- @prefix_style = @terminal.color(Terminal::Colors::CYAN)
70
- @subject_style = @terminal.color(nil, nil, Terminal::Attributes::BOLD)
71
- @exception_title_style = @terminal.color(Terminal::Colors::RED, nil, Terminal::Attributes::BOLD)
72
- @exception_details_style = @terminal.color(Terminal::Colors::YELLOW)
73
- @exception_line_style = @terminal.color(Terminal::Colors::RED)
74
-
75
- @subjects = {}
76
- end
77
-
78
- attr :level
79
-
80
- def level= value
81
- if value.is_a? Symbol
82
- @level = LEVELS[value]
83
- else
84
- @level = value
85
- end
86
- end
87
-
88
- def enabled?(subject)
89
- @subjects[subject.class] == true
90
- end
91
-
92
- def enable(subject)
93
- @subjects[subject.class] = true
94
- end
95
-
96
- def disable(subject)
97
- @subjects[subject.class] = false
98
- end
99
-
100
- def log(level, *arguments, &block)
101
- unless level.is_a? Symbol
102
- level = LEVELS[level]
103
- end
104
-
105
- self.send(level, *arguments, &block)
106
- end
107
-
108
- def format(subject = nil, *arguments, &block)
109
- prefix = time_offset_prefix
110
- indent = " " * prefix.size
111
-
112
- buffer = Buffer.new("#{indent}| ")
113
-
114
- if subject
115
- format_subject(prefix, subject, output: buffer)
116
- end
117
-
118
- arguments.each do |argument|
119
- format_argument(argument, output: buffer)
120
- end
121
-
122
- if block_given?
123
- if block.arity.zero?
124
- format_argument(yield, output: buffer)
125
- else
126
- yield(buffer, @terminal)
127
- end
128
- end
129
-
130
- @output.write buffer.string
131
- end
132
-
133
- def format_argument(argument, output: @output)
134
- if argument.is_a? Exception
135
- format_exception(argument, output: output)
136
- else
137
- format_value(argument, output: output)
138
- end
139
- end
140
-
141
- def format_exception(exception, prefix = nil, pwd: Dir.pwd, output: @output)
142
- lines = exception.message.lines.map(&:chomp)
143
-
144
- output.puts " #{prefix}#{@exception_title_style}#{exception.class}#{@reset_style}: #{lines.shift}"
145
-
146
- lines.each do |line|
147
- output.puts " #{@exception_details_style}" + line + @reset_style
148
- end
149
-
150
- exception.backtrace.each_with_index do |line, index|
151
- path, offset, message = line.split(":")
152
-
153
- # Make the path a bit more readable
154
- path.gsub!(/^#{pwd}\//, "./")
155
-
156
- output.puts " #{index == 0 ? "→" : " "} #{@exception_line_style}#{path}:#{offset}#{@reset_style} #{message}"
157
- end
158
-
159
- if exception.cause
160
- format_exception(exception.cause, "Caused by ", pwd: pwd, output: output)
161
- end
162
- end
163
-
164
- def format_subject(prefix, subject, output: @output)
165
- output.puts "#{@subject_style}#{subject}#{@reset_style}", prefix: "#{@prefix_style}#{prefix}: "
166
- end
167
-
168
- def format_value(value, output: @output)
169
- string = value.to_s
170
-
171
- string.each_line do |line|
172
- output.puts "#{line}"
173
- end
174
- end
175
-
176
- def time_offset_prefix
177
- offset = Time.now - @start
178
- minutes = (offset/60).floor
179
- seconds = (offset - (minutes*60))
180
-
181
- if minutes > 0
182
- "#{minutes}m#{seconds.floor}s"
183
- else
184
- "#{seconds.round(2)}s"
185
- end.rjust(6)
186
- end
187
- end
188
-
189
- # The Async Logger class.
190
- class << self
191
- # @attr logger [Logger] the global logger instance used by `Async`.
192
- attr :logger
193
-
194
- # Set the default log level based on `$DEBUG` and `$VERBOSE`.
195
- def default_log_level
196
- if $DEBUG
197
- Logger::DEBUG
198
- elsif $VERBOSE
199
- Logger::INFO
200
- else
201
- Logger::WARN
202
- end
203
- end
204
- end
205
-
206
- # Create the logger instance.
207
- @logger = Logger.new($stderr, level: self.default_log_level)
24
+ extend Event::Console
208
25
  end
@@ -51,7 +51,7 @@ module Async
51
51
  super()
52
52
 
53
53
  @limit = limit
54
- @full = Async::Condition.new
54
+ @full = Async::Queue.new
55
55
  end
56
56
 
57
57
  attr :limit
@@ -63,7 +63,7 @@ module Async
63
63
 
64
64
  def enqueue item
65
65
  if limited?
66
- @full.wait
66
+ @full.dequeue
67
67
  end
68
68
 
69
69
  super
@@ -72,7 +72,7 @@ module Async
72
72
  def dequeue
73
73
  item = super
74
74
 
75
- @full.signal unless @full.empty?
75
+ @full.enqueue(nil) unless @full.empty?
76
76
 
77
77
  return item
78
78
  end
@@ -193,7 +193,8 @@ module Async
193
193
 
194
194
  return initial_task
195
195
  ensure
196
- Async.logger.debug(self) {"Exiting run-loop because #{$! ? $!.inspect : 'finished'}."}
196
+ Async.logger.debug(self) {"Exiting run-loop because #{$! ? $! : 'finished'}."}
197
+
197
198
  @stopped = true
198
199
  end
199
200
 
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Async
22
- VERSION = "1.15.5"
22
+ VERSION = "1.16.0"
23
23
  end
@@ -53,4 +53,25 @@ RSpec.describe Async::LimitedQueue do
53
53
  subject.enqueue(10)
54
54
  expect(subject).to be_limited
55
55
  end
56
+
57
+ it 'should resume waiting tasks in order' do
58
+ total_resumed = 0
59
+ total_dequeued = 0
60
+ Async do |producer|
61
+ 10.times do
62
+ producer.async do
63
+ subject.enqueue('foo')
64
+ total_resumed += 1
65
+ end
66
+ end
67
+ end
68
+ Async do |consumer|
69
+ 10.times do
70
+ subject.dequeue
71
+ total_dequeued += 1
72
+
73
+ expect(total_resumed).to be == total_dequeued
74
+ end
75
+ end
76
+ end
56
77
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.15.5
4
+ version: 1.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-03 00:00:00.000000000 Z
11
+ date: 2019-03-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nio4r
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '4.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: event
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.1'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.1'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: async-rspec
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -144,7 +158,6 @@ files:
144
158
  - lib/async/reactor.rb
145
159
  - lib/async/semaphore.rb
146
160
  - lib/async/task.rb
147
- - lib/async/terminal.rb
148
161
  - lib/async/version.rb
149
162
  - lib/async/wrapper.rb
150
163
  - logo.png
@@ -154,7 +167,6 @@ files:
154
167
  - spec/async/clock_spec.rb
155
168
  - spec/async/condition_examples.rb
156
169
  - spec/async/condition_spec.rb
157
- - spec/async/logger_spec.rb
158
170
  - spec/async/node_spec.rb
159
171
  - spec/async/notification_spec.rb
160
172
  - spec/async/performance_spec.rb
@@ -193,7 +205,6 @@ test_files:
193
205
  - spec/async/clock_spec.rb
194
206
  - spec/async/condition_examples.rb
195
207
  - spec/async/condition_spec.rb
196
- - spec/async/logger_spec.rb
197
208
  - spec/async/node_spec.rb
198
209
  - spec/async/notification_spec.rb
199
210
  - spec/async/performance_spec.rb
@@ -1,99 +0,0 @@
1
- # Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
20
-
21
- module Async
22
- # Styled terminal output. **Internal Use Only**
23
- class Terminal
24
- module Attributes
25
- NORMAL = 0
26
- BOLD = 1
27
- FAINT = 2
28
- ITALIC = 3
29
- UNDERLINE = 4
30
- BLINK = 5
31
- REVERSE = 7
32
- HIDDEN = 8
33
- end
34
-
35
- module Colors
36
- BLACK = 0
37
- RED = 1
38
- GREEN = 2
39
- YELLOW = 3
40
- BLUE = 4
41
- MAGENTA = 5
42
- CYAN = 6
43
- WHITE = 7
44
- DEFAULT = 9
45
- end
46
-
47
- def initialize(output)
48
- @output = output
49
- end
50
-
51
- def tty?
52
- @output.isatty
53
- end
54
-
55
- def color(foreground, background = nil, attributes = nil)
56
- return nil unless tty?
57
-
58
- buffer = String.new
59
-
60
- buffer << "\e["
61
- first = true
62
-
63
- if attributes
64
- buffer << (attributes).to_s
65
- first = false
66
- end
67
-
68
- if foreground
69
- if !first
70
- buffer << ";"
71
- else
72
- first = false
73
- end
74
-
75
- buffer << (30 + foreground).to_s
76
- end
77
-
78
- if background
79
- if !first
80
- buffer << ";"
81
- else
82
- first = false
83
- end
84
-
85
- buffer << (40 + background).to_s
86
- end
87
-
88
- buffer << 'm'
89
-
90
- return buffer
91
- end
92
-
93
- def reset
94
- return nil unless tty?
95
-
96
- return "\e[0m"
97
- end
98
- end
99
- end
@@ -1,101 +0,0 @@
1
- # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
20
-
21
- RSpec.describe Async::Logger do
22
- let(:output) {StringIO.new}
23
- subject{described_class.new(output)}
24
-
25
- let(:message) {"Hello World"}
26
-
27
- context "default log level" do
28
- it "logs info" do
29
- subject.info(message)
30
-
31
- expect(output.string).to include message
32
- end
33
-
34
- it "doesn't log debug" do
35
- subject.debug(message)
36
-
37
- expect(output.string).to_not include message
38
- end
39
-
40
- it "can log to buffer" do
41
- subject.info do |buffer|
42
- buffer << message
43
- end
44
-
45
- expect(output.string).to include message
46
- end
47
- end
48
-
49
- described_class::LEVELS.each do |name, level|
50
- it "can log #{name} messages" do
51
- subject.level = level
52
- subject.log(name, message)
53
-
54
- expect(output.string).to include message
55
- end
56
- end
57
-
58
- describe '#enable' do
59
- let(:object) {Async::Node.new}
60
-
61
- it "can enable specific subjects" do
62
- subject.warn!
63
-
64
- subject.enable(object)
65
- expect(subject).to be_enabled(object)
66
-
67
- subject.debug(object, message)
68
- expect(output.string).to include message
69
- end
70
- end
71
- end
72
-
73
- RSpec.describe Async.logger do
74
- describe 'default_log_level' do
75
- let!(:debug) {$DEBUG}
76
- after {$DEBUG = debug}
77
-
78
- let!(:verbose) {$VERBOSE}
79
- after {$VERBOSE = verbose}
80
-
81
- it 'should set default log level' do
82
- $DEBUG = false
83
- $VERBOSE = false
84
-
85
- expect(Async.default_log_level).to be == Async::Logger::WARN
86
- end
87
-
88
- it 'should set default log level based on $DEBUG' do
89
- $DEBUG = true
90
-
91
- expect(Async.default_log_level).to be == Async::Logger::DEBUG
92
- end
93
-
94
- it 'should set default log level based on $VERBOSE' do
95
- $DEBUG = false
96
- $VERBOSE = true
97
-
98
- expect(Async.default_log_level).to be == Async::Logger::INFO
99
- end
100
- end
101
- end