http_router 0.7.10 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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