rewritten 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +4 -0
  3. data/README.rdoc +93 -0
  4. data/Rakefile +28 -0
  5. data/bin/rewritten-web.rb +25 -0
  6. data/config.ru +4 -0
  7. data/lib/rack/dummy.rb +22 -0
  8. data/lib/rack/html.rb +44 -0
  9. data/lib/rack/record.rb +30 -0
  10. data/lib/rack/url.rb +47 -0
  11. data/lib/rewritten/config.ru +4 -0
  12. data/lib/rewritten/helpers.rb +58 -0
  13. data/lib/rewritten/server/public/favicon.ico +0 -0
  14. data/lib/rewritten/server/public/idle.png +0 -0
  15. data/lib/rewritten/server/public/jquery-1.3.2.min.js +19 -0
  16. data/lib/rewritten/server/public/jquery.relatize_date.js +95 -0
  17. data/lib/rewritten/server/public/poll.png +0 -0
  18. data/lib/rewritten/server/public/ranger.js +73 -0
  19. data/lib/rewritten/server/public/reset.css +48 -0
  20. data/lib/rewritten/server/public/style.css +85 -0
  21. data/lib/rewritten/server/public/working.png +0 -0
  22. data/lib/rewritten/server/test_helper.rb +19 -0
  23. data/lib/rewritten/server/views/clear_hits.erb +10 -0
  24. data/lib/rewritten/server/views/delete.erb +16 -0
  25. data/lib/rewritten/server/views/error.erb +1 -0
  26. data/lib/rewritten/server/views/failed.erb +64 -0
  27. data/lib/rewritten/server/views/hits.erb +30 -0
  28. data/lib/rewritten/server/views/key_sets.erb +19 -0
  29. data/lib/rewritten/server/views/key_string.erb +11 -0
  30. data/lib/rewritten/server/views/layout.erb +44 -0
  31. data/lib/rewritten/server/views/mappings.erb +61 -0
  32. data/lib/rewritten/server/views/new.erb +16 -0
  33. data/lib/rewritten/server/views/next_more.erb +11 -0
  34. data/lib/rewritten/server/views/overview.erb +8 -0
  35. data/lib/rewritten/server/views/queues.erb +49 -0
  36. data/lib/rewritten/server/views/stats.erb +62 -0
  37. data/lib/rewritten/server/views/to.erb +22 -0
  38. data/lib/rewritten/server/views/workers.erb +109 -0
  39. data/lib/rewritten/server/views/working.erb +72 -0
  40. data/lib/rewritten/server.rb +209 -0
  41. data/lib/rewritten/version.rb +3 -0
  42. data/lib/rewritten.rb +403 -0
  43. data/lib/test.ru +17 -0
  44. data/rewritten.gemspec +40 -0
  45. data/test/test_rewritten.rb +6 -0
  46. metadata +174 -0
data/lib/rewritten.rb ADDED
@@ -0,0 +1,403 @@
1
+ require 'redis/namespace'
2
+ require 'rewritten/version'
3
+ require 'rewritten/helpers'
4
+ require 'rack/dummy'
5
+ require 'rack/url'
6
+ require 'rack/record'
7
+ require 'rack/html'
8
+
9
+ module Rewritten
10
+ include Helpers
11
+ extend self
12
+
13
+ # Accepts:
14
+ # 1. A 'hostname:port' String
15
+ # 2. A 'hostname:port:db' String (to select the Redis db)
16
+ # 3. A 'hostname:port/namespace' String (to set the Redis namespace)
17
+ # 4. A Redis URL String 'redis://host:port'
18
+ # 5. An instance of `Redis`, `Redis::Client`, `Redis::DistRedis`,
19
+ # or `Redis::Namespace`.
20
+ def redis=(server)
21
+ case server
22
+ when String
23
+ if server =~ /redis\:\/\//
24
+ redis = Redis.connect(:url => server, :thread_safe => true)
25
+ else
26
+ server, namespace = server.split('/', 2)
27
+ host, port, db = server.split(':')
28
+ redis = Redis.new(:host => host, :port => port,
29
+ :thread_safe => true, :db => db)
30
+ end
31
+ namespace ||= :rewritten
32
+
33
+ @redis = Redis::Namespace.new(namespace, :redis => redis)
34
+ when Redis::Namespace
35
+ @redis = server
36
+ else
37
+ @redis = Redis::Namespace.new(:rewritten, :redis => server)
38
+ end
39
+ end
40
+
41
+ # Returns the current Redis connection. If none has been created, will
42
+ # create a new one.
43
+ def redis
44
+ return @redis if @redis
45
+ self.redis = Redis.respond_to?(:connect) ? Redis.connect : "localhost:6379"
46
+ self.redis
47
+ end
48
+
49
+ def redis_id
50
+ # support 1.x versions of redis-rb
51
+ if redis.respond_to?(:server)
52
+ redis.server
53
+ elsif redis.respond_to?(:nodes) # distributed
54
+ redis.nodes.map { |n| n.id }.join(', ')
55
+ else
56
+ redis.client.id
57
+ end
58
+ end
59
+
60
+ # The `before_first_fork` hook will be run in the **parent** process
61
+ # only once, before forking to run the first job. Be careful- any
62
+ # changes you make will be permanent for the lifespan of the
63
+ # worker.
64
+ #
65
+ # Call with a block to set the hook.
66
+ # Call with no arguments to return the hook.
67
+ def before_first_fork(&block)
68
+ block ? (@before_first_fork = block) : @before_first_fork
69
+ end
70
+
71
+ # Set a proc that will be called in the parent process before the
72
+ # worker forks for the first time.
73
+ def before_first_fork=(before_first_fork)
74
+ @before_first_fork = before_first_fork
75
+ end
76
+
77
+ # The `before_fork` hook will be run in the **parent** process
78
+ # before every job, so be careful- any changes you make will be
79
+ # permanent for the lifespan of the worker.
80
+ #
81
+ # Call with a block to set the hook.
82
+ # Call with no arguments to return the hook.
83
+ def before_fork(&block)
84
+ block ? (@before_fork = block) : @before_fork
85
+ end
86
+
87
+ # Set the before_fork proc.
88
+ def before_fork=(before_fork)
89
+ @before_fork = before_fork
90
+ end
91
+
92
+ # The `after_fork` hook will be run in the child process and is passed
93
+ # the current job. Any changes you make, therefore, will only live as
94
+ # long as the job currently being processed.
95
+ #
96
+ # Call with a block to set the hook.
97
+ # Call with no arguments to return the hook.
98
+ def after_fork(&block)
99
+ block ? (@after_fork = block) : @after_fork
100
+ end
101
+
102
+ # Set the after_fork proc.
103
+ def after_fork=(after_fork)
104
+ @after_fork = after_fork
105
+ end
106
+
107
+ def to_s
108
+ "Rewritten Client connected to #{redis_id}"
109
+ end
110
+
111
+ # If 'inline' is true Resque will call #perform method inline
112
+ # without queuing it into Redis and without any Resque callbacks.
113
+ # The 'inline' is false Resque jobs will be put in queue regularly.
114
+ def inline?
115
+ @inline
116
+ end
117
+ alias_method :inline, :inline?
118
+
119
+ def inline=(inline)
120
+ @inline = inline
121
+ end
122
+
123
+ #
124
+ # translations
125
+ #
126
+
127
+ def add_translation(from, to)
128
+ redis.set("from:#{from}", to)
129
+ redis.lpush(:froms, from)
130
+ redis.lpush(:tos, to)
131
+ redis.rpush("to:#{to}", from)
132
+ end
133
+
134
+ def num_translations(to)
135
+ Rewritten.size("to:#{to}")
136
+ end
137
+
138
+ def remove_translation(from, to)
139
+ Rewritten.redis.del("from:#{from}")
140
+ Rewritten.redis.lrem("froms", 0, from)
141
+ Rewritten.redis.lrem("to:#{to}", 0, from)
142
+ Rewritten.redis.lrem("tos", 0, to) if num_translations(to) == 0
143
+ end
144
+
145
+ def get_current_translation(path)
146
+ translation = Rewritten.list_range("to:#{path}", -1, 1)
147
+ return translation if translation
148
+ return path
149
+ end
150
+
151
+
152
+
153
+ def add_hit(path, code, content_type)
154
+ h = {:path => path, :code => code, :content_type => content_type}
155
+ Rewritten.redis.sadd("hits", encode(h) )
156
+ end
157
+
158
+ def all_hits
159
+ Rewritten.redis.smembers("hits").map{|e| decode(e)}
160
+ end
161
+
162
+ def include?(path)
163
+ Rewritten.redis.get("from:#{path}")
164
+ end
165
+
166
+ #
167
+ # queue manipulation
168
+ #
169
+
170
+ # Pushes a job onto a queue. Queue name should be a string and the
171
+ # item should be any JSON-able Ruby object.
172
+ #
173
+ # Resque works generally expect the `item` to be a hash with the following
174
+ # keys:
175
+ #
176
+ # class - The String name of the job to run.
177
+ # args - An Array of arguments to pass the job. Usually passed
178
+ # via `class.to_class.perform(*args)`.
179
+ #
180
+ # Example
181
+ #
182
+ # Resque.push('archive', :class => 'Archive', :args => [ 35, 'tar' ])
183
+ #
184
+ # Returns nothing
185
+ def push(queue, item)
186
+ watch_queue(queue)
187
+ redis.rpush "queue:#{queue}", encode(item)
188
+ end
189
+
190
+ # Pops a job off a queue. Queue name should be a string.
191
+ #
192
+ # Returns a Ruby object.
193
+ def pop(queue)
194
+ decode redis.lpop("queue:#{queue}")
195
+ end
196
+
197
+ # Returns an integer representing the size of translations for a target.
198
+ # Target name should be a string.
199
+ def size(target)
200
+ #redis.llen("target:#{target}").to_i
201
+ redis.llen(target).to_i
202
+ end
203
+
204
+ # Returns an array of items currently queued. Queue name should be
205
+ # a string.
206
+ #
207
+ # start and count should be integer and can be used for pagination.
208
+ # start is the item to begin, count is how many items to return.
209
+ #
210
+ # To get the 3rd page of a 30 item, paginatied list one would use:
211
+ # Resque.peek('my_list', 59, 30)
212
+ def peek(queue, start = 0, count = 1)
213
+ list_range("queue:#{queue}", start, count)
214
+ end
215
+
216
+ # Does the dirty work of fetching a range of items from a Redis list
217
+ # and converting them into Ruby objects.
218
+ def list_range(key, start = 0, count = 1)
219
+ if count == 1
220
+ #decode redis.lindex(key, start)
221
+ redis.lindex(key, start)
222
+ else
223
+ Array(redis.lrange(key, start, start+count-1)).map do |item|
224
+ #decode item
225
+ item
226
+ end
227
+ end
228
+ end
229
+
230
+ # Returns an array of all known Resque queues as strings.
231
+ def queues
232
+ Array(redis.smembers(:queues))
233
+ end
234
+
235
+ # Returns an array of all known URL targets.
236
+ def targets
237
+ Array(redis.smembers(:targets))
238
+ end
239
+
240
+ # Returns an array of all known source URLs (that are to translated)
241
+ def froms
242
+ Array(redis.smembers(:froms))
243
+ end
244
+
245
+
246
+
247
+ # Given a queue name, completely deletes the queue.
248
+ def remove_queue(queue)
249
+ redis.srem(:queues, queue.to_s)
250
+ redis.del("queue:#{queue}")
251
+ end
252
+
253
+ # Used internally to keep track of which queues we've created.
254
+ # Don't call this directly.
255
+ def watch_queue(queue)
256
+ redis.sadd(:queues, queue.to_s)
257
+ end
258
+
259
+
260
+ #
261
+ # job shortcuts
262
+ #
263
+
264
+ # This method can be used to conveniently add a job to a queue.
265
+ # It assumes the class you're passing it is a real Ruby class (not
266
+ # a string or reference) which either:
267
+ #
268
+ # a) has a @queue ivar set
269
+ # b) responds to `queue`
270
+ #
271
+ # If either of those conditions are met, it will use the value obtained
272
+ # from performing one of the above operations to determine the queue.
273
+ #
274
+ # If no queue can be inferred this method will raise a `Resque::NoQueueError`
275
+ #
276
+ # This method is considered part of the `stable` API.
277
+ def enqueue(klass, *args)
278
+ Job.create(queue_from_class(klass), klass, *args)
279
+
280
+ Plugin.after_enqueue_hooks(klass).each do |hook|
281
+ klass.send(hook, *args)
282
+ end
283
+ end
284
+
285
+ # This method can be used to conveniently remove a job from a queue.
286
+ # It assumes the class you're passing it is a real Ruby class (not
287
+ # a string or reference) which either:
288
+ #
289
+ # a) has a @queue ivar set
290
+ # b) responds to `queue`
291
+ #
292
+ # If either of those conditions are met, it will use the value obtained
293
+ # from performing one of the above operations to determine the queue.
294
+ #
295
+ # If no queue can be inferred this method will raise a `Resque::NoQueueError`
296
+ #
297
+ # If no args are given, this method will dequeue *all* jobs matching
298
+ # the provided class. See `Resque::Job.destroy` for more
299
+ # information.
300
+ #
301
+ # Returns the number of jobs destroyed.
302
+ #
303
+ # Example:
304
+ #
305
+ # # Removes all jobs of class `UpdateNetworkGraph`
306
+ # Resque.dequeue(GitHub::Jobs::UpdateNetworkGraph)
307
+ #
308
+ # # Removes all jobs of class `UpdateNetworkGraph` with matching args.
309
+ # Resque.dequeue(GitHub::Jobs::UpdateNetworkGraph, 'repo:135325')
310
+ #
311
+ # This method is considered part of the `stable` API.
312
+ def dequeue(klass, *args)
313
+ Job.destroy(queue_from_class(klass), klass, *args)
314
+ end
315
+
316
+ # Given a class, try to extrapolate an appropriate queue based on a
317
+ # class instance variable or `queue` method.
318
+ def queue_from_class(klass)
319
+ klass.instance_variable_get(:@queue) ||
320
+ (klass.respond_to?(:queue) and klass.queue)
321
+ end
322
+
323
+ # This method will return a `Resque::Job` object or a non-true value
324
+ # depending on whether a job can be obtained. You should pass it the
325
+ # precise name of a queue: case matters.
326
+ #
327
+ # This method is considered part of the `stable` API.
328
+ def reserve(queue)
329
+ Job.reserve(queue)
330
+ end
331
+
332
+ # Validates if the given klass could be a valid Resque job
333
+ #
334
+ # If no queue can be inferred this method will raise a `Resque::NoQueueError`
335
+ #
336
+ # If given klass is nil this method will raise a `Resque::NoClassError`
337
+ def validate(klass, queue = nil)
338
+ queue ||= queue_from_class(klass)
339
+
340
+ if !queue
341
+ raise NoQueueError.new("Jobs must be placed onto a queue.")
342
+ end
343
+
344
+ if klass.to_s.empty?
345
+ raise NoClassError.new("Jobs must be given a class.")
346
+ end
347
+ end
348
+
349
+
350
+ #
351
+ # worker shortcuts
352
+ #
353
+
354
+ # A shortcut to Worker.all
355
+ def workers
356
+ Worker.all
357
+ end
358
+
359
+ # A shortcut to Worker.working
360
+ def working
361
+ Worker.working
362
+ end
363
+
364
+ # A shortcut to unregister_worker
365
+ # useful for command line tool
366
+ def remove_worker(worker_id)
367
+ worker = Resque::Worker.find(worker_id)
368
+ worker.unregister_worker
369
+ end
370
+
371
+ #
372
+ # stats
373
+ #
374
+
375
+ # Returns a hash, similar to redis-rb's #info, of interesting stats.
376
+ def info
377
+ return {
378
+ :pending => queues.inject(0) { |m,k| m + size(k) },
379
+ #:processed => Stat[:processed],
380
+ #:queues => queues.size,
381
+ #:workers => workers.size.to_i,
382
+ #:working => working.size,
383
+ #:failed => Stat[:failed],
384
+ :servers => [redis_id],
385
+ :environment => ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
386
+ }
387
+ end
388
+
389
+ # Returns an array of all known Resque keys in Redis. Redis' KEYS operation
390
+ # is O(N) for the keyspace, so be careful - this can be slow for big databases.
391
+ def keys
392
+ redis.keys("*").map do |key|
393
+ key.sub("#{redis.namespace}:", '')
394
+ end
395
+ end
396
+
397
+ def per_page
398
+ 20
399
+ end
400
+
401
+
402
+ end
403
+
data/lib/test.ru ADDED
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require 'rack'
3
+ require 'rewritten'
4
+ require 'rewritten/server'
5
+
6
+ map "/" do
7
+ use Rack::Rewritten::Record
8
+ use Rack::Rewritten::Url
9
+ use Rack::Rewritten::Html
10
+ run Rack::Dummy.new
11
+ end
12
+
13
+ map "/rewritten" do
14
+ run Rewritten::Server
15
+ end
16
+
17
+
data/rewritten.gemspec ADDED
@@ -0,0 +1,40 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rewritten/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rewritten"
7
+ s.version = Rewritten::VERSION
8
+ s.authors = ["Kai Rubarth"]
9
+ s.email = ["kai@doxter.de"]
10
+ s.homepage = ""
11
+ s.summary = %q{Rack app that rewrites URLs -- nicely and uncomplicated}
12
+
13
+ s.rubyforge_project = "rewritten"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_dependency "redis-namespace", "~> 1.0.2"
21
+ s.add_dependency "vegas", "~> 0.1.2"
22
+ s.add_dependency "sinatra", ">= 0.9.2"
23
+ s.add_dependency "multi_json", "~> 1.0"
24
+
25
+ s.description = <<description
26
+ Rewritten is a simple Redis-backed Ruby library that facilitates creating and refactoring
27
+ arbitrary urls in your Rack applications.
28
+
29
+ Rewritten is inspired by the awesome Resque and Rack::Rewrite gems. It is
30
+ compromised of four parts:
31
+
32
+ * A Ruby library for creating and modifying URLs for resources
33
+ * A Rack app that takes care of redirecting old URLS in a SEO friendly matter
34
+ * A Rack app that rewrites links to their nice counterpart
35
+ * A Sinatra app for managing URLs
36
+ description
37
+
38
+ end
39
+
40
+
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+ require 'rack'
3
+ require "../lib/rack/dummy"
4
+
5
+ run Rack::Dummy.new
6
+
metadata ADDED
@@ -0,0 +1,174 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rewritten
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Kai Rubarth
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-08-26 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: redis-namespace
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 19
30
+ segments:
31
+ - 1
32
+ - 0
33
+ - 2
34
+ version: 1.0.2
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: vegas
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ hash: 31
46
+ segments:
47
+ - 0
48
+ - 1
49
+ - 2
50
+ version: 0.1.2
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: sinatra
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 63
62
+ segments:
63
+ - 0
64
+ - 9
65
+ - 2
66
+ version: 0.9.2
67
+ type: :runtime
68
+ version_requirements: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ name: multi_json
71
+ prerelease: false
72
+ requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ hash: 15
78
+ segments:
79
+ - 1
80
+ - 0
81
+ version: "1.0"
82
+ type: :runtime
83
+ version_requirements: *id004
84
+ description: " Rewritten is a simple Redis-backed Ruby library that facilitates creating and refactoring \n arbitrary urls in your Rack applications.\n\n Rewritten is inspired by the awesome Resque and Rack::Rewrite gems. It is\n compromised of four parts:\n\n * A Ruby library for creating and modifying URLs for resources \n * A Rack app that takes care of redirecting old URLS in a SEO friendly matter\n * A Rack app that rewrites links to their nice counterpart \n * A Sinatra app for managing URLs \n"
85
+ email:
86
+ - kai@doxter.de
87
+ executables:
88
+ - rewritten-web.rb
89
+ extensions: []
90
+
91
+ extra_rdoc_files: []
92
+
93
+ files:
94
+ - .gitignore
95
+ - Gemfile
96
+ - README.rdoc
97
+ - Rakefile
98
+ - bin/rewritten-web.rb
99
+ - config.ru
100
+ - lib/rack/dummy.rb
101
+ - lib/rack/html.rb
102
+ - lib/rack/record.rb
103
+ - lib/rack/url.rb
104
+ - lib/rewritten.rb
105
+ - lib/rewritten/config.ru
106
+ - lib/rewritten/helpers.rb
107
+ - lib/rewritten/server.rb
108
+ - lib/rewritten/server/public/favicon.ico
109
+ - lib/rewritten/server/public/idle.png
110
+ - lib/rewritten/server/public/jquery-1.3.2.min.js
111
+ - lib/rewritten/server/public/jquery.relatize_date.js
112
+ - lib/rewritten/server/public/poll.png
113
+ - lib/rewritten/server/public/ranger.js
114
+ - lib/rewritten/server/public/reset.css
115
+ - lib/rewritten/server/public/style.css
116
+ - lib/rewritten/server/public/working.png
117
+ - lib/rewritten/server/test_helper.rb
118
+ - lib/rewritten/server/views/clear_hits.erb
119
+ - lib/rewritten/server/views/delete.erb
120
+ - lib/rewritten/server/views/error.erb
121
+ - lib/rewritten/server/views/failed.erb
122
+ - lib/rewritten/server/views/hits.erb
123
+ - lib/rewritten/server/views/key_sets.erb
124
+ - lib/rewritten/server/views/key_string.erb
125
+ - lib/rewritten/server/views/layout.erb
126
+ - lib/rewritten/server/views/mappings.erb
127
+ - lib/rewritten/server/views/new.erb
128
+ - lib/rewritten/server/views/next_more.erb
129
+ - lib/rewritten/server/views/overview.erb
130
+ - lib/rewritten/server/views/queues.erb
131
+ - lib/rewritten/server/views/stats.erb
132
+ - lib/rewritten/server/views/to.erb
133
+ - lib/rewritten/server/views/workers.erb
134
+ - lib/rewritten/server/views/working.erb
135
+ - lib/rewritten/version.rb
136
+ - lib/test.ru
137
+ - rewritten.gemspec
138
+ - test/test_rewritten.rb
139
+ has_rdoc: true
140
+ homepage: ""
141
+ licenses: []
142
+
143
+ post_install_message:
144
+ rdoc_options: []
145
+
146
+ require_paths:
147
+ - lib
148
+ required_ruby_version: !ruby/object:Gem::Requirement
149
+ none: false
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ hash: 3
154
+ segments:
155
+ - 0
156
+ version: "0"
157
+ required_rubygems_version: !ruby/object:Gem::Requirement
158
+ none: false
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ hash: 3
163
+ segments:
164
+ - 0
165
+ version: "0"
166
+ requirements: []
167
+
168
+ rubyforge_project: rewritten
169
+ rubygems_version: 1.6.2
170
+ signing_key:
171
+ specification_version: 3
172
+ summary: Rack app that rewrites URLs -- nicely and uncomplicated
173
+ test_files: []
174
+