diff --git a/bin/couchapp b/bin/couchapp deleted file mode 100755 index bf86f08..0000000 --- a/bin/couchapp +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env ruby - -require 'optparse' -require File.expand_path(File.dirname(__FILE__)) + '/../lib/couchrest' - -options = { - :loud => true, -} - -opts = OptionParser.new do |opts| - opts.banner = "Usage: #$0 [options] (push|pull|generate)" - opts.on('-q', '--quiet', "Omit extra debug info") do - options[:loud] = false - end - opts.on_tail('-h', '--help', "Display detailed help and exit") do - puts opts - exit - end -end - -opts.parse!(ARGV) - -case ARGV.shift -when /generate/ - appname = ARGV.shift - current = Dir.getwd - appdir = File.join(current, appname) - puts "generating couchapp in #{appdir}" - CouchRest::FileManager.generate_app(appdir) - -when /push/ - dirname = ARGV.shift - current = Dir.getwd - dir = File.expand_path(File.join(current, dirname)) - dirapp = File.split(dir).last - if ARGV.length == 2 - appname = ARGV.shift - dbstring = ARGV.shift - elsif ARGV.length == 1 - appname = dirapp - dbstring = ARGV.shift - else - puts opts - puts "push dirname [appname] database" - exit(0) - end - CouchRest.database!(dbstring) - dbspec = CouchRest.parse(dbstring) - fm = CouchRest::FileManager.new(dbspec[:database], dbspec[:host]) - fm.push_app(dir, appname) - -when /pull/ - puts "pull is not yet implemented" - -else - puts opts - puts "please specify a command" -end \ No newline at end of file diff --git a/lib/couchrest/helper/app-template/_attachments/index.html b/lib/couchrest/helper/app-template/_attachments/index.html deleted file mode 100644 index f004b99..0000000 --- a/lib/couchrest/helper/app-template/_attachments/index.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - Generated CouchApp - - - -

Generated CouchApp

- - - - - - - \ No newline at end of file diff --git a/lib/couchrest/helper/app-template/foo/bar.txt b/lib/couchrest/helper/app-template/foo/bar.txt deleted file mode 100644 index 5a8cbe4..0000000 --- a/lib/couchrest/helper/app-template/foo/bar.txt +++ /dev/null @@ -1,11 +0,0 @@ -Couchapp will create a field on your document corresponding to any directories you make within the application directory, with the text of any files found as key/value pairs. - -Also, any files that end in .json will be treated as json rather than text, and put in the corresponding field. Also note that file.json, file.js, or file.txt will be stored under the "file" key, so don't make collisions in the filesystem unless you want unpredictable results. - -Of course you know that the views directory will be treated specially and -map and -reduce files will be mapped to the map and reduce functions. And the _attachments directory will be treated strangely as well. - -doc.json is a special case, it is treated as json and its keys are applied to the document root; eg it does not result in a "doc" field on your design document. If you need a doc field on the design document, you'll have to define it with a doc.json like so: {"doc":"value for doc field"} - -ps: each design document only has one language key: it will be set based on the file extensions in the views directory. CouchDB defaults to Javascript, so that's what you'll get if you don't define any views. You can override it with the doc.json file, but don't say we didn't warn you. - -Oh yeah it's recommended that you delete this file. \ No newline at end of file diff --git a/lib/couchrest/helper/app-template/forms/example-form.js b/lib/couchrest/helper/app-template/forms/example-form.js deleted file mode 100644 index e145fc5..0000000 --- a/lib/couchrest/helper/app-template/forms/example-form.js +++ /dev/null @@ -1,16 +0,0 @@ -function(doc, req) { - // !code lib.helpers.template - // !json lib.templates - - respondWith(req, { - html : function() { - var html = template(lib.templates.example, doc); - return {body:html} - }, - xml : function() { - return { - body : - } - } - }) -}; \ No newline at end of file diff --git a/lib/couchrest/helper/app-template/lib/helpers/math.js b/lib/couchrest/helper/app-template/lib/helpers/math.js deleted file mode 100644 index 2b0ee11..0000000 --- a/lib/couchrest/helper/app-template/lib/helpers/math.js +++ /dev/null @@ -1 +0,0 @@ -function stddev() {}; \ No newline at end of file diff --git a/lib/couchrest/helper/app-template/lib/helpers/template.js b/lib/couchrest/helper/app-template/lib/helpers/template.js deleted file mode 100644 index 03499b0..0000000 --- a/lib/couchrest/helper/app-template/lib/helpers/template.js +++ /dev/null @@ -1,32 +0,0 @@ -// Simple JavaScript Templating -// John Resig - http://ejohn.org/ - MIT Licensed -var cache = {}; - -function template(str, data){ - // Figure out if we're getting a template, or if we need to - // load the template - and be sure to cache the result. - var fn = cache[str] || - - // Generate a reusable function that will serve as a template - // generator (and which will be cached). - new Function("obj", - "var p=[],print=function(){p.push.apply(p,arguments);};" + - - // Introduce the data as local variables using with(){} - "with(obj){p.push('" + - - // Convert the template into pure JavaScript - str - .replace(/[\r\t\n]/g, " ") - .replace(/'(?=[^%]*%>)/g,"\t") - .split("'").join("\\'") - .split("\t").join("'") - .replace(/<%=(.+?)%>/g, "',$1,'") - .split("<%").join("');") - .split("%>").join("p.push('") - + "');}return p.join('');"); - cache[str] = fn; - - // Provide some basic currying to the user - return data ? fn( data ) : fn; -}; \ No newline at end of file diff --git a/lib/couchrest/helper/app-template/lib/templates/example.html b/lib/couchrest/helper/app-template/lib/templates/example.html deleted file mode 100644 index 6e1aa89..0000000 --- a/lib/couchrest/helper/app-template/lib/templates/example.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - Generated CouchApp Form Template - - - -
-

<% doc.title %>

-
- - - - - - - - - \ No newline at end of file diff --git a/lib/couchrest/helper/app-template/views/example/map.js b/lib/couchrest/helper/app-template/views/example/map.js deleted file mode 100644 index ead196b..0000000 --- a/lib/couchrest/helper/app-template/views/example/map.js +++ /dev/null @@ -1,9 +0,0 @@ -// an example map function, emits the doc id -// and the list of keys it contains -// !code lib.helpers.math - -function(doc) { - var k, keys = [] - for (k in doc) keys.push(k); - emit(doc._id, keys); -}; diff --git a/lib/couchrest/helper/app-template/views/example/reduce.js b/lib/couchrest/helper/app-template/views/example/reduce.js deleted file mode 100644 index 23eea60..0000000 --- a/lib/couchrest/helper/app-template/views/example/reduce.js +++ /dev/null @@ -1,10 +0,0 @@ -// example reduce function to count the -// number of rows in a given key range. - -function(keys, values, rereduce) { - if (rereduce) { - return sum(values); - } else { - return values.length; - } -}; \ No newline at end of file diff --git a/lib/couchrest/helper/file_manager.rb b/lib/couchrest/helper/file_manager.rb deleted file mode 100644 index f4440e4..0000000 --- a/lib/couchrest/helper/file_manager.rb +++ /dev/null @@ -1,233 +0,0 @@ -require 'digest/md5' - -module CouchRest - class FileManager - attr_reader :db - attr_accessor :loud - - LANGS = {"rb" => "ruby", "js" => "javascript"} - MIMES = { - "html" => "text/html", - "htm" => "text/html", - "png" => "image/png", - "gif" => "image/gif", - "css" => "text/css", - "js" => "test/javascript", - "txt" => "text/plain" - } - - # Generate an application in the given directory. - # This is a class method because it doesn't depend on - # specifying a database. - def self.generate_app(app_dir) - templatedir = File.join(File.expand_path(File.dirname(__FILE__)), 'app-template') - FileUtils.cp_r(templatedir, app_dir) - end - - # instance methods - - def initialize(dbname, host="http://127.0.0.1:5984") - @db = CouchRest.new(host).database(dbname) - end - - # maintain the correspondence between an fs and couch - - def push_app(appdir, appname) - libs = [] - viewdir = File.join(appdir,"views") - attachdir = File.join(appdir,"_attachments") - - @doc = dir_to_fields(appdir) - package_forms(@doc["forms"]) if @doc['forms'] - package_views(@doc["views"]) if @doc['views'] - - docid = "_design/#{appname}" - design = @db.get(docid) rescue {} - design.merge!(@doc) - design['_id'] = docid - # design['language'] = lang if lang - @db.save(design) - push_directory(attachdir, docid) - end - - def dir_to_fields(dir) - fields = {} - (Dir["#{dir}/**/*.*"] - - Dir["#{dir}/_attachments/**/*.*"]).each do |file| - farray = file.sub(dir, '').sub(/^\//,'').split('/') - myfield = fields - while farray.length > 1 - front = farray.shift - myfield[front] ||= {} - myfield = myfield[front] - end - fname, fext = farray.shift.split('.') - fguts = File.open(file).read - if fext == 'json' - myfield[fname] = JSON.parse(fguts) - else - myfield[fname] = fguts - end - end - return fields - end - - def push_directory(push_dir, docid=nil) - docid ||= push_dir.split('/').reverse.find{|part|!part.empty?} - - pushfiles = Dir["#{push_dir}/**/*.*"].collect do |f| - {f.split("#{push_dir}/").last => open(f).read} - end - - return if pushfiles.empty? - - @attachments = {} - @signatures = {} - pushfiles.each do |file| - name = file.keys.first - value = file.values.first - @signatures[name] = md5(value) - - @attachments[name] = { - "data" => value, - "content_type" => MIMES[name.split('.').last] - } - end - - doc = @db.get(docid) rescue nil - - unless doc - say "creating #{docid}" - @db.save({"_id" => docid, "_attachments" => @attachments, "signatures" => @signatures}) - return - end - - doc["signatures"] ||= {} - doc["_attachments"] ||= {} - # remove deleted docs - to_be_removed = doc["signatures"].keys.select do |d| - !pushfiles.collect{|p| p.keys.first}.include?(d) - end - - to_be_removed.each do |p| - say "deleting #{p}" - doc["signatures"].delete(p) - doc["_attachments"].delete(p) - end - - # update existing docs: - doc["signatures"].each do |path, sig| - if (@signatures[path] == sig) - say "no change to #{path}. skipping..." - else - say "replacing #{path}" - doc["signatures"][path] = md5(@attachments[path]["data"]) - doc["_attachments"][path].delete("stub") - doc["_attachments"][path].delete("length") - doc["_attachments"][path]["data"] = @attachments[path]["data"] - doc["_attachments"][path].merge!({"data" => @attachments[path]["data"]} ) - end - end - - # add in new files - new_files = pushfiles.select{|d| !doc["signatures"].keys.include?( d.keys.first) } - - new_files.each do |f| - say "creating #{f}" - path = f.keys.first - content = f.values.first - doc["signatures"][path] = md5(content) - - doc["_attachments"][path] = { - "data" => content, - "content_type" => MIMES[path.split('.').last] - } - end - - begin - @db.save(doc) - rescue Exception => e - say e.message - end - end - - private - - def package_forms(funcs) - apply_lib(funcs) - end - - def package_views(views) - views.each do |view, funcs| - apply_lib(funcs) - end - end - - def apply_lib(funcs) - funcs.each do |k,v| - next unless v.is_a?(String) - funcs[k] = process_include(process_require(v)) - end - end - - # process requires - def process_require(f_string) - f_string.gsub /(\/\/|#)\ ?!code (.*)/ do - fields = $2.split('.') - library = @doc - fields.each do |field| - library = library[field] - break unless library - end - library - end - end - - - def process_include(f_string) - - # process includes - included = {} - f_string.gsub /(\/\/|#)\ ?!json (.*)/ do - fields = $2.split('.') - library = @doc - include_to = included - count = fields.length - fields.each_with_index do |field, i| - break unless library[field] - library = library[field] - # normal case - if i+1 < count - include_to[field] = include_to[field] || {} - include_to = include_to[field] - else - # last one - include_to[field] = library - end - end - - end - # puts included.inspect - rval = if included == {} - f_string - else - varstrings = included.collect do |k, v| - "var #{k} = #{v.to_json};" - end - # just replace the first instance of the macro - f_string.sub /(\/\/|#)\ ?!json (.*)/, varstrings.join("\n") - end - - rval - end - - - def say words - puts words if @loud - end - - def md5 string - Digest::MD5.hexdigest(string) - end - end -end diff --git a/spec/couchapp_spec.rb b/spec/couchapp_spec.rb deleted file mode 100644 index 4d7fbba..0000000 --- a/spec/couchapp_spec.rb +++ /dev/null @@ -1,111 +0,0 @@ -require File.dirname(__FILE__) + '/spec_helper' - -describe "couchapp" do - before(:all) do - @fixdir = FIXTURE_PATH + '/couchapp-test' - @couchapp = File.expand_path(File.dirname(__FILE__)) + '/../bin/couchapp' - `rm -rf #{@fixdir}` - `mkdir -p #{@fixdir}` - @run = "cd #{@fixdir} && #{@couchapp}" - end - - describe "--help" do - it "should output the opts" do - `#{@run} --help`.should match(/Usage/) - end - end - - describe "generate my-app" do - before(:all) do - `#{@run} generate my-app`.should match(/generating/i) - end - it "should create an app directory" do - Dir["#{@fixdir}/*"].select{|x|x =~ /my-app/}.length.should == 1 - end - it "should create a views directory" do - Dir["#{@fixdir}/my-app/*"].select{|x|x =~ /views/}.length.should == 1 - end - it "should create an _attachments directory" do - Dir["#{@fixdir}/my-app/*"].select{|x|x =~ /_attachments/}.length.should == 1 - Dir["#{@fixdir}/my-app/_attachments/*"].select{|x|x =~ /index.html/}.length.should == 1 - end - it "should create a forms directory" do - Dir["#{@fixdir}/my-app/*"].select{|x|x =~ /forms/}.length.should == 1 - end - it "should create a forms and libs" do - Dir["#{@fixdir}/my-app/forms/*"].select{|x|x =~ /example-form.js/}.length.should == 1 - Dir["#{@fixdir}/my-app/lib/templates/*"].select{|x|x =~ /example.html/}.length.should == 1 - end - end - - describe "push my-app #{TESTDB}" do - before(:all) do - @cr = CouchRest.new(COUCHHOST) - @db = @cr.database(TESTDB) - @db.delete! rescue nil - @db = @cr.create_db(TESTDB) rescue nil - `#{@run} generate my-app` - `#{@run} push my-app #{TESTDB}` - @doc = @db.get("_design/my-app") - end - it "should create the design document with the app name" do - lambda{@db.get("_design/my-app")}.should_not raise_error - end - it "should create the views" do - @doc['views']['example']['map'].should match(/function/) - end - it "should create the view libs" do - @doc['views']['example']['map'].should match(/stddev/) - @doc['forms']['example-form'].should_not match(/\"helpers\"/) - end - it "should create view for all the views" do - `mkdir -p #{@fixdir}/my-app/views/more` - `echo 'moremap' > #{@fixdir}/my-app/views/more/map.js` - `#{@run} push my-app #{TESTDB}` - doc = @db.get("_design/my-app") - doc['views']['more']['map'].should match(/moremap/) - end - it "should create the index" do - @doc['_attachments']['index.html']["content_type"].should == 'text/html' - end - it "should push the forms" do - @doc['forms']['example-form'].should match(/Generated CouchApp Form Template/) - end - it "should allow deeper includes" do - @doc['forms']['example-form'].should_not match(/\"helpers\"/) - end - it "deep requires" do - @doc['forms']['example-form'].should_not match(/\"template\"/) - @doc['forms']['example-form'].should match(/Resig/) - end - end - - describe "push . #{TESTDB}" do - before(:all) do - @cr = CouchRest.new(COUCHHOST) - @db = @cr.database(TESTDB) - @db.delete! rescue nil - @db = @cr.create_db(TESTDB) rescue nil - `#{@run} generate my-app` - end - it "should create the design document" do - `cd #{@fixdir}/my-app && #{@couchapp} push . #{TESTDB}` - lambda{@db.get("_design/my-app")}.should_not raise_error - end - end - - describe "push my-app my-design #{TESTDB}" do - before(:all) do - @cr = CouchRest.new(COUCHHOST) - @db = @cr.database(TESTDB) - @db.delete! rescue nil - @db = @cr.create_db(TESTDB) rescue nil - `#{@run} generate my-app` - end - it "should create the design document" do - `#{@run} push my-app my-design #{TESTDB}` - lambda{@db.get("_design/my-design")}.should_not raise_error - end - end -end -