redis-attrs 0.1.0 → 0.1.1
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/README.md +83 -53
- data/lib/redis-attrs.rb +7 -5
- data/lib/redis-attrs/complex.rb +1 -1
- data/lib/redis-attrs/objects_extensions.rb +2 -2
- data/lib/redis-attrs/version.rb +1 -1
- data/redis-attrs.gemspec +2 -1
- data/spec/redis_attrs_spec.rb +67 -62
- data/spec/spec_helper.rb +5 -0
- metadata +25 -3
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Redis::Attrs - Add attributes to Ruby classes backed by Redis
|
2
2
|
|
3
|
+
[](https://codeclimate.com/github/gnapse/redis-attrs)
|
4
|
+
|
3
5
|
This gem is an amalgamation of the ideas found within the [redis_props][redis_props]
|
4
6
|
and [redis-objects][redis-objects] gems, plus a few new ideas here and there. It
|
5
7
|
provides a way to define, on any Ruby class, some attributes that are backed by
|
@@ -33,47 +35,65 @@ Or install it yourself as:
|
|
33
35
|
|
34
36
|
$ gem install redis-attrs
|
35
37
|
|
38
|
+
## Setting up the connection
|
39
|
+
|
40
|
+
You can include some of the following code snippets at the beginning of your
|
41
|
+
app or script. In case you're using Rails, you can use an initializer.
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
# Standard connection
|
45
|
+
Redis::Attrs.redis = Redis.new
|
46
|
+
|
47
|
+
# Connection with specific parameters
|
48
|
+
Redis::Attrs.redis = Redis.new(host: 'hostname', port: 8888, password: 'secret')
|
49
|
+
|
50
|
+
# You can even use a redis namespace
|
51
|
+
Redis::Attrs.redis = Redis::Namespace.new("blah", redis: Redis.new)
|
52
|
+
```
|
53
|
+
|
36
54
|
## Usage
|
37
55
|
|
38
56
|
Start by defining some attributes on your class:
|
39
57
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
58
|
+
```ruby
|
59
|
+
class Film
|
60
|
+
include Redis::Attrs
|
61
|
+
redis_attrs :title => :string, :length => :integer
|
62
|
+
redis_attrs :released_on => :date, :cast => :list
|
44
63
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
64
|
+
# Remember that the objects need an id for this to work
|
65
|
+
attr_reader :id
|
66
|
+
def initialize(id)
|
67
|
+
@id = id
|
68
|
+
end
|
50
69
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
70
|
+
def presentation_title
|
71
|
+
"#{title} (#{released_on.year})"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
```
|
55
75
|
|
56
76
|
Then you can use those attributes as you would regularly, but internally they are
|
57
77
|
reading from and writing to Redis.
|
58
78
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
79
|
+
```ruby
|
80
|
+
>> film = Film.new(3)
|
81
|
+
>> film.title = "Argo"
|
82
|
+
>> film.released_on = "2012-10-12"
|
83
|
+
>> puts film.presentation_title
|
84
|
+
Argo (2012)
|
85
|
+
>> puts film.cast.size
|
86
|
+
0
|
87
|
+
>> film.cast = ["Ben Affleck", "Alan Arkin", "Brian Cranston"]
|
88
|
+
>> puts film.cast.size
|
89
|
+
3
|
90
|
+
>> puts film.cast[-3]
|
91
|
+
Ben Affleck
|
92
|
+
```
|
71
93
|
|
72
94
|
`Redis::Attrs` will work on _any_ class that provides an `id` method that returns
|
73
95
|
a unique value. `Redis::Attrs` will automatically create keys that are unique to
|
74
|
-
each object, in the format:
|
75
|
-
|
76
|
-
class_name:id:attr_name
|
96
|
+
each object, in the format `class_name:id:attr_name`.
|
77
97
|
|
78
98
|
### Supported types
|
79
99
|
|
@@ -97,29 +117,33 @@ The `serialize` and `deserialize` methods define how this process is done. Afte
|
|
97
117
|
registering the type with `Redis::Attrs`, a new attribute is added to the class
|
98
118
|
`Film` defined above.
|
99
119
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
120
|
+
```ruby
|
121
|
+
class JSONScalar < Redis::Attrs::Scalar
|
122
|
+
def serialize(value)
|
123
|
+
value.to_json
|
124
|
+
end
|
104
125
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
126
|
+
def deserialize(value)
|
127
|
+
JSON.parse(value)
|
128
|
+
end
|
129
|
+
end
|
109
130
|
|
110
|
-
|
131
|
+
Redis::Attrs.register_type(:json, JSONScalar)
|
111
132
|
|
112
|
-
|
113
|
-
|
114
|
-
|
133
|
+
class Film
|
134
|
+
redis_attrs :director => :json
|
135
|
+
end
|
136
|
+
```
|
115
137
|
|
116
138
|
After the definitions above, more complex data structures could be stored as a single
|
117
139
|
scalar value, by being serialized as JSON.
|
118
140
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
141
|
+
```ruby
|
142
|
+
>> film = Film.new(1)
|
143
|
+
>> film.director = { "first_name" => "Ben", "last_name" => "Affleck" }
|
144
|
+
>> puts Redis::Attrs.redis.get("film:1:director")
|
145
|
+
{"first_name":"Ben","last_name":"Affleck"}
|
146
|
+
```
|
123
147
|
|
124
148
|
### Attribute configuration options
|
125
149
|
|
@@ -127,8 +151,10 @@ The complex attribute types support some configuration options, mostly specific
|
|
127
151
|
each type. When an attribute needs to be configured with some of these options, then
|
128
152
|
it must be declared with the singular version of the method `redis_attrs`, like below:
|
129
153
|
|
130
|
-
|
131
|
-
|
154
|
+
```ruby
|
155
|
+
redis_attr :crawl, :lock, :expiration => 15.minutes
|
156
|
+
redis_attr :cast, :list, :marshal => true
|
157
|
+
```
|
132
158
|
|
133
159
|
For more details about the supported configuration options for each of the complex
|
134
160
|
data types, please refer to the [redis-objects][redis-objects] gem.
|
@@ -139,16 +165,20 @@ There's an attribute configuration option for lists and sets, the `:filter` opti
|
|
139
165
|
that allows the user to define a function that will modify the items upon insertion
|
140
166
|
into the collection.
|
141
167
|
|
142
|
-
|
143
|
-
|
144
|
-
|
168
|
+
```ruby
|
169
|
+
class Film
|
170
|
+
redis_attr :genres, :set, :filter => lambda { |v| v.strip.downcase.gsub(/\s+/, ' ') }
|
171
|
+
end
|
172
|
+
```
|
145
173
|
|
146
174
|
After the above declaration we could do:
|
147
175
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
176
|
+
```ruby
|
177
|
+
>> film = Film.new(1)
|
178
|
+
>> film.genres = ["Action ", " drama", "film Noir", "Drama", "Film noir "]
|
179
|
+
>> puts film.genres.members.sort
|
180
|
+
["action", "drama", "film noir"]
|
181
|
+
```
|
152
182
|
|
153
183
|
## Contributing
|
154
184
|
|
data/lib/redis-attrs.rb
CHANGED
@@ -5,11 +5,11 @@ require "active_support/inflector"
|
|
5
5
|
class Redis
|
6
6
|
module Attrs
|
7
7
|
def self.redis
|
8
|
-
@redis
|
8
|
+
@redis || $redis || Redis.current ||
|
9
|
+
raise(NotConnected, "Redis::Attrs.redis not set to a valid redis connection")
|
9
10
|
end
|
10
11
|
|
11
12
|
def self.redis=(r)
|
12
|
-
raise ArgumentError, "Redis Attrs: Invalid Redis instance" unless r.is_a?(Redis)
|
13
13
|
@redis = r
|
14
14
|
end
|
15
15
|
|
@@ -19,7 +19,7 @@ class Redis
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def redis_key_prefix
|
22
|
-
@redis_key_refix ||= ActiveSupport::Inflector.underscore(
|
22
|
+
@redis_key_refix ||= ActiveSupport::Inflector.underscore(name)
|
23
23
|
end
|
24
24
|
|
25
25
|
def redis_attrs(attrs = nil)
|
@@ -32,7 +32,7 @@ class Redis
|
|
32
32
|
|
33
33
|
def redis_attr(name, type, options = {})
|
34
34
|
@redis_attrs ||= []
|
35
|
-
klass = Redis::Attrs
|
35
|
+
klass = Redis::Attrs.supported_types[type]
|
36
36
|
raise ArgumentError, "Unknown Redis::Attr type #{type}" if klass.nil?
|
37
37
|
attr = klass.new(self, name, type, options)
|
38
38
|
@redis_attrs << attr
|
@@ -73,7 +73,9 @@ class Redis
|
|
73
73
|
def self.register_type(type, klass)
|
74
74
|
type = type.to_sym
|
75
75
|
raise ArgumentError, "Redis attr type #{type} is already defined" if supported_types.include?(type)
|
76
|
-
|
76
|
+
unless klass.ancestors.include?(Scalar)
|
77
|
+
raise ArgumentError, "Class implementing new type #{type} must be a subclass of Redis::Attrs::Scalar"
|
78
|
+
end
|
77
79
|
@supported_types[type] = klass
|
78
80
|
end
|
79
81
|
|
data/lib/redis-attrs/complex.rb
CHANGED
@@ -8,7 +8,7 @@ class Redis
|
|
8
8
|
end
|
9
9
|
|
10
10
|
# Add a member before or after pivot in the list. Redis: LINSERT
|
11
|
-
def insert(where,pivot,value)
|
11
|
+
def insert(where, pivot, value)
|
12
12
|
if options[:filter]
|
13
13
|
value = options[:filter].call(value)
|
14
14
|
pivot = options[:filter].call(pivot)
|
@@ -22,7 +22,7 @@ class Redis
|
|
22
22
|
super
|
23
23
|
end
|
24
24
|
|
25
|
-
def delete(name, count=0)
|
25
|
+
def delete(name, count = 0)
|
26
26
|
name = options[:filter].call(name) if options[:filter]
|
27
27
|
super
|
28
28
|
end
|
data/lib/redis-attrs/version.rb
CHANGED
data/redis-attrs.gemspec
CHANGED
@@ -13,11 +13,12 @@ Gem::Specification.new do |gem|
|
|
13
13
|
gem.homepage = "http://github.com/gnapse/redis-attrs"
|
14
14
|
|
15
15
|
gem.files = `git ls-files`.split($/)
|
16
|
-
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
17
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
18
|
gem.require_paths = ["lib"]
|
19
19
|
|
20
20
|
gem.add_development_dependency "rspec"
|
21
|
+
gem.add_development_dependency "rake"
|
21
22
|
gem.add_dependency "redis"
|
22
23
|
gem.add_dependency "activesupport"
|
23
24
|
gem.add_dependency "redis-objects"
|
data/spec/redis_attrs_spec.rb
CHANGED
@@ -26,37 +26,40 @@ describe Redis::Attrs do
|
|
26
26
|
let(:film) { Film.new }
|
27
27
|
|
28
28
|
it "has a version number" do
|
29
|
-
Redis::Attrs::VERSION.
|
29
|
+
expect(Redis::Attrs::VERSION).not_to be_nil
|
30
30
|
end
|
31
31
|
|
32
32
|
context "when included in a class" do
|
33
33
|
it "makes the class respond to .redis_attrs" do
|
34
|
-
Film.
|
34
|
+
expect(Film).to respond_to(:redis_attrs)
|
35
35
|
end
|
36
36
|
|
37
37
|
it "provides the class and its instances with a .redis interface" do
|
38
|
-
Film.
|
39
|
-
film.
|
38
|
+
expect(Film).to respond_to(:redis)
|
39
|
+
expect(film).to respond_to(:redis)
|
40
40
|
|
41
|
-
Film.redis.
|
42
|
-
Film.redis.
|
41
|
+
expect(Film.redis).to be_a(Redis)
|
42
|
+
expect(Film.redis).to equal(film.redis)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
46
|
describe ".redis_attrs" do
|
47
47
|
it "adds getters and setters for the attributes defined" do
|
48
48
|
%w(title released_on length created_at rating featured).each do |attr|
|
49
|
-
film.
|
50
|
-
film.
|
49
|
+
expect(film).to respond_to(attr)
|
50
|
+
expect(film).to respond_to("#{attr}=")
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
54
|
context "with no paremeters" do
|
55
|
+
let(:attrs) { [:title, :released_on, :length, :created_at, :rating, :featured] }
|
56
|
+
let(:types) { [:string, :date, :integer, :time, :float, :boolean] }
|
57
|
+
|
55
58
|
it "returns a list of all Redis attributes defined for the class" do
|
56
|
-
Film.redis_attrs.
|
57
|
-
Film.redis_attrs.count.
|
58
|
-
Film.redis_attrs.map(&:name).
|
59
|
-
Film.redis_attrs.map(&:type).
|
59
|
+
expect(Film.redis_attrs).to be_a(Array)
|
60
|
+
expect(Film.redis_attrs.count).to eq(6)
|
61
|
+
expect(Film.redis_attrs.map(&:name)).to eq(attrs)
|
62
|
+
expect(Film.redis_attrs.map(&:type)).to eq(types)
|
60
63
|
end
|
61
64
|
end
|
62
65
|
end
|
@@ -64,119 +67,121 @@ describe Redis::Attrs do
|
|
64
67
|
describe "getters" do
|
65
68
|
let(:now) { Time.parse("2013-02-22 22:31:12 -0500") }
|
66
69
|
|
67
|
-
it "
|
68
|
-
film.title.
|
69
|
-
film.released_on.
|
70
|
-
film.length.
|
70
|
+
it "returns nil by default" do
|
71
|
+
expect(film.title).to be_nil
|
72
|
+
expect(film.released_on).to be_nil
|
73
|
+
expect(film.length).to be_nil
|
71
74
|
end
|
72
75
|
|
73
|
-
it "
|
76
|
+
it "returns whatever was last set with the corresponding setter" do
|
74
77
|
film.title = "Argo"
|
75
|
-
film.title.
|
78
|
+
expect(film.title).to eq("Argo")
|
76
79
|
end
|
77
80
|
|
78
|
-
it "
|
81
|
+
it "keeps the original value type" do
|
79
82
|
film.released_on = Date.parse("2012-10-12")
|
80
|
-
film.released_on.
|
83
|
+
expect(film.released_on).to eq(Date.parse("2012-10-12"))
|
81
84
|
film.created_at = now
|
82
|
-
film.created_at.
|
85
|
+
expect(film.created_at).to eq(now)
|
83
86
|
film.length = 135
|
84
|
-
film.length.
|
87
|
+
expect(film.length).to eq(135)
|
85
88
|
film.rating = 8.2
|
86
|
-
film.rating.
|
89
|
+
expect(film.rating).to eq(8.2)
|
87
90
|
film.featured = true
|
88
|
-
film.featured.
|
91
|
+
expect(film.featured).to eq(true)
|
89
92
|
end
|
90
93
|
end
|
91
94
|
|
92
95
|
describe "setters" do
|
93
|
-
it "
|
96
|
+
it "sets the corresponding key in Redis" do
|
94
97
|
film.title = "Argo"
|
95
|
-
redis.get("film:1:title").
|
98
|
+
expect(redis.get("film:1:title")).to eq("Argo")
|
96
99
|
|
97
100
|
film.rating = 8.1
|
98
|
-
redis.get("film:1:rating").
|
101
|
+
expect(redis.get("film:1:rating")).to eq("8.1")
|
99
102
|
end
|
100
103
|
|
101
|
-
it "
|
104
|
+
it "unsets the key when being assigned nil" do
|
102
105
|
film.rating = 8.1
|
103
|
-
redis.keys.
|
106
|
+
expect(redis.keys).to include("film:1:rating")
|
104
107
|
|
105
108
|
film.rating = nil
|
106
|
-
redis.keys.
|
107
|
-
redis.get("film:1:rating").
|
109
|
+
expect(redis.keys).not_to include("film:1:rating")
|
110
|
+
expect(redis.get("film:1:rating")).to be_nil
|
108
111
|
end
|
109
112
|
end
|
110
113
|
|
111
114
|
describe ".register_type" do
|
115
|
+
let(:director) { { first_name: "Ben", last_name: "Affleck" } }
|
116
|
+
|
112
117
|
it "allows to define support for scalar value types not covered by the library" do
|
113
118
|
Redis::Attrs.register_type(:json, JSONScalar)
|
114
119
|
Film.redis_attrs director: :json
|
115
|
-
film.director =
|
116
|
-
redis.keys.
|
117
|
-
redis.get("film:1:director").
|
118
|
-
film.director.
|
120
|
+
film.director = director
|
121
|
+
expect(redis.keys).to include("film:1:director")
|
122
|
+
expect(redis.get("film:1:director")).to eq(director.to_json)
|
123
|
+
expect(film.director).to eq({ "first_name" => "Ben", "last_name" => "Affleck" })
|
119
124
|
end
|
120
125
|
end
|
121
126
|
|
122
127
|
describe "collection attributes" do
|
123
|
-
it "
|
128
|
+
it "supports lists" do
|
124
129
|
Film.redis_attrs cast: :list
|
125
|
-
film.cast.
|
130
|
+
expect(film.cast).to be_empty
|
126
131
|
film.cast = ["Ben Affleck", "Alan Arkin", "John Goodman", "Ben Affleck"]
|
127
|
-
film.cast.size.
|
132
|
+
expect(film.cast.size).to eq(4)
|
128
133
|
end
|
129
134
|
|
130
|
-
it "
|
135
|
+
it "supports hashes" do
|
131
136
|
Film.redis_attrs crew: :hash
|
132
|
-
film.crew.
|
137
|
+
expect(film.crew).to be_empty
|
133
138
|
film.crew = { costume: "John Doe", makeup: "Jane Doe", camera: "James Doe" }
|
134
|
-
film.crew.size.
|
135
|
-
film.crew.keys.
|
139
|
+
expect(film.crew.size).to eq(3)
|
140
|
+
expect(film.crew.keys).to eq(%w(costume makeup camera))
|
136
141
|
end
|
137
142
|
|
138
|
-
it "
|
143
|
+
it "supports sets" do
|
139
144
|
Film.redis_attrs producers: :set
|
140
|
-
film.producers.
|
145
|
+
expect(film.producers).to be_empty
|
141
146
|
film.producers = ["Grant Heslov", "Ben Affleck", "George Clooney", "Ben Affleck"]
|
142
|
-
film.producers.size.
|
147
|
+
expect(film.producers.size).to eq(3)
|
143
148
|
end
|
144
149
|
|
145
|
-
it "
|
150
|
+
it "supports sorted sets" do
|
146
151
|
Film.redis_attrs rankings: :sorted_set
|
147
|
-
film.rankings.
|
152
|
+
expect(film.rankings).to be_empty
|
148
153
|
film.rankings = { "oscars" => 3, "golden globe" => 1, "bafta" => 2 }
|
149
|
-
film.rankings.first.
|
150
|
-
film.rankings.last.
|
151
|
-
film.rankings.members.
|
154
|
+
expect(film.rankings.first).to eq("golden globe")
|
155
|
+
expect(film.rankings.last).to eq("oscars")
|
156
|
+
expect(film.rankings.members).to eq(["golden globe", "bafta", "oscars"])
|
152
157
|
end
|
153
158
|
|
154
|
-
it "
|
159
|
+
it "supports counters" do
|
155
160
|
Film.redis_attrs awards_count: :counter
|
156
|
-
film.awards_count.value.
|
161
|
+
expect(film.awards_count.value).to eq(0)
|
157
162
|
film.awards_count.incr
|
158
|
-
film.awards_count.value.
|
163
|
+
expect(film.awards_count.value).to eq(1)
|
159
164
|
end
|
160
165
|
|
161
|
-
it "
|
166
|
+
it "supports locks" do
|
162
167
|
Film.redis_attrs playing: :lock
|
163
168
|
film.playing.lock { }
|
164
169
|
end
|
165
170
|
|
166
|
-
it "
|
171
|
+
it "supports specifying configuration options" do
|
167
172
|
require "active_support/core_ext/numeric/time"
|
168
|
-
Film.redis_attr :watching, :lock, :
|
169
|
-
film.watching.options[:expiration].
|
173
|
+
Film.redis_attr :watching, :lock, expiration: 3.hours
|
174
|
+
expect(film.watching.options[:expiration]).to eq(3.hours)
|
170
175
|
end
|
171
176
|
|
172
177
|
it "supports filtering the values inserted into a list or set" do
|
173
|
-
Film.redis_attr :genres, :set, filter:
|
178
|
+
Film.redis_attr :genres, :set, filter: ->(genre) { genre.strip.downcase.gsub(/\s+/, ' ') }
|
174
179
|
film.genres = ["Action ", " drama", "film Noir", "Drama", "Film noir "]
|
175
|
-
film.genres.members.sort.
|
180
|
+
expect(film.genres.members.sort).to eq(["action", "drama", "film noir"])
|
176
181
|
film.genres << " ACTION " << "Western"
|
177
|
-
film.genres.
|
178
|
-
film.genres.
|
179
|
-
film.genres.members.sort.
|
182
|
+
expect(film.genres).not_to include("Western")
|
183
|
+
expect(film.genres).to include("western")
|
184
|
+
expect(film.genres.members.sort).to eq(["action", "drama", "film noir", "western"])
|
180
185
|
end
|
181
186
|
end
|
182
187
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-attrs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
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: 2013-
|
12
|
+
date: 2013-08-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -27,6 +27,22 @@ dependencies:
|
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
30
46
|
- !ruby/object:Gem::Dependency
|
31
47
|
name: redis
|
32
48
|
requirement: !ruby/object:Gem::Requirement
|
@@ -118,15 +134,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
118
134
|
- - ! '>='
|
119
135
|
- !ruby/object:Gem::Version
|
120
136
|
version: '0'
|
137
|
+
segments:
|
138
|
+
- 0
|
139
|
+
hash: -3942124308415567947
|
121
140
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
141
|
none: false
|
123
142
|
requirements:
|
124
143
|
- - ! '>='
|
125
144
|
- !ruby/object:Gem::Version
|
126
145
|
version: '0'
|
146
|
+
segments:
|
147
|
+
- 0
|
148
|
+
hash: -3942124308415567947
|
127
149
|
requirements: []
|
128
150
|
rubyforge_project:
|
129
|
-
rubygems_version: 1.8.
|
151
|
+
rubygems_version: 1.8.23
|
130
152
|
signing_key:
|
131
153
|
specification_version: 3
|
132
154
|
summary: Add persistent object attributes backed by redis
|