async-await 0.5.0 → 0.7.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 982110e1afe4ee24f5931671df9df8036170b4b2b3cb4dcc8bc1e924739c2099
4
- data.tar.gz: d6fd5e852edadf8a2b48090847225ac1df2e372ac37c4fbd126b0dc6970c9637
3
+ metadata.gz: bb18ada12c5c9f610552caf9497fea312501470bb22280bd5053d16cb1fc2e5d
4
+ data.tar.gz: 908a0ec28c62ee51fd8fbbb47513d4102553a9afd596cd4297c00654dd961f22
5
5
  SHA512:
6
- metadata.gz: f05e45a97e6cac339a4f6a1bba1e59d2a78ebe7f8f0741adb95525f9c376b5c358685d7a3b68ef3df98ece474f269903fd205bc74d7002b0c6a77183f0cd943f
7
- data.tar.gz: 0c43a301fb491a90611d14717885913c6934c943f2616d744e23e360bc86b43cb33cd6752dddd7edbcbff370220bbd916f23fa994d302d938f9b9f7719921e89
6
+ metadata.gz: ae3e7f82650b4ef2af5a392f5b5e22bc0eaec2a38b0de10bbd1e15d0c7dd56d711cc5c9584145adfbb5e30ca8834064ee905ba8b014e6383461706e19b6483f0
7
+ data.tar.gz: b154981442ff02d51337e201ff965eea85282c47c47d6065a09057e96c0b21b81a129a3a8ee5b9e8c753b55a8a514c1b80f7ad4d2763d148d2b00dd388f145c0
checksums.yaml.gz.sig ADDED
Binary file
@@ -1,38 +1,33 @@
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.
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2020-2024, by Samuel Williams.
5
+
6
+ require 'async'
20
7
 
21
8
  module Async
22
9
  module Await
23
10
  module Enumerable
24
- def async_map(parent: Task.current, &block)
25
- self.map do |*args|
26
- parent.async do
27
- yield *args
28
- end
29
- end.map(&:wait)
11
+ def async_map(parent: nil, &block)
12
+ Sync do |task|
13
+ parent ||= task
14
+
15
+ self.map do |*arguments|
16
+ parent.async do
17
+ yield(*arguments)
18
+ end
19
+ end.map(&:wait)
20
+ end
30
21
  end
31
22
 
32
- def async_each(parent: Task.current, &block)
33
- self.each do |*args|
34
- parent.async do
35
- yield *args
23
+ def async_each(parent: nil, &block)
24
+ Sync do |task|
25
+ parent ||= task
26
+
27
+ self.each do |*arguments|
28
+ parent.async do
29
+ yield(*arguments)
30
+ end
36
31
  end
37
32
  end
38
33
 
@@ -42,10 +37,4 @@ module Async
42
37
  end
43
38
  end
44
39
 
45
- # ::Enumerable.include(Async::Await::Enumerable)
46
- # https://bugs.ruby-lang.org/issues/9573
47
- module Enumerable
48
- Async::Await::Enumerable.instance_methods.each do |name|
49
- self.define_method(name, Async::Await::Enumerable.instance_method(name))
50
- end
51
- end
40
+ ::Enumerable.include(Async::Await::Enumerable)
@@ -1,25 +1,10 @@
1
- # Copyright, 2017, 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.
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2017-2024, by Samuel Williams.
20
5
 
21
6
  module Async
22
7
  module Await
23
- VERSION = "0.5.0"
8
+ VERSION = "0.7.0"
24
9
  end
25
10
  end
data/lib/async/await.rb CHANGED
@@ -1,32 +1,13 @@
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.
1
+ # frozen_string_literal: true
20
2
 
21
- require_relative 'await/version'
22
- require_relative 'await/methods'
3
+ # Released under the MIT License.
4
+ # Copyright, 2017-2024, by Samuel Williams.
23
5
 
24
- require 'ruby2_keywords'
6
+ require_relative 'await/version'
25
7
 
26
8
  module Async
27
9
  module Await
28
10
  def self.included(klass)
29
- klass.include(Methods)
30
11
  klass.extend(self)
31
12
  end
32
13
 
@@ -44,8 +25,6 @@ module Async
44
25
  end.wait
45
26
  end
46
27
  end
47
-
48
- ruby2_keywords(name)
49
28
  end
50
29
 
51
30
  def async(name)
@@ -58,8 +37,6 @@ module Async
58
37
  original_method.bind(self).call(*arguments, &block)
59
38
  end
60
39
  end
61
-
62
- ruby2_keywords(name)
63
40
  end
64
41
  end
65
42
  end
data/license.md ADDED
@@ -0,0 +1,23 @@
1
+ # MIT License
2
+
3
+ Copyright, 2017-2024, by Samuel Williams.
4
+ Copyright, 2018, by Kent 'picat' Gruber.
5
+ Copyright, 2020, by Olle Jonsson.
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
data/readme.md ADDED
@@ -0,0 +1,61 @@
1
+ # Async::Await
2
+
3
+ Implements the async/await pattern for Ruby using [async](https://github.com/socketry/async).
4
+
5
+ [![Development Status](https://github.com/socketry/async-await/workflows/Test/badge.svg)](https://github.com/socketry/async-await/actions?workflow=Test)
6
+
7
+ ## Installation
8
+
9
+ ``` shell
10
+ bundle add async-await
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ In any asynchronous context (e.g. a reactor), simply use the `await` function like so:
16
+
17
+ ``` ruby
18
+ require 'async/await'
19
+
20
+ class Coop
21
+ include Async::Await
22
+
23
+ async def count_chickens(area_name)
24
+ 3.times do |i|
25
+ sleep rand
26
+
27
+ puts "Found a chicken in the #{area_name}!"
28
+ end
29
+ end
30
+
31
+ async def count_all_chickens
32
+ # These methods all run at the same time.
33
+ count_chickens("garden")
34
+ count_chickens("house")
35
+
36
+ # We wait for the result
37
+ count_chickens("tree").wait
38
+ end
39
+ end
40
+
41
+ coop = Coop.new
42
+ coop.count_all_chickens
43
+ ```
44
+
45
+ ## Contributing
46
+
47
+ We welcome contributions to this project.
48
+
49
+ 1. Fork it.
50
+ 2. Create your feature branch (`git checkout -b my-new-feature`).
51
+ 3. Commit your changes (`git commit -am 'Add some feature'`).
52
+ 4. Push to the branch (`git push origin my-new-feature`).
53
+ 5. Create new Pull Request.
54
+
55
+ ### Developer Certificate of Origin
56
+
57
+ This project uses the [Developer Certificate of Origin](https://developercertificate.org/). All contributors to this project must agree to this document to have their contributions accepted.
58
+
59
+ ### Contributor Covenant
60
+
61
+ This project is governed by the [Contributor Covenant](https://www.contributor-covenant.org/). All contributors and participants agree to abide by its terms.
data.tar.gz.sig ADDED
Binary file
metadata CHANGED
@@ -1,45 +1,48 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-await
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
- autorequire:
8
+ - Kent 'picat' Gruber
9
+ - Olle Jonsson
10
+ autorequire:
9
11
  bindir: bin
10
- cert_chain: []
11
- date: 2020-01-09 00:00:00.000000000 Z
12
+ cert_chain:
13
+ - |
14
+ -----BEGIN CERTIFICATE-----
15
+ MIIE2DCCA0CgAwIBAgIBATANBgkqhkiG9w0BAQsFADBhMRgwFgYDVQQDDA9zYW11
16
+ ZWwud2lsbGlhbXMxHTAbBgoJkiaJk/IsZAEZFg1vcmlvbnRyYW5zZmVyMRIwEAYK
17
+ CZImiZPyLGQBGRYCY28xEjAQBgoJkiaJk/IsZAEZFgJuejAeFw0yMjA4MDYwNDUz
18
+ MjRaFw0zMjA4MDMwNDUzMjRaMGExGDAWBgNVBAMMD3NhbXVlbC53aWxsaWFtczEd
19
+ MBsGCgmSJomT8ixkARkWDW9yaW9udHJhbnNmZXIxEjAQBgoJkiaJk/IsZAEZFgJj
20
+ bzESMBAGCgmSJomT8ixkARkWAm56MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIB
21
+ igKCAYEAomvSopQXQ24+9DBB6I6jxRI2auu3VVb4nOjmmHq7XWM4u3HL+pni63X2
22
+ 9qZdoq9xt7H+RPbwL28LDpDNflYQXoOhoVhQ37Pjn9YDjl8/4/9xa9+NUpl9XDIW
23
+ sGkaOY0eqsQm1pEWkHJr3zn/fxoKPZPfaJOglovdxf7dgsHz67Xgd/ka+Wo1YqoE
24
+ e5AUKRwUuvaUaumAKgPH+4E4oiLXI4T1Ff5Q7xxv6yXvHuYtlMHhYfgNn8iiW8WN
25
+ XibYXPNP7NtieSQqwR/xM6IRSoyXKuS+ZNGDPUUGk8RoiV/xvVN4LrVm9upSc0ss
26
+ RZ6qwOQmXCo/lLcDUxJAgG95cPw//sI00tZan75VgsGzSWAOdjQpFM0l4dxvKwHn
27
+ tUeT3ZsAgt0JnGqNm2Bkz81kG4A2hSyFZTFA8vZGhp+hz+8Q573tAR89y9YJBdYM
28
+ zp0FM4zwMNEUwgfRzv1tEVVUEXmoFCyhzonUUw4nE4CFu/sE3ffhjKcXcY//qiSW
29
+ xm4erY3XAgMBAAGjgZowgZcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0O
30
+ BBYEFO9t7XWuFf2SKLmuijgqR4sGDlRsMC4GA1UdEQQnMCWBI3NhbXVlbC53aWxs
31
+ aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MC4GA1UdEgQnMCWBI3NhbXVlbC53aWxs
32
+ aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MA0GCSqGSIb3DQEBCwUAA4IBgQB5sxkE
33
+ cBsSYwK6fYpM+hA5B5yZY2+L0Z+27jF1pWGgbhPH8/FjjBLVn+VFok3CDpRqwXCl
34
+ xCO40JEkKdznNy2avOMra6PFiQyOE74kCtv7P+Fdc+FhgqI5lMon6tt9rNeXmnW/
35
+ c1NaMRdxy999hmRGzUSFjozcCwxpy/LwabxtdXwXgSay4mQ32EDjqR1TixS1+smp
36
+ 8C/NCWgpIfzpHGJsjvmH2wAfKtTTqB9CVKLCWEnCHyCaRVuKkrKjqhYCdmMBqCws
37
+ JkxfQWC+jBVeG9ZtPhQgZpfhvh+6hMhraUYRQ6XGyvBqEUe+yo6DKIT3MtGE2+CP
38
+ eX9i9ZWBydWb8/rvmwmX2kkcBbX0hZS1rcR593hGc61JR6lvkGYQ2MYskBveyaxt
39
+ Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
40
+ voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
41
+ -----END CERTIFICATE-----
42
+ date: 2024-06-04 00:00:00.000000000 Z
12
43
  dependencies:
13
44
  - !ruby/object:Gem::Dependency
14
45
  name: async
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.3'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.3'
27
- - !ruby/object:Gem::Dependency
28
- name: async-rspec
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '1.1'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '1.1'
41
- - !ruby/object:Gem::Dependency
42
- name: ruby2_keywords
43
46
  requirement: !ruby/object:Gem::Requirement
44
47
  requirements:
45
48
  - - ">="
@@ -52,92 +55,23 @@ dependencies:
52
55
  - - ">="
53
56
  - !ruby/object:Gem::Version
54
57
  version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: covered
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: bundler
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: rake
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: '10.0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: '10.0'
97
- - !ruby/object:Gem::Dependency
98
- name: rspec
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: '3.0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: '3.0'
111
- description:
58
+ description:
112
59
  email:
113
- - samuel.williams@oriontransfer.co.nz
114
60
  executables: []
115
61
  extensions: []
116
62
  extra_rdoc_files: []
117
63
  files:
118
- - ".editorconfig"
119
- - ".gitignore"
120
- - ".rspec"
121
- - ".travis.yml"
122
- - Gemfile
123
- - README.md
124
- - Rakefile
125
- - async-await.gemspec
126
- - examples/chickens.rb
127
- - examples/echo.rb
128
- - examples/port_scanner/README.md
129
- - examples/port_scanner/port_scanner.go
130
- - examples/port_scanner/port_scanner.py
131
- - examples/port_scanner/port_scanner.rb
132
- - examples/sleep_sort.rb
133
64
  - lib/async/await.rb
134
65
  - lib/async/await/enumerable.rb
135
- - lib/async/await/methods.rb
136
66
  - lib/async/await/version.rb
67
+ - license.md
68
+ - readme.md
137
69
  homepage: https://github.com/socketry/async-await
138
- licenses: []
139
- metadata: {}
140
- post_install_message:
70
+ licenses:
71
+ - MIT
72
+ metadata:
73
+ source_code_uri: https://github.com/socketry/async-await.git
74
+ post_install_message:
141
75
  rdoc_options: []
142
76
  require_paths:
143
77
  - lib
@@ -145,15 +79,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
145
79
  requirements:
146
80
  - - ">="
147
81
  - !ruby/object:Gem::Version
148
- version: '0'
82
+ version: '3.1'
149
83
  required_rubygems_version: !ruby/object:Gem::Requirement
150
84
  requirements:
151
85
  - - ">="
152
86
  - !ruby/object:Gem::Version
153
87
  version: '0'
154
88
  requirements: []
155
- rubygems_version: 3.1.2
156
- signing_key:
89
+ rubygems_version: 3.5.3
90
+ signing_key:
157
91
  specification_version: 4
158
92
  summary: Implements the async/await pattern on top of async :)
159
93
  test_files: []
metadata.gz.sig ADDED
Binary file
data/.editorconfig DELETED
@@ -1,6 +0,0 @@
1
- root = true
2
-
3
- [*]
4
- indent_style = tab
5
- indent_size = 2
6
-
data/.gitignore DELETED
@@ -1,12 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
- /pkg/
8
- /spec/reports/
9
- /tmp/
10
-
11
- # rspec failure tracking
12
- .rspec_status
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --warnings
3
- --require spec_helper
data/.travis.yml DELETED
@@ -1,19 +0,0 @@
1
- language: ruby
2
- cache: bundler
3
-
4
- matrix:
5
- include:
6
- - rvm: 2.3
7
- - rvm: 2.4
8
- - rvm: 2.5
9
- - rvm: 2.6
10
- - rvm: 2.7
11
- - rvm: 2.6
12
- env: COVERAGE=BriefSummary,Coveralls
13
- - rvm: ruby-head
14
- - rvm: jruby-head
15
- - rvm: truffleruby
16
- allow_failures:
17
- - rvm: ruby-head
18
- - rvm: jruby-head
19
- - rvm: truffleruby
data/Gemfile DELETED
@@ -1,13 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gemspec
4
-
5
- group :development do
6
- gem 'pry'
7
- gem 'async-io', '~> 1.4'
8
- end
9
-
10
- group :test do
11
- gem 'benchmark-ips'
12
- gem 'ruby-prof', platforms: :mri
13
- end
data/README.md DELETED
@@ -1,95 +0,0 @@
1
- # Async::Await
2
-
3
- Implements the async/await pattern for Ruby using [async].
4
-
5
- [![Build Status](https://secure.travis-ci.org/socketry/async-await.svg)](http://travis-ci.org/socketry/async-await)
6
- [![Code Climate](https://codeclimate.com/github/socketry/async-await.svg)](https://codeclimate.com/github/socketry/async-await)
7
- [![Coverage Status](https://coveralls.io/repos/socketry/async-await/badge.svg)](https://coveralls.io/r/socketry/async-await)
8
-
9
- [async]: https://github.com/socketry/async
10
-
11
- ## Installation
12
-
13
- Add this line to your application's Gemfile:
14
-
15
- ```ruby
16
- gem 'async-await'
17
- ```
18
-
19
- And then execute:
20
-
21
- $ bundle
22
-
23
- Or install it yourself as:
24
-
25
- $ gem install async-await
26
-
27
- ## Usage
28
-
29
- In any asynchronous context (e.g. a reactor), simply use the `await` function like so:
30
-
31
- ```ruby
32
- require 'async/await'
33
-
34
- class Coop
35
- include Async::Await
36
-
37
- async def count_chickens(area_name)
38
- 3.times do |i|
39
- sleep rand
40
-
41
- puts "Found a chicken in the #{area_name}!"
42
- end
43
- end
44
-
45
- async def count_all_chickens
46
- # These methods all run at the same time.
47
- count_chickens("garden")
48
- count_chickens("house")
49
-
50
- # We wait for the result
51
- count_chickens("tree").wait
52
- end
53
- end
54
-
55
- coop = Coop.new
56
- coop.count_all_chickens
57
- ```
58
-
59
- ## Contributing
60
-
61
- 1. Fork it
62
- 2. Create your feature branch (`git checkout -b my-new-feature`)
63
- 3. Commit your changes (`git commit -am 'Add some feature'`)
64
- 4. Push to the branch (`git push origin my-new-feature`)
65
- 5. Create new Pull Request
66
-
67
- ## See Also
68
-
69
- - [async-io](https://github.com/socketry/async-io) — Asynchronous networking and sockets.
70
- - [async-dns](https://github.com/socketry/async-dns) — Asynchronous DNS resolver and server.
71
- - [async-rspec](https://github.com/socketry/async-rspec) — Shared contexts for running async specs.
72
-
73
- ## License
74
-
75
- Released under the MIT license.
76
-
77
- Copyright, 2017, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
78
-
79
- Permission is hereby granted, free of charge, to any person obtaining a copy
80
- of this software and associated documentation files (the "Software"), to deal
81
- in the Software without restriction, including without limitation the rights
82
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
83
- copies of the Software, and to permit persons to whom the Software is
84
- furnished to do so, subject to the following conditions:
85
-
86
- The above copyright notice and this permission notice shall be included in
87
- all copies or substantial portions of the Software.
88
-
89
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
90
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
91
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
92
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
93
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
94
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
95
- THE SOFTWARE.
data/Rakefile DELETED
@@ -1,6 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
-
4
- RSpec::Core::RakeTask.new(:spec)
5
-
6
- task :default => :spec
data/async-await.gemspec DELETED
@@ -1,28 +0,0 @@
1
- # coding: utf-8
2
- require_relative "lib/async/await/version"
3
-
4
- Gem::Specification.new do |spec|
5
- spec.name = "async-await"
6
- spec.version = Async::Await::VERSION
7
- spec.authors = ["Samuel Williams"]
8
- spec.email = ["samuel.williams@oriontransfer.co.nz"]
9
-
10
- spec.summary = "Implements the async/await pattern on top of async :)"
11
- spec.homepage = "https://github.com/socketry/async-await"
12
-
13
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
14
- f.match(%r{^(test|spec|features)/})
15
- end
16
-
17
- spec.require_paths = ["lib"]
18
-
19
- spec.add_dependency "async", "~> 1.3"
20
- spec.add_development_dependency "async-rspec", "~> 1.1"
21
-
22
- spec.add_dependency "ruby2_keywords"
23
-
24
- spec.add_development_dependency "covered"
25
- spec.add_development_dependency "bundler"
26
- spec.add_development_dependency "rake", "~> 10.0"
27
- spec.add_development_dependency "rspec", "~> 3.0"
28
- end
data/examples/chickens.rb DELETED
@@ -1,37 +0,0 @@
1
-
2
- require_relative '../lib/async/await'
3
-
4
- class Coop
5
- include Async::Await
6
-
7
- async def count_chickens(area_name)
8
- 3.times do |i|
9
- sleep rand
10
-
11
- puts "Found a chicken in the #{area_name}!"
12
- end
13
- end
14
-
15
- async def find_chicken(areas)
16
- puts "Searching for chicken..."
17
-
18
- sleep rand * 5
19
-
20
- return areas.sample
21
- end
22
-
23
- async def count_all_chickens
24
- # These methods all run at the same time.
25
- count_chickens("garden")
26
- count_chickens("house")
27
- count_chickens("tree")
28
-
29
- # Wait for all previous async work to complete...
30
- barrier!
31
-
32
- puts "There was a chicken in the #{find_chicken(["garden", "house", "tree"]).wait}"
33
- end
34
- end
35
-
36
- coop = Coop.new
37
- coop.count_all_chickens
data/examples/echo.rb DELETED
@@ -1,55 +0,0 @@
1
-
2
- require_relative '../lib/async/await'
3
-
4
- require 'async/io'
5
- require 'async/io/tcp_socket'
6
-
7
- require 'pry'
8
-
9
- class Echo
10
- include Async::Await
11
- include Async::IO
12
-
13
- async def handle(peer, address)
14
- data = peer.gets
15
- peer.puts("#{data} #{Time.now}")
16
- ensure
17
- peer.close
18
- end
19
-
20
- async def server
21
- puts "Binding server..."
22
- server = TCPServer.new("127.0.0.1", 9009)
23
-
24
- handle(*server.accept)
25
- ensure
26
- server.close rescue nil
27
- end
28
-
29
- async def client
30
- puts "Client connecting..."
31
- client = TCPSocket.new("127.0.0.1", 9009)
32
-
33
- client.puts("Hello World!")
34
- response = client.gets
35
-
36
- puts "Server said: #{response}"
37
- ensure
38
- client.close rescue nil
39
- end
40
-
41
- async def run
42
- puts "Creating server..."
43
- server
44
-
45
- puts "Creating client..."
46
- client
47
-
48
- puts "Run returning..."
49
- end
50
- end
51
-
52
- puts "Starting echo..."
53
- echo = Echo.new
54
- echo.run
55
- puts "Echo finished :)"
@@ -1,90 +0,0 @@
1
- # Port Scanner
2
-
3
- A simple `connect`-based port scanner. It scans locahost for all open ports.
4
-
5
- ## Usage
6
-
7
- ### Go
8
-
9
- Go is pretty awesome, because when the operation would not block, it runs sequentially in the same thread. Go spins up threads and delegates work across available CPU cores.
10
-
11
- $ go get golang.org/x/sync/semaphore
12
- $ go build port_scanner.go
13
- $ time ./port_scanner
14
- 22 open
15
- 139 open
16
- 445 open
17
- 3306 open
18
- 5355 open
19
- 5432 open
20
- 6379 open
21
- 9293 open
22
- 9292 open
23
- 9516 open
24
- 9515 open
25
- 12046 open
26
- 12813 open
27
- ./port_scanner 1.70s user 1.18s system 503% cpu 0.572 total
28
-
29
- ### Python
30
-
31
- Python was the slowest. This is possibly due to the implementation of semaphore. It creates all 65,535 tasks, and then most of them block on the semaphore.
32
-
33
- $ ./port_scanner.py
34
- 5355 open
35
- 5432 open
36
- 3306 open
37
- 39610 open
38
- 58260 open
39
- 12813 open
40
- 139 open
41
- 445 open
42
- 12046 open
43
- 22 open
44
- 9292 open
45
- 9293 open
46
- 9515 open
47
- 9516 open
48
- 6379 open
49
- ./port_scanner.py 11.41s user 0.88s system 98% cpu 12.485 total
50
-
51
- ### Ruby
52
-
53
- Ruby performance isn't that bad. It's only about half as fast as Go, considering that Go runs across all cores, while the Ruby implementation is limited to one core.
54
-
55
- $ ./port_scanner.rb
56
- 22 open
57
- 139 open
58
- 445 open
59
- 3306 open
60
- 5432 open
61
- 5355 open
62
- 6379 open
63
- 9516 open
64
- 9515 open
65
- 9293 open
66
- 9292 open
67
- 12046 open
68
- 12813 open
69
- ./port_scanner.rb 5.99s user 1.18s system 95% cpu 7.543 total
70
-
71
- ## Notes
72
-
73
- ### Why do I sometimes see high ports?
74
-
75
- Believe it or not, you can connect to your own sockets.
76
-
77
- ```ruby
78
- require 'socket'
79
- a = Addrinfo.tcp("127.0.0.1", 50000)
80
- s = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
81
- s.bind(a)
82
- s.connect(a)
83
-
84
- s.write("Hello World")
85
- => 11
86
- [8] pry(main)> s.read(11)
87
- => "Hello World"
88
- ```
89
-
90
- What's happening is that your socket is implicitly binding to a high port, and at the same time it's trying to connect to it.
@@ -1,107 +0,0 @@
1
- package main
2
-
3
- import (
4
- "context"
5
- "fmt"
6
- "golang.org/x/sync/semaphore"
7
- "net"
8
- "syscall"
9
- "strings"
10
- "sync"
11
- "time"
12
- )
13
-
14
- // The star of the show, of modest means,
15
- // used to manage the port scan for a single host.
16
- type PortScanner struct {
17
- ip string
18
- lock *semaphore.Weighted
19
- }
20
-
21
- // Provides a simple wrapper to initializing a PortScanner.
22
- func NewPortScanner(ip string, limit uint64) *PortScanner {
23
- return &PortScanner{
24
- ip: ip,
25
- lock: semaphore.NewWeighted(int64(limit)),
26
- }
27
- }
28
-
29
- // Compute the maximum number of files we can open.
30
- func FileLimit(max uint64) uint64 {
31
- var rlimit syscall.Rlimit
32
- err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit)
33
- if err != nil {
34
- panic(err)
35
- }
36
-
37
- if (max < rlimit.Cur) {
38
- return max
39
- }
40
-
41
- return rlimit.Cur
42
- }
43
-
44
- // As the name might suggest, this function checks if a given port
45
- // is open to TCP communication. Used in conjunction with the Start function
46
- // to sweep over a range of ports concurrently.
47
- func checkPortOpen(ip string, port int, timeout time.Duration) {
48
- conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", ip, port), timeout)
49
-
50
- if err != nil {
51
- if strings.Contains(err.Error(), "timeout") {
52
- fmt.Println(port, "timeout", err.Error())
53
- } else if strings.Contains(err.Error(), "deadline exceeded") {
54
- fmt.Println(port, "timeout", err.Error())
55
- } else if strings.Contains(err.Error(), "refused") {
56
- // fmt.Println(port, "closed", err.Error())
57
- } else {
58
- panic(err)
59
- }
60
- return
61
- }
62
-
63
- fmt.Println(port, "open")
64
- conn.Close()
65
- }
66
-
67
- // This function is the bread and butter of this script. It manages the
68
- // port scanning for a given range of ports with the given timeout value
69
- // to deal with filtered ports by a firewall typically.
70
- func (ps *PortScanner) Start(start, stop int, timeout time.Duration) {
71
- wg := sync.WaitGroup{}
72
- defer wg.Wait()
73
-
74
- for port := start; port <= stop; port++ {
75
-
76
- ctx := context.TODO()
77
-
78
- for {
79
- err := ps.lock.Acquire(ctx, 1)
80
- if err == nil {
81
- break
82
- }
83
- }
84
-
85
- wg.Add(1)
86
-
87
- go func(ip string, port int) {
88
- defer ps.lock.Release(1)
89
- defer wg.Done()
90
-
91
- checkPortOpen(ps.ip, port, timeout)
92
- }(ps.ip, port)
93
-
94
- }
95
- }
96
-
97
- // This function kicks off the whole shindig' and provides a
98
- // basic example of the internal API usage.
99
- func main() {
100
- batch_size := FileLimit(512)
101
-
102
- // Create a new PortScanner for localhost.
103
- ps := NewPortScanner("127.0.0.1", batch_size)
104
-
105
- // Start scanning all the ports on localhost.
106
- ps.Start(1, 65535, 1000*time.Millisecond)
107
- }
@@ -1,36 +0,0 @@
1
- #!/usr/bin/env python
2
-
3
- import os, resource
4
- import asyncio
5
-
6
- class PortScanner:
7
- def __init__(self, host="0.0.0.0", ports=range(1, 1024+1), batch_size=1024):
8
- self.host = host
9
- self.ports = ports
10
- self.semaphore = asyncio.Semaphore(value=batch_size)
11
- self.loop = asyncio.get_event_loop()
12
-
13
- async def scan_port(self, port, timeout):
14
- async with self.semaphore:
15
- try:
16
- future = asyncio.open_connection(self.host, port, loop=self.loop)
17
- reader, writer = await asyncio.wait_for(future, timeout=timeout)
18
- print("{} open".format(port))
19
- writer.close()
20
- except ConnectionRefusedError:
21
- pass
22
- # print("{} closed".format(port))
23
- except asyncio.TimeoutError:
24
- print("{} timeout".format(port))
25
-
26
- def start(self, timeout=1.0):
27
- self.loop.run_until_complete(asyncio.gather(
28
- *[self.scan_port(port, timeout) for port in self.ports]
29
- ))
30
-
31
- limits = resource.getrlimit(resource.RLIMIT_NOFILE)
32
- batch_size = min(512, limits[0])
33
-
34
- scanner = PortScanner(host="127.0.0.1", ports=range(1, 65535+1), batch_size=batch_size)
35
-
36
- scanner.start()
@@ -1,44 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'async/io'
4
- require 'async/semaphore'
5
- require_relative '../../lib/async/await'
6
-
7
- class PortScanner
8
- include Async::Await
9
- include Async::IO
10
-
11
- def initialize(host: '0.0.0.0', ports:, batch_size: 1024)
12
- @host = host
13
- @ports = ports
14
- @semaphore = Async::Semaphore.new(batch_size)
15
- end
16
-
17
- def scan_port(port, timeout)
18
- with_timeout(timeout) do
19
- address = Async::IO::Address.tcp(@host, port)
20
- peer = Socket.connect(address)
21
- puts "#{port} open"
22
- peer.close
23
- end
24
- rescue Errno::ECONNREFUSED
25
- # puts "#{port} closed"
26
- rescue Async::TimeoutError
27
- puts "#{port} timeout"
28
- end
29
-
30
- async def start(timeout = 1.0)
31
- @ports.map do |port|
32
- @semaphore.async do
33
- scan_port(port, timeout)
34
- end
35
- end.collect(&:result)
36
- end
37
- end
38
-
39
- limits = Process.getrlimit(Process::RLIMIT_NOFILE)
40
- batch_size = [512, (limits.first * 0.9).ceil].min
41
-
42
- scanner = PortScanner.new(host: "127.0.0.1", ports: Range.new(1, 65535), batch_size: batch_size)
43
-
44
- scanner.start
@@ -1,29 +0,0 @@
1
-
2
- require_relative '../lib/async/await'
3
-
4
- class << self
5
- include Async::Await
6
-
7
- async def sort_one(item, into)
8
- sleep(item.to_f)
9
- into << item
10
-
11
- puts "I've sorted #{item} for you."
12
- end
13
-
14
- async def sort(items)
15
- result = []
16
-
17
- items.each do |item|
18
- sort_one(item, result)
19
- end
20
-
21
- # Wait until all previous async method calls have finished executing.
22
- barrier!
23
-
24
- return result
25
- end
26
- end
27
-
28
- puts "Hold on, sorting..."
29
- puts sort([5, 2, 3, 4, 9, 2, 5, 7, 8]).result.inspect
@@ -1,43 +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
- require 'async/reactor'
22
-
23
- module Async
24
- module Await
25
- module Methods
26
- extend Forwardable
27
-
28
- def task
29
- Async::Task.current
30
- end
31
-
32
- def_delegators :task, :with_timeout, :sleep, :async
33
-
34
- def await(&block)
35
- block.call.wait
36
- end
37
-
38
- def barrier!
39
- task.children.each(&:wait)
40
- end
41
- end
42
- end
43
- end