http_router 0.7.10 → 0.8.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/README.md CHANGED
@@ -6,6 +6,7 @@ This is an HTTP router for use in either a web framework, or on it's own using R
6
6
 
7
7
  ## Features
8
8
 
9
+ * Ordered route resolution.
9
10
  * Supports variables, and globbing, both named and unnamed.
10
11
  * Regex support for variables.
11
12
  * Request condition support.
data/benchmarks/rec2.rb CHANGED
@@ -15,6 +15,8 @@ u.add('/dynamic/:variable').to {|env| [200, {'Content-type'=>'text/html'}, []]}
15
15
  #u.add('/greedy/:greed').matching(:greed => /.*/).compile.to {|env| [200, {'Content-type'=>'text/html'}, []]}
16
16
  #u.add('/greedy/hey.:greed.html').to {|env| [200, {'Content-type'=>'text/html'}, []]}
17
17
 
18
+ u.compile rescue nil
19
+
18
20
  puts Benchmark.measure {
19
21
  ('aa'..'nn').each do |first|
20
22
  ('a'..'n').each do |second|
@@ -34,7 +36,7 @@ TIMES = 50_000
34
36
  #simple_and_dynamic_env1 = Rack::MockRequest.env_for('/rails/controller/action/id')
35
37
  #simple_and_dynamic_env2 = Rack::MockRequest.env_for('/greedy/controller/action/id')
36
38
  #simple_and_dynamic_env3 = Rack::MockRequest.env_for('/greedy/hey.hello.html')
37
- #5.times {
39
+ 5.times {
38
40
  RBench.run(TIMES) do
39
41
 
40
42
  report "2 levels, static" do
@@ -62,5 +64,5 @@ TIMES = 50_000
62
64
  #end
63
65
 
64
66
  end
65
- #}
67
+ }
66
68
  puts `ps -o rss= -p #{Process.pid}`.to_i
data/lib/http_router.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  require 'set'
2
2
  require 'rack'
3
+ require 'uri'
4
+ require 'cgi'
5
+ require 'url_mount'
3
6
  require 'http_router/node'
4
7
  require 'http_router/request'
5
8
  require 'http_router/response'
@@ -11,7 +14,7 @@ require 'http_router/optional_compiler'
11
14
 
12
15
  class HttpRouter
13
16
 
14
- attr_reader :root, :routes, :known_methods, :named_routes
17
+ attr_reader :root, :routes, :known_methods, :named_routes, :nodes
15
18
  attr_accessor :default_app, :url_mount
16
19
 
17
20
  # Raised when a Route is not able to be generated.
@@ -36,6 +39,7 @@ class HttpRouter
36
39
  @ignore_trailing_slash = options && options.key?(:ignore_trailing_slash) ? options[:ignore_trailing_slash] : true
37
40
  @redirect_trailing_slash = options && options.key?(:redirect_trailing_slash) ? options[:redirect_trailing_slash] : false
38
41
  @known_methods = Set.new(options && options[:known_methods] || [])
42
+ @nodes = []
39
43
  reset!
40
44
  instance_eval(&blk) if blk
41
45
  end
@@ -143,6 +147,15 @@ class HttpRouter
143
147
  @default_app = app
144
148
  end
145
149
 
150
+ def register_node(n)
151
+ @nodes << n
152
+ @nodes.size - 1
153
+ end
154
+
155
+ def [](pos)
156
+ @nodes.at(pos)
157
+ end
158
+
146
159
  # Generate a URL for a specified route. This will accept a list of variable values plus any other variable names named as a hash.
147
160
  # This first value must be either the Route object or the name of the route.
148
161
  #
@@ -191,6 +204,10 @@ class HttpRouter
191
204
  cloned_router
192
205
  end
193
206
 
207
+ def compile
208
+ @root.compile
209
+ end
210
+
194
211
  private
195
212
  def no_response(env, perform_call = true)
196
213
  supported_methods = (@known_methods - [env['REQUEST_METHOD']]).select do |m|
@@ -11,16 +11,12 @@ class HttpRouter
11
11
  autoload :Lookup, 'http_router/node/lookup'
12
12
  autoload :Destination, 'http_router/node/destination'
13
13
 
14
- attr_reader :priority, :router
14
+ attr_reader :priority, :router, :node_position
15
15
 
16
16
  def initialize(router, matchers = [])
17
17
  @router, @matchers = router, matchers
18
18
  end
19
19
 
20
- def [](request)
21
- @matchers.each {|m| m[request] }; nil
22
- end
23
-
24
20
  def add_variable
25
21
  add(Variable.new(@router))
26
22
  end
@@ -61,15 +57,37 @@ class HttpRouter
61
57
  false
62
58
  end
63
59
 
60
+ def method_missing(m, *args, &blk)
61
+ if m.to_s == '[]'
62
+ compile
63
+ send(:[], *args)
64
+ else
65
+ super
66
+ end
67
+ end
68
+
69
+ def compile
70
+ instance_eval "def [](r0)\n#{to_code(0)}\nnil\nend", __FILE__, __LINE__
71
+ end
72
+
64
73
  private
65
74
  def add(matcher)
66
75
  @matchers << matcher unless matcher.usable?(@matchers.last)
67
76
  @matchers.last
68
77
  end
69
78
 
70
- def unescape(val)
71
- val.to_s.gsub!(/((?:%[0-9a-fA-F]{2})+)/n){ [$1.delete('%')].pack('H*') }
72
- val
79
+ def to_code(pos)
80
+ @matchers.map{ |m| m.to_code(pos) }.join("\n") << "\n"
81
+ end
82
+
83
+ def indented_code(pos, code)
84
+ lines = code.
85
+ strip.
86
+ split(/\n/).
87
+ select{|l| !l.strip.size.zero?}
88
+ indent_size = lines.first[/ */].size
89
+ lines.map! {|l| "#{' ' * pos.next}#{l[indent_size, l.size]}"}
90
+ "\n" << lines.join("\n") << "\n"
73
91
  end
74
92
  end
75
93
  end
@@ -1,26 +1,30 @@
1
1
  class HttpRouter
2
2
  class Node
3
3
  class Arbitrary < Node
4
- alias_method :node_lookup, :[]
5
4
  attr_reader :allow_partial, :blk, :param_names
6
5
 
7
6
  def initialize(router, allow_partial, blk, param_names)
8
7
  @allow_partial, @blk, @param_names = allow_partial, blk, param_names
8
+ @node_position = router.register_node(blk)
9
9
  super(router)
10
10
  end
11
11
 
12
- def [](request)
13
- if request.path.empty? or (request.path.size == 1 and request.path[0] == '') or @allow_partial
14
- request = request.clone
15
- request.continue = proc { |state| node_lookup(request) if state }
16
- params = @param_names.nil? ? {} : Hash[@param_names.zip(request.params)]
17
- @blk.call(request, params)
18
- end
19
- end
20
-
21
12
  def usuable?(other)
22
13
  other.class == self.class && other.allow_partial == allow_partial && other.blk == blk && other.param_names == param_names
23
14
  end
15
+
16
+ def to_code(pos)
17
+ indented_code pos, "
18
+ #{"if r#{pos}.path_finished?" unless @allow_partial}
19
+ r#{pos.next} = r#{pos}.dup
20
+ r#{pos.next}.continue = proc { |state|
21
+ if state
22
+ #{super(pos.next)}
23
+ end
24
+ }
25
+ router.nodes.at(#{node_position})[r#{pos.next}, #{@param_names.nil? || @param_names.empty? ? '{}' : "Hash[#{@param_names.inspect}.zip(r#{pos.next}.params)]"}]
26
+ #{"end" unless @allow_partial}"
27
+ end
24
28
  end
25
29
  end
26
30
  end
@@ -1,25 +1,26 @@
1
1
  class HttpRouter
2
2
  class Node
3
3
  class Destination < Node
4
+ attr_reader :blk, :allow_partial, :param_names
5
+
4
6
  def initialize(router, blk, allow_partial)
5
7
  @blk, @allow_partial = blk, allow_partial
8
+ @node_position = router.register_node(blk)
6
9
  super(router)
7
10
  end
8
11
 
9
- def [](request)
10
- if request.path.empty? or (request.path.size == 1 and request.path[0] == '') or @allow_partial
11
- request.passed_with = catch(:pass) do
12
- request = request.clone
13
- request.continue = proc { |state| destination(request) if state }
14
- params = @param_names.nil? ? {} : Hash[@param_names.zip(request.params)]
15
- @blk.call(request, params)
16
- end
17
- end
18
- end
19
-
20
12
  def usuable?(other)
21
13
  other.class == self.class && other.allow_partial == allow_partial && other.blk == blk
22
14
  end
15
+
16
+ def to_code(pos)
17
+ indented_code pos, "
18
+ #{"if r#{pos}.path_finished?" unless @allow_partial}
19
+ r0.passed_with = catch(:pass) do
20
+ router.nodes.at(#{node_position})[r#{pos}, #{@param_names.nil? || @param_names.empty? ? 'nil' : "Hash[#{@param_names.inspect}.zip(r#{pos.next}.params)]"}]
21
+ end
22
+ #{"end" unless @allow_partial}"
23
+ end
23
24
  end
24
25
  end
25
26
  end
@@ -7,15 +7,17 @@ class HttpRouter
7
7
  super(router)
8
8
  end
9
9
 
10
- def [](request)
11
- whole_path = "/#{request.joined_path}"
12
- if match = @matcher.match(whole_path) and match[0].size == whole_path.size
13
- request = request.clone
14
- request.extra_env['router.regex_match'] = match
15
- request.path = ['']
16
- match.names.size.times{|i| request.params << match[i + 1]} if match.respond_to?(:names) && match.names
17
- super
18
- end
10
+ def to_code(pos)
11
+ indented_code pos, "
12
+ whole_path = \"/\#{r#{pos}.joined_path}\"
13
+ if match = #{matcher.inspect}.match(whole_path) and match[0].size == whole_path.size
14
+ r#{pos.next} = r#{pos}.dup
15
+ r#{pos.next}.extra_env['router.regex_match'] = match
16
+ r#{pos.next}.path = ['']
17
+ " << (//.respond_to?(:names) ?
18
+ "match.names.size.times{|i| r#{pos.next}.params << match[i + 1]} if match.respond_to?(:names) && match.names" : "") << "
19
+ #{super(pos.next)}
20
+ end"
19
21
  end
20
22
 
21
23
  def usuable?(other)
@@ -1,20 +1,21 @@
1
1
  class HttpRouter
2
2
  class Node
3
3
  class Glob < Node
4
- def [](request)
5
- request = request.clone
6
- request.params << []
7
- remaining_parts = request.path.dup
8
- until remaining_parts.empty?
9
- request.params[-1] << unescape(remaining_parts.shift)
10
- request.path = remaining_parts
11
- super(request)
12
- end
13
- end
14
-
15
4
  def usuable?(other)
16
5
  other.class == self.class
17
6
  end
7
+
8
+ def to_code(pos)
9
+ indented_code pos, "
10
+ r#{pos.next} = r#{pos}.dup
11
+ r#{pos.next}.params << []
12
+ remaining_parts = r#{pos.next}.path.dup
13
+ until remaining_parts.empty?
14
+ r#{pos.next}.params[-1] << URI.unescape(remaining_parts.shift)
15
+ r#{pos.next}.path = remaining_parts
16
+ #{super(pos.next)}
17
+ end"
18
+ end
18
19
  end
19
20
  end
20
21
  end
@@ -1,8 +1,17 @@
1
1
  class HttpRouter
2
2
  class Node
3
3
  class GlobRegex < SpanningRegex
4
- def add_params(request)
5
- @capturing_indicies.each { |idx| request.params << unescape(match[idx].split('/')) }
4
+ def to_code(pos)
5
+ indented_code pos, "
6
+ whole_path = r#{pos}.joined_path
7
+ if match = #{@matcher.inspect}.match(whole_path) and match.begin(0).zero?
8
+ r#{pos.next} = r#{pos}.dup\n" <<
9
+ @capturing_indicies.map { |c| "r#{pos.next}.params << URI.unescape(match[#{c}].split(/\\//))\n" }.join << "
10
+ remaining_path = whole_path[match[0].size + (whole_path[match[0].size] == ?/ ? 1 : 0), whole_path.size]
11
+ r#{pos.next}.path = remaining_path.split('/')
12
+ #{super(pos.next)}
13
+ end
14
+ "
6
15
  end
7
16
  end
8
17
  end
@@ -6,13 +6,6 @@ class HttpRouter
6
6
  super(router)
7
7
  end
8
8
 
9
- def [](request)
10
- if @map[request.path.first]
11
- request = request.clone
12
- @map[request.path.shift].each{|m| m[request]}
13
- end
14
- end
15
-
16
9
  def add(part)
17
10
  Node.new(@router, @map[part] ||= [])
18
11
  end
@@ -20,6 +13,18 @@ class HttpRouter
20
13
  def usuable?(other)
21
14
  other.class == self.class
22
15
  end
16
+
17
+ def to_code(pos)
18
+ code = "case r#{pos}.path.first\n"
19
+ @map.keys.each do |k|
20
+ code << "when #{k.inspect}\n
21
+ r#{pos.next} = r#{pos}.dup
22
+ r#{pos.next}.path.shift
23
+ #{@map[k].map{|n| n.to_code(pos.next)} * "\n"}"
24
+ end
25
+ code << "\nend"
26
+ indented_code pos, code
27
+ end
23
28
  end
24
29
  end
25
30
  end
@@ -1,7 +1,7 @@
1
1
  class HttpRouter
2
2
  class Node
3
3
  class Regex < Node
4
- alias_method :node_lookup, :[]
4
+ alias_method :node_to_code, :to_code
5
5
  attr_reader :matcher, :splitting_indicies, :capturing_indicies
6
6
 
7
7
  def initialize(router, matcher, capturing_indicies, splitting_indicies = nil)
@@ -9,23 +9,20 @@ class HttpRouter
9
9
  super(router)
10
10
  end
11
11
 
12
- def [](request)
13
- if match = @matcher.match(request.path.first) and match.begin(0).zero?
14
- request = request.clone
15
- request.path.shift
16
- add_params(request, match)
17
- super(request)
18
- end
19
- end
20
-
21
- def add_params(request, match)
22
- @splitting_indicies.each { |idx| request.params << unescape(match[idx]).split(/\//) } if @splitting_indicies
23
- @capturing_indicies.each { |idx| request.params << unescape(match[idx]) }
24
- end
25
-
26
12
  def usuable?(other)
27
13
  other.class == self.class && other.matcher == matcher && other.splitting_indicies == splitting_indicies && other.capturing_indicies == capturing_indicies
28
14
  end
15
+
16
+ def to_code(pos)
17
+ indented_code pos, "
18
+ if match = #{@matcher.inspect}.match(r#{pos}.path.first) and match.begin(0).zero?
19
+ r#{pos.next} = r#{pos}.dup
20
+ r#{pos.next}.path.shift\n" <<
21
+ @splitting_indicies.map { |s| "r#{pos.next}.params << URI.unescape(match[#{s}]).split(/\\//)\n" }.join <<
22
+ @capturing_indicies.map { |c| "r#{pos.next}.params << URI.unescape(match[#{c}])\n" }.join << "
23
+ #{super(pos.next)}
24
+ end"
25
+ end
29
26
  end
30
27
  end
31
28
  end
@@ -9,20 +9,21 @@ class HttpRouter
9
9
  super(router)
10
10
  end
11
11
 
12
- def [](request)
13
- @opts.each{|k,v|
14
- test = request.rack_request.send(k)
15
- return unless case v
16
- when Array then v.any?{|vv| vv === test}
17
- else v === test
18
- end
19
- }
20
- super(request)
21
- end
22
-
23
12
  def usuable?(other)
24
13
  other.class == self.class && other.opts == opts
25
14
  end
15
+
16
+ def to_code(pos)
17
+ code = "if "
18
+ code << @opts.map do |k,v|
19
+ case v
20
+ when Array then "(#{v.map{|vv| "#{vv.inspect} === r#{pos}.rack_request.#{k}"}.join(' or ')})"
21
+ else "#{v.inspect} === r#{pos}.rack_request.#{k.inspect}"
22
+ end
23
+ end * ' and '
24
+ code << "\n #{super}\nend"
25
+ indented_code pos, code
26
+ end
26
27
  end
27
28
  end
28
29
  end
@@ -1,15 +1,18 @@
1
1
  class HttpRouter
2
2
  class Node
3
3
  class SpanningRegex < Regex
4
- def [](request)
5
- whole_path = request.joined_path
6
- if match = @matcher.match(whole_path) and match.begin(0).zero?
7
- request = request.clone
8
- add_params(request, match)
9
- remaining_path = whole_path[match[0].size + (whole_path[match[0].size] == ?/ ? 1 : 0), whole_path.size]
10
- request.path = remaining_path.split('/')
11
- node_lookup(request)
12
- end
4
+ def to_code(pos)
5
+ indented_code(pos, "
6
+ whole_path = r#{pos}.joined_path
7
+ if match = #{@matcher.inspect}.match(whole_path) and match.begin(0).zero?
8
+ r#{pos.next} = r#{pos}.dup\n" <<
9
+ (@splitting_indicies || []).map { |s| "r#{pos.next}.params << URI.unescape(match[#{s}]).split(/\\//)\n" }.join <<
10
+ @capturing_indicies.map { |c| "r#{pos.next}.params << URI.unescape(match[#{c}])\n" }.join << "
11
+ remaining_path = whole_path[match[0].size + (whole_path[match[0].size] == ?/ ? 1 : 0), whole_path.size]
12
+ r#{pos.next}.path = remaining_path.split('/')
13
+ #{node_to_code(pos.next)}
14
+ end
15
+ ")
13
16
  end
14
17
  end
15
18
  end
@@ -1,17 +1,18 @@
1
1
  class HttpRouter
2
2
  class Node
3
3
  class Variable < Node
4
- def [](request)
5
- unless request.path.empty?
6
- request = request.clone
7
- request.params << unescape(request.path.shift)
8
- super(request)
9
- end
10
- end
11
-
12
4
  def usuable?(other)
13
5
  other.class == self.class
14
6
  end
7
+
8
+ def to_code(pos)
9
+ indented_code(pos, "
10
+ unless r#{pos}.path_finished?
11
+ r#{pos.next} = r#{pos}.dup
12
+ r#{pos.next}.params << URI.unescape(r#{pos.next}.path.shift)
13
+ #{super(pos.next)}
14
+ end")
15
+ end
15
16
  end
16
17
  end
17
18
  end
@@ -27,12 +27,16 @@ class HttpRouter
27
27
  "request path, #{path.inspect}"
28
28
  end
29
29
 
30
- def clone
30
+ def dup
31
31
  dup_obj = super
32
32
  dup_obj.path = path.dup
33
33
  dup_obj.params = params.dup
34
34
  dup_obj.extra_env = extra_env.dup
35
35
  dup_obj
36
36
  end
37
+
38
+ def path_finished?
39
+ @path.size == 0 or @path.size == 1 && @path.first == ''
40
+ end
37
41
  end
38
42
  end
@@ -1,5 +1,3 @@
1
- require 'url_mount'
2
- require 'uri'
3
1
 
4
2
  class HttpRouter
5
3
  class Route
@@ -300,7 +298,7 @@ class HttpRouter
300
298
  when Hash
301
299
  value.each{ |k, v| append_querystring_value(uri, "#{key}[#{k}]", v) }
302
300
  else
303
- uri << '&' << ::Rack::Utils.escape(key.to_s) << '=' << ::Rack::Utils.escape(value.to_s)
301
+ uri << '&' << CGI.escape(key.to_s) << '=' << CGI.escape(value.to_s)
304
302
  end
305
303
  end
306
304
 
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  class HttpRouter #:nodoc
3
- VERSION = '0.7.10'
3
+ VERSION = '0.8.0'
4
4
  end
@@ -4,12 +4,27 @@ class TestRecognition < MiniTest::Unit::TestCase
4
4
  assert_route router.add(''), '/'
5
5
  end
6
6
 
7
- def test_simple
7
+ def test_simple1
8
8
  assert_route router.add('/'), '/'
9
+ end
10
+
11
+ def test_simple2
9
12
  assert_route router.add('/test'), '/test'
13
+ end
14
+
15
+ def test_simple3
10
16
  assert_route router.add('/test/one'), '/test/one'
17
+ end
18
+
19
+ def test_simple4
11
20
  assert_route router.add('/test/one/two'), '/test/one/two'
21
+ end
22
+
23
+ def test_simple5
12
24
  assert_route router.add('/test.html'), '/test.html'
25
+ end
26
+
27
+ def test_simple6
13
28
  assert_route router.add('/.html'), '/.html'
14
29
  end
15
30
 
data/test/test_request.rb CHANGED
@@ -6,6 +6,12 @@ class TestRequest < MiniTest::Unit::TestCase
6
6
  assert_status(405, Rack::MockRequest.env_for('/test', :method => 'GET'))
7
7
  end
8
8
 
9
+ def test_simple_case_with_array
10
+ r = router { add('test', :request => {:request_methods => ['POST', 'GET']}) }
11
+ assert_route r, Rack::MockRequest.env_for('/test', :method => 'POST')
12
+ assert_route r, Rack::MockRequest.env_for('/test', :method => 'GET')
13
+ end
14
+
9
15
  def test_single_app_with_404
10
16
  r = router { add('test').post.to{|env| [404, {}, []]} }
11
17
  assert_route nil, Rack::MockRequest.env_for('/test', :method => 'POST')
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  class TestVariable < MiniTest::Unit::TestCase
2
3
  def test_variable
3
4
  assert_route ':one', '/two', {:one => 'two'}
metadata CHANGED
@@ -1,8 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: http_router
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 63
4
5
  prerelease:
5
- version: 0.7.10
6
+ segments:
7
+ - 0
8
+ - 8
9
+ - 0
10
+ version: 0.8.0
6
11
  platform: ruby
7
12
  authors:
8
13
  - Joshua Hull
@@ -10,108 +15,147 @@ autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
17
 
13
- date: 2011-05-30 00:00:00 -07:00
18
+ date: 2011-06-01 00:00:00 -04:00
14
19
  default_executable:
15
20
  dependencies:
16
21
  - !ruby/object:Gem::Dependency
17
- name: rack
18
- prerelease: false
19
- requirement: &id001 !ruby/object:Gem::Requirement
22
+ version_requirements: &id001 !ruby/object:Gem::Requirement
20
23
  none: false
21
24
  requirements:
22
25
  - - ">="
23
26
  - !ruby/object:Gem::Version
27
+ hash: 23
28
+ segments:
29
+ - 1
30
+ - 0
31
+ - 0
24
32
  version: 1.0.0
33
+ requirement: *id001
34
+ prerelease: false
25
35
  type: :runtime
26
- version_requirements: *id001
36
+ name: rack
27
37
  - !ruby/object:Gem::Dependency
28
- name: url_mount
29
- prerelease: false
30
- requirement: &id002 !ruby/object:Gem::Requirement
38
+ version_requirements: &id002 !ruby/object:Gem::Requirement
31
39
  none: false
32
40
  requirements:
33
41
  - - ~>
34
42
  - !ruby/object:Gem::Version
43
+ hash: 21
44
+ segments:
45
+ - 0
46
+ - 2
47
+ - 1
35
48
  version: 0.2.1
49
+ requirement: *id002
50
+ prerelease: false
36
51
  type: :runtime
37
- version_requirements: *id002
52
+ name: url_mount
38
53
  - !ruby/object:Gem::Dependency
39
- name: minitest
40
- prerelease: false
41
- requirement: &id003 !ruby/object:Gem::Requirement
54
+ version_requirements: &id003 !ruby/object:Gem::Requirement
42
55
  none: false
43
56
  requirements:
44
57
  - - ~>
45
58
  - !ruby/object:Gem::Version
59
+ hash: 15
60
+ segments:
61
+ - 2
62
+ - 0
63
+ - 0
46
64
  version: 2.0.0
65
+ requirement: *id003
66
+ prerelease: false
47
67
  type: :development
48
- version_requirements: *id003
68
+ name: minitest
49
69
  - !ruby/object:Gem::Dependency
50
- name: code_stats
51
- prerelease: false
52
- requirement: &id004 !ruby/object:Gem::Requirement
70
+ version_requirements: &id004 !ruby/object:Gem::Requirement
53
71
  none: false
54
72
  requirements:
55
73
  - - ">="
56
74
  - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 0
57
78
  version: "0"
79
+ requirement: *id004
80
+ prerelease: false
58
81
  type: :development
59
- version_requirements: *id004
82
+ name: code_stats
60
83
  - !ruby/object:Gem::Dependency
61
- name: rake
62
- prerelease: false
63
- requirement: &id005 !ruby/object:Gem::Requirement
84
+ version_requirements: &id005 !ruby/object:Gem::Requirement
64
85
  none: false
65
86
  requirements:
66
87
  - - ~>
67
88
  - !ruby/object:Gem::Version
89
+ hash: 49
90
+ segments:
91
+ - 0
92
+ - 8
93
+ - 7
68
94
  version: 0.8.7
95
+ requirement: *id005
96
+ prerelease: false
69
97
  type: :development
70
- version_requirements: *id005
98
+ name: rake
71
99
  - !ruby/object:Gem::Dependency
72
- name: rbench
73
- prerelease: false
74
- requirement: &id006 !ruby/object:Gem::Requirement
100
+ version_requirements: &id006 !ruby/object:Gem::Requirement
75
101
  none: false
76
102
  requirements:
77
103
  - - ">="
78
104
  - !ruby/object:Gem::Version
105
+ hash: 3
106
+ segments:
107
+ - 0
79
108
  version: "0"
109
+ requirement: *id006
110
+ prerelease: false
80
111
  type: :development
81
- version_requirements: *id006
112
+ name: rbench
82
113
  - !ruby/object:Gem::Dependency
83
- name: phocus
84
- prerelease: false
85
- requirement: &id007 !ruby/object:Gem::Requirement
114
+ version_requirements: &id007 !ruby/object:Gem::Requirement
86
115
  none: false
87
116
  requirements:
88
117
  - - ">="
89
118
  - !ruby/object:Gem::Version
119
+ hash: 3
120
+ segments:
121
+ - 0
90
122
  version: "0"
123
+ requirement: *id007
124
+ prerelease: false
91
125
  type: :development
92
- version_requirements: *id007
126
+ name: phocus
93
127
  - !ruby/object:Gem::Dependency
94
- name: bundler
95
- prerelease: false
96
- requirement: &id008 !ruby/object:Gem::Requirement
128
+ version_requirements: &id008 !ruby/object:Gem::Requirement
97
129
  none: false
98
130
  requirements:
99
131
  - - ~>
100
132
  - !ruby/object:Gem::Version
133
+ hash: 23
134
+ segments:
135
+ - 1
136
+ - 0
137
+ - 0
101
138
  version: 1.0.0
139
+ requirement: *id008
140
+ prerelease: false
102
141
  type: :development
103
- version_requirements: *id008
142
+ name: bundler
104
143
  - !ruby/object:Gem::Dependency
105
- name: thin
106
- prerelease: false
107
- requirement: &id009 !ruby/object:Gem::Requirement
144
+ version_requirements: &id009 !ruby/object:Gem::Requirement
108
145
  none: false
109
146
  requirements:
110
147
  - - "="
111
148
  - !ruby/object:Gem::Version
149
+ hash: 15
150
+ segments:
151
+ - 1
152
+ - 2
153
+ - 8
112
154
  version: 1.2.8
155
+ requirement: *id009
156
+ prerelease: false
113
157
  type: :development
114
- version_requirements: *id009
158
+ name: thin
115
159
  description: This library allows you to recognize and build URLs in a Rack application.
116
160
  email: joshbuddy@gmail.com
117
161
  executables: []
@@ -195,12 +239,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
195
239
  requirements:
196
240
  - - ">="
197
241
  - !ruby/object:Gem::Version
242
+ hash: 3
243
+ segments:
244
+ - 0
198
245
  version: "0"
199
246
  required_rubygems_version: !ruby/object:Gem::Requirement
200
247
  none: false
201
248
  requirements:
202
249
  - - ">="
203
250
  - !ruby/object:Gem::Version
251
+ hash: 3
252
+ segments:
253
+ - 0
204
254
  version: "0"
205
255
  requirements: []
206
256