couch 0.2.0 → 0.2.1

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.
Files changed (51) hide show
  1. data/README.rdoc +6 -88
  2. data/Rakefile +3 -54
  3. data/bin/couch +1 -7
  4. data/couch.gemspec +6 -72
  5. data/lib/couch.rb +0 -41
  6. metadata +9 -127
  7. data/.gitmodules +0 -3
  8. data/LICENSE +0 -20
  9. data/lib/couch/actions/base.rb +0 -15
  10. data/lib/couch/actions/pull.rb +0 -28
  11. data/lib/couch/actions/push.rb +0 -53
  12. data/lib/couch/actions/routes.rb +0 -41
  13. data/lib/couch/commands.rb +0 -41
  14. data/lib/couch/commands/destroy.rb +0 -9
  15. data/lib/couch/commands/generate.rb +0 -9
  16. data/lib/couch/commands/pull.rb +0 -4
  17. data/lib/couch/commands/push.rb +0 -4
  18. data/lib/couch/commands/routes.rb +0 -4
  19. data/lib/couch/design_document.rb +0 -314
  20. data/lib/couch/generators.rb +0 -63
  21. data/lib/couch/generators/application/USAGE +0 -10
  22. data/lib/couch/generators/application/application_generator.rb +0 -51
  23. data/lib/couch/generators/application/templates/README +0 -1
  24. data/lib/couch/generators/application/templates/_attachments/index.html +0 -11
  25. data/lib/couch/generators/application/templates/_attachments/stylesheets/application.css +0 -25
  26. data/lib/couch/generators/application/templates/_id +0 -1
  27. data/lib/couch/generators/application/templates/couchrc +0 -1
  28. data/lib/couch/generators/application/templates/gitignore +0 -0
  29. data/lib/couch/generators/application/templates/lib/mustache.js +0 -305
  30. data/lib/couch/generators/application/templates/validate_doc_update.js +0 -3
  31. data/lib/couch/generators/base.rb +0 -66
  32. data/lib/couch/generators/list/USAGE +0 -8
  33. data/lib/couch/generators/list/list_generator.rb +0 -9
  34. data/lib/couch/generators/list/templates/list.js +0 -29
  35. data/lib/couch/generators/named_base.rb +0 -22
  36. data/lib/couch/generators/scaffold/USAGE +0 -10
  37. data/lib/couch/generators/scaffold/scaffold_generator.rb +0 -28
  38. data/lib/couch/generators/show/USAGE +0 -8
  39. data/lib/couch/generators/show/show_generator.rb +0 -9
  40. data/lib/couch/generators/show/templates/show.js +0 -20
  41. data/lib/couch/generators/validation/USAGE +0 -9
  42. data/lib/couch/generators/validation/templates/validate_doc_update.js +0 -3
  43. data/lib/couch/generators/validation/validation_generator.rb +0 -34
  44. data/lib/couch/generators/view/USAGE +0 -8
  45. data/lib/couch/generators/view/templates/map.js +0 -5
  46. data/lib/couch/generators/view/view_generator.rb +0 -17
  47. data/lib/couch/version.rb +0 -3
  48. data/spec/couch/design_document_spec.rb +0 -313
  49. data/spec/couch_spec.rb +0 -7
  50. data/spec/spec.opts +0 -1
  51. data/spec/spec_helper.rb +0 -9
@@ -1,3 +0,0 @@
1
- [submodule "vendor/mustache.js"]
2
- path = vendor/mustache.js
3
- url = git://github.com/janl/mustache.js.git
data/LICENSE DELETED
@@ -1,20 +0,0 @@
1
- Copyright (c) 2009 Johannes J. Schmidt
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.
@@ -1,15 +0,0 @@
1
- require 'thor/group'
2
- require 'active_support/inflector'
3
-
4
- module Couch
5
- module Actions
6
- class Base < Thor::Group
7
- include Thor::Actions
8
-
9
- def self.banner
10
- "couch #{to_s.split('::').last.underscore}"
11
- end
12
- end
13
- end
14
- end
15
-
@@ -1,28 +0,0 @@
1
- require 'couch/actions/base'
2
- require 'couch/design_document'
3
-
4
- require "rest_client"
5
-
6
- module Couch
7
- module Actions
8
- class Pull < Base
9
- add_runtime_options!
10
-
11
- def pull
12
- doc = DesignDocument.new
13
- say "Pulling %s" % doc.url
14
-
15
- resp = RestClient.get doc.url(:attachments => true)
16
- doc.json = resp.body
17
-
18
- doc.write do |filename, content|
19
- create_file filename, content
20
- end
21
-
22
- say "Checked out %s" % doc.rev
23
- rescue RestClient::ResourceNotFound
24
- say "Error: Document %s does not exist!" % doc.id
25
- end
26
- end
27
- end
28
- end
@@ -1,53 +0,0 @@
1
- require 'couch/actions/base'
2
- require 'couch/design_document'
3
-
4
- require 'pathname'
5
- require "rest_client"
6
-
7
- module Couch
8
- module Actions
9
- class Push < Base
10
- def initialize(*args)
11
- super
12
- @doc = DesignDocument.new
13
- end
14
-
15
- def create_database_unless_exists
16
- RestClient.put @doc.database, nil
17
- say "Created database %s" % @doc.database
18
- rescue RestClient::PreconditionFailed
19
- end
20
-
21
- def push
22
- root = Pathname.new(destination_root)
23
- filenames = Dir[root.join "**/*"]
24
- filenames.map! { |file| Pathname.new file }
25
- filenames.map! { |path| path.relative_path_from root }
26
- filenames.delete_if { |path| !path.file? }
27
- filenames.map!(&:to_s)
28
- @doc.read(filenames) do |filename|
29
- File.read File.join(destination_root, filename)
30
- end
31
-
32
- say "Pushing to %s" % @doc.url
33
-
34
- resp = RestClient.put @doc.url, @doc.json
35
- response = JSON.parse(resp.body)
36
-
37
- if response["ok"]
38
- @doc.rev = response["rev"]
39
- File.open File.join(destination_root, "_rev"), "w" do |file|
40
- file << @doc.rev
41
- end
42
-
43
- say "Pushed %s" % @doc.rev
44
- else
45
- say "Error occured: %s" % response.inspect
46
- end
47
-
48
- rescue RestClient::Conflict
49
- say "Conflict! Try to pull first or delete ./_rev."
50
- end
51
- end
52
- end
53
- end
@@ -1,41 +0,0 @@
1
- require 'couch/actions/base'
2
-
3
- module Couch
4
- module Actions
5
- class Routes < Base
6
- def routes
7
- say 'Static:'
8
- Dir.glob(File.join(destination_root, "_attachments/*.html")).each do |file|
9
- say ' %s' % attachment_url(file)
10
- end
11
-
12
- say 'Lists:'
13
- Dir.glob(File.join(destination_root, "lists/*")).each do |list|
14
- Dir.glob(File.join(destination_root, "views/*")).each do |view|
15
- say ' %s' % list_url(list, view)
16
- end
17
- end
18
-
19
- say 'Shows:'
20
- Dir.glob(File.join(destination_root, "shows/*")).each do |show|
21
- say ' %s' % show_url(show)
22
- say ' %s' % show_url(show, '/:id')
23
- end
24
- end
25
-
26
- protected
27
-
28
- def attachment_url(file)
29
- File.join(Couch.database, '_design', File.basename(Couch.database), File.basename(file))
30
- end
31
-
32
- def list_url(list, view)
33
- File.join(Couch.database, '_design', File.basename(Couch.database), '_list', File.basename(view), File.basename(list, '.js'))
34
- end
35
-
36
- def show_url(show, id = '/')
37
- File.join(Couch.database, '_design', File.basename(Couch.database), '_show', File.basename(show, '.js'), id)
38
- end
39
- end
40
- end
41
- end
@@ -1,41 +0,0 @@
1
- if ARGV.empty?
2
- ARGV << '--help'
3
- end
4
-
5
- HELP_TEXT = <<-EOT
6
- Usage: couch COMMAND [ARGS]
7
-
8
- The most common couch commands are:
9
- generate Generate new code (short-cut alias: "g")
10
- push Push application code to CouchDB
11
- pull Pull latest application code from CouchDB
12
- routes List application urls
13
-
14
- In addition to those, there are:
15
- destroy Undo code generated with "generate"
16
-
17
- All commands can be run with -h for more information.
18
- EOT
19
-
20
-
21
- case ARGV.shift
22
- when 'g', 'generate'
23
- require 'couch/commands/generate'
24
- when 'destroy'
25
- require 'couch/commands/destroy'
26
- when 'push'
27
- require 'couch/commands/push'
28
- when 'pull'
29
- require 'couch/commands/pull'
30
- when 'routes'
31
- require 'couch/commands/routes'
32
-
33
- when '--help', '-h'
34
- puts HELP_TEXT
35
- when '--version', '-v'
36
- require 'couch/version'
37
- puts "Couch #{Couch::VERSION}"
38
- else
39
- puts "Error: Command not recognized"
40
- puts HELP_TEXT
41
- end
@@ -1,9 +0,0 @@
1
- require 'couch/generators'
2
-
3
- if [nil, "-h", "--help"].include?(ARGV.first)
4
- Couch::Generators.help 'destroy'
5
- exit
6
- end
7
-
8
- name = ARGV.shift
9
- Couch::Generators.invoke name, ARGV, :behavior => :revoke, :destination_root => Couch.root
@@ -1,9 +0,0 @@
1
- require 'couch/generators'
2
-
3
- if [nil, "-h", "--help"].include?(ARGV.first)
4
- Couch::Generators.help 'generate'
5
- exit
6
- end
7
-
8
- name = ARGV.shift
9
- Couch::Generators.invoke name, ARGV, :behavior => :invoke, :destination_root => Couch.root
@@ -1,4 +0,0 @@
1
- require 'couch'
2
- require 'couch/actions/pull'
3
-
4
- Couch::Actions::Pull.start ARGV, :destination_root => Couch.root
@@ -1,4 +0,0 @@
1
- require 'couch'
2
- require 'couch/actions/push'
3
-
4
- Couch::Actions::Push.start ARGV, :destination_root => Couch.root
@@ -1,4 +0,0 @@
1
- require 'couch'
2
- require 'couch/actions/routes'
3
-
4
- Couch::Actions::Routes.start ARGV, :destination_root => Couch.root
@@ -1,314 +0,0 @@
1
- require 'uri'
2
-
3
- module Couch
4
- class DesignDocument
5
- # Mime type mapping from extensions
6
- MIME_TYPE_MAPPING = {
7
- ".html" => "text/html",
8
- ".js" => "text/javascript",
9
- ".css" => "text/css",
10
- }
11
-
12
- # Files that should have a .js extension
13
- JAVASCRIPT_FILES = %w[
14
- validate_doc_update
15
- lists/*
16
- shows/*
17
- updates/*
18
- views/*/*
19
- ]
20
-
21
- # Files that should not be included in document
22
- EXCLUDE_FILES = %w[
23
- README
24
- ]
25
-
26
- attr_accessor :hash
27
-
28
- def initialize
29
- @hash = {}
30
- end
31
-
32
- # Read document from a filesystem.
33
- #
34
- # Takes a filename,
35
- # many filenames,
36
- # or an array of filenames
37
- # and assign the return value of a yielded block to the hash.
38
- #
39
- # Nested hashes
40
- # like { "hash" => { "key" => "value" } }
41
- # can be constructed if the filename contains a slash (/),
42
- # eg "hash/key".
43
- #
44
- def read(*filenames, &block)
45
- filenames.flatten.uniq.each do |filename|
46
- # skip exclude files
47
- next if EXCLUDE_FILES.include?(filename)
48
-
49
- key = filename.dup
50
- # strip extname from javascript files
51
- key.sub!(/\.js$/, '') if filename =~ /#{JAVASCRIPT_FILES.join('|')}/
52
-
53
- set_hash_at key, block.call(filename)
54
- end
55
-
56
- map_attachments!
57
- inject_makros!
58
- end
59
-
60
- # Write document to a filesystem
61
- #
62
- # Takes a directoy as startpoint (default is nil),
63
- # a document hash (default is the design documents hash)
64
- # and recursively yields all keys and values to the given block.
65
- #
66
- # Nested hashes
67
- # like { "hash" => { "key" => "value" } }
68
- # will result in the yielded filename
69
- # "hash/key".
70
- #
71
- # The key "_attachments" has a special meaning:
72
- # the value holds base64 encoded data as well as other metadata.
73
- # This data will gets decoded and used as value for the key.
74
- #
75
- def write(directory = nil, doc = nil, &block)
76
- reduce_attachments!
77
- reject_makros!
78
-
79
- doc ||= hash
80
- doc.each do |key, value|
81
- filename = directory ? File.join(directory, key) : key.dup
82
- if value.is_a?(Hash)
83
- write(filename, value, &block)
84
- else
85
- # append extname to javascript files
86
- filename << '.js' if filename =~ /#{JAVASCRIPT_FILES.join('|')}/
87
- block.call(filename, value)
88
- end
89
- end
90
- end
91
-
92
- # Returns a JSON string representation of the documents hash
93
- #
94
- def json
95
- hash.to_json
96
- end
97
-
98
- # Build the documents hash from a JSON string
99
- #
100
- def json=(json)
101
- self.hash = JSON.parse(json)
102
- end
103
-
104
-
105
- # Accessor for id
106
- def id
107
- hash["_id"] || Couch.id
108
- end
109
-
110
- # Accessor for rev
111
- def rev
112
- hash["_rev"] || Couch.rev
113
- end
114
-
115
- # Updates rev in documents hash
116
- def rev=(new_rev)
117
- hash["_rev"] = new_rev
118
- end
119
-
120
-
121
- # Accessor for couch database
122
- def database
123
- @database ||= Couch.database
124
- end
125
-
126
- # Base URL for document
127
- def base_url
128
- @base_url ||= File.join(database, id)
129
- end
130
-
131
- # URL for accessing design document
132
- #
133
- # Takes an optional options hash
134
- # which gets converted to url encoded options
135
- # and appended to the documents base url
136
- #
137
- def url(options = {})
138
- base_url + build_options_string(options)
139
- end
140
-
141
- private
142
-
143
- def hash_at(path)
144
- current_hash = hash
145
-
146
- parts = path.split('/')
147
- key = parts.pop
148
-
149
- parts.each do |part|
150
- current_hash[part] ||= {}
151
- current_hash = current_hash[part]
152
- end
153
-
154
- current_hash[key]
155
- end
156
-
157
- def set_hash_at(path, value)
158
- current_hash = hash
159
-
160
- parts = path.split('/')
161
- key = parts.pop
162
-
163
- parts.each do |part|
164
- current_hash[part] ||= {}
165
- current_hash = current_hash[part]
166
- end
167
-
168
- current_hash[key] = value
169
- end
170
-
171
- def build_options_string(options)
172
- return '' if options.empty?
173
- options_array = []
174
- options.each do |key, value|
175
- options_array << URI.escape([key, value].join('='))
176
- end
177
- '?' + options_array.join("&")
178
- end
179
-
180
- def inject_makros!
181
- self.hash = inject_code_makro(hash)
182
- self.hash = inject_json_makro(hash)
183
- end
184
-
185
- def inject_code_makro(doc)
186
- doc.each do |key, value|
187
- doc[key] = if value.is_a?(String)
188
- value.gsub(/\/\/\s*!code.*$/) do |match|
189
- filename = match.sub(/^.*!code\s*(\S+).*$/, '\1')
190
- hash_at File.join('lib', filename)
191
- end
192
- elsif value.is_a?(Hash)
193
- inject_code_makro(value)
194
- else
195
- value
196
- end
197
- end
198
-
199
- doc
200
- end
201
-
202
- def inject_json_makro(doc)
203
- doc.each do |key, value|
204
- doc[key] = if value.is_a?(String)
205
- value.gsub(/\/\/\s*!json.*$/) do |match|
206
- filename = match.sub(/^.*!json\s*(\S+).*$/, '\1')
207
- 'var %s = %s;' % [filename.sub(/\..*$/, ''), hash_at(File.join('lib', filename)).to_json]
208
- end
209
- elsif value.is_a?(Hash)
210
- inject_json_makro(value)
211
- else
212
- value
213
- end
214
- end
215
-
216
- doc
217
- end
218
-
219
- def reject_makros!
220
- # TODO: recursive walk libs
221
- libs = hash["lib"]
222
- return if libs.nil? || libs.empty?
223
- # Attention: replace json makros first!
224
- self.hash = reject_json_makro(hash, libs)
225
- self.hash = reject_code_makro(hash, libs)
226
- end
227
-
228
- def reject_code_makro(doc, libs)
229
- doc = doc.dup
230
- doc.each do |key, value|
231
- next if key == "lib"
232
-
233
- if value.is_a?(String)
234
- libs.each do |name, content|
235
- # only try substituting strings
236
- next unless content.is_a?(String)
237
- next unless value.include?(content)
238
- doc[key] = value.gsub(content, "// !code #{name}")
239
- end
240
- elsif value.is_a?(Hash)
241
- doc[key] = reject_code_makro(value, libs)
242
- end
243
- end
244
- doc
245
- end
246
-
247
- def reject_json_makro(doc, libs)
248
- doc.each do |key, value|
249
- next if key == "lib"
250
- if value.is_a?(String)
251
- libs.each do |name, content|
252
- # only try substituting strings
253
- next unless content.is_a?(String)
254
- json = 'var %s = %s;' % [name.sub(/\..*$/, ''), content.to_json]
255
- next unless value.include?(json)
256
- doc[key] = value.gsub(json, "// !json #{name}")
257
- end
258
- elsif value.is_a?(Hash)
259
- doc[key] = reject_json_makro(value, libs)
260
- end
261
- end
262
- doc
263
- end
264
-
265
- def reduce_attachments!
266
- return hash unless hash["_attachments"]
267
- attachments = {}
268
- hash["_attachments"].each do |key, value|
269
- data = value["data"]
270
- next unless data
271
- attachments.update key => decode_attachment(data)
272
- end
273
- hash.update "_attachments" => attachments
274
- end
275
-
276
- def map_attachments!
277
- return unless hash["_attachments"]
278
- attachments = {}
279
- flatten_attachements(hash["_attachments"]).each do |key, value|
280
- attachments.update key => {
281
- "data" => encode_attachment(value),
282
- "content_type" => mime_type_for(key)
283
- }
284
- end
285
- self.hash.update "_attachments" => attachments
286
- end
287
-
288
- def flatten_attachements(doc, base = nil)
289
- result = {}
290
- doc.each do |key, value|
291
- new_base = base ? [base, key].join('/') : key
292
- if value.is_a?(Hash)
293
- result.update flatten_attachements(value, new_base)
294
- else
295
- result.update new_base => value
296
- end
297
- end
298
- result
299
- end
300
-
301
- def decode_attachment(data)
302
- data.unpack("m").first
303
- end
304
-
305
- def encode_attachment(data)
306
- [data].pack("m").gsub(/\s+/,'')
307
- end
308
-
309
- def mime_type_for(filename)
310
- ext = File.extname(filename)
311
- MIME_TYPE_MAPPING[ext] || 'text/plain'
312
- end
313
- end
314
- end