ShyCouch 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "bundler", "~> 1.0.0"
10
+ gem "jeweler", "~> 1.6.4"
11
+ gem "rcov", ">= 0"
12
+ gem "sourcify", "~> 0.5.0"
13
+ gem "ShyRubyJS"
14
+ end
@@ -0,0 +1,36 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ ShyRubyJS (0.0.1)
5
+ sourcify (~> 0)
6
+ file-tail (1.0.6)
7
+ spruz (~> 0.2)
8
+ git (1.2.5)
9
+ jeweler (1.6.4)
10
+ bundler (~> 1.0)
11
+ git (>= 1.2.5)
12
+ rake
13
+ rake (0.8.7)
14
+ rcov (0.9.10)
15
+ ruby2ruby (1.2.5)
16
+ ruby_parser (~> 2.0)
17
+ sexp_processor (~> 3.0)
18
+ ruby_parser (2.0.6)
19
+ sexp_processor (~> 3.0)
20
+ sexp_processor (3.0.5)
21
+ sourcify (0.5.0)
22
+ file-tail (>= 1.0.5)
23
+ ruby2ruby (>= 1.2.5)
24
+ ruby_parser (>= 2.0.5)
25
+ sexp_processor (>= 3.0.5)
26
+ spruz (0.2.12)
27
+
28
+ PLATFORMS
29
+ ruby
30
+
31
+ DEPENDENCIES
32
+ ShyRubyJS
33
+ bundler (~> 1.0.0)
34
+ jeweler (~> 1.6.4)
35
+ rcov
36
+ sourcify (~> 0.5.0)
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Cerales
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.
@@ -0,0 +1,36 @@
1
+ = ShyCouch
2
+
3
+ ShyCouch is a Ruby library for CouchDB. It's a data persistence layer that uses native objects and a simple query language, designed primarily to replace ActiveRecord in micro-frameworks like Camping. A Python version is forthcoming.
4
+
5
+ I'm mainly putting this up for feedback at the moment. It's a complete mess, I haven't figured out where
6
+
7
+ ShyCouch does not come with an elaborate query language. It'll automatically create an 'all' query for all your models (don't use it unless you have a really good excuse not to write a custom query, doing the filtering at the application layer is hell slow), but aside from that you have to write your own map and reduce functions.
8
+
9
+ = Usage
10
+
11
+ erghgrehg TODO
12
+
13
+ = Map/Reduce
14
+
15
+ ShyCouch uses the related ShyRubyJS library to parse Ruby blocks as JavaScript. This means you can do this:
16
+
17
+ map {
18
+ def function(doc)
19
+ if doc.kind == "post" and !doc.hidden
20
+ emit(doc)
21
+ end
22
+ }
23
+
24
+ and you'll get this:
25
+
26
+ function ( doc ) {
27
+ if( doc.kind.==("post") && !doc.hidden ) {
28
+ emit(doc)
29
+ }
30
+ }
31
+
32
+ == Copyright
33
+
34
+ Copyright (c) 2011 Cerales. See LICENSE.txt for
35
+ further details.
36
+
@@ -0,0 +1,55 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "ShyCouch"
18
+ gem.homepage = "http://github.com/Cerales/ShyCouch"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Ruby API for CouchDB, designed to work with the Camping micro-framework.}
21
+ gem.description = %Q{Ruby API for CouchDB, designed to work with the Camping micro-framework.}
22
+ gem.email = "danbryan@gmail.com"
23
+ gem.authors = ["Shy Inc.", "Daniel Bryan", "Cerales"]
24
+ gem.add_dependency "ShyRubyJS"
25
+ gem.add_dependency "sourcify", ">=0"
26
+ # dependencies defined in Gemfile
27
+ end
28
+ Jeweler::RubygemsDotOrgTasks.new
29
+
30
+ require 'rake/testtask'
31
+ Rake::TestTask.new(:test) do |test|
32
+ test.libs << 'lib' << 'test'
33
+ test.pattern = 'test/**/test_*.rb'
34
+ test.verbose = true
35
+ end
36
+
37
+ require 'rcov/rcovtask'
38
+ Rcov::RcovTask.new do |test|
39
+ test.libs << 'test'
40
+ test.pattern = 'test/**/test_*.rb'
41
+ test.verbose = true
42
+ test.rcov_opts << '--exclude "gems/*"'
43
+ end
44
+
45
+ task :default => :test
46
+
47
+ require 'rake/rdoctask'
48
+ Rake::RDocTask.new do |rdoc|
49
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
50
+
51
+ rdoc.rdoc_dir = 'rdoc'
52
+ rdoc.title = "ShyCouch #{version}"
53
+ rdoc.rdoc_files.include('README*')
54
+ rdoc.rdoc_files.include('lib/**/*.rb')
55
+ end
@@ -0,0 +1,75 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ShyCouch}
8
+ s.version = "0.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = [%q{Shy Inc.}, %q{Daniel Bryan}, %q{Cerales}]
12
+ s.date = %q{2011-08-14}
13
+ s.description = %q{Ruby API for CouchDB, designed to work with the Camping micro-framework.}
14
+ s.email = %q{danbryan@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ "Gemfile",
22
+ "Gemfile.lock",
23
+ "LICENSE.txt",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "ShyCouch.gemspec",
27
+ "VERSION",
28
+ "lib/ShyCouch.rb",
29
+ "test/helper.rb",
30
+ "test/old-test.rb",
31
+ "test/old-tests.rb",
32
+ "test/test_ShyCouch.rb",
33
+ "test/test_camping_integration.rb",
34
+ "test/test_couch_document.rb",
35
+ "test/test_couchdb_api.rb",
36
+ "test/test_couchdb_factory.rb",
37
+ "test/test_fields.rb"
38
+ ]
39
+ s.homepage = %q{http://github.com/Cerales/ShyCouch}
40
+ s.licenses = [%q{MIT}]
41
+ s.require_paths = [%q{lib}]
42
+ s.rubygems_version = %q{1.8.6}
43
+ s.summary = %q{Ruby API for CouchDB, designed to work with the Camping micro-framework.}
44
+
45
+ if s.respond_to? :specification_version then
46
+ s.specification_version = 3
47
+
48
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
49
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
50
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
51
+ s.add_development_dependency(%q<rcov>, [">= 0"])
52
+ s.add_development_dependency(%q<sourcify>, ["~> 0.5.0"])
53
+ s.add_development_dependency(%q<ShyRubyJS>, [">= 0"])
54
+ s.add_runtime_dependency(%q<ShyRubyJS>, [">= 0"])
55
+ s.add_runtime_dependency(%q<sourcify>, [">= 0"])
56
+ else
57
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
58
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
59
+ s.add_dependency(%q<rcov>, [">= 0"])
60
+ s.add_dependency(%q<sourcify>, ["~> 0.5.0"])
61
+ s.add_dependency(%q<ShyRubyJS>, [">= 0"])
62
+ s.add_dependency(%q<ShyRubyJS>, [">= 0"])
63
+ s.add_dependency(%q<sourcify>, [">= 0"])
64
+ end
65
+ else
66
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
67
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
68
+ s.add_dependency(%q<rcov>, [">= 0"])
69
+ s.add_dependency(%q<sourcify>, ["~> 0.5.0"])
70
+ s.add_dependency(%q<ShyRubyJS>, [">= 0"])
71
+ s.add_dependency(%q<ShyRubyJS>, [">= 0"])
72
+ s.add_dependency(%q<sourcify>, [">= 0"])
73
+ end
74
+ end
75
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.0
@@ -0,0 +1,358 @@
1
+ # July 2011
2
+ # This is a small Ruby layer for working with CouchDB
3
+ # Built primarily to allow Camping apps to use CouchDB for data persistence
4
+ # ShyRubyJS is library used to build map and reduce functions from Ruby blocks
5
+
6
+ require 'net/http'
7
+ require 'json'
8
+ require 'resolv'
9
+ require 'shyrubyjs'
10
+
11
+ module Kernel
12
+ def shycouch
13
+ $database = ShyCouch::Connection.Create
14
+ end
15
+ end
16
+
17
+ module ShyCouch
18
+
19
+ attr_accessor :database
20
+
21
+ class Connection
22
+ def self.Create(settings=nil)
23
+ settings = $settings unless settings
24
+ database = CouchDBAPI.new(settings["db"]["host"], settings["db"]["port"], settings["db"]["name"], settings["db"]["user"], settings["db"]["password"])
25
+ puts database.connect unless database.connect["ok"]
26
+ database.create unless database.on_server?
27
+ return database
28
+ end
29
+
30
+ def push_generic_views
31
+ #TODO
32
+ end
33
+ end
34
+
35
+
36
+ module Data
37
+ class Model < Hash
38
+ # takes hash that will be the document contents as well as an array of expected keys for validation
39
+ # todo - enforce keys that work as attrs
40
+
41
+ def initialize(hash=nil, requirements)
42
+ @requirements = requirements
43
+ merge!(hash) if hash
44
+ raise TypeError unless valid? #TODO - should raise a more specific and useful error
45
+ end
46
+
47
+ def method_missing(name, *args)
48
+ # Makes the object behave as if the hash keys are instance properties with attr_accessors
49
+ if name.to_s
50
+ if name[name.length-1] == "="
51
+ key = name[0, name.length-1]
52
+ if self.key?(key)
53
+ self[key] = args
54
+ return args
55
+ end
56
+ else
57
+ return self[name.to_s] unless !self[name.to_s]
58
+ end
59
+ end
60
+ super
61
+ end
62
+
63
+ def respond_to?(method)
64
+ # so that testing for whether it responds to a method is equivalent to testing for the existence of a key
65
+ return true if self.key?(method.to_s)
66
+ super
67
+ end
68
+ end
69
+
70
+ class CouchDocument < Model
71
+ class << self
72
+ # allows instance.class.requirements to be called
73
+ attr_accessor :requirements
74
+ end
75
+
76
+ def initialize(hash={})
77
+ # Assumes that the "kind" is the class name unless explicitly stated otherwise
78
+ # TODO - maybe just force it to be the class name no matter what tbh
79
+ hash["kind"] = self.class.to_s unless hash["kind"]
80
+ super(hash, @requirements)
81
+ end
82
+
83
+ def self.all
84
+ database = CouchDatabase.new($settings)
85
+ database.get()
86
+ end
87
+
88
+ def self.requires(*requirements)
89
+ @requirements = requirements
90
+ end
91
+
92
+ def add_key(key, value=nil)
93
+ # The attr value assignment operator has been overriden, but it checks for the existence of a key.
94
+ # And therefore the user has to explicitly call this method first.
95
+ self[key] = value
96
+ end
97
+
98
+ def attr_keys
99
+ # returns the keys for all the attrs that aren't the id or rev
100
+ attr_keys = []
101
+ self.map { |k,v|
102
+ attr_keys << k unless k == "_id" or k == "_rev"
103
+ }
104
+ return attr_keys
105
+ end
106
+
107
+ def _requirements
108
+ #TODO - hm
109
+ return self.class.requirements
110
+ end
111
+
112
+ def pull(database=nil)
113
+ database = $database unless database
114
+ new_doc = database.pull_document(self)
115
+ if new_doc
116
+ self.clear
117
+ self.merge! new_doc
118
+ end
119
+ end
120
+
121
+ def push(database = nil)
122
+ # assumes $database unless it receives a database argument
123
+ database = $database unless database
124
+ res = database.push_document(self)
125
+ self["_id"] = res["id"]
126
+ self["_rev"] = res["rev"]
127
+ return res
128
+ end
129
+
130
+ def valid?; to_json ? true : false; end
131
+
132
+ def to_json
133
+ JSON::generate(self)
134
+ rescue JSON::GeneratorError
135
+ false
136
+ end
137
+ end
138
+ end
139
+
140
+ module Fields
141
+ #TODO - lightweight validation framework
142
+
143
+ class Email_Addr < String
144
+ def valid?
145
+ # Valid if: one and only one '@'; at least one "." after the '@'; an mx record can be resolved at the domain
146
+ valid_address? and valid_domain?
147
+ end
148
+ def valid_address?
149
+ self.split("@").length == 2 and self.split("@")[1].split(".").length >= 2
150
+
151
+ end
152
+ def valid_domain?
153
+ domain = self.match(/\@(.+)/)[1]
154
+ Resolv::DNS.open { |dns| dns.getresources(domain, Resolv::DNS::Resource::IN::MX) }.size > 0 ? true : false
155
+ rescue Resolv::ResolvError
156
+ false
157
+ end
158
+ end
159
+ end
160
+
161
+ #TODO - split this stuff into modules too
162
+ class CouchDBAPI
163
+ def initialize(host, port, name, user, password)
164
+ @host, @port, @name, @user, @password = host, port, name, user, password
165
+ @views = []
166
+ @server = CouchServerConnection.allocate
167
+ end
168
+ #
169
+ # def initialize(*settings)
170
+ # @host, @port, @name, @user, @password = settings["db"]["host"], settings["db"]["port"], settings["db"]["name"], settings["db"]["user"], settings["db"]["password"]
171
+ # end
172
+
173
+ attr_accessor :server, :name, :host, :port, :views
174
+
175
+ def connect
176
+ @server = CouchServerConnection.new({"host"=>@host, "port"=>@port, "user"=>@user, "password"=>@password})
177
+ if @server.responds?
178
+ return {"ok"=>true, "message"=>"Successfully connected to the couch database at #{@host}: #{@port}."}
179
+ else
180
+ return {"ok"=>false, "message"=>"Could not connect to the couch database."}
181
+ end
182
+ end
183
+ def delete_database
184
+ @server.delete_db(self.name)
185
+ end
186
+ def server_responds?; return @server.responds?; end
187
+
188
+ def on_server?
189
+ @server.has_database?(@name)
190
+ end
191
+
192
+ def create
193
+ @server.create_db(@name)
194
+ end
195
+ def get_document(id)
196
+ @server.get_document(@name, id)
197
+ end
198
+ def all_docs
199
+ get_document('_all_docs').rows.map { |doc|
200
+ get_document(doc["id"])
201
+ }
202
+ end
203
+ def all_docs_with(attribute, value=nil)
204
+ #TODO - change this to build a couch map query, cache it in couch then call it
205
+ # maybe?!?!
206
+ docs = []
207
+ all_docs.each do |doc|
208
+ if value
209
+ docs << doc if doc[attribute] == value
210
+ else
211
+ docs << doc if doc[attribute]
212
+ end
213
+ end
214
+ return docs
215
+ rescue NameError
216
+ end
217
+ def uri
218
+ return "http://#{host}/#{port}/#{name}"
219
+ end
220
+
221
+ def pull_document(document)
222
+ @server.push_document(self.name, document)
223
+ end
224
+
225
+ def push_document(document)
226
+ @server.push_document(self.name, document)
227
+ end
228
+
229
+ def designs
230
+ @server.pull_all_design_docs(self.name)
231
+ end
232
+
233
+ def views
234
+ designs.map{ |d| d["views"] }
235
+ end
236
+
237
+ private
238
+ class CouchServerConnection
239
+ def initialize(args, options=nil)#host, port, user, password, options = nil)
240
+ @host = args["host"]
241
+ @port = args["port"]
242
+ @user = args["user"]
243
+ @password = args["password"]
244
+ @options = options
245
+ end
246
+
247
+ def responds?
248
+ if get('/')['couchdb'] == "Welcome"
249
+ true
250
+ else
251
+ false
252
+ end
253
+ rescue Errno::ECONNREFUSED
254
+ false
255
+ end
256
+
257
+ def has_database?(db_name)
258
+ get("/#{db_name}/")
259
+ true
260
+ rescue RuntimeError => error
261
+ false
262
+ end
263
+
264
+ #defining the get and delete methods
265
+ ['get', 'delete'].each do |name|
266
+ define_method name do |uri|
267
+ response = request(Net::HTTP.const_get(name.capitalize).new(uri)).body
268
+ JSON.parse(response)
269
+ end
270
+ end
271
+
272
+ def get_database_info(db_name)
273
+ get("/#{db+name}/")
274
+ end
275
+
276
+ def pull_all_design_docs(db_name)
277
+ pull_all_doc_ids(db_name).map { get_document(db_name, id) if id[0,7] == "_design" }
278
+ end
279
+
280
+ def pull_all_doc_ids(db_name)
281
+ get("/#{db_name}/_all_docs")["rows"].map { |doc| doc["id"] }
282
+ end
283
+
284
+ def all_docs_from_database(db_name)
285
+ pull_all_doc_ids(db_name).map { |id| Data::CouchDocument.new(get("/#{db_name}/#{id}")) }
286
+ end
287
+
288
+ def get_document(db_name, id)
289
+ document = Data::CouchDocument.new(get("/#{db_name}/#{id}"))
290
+ end
291
+
292
+ def delete_document(db_name, id)
293
+ delete("/#{db_name}/#{id}")
294
+ end
295
+
296
+ # Haven't decided whether PUT/POST should take a CouchDocument or a JSON string.
297
+ def put( uri, json = nil )
298
+ #TODO - make this private
299
+ req = Net::HTTP::Put.new(uri)
300
+ req["content-type"] = "application/json"
301
+ req.body = json unless json == nil
302
+ JSON.parse(request(req).body)
303
+ end
304
+
305
+ def post(uri, json = nil)
306
+ # couch uses POST for new documents and gives them an ID
307
+ req = Net::HTTP::Post.new(uri)
308
+ req["content-type"] = "application/json"
309
+ req.body = json unless json == nil
310
+ JSON.parse(request(req).body)
311
+ #TODO - return success more meaningfully maybe?
312
+ end
313
+
314
+ def pull_document(db_name, document)
315
+ document = Data::CouchDocument.new(get("/#{db_name}/#{id}"))
316
+ end
317
+
318
+ def push_document(db_name, document)
319
+ raise TypeError unless document.class == Data::CouchDocument
320
+ raise JSON::GeneratorError unless document.valid?
321
+ if document["_rev"]
322
+ put("/#{db_name}/#{document._id}?rev=#{document._rev}/", document.to_json)
323
+ else
324
+ post("/#{db_name}/", document.to_json)
325
+ end
326
+ end
327
+
328
+ def create_db(db_name)
329
+ put("/#{db_name}/")
330
+ end
331
+ def delete_db(db_name)
332
+ delete("/#{db_name}/")
333
+ end
334
+
335
+ def UUID
336
+ get('/_uuids/')['uuids'][0]
337
+ end
338
+
339
+ private
340
+
341
+ def handle_error(req, res)
342
+ raise RuntimeError.new("#{res.code}:#{res.message}\nMETHOD:#{req.method}\nURI:#{req.path}\n#{res.body}")
343
+ end
344
+
345
+ def request(req)
346
+ res = Net::HTTP.start(@host, @port) { |http|
347
+ req.basic_auth(@user, @password) if @user and @password
348
+ http.request(req)
349
+ }
350
+ unless res.kind_of?(Net::HTTPSuccess)
351
+ handle_error(req, res)
352
+ end
353
+ res
354
+ end
355
+ end
356
+
357
+ end
358
+ end
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'ShyCouch'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,10 @@
1
+ require '~/dev/shycouch/shycouch'
2
+ require '~/dev/shycouch/shycouchtests'
3
+ require 'irb'
4
+
5
+ ShyCouchTests::test_up
6
+ ShyCouchTests::test_down
7
+ message = "Test methods: "
8
+ message += ShyCouchTests::singleton_methods.map { |m| "ShyCouchTests::#{m}"}.join(', ')
9
+ puts message
10
+ IRB.start
@@ -0,0 +1,89 @@
1
+ require '~/dev/shycouch/shycouch'
2
+ module ShyCouchTests
3
+ def self.test_up
4
+ begin
5
+ # set everything up
6
+ $t_database, $t_id, $t_document = ShyCouch::CouchDatabase.allocate, "", ShyCouch::Data::CouchDocument.new
7
+
8
+ #set up the database
9
+ setup_database
10
+ setup_document
11
+ test_model
12
+ test_doc_kinds
13
+ # check that everything at least exists
14
+ result = if $t_database and $t_database.server and $t_id and $t_document #and $test_doc_kinds.length == 1
15
+ {"ok"=>true,"message"=>"Test environment appears to work","database"=>"$t_database",
16
+ "server connection"=>"$t_database.server","test doc id"=>"$t_id", "test document"=>"$t_doc",
17
+ "test doc model"=>"$t_model"}
18
+ else
19
+ {"ok"=>false,"message"=>"Test environment appears not to be working","database"=>$t_database,
20
+ "server connection"=>$t_database.server,"test doc id"=>$t_id,"test document"=>$t_doc}
21
+ end
22
+ rescue Errno::ECONNREFUSED
23
+ result = {"ok"=>false, "message"=>"""Server Connection refused.
24
+ Is CouchDB running at http://#{$t_database.host}:#{$t_database.port} ?"""}
25
+ end
26
+ result.each do |k, v| puts "#{k}: #{v}"; end
27
+ result["ok"]
28
+ end
29
+
30
+ def self.test_down
31
+ $t_database.server.delete_db('test')
32
+ $t_database = nil
33
+ $t_id = nil
34
+ $t_doc = nil
35
+ result = {"ok"=>true, "message"=>"Test environment has been brought down."}
36
+ result.each do|k, v| puts "#{k}: #{v}"; end
37
+ end
38
+
39
+ class TestModel < ShyCouch::Data::CouchDocument
40
+ def initialize hash
41
+ requirements = {
42
+ "me"=>String,
43
+ "you"=>Array
44
+ }
45
+ super hash, requirements
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def self.setup_database
52
+ settings = {
53
+ "db"=> {
54
+ "host" => "localhost",
55
+ "port" => 5984,
56
+ "name" => "test",
57
+ "user" => "cerales",
58
+ "password" => "password"
59
+ },
60
+ }
61
+ $t_database = ShyCouch::Create.go(settings)
62
+ raise Errno::ECONNREFUSED unless $t_database.connect["ok"]
63
+ $t_database.create_on_server unless $t_database.exists_on_server?
64
+ end
65
+
66
+ def self.setup_document
67
+ if $t_database.all_docs.length == 0
68
+ emptyDoc = ShyCouch::Data::CouchDocument.new
69
+ #$t_id = $t_database.server.push_document($t_database, emptyDoc)["id"]
70
+ $t_id = $t_database.push_document(emptyDoc)["id"]
71
+ else
72
+ $t_id = $t_database.all_docs[0]["id"]
73
+ end
74
+ end
75
+
76
+ def self.test_doc_kinds
77
+ doc = ShyCouch::Data::CouchDocument.new.merge!("kind"=>"test")
78
+ doc2 = ShyCouch::Data::CouchDocument.new.merge!("kind"=>"nope")
79
+ doc3 = ShyCouch::Data::CouchDocument.new.merge!("kind"=>"not me!")
80
+ $t_database.push_document(doc)
81
+ $t_database.push_document(doc2)
82
+ $t_database.push_document(doc3)
83
+ $t_doc_kind = $t_database.all_docs_with("kind", "not me!")
84
+ end
85
+
86
+ def self.test_model
87
+ $t_document.merge!($t_database.get_document($t_id))
88
+ end
89
+ end
@@ -0,0 +1,28 @@
1
+ require 'test/unit'
2
+ require_relative '../lib/ShyCouch'
3
+
4
+ # Most of these tests require a working CouchDB installation to be up and running.
5
+ # All the tests that expect to work with the database will use the settings defined below.
6
+
7
+ # Settings for a database that is set up and working, with an admin user
8
+ $settings = {
9
+ "db"=> {
10
+ "host" => "localhost",
11
+ "port" => 5984,
12
+ "name" => "test",
13
+ "user" => "cerales",
14
+ "password" => "password"
15
+ },
16
+ }
17
+
18
+ # test ShyCouch::CouchDBAPI
19
+ require_relative 'test_couchdb_api'
20
+
21
+ # test ShyCouch::Fields
22
+ # some of the tests in here are disabled cos they involve attempting to resolve a bad domain name
23
+ require_relative 'test_fields'
24
+
25
+ # test ShyCouch::Data::CouchDocument
26
+ require_relative 'test_couch_document'
27
+
28
+ require_relative 'test_camping_integration'
@@ -0,0 +1,15 @@
1
+ require 'test/unit'
2
+ require_relative '../lib/ShyCouch.rb'
3
+
4
+ class CampingIntegrationTests
5
+
6
+ class TestModelInheritence < Test::Unit::TestCase
7
+
8
+ class InheritanceTest < ShyCouch::Data::CouchDocument; end
9
+ def test_document_kind_assignment
10
+ m = InheritanceTest.new
11
+ assert_equal(InheritanceTest.to_s, m.kind)
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,141 @@
1
+ require 'test/unit'
2
+ require_relative '../lib/ShyCouch.rb'
3
+
4
+ class CouchDocumentTests# < Test::Unit::TestCase
5
+
6
+ class TestDocumentCreation < Test::Unit::TestCase
7
+ def setup
8
+ valid_settings = $settings
9
+ @database = ShyCouch::Connection.Create(valid_settings)
10
+ end
11
+ def teardown
12
+ @database.delete_database
13
+ @database = nil
14
+ end
15
+
16
+ def test_create_from_empty_hash
17
+ # should be able to create a couch doc with a hash argument
18
+ hash = {}
19
+ couch_document = ShyCouch::Data::CouchDocument.new(hash)
20
+ assert_kind_of(ShyCouch::Data::CouchDocument, couch_document)
21
+ end
22
+
23
+ def test_create_from_hash
24
+ # should be able to create a couch doc with a hash argument
25
+ hash = {"id" => "rejrandomrandomfhdjf", "rev"=>"1000000", "message"=>"up in here yo"}
26
+ couch_document = ShyCouch::Data::CouchDocument.new(hash)
27
+ assert_kind_of(ShyCouch::Data::CouchDocument, couch_document)
28
+ end
29
+
30
+ def test_create_from_string
31
+ # Ensure no doc creation with fixnum argument
32
+ string = "hehe i'm all over here you know"
33
+ assert_raises IndexError do
34
+ doc = ShyCouch::Data::CouchDocument.new(string)
35
+ end
36
+ end
37
+
38
+ def test_create_from_fixnum
39
+ # Ensure no doc creation with fixnum argument
40
+ fixnum = 1
41
+ assert_raises TypeError do
42
+ doc = ShyCouch::Data::CouchDocument.new(fixnum)
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ class TestDocumentPulling < Test::Unit::TestCase
49
+ #TODO
50
+ end
51
+
52
+ class TestDocumentPushing < Test::Unit::TestCase
53
+ # assumes success of the stuff in TestDocumentPulling
54
+ def setup
55
+ valid_settings = $settings
56
+ $database = ShyCouch::Connection.Create(valid_settings)
57
+
58
+ @valid_documents = [
59
+ ShyCouch::Data::CouchDocument.new({"kind"=>"post", "message"=>"BUY TRAMADOL ONLINE!!"}),
60
+ ShyCouch::Data::CouchDocument.new({"kind"=>"comment",
61
+ "message"=>"gry gry online gry gry online gry gry online gry gry online gry gry online "}),
62
+ ShyCouch::Data::CouchDocument.new({"kind"=>"tag", "name"=>"FREE CANADIAN PRESCRIPTION DRUGS"}),
63
+ ShyCouch::Data::CouchDocument.new({"kind"=>"helpers",
64
+ "helpers"=>["helper", "bad helper", "terrible helper", "this isn't helping"],
65
+ "actually_helpful"=>false, "times_helped"=>0}),
66
+ ]
67
+ @existing_valid_documents = [
68
+ ShyCouch::Data::CouchDocument.new("whatever"=>"yep"),
69
+ ShyCouch::Data::CouchDocument.new("is_a_document"=>true, "number_of_docs_this_is"=>1)
70
+ ].each { |doc|
71
+ doc.push
72
+ }
73
+ @invalid_documents = nil # make sure user can't set rev maybe? or is that legal?
74
+ end
75
+ def teardown
76
+ $database.delete_database
77
+ $database = nil
78
+ # delete the database
79
+ end
80
+
81
+ def test_keys_as_attr_accessors
82
+ # tests that if there is a "phone" key on "doc" object you can do doc.phone
83
+ @valid_documents.each { |doc|
84
+ doc.keys.each { |key|
85
+ assert_respond_to(doc, key)
86
+ }
87
+ }
88
+ end
89
+
90
+ def test_push_new_documents
91
+ @valid_documents.each { |doc|
92
+ # put the document on the server, grab the server's response
93
+ res = doc.push
94
+ # check that the server included "ok"=>true in its response
95
+ assert(res["ok"])
96
+ # check that the doc now has an id and a rev
97
+ assert(doc["_id"])
98
+ assert(doc["_rev"])
99
+ # get the new doc
100
+ newDoc = $database.get_document(doc._id)
101
+ # test equality of all the attributes aside from id and rev on the new document
102
+ doc.attr_keys.each { |k|
103
+ assert_equal(doc["k"], newDoc["k"])
104
+ }
105
+ }
106
+ end
107
+
108
+ def test_change_existing_documents
109
+ @existing_valid_documents.each { |doc|
110
+ # add some more attributes
111
+ assert(doc._rev)
112
+ doc.add_key("owner", "the guvvmint")
113
+ doc.add_key("buttonCount")
114
+ doc.add_key("friends")
115
+ doc.buttonCount = 5
116
+ doc.friends = ["alan", "alex", "all me other mates"]
117
+
118
+ res = doc.push
119
+ assert(res["ok"])
120
+
121
+ # pull it from the database again
122
+ checkDoc = $database.get_document(doc._id)
123
+
124
+ # check that the one from the database has all the new attributes
125
+ assert_equal(doc.owner, checkDoc.owner)
126
+ assert_equal(doc.buttonCount, checkDoc.buttonCount)
127
+ assert_equal(doc.friends, checkDoc.friends)
128
+ }
129
+ end
130
+
131
+ def test_illegal_change_to_rev
132
+ @existing_valid_documents.each { |doc|
133
+ doc._rev = "hurr"
134
+ assert_raises RuntimeError do
135
+ res = doc.push
136
+ end
137
+ }
138
+ end
139
+
140
+ end
141
+ end
@@ -0,0 +1,18 @@
1
+ require 'test/unit'
2
+ require_relative '../lib/ShyCouch.rb'
3
+
4
+ class TestCouchDBAPI < Test::Unit::TestCase
5
+ def setup
6
+ valid_settings = $settings
7
+ $database = ShyCouch::Connection.Create(valid_settings)
8
+ end
9
+
10
+ def teardown
11
+ $database.delete_database
12
+ $database = nil
13
+ end
14
+
15
+ def test_connection
16
+ assert_equal(true, $database.connect["ok"])
17
+ end
18
+ end
@@ -0,0 +1,15 @@
1
+ require 'test/unit'
2
+ require_relative '../lib/ShyCouch.rb'
3
+
4
+ class TestCouchDBFactory < Test::Unit::TestCase
5
+ def setup
6
+ @valid_settings = $settings
7
+ end
8
+
9
+ def teardown
10
+ end
11
+
12
+ def test_create_database
13
+ assert_kind_of(ShyCouch::CouchDBAPI, ShyCouch::Create.go(@valid_settings))
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ require 'test/unit'
2
+ require_relative '../lib/ShyCouch.rb'
3
+
4
+ class TestEmailField < Test::Unit::TestCase
5
+ def setup
6
+ @valid_emails = ['bigbeggar@gmail.com', 'helpmeout@bigpond.com'] # more!
7
+ @invalid_emails = ['byby.head@heat']#, 'looptheloop@ireallyhopethisisntadomainpleasedontbeadomain.org'] # more!
8
+ #commented out the one with an invalid domain cos resolve timeout long
9
+ end
10
+
11
+ def teardown; end
12
+
13
+ def test_valid_emails
14
+ @valid_emails.each do |email|
15
+ email_addr = ShyCouch::Fields::Email_Addr.new(email)
16
+ assert_equal(true, email_addr.valid?)
17
+ end
18
+ end
19
+
20
+ def test_invalid_emails
21
+ @invalid_emails.each do |email|
22
+ email_addr = ShyCouch::Fields::Email_Addr.new(email)
23
+ assert_equal(false, email_addr.valid?)
24
+ end
25
+ end
26
+ end
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ShyCouch
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Shy Inc.
9
+ - Daniel Bryan
10
+ - Cerales
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+ date: 2011-08-14 00:00:00.000000000Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: bundler
18
+ requirement: &70299706365800 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: 1.0.0
24
+ type: :development
25
+ prerelease: false
26
+ version_requirements: *70299706365800
27
+ - !ruby/object:Gem::Dependency
28
+ name: jeweler
29
+ requirement: &70299706364960 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: 1.6.4
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: *70299706364960
38
+ - !ruby/object:Gem::Dependency
39
+ name: rcov
40
+ requirement: &70299706364040 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ type: :development
47
+ prerelease: false
48
+ version_requirements: *70299706364040
49
+ - !ruby/object:Gem::Dependency
50
+ name: sourcify
51
+ requirement: &70299706363060 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ version: 0.5.0
57
+ type: :development
58
+ prerelease: false
59
+ version_requirements: *70299706363060
60
+ - !ruby/object:Gem::Dependency
61
+ name: ShyRubyJS
62
+ requirement: &70299706361900 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: *70299706361900
71
+ - !ruby/object:Gem::Dependency
72
+ name: ShyRubyJS
73
+ requirement: &70299706360460 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ type: :runtime
80
+ prerelease: false
81
+ version_requirements: *70299706360460
82
+ - !ruby/object:Gem::Dependency
83
+ name: sourcify
84
+ requirement: &70299706359260 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: *70299706359260
93
+ description: Ruby API for CouchDB, designed to work with the Camping micro-framework.
94
+ email: danbryan@gmail.com
95
+ executables: []
96
+ extensions: []
97
+ extra_rdoc_files:
98
+ - LICENSE.txt
99
+ - README.rdoc
100
+ files:
101
+ - .document
102
+ - Gemfile
103
+ - Gemfile.lock
104
+ - LICENSE.txt
105
+ - README.rdoc
106
+ - Rakefile
107
+ - ShyCouch.gemspec
108
+ - VERSION
109
+ - lib/ShyCouch.rb
110
+ - test/helper.rb
111
+ - test/old-test.rb
112
+ - test/old-tests.rb
113
+ - test/test_ShyCouch.rb
114
+ - test/test_camping_integration.rb
115
+ - test/test_couch_document.rb
116
+ - test/test_couchdb_api.rb
117
+ - test/test_couchdb_factory.rb
118
+ - test/test_fields.rb
119
+ homepage: http://github.com/Cerales/ShyCouch
120
+ licenses:
121
+ - MIT
122
+ post_install_message:
123
+ rdoc_options: []
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ! '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ segments:
133
+ - 0
134
+ hash: 2260560036860812579
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ none: false
137
+ requirements:
138
+ - - ! '>='
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ requirements: []
142
+ rubyforge_project:
143
+ rubygems_version: 1.8.6
144
+ signing_key:
145
+ specification_version: 3
146
+ summary: Ruby API for CouchDB, designed to work with the Camping micro-framework.
147
+ test_files: []