asynchronize 0.1.2 → 0.2.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: af0aada41350e739802a92c04ef32bc64fbb897dd4d3ff7b0450c1485f9a243a
4
- data.tar.gz: 457e2ccdf4b87955b8dc68011f8e7d84be3458fa6a83333f56b755457729121f
3
+ metadata.gz: eac19fda33067270bc4464149d1f02a9561cd6a994e004f9e73c0b288ae38f5c
4
+ data.tar.gz: 55301cee6db401579e3d8836c6485b4ae33e76f6319f98e6853f151076c77a83
5
5
  SHA512:
6
- metadata.gz: d0f2214354035c147289553f31326709f7707a1a6a5a6101778f87198f18abd99c511763297f87662cec869426c20bae9ee5522d19232ce33878c4e238a573ae
7
- data.tar.gz: 7abf0867f9c2e238f475b0925db4610194de9ef954baa48648d79492ae4fc89eaddba1e2801394cafc4034f675aaf5e5f4b0b80677c348404ef3b97cc81567af
6
+ metadata.gz: 1c06a933de8ec8aab5f2f97bf0943b5405a02ff3ff74f3612506cab6eb74117ac090f1810b5e3aa1a52b98babae51499fe8319c773e74cf41f6dbfa106d62c6b
7
+ data.tar.gz: 19661f53978d370e1cf80b34c1ee5a19bb7575a7f5600752ddd67960a4da6dc9148f3ac6c52e1cb06f249f99281cc6bc247e14642728fa4e6080552b8235ab9d
@@ -2,7 +2,7 @@ require 'date'
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'asynchronize'
5
- s.version = '0.1.2'
5
+ s.version = '0.2.0'
6
6
  s.date = Date.today.to_s
7
7
  s.summary = 'Easily make multiple methods asynchronous with one line of code.'
8
8
  s.description = 'Take any synchronous method, and run it asynchronously, ' +
@@ -3,13 +3,13 @@ module Asynchronize
3
3
  def self.included(base)
4
4
  base.class_eval do
5
5
  # The methods we have already asynchronized
6
- @@asynced_methods = Set.new
6
+ @asynced_methods = Set.new
7
7
  # The methods that should be asynchronized.
8
- @@methods_to_async = Set.new
8
+ @methods_to_async = Set.new
9
9
  # Originally used a single value here, but that's not thread safe.
10
10
  # ...Though you probably have other problems if you have multiple
11
11
  # threads adding methods to your class.
12
- @@methods_asyncing = Set.new
12
+ @methods_asyncing = Set.new
13
13
 
14
14
  ##
15
15
  # Call to asynchronize a method.
@@ -23,19 +23,18 @@ module Asynchronize
23
23
  # @example To add any number of methods to be asynchronized.
24
24
  # asynchronize :method1, :method2, :methodn
25
25
  def self.asynchronize(*methods)
26
- @@methods_to_async.merge(methods)
26
+ @methods_to_async.merge(methods)
27
27
  methods.each do |method|
28
28
  # If it's not defined yet, we'll get it with method_added
29
- next unless method_defined? method
29
+ next unless method_defined?(method)
30
30
  Asynchronize.create_new_method(method, self)
31
31
  end
32
32
  end
33
33
 
34
- # require 'pry'; binding.pry
35
34
  # Save the old method_added so we don't overwrite it.
36
- if self.methods.include? :method_added
35
+ if self.methods.include?(:method_added)
37
36
  singleton_class.send(:alias_method, :old_method_added, :method_added)
38
- singleton_class.undef_method(:method_added)
37
+ singleton_class.send(:undef_method, :method_added)
39
38
  end
40
39
 
41
40
  ##
@@ -45,12 +44,14 @@ module Asynchronize
45
44
  # anything else Ruby calls this automatically when defining a method; it
46
45
  # should not be called directly.
47
46
  def self.method_added(method)
48
- # Don't do anything else if we're not actually adding a new method
49
- return if @@methods_asyncing.include? method
50
- @@methods_asyncing.add(method)
51
- self.old_method_added(method) if self.methods.include? :old_method_added
52
- return unless @@methods_to_async.include? method
53
- # This will delete from @@methods_asyncing
47
+ # Return if this is an inherited class that hasn't included asynchronize
48
+ return if @methods_asyncing.nil?
49
+ # Return if we're already processing this method
50
+ return if @methods_asyncing.include?(method)
51
+ @methods_asyncing.add(method)
52
+ self.old_method_added(method) if self.methods.include?(:old_method_added)
53
+ return unless @methods_to_async.include?(method)
54
+ # This will delete from @methods_asyncing
54
55
  Asynchronize.create_new_method(method, self)
55
56
  end
56
57
  end
@@ -63,13 +64,13 @@ module Asynchronize
63
64
  old_method = instance_method(method)
64
65
  # Can't just store the method name, since it would break if the method
65
66
  # was redefined.
66
- return if @@asynced_methods.include?(old_method)
67
- undef_method method
67
+ return if @asynced_methods.include?(old_method)
68
+ undef_method(method)
68
69
 
69
- @@methods_asyncing.add(method)
70
+ @methods_asyncing.add(method)
70
71
  define_method(method, Asynchronize._build_new_method(old_method))
71
- @@methods_asyncing.delete(method)
72
- @@asynced_methods.add(instance_method(method))
72
+ @methods_asyncing.delete(method)
73
+ @asynced_methods.add(instance_method(method))
73
74
  end
74
75
  end
75
76
 
@@ -77,12 +78,8 @@ module Asynchronize
77
78
  def self._build_new_method(old_method)
78
79
  return Proc.new do |*args, &block|
79
80
  return Thread.new(old_method, args, block) do |told_method, targs, tblock|
80
- result = told_method.bind(self).call(*targs)
81
- if tblock.nil?
82
- Thread.current[:return_value] = result
83
- else
84
- tblock.call(result)
85
- end
81
+ Thread.current[:return_value] = told_method.bind(self).call(*targs)
82
+ tblock.call(Thread.current[:return_value]) unless tblock.nil?
86
83
  end
87
84
  end
88
85
  end
data/readme.md CHANGED
@@ -5,7 +5,7 @@
5
5
  ### The easiest way to make multiple methods asynchronous.
6
6
 
7
7
  Find yourself writing the same boilerplate for all your asynchronous methods?
8
- Get dryyy with asynchronize.
8
+ Get dry with asynchronize.
9
9
 
10
10
  Just install with `gem install asynchronize` or add to your Gemfile and `bundle`
11
11
 
@@ -27,21 +27,20 @@ end
27
27
  ```
28
28
 
29
29
  Now, to call those methods.
30
- You can just pass it a block.
31
- ```Ruby
32
- Test.new.my_test do |return_value|
33
- puts return_value
34
- end
35
- # > test
36
- ```
37
-
38
- Or, you can manage the thread yourself; the returned value will be in the thread
30
+ You can manage the thread yourself; the returned value will be in the thread
39
31
  variable `:return_value` once it returns.
40
32
  ```Ruby
41
33
  thread = Test.new.my_test
42
34
  thread.join
43
- puts thread[:return_value]
44
- # > test
35
+ puts thread[:return_value] # > test
36
+ ```
37
+
38
+ Or for convenience, you can just pass it a block.
39
+ The return value, will still be in the thread variable `:return_value`
40
+ ```Ruby
41
+ Test.new.my_test do |return_value|
42
+ puts return_value # > test
43
+ end
45
44
  ```
46
45
 
47
46
  ## Inspiration
@@ -54,10 +53,21 @@ def method_name(args)
54
53
  end
55
54
  ```
56
55
  It's extra typing, adds an unneeded extra layer of nesting, and just feels
57
- dirty. Now, I can just call asynchronize to make any method asynchronous.
56
+ dirty. I couldn't find an existing library that wasn't trying to solve other
57
+ problems I didn't have. Now, just call asynchronize to make any method
58
+ asynchronous.
59
+
60
+ ## Versioning Policy
61
+ Once I feel like this is ready for production code - version 1.0.0, this project
62
+ will follow [Semantic Versioning](https://semver.org) until then, the patch
63
+ number (0.0.x) will be updated for any changes that do not affect the public
64
+ interface. Versions that increment the minor number will have at least one of
65
+ the following. A new feature will be added, some feature will be deprecated, or
66
+ some previously deprecated feature will be removed. Deprecated features will be
67
+ removed on the very next version that increments the minor version number.
58
68
 
59
69
  ## FAQ
60
- ### Metaprogramming?? won't this hurt performance?
70
+ ### Doesn't metaprogramming hurt performance?
61
71
  Not at all! We're actually totally redefining the methods, so the method itself
62
72
  is exactly as efficient as it would have been had you wrote it that way
63
73
  originally.
@@ -87,6 +97,12 @@ tests as the source. You should read it, I'd love feedback!
87
97
  ### Do you accept contributions?
88
98
  Absolutely! If your use case isn't compatible with the project, you find a
89
99
  bug, or just want to donate some tests; make an issue or send a PR please.
100
+ To run the test suite, just run `bundle` then `rake` from the project directory.
101
+
102
+ ### What's the difference between this and promises?
103
+ This attempts to be a very lightweight wrapper around threads. There's no new
104
+ interface to use, just define a regular method, and interact with it like a
105
+ regular thread.
90
106
 
91
107
  ## License
92
108
  MIT
@@ -4,9 +4,6 @@ require './lib/asynchronize.rb'
4
4
  class BasicSpec < Minitest::Test
5
5
  describe Asynchronize do
6
6
  before do
7
- if defined? Test
8
- BasicSpec.send(:remove_const, :Test)
9
- end
10
7
  class Test
11
8
  include Asynchronize
12
9
  def test(val=5)
@@ -14,6 +11,9 @@ class BasicSpec < Minitest::Test
14
11
  end
15
12
  end
16
13
  end
14
+ after do
15
+ BasicSpec.send(:remove_const, :Test)
16
+ end
17
17
 
18
18
  describe "when we asynchronize a method" do
19
19
  it "should not be the same method" do
@@ -42,21 +42,21 @@ class BasicSpec < Minitest::Test
42
42
  end
43
43
  it "should not affect methods on other classes when called before" do
44
44
  Test.asynchronize :test
45
- class MyTest
45
+ class OtherBeforeTest
46
46
  def test
47
47
  end
48
48
  end
49
49
  Test.new.test.class.must_equal(Thread)
50
- MyTest.new.test.class.wont_equal(Thread)
50
+ OtherBeforeTest.new.test.class.wont_equal(Thread)
51
51
  end
52
52
  it "should not affect methods on other classes when called after" do
53
- class AnotherTest
53
+ class OtherAfterTest
54
54
  def test
55
55
  end
56
56
  end
57
57
  Test.asynchronize :test
58
58
  Test.new.test.class.must_equal(Thread)
59
- AnotherTest.new.test.class.wont_equal(Thread)
59
+ OtherAfterTest.new.test.class.wont_equal(Thread)
60
60
  end
61
61
  end
62
62
 
@@ -107,10 +107,7 @@ class BasicSpec < Minitest::Test
107
107
 
108
108
  describe "when there is an existing method_added" do
109
109
  before do
110
- if defined? AnotherTest
111
- BasicSpec.send(:remove_const, :AnotherTest)
112
- end
113
- class AnotherTest
110
+ class MethodAddedTest
114
111
  @running = false
115
112
  def self.method_added(method)
116
113
  return if @running
@@ -129,9 +126,51 @@ class BasicSpec < Minitest::Test
129
126
  end
130
127
  end
131
128
  end
129
+ after do
130
+ BasicSpec.send(:remove_const, :MethodAddedTest)
131
+ end
132
132
  it "should call that method_added before, and only once." do
133
- AnotherTest.new.test.join[:return_value].must_equal 5
133
+ MethodAddedTest.new.test.join[:return_value].must_equal 5
134
+ end
135
+ end
136
+
137
+ describe "when inheriting from another class" do
138
+ before do
139
+ class ChildClassTest < Test
140
+ include Asynchronize
141
+ def test
142
+ return super + 1
143
+ end
144
+ end
145
+ end
146
+ after do
147
+ BasicSpec.send(:remove_const, :ChildClassTest)
148
+ end
149
+ it "should be able to call super when it's been asynchronized" do
150
+ class ChildClassTest
151
+ asynchronize :test
152
+ end
153
+ ChildClassTest.new.test.join[:return_value].must_equal 6
154
+ end
155
+ it "should be able to call super when super has been asynchronized" do
156
+ class Test
157
+ asynchronize :test
158
+ end
159
+ class ChildClassTest
160
+ undef_method :test
161
+ def test
162
+ return super.join[:return_value] + 1
163
+ end
164
+ end
165
+ ChildClassTest.new.test.must_equal 6
134
166
  end
135
167
  end
136
168
  end
169
+
170
+ # describe "when being inherited from another class" do
171
+ # before do
172
+ #
173
+ # end
174
+ # after do
175
+ # end
137
176
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asynchronize
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kenneth Cochran
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-31 00:00:00.000000000 Z
11
+ date: 2018-06-02 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Take any synchronous method, and run it asynchronously, without cluttering
14
14
  your code with repetetive boilerplate.