leaflet 0.0.1
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 +37 -0
- data/lib/leaflet/collection.rb +124 -0
- data/lib/leaflet/configuration.rb +42 -0
- data/lib/leaflet/version.rb +9 -0
- data/lib/leaflet.rb +35 -0
- data/spec/lib/leaflet/collection_spec.rb +97 -0
- data/spec/lib/leaflet_spec.rb +45 -0
- data/spec/spec_helper.rb +1 -0
- metadata +104 -0
data/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# Leaflet
|
2
|
+
|
3
|
+
A very robust light-weight paginator based on [leaf](http://github.com/c7/leaf) which is based on [will_paginate](http://github.com/mislav/will_paginate).
|
4
|
+
|
5
|
+
# Design principles
|
6
|
+
|
7
|
+
* Does not fiddle with Array, ActiveRecord, or anything else. It is self-contained.
|
8
|
+
* Compatible with both [will_paginate](http://github.com/mislav/will_paginate) and [kaminari](http://github.com/amatsuda/kaminari) API.
|
9
|
+
* Never raise an exception! Negative pages will simple become positive, out of bounds simple means to the last page, etc...
|
10
|
+
|
11
|
+
# Features
|
12
|
+
|
13
|
+
* Convert an Array into a Collection
|
14
|
+
* Create a partial Collection from any data subset (something [like this](http://wiseleyb.tumblr.com/post/2896145167/willpaginate-with-redis-on-rails-3))
|
15
|
+
* Export as JSON for transferring the collection over an API
|
16
|
+
|
17
|
+
# Installation
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
gem install leaflet
|
21
|
+
```
|
22
|
+
|
23
|
+
# Examples
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
# Converting an Array into a paginatable Collection
|
27
|
+
complete_collection = Leafet::Collection.new my_array
|
28
|
+
complete_collection.paginate(page: 5, per_page: 3) # <-- Returns an Array with the paginated subset of the original Array
|
29
|
+
|
30
|
+
# Creating a custom Collection
|
31
|
+
my_array_subset = [:d, :e, :f] # E.g. fetched from Redis according to page and per_page
|
32
|
+
collection = Leafet::Collection.new my_array_subset, total: 26, page:2, per_page: 3
|
33
|
+
```
|
34
|
+
|
35
|
+
# Credits
|
36
|
+
|
37
|
+
Leaflet is based on [leaf](http://github.com/c7/leaf) (by Peter Hellberg) which is based on [will_paginate](http://github.com/mislav/will_paginate) by PJ Hyett, who later handed over development to Mislav Marohnić.
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'leaflet/configuration'
|
2
|
+
|
3
|
+
module Leaflet
|
4
|
+
class Collection < Array
|
5
|
+
|
6
|
+
PartialCollectionCannotBePaginated = Class.new(StandardError)
|
7
|
+
|
8
|
+
# ––––––––––––––
|
9
|
+
# Initialization
|
10
|
+
# ––––––––––––––
|
11
|
+
|
12
|
+
def initialize(*args)
|
13
|
+
if args.size == 1
|
14
|
+
# An Array was passed in. "Convert" it to a Collection.
|
15
|
+
replace args.shift
|
16
|
+
|
17
|
+
elsif args.size == 2
|
18
|
+
# Someone is building a custom Paginator, let's fetch the data.
|
19
|
+
options = args.pop
|
20
|
+
records = Array(args.shift)
|
21
|
+
replace records
|
22
|
+
@current_page = options[:page]
|
23
|
+
@per_page = options[:per_page]
|
24
|
+
@total_entries = options[:total] || self.size
|
25
|
+
|
26
|
+
else
|
27
|
+
raise ArgumentError
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def paginate(options = {})
|
32
|
+
raise PartialCollectionCannotBePaginated unless complete?
|
33
|
+
preliminary = self.class.new [], options.merge!(total: self.size)
|
34
|
+
result = self.class.new self[preliminary.offset, preliminary.per_page].to_a, options
|
35
|
+
end
|
36
|
+
|
37
|
+
# –––––––––––––––––––––––
|
38
|
+
# Public Instance Getters
|
39
|
+
# –––––––––––––––––––––––
|
40
|
+
|
41
|
+
def total_entries
|
42
|
+
Leaflet.positify {
|
43
|
+
@total_entries ||= self.size
|
44
|
+
}
|
45
|
+
end
|
46
|
+
alias :total_count :total_entries # Kaminari
|
47
|
+
|
48
|
+
def per_page
|
49
|
+
Leaflet.positify(max: Leaflet.config.max_per_page) {
|
50
|
+
@per_page ||= Leaflet.config.default_per_page
|
51
|
+
}
|
52
|
+
end
|
53
|
+
alias :limit_value :per_page # Kaminari
|
54
|
+
|
55
|
+
def current_page
|
56
|
+
Leaflet.positify(max: total_pages) {
|
57
|
+
@current_page ||= 1
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
# ––––––––––––––––––––
|
62
|
+
# Public Class Getters
|
63
|
+
# ––––––––––––––––––––
|
64
|
+
|
65
|
+
def offset
|
66
|
+
(current_page - 1) * per_page
|
67
|
+
end
|
68
|
+
alias :offset_value :offset # Kaminari
|
69
|
+
|
70
|
+
def total_pages
|
71
|
+
Leaflet.positify {
|
72
|
+
total_entries.zero? ? 1 : (total_entries / per_page.to_f).ceil
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
def inspect
|
77
|
+
result = ['#<Collection with']
|
78
|
+
result << (complete? ? "#{self.size} records" : "#{self.size}/#{total_entries} records")
|
79
|
+
result << "on page #{current_page}/#{total_pages} (#{per_page} per page): #{self.to_a}>"
|
80
|
+
result.join(' ')
|
81
|
+
end
|
82
|
+
|
83
|
+
def previous_page
|
84
|
+
current_page > 1 ? (current_page - 1) : nil
|
85
|
+
end
|
86
|
+
|
87
|
+
def next_page
|
88
|
+
current_page < total_pages ? (current_page + 1) : nil
|
89
|
+
end
|
90
|
+
|
91
|
+
def first_page?
|
92
|
+
current_page == 1
|
93
|
+
end
|
94
|
+
|
95
|
+
def last_page?
|
96
|
+
current_page == total_pages
|
97
|
+
end
|
98
|
+
|
99
|
+
def as_json(options = {})
|
100
|
+
{
|
101
|
+
total_entries: total_entries,
|
102
|
+
total_count: total_count,
|
103
|
+
per_page: per_page,
|
104
|
+
limit_value: limit_value,
|
105
|
+
current_page: current_page,
|
106
|
+
offset: offset,
|
107
|
+
offset_value: offset_value,
|
108
|
+
otal_pages: total_pages,
|
109
|
+
records: self.to_a
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
# ––––––––––––––––––––––
|
116
|
+
# Internal Class Getters
|
117
|
+
# ––––––––––––––––––––––
|
118
|
+
|
119
|
+
def complete?
|
120
|
+
self.size == total_entries
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Leaflet
|
4
|
+
class Configuration
|
5
|
+
|
6
|
+
attr_writer :default_per_page, :max_per_page
|
7
|
+
|
8
|
+
def default_per_page
|
9
|
+
Leaflet.positify {
|
10
|
+
@default_per_page ||= 20
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
def max_per_page
|
15
|
+
Leaflet.positify {
|
16
|
+
@max_per_page ||= 30
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module Leaflet
|
24
|
+
|
25
|
+
# Public: Returns the the configuration instance.
|
26
|
+
#
|
27
|
+
def self.config
|
28
|
+
@config ||= Configuration.new
|
29
|
+
end
|
30
|
+
|
31
|
+
# Public: Yields the configuration instance.
|
32
|
+
#
|
33
|
+
def self.configure(&block)
|
34
|
+
yield config
|
35
|
+
end
|
36
|
+
|
37
|
+
# Public: Reset the configuration (useful for testing)
|
38
|
+
#
|
39
|
+
def self.reset!
|
40
|
+
@config = nil
|
41
|
+
end
|
42
|
+
end
|
data/lib/leaflet.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'leaflet/configuration'
|
2
|
+
require 'leaflet/collection'
|
3
|
+
require 'leaflet/version'
|
4
|
+
|
5
|
+
module Leaflet
|
6
|
+
|
7
|
+
def self.positify(*args, &block)
|
8
|
+
if block_given?
|
9
|
+
raise(ArgumentError, "You can only pass in one options Hash in block mode, not #{args.inspect}") if args.size > 1
|
10
|
+
object = block.call
|
11
|
+
options = args.shift || {}
|
12
|
+
else
|
13
|
+
case args.size
|
14
|
+
when 1
|
15
|
+
object = args.shift
|
16
|
+
options = {}
|
17
|
+
raise(ArgumentError, "You forgot the brackets in your call. Try: Leaflet.positify(...) do") if object.is_a?(Hash)
|
18
|
+
when 2
|
19
|
+
object = args.shift
|
20
|
+
options = args.shift
|
21
|
+
else
|
22
|
+
raise ArgumentError, "You must pass in an object and may pass in an options Hash, not #{args.inspect}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
options[:max] = positify(options[:max]) if options[:max]
|
27
|
+
|
28
|
+
return 1 unless object.respond_to?(:to_i)
|
29
|
+
result = object.to_i.abs > 0 ? object.to_i.abs : 1
|
30
|
+
result = options[:max] if options[:max] && options[:max] < result
|
31
|
+
result
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Leaflet::Collection do
|
4
|
+
let(:array) { ('a'..'e').to_a }
|
5
|
+
|
6
|
+
context 'converting an Array into a Collection' do
|
7
|
+
let(:collection) { Leaflet::Collection.new(array) }
|
8
|
+
|
9
|
+
describe '#current_page' do
|
10
|
+
it 'is the passed in parameter' do
|
11
|
+
collection.current_page.should == 1
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'never gets out of bounds' do
|
15
|
+
collection = Leaflet::Collection.new(array, page: 99, per_page: 2)
|
16
|
+
collection.current_page.should == 3
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#per_page' do
|
21
|
+
it 'is the default per_page' do
|
22
|
+
collection.per_page.should == 20
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#limit_value ' do
|
27
|
+
it 'is an alias for per_page' do
|
28
|
+
collection.per_page.should == collection.per_page
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#total_entries' do
|
33
|
+
it 'corresponds to the records size' do
|
34
|
+
collection.total_entries.should == 5
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#total_count' do
|
39
|
+
it 'is an alias for #total_entries' do
|
40
|
+
collection.total_count.should == collection.total_entries
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#paginate' do
|
45
|
+
it 'returns a subset of original collection' do
|
46
|
+
collection.paginate(page: 1, per_page: 3).should == %w{ a b c }
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'can be shorter than per_page if on last page' do
|
50
|
+
collection.paginate(page: 2, per_page: 3).should == %w{ d e }
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'includes whole collection if per_page permits' do
|
54
|
+
collection.paginate(page: 1, per_page: 5).should == collection
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'never gets out of bounds' do
|
58
|
+
collection.paginate(page: 4, per_page: 2).should == %w{ e }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'custom Collection' do
|
64
|
+
let(:collection) { Leaflet::Collection.new(array, total: 40, per_page: 4, page: 4) }
|
65
|
+
|
66
|
+
describe '#total_entries' do
|
67
|
+
it 'is the passed in parameter' do
|
68
|
+
collection.total_entries.should == 40
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#total_pages' do
|
73
|
+
it 'is calculated from the passed in total' do
|
74
|
+
collection.total_pages.should == 10
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '#per_page' do
|
79
|
+
it 'is calculated from the passed in total' do
|
80
|
+
collection.per_page.should == 4
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#current_page' do
|
85
|
+
it 'is the passed in parameter' do
|
86
|
+
collection.current_page.should == 4
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe '#paginate' do
|
91
|
+
it 'is not possible on a non-complete collection' do
|
92
|
+
expect { collection.paginate }.to raise_exception(Leaflet::Collection::PartialCollectionCannotBePaginated)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Leaflet do
|
4
|
+
|
5
|
+
describe '.positify' do
|
6
|
+
it 'makes negative numbers positive' do
|
7
|
+
Leaflet.positify(-5).should == 5
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'turns 0 to 1' do
|
11
|
+
Leaflet.positify(0).should == 1
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'returns 1 on non Fixnumerable objects' do
|
15
|
+
Leaflet.positify(OpenStruct.new).should == 1
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'chops Floats to Fixnums' do
|
19
|
+
Leaflet.positify(5.9).should == 5
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'sets a ceiling' do
|
23
|
+
Leaflet.positify(30, max: 22).should == 22
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'ignores the ceiling if the value is below it ' do
|
27
|
+
Leaflet.positify(30, max: 35).should == 30
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'block mode' do
|
31
|
+
it 'makes negative numbers positive' do
|
32
|
+
Leaflet.positify { -5 }.should == 5
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'sets a ceiling' do
|
36
|
+
Leaflet.positify(max: 25) { 30 }.should == 25
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'ignores the ceiling if the value is below it ' do
|
40
|
+
Leaflet.positify(max: 35) { 30 }.should == 30
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'leaflet'
|
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: leaflet
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- bukowskis
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-05 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: guard-rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rb-fsevent
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: A very robust, custom, light-weight paginator. Based on the leaf gem
|
63
|
+
which is based on the will_paginate gem.
|
64
|
+
email:
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- lib/leaflet/collection.rb
|
70
|
+
- lib/leaflet/configuration.rb
|
71
|
+
- lib/leaflet/version.rb
|
72
|
+
- lib/leaflet.rb
|
73
|
+
- spec/lib/leaflet/collection_spec.rb
|
74
|
+
- spec/lib/leaflet_spec.rb
|
75
|
+
- spec/spec_helper.rb
|
76
|
+
- README.md
|
77
|
+
homepage: https://github.com/bukowskis/leaflet
|
78
|
+
licenses:
|
79
|
+
- MIT
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options:
|
82
|
+
- --encoding
|
83
|
+
- UTF-8
|
84
|
+
require_paths:
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ! '>='
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ! '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
requirements: []
|
99
|
+
rubyforge_project:
|
100
|
+
rubygems_version: 1.8.23
|
101
|
+
signing_key:
|
102
|
+
specification_version: 3
|
103
|
+
summary: A very robust, custom, light-weight paginator.
|
104
|
+
test_files: []
|