ShyCouch 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: []