palsy 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +3 -0
- data/lib/palsy.rb +62 -3
- data/lib/palsy/basic/list.rb +20 -11
- data/lib/palsy/basic/map.rb +23 -4
- data/lib/palsy/basic/object.rb +11 -3
- data/lib/palsy/basic/set.rb +10 -6
- data/lib/palsy/version.rb +1 -1
- data/test/helper.rb +1 -0
- data/test/test_init.rb +15 -0
- data/test/test_list.rb +40 -0
- data/test/test_map.rb +53 -0
- data/test/test_object.rb +35 -0
- data/test/test_set.rb +55 -0
- metadata +15 -39
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 60fb2ba51b992f7b83ce4d94f0999bbdd57ba8a7
|
4
|
+
data.tar.gz: b52c06df6875bade0c18b0261c19ee2c1c27c51a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ba0b46d264bd49e24ed3780827705ab7a17a7cf1145a6e81beb903ec2fcfcd79f986ea7c5e564b48b5ac26fc8183cd2f2b8d42a7bccb2a83cb4fce63d395a84a
|
7
|
+
data.tar.gz: aa00113a932da3527a871e940493d099698c42d025b8d6093f27ccb1b1a95397c67705465c649964494ce5c44354e6cbdb3781a66aed4973eaf2b9b4d16abdf9
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
* 0.0.4 - April 6, 2013
|
2
|
+
* This takes the changes in 0.0.3 and improves robustness over high-volume
|
3
|
+
concurrency and improves transaction isolation for single operations.
|
1
4
|
* 0.0.3 - April 2, 2013
|
2
5
|
* Ensure exclusive transactions are being used for all operations. This
|
3
6
|
should make it a little more viable for non-MRI things.
|
data/lib/palsy.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'sqlite3'
|
2
2
|
require 'singleton'
|
3
3
|
require 'delegate'
|
4
|
+
require 'thread'
|
4
5
|
require "palsy/version"
|
5
6
|
|
6
7
|
# Present ruby core data structures in a manner similar to perl's tie backed by a
|
@@ -67,6 +68,7 @@ class Palsy < DelegateClass(SQLite3::Database)
|
|
67
68
|
# working with the rest of the library.
|
68
69
|
#
|
69
70
|
def initialize
|
71
|
+
@palsy_lock = Mutex.new
|
70
72
|
super(connect)
|
71
73
|
end
|
72
74
|
|
@@ -88,15 +90,72 @@ class Palsy < DelegateClass(SQLite3::Database)
|
|
88
90
|
end
|
89
91
|
end
|
90
92
|
|
93
|
+
# Override the explicit lock for the current thread. For things that generate
|
94
|
+
# queries, will not attempt to acquire a mutex, will not attempt to run a
|
95
|
+
# transaction. Will just run the block. See #with_t for information on lock
|
96
|
+
# semantics.
|
97
|
+
#
|
98
|
+
# For Ruby 2.0 users and above: If you wrap your palsy operations in #no_lock
|
99
|
+
# on the current thread, #with_t will not try to use a mutex lock or
|
100
|
+
# transaction.
|
101
|
+
#
|
102
|
+
# This is useful if you want to use palsy in a signal handler:
|
103
|
+
#
|
104
|
+
# trap("INFO") do
|
105
|
+
# Palsy.instance.no_lock do
|
106
|
+
# some_palsy_thing
|
107
|
+
# end
|
108
|
+
# end
|
109
|
+
#
|
110
|
+
# The caveat is that any writes done in this region will not be isolated and
|
111
|
+
# will likely cause problems.
|
112
|
+
#
|
113
|
+
def no_lock
|
114
|
+
retval = nil
|
115
|
+
Thread.current[:palsy_no_lock] = true
|
116
|
+
retval = yield
|
117
|
+
Thread.current[:palsy_no_lock] = false
|
118
|
+
return retval
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# Start a mutex-wrapped exclusive transaction, then execute the block. If
|
123
|
+
# we're already the owner of the transaction, just execute.
|
124
|
+
#
|
125
|
+
# This is used by most things in Palsy. If you want to step around the lock
|
126
|
+
# (necessary for specific situations, and has certain caveats), take a look
|
127
|
+
# at #no_lock.
|
128
|
+
#
|
129
|
+
def with_t
|
130
|
+
result = nil
|
131
|
+
tc = Thread.current
|
132
|
+
|
133
|
+
if tc[:lock] or tc[:palsy_no_lock]
|
134
|
+
result = yield
|
135
|
+
else
|
136
|
+
@palsy_lock.synchronize do
|
137
|
+
begin
|
138
|
+
tc[:lock] = @palsy_lock
|
139
|
+
transaction(:exclusive) { result = yield }
|
140
|
+
rescue StandardError => e
|
141
|
+
rollback if transaction_active?
|
142
|
+
raise e
|
143
|
+
ensure
|
144
|
+
tc[:lock] = nil
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
return result
|
150
|
+
end
|
151
|
+
|
91
152
|
#
|
92
153
|
# Execute this query in an exclusive transaction.
|
93
154
|
#
|
94
155
|
def execute_t(query, args=[], &block)
|
95
156
|
result = nil
|
96
157
|
|
97
|
-
|
98
|
-
result = execute(query, args, &block)
|
99
|
-
end
|
158
|
+
with_t { result = execute(query, args, &block) }
|
100
159
|
|
101
160
|
return result
|
102
161
|
end
|
data/lib/palsy/basic/list.rb
CHANGED
@@ -49,16 +49,23 @@ class Palsy
|
|
49
49
|
# Add a value to the head of the list.
|
50
50
|
#
|
51
51
|
def unshift(val)
|
52
|
-
|
52
|
+
@db.with_t do
|
53
|
+
replace([val] + to_a)
|
54
|
+
end
|
53
55
|
end
|
54
56
|
|
55
57
|
#
|
56
58
|
# Helper method for mutators.
|
57
59
|
#
|
58
60
|
def mutate(meth)
|
59
|
-
|
60
|
-
|
61
|
-
|
61
|
+
val = nil
|
62
|
+
|
63
|
+
@db.with_t do
|
64
|
+
a = to_a
|
65
|
+
val = a.send(meth)
|
66
|
+
replace(a)
|
67
|
+
end
|
68
|
+
|
62
69
|
return val
|
63
70
|
end
|
64
71
|
|
@@ -81,15 +88,17 @@ class Palsy
|
|
81
88
|
# like an Enumerable.
|
82
89
|
#
|
83
90
|
def replace(ary)
|
84
|
-
|
85
|
-
|
91
|
+
@db.with_t do
|
92
|
+
clear
|
93
|
+
return if ary.count == 0
|
86
94
|
|
87
|
-
|
95
|
+
value_string = ("(?, ?)," * ary.count).chop
|
88
96
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
97
|
+
@db.execute_t(
|
98
|
+
"insert into #{@table_name} (name, value) values #{value_string}",
|
99
|
+
ary.map { |x| [@object_name, Marshal.dump(x)] }.flatten
|
100
|
+
)
|
101
|
+
end
|
93
102
|
end
|
94
103
|
|
95
104
|
#
|
data/lib/palsy/basic/map.rb
CHANGED
@@ -49,18 +49,37 @@ class Palsy
|
|
49
49
|
# database before attempting to write the new pair.
|
50
50
|
#
|
51
51
|
def []=(key, value)
|
52
|
-
|
53
|
-
|
52
|
+
@db.with_t do
|
53
|
+
delete(key)
|
54
|
+
@db.execute_t("insert into #{@table_name} (name, key, value) values (?, ?, ?)", [@object_name, Marshal.dump(key), Marshal.dump(value)])
|
55
|
+
end
|
54
56
|
value
|
55
57
|
end
|
56
58
|
|
59
|
+
#
|
60
|
+
# replace this map with the contents of a Hash.
|
61
|
+
#
|
62
|
+
def replace(hash)
|
63
|
+
@db.with_t do
|
64
|
+
clear
|
65
|
+
|
66
|
+
return if hash.keys.empty?
|
67
|
+
|
68
|
+
value_string = ("(?, ?, ?)," * hash.keys.count).chop
|
69
|
+
|
70
|
+
@db.execute_t("insert into #{@table_name} (name, key, value) values #{value_string}", hash.map { |key, value| [@object_name, Marshal.dump(key), Marshal.dump(value)] }.flatten)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
57
74
|
#
|
58
75
|
# Successively yields key and value for each item in the map. Modifications
|
59
76
|
# to either the key or value yielded will not persist.
|
60
77
|
#
|
61
78
|
def each
|
62
|
-
|
63
|
-
|
79
|
+
@db.with_t do
|
80
|
+
keys.each do |key|
|
81
|
+
yield key, self[key]
|
82
|
+
end
|
64
83
|
end
|
65
84
|
end
|
66
85
|
|
data/lib/palsy/basic/object.rb
CHANGED
@@ -27,7 +27,13 @@ class Palsy
|
|
27
27
|
# Get an object by referencing its key. Returns nil unless it exists.
|
28
28
|
#
|
29
29
|
def [](key)
|
30
|
-
value =
|
30
|
+
value = begin
|
31
|
+
ret = @db.execute_t("select value from #{@table_name} where key=?", [key])
|
32
|
+
(ret && ret.first) ? ret.first.first : nil
|
33
|
+
rescue SQLite3::Exception
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
31
37
|
return value && Marshal.load(value)
|
32
38
|
end
|
33
39
|
|
@@ -35,8 +41,10 @@ class Palsy
|
|
35
41
|
# Set an object. Returns the object. The object must be able to be Marshalled.
|
36
42
|
#
|
37
43
|
def []=(key, value)
|
38
|
-
|
39
|
-
|
44
|
+
@db.with_t do
|
45
|
+
delete(key)
|
46
|
+
@db.execute_t("insert into #{@table_name} (key, value) values (?, ?)", [key, Marshal.dump(value)])
|
47
|
+
end
|
40
48
|
value
|
41
49
|
end
|
42
50
|
|
data/lib/palsy/basic/set.rb
CHANGED
@@ -41,8 +41,10 @@ class Palsy
|
|
41
41
|
# avoid raising a constraint from sqlite.
|
42
42
|
#
|
43
43
|
def add(key)
|
44
|
-
|
45
|
-
|
44
|
+
@db.with_t do
|
45
|
+
delete(key)
|
46
|
+
@db.execute_t("insert into #{@table_name} (name, key) values (?, ?)", [@object_name, Marshal.dump(key)])
|
47
|
+
end
|
46
48
|
end
|
47
49
|
|
48
50
|
#
|
@@ -73,13 +75,15 @@ class Palsy
|
|
73
75
|
# set, or any Enumerable that has a set of unique values.
|
74
76
|
#
|
75
77
|
def replace(set)
|
76
|
-
|
78
|
+
@db.with_t do
|
79
|
+
clear
|
77
80
|
|
78
|
-
|
81
|
+
return if set.empty?
|
79
82
|
|
80
|
-
|
83
|
+
value_string = ("(?, ?)," * set.count).chop
|
81
84
|
|
82
|
-
|
85
|
+
@db.execute_t("insert into #{@table_name} (name, key) values #{value_string}", set.map { |x| [@object_name, Marshal.dump(x)] }.flatten)
|
86
|
+
end
|
83
87
|
end
|
84
88
|
|
85
89
|
#
|
data/lib/palsy/version.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
PalsyVersion = "0.0.
|
1
|
+
PalsyVersion = "0.0.4"
|
data/test/helper.rb
CHANGED
data/test/test_init.rb
CHANGED
@@ -38,4 +38,19 @@ class TestInit < MiniTest::Unit::TestCase
|
|
38
38
|
Palsy.reconnect
|
39
39
|
assert_raises(NoMethodError) { Palsy.instance.closed? }
|
40
40
|
end
|
41
|
+
|
42
|
+
def test_with_t
|
43
|
+
dbfile = new_dbfile
|
44
|
+
Palsy.change_db(dbfile.path)
|
45
|
+
|
46
|
+
(0..2).map do
|
47
|
+
Thread.new do
|
48
|
+
assert_raises(ArgumentError) do
|
49
|
+
Palsy.instance.with_t do
|
50
|
+
raise ArgumentError
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end.map(&:join)
|
55
|
+
end
|
41
56
|
end
|
data/test/test_list.rb
CHANGED
@@ -15,6 +15,46 @@ class TestList < PalsyTypeTest
|
|
15
15
|
t.each(&:join)
|
16
16
|
|
17
17
|
assert_equal(syms.sort, @list.to_a.sort)
|
18
|
+
|
19
|
+
writer = Thread.new { loop { @list.push(rand.to_i) } }
|
20
|
+
reader = Thread.new { loop { @list.shift } }
|
21
|
+
|
22
|
+
begin
|
23
|
+
Timeout.timeout(10) do
|
24
|
+
writer.join
|
25
|
+
reader.join
|
26
|
+
end
|
27
|
+
rescue TimeoutError
|
28
|
+
pass "push and shift competed for 10 seconds without any exceptions"
|
29
|
+
writer.raise
|
30
|
+
reader.raise
|
31
|
+
writer.join rescue nil
|
32
|
+
reader.join rescue nil
|
33
|
+
end
|
34
|
+
|
35
|
+
replacer = Thread.new { loop { @list.replace(Set[1,2,3]) } }
|
36
|
+
clearer = Thread.new { loop { @list.clear } }
|
37
|
+
|
38
|
+
begin
|
39
|
+
Timeout.timeout(10) do
|
40
|
+
replacer.join
|
41
|
+
clearer.join
|
42
|
+
end
|
43
|
+
rescue TimeoutError
|
44
|
+
pass "replace and clear competed for 10 seconds without any exceptions"
|
45
|
+
replacer.raise
|
46
|
+
clearer.raise
|
47
|
+
replacer.join rescue nil
|
48
|
+
clearer.join rescue nil
|
49
|
+
end
|
50
|
+
|
51
|
+
refute(@list.db.transaction_active?)
|
52
|
+
|
53
|
+
# XXX there's no solid way of knowing what'll be in here without inserting
|
54
|
+
# locks which will actually defeat the point of the test. Check the type,
|
55
|
+
# which will cause an execution and ensure we don't have a stale
|
56
|
+
# transaction.
|
57
|
+
assert_kind_of(Array, @list.to_a)
|
18
58
|
end
|
19
59
|
|
20
60
|
def test_semantics
|
data/test/test_map.rb
CHANGED
@@ -16,6 +16,46 @@ class TestMap < PalsyTypeTest
|
|
16
16
|
t.each(&:join)
|
17
17
|
|
18
18
|
assert_equal(@map.to_hash, args)
|
19
|
+
|
20
|
+
writer = Thread.new { loop { @map[rand.to_i] = 1 } }
|
21
|
+
reader = Thread.new { loop { @map.keys } }
|
22
|
+
|
23
|
+
begin
|
24
|
+
Timeout.timeout(10) do
|
25
|
+
writer.join
|
26
|
+
reader.join
|
27
|
+
end
|
28
|
+
rescue TimeoutError
|
29
|
+
pass "[] and keys competed for 10 seconds without any exceptions"
|
30
|
+
writer.raise
|
31
|
+
reader.raise
|
32
|
+
writer.join rescue nil
|
33
|
+
reader.join rescue nil
|
34
|
+
end
|
35
|
+
|
36
|
+
replacer = Thread.new { loop { @map.replace(Hash[[1,2,3].zip([2,3,4])]) } }
|
37
|
+
clearer = Thread.new { loop { @map.clear } }
|
38
|
+
|
39
|
+
begin
|
40
|
+
Timeout.timeout(10) do
|
41
|
+
replacer.join
|
42
|
+
clearer.join
|
43
|
+
end
|
44
|
+
rescue TimeoutError
|
45
|
+
pass "replace and clear competed for 10 seconds without any exceptions"
|
46
|
+
replacer.raise
|
47
|
+
clearer.raise
|
48
|
+
replacer.join rescue nil
|
49
|
+
clearer.join rescue nil
|
50
|
+
end
|
51
|
+
|
52
|
+
refute(@map.db.transaction_active?)
|
53
|
+
|
54
|
+
# XXX there's no solid way of knowing what'll be in here without inserting
|
55
|
+
# locks which will actually defeat the point of the test. Check the type,
|
56
|
+
# which will cause an execution and ensure we don't have a stale
|
57
|
+
# transaction.
|
58
|
+
assert_kind_of(Hash, @map.to_hash)
|
19
59
|
end
|
20
60
|
|
21
61
|
def test_inherits
|
@@ -86,4 +126,17 @@ class TestMap < PalsyTypeTest
|
|
86
126
|
assert_equal(@map[k], v, "#each yields each value")
|
87
127
|
end
|
88
128
|
end
|
129
|
+
|
130
|
+
def test_replace
|
131
|
+
@map[1] = "foo"
|
132
|
+
assert_equal("foo", @map[1])
|
133
|
+
|
134
|
+
hash = {2 => "bar", 3 => "foo"}
|
135
|
+
|
136
|
+
@map.replace(hash)
|
137
|
+
refute_equal("foo", @map[1])
|
138
|
+
assert_equal("bar", @map[2])
|
139
|
+
assert_equal("foo", @map[3])
|
140
|
+
assert_equal(hash, @map.to_hash)
|
141
|
+
end
|
89
142
|
end
|
data/test/test_object.rb
CHANGED
@@ -14,6 +14,41 @@ class TestObject < PalsyTypeTest
|
|
14
14
|
args.each do |k,v|
|
15
15
|
assert_equal(obj[k], args[k])
|
16
16
|
end
|
17
|
+
|
18
|
+
writer = Thread.new { loop { obj["1"] = "1" } }
|
19
|
+
reader = Thread.new { loop { obj["1"] } }
|
20
|
+
|
21
|
+
begin
|
22
|
+
Timeout.timeout(10) do
|
23
|
+
writer.join
|
24
|
+
reader.join
|
25
|
+
end
|
26
|
+
rescue TimeoutError
|
27
|
+
pass "[]= and [] competed for 10 seconds without any exceptions"
|
28
|
+
writer.raise
|
29
|
+
reader.raise
|
30
|
+
writer.join rescue nil
|
31
|
+
reader.join rescue nil
|
32
|
+
end
|
33
|
+
|
34
|
+
replacer = Thread.new { loop { obj[1] = 1 } }
|
35
|
+
clearer = Thread.new { loop { obj.delete(1) } }
|
36
|
+
|
37
|
+
begin
|
38
|
+
Timeout.timeout(10) do
|
39
|
+
replacer.join
|
40
|
+
clearer.join
|
41
|
+
end
|
42
|
+
rescue TimeoutError
|
43
|
+
pass "[]= and delete competed for 10 seconds without any exceptions"
|
44
|
+
replacer.raise
|
45
|
+
clearer.raise
|
46
|
+
replacer.join rescue nil
|
47
|
+
clearer.join rescue nil
|
48
|
+
end
|
49
|
+
|
50
|
+
refute(obj.db.transaction_active?)
|
51
|
+
obj.delete(1)
|
17
52
|
end
|
18
53
|
|
19
54
|
def test_index
|
data/test/test_set.rb
CHANGED
@@ -15,6 +15,61 @@ class TestSet < PalsyTypeTest
|
|
15
15
|
t.each(&:join)
|
16
16
|
|
17
17
|
assert_equal(syms.sort, @set.to_a.sort)
|
18
|
+
|
19
|
+
writer = Thread.new { loop { @set.add(rand.to_i) } }
|
20
|
+
reader = Thread.new { loop { @set.keys } }
|
21
|
+
|
22
|
+
begin
|
23
|
+
Timeout.timeout(10) do
|
24
|
+
writer.join
|
25
|
+
reader.join
|
26
|
+
end
|
27
|
+
rescue TimeoutError
|
28
|
+
pass "add and keys competed for 10 seconds without any exceptions"
|
29
|
+
writer.raise
|
30
|
+
reader.raise
|
31
|
+
writer.join rescue nil
|
32
|
+
reader.join rescue nil
|
33
|
+
end
|
34
|
+
|
35
|
+
replacer = Thread.new { loop { @set.replace(Set[1,2,3]) } }
|
36
|
+
clearer = Thread.new { loop { @set.clear } }
|
37
|
+
|
38
|
+
begin
|
39
|
+
Timeout.timeout(10) do
|
40
|
+
replacer.join
|
41
|
+
clearer.join
|
42
|
+
end
|
43
|
+
rescue TimeoutError
|
44
|
+
pass "replace and clear competed for 10 seconds without any exceptions"
|
45
|
+
replacer.raise
|
46
|
+
clearer.raise
|
47
|
+
replacer.join rescue nil
|
48
|
+
clearer.join rescue nil
|
49
|
+
end
|
50
|
+
|
51
|
+
refute(@set.db.transaction_active?)
|
52
|
+
|
53
|
+
# XXX there's no solid way of knowing what'll be in here without inserting
|
54
|
+
# locks which will actually defeat the point of the test. Check the type,
|
55
|
+
# which will cause an execution and ensure we don't have a stale
|
56
|
+
# transaction.
|
57
|
+
assert_kind_of(Set, @set.to_set)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_enumerable_freebies
|
61
|
+
(0..10).each { |x| @set.add(x) }
|
62
|
+
real_set = @set.to_set
|
63
|
+
assert_kind_of(Set, real_set)
|
64
|
+
assert_equal(Set[*(0..10).to_a], real_set)
|
65
|
+
array = @set.to_a
|
66
|
+
assert_kind_of(Array, array)
|
67
|
+
assert_equal((0..10).to_a, array.sort)
|
68
|
+
|
69
|
+
t = (0..2).map { Thread.new { @set.to_set } }
|
70
|
+
t.each(&:join)
|
71
|
+
|
72
|
+
t = (0..2).map { Thread.new { @set.to_a } }
|
18
73
|
end
|
19
74
|
|
20
75
|
def test_semantics
|
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: palsy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.4
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Erik Hollensbe
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-04-
|
11
|
+
date: 2013-04-06 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: sqlite3
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ~>
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ~>
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,7 +27,6 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: minitest
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ~>
|
36
32
|
- !ruby/object:Gem::Version
|
@@ -38,7 +34,6 @@ dependencies:
|
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ~>
|
44
39
|
- !ruby/object:Gem::Version
|
@@ -46,23 +41,20 @@ dependencies:
|
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: rake
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - '>='
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: '0'
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - '>='
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: '0'
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: rdoc
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
59
|
- - ~>
|
68
60
|
- !ruby/object:Gem::Version
|
@@ -70,7 +62,6 @@ dependencies:
|
|
70
62
|
type: :development
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
66
|
- - ~>
|
76
67
|
- !ruby/object:Gem::Version
|
@@ -78,39 +69,34 @@ dependencies:
|
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: simplecov
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
|
-
- -
|
73
|
+
- - '>='
|
84
74
|
- !ruby/object:Gem::Version
|
85
75
|
version: '0'
|
86
76
|
type: :development
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
|
-
- -
|
80
|
+
- - '>='
|
92
81
|
- !ruby/object:Gem::Version
|
93
82
|
version: '0'
|
94
83
|
- !ruby/object:Gem::Dependency
|
95
84
|
name: guard-minitest
|
96
85
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
86
|
requirements:
|
99
|
-
- -
|
87
|
+
- - '>='
|
100
88
|
- !ruby/object:Gem::Version
|
101
89
|
version: '0'
|
102
90
|
type: :development
|
103
91
|
prerelease: false
|
104
92
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
93
|
requirements:
|
107
|
-
- -
|
94
|
+
- - '>='
|
108
95
|
- !ruby/object:Gem::Version
|
109
96
|
version: '0'
|
110
97
|
- !ruby/object:Gem::Dependency
|
111
98
|
name: guard-rake
|
112
99
|
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
100
|
requirements:
|
115
101
|
- - ~>
|
116
102
|
- !ruby/object:Gem::Version
|
@@ -118,7 +104,6 @@ dependencies:
|
|
118
104
|
type: :development
|
119
105
|
prerelease: false
|
120
106
|
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
107
|
requirements:
|
123
108
|
- - ~>
|
124
109
|
- !ruby/object:Gem::Version
|
@@ -126,17 +111,15 @@ dependencies:
|
|
126
111
|
- !ruby/object:Gem::Dependency
|
127
112
|
name: rb-fsevent
|
128
113
|
requirement: !ruby/object:Gem::Requirement
|
129
|
-
none: false
|
130
114
|
requirements:
|
131
|
-
- -
|
115
|
+
- - '>='
|
132
116
|
- !ruby/object:Gem::Version
|
133
117
|
version: '0'
|
134
118
|
type: :development
|
135
119
|
prerelease: false
|
136
120
|
version_requirements: !ruby/object:Gem::Requirement
|
137
|
-
none: false
|
138
121
|
requirements:
|
139
|
-
- -
|
122
|
+
- - '>='
|
140
123
|
- !ruby/object:Gem::Version
|
141
124
|
version: '0'
|
142
125
|
description: An extremely simple marshalling persistence layer for SQLite based on
|
@@ -174,33 +157,26 @@ files:
|
|
174
157
|
- test/test_set.rb
|
175
158
|
homepage: ''
|
176
159
|
licenses: []
|
160
|
+
metadata: {}
|
177
161
|
post_install_message:
|
178
162
|
rdoc_options: []
|
179
163
|
require_paths:
|
180
164
|
- lib
|
181
165
|
required_ruby_version: !ruby/object:Gem::Requirement
|
182
|
-
none: false
|
183
166
|
requirements:
|
184
|
-
- -
|
167
|
+
- - '>='
|
185
168
|
- !ruby/object:Gem::Version
|
186
169
|
version: '0'
|
187
|
-
segments:
|
188
|
-
- 0
|
189
|
-
hash: 3156010217290385344
|
190
170
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
191
|
-
none: false
|
192
171
|
requirements:
|
193
|
-
- -
|
172
|
+
- - '>='
|
194
173
|
- !ruby/object:Gem::Version
|
195
174
|
version: '0'
|
196
|
-
segments:
|
197
|
-
- 0
|
198
|
-
hash: 3156010217290385344
|
199
175
|
requirements: []
|
200
176
|
rubyforge_project:
|
201
|
-
rubygems_version:
|
177
|
+
rubygems_version: 2.0.0
|
202
178
|
signing_key:
|
203
|
-
specification_version:
|
179
|
+
specification_version: 4
|
204
180
|
summary: An extremely simple marshalling persistence layer for SQLite based on perl's
|
205
181
|
tie()
|
206
182
|
test_files:
|