keymap 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/.travis.yml +2 -0
- data/README.rdoc +47 -31
- data/Rakefile +21 -1
- data/keymap.gemspec +4 -5
- data/lib/keymap/connection_adapters/abstract/connection_pool.rb +4 -21
- data/lib/keymap/connection_adapters/abstract/connection_specification.rb +1 -1
- data/lib/keymap/connection_adapters/redis_adapter.rb +113 -20
- data/lib/keymap/version.rb +1 -1
- data/spec/functional/hash_spec.rb +140 -0
- data/spec/functional/list_spec.rb +36 -0
- data/spec/support/config.yml +1 -1
- metadata +25 -7
- data/spec/unit/test.rb +0 -89
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/README.rdoc
CHANGED
@@ -1,21 +1,16 @@
|
|
1
1
|
= Keymap
|
2
2
|
|
3
|
+
{<img src="https://secure.travis-ci.org/rbuck/keymap.png?branch=master" alt="Continuous Integration Status" />}[http://travis-ci.org/rbuck/keymap]
|
4
|
+
{<img src="https://gemnasium.com/rbuck/keymap.png?travis" alt="Dependency Status" />}[https://gemnasium.com/rbuck/keymap]
|
5
|
+
{<img src="https://codeclimate.com/badge.png" alt="Code Climate" />}[https://codeclimate.com/github/rbuck/keymap]
|
6
|
+
|
3
7
|
Helping Ruby developers and their companies, unlock their key-value store data,
|
4
8
|
through associative and sequential based access, providing unprecedented support
|
5
9
|
for map reduce behaviors, native to the Ruby language.
|
6
10
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
1. Provide a simple abstraction layer over NoSQL databases, allowing easy
|
11
|
-
migration from one to another without having to rewrite application code.
|
12
|
-
|
13
|
-
2. Provide a natural Ruby integration with NoSQL database, allowing direct
|
14
|
-
use of Enumerable operations on returned values (implying returned values
|
15
|
-
are always lists or hashes, or are manipulated to be represented in these
|
16
|
-
forms).
|
17
|
-
|
18
|
-
{<img src="https://secure.travis-ci.org/rbuck/keymap.png?branch=master" alt="Continuous Integration Status" />}[http://travis-ci.org/rbuck/keymap]
|
11
|
+
Keymap provides a natural Ruby integration with NoSQL database, allowing direct
|
12
|
+
use of Enumerable operations on returned values (implying returned values are
|
13
|
+
always lists or hashes, or are manipulated to be represented in these forms).
|
19
14
|
|
20
15
|
== Installation
|
21
16
|
|
@@ -33,7 +28,35 @@ Or install it yourself as:
|
|
33
28
|
|
34
29
|
== Usage
|
35
30
|
|
36
|
-
|
31
|
+
Here is a simple example of how to use keymap:
|
32
|
+
|
33
|
+
Keymap::Base.establish_connection 'test'
|
34
|
+
connection = Keymap::Base.connection
|
35
|
+
|
36
|
+
list = connection.list :what
|
37
|
+
(0..10).each do |value|
|
38
|
+
list << value
|
39
|
+
end
|
40
|
+
|
41
|
+
sum = list.inject(0) do |result, item|
|
42
|
+
result + item.to_i
|
43
|
+
end
|
44
|
+
|
45
|
+
The key observation here is this: no key-value store specific API, its plain ordinary Ruby.
|
46
|
+
One more example on how to use keymap, this time with a hash:
|
47
|
+
|
48
|
+
accounting = @connection.hash :accounting
|
49
|
+
salaries = {
|
50
|
+
Bob: 82000,
|
51
|
+
Jim: 94000,
|
52
|
+
Billy: 58000
|
53
|
+
}
|
54
|
+
accounting.merge! salaries
|
55
|
+
total = 0
|
56
|
+
accounting.each_value do |value|
|
57
|
+
total = total + value.to_i
|
58
|
+
end
|
59
|
+
total => # 234000
|
37
60
|
|
38
61
|
== Contributing
|
39
62
|
|
@@ -54,40 +77,33 @@ TBD
|
|
54
77
|
|
55
78
|
== Configure databases
|
56
79
|
|
57
|
-
Copy
|
58
|
-
the first time, which will do the copy automatically and use the default (
|
80
|
+
Copy spec/support/config.example.yml to spec/support/config.yml and edit as needed. Or just run the tests for
|
81
|
+
the first time, which will do the copy automatically and use the default (redis).
|
59
82
|
|
60
|
-
You can
|
83
|
+
You can set up redis using the redis:start_server rake tasks.
|
61
84
|
|
62
85
|
== Running the tests
|
63
86
|
|
64
87
|
You can run a particular test file from the command line, e.g.
|
65
88
|
|
66
|
-
$ ruby -Itest
|
89
|
+
$ ruby -Itest spec/functional/adapter_spec.rb
|
67
90
|
|
68
91
|
To run a specific test:
|
69
92
|
|
70
|
-
$ ruby -Itest
|
93
|
+
$ ruby -Itest spec/functional/adapter_spec.rb -n test_something_works
|
71
94
|
|
72
|
-
You can run with a database other than the default you set in
|
95
|
+
You can run with a database other than the default you set in spec/support/config.yml, using the KEYCONN
|
73
96
|
environment variable:
|
74
97
|
|
75
|
-
$
|
98
|
+
$ KEYCONN=redis ruby -Itest spec/functional/adapter_spec.rb
|
76
99
|
|
77
100
|
You can run all the tests for a given database via rake:
|
78
101
|
|
79
|
-
$ rake
|
80
|
-
|
81
|
-
The 'rake test' task will run all the tests for mysql, mysql2, sqlite3 and postgresql.
|
82
|
-
|
83
|
-
== Identity Map
|
84
|
-
|
85
|
-
By default the tests run with the Identity Map turned off. But all tests should pass whether or
|
86
|
-
not the identity map is on or off. You can turn it on using the IM env variable:
|
102
|
+
$ rake test_redis
|
87
103
|
|
88
|
-
|
104
|
+
The 'rake test' task will run all the tests for redis, couchdb, and riak,
|
89
105
|
|
90
106
|
== Config file
|
91
107
|
|
92
|
-
By default, the config file is expected to be at the path
|
93
|
-
custom location with the
|
108
|
+
By default, the config file is expected to be at the path spec/support/config.yml. You can specify a
|
109
|
+
custom location with the KEYCONFIG environment variable.
|
data/Rakefile
CHANGED
@@ -21,6 +21,8 @@ Dir['tasks/**/*.rb'].each { |file| load file }
|
|
21
21
|
GEM_NAME = "keymap"
|
22
22
|
GEM_VERSION = Keymap::VERSION
|
23
23
|
|
24
|
+
CLEAN.include('doc/ri')
|
25
|
+
CLEAN.include('doc/site')
|
24
26
|
CLEAN.include('pkg')
|
25
27
|
|
26
28
|
task :default => :spec
|
@@ -48,7 +50,7 @@ desc "Release version #{Keymap::VERSION}"
|
|
48
50
|
task :release => [:tag, :push]
|
49
51
|
|
50
52
|
desc "Provides tasks for each adapter type, e.g. test_redis"
|
51
|
-
%w(
|
53
|
+
%w( redis ).each do |adapter|
|
52
54
|
Rake::TestTask.new("test_#{adapter}") { |t|
|
53
55
|
adapter_short = adapter[/^[a-z0-9]+/]
|
54
56
|
t.libs << 'test'
|
@@ -108,3 +110,21 @@ task :lines do
|
|
108
110
|
|
109
111
|
puts "Total: Lines #{total_lines}, LOC #{total_codelines}"
|
110
112
|
end
|
113
|
+
|
114
|
+
RDOC_FILES = FileList['README.rdoc', 'lib/**/*.rb']
|
115
|
+
|
116
|
+
require 'rdoc/task'
|
117
|
+
Rake::RDocTask.new do |rdoc|
|
118
|
+
rdoc.title = "#{GEM_NAME} #{GEM_VERSION}"
|
119
|
+
rdoc.main = 'README.rdoc'
|
120
|
+
rdoc.rdoc_dir = 'doc/site/api'
|
121
|
+
rdoc.options << "-a" << "-U" << "-D" << "-v"
|
122
|
+
rdoc.rdoc_files.include(RDOC_FILES)
|
123
|
+
end
|
124
|
+
|
125
|
+
Rake::RDocTask.new(:ri) do |rdoc|
|
126
|
+
rdoc.main = "README.rdoc"
|
127
|
+
rdoc.rdoc_dir = "doc/ri"
|
128
|
+
rdoc.options << "--ri-system"
|
129
|
+
rdoc.rdoc_files.include(RDOC_FILES)
|
130
|
+
end
|
data/keymap.gemspec
CHANGED
@@ -8,21 +8,20 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Keymap::VERSION
|
9
9
|
spec.authors = ['Robert Buck']
|
10
10
|
spec.email = 'buck.robert.j@gmail.com'
|
11
|
-
spec.description =
|
12
|
-
spec.summary =
|
11
|
+
spec.description = 'Helping Ruby developers and their companies, unlock their key-value store data, through associative and sequential based access, providing unprecedented support for map reduce behaviors, native to the Ruby language'
|
12
|
+
spec.summary = 'Abstracts choosing a key-value store implementation, and provides a natural enumerable-based Ruby API for hashed and sequential collections.'
|
13
13
|
spec.homepage = 'https://github.com/rbuck/keymap'
|
14
|
-
spec.date = '2012-10-28'
|
15
14
|
|
16
15
|
spec.files = `git ls-files`.split($/)
|
17
16
|
spec.executables = spec.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
18
17
|
spec.test_files = spec.files.grep(%r{^(tasks|spec|features)/})
|
19
|
-
spec.require_paths =
|
18
|
+
spec.require_paths = %w(lib)
|
20
19
|
|
21
20
|
spec.add_dependency "erubis", "~> 2.7.0"
|
22
21
|
spec.add_dependency "redis", "~> 3.0.2"
|
23
22
|
spec.add_dependency "activesupport", "~> 3.2.8"
|
24
23
|
|
25
|
-
%w(rake rdoc simplecov).each { |gem| spec.add_development_dependency gem }
|
24
|
+
%w(rake rdoc simplecov hanna-nouveau).each { |gem| spec.add_development_dependency gem }
|
26
25
|
%w(ruby-prof).each { |gem| spec.add_development_dependency gem }
|
27
26
|
%w(rspec rspec-core rspec-expectations rspec-mocks).each { |gem| spec.add_development_dependency gem, "~> 2.11.0" }
|
28
27
|
end
|
@@ -178,7 +178,7 @@ module Keymap
|
|
178
178
|
ActiveSupport::Deprecation.warn(<<-eowarn) if conn.in_use?
|
179
179
|
Database connections will not be closed automatically, please close your
|
180
180
|
database connection at the end of the thread by calling `close` on your
|
181
|
-
connection. For example:
|
181
|
+
connection. For example: Keymap::Base.connection.close
|
182
182
|
eowarn
|
183
183
|
checkin conn
|
184
184
|
@reserved_connections.delete(key)
|
@@ -304,28 +304,11 @@ connection. For example: ActiveRecord::Base.connection.close
|
|
304
304
|
end
|
305
305
|
|
306
306
|
# ConnectionHandler is a collection of ConnectionPool objects. It is used
|
307
|
-
# for keeping separate connection pools for
|
308
|
-
#
|
309
|
-
#
|
310
|
-
# For example, suppose that you have 5 models, with the following hierarchy:
|
311
|
-
#
|
312
|
-
# |
|
313
|
-
# +-- Book
|
314
|
-
# | |
|
315
|
-
# | +-- ScaryBook
|
316
|
-
# | +-- GoodBook
|
317
|
-
# +-- Author
|
318
|
-
# +-- BankAccount
|
319
|
-
#
|
320
|
-
# Suppose that Book is to connect to a separate database (i.e. one other
|
321
|
-
# than the default database). Then Book, ScaryBook and GoodBook will all use
|
322
|
-
# the same connection pool. Likewise, Author and BankAccount will use the
|
323
|
-
# same connection pool. However, the connection pool used by Author/BankAccount
|
324
|
-
# is not the same as the one used by Book/ScaryBook/GoodBook.
|
307
|
+
# for keeping separate connection pools for Keymap objects stored in
|
308
|
+
# different databases.
|
325
309
|
#
|
326
310
|
# Normally there is only a single ConnectionHandler instance, accessible via
|
327
|
-
#
|
328
|
-
# determine that connection pool that they should use.
|
311
|
+
# Keymap::Base.connection_handler.
|
329
312
|
class ConnectionHandler
|
330
313
|
attr_reader :connection_pools
|
331
314
|
|
@@ -107,7 +107,7 @@ module Keymap
|
|
107
107
|
class << self
|
108
108
|
# Returns the connection currently associated with the class. This can
|
109
109
|
# also be used to "borrow" the connection to do database work unrelated
|
110
|
-
# to any of the specific
|
110
|
+
# to any of the specific Keymap collections.
|
111
111
|
def connection
|
112
112
|
retrieve_connection
|
113
113
|
end
|
@@ -70,28 +70,108 @@ module Keymap
|
|
70
70
|
raw_connection.discard
|
71
71
|
end
|
72
72
|
|
73
|
-
def delete(
|
74
|
-
raw_connection.del(
|
73
|
+
def delete(id)
|
74
|
+
raw_connection.del(id) != 0
|
75
|
+
end
|
76
|
+
|
77
|
+
def hash (id)
|
78
|
+
RedisHash.new(raw_connection, id)
|
75
79
|
end
|
76
80
|
|
77
|
-
|
78
|
-
|
79
|
-
|
81
|
+
def list (id)
|
82
|
+
# todo idea: add an optional argument where we specify the data type for elements in the collection
|
83
|
+
RedisList.new(raw_connection, id)
|
80
84
|
end
|
81
85
|
end
|
82
86
|
|
83
87
|
private
|
84
88
|
|
85
|
-
class
|
89
|
+
class RedisHash
|
90
|
+
|
91
|
+
include Enumerable
|
92
|
+
|
93
|
+
attr_reader :connection, :id, :sentinel
|
94
|
+
|
95
|
+
# n.b. nil gets represented as an empty string by redis, so the two are
|
96
|
+
# in effect identical keys.
|
97
|
+
def initialize(connection, id, sentinel=nil)
|
98
|
+
@connection = connection
|
99
|
+
@id = id
|
100
|
+
@sentinel = sentinel
|
101
|
+
self[sentinel] = sentinel
|
102
|
+
end
|
103
|
+
|
104
|
+
def empty?
|
105
|
+
connection.hlen id == 1
|
106
|
+
end
|
107
|
+
|
108
|
+
def [](key)
|
109
|
+
connection.hget id, key
|
110
|
+
end
|
111
|
+
|
112
|
+
def []=(key, value)
|
113
|
+
connection.hset id, key, value
|
114
|
+
end
|
115
|
+
|
116
|
+
def each
|
117
|
+
if block_given?
|
118
|
+
hash_keys.each { |key| yield [key, self[key]] unless key == sentinel }
|
119
|
+
else
|
120
|
+
::Enumerable::Enumerator.new(self, :each)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def each_pair
|
125
|
+
if block_given?
|
126
|
+
hash_keys.each { |key| yield key, self[key] unless key == sentinel }
|
127
|
+
else
|
128
|
+
::Enumerable::Enumerator.new(self, :each_pair)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def each_value
|
133
|
+
if block_given?
|
134
|
+
hash_keys.each { |key| yield self[key] unless key == sentinel }
|
135
|
+
else
|
136
|
+
::Enumerable::Enumerator.new(self, :each_value)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def delete(key)
|
141
|
+
value = self[key]
|
142
|
+
connection.hdel id, key
|
143
|
+
value
|
144
|
+
end
|
145
|
+
|
146
|
+
def merge!(hash)
|
147
|
+
hash.each do |key, value|
|
148
|
+
self[key] = value
|
149
|
+
end
|
150
|
+
self
|
151
|
+
end
|
152
|
+
|
153
|
+
alias merge merge!
|
154
|
+
|
155
|
+
private
|
156
|
+
|
157
|
+
def hash_keys
|
158
|
+
keys = connection.hkeys id
|
159
|
+
keys.delete sentinel
|
160
|
+
keys.delete ''
|
161
|
+
keys
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
class RedisList
|
86
166
|
|
87
167
|
include Enumerable
|
88
168
|
|
89
|
-
attr_reader :connection, :
|
169
|
+
attr_reader :connection, :id
|
90
170
|
|
91
|
-
def initialize(connection,
|
171
|
+
def initialize(connection, id, sentinel=nil)
|
92
172
|
@connection = connection
|
93
|
-
@
|
94
|
-
self <<
|
173
|
+
@id = id
|
174
|
+
self << sentinel # sentinel to force creation of an "empty list"
|
95
175
|
end
|
96
176
|
|
97
177
|
def each
|
@@ -100,7 +180,7 @@ module Keymap
|
|
100
180
|
(0..length % step_size).step(step_size) do |step|
|
101
181
|
first = step_size * step
|
102
182
|
last = first + step_size
|
103
|
-
list = connection.lrange
|
183
|
+
list = connection.lrange id, first + 1, last
|
104
184
|
list.each do |item|
|
105
185
|
yield item
|
106
186
|
end
|
@@ -111,22 +191,29 @@ module Keymap
|
|
111
191
|
end
|
112
192
|
|
113
193
|
def <<(value)
|
114
|
-
connection.rpush
|
194
|
+
connection.rpush id, value
|
115
195
|
self
|
116
196
|
end
|
117
197
|
|
118
198
|
alias :push :<<
|
119
199
|
|
120
200
|
def [](index)
|
121
|
-
connection.lindex
|
201
|
+
connection.lindex id, index + 1
|
122
202
|
end
|
123
203
|
|
124
204
|
def []=(index, value)
|
125
|
-
connection.lset
|
205
|
+
connection.lset id, index + 1, value
|
206
|
+
end
|
207
|
+
|
208
|
+
def concat array
|
209
|
+
array.each do |entry|
|
210
|
+
self << entry
|
211
|
+
end
|
212
|
+
self
|
126
213
|
end
|
127
214
|
|
128
215
|
def length
|
129
|
-
connection.llen(
|
216
|
+
connection.llen(id) -1
|
130
217
|
end
|
131
218
|
|
132
219
|
alias size length
|
@@ -136,18 +223,24 @@ module Keymap
|
|
136
223
|
end
|
137
224
|
|
138
225
|
def pop()
|
139
|
-
connection.rpop
|
226
|
+
connection.rpop id unless length == 0
|
140
227
|
end
|
141
228
|
|
142
229
|
def delete(value)
|
143
|
-
value = connection.lrem(
|
230
|
+
value = connection.lrem(id, 0, value) == 0 ? nil : value
|
144
231
|
yield value if block_given?
|
145
232
|
value
|
146
233
|
end
|
147
234
|
|
148
|
-
def delete_if
|
149
|
-
|
150
|
-
|
235
|
+
def delete_if
|
236
|
+
if block_given?
|
237
|
+
each do |value|
|
238
|
+
delete(value) if yield(value)
|
239
|
+
end
|
240
|
+
self
|
241
|
+
else
|
242
|
+
nil
|
243
|
+
end
|
151
244
|
end
|
152
245
|
end
|
153
246
|
|
data/lib/keymap/version.rb
CHANGED
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Keymap::Base do
|
4
|
+
before do
|
5
|
+
@connection = Keymap::Base.connection
|
6
|
+
end
|
7
|
+
|
8
|
+
context "a connection yields hashes" do
|
9
|
+
|
10
|
+
before(:each) do
|
11
|
+
@connection.delete :what
|
12
|
+
end
|
13
|
+
|
14
|
+
after(:each) do
|
15
|
+
@connection.delete :what
|
16
|
+
end
|
17
|
+
|
18
|
+
it "that are empty upon creation" do
|
19
|
+
hash = @connection.hash :what
|
20
|
+
hash.nil?.should be_false
|
21
|
+
end
|
22
|
+
|
23
|
+
it "that support an empty? operation" do
|
24
|
+
hash = @connection.hash :what
|
25
|
+
hash.respond_to?(:empty?).should be_true
|
26
|
+
end
|
27
|
+
|
28
|
+
it "that are empty upon creation" do
|
29
|
+
hash = @connection.hash :what
|
30
|
+
hash.empty?.should be_true
|
31
|
+
end
|
32
|
+
|
33
|
+
it "that if not yet allocated an attempt to delete them returns false" do
|
34
|
+
exists = @connection.delete :what
|
35
|
+
exists.should be_false
|
36
|
+
end
|
37
|
+
|
38
|
+
it "that if already allocated an attempt to delete them returns true" do
|
39
|
+
@connection.hash :what
|
40
|
+
exists = @connection.delete :what
|
41
|
+
exists.should be_true
|
42
|
+
end
|
43
|
+
|
44
|
+
it "that yield no value when accessing with an unknown key" do
|
45
|
+
hash = @connection.hash :what
|
46
|
+
hash[:id].should eq(nil)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "that yield values for which an association exists" do
|
50
|
+
hash = @connection.hash :what
|
51
|
+
hash[:id] = 'value'
|
52
|
+
hash[:id].should eq('value')
|
53
|
+
end
|
54
|
+
|
55
|
+
it "that returns the value when deleting keys for which an association does exist" do
|
56
|
+
hash = @connection.hash :what
|
57
|
+
hash[:id] = 'value'
|
58
|
+
hash.delete(:id).should be_true
|
59
|
+
end
|
60
|
+
|
61
|
+
it "that returns nil when deleting keys for which an association does not exists and for which there is no default value" do
|
62
|
+
hash = @connection.hash :what
|
63
|
+
hash.delete(:id).should be_nil
|
64
|
+
end
|
65
|
+
|
66
|
+
it "that support merging key value pairs from other hashes" do
|
67
|
+
hash = @connection.hash :what
|
68
|
+
grades = {
|
69
|
+
Bob: 82,
|
70
|
+
Jim: 94,
|
71
|
+
Billy: 58
|
72
|
+
}
|
73
|
+
hash.merge! grades
|
74
|
+
hash[:Bob].should eq('82')
|
75
|
+
end
|
76
|
+
|
77
|
+
it "that implement enumerable" do
|
78
|
+
hash = @connection.hash :what
|
79
|
+
hash.respond_to?(:each).should be_true
|
80
|
+
end
|
81
|
+
|
82
|
+
it "that support each operations" do
|
83
|
+
hash = @connection.hash :what
|
84
|
+
grades = {
|
85
|
+
Bob: 82,
|
86
|
+
Jim: 94,
|
87
|
+
Billy: 58
|
88
|
+
}
|
89
|
+
hash.merge! grades
|
90
|
+
sum = 0
|
91
|
+
hash.each do |pair|
|
92
|
+
sum = sum + pair.last.to_i
|
93
|
+
end
|
94
|
+
sum.should eq(234)
|
95
|
+
end
|
96
|
+
|
97
|
+
it "that support each_pair operations" do
|
98
|
+
hash = @connection.hash :what
|
99
|
+
grades = {
|
100
|
+
Bob: 82,
|
101
|
+
Jim: 94,
|
102
|
+
Billy: 58
|
103
|
+
}
|
104
|
+
hash.merge! grades
|
105
|
+
sum = 0
|
106
|
+
hash.each_pair do |key, value|
|
107
|
+
key
|
108
|
+
sum = sum + value.to_i
|
109
|
+
end
|
110
|
+
sum.should eq(234)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "that support each_value operations" do
|
114
|
+
hash = @connection.hash :what
|
115
|
+
grades = {
|
116
|
+
Bob: 82,
|
117
|
+
Jim: 94,
|
118
|
+
Billy: 58
|
119
|
+
}
|
120
|
+
hash.merge! grades
|
121
|
+
sum = 0
|
122
|
+
hash.each_value do |value|
|
123
|
+
sum = sum + value.to_i
|
124
|
+
end
|
125
|
+
sum.should eq(234)
|
126
|
+
end
|
127
|
+
|
128
|
+
it "that support merging key value pairs from other hashes" do
|
129
|
+
hash = @connection.hash :what
|
130
|
+
grades = {
|
131
|
+
Bob: 82,
|
132
|
+
Jim: 94,
|
133
|
+
Billy: 58
|
134
|
+
}
|
135
|
+
hash.merge! grades
|
136
|
+
hash[:Bob].should eq('82')
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
end
|
@@ -52,6 +52,42 @@ describe Keymap::Base do
|
|
52
52
|
list.pop.to_i.should eq(1)
|
53
53
|
end
|
54
54
|
|
55
|
+
it "that supports replacing an entry by index" do
|
56
|
+
list = @connection.list :what
|
57
|
+
list << 'a' << 'b'
|
58
|
+
list[0] = 'c'
|
59
|
+
list[0].should eq('c')
|
60
|
+
end
|
61
|
+
|
62
|
+
it "that returns the value when deleting values that does exist" do
|
63
|
+
list = @connection.list :what
|
64
|
+
list << 'a'
|
65
|
+
list.delete('a').should eq('a')
|
66
|
+
end
|
67
|
+
|
68
|
+
it "that returns nil when deleting values that does not exist" do
|
69
|
+
list = @connection.list :what
|
70
|
+
list.delete('a').should be_nil
|
71
|
+
end
|
72
|
+
|
73
|
+
it "that supports concatenation" do
|
74
|
+
list = @connection.list :what
|
75
|
+
list << 'a'
|
76
|
+
list.concat %w(b)
|
77
|
+
list[0].should eq('a')
|
78
|
+
list[1].should eq('b')
|
79
|
+
end
|
80
|
+
|
81
|
+
it "that supports selectively deleting entries by a matching condition" do
|
82
|
+
list = @connection.list :what
|
83
|
+
list.concat [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
84
|
+
list.delete_if { |value|
|
85
|
+
value.to_i % 2 > 0
|
86
|
+
}
|
87
|
+
list.length.should eq(4)
|
88
|
+
list[1].to_i.should eq(4)
|
89
|
+
end
|
90
|
+
|
55
91
|
it "lists support append operators and inject" do
|
56
92
|
list = @connection.list :what
|
57
93
|
(0..10).each do |value|
|
data/spec/support/config.yml
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: keymap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-11-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: erubis
|
@@ -107,6 +107,22 @@ dependencies:
|
|
107
107
|
- - ! '>='
|
108
108
|
- !ruby/object:Gem::Version
|
109
109
|
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: hanna-nouveau
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
110
126
|
- !ruby/object:Gem::Dependency
|
111
127
|
name: ruby-prof
|
112
128
|
requirement: !ruby/object:Gem::Requirement
|
@@ -187,7 +203,9 @@ dependencies:
|
|
187
203
|
- - ~>
|
188
204
|
- !ruby/object:Gem::Version
|
189
205
|
version: 2.11.0
|
190
|
-
description:
|
206
|
+
description: Helping Ruby developers and their companies, unlock their key-value store
|
207
|
+
data, through associative and sequential based access, providing unprecedented support
|
208
|
+
for map reduce behaviors, native to the Ruby language
|
191
209
|
email: buck.robert.j@gmail.com
|
192
210
|
executables: []
|
193
211
|
extensions: []
|
@@ -216,6 +234,7 @@ files:
|
|
216
234
|
- spec/functional/abstract_adapter_spec.rb
|
217
235
|
- spec/functional/adapter_spec.rb
|
218
236
|
- spec/functional/adapters/redis/connection_spec.rb
|
237
|
+
- spec/functional/hash_spec.rb
|
219
238
|
- spec/functional/list_spec.rb
|
220
239
|
- spec/rcov.opts
|
221
240
|
- spec/spec.opts
|
@@ -224,7 +243,6 @@ files:
|
|
224
243
|
- spec/support/config.yml
|
225
244
|
- spec/support/connection.rb
|
226
245
|
- spec/unit/.gitignore
|
227
|
-
- spec/unit/test.rb
|
228
246
|
- tasks/rspec.rb
|
229
247
|
homepage: https://github.com/rbuck/keymap
|
230
248
|
licenses: []
|
@@ -249,13 +267,14 @@ rubyforge_project:
|
|
249
267
|
rubygems_version: 1.8.24
|
250
268
|
signing_key:
|
251
269
|
specification_version: 3
|
252
|
-
summary: Abstracts choosing a key-value store implementation, and provides a
|
253
|
-
API.
|
270
|
+
summary: Abstracts choosing a key-value store implementation, and provides a natural
|
271
|
+
enumerable-based Ruby API for hashed and sequential collections.
|
254
272
|
test_files:
|
255
273
|
- spec/data/.gitignore
|
256
274
|
- spec/functional/abstract_adapter_spec.rb
|
257
275
|
- spec/functional/adapter_spec.rb
|
258
276
|
- spec/functional/adapters/redis/connection_spec.rb
|
277
|
+
- spec/functional/hash_spec.rb
|
259
278
|
- spec/functional/list_spec.rb
|
260
279
|
- spec/rcov.opts
|
261
280
|
- spec/spec.opts
|
@@ -264,5 +283,4 @@ test_files:
|
|
264
283
|
- spec/support/config.yml
|
265
284
|
- spec/support/connection.rb
|
266
285
|
- spec/unit/.gitignore
|
267
|
-
- spec/unit/test.rb
|
268
286
|
- tasks/rspec.rb
|
data/spec/unit/test.rb
DELETED
@@ -1,89 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'keymap'
|
3
|
-
require 'yaml'
|
4
|
-
require 'logger'
|
5
|
-
|
6
|
-
Keymap::Base.configurations['redis'] = {
|
7
|
-
:adapter => 'redis',
|
8
|
-
:host => 'localhost'
|
9
|
-
}
|
10
|
-
|
11
|
-
class User < Keymap::Base
|
12
|
-
|
13
|
-
establish_connection 'redis'
|
14
|
-
|
15
|
-
def test
|
16
|
-
c = self.connection
|
17
|
-
puts 'hi'
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
user = User.new
|
22
|
-
user.test
|
23
|
-
|
24
|
-
#
|
25
|
-
#config = {adapter: 'redis',
|
26
|
-
# host: 'localhost'
|
27
|
-
# #database: database,
|
28
|
-
# #username: user,
|
29
|
-
# #password: password,
|
30
|
-
#}
|
31
|
-
#Keymap::Base.establish_connection(config)
|
32
|
-
#Keymap::Base.logger = Logger.new(STDERR)
|
33
|
-
#
|
34
|
-
#class User < Keymap::Base
|
35
|
-
#end
|
36
|
-
|
37
|
-
#puts User.count
|
38
|
-
# SQL (0.000277) SELECT count(*) AS count_all FROM users
|
39
|
-
# 6
|
40
|
-
|
41
|
-
|
42
|
-
#require 'redis'
|
43
|
-
#require 'keymap/connection_adapters/redis_adapter'
|
44
|
-
#require 'keymap/connection_adapters/abstract/connection_specification'
|
45
|
-
#
|
46
|
-
#Base.configurations["redis"] = {
|
47
|
-
# :adapter => 'redis',
|
48
|
-
# :host => 'localhost'
|
49
|
-
#}
|
50
|
-
#
|
51
|
-
#Base.establish_connection(
|
52
|
-
# :adapter => "redis",
|
53
|
-
# :host => "localhost"
|
54
|
-
#)
|
55
|
-
#
|
56
|
-
#
|
57
|
-
##
|
58
|
-
##class Table1 < ActiveRecord::Base
|
59
|
-
## establish_connection "db1"
|
60
|
-
##end
|
61
|
-
##
|
62
|
-
##class Table2 < ActiveRecord::Base
|
63
|
-
## establish_connection "db2"
|
64
|
-
##end
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#redis = ConnectionAdapters::RedisAdapter.new nil, nil, {host: "localhost"}
|
68
|
-
#puts redis.active?
|
69
|
-
#
|
70
|
-
#redis.reconnect!
|
71
|
-
#puts redis.active?
|
72
|
-
#
|
73
|
-
#redis.transaction do
|
74
|
-
# tokens = redis.hash 'tokens'
|
75
|
-
# tokens[:auth] = 'no way'
|
76
|
-
# puts tokens[:auth]
|
77
|
-
#end
|
78
|
-
#
|
79
|
-
#redis.transaction do
|
80
|
-
# tokens = redis.hash 'tokens'
|
81
|
-
# tokens.each do |key, value|
|
82
|
-
# puts "#{key},#{value}"
|
83
|
-
# end
|
84
|
-
#end
|
85
|
-
#
|
86
|
-
#redis.disconnect!
|
87
|
-
#puts redis.active?
|
88
|
-
#
|
89
|
-
#
|