simple_paginate 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +39 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +22 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +77 -0
  7. data/Rakefile +50 -0
  8. data/app/views/simple_paginate/_next_page.html.erb +9 -0
  9. data/app/views/simple_paginate/_next_page.html.haml +7 -0
  10. data/app/views/simple_paginate/_next_page.html.slim +7 -0
  11. data/app/views/simple_paginate/_paginator.html.erb +12 -0
  12. data/app/views/simple_paginate/_paginator.html.haml +9 -0
  13. data/app/views/simple_paginate/_paginator.html.slim +9 -0
  14. data/app/views/simple_paginate/_prev_page.html.erb +9 -0
  15. data/app/views/simple_paginate/_prev_page.html.haml +7 -0
  16. data/app/views/simple_paginate/_prev_page.html.slim +7 -0
  17. data/config/locales/simple_paginate.yml +5 -0
  18. data/gemfiles/.bundle/config +2 -0
  19. data/gemfiles/active_record_42.gemfile +24 -0
  20. data/gemfiles/active_record_42.gemfile.lock +319 -0
  21. data/lib/generators/simple_paginate/config_generator.rb +16 -0
  22. data/lib/generators/simple_paginate/templates/simple_paginate_config.rb +3 -0
  23. data/lib/generators/simple_paginate/views_generator.rb +31 -0
  24. data/lib/simple_paginate/config.rb +21 -0
  25. data/lib/simple_paginate/engine.rb +4 -0
  26. data/lib/simple_paginate/helpers/action_view_extension.rb +19 -0
  27. data/lib/simple_paginate/helpers/paginator.rb +70 -0
  28. data/lib/simple_paginate/helpers/tags.rb +84 -0
  29. data/lib/simple_paginate/models/active_record_extension.rb +27 -0
  30. data/lib/simple_paginate/railtie.rb +16 -0
  31. data/lib/simple_paginate/version.rb +3 -0
  32. data/lib/simple_paginate.rb +9 -0
  33. data/simple_paginate.gemspec +28 -0
  34. data/spec/fake_app/active_record/config.rb +3 -0
  35. data/spec/fake_app/active_record/models.rb +12 -0
  36. data/spec/fake_app/log/development.log +0 -0
  37. data/spec/fake_app/rails_app.rb +38 -0
  38. data/spec/simple_paginate/config_spec.rb +27 -0
  39. data/spec/simple_paginate/helpers/action_view_extension_spec.rb +43 -0
  40. data/spec/simple_paginate/helpers/tags_spec.rb +57 -0
  41. data/spec/simple_paginate/models/active_record_extension_spec.rb +71 -0
  42. data/spec/simple_paginate/version_spec.rb +8 -0
  43. data/spec/spec_helper.rb +19 -0
  44. data/spec/support/database_cleaner.rb +12 -0
  45. metadata +182 -0
@@ -0,0 +1,3 @@
1
+ SimplePaginte.configure do |config|
2
+ # config.default_per_page = 25
3
+ end
@@ -0,0 +1,31 @@
1
+ module SimplePaginate
2
+ module Generators
3
+
4
+ class ViewsGenerator < Rails::Generators::Base
5
+ source_root File.expand_path('../../../../app/views/simple_paginate', __FILE__)
6
+
7
+ class_option :template_engine, :type => :string, :aliases => '-e', :desc => 'Template engine for the views. Available options are "erb", "haml", and "slim".'
8
+
9
+ def self.banner #:nodoc:
10
+ <<-BANNER.chomp
11
+ rails g simple_paginate:views [options]
12
+
13
+ Copies all paginator partial templates to your application.
14
+ BANNER
15
+ end
16
+
17
+ def copy_views
18
+ filename_pattern = File.join self.class.source_root, "*.html.#{template_engine}"
19
+ Dir.glob(filename_pattern).map {|f| File.basename f}.each do |f|
20
+ copy_file f, "app/views/simple_paginate/#{f}"
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def template_engine
27
+ options[:template_engine].try(:to_s).try(:downcase) || 'erb'
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,21 @@
1
+ require 'active_support/configurable'
2
+
3
+ module SimplePaginate
4
+ def self.configure(&block)
5
+ yield @config ||= SimplePaginate::Configuration.new
6
+ end
7
+
8
+ def self.config
9
+ @config
10
+ end
11
+
12
+ class Configuration
13
+ include ActiveSupport::Configurable
14
+
15
+ config_accessor :default_per_page
16
+ end
17
+
18
+ configure do |config|
19
+ config.default_per_page = 25
20
+ end
21
+ end
@@ -0,0 +1,4 @@
1
+ module SimplePaginate
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,19 @@
1
+ module SimplePaginate
2
+ module ActionViewExtension
3
+ # A helper that renders the pagination links
4
+ def simple_paginate(scope, options = {})
5
+ paginator = SimplePaginate::Helpers::Paginator.new self, options.reverse_merge(current_page: scope.current_page, per_page: scope.limit_value, length: scope.length)
6
+ paginator.to_s
7
+ end
8
+
9
+ def link_to_previous_page(scope, name = nil, options = {})
10
+ prev_page = SimplePaginate::Helpers::PrevPage.new self, options.reverse_merge(:current_page => scope.current_page)
11
+ link_to_unless scope.first_page?, name, prev_page.url, options.except(:params, :param_name).reverse_merge(:rel => 'prev')
12
+ end
13
+
14
+ def link_to_next_page(scope, name = nil, options = {})
15
+ next_page = SimplePaginate::Helpers::NextPage.new self, options.reverse_merge(:current_page => scope.current_page)
16
+ link_to_unless scope.last_page?, name, next_page.url, options.except(:params, :param_name).reverse_merge(:rel => 'next')
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,70 @@
1
+ require 'action_view'
2
+ require 'simple_paginate/helpers/tags'
3
+
4
+ module SimplePaginate
5
+ module Helpers
6
+ class Paginator < Tag
7
+ include ActionView::Context
8
+
9
+ def initialize(template, options)
10
+ super template, options.merge(current_page: PageProxy.new(options))
11
+ @output_buffer = ActionView::OutputBuffer.new
12
+ end
13
+
14
+ def render(&block)
15
+ instance_eval(&block)
16
+ @output_buffer
17
+ end
18
+
19
+ def prev_page_tag
20
+ PrevPage.new @template, @options
21
+ end
22
+
23
+ def next_page_tag
24
+ NextPage.new @template, @options
25
+ end
26
+
27
+ def to_s
28
+ super @options.merge(paginator: self)
29
+ end
30
+
31
+ class PageProxy
32
+ def initialize(options)
33
+ @options = options
34
+ end
35
+
36
+ def number
37
+ @options[:current_page]
38
+ end
39
+
40
+ def first?
41
+ @options[:current_page] == 1
42
+ end
43
+
44
+ def last?
45
+ @options[:length] < @options[:per_page]
46
+ end
47
+
48
+ def to_i
49
+ number
50
+ end
51
+
52
+ def to_s
53
+ number.to_s
54
+ end
55
+
56
+ def +(other)
57
+ to_i + other.to_i
58
+ end
59
+
60
+ def -(other)
61
+ to_i - other.to_i
62
+ end
63
+
64
+ def <=>(other)
65
+ to_i <=> other.to_i
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,84 @@
1
+ module SimplePaginate
2
+ module Helpers
3
+ PARAM_KEY_BLACKLIST = :authenticity_token, :commit, :utf8, :_method
4
+ PARAM_NAME = 'page'
5
+
6
+ class Tag
7
+ def initialize(template, options = {})
8
+ @template, @options = template, options
9
+ @views_prefix = @options.delete(:views_prefix)
10
+ @params = template.params.except(*PARAM_KEY_BLACKLIST).merge(@options.delete(:params) || {})
11
+ end
12
+
13
+ def to_s(locals = {})
14
+ @template.render partial: partial_path, locals: @options.merge(locals), formats: [:html]
15
+ end
16
+
17
+ def page_url_for(page)
18
+ @template.url_for params_for(page).merge(only_path: true)
19
+ end
20
+
21
+ private
22
+
23
+ def params_for(page)
24
+ page_params = Rack::Utils.parse_nested_query("#{PARAM_NAME}=#{page}")
25
+ page_params = @params.with_indifferent_access.deep_merge(page_params)
26
+
27
+ if page <= 1
28
+ PARAM_NAME.to_s.scan(/\w+/)[0..-2].inject(page_params){|h, k| h[k] }[$&] = nil
29
+ end
30
+
31
+ page_params
32
+ end
33
+
34
+ def partial_path
35
+ [@views_prefix,
36
+ 'simple_paginate',
37
+ self.class.name.demodulize.underscore
38
+ ].compact.join('/')
39
+ end
40
+ end
41
+
42
+ module Link
43
+ def page
44
+ raise 'Override page with the actual page value to be a Page.'
45
+ end
46
+
47
+ def url
48
+ page_url_for(page)
49
+ end
50
+
51
+ def to_s(locals = {})
52
+ super locals.merge(url: url)
53
+ end
54
+ end
55
+
56
+ class Page < Tag
57
+ include Link
58
+
59
+ def page
60
+ @options[:page]
61
+ end
62
+
63
+ def to_s(locals = {})
64
+ super locals.merge(page: page)
65
+ end
66
+ end
67
+
68
+ class PrevPage < Tag
69
+ include Link
70
+
71
+ def page
72
+ @options[:current_page] - 1
73
+ end
74
+ end
75
+
76
+ class NextPage < Tag
77
+ include Link
78
+
79
+ def page
80
+ @options[:current_page] + 1
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,27 @@
1
+ module SimplePaginate
2
+ module ActiveRecordExtension
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ def self.paginate(options = {})
7
+ options = options.dup
8
+ page = options.delete(:page) || 1
9
+ per_page = options.delete(:per_page) || SimplePaginate.config.default_per_page
10
+
11
+ offset(per_page * (page - 1)).limit(per_page + 1).extending do
12
+ def current_page
13
+ (offset_value / (limit_value - 1)) + 1
14
+ end
15
+
16
+ def first_page?
17
+ current_page == 1
18
+ end
19
+
20
+ def last_page?
21
+ length < limit_value
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,16 @@
1
+ module SimplePaginate
2
+ class Railtie < Rails::Railtie
3
+ initializer 'simple_paginate' do |app|
4
+ ActiveSupport.on_load :active_record do
5
+ require 'simple_paginate/models/active_record_extension'
6
+ ::ActiveRecord::Base.send :include, SimplePaginate::ActiveRecordExtension
7
+ end
8
+
9
+ ActiveSupport.on_load :action_view do
10
+ require 'simple_paginate/helpers/action_view_extension'
11
+ require 'simple_paginate/helpers/paginator'
12
+ ::ActionView::Base.send :include, SimplePaginate::ActionViewExtension
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,3 @@
1
+ module SimplePaginate
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,9 @@
1
+ module SimplePaginate
2
+ end
3
+
4
+ if defined?(Rails::Railtie)
5
+ require 'simple_paginate/railtie'
6
+ require 'simple_paginate/engine'
7
+ end
8
+
9
+ require 'simple_paginate/config'
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'simple_paginate/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "simple_paginate"
8
+ spec.version = SimplePaginate::VERSION
9
+ spec.authors = ["Yong Gu"]
10
+ spec.email = ["zerogy921@gmail.com"]
11
+ spec.summary = %q{Simple pagination solution for previous and next page navigation.}
12
+ spec.description = %q{Simple pagination solution for previous and next page navigation.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'activesupport', ['>= 3.0.0']
22
+ spec.add_dependency 'actionpack', ['>= 3.0.0']
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.6"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "rspec", "~> 3.2"
27
+ spec.add_development_dependency 'database_cleaner', ['~> 1.4.0']
28
+ end
@@ -0,0 +1,3 @@
1
+ # database
2
+ ActiveRecord::Base.configurations = {'test' => {:adapter => 'sqlite3', :database => ':memory:'}}
3
+ ActiveRecord::Base.establish_connection :test
@@ -0,0 +1,12 @@
1
+ # models
2
+ class User < ActiveRecord::Base
3
+ end
4
+
5
+ #migrations
6
+ class CreateAllTables < ActiveRecord::Migration
7
+ def self.up
8
+ create_table(:users) {|t| t.string :name; t.integer :age}
9
+ end
10
+ end
11
+ ActiveRecord::Migration.verbose = false
12
+ CreateAllTables.up
File without changes
@@ -0,0 +1,38 @@
1
+ require 'action_controller/railtie'
2
+ require 'action_view/railtie'
3
+
4
+ require 'fake_app/active_record/config'
5
+ # config
6
+ app = Class.new(Rails::Application)
7
+ app.config.secret_key_base = '9489b3eee4eccf317ed77407553e8adc97baca7c74dc7ee33cd93e4c8b69477eea66eaedeb18af0be2679887c7c69c0a28c0fded0a71ea472a8c4laalal19cb'
8
+ app.config.secret_token = '3b7cd727ee24e8444053437c36cc66c4'
9
+ app.config.session_store :cookie_store, :key => '_myapp_session'
10
+ app.config.active_support.deprecation = :log
11
+ app.config.eager_load = false
12
+ # Rais.root
13
+ app.config.root = File.dirname(__FILE__)
14
+ Rails.backtrace_cleaner.remove_silencers!
15
+ app.initialize!
16
+
17
+ # routes
18
+ app.routes.draw do
19
+ resources :users
20
+ end
21
+
22
+ #models
23
+ require 'fake_app/active_record/models'
24
+
25
+ # controllers
26
+ class ApplicationController < ActionController::Base; end
27
+ class UsersController < ApplicationController
28
+ def index
29
+ @users = User.paginate page: params[:page]
30
+ render :inline => <<-ERB
31
+ <%= @users.map(&:name).join("\n") %>
32
+ <%= simple_paginate @users %>
33
+ ERB
34
+ end
35
+ end
36
+
37
+ # helpers
38
+ Object.const_set(:ApplicationHelper, Module.new)
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe SimplePaginate::Configuration do
4
+ subject { SimplePaginate.config }
5
+
6
+ describe 'default_per_page' do
7
+ context 'by default' do
8
+ it { expect(subject.default_per_page).to eq 25 }
9
+ end
10
+
11
+ context 'configured via config block' do
12
+ before do
13
+ SimplePaginate.configure do |config|
14
+ config.default_per_page = 20
15
+ end
16
+ end
17
+
18
+ it { expect(subject.default_per_page).to eq 25 }
19
+
20
+ before do
21
+ SimplePaginate.configure do |config|
22
+ config.default_per_page = 25
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'SimplePaginate::ActionViewExtension', type: :helper do
4
+ before :all do
5
+ 1.upto(100) {|i| User.create name: "user#{'%03d' % i}"}
6
+ end
7
+
8
+ after :all do
9
+ DatabaseCleaner.clean_with(:truncation)
10
+ end
11
+
12
+ describe '#link_to_previous_page' do
13
+ subject { helper.link_to_previous_page users, 'Previous Page', params: { controller: 'users', action: 'index' } }
14
+
15
+ context 'having previous pages' do
16
+ let(:users) { User.paginate(page: 3) }
17
+
18
+ it { expect(subject).to eq('<a rel="prev" href="/users?page=2">Previous Page</a>') }
19
+ end
20
+
21
+ context 'the first page' do
22
+ let(:users) { User.paginate(page: 1) }
23
+
24
+ it { expect(subject).to eq('Previous Page') }
25
+ end
26
+ end
27
+
28
+ describe '#link_to_next_page' do
29
+ subject { helper.link_to_next_page users, 'Next Page', params: { controller: 'users', action: 'index' } }
30
+
31
+ context 'having next pages' do
32
+ let(:users) { User.paginate(page: 3) }
33
+
34
+ it { expect(subject).to eq('<a rel="next" href="/users?page=4">Next Page</a>') }
35
+ end
36
+
37
+ context 'the last page' do
38
+ let(:users) { User.paginate(page: 4) }
39
+
40
+ it { expect(subject).to eq('Next Page') }
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+ include SimplePaginate::Helpers
3
+
4
+ describe 'SimplePaginate::Helpers', type: :helper do
5
+ describe 'Tag' do
6
+ describe '#page_url_for' do
7
+ before { helper.request.assign_parameters(_routes, 'users', 'index') }
8
+
9
+ context 'for first page' do
10
+ subject { Tag.new(helper).page_url_for(1) }
11
+ it { expect(subject).to eq('/users') }
12
+ end
13
+
14
+ context 'with a friendly route setting' do
15
+ before do
16
+ helper.request.assign_parameters(_routes, 'users', 'index', page: 3)
17
+ end
18
+
19
+ context 'for first page' do
20
+ subject { Tag.new(helper).page_url_for(1) }
21
+ it { expect(subject).to eq('/users') }
22
+ end
23
+
24
+ context 'for other page' do
25
+ subject { Tag.new(helper).page_url_for(5) }
26
+ it { expect(subject).to eq('/users?page=5') }
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ describe 'Paginator' do
33
+ describe 'Paginator::PageProxy' do
34
+ describe '#first?' do
35
+ context 'page == 1' do
36
+ subject { Paginator::PageProxy.new(current_page: 1, length: 20, per_page: 25) }
37
+ it { expect(subject.first?).to be_truthy }
38
+ end
39
+ context 'page != 1' do
40
+ subject { Paginator::PageProxy.new(current_page: 5, length: 20, per_page: 25) }
41
+ it { expect(subject.first?).to be_falsey }
42
+ end
43
+ end
44
+
45
+ describe '#last?' do
46
+ context 'length == per_page' do
47
+ subject { Paginator::PageProxy.new(current_page: 5, length: 25, per_page: 25) }
48
+ it { expect(subject.last?).to be_falsey}
49
+ end
50
+ context 'length < per_page' do
51
+ subject { Paginator::PageProxy.new(current_page: 5, length: 20, per_page: 25) }
52
+ it { expect(subject.last?).to be_truthy }
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ describe SimplePaginate::ActiveRecordExtension do
4
+ before :all do
5
+ 1.upto(100) {|i| User.create name: "user#{'%03d' % i}"}
6
+ end
7
+
8
+ after :all do
9
+ DatabaseCleaner.clean_with(:truncation)
10
+ end
11
+
12
+ describe '#paginate' do
13
+ subject { User.paginate(page: page) }
14
+
15
+ context 'page 1' do
16
+ let(:page) { 1 }
17
+
18
+ it { expect(subject.first.name).to eq('user001') }
19
+ end
20
+
21
+ context 'page 2' do
22
+ let(:page) { 2 }
23
+
24
+ it { expect(subject.first.name).to eq('user026') }
25
+ end
26
+
27
+ context 'page < 1' do
28
+ let(:page) { 0 }
29
+
30
+ it { expect(subject.first.name).to eq('user001') }
31
+ end
32
+
33
+ context 'page > max page' do
34
+ let(:page) { 5 }
35
+
36
+ it { expect(subject).to be_empty }
37
+ end
38
+ end
39
+
40
+ describe '#current_page' do
41
+ context 'page 1' do
42
+ subject { User.paginate(page: 1) }
43
+ it { expect(subject.current_page).to eq 1 }
44
+ end
45
+ end
46
+
47
+ describe '#first_page?' do
48
+ context 'on first page' do
49
+ subject { User.paginate(page: 1) }
50
+ it { expect(subject.first_page?).to be_truthy }
51
+ end
52
+
53
+ context 'not on first page' do
54
+ subject { User.paginate(page: 2) }
55
+ it { expect(subject.first_page?).to be_falsey }
56
+ end
57
+ end
58
+
59
+ describe '#last_page?' do
60
+ context 'on last page' do
61
+ subject { User.paginate(page: 4) }
62
+
63
+ it { expect(subject.last_page?).to be_truthy }
64
+ end
65
+
66
+ context 'not on last page' do
67
+ subject { User.paginate(page: 3) }
68
+ it { expect(subject.last_page?).to be_falsey }
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe SimplePaginate::VERSION do
4
+ it 'returns right value' do
5
+ expect(SimplePaginate::VERSION).to eq('0.0.1')
6
+ end
7
+ end
8
+
@@ -0,0 +1,19 @@
1
+ begin
2
+ require 'rails'
3
+ rescue LoadError
4
+ end
5
+
6
+ require 'bundler/setup'
7
+ Bundler.require
8
+
9
+ require 'database_cleaner'
10
+ require 'fake_app/rails_app'
11
+ require 'rspec/rails'
12
+
13
+ # Requires supporting files with custom matchers and macros, etc,
14
+ # in ./support/ and its subdirectories.
15
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
16
+
17
+ RSpec.configure do |config|
18
+ config.infer_spec_type_from_file_location!
19
+ end
@@ -0,0 +1,12 @@
1
+ RSpec.configure do |config|
2
+ config.before :suite do
3
+ DatabaseCleaner.strategy = :transaction
4
+ DatabaseCleaner.clean_with :truncation
5
+ end
6
+
7
+ config.around(:each) do |example|
8
+ DatabaseCleaner.cleaning do
9
+ example.run
10
+ end
11
+ end
12
+ end