loveseat 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ class Hash
2
+ def to_query
3
+ components = self.map do |k,v|
4
+ [URI.escape(k.to_s), URI.escape(v.to_s)].join('=')
5
+ end
6
+ components.join("&")
7
+ end
8
+ end
@@ -0,0 +1,26 @@
1
+ require 'core_ext/hash.rb'
2
+ require 'rest/resource.rb'
3
+ require 'rest/server.rb'
4
+ require 'rest/document.rb'
5
+ require 'rest/database.rb'
6
+ require 'rest/design_document.rb'
7
+ require 'loveseat/document.rb'
8
+ require 'loveseat/document/dsl.rb'
9
+ require 'loveseat/document/support.rb'
10
+ require 'loveseat/document/instance_adapter.rb'
11
+ require 'loveseat/document/property/base.rb'
12
+ require 'loveseat/document/property/string.rb'
13
+ require 'loveseat/document/property/integer.rb'
14
+ require 'loveseat/document/property/float.rb'
15
+ require 'loveseat/document/property/date.rb'
16
+ require 'loveseat/document/property/time.rb'
17
+ require 'loveseat/document/property/array.rb'
18
+ require 'loveseat/document/property/hash.rb'
19
+ require 'loveseat/document/property/raw.rb'
20
+ require 'loveseat/design_document.rb'
21
+ require 'loveseat/design_document/dsl.rb'
22
+ require 'loveseat/design_document/support.rb'
23
+ require 'loveseat/design_document/view_row.rb'
24
+ require 'loveseat/model.rb'
25
+ require 'loveseat/view_set.rb'
26
+
@@ -0,0 +1,45 @@
1
+ module Loveseat
2
+ module DesignDocument
3
+ Document.add_resolver(/_design\/([A-Za-z:]+)/)
4
+
5
+ def self.setup(klass, options = {}, &block)
6
+ Document.setup(klass, { :support => Support.new(klass, options) }, &block)
7
+ end
8
+
9
+ def self.all(db)
10
+ resource = db._all_docs
11
+ response, body = resource.get(:query => {:startkey => "_design/".to_json,
12
+ :endkey => "_design/\ufff0".to_json,
13
+ :include_docs => true})
14
+ response.value
15
+
16
+ body['rows'].map do |row|
17
+ klass = Document.resolve(row['id'])
18
+ support = Document.registry[klass]
19
+ support.from_hash(row['doc'])
20
+ end
21
+ end
22
+
23
+ def self.view(db, design_document, name, options = {})
24
+ resource = Rest::DesignDocument.new(db, design_document.name)
25
+ view_resource = resource._view(name)
26
+
27
+ keys = options.delete(:keys)
28
+
29
+ response, body = if keys
30
+ view_resource.post(:query => options, :body => {:keys => keys}.to_json)
31
+ else
32
+ view_resource.get(:query => options)
33
+ end
34
+ response.value
35
+
36
+ body['rows'].map do |row|
37
+ ViewRow.from_hash(row)
38
+ end
39
+ end
40
+
41
+ def self.generate_id(klass)
42
+ "_design/#{klass.name}"
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,9 @@
1
+ module Loveseat
2
+ module DesignDocument
3
+ class DSL < Document::DSL
4
+ def view(name, functions = {})
5
+ @support.add_view(name, functions)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,25 @@
1
+ module Loveseat
2
+ module DesignDocument
3
+ class Support < Document::Support
4
+ def initialize(klass, options = {})
5
+ super(klass, options)
6
+ @dsl = DSL.new(self)
7
+ add_property(:views, Document::Property::Hash, {})
8
+ alter_property(:_id, Document::Property::String, DesignDocument.generate_id(klass))
9
+ end
10
+
11
+ def from_hash(doc)
12
+ object = super(doc)
13
+ object.views = properties[:views][DEFAULT]
14
+ object
15
+ end
16
+
17
+ def add_view(name, options = {})
18
+ type, default = properties[:views]
19
+ default.merge!(
20
+ name => options
21
+ )
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,16 @@
1
+ module Loveseat
2
+ module DesignDocument
3
+ class ViewRow
4
+ Loveseat::Document.setup(self, :abstract => true) do
5
+ string :id
6
+ raw :key
7
+ raw :value
8
+ hash :doc
9
+ end
10
+
11
+ def self.from_hash(doc)
12
+ Document.registry[self.name].from_hash(doc)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,92 @@
1
+ module Loveseat
2
+ module Document
3
+ @@registry = {}
4
+ @@resolvers = [
5
+ /^([A-Za-z:]+):/
6
+ ]
7
+
8
+ def self.registry
9
+ @@registry
10
+ end
11
+
12
+ def self.add_resolver(regexp)
13
+ @@resolvers << regexp
14
+ end
15
+
16
+ def self.next_id(server, klass)
17
+ response, body = server._uuids.get
18
+ response.value
19
+
20
+ uuid = body['uuids'].first
21
+ "#{klass.name}:#{uuid}"
22
+ end
23
+
24
+ def self.resolve(id)
25
+ @@resolvers.each do |regexp|
26
+ match = regexp.match(id)
27
+ if match
28
+ return match[1]
29
+ end
30
+ end
31
+ nil
32
+ end
33
+
34
+ def self.setup(klass, options = {}, &block)
35
+ support = options.delete(:support) ||
36
+ Support.new(klass, options)
37
+ Document.registry[klass.name] = support
38
+ support.dsl.instance_eval(&block)
39
+ support
40
+ end
41
+
42
+ def self.put(db, object)
43
+ klass = ( object.instance_of?(Class) ) ? object : object.class
44
+ support = Document.registry[klass.name]
45
+ raise "Not Registered" if support.nil?
46
+ raise "Abstract Document" if support.abstract?
47
+
48
+ if object._id.nil?
49
+ object._id = next_id(db.server, object.class)
50
+ end
51
+
52
+ resource = Rest::Document.new(db, object._id)
53
+ response, body = resource.put(support.to_doc(object))
54
+
55
+ response.value
56
+
57
+ object._rev = body["rev"]
58
+ object
59
+ end
60
+
61
+ def self.get(db, id)
62
+ resource = Rest::Document.new(db, id)
63
+ response, body = resource.get
64
+ response.value
65
+
66
+ klass = resolve(id)
67
+ support = Document.registry[klass]
68
+ support.from_hash(body)
69
+ end
70
+
71
+ def self.all(db, klass)
72
+ support = Document.registry[klass.name]
73
+ resource = db._all_docs
74
+ response, body = resource.get(:query => {:startkey => "#{klass.name}:".to_json,
75
+ :endkey => "#{klass.name}:\ufff0".to_json,
76
+ :include_docs => true})
77
+ response.value
78
+
79
+ body['rows'].map do |row|
80
+ support.from_hash(row['doc'])
81
+ end
82
+ end
83
+
84
+ def self.delete(db, object)
85
+ resource = Rest::Document.new(db, object._id)
86
+ response, body = resource.delete(:query => {:rev => object._rev})
87
+ response.value
88
+ object._rev = nil
89
+ end
90
+ end
91
+ end
92
+
@@ -0,0 +1,41 @@
1
+ module Loveseat
2
+ module Document
3
+ class DSL
4
+ def initialize(support)
5
+ @support = support
6
+ end
7
+
8
+ def integer(name, default = nil)
9
+ @support.add_property(name, Property::Integer, default)
10
+ end
11
+
12
+ def string(name, default = nil)
13
+ @support.add_property(name, Property::String, default)
14
+ end
15
+
16
+ def float(name, default = nil)
17
+ @support.add_property(name, Property::Float, default)
18
+ end
19
+
20
+ def date(name, default = nil)
21
+ @support.add_property(name, Property::Date, default)
22
+ end
23
+
24
+ def time(name, default = nil)
25
+ @support.add_property(name, Property::Time, default)
26
+ end
27
+
28
+ def hash(name, default = nil)
29
+ @support.add_property(name, Property::Hash, default)
30
+ end
31
+
32
+ def array(name, default = nil)
33
+ @support.add_property(name, Property::Array, default)
34
+ end
35
+
36
+ def raw(name, default = nil)
37
+ @support.add_property(name, Property::Raw, default)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,22 @@
1
+ module Loveseat
2
+ module Document
3
+ class InstanceAdapter
4
+ def initialize(klass)
5
+ @support = Document.registry[klass]
6
+ @klass = klass
7
+ end
8
+
9
+ def [](name)
10
+ property_map[name]
11
+ end
12
+
13
+ def inspect
14
+ "#<Loveseat::Document::InstanceAdapter:#{@klass}>"
15
+ end
16
+
17
+ def property_map
18
+ @property_map ||= @support.generate_property_map
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ module Loveseat
2
+ module Document
3
+ module Property
4
+ class Array < Base
5
+ def self.cast(value)
6
+ value.to_a
7
+ end
8
+
9
+ def empty?
10
+ @value.nil? || @value.empty?
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,30 @@
1
+ module Loveseat
2
+ module Document
3
+ module Property
4
+ class Base
5
+ attr_reader :value
6
+
7
+ def initialize(default_value = nil)
8
+ @value = cast(default_value)
9
+ end
10
+
11
+ def get
12
+ @value
13
+ end
14
+
15
+ def set(value)
16
+ @value = cast(value)
17
+ end
18
+
19
+ def empty?
20
+ @value.nil?
21
+ end
22
+
23
+ private
24
+ def cast(value)
25
+ self.class.cast(value) unless value.nil?
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,17 @@
1
+ require 'date'
2
+
3
+ module Loveseat
4
+ module Document
5
+ module Property
6
+ class Date < Base
7
+ def self.cast(value)
8
+ if value.is_a?(::Date)
9
+ return value
10
+ end
11
+
12
+ ::Date.parse(value)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ module Loveseat
2
+ module Document
3
+ module Property
4
+ class Float < Base
5
+ def self.cast(value)
6
+ value.to_f
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module Loveseat
2
+ module Document
3
+ module Property
4
+ class Hash < Base
5
+ def self.cast(value)
6
+ value.to_hash
7
+ end
8
+
9
+ def empty?
10
+ @value.nil? || @value.empty?
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module Loveseat
2
+ module Document
3
+ module Property
4
+ class Integer < Base
5
+ def self.cast(value)
6
+ value.to_i
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Loveseat
2
+ module Document
3
+ module Property
4
+ class Raw < Base
5
+ def self.cast(value)
6
+ value
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Loveseat
2
+ module Document
3
+ module Property
4
+ class String < Base
5
+ def self.cast(value)
6
+ value.to_s
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ require 'time'
2
+
3
+ module Loveseat
4
+ module Document
5
+ module Property
6
+ class Time < Base
7
+ def self.cast(value)
8
+ if value.is_a?(::Time)
9
+ return value
10
+ end
11
+
12
+ ::Time.parse(value)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,106 @@
1
+ module Loveseat
2
+ module Document
3
+ class Support
4
+ attr_accessor :properties, :dsl
5
+
6
+ TYPE = 0
7
+ DEFAULT= 1
8
+
9
+ def initialize(klass, options = {})
10
+ @klass = klass
11
+ @properties = {}
12
+ @dsl = DSL.new(self)
13
+ @abstract = !!options[:abstract]
14
+ @singleton = !!options[:singleton]
15
+
16
+ add_instance_adapter_accessor!
17
+
18
+ unless @abstract
19
+ add_property(:_id, Property::String)
20
+ add_property(:_rev, Property::String)
21
+ end
22
+ end
23
+
24
+ def add_property(name,type,default = nil)
25
+ name = name.to_sym
26
+ alter_property(name,type,default)
27
+ add_instance_methods!(name)
28
+ end
29
+
30
+ def alter_property(name,type,default = nil)
31
+ @properties[name] = [type, default]
32
+ end
33
+
34
+ def to_doc(instance)
35
+ doc = {}
36
+ instance.__loveseat_instance_adapter.property_map.each do |k,v|
37
+ value = v.get
38
+ doc[k] = value unless v.empty?
39
+ end
40
+ doc.to_json
41
+ end
42
+
43
+ def from_hash(doc)
44
+ object = nil
45
+ if singleton?
46
+ object = @klass
47
+ else
48
+ object = @klass.new
49
+ end
50
+ properties.each do |k,v|
51
+ object.send(:"#{k}=", doc[k.to_s])
52
+ end
53
+ object
54
+ end
55
+
56
+ def generate_property_map
57
+ map = {}
58
+ properties.each do |name,value|
59
+ type, default = value
60
+ map[name] = type.new(default)
61
+ end
62
+ map
63
+ end
64
+
65
+ def singleton?
66
+ @singleton
67
+ end
68
+
69
+ def abstract?
70
+ @abstract
71
+ end
72
+
73
+ private
74
+
75
+ def add_instance_adapter_accessor!
76
+ method = <<-SOURCE
77
+ def __loveseat_instance_adapter
78
+ class_name = ( self.instance_of?(Class) ) ? self.name : self.class.name
79
+ @__loveseat_instance_adapter ||= Loveseat::Document::InstanceAdapter.new(class_name)
80
+ end
81
+ SOURCE
82
+ eval_appropriately(method)
83
+ end
84
+
85
+ def add_instance_methods!(method)
86
+ methods = <<-SOURCE
87
+ def #{method}
88
+ __loveseat_instance_adapter["#{method}".to_sym].get
89
+ end
90
+ def #{method}=(value)
91
+ __loveseat_instance_adapter["#{method}".to_sym].set(value)
92
+ end
93
+ SOURCE
94
+ eval_appropriately(methods)
95
+ end
96
+
97
+ def eval_appropriately(arg)
98
+ if singleton?
99
+ @klass.instance_eval(arg)
100
+ else
101
+ @klass.class_eval(arg)
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,42 @@
1
+ module Loveseat
2
+ class Model
3
+ def self.connection=(connection_hash)
4
+ @@server = Rest::Server.new(connection_hash[:host],
5
+ connection_hash[:port],
6
+ connection_hash[:user],
7
+ connection_hash[:password])
8
+ @@database = Rest::Database.new(@@server, connection_hash[:database])
9
+ end
10
+
11
+ def put
12
+ Document.put(self.class.database, self)
13
+ end
14
+
15
+ def delete
16
+ Document.delete(self.class.database, self)
17
+ end
18
+
19
+ def self.get(id)
20
+ unless id[self.name]
21
+ id = [self.name, id].join(':')
22
+ end
23
+ Document.get(self.database, id)
24
+ end
25
+
26
+ def self.all
27
+ Document.all(self.database, self)
28
+ end
29
+
30
+ def self.setup(options = {}, &block)
31
+ Document.setup(self, options, &block)
32
+ end
33
+
34
+ def self.server
35
+ @@server
36
+ end
37
+
38
+ def self.database
39
+ @@database
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,39 @@
1
+ module Loveseat
2
+ class ViewSet < Model
3
+ def self.setup(options = {}, &block)
4
+ options = options.merge(:singleton => true)
5
+ DesignDocument.setup(self, options, &block)
6
+ end
7
+
8
+ def self.view(name, options = {})
9
+ DesignDocument.view(self.database, self, name, options)
10
+ end
11
+
12
+ def self.put
13
+ Document.put(self.database, self)
14
+ end
15
+
16
+ def self.delete
17
+ Document.delete(self.database, self)
18
+ end
19
+
20
+ def self.latest!
21
+ begin
22
+ put
23
+ rescue
24
+ Document.get(self.database, self._id)
25
+ retry
26
+ end
27
+ end
28
+
29
+ def self.get(*args)
30
+ latest!
31
+ end
32
+
33
+ def self.all
34
+ DesignDocument.all(self.database)
35
+ end
36
+
37
+ private :put, :delete
38
+ end
39
+ end
@@ -0,0 +1,18 @@
1
+ module Rest
2
+ class Database < Resource
3
+ attr_reader :server
4
+
5
+ nested_resource :_all_docs
6
+ nested_resource :_revs_limit
7
+ nested_resource :_changes
8
+ nested_resource :_bulk_docs
9
+ nested_resource :_temp_view
10
+ nested_resource :_view_cleanup
11
+ nested_resource :_compact
12
+
13
+ def initialize(server, name)
14
+ @server = server
15
+ super(server.connection, "/#{name}/", server.username, server.password)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,9 @@
1
+ module Rest
2
+ class DesignDocument < Document
3
+ nested_resource :_view
4
+
5
+ def initialize(database, name)
6
+ super(database, "_design/#{name}")
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ module Rest
2
+ class Document < Resource
3
+ def initialize(database, id)
4
+ super(database.connection, database.nested_resource_path(id), database.server.username, database.server.password)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,84 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+ require 'json'
4
+
5
+ module Rest
6
+ class Resource
7
+ attr_reader :connection
8
+
9
+ def initialize(connection, path = '/', username=nil, password=nil)
10
+ @connection = connection
11
+ uri = [ 'http://',
12
+ [connection.address,
13
+ connection.port].join(':'),
14
+ path ].join
15
+ @uri = URI.parse(uri)
16
+ @username = username
17
+ @password = password
18
+ end
19
+
20
+ def self.nested_resource(name)
21
+ define_method name.to_sym do |*args|
22
+ resource = [name.to_s, *args.first].compact.join('/')
23
+ Resource.new(@connection, nested_resource_path(resource))
24
+ end
25
+ end
26
+
27
+ def nested_resource_path(nested_resource = '')
28
+ components = @uri.request_uri.split('/')
29
+ components << "" if components.empty?
30
+ components << nested_resource
31
+ components.join('/')
32
+ end
33
+
34
+ def put(options_or_body = '')
35
+ do_request(options_or_body, Net::HTTP::Put)
36
+ end
37
+
38
+ def get(options_or_body = '')
39
+ do_request(options_or_body, Net::HTTP::Get)
40
+ end
41
+
42
+ def delete(options_or_body = '')
43
+ do_request(options_or_body, Net::HTTP::Delete)
44
+ end
45
+
46
+ def post(options_or_body = '')
47
+ do_request(options_or_body, Net::HTTP::Post)
48
+ end
49
+
50
+ private
51
+ def do_request(options_or_body, request_const)
52
+ request_uri = nil
53
+ request_body = nil
54
+ if options_or_body.is_a?(String)
55
+ request_uri = @uri.request_uri
56
+ request_body = options_or_body
57
+ elsif options_or_body.is_a?(Hash)
58
+ uri = @uri.dup
59
+ uri.query = (options_or_body[:query] || {}).to_query
60
+ request_uri = uri.request_uri
61
+ request_body = options_or_body[:body]
62
+ end
63
+ request = request_const.new(request_uri)
64
+ request['Content-Type'] = 'application/json'
65
+
66
+ request.body = if request_body.is_a?(String)
67
+ request_body
68
+ else
69
+ request_body.to_json
70
+ end
71
+
72
+ if @username and @password
73
+ request.basic_auth(@username, @password)
74
+ end
75
+
76
+ response = @connection.start do |http|
77
+ http.request(request)
78
+ end
79
+
80
+ [response, JSON.parse(response.body)]
81
+ end
82
+ end
83
+ end
84
+
@@ -0,0 +1,19 @@
1
+ module Rest
2
+ class Server < Resource
3
+ attr_reader :username
4
+ attr_reader :password
5
+
6
+ nested_resource :_all_dbs
7
+ nested_resource :_config
8
+ nested_resource :_uuids
9
+ nested_resource :_replicate
10
+ nested_resource :_stats
11
+ nested_resource :_active_tasks
12
+
13
+ def initialize(host, port, username=nil, password=nil)
14
+ @username = username
15
+ @password = password
16
+ super(Net::HTTP.new(host, port), '/', username, password)
17
+ end
18
+ end
19
+ end
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: loveseat
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - John MacKenzie
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-12-21 00:00:00 -06:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: json
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - "="
28
+ - !ruby/object:Gem::Version
29
+ hash: 11
30
+ segments:
31
+ - 1
32
+ - 4
33
+ - 6
34
+ version: 1.4.6
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ description: Small, lightweight CouchDB client and object document mapper. Library is meant to be kept lean while still exposing the most powerful features of the database. Took a little inspiration from outoftime/sunspot.
38
+ email: john@nineteeneightd.com
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files: []
44
+
45
+ files:
46
+ - lib/core_ext/hash.rb
47
+ - lib/loveseat/design_document/dsl.rb
48
+ - lib/loveseat/design_document/support.rb
49
+ - lib/loveseat/design_document/view_row.rb
50
+ - lib/loveseat/design_document.rb
51
+ - lib/loveseat/document/dsl.rb
52
+ - lib/loveseat/document/instance_adapter.rb
53
+ - lib/loveseat/document/property/array.rb
54
+ - lib/loveseat/document/property/base.rb
55
+ - lib/loveseat/document/property/date.rb
56
+ - lib/loveseat/document/property/float.rb
57
+ - lib/loveseat/document/property/hash.rb
58
+ - lib/loveseat/document/property/integer.rb
59
+ - lib/loveseat/document/property/raw.rb
60
+ - lib/loveseat/document/property/string.rb
61
+ - lib/loveseat/document/property/time.rb
62
+ - lib/loveseat/document/support.rb
63
+ - lib/loveseat/document.rb
64
+ - lib/loveseat/model.rb
65
+ - lib/loveseat/view_set.rb
66
+ - lib/loveseat.rb
67
+ - lib/rest/database.rb
68
+ - lib/rest/design_document.rb
69
+ - lib/rest/document.rb
70
+ - lib/rest/resource.rb
71
+ - lib/rest/server.rb
72
+ has_rdoc: true
73
+ homepage: http://198d.github.com/loveseat
74
+ licenses: []
75
+
76
+ post_install_message:
77
+ rdoc_options: []
78
+
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ hash: 3
87
+ segments:
88
+ - 0
89
+ version: "0"
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ hash: 3
96
+ segments:
97
+ - 0
98
+ version: "0"
99
+ requirements: []
100
+
101
+ rubyforge_project:
102
+ rubygems_version: 1.3.7
103
+ signing_key:
104
+ specification_version: 3
105
+ summary: Simple Couch Client / Object Document Mapper
106
+ test_files: []
107
+