elasticsearch-paramedic-rack 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3d1cdf93047a52b62e6de9e09532324df11f3e38
4
+ data.tar.gz: 97c20190845cc5be4e89f0d53bd01894aff368bb
5
+ SHA512:
6
+ metadata.gz: 05309b2af64c022f0c29d7e566b927dd6cfecbe94e539a03a559423d85517bed3a9c8a459244407e5ea61c9310fbe061edcab5ab9aa9e8843111c725d0eca218
7
+ data.tar.gz: 0eeea24c0aa9ec1cfe03b338bbfb90d029ffdc340f8fd5b95fbc5c3671adc8d12bd2c7e3fc514c8017caf531d386ef2f283b3ec1154d80b5d19ee795447b0771
data/.travis.yml CHANGED
@@ -4,6 +4,7 @@ rvm:
4
4
  - 1.8.7
5
5
  - 1.9.2
6
6
  - 1.9.3
7
+ - 2.0.0
7
8
  - ruby-head
8
9
  - rbx-19mode
9
10
  - rbx-18mode
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.0
4
+
5
+ * fix typo in Middleware constant
6
+
3
7
  ## 0.1.1
4
8
 
5
9
  * add changelog
data/README.md CHANGED
@@ -16,17 +16,20 @@ Or install it yourself as:
16
16
 
17
17
  $ gem install elasticsearch-paramedic-rack
18
18
 
19
- ## Usage
19
+ ## Config
20
20
 
21
21
  use Elasticsearch::Paramedic::Rack::Middleware
22
22
 
23
+ ## Usage
24
+
25
+ Visit `http://host:port/elasticsearch-paramedic`, for example `http://localhost:3000/elasticsearch-paramedic`
26
+
23
27
  ## Todos
24
28
 
25
29
  * Authlogic
26
30
  * Tests
27
31
  * Rails integration
28
- * Proxy to MongoDB to use on remote Server
29
- * Usage
32
+ * Proxy to Elasticsearch to use on remote Server
30
33
  * Configuration
31
34
  * debug options / logger
32
35
 
@@ -4,6 +4,7 @@ require "elasticsearch-paramedic-rack/middleware"
4
4
  module Elasticsearch
5
5
  module Paramedic
6
6
  module Rack
7
+ PATH = "/elasticsearch-paramedic"
7
8
  ROOT = File.expand_path("../../public", __FILE__)
8
9
  end
9
10
  end
@@ -5,14 +5,15 @@ module Elasticsearch
5
5
  module Rack
6
6
  class Middleware < ::Rack::Static
7
7
  def initialize app
8
- super app, :root => Elasticsearch::Paramedic::Rack::ROOT, :urls => ["/elasticsearch-paramedic"]
8
+ super app, :root => Elasticsearch::Paramedic::Rack::ROOT, :urls => [PATH]
9
9
  end
10
10
 
11
11
  def call env
12
- if env["PATH_INFO"] =~ %r"^/elasticsearch-paramedic$"
13
- return [302, {"Location" => "/elasticsearch-paramedic/", "Content-Type" => "text/plain"}, []]
14
- elsif env["PATH_INFO"] == "/elasticsearch-paramedic/"
15
- env["PATH_INFO"] = "/elasticsearch-paramedic/index.html"
12
+ case env["PATH_INFO"]
13
+ when PATH
14
+ return [302, {"Location" => "#{PATH}/", "Content-Type" => "text/plain"}, []]
15
+ when "#{PATH}/"
16
+ env["PATH_INFO"] = "#{PATH}/index.html"
16
17
  end
17
18
 
18
19
  super
@@ -1,7 +1,7 @@
1
1
  module Elasticsearch
2
2
  module Paramedic
3
3
  module Rack
4
- VERSION = "0.2.0"
4
+ VERSION = "0.2.1"
5
5
  end
6
6
  end
7
7
  end
@@ -122,6 +122,16 @@ header section .label.darker
122
122
 
123
123
  /* Nodes */
124
124
 
125
+ #nodes-wrapper h2 a
126
+ { color: #999;
127
+ text-transform: none;
128
+ float: right; }
129
+
130
+ #nodes-wrapper h2 a:hover
131
+ { color: #666;
132
+ border-bottom: 1px solid #666;
133
+ cursor: pointer; }
134
+
125
135
  #nodes .node
126
136
  { margin: 0.25em 0.5em 0.25em 0;
127
137
  padding: 0.25em 0.5em 0.25em 0;
@@ -138,6 +148,16 @@ header section .label.darker
138
148
 
139
149
  /* Indices */
140
150
 
151
+ #indices-wrapper h2 a
152
+ { color: #999;
153
+ text-transform: none;
154
+ float: right; }
155
+
156
+ #indices-wrapper h2 a:hover
157
+ { color: #666;
158
+ border-bottom: 1px solid #666;
159
+ cursor: pointer; }
160
+
141
161
  #indices
142
162
  { counter-reset: index; }
143
163
 
@@ -86,98 +86,116 @@
86
86
  <div id="chart"></div>
87
87
  </section>
88
88
 
89
- <h2 class="label">Nodes</h2>
90
- <script type="text/x-handlebars">
91
- <div id="nodes" class="clearfix">
92
- {{#each App.nodes}}
93
- <div {{bindAttr class=":node master"}}>
94
- <h3><span {{bindAttr class="master:icon-star"}}></span> {{name}}</h3>
95
- <div class="meta">
96
- <p><span class="label">ID: </span>{{id}}</p>
97
- <p><span class="label">IP: </span>{{http_address}}</p>
98
- <p><span class="label">Host: </span>{{hostname}}</p>
99
- <p><span class="label">Load: </span>{{load}}</p>
100
- <p><span class="label">Size: </span>{{disk}}</p>
101
- <p><span class="label">Docs: </span>{{#bind docs}}{{number_with_delimiter docs}}{{/bind}}</p>
102
- <p><span class="label">Heap: </span>{{jvm_heap_used}}
103
- <small class="dimmed" title="Heap max">/{{jvm_heap_max}}</small></p>
104
- </div>
89
+ <section id="nodes-wrapper">
90
+ <script type="text/x-handlebars">
91
+ <h2 class="label clear">
92
+ Nodes
93
+ <small><a {{action "toggle" target="App.toggleNodes"}}>{{App.toggleNodes.text}}</a></small>
94
+ </h2>
95
+ </script>
96
+ <script type="text/x-handlebars">
97
+ {{#unless App.nodes.hidden}}
98
+ <div id="nodes" class="clearfix">
99
+ {{#each App.nodes}}
100
+ <div {{bindAttr class=":node master"}}>
101
+ <h3><span {{bindAttr class="master:icon-star"}}></span> {{name}}</h3>
102
+ <div class="meta">
103
+ <p><span class="label">ID: </span>{{id}}</p>
104
+ <p><span class="label">IP: </span>{{http_address}}</p>
105
+ <p><span class="label">Host: </span>{{hostname}}</p>
106
+ <p><span class="label">Load: </span>{{load}}</p>
107
+ <p><span class="label">Size: </span>{{disk}}</p>
108
+ <p><span class="label">Docs: </span>{{#bind docs}}{{number_with_delimiter docs}}{{/bind}}</p>
109
+ <p><span class="label">Heap: </span>{{jvm_heap_used}}
110
+ <small class="dimmed" title="Heap max">/{{jvm_heap_max}}</small></p>
111
+ </div>
112
+ </div>
113
+ {{/each}}
105
114
  </div>
106
- {{/each}}
107
- </div>
108
- </script>
109
- <br>
110
-
111
- <h2 class="label">Indices</h2>
112
- <script type="text/x-handlebars">
113
- <div id="indices">
114
- {{#each index in App.indices.sorted}}
115
- {{#with index}}
116
- <div {{bindAttr class=":index :clearfix state show_detail:expanded"}}>
117
- <div class="basic-info clearfix">
118
- <h3><a {{bindAttr href="url"}} title="Browse Index">{{name}}</a></h3>
119
-
120
- <div class="buttons">
121
- {{#unless closed}}
122
- <button {{action "showDetail" target="App.indices"}}>
123
- {{#if show_detail}}Hide details{{else}}Show details{{/if}}
124
- </button>
125
- {{/unless}}
126
- </div>
115
+ {{/unless}}
116
+ </script>
117
+ <br>
118
+ </section>
119
+
120
+ <section id="indices-wrapper">
121
+ <script type="text/x-handlebars">
122
+ <h2 class="label clear">
123
+ Indices
124
+ <small><a {{action "toggle" target="App.toggleIndices"}}>{{App.toggleIndices.text}}</a></small>
125
+ </h2>
126
+ </script>
127
+ <script type="text/x-handlebars">
128
+ {{#unless App.indices.hidden}}
129
+ <div id="indices">
130
+ {{#each index in App.indices.sorted}}
131
+ {{#with index}}
132
+ <div {{bindAttr class=":index :clearfix state show_detail:expanded"}}>
133
+ <div class="basic-info clearfix">
134
+ <h3><a {{bindAttr href="url"}} title="Browse Index">{{name}}</a></h3>
135
+
136
+ <div class="buttons">
137
+ {{#unless closed}}
138
+ <button {{action "showDetail" target="App.indices"}}>
139
+ {{#if show_detail}}Hide details{{else}}Show details{{/if}}
140
+ </button>
141
+ {{/unless}}
142
+ </div>
127
143
 
128
- <div class="shards">
129
- {{#each shards}}
130
- <div {{bindAttr class=":shard primary state recovery.stage" title="state"}}>
131
- {{name}}
144
+ <div class="shards">
145
+ {{#each shards}}
146
+ <div {{bindAttr class=":shard primary state recovery.stage" title="state"}}>
147
+ {{name}}
148
+ </div>
149
+ {{/each}}
132
150
  </div>
133
- {{/each}}
134
- </div>
135
151
 
136
- <div class="meta">
137
- <p>
138
- {{settings.number_of_shards}} shards /
139
- {{settings.number_of_replicas}} replicas /
140
- {{#bind docs}}{{number_with_delimiter docs}}{{/bind}} docs /
141
- {{size}} /
142
- {{indexing.index_time}} indexing /
143
- {{search.query_time}} querying /
144
- {{state}}
145
- </p>
152
+ <div class="meta">
153
+ <p>
154
+ {{settings.number_of_shards}} shards /
155
+ {{settings.number_of_replicas}} replicas /
156
+ {{#bind docs}}{{number_with_delimiter docs}}{{/bind}} docs /
157
+ {{size}} /
158
+ {{indexing.index_time}} indexing /
159
+ {{search.query_time}} querying /
160
+ {{state}}
161
+ </p>
162
+ </div>
146
163
  </div>
147
- </div>
148
164
 
149
- <!-- Shard Allocation -->
150
- {{#if show_detail}}
151
- <div class="extra-info shards clearfix">
152
- {{#unless show_detail_loaded}}
153
- <div class="loading">Waiting for data...</div>
154
- {{/unless}}
155
- {{#each nodes}}
156
- <div class="node">
157
- <h3>{{name}} <small>{{hostname}}</small></h3>
158
- <div class="clearfix">
159
- {{#each shards}}
160
- <div {{bindAttr class=":shard primary state recovery.stage" title="state"}}>
161
- <h3>{{name}}</h3>
162
- <div class="meta">
163
- <p>{{state}}/{{recovery.stage}}</p>
164
- <p>
165
- {{recovery.time}}
166
- {{recovery.size}}
167
- </p>
168
- </div>
169
- </div>
170
- {{/each}}
165
+ <!-- Shard Allocation -->
166
+ {{#if show_detail}}
167
+ <div class="extra-info shards clearfix">
168
+ {{#unless show_detail_loaded}}
169
+ <div class="loading">Waiting for data...</div>
170
+ {{/unless}}
171
+ {{#each nodes}}
172
+ <div class="node">
173
+ <h3>{{name}} <small>{{hostname}}</small></h3>
174
+ <div class="clearfix">
175
+ {{#each shards}}
176
+ <div {{bindAttr class=":shard primary state recovery.stage" title="state"}}>
177
+ <h3>{{name}}</h3>
178
+ <div class="meta">
179
+ <p>{{state}}/{{recovery.stage}}</p>
180
+ <p>
181
+ {{recovery.time}}
182
+ {{recovery.size}}
183
+ </p>
184
+ </div>
185
+ </div>
186
+ {{/each}}
187
+ </div>
171
188
  </div>
189
+ {{/each}}
172
190
  </div>
173
- {{/each}}
174
- </div>
175
- {{/if}}
191
+ {{/if}}
192
+ </div>
193
+ {{/with}}
194
+ {{/each}}
176
195
  </div>
177
- {{/with}}
178
- {{/each}}
179
- </ul>
180
- </script>
196
+ {{/unless}}
197
+ </script>
198
+ </section>
181
199
 
182
200
  <audio id="alert-green" src="audio/alert-green.mp3"></audio>
183
201
  <audio id="alert-yellow" src="audio/alert-yellow.mp3"></audio>
@@ -12,8 +12,9 @@ var App = Em.Application.create({
12
12
  },
13
13
 
14
14
  elasticsearch_url: function() {
15
- var location = window.location
16
- return (/_plugin/.test(location.href.toString())) ? location.protocol + "//" + location.host : "http://localhost:9200"
15
+ var href = window.location.href.toString()
16
+
17
+ return /_plugin/.test(href) ? href.substring(0, href.indexOf('/_plugin/')) : "http://localhost:9200"
17
18
  }(),
18
19
 
19
20
  refresh_intervals : Ember.ArrayController.create({
@@ -94,6 +95,7 @@ App.cluster = Ember.Object.create({
94
95
  });
95
96
 
96
97
  App.nodes = Ember.ArrayController.create({
98
+ hidden: false,
97
99
  content: [],
98
100
 
99
101
  contains: function(item) {
@@ -101,6 +103,8 @@ App.nodes = Ember.ArrayController.create({
101
103
  },
102
104
 
103
105
  refresh: function() {
106
+ if (App.nodes.hidden) { return }
107
+
104
108
  clearTimeout(App.nodes.poller)
105
109
  setTimeout(function() { App.set("refreshing", false) }, 1000)
106
110
  App.nodes.poller = setTimeout( function() { App.nodes.__perform_refresh() }, App.refresh_interval.value )
@@ -152,12 +156,13 @@ App.nodes = Ember.ArrayController.create({
152
156
  };
153
157
 
154
158
  App.set("refreshing", true)
155
- $.getJSON(App.elasticsearch_url+"/_cluster/nodes?jvm", __load_nodes_info);
156
- $.getJSON(App.elasticsearch_url+"/_cluster/nodes/stats?indices&os&process&jvm", __load_nodes_stats);
159
+ $.getJSON(App.elasticsearch_url+"/_nodes?jvm", __load_nodes_info);
160
+ $.getJSON(App.elasticsearch_url+"/_nodes/stats?indices&os&process&jvm", __load_nodes_stats);
157
161
  }
158
162
  });
159
163
 
160
164
  App.indices = Ember.ArrayController.create({
165
+ hidden: false,
161
166
  content: [],
162
167
 
163
168
  contains: function(item) {
@@ -165,6 +170,8 @@ App.indices = Ember.ArrayController.create({
165
170
  },
166
171
 
167
172
  refresh: function() {
173
+ if (App.indices.hidden) { return }
174
+
168
175
  clearTimeout(App.indices.poller)
169
176
  setTimeout(function() { App.set("refreshing", false) }, 1000)
170
177
  App.indices.poller = setTimeout( function() { App.indices.__perform_refresh() }, App.refresh_interval.value )
@@ -330,17 +337,19 @@ App.indices = Ember.ArrayController.create({
330
337
  App.cluster.set("docs_count",
331
338
  data._all.primaries.docs ? data._all.primaries.docs.count : 0)
332
339
 
333
- for (var index_name in data._all.indices) {
340
+ var indices = data._all.indices || data.indices
341
+
342
+ for (var index_name in indices) {
334
343
  var index = self.findProperty("name", index_name)
335
344
  if (!index) continue
336
345
 
337
346
  index
338
- .set("size", data._all.indices[index_name]['primaries']['store']['size'])
339
- .set("size_in_bytes", data._all.indices[index_name]['primaries']['store']['size_in_bytes'])
340
- .set("docs", data._all.indices[index_name]['primaries']['docs']['count'])
341
- .set("indexing", data._all.indices[index_name]['primaries']['indexing'])
342
- .set("search", data._all.indices[index_name]['primaries']['search'])
343
- .set("get", data._all.indices[index_name]['primaries']['get'])
347
+ .set("size", indices[index_name]['primaries']['store']['size'])
348
+ .set("size_in_bytes", indices[index_name]['primaries']['store']['size_in_bytes'])
349
+ .set("docs", indices[index_name]['primaries']['docs']['count'])
350
+ .set("indexing", indices[index_name]['primaries']['indexing'])
351
+ .set("search", indices[index_name]['primaries']['search'])
352
+ .set("get", indices[index_name]['primaries']['get'])
344
353
  }
345
354
  };
346
355
 
@@ -413,6 +422,30 @@ App.toggleChart = Ember.View.create({
413
422
 
414
423
  this.set("text", visible ? 'Show' : 'Hide')
415
424
  visible ? chart.hide('fast') : chart.show('fast')
425
+ App.nodes.refresh();
426
+ }
427
+ });
428
+
429
+ App.toggleIndices = Ember.View.create({
430
+ hidden: false,
431
+ text: 'Hide',
432
+
433
+ toggle: function(event) {
434
+ this.set("text", this.get('hidden') ? 'Hide' : 'Show')
435
+ this.toggleProperty('hidden')
436
+ App.indices.toggleProperty('hidden')
437
+ App.indices.refresh();
438
+ }
439
+ });
440
+
441
+ App.toggleNodes = Ember.View.create({
442
+ hidden: false,
443
+ text: 'Hide',
444
+
445
+ toggle: function(event) {
446
+ this.set("text", this.get('hidden') ? 'Hide' : 'Show')
447
+ this.toggleProperty('hidden')
448
+ App.nodes.toggleProperty('hidden')
416
449
  }
417
450
  });
418
451
 
@@ -209,7 +209,7 @@ cubism.elasticsearch = function(context, options, callback) {
209
209
  // Load information about ElasticSearch nodes from the Nodes Info API
210
210
  // [http://www.elasticsearch.org/guide/reference/api/admin-cluster-nodes-info.html]
211
211
  //
212
- d3.json(options.host + "/_cluster/nodes", function(cluster) {
212
+ d3.json(options.host + "/_nodes", function(cluster) {
213
213
  source.cluster = cluster
214
214
  source.node_names = d3.keys(cluster.nodes)
215
215
 
@@ -267,7 +267,7 @@ cubism.elasticsearch = function(context, options, callback) {
267
267
  })
268
268
 
269
269
  source.toString = function() { return options.host };
270
- source.url = function() { return options.host + "/_cluster/nodes/stats?all" };
270
+ source.url = function() { return options.host + "/_nodes/stats?all" };
271
271
 
272
272
  return source;
273
273
  };
@@ -3,19 +3,19 @@ require 'minitest/autorun'
3
3
  require 'rack/lint'
4
4
  require 'rack/mock'
5
5
 
6
- require "elasticsearch-paramedic-rack/middelware"
6
+ require "elasticsearch-paramedic-rack/middleware"
7
7
 
8
8
  class MiddlewareTest < Minitest::Unit::TestCase
9
- PATH = "/elasticsearch-paramedic"
9
+ PATH = Elasticsearch::Paramedic::Rack::PATH
10
10
 
11
11
  def middelware
12
- Rack::Lint.new Elasticsearch::Paramedic::Rack::Middelware.new(RackApp.new)
12
+ Rack::Lint.new Elasticsearch::Paramedic::Rack::Middleware.new(RackApp.new)
13
13
  end
14
14
 
15
15
  def test_root
16
16
  res = Rack::MockRequest.new(middelware).get(PATH)
17
17
  assert_equal 302, res.status
18
- assert_equal "/elasticsearch-paramedic/", res.header["Location"]
18
+ assert_equal "#{PATH}/", res.header["Location"]
19
19
  end
20
20
 
21
21
  def test_root2
metadata CHANGED
@@ -1,62 +1,55 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elasticsearch-paramedic-rack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
5
- prerelease:
4
+ version: 0.2.1
6
5
  platform: ruby
7
6
  authors:
8
7
  - Timo Schilling
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-02-17 00:00:00.000000000 Z
11
+ date: 2014-04-07 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rack
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - ">="
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rake
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - ">="
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - ">="
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: minitest
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ~>
45
+ - - "~>"
52
46
  - !ruby/object:Gem::Version
53
47
  version: '3.0'
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ~>
52
+ - - "~>"
60
53
  - !ruby/object:Gem::Version
61
54
  version: '3.0'
62
55
  description: A gemed version of elasticsearch-paramedic with Rack support.
@@ -66,8 +59,8 @@ executables: []
66
59
  extensions: []
67
60
  extra_rdoc_files: []
68
61
  files:
69
- - .gitignore
70
- - .travis.yml
62
+ - ".gitignore"
63
+ - ".travis.yml"
71
64
  - CHANGELOG.md
72
65
  - Gemfile
73
66
  - LICENSE.txt
@@ -98,38 +91,32 @@ files:
98
91
  - public/elasticsearch-paramedic/js/libs/ember-0.9.8.js
99
92
  - public/elasticsearch-paramedic/js/libs/ember-0.9.8.min.js
100
93
  - public/elasticsearch-paramedic/js/libs/jquery-1.7.2.min.js
101
- - test/middelware_test.rb
94
+ - test/middleware_test.rb
102
95
  - test/test_helper.rb
103
96
  homepage: https://github.com/timoschilling/elasticsearch-paramedic-rack
104
97
  licenses: []
98
+ metadata: {}
105
99
  post_install_message:
106
100
  rdoc_options: []
107
101
  require_paths:
108
102
  - lib
109
103
  required_ruby_version: !ruby/object:Gem::Requirement
110
- none: false
111
104
  requirements:
112
- - - ! '>='
105
+ - - ">="
113
106
  - !ruby/object:Gem::Version
114
107
  version: '0'
115
- segments:
116
- - 0
117
- hash: 217892655081849790
118
108
  required_rubygems_version: !ruby/object:Gem::Requirement
119
- none: false
120
109
  requirements:
121
- - - ! '>='
110
+ - - ">="
122
111
  - !ruby/object:Gem::Version
123
112
  version: '0'
124
- segments:
125
- - 0
126
- hash: 217892655081849790
127
113
  requirements: []
128
114
  rubyforge_project:
129
- rubygems_version: 1.8.24
115
+ rubygems_version: 2.2.2
130
116
  signing_key:
131
- specification_version: 3
117
+ specification_version: 4
132
118
  summary: A gemed version of elasticsearch-paramedic with Rack support.
133
119
  test_files:
134
- - test/middelware_test.rb
120
+ - test/middleware_test.rb
135
121
  - test/test_helper.rb
122
+ has_rdoc: