keymap 0.2.0 → 0.3.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.
- 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
|
-
#
|