godfat-pagify 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,14 @@
1
+
2
+ module Pagify
3
+ module PageAcceptStringOrBlank
4
+ private
5
+ def normalize_page n
6
+ if n.blank?
7
+ n = 1
8
+ else
9
+ n = n.to_i
10
+ end
11
+ end
12
+ end
13
+
14
+ 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,11 @@
1
+
2
+ module Pagify
3
+
4
+ # a null page that stubs anything to 0 or [], etc.
5
+ class NullPage < BasicPage
6
+ def initialize pager = NullPager.instance, page = 0
7
+ super(pager, page)
8
+ end
9
+ end
10
+
11
+ end # of Pagify
@@ -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
+ }
@@ -0,0 +1,9 @@
1
+
2
+ require 'pagify/pagifiers/abstract'
3
+
4
+ class Array
5
+ include Pagify::Pagifier
6
+ def pagify_pager_create model, opts
7
+ Pagify::ArrayPager.new model, opts
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+
2
+ require 'pagify/pagifiers/abstract'
3
+
4
+ module DataMapper
5
+ module Model
6
+ include Pagify::Pagifier
7
+ def pagify_pager_create model, opts
8
+ Pagify::DataMapperPager.new model, opts, model.query
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,4 @@
1
+
2
+ module Pagify
3
+ VERSION = '0.5.0'
4
+ end
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
@@ -0,0 +1,8 @@
1
+ # $Id$
2
+
3
+ require File.join(File.dirname(__FILE__), %w[spec_helper])
4
+
5
+ describe Pagify do
6
+ end
7
+
8
+ # EOF
@@ -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