couchobject 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/License.txt +20 -0
- data/Manifest.txt +41 -0
- data/README.txt +119 -0
- data/Rakefile +4 -0
- data/TODO +8 -0
- data/config/hoe.rb +73 -0
- data/config/requirements.rb +17 -0
- data/lib/couch_object.rb +27 -0
- data/lib/couch_object/database.rb +115 -0
- data/lib/couch_object/document.rb +106 -0
- data/lib/couch_object/model.rb +5 -0
- data/lib/couch_object/persistable.rb +59 -0
- data/lib/couch_object/response.rb +44 -0
- data/lib/couch_object/server.rb +53 -0
- data/lib/couch_object/utils.rb +13 -0
- data/lib/couch_object/version.rb +9 -0
- data/lib/couch_object/view.rb +23 -0
- data/log/debug.log +0 -0
- data/script/console +17 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/setup.rb +1585 -0
- data/spec/database_spec.rb +143 -0
- data/spec/document_spec.rb +142 -0
- data/spec/integration/database_integration_spec.rb +78 -0
- data/spec/integration/document_integration_spec.rb +41 -0
- data/spec/integration/integration_helper.rb +20 -0
- data/spec/model_spec.rb +5 -0
- data/spec/persistable_spec.rb +91 -0
- data/spec/response_spec.rb +47 -0
- data/spec/rspec_autotest.rb +149 -0
- data/spec/server_spec.rb +74 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/utils_spec.rb +18 -0
- data/spec/view_spec.rb +36 -0
- data/tasks/deployment.rake +27 -0
- data/tasks/environment.rake +7 -0
- data/tasks/rspec.rake +42 -0
- data/tasks/website.rake +9 -0
- metadata +98 -0
data/History.txt
ADDED
data/License.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2007 Johan Sørensen
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest.txt
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
History.txt
|
2
|
+
License.txt
|
3
|
+
Manifest.txt
|
4
|
+
README.txt
|
5
|
+
Rakefile
|
6
|
+
TODO
|
7
|
+
config/hoe.rb
|
8
|
+
config/requirements.rb
|
9
|
+
lib/couch_object.rb
|
10
|
+
lib/couch_object/database.rb
|
11
|
+
lib/couch_object/document.rb
|
12
|
+
lib/couch_object/model.rb
|
13
|
+
lib/couch_object/persistable.rb
|
14
|
+
lib/couch_object/response.rb
|
15
|
+
lib/couch_object/server.rb
|
16
|
+
lib/couch_object/utils.rb
|
17
|
+
lib/couch_object/version.rb
|
18
|
+
lib/couch_object/view.rb
|
19
|
+
log/debug.log
|
20
|
+
script/console
|
21
|
+
script/destroy
|
22
|
+
script/generate
|
23
|
+
setup.rb
|
24
|
+
spec/database_spec.rb
|
25
|
+
spec/document_spec.rb
|
26
|
+
spec/integration/database_integration_spec.rb
|
27
|
+
spec/integration/document_integration_spec.rb
|
28
|
+
spec/integration/integration_helper.rb
|
29
|
+
spec/model_spec.rb
|
30
|
+
spec/persistable_spec.rb
|
31
|
+
spec/response_spec.rb
|
32
|
+
spec/rspec_autotest.rb
|
33
|
+
spec/server_spec.rb
|
34
|
+
spec/spec.opts
|
35
|
+
spec/spec_helper.rb
|
36
|
+
spec/utils_spec.rb
|
37
|
+
spec/view_spec.rb
|
38
|
+
tasks/deployment.rake
|
39
|
+
tasks/environment.rake
|
40
|
+
tasks/rspec.rake
|
41
|
+
tasks/website.rake
|
data/README.txt
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
= CouchObject
|
2
|
+
|
3
|
+
CouchObject is a set of classes to help you talk to CouchDb (http://couchdbwiki.com/) with Ruby.
|
4
|
+
|
5
|
+
* Author: Johan Sørensen
|
6
|
+
* Contact: johan (at) johansorensen DOT com
|
7
|
+
* Home: http://rubyforge.org/projects/couchobject/
|
8
|
+
* Source (Git): http://repo.or.cz/w/couchobject.git
|
9
|
+
|
10
|
+
== Creating, opening and deleting databases
|
11
|
+
|
12
|
+
CouchObject::Database is the first interaction point to your CouchDb. Creating a CouchDb database:
|
13
|
+
|
14
|
+
>> CouchObject::Database.create!("http://localhost:8888", "mydb")
|
15
|
+
=> {"ok"=>true}
|
16
|
+
>> CouchObject::Database.all_databases("http://localhost:8888")
|
17
|
+
=> ["couchobject", "couchobject_test", "foo", "mydb"]
|
18
|
+
>> db = CouchObject::Database.open("http://localhost:8888/mydb")
|
19
|
+
=> #<CouchObject::Database:0x642fa8 @server=#<CouchObject::Server:0x642ef4 @connection=#<Net::HTTP localhost:8888 open=false>, @port=8888, @uri=#<URI::HTTP:0x321612 URL:http://localhost:8888>, @host="localhost">, @uri="http://localhost:8888", @dbname="mydb">
|
20
|
+
>> db.name
|
21
|
+
=> "mydb"
|
22
|
+
>> CouchObject::Database.delete!("http://localhost:8888", "mydb")
|
23
|
+
=> {"ok"=>true}
|
24
|
+
>> CouchObject::Database.all_databases("http://localhost:8888").include?("mydb")
|
25
|
+
=> false
|
26
|
+
|
27
|
+
=== Interacting with the database
|
28
|
+
|
29
|
+
>> db.get("_all_docs")
|
30
|
+
=> #<CouchObject::Response:0x14ed364 @response=#<Net::HTTPOK 200 OK readbody=true>, @parsed_body={"rows"=>[], "view"=>"_all_docs"}>
|
31
|
+
|
32
|
+
Issueing CouchObject::Database#get, CouchObject::Database#post, CouchObject::Database#put and CouchObject::Database#delete requests will return a CouchObject::Response object
|
33
|
+
|
34
|
+
>> db.get("_all_docs").body
|
35
|
+
=> "{\"view\":\"_all_docs\", \"rows\":[\n\n]}"
|
36
|
+
>> db.get("_all_docs").parsed_body
|
37
|
+
=> {"rows"=>[], "view"=>"_all_docs"}
|
38
|
+
>> db.post("", JSON.unparse({"foo" => "bar"}))
|
39
|
+
=> #<CouchObject::Response:0x14d7780 @response=#<Net::HTTPCreated 201 Created readbody=true>, @parsed_body={"_rev"=>-992681820, "_id"=>"1206189E4496409DAD3818D241F5478F", "ok"=>true}>
|
40
|
+
>> db.get("_all_docs").parsed_body
|
41
|
+
=> {"rows"=>[{"_rev"=>-992681820, "_id"=>"1206189E4496409DAD3818D241F5478F"}], "view"=>"_all_docs"}
|
42
|
+
>> db.get("1206189E4496409DAD3818D241F5478F").parsed_body
|
43
|
+
=> {"_rev"=>-992681820, "_id"=>"1206189E4496409DAD3818D241F5478F", "foo"=>"bar"}
|
44
|
+
>> db.delete("1206189E4496409DAD3818D241F5478F").parsed_body
|
45
|
+
=> {"_rev"=>548318611, "ok"=>true}
|
46
|
+
>> db.get("_all_docs").parsed_body
|
47
|
+
=> {"rows"=>[], "view"=>"_all_docs"}
|
48
|
+
|
49
|
+
== The Document object
|
50
|
+
|
51
|
+
CouchObject::Document wraps a few things in a nice api. In particular you can use it if you don't want to deal with hashes all the time (similar to ActiveRecord and so on):
|
52
|
+
|
53
|
+
>> doc = CouchObject::Document.new({ "foo" => [1,2], "bar" => true })
|
54
|
+
=> #<CouchObject::Document:0x14a7224 @id=nil, @attributes={"foo"=>[1, 2], "bar"=>true}, @revision=nil>
|
55
|
+
>> doc["foo"]
|
56
|
+
=> [1, 2]
|
57
|
+
>> doc.foo
|
58
|
+
=> [1, 2]
|
59
|
+
>> doc.bar
|
60
|
+
=> true
|
61
|
+
>> doc.bar?
|
62
|
+
=> true
|
63
|
+
|
64
|
+
You can also save a document to the database:
|
65
|
+
|
66
|
+
>> doc.new?
|
67
|
+
=> true
|
68
|
+
>> doc.save(db)
|
69
|
+
=> #<CouchObject::Response:0x149f358 @response=#<Net::HTTPCreated 201 Created readbody=true>, @parsed_body={"_rev"=>2030456697, "_id"=>"CAEADDC895AC4D506542A3796CCA355D", "ok"=>true}>
|
70
|
+
>> doc.id
|
71
|
+
=> "CAEADDC895AC4D506542A3796CCA355D"
|
72
|
+
|
73
|
+
Since CouchObject::Database#get returns a CouchObject::Response object we can convert it into a Document instance easily with CouchObject::Database#to_document:
|
74
|
+
|
75
|
+
>> response = db.get(doc.id)
|
76
|
+
=> #<CouchObject::Response:0x1498b98 @response=#<Net::HTTPOK 200 OK readbody=true>, @parsed_body={"_rev"=>2030456697, "_id"=>"CAEADDC895AC4D506542A3796CCA355D", "foo"=>[1, 2], "bar"=>true}>
|
77
|
+
>> the_doc_we_just_saved = response.to_document
|
78
|
+
=> #<CouchObject::Document:0x148415c @id="CAEADDC895AC4D506542A3796CCA355D", @attributes={"foo"=>[1, 2], "bar"=>true}, @revision=2030456697>
|
79
|
+
>> the_doc_we_just_saved.foo
|
80
|
+
=> [1, 2]
|
81
|
+
>> doc.foo = "quux"
|
82
|
+
=> "quux"
|
83
|
+
>> doc.save(db)
|
84
|
+
=> #<CouchObject::Response:0x4b0adc @response=#<Net::HTTPCreated 201 Created readbody=true>, @parsed_body={"_rev"=>1670064786, "_id"=>"B4077269D2DF8433D145DC0702B9791C", "ok"=>true}>
|
85
|
+
|
86
|
+
|
87
|
+
== CouchObject::Persistable
|
88
|
+
|
89
|
+
It all started with this module, it maps ruby objects to CouchDb documents, using two mapping methods. It's highly experimental and may go away n future releases
|
90
|
+
|
91
|
+
gem "couchobject"
|
92
|
+
require "couch_object"
|
93
|
+
class Bike
|
94
|
+
include CouchObject::Persistable
|
95
|
+
|
96
|
+
def initialize(wheels)
|
97
|
+
@wheels = wheels
|
98
|
+
end
|
99
|
+
attr_accessor :wheels
|
100
|
+
|
101
|
+
def to_couch
|
102
|
+
{:wheels => @wheels}
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.from_couch(attributes)
|
106
|
+
new(attributes["wheels"])
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
By including the CouchObject::Persistable and defining two methods on our class we specify how we should serialize and deserialize our object to and from a CouchDb:
|
111
|
+
|
112
|
+
>> bike_4wd = Bike.new(4)
|
113
|
+
=> #<Bike:0x6a0a68 @wheels=4>
|
114
|
+
>> bike_4wd.save("http://localhost:8888/couchobject")
|
115
|
+
=> {"_rev"=>1745167971, "_id"=>"6FA2AFB623A93E0E77DEAAF59BB02565", "ok"=>true}
|
116
|
+
>> bike = Bike.get_by_id("http://localhost:8888/couchobject", bike_4wd.id)
|
117
|
+
=> #<Bike:0x64846c @wheels=4>
|
118
|
+
|
119
|
+
|
data/Rakefile
ADDED
data/TODO
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
- flat namespace for object attributes? (instead of the "attributes" key)
|
2
|
+
- Query/View API
|
3
|
+
- better handling of document id, including setting a custom ones
|
4
|
+
- Database#filter for filtering documents with Ruby (with some ruby2js or RubyToRuby magic)
|
5
|
+
- Expand on View class
|
6
|
+
- A Document object
|
7
|
+
|
8
|
+
- CouchObject::Model for more domain specific/clearer way to model Couch docs in ruby
|
data/config/hoe.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'couch_object/version'
|
2
|
+
|
3
|
+
AUTHOR = 'Johan Sørensen' # can also be an array of Authors
|
4
|
+
EMAIL = "johan@johansorensen.com"
|
5
|
+
DESCRIPTION = "CouchObject is a library that maps ruby objects to CouchDb documents"
|
6
|
+
GEM_NAME = 'couchobject' # what ppl will type to install your gem
|
7
|
+
RUBYFORGE_PROJECT = 'couchobject' # The unix name for your project
|
8
|
+
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
9
|
+
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
10
|
+
|
11
|
+
@config_file = "~/.rubyforge/user-config.yml"
|
12
|
+
@config = nil
|
13
|
+
RUBYFORGE_USERNAME = "unknown"
|
14
|
+
def rubyforge_username
|
15
|
+
unless @config
|
16
|
+
begin
|
17
|
+
@config = YAML.load(File.read(File.expand_path(@config_file)))
|
18
|
+
rescue
|
19
|
+
puts <<-EOS
|
20
|
+
ERROR: No rubyforge config file found: #{@config_file}"
|
21
|
+
Run 'rubyforge setup' to prepare your env for access to Rubyforge
|
22
|
+
- See http://newgem.rubyforge.org/rubyforge.html for more details
|
23
|
+
EOS
|
24
|
+
exit
|
25
|
+
end
|
26
|
+
end
|
27
|
+
RUBYFORGE_USERNAME.replace @config["username"]
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
REV = nil
|
32
|
+
# UNCOMMENT IF REQUIRED:
|
33
|
+
# REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
|
34
|
+
VERS = CouchObject::VERSION::STRING + (REV ? ".#{REV}" : "")
|
35
|
+
RDOC_OPTS = ['--quiet', '--title', 'couch_object documentation',
|
36
|
+
"--opname", "index.html",
|
37
|
+
"--line-numbers",
|
38
|
+
"--main", "README",
|
39
|
+
"--inline-source"]
|
40
|
+
|
41
|
+
class Hoe
|
42
|
+
def extra_deps
|
43
|
+
@extra_deps.reject! { |x| Array(x).first == 'hoe' }
|
44
|
+
@extra_deps
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Generate all the Rake tasks
|
49
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
50
|
+
hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
51
|
+
p.author = AUTHOR
|
52
|
+
p.description = DESCRIPTION
|
53
|
+
p.email = EMAIL
|
54
|
+
p.summary = DESCRIPTION
|
55
|
+
p.url = HOMEPATH
|
56
|
+
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
57
|
+
p.test_globs = ["spec/**/spec_*.rb"]
|
58
|
+
p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
|
59
|
+
|
60
|
+
# == Optional
|
61
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\\n\\n")
|
62
|
+
# An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
|
63
|
+
p.extra_deps = [
|
64
|
+
["json", ">= 1.1.1"]
|
65
|
+
]
|
66
|
+
|
67
|
+
#p.spec_extras = {} # A hash of extra values to set in the gemspec.
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
|
72
|
+
PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
|
73
|
+
hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
include FileUtils
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
%w[rake hoe newgem rubigen].each do |req_gem|
|
6
|
+
begin
|
7
|
+
require req_gem
|
8
|
+
rescue LoadError
|
9
|
+
puts "This Rakefile requires the '#{req_gem}' RubyGem."
|
10
|
+
puts "Installation: gem install #{req_gem} -y"
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
|
16
|
+
|
17
|
+
require 'couch_object'
|
data/lib/couch_object.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
$KCODE = 'u'
|
2
|
+
require 'jcode'
|
3
|
+
|
4
|
+
require "rubygems"
|
5
|
+
gem "json"
|
6
|
+
begin
|
7
|
+
require "json/ext"
|
8
|
+
rescue LoadError
|
9
|
+
$stderr.puts "C version of json (fjson) could not be loaded, using pure ruby one"
|
10
|
+
require "json/pure"
|
11
|
+
end
|
12
|
+
require 'json/add/core'
|
13
|
+
|
14
|
+
$:.unshift File.dirname(__FILE__)
|
15
|
+
|
16
|
+
require "couch_object/utils"
|
17
|
+
require "couch_object/document"
|
18
|
+
require "couch_object/response"
|
19
|
+
require "couch_object/server"
|
20
|
+
require "couch_object/database"
|
21
|
+
require "couch_object/view"
|
22
|
+
require "couch_object/persistable"
|
23
|
+
require "couch_object/model"
|
24
|
+
|
25
|
+
module CouchObject
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module CouchObject
|
2
|
+
# A CouchDb database object
|
3
|
+
class Database
|
4
|
+
# Create a new database at +uri+ with the name if +dbname+
|
5
|
+
def self.create!(uri, dbname)
|
6
|
+
server = Server.new(uri)
|
7
|
+
response = Response.new(server.put("/#{dbname}", "")).parse
|
8
|
+
response.parsed_body
|
9
|
+
end
|
10
|
+
|
11
|
+
# Delete the database at +uri+ with the name if +dbname+
|
12
|
+
def self.delete!(uri, dbname)
|
13
|
+
server = Server.new(uri)
|
14
|
+
response = Response.new(server.delete("/#{dbname}")).parse
|
15
|
+
response.parsed_body
|
16
|
+
end
|
17
|
+
|
18
|
+
# All databases at +uri+
|
19
|
+
def self.all_databases(uri)
|
20
|
+
# FIXME: Move to Server ?
|
21
|
+
server = Server.new(uri)
|
22
|
+
resp = server.get("/_all_dbs")
|
23
|
+
response = Response.new(resp).parse
|
24
|
+
response.parsed_body
|
25
|
+
end
|
26
|
+
|
27
|
+
# Open a connection to the database at +uri+, where +uri+ is a full uri
|
28
|
+
# like: http://localhost:8888/foo
|
29
|
+
def self.open(uri)
|
30
|
+
uri = URI.parse(uri)
|
31
|
+
server_uri = "#{uri.scheme}://#{uri.host}:#{uri.port}"
|
32
|
+
new(server_uri, uri.path.tr("/", ""))
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize(uri, dbname)
|
36
|
+
@uri = uri
|
37
|
+
@dbname = dbname
|
38
|
+
@server = Server.new(@uri)
|
39
|
+
end
|
40
|
+
attr_accessor :server
|
41
|
+
|
42
|
+
# The full url of this database, eg http://localhost:8888/foo
|
43
|
+
def url
|
44
|
+
Utils.join_url(@uri, @dbname).to_s
|
45
|
+
end
|
46
|
+
|
47
|
+
# Name of this database
|
48
|
+
def name
|
49
|
+
@dbname.dup
|
50
|
+
end
|
51
|
+
|
52
|
+
# Send a GET request to the +path+ which is relative to the database path
|
53
|
+
# so calling with with "bar" as the path in the "foo_db" database will call
|
54
|
+
# http://host:port/foo_db/bar.
|
55
|
+
# Returns a Response object
|
56
|
+
def get(path)
|
57
|
+
Response.new(@server.get("/#{Utils.join_url(@dbname, path)}")).parse
|
58
|
+
end
|
59
|
+
|
60
|
+
# Send a POST request to the +path+ which is relative to the database path
|
61
|
+
# so calling with with "bar" as the path in the "foo_db" database will call
|
62
|
+
# http://host:port/foo_db/bar. The post body is the +payload+
|
63
|
+
# Returns a Response object
|
64
|
+
def post(path, payload)
|
65
|
+
Response.new(@server.post("/#{Utils.join_url(@dbname, path)}", payload)).parse
|
66
|
+
end
|
67
|
+
|
68
|
+
# Send a PUT request to the +path+ which is relative to the database path
|
69
|
+
# so calling with with "bar" as the path in the "foo_db" database will call
|
70
|
+
# http://host:port/foo_db/bar. The put body is the +payload+
|
71
|
+
# Returns a Response object
|
72
|
+
def put(path, payload="")
|
73
|
+
Response.new(@server.put("/#{Utils.join_url(@dbname, path)}", payload)).parse
|
74
|
+
end
|
75
|
+
|
76
|
+
# Send a DELETE request to the +path+ which is relative to the database path
|
77
|
+
# so calling with with "bar" as the path in the "foo_db" database will call
|
78
|
+
# http://host:port/foo_db/bar.
|
79
|
+
# Returns a Response object
|
80
|
+
def delete(path)
|
81
|
+
Response.new(@server.delete("/#{Utils.join_url(@dbname, path)}")).parse
|
82
|
+
end
|
83
|
+
|
84
|
+
# Get a document by id
|
85
|
+
def [](id)
|
86
|
+
get(id.to_s)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Get a document by +id+, optionally a specific +revision+ too
|
90
|
+
def document(id, revision=nil)
|
91
|
+
if revision
|
92
|
+
get("#{id}?rev=#{revision}")
|
93
|
+
else
|
94
|
+
get(id.to_s)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Returns an Array of all the documents in this db
|
99
|
+
def all_documents
|
100
|
+
resp = Response.new(get("_all_docs")).parse
|
101
|
+
resp.to_document.rows
|
102
|
+
end
|
103
|
+
|
104
|
+
# Queries the database with the block (using a temp. view)
|
105
|
+
def filter(&blk)
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
def views(view_name)
|
110
|
+
view = View.new(self, view_name)
|
111
|
+
view.query
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module CouchObject
|
2
|
+
# Represents a CouchDb document
|
3
|
+
class Document
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
# initializes a new document object with +attributes+ as
|
7
|
+
# the document values
|
8
|
+
def initialize(attributes={})
|
9
|
+
@attributes = attributes.dup
|
10
|
+
@id = @attributes.delete("_id")
|
11
|
+
@revision = @attributes.delete("_rev")
|
12
|
+
end
|
13
|
+
attr_accessor :attributes, :id, :revision
|
14
|
+
|
15
|
+
# Sets the id to +new_id+
|
16
|
+
# (Only for internal use really, but public nevertheless)
|
17
|
+
def id=(new_id)
|
18
|
+
if new?
|
19
|
+
attributes["_id"] = @id = new_id
|
20
|
+
else
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# is this a new document?
|
26
|
+
def new?
|
27
|
+
@id.nil? && @revision.nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
# yields each document attribute
|
31
|
+
def each(&blk)
|
32
|
+
@attributes.each(&blk)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Saves this document to the +database+
|
36
|
+
def save(database)
|
37
|
+
new? ? create(database) : update(database)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Look up an attribute by +key+
|
41
|
+
def [](key)
|
42
|
+
attributes[key]
|
43
|
+
end
|
44
|
+
|
45
|
+
# Set an attributes by +key+ to +value+
|
46
|
+
def []=(key, value)
|
47
|
+
attributes[key] = value
|
48
|
+
end
|
49
|
+
|
50
|
+
# is the attribute +key+ in this document?
|
51
|
+
def has_key?(key)
|
52
|
+
attributes.has_key?(key)
|
53
|
+
end
|
54
|
+
|
55
|
+
# is the attribute +key+ in this document?
|
56
|
+
def respond_to?(meth)
|
57
|
+
method_name = meth.to_s
|
58
|
+
|
59
|
+
if has_key?(method_name)
|
60
|
+
return true
|
61
|
+
elsif %w[ ? = ].include?(method_name[-1..-1]) && has_key?(method_name[0..-2])
|
62
|
+
return true
|
63
|
+
end
|
64
|
+
|
65
|
+
super
|
66
|
+
end
|
67
|
+
|
68
|
+
# Converts the Document to a JSON representation of its attributes
|
69
|
+
def to_json(extra={})
|
70
|
+
if id.nil?
|
71
|
+
opts = {}.merge(extra)
|
72
|
+
else
|
73
|
+
opts = {"_id" => id}.merge(extra)
|
74
|
+
end
|
75
|
+
attributes.merge(opts).to_json
|
76
|
+
end
|
77
|
+
|
78
|
+
protected
|
79
|
+
def create(database)
|
80
|
+
response = database.post("", self.to_json)
|
81
|
+
# TODO error handling
|
82
|
+
@id = response.to_document.id
|
83
|
+
@revision = response.to_document.revision
|
84
|
+
response
|
85
|
+
end
|
86
|
+
|
87
|
+
def update(database)
|
88
|
+
response = database.put(id, self.to_json("_rev" => revision))
|
89
|
+
# TODO error handling
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
def method_missing(method_symbol, *arguments)
|
94
|
+
method_name = method_symbol.to_s
|
95
|
+
|
96
|
+
case method_name[-1..-1]
|
97
|
+
when "="
|
98
|
+
self[method_name[0..-2]] = arguments.first
|
99
|
+
when "?"
|
100
|
+
self[method_name[0..-2]] == true
|
101
|
+
else
|
102
|
+
has_key?(method_name) ? self[method_name] : super
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|