Skip to content

Commit

Permalink
Merge branch 'master' of git://github.com/couchrest/couchrest
Browse files Browse the repository at this point in the history
  • Loading branch information
Sam Lown committed Mar 3, 2010
2 parents bb2c7e8 + 0d0a8ae commit 857695e
Show file tree
Hide file tree
Showing 44 changed files with 798 additions and 371 deletions.
2 changes: 2 additions & 0 deletions .gitignore
@@ -1,3 +1,5 @@
.DS_Store
html/*
pkg
*.swp
couchrest.gemspec
152 changes: 7 additions & 145 deletions README.md
Expand Up @@ -14,11 +14,6 @@ Note: CouchRest only support CouchDB 0.9.0 or newer.

$ sudo gem install couchrest

Alternatively, you can install from Github:

$ gem sources -a http://gems.github.com (you only have to do this once)
$ sudo gem install couchrest-couchrest

### Relax, it's RESTful

CouchRest rests on top of a HTTP abstraction layer using by default Heroku’s excellent REST Client Ruby HTTP wrapper.
Expand All @@ -30,152 +25,19 @@ The most complete documentation is the spec/ directory. To validate your
CouchRest install, from the project root directory run `rake`, or `autotest`
(requires RSpec and optionally ZenTest for autotest support).

## Examples (CouchRest Core)

Quick Start:

# with !, it creates the database if it doesn't already exist
@db = CouchRest.database!("http://127.0.0.1:5984/couchrest-test")
response = @db.save_doc({:key => 'value', 'another key' => 'another value'})
doc = @db.get(response['id'])
puts doc.inspect

Bulk Save:

@db.bulk_save([
{"wild" => "and random"},
{"mild" => "yet local"},
{"another" => ["set","of","keys"]}
])
# returns ids and revs of the current docs
puts @db.documents.inspect

Creating and Querying Views:

@db.save_doc({
"_id" => "_design/first",
:views => {
:test => {
:map => "function(doc){for(var w in doc){ if(!w.match(/^_/))emit(w,doc[w])}}"
}
}
})
puts @db.view('first/test')['rows'].inspect


## CouchRest::ExtendedDocument

CouchRest::ExtendedDocument is a DSL/ORM for CouchDB. Basically, ExtendedDocument seats on top of CouchRest Core to add the concept of Model.
ExtendedDocument offers a lot of the usual ORM tools such as optional yet defined schema, validation, callbacks, pagination, casting and much more.

### Model example

Check spec/couchrest/more and spec/fixtures/more for more examples

class Article < CouchRest::ExtendedDocument
use_database DB
unique_id :slug

view_by :date, :descending => true
view_by :user_id, :date

view_by :tags,
:map =>
"function(doc) {
if (doc['couchrest-type'] == 'Article' && doc.tags) {
doc.tags.forEach(function(tag){
emit(tag, 1);
});
}
}",
:reduce =>
"function(keys, values, rereduce) {
return sum(values);
}"

property :date
property :slug, :read_only => true
property :title
property :tags, :cast_as => ['String']

timestamps!

save_callback :before, :generate_slug_from_title

def generate_slug_from_title
self['slug'] = title.downcase.gsub(/[^a-z0-9]/,'-').squeeze('-').gsub(/^\-|\-$/,'') if new?
end
end
## Docs

### Callbacks
API: [http://rdoc.info/projects/couchrest/couchrest](http://rdoc.info/projects/couchrest/couchrest)

`CouchRest::ExtendedDocuments` instances have 4 callbacks already defined for you:
`:validate`, `:create`, `:save`, `:update` and `:destroy`

`CouchRest::CastedModel` instances have 1 callback already defined for you:
`:validate`

Define your callback as follows:
Check the wiki for documentation and examples [http://wiki.github.com/couchrest/couchrest](http://wiki.github.com/couchrest/couchrest)

set_callback :save, :before, :generate_slug_from_name

CouchRest uses a mixin you can find in lib/mixins/callbacks which is extracted from Rails 3, here are some simple usage examples:
## Contact

set_callback :save, :before, :before_method
set_callback :save, :after, :after_method, :if => :condition
set_callback :save, :around {|r| stuff; yield; stuff }

Or the aliased short version:

before_save :before_method, :another_method
after_save :after_method, :another_method, :if => :condition
around_save {|r| stuff; yield; stuff }

To halt the callback, simply return a :halt symbol in your callback method.

Check the mixin or the ExtendedDocument class to see how to implement your own callbacks.

### Properties

property :last_name, :alias => :family_name
property :read_only_value, :read_only => true
property :name, :length => 4...20
property :price, :type => Integer

### Casting

Often, you will want to store multiple objects within a document, to be able to retrieve your objects when you load the document,
you can define some casting rules.

property :casted_attribute, :cast_as => 'WithCastedModelMixin'
property :keywords, :cast_as => ["String"]
property :occurs_at, :cast_as => 'Time', :send => 'parse
property :end_date, :cast_as => 'Date', :send => 'parse

If you want to cast an array of instances from a specific Class, use the trick shown above ["ClassName"]

### Pagination

Pagination is available in any ExtendedDocument classes. Here are some usage examples:
Please post bugs, suggestions and patches to the bug tracker at <http://jchris.lighthouseapp.com/projects/17807-couchrest/overview>.

basic usage:
Follow us on Twitter: http://twitter.com/couchrest

Article.all.paginate(:page => 1, :per_page => 5)

note: the above query will look like: `GET /db/_design/Article/_view/all?include_docs=true&skip=0&limit=5&reduce=false` and only fetch 5 documents.

Slightly more advance usage:

Article.by_name(:startkey => 'a', :endkey => {}).paginate(:page => 1, :per_page => 5)

note: the above query will look like: `GET /db/_design/Article/_view/by_name?startkey=%22a%22&limit=5&skip=0&endkey=%7B%7D&include_docs=true`
Basically, you can paginate through the articles starting by the letter a, 5 articles at a time.


Low level usage:

Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
:per_page => 3, :page => 2, :descending => true, :key => Date.today, :include_docs => true)
Also, check http://twitter.com/#search?q=%23couchrest

## Ruby on Rails

Expand Down
64 changes: 28 additions & 36 deletions Rakefile
@@ -1,9 +1,7 @@
require 'rake'
require "rake/rdoctask"
require 'rake/gempackagetask'
require File.join(File.expand_path(File.dirname(__FILE__)),'lib','couchrest')


begin
require 'spec/rake/spectask'
rescue LoadError
Expand All @@ -14,41 +12,26 @@ EOS
exit(0)
end

spec = Gem::Specification.new do |s|
s.name = "couchrest"
s.version = CouchRest::VERSION
s.date = "2008-11-22"
s.summary = "Lean and RESTful interface to CouchDB."
s.email = "jchris@apache.org"
s.homepage = "http://github.com/jchris/couchrest"
s.description = "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.has_rdoc = true
s.authors = ["J. Chris Anderson", "Matt Aimonetti"]
s.files = %w( LICENSE README.md Rakefile THANKS.md history.txt) +
Dir["{examples,lib,spec,utils}/**/*"] -
Dir["spec/tmp"]
s.extra_rdoc_files = %w( README.md LICENSE THANKS.md )
s.require_path = "lib"
s.add_dependency("rest-client", ">= 0.5")
s.add_dependency("mime-types", ">= 1.15")
end


desc "Create .gemspec file (useful for github)"
task :gemspec do
filename = "#{spec.name}.gemspec"
File.open(filename, "w") do |f|
f.puts spec.to_ruby
begin
require 'jeweler'
Jeweler::Tasks.new do |gemspec|
gemspec.name = "couchrest"
gemspec.summary = "Lean and RESTful interface to CouchDB."
gemspec.description = "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."
gemspec.email = "jchris@apache.org"
gemspec.homepage = "http://github.com/couchrest/couchrest"
gemspec.authors = ["J. Chris Anderson", "Matt Aimonetti", "Marcos Tapajos"]
gemspec.extra_rdoc_files = %w( README.md LICENSE THANKS.md )
gemspec.files = %w( LICENSE README.md Rakefile THANKS.md history.txt) + Dir["{examples,lib,spec,utils}/**/*"] - Dir["spec/tmp"]
gemspec.has_rdoc = true
gemspec.add_dependency("rest-client", ">= 0.5")
gemspec.add_dependency("mime-types", ">= 1.15")
gemspec.version = CouchRest::VERSION
gemspec.date = "2008-11-22"
gemspec.require_path = "lib"
end
end

Rake::GemPackageTask.new(spec) do |pkg|
pkg.gem_spec = spec
end

desc "Install the gem locally"
task :install => [:package] do
sh %{sudo gem install pkg/couchrest-#{CouchRest::VERSION}}
rescue LoadError
puts "Jeweler not available. Install it with: gem install jeweler"
end

desc "Run all specs"
Expand All @@ -73,3 +56,12 @@ end

desc "Run the rspec"
task :default => :spec

module Rake
def self.remove_task(task_name)
Rake.application.instance_variable_get('@tasks').delete(task_name.to_s)
end
end

Rake.remove_task("github:release")
Rake.remove_task("release")
2 changes: 1 addition & 1 deletion THANKS.md
Expand Up @@ -14,6 +14,6 @@ changes. A list of these people is included below.
* Simon Rozet (simon /at/ rozet /dot/ name)
* [Marcos Tapajós](http://tapajos.me)

Patches are welcome. The primary source for this software project is [on Github](http://github.com/jchris/couchrest/tree/master)
Patches are welcome. The primary source for this software project is [on Github](http://github.com/couchrest/couchrest)

A lot of people have active forks - thank you all - even the patches I don't end up using are helpful.
35 changes: 0 additions & 35 deletions couchrest.gemspec

This file was deleted.

20 changes: 0 additions & 20 deletions github_gemtest.rb

This file was deleted.

49 changes: 48 additions & 1 deletion history.txt
@@ -1,3 +1,50 @@
== Next Version

* Major enhancements

* Minor enhancements

== 0.35

* Major enhancements
* CouchRest::ExtendedDocument allow chaining the inherit class callback (Kenneth Kalmer) - http://github.com/couchrest/couchrest/issues#issue/8

* Minor enhancements
* Fix attachment bug (Johannes Jörg Schmidt)
* Fix create database exception bug (Damien Mathieu)
* Compatible with restclient >= 1.4.0 new responses (Julien Kirch)
* Bug fix: Attribute protection no longer strips attributes coming from the database (Will Leinweber)
* Bug fix: Remove double CGI escape when PUTting an attachment (nzoschke)
* Bug fix: Changing Class proxy to set database on result sets (Peter Gumeson)
* Bug fix: Updated time regexp (Nolan Darilek)
* Added an update_doc method to database to handle conflicts during atomic updates. (Pierre Larochelle)
* Bug fix: http://github.com/couchrest/couchrest/issues/#issue/2 (Luke Burton)

== 0.34

* Major enhancements

* Added support for https database URIs. (Mathias Meyer)
* Changing some validations to be compatible with activemodel. (Marcos Tapajós)
* Adds attribute protection to properties. (Will Leinweber)
* Improved CouchRest::Database#save_doc, added "batch" mode to significantly speed up saves at cost of lower durability gurantees. (Igal Koshevoy)
* Added CouchRest::Database#bulk_save_doc and #batch_save_doc as human-friendlier wrappers around #save_doc. (Igal Koshevoy)

* Minor enhancements

* Fix content_type handling for attachments
* Fixed a bug in the pagination code that caused it to paginate over records outside of the scope of the view parameters.(John Wood)
* Removed amount_pages calculation for the pagination collection, since it cannot be reliably calculated without a view.(John Wood)
* Bug fix: http://github.com/couchrest/couchrest/issues/#issue/2 (Luke Burton)
* Bug fix: http://github.com/couchrest/couchrest/issues/#issue/1 (Marcos Tapajós)
* Removed the Database class deprecation notices (Matt Aimonetti)
* Adding support to :cast_as => 'Date'. (Marcos Tapajós)
* Improve documentation (Marcos Tapajós)
* Streamer fixes (Julien Sanchez)
* Fix Save on Document & ExtendedDocument crashed if bulk (Julien Sanchez)
* Fix Initialization of ExtendentDocument model shouldn't failed on a nil value in argument (deepj)
* Change to use Jeweler and Gemcutter (Marcos Tapajós)

== 0.33

* Major enhancements
Expand Down Expand Up @@ -60,4 +107,4 @@
---

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/couchrest/couchrest/commits/master/
You can see the full commit history on GitHub: http://github.com/couchrest/couchrest/commits/master/

0 comments on commit 857695e

Please sign in to comment.