jchris-couchrest 0.9.5 → 0.9.6

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.
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ require 'spec/rake/spectask'
5
5
 
6
6
  spec = Gem::Specification.new do |s|
7
7
  s.name = "couchrest"
8
- s.version = "0.9.5"
8
+ s.version = "0.9.7"
9
9
  s.date = "2008-09-11"
10
10
  s.summary = "Lean and RESTful interface to CouchDB."
11
11
  s.email = "jchris@grabb.it"
@@ -36,7 +36,6 @@ namespace :github do # thanks merb!
36
36
  next if skip_fields.include?(name) || value.nil? || value == "" || (value.respond_to?(:empty?) && value.empty?)
37
37
  if name == "dependencies"
38
38
  value.each do |d|
39
- puts d.to_s
40
39
  dep, *ver = d.to_s.split(" ")
41
40
  result << " s.add_dependency #{dep.inspect}, [#{ /\(([^\,]*)/ . match(ver.join(" "))[1].inspect}]\n"
42
41
  end
data/bin/couchapp ADDED
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require File.expand_path(File.dirname(__FILE__)) + '/../lib/couchrest'
5
+
6
+ options = {
7
+ :loud => true,
8
+ }
9
+
10
+ opts = OptionParser.new do |opts|
11
+ opts.banner = "Usage: #$0 [options] (push|pull|generate)"
12
+ opts.on('-q', '--quiet', "Omit extra debug info") do
13
+ options[:loud] = false
14
+ end
15
+ opts.on_tail('-h', '--help', "Display detailed help and exit") do
16
+ puts opts
17
+ exit
18
+ end
19
+ end
20
+
21
+ opts.parse!(ARGV)
22
+
23
+ case ARGV.shift
24
+ when /generate/
25
+ appname = ARGV.shift
26
+ current = Dir.getwd
27
+ appdir = File.join(current, appname)
28
+ puts "generating couchapp in #{appdir}"
29
+ CouchRest::FileManager.generate_app(appdir)
30
+
31
+ when /push/
32
+ dirname = ARGV.shift
33
+ if ARGV.length == 2
34
+ appname = ARGV.shift
35
+ dbstring = ARGV.shift
36
+ elsif ARGV.length == 1
37
+ appname = dirname
38
+ dbstring = ARGV.shift
39
+ else
40
+ puts opts
41
+ puts "push dirname [appname] database"
42
+ exit(0)
43
+ end
44
+ dbspec = CouchRest.parse(dbstring)
45
+ fm = CouchRest::FileManager.new(dbspec[:database], dbspec[:host])
46
+ fm.push_app(dirname, appname)
47
+ when /pull/
48
+
49
+ else
50
+ puts opts
51
+ puts "please specify a command"
52
+ end
@@ -47,10 +47,12 @@ module CouchRest
47
47
  return
48
48
  end
49
49
 
50
+ doc["signatures"] ||= {}
51
+ doc["_attachments"] ||= {}
50
52
  # remove deleted docs
51
53
  to_be_removed = doc["signatures"].keys.select do |d|
52
54
  !pushfiles.collect{|p| p.keys.first}.include?(d)
53
- end
55
+ end
54
56
 
55
57
  to_be_removed.each do |p|
56
58
  say "deleting #{p}"
@@ -69,7 +71,6 @@ module CouchRest
69
71
  doc["_attachments"][path].delete("length")
70
72
  doc["_attachments"][path]["data"] = @attachments[path]["data"]
71
73
  doc["_attachments"][path].merge!({"data" => @attachments[path]["data"]} )
72
-
73
74
  end
74
75
  end
75
76
 
@@ -185,9 +186,70 @@ module CouchRest
185
186
 
186
187
  end
187
188
 
189
+ def push_app(appdir, appname)
190
+ libs = []
191
+ viewdir = File.join(appdir,"views")
192
+ attachdir = File.join(appdir,"attachments")
193
+ views, lang = read_design_views(viewdir)
194
+ # attachments = read_attachments(attachdir)
195
+ docid = "_design/#{appname}"
196
+ design = @db.get(docid) rescue {}
197
+ design['_id'] = docid
198
+ design['views'] = views
199
+ design['language'] = lang
200
+ @db.save(design)
201
+ push_directory(attachdir, docid)
202
+ # puts views.inspect
203
+ end
204
+
205
+ # Generate an application in the given directory.
206
+ # This is a class method because it doesn't depend on
207
+ # specifying a database.
208
+ def self.generate_app(app_dir)
209
+ FileUtils.mkdir_p(app_dir)
210
+ FileUtils.mkdir_p(File.join(app_dir,"attachments"))
211
+ FileUtils.mkdir_p(File.join(app_dir,"views"))
212
+
213
+ index_template = File.join(File.expand_path(File.dirname(__FILE__)), 'templates','index.html')
214
+ index_dest = File.join(app_dir,"attachments","index.html")
215
+ FileUtils.cp(index_template, index_dest)
216
+
217
+ map_template = File.join(File.expand_path(File.dirname(__FILE__)), 'templates','example-map.js')
218
+ map_dest = File.join(app_dir,"views","example-map.js")
219
+ FileUtils.cp(map_template, map_dest)
220
+
221
+ rereduce_template = File.join(File.expand_path(File.dirname(__FILE__)), 'templates','example-reduce.js')
222
+ rereduce_dest = File.join(app_dir,"views","example-reduce.js")
223
+ FileUtils.cp(rereduce_template, rereduce_dest)
224
+ end
188
225
 
189
226
  private
190
227
 
228
+ def read_design_views(viewdir)
229
+ libs = []
230
+ language = nil
231
+ views = {}
232
+ Dir["#{viewdir}/*.*"].each do |viewfile|
233
+ view_parts = viewfile.split('/')
234
+ viewfile_name = view_parts.last
235
+ # example-map.js
236
+ viewfile_name_parts = viewfile_name.split('.')
237
+ viewfile_ext = viewfile_name_parts.last
238
+ view_name_parts = viewfile_name_parts.first.split('-')
239
+ func_type = view_name_parts.pop
240
+ view_name = view_name_parts.join('-')
241
+ contents = File.open(viewfile).read
242
+ if /^lib\..*$/.match viewfile_name
243
+ libs.push(contents)
244
+ else
245
+ views[view_name] ||= {}
246
+ language = LANGS[viewfile_ext]
247
+ views[view_name][func_type] = contents.sub(/(\/\/|#)include-lib/,libs.join("\n"))
248
+ end
249
+ end
250
+ [views, language]
251
+ end
252
+
191
253
  def say words
192
254
  puts words if @loud
193
255
  end
@@ -206,7 +268,7 @@ module CouchRest
206
268
  existing = @db.get(id) rescue nil
207
269
 
208
270
  if existing
209
- updated = fields.merge({"_id" => id, "_rev" => existing["_rev"]})
271
+ updated = existing.merge(fields)
210
272
  if existing != updated
211
273
  say "replacing #{id}"
212
274
  db.save(updated)
@@ -0,0 +1,8 @@
1
+ // an example map function, emits the doc id
2
+ // and the list of keys it contains
3
+
4
+ function(doc) {
5
+ var k, keys = []
6
+ for (k in doc) keys.push(k);
7
+ emit(doc._id, keys);
8
+ };
@@ -0,0 +1,10 @@
1
+ // example reduce function to count the
2
+ // number of rows in a given key range.
3
+
4
+ function(keys, value, rereduce) {
5
+ if (rereduce) {
6
+ return sum(values);
7
+ } else {
8
+ return values.length;
9
+ }
10
+ };
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Generated CouchApp</title>
5
+ <link rel="stylesheet" href="screen.css" type="text/css">
6
+ </head>
7
+ <body>
8
+ <h1>Generated CouchApp</h1>
9
+ <ul id="view"></ul>
10
+ </body>
11
+ <script src="/_utils/script/json2.js"></script>
12
+ <script src="/_utils/script/jquery.js?1.2.6"></script>
13
+ <script src="/_utils/script/jquery.couch.js?0.8.0"></script>
14
+ <script type="text/javascript" charset="utf-8">
15
+ $(function() {
16
+ var dbname = document.location.href.split('/')[3];
17
+ var design = unescape(document.location.href.split('/')[4]).split('/')[1];
18
+ var DB = $.couch.db(dbname);
19
+ DB.view(design+"/example-map",{success: function(json) {
20
+ $("#view").html(json.rows.map(function(row) {
21
+ return '<li>'+row.key+'</li>';
22
+ }).join(''));
23
+ }});
24
+ });
25
+ </script>
26
+ </html>
data/lib/couchrest.rb CHANGED
@@ -41,6 +41,37 @@ module CouchRest
41
41
  Server.new(*opts)
42
42
  end
43
43
 
44
+ def parse url
45
+ case url
46
+ when /^http:\/\/(.*)\/(.*)\/(.*)/
47
+ host = $1
48
+ db = $2
49
+ docid = $3
50
+ when /^http:\/\/(.*)\/(.*)/
51
+ host = $1
52
+ db = $2
53
+ when /^http:\/\/(.*)/
54
+ host = $1
55
+ when /(.*)\/(.*)\/(.*)/
56
+ host = $1
57
+ db = $2
58
+ docid = $3
59
+ when /(.*)\/(.*)/
60
+ host = $1
61
+ db = $2
62
+ else
63
+ db = url
64
+ end
65
+
66
+ db = nil if db && db.empty?
67
+
68
+ {
69
+ :host => host || "localhost:5984",
70
+ :database => db,
71
+ :doc => docid
72
+ }
73
+ end
74
+
44
75
  # ensure that a database exists
45
76
  # creates it if it isn't already there
46
77
  # returns it after it's been created
@@ -0,0 +1,68 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "couchapp" do
4
+ before(:all) do
5
+ @fixdir = File.expand_path(File.dirname(__FILE__)) + '/fixtures/couchapp-test'
6
+ @couchapp = File.expand_path(File.dirname(__FILE__)) + '/../bin/couchapp'
7
+ `rm -rf #{@fixdir}`
8
+ `mkdir -p #{@fixdir}`
9
+ @run = "cd #{@fixdir} && #{@couchapp}"
10
+
11
+ end
12
+
13
+ describe "--help" do
14
+ it "should output the opts" do
15
+ `#{@run} --help`.should match(/Usage/)
16
+ end
17
+ end
18
+
19
+ describe "generate my-app" do
20
+ it "should create an app directory" do
21
+ `#{@run} generate my-app`.should match(/generating/i)
22
+ Dir["#{@fixdir}/*"].select{|x|x =~ /my-app/}.length.should == 1
23
+ end
24
+ it "should create a views directory" do
25
+ `#{@run} generate my-app`.should match(/generating/i)
26
+ Dir["#{@fixdir}/my-app/*"].select{|x|x =~ /views/}.length.should == 1
27
+ end
28
+ end
29
+
30
+ describe "push my-app #{TESTDB}" do
31
+ before(:all) do
32
+ @cr = CouchRest.new(COUCHHOST)
33
+ @db = @cr.database(TESTDB)
34
+ @db.delete! rescue nil
35
+ @db = @cr.create_db(TESTDB) rescue nil
36
+ `#{@run} generate my-app`
37
+ end
38
+ it "should create the design document with the app name" do
39
+ `#{@run} push my-app #{TESTDB}`
40
+ lambda{@db.get("_design/my-app")}.should_not raise_error
41
+ end
42
+ it "should create the views" do
43
+ `#{@run} push my-app #{TESTDB}`
44
+ doc = @db.get("_design/my-app")
45
+ doc['views']['example']['map'].should match(/function/)
46
+ end
47
+ it "should create the index" do
48
+ `#{@run} push my-app #{TESTDB}`
49
+ doc = @db.get("_design/my-app")
50
+ doc['_attachments']['index.html']["content_type"].should == 'text/html'
51
+ end
52
+ end
53
+
54
+ describe "push my-app my-design #{TESTDB}" do
55
+ before(:all) do
56
+ @cr = CouchRest.new(COUCHHOST)
57
+ @db = @cr.database(TESTDB)
58
+ @db.delete! rescue nil
59
+ @db = @cr.create_db(TESTDB) rescue nil
60
+ `#{@run} generate my-app`
61
+ end
62
+ it "should create the design document" do
63
+ `#{@run} push my-app my-design #{TESTDB}`
64
+ lambda{@db.get("_design/my-design")}.should_not raise_error
65
+ end
66
+ end
67
+ end
68
+
@@ -42,6 +42,99 @@ describe CouchRest do
42
42
  end
43
43
  end
44
44
 
45
+ describe "parsing urls" do
46
+ it "should parse just a dbname" do
47
+ db = CouchRest.parse "my-db"
48
+ db[:database].should == "my-db"
49
+ db[:host].should == "localhost:5984"
50
+ end
51
+ it "should parse a host and db" do
52
+ db = CouchRest.parse "localhost/my-db"
53
+ db[:database].should == "my-db"
54
+ db[:host].should == "localhost"
55
+ end
56
+ it "should parse a host and db with http" do
57
+ db = CouchRest.parse "http://localhost/my-db"
58
+ db[:database].should == "my-db"
59
+ db[:host].should == "localhost"
60
+ end
61
+ it "should parse a host with a port and db" do
62
+ db = CouchRest.parse "localhost:5555/my-db"
63
+ db[:database].should == "my-db"
64
+ db[:host].should == "localhost:5555"
65
+ end
66
+ it "should parse a host with a port and db with http" do
67
+ db = CouchRest.parse "http://localhost:5555/my-db"
68
+ db[:database].should == "my-db"
69
+ db[:host].should == "localhost:5555"
70
+ end
71
+ it "should parse just a host" do
72
+ db = CouchRest.parse "http://localhost:5555/"
73
+ db[:database].should be_nil
74
+ db[:host].should == "localhost:5555"
75
+ end
76
+ it "should parse just a host no slash" do
77
+ db = CouchRest.parse "http://localhost:5555"
78
+ db[:host].should == "localhost:5555"
79
+ db[:database].should be_nil
80
+ end
81
+ it "should get docid" do
82
+ db = CouchRest.parse "localhost:5555/my-db/my-doc"
83
+ db[:database].should == "my-db"
84
+ db[:host].should == "localhost:5555"
85
+ db[:doc].should == "my-doc"
86
+ end
87
+ it "should get docid with http" do
88
+ db = CouchRest.parse "http://localhost:5555/my-db/my-doc"
89
+ db[:database].should == "my-db"
90
+ db[:host].should == "localhost:5555"
91
+ db[:doc].should == "my-doc"
92
+ end
93
+
94
+ it "should parse a host and db" do
95
+ db = CouchRest.parse "127.0.0.1/my-db"
96
+ db[:database].should == "my-db"
97
+ db[:host].should == "127.0.0.1"
98
+ end
99
+ it "should parse a host and db with http" do
100
+ db = CouchRest.parse "http://127.0.0.1/my-db"
101
+ db[:database].should == "my-db"
102
+ db[:host].should == "127.0.0.1"
103
+ end
104
+ it "should parse a host with a port and db" do
105
+ db = CouchRest.parse "127.0.0.1:5555/my-db"
106
+ db[:database].should == "my-db"
107
+ db[:host].should == "127.0.0.1:5555"
108
+ end
109
+ it "should parse a host with a port and db with http" do
110
+ db = CouchRest.parse "http://127.0.0.1:5555/my-db"
111
+ db[:database].should == "my-db"
112
+ db[:host].should == "127.0.0.1:5555"
113
+ end
114
+ it "should parse just a host" do
115
+ db = CouchRest.parse "http://127.0.0.1:5555/"
116
+ db[:database].should be_nil
117
+ db[:host].should == "127.0.0.1:5555"
118
+ end
119
+ it "should parse just a host no slash" do
120
+ db = CouchRest.parse "http://127.0.0.1:5555"
121
+ db[:host].should == "127.0.0.1:5555"
122
+ db[:database].should be_nil
123
+ end
124
+ it "should get docid" do
125
+ db = CouchRest.parse "127.0.0.1:5555/my-db/my-doc"
126
+ db[:database].should == "my-db"
127
+ db[:host].should == "127.0.0.1:5555"
128
+ db[:doc].should == "my-doc"
129
+ end
130
+ it "should get docid with http" do
131
+ db = CouchRest.parse "http://127.0.0.1:5555/my-db/my-doc"
132
+ db[:database].should == "my-db"
133
+ db[:host].should == "127.0.0.1:5555"
134
+ db[:doc].should == "my-doc"
135
+ end
136
+ end
137
+
45
138
  describe "easy initializing a database adapter" do
46
139
  it "should be possible without an explicit CouchRest instantiation" do
47
140
  db = CouchRest.database "http://localhost:5984/couchrest-test"
@@ -24,6 +24,60 @@ describe CouchRest::FileManager do
24
24
  end
25
25
  end
26
26
 
27
+ describe CouchRest::FileManager, "generating an app" do
28
+ before(:all) do
29
+ @appdir = File.expand_path(File.dirname(__FILE__)) + '/fixtures/couchapp'
30
+ `rm -rf #{@appdir}`
31
+ `mkdir -p #{@appdir}`
32
+ CouchRest::FileManager.generate_app(@appdir)
33
+ end
34
+ it "should create an attachments directory" do
35
+ Dir["#{@appdir}/*"].select{|x|x =~ /attachments/}.length.should == 1
36
+ end
37
+ it "should create a views directory" do
38
+ Dir["#{@appdir}/*"].select{|x|x =~ /views/}.length.should == 1
39
+ end
40
+ it "should create index.html" do
41
+ html = File.open("#{@appdir}/attachments/index.html").read
42
+ html.should match(/DOCTYPE/)
43
+ end
44
+ it "should create an example view" do
45
+ map = File.open("#{@appdir}/views/example-map.js").read
46
+ map.should match(/function\(doc\)/)
47
+ reduce = File.open("#{@appdir}/views/example-reduce.js").read
48
+ reduce.should match(/rereduce/)
49
+ end
50
+ end
51
+
52
+ describe CouchRest::FileManager, "pushing an app" do
53
+ before(:all) do
54
+ @cr = CouchRest.new(COUCHHOST)
55
+ @db = @cr.database(TESTDB)
56
+ @db.delete! rescue nil
57
+ @db = @cr.create_db(TESTDB) rescue nil
58
+
59
+ @appdir = File.expand_path(File.dirname(__FILE__)) + '/fixtures/couchapp'
60
+ `rm -rf #{@appdir}`
61
+ `mkdir -p #{@appdir}`
62
+ CouchRest::FileManager.generate_app(@appdir)
63
+
64
+ @fm = CouchRest::FileManager.new(TESTDB, COUCHHOST)
65
+ r = @fm.push_app(@appdir, "couchapp")
66
+ end
67
+ it "should create a design document" do
68
+ lambda{@db.get("_design/couchapp")}.should_not raise_error
69
+ end
70
+ it "should create the views" do
71
+ doc = @db.get("_design/couchapp")
72
+ doc['views']['example']['map'].should match(/function/)
73
+ end
74
+ it "should create the index" do
75
+ doc = @db.get("_design/couchapp")
76
+ doc['_attachments']['index.html']["content_type"].should == 'text/html'
77
+ end
78
+ end
79
+
80
+
27
81
  describe CouchRest::FileManager, "pushing views" do
28
82
  before(:all) do
29
83
  @cr = CouchRest.new(COUCHHOST)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jchris-couchrest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.5
4
+ version: 0.9.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - J. Chris Anderson
@@ -46,6 +46,7 @@ files:
46
46
  - README.rdoc
47
47
  - Rakefile
48
48
  - THANKS
49
+ - bin/couchapp
49
50
  - bin/couchdir
50
51
  - bin/couchview
51
52
  - examples/word_count
@@ -73,14 +74,26 @@ files:
73
74
  - lib/couchrest/helper/file_manager.rb
74
75
  - lib/couchrest/helper/pager.rb
75
76
  - lib/couchrest/helper/streamer.rb
77
+ - lib/couchrest/helper/templates
78
+ - lib/couchrest/helper/templates/example-map.js
79
+ - lib/couchrest/helper/templates/example-reduce.js
80
+ - lib/couchrest/helper/templates/index.html
76
81
  - lib/couchrest/monkeypatches.rb
77
82
  - lib/couchrest.rb
83
+ - spec/couchapp_spec.rb
78
84
  - spec/couchrest_spec.rb
79
85
  - spec/database_spec.rb
80
86
  - spec/file_manager_spec.rb
81
87
  - spec/fixtures
82
88
  - spec/fixtures/attachments
83
89
  - spec/fixtures/attachments/test.html
90
+ - spec/fixtures/couchapp
91
+ - spec/fixtures/couchapp/attachments
92
+ - spec/fixtures/couchapp/attachments/index.html
93
+ - spec/fixtures/couchapp/views
94
+ - spec/fixtures/couchapp/views/example-map.js
95
+ - spec/fixtures/couchapp/views/example-reduce.js
96
+ - spec/fixtures/couchapp-test
84
97
  - spec/fixtures/views
85
98
  - spec/fixtures/views/lib.js
86
99
  - spec/fixtures/views/test_view