From be7cd7442b2b193dc65137e0c679970f6db93588 Mon Sep 17 00:00:00 2001 From: Daniel Kirsch Date: Tue, 21 Jul 2009 14:14:58 +0200 Subject: [PATCH 01/22] added count to proxy --- lib/couchrest/mixins/class_proxy.rb | 4 ++++ spec/couchrest/more/extended_doc_view_spec.rb | 3 +++ 2 files changed, 7 insertions(+) diff --git a/lib/couchrest/mixins/class_proxy.rb b/lib/couchrest/mixins/class_proxy.rb index 6b800bc..2e5ffdb 100644 --- a/lib/couchrest/mixins/class_proxy.rb +++ b/lib/couchrest/mixins/class_proxy.rb @@ -59,6 +59,10 @@ module CouchRest @klass.all({:database => @database}.merge(opts), &block) end + def count(opts = {}, &block) + @klass.all({:raw => true, :limit => 0}.merge(opts), &block)['total_rows'] + end + def first(opts = {}) @klass.first({:database => @database}.merge(opts)) end diff --git a/spec/couchrest/more/extended_doc_view_spec.rb b/spec/couchrest/more/extended_doc_view_spec.rb index f735c4c..8bb3e32 100644 --- a/spec/couchrest/more/extended_doc_view_spec.rb +++ b/spec/couchrest/more/extended_doc_view_spec.rb @@ -212,6 +212,9 @@ describe "ExtendedDocument views" do rs = @us.all rs.length.should == 4 end + it "should count" do + @us.count.should == 4 + end it "should make the design doc upon first query" do @us.by_title doc = @us.design_doc From 3ee810010d77d34f80cd0c0d6b0a3a518cd56823 Mon Sep 17 00:00:00 2001 From: Daniel Kirsch Date: Tue, 21 Jul 2009 14:36:09 +0200 Subject: [PATCH 02/22] forgot to add database to count query --- lib/couchrest/mixins/class_proxy.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/couchrest/mixins/class_proxy.rb b/lib/couchrest/mixins/class_proxy.rb index 2e5ffdb..ab5831c 100644 --- a/lib/couchrest/mixins/class_proxy.rb +++ b/lib/couchrest/mixins/class_proxy.rb @@ -60,7 +60,7 @@ module CouchRest end def count(opts = {}, &block) - @klass.all({:raw => true, :limit => 0}.merge(opts), &block)['total_rows'] + @klass.all({:database => @database, :raw => true, :limit => 0}.merge(opts), &block)['total_rows'] end def first(opts = {}) From 4d4972f0de44d0733068182c39650d3d5781134c Mon Sep 17 00:00:00 2001 From: Daniel Kirsch Date: Tue, 21 Jul 2009 23:23:12 +0200 Subject: [PATCH 03/22] fixed class proxy design doc wreidness --- lib/couchrest/mixins/class_proxy.rb | 2 +- lib/couchrest/mixins/design_doc.rb | 5 +++++ lib/couchrest/mixins/views.rb | 6 +++--- spec/couchrest/more/extended_doc_view_spec.rb | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/couchrest/mixins/class_proxy.rb b/lib/couchrest/mixins/class_proxy.rb index ab5831c..0101639 100644 --- a/lib/couchrest/mixins/class_proxy.rb +++ b/lib/couchrest/mixins/class_proxy.rb @@ -104,7 +104,7 @@ module CouchRest end def refresh_design_doc - @klass.refresh_design_doc + @klass.refresh_design_doc_on(@database) end def save_design_doc diff --git a/lib/couchrest/mixins/design_doc.rb b/lib/couchrest/mixins/design_doc.rb index 661b6ef..a8714c9 100644 --- a/lib/couchrest/mixins/design_doc.rb +++ b/lib/couchrest/mixins/design_doc.rb @@ -48,6 +48,11 @@ module CouchRest save_design_doc end + def refresh_design_doc_on(db) + reset_design_doc + save_design_doc_on(db) + end + # Save the design doc onto the default database, and update the # design_doc attribute def save_design_doc diff --git a/lib/couchrest/mixins/views.rb b/lib/couchrest/mixins/views.rb index f520998..de530e3 100644 --- a/lib/couchrest/mixins/views.rb +++ b/lib/couchrest/mixins/views.rb @@ -95,11 +95,11 @@ module CouchRest # Dispatches to any named view. def view(name, query={}, &block) - unless design_doc_fresh - refresh_design_doc + db = query.delete(:database) || database + unless design_doc_fresh + refresh_design_doc_on(db) end query[:raw] = true if query[:reduce] - db = query.delete(:database) || database raw = query.delete(:raw) fetch_view_with_docs(db, name, query, raw, &block) end diff --git a/spec/couchrest/more/extended_doc_view_spec.rb b/spec/couchrest/more/extended_doc_view_spec.rb index 8bb3e32..1444f4b 100644 --- a/spec/couchrest/more/extended_doc_view_spec.rb +++ b/spec/couchrest/more/extended_doc_view_spec.rb @@ -200,7 +200,7 @@ describe "ExtendedDocument views" do before(:all) do reset_test_db! # setup the class default doc to save the design doc - Unattached.use_database DB + Unattached.use_database nil # just to be sure it is really unattached @us = Unattached.on(DB) %w{aaa bbb ddd eee}.each do |title| u = @us.new(:title => title) From 52255e50a2ada47fcef1e293ff4b317a756e0403 Mon Sep 17 00:00:00 2001 From: Matt Aimonetti Date: Tue, 21 Jul 2009 23:06:35 -0700 Subject: [PATCH 04/22] updated the history.txt file --- history.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/history.txt b/history.txt index a026ff0..8727642 100644 --- a/history.txt +++ b/history.txt @@ -11,8 +11,16 @@ you will need to make the following modifications. * -* Minor enhancements +* Minor enhancements + * + +== 0.32 + +* Minor enhancements + + * Bug fix: class proxy design doc refresh (Daniel Kirsh) + * Bug fix: the count method on the proxy collection was missing (Daniel Kirsch) * Added #amount_pages to a paginated collection. (Matt Aimonetti) == 0.31 From 153ce54b1e9a84d362d24062c0496065407fe1f2 Mon Sep 17 00:00:00 2001 From: Peter Wagenet Date: Tue, 21 Jul 2009 16:54:31 -0700 Subject: [PATCH 05/22] Added ValidationErrors#count in order to play nicely with Rails --- lib/couchrest/validation/validation_errors.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/couchrest/validation/validation_errors.rb b/lib/couchrest/validation/validation_errors.rb index 4ddbb6e..7b7da0b 100644 --- a/lib/couchrest/validation/validation_errors.rb +++ b/lib/couchrest/validation/validation_errors.rb @@ -104,6 +104,13 @@ module CouchRest entries.empty? end + # Return size of errors hash + # + # Allows us to play nicely with Rails' helpers + def count + errors.size + end + def method_missing(meth, *args, &block) errors.send(meth, *args, &block) end From fc1ad2a07eda5c22ccc09346760c6b0579e606c8 Mon Sep 17 00:00:00 2001 From: Matt Aimonetti Date: Tue, 21 Jul 2009 23:38:50 -0700 Subject: [PATCH 06/22] updated history --- history.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/history.txt b/history.txt index 8727642..1001d21 100644 --- a/history.txt +++ b/history.txt @@ -19,6 +19,7 @@ you will need to make the following modifications. * Minor enhancements + * Added ValidationErrors#count in order to play nicely with Rails (Peter Wagenet) * Bug fix: class proxy design doc refresh (Daniel Kirsh) * Bug fix: the count method on the proxy collection was missing (Daniel Kirsch) * Added #amount_pages to a paginated collection. (Matt Aimonetti) From 87d246d30ec51e012b2f660bb1365a25ef4a3293 Mon Sep 17 00:00:00 2001 From: Matt Aimonetti Date: Wed, 22 Jul 2009 15:45:18 -0700 Subject: [PATCH 07/22] modified the 'all' view to emit doc ids so we can do Model.all(:keys => [1,2]) --- lib/couchrest/mixins/design_doc.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/couchrest/mixins/design_doc.rb b/lib/couchrest/mixins/design_doc.rb index a8714c9..35729a7 100644 --- a/lib/couchrest/mixins/design_doc.rb +++ b/lib/couchrest/mixins/design_doc.rb @@ -35,7 +35,7 @@ module CouchRest 'all' => { 'map' => "function(doc) { if (doc['couchrest-type'] == '#{self.to_s}') { - emit(null,1); + emit(doc['_id'],1); } }" } From 5cd2eaf18ae20ad9e21a77135627cd2b764a8c4d Mon Sep 17 00:00:00 2001 From: Matt Aimonetti Date: Wed, 22 Jul 2009 16:05:55 -0700 Subject: [PATCH 08/22] made get not raise an exception anymore, use get! instead if you need to raise exceptions. * ExtendedDocument.get doesn't raise an exception anymore. If no documents are found nil is returned. * ExtendedDocument.get! works the say #get used to work and will raise an exception if a document isn't found. --- lib/couchrest/mixins/document_queries.rb | 31 +++++++++++++++++++ spec/couchrest/more/extended_doc_spec.rb | 11 ++++++- spec/couchrest/more/extended_doc_view_spec.rb | 7 +++-- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/lib/couchrest/mixins/document_queries.rb b/lib/couchrest/mixins/document_queries.rb index defff3d..a1312d9 100644 --- a/lib/couchrest/mixins/document_queries.rb +++ b/lib/couchrest/mixins/document_queries.rb @@ -39,7 +39,38 @@ module CouchRest end # Load a document from the database by id + # No exceptions will be raised if the document isn't found + # + # ==== Returns + # Object:: if the document was found + # or + # Nil:: + # + # === Parameters + # id:: Document ID + # db:: optional option to pass a custom database to use def get(id, db = database) + begin + doc = db.get id + rescue + nil + else + new(doc) + end + end + + # Load a document from the database by id + # An exception will be raised if the document isn't found + # + # ==== Returns + # Object:: if the document was found + # or + # Exception + # + # === Parameters + # id:: Document ID + # db:: optional option to pass a custom database to use + def get!(id, db = database) doc = db.get id new(doc) end diff --git a/spec/couchrest/more/extended_doc_spec.rb b/spec/couchrest/more/extended_doc_spec.rb index 5d71d7f..f3097ff 100644 --- a/spec/couchrest/more/extended_doc_spec.rb +++ b/spec/couchrest/more/extended_doc_spec.rb @@ -216,6 +216,15 @@ describe "ExtendedDocument" do foundart = Article.get @art.id foundart.title.should == "All About Getting" end + + it "should return nil if `get` is used and the document doesn't exist" do + foundart = Article.get 'matt aimonetti' + foundart.should be_nil + end + + it "should raise an error if `get!` is used and the document doesn't exist" do + lambda{foundart = Article.get!('matt aimonetti')}.should raise_error + end end describe "getting a model with a subobjects array" do @@ -507,7 +516,7 @@ describe "ExtendedDocument" do end it "should make it go away" do @dobj.destroy - lambda{Basic.get(@dobj.id)}.should raise_error + lambda{Basic.get!(@dobj.id)}.should raise_error end end diff --git a/spec/couchrest/more/extended_doc_view_spec.rb b/spec/couchrest/more/extended_doc_view_spec.rb index 1444f4b..be6056e 100644 --- a/spec/couchrest/more/extended_doc_view_spec.rb +++ b/spec/couchrest/more/extended_doc_view_spec.rb @@ -168,8 +168,11 @@ describe "ExtendedDocument views" do end things[0]["doc"]["title"].should =='aaa' end - it "should barf on get if no database given" do - lambda{Unattached.get("aaa")}.should raise_error + it "should return nil on get if no database given" do + Unattached.get("aaa").should be_nil + end + it "should barf on get! if no database given" do + lambda{Unattached.get!("aaa")}.should raise_error end it "should get from specific database" do u = Unattached.get(@first_id, @db) From a4254be8eb91cba53f1eabdaea177da6dd123487 Mon Sep 17 00:00:00 2001 From: Matt Aimonetti Date: Wed, 22 Jul 2009 16:06:24 -0700 Subject: [PATCH 09/22] updated history.txt --- history.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/history.txt b/history.txt index 1001d21..52468a0 100644 --- a/history.txt +++ b/history.txt @@ -17,8 +17,14 @@ you will need to make the following modifications. == 0.32 -* Minor enhancements +* Major enhancements + + * ExtendedDocument.get doesn't raise an exception anymore. If no documents are found nil is returned. + * ExtendedDocument.get! works the say #get used to work and will raise an exception if a document isn't found. +* Minor enhancements + + * Bug fix: Model.all(:keys => [1,2]) was not working (Matt Aimonetti) * Added ValidationErrors#count in order to play nicely with Rails (Peter Wagenet) * Bug fix: class proxy design doc refresh (Daniel Kirsh) * Bug fix: the count method on the proxy collection was missing (Daniel Kirsch) From dd480bcd7524e7da89e505cee8a0c943167b9885 Mon Sep 17 00:00:00 2001 From: Matt Aimonetti Date: Wed, 22 Jul 2009 16:54:28 -0700 Subject: [PATCH 10/22] bumped version to 0.32 --- couchrest.gemspec | 2 +- history.txt | 17 ----------------- lib/couchrest.rb | 2 +- 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/couchrest.gemspec b/couchrest.gemspec index 85fb9c3..9dea7e5 100644 --- a/couchrest.gemspec +++ b/couchrest.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{couchrest} - s.version = "0.31" + s.version = "0.32" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["J. Chris Anderson", "Matt Aimonetti"] diff --git a/history.txt b/history.txt index 52468a0..941aaba 100644 --- a/history.txt +++ b/history.txt @@ -1,20 +1,3 @@ -== 0.40 - -=== Notes - - This release slightly modifies the API and if you were using a previous version of CouchRest, -you will need to make the following modifications. - - - -* Major enhancements - - * - -* Minor enhancements - - * - == 0.32 * Major enhancements diff --git a/lib/couchrest.rb b/lib/couchrest.rb index ada8ab2..572902f 100644 --- a/lib/couchrest.rb +++ b/lib/couchrest.rb @@ -28,7 +28,7 @@ require 'couchrest/monkeypatches' # = CouchDB, close to the metal module CouchRest - VERSION = '0.31' unless self.const_defined?("VERSION") + VERSION = '0.32' unless self.const_defined?("VERSION") autoload :Server, 'couchrest/core/server' autoload :Database, 'couchrest/core/database' From 41eeedd49b69f2072fd0b2e7f3bf1c34dc9e1960 Mon Sep 17 00:00:00 2001 From: tc Date: Fri, 24 Jul 2009 22:31:36 -0700 Subject: [PATCH 11/22] removed {:reduce => false} in #all method to make it 0.10 comp. --- lib/couchrest/mixins/document_queries.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/couchrest/mixins/document_queries.rb b/lib/couchrest/mixins/document_queries.rb index a1312d9..d7c8a11 100644 --- a/lib/couchrest/mixins/document_queries.rb +++ b/lib/couchrest/mixins/document_queries.rb @@ -12,7 +12,7 @@ module CouchRest # name of the current class. Take the standard set of # CouchRest::Database#view options. def all(opts = {}, &block) - view(:all, {:reduce => false}.merge(opts), &block) + view(:all, opts, &block) end # Returns the number of documents that have the "couchrest-type" field From ac3d0a988f54737d11eeb0f38bbd497850851896 Mon Sep 17 00:00:00 2001 From: Matt Aimonetti Date: Mon, 27 Jul 2009 00:14:38 -0700 Subject: [PATCH 12/22] added a Rack logger middleware --- lib/couchrest/middlewares/logger.rb | 263 ++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 lib/couchrest/middlewares/logger.rb diff --git a/lib/couchrest/middlewares/logger.rb b/lib/couchrest/middlewares/logger.rb new file mode 100644 index 0000000..11035b8 --- /dev/null +++ b/lib/couchrest/middlewares/logger.rb @@ -0,0 +1,263 @@ +#################################### +# USAGE +# +# in your rack.rb file +# require this file and then: +# +# couch = CouchRest.new +# LOG_DB = couch.database!('couchrest-logger') +# use CouchRest::Logger, LOG_DB +# +# Note: +# to require just this middleware, if you have the gem installed do: +# require 'couchrest/middlewares/logger' +# +# For log processing examples, see examples at the bottom of this file + +module CouchRest + class Logger + + def self.log + Thread.current["couchrest.logger"] ||= {:queries => []} + end + + def initialize(app, db=nil) + @app = app + @db = db + end + + def self.record(log_info) + log[:queries] << log_info + end + + def log + Thread.current["couchrest.logger"] ||= {:queries => []} + end + + def reset_log + Thread.current["couchrest.logger"] = nil + end + + def call(env) + reset_log + log['started_at'] = Time.now + log['env'] = env + log['url'] = 'http://' + env['HTTP_HOST'] + env['REQUEST_URI'] + response = @app.call(env) + log['ended_at'] = Time.now + log['duration'] = log['ended_at'] - log['started_at'] + # let's report the log in a different thread so we don't slow down the app + @db ? Thread.new(@db, log){|db, rlog| db.save_doc(rlog);} : p(log.inspect) + response + end + end +end + +# inject our logger into CouchRest HTTP abstraction layer +module HttpAbstraction + + def self.get(uri, headers=nil) + start_query = Time.now + log = {:method => :get, :uri => uri, :headers => headers} + response = super(uri, headers=nil) + end_query = Time.now + log[:duration] = (end_query - start_query) + CouchRest::Logger.record(log) + response + end + + def self.post(uri, payload, headers=nil) + start_query = Time.now + log = {:method => :post, :uri => uri, :payload => (payload ? (JSON.load(payload) rescue 'parsing error') : nil), :headers => headers} + response = super(uri, payload, headers=nil) + end_query = Time.now + log[:duration] = (end_query - start_query) + CouchRest::Logger.record(log) + response + end + + def self.put(uri, payload, headers=nil) + start_query = Time.now + log = {:method => :put, :uri => uri, :payload => (payload ? (JSON.load(payload) rescue 'parsing error') : nil), :headers => headers} + response = super(uri, payload, headers=nil) + end_query = Time.now + log[:duration] = (end_query - start_query) + CouchRest::Logger.record(log) + response + end + + def self.delete(uri, headers=nil) + start_query = Time.now + log = {:method => :delete, :uri => uri, :headers => headers} + response = super(uri, headers=nil) + end_query = Time.now + log[:duration] = (end_query - start_query) + CouchRest::Logger.record(log) + response + end + +end + + +# Advanced usage example +# +# +# # DB VIEWS +# by_url = { +# :map => +# "function(doc) { +# if(doc['url']){ emit(doc['url'], 1) }; +# }", +# :reduce => +# 'function (key, values, rereduce) { +# return(sum(values)); +# };' +# } +# req_duration = { +# :map => +# "function(doc) { +# if(doc['duration']){ emit(doc['url'], doc['duration']) }; +# }", +# :reduce => +# 'function (key, values, rereduce) { +# return(sum(values)/values.length); +# };' +# } +# +# query_duration = { +# :map => +# "function(doc) { +# if(doc['queries']){ +# doc.queries.forEach(function(query){ +# if(query['duration'] && query['method']){ +# emit(query['method'], query['duration']) +# } +# }); +# }; +# }" , +# :reduce => +# 'function (key, values, rereduce) { +# return(sum(values)/values.length); +# };' +# } +# +# action_queries = { +# :map => +# "function(doc) { +# if(doc['queries']){ +# emit(doc['url'], doc['queries'].length) +# }; +# }", +# :reduce => +# 'function (key, values, rereduce) { +# return(sum(values)/values.length); +# };' +# } +# +# action_time_spent_in_db = { +# :map => +# "function(doc) { +# if(doc['queries']){ +# var totalDuration = 0; +# doc.queries.forEach(function(query){ +# totalDuration += query['duration'] +# }) +# emit(doc['url'], totalDuration) +# }; +# }", +# :reduce => +# 'function (key, values, rereduce) { +# return(sum(values)/values.length); +# };' +# } +# +# show_queries = %Q~function(doc, req) { +# var body = "" +# body += "

" + doc['url'] + "

" +# body += "

Request duration in seconds: " + doc['duration'] + "

" +# body += "

" + doc['queries'].length + " queries

    " +# if (doc.queries){ +# doc.queries.forEach(function(query){ +# body += "
  • "+ query['uri'] +"
  • " +# }); +# }; +# body += "
" +# if(doc){ return { body: body} } +# }~ +# +# +# couch = CouchRest.new +# LOG_DB = couch.database!('couchrest-logger') +# design_doc = LOG_DB.get("_design/stats") rescue nil +# LOG_DB.delete_doc design_doc rescue nil +# LOG_DB.save_doc({ +# "_id" => "_design/stats", +# :views => { +# :by_url => by_url, +# :request_duration => req_duration, +# :query_duration => query_duration, +# :action_queries => action_queries, +# :action_time_spent_in_db => action_time_spent_in_db +# }, +# :shows => { +# :queries => show_queries +# } +# }) +# +# module CouchRest +# class Logger +# +# def self.roundup(value) +# begin +# value = Float(value) +# (value * 100).round.to_f / 100 +# rescue +# value +# end +# end +# +# # Usage example: +# # CouchRest::Logger.average_request_duration(LOG_DB)['rows'].first['value'] +# def self.average_request_duration(db) +# raw = db.view('stats/request_duration', :reduce => true) +# (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet' +# end +# +# def self.average_query_duration(db) +# raw = db.view('stats/query_duration', :reduce => true) +# (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet' +# end +# +# def self.average_get_query_duration(db) +# raw = db.view('stats/query_duration', :key => 'get', :reduce => true) +# (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet' +# end +# +# def self.average_post_query_duration(db) +# raw = db.view('stats/query_duration', :key => 'post', :reduce => true) +# (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet' +# end +# +# def self.average_queries_per_action(db) +# raw = db.view('stats/action_queries', :reduce => true) +# (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet' +# end +# +# def self.average_db_time_per_action(db) +# raw = db.view('stats/action_time_spent_in_db', :reduce => true) +# (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet' +# end +# +# def self.stats(db) +# Thread.new(db){|db| +# puts "=== STATS ===\n" +# puts "average request duration: #{average_request_duration(db)}\n" +# puts "average query duration: #{average_query_duration(db)}\n" +# puts "average queries per action : #{average_queries_per_action(db)}\n" +# puts "average time spent in DB (per action): #{average_db_time_per_action(db)}\n" +# puts "===============\n" +# } +# end +# +# end +# end \ No newline at end of file From 0958be55f78a69e0650898abd55508d8aa511151 Mon Sep 17 00:00:00 2001 From: Matt Aimonetti Date: Mon, 27 Jul 2009 00:17:34 -0700 Subject: [PATCH 13/22] updated the history.txt file --- history.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/history.txt b/history.txt index 941aaba..7980257 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,20 @@ +== 0.40 + +=== Notes + + This release slightly modifies the API and if you were using a previous version of CouchRest, +you will need to make the following modifications. + + + +* Major enhancements + + * Added a new Rack logger middleware letting you log/save requests/queries (Matt Aimonetti) + +* Minor enhancements + + * Bug fix: made ExtendedDocument#all compatible with Couch 0.10 (tc) + == 0.32 * Major enhancements From 9141669df1cea508571a125e8a0ca12005dd11ed Mon Sep 17 00:00:00 2001 From: Matt Aimonetti Date: Wed, 29 Jul 2009 18:32:34 -0700 Subject: [PATCH 14/22] extracted the rest API to its own module --- lib/couchrest.rb | 51 +++------------------------- lib/couchrest/core/rest_api.rb | 49 ++++++++++++++++++++++++++ lib/couchrest/more/casted_model.rb | 2 +- spec/couchrest/core/database_spec.rb | 2 +- 4 files changed, 56 insertions(+), 48 deletions(-) create mode 100644 lib/couchrest/core/rest_api.rb diff --git a/lib/couchrest.rb b/lib/couchrest.rb index 572902f..efb5847 100644 --- a/lib/couchrest.rb +++ b/lib/couchrest.rb @@ -45,8 +45,13 @@ module CouchRest autoload :ExtendedDocument, 'couchrest/more/extended_document' autoload :CastedModel, 'couchrest/more/casted_model' + require File.join(File.dirname(__FILE__), 'couchrest', 'core', 'rest_api') require File.join(File.dirname(__FILE__), 'couchrest', 'core', 'http_abstraction') require File.join(File.dirname(__FILE__), 'couchrest', 'mixins') + + # we extend CouchRest with the RestAPI module which gives us acess to + # the get, post, put, delete and copy + CouchRest.extend(::RestAPI) # The CouchRest module methods handle the basic JSON serialization # and deserialization, as well as query parameters. The module also includes @@ -139,52 +144,6 @@ module CouchRest cr.database(parsed[:database]) end - def put(uri, doc = nil) - payload = doc.to_json if doc - begin - JSON.parse(HttpAbstraction.put(uri, payload)) - rescue Exception => e - if $DEBUG - raise "Error while sending a PUT request #{uri}\npayload: #{payload.inspect}\n#{e}" - else - raise e - end - end - end - - def get(uri) - begin - JSON.parse(HttpAbstraction.get(uri), :max_nesting => false) - rescue => e - if $DEBUG - raise "Error while sending a GET request #{uri}\n: #{e}" - else - raise e - end - end - end - - def post uri, doc = nil - payload = doc.to_json if doc - begin - JSON.parse(HttpAbstraction.post(uri, payload)) - rescue Exception => e - if $DEBUG - raise "Error while sending a POST request #{uri}\npayload: #{payload.inspect}\n#{e}" - else - raise e - end - end - end - - def delete uri - JSON.parse(HttpAbstraction.delete(uri)) - end - - def copy uri, destination - JSON.parse(HttpAbstraction.copy(uri, {'Destination' => destination})) - end - def paramify_url url, params = {} if params && !params.empty? query = params.collect do |k,v| diff --git a/lib/couchrest/core/rest_api.rb b/lib/couchrest/core/rest_api.rb new file mode 100644 index 0000000..62075b0 --- /dev/null +++ b/lib/couchrest/core/rest_api.rb @@ -0,0 +1,49 @@ +module RestAPI + + def put(uri, doc = nil) + payload = doc.to_json if doc + begin + JSON.parse(HttpAbstraction.put(uri, payload)) + rescue Exception => e + if $DEBUG + raise "Error while sending a PUT request #{uri}\npayload: #{payload.inspect}\n#{e}" + else + raise e + end + end + end + + def get(uri) + begin + JSON.parse(HttpAbstraction.get(uri), :max_nesting => false) + rescue => e + if $DEBUG + raise "Error while sending a GET request #{uri}\n: #{e}" + else + raise e + end + end + end + + def post(uri, doc = nil) + payload = doc.to_json if doc + begin + JSON.parse(HttpAbstraction.post(uri, payload)) + rescue Exception => e + if $DEBUG + raise "Error while sending a POST request #{uri}\npayload: #{payload.inspect}\n#{e}" + else + raise e + end + end + end + + def delete(uri) + JSON.parse(HttpAbstraction.delete(uri)) + end + + def copy(uri, destination) + JSON.parse(HttpAbstraction.copy(uri, {'Destination' => destination})) + end + +end \ No newline at end of file diff --git a/lib/couchrest/more/casted_model.rb b/lib/couchrest/more/casted_model.rb index 6f442c8..5e4da2e 100644 --- a/lib/couchrest/more/casted_model.rb +++ b/lib/couchrest/more/casted_model.rb @@ -4,7 +4,7 @@ module CouchRest module CastedModel def self.included(base) - base.send(:include, CouchRest::Mixins::Properties) + base.send(:include, ::CouchRest::Mixins::Properties) base.send(:attr_accessor, :casted_by) end diff --git a/spec/couchrest/core/database_spec.rb b/spec/couchrest/core/database_spec.rb index 3375779..8d4bdd9 100644 --- a/spec/couchrest/core/database_spec.rb +++ b/spec/couchrest/core/database_spec.rb @@ -369,7 +369,7 @@ describe CouchRest::Database do it "should delete the attachment" do lambda { @db.fetch_attachment(@doc,'test.html') }.should_not raise_error @db.delete_attachment(@doc, "test.html") - lambda { @db.fetch_attachment(@doc,'test.html') }.should raise_error(RestClient::ResourceNotFound) + @db.fetch_attachment(@doc,'test.html').should be_nil end end From beb801d1bde54d780be07a9e4d925d8c23b66fa5 Mon Sep 17 00:00:00 2001 From: Matt Aimonetti Date: Wed, 29 Jul 2009 19:01:38 -0700 Subject: [PATCH 15/22] fixed the database attachment specs --- spec/couchrest/core/database_spec.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spec/couchrest/core/database_spec.rb b/spec/couchrest/core/database_spec.rb index 8d4bdd9..632ba52 100644 --- a/spec/couchrest/core/database_spec.rb +++ b/spec/couchrest/core/database_spec.rb @@ -368,8 +368,9 @@ describe CouchRest::Database do end it "should delete the attachment" do lambda { @db.fetch_attachment(@doc,'test.html') }.should_not raise_error - @db.delete_attachment(@doc, "test.html") - @db.fetch_attachment(@doc,'test.html').should be_nil + @db.delete_attachment(@doc, "test.html") + @doc = @db.get('mydocwithattachment') # avoid getting a 409 + lambda{ @db.fetch_attachment(@doc,'test.html')}.should raise_error end end From 41055fd5adeb8bcf4e43ed56428d86d1c5cad260 Mon Sep 17 00:00:00 2001 From: Matt Aimonetti Date: Wed, 29 Jul 2009 20:07:02 -0700 Subject: [PATCH 16/22] added an option to force the deletion of a attachment --- lib/couchrest/core/database.rb | 15 +++++++++++++-- spec/couchrest/core/database_spec.rb | 9 +++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/couchrest/core/database.rb b/lib/couchrest/core/database.rb index 08eb4cb..ce7e1a6 100644 --- a/lib/couchrest/core/database.rb +++ b/lib/couchrest/core/database.rb @@ -113,10 +113,21 @@ module CouchRest end # DELETE an attachment directly from CouchDB - def delete_attachment doc, name + def delete_attachment(doc, name, force=false) uri = url_for_attachment(doc, name) # this needs a rev - JSON.parse(HttpAbstraction.delete(uri)) + begin + JSON.parse(HttpAbstraction.delete(uri)) + rescue Exception => error + if force + # get over a 409 + doc = get(doc['_id']) + uri = url_for_attachment(doc, name) + JSON.parse(HttpAbstraction.delete(uri)) + else + error + end + end end # Save a document to CouchDB. This will use the _id field from diff --git a/spec/couchrest/core/database_spec.rb b/spec/couchrest/core/database_spec.rb index 632ba52..d1c58ad 100644 --- a/spec/couchrest/core/database_spec.rb +++ b/spec/couchrest/core/database_spec.rb @@ -372,6 +372,15 @@ describe CouchRest::Database do @doc = @db.get('mydocwithattachment') # avoid getting a 409 lambda{ @db.fetch_attachment(@doc,'test.html')}.should raise_error end + + it "should force a delete even if we get a 409" do + @doc['new_attribute'] = 'something new' + @db.put_attachment(@doc, 'test', File.open(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'attachments', 'test.html')).read) + # at this point the revision number changed, if we try to save doc one more time + # we would get a 409. + lambda{ @db.save_doc(@doc) }.should raise_error + lambda{ @db.delete_attachment(@doc, "test", true) }.should_not raise_error + end end describe "POST document with attachment (with funky name)" do From 5270fde0fafb21e9e65dfc161fc09c3740d2f62d Mon Sep 17 00:00:00 2001 From: Matt Aimonetti Date: Wed, 29 Jul 2009 20:12:35 -0700 Subject: [PATCH 17/22] added an option to force the deletion of a attachment --- lib/couchrest/core/database.rb | 15 +++++++++++++-- lib/couchrest/mixins/attachments.rb | 4 ++-- spec/couchrest/core/database_spec.rb | 9 +++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/couchrest/core/database.rb b/lib/couchrest/core/database.rb index 08eb4cb..ce7e1a6 100644 --- a/lib/couchrest/core/database.rb +++ b/lib/couchrest/core/database.rb @@ -113,10 +113,21 @@ module CouchRest end # DELETE an attachment directly from CouchDB - def delete_attachment doc, name + def delete_attachment(doc, name, force=false) uri = url_for_attachment(doc, name) # this needs a rev - JSON.parse(HttpAbstraction.delete(uri)) + begin + JSON.parse(HttpAbstraction.delete(uri)) + rescue Exception => error + if force + # get over a 409 + doc = get(doc['_id']) + uri = url_for_attachment(doc, name) + JSON.parse(HttpAbstraction.delete(uri)) + else + error + end + end end # Save a document to CouchDB. This will use the _id field from diff --git a/lib/couchrest/mixins/attachments.rb b/lib/couchrest/mixins/attachments.rb index f009b3e..b4c1bfe 100644 --- a/lib/couchrest/mixins/attachments.rb +++ b/lib/couchrest/mixins/attachments.rb @@ -19,9 +19,9 @@ module CouchRest end # deletes an attachment directly from couchdb - def delete_attachment(name) + def delete_attachment(name, force=false) raise ArgumentError, "doc.database required to delete_attachment" unless database - result = database.delete_attachment(self, name) + result = database.delete_attachment(self, name, force) self['_rev'] = result['rev'] result['ok'] end diff --git a/spec/couchrest/core/database_spec.rb b/spec/couchrest/core/database_spec.rb index 632ba52..d1c58ad 100644 --- a/spec/couchrest/core/database_spec.rb +++ b/spec/couchrest/core/database_spec.rb @@ -372,6 +372,15 @@ describe CouchRest::Database do @doc = @db.get('mydocwithattachment') # avoid getting a 409 lambda{ @db.fetch_attachment(@doc,'test.html')}.should raise_error end + + it "should force a delete even if we get a 409" do + @doc['new_attribute'] = 'something new' + @db.put_attachment(@doc, 'test', File.open(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'attachments', 'test.html')).read) + # at this point the revision number changed, if we try to save doc one more time + # we would get a 409. + lambda{ @db.save_doc(@doc) }.should raise_error + lambda{ @db.delete_attachment(@doc, "test", true) }.should_not raise_error + end end describe "POST document with attachment (with funky name)" do From 0fc1a88ede989a6d0a3a13e6e73d220aeffb6f0d Mon Sep 17 00:00:00 2001 From: Matt Aimonetti Date: Wed, 29 Jul 2009 20:16:59 -0700 Subject: [PATCH 18/22] updated the history file --- history.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/history.txt b/history.txt index 7980257..b505d2a 100644 --- a/history.txt +++ b/history.txt @@ -12,7 +12,9 @@ you will need to make the following modifications. * Added a new Rack logger middleware letting you log/save requests/queries (Matt Aimonetti) * Minor enhancements - + + * Added an option to force the deletion of a attachments (bypass 409s) (Matt Aimonetti) + * Created a new abstraction layer for the REST API (Matt Aimonetti) * Bug fix: made ExtendedDocument#all compatible with Couch 0.10 (tc) == 0.32 From d1d8da513c9a5e8782455ab7516291a45e3e4a7e Mon Sep 17 00:00:00 2001 From: John Wood Date: Sat, 25 Jul 2009 11:12:03 +0800 Subject: [PATCH 19/22] Added code to generate a property? method for properties casted as :boolean Signed-off-by: Matt Aimonetti --- lib/couchrest/mixins/properties.rb | 15 +++++++++++++++ spec/couchrest/more/property_spec.rb | 28 +++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/lib/couchrest/mixins/properties.rb b/lib/couchrest/mixins/properties.rb index 2982d30..69c9411 100644 --- a/lib/couchrest/mixins/properties.rb +++ b/lib/couchrest/mixins/properties.rb @@ -77,6 +77,9 @@ module CouchRest # Float instances don't get initialized with #new elsif ((property.init_method == 'new') && target == 'Float') cast_float(self[key]) + # 'boolean' type is simply used to generate a property? accessor method + elsif ((property.init_method == 'new') && target == 'boolean') + self[key] else # Let people use :send as a Time parse arg klass = ::CouchRest.constantize(target) @@ -128,6 +131,18 @@ module CouchRest end EOS + if property.type == 'boolean' + class_eval <<-EOS, __FILE__, __LINE__ + def #{property.name}? + if self['#{property.name}'].nil? || self['#{property.name}'] == false || self['#{property.name}'].to_s.downcase == 'false' + false + else + true + end + end + EOS + end + if property.alias class_eval <<-EOS, __FILE__, __LINE__ alias #{property.alias.to_sym} #{property.name.to_sym} diff --git a/spec/couchrest/more/property_spec.rb b/spec/couchrest/more/property_spec.rb index 6782789..efeba94 100644 --- a/spec/couchrest/more/property_spec.rb +++ b/spec/couchrest/more/property_spec.rb @@ -161,9 +161,35 @@ describe "ExtendedDocument properties" do it "should work fine when a float is being passed" do RootBeerFloat.new(:price => 9.99).price.should == 9.99 end - end + describe "casting to a boolean value" do + class RootBeerFloat < CouchRest::ExtendedDocument + use_database DB + property :tasty, :cast_as => :boolean + end + + it "should add an accessor with a '?' for boolean attributes that returns true or false" do + RootBeerFloat.new(:tasty => true).tasty?.should == true + RootBeerFloat.new(:tasty => 'you bet').tasty?.should == true + RootBeerFloat.new(:tasty => 123).tasty?.should == true + + RootBeerFloat.new(:tasty => false).tasty?.should == false + RootBeerFloat.new(:tasty => 'false').tasty?.should == false + RootBeerFloat.new(:tasty => 'FaLsE').tasty?.should == false + RootBeerFloat.new(:tasty => nil).tasty?.should == false + end + + it "should return the real value when the default accessor is used" do + RootBeerFloat.new(:tasty => true).tasty.should == true + RootBeerFloat.new(:tasty => 'you bet').tasty.should == 'you bet' + RootBeerFloat.new(:tasty => 123).tasty.should == 123 + RootBeerFloat.new(:tasty => 'false').tasty.should == 'false' + RootBeerFloat.new(:tasty => false).tasty.should == false + RootBeerFloat.new(:tasty => nil).tasty.should == nil + end + end + end end From a17df45fc3909c48099393eb44b419881107280c Mon Sep 17 00:00:00 2001 From: Matt Aimonetti Date: Sat, 1 Aug 2009 14:21:18 -0700 Subject: [PATCH 20/22] made all the specs run on 1.9.2, yay :) --- lib/couchrest/more/casted_model.rb | 3 ++- spec/couchrest/core/couchrest_spec.rb | 2 +- spec/couchrest/core/database_spec.rb | 8 ++++++-- spec/couchrest/core/design_spec.rb | 2 +- spec/couchrest/core/document_spec.rb | 2 +- spec/couchrest/core/server_spec.rb | 2 +- spec/couchrest/helpers/pager_spec.rb | 2 +- spec/couchrest/helpers/streamer_spec.rb | 2 +- spec/couchrest/more/casted_extended_doc_spec.rb | 2 +- spec/couchrest/more/casted_model_spec.rb | 2 +- spec/couchrest/more/extended_doc_attachment_spec.rb | 2 +- spec/couchrest/more/extended_doc_spec.rb | 2 +- spec/couchrest/more/extended_doc_subclass_spec.rb | 2 +- spec/couchrest/more/extended_doc_view_spec.rb | 5 +++-- spec/couchrest/more/property_spec.rb | 2 +- 15 files changed, 23 insertions(+), 17 deletions(-) diff --git a/lib/couchrest/more/casted_model.rb b/lib/couchrest/more/casted_model.rb index 5e4da2e..5b8d383 100644 --- a/lib/couchrest/more/casted_model.rb +++ b/lib/couchrest/more/casted_model.rb @@ -1,4 +1,5 @@ -require File.join(File.dirname(__FILE__), '..', 'mixins', 'properties') +require File.expand_path('../../mixins/properties', __FILE__) + module CouchRest module CastedModel diff --git a/spec/couchrest/core/couchrest_spec.rb b/spec/couchrest/core/couchrest_spec.rb index 35e48e6..ef6637c 100644 --- a/spec/couchrest/core/couchrest_spec.rb +++ b/spec/couchrest/core/couchrest_spec.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../../spec_helper' +require File.expand_path("../../../spec_helper", __FILE__) describe CouchRest do diff --git a/spec/couchrest/core/database_spec.rb b/spec/couchrest/core/database_spec.rb index d1c58ad..98b7947 100644 --- a/spec/couchrest/core/database_spec.rb +++ b/spec/couchrest/core/database_spec.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../../spec_helper' +require File.expand_path("../../../spec_helper", __FILE__) describe CouchRest::Database do before(:each) do @@ -263,7 +263,11 @@ describe CouchRest::Database do r['ok'].should == true doc = @db.get("attach-this") attachment = @db.fetch_attachment(doc,"couchdb.png") - attachment.should == image + if attachment.respond_to?(:net_http_res) + attachment.net_http_res.body.should == image + else + attachment.should == image + end end end diff --git a/spec/couchrest/core/design_spec.rb b/spec/couchrest/core/design_spec.rb index 8b367c7..b5b2ce1 100644 --- a/spec/couchrest/core/design_spec.rb +++ b/spec/couchrest/core/design_spec.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../../spec_helper' +require File.expand_path("../../../spec_helper", __FILE__) describe CouchRest::Design do diff --git a/spec/couchrest/core/document_spec.rb b/spec/couchrest/core/document_spec.rb index e83c05f..287ee79 100644 --- a/spec/couchrest/core/document_spec.rb +++ b/spec/couchrest/core/document_spec.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../../spec_helper' +require File.expand_path("../../../spec_helper", __FILE__) class Video < CouchRest::Document; end diff --git a/spec/couchrest/core/server_spec.rb b/spec/couchrest/core/server_spec.rb index 5e0f1f7..f55dd29 100644 --- a/spec/couchrest/core/server_spec.rb +++ b/spec/couchrest/core/server_spec.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../../spec_helper' +require File.expand_path("../../../spec_helper", __FILE__) describe CouchRest::Server do diff --git a/spec/couchrest/helpers/pager_spec.rb b/spec/couchrest/helpers/pager_spec.rb index ed16df3..3c111f6 100644 --- a/spec/couchrest/helpers/pager_spec.rb +++ b/spec/couchrest/helpers/pager_spec.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../../spec_helper' +require File.expand_path("../../../spec_helper", __FILE__) describe CouchRest::Pager do before(:all) do diff --git a/spec/couchrest/helpers/streamer_spec.rb b/spec/couchrest/helpers/streamer_spec.rb index 5479390..cf828ca 100644 --- a/spec/couchrest/helpers/streamer_spec.rb +++ b/spec/couchrest/helpers/streamer_spec.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../../spec_helper' +require File.expand_path("../../../spec_helper", __FILE__) describe CouchRest::Streamer do before(:all) do diff --git a/spec/couchrest/more/casted_extended_doc_spec.rb b/spec/couchrest/more/casted_extended_doc_spec.rb index 51afd77..6e3e13c 100644 --- a/spec/couchrest/more/casted_extended_doc_spec.rb +++ b/spec/couchrest/more/casted_extended_doc_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') +require File.expand_path('../../../spec_helper', __FILE__) require File.join(FIXTURE_PATH, 'more', 'card') class Car < CouchRest::ExtendedDocument diff --git a/spec/couchrest/more/casted_model_spec.rb b/spec/couchrest/more/casted_model_spec.rb index 75b0c57..c1de242 100644 --- a/spec/couchrest/more/casted_model_spec.rb +++ b/spec/couchrest/more/casted_model_spec.rb @@ -1,6 +1,6 @@ # encoding: utf-8 -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') +require File.expand_path('../../../spec_helper', __FILE__) require File.join(FIXTURE_PATH, 'more', 'card') require File.join(FIXTURE_PATH, 'more', 'cat') require File.join(FIXTURE_PATH, 'more', 'person') diff --git a/spec/couchrest/more/extended_doc_attachment_spec.rb b/spec/couchrest/more/extended_doc_attachment_spec.rb index d82d9fe..e73db96 100644 --- a/spec/couchrest/more/extended_doc_attachment_spec.rb +++ b/spec/couchrest/more/extended_doc_attachment_spec.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../../spec_helper' +require File.expand_path('../../../spec_helper', __FILE__) describe "ExtendedDocument attachments" do diff --git a/spec/couchrest/more/extended_doc_spec.rb b/spec/couchrest/more/extended_doc_spec.rb index f3097ff..1b05bc3 100644 --- a/spec/couchrest/more/extended_doc_spec.rb +++ b/spec/couchrest/more/extended_doc_spec.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../../spec_helper' +require File.expand_path("../../../spec_helper", __FILE__) require File.join(FIXTURE_PATH, 'more', 'article') require File.join(FIXTURE_PATH, 'more', 'course') diff --git a/spec/couchrest/more/extended_doc_subclass_spec.rb b/spec/couchrest/more/extended_doc_subclass_spec.rb index ef31a7a..6a9bdc9 100644 --- a/spec/couchrest/more/extended_doc_subclass_spec.rb +++ b/spec/couchrest/more/extended_doc_subclass_spec.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../../spec_helper' +require File.expand_path("../../../spec_helper", __FILE__) require File.join(FIXTURE_PATH, 'more', 'card') require File.join(FIXTURE_PATH, 'more', 'course') diff --git a/spec/couchrest/more/extended_doc_view_spec.rb b/spec/couchrest/more/extended_doc_view_spec.rb index be6056e..f532e95 100644 --- a/spec/couchrest/more/extended_doc_view_spec.rb +++ b/spec/couchrest/more/extended_doc_view_spec.rb @@ -1,4 +1,4 @@ -require File.dirname(__FILE__) + '/../../spec_helper' +require File.expand_path("../../../spec_helper", __FILE__) require File.join(FIXTURE_PATH, 'more', 'article') require File.join(FIXTURE_PATH, 'more', 'course') @@ -354,7 +354,8 @@ describe "ExtendedDocument views" do a = Article.new(:title => title, :date => Date.today) a.save end - end + end + require 'date' it "should return a proxy that looks like an array of 7 Article objects" do articles = Article.by_date :key => Date.today articles.class.should == Array diff --git a/spec/couchrest/more/property_spec.rb b/spec/couchrest/more/property_spec.rb index efeba94..126d86f 100644 --- a/spec/couchrest/more/property_spec.rb +++ b/spec/couchrest/more/property_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') +require File.expand_path('../../../spec_helper', __FILE__) require File.join(FIXTURE_PATH, 'more', 'person') require File.join(FIXTURE_PATH, 'more', 'card') require File.join(FIXTURE_PATH, 'more', 'invoice') From 889a923dbf25a2aba6034b063d9f3e09844b7896 Mon Sep 17 00:00:00 2001 From: Matt Aimonetti Date: Mon, 3 Aug 2009 12:19:07 -0700 Subject: [PATCH 21/22] Added #amount_pages to a paginated result array --- lib/couchrest/mixins/collection.rb | 16 ++++++++++++++-- spec/couchrest/more/extended_doc_view_spec.rb | 3 +-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/couchrest/mixins/collection.rb b/lib/couchrest/mixins/collection.rb index e388146..a5f7d99 100644 --- a/lib/couchrest/mixins/collection.rb +++ b/lib/couchrest/mixins/collection.rb @@ -1,5 +1,14 @@ module CouchRest module Mixins + module PaginatedResults + def amount_pages + @amount_pages ||= 0 + end + def amount_pages=(value) + @amount_pages = value + end + end + module Collection def self.included(base) @@ -115,7 +124,10 @@ module CouchRest results = @database.view(@view_name, pagination_options(page, per_page)) @amount_pages ||= (results['total_rows'].to_f / per_page.to_f).ceil remember_where_we_left_off(results, page) - convert_to_container_array(results) + results = convert_to_container_array(results) + results.extend(PaginatedResults) + results.amount_pages = @amount_pages + results end # See Collection.paginated_each @@ -181,7 +193,7 @@ module CouchRest @target.inspect end - def convert_to_container_array(results) + def convert_to_container_array(results) if @container_class.nil? results else diff --git a/spec/couchrest/more/extended_doc_view_spec.rb b/spec/couchrest/more/extended_doc_view_spec.rb index f532e95..d23061a 100644 --- a/spec/couchrest/more/extended_doc_view_spec.rb +++ b/spec/couchrest/more/extended_doc_view_spec.rb @@ -375,8 +375,7 @@ describe "ExtendedDocument views" do end it "should have the amount of paginated pages" do articles = Article.by_date :key => Date.today - articles.paginate(:per_page => 3) - articles.amount_pages.should == 3 + articles.paginate(:per_page => 3).amount_pages.should == 3 end it "should provide a class method to access the collection directly" do articles = Article.collection_proxy_for('Article', 'by_date', :descending => true, From 6811745a324fdac0ab282a387eb1314a182034b3 Mon Sep 17 00:00:00 2001 From: Matt Aimonetti Date: Mon, 3 Aug 2009 12:23:13 -0700 Subject: [PATCH 22/22] bumped the version number to 0.33 --- README.md | 2 +- couchrest.gemspec | 4 ++-- history.txt | 16 ++++++---------- lib/couchrest.rb | 2 +- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index d9cc490..5692d35 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Note: CouchRest only support CouchDB 0.9.0 or newer. Alternatively, you can install from Github: $ gem sources -a http://gems.github.com (you only have to do this once) - $ sudo gem install mattetti-couchrest + $ sudo gem install couchrest-couchrest ### Relax, it's RESTful diff --git a/couchrest.gemspec b/couchrest.gemspec index 9dea7e5..26fa2a0 100644 --- a/couchrest.gemspec +++ b/couchrest.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{couchrest} - s.version = "0.32" + s.version = "0.33" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["J. Chris Anderson", "Matt Aimonetti"] @@ -10,7 +10,7 @@ Gem::Specification.new do |s| s.description = %q{CouchRest provides a simple interface on top of CouchDB's RESTful HTTP API, as well as including some utility scripts for managing views and attachments.} s.email = %q{jchris@apache.org} s.extra_rdoc_files = ["README.md", "LICENSE", "THANKS.md"] - s.files = ["LICENSE", "README.md", "Rakefile", "THANKS.md", "history.txt", "examples/model", "examples/model/example.rb", "examples/word_count", "examples/word_count/markov", "examples/word_count/views", "examples/word_count/views/books", "examples/word_count/views/books/chunked-map.js", "examples/word_count/views/books/united-map.js", "examples/word_count/views/markov", "examples/word_count/views/markov/chain-map.js", "examples/word_count/views/markov/chain-reduce.js", "examples/word_count/views/word_count", "examples/word_count/views/word_count/count-map.js", "examples/word_count/views/word_count/count-reduce.js", "examples/word_count/word_count.rb", "examples/word_count/word_count_query.rb", "examples/word_count/word_count_views.rb", "lib/couchrest", "lib/couchrest/commands", "lib/couchrest/commands/generate.rb", "lib/couchrest/commands/push.rb", "lib/couchrest/core", "lib/couchrest/core/adapters", "lib/couchrest/core/adapters/restclient.rb", "lib/couchrest/core/database.rb", "lib/couchrest/core/design.rb", "lib/couchrest/core/document.rb", "lib/couchrest/core/http_abstraction.rb", "lib/couchrest/core/response.rb", "lib/couchrest/core/server.rb", "lib/couchrest/core/view.rb", "lib/couchrest/helper", "lib/couchrest/helper/pager.rb", "lib/couchrest/helper/streamer.rb", "lib/couchrest/helper/upgrade.rb", "lib/couchrest/mixins", "lib/couchrest/mixins/attachments.rb", "lib/couchrest/mixins/callbacks.rb", "lib/couchrest/mixins/class_proxy.rb", "lib/couchrest/mixins/collection.rb", "lib/couchrest/mixins/design_doc.rb", "lib/couchrest/mixins/document_queries.rb", "lib/couchrest/mixins/extended_attachments.rb", "lib/couchrest/mixins/extended_document_mixins.rb", "lib/couchrest/mixins/properties.rb", "lib/couchrest/mixins/validation.rb", "lib/couchrest/mixins/views.rb", "lib/couchrest/mixins.rb", "lib/couchrest/monkeypatches.rb", "lib/couchrest/more", "lib/couchrest/more/casted_model.rb", "lib/couchrest/more/extended_document.rb", "lib/couchrest/more/property.rb", "lib/couchrest/support", "lib/couchrest/support/blank.rb", "lib/couchrest/support/class.rb", "lib/couchrest/support/rails.rb", "lib/couchrest/validation", "lib/couchrest/validation/auto_validate.rb", "lib/couchrest/validation/contextual_validators.rb", "lib/couchrest/validation/validation_errors.rb", "lib/couchrest/validation/validators", "lib/couchrest/validation/validators/absent_field_validator.rb", "lib/couchrest/validation/validators/confirmation_validator.rb", "lib/couchrest/validation/validators/format_validator.rb", "lib/couchrest/validation/validators/formats", "lib/couchrest/validation/validators/formats/email.rb", "lib/couchrest/validation/validators/formats/url.rb", "lib/couchrest/validation/validators/generic_validator.rb", "lib/couchrest/validation/validators/length_validator.rb", "lib/couchrest/validation/validators/method_validator.rb", "lib/couchrest/validation/validators/numeric_validator.rb", "lib/couchrest/validation/validators/required_field_validator.rb", "lib/couchrest.rb", "spec/couchrest", "spec/couchrest/core", "spec/couchrest/core/couchrest_spec.rb", "spec/couchrest/core/database_spec.rb", "spec/couchrest/core/design_spec.rb", "spec/couchrest/core/document_spec.rb", "spec/couchrest/core/server_spec.rb", "spec/couchrest/helpers", "spec/couchrest/helpers/pager_spec.rb", "spec/couchrest/helpers/streamer_spec.rb", "spec/couchrest/more", "spec/couchrest/more/casted_extended_doc_spec.rb", "spec/couchrest/more/casted_model_spec.rb", "spec/couchrest/more/extended_doc_attachment_spec.rb", "spec/couchrest/more/extended_doc_spec.rb", "spec/couchrest/more/extended_doc_subclass_spec.rb", "spec/couchrest/more/extended_doc_view_spec.rb", "spec/couchrest/more/property_spec.rb", "spec/fixtures", "spec/fixtures/attachments", "spec/fixtures/attachments/couchdb.png", "spec/fixtures/attachments/README", "spec/fixtures/attachments/test.html", "spec/fixtures/more", "spec/fixtures/more/article.rb", "spec/fixtures/more/card.rb", "spec/fixtures/more/cat.rb", "spec/fixtures/more/course.rb", "spec/fixtures/more/event.rb", "spec/fixtures/more/invoice.rb", "spec/fixtures/more/person.rb", "spec/fixtures/more/question.rb", "spec/fixtures/more/service.rb", "spec/fixtures/views", "spec/fixtures/views/lib.js", "spec/fixtures/views/test_view", "spec/fixtures/views/test_view/lib.js", "spec/fixtures/views/test_view/only-map.js", "spec/fixtures/views/test_view/test-map.js", "spec/fixtures/views/test_view/test-reduce.js", "spec/spec.opts", "spec/spec_helper.rb", "utils/remap.rb", "utils/subset.rb"] + s.files = ["LICENSE", "README.md", "Rakefile", "THANKS.md", "history.txt", "examples/model", "examples/model/example.rb", "examples/word_count", "examples/word_count/markov", "examples/word_count/views", "examples/word_count/views/books", "examples/word_count/views/books/chunked-map.js", "examples/word_count/views/books/united-map.js", "examples/word_count/views/markov", "examples/word_count/views/markov/chain-map.js", "examples/word_count/views/markov/chain-reduce.js", "examples/word_count/views/word_count", "examples/word_count/views/word_count/count-map.js", "examples/word_count/views/word_count/count-reduce.js", "examples/word_count/word_count.rb", "examples/word_count/word_count_query.rb", "examples/word_count/word_count_views.rb", "lib/couchrest", "lib/couchrest/commands", "lib/couchrest/commands/generate.rb", "lib/couchrest/commands/push.rb", "lib/couchrest/core", "lib/couchrest/core/adapters", "lib/couchrest/core/adapters/restclient.rb", "lib/couchrest/core/database.rb", "lib/couchrest/core/design.rb", "lib/couchrest/core/document.rb", "lib/couchrest/core/http_abstraction.rb", "lib/couchrest/core/response.rb", "lib/couchrest/core/rest_api.rb", "lib/couchrest/core/server.rb", "lib/couchrest/core/view.rb", "lib/couchrest/helper", "lib/couchrest/helper/pager.rb", "lib/couchrest/helper/streamer.rb", "lib/couchrest/helper/upgrade.rb", "lib/couchrest/middlewares", "lib/couchrest/middlewares/logger.rb", "lib/couchrest/mixins", "lib/couchrest/mixins/attachments.rb", "lib/couchrest/mixins/callbacks.rb", "lib/couchrest/mixins/class_proxy.rb", "lib/couchrest/mixins/collection.rb", "lib/couchrest/mixins/design_doc.rb", "lib/couchrest/mixins/document_queries.rb", "lib/couchrest/mixins/extended_attachments.rb", "lib/couchrest/mixins/extended_document_mixins.rb", "lib/couchrest/mixins/properties.rb", "lib/couchrest/mixins/validation.rb", "lib/couchrest/mixins/views.rb", "lib/couchrest/mixins.rb", "lib/couchrest/monkeypatches.rb", "lib/couchrest/more", "lib/couchrest/more/casted_model.rb", "lib/couchrest/more/extended_document.rb", "lib/couchrest/more/property.rb", "lib/couchrest/support", "lib/couchrest/support/blank.rb", "lib/couchrest/support/class.rb", "lib/couchrest/support/rails.rb", "lib/couchrest/validation", "lib/couchrest/validation/auto_validate.rb", "lib/couchrest/validation/contextual_validators.rb", "lib/couchrest/validation/validation_errors.rb", "lib/couchrest/validation/validators", "lib/couchrest/validation/validators/absent_field_validator.rb", "lib/couchrest/validation/validators/confirmation_validator.rb", "lib/couchrest/validation/validators/format_validator.rb", "lib/couchrest/validation/validators/formats", "lib/couchrest/validation/validators/formats/email.rb", "lib/couchrest/validation/validators/formats/url.rb", "lib/couchrest/validation/validators/generic_validator.rb", "lib/couchrest/validation/validators/length_validator.rb", "lib/couchrest/validation/validators/method_validator.rb", "lib/couchrest/validation/validators/numeric_validator.rb", "lib/couchrest/validation/validators/required_field_validator.rb", "lib/couchrest.rb", "spec/couchrest", "spec/couchrest/core", "spec/couchrest/core/couchrest_spec.rb", "spec/couchrest/core/database_spec.rb", "spec/couchrest/core/design_spec.rb", "spec/couchrest/core/document_spec.rb", "spec/couchrest/core/server_spec.rb", "spec/couchrest/helpers", "spec/couchrest/helpers/pager_spec.rb", "spec/couchrest/helpers/streamer_spec.rb", "spec/couchrest/more", "spec/couchrest/more/casted_extended_doc_spec.rb", "spec/couchrest/more/casted_model_spec.rb", "spec/couchrest/more/extended_doc_attachment_spec.rb", "spec/couchrest/more/extended_doc_spec.rb", "spec/couchrest/more/extended_doc_subclass_spec.rb", "spec/couchrest/more/extended_doc_view_spec.rb", "spec/couchrest/more/property_spec.rb", "spec/fixtures", "spec/fixtures/attachments", "spec/fixtures/attachments/couchdb.png", "spec/fixtures/attachments/README", "spec/fixtures/attachments/test.html", "spec/fixtures/more", "spec/fixtures/more/article.rb", "spec/fixtures/more/card.rb", "spec/fixtures/more/cat.rb", "spec/fixtures/more/course.rb", "spec/fixtures/more/event.rb", "spec/fixtures/more/invoice.rb", "spec/fixtures/more/person.rb", "spec/fixtures/more/question.rb", "spec/fixtures/more/service.rb", "spec/fixtures/views", "spec/fixtures/views/lib.js", "spec/fixtures/views/test_view", "spec/fixtures/views/test_view/lib.js", "spec/fixtures/views/test_view/only-map.js", "spec/fixtures/views/test_view/test-map.js", "spec/fixtures/views/test_view/test-reduce.js", "spec/spec.opts", "spec/spec_helper.rb", "utils/remap.rb", "utils/subset.rb"] s.homepage = %q{http://github.com/jchris/couchrest} s.require_paths = ["lib"] s.rubygems_version = %q{1.3.4} diff --git a/history.txt b/history.txt index b505d2a..5ce94b2 100644 --- a/history.txt +++ b/history.txt @@ -1,18 +1,14 @@ -== 0.40 - -=== Notes - - This release slightly modifies the API and if you were using a previous version of CouchRest, -you will need to make the following modifications. - - +== 0.33 * Major enhancements * Added a new Rack logger middleware letting you log/save requests/queries (Matt Aimonetti) * Minor enhancements - + + * Added #amount_pages to a paginated result array (Matt Aimonetti) + * Ruby 1.9.2 compatible (Matt Aimonetti) + * Added a property? method for property cast as :boolean (John Wood) * Added an option to force the deletion of a attachments (bypass 409s) (Matt Aimonetti) * Created a new abstraction layer for the REST API (Matt Aimonetti) * Bug fix: made ExtendedDocument#all compatible with Couch 0.10 (tc) @@ -64,4 +60,4 @@ you will need to make the following modifications. --- Unfortunately, before 0.30 we did not keep a track of the modifications made to CouchRest. -You can see the full commit history on GitHub: http://github.com/mattetti/couchrest/commits/master/ \ No newline at end of file +You can see the full commit history on GitHub: http://github.com/couchrest/couchrest/commits/master/ \ No newline at end of file diff --git a/lib/couchrest.rb b/lib/couchrest.rb index efb5847..3da42d8 100644 --- a/lib/couchrest.rb +++ b/lib/couchrest.rb @@ -28,7 +28,7 @@ require 'couchrest/monkeypatches' # = CouchDB, close to the metal module CouchRest - VERSION = '0.32' unless self.const_defined?("VERSION") + VERSION = '0.33' unless self.const_defined?("VERSION") autoload :Server, 'couchrest/core/server' autoload :Database, 'couchrest/core/database'