observable_roles 0.1.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 +7 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +64 -0
- data/LICENSE.txt +1 -0
- data/README.markdown +111 -0
- data/Rakefile +26 -0
- data/VERSION +1 -0
- data/examples/example1.rb +20 -0
- data/examples/example2.rb +25 -0
- data/lib/observable_roles.rb +76 -0
- data/observable_roles.gemspec +53 -0
- data/spec/observable_roles_spec.rb +56 -0
- metadata +84 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cb3f4e951c750d292221ff30110a7b1b444643bc
|
4
|
+
data.tar.gz: 2911b86876b569632a45d353af8b52d6cf167ae0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7d42563121dd2e1ab84df31cc6401ff9d199daa755673ac7f5b0e7203d0117a93fa171a50f06df87dc065632bc074f8ca2c529eb39a9c49a3ed579a80709604c
|
7
|
+
data.tar.gz: 626fae1055853d4c904f04f647b0284681bb9c03f6762c9d20ca26c49168de5323f5cf95c94687158bfd4500df84d96039c805a31cd07070f41bf95fb231828c
|
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem "bundler", "~> 1.0"
|
10
|
+
gem "jeweler", "~> 2.0.1"
|
11
|
+
end
|
12
|
+
|
13
|
+
group :test do
|
14
|
+
gem 'rspec'
|
15
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
addressable (2.3.5)
|
5
|
+
builder (3.2.2)
|
6
|
+
descendants_tracker (0.0.3)
|
7
|
+
diff-lcs (1.2.5)
|
8
|
+
faraday (0.9.0)
|
9
|
+
multipart-post (>= 1.2, < 3)
|
10
|
+
git (1.2.6)
|
11
|
+
github_api (0.11.3)
|
12
|
+
addressable (~> 2.3)
|
13
|
+
descendants_tracker (~> 0.0.1)
|
14
|
+
faraday (~> 0.8, < 0.10)
|
15
|
+
hashie (>= 1.2)
|
16
|
+
multi_json (>= 1.7.5, < 2.0)
|
17
|
+
nokogiri (~> 1.6.0)
|
18
|
+
oauth2
|
19
|
+
hashie (2.0.5)
|
20
|
+
highline (1.6.21)
|
21
|
+
jeweler (2.0.1)
|
22
|
+
builder
|
23
|
+
bundler (>= 1.0)
|
24
|
+
git (>= 1.2.5)
|
25
|
+
github_api
|
26
|
+
highline (>= 1.6.15)
|
27
|
+
nokogiri (>= 1.5.10)
|
28
|
+
rake
|
29
|
+
rdoc
|
30
|
+
json (1.8.1)
|
31
|
+
jwt (0.1.11)
|
32
|
+
multi_json (>= 1.5)
|
33
|
+
mini_portile (0.5.2)
|
34
|
+
multi_json (1.9.0)
|
35
|
+
multi_xml (0.5.5)
|
36
|
+
multipart-post (2.0.0)
|
37
|
+
nokogiri (1.6.1)
|
38
|
+
mini_portile (~> 0.5.0)
|
39
|
+
oauth2 (0.9.3)
|
40
|
+
faraday (>= 0.8, < 0.10)
|
41
|
+
jwt (~> 0.1.8)
|
42
|
+
multi_json (~> 1.3)
|
43
|
+
multi_xml (~> 0.5)
|
44
|
+
rack (~> 1.2)
|
45
|
+
rack (1.5.2)
|
46
|
+
rake (10.1.1)
|
47
|
+
rdoc (4.1.1)
|
48
|
+
json (~> 1.4)
|
49
|
+
rspec (2.14.1)
|
50
|
+
rspec-core (~> 2.14.0)
|
51
|
+
rspec-expectations (~> 2.14.0)
|
52
|
+
rspec-mocks (~> 2.14.0)
|
53
|
+
rspec-core (2.14.8)
|
54
|
+
rspec-expectations (2.14.5)
|
55
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
56
|
+
rspec-mocks (2.14.6)
|
57
|
+
|
58
|
+
PLATFORMS
|
59
|
+
ruby
|
60
|
+
|
61
|
+
DEPENDENCIES
|
62
|
+
bundler (~> 1.0)
|
63
|
+
jeweler (~> 2.0.1)
|
64
|
+
rspec
|
data/LICENSE.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Use however you want, I don't care.
|
data/README.markdown
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
Observable Roles
|
2
|
+
===============================================================================
|
3
|
+
Thread safe implementation of the Observable pattern which also supports roles.
|
4
|
+
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
gem install observable_roles
|
9
|
+
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
Let's start with an example. First, create two classes:
|
14
|
+
|
15
|
+
class DummySubscriber
|
16
|
+
include ObservableRoles::Subscriber
|
17
|
+
end
|
18
|
+
|
19
|
+
class DummyPublisher
|
20
|
+
include ObservableRoles::Publisher
|
21
|
+
end
|
22
|
+
|
23
|
+
And now create objects out of them and connect them:
|
24
|
+
|
25
|
+
subscriber = DummySubscriber.new
|
26
|
+
publisher = DummyPublisher.new
|
27
|
+
publisher.role = :kitty
|
28
|
+
publisher.subscribe(subscriber)
|
29
|
+
|
30
|
+
Let's try triggering an event:
|
31
|
+
|
32
|
+
publisher.publish_event(:myau, "saying myau")
|
33
|
+
|
34
|
+
And nothing is going to happen. Why? Because `subscriber` cannot yet handle kitty events.
|
35
|
+
He knows nothing about kittens, so even though he is subscribed to that kitty, he ignores it.
|
36
|
+
Let's help him learn:
|
37
|
+
|
38
|
+
class DummySubscriber
|
39
|
+
set_observed_publisher_callbacks(
|
40
|
+
kitty: { myau: -> (me, data) { puts data }}
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
`me` in this case is a reference to the object which you might or might not need and `data`
|
45
|
+
holds some arbitrary data that an event passes (in this case, a String). Now let's see if it works:
|
46
|
+
|
47
|
+
publisher.publish_event(:myau, "saying myau") # => saying myau
|
48
|
+
|
49
|
+
You can also control which subscriber are getting notified from the publisher itself. Of course,
|
50
|
+
the publisher doesn't need to who the subscribers are, but may simply rely on some characteristics,
|
51
|
+
essentially using polymorphism. Suppose we only want women to be notified when a kitten myaus, because
|
52
|
+
men are too busy hunting. We'll then do this:
|
53
|
+
|
54
|
+
|
55
|
+
class DummyPublisher
|
56
|
+
include ObservableRoles::Publisher
|
57
|
+
end
|
58
|
+
|
59
|
+
class DummySubscriber
|
60
|
+
attr_accessor :gender
|
61
|
+
include ObservableRoles::Subscriber
|
62
|
+
set_observed_publisher_callbacks(
|
63
|
+
kitty: { myau: -> (me, data) { puts "I'm a #{me.gender}, I hear kitten said #{data}" }}
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
subscriber1 = DummySubscriber.new
|
68
|
+
subscriber2 = DummySubscriber.new
|
69
|
+
publisher = DummyPublisher.new
|
70
|
+
publisher.role = :kitty
|
71
|
+
subscriber1.gender = 'female'
|
72
|
+
subscriber2.gender = 'male'
|
73
|
+
|
74
|
+
publisher.subscribe(subscriber1)
|
75
|
+
publisher.subscribe(subscriber1)
|
76
|
+
|
77
|
+
publisher.publish_event(:myau, "saying myau") { |subscriber| subscriber.gender == 'female' }
|
78
|
+
|
79
|
+
This will result in only output:
|
80
|
+
|
81
|
+
I'm a female, I hear kitten said myau
|
82
|
+
|
83
|
+
|
84
|
+
Both of these examples can be found in `/examples`.
|
85
|
+
|
86
|
+
## The following will be a short, but somewhat deeper explanation of the implementation
|
87
|
+
|
88
|
+
You have two objects: one is a Subscriber, another one is a Publisher.
|
89
|
+
You subscribe a Subscriber to the Publisher events with a Publisher#subscribe.
|
90
|
+
However the Subscriber would still ignore anything that Publisher publishes.
|
91
|
+
|
92
|
+
In order for it to be notified of the events, you must define callbacks with
|
93
|
+
Subscriber.set_observed_publisher_callbacks. These callbacks have the following form:
|
94
|
+
|
95
|
+
role_name: { event_name: -> (me, data) { } }
|
96
|
+
|
97
|
+
where `me` is a reference to the Subscriber object and `data` is a hash of some info
|
98
|
+
that is passed from the Publisher.
|
99
|
+
|
100
|
+
Now `role_name` is a role of the Pubslisher, which can be set as follows:
|
101
|
+
|
102
|
+
publisher.role = :good_cop
|
103
|
+
|
104
|
+
Obviously, each role may have many different events and those events may come from various
|
105
|
+
publishers who play the same role. This approach is more flexible than the standard Observer pattern,
|
106
|
+
since it allows easy many-to-many relationship to be established.
|
107
|
+
|
108
|
+
## Thread safety
|
109
|
+
|
110
|
+
Each new event that has a callback doesn't execute this callback immediately after said event is caught.
|
111
|
+
Instead, it is added into a queue of events, which are then executed one by one. This ensures that each event callback execution doesn't interfere with the other.
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
|
17
|
+
gem.name = "observable_roles"
|
18
|
+
gem.homepage = "http://github.com/snitko/observable_roles"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Thread-safe Observable pattern implementation with a queue}
|
21
|
+
gem.description = %Q{Thread-safe Observable pattern implementation with a queue}
|
22
|
+
gem.email = "roman.snitko@gmail.com"
|
23
|
+
gem.authors = ["Roman Snitko"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative '../lib/observable_roles'
|
2
|
+
|
3
|
+
class DummySubscriber
|
4
|
+
include ObservableRoles::Subscriber
|
5
|
+
set_observed_publisher_callbacks(
|
6
|
+
kitty: { myau: -> (me, data) { puts data }}
|
7
|
+
)
|
8
|
+
end
|
9
|
+
|
10
|
+
class DummyPublisher
|
11
|
+
include ObservableRoles::Publisher
|
12
|
+
end
|
13
|
+
|
14
|
+
subscriber = DummySubscriber.new
|
15
|
+
publisher = DummyPublisher.new
|
16
|
+
publisher.role = :kitty
|
17
|
+
publisher.subscribe(subscriber)
|
18
|
+
|
19
|
+
|
20
|
+
publisher.publish_event(:myau, "saying myau")
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative '../lib/observable_roles'
|
2
|
+
|
3
|
+
class DummyPublisher
|
4
|
+
include ObservableRoles::Publisher
|
5
|
+
end
|
6
|
+
|
7
|
+
class DummySubscriber
|
8
|
+
attr_accessor :gender
|
9
|
+
include ObservableRoles::Subscriber
|
10
|
+
set_observed_publisher_callbacks(
|
11
|
+
kitty: { myau: -> (me, data) { puts "I'm a #{me.gender}, I hear kitten said #{data}" }}
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
subscriber1 = DummySubscriber.new
|
16
|
+
subscriber2 = DummySubscriber.new
|
17
|
+
publisher = DummyPublisher.new
|
18
|
+
publisher.role = :kitty
|
19
|
+
subscriber1.gender = 'female'
|
20
|
+
subscriber2.gender = 'male'
|
21
|
+
|
22
|
+
publisher.subscribe(subscriber1)
|
23
|
+
publisher.subscribe(subscriber2)
|
24
|
+
|
25
|
+
publisher.publish_event(:myau, "saying myau") { |subscriber| subscriber.gender == 'female' }
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module ObservableRoles
|
2
|
+
|
3
|
+
module Subscriber
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
def set_observed_publisher_callbacks(callbacks)
|
7
|
+
@observed_publisher_callbacks = callbacks
|
8
|
+
end
|
9
|
+
def get_observed_publisher_callbacks
|
10
|
+
@observed_publisher_callbacks
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.included(base)
|
15
|
+
attr_accessor :subscriber_lock
|
16
|
+
attr_reader :captured_observable_events
|
17
|
+
base.extend(ClassMethods)
|
18
|
+
end
|
19
|
+
|
20
|
+
def capture_observable_event(role, event_name, data={})
|
21
|
+
return if role.nil? || event_name.nil?
|
22
|
+
role = role.to_sym
|
23
|
+
event_name = event_name.to_sym
|
24
|
+
if self.class.get_observed_publisher_callbacks.nil? || self.class.get_observed_publisher_callbacks[role].nil? || self.class.get_observed_publisher_callbacks[role][event_name].nil?
|
25
|
+
return
|
26
|
+
end
|
27
|
+
|
28
|
+
@captured_observable_events ||= []
|
29
|
+
@captured_observable_events.push({ callback: self.class.get_observed_publisher_callbacks[role][event_name], data: data })
|
30
|
+
release_captured_events unless @subscriber_lock
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def release_captured_events
|
37
|
+
@subscriber_lock = true
|
38
|
+
while !@captured_observable_events.empty?
|
39
|
+
e = @captured_observable_events.shift
|
40
|
+
e[:callback].call(self, e[:data])
|
41
|
+
end
|
42
|
+
@subscriber_lock = false
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
module Publisher
|
49
|
+
|
50
|
+
def self.included(base)
|
51
|
+
attr_accessor :role
|
52
|
+
end
|
53
|
+
|
54
|
+
def subscribe(s)
|
55
|
+
@observing_subscriber = [] unless @observing_subscriber
|
56
|
+
@observing_subscriber << s
|
57
|
+
end
|
58
|
+
|
59
|
+
def unsubscribe(s)
|
60
|
+
unless @observing_subscriber.blank?
|
61
|
+
@observing_subscriber.delete(s)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def publish_event(event_name, data={})
|
66
|
+
return unless @observing_subscriber
|
67
|
+
@observing_subscriber.each do |s|
|
68
|
+
if !block_given? || yield(s)
|
69
|
+
s.capture_observable_event(role, event_name, data)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "observable_roles"
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Roman Snitko"]
|
12
|
+
s.date = "2014-03-14"
|
13
|
+
s.description = "Thread-safe Observable pattern implementation with a queue"
|
14
|
+
s.email = "roman.snitko@gmail.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.markdown"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
"Gemfile",
|
21
|
+
"Gemfile.lock",
|
22
|
+
"LICENSE.txt",
|
23
|
+
"README.markdown",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"examples/example1.rb",
|
27
|
+
"examples/example2.rb",
|
28
|
+
"lib/observable_roles.rb",
|
29
|
+
"observable_roles.gemspec",
|
30
|
+
"spec/observable_roles_spec.rb"
|
31
|
+
]
|
32
|
+
s.homepage = "http://github.com/snitko/observable_roles"
|
33
|
+
s.licenses = ["MIT"]
|
34
|
+
s.require_paths = ["lib"]
|
35
|
+
s.rubygems_version = "2.0.3"
|
36
|
+
s.summary = "Thread-safe Observable pattern implementation with a queue"
|
37
|
+
|
38
|
+
if s.respond_to? :specification_version then
|
39
|
+
s.specification_version = 4
|
40
|
+
|
41
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
42
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0"])
|
43
|
+
s.add_development_dependency(%q<jeweler>, ["~> 2.0.1"])
|
44
|
+
else
|
45
|
+
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
46
|
+
s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
|
47
|
+
end
|
48
|
+
else
|
49
|
+
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
50
|
+
s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../lib/observable_roles'
|
2
|
+
|
3
|
+
class DummySubscriber
|
4
|
+
|
5
|
+
attr_accessor :dumbness_level
|
6
|
+
|
7
|
+
include ObservableRoles::Subscriber
|
8
|
+
|
9
|
+
set_observed_publisher_callbacks(
|
10
|
+
kitty: { myau: -> (me, data) { data.myau }}
|
11
|
+
)
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
class DummyPublisher
|
16
|
+
include ObservableRoles::Publisher
|
17
|
+
end
|
18
|
+
|
19
|
+
describe ObservableRoles do
|
20
|
+
|
21
|
+
before(:each) do
|
22
|
+
@subscriber = DummySubscriber.new
|
23
|
+
@publisher = DummyPublisher.new
|
24
|
+
@publisher.role = :kitty
|
25
|
+
@publisher.subscribe(@subscriber)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "executes a callback when an event is published" do
|
29
|
+
kitty_mock = double()
|
30
|
+
kitty_mock.should_receive(:myau).once
|
31
|
+
@publisher.publish_event(:myau, kitty_mock)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "puts callbacks in a queue and executes them one by one until the queue is empty" do
|
35
|
+
kitty_mock = double()
|
36
|
+
kitty_mock.should_receive(:myau).exactly(3).times
|
37
|
+
@subscriber.subscriber_lock = true
|
38
|
+
3.times { @publisher.publish_event(:myau, kitty_mock) }
|
39
|
+
@subscriber.subscriber_lock = false
|
40
|
+
@subscriber.captured_observable_events.should have(3).items
|
41
|
+
@subscriber.send(:release_captured_events)
|
42
|
+
@subscriber.captured_observable_events.should have(0).items
|
43
|
+
end
|
44
|
+
|
45
|
+
it "published event only to certain filtered subscribers" do
|
46
|
+
subscriber2 = DummySubscriber.new
|
47
|
+
@publisher.subscribe(subscriber2)
|
48
|
+
subscriber2.dumbness_level = 7
|
49
|
+
@subscriber.dumbness_level = 3
|
50
|
+
|
51
|
+
kitty_mock = double()
|
52
|
+
kitty_mock.should_receive(:myau).once
|
53
|
+
@publisher.publish_event(:myau, kitty_mock) { |subscriber| subscriber.dumbness_level < 5 }
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: observable_roles
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Roman Snitko
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-14 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.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: jeweler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.0.1
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.0.1
|
41
|
+
description: Thread-safe Observable pattern implementation with a queue
|
42
|
+
email: roman.snitko@gmail.com
|
43
|
+
executables: []
|
44
|
+
extensions: []
|
45
|
+
extra_rdoc_files:
|
46
|
+
- LICENSE.txt
|
47
|
+
- README.markdown
|
48
|
+
files:
|
49
|
+
- Gemfile
|
50
|
+
- Gemfile.lock
|
51
|
+
- LICENSE.txt
|
52
|
+
- README.markdown
|
53
|
+
- Rakefile
|
54
|
+
- VERSION
|
55
|
+
- examples/example1.rb
|
56
|
+
- examples/example2.rb
|
57
|
+
- lib/observable_roles.rb
|
58
|
+
- observable_roles.gemspec
|
59
|
+
- spec/observable_roles_spec.rb
|
60
|
+
homepage: http://github.com/snitko/observable_roles
|
61
|
+
licenses:
|
62
|
+
- MIT
|
63
|
+
metadata: {}
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - '>='
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
requirements: []
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 2.0.3
|
81
|
+
signing_key:
|
82
|
+
specification_version: 4
|
83
|
+
summary: Thread-safe Observable pattern implementation with a queue
|
84
|
+
test_files: []
|