switch_board 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 91e063073337aaae7434db2dfac68242ede19862
4
+ data.tar.gz: 69c598242c91f8cae70bc15e1d36bd1bec949fc4
5
+ SHA512:
6
+ metadata.gz: 710f0b21c6665cfaa75493c1fa3c02a464a45ed8589c5542868573558b180d9b3d6cc193132b230656139fbc972b033da111811ee72670696daf95e2db04d0a7
7
+ data.tar.gz: 50449a1bb33c60dec1cbc2e4673f5b71ce99d44428d2dcc2d5b8c1978526a8456a561111e1f9a5fe9a1f6a23e7deb6b8f96ced6fadfb78da1cb6cf12a02f104c
data/.document ADDED
@@ -0,0 +1,4 @@
1
+ lib/**/*.rb
2
+ README.rdoc
3
+ ChangeLog.rdoc
4
+ LICENSE.txt
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ html/
2
+ pkg/
3
+ *.gem
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ switch_board
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.0.0-p247
data/ChangeLog.rdoc ADDED
@@ -0,0 +1,4 @@
1
+ === 0.1.0 / 2013-07-16
2
+
3
+ * Initial release:
4
+
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rdoc'
6
+ gem 'rubygems-tasks'
7
+
8
+ #For the redis dataset
9
+ gem 'redis'
10
+ gem 'redis-objects'
11
+ gem 'rsolr'
12
+
13
+ group :test do
14
+ gem 'rspec'
15
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,39 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ switch_board (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ builder (3.2.2)
10
+ diff-lcs (1.2.4)
11
+ json (1.8.0)
12
+ rdoc (4.0.1)
13
+ json (~> 1.4)
14
+ redis (3.0.2)
15
+ redis-objects (0.6.1)
16
+ redis (>= 3.0.2)
17
+ rsolr (1.0.9)
18
+ builder (>= 2.1.2)
19
+ rspec (2.14.1)
20
+ rspec-core (~> 2.14.0)
21
+ rspec-expectations (~> 2.14.0)
22
+ rspec-mocks (~> 2.14.0)
23
+ rspec-core (2.14.3)
24
+ rspec-expectations (2.14.0)
25
+ diff-lcs (>= 1.1.3, < 2.0)
26
+ rspec-mocks (2.14.1)
27
+ rubygems-tasks (0.2.4)
28
+
29
+ PLATFORMS
30
+ ruby
31
+
32
+ DEPENDENCIES
33
+ rdoc
34
+ redis
35
+ redis-objects
36
+ rsolr
37
+ rspec
38
+ rubygems-tasks
39
+ switch_board!
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Avner Cohen
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,78 @@
1
+ ## switch_board
2
+
3
+ ![http://makemusicals.com/2011/11/communication-101-toeing-the-party-line/switchboard1/](http://makemusicals.com/wp-content/uploads/2011/11/switchboard1-300x236.jpg "Switchboard")
4
+
5
+ ### Description
6
+
7
+ **SwitchBoard** is a utility gem designed to help in the coordination of locked objects by a set of "lockers".
8
+ Think of a bank's cashiers, where customers are in line to be served.
9
+ When a customer is served by a cashier, it is still in line to be served, but is now "locked".
10
+
11
+ Locking expiration is allowed so that if during "serving" a cashier got some other business to do and runs home, it will go back to the queue when lock expires.
12
+
13
+ The overall scope of the gem is:
14
+
15
+ * Allow "lockers" to register themselves
16
+ * Allow "lockers" to set a "lock" on object, with a predefined expiration period
17
+ * Allow lockers with special "roles" to force locks
18
+ * Allow external observes to see current state of locked object
19
+
20
+ ### Features
21
+
22
+ The system is light weight and is designed to have low number of "lockers" with many object to be locked.
23
+ It is pluggable and well tested so should allow extensions as needed.
24
+
25
+ ### Examples
26
+
27
+ ````ruby
28
+
29
+ require 'switch_board'
30
+
31
+
32
+ #create a new switch_board configuration
33
+ sb = SwitchBoard::Configuration.new #Redis backends
34
+ dataset = sb.dataset
35
+
36
+ #Register Lockers (unique identifier, Name/Alias)
37
+ dataset.register_locker(1, "Django")
38
+ dataset.register_locker(2, "Pier")
39
+ dataset.register_locker(3, "Mark")
40
+
41
+ #Print out the list of active users
42
+ p dataset.list_lockers
43
+
44
+ #Lock IDs for Pier - IDed as 2
45
+ dataset.lock_id(2, "qwerfggj", 5) # lock for 5 seconds
46
+ dataset.lock_id(2, "12345", 600) #Lock for 10 minutes
47
+
48
+ #Check to see if ID is locked
49
+ dataset.id_locked?("12345") #=> true
50
+ dataset.id_locked?("qwerfggj") #=> true
51
+ dataset.id_locked?("not_locked_id") #=> false
52
+
53
+ #Show all locked objects
54
+ dataset.get_all_locked_ids #=> {"12345"=>"2", "qwerfggj"=>"2"}
55
+
56
+ ````
57
+ ### Other Gems
58
+
59
+ Worth mentioning that there are other nice gems that takes care of Redis-backed Mutex implementaion:
60
+
61
+ * https://github.com/dv/redis-semaphore
62
+ * https://github.com/mlanett/redis-lock
63
+ * https://github.com/kenn/redis-mutex
64
+
65
+ However, this gem is not target a protection on specific a single resource during operation,
66
+ instead it is targated to manage Distrbition of work between multiple clients/lockers that can take longer time to process the locked resources.
67
+ It is also not targated for high scale systems, locking is done by humans so there is little to no risk in race conditions.
68
+ And lastly, the gem provides an API to get all currently locked IDs which is important for the "switch_board" problem where some high level managment of the currently locked ID is needed.
69
+
70
+
71
+ ### Install
72
+
73
+ ````
74
+ $ gem install switch_board
75
+ ````
76
+ ### Copyright
77
+
78
+ See LICENSE.txt for details.
data/Rakefile ADDED
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'rake'
5
+
6
+ begin
7
+ gem 'rubygems-tasks', '~> 0.2'
8
+ require 'rubygems/tasks'
9
+
10
+ Gem::Tasks.new
11
+ rescue LoadError => e
12
+ warn e.message
13
+ warn "Run `gem install rubygems-tasks` to install Gem::Tasks."
14
+ end
15
+
16
+ begin
17
+ gem 'rdoc', '~> 3.0'
18
+ require 'rdoc/task'
19
+
20
+ RDoc::Task.new do |rdoc|
21
+ rdoc.title = "switch_board"
22
+ end
23
+ rescue LoadError => e
24
+ warn e.message
25
+ warn "Run `gem install rdoc` to install 'rdoc/task'."
26
+ end
27
+ task :doc => :rdoc
28
+
29
+ begin
30
+ gem 'rspec', '~> 2.4'
31
+ require 'rspec/core/rake_task'
32
+
33
+ RSpec::Core::RakeTask.new
34
+ rescue LoadError => e
35
+ task :spec do
36
+ abort "Please run `gem install rspec` to install RSpec."
37
+ end
38
+ end
39
+
40
+ task :test => :spec
41
+ task :default => :spec
@@ -0,0 +1,13 @@
1
+ require 'switch_board/datasets/redis_dataset'
2
+
3
+ module SwitchBoard
4
+
5
+ class Configuration
6
+ attr_accessor :dataset
7
+
8
+ def initialize(dataset = SwitchBoard::RedisDataset.new)
9
+ @dataset = dataset
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,62 @@
1
+ #define API for the data set
2
+ module SwitchBoard
3
+ class AbstractDataset
4
+
5
+ attr_accessor :persistance
6
+
7
+ def set_persistance(persistance)
8
+ @persistance = persistance
9
+ end
10
+
11
+ #Returns the next Model/ID that is available from the dataset
12
+ def get_next(limit = 1)
13
+ raise "#{__method__} not implemented in #{self.class.name}"
14
+ end
15
+
16
+ #get the IDs that are now locked by other lockers
17
+ def get_locked
18
+ raise "#{__method__} not implemented in #{self.class.name}"
19
+ end
20
+
21
+ #setup a new switchboard, a coordination persistence schema
22
+ def switchboard
23
+ raise "#{__method__} not implemented in #{self.class.name}"
24
+ end
25
+
26
+ #Add a new locker to the switchboard for future coordination
27
+ def register_locker(uid, name)
28
+ raise "#{__method__} not implemented in #{self.class.name}"
29
+ end
30
+
31
+ #list all the lockers registerd for this switchboard
32
+ def list_lockers
33
+ raise "#{__method__} not implemented in #{self.class.name}"
34
+ end
35
+
36
+ #list retrive data of a specific locker
37
+ def locker(uid)
38
+ raise "#{__method__} not implemented in #{self.class.name}"
39
+ end
40
+
41
+ #Set ID of an object as locked for a specific uid
42
+ def lock_id(locker_uid, id_to_lock, expire_in_sec = 60)
43
+ raise "#{__method__} not implemented in #{self.class.name}"
44
+ end
45
+
46
+ #Set ID of an object as locked for a specific uid
47
+ def unlock_id(locker_uid, id_to_unlock)
48
+ raise "#{__method__} not implemented in #{self.class.name}"
49
+ end
50
+
51
+ #Check to see if a certain ID is locked or not
52
+ def id_locked?(uid)
53
+ raise "#{__method__} not implemented in #{self.class.name}"
54
+ end
55
+
56
+ #Retrive all the locked ids in the switchboard
57
+ def get_all_locked_ids
58
+ raise "#{__method__} not implemented in #{self.class.name}"
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,102 @@
1
+ require 'switch_board/datasets/abstract_dataset'
2
+ require "redis"
3
+ require 'json'
4
+
5
+ module SwitchBoard
6
+
7
+ class RedisDataset < SwitchBoard::AbstractDataset
8
+
9
+
10
+ LOCK_MAP_KEY = "switch_board::locked_ids"
11
+ attr_accessor :con, :switchboard, :name
12
+
13
+ def initialize(host = "127.0.0.1", port = 6379, name = "redis_switchbord")
14
+ @con = Redis.new(:host => host, :port => port)
15
+ @name = name
16
+ end
17
+
18
+ def cleanup
19
+ ## clean up keys, used mainly for testing
20
+ @con.del @name
21
+ @con.del "#{LOCK_MAP_KEY}_z"
22
+ @con.del "#{LOCK_MAP_KEY}_h"
23
+ end
24
+
25
+ def get_locked
26
+ active_lockers = list_lockers.map { |item| JSON.parse(item)}
27
+ active_lockers
28
+ end
29
+
30
+ def switchboard
31
+ @switchboard ||= @con.smembers @name
32
+ end
33
+
34
+ def register_locker(uid, name)
35
+ @con.sadd @name, {uid: uid, name: name, created_at: redis_time}.to_json.to_s
36
+ list_lockers ## update lockers list
37
+ true
38
+ end
39
+
40
+ def list_lockers
41
+ list_lockers ||= (@con.smembers @name).map { |item| JSON.parse(item)}
42
+ end
43
+
44
+ def locker(uid)
45
+ (list_lockers.select {|locker| locker["uid"] == uid}).first
46
+ end
47
+
48
+ #Locking mechanisem is based on sorted set, sorted set is used to allow a simulation
49
+ # of expiration time on the keys in the map
50
+ def lock_id(locker_uid, id_to_lock, expire_in_sec = 5)
51
+ now = redis_time
52
+ @con.multi do
53
+ @con.zadd("#{LOCK_MAP_KEY}_z", (now + expire_in_sec), id_to_lock)
54
+ @con.hset("#{LOCK_MAP_KEY}_h", id_to_lock, locker_uid)
55
+ end
56
+ end
57
+
58
+ #Check if key exists to see if it is locked and it has not expired
59
+ #before getting keys, remove expired keys
60
+ def id_locked?(id_to_check)
61
+ @con.hexists("#{LOCK_MAP_KEY}_h", id_to_check)
62
+ end
63
+
64
+
65
+ def unlock_id(locker_uid, id_to_unlock)
66
+ @con.hset("#{LOCK_MAP_KEY}_h", id_to_lock, locker_uid)
67
+ end
68
+
69
+ def get_all_locked_ids
70
+ clean_old_keys
71
+ @con.hgetall "#{LOCK_MAP_KEY}_h"
72
+ end
73
+
74
+ def get_all_their_locked_ids(uid)
75
+ res = get_all_locked_ids
76
+ res.reject {|key, key_uid| key_uid.to_s == uid.to_s }
77
+ end
78
+
79
+ def get_all_my_locked_ids(uid)
80
+ res = get_all_locked_ids
81
+ res.select {|key, key_uid| key_uid.to_s == uid.to_s }
82
+ end
83
+
84
+ ##################### Private Methods #################
85
+ private
86
+
87
+ def clean_old_keys
88
+ keys = @con.zrangebyscore("#{LOCK_MAP_KEY}_z", 0, redis_time)
89
+ if keys.size > 0
90
+ @con.zremrangebyscore("#{LOCK_MAP_KEY}_z", 0, redis_time)
91
+ keys.each {|key| @con.hdel("#{LOCK_MAP_KEY}_h", key)}
92
+ end
93
+ end
94
+
95
+ def redis_time
96
+ instant = @con.time
97
+ Time.at(instant[0], instant[1]).to_i
98
+ end
99
+
100
+ end
101
+
102
+ end
@@ -0,0 +1,3 @@
1
+ module SwitchBoard
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,26 @@
1
+ require 'switch_board/version'
2
+ require 'switch_board/configuration'
3
+
4
+ module SwitchBoard
5
+
6
+ def self.logger
7
+ @logger ||= (rails_logger || default_logger)
8
+ end
9
+
10
+ def self.rails_logger
11
+ (defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger) ||
12
+ (defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER.respond_to?(:debug) && RAILS_DEFAULT_LOGGER)
13
+ end
14
+
15
+ def self.default_logger
16
+ require 'logger'
17
+ l = Logger.new(STDOUT)
18
+ l.level = Logger::INFO
19
+ l
20
+ end
21
+
22
+ def self.logger=(logger)
23
+ @logger = logger
24
+ end
25
+
26
+ end
data/run_test ADDED
@@ -0,0 +1 @@
1
+ rspec ./spec/**.*
@@ -0,0 +1,3 @@
1
+ require 'rspec'
2
+
3
+ Dir["#{File.dirname(__FILE__)}/../lib/**/*.rb"].each { |f| load(f) }
@@ -0,0 +1,166 @@
1
+ describe SwitchBoard do
2
+ it "should have a VERSION constant" do
3
+ subject.const_get('VERSION').should_not be_empty
4
+ end
5
+
6
+ it "should have a logger defined" do
7
+ subject.logger.should_not be_nil
8
+ end
9
+
10
+ it "should have good working logger" do
11
+ subject.logger.should respond_to(:info, :error, :debug)
12
+ end
13
+ end
14
+
15
+ describe :Configuration do
16
+ it "should have a dataset" do
17
+ conf = SwitchBoard::Configuration.new(SwitchBoard::RedisDataset.new("127.0.0.1", 6379, "testing_playground"))
18
+ conf.should respond_to(:dataset)
19
+ end
20
+ end
21
+
22
+ describe :ApplicationLifeCycle do
23
+ it "should not lose locks with multiple workers starting a new dataset" do
24
+ dataset1 = SwitchBoard::Configuration.new(SwitchBoard::RedisDataset.new("127.0.0.1", 6379, "testing_playground")).dataset
25
+ dataset1.cleanup
26
+ dataset1.register_locker(1, "Moshe")
27
+ dataset1.list_lockers.count.should eq 1
28
+ dataset2 = SwitchBoard::Configuration.new(SwitchBoard::RedisDataset.new("127.0.0.1", 6379, "testing_playground")).dataset
29
+ #dataset1 should still show single locker
30
+ dataset1.list_lockers.count.should eq 1
31
+ end
32
+
33
+ it "should be possible to name switchboard dataset" do
34
+ dataset = SwitchBoard::RedisDataset.new("127.0.0.1", 6379, "testing_playground")
35
+ dataset.name.should eq "testing_playground"
36
+ end
37
+ end
38
+
39
+ describe :RedisDataset do
40
+ let!(:dataset) {
41
+ dataset = SwitchBoard::Configuration.new(SwitchBoard::RedisDataset.new("127.0.0.1", 6379, "testing_playground")).dataset
42
+ dataset.cleanup
43
+ dataset
44
+ }
45
+
46
+ it "should implemenet get_locked" do
47
+ expect { dataset.get_locked }.not_to raise_error
48
+ end
49
+
50
+ describe :RedisDatasetSwitchBoard do
51
+ let!(:switchboard) {SwitchBoard::Configuration.new(SwitchBoard::RedisDataset.new("127.0.0.1", 6379, "testing_playground")).dataset.switchboard }
52
+
53
+ it "should be able to create a new locking set" do
54
+ switchboard.should match_array([])
55
+ end
56
+
57
+ it "should have clean locker board on startup" do
58
+ lockers = dataset.list_lockers
59
+ lockers.count.should eq 0
60
+ end
61
+
62
+ it "should allow registering lockers" do
63
+ dataset.register_locker(1, "Moshe")
64
+ dataset.register_locker(2, "Raz")
65
+ dataset.register_locker(3, "Pupik")
66
+ lockers = dataset.list_lockers
67
+ lockers.count.should eq 3
68
+ end
69
+
70
+ it "should allow registering with strings" do
71
+ dataset.register_locker("muke", "Moshe")
72
+ dataset.register_locker("uke", "Raz")
73
+ lockers = dataset.list_lockers
74
+ lockers.count.should eq 2
75
+ end
76
+
77
+ it "should allow getting a locker registerd with a non int UID" do
78
+ dataset.register_locker("muke", "Moshe")
79
+ dataset.locker("muke")["name"].should eq("Moshe")
80
+ end
81
+
82
+ it "should allow getting name of a registered locker by uid" do
83
+ dataset.register_locker(1, "Pupik")
84
+ dataset.register_locker(2, "Raz")
85
+ dataset.register_locker(3, "Moshe")
86
+ dataset.locker(3)["name"].should eq "Moshe"
87
+ end
88
+
89
+ it "should return nil for non existing uid" do
90
+ dataset.register_locker(1, "Pupik")
91
+ dataset.register_locker(2, "Raz")
92
+ dataset.register_locker(3, "Moshe")
93
+ dataset.locker(4).should be_nil
94
+ end
95
+
96
+ it "should allow locking object id for specific locker" do
97
+ dataset.register_locker(1, "Pupik")
98
+ dataset.register_locker(2, "Raz")
99
+ expect { dataset.lock_id(1, "SOME_ID") }.not_to raise_error
100
+ end
101
+
102
+ it "should allow checking lock state for a given id " do
103
+ dataset.register_locker(1, "Pupik")
104
+ dataset.register_locker(2, "Raz")
105
+ expect { dataset.lock_id(1, "SOME_ID_E") }.not_to raise_error
106
+ is_locked = dataset.id_locked?("SOME_ID_E")
107
+ is_locked.should eq true
108
+ end
109
+
110
+
111
+ it "should allow should lock id only for as per expiration time" do
112
+ dataset.register_locker(1, "Pupik")
113
+ dataset.register_locker(2, "Raz")
114
+ expect { dataset.lock_id(1, "SOME_ID_2", 1) }.not_to raise_error
115
+ dataset.id_locked?("SOME_ID_2").should be_true
116
+ sleep(2)
117
+ dataset.id_locked?("SOME_ID_3").should be_false
118
+ end
119
+
120
+ it "should return unlocked of unlocked key" do
121
+ dataset.register_locker(1, "Pupik")
122
+ dataset.register_locker(2, "Raz")
123
+ dataset.id_locked?("SOME_ID_4").should be_false
124
+ end
125
+
126
+ it "should allow getting all the locked IDs" do
127
+ dataset.register_locker(1, "Pupik")
128
+ dataset.register_locker(2, "Raz")
129
+ expect { dataset.lock_id(1, "SOME_ID_5") }.not_to raise_error
130
+ expect { dataset.lock_id(1, "SOME_OTHER_ID") }.not_to raise_error
131
+ expect { dataset.lock_id(2, "SOME_THIRD_ID") }.not_to raise_error
132
+ expect { dataset.lock_id(2, "SOME_FOURTH_ID") }.not_to raise_error
133
+ dataset.get_all_locked_ids.count.should eq 4
134
+ end
135
+
136
+ it "should get clean results when no IDs are locked" do
137
+ dataset.register_locker(1, "Pupik")
138
+ dataset.register_locker(2, "Raz")
139
+ dataset.get_all_locked_ids.count.should eq 0
140
+ end
141
+
142
+ it "should allow users to get all IDs not locked by itself" do
143
+ dataset.register_locker(1, "Pupik")
144
+ dataset.register_locker(2, "Raz")
145
+ dataset.lock_id(1, "SOME_ID_6")
146
+ dataset.lock_id(1, "SOME_ID_7")
147
+ dataset.lock_id(1, "SOME_ID_8")
148
+ dataset.lock_id(2, "SOME_ID_9")
149
+ dataset.get_all_their_locked_ids(2).count.should eq 3
150
+ end
151
+
152
+
153
+ it "should allow users to get all IDs locked by themselves" do
154
+ dataset.register_locker(1, "Pupik")
155
+ dataset.register_locker(2, "Raz")
156
+ dataset.lock_id(1, "SOME_ID_6")
157
+ dataset.lock_id(1, "SOME_ID_7")
158
+ dataset.lock_id(1, "SOME_ID_8")
159
+ dataset.lock_id(2, "SOME_ID_9")
160
+ dataset.get_all_my_locked_ids(2).count.should eq 1
161
+ end
162
+
163
+
164
+ end
165
+
166
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require File.expand_path('../lib/switch_board/version', __FILE__)
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = "switch_board"
7
+ gem.version = SwitchBoard::VERSION
8
+ gem.summary = %q{Coordinate a set of persisted data and distribute to an active set of registerd clients}
9
+ gem.description = %q{Coordinate a set of persisted data models and distribute to an active set of registerd clients. Allows locking and automatic expiration for locking on portions of the data}
10
+ gem.license = "MIT"
11
+ gem.authors = ["Avner Cohen"]
12
+ gem.email = "israbirding@gmail.com"
13
+ gem.homepage = "https://rubygems.org/gems/switch_board"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ['lib']
19
+
20
+ gem.add_development_dependency 'rdoc', '~> 3.0'
21
+ gem.add_development_dependency 'rspec', '~> 2.4'
22
+ gem.add_development_dependency 'rubygems-tasks', '~> 0.2'
23
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: switch_board
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Avner Cohen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-09-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rdoc
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '2.4'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '2.4'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubygems-tasks
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '0.2'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '0.2'
55
+ description: Coordinate a set of persisted data models and distribute to an active
56
+ set of registerd clients. Allows locking and automatic expiration for locking on
57
+ portions of the data
58
+ email: israbirding@gmail.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - .document
64
+ - .gitignore
65
+ - .rspec
66
+ - .ruby-gemset
67
+ - .ruby-version
68
+ - ChangeLog.rdoc
69
+ - Gemfile
70
+ - Gemfile.lock
71
+ - LICENSE.txt
72
+ - README.md
73
+ - Rakefile
74
+ - lib/switch_board.rb
75
+ - lib/switch_board/configuration.rb
76
+ - lib/switch_board/datasets/abstract_dataset.rb
77
+ - lib/switch_board/datasets/redis_dataset.rb
78
+ - lib/switch_board/version.rb
79
+ - run_test
80
+ - spec/spec_helper.rb
81
+ - spec/switch_board_spec.rb
82
+ - switch_board.gemspec
83
+ homepage: https://rubygems.org/gems/switch_board
84
+ licenses:
85
+ - MIT
86
+ metadata: {}
87
+ post_install_message:
88
+ rdoc_options: []
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ requirements: []
102
+ rubyforge_project:
103
+ rubygems_version: 2.0.3
104
+ signing_key:
105
+ specification_version: 4
106
+ summary: Coordinate a set of persisted data and distribute to an active set of registerd
107
+ clients
108
+ test_files:
109
+ - spec/spec_helper.rb
110
+ - spec/switch_board_spec.rb