geared_pagination 0.1 → 0.2
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.
- checksums.yaml +4 -4
- data/Gemfile +2 -1
- data/Gemfile.lock +34 -5
- data/README.md +29 -7
- data/geared_pagination.gemspec +1 -1
- data/lib/geared_pagination/controller.rb +6 -1
- data/lib/geared_pagination/headers.rb +1 -1
- data/lib/geared_pagination/page.rb +10 -5
- data/lib/geared_pagination/portion.rb +5 -0
- data/lib/geared_pagination/railtie.rb +1 -1
- data/lib/geared_pagination/ratios.rb +4 -0
- data/lib/geared_pagination/recordset.rb +1 -1
- data/test/controller_test.rb +66 -0
- data/test/headers_test.rb +12 -12
- data/test/page_test.rb +19 -0
- data/test/portion_test.rb +11 -0
- data/test/ratios_test.rb +4 -0
- data/test/recordset_test.rb +12 -12
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f2ef2f3f5dc638b5cd4b6ab2459cbf4e513b85e4
|
4
|
+
data.tar.gz: 3ae73c3c52ee2dd1a257daff921cabe401373733
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a66259e261f8f9b98459cbd754039fbfb304fd8c700181b3babb4dca4ceeb83efb2e49dbf1e00d1238ede83f1ddbc9d96812cdf603c5e0644bd2d59969fab21a
|
7
|
+
data.tar.gz: ba3b678d00e7615b1c8595ca342bd2d9cd1f4dee75a2e20f5ab93f178caf19b25b6d2abd6af3a4eb26b8dcf798ecee69a21d231fd4637e22a33f3fe9ce1087aa
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -8,27 +8,56 @@ PATH
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
-
|
11
|
+
actionpack (5.0.2)
|
12
|
+
actionview (= 5.0.2)
|
13
|
+
activesupport (= 5.0.2)
|
14
|
+
rack (~> 2.0)
|
15
|
+
rack-test (~> 0.6.3)
|
16
|
+
rails-dom-testing (~> 2.0)
|
17
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
18
|
+
actionview (5.0.2)
|
19
|
+
activesupport (= 5.0.2)
|
20
|
+
builder (~> 3.1)
|
21
|
+
erubis (~> 2.7.0)
|
22
|
+
rails-dom-testing (~> 2.0)
|
23
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
24
|
+
activesupport (5.0.2)
|
12
25
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
13
26
|
i18n (~> 0.7)
|
14
27
|
minitest (~> 5.1)
|
15
28
|
tzinfo (~> 1.1)
|
16
|
-
addressable (2.5.
|
29
|
+
addressable (2.5.1)
|
17
30
|
public_suffix (~> 2.0, >= 2.0.2)
|
31
|
+
builder (3.2.3)
|
18
32
|
byebug (9.0.6)
|
19
|
-
concurrent-ruby (1.0.
|
33
|
+
concurrent-ruby (1.0.5)
|
34
|
+
erubis (2.7.0)
|
20
35
|
i18n (0.8.1)
|
36
|
+
loofah (2.0.3)
|
37
|
+
nokogiri (>= 1.5.9)
|
38
|
+
mini_portile2 (2.1.0)
|
21
39
|
minitest (5.10.1)
|
40
|
+
nokogiri (1.7.1)
|
41
|
+
mini_portile2 (~> 2.1.0)
|
22
42
|
public_suffix (2.0.5)
|
43
|
+
rack (2.0.1)
|
44
|
+
rack-test (0.6.3)
|
45
|
+
rack (>= 1.0)
|
46
|
+
rails-dom-testing (2.0.2)
|
47
|
+
activesupport (>= 4.2.0, < 6.0)
|
48
|
+
nokogiri (~> 1.6)
|
49
|
+
rails-html-sanitizer (1.0.3)
|
50
|
+
loofah (~> 2.0)
|
23
51
|
rake (12.0.0)
|
24
|
-
thread_safe (0.3.
|
25
|
-
tzinfo (1.2.
|
52
|
+
thread_safe (0.3.6)
|
53
|
+
tzinfo (1.2.3)
|
26
54
|
thread_safe (~> 0.1)
|
27
55
|
|
28
56
|
PLATFORMS
|
29
57
|
ruby
|
30
58
|
|
31
59
|
DEPENDENCIES
|
60
|
+
actionpack (>= 5)
|
32
61
|
bundler (~> 1.12)
|
33
62
|
byebug
|
34
63
|
geared_pagination!
|
data/README.md
CHANGED
@@ -1,30 +1,30 @@
|
|
1
1
|
# Geared Pagination
|
2
2
|
|
3
3
|
Most pagination schemes use a fixed page size. Page 1 returns as many elements as page 2. But that's
|
4
|
-
frequently not the most sensible way to page through a large
|
4
|
+
frequently not the most sensible way to page through a large recordset when you care about serving the
|
5
5
|
initial request as quickly as possible. This is particularly the case when using the pagination scheme
|
6
6
|
in combination with an infinite scrolling UI.
|
7
7
|
|
8
8
|
Geared Pagination allows you to define different ratios. By default, we will return 15 elements on page 1,
|
9
|
-
30 on page 2, 50 on page 3, and 100 from page 4 and forward. This has
|
9
|
+
30 on page 2, 50 on page 3, and 100 from page 4 and forward. This has proven to be a very sensible set of
|
10
10
|
ratios for much of the Basecamp UIs. But you can of course tweak the ratios, use fewer, or even none at all,
|
11
|
-
if
|
11
|
+
if a certain page calls for a fixed-rate scheme.
|
12
12
|
|
13
|
-
On
|
14
|
-
to be able to page through a
|
13
|
+
On JSON actions that set a page, we'll also automatically set Link and X-Total-Count headers for APIs
|
14
|
+
to be able to page through a recordset.
|
15
15
|
|
16
16
|
## Example
|
17
17
|
|
18
18
|
```ruby
|
19
19
|
class MessagesController < ApplicationController
|
20
20
|
def index
|
21
|
-
|
21
|
+
set_page_and_extract_portion_from Message.order(created_at: :desc)
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
25
|
# app/views/messages/index.html.erb
|
26
26
|
|
27
|
-
Showing page <%= @page.number %> of <%= @page.
|
27
|
+
Showing page <%= @page.number %> of <%= @page.recordset.page_count %> (<%= @page.recordset.records_count %> total messages):
|
28
28
|
|
29
29
|
<%= render @page.records %>
|
30
30
|
|
@@ -36,5 +36,27 @@ Showing page <%= @page.number %> of <%= @page.collection.page_count %> (<%= @pag
|
|
36
36
|
|
37
37
|
```
|
38
38
|
|
39
|
+
|
40
|
+
## Caching
|
41
|
+
|
42
|
+
To account for the current page in fragment caches, include the `@page` directly.
|
43
|
+
That includes the current page number and gear ratios.
|
44
|
+
|
45
|
+
Fragment caching a message's comments:
|
46
|
+
```ruby
|
47
|
+
<% cache [ @message, @page ] do %>
|
48
|
+
<%= render @page.records %>
|
49
|
+
<% end %>
|
50
|
+
```
|
51
|
+
|
52
|
+
NOTE: The page does not include cache keys for all the records. That would require loading all the records,
|
53
|
+
defeating the purpose of using the cache. Use a parent record, like a message that's touched when
|
54
|
+
new comments are posted, as the cache key instead.
|
55
|
+
|
56
|
+
## ETags
|
57
|
+
|
58
|
+
When a controller action sets an ETag and uses geared pagination, the current page and gear ratios are
|
59
|
+
automatically included in the ETag.
|
60
|
+
|
39
61
|
## License
|
40
62
|
Geared Pagination is released under the [MIT License](https://opensource.org/licenses/MIT).
|
data/geared_pagination.gemspec
CHANGED
@@ -7,6 +7,7 @@ module GearedPagination
|
|
7
7
|
|
8
8
|
included do
|
9
9
|
after_action :set_paginated_headers
|
10
|
+
etag { @page if geared_page? }
|
10
11
|
end
|
11
12
|
|
12
13
|
private
|
@@ -20,7 +21,11 @@ module GearedPagination
|
|
20
21
|
end
|
21
22
|
|
22
23
|
def set_paginated_headers
|
23
|
-
GearedPagination::Headers.new(page: @page, controller: self).apply if
|
24
|
+
GearedPagination::Headers.new(page: @page, controller: self).apply if geared_page?
|
25
|
+
end
|
26
|
+
|
27
|
+
def geared_page?
|
28
|
+
@page.is_a? GearedPagination::Page
|
24
29
|
end
|
25
30
|
|
26
31
|
def current_page_param
|
@@ -13,7 +13,7 @@ module GearedPagination
|
|
13
13
|
private
|
14
14
|
def headers
|
15
15
|
Hash.new.tap do |h|
|
16
|
-
h["X-Total-Count"] = @page.
|
16
|
+
h["X-Total-Count"] = @page.recordset.records_count.to_s
|
17
17
|
h["Link"] = next_page_link_header unless @page.last?
|
18
18
|
end
|
19
19
|
end
|
@@ -2,15 +2,15 @@ require 'geared_pagination/portion'
|
|
2
2
|
|
3
3
|
module GearedPagination
|
4
4
|
class Page
|
5
|
-
attr_reader :number, :
|
5
|
+
attr_reader :number, :recordset
|
6
6
|
|
7
7
|
def initialize(number, from:)
|
8
|
-
@number, @
|
8
|
+
@number, @recordset = number, from
|
9
9
|
@portion = GearedPagination::Portion.new(page_number: number, per_page: from.ratios)
|
10
10
|
end
|
11
11
|
|
12
12
|
def records
|
13
|
-
@records ||= @portion.from(
|
13
|
+
@records ||= @portion.from(recordset.records)
|
14
14
|
end
|
15
15
|
|
16
16
|
|
@@ -28,16 +28,21 @@ module GearedPagination
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def only?
|
31
|
-
|
31
|
+
recordset.page_count == 1
|
32
32
|
end
|
33
33
|
|
34
34
|
def last?
|
35
|
-
number ==
|
35
|
+
number == recordset.page_count
|
36
36
|
end
|
37
37
|
|
38
38
|
|
39
39
|
def next_number
|
40
40
|
number + 1
|
41
41
|
end
|
42
|
+
|
43
|
+
|
44
|
+
def cache_key
|
45
|
+
"page/#{@portion.cache_key}"
|
46
|
+
end
|
42
47
|
end
|
43
48
|
end
|
@@ -2,7 +2,7 @@ require 'rails/railtie'
|
|
2
2
|
require 'geared_pagination/controller'
|
3
3
|
|
4
4
|
class GearedPagination::Engine < ::Rails::Engine
|
5
|
-
initializer :
|
5
|
+
initializer :geared_pagination do |app|
|
6
6
|
ActiveSupport.on_load :action_controller do
|
7
7
|
ActionController::Base.send :include, GearedPagination::Controller
|
8
8
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'geared_pagination'
|
3
|
+
require 'geared_pagination/controller'
|
4
|
+
require 'active_support/all'
|
5
|
+
require 'action_controller'
|
6
|
+
|
7
|
+
class RecordingsController < ActionController::Base
|
8
|
+
include GearedPagination::Controller
|
9
|
+
|
10
|
+
def index
|
11
|
+
set_page_and_extract_portion_from Recording.all, per_page: params[:per_page]
|
12
|
+
render json: @page.records if stale? etag: "placeholder"
|
13
|
+
end
|
14
|
+
|
15
|
+
def unpaged
|
16
|
+
@page = "not a geared pagination page"
|
17
|
+
head :ok if stale? etag: "placeholder"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class GearedPagination::ControllerTest < ActionController::TestCase
|
22
|
+
tests RecordingsController
|
23
|
+
|
24
|
+
setup do
|
25
|
+
@routes = ActionDispatch::Routing::RouteSet.new.tap do |r|
|
26
|
+
r.draw do
|
27
|
+
resources :recordings do
|
28
|
+
get :unpaged, on: :collection
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
test "ETag includes the current page and gearing" do
|
35
|
+
get :index, params: { per_page: [ 1, 2 ] }
|
36
|
+
assert_equal etag_for("placeholder", "page/1:1-2"), response.etag
|
37
|
+
etag_before_gearing_change = response.etag
|
38
|
+
|
39
|
+
get :index, params: { page: 1, per_page: [ 1, 2 ] }
|
40
|
+
assert_equal etag_before_gearing_change, response.etag
|
41
|
+
|
42
|
+
get :index, params: { page: 1, per_page: [ 1, 3 ] }
|
43
|
+
assert_not_equal etag_before_gearing_change, response.etag
|
44
|
+
end
|
45
|
+
|
46
|
+
test "ETag is ignored when @page is not a geared page" do
|
47
|
+
get :unpaged
|
48
|
+
assert_equal etag_for("placeholder"), response.etag
|
49
|
+
end
|
50
|
+
|
51
|
+
test "Link headers on JSON requests" do
|
52
|
+
get :index, format: 'json'
|
53
|
+
assert_equal "120", response.headers["X-Total-Count"]
|
54
|
+
assert_equal '<http://test.host/recordings.json?page=2>; rel="next"', response.headers["Link"]
|
55
|
+
end
|
56
|
+
|
57
|
+
test "no Link headers on non-JSON requests" do
|
58
|
+
get :index
|
59
|
+
assert_nil response.headers["Link"]
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
def etag_for(*keys)
|
64
|
+
%(W/"#{Digest::MD5.hexdigest(ActiveSupport::Cache.expand_cache_key(keys))}")
|
65
|
+
end
|
66
|
+
end
|
data/test/headers_test.rb
CHANGED
@@ -8,40 +8,40 @@ class GearedPagination::HeadersTest < ActiveSupport::TestCase
|
|
8
8
|
Controller = Struct.new(:request, :headers)
|
9
9
|
|
10
10
|
setup do
|
11
|
-
@controller_serving_json = Controller.new(Request.new("http://example.com/
|
12
|
-
@controller_serving_html = Controller.new(Request.new("http://example.com/
|
11
|
+
@controller_serving_json = Controller.new(Request.new("http://example.com/recordset.json", "json".inquiry), {})
|
12
|
+
@controller_serving_html = Controller.new(Request.new("http://example.com/recordset", "html".inquiry), {})
|
13
13
|
|
14
|
-
@
|
15
|
-
@
|
14
|
+
@single_page_recordset = GearedPagination::Recordset.new(Recording.all, per_page: 1000)
|
15
|
+
@many_page_recordset = GearedPagination::Recordset.new(Recording.all, per_page: 1)
|
16
16
|
end
|
17
17
|
|
18
18
|
test "total count" do
|
19
|
-
GearedPagination::Headers.new(page: @
|
19
|
+
GearedPagination::Headers.new(page: @many_page_recordset.page(1), controller: @controller_serving_json).apply
|
20
20
|
assert_equal Recording.all.count.to_s, @controller_serving_json.headers["X-Total-Count"]
|
21
21
|
end
|
22
22
|
|
23
23
|
test "no link for html requests" do
|
24
|
-
GearedPagination::Headers.new(page: @
|
24
|
+
GearedPagination::Headers.new(page: @many_page_recordset.page(1), controller: @controller_serving_html).apply
|
25
25
|
assert @controller_serving_html.headers["Link"].nil?
|
26
26
|
end
|
27
27
|
|
28
28
|
test "no link for json request with single page" do
|
29
|
-
GearedPagination::Headers.new(page: @
|
29
|
+
GearedPagination::Headers.new(page: @many_page_recordset.page(1), controller: @controller_serving_html).apply
|
30
30
|
assert @controller_serving_html.headers["Link"].nil?
|
31
31
|
end
|
32
32
|
|
33
33
|
test "links for json request with multiple pages" do
|
34
|
-
GearedPagination::Headers.new(page: @
|
35
|
-
assert_equal '<http://example.com/
|
34
|
+
GearedPagination::Headers.new(page: @many_page_recordset.page(1), controller: @controller_serving_json).apply
|
35
|
+
assert_equal '<http://example.com/recordset.json?page=2>; rel="next"',
|
36
36
|
@controller_serving_json.headers["Link"]
|
37
37
|
|
38
|
-
GearedPagination::Headers.new(page: @
|
39
|
-
assert_equal '<http://example.com/
|
38
|
+
GearedPagination::Headers.new(page: @many_page_recordset.page(2), controller: @controller_serving_json).apply
|
39
|
+
assert_equal '<http://example.com/recordset.json?page=3>; rel="next"',
|
40
40
|
@controller_serving_json.headers["Link"]
|
41
41
|
end
|
42
42
|
|
43
43
|
test "no link for json request with multiple pages on last page" do
|
44
|
-
GearedPagination::Headers.new(page: @
|
44
|
+
GearedPagination::Headers.new(page: @many_page_recordset.page(Recording.all.count), controller: @controller_serving_json).apply
|
45
45
|
assert @controller_serving_json.headers["Link"].nil?
|
46
46
|
end
|
47
47
|
end
|
data/test/page_test.rb
CHANGED
@@ -20,4 +20,23 @@ class GearedPagination::PageTest < ActiveSupport::TestCase
|
|
20
20
|
test "next_number" do
|
21
21
|
assert_equal 2, GearedPagination::Recordset.new(Recording.all, per_page: 1000).page(1).next_number
|
22
22
|
end
|
23
|
+
|
24
|
+
test "with empty recordset" do
|
25
|
+
page_for_empty_set = GearedPagination::Recordset.new(Recordings.new([]), per_page: 1000).page(1)
|
26
|
+
|
27
|
+
assert page_for_empty_set.first?
|
28
|
+
assert page_for_empty_set.only?
|
29
|
+
assert page_for_empty_set.last?
|
30
|
+
end
|
31
|
+
|
32
|
+
test "cache key changes according to current page and gearing" do
|
33
|
+
assert_equal 'page/2:3', cache_key(page: 2, per_page: 3)
|
34
|
+
assert_equal 'page/2:1-3', cache_key(page: 2, per_page: [ 1, 3 ])
|
35
|
+
assert_equal 'page/2:2-3', cache_key(page: 2, per_page: [ 2, 3 ])
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def cache_key(page:, per_page:)
|
40
|
+
GearedPagination::Recordset.new(Recording.all, per_page: per_page).page(page).cache_key
|
41
|
+
end
|
23
42
|
end
|
data/test/portion_test.rb
CHANGED
@@ -13,4 +13,15 @@ class GearedPagination::PortionTest < ActiveSupport::TestCase
|
|
13
13
|
assert_equal GearedPagination::Ratios::DEFAULTS.first, GearedPagination::Portion.new(page_number: 1).limit
|
14
14
|
assert_equal GearedPagination::Ratios::DEFAULTS.second, GearedPagination::Portion.new(page_number: 2).limit
|
15
15
|
end
|
16
|
+
|
17
|
+
test "cache key changes according to current page and gearing" do
|
18
|
+
assert_equal '2:3', cache_key(page: 2, per_page: 3)
|
19
|
+
assert_equal '2:1-3', cache_key(page: 2, per_page: [ 1, 3 ])
|
20
|
+
assert_equal '2:2-3', cache_key(page: 2, per_page: [ 2, 3 ])
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def cache_key(page:, per_page:)
|
25
|
+
GearedPagination::Portion.new(page_number: page, per_page: GearedPagination::Ratios.new(per_page)).cache_key
|
26
|
+
end
|
16
27
|
end
|
data/test/ratios_test.rb
CHANGED
@@ -24,4 +24,8 @@ class GearedPagination::RatiosTest < ActiveSupport::TestCase
|
|
24
24
|
assert_equal GearedPagination::Ratios::DEFAULTS.first, limits[1]
|
25
25
|
assert_equal GearedPagination::Ratios::DEFAULTS.last, limits[99]
|
26
26
|
end
|
27
|
+
|
28
|
+
test "cache key" do
|
29
|
+
assert_equal "1-2-3", GearedPagination::Ratios.new([ 1, 2, 3 ]).cache_key
|
30
|
+
end
|
27
31
|
end
|
data/test/recordset_test.rb
CHANGED
@@ -3,26 +3,26 @@ require 'geared_pagination/recordset'
|
|
3
3
|
|
4
4
|
class GearedPagination::RecordsetTest < ActiveSupport::TestCase
|
5
5
|
test "single limit pagination" do
|
6
|
-
|
6
|
+
recordset = GearedPagination::Recordset.new(Recording.all, per_page: 10)
|
7
7
|
|
8
|
-
assert_equal 10,
|
9
|
-
assert_equal 10,
|
8
|
+
assert_equal 10, recordset.page(1).records.size
|
9
|
+
assert_equal 10, recordset.page(2).records.size
|
10
10
|
end
|
11
11
|
|
12
12
|
test "variable limit pagination" do
|
13
|
-
|
13
|
+
recordset = GearedPagination::Recordset.new(Recording.all, per_page: [ 10, 15, 20 ])
|
14
14
|
|
15
|
-
assert_equal 10,
|
16
|
-
assert
|
15
|
+
assert_equal 10, recordset.page(1).records.size
|
16
|
+
assert recordset.page(1).records.include?(Recording.all[0])
|
17
17
|
|
18
|
-
assert_equal 15,
|
19
|
-
assert
|
18
|
+
assert_equal 15, recordset.page(2).records.size
|
19
|
+
assert recordset.page(2).records.include?(Recording.all[11])
|
20
20
|
|
21
|
-
assert_equal 20,
|
22
|
-
assert
|
21
|
+
assert_equal 20, recordset.page(3).records.size
|
22
|
+
assert recordset.page(3).records.include?(Recording.all[26])
|
23
23
|
|
24
|
-
assert_equal 20,
|
25
|
-
assert
|
24
|
+
assert_equal 20, recordset.page(4).records.size
|
25
|
+
assert recordset.page(4).records.include?(Recording.all[46])
|
26
26
|
end
|
27
27
|
|
28
28
|
test "page count" do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: geared_pagination
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.2'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-05-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -72,6 +72,7 @@ files:
|
|
72
72
|
- lib/geared_pagination/railtie.rb
|
73
73
|
- lib/geared_pagination/ratios.rb
|
74
74
|
- lib/geared_pagination/recordset.rb
|
75
|
+
- test/controller_test.rb
|
75
76
|
- test/headers_test.rb
|
76
77
|
- test/page_test.rb
|
77
78
|
- test/portion_test.rb
|
@@ -104,6 +105,7 @@ signing_key:
|
|
104
105
|
specification_version: 4
|
105
106
|
summary: Paginate Active Record sets at variable speeds
|
106
107
|
test_files:
|
108
|
+
- test/controller_test.rb
|
107
109
|
- test/headers_test.rb
|
108
110
|
- test/page_test.rb
|
109
111
|
- test/portion_test.rb
|