will_paginate_couchrest 0.2.2 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -10,6 +10,10 @@ Automatically generate views with an extra reduce method used to generate the to
10
10
 
11
11
  == History
12
12
 
13
+ 2010-06-26 - 0.3.1 - Minor fix, duplicate view options to avoid ExtendedDocument bug
14
+
15
+ 2010-06-21 - 0.3.0 - Added support for new CouchRest Model
16
+
13
17
  2010-04-05 - 0.2.0 - Added support for CouchRest Proxy class
14
18
 
15
19
  2010-03-05 - 0.1.0 - Initial version
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.2
1
+ 0.3.1
@@ -1,22 +1,47 @@
1
1
 
2
- require('will_paginate_couchrest/class_methods')
3
- require('will_paginate_couchrest/proxy_methods')
2
+ require 'will_paginate'
3
+ require 'will_paginate_couchrest/class_methods'
4
+ require 'will_paginate_couchrest/proxy_methods'
4
5
 
5
6
  # Take the liberty of adding ourself to the couchrest library
6
7
 
7
- module CouchRest
8
- class ExtendedDocument < Document
9
- include CouchRest::Mixins::WillPaginate
8
+ if defined?(CouchRest::ExtendedDocument)
9
+ module CouchRest
10
+ class ExtendedDocument < Document
11
+ include CouchRest::WillPaginate
12
+ end
13
+ end
14
+
15
+ module CouchRest
16
+ module Mixins
17
+ module ClassProxy
18
+ class Proxy
19
+ include CouchRest::WillPaginate::ProxyMethods
20
+ end
21
+ end
22
+ end
10
23
  end
11
24
  end
12
25
 
13
- module CouchRest
14
- module Mixins
15
- module ClassProxy
16
- class Proxy
17
- include CouchRest::Mixins::WillPaginate::ProxyMethods
26
+ if defined?(CouchRest::Model::Base)
27
+ module CouchRest
28
+ module Model
29
+ class Base < Document
30
+ include CouchRest::WillPaginate
31
+ end
32
+ end
33
+ end
34
+
35
+ module CouchRest
36
+ module Model
37
+ module ClassProxy
38
+ class Proxy
39
+ include CouchRest::WillPaginate::ProxyMethods
40
+ end
18
41
  end
19
42
  end
20
43
  end
21
44
  end
22
45
 
46
+
47
+
@@ -1,147 +1,146 @@
1
1
  module CouchRest
2
- module Mixins
3
- module WillPaginate
2
+ module WillPaginate
4
3
 
5
- def self.included(base)
6
- base.extend(ClassMethods)
7
- end
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
8
7
 
9
- module ClassMethods
10
- # Define a CouchDB will paginate view. The name of the view will be the concatenation
11
- # of <tt>paginate_by</tt> and the keys joined by <tt>_and_</tt>
12
- #
13
- # ==== Example paginated views:
14
- #
15
- # class Post
16
- # # view with default options
17
- # # query with Post.paginate_by_date
18
- # paginated_view_by :date, :descending => true
19
- #
20
- # # view with compound sort-keys
21
- # # query with Post.by_user_id_and_date
22
- # paginated_view_by :user_id, :date
23
- #
24
- # # view with custom map/reduce functions
25
- # # query with Post.by_tags :reduce => true
26
- # paginated_view_by :tags,
27
- # :map =>
28
- # "function(doc) {
29
- # if (doc['couchrest-type'] == 'Post' && doc.tags) {
30
- # doc.tags.forEach(function(tag){
31
- # emit(doc.tag, 1);
32
- # });
33
- # }
34
- # }",
35
- # :reduce =>
36
- # "function(keys, values, rereduce) {
37
- # return sum(values);
38
- # }"
39
- # end
40
- #
41
- # <tt>paginated_view_by :date</tt> will create a view defined by this Javascript
42
- # function:
43
- #
44
- # function(doc) {
45
- # if (doc['couchrest-type'] == 'Post' && doc.date) {
46
- # emit(doc.date, 1);
47
- # }
48
- # }
49
- #
50
- # And a standard summing reduce function like the following:
51
- #
52
- # function(keys, values, rereduce) {
53
- # return sum(values);
54
- # }
55
- #
56
- # It can be queried by calling <tt>Post.paginate_by_date</tt> which accepts all
57
- # valid options for CouchRest::Database#view. In addition, calling with
58
- # the <tt>:raw => true</tt> option will return the view rows
59
- # themselves. By default <tt>Post.by_date</tt> will return the
60
- # documents included in the generated view.
61
- #
62
- # For further details on <tt>view_by</tt>'s other options, please see the
63
- # standard documentation.
64
- def paginated_view_by(*keys)
8
+ module ClassMethods
9
+ # Define a CouchDB will paginate view. The name of the view will be the concatenation
10
+ # of <tt>paginate_by</tt> and the keys joined by <tt>_and_</tt>
11
+ #
12
+ # ==== Example paginated views:
13
+ #
14
+ # class Post
15
+ # # view with default options
16
+ # # query with Post.paginate_by_date
17
+ # paginated_view_by :date, :descending => true
18
+ #
19
+ # # view with compound sort-keys
20
+ # # query with Post.by_user_id_and_date
21
+ # paginated_view_by :user_id, :date
22
+ #
23
+ # # view with custom map/reduce functions
24
+ # # query with Post.by_tags :reduce => true
25
+ # paginated_view_by :tags,
26
+ # :map =>
27
+ # "function(doc) {
28
+ # if (doc['couchrest-type'] == 'Post' && doc.tags) {
29
+ # doc.tags.forEach(function(tag){
30
+ # emit(doc.tag, 1);
31
+ # });
32
+ # }
33
+ # }",
34
+ # :reduce =>
35
+ # "function(keys, values, rereduce) {
36
+ # return sum(values);
37
+ # }"
38
+ # end
39
+ #
40
+ # <tt>paginated_view_by :date</tt> will create a view defined by this Javascript
41
+ # function:
42
+ #
43
+ # function(doc) {
44
+ # if (doc['couchrest-type'] == 'Post' && doc.date) {
45
+ # emit(doc.date, 1);
46
+ # }
47
+ # }
48
+ #
49
+ # And a standard summing reduce function like the following:
50
+ #
51
+ # function(keys, values, rereduce) {
52
+ # return sum(values);
53
+ # }
54
+ #
55
+ # It can be queried by calling <tt>Post.paginate_by_date</tt> which accepts all
56
+ # valid options for CouchRest::Database#view. In addition, calling with
57
+ # the <tt>:raw => true</tt> option will return the view rows
58
+ # themselves. By default <tt>Post.by_date</tt> will return the
59
+ # documents included in the generated view.
60
+ #
61
+ # For further details on <tt>view_by</tt>'s other options, please see the
62
+ # standard documentation.
63
+ def paginated_view_by(*keys)
65
64
 
66
- # Prepare the Traditional view
67
- opts = keys.last.is_a?(Hash) ? keys.pop : {}
68
- view_name = "by_#{keys.join('_and_')}"
69
- method_name = "paginate_#{view_name}"
65
+ # Prepare the Traditional view
66
+ opts = keys.last.is_a?(Hash) ? keys.pop : {}
67
+ view_name = "by_#{keys.join('_and_')}"
68
+ method_name = "paginate_#{view_name}"
70
69
 
71
- doc_keys = keys.collect{|k| "doc['#{k}']"}
72
- key_emit = doc_keys.length == 1 ? "#{doc_keys.first}" : "[#{doc_keys.join(', ')}]"
73
- guards = opts.delete(:guards) || []
74
- guards.push("(doc['couchrest-type'] == '#{self.to_s}')")
75
- guards.concat doc_keys
70
+ doc_keys = keys.collect{|k| "doc['#{k}']"}
71
+ key_emit = doc_keys.length == 1 ? "#{doc_keys.first}" : "[#{doc_keys.join(', ')}]"
72
+ guards = opts.delete(:guards) || []
73
+ guards.push("(doc['couchrest-type'] == '#{self.to_s}')")
74
+ guards.concat doc_keys
76
75
 
77
- opts = {
78
- :map => "
79
- function( doc ) {
80
- if (#{guards.join(' && ')}) {
81
- emit(#{key_emit}, 1 );
82
- }
76
+ opts = {
77
+ :map => "
78
+ function( doc ) {
79
+ if (#{guards.join(' && ')}) {
80
+ emit(#{key_emit}, 1 );
83
81
  }
84
- ",
85
- :reduce => "
86
- function(keys, values, rereduce) {
87
- return sum(values);
88
- }
89
- "
90
- }.merge(opts)
82
+ }
83
+ ",
84
+ :reduce => "
85
+ function(keys, values, rereduce) {
86
+ return sum(values);
87
+ }
88
+ "
89
+ }.merge(opts)
91
90
 
92
- # View prepared, send to traditional view_by
93
- view_by keys, opts
91
+ # View prepared, send to traditional view_by
92
+ view_by keys, opts
94
93
 
95
- instance_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
96
- def #{method_name}(options = {})
97
- paginated_view('#{view_name}', options)
98
- end
99
- RUBY_EVAL
100
- end
94
+ instance_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
95
+ def #{method_name}(options = {})
96
+ paginated_view('#{view_name}', options)
97
+ end
98
+ RUBY_EVAL
99
+ end
101
100
 
102
- ##
103
- # Generate a Will Paginate collection from all the available
104
- # documents stored with a matching couchrest-type.
105
- #
106
- # Requires no declaration as the 'all' view is built into couchrest
107
- # Extended Documents.
108
- #
109
- def paginate_all(options = {})
110
- paginated_view(:all, options)
111
- end
101
+ ##
102
+ # Generate a Will Paginate collection from all the available
103
+ # documents stored with a matching couchrest-type.
104
+ #
105
+ # Requires no declaration as the 'all' view is built into couchrest
106
+ # Extended Documents.
107
+ #
108
+ def paginate_all(options = {})
109
+ paginated_view(:all, options)
110
+ end
112
111
 
113
- ##
114
- # Return a WillPaginate collection suitable for usage
115
- #
116
- def paginated_view(view_name, options = {})
117
- raise "Missing per_page parameter" if options[:per_page].nil?
112
+ ##
113
+ # Return a WillPaginate collection suitable for usage
114
+ #
115
+ def paginated_view(view_name, options = {})
116
+ raise "Missing per_page parameter" if options[:per_page].nil?
118
117
 
119
- options[:page] ||= 1
118
+ options[:page] ||= 1
120
119
 
121
- ::WillPaginate::Collection.create( options[:page], options[:per_page] ) do |pager|
122
- # perform view count first (should create designs if missing)
123
- if view_name.to_sym == :all
124
- pager.total_entries = count({:database => options[:database]})
125
- else
126
- total = view( view_name, options.dup.update(:reduce => true) )['rows'].pop
127
- pager.total_entries = total ? total['value'] : 0
128
- end
129
- p_options = options.merge(
130
- :design_doc => self.to_s, :view_name => view_name,
131
- :include_docs => true
132
- )
133
- # Only provide the reduce parameter when necessary. This is when the view has
134
- # been set with a reduce method and requires the reduce boolean parameter
135
- # to be either true or false on all requests.
136
- p_options[:reduce] = false unless view_name.to_sym == :all
137
- results = paginate(p_options)
138
- pager.replace( results )
120
+ ::WillPaginate::Collection.create( options[:page], options[:per_page] ) do |pager|
121
+ # perform view count first (should create designs if missing)
122
+ if view_name.to_sym == :all
123
+ pager.total_entries = count({:database => options[:database]})
124
+ else
125
+ total = view( view_name, options.update(:reduce => true).dup )['rows'].pop
126
+ pager.total_entries = total ? total['value'] : 0
139
127
  end
128
+ p_options = options.merge(
129
+ :design_doc => self.to_s,
130
+ :view_name => view_name,
131
+ :include_docs => true
132
+ )
133
+ # Only provide the reduce parameter when necessary. This is when the view has
134
+ # been set with a reduce method and requires the reduce boolean parameter
135
+ # to be either true or false on all requests.
136
+ p_options[:reduce] = false unless view_name.to_sym == :all
137
+ results = paginate(p_options)
138
+ pager.replace( results )
140
139
  end
141
140
  end
142
-
143
141
  end
144
- end # module mixins
142
+
143
+ end
145
144
  end # module CouchRest
146
145
 
147
146
 
@@ -1,28 +1,26 @@
1
1
  module CouchRest
2
- module Mixins
3
- module WillPaginate
4
- module ProxyMethods
2
+ module WillPaginate
3
+ module ProxyMethods
5
4
 
6
- def method_missing(m, *args, &block)
7
- if m.to_s =~ /^paginate_(.+)/ && @klass.respond_to?(m)
8
- view_name = $1 # view name
9
- opts = args.shift || {}
10
- paginated_view(view_name, opts)
11
- else
12
- super
13
- end
14
- end
15
-
16
- def paginated_view(view_name, opts = {})
17
- opts = {
18
- :database => @database
19
- }.merge(opts)
20
- result = @klass.paginated_view(view_name, opts)
21
- result.each{|doc| doc.database = @database if respond_to?(:database) } if result
22
- result
5
+ def method_missing(m, *args, &block)
6
+ if m.to_s =~ /^paginate_(.+)/ && @klass.respond_to?(m)
7
+ view_name = $1 # view name
8
+ opts = args.shift || {}
9
+ paginated_view(view_name, opts)
10
+ else
11
+ super
23
12
  end
13
+ end
24
14
 
15
+ def paginated_view(view_name, opts = {})
16
+ opts = {
17
+ :database => @database
18
+ }.merge(opts)
19
+ result = @klass.paginated_view(view_name, opts)
20
+ result.each{|doc| doc.database = @database if respond_to?(:database) } if result
21
+ result
25
22
  end
23
+
26
24
  end
27
25
  end
28
26
  end
data/spec/spec_helper.rb CHANGED
@@ -2,12 +2,13 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
2
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
3
 
4
4
  require 'rubygems'
5
- require 'couchrest'
6
- require 'will_paginate'
5
+ require 'couchrest_extended_document'
6
+ require 'couchrest_model'
7
7
  require 'will_paginate_couchrest'
8
8
  require 'spec'
9
9
  require 'spec/autorun'
10
10
 
11
+
11
12
  unless defined?(SPEC_COUCH)
12
13
  COUCH_URL = "http://127.0.0.1:5984"
13
14
  COUCH_NAME = 'couchrest-test'
@@ -26,6 +27,6 @@ Spec::Runner.configure do |config|
26
27
  }
27
28
 
28
29
  config.after(:all) do
29
- SPEC_COUCH.delete! rescue nil
30
+ SPEC_COUCH.delete!
30
31
  end
31
32
  end
@@ -1,97 +1,104 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
- describe CouchRest::Mixins::WillPaginate do
3
+ describe CouchRest::WillPaginate do
4
4
 
5
- class SomeDoc < CouchRest::ExtendedDocument
5
+ class SomeExtendedDoc < CouchRest::ExtendedDocument
6
6
  use_database SPEC_COUCH
7
-
8
7
  property :name
9
-
10
8
  paginated_view_by :name
11
9
  end
12
10
 
13
- it "should respond to paginated_view_by class method" do
14
- SomeDoc.should respond_to :paginated_view_by
15
- end
16
-
17
- it "should call view_by method when paginated view_by included" do
18
- SomeDoc.should_receive(:view_by)
19
- class SomeDoc
20
- paginated_view_by :name
21
- end
22
- end
23
-
24
- it "should respond to the view and paginated method" do
25
- SomeDoc.should respond_to :paginate_by_name
26
- # @some_doc.stub(:id).and_return(123)
27
- end
28
-
29
- it "should accept request when no results" do
30
- docs = SomeDoc.paginate_by_name(:per_page => 5)
31
- docs.total_entries.should eql(0)
11
+ class SomeModel < CouchRest::Model::Base
12
+ use_database SPEC_COUCH
13
+ property :name
14
+ paginated_view_by :name
32
15
  end
33
16
 
34
- it "should accept request without page" do
35
- docs = nil
36
- lambda { docs = SomeDoc.paginate_by_name(:per_page => 5) }.should_not raise_error
37
- docs.current_page.should eql(1)
38
- end
17
+ [SomeExtendedDoc, SomeModel].each do |klass|
18
+
19
+ describe klass do
39
20
 
40
- it "should throw an exception when missing per_page parameter" do
41
- lambda { SomeDoc.paginate_by_name() }.should raise_error
42
- end
21
+ before(:all) do
22
+ reset_test_db!
23
+ end
43
24
 
25
+ it "should respond to paginated_view_by class method" do
26
+ klass.should respond_to :paginated_view_by
27
+ end
44
28
 
45
- describe "performing pagination with lots of documents" do
29
+ it "should call view_by method when paginated view_by included" do
30
+ klass.should_receive(:view_by)
31
+ klass.paginated_view_by :name
32
+ end
33
+
34
+ it "should respond to the view and paginated method" do
35
+ klass.should respond_to :paginate_by_name
36
+ # @some_doc.stub(:id).and_return(123)
37
+ end
46
38
 
47
- before(:each) do
48
- reset_test_db!
49
- 20.times do |i|
50
- txt = "%02d" % i
51
- SomeDoc.new(:name => "document #{txt}").save
39
+ it "should accept request when no results" do
40
+ docs = klass.paginate_by_name(:per_page => 5)
41
+ docs.total_entries.should eql(0)
52
42
  end
53
- end
54
43
 
55
- it "should produce a will paginate collection" do
56
- docs = SomeDoc.paginate_by_name( :page => 1, :per_page => 5 )
57
- docs.should be_a_kind_of(::WillPaginate::Collection)
58
- docs.total_pages.should eql(4)
59
- docs.first.name.should eql('document 00')
60
- docs.length.should eql(5)
61
- docs.last.name.should eql('document 04')
62
- end
44
+ it "should accept request without page" do
45
+ docs = nil
46
+ lambda { docs = klass.paginate_by_name(:per_page => 5) }.should_not raise_error
47
+ docs.current_page.should eql(1)
48
+ end
63
49
 
64
- it "should produce second page from paginate collection" do
65
- docs = SomeDoc.paginate_by_name( :page => 2, :per_page => 5 )
66
- docs.first.name.should eql('document 05')
67
- docs.length.should eql(5)
68
- docs.last.name.should eql('document 09')
69
- end
50
+ it "should throw an exception when missing per_page parameter" do
51
+ lambda { klass.paginate_by_name() }.should raise_error
52
+ end
70
53
 
71
- it "should perform paginate on all entries" do
72
- docs = SomeDoc.paginate_all(:page => 1, :per_page => 5)
73
- docs.first.class.should eql(SomeDoc)
74
- docs.total_pages.should eql(4)
75
- docs.total_entries.should eql(20)
76
- docs.length.should eql(5)
77
- end
78
54
 
79
- end
55
+ describe "performing pagination with lots of documents" do
56
+
57
+ before(:each) do
58
+ reset_test_db!
59
+ 20.times do |i|
60
+ txt = "%02d" % i
61
+ klass.new(:name => "document #{txt}").save
62
+ end
63
+ end
64
+
65
+ it "should produce a will paginate collection" do
66
+ docs = klass.paginate_by_name( :page => 1, :per_page => 5 )
67
+ docs.should be_a_kind_of(::WillPaginate::Collection)
68
+ docs.total_pages.should eql(4)
69
+ docs.first.name.should eql('document 00')
70
+ docs.length.should eql(5)
71
+ docs.last.name.should eql('document 04')
72
+ end
73
+
74
+ it "should produce second page from paginate collection" do
75
+ docs = klass.paginate_by_name( :page => 2, :per_page => 5 )
76
+ docs.first.name.should eql('document 05')
77
+ docs.length.should eql(5)
78
+ docs.last.name.should eql('document 09')
79
+ end
80
+
81
+ it "should perform paginate on all entries" do
82
+ docs = klass.paginate_all(:page => 1, :per_page => 5)
83
+ docs.first.class.should eql(klass)
84
+ docs.total_pages.should eql(4)
85
+ docs.total_entries.should eql(20)
86
+ docs.length.should eql(5)
87
+ end
80
88
 
89
+ end
81
90
 
82
- describe "using pagination via proxy class" do
83
- before(:each) do
84
- @proxy = SomeDoc.on(SPEC_COUCH)
85
- end
86
91
 
87
- it "should allow paginate call on proxy with database" do
88
- SomeDoc.should_receive(:paginated_view).with('by_name', {:key => 'foo', :database => SPEC_COUCH})
89
- @proxy.paginate_by_name :key => 'foo'
90
- end
92
+ describe "using pagination via proxy class" do
93
+ before(:each) do
94
+ @proxy = klass.on(SPEC_COUCH)
95
+ end
91
96
 
92
- it "should call paginate parent with database" do
93
- SomeDoc.should_receive(:paginate).with(hash_including(:database => SPEC_COUCH)).and_return([])
94
- @proxy.paginate_by_name :key => 'foo', :per_page => 10
97
+ it "should allow paginate call on proxy" do
98
+ klass.should_receive(:paginated_view).with('by_name', {:key => 'foo', :database => SPEC_COUCH})
99
+ @proxy.paginate_by_name :key => 'foo'
100
+ end
101
+ end
95
102
  end
96
103
  end
97
104
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 2
8
- - 2
9
- version: 0.2.2
7
+ - 3
8
+ - 1
9
+ version: 0.3.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - samlown
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-04-05 00:00:00 +00:00
17
+ date: 2010-07-07 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -96,5 +96,5 @@ signing_key:
96
96
  specification_version: 3
97
97
  summary: adds will-paginate support to CouchRest
98
98
  test_files:
99
- - spec/will_paginate_couchrest_spec.rb
100
99
  - spec/spec_helper.rb
100
+ - spec/will_paginate_couchrest_spec.rb