godfat-pagify 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +31 -0
- data/LICENSE +201 -0
- data/NOTICE +5 -0
- data/README +121 -0
- data/Rakefile +62 -0
- data/TODO +4 -0
- data/lib/pagify.rb +9 -0
- data/lib/pagify/active_record.rb +19 -0
- data/lib/pagify/array.rb +6 -0
- data/lib/pagify/basic.rb +3 -0
- data/lib/pagify/data_mapper.rb +16 -0
- data/lib/pagify/helpers/abstract.rb +92 -0
- data/lib/pagify/helpers/details/setting.rb +54 -0
- data/lib/pagify/helpers/details/setup.rb +23 -0
- data/lib/pagify/helpers/html.rb +85 -0
- data/lib/pagify/null.rb +5 -0
- data/lib/pagify/pagers/active_record.rb +32 -0
- data/lib/pagify/pagers/array.rb +22 -0
- data/lib/pagify/pagers/basic.rb +114 -0
- data/lib/pagify/pagers/data_mapper.rb +30 -0
- data/lib/pagify/pagers/details/page_accept_string_or_blank.rb +14 -0
- data/lib/pagify/pagers/null.rb +17 -0
- data/lib/pagify/pages/basic.rb +58 -0
- data/lib/pagify/pages/null.rb +11 -0
- data/lib/pagify/pagifiers/abstract.rb +34 -0
- data/lib/pagify/pagifiers/active_record.rb +11 -0
- data/lib/pagify/pagifiers/array.rb +9 -0
- data/lib/pagify/pagifiers/data_mapper.rb +11 -0
- data/lib/pagify/version.rb +4 -0
- data/pagify.gemspec +51 -0
- data/spec/pagify_spec.rb +8 -0
- data/spec/spec_helper.rb +17 -0
- data/test/helper.rb +14 -0
- data/test/suite_for_model.rb +125 -0
- data/test/test_active_record.rb +71 -0
- data/test/test_array.rb +19 -0
- data/test/test_basic.rb +22 -0
- data/test/test_data_mapper.rb +55 -0
- data/test/test_html.rb +160 -0
- data/test/test_null.rb +22 -0
- data/test/test_pagify.rb +41 -0
- metadata +176 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
# you'll need dm-core and dm-aggregates to use DataMapperPager
|
3
|
+
|
4
|
+
module Pagify
|
5
|
+
|
6
|
+
class DataMapperPager < BasicPager
|
7
|
+
include PageAcceptStringOrBlank
|
8
|
+
attr_reader :model
|
9
|
+
|
10
|
+
def initialize model_class, opts = {}, query = {}
|
11
|
+
@model = model_class
|
12
|
+
query ||= {}
|
13
|
+
query_opts = reject_pager_opts(opts)
|
14
|
+
|
15
|
+
super(opts.merge(
|
16
|
+
:fetcher => lambda{ |offset, per_page|
|
17
|
+
model.send :with_scope, query do
|
18
|
+
model.all(query_opts.merge(:offset => offset, :limit => per_page))
|
19
|
+
end
|
20
|
+
},
|
21
|
+
:counter => lambda{
|
22
|
+
model.send :with_scope, query do
|
23
|
+
model.count(query_opts)
|
24
|
+
end
|
25
|
+
}))
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
module Pagify
|
3
|
+
|
4
|
+
# a null paginator that stubs any page into a null page.
|
5
|
+
class NullPager < BasicPager
|
6
|
+
include Singleton
|
7
|
+
def initialize
|
8
|
+
super(:fetcher => lambda{|*a|[]}, :counter => lambda{0})
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
def normalize_page n
|
13
|
+
0
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end # of Pagify
|
@@ -0,0 +1,58 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
module Pagify
|
5
|
+
# which was produced by Paginator#page / Paginator#[],
|
6
|
+
# representing page that contained target data.
|
7
|
+
# it would use lazy fetching, whenever you need the data,
|
8
|
+
# the fetcher would be invoked that time. whenever the data
|
9
|
+
# was fetched, it won't fetch again. it you need refetch,
|
10
|
+
# call Page#fetch
|
11
|
+
class BasicPage
|
12
|
+
# prvent Page#to_a return [#<Page:0x12345>]
|
13
|
+
undef_method :to_a if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('1.9.0')
|
14
|
+
|
15
|
+
# pager to get the original pager; page to get the number of this page
|
16
|
+
attr_reader :pager, :page
|
17
|
+
|
18
|
+
# don't create a page instance yourself unless you have to
|
19
|
+
def initialize pager, page; @pager, @page = pager, page; end
|
20
|
+
|
21
|
+
# return the page instance next to this page
|
22
|
+
def next; pager.page(page + 1); end
|
23
|
+
|
24
|
+
# return the page instance prev to this page
|
25
|
+
def prev; pager.page(page - 1); end
|
26
|
+
|
27
|
+
# if the page numbers and the pagers are equal,
|
28
|
+
# then the pages are equal.
|
29
|
+
def == rhs
|
30
|
+
rhs.kind_of?(BasicPage) &&
|
31
|
+
page == rhs.page &&
|
32
|
+
pager == rhs.pager
|
33
|
+
end
|
34
|
+
|
35
|
+
# explicitly fetch the data from pager
|
36
|
+
def fetch; @data = pager.fetcher[self.begin, pager.per_page]; end
|
37
|
+
|
38
|
+
# get the data fetched from pager
|
39
|
+
def data; @data ||= fetch; end
|
40
|
+
|
41
|
+
# the real beginning index
|
42
|
+
def begin; pager.offset page; end
|
43
|
+
|
44
|
+
# the real ending index (need fetch, because we don't know the size)
|
45
|
+
def end; self.begin + self.size - 1; end
|
46
|
+
|
47
|
+
# any other method call would delegate to the data,
|
48
|
+
# e.g., each, to_a, map, first, method_you_defined, etc.
|
49
|
+
def method_missing msg, *args, &block
|
50
|
+
if data.respond_to?(msg)
|
51
|
+
data.__send__(msg, *args, &block)
|
52
|
+
else
|
53
|
+
super(msg, *args, &block)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
module Pagify
|
3
|
+
module Pagifier
|
4
|
+
|
5
|
+
attr_reader :pagify_pager
|
6
|
+
|
7
|
+
def pagify_cache
|
8
|
+
@pagify_cache ||= false
|
9
|
+
end
|
10
|
+
|
11
|
+
# cleanup cache if turn off cache
|
12
|
+
# NOTE: you would face thread-safety problem if you turn on cache
|
13
|
+
def pagify_cache= bool
|
14
|
+
@pagify_pager = nil unless bool
|
15
|
+
@pagify_cache = bool
|
16
|
+
end
|
17
|
+
|
18
|
+
def pagify opts = {}
|
19
|
+
opts = {:per_page => 20, :null_page => false, :page => 1}.merge(opts)
|
20
|
+
page = opts.delete(:page)
|
21
|
+
|
22
|
+
pager = if pagify_cache
|
23
|
+
@pagify_pager ||= pagify_pager_create(self, opts)
|
24
|
+
pagify_pager.opts = opts
|
25
|
+
pagify_pager
|
26
|
+
else
|
27
|
+
pagify_pager_create(self, opts)
|
28
|
+
end
|
29
|
+
|
30
|
+
pager.page(page)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
|
2
|
+
require 'pagify/pagifiers/abstract'
|
3
|
+
|
4
|
+
[ActiveRecord::Base, ActiveRecord::Associations::AssociationCollection].each{ |klass|
|
5
|
+
klass.module_eval do
|
6
|
+
extend Pagify::Pagifier
|
7
|
+
def self.pagify_pager_create model, opts
|
8
|
+
Pagify::ActiveRecordPager.new model, opts
|
9
|
+
end
|
10
|
+
end
|
11
|
+
}
|
data/pagify.gemspec
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
|
2
|
+
# -*- encoding: utf-8 -*-
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = %q{pagify}
|
6
|
+
s.version = "0.5.0"
|
7
|
+
|
8
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
9
|
+
s.authors = ["Lin Jen-Shin (a.k.a. godfat \347\234\237\345\270\270)"]
|
10
|
+
s.date = %q{2008-12-11}
|
11
|
+
s.description = %q{pagination tools for plain Ruby, DataMapper, ActiveRecord, and other ORM.}
|
12
|
+
s.email = %q{godfat (XD) godfat.org}
|
13
|
+
s.extra_rdoc_files = ["CHANGES", "LICENSE", "NOTICE", "README", "TODO", "pagify.gemspec"]
|
14
|
+
s.files = ["CHANGES", "LICENSE", "NOTICE", "README", "Rakefile", "TODO", "lib/pagify.rb", "lib/pagify/active_record.rb", "lib/pagify/array.rb", "lib/pagify/basic.rb", "lib/pagify/data_mapper.rb", "lib/pagify/helpers/abstract.rb", "lib/pagify/helpers/details/setting.rb", "lib/pagify/helpers/details/setup.rb", "lib/pagify/helpers/html.rb", "lib/pagify/null.rb", "lib/pagify/pagers/active_record.rb", "lib/pagify/pagers/array.rb", "lib/pagify/pagers/basic.rb", "lib/pagify/pagers/data_mapper.rb", "lib/pagify/pagers/details/page_accept_string_or_blank.rb", "lib/pagify/pagers/null.rb", "lib/pagify/pages/basic.rb", "lib/pagify/pages/null.rb", "lib/pagify/pagifiers/abstract.rb", "lib/pagify/pagifiers/active_record.rb", "lib/pagify/pagifiers/array.rb", "lib/pagify/pagifiers/data_mapper.rb", "lib/pagify/version.rb", "pagify.gemspec", "spec/pagify_spec.rb", "spec/spec_helper.rb", "tasks/ann.rake", "tasks/bones.rake", "tasks/gem.rake", "tasks/git.rake", "tasks/manifest.rake", "tasks/notes.rake", "tasks/post_load.rake", "tasks/rdoc.rake", "tasks/rubyforge.rake", "tasks/setup.rb", "tasks/spec.rake", "tasks/svn.rake", "tasks/test.rake", "test/helper.rb", "test/suite_for_model.rb", "test/test_active_record.rb", "test/test_array.rb", "test/test_basic.rb", "test/test_data_mapper.rb", "test/test_html.rb", "test/test_null.rb", "test/test_pagify.rb"]
|
15
|
+
s.has_rdoc = true
|
16
|
+
s.homepage = %q{http://github.com/godfat/pagify}
|
17
|
+
s.rdoc_options = ["--diagram", "--charset=utf-8", "--inline-source", "--line-numbers", "--promiscuous", "--main", "README"]
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
s.rubyforge_project = %q{ludy}
|
20
|
+
s.rubygems_version = %q{1.3.1}
|
21
|
+
s.summary = %q{pagination tools for plain Ruby, DataMapper, ActiveRecord, and other ORM.}
|
22
|
+
s.test_files = ["test/test_active_record.rb", "test/test_array.rb", "test/test_basic.rb", "test/test_data_mapper.rb", "test/test_html.rb", "test/test_null.rb", "test/test_pagify.rb"]
|
23
|
+
|
24
|
+
if s.respond_to? :specification_version then
|
25
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
26
|
+
s.specification_version = 2
|
27
|
+
|
28
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
29
|
+
s.add_development_dependency(%q<bones>, [">= 2.1.0"])
|
30
|
+
s.add_development_dependency(%q<extlib>, ["<= 0.9.8"])
|
31
|
+
s.add_development_dependency(%q<dm-core>, ["<= 0.9.7"])
|
32
|
+
s.add_development_dependency(%q<dm-aggregates>, ["<= 0.9.7"])
|
33
|
+
s.add_development_dependency(%q<activerecord>, [">= 2.0.0"])
|
34
|
+
s.add_development_dependency(%q<minitest>, [">= 1.3.0"])
|
35
|
+
else
|
36
|
+
s.add_dependency(%q<bones>, [">= 2.1.0"])
|
37
|
+
s.add_dependency(%q<extlib>, ["<= 0.9.8"])
|
38
|
+
s.add_dependency(%q<dm-core>, ["<= 0.9.7"])
|
39
|
+
s.add_dependency(%q<dm-aggregates>, ["<= 0.9.7"])
|
40
|
+
s.add_dependency(%q<activerecord>, [">= 2.0.0"])
|
41
|
+
s.add_dependency(%q<minitest>, [">= 1.3.0"])
|
42
|
+
end
|
43
|
+
else
|
44
|
+
s.add_dependency(%q<bones>, [">= 2.1.0"])
|
45
|
+
s.add_dependency(%q<extlib>, ["<= 0.9.8"])
|
46
|
+
s.add_dependency(%q<dm-core>, ["<= 0.9.7"])
|
47
|
+
s.add_dependency(%q<dm-aggregates>, ["<= 0.9.7"])
|
48
|
+
s.add_dependency(%q<activerecord>, [">= 2.0.0"])
|
49
|
+
s.add_dependency(%q<minitest>, [">= 1.3.0"])
|
50
|
+
end
|
51
|
+
end
|
data/spec/pagify_spec.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# $Id$
|
2
|
+
|
3
|
+
require File.expand_path(
|
4
|
+
File.join(File.dirname(__FILE__), %w[.. lib pagify]))
|
5
|
+
|
6
|
+
Spec::Runner.configure do |config|
|
7
|
+
# == Mock Framework
|
8
|
+
#
|
9
|
+
# RSpec uses it's own mocking framework by default. If you prefer to
|
10
|
+
# use mocha, flexmock or RR, uncomment the appropriate line:
|
11
|
+
#
|
12
|
+
# config.mock_with :mocha
|
13
|
+
# config.mock_with :flexmock
|
14
|
+
# config.mock_with :rr
|
15
|
+
end
|
16
|
+
|
17
|
+
# EOF
|
data/test/helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'minitest/unit'
|
4
|
+
MiniTest::Unit.autorun
|
5
|
+
|
6
|
+
require 'pagify'
|
7
|
+
|
8
|
+
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('1.8.7')
|
9
|
+
class Symbol
|
10
|
+
def to_proc
|
11
|
+
lambda{ |*args| args.shift.__send__(self, *args) }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
|
2
|
+
# require 'extlib'
|
3
|
+
require 'test/test_pagify'
|
4
|
+
|
5
|
+
module SuiteForModel
|
6
|
+
|
7
|
+
def test_cache_for_pager
|
8
|
+
send(:User).pagify_cache = true
|
9
|
+
|
10
|
+
users1 = send(:User).pagify :page => 1, :per_page => 2
|
11
|
+
pager = send(:User).pagify_pager
|
12
|
+
|
13
|
+
users2 = send(:User).pagify :page => 2, :per_page => 2
|
14
|
+
|
15
|
+
# same pager
|
16
|
+
assert_equal users1.pager.object_id, send(:User).pagify_pager.object_id
|
17
|
+
assert_equal users2.pager.object_id, send(:User).pagify_pager.object_id
|
18
|
+
assert_equal send(:User).pagify(:per_page => 1).pager.object_id, users1.pager.object_id
|
19
|
+
|
20
|
+
# there's cache
|
21
|
+
assert send(:User).pagify_pager != nil
|
22
|
+
|
23
|
+
# cleanup cache
|
24
|
+
send(:User).pagify_cache = false
|
25
|
+
assert_nil send(:User).pagify_pager
|
26
|
+
ensure
|
27
|
+
# ensure we cleanup the cache.
|
28
|
+
send(:User).pagify_cache = false
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_no_cache_for_pager
|
32
|
+
assert_nil send(:User).pagify_pager
|
33
|
+
|
34
|
+
users1 = send(:User).pagify :page => 1, :per_page => 2
|
35
|
+
pager = send(:User).pagify_pager
|
36
|
+
|
37
|
+
users2 = send(:User).pagify :page => 2, :per_page => 2
|
38
|
+
|
39
|
+
assert_nil send(:User).pagify_pager
|
40
|
+
|
41
|
+
# not same pager for same opts
|
42
|
+
assert users1.pager.object_id != send(:User).pagify_pager.object_id
|
43
|
+
assert users2.pager.object_id != send(:User).pagify_pager.object_id
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_page_correctness_fixnum
|
47
|
+
page_correctness 1
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_page_correctness_string
|
51
|
+
page_correctness '1'
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_nil_page_default_page_1
|
55
|
+
users = send(:User).pagify :page => nil, :per_page => 2
|
56
|
+
assert_equal 2, users.pager.size
|
57
|
+
assert_equal 1, users.page
|
58
|
+
end
|
59
|
+
|
60
|
+
def page_correctness page
|
61
|
+
users = send(:User).pagify :page => page, :per_page => 2
|
62
|
+
|
63
|
+
assert_equal 2, users.pager.size
|
64
|
+
assert_equal 1, users.page
|
65
|
+
assert_equal send(:User).first, users.first
|
66
|
+
assert_equal 2, users.size
|
67
|
+
assert_equal send(:User).first(:offset => 2), users.next.first
|
68
|
+
assert_equal 1, users.next.size
|
69
|
+
assert_equal Pagify::NullPage.new(users.pager), users.next.next
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_condition_chain
|
73
|
+
users_A = send(:User).all(:conditions => ['name = ?', 'A']).pagify :page => 1, :per_page => 1
|
74
|
+
assert_equal 1, users_A.size
|
75
|
+
assert_equal 2, users_A.pager.entries_count
|
76
|
+
assert_equal 2, users_A.pager.size # pages
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_association_pagify
|
80
|
+
user = send(:User).first
|
81
|
+
user.pets.push(*send(:Pet).all)
|
82
|
+
assert user.save
|
83
|
+
assert_equal 3, user.pets.count
|
84
|
+
|
85
|
+
page = all_pets_with_name_godfat(user).pagify :page => 2, :per_page => 1
|
86
|
+
assert_equal 1, page.size
|
87
|
+
assert_equal 2, page.pager.size
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.included test_case
|
91
|
+
test_case.module_eval do
|
92
|
+
# due to ruby const lookup is different from method lookup
|
93
|
+
def User; self.class.const_get(:User); end
|
94
|
+
def Pet; self.class.const_get(:Pet); end
|
95
|
+
end
|
96
|
+
|
97
|
+
test_case.const_get(:User).module_eval do
|
98
|
+
create :name => 'A'
|
99
|
+
create :name => 'A'
|
100
|
+
create :name => 'B'
|
101
|
+
end
|
102
|
+
|
103
|
+
test_case.const_get(:Pet).module_eval do
|
104
|
+
create :name => 'Qoo'
|
105
|
+
create :name => 'godfat'
|
106
|
+
create :name => 'godfat'
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# include Extlib::Hook
|
111
|
+
#
|
112
|
+
# private
|
113
|
+
# def i_give_up
|
114
|
+
# if self.class == TestActiveRecord
|
115
|
+
# skip "it's toooooo hard to implement this for active record!! patch wanted!"
|
116
|
+
# end
|
117
|
+
# end
|
118
|
+
#
|
119
|
+
# [:test_same_pager_with_same_opts,
|
120
|
+
# :test_page_correctness,
|
121
|
+
# :test_condition_chain].each{ |test|
|
122
|
+
# before test.to_sym, :i_give_up
|
123
|
+
# }
|
124
|
+
|
125
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
|
2
|
+
require 'test/helper'
|
3
|
+
require 'test/suite_for_model'
|
4
|
+
|
5
|
+
require 'pagify/active_record'
|
6
|
+
|
7
|
+
gem 'dm-core', '<=0.9.7'
|
8
|
+
require 'dm-core' # to help with active record to create database
|
9
|
+
|
10
|
+
class TestActiveRecord < TestPagify
|
11
|
+
def test_for_active_record
|
12
|
+
for_pager Pagify::ActiveRecordPager.new(Topic)
|
13
|
+
end
|
14
|
+
|
15
|
+
class Topic
|
16
|
+
class << self
|
17
|
+
def count opts = {}
|
18
|
+
101
|
19
|
+
end
|
20
|
+
def find all, opts = {}
|
21
|
+
TestPagify.data[opts[:offset], opts[:limit]]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# i am tired with active record!!
|
27
|
+
DataMapper.setup :active_record, 'sqlite3:tmp/active_record.sqlite3'
|
28
|
+
class UserForActiveRecord
|
29
|
+
include DataMapper::Resource
|
30
|
+
property :id, Serial
|
31
|
+
property :name, String
|
32
|
+
def self.default_repository_name
|
33
|
+
:active_record
|
34
|
+
end
|
35
|
+
# why can't i use:
|
36
|
+
storage_name = 'users'
|
37
|
+
# end why
|
38
|
+
storage_names[default_repository_name] = 'users'
|
39
|
+
auto_migrate!
|
40
|
+
end
|
41
|
+
|
42
|
+
class PetForActiveRecord
|
43
|
+
include DataMapper::Resource
|
44
|
+
property :id, Serial
|
45
|
+
property :name, String
|
46
|
+
property :user_id, Integer
|
47
|
+
def self.default_repository_name
|
48
|
+
:active_record
|
49
|
+
end
|
50
|
+
storage_names[default_repository_name] = 'pets'
|
51
|
+
auto_migrate!
|
52
|
+
end
|
53
|
+
|
54
|
+
ActiveRecord::Base.establish_connection(
|
55
|
+
:adapter => 'sqlite3', :database => 'tmp/active_record.sqlite3')
|
56
|
+
|
57
|
+
class User < ActiveRecord::Base
|
58
|
+
has_many :pets
|
59
|
+
end
|
60
|
+
|
61
|
+
class Pet < ActiveRecord::Base
|
62
|
+
belongs_to :user
|
63
|
+
end
|
64
|
+
|
65
|
+
include SuiteForModel
|
66
|
+
|
67
|
+
def all_pets_with_name_godfat user
|
68
|
+
user.pets.all(:conditions => ['name = ?', 'godfat'])
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|