ruote-redis 2.1.10 → 2.1.11
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/CHANGELOG.txt +8 -0
- data/CREDITS.txt +18 -0
- data/README.rdoc +2 -2
- data/Rakefile +13 -16
- data/lib/ruote/redis/storage.rb +176 -116
- data/lib/ruote/redis/version.rb +1 -1
- data/ruote-redis.gemspec +9 -8
- metadata +8 -7
data/CHANGELOG.txt
CHANGED
@@ -2,6 +2,14 @@
|
|
2
2
|
= ruote-redis - CHANGELOG.txt
|
3
3
|
|
4
4
|
|
5
|
+
== ruote-redis 2.1.11 released 2010/10/01
|
6
|
+
|
7
|
+
- storage format change (thanks @wwkeyboard)
|
8
|
+
- get_many(type, keys) support (array of keys instead of lonely regex key)
|
9
|
+
- get_many(type, nil, :skip => 10) support
|
10
|
+
- get_many(type, nil, :count => true) support
|
11
|
+
|
12
|
+
|
5
13
|
== ruote-redis 2.1.10 released 2010/06/15
|
6
14
|
|
7
15
|
- works with redis-rb 1.0.2 and 2.0
|
data/CREDITS.txt
ADDED
data/README.rdoc
CHANGED
@@ -38,13 +38,13 @@ start a redis server instance (port 6379) and then
|
|
38
38
|
|
39
39
|
get into ruote/ and do
|
40
40
|
|
41
|
-
ruby test/unit/storage.rb --redis
|
41
|
+
ruby test/unit/storage.rb -- --redis
|
42
42
|
|
43
43
|
* functional tests :
|
44
44
|
|
45
45
|
get into ruote/ and do
|
46
46
|
|
47
|
-
ruby test/functional/test.rb --redis
|
47
|
+
ruby test/functional/test.rb -- --redis
|
48
48
|
|
49
49
|
|
50
50
|
== license
|
data/Rakefile
CHANGED
@@ -33,7 +33,7 @@ Redis storage for ruote (a ruby workflow engine)
|
|
33
33
|
#gem.test_file = 'test/test.rb'
|
34
34
|
|
35
35
|
gem.add_dependency 'ruote', ">= #{Ruote::Redis::VERSION}"
|
36
|
-
gem.add_dependency 'redis', '>= 2.0.
|
36
|
+
gem.add_dependency 'redis', '>= 2.0.5'
|
37
37
|
gem.add_development_dependency 'yard'
|
38
38
|
gem.add_development_dependency 'rake'
|
39
39
|
gem.add_development_dependency 'jeweler'
|
@@ -46,33 +46,30 @@ Jeweler::GemcutterTasks.new
|
|
46
46
|
#
|
47
47
|
# DOC
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
#
|
50
|
+
# make sure to have rdoc 2.5.x to run that
|
51
|
+
#
|
52
|
+
require 'rake/rdoctask'
|
53
|
+
Rake::RDocTask.new do |rd|
|
52
54
|
|
53
|
-
|
54
|
-
|
55
|
-
'-o', 'html/ruote-redis', '--title',
|
56
|
-
"ruote-redis #{Ruote::Redis::VERSION}"
|
57
|
-
]
|
58
|
-
end
|
55
|
+
rd.main = 'README.rdoc'
|
56
|
+
rd.rdoc_dir = 'rdoc/ruote-redis_rdoc'
|
59
57
|
|
60
|
-
|
58
|
+
rd.rdoc_files.include(
|
59
|
+
'README.rdoc', 'CHANGELOG.txt', 'CREDITS.txt', 'lib/**/*.rb')
|
61
60
|
|
62
|
-
|
63
|
-
abort "YARD is not available : sudo gem install yard"
|
64
|
-
end
|
61
|
+
rd.title = "ruote-redis #{Ruote::Redis::VERSION}"
|
65
62
|
end
|
66
63
|
|
67
64
|
|
68
65
|
#
|
69
66
|
# TO THE WEB
|
70
67
|
|
71
|
-
task :
|
68
|
+
task :upload_rdoc => [ :clean, :rdoc ] do
|
72
69
|
|
73
70
|
account = 'jmettraux@rubyforge.org'
|
74
71
|
webdir = '/var/www/gforge-projects/ruote'
|
75
72
|
|
76
|
-
sh "rsync -azv -e ssh
|
73
|
+
sh "rsync -azv -e ssh rdoc/ruote-redis_rdoc #{account}:#{webdir}/"
|
77
74
|
end
|
78
75
|
|
data/lib/ruote/redis/storage.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright
|
2
|
+
# Copyright(c) 2005-2010, John Mettraux, jmettraux@gmail.com
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
-
# of this software and associated documentation files
|
5
|
+
# of this software and associated documentation files(the "Software"), to deal
|
6
6
|
# in the Software without restriction, including without limitation the rights
|
7
7
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
8
|
# copies of the Software, and to permit persons to whom the Software is
|
@@ -37,8 +37,8 @@ module Redis
|
|
37
37
|
# A Redis storage for ruote.
|
38
38
|
#
|
39
39
|
# The constructor accepts two arguments, the first one is a Redis instance
|
40
|
-
#
|
41
|
-
# ruote engine options
|
40
|
+
#( see http://github.com/ezmobius/redis-rb ), the second one is the classic
|
41
|
+
# ruote engine options( see
|
42
42
|
# http://ruote.rubyforge.org/configuration.html#engine )
|
43
43
|
#
|
44
44
|
# require 'redis' # gem install redis
|
@@ -66,12 +66,14 @@ module Redis
|
|
66
66
|
|
67
67
|
attr_reader :redis
|
68
68
|
|
69
|
-
|
69
|
+
# A Redis storage for ruote.
|
70
|
+
#
|
71
|
+
def initialize(redis, options={})
|
70
72
|
|
71
73
|
@redis = redis
|
72
74
|
@options = options
|
73
75
|
|
74
|
-
def @redis.keys_to_a
|
76
|
+
def @redis.keys_to_a(opt)
|
75
77
|
r = keys(opt)
|
76
78
|
r.is_a?(Array) ? r : r.split(' ')
|
77
79
|
end
|
@@ -79,132 +81,167 @@ module Redis
|
|
79
81
|
put_configuration
|
80
82
|
end
|
81
83
|
|
82
|
-
def reserve
|
84
|
+
def reserve(doc)
|
83
85
|
|
84
86
|
@redis.del(key_for(doc))
|
85
87
|
end
|
86
88
|
|
87
|
-
def put_msg
|
89
|
+
def put_msg(action, options)
|
88
90
|
|
89
91
|
doc = prepare_msg_doc(action, options)
|
90
92
|
|
93
|
+
puts "XXX" if @redis.nil?
|
94
|
+
|
91
95
|
@redis.set(key_for(doc), to_json(doc))
|
92
96
|
|
93
97
|
nil
|
94
98
|
end
|
95
99
|
|
96
|
-
def put_schedule
|
100
|
+
def put_schedule(flavour, owner_fei, s, msg)
|
97
101
|
|
98
|
-
|
99
|
-
@redis.set(key_for(doc), to_json(doc))
|
100
|
-
return doc['_id']
|
101
|
-
end
|
102
|
+
doc = prepare_schedule_doc(flavour, owner_fei, s, msg)
|
102
103
|
|
103
|
-
nil
|
104
|
+
return nil unless doc
|
105
|
+
|
106
|
+
@redis.set(key_for(doc), to_json(doc))
|
107
|
+
|
108
|
+
doc['_id']
|
104
109
|
end
|
105
110
|
|
106
|
-
def delete_schedule
|
111
|
+
def delete_schedule(schedule_id)
|
107
112
|
|
108
113
|
@redis.del(key_for('schedules', schedule_id))
|
109
114
|
end
|
110
115
|
|
111
|
-
def put
|
116
|
+
def put(doc, opts={})
|
112
117
|
|
113
|
-
rev = doc['_rev'].to_i
|
114
118
|
key = key_for(doc)
|
119
|
+
rev = doc['_rev']
|
120
|
+
|
121
|
+
lock(key) do
|
122
|
+
|
123
|
+
current_doc = do_get(key)
|
124
|
+
current_rev = current_doc ? current_doc['_rev'] : nil
|
125
|
+
|
126
|
+
if current_rev && rev != current_rev
|
127
|
+
#
|
128
|
+
# version in storage is newer than version being put,
|
129
|
+
# (eturn version in storage)
|
130
|
+
#
|
131
|
+
current_doc
|
132
|
+
|
133
|
+
elsif rev && current_rev.nil?
|
134
|
+
#
|
135
|
+
# document deleted, put fails (return true)
|
136
|
+
#
|
137
|
+
true
|
138
|
+
|
139
|
+
else
|
140
|
+
#
|
141
|
+
# put is successful (return nil)
|
142
|
+
#
|
143
|
+
nrev = (rev.to_i + 1).to_s
|
144
|
+
@redis.set(key, to_json(doc.merge('_rev' => nrev)))
|
145
|
+
doc['_rev'] = nrev if opts[:update_rev]
|
146
|
+
|
147
|
+
nil
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
115
151
|
|
116
|
-
|
152
|
+
def get(type, key)
|
117
153
|
|
118
|
-
|
119
|
-
|
154
|
+
do_get(key_for(type, key))
|
155
|
+
end
|
120
156
|
|
121
|
-
|
157
|
+
def delete(doc)
|
122
158
|
|
123
|
-
|
159
|
+
rev = doc['_rev']
|
124
160
|
|
125
|
-
|
126
|
-
key_rev_for(doc, nrev),
|
127
|
-
to_json(doc.merge('_rev' => nrev), opts))
|
161
|
+
raise ArgumentError.new("can't delete doc without _rev") unless rev
|
128
162
|
|
129
|
-
|
163
|
+
key = key_for(doc)
|
130
164
|
|
131
|
-
|
132
|
-
@redis.del(key_rev_for(doc, rev)) if rev > 0
|
165
|
+
lock(key) do
|
133
166
|
|
134
|
-
|
167
|
+
current_doc = do_get(key)
|
135
168
|
|
136
|
-
|
137
|
-
|
169
|
+
if current_doc.nil?
|
170
|
+
#
|
171
|
+
# document is [already] gone, delete fails (return true)
|
172
|
+
#
|
173
|
+
true
|
138
174
|
|
139
|
-
|
175
|
+
elsif current_doc['_rev'] != rev
|
176
|
+
#
|
177
|
+
# version in storage doesn't match version to delete
|
178
|
+
# (return version in storage)
|
179
|
+
#
|
180
|
+
current_doc
|
140
181
|
|
141
|
-
|
142
|
-
|
182
|
+
else
|
183
|
+
#
|
184
|
+
# delete is successful (return nil)
|
185
|
+
#
|
186
|
+
@redis.del(key)
|
143
187
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
r = put(doc, :delete => true)
|
188
|
+
nil
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
150
192
|
|
151
|
-
|
193
|
+
def get_many(type, key=nil, opts={})
|
152
194
|
|
153
|
-
|
154
|
-
Thread.pass # lingering a bit...
|
155
|
-
@redis.del(k)
|
156
|
-
}
|
157
|
-
# deleting the key_rev last and making 1 'keys' call preliminarily
|
195
|
+
keys = key ? Array(key) : nil
|
158
196
|
|
159
|
-
|
160
|
-
|
197
|
+
#ids = if type == 'msgs' || type == 'schedules'
|
198
|
+
# @redis.keys_to_a("#{type}/*")
|
161
199
|
|
162
|
-
|
200
|
+
ids = if keys == nil
|
163
201
|
|
164
|
-
|
202
|
+
@redis.keys_to_a("#{type}/*")
|
165
203
|
|
166
|
-
|
204
|
+
elsif keys.first.is_a?(String)
|
167
205
|
|
168
|
-
@redis.keys_to_a(
|
206
|
+
keys.collect { |k| @redis.keys_to_a("#{type}/*!#{k}") }.flatten
|
169
207
|
|
170
|
-
else
|
208
|
+
else #if keys.first.is_a?(Regexp)
|
171
209
|
|
172
|
-
@redis.keys_to_a(
|
210
|
+
@redis.keys_to_a("#{type}/*").select { |i|
|
173
211
|
|
174
|
-
|
212
|
+
i = i[type.length + 1..-1]
|
213
|
+
# removing "^type/"
|
175
214
|
|
176
|
-
|
215
|
+
keys.find { |k| k.match(i) }
|
216
|
+
}
|
217
|
+
end
|
177
218
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
end
|
182
|
-
end
|
219
|
+
ids = ids.reject { |i| i.match(LOCK_KEY) }
|
220
|
+
ids = ids.sort
|
221
|
+
ids = ids.reverse if opts[:descending]
|
183
222
|
|
184
|
-
|
185
|
-
|
186
|
-
|
223
|
+
skip = opts[:skip] || 0
|
224
|
+
limit = opts[:limit] || ids.length
|
225
|
+
ids = ids[skip, limit]
|
187
226
|
|
188
|
-
|
189
|
-
|
227
|
+
docs = ids.length > 0 ? @redis.mget(*ids) : []
|
228
|
+
docs = docs.inject({}) do |h, doc|
|
229
|
+
if doc
|
230
|
+
doc = Rufus::Json.decode(doc)
|
231
|
+
h[doc['_id']] = doc
|
232
|
+
end
|
233
|
+
h
|
190
234
|
end
|
191
235
|
|
192
|
-
|
193
|
-
v = @redis.get(i)
|
194
|
-
a << Rufus::Json.decode(v) if v
|
195
|
-
a
|
196
|
-
end
|
236
|
+
opts[:count] ? docs.size : docs.values
|
197
237
|
end
|
198
238
|
|
199
|
-
def ids
|
200
|
-
|
201
|
-
@redis.keys_to_a("#{type}/*").inject([]) { |a, k|
|
202
|
-
|
203
|
-
if m = k.match(/^[^\/]+\/([^\/]+)$/)
|
204
|
-
a << m[1]
|
205
|
-
end
|
239
|
+
def ids(type)
|
206
240
|
|
207
|
-
|
241
|
+
@redis.keys_to_a("#{type}/*").reject { |i|
|
242
|
+
i.match(LOCK_KEY)
|
243
|
+
}.collect { |i|
|
244
|
+
i.split('/').last
|
208
245
|
}.sort
|
209
246
|
end
|
210
247
|
|
@@ -213,77 +250,100 @@ module Redis
|
|
213
250
|
@redis.keys_to_a('*').each { |k| @redis.del(k) }
|
214
251
|
end
|
215
252
|
|
216
|
-
#
|
217
|
-
#
|
218
|
-
#
|
253
|
+
# Returns a String containing a representation of the current content of
|
254
|
+
# in this Redis storage.
|
255
|
+
#
|
256
|
+
def dump(type)
|
257
|
+
|
258
|
+
@redis.keys_to_a("#{type}/*").sort.join("\n")
|
259
|
+
end
|
260
|
+
|
261
|
+
def close
|
219
262
|
|
220
|
-
|
263
|
+
@redis.quit
|
221
264
|
end
|
222
265
|
|
223
266
|
# Mainly used by ruote's test/unit/ut_17_storage.rb
|
224
267
|
#
|
225
|
-
def add_type
|
268
|
+
def add_type(type)
|
226
269
|
end
|
227
270
|
|
228
|
-
# Nukes a db type and reputs it
|
271
|
+
# Nukes a db type and reputs it(losing all the documents that were in it).
|
229
272
|
#
|
230
|
-
def purge_type!
|
273
|
+
def purge_type!(type)
|
231
274
|
|
232
275
|
@redis.keys_to_a("#{type}/*").each { |k| @redis.del(k) }
|
233
276
|
end
|
234
277
|
|
235
278
|
protected
|
236
279
|
|
237
|
-
|
238
|
-
|
280
|
+
LOCK_KEY = /-lock$/
|
281
|
+
|
282
|
+
# A locking mecha.
|
283
|
+
#
|
284
|
+
# Mostly inspired from http://code.google.com/p/redis/wiki/SetnxCommand
|
239
285
|
#
|
240
|
-
def
|
286
|
+
def lock(key, &block)
|
241
287
|
|
242
|
-
|
288
|
+
kl = "#{key}-lock"
|
243
289
|
|
244
|
-
|
245
|
-
end
|
290
|
+
loop do
|
246
291
|
|
247
|
-
|
248
|
-
# key_rev_for(doc, rev)
|
249
|
-
# key_rev_for(type, key, rev)
|
250
|
-
#
|
251
|
-
def key_rev_for (*args)
|
292
|
+
r = @redis.setnx(kl, Time.now.to_f.to_s)
|
252
293
|
|
253
|
-
|
254
|
-
|
294
|
+
if r == false
|
295
|
+
|
296
|
+
t = @redis.get(kl)
|
297
|
+
|
298
|
+
@redis.del(kl) if t && Time.now.to_f - t.to_f > 60.0
|
299
|
+
# after 1 minute, locks time out
|
300
|
+
|
301
|
+
sleep 0.007 # let's try to lock again after a while
|
302
|
+
else
|
255
303
|
|
256
|
-
|
257
|
-
|
258
|
-
as[2] = args[1] if args[1]
|
259
|
-
else
|
260
|
-
as = args[0, 3]
|
304
|
+
break # lock acquired
|
305
|
+
end
|
261
306
|
end
|
262
307
|
|
263
|
-
|
308
|
+
#@redis.expire(kl, 2)
|
309
|
+
# this doesn't work, it makes the next call to setnx succeed
|
310
|
+
|
311
|
+
result = block.call
|
312
|
+
|
313
|
+
@redis.del(kl)
|
314
|
+
|
315
|
+
result
|
264
316
|
end
|
265
317
|
|
266
|
-
|
318
|
+
# key_for(doc)
|
319
|
+
# key_for(type, key)
|
320
|
+
#
|
321
|
+
def key_for(*args)
|
322
|
+
|
323
|
+
a = args.first
|
324
|
+
|
325
|
+
(a.is_a?(Hash) ? [ a['type'], a['_id'] ] : args[0, 2]).join('/')
|
326
|
+
end
|
267
327
|
|
268
|
-
|
328
|
+
def do_get(key)
|
269
329
|
|
270
|
-
|
330
|
+
from_json(@redis.get(key))
|
271
331
|
end
|
272
332
|
|
273
|
-
def
|
333
|
+
def from_json(s)
|
274
334
|
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
end
|
335
|
+
s ? Rufus::Json.decode(s) : nil
|
336
|
+
end
|
337
|
+
|
338
|
+
def to_json(doc, opts={})
|
280
339
|
|
281
|
-
Rufus::Json.encode(
|
340
|
+
Rufus::Json.encode(
|
341
|
+
opts[:delete] ? nil : doc.merge('put_at' => Ruote.now_to_utc_s))
|
282
342
|
end
|
283
343
|
|
284
344
|
# Don't put configuration if it's already in
|
285
345
|
#
|
286
|
-
# (
|
346
|
+
# (prevent storages from trashing configuration...)
|
287
347
|
#
|
288
348
|
def put_configuration
|
289
349
|
|
data/lib/ruote/redis/version.rb
CHANGED
data/ruote-redis.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ruote-redis}
|
8
|
-
s.version = "2.1.
|
8
|
+
s.version = "2.1.11"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["John Mettraux"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-10-01}
|
13
13
|
s.description = %q{Redis storage for ruote (a ruby workflow engine)}
|
14
14
|
s.email = %q{jmettraux@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -18,6 +18,7 @@ Gem::Specification.new do |s|
|
|
18
18
|
]
|
19
19
|
s.files = [
|
20
20
|
"CHANGELOG.txt",
|
21
|
+
"CREDITS.txt",
|
21
22
|
"LICENSE.txt",
|
22
23
|
"README.rdoc",
|
23
24
|
"Rakefile",
|
@@ -44,21 +45,21 @@ Gem::Specification.new do |s|
|
|
44
45
|
s.specification_version = 3
|
45
46
|
|
46
47
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
47
|
-
s.add_runtime_dependency(%q<ruote>, [">= 2.1.
|
48
|
-
s.add_runtime_dependency(%q<redis>, [">= 2.0.
|
48
|
+
s.add_runtime_dependency(%q<ruote>, [">= 2.1.11"])
|
49
|
+
s.add_runtime_dependency(%q<redis>, [">= 2.0.5"])
|
49
50
|
s.add_development_dependency(%q<yard>, [">= 0"])
|
50
51
|
s.add_development_dependency(%q<rake>, [">= 0"])
|
51
52
|
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
52
53
|
else
|
53
|
-
s.add_dependency(%q<ruote>, [">= 2.1.
|
54
|
-
s.add_dependency(%q<redis>, [">= 2.0.
|
54
|
+
s.add_dependency(%q<ruote>, [">= 2.1.11"])
|
55
|
+
s.add_dependency(%q<redis>, [">= 2.0.5"])
|
55
56
|
s.add_dependency(%q<yard>, [">= 0"])
|
56
57
|
s.add_dependency(%q<rake>, [">= 0"])
|
57
58
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
58
59
|
end
|
59
60
|
else
|
60
|
-
s.add_dependency(%q<ruote>, [">= 2.1.
|
61
|
-
s.add_dependency(%q<redis>, [">= 2.0.
|
61
|
+
s.add_dependency(%q<ruote>, [">= 2.1.11"])
|
62
|
+
s.add_dependency(%q<redis>, [">= 2.0.5"])
|
62
63
|
s.add_dependency(%q<yard>, [">= 0"])
|
63
64
|
s.add_dependency(%q<rake>, [">= 0"])
|
64
65
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 2
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 2.1.
|
8
|
+
- 11
|
9
|
+
version: 2.1.11
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- John Mettraux
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-10-01 00:00:00 +09:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -27,8 +27,8 @@ dependencies:
|
|
27
27
|
segments:
|
28
28
|
- 2
|
29
29
|
- 1
|
30
|
-
-
|
31
|
-
version: 2.1.
|
30
|
+
- 11
|
31
|
+
version: 2.1.11
|
32
32
|
type: :runtime
|
33
33
|
version_requirements: *id001
|
34
34
|
- !ruby/object:Gem::Dependency
|
@@ -41,8 +41,8 @@ dependencies:
|
|
41
41
|
segments:
|
42
42
|
- 2
|
43
43
|
- 0
|
44
|
-
-
|
45
|
-
version: 2.0.
|
44
|
+
- 5
|
45
|
+
version: 2.0.5
|
46
46
|
type: :runtime
|
47
47
|
version_requirements: *id002
|
48
48
|
- !ruby/object:Gem::Dependency
|
@@ -92,6 +92,7 @@ extra_rdoc_files:
|
|
92
92
|
- README.rdoc
|
93
93
|
files:
|
94
94
|
- CHANGELOG.txt
|
95
|
+
- CREDITS.txt
|
95
96
|
- LICENSE.txt
|
96
97
|
- README.rdoc
|
97
98
|
- Rakefile
|