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.
@@ -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