godfat-pagify 0.5.0
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/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
|