dm-pagination 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 YOUR NAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,23 @@
1
+ dm-pagination
2
+ =============
3
+
4
+ A plugin for the Merb framework that provides pagination for DataMapper.
5
+
6
+ USAGE:
7
+
8
+ In your controller,
9
+
10
+ class Posts
11
+ def index
12
+ @posts = Post.paginate(:page => params[:page])
13
+ end
14
+
15
+ In your view,
16
+
17
+ <ul>
18
+ <% @posts.each do |post| %>
19
+ <li><%= h(post.body) %></li>
20
+ <% end %>
21
+ </ul>
22
+ <%= paginate @posts %>
23
+
data/Rakefile ADDED
@@ -0,0 +1,85 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+
4
+ require 'merb-core'
5
+ require 'merb-core/tasks/merb'
6
+
7
+ GEM_NAME = "dm-pagination"
8
+ GEM_VERSION = "0.2.1"
9
+ AUTHOR = "Genki Takiuchi"
10
+ EMAIL = "genki@s21g.com"
11
+ HOMEPAGE = "http://blog.s21g.com/genki"
12
+ SUMMARY = "Merb plugin that provides pagination for DataMapper"
13
+ RUBYFORGE_PROJECT = "asakusarb"
14
+
15
+ spec = Gem::Specification.new do |s|
16
+ s.rubyforge_project = RUBYFORGE_PROJECT
17
+ s.name = GEM_NAME
18
+ s.version = GEM_VERSION
19
+ s.platform = Gem::Platform::RUBY
20
+ s.has_rdoc = true
21
+ s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
22
+ s.summary = SUMMARY
23
+ s.description = s.summary
24
+ s.author = AUTHOR
25
+ s.email = EMAIL
26
+ s.homepage = HOMEPAGE
27
+ s.add_dependency('merb', '>= 1.0.7.1')
28
+ s.require_path = 'lib'
29
+ s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,spec}/**/*")
30
+ end
31
+
32
+ Rake::GemPackageTask.new(spec) do |pkg|
33
+ pkg.need_tar = true
34
+ pkg.gem_spec = spec
35
+ end
36
+
37
+ desc "install the plugin as a gem"
38
+ task :install do
39
+ Merb::RakeHelper.install(GEM_NAME, :version => GEM_VERSION)
40
+ end
41
+
42
+ desc "Uninstall the gem"
43
+ task :uninstall do
44
+ Merb::RakeHelper.uninstall(GEM_NAME, :version => GEM_VERSION)
45
+ end
46
+
47
+ desc "Create a gemspec file"
48
+ task :gemspec do
49
+ File.open("#{GEM_NAME}.gemspec", "w") do |file|
50
+ file.puts spec.to_ruby
51
+ end
52
+ end
53
+
54
+ desc "Run spec"
55
+ task :spec do
56
+ sh "spec spec --color"
57
+ end
58
+
59
+ desc 'Package and upload the release to rubyforge.'
60
+ task :release => :package do |t|
61
+ require 'rubyforge'
62
+ v = ENV["VERSION"] or abort "Must supply VERSION=x.y.z"
63
+ abort "Versions don't match #{v} vs #{GEM_VERSION}" unless v == GEM_VERSION
64
+ pkg = "pkg/#{GEM_NAME}-#{GEM_VERSION}"
65
+
66
+ require 'rubyforge'
67
+ rf = RubyForge.new.configure
68
+ puts "Logging in"
69
+ rf.login
70
+
71
+ c = rf.userconfig
72
+ # c["release_notes"] = description if description
73
+ # c["release_changes"] = changes if changes
74
+ c["preformatted"] = true
75
+
76
+ files = [
77
+ "#{pkg}.tgz",
78
+ "#{pkg}.gem"
79
+ ].compact
80
+
81
+ puts "Releasing #{GEM_NAME} v. #{GEM_VERSION}"
82
+ rf.add_release RUBYFORGE_PROJECT, GEM_NAME, GEM_VERSION, *files
83
+ end
84
+
85
+ task :default => :spec
data/TODO ADDED
@@ -0,0 +1,5 @@
1
+ TODO:
2
+ Fix LICENSE with your name
3
+ Fix Rakefile with your name and contact info
4
+ Add your code to lib/dm-pagination.rb
5
+ Add your Merb rake tasks to lib/dm-pagination/merbtasks.rb
@@ -0,0 +1,6 @@
1
+ namespace :dm_pagination do
2
+ desc "Do something for dm-pagination"
3
+ task :default do
4
+ puts "dm-pagination doesn't do anything"
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ require 'dm-pagination/pagination'
2
+
3
+ module DmPagination
4
+ module Paginatable
5
+ def paginate(options = {})
6
+ Pagination.new(all, options)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,41 @@
1
+ module DmPagination
2
+ class Pagination
3
+ def initialize(collection, options)
4
+ @page = (options[:page] || 1).to_i
5
+ @per_page = (options[:per_page] || 10).to_i
6
+ @proxy_collection = collection
7
+ @collection = collection.all(
8
+ :offset => (@page - 1)*@per_page, :limit => @per_page)
9
+ @num_pages = num_pages
10
+ end
11
+
12
+ def page
13
+ @page
14
+ end
15
+
16
+ def num_pages
17
+ (@proxy_collection.count + @per_page - 1) / @per_page
18
+ end
19
+
20
+ def pages(window = 5, left = 2, right = 2)
21
+ return [] if @num_pages <= 1
22
+ (1..@num_pages).inject([]) do |result, i|
23
+ i <= left || (@num_pages - i) < right || (i-page).abs < window ?
24
+ result << i : (result.last.nil? ? result : result << nil)
25
+ end
26
+ end
27
+
28
+ def count
29
+ offset = (@page - 1)*@per_page
30
+ [0, [@proxy_collection.count - offset, @per_page].min].max
31
+ end
32
+
33
+ def respond_to?(*args, &block)
34
+ super || @collection.send(:respond_to?, *args, &block)
35
+ end
36
+
37
+ def method_missing(method, *args, &block)
38
+ @collection.send(method, *args, &block)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,85 @@
1
+ module DmPagination
2
+ class PaginationBuilder
3
+ def initialize(context, pagination, *args, &block)
4
+ @context = context
5
+ @pagination = pagination
6
+ @block = block
7
+ @options = args.last.kind_of?(Hash) ? args.pop : {}
8
+ @options[:page] ||= :page
9
+ @args = args.blank? ? [:prev, :pages, :next] : args
10
+ end
11
+
12
+ def to_s(*args)
13
+ args = @args if args.blank?
14
+ items = args.map{|i| respond_to?("link_to_#{i}") ?
15
+ send("link_to_#{i}") : []}.flatten
16
+ @context.tag(:div, items.join("\n"), :class => "pagination")
17
+ end
18
+
19
+ def link_to_pages
20
+ @pagination.pages.map{|page| link_to_page(page)}
21
+ end
22
+
23
+ def link_to_prev
24
+ if @pagination.page > 1
25
+ @context.link_to prev_label,
26
+ url(@options[:page] => @pagination.page - 1),
27
+ :class => :prev, :rel => "prev"
28
+ else
29
+ span.call(prev_label, :prev)
30
+ end
31
+ end
32
+
33
+ def link_to_next
34
+ if @pagination.page < @pagination.num_pages
35
+ @context.link_to next_label,
36
+ url(@options[:page] => @pagination.page + 1),
37
+ :class => :next, :rel => "next"
38
+ else
39
+ span.call(next_label, :next)
40
+ end
41
+ end
42
+
43
+ def link_to_page(page)
44
+ if page.nil?
45
+ span.call truncate, @options[:style]
46
+ elsif page == @pagination.page
47
+ span.call page, [@options[:style], 'current'].compact.join(' ')
48
+ else
49
+ span.call link(page), @options[:style]
50
+ end
51
+ end
52
+
53
+ private
54
+ def span
55
+ proc do |*args|
56
+ @context.tag(:span, args[0].to_s,
57
+ :class => [args[1], "disabled"].compact.join(' '))
58
+ end
59
+ end
60
+
61
+ def link(page, *args)
62
+ if @block
63
+ @block.call(page, *args)
64
+ else
65
+ @context.link_to(page, url(@options[:page] => page))
66
+ end
67
+ end
68
+
69
+ def truncate
70
+ @options[:truncate] || Merb::Plugins.config[:dm_pagination][:truncate]
71
+ end
72
+
73
+ def prev_label
74
+ @options[:prev] || Merb::Plugins.config[:dm_pagination][:prev_label]
75
+ end
76
+
77
+ def next_label
78
+ @options[:next] || Merb::Plugins.config[:dm_pagination][:next_label]
79
+ end
80
+
81
+ def url(params)
82
+ @context.url(@context.params.merge(params))
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,41 @@
1
+ # make sure we're running inside Merb
2
+ if defined?(Merb::Plugins)
3
+
4
+ # Merb gives you a Merb::Plugins.config hash...feel free to put your stuff in your piece of it
5
+ Merb::Plugins.config[:dm_pagination] = {
6
+ :prev_label => '&laquo; Prev',
7
+ :next_label => 'Next &raquo;',
8
+ :truncate => '...'
9
+ }
10
+
11
+ Merb::BootLoader.before_app_loads do
12
+ # require code that must be loaded before the application
13
+ require 'dm-pagination/paginatable'
14
+ module DataMapper
15
+ module Resource
16
+ module ClassMethods
17
+ include DmPagination::Paginatable
18
+ end
19
+ end
20
+
21
+ class Collection
22
+ extend DmPagination::Paginatable
23
+ end
24
+ end
25
+
26
+ require 'dm-pagination/pagination_builder'
27
+ module Merb
28
+ module GlobalHelpers
29
+ def paginate(pagination, *args, &block)
30
+ DmPagination::PaginationBuilder.new(self, pagination, *args, &block)
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ Merb::BootLoader.after_app_loads do
37
+ # code that can be required after the application loads
38
+ end
39
+
40
+ Merb::Plugins.add_rakefiles "dm-pagination/merbtasks"
41
+ end
@@ -0,0 +1,99 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ DataMapper.setup(:default, "sqlite3::memory:")
4
+
5
+ Post.auto_migrate!
6
+
7
+ describe "dm-pagination" do
8
+ describe "paginatable" do
9
+ it "should extend DataMapper::Resource" do
10
+ test = Post.new
11
+ test.should_not be_nil
12
+ Post.should be_respond_to(:paginate)
13
+ Post.all.should be_respond_to(:paginate)
14
+ end
15
+
16
+ it "should return Pagination object" do
17
+ Post.paginate.should be_kind_of(DmPagination::Pagination)
18
+ Post.all.paginate.should be_kind_of(DmPagination::Pagination)
19
+ end
20
+
21
+ it "should respond to model's method" do
22
+ Post.paginate.should be_respond_to(:to_atom)
23
+ end
24
+ end
25
+
26
+ describe "pagination" do
27
+ before :all do
28
+ Post.all.destroy!
29
+ 101.times{|i| Post.create(:index => i)}
30
+ end
31
+
32
+ it "should be specified on 101 test posts" do
33
+ Post.count.should == 101
34
+ end
35
+
36
+ it "should have 10 pages" do
37
+ Post.paginate.num_pages.should == 11
38
+ Post.all.paginate.num_pages.should == 11
39
+ end
40
+
41
+ it "should be able to calculate num pages on scope" do
42
+ Post.all(:index.gt => 50).count.should == 50
43
+ Post.all(:index.gt => 50).paginate.num_pages.should == 5
44
+ Post.all(:index.gt => 49).paginate.num_pages.should == 6
45
+ end
46
+
47
+ it "should act as Collection" do
48
+ Post.paginate(:page => 8).count.should == 10
49
+ Post.paginate(:page => 11).count.should == 1
50
+ Post.paginate(:page => 12).count.should == 0
51
+ Post.paginate(:page => 5, :per_page => 6).count.should == 6
52
+ end
53
+ end
54
+
55
+ describe "pagination builder" do
56
+ include Merb::Helpers::Tag
57
+
58
+ before :all do
59
+ Post.all.destroy!
60
+ 101.times{|i| Post.create(:index => i)}
61
+ end
62
+
63
+ it "should be tested on 101 posts" do
64
+ Post.count.should == 101
65
+ end
66
+
67
+ it "should have rendered with pagination" do
68
+ response = request "/pagination_builder/simple"
69
+ response.should be_successful
70
+ response.should have_selector("div.pagination")
71
+ response.should have_selector("ul")
72
+ response.should have_selector("li")
73
+ response.should have_selector("a[rel=next]")
74
+ end
75
+
76
+ it "should have rendered with pagination at page 2" do
77
+ response = request "/pagination_builder/simple", :params => {:page => 2}
78
+ response.should be_successful
79
+ response.should have_selector("a.prev[rel=prev]")
80
+ response.should have_selector("a.next[rel=next]")
81
+ response.body.scan(/Prev|Next/).should == %w(Prev Next)
82
+ url = "/pagination_builder/simple?page=3"
83
+ response.should have_xpath("//a[@href='#{url}']")
84
+ end
85
+
86
+ it "should be able to control links" do
87
+ response = request "/pagination_builder/variant"
88
+ response.should be_successful
89
+ response.body.scan(/Prev|Next/).should == %w(Next Prev)
90
+ response.should have_selector("a.next[rel=next]")
91
+ response.should_not have_selector("a.prev[rel=prev]")
92
+ response.should have_selector("span.prev")
93
+ response.should have_selector("span.number")
94
+ response.should_not have_selector("span.prev.number")
95
+ url = "/pagination_builder/variant?foo=2"
96
+ response.should have_xpath("//a[@href='#{url}']")
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,11 @@
1
+ class PaginationBuilder < Merb::Controller
2
+ def simple
3
+ @posts = Post.paginate(params)
4
+ render
5
+ end
6
+
7
+ def variant
8
+ @posts = Post.paginate(params)
9
+ render
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ class Post
2
+ include DataMapper::Resource
3
+
4
+ property :id, Serial
5
+ property :index, Integer
6
+
7
+ def self.to_atom
8
+ "atom"
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-us" lang="en-us">
3
+ <head>
4
+ <title>Fresh Merb App</title>
5
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
6
+ <link rel="stylesheet" href="/stylesheets/master.css" type="text/css" media="screen" charset="utf-8"/>
7
+ </head>
8
+ <body>
9
+ <%= catch_content :for_layout %>
10
+ </body>
11
+ </html>
@@ -0,0 +1,7 @@
1
+ <ul>
2
+ <% @posts.each do |post| %>
3
+ <li><%= post.index %></li>
4
+ <% end %>
5
+ </ul>
6
+
7
+ <%= paginate @posts %>
@@ -0,0 +1 @@
1
+ <%= paginate @posts, :pages, :next, :prev, :style => 'number', :page => :foo %>
@@ -0,0 +1,13 @@
1
+ Merb::Router.prepare do |r|
2
+ # RESTful routes
3
+ # r.resources :posts
4
+
5
+ # This is the default route for /:controller/:action/:id
6
+ # This is fine for most cases. If you're heavily using resource-based
7
+ # routes, you may want to comment/remove this line to prevent
8
+ # clients from calling your create or destroy actions with a GET
9
+ r.default_routes
10
+
11
+ # Change this for your home page to be available at /
12
+ # r.match('/').to(:controller => 'whatever', :action =>'index')
13
+ end
@@ -0,0 +1,42 @@
1
+ $:.push File.join(File.dirname(__FILE__), '..', 'lib')
2
+ require 'rubygems'
3
+ require 'spec'
4
+ require 'merb-core'
5
+ require 'merb-helpers'
6
+ require 'merb-assets'
7
+ require 'dm-core'
8
+ require 'dm-pagination'
9
+ require 'dm-pagination/paginatable'
10
+ require 'dm-pagination/pagination_builder'
11
+ require 'dm-aggregates'
12
+
13
+ default_options = {
14
+ :environment => 'test',
15
+ :adapter => 'runner',
16
+ :merb_root => File.dirname(__FILE__) / 'fixture',
17
+ :log_file => File.dirname(__FILE__) / '..' / 'log' / "merb_test.log"
18
+ }
19
+ options = default_options.merge($START_OPTIONS || {})
20
+ DataMapper::Model.append_extensions DmPagination::Paginatable
21
+ module Merb
22
+ module GlobalHelpers
23
+ def paginate(pagination, *args, &block)
24
+ DmPagination::PaginationBuilder.new(self, pagination, *args, &block)
25
+ end
26
+ end
27
+ end
28
+
29
+ Merb.disable(:initfile)
30
+ Merb.start_environment(options)
31
+
32
+ Spec::Runner.configure do |config|
33
+ config.include Merb::Test::RequestHelper
34
+ config.include Webrat::Matchers
35
+ config.include Webrat::HaveTagMatcher
36
+
37
+ def with_level(level)
38
+ Merb.logger = Merb::Logger.new(StringIO.new, level)
39
+ yield
40
+ Merb.logger
41
+ end
42
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dm-pagination
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Genki Takiuchi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-27 00:00:00 +09:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: merb
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.0.7.1
24
+ version:
25
+ description: Merb plugin that provides pagination for DataMapper
26
+ email: genki@s21g.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README
33
+ - LICENSE
34
+ - TODO
35
+ files:
36
+ - LICENSE
37
+ - README
38
+ - Rakefile
39
+ - TODO
40
+ - lib/dm-pagination
41
+ - lib/dm-pagination/merbtasks.rb
42
+ - lib/dm-pagination/paginatable.rb
43
+ - lib/dm-pagination/pagination.rb
44
+ - lib/dm-pagination/pagination_builder.rb
45
+ - lib/dm-pagination.rb
46
+ - spec/dm-pagination_spec.rb
47
+ - spec/fixture
48
+ - spec/fixture/app
49
+ - spec/fixture/app/controllers
50
+ - spec/fixture/app/controllers/pagination_builder.rb
51
+ - spec/fixture/app/models
52
+ - spec/fixture/app/models/post.rb
53
+ - spec/fixture/app/views
54
+ - spec/fixture/app/views/layout
55
+ - spec/fixture/app/views/layout/application.html.erb
56
+ - spec/fixture/app/views/pagination_builder
57
+ - spec/fixture/app/views/pagination_builder/simple.html.erb
58
+ - spec/fixture/app/views/pagination_builder/variant.html.erb
59
+ - spec/fixture/config
60
+ - spec/fixture/config/router.rb
61
+ - spec/spec_helper.rb
62
+ has_rdoc: true
63
+ homepage: http://blog.s21g.com/genki
64
+ post_install_message:
65
+ rdoc_options: []
66
+
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: "0"
74
+ version:
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: "0"
80
+ version:
81
+ requirements: []
82
+
83
+ rubyforge_project: asakusarb
84
+ rubygems_version: 1.3.1
85
+ signing_key:
86
+ specification_version: 2
87
+ summary: Merb plugin that provides pagination for DataMapper
88
+ test_files: []
89
+