careo-makura 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,56 @@
1
+ module Makura
2
+ module Plugin
3
+ module Pager
4
+ module SingletonMethods
5
+ def pager(page, limit)
6
+ Makura::Plugin::Pager::Pagination.new(self, :pager, page, limit)
7
+ end
8
+ end
9
+
10
+ class Pagination
11
+ def initialize(model, view, page, limit)
12
+ @model, @view, @page, @limit = model, view, page, limit
13
+ end
14
+
15
+ # /pager/_all_docs?count=10&group=true
16
+ # /pager/_all_docs?startkey=%224f9dca1c66121f9320a69553546db07a%22&startkey_docid=4f9dca1c66121f9320a69553546db07a&skip=1&descending=false&count=10&group=true
17
+ # /pager/_all_docs?startkey=%22_design%2FUser%22&startkey_docid=_design%2FUser&skip=1&descending=false&count=10&group=true
18
+ # /pager/_all_docs?startkey=%22d850f0801686b85035680bb6f38d5c5c%22&startkey_docid=d850f0801686b85035680bb6f38d5c5c&skip=1&descending=false&count=10&group=true
19
+
20
+ # NOTE:
21
+ # * descending should be true if you page backwards
22
+
23
+ include Enumerable
24
+
25
+ def each(start_id = nil, descending = false, &block)
26
+ opts = {
27
+ :count => @limit,
28
+ :group => true,
29
+ :descending => descending,
30
+ # :include_docs => true,
31
+ }
32
+
33
+ if start_id
34
+ opts[:skip] = 1
35
+ opts[:startkey_docid] = start_id
36
+ opts[:startkey] = start_id
37
+ end
38
+
39
+ @model.view(@view, opts).each(&block)
40
+ end
41
+
42
+ def count
43
+ end
44
+
45
+ def first_page?
46
+ end
47
+
48
+ def last_page?
49
+ end
50
+
51
+ def empty?
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,203 @@
1
+ module Makura
2
+ class Server
3
+ include HTTPMethods
4
+ attr_accessor :uri, :cache_ttl, :cache_tries
5
+
6
+ COUCHDB_URI = 'http://localhost:5984'
7
+ CACHE_TTL = 5
8
+ CACHE_TRIES = 2
9
+
10
+ # Usage:
11
+ # server = Makura::Server.new
12
+ # #<URI::HTTP:0xb778ce38 URL:http://localhost:5984>
13
+ # server.info
14
+ # {"couchdb"=>"Welcome", "version"=>"0.9.0a718650-incubating"}
15
+
16
+ def initialize(uri = COUCHDB_URI, cache_ttl = CACHE_TTL, cache_tries = CACHE_TRIES)
17
+ @uri = URI(uri.to_s)
18
+ @cache_ttl = cache_ttl
19
+ @cache_tries = cache_tries
20
+ @uuids = UUIDCache.new(self)
21
+ end
22
+
23
+ def inspect
24
+ @uri.inspect
25
+ end
26
+
27
+ # General queries
28
+
29
+ # Answers with general couchdb info, looks like:
30
+ #
31
+ # Usage:
32
+ # server.info
33
+ # # {'couchdb' => 'Welcome', 'version' => '0.9.0a718650-incubating'}
34
+ def info
35
+ get('/')
36
+ end
37
+
38
+ # Answers with configuration info.
39
+ #
40
+ # Usage:
41
+ # server.config
42
+ #
43
+ def config
44
+ get('/_config')
45
+ end
46
+
47
+ # Issue restart of the CouchDB daemon.
48
+ #
49
+ # Usage:
50
+ # server.restart
51
+ # # {'ok' => true}
52
+ def restart
53
+ post('/_restart')
54
+ end
55
+
56
+ # Array of names of databases on the server
57
+ #
58
+ # Usage:
59
+ # server.databases
60
+ # # ["another", "blog", "makura-spec"]
61
+ def databases
62
+ get('/_all_dbs')
63
+ end
64
+
65
+ # Return new database instance using this server instance.
66
+ #
67
+ # Usage:
68
+ # foo = server.database('foo')
69
+ # # #<Makura::Database 'http://localhost:5984/foo'>
70
+ # server.databases
71
+ # # ["another", "blog", "foo", "makura-spec"]
72
+
73
+ def database(name)
74
+ Database.new(self, name)
75
+ end
76
+
77
+ # Answers with an uuid from the UUIDCache.
78
+ #
79
+ # Usage:
80
+ # server.next_uuid
81
+ # # "55fdca746fa5a5b56f5270875477a2cc"
82
+
83
+ def next_uuid
84
+ @uuids.next
85
+ end
86
+
87
+ def start_cache(namespace = 'makura', *servers)
88
+ servers << 'localhost:11211' if servers.empty?
89
+ @cache = MemCache.new(servers, :namespace => namespace, :multithread => true)
90
+ end
91
+
92
+ def stop_cache
93
+ @cache = nil
94
+ end
95
+
96
+ def cached(request, ttl = cache_ttl, tries = cache_tries)
97
+ key = request[:url]
98
+
99
+ unless response = @cache.get(key)
100
+ response = execute(request)
101
+ @cache.add(key, response, ttl)
102
+ end
103
+
104
+ return response
105
+ rescue MemCache::MemCacheError => error
106
+ servers = @cache.servers.map{|s| "#{s.host}:#{s.port}"}
107
+ start_cache(@cache.namespace, *servers)
108
+ tries -= 1
109
+ retry if tries > 0
110
+ warn "[makura caching disabled] #{error.message}"
111
+ @cache = nil
112
+ execute(request)
113
+ end
114
+
115
+ # Helpers
116
+
117
+ def request(method, path, params = {})
118
+ keep_raw = params.delete(:raw)
119
+ payload = params.delete(:payload)
120
+ payload = payload.to_json if payload and not keep_raw
121
+ headers = {}
122
+
123
+ if content_type = params.delete('Content-Type')
124
+ headers['Content-Type'] = content_type
125
+ end
126
+
127
+ params.delete_if{|k,v| v.nil? }
128
+ uri = uri(path, params).to_s
129
+
130
+ request = {
131
+ :method => method,
132
+ :url => uri,
133
+ :payload => payload,
134
+ :headers => headers}
135
+
136
+ if @cache and request[:method] == :get
137
+ raw = cached(request)
138
+ else
139
+ raw = execute(request)
140
+ end
141
+
142
+ return raw if keep_raw
143
+ json = JSON.parse(raw)
144
+ rescue JSON::ParserError
145
+ return raw
146
+ rescue RestClient::RequestFailed => ex
147
+ raise appropriate_error(ex)
148
+ rescue RestClient::ResourceNotFound => ex
149
+ raise Error::ResourceNotFound, request[:url], ex.backtrace
150
+ rescue Errno::ECONNREFUSED
151
+ raise Error::ConnectionRefused, "Is CouchDB running at #{@uri}?"
152
+ end
153
+
154
+ def execute(request)
155
+ RestClient::Request.execute(request)
156
+ end
157
+
158
+ def appropriate_error(exception)
159
+ body = exception.response.body if exception.respond_to?(:response)
160
+ backtrace = exception.backtrace
161
+
162
+ raise(Error::RequestFailed, exception.message, backtrace) unless body
163
+ raise(Error::RequestFailed, exception.message, backtrace) if body.empty?
164
+
165
+ json = JSON.parse(body)
166
+ error, reason = json['error'], json['reason']
167
+
168
+ case error
169
+ when 'bad_request'
170
+ raise(Error::BadRequest, reason, backtrace)
171
+ when 'authorization'
172
+ raise(Error::Authorization, reason, backtrace)
173
+ when 'not_found'
174
+ raise(Error::NotFound, reason, backtrace)
175
+ when 'file_exists'
176
+ raise(Error::FileExists, reason, backtrace)
177
+ when 'missing_rev'
178
+ raise(Error::MissingRevision, reason, backtrace)
179
+ when 'conflict'
180
+ raise(Error::Conflict, reason, backtrace)
181
+ else
182
+ raise(Error::RequestFailed, json.inspect, backtrace)
183
+ end
184
+ end
185
+
186
+ JSON_PARAMS = %w[key startkey endkey]
187
+
188
+ def paramify(hash)
189
+ hash.map{|k,v|
190
+ k = k.to_s
191
+ v = v.to_json if JSON_PARAMS.include?(k)
192
+ "#{Makura.escape(k)}=#{Makura.escape(v)}"
193
+ }.join('&')
194
+ end
195
+
196
+ def uri(path = '/', params = {})
197
+ uri = @uri.dup
198
+ uri.path = (path[0,1] == '/' ? path : "/#{path}").squeeze('/')
199
+ uri.query = paramify(params) unless params.empty?
200
+ uri
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,23 @@
1
+ module Makura
2
+ class UUIDCache
3
+ attr_accessor :min, :max, :server, :pretty
4
+
5
+ def initialize(server, min = 500, max = 1500, pretty = true)
6
+ @server, @min, @max, @pretty = server, min, max, pretty
7
+ @uuids = []
8
+ end
9
+
10
+ def next
11
+ fetch if @uuids.size < min
12
+ @uuids.shift
13
+ end
14
+
15
+ def fetch(count = 0)
16
+ todo = max - @uuids.size
17
+ count = [min, todo, max].sort[1]
18
+ uuids = @server.get('/_uuids', :count => count)['uuids']
19
+ uuids.map!{|u| Makura.pretty_from_md5(u) } if pretty
20
+ @uuids.concat(uuids)
21
+ end
22
+ end
23
+ end
data/makura.gemspec ADDED
@@ -0,0 +1,41 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "makura"
3
+ s.version = "0.1"
4
+
5
+ s.summary = "Ruby wrapper around the CouchDB REST API."
6
+ s.description = "Ruby wrapper around the CouchDB REST API."
7
+ s.platform = "ruby"
8
+ s.has_rdoc = true
9
+ s.author = "Michael 'manveru' Fellinger"
10
+ s.email = "m.fellinger@gmail.com"
11
+ s.homepage = "http://github.com/manveru/makura"
12
+ s.executables = ['makura']
13
+ s.bindir = "bin"
14
+ s.require_path = "lib"
15
+
16
+ s.add_dependency('rest-client', '>= 0.8.1')
17
+ s.add_dependency('json', '>= 1.1.3')
18
+
19
+ s.files = [
20
+ "COPYING",
21
+ "README.md",
22
+ "bin/makura",
23
+ "example/blog.rb",
24
+ "example/couch/map/author_all.js",
25
+ "example/couch/map/author_posts.js",
26
+ "example/couch/map/post_all.js",
27
+ "example/couch/map/post_comments.js",
28
+ "example/couch/reduce/sum_length.js",
29
+ "lib/makura/database.rb",
30
+ "lib/makura/design.rb",
31
+ "lib/makura/error.rb",
32
+ "lib/makura/http_methods.rb",
33
+ "lib/makura/layout.rb",
34
+ "lib/makura/model.rb",
35
+ "lib/makura/plugin/pager.rb",
36
+ "lib/makura/server.rb",
37
+ "lib/makura/uuid_cache.rb",
38
+ "lib/makura.rb",
39
+ "makura.gemspec"
40
+ ]
41
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: careo-makura
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Michael 'manveru' Fellinger
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-02-13 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rest-client
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.8.1
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: json
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.1.3
34
+ version:
35
+ description: Ruby wrapper around the CouchDB REST API.
36
+ email: m.fellinger@gmail.com
37
+ executables:
38
+ - makura
39
+ extensions: []
40
+
41
+ extra_rdoc_files: []
42
+
43
+ files:
44
+ - COPYING
45
+ - README.md
46
+ - bin/makura
47
+ - example/blog.rb
48
+ - example/couch/map/author_all.js
49
+ - example/couch/map/author_posts.js
50
+ - example/couch/map/post_all.js
51
+ - example/couch/map/post_comments.js
52
+ - example/couch/reduce/sum_length.js
53
+ - lib/makura/database.rb
54
+ - lib/makura/design.rb
55
+ - lib/makura/error.rb
56
+ - lib/makura/http_methods.rb
57
+ - lib/makura/layout.rb
58
+ - lib/makura/model.rb
59
+ - lib/makura/plugin/pager.rb
60
+ - lib/makura/server.rb
61
+ - lib/makura/uuid_cache.rb
62
+ - lib/makura.rb
63
+ - makura.gemspec
64
+ has_rdoc: true
65
+ homepage: http://github.com/manveru/makura
66
+ post_install_message:
67
+ rdoc_options: []
68
+
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: "0"
76
+ version:
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: "0"
82
+ version:
83
+ requirements: []
84
+
85
+ rubyforge_project:
86
+ rubygems_version: 1.2.0
87
+ signing_key:
88
+ specification_version: 2
89
+ summary: Ruby wrapper around the CouchDB REST API.
90
+ test_files: []
91
+