diff --git a/README.rdoc b/README.rdoc index 0d5686f..a9a0255 100644 --- a/README.rdoc +++ b/README.rdoc @@ -31,7 +31,7 @@ CouchRest install, from the project root directory run `rake`, or `autotest` Quick Start: # with !, it creates the database if it doesn't already exist - @db = CouchRest.database!("http://localhost:5984/couchrest-test") + @db = CouchRest.database!("http://127.0.0.1:5984/couchrest-test") response = @db.save({:key => 'value', 'another key' => 'another value'}) doc = @db.get(response['id']) puts doc.inspect diff --git a/Rakefile b/Rakefile index 6195eee..0df1425 100644 --- a/Rakefile +++ b/Rakefile @@ -5,7 +5,7 @@ require 'rake/gempackagetask' spec = Gem::Specification.new do |s| s.name = "couchrest" - s.version = "0.10.1" + s.version = "0.11.1" s.date = "2008-11-22" s.summary = "Lean and RESTful interface to CouchDB." s.email = "jchris@grabb.it" @@ -19,7 +19,6 @@ spec = Gem::Specification.new do |s| s.extra_rdoc_files = %w( README.rdoc LICENSE THANKS ) s.require_path = "lib" s.bindir = 'bin' - s.executables << 'couchview' s.executables << 'couchdir' s.executables << 'couchapp' s.add_dependency("json", ">= 1.1.2") diff --git a/bin/couchview b/bin/couchview deleted file mode 100755 index c87a741..0000000 --- a/bin/couchview +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env ruby - -require 'optparse' -require 'couchrest' - -%w(generate push).each do |file| - require File.dirname(__FILE__) + "/../lib/couchrest/commands/#{file}" -end - -# Set defaults -options = { - :loud => true, -} - -opts = OptionParser.new do |opts| - opts.banner = "Usage: #$0 [options] (push|generate) directory database" - opts.on('-q', '--quiet', "Omit extra debug info") do - options[:loud] = false - end - opts.on_tail('-h', '--help [push|generate]', "Display detailed help and exit") do |help_command| - puts opts - case help_command - when "push" - puts CouchRest::Commands::Push.help - when "generate" - puts CouchRest::Commands::Generate.help - end - exit - end -end -opts.parse!(ARGV) - -options[:command] = ARGV.shift -options[:directory] = ARGV.shift -options[:trailing_args] = ARGV - -# There must be a better way to check for extra required args -unless (["push", "generate"].include?(options[:command]) && options[:directory] && options[:trailing_args]) - puts(opts) - exit -end - -case options[:command] -when "push" - CouchRest::Commands::Push.run(options) -when "generate" - CouchRest::Commands::Generate.run(options) -end diff --git a/couchrest.gemspec b/couchrest.gemspec index 9a66fb6..b3da1c9 100644 --- a/couchrest.gemspec +++ b/couchrest.gemspec @@ -1,17 +1,16 @@ Gem::Specification.new do |s| s.extra_rdoc_files = ["README.rdoc", "LICENSE", "THANKS"] s.date = "Sat Nov 22 00:00:00 -0800 2008" - s.executables = ["couchview", "couchdir", "couchapp"] + s.executables = ["couchdir", "couchapp"] s.authors = ["J. Chris Anderson"] s.required_rubygems_version = ">= 0" - s.version = "0.10.1" + s.version = "0.11.1" s.files = ["LICENSE", "README.rdoc", "Rakefile", "THANKS", "bin/couchapp", "bin/couchdir", - "bin/couchview", "examples/model", "examples/model/example.rb", "examples/word_count", @@ -43,11 +42,21 @@ Gem::Specification.new do |s| "lib/couchrest/helper/file_manager.rb", "lib/couchrest/helper/pager.rb", "lib/couchrest/helper/streamer.rb", - "lib/couchrest/helper/templates", - "lib/couchrest/helper/templates/bar.txt", - "lib/couchrest/helper/templates/example-map.js", - "lib/couchrest/helper/templates/example-reduce.js", - "lib/couchrest/helper/templates/index.html", + "lib/couchrest/helper/template-app", + "lib/couchrest/helper/template-app/_attachments", + "lib/couchrest/helper/template-app/_attachments/index.html", + "lib/couchrest/helper/template-app/foo", + "lib/couchrest/helper/template-app/foo/bar.txt", + "lib/couchrest/helper/template-app/forms", + "lib/couchrest/helper/template-app/forms/example-form.js", + "lib/couchrest/helper/template-app/forms/lib", + "lib/couchrest/helper/template-app/forms/lib/example-template.html", + "lib/couchrest/helper/template-app/views", + "lib/couchrest/helper/template-app/views/_lib", + "lib/couchrest/helper/template-app/views/_lib/helper.js", + "lib/couchrest/helper/template-app/views/example", + "lib/couchrest/helper/template-app/views/example/map.js", + "lib/couchrest/helper/template-app/views/example/reduce.js", "lib/couchrest/monkeypatches.rb", "lib/couchrest.rb", "spec/couchapp_spec.rb", diff --git a/examples/word_count/markov b/examples/word_count/markov index af7465e..b873f3e 100755 --- a/examples/word_count/markov +++ b/examples/word_count/markov @@ -2,7 +2,7 @@ require File.expand_path(File.dirname(__FILE__)) + '/../../couchrest' -cr = CouchRest.new("http://localhost:5984") +cr = CouchRest.new("http://127.0.0.1:5984") @db = cr.database('word-count-example') @word_memoizer = {} diff --git a/examples/word_count/word_count.rb b/examples/word_count/word_count.rb index 36c1351..f0321ae 100644 --- a/examples/word_count/word_count.rb +++ b/examples/word_count/word_count.rb @@ -1,6 +1,6 @@ require File.dirname(__FILE__) + '/../../couchrest' -couch = CouchRest.new("http://localhost:5984") +couch = CouchRest.new("http://127.0.0.1:5984") db = couch.database('word-count-example') db.delete! rescue nil db = couch.create_db('word-count-example') @@ -62,6 +62,6 @@ end # } # }) -# puts "The books have been stored in your CouchDB. To initiate the MapReduce process, visit http://localhost:5984/_utils/ in your browser and click 'word-count-example', then select view 'words' or 'count'. The process could take about 15 minutes on an average MacBook." +# puts "The books have been stored in your CouchDB. To initiate the MapReduce process, visit http://127.0.0.1:5984/_utils/ in your browser and click 'word-count-example', then select view 'words' or 'count'. The process could take about 15 minutes on an average MacBook." # diff --git a/examples/word_count/word_count_query.rb b/examples/word_count/word_count_query.rb index 31a0222..e69b99a 100644 --- a/examples/word_count/word_count_query.rb +++ b/examples/word_count/word_count_query.rb @@ -1,6 +1,6 @@ require File.dirname(__FILE__) + '/../../couchrest' -couch = CouchRest.new("http://localhost:5984") +couch = CouchRest.new("http://127.0.0.1:5984") db = couch.database('word-count-example') puts "Now that we've parsed all those books into CouchDB, the queries we can run are incredibly flexible." @@ -35,5 +35,5 @@ puts "\nHere are the params for 'flight' in the da-vinci book:" puts params.inspect puts puts 'The url looks like this:' -puts 'http://localhost:5984/word-count-example/_view/word_count/count?key=["flight","da-vinci"]' +puts 'http://127.0.0.1:5984/word-count-example/_view/word_count/count?key=["flight","da-vinci"]' puts "\nTry dropping that in your browser..." \ No newline at end of file diff --git a/lib/couchrest.rb b/lib/couchrest.rb index cff840f..1dc3581 100644 --- a/lib/couchrest.rb +++ b/lib/couchrest.rb @@ -72,7 +72,7 @@ module CouchRest db = nil if db && db.empty? { - :host => host || "localhost:5984", + :host => host || "127.0.0.1:5984", :database => db, :doc => docid } diff --git a/lib/couchrest/commands/push.rb b/lib/couchrest/commands/push.rb index 651df6c..a1dcc93 100644 --- a/lib/couchrest/commands/push.rb +++ b/lib/couchrest/commands/push.rb @@ -52,7 +52,7 @@ module CouchRest foo-project/bar-views/my-design/viewname-reduce.js foo-project/bar-views/my-design/noreduce-map.js - Pushed to => http://localhost:5984/baz-database/_design/my-design + Pushed to => http://127.0.0.1:5984/baz-database/_design/my-design And the design document: { @@ -81,11 +81,11 @@ module CouchRest (for project global libs). These libraries are only inserted into views which include the text - //include-lib + // !include lib or - #include-lib + # !include lib Couchview is a result of scratching my own itch. I'd be happy to make it more general, so please contact me at jchris@grabb.it if you'd like to see anything diff --git a/lib/couchrest/core/model.rb b/lib/couchrest/core/model.rb index 1d2daa9..199420f 100644 --- a/lib/couchrest/core/model.rb +++ b/lib/couchrest/core/model.rb @@ -18,7 +18,7 @@ module CouchRest # than this example. # # class Article < CouchRest::Model - # use_database CouchRest.database!('http://localhost:5984/couchrest-model-test') + # use_database CouchRest.database!('http://127.0.0.1:5984/couchrest-model-test') # unique_id :slug # # view_by :date, :descending => true @@ -519,16 +519,17 @@ module CouchRest self.class.casts.each do |k,v| next unless self[k] target = v[:as] + v[:send] || 'new' if target.is_a?(Array) klass = ::Extlib::Inflection.constantize(target[0]) self[k] = self[k].collect do |value| - klass == Time ? Time.parse(value) : klass.new(value) + (!v[:send] && klass == Time) ? Time.parse(value) : klass.send((v[:send] || 'new'), value) end else - self[k] = if target == 'Time' + self[k] = if (!v[:send] && target == 'Time') Time.parse(self[k]) else - ::Extlib::Inflection.constantize(target).new(self[k]) + ::Extlib::Inflection.constantize(target).send((v[:send] || 'new'), self[k]) end end end diff --git a/lib/couchrest/core/server.rb b/lib/couchrest/core/server.rb index 3e62ee2..e76ab82 100644 --- a/lib/couchrest/core/server.rb +++ b/lib/couchrest/core/server.rb @@ -1,7 +1,7 @@ module CouchRest class Server attr_accessor :uri, :uuid_batch_count - def initialize server = 'http://localhost:5984', uuid_batch_count = 1000 + def initialize server = 'http://127.0.0.1:5984', uuid_batch_count = 1000 @uri = server @uuid_batch_count = uuid_batch_count end diff --git a/lib/couchrest/helper/file_manager.rb b/lib/couchrest/helper/file_manager.rb index 6e02fd8..d7dd0a6 100644 --- a/lib/couchrest/helper/file_manager.rb +++ b/lib/couchrest/helper/file_manager.rb @@ -12,12 +12,63 @@ module CouchRest "png" => "image/png", "gif" => "image/gif", "css" => "text/css", - "js" => "test/javascript" - } - def initialize(dbname, host="http://localhost:5984") + "js" => "test/javascript", + "txt" => "text/plain" + } + + def initialize(dbname, host="http://127.0.0.1:5984") @db = CouchRest.new(host).database(dbname) end + 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"]) + package_views(@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 + + + # 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__)), 'template-app') + FileUtils.cp_r(templatedir, app_dir) + end + def push_directory(push_dir, docid=nil) docid ||= push_dir.split('/').reverse.find{|part|!part.empty?} @@ -37,7 +88,7 @@ module CouchRest @attachments[name] = { "data" => value, "content_type" => MIMES[name.split('.').last] - } + } end doc = @db.get(docid) rescue nil @@ -97,191 +148,76 @@ module CouchRest end end - def push_views(view_dir) - designs = {} - - Dir["#{view_dir}/**/*.*"].each do |design_doc| - design_doc_parts = design_doc.split('/') - next if /^lib\..*$/.match design_doc_parts.last - pre_normalized_view_name = design_doc_parts.last.split("-") - view_name = pre_normalized_view_name[0..pre_normalized_view_name.length-2].join("-") - - folder = design_doc_parts[-2] - - designs[folder] ||= {} - designs[folder]["views"] ||= {} - design_lang = design_doc_parts.last.split(".").last - designs[folder]["language"] ||= LANGS[design_lang] - - libs = "" - Dir["#{view_dir}/lib.#{design_lang}"].collect do |global_lib| - libs << open(global_lib).read - libs << "\n" - end - Dir["#{view_dir}/#{folder}/lib.#{design_lang}"].collect do |global_lib| - libs << open(global_lib).read - libs << "\n" - end - if design_doc_parts.last =~ /-map/ - designs[folder]["views"]["#{view_name}-map"] ||= {} - - designs[folder]["views"]["#{view_name}-map"]["map"] = read(design_doc, libs) - - designs[folder]["views"]["#{view_name}-reduce"] ||= {} - designs[folder]["views"]["#{view_name}-reduce"]["map"] = read(design_doc, libs) - end - - if design_doc_parts.last =~ /-reduce/ - designs[folder]["views"]["#{view_name}-reduce"] ||= {} - - designs[folder]["views"]["#{view_name}-reduce"]["reduce"] = read(design_doc, libs) - end - end - - # cleanup empty maps and reduces - designs.each do |name, props| - props["views"].each do |view, funcs| - next unless view.include?("reduce") - props["views"].delete(view) unless funcs.keys.include?("reduce") - end - end - - designs.each do |k,v| - create_or_update("_design/#{k}", v) - end - - designs - end - - def pull_views(view_dir) - prefix = "_design" - ds = db.documents(:startkey => '#{prefix}/', :endkey => '#{prefix}/ZZZZZZZZZ') - ds['rows'].collect{|r|r['id']}.each do |id| - puts directory = id.split('/').last - FileUtils.mkdir_p(File.join(view_dir,directory)) - views = db.get(id)['views'] - - vgroups = views.keys.group_by{|k|k.sub(/\-(map|reduce)$/,'')} - vgroups.each do|g,vs| - mapname = vs.find {|v|views[v]["map"]} - if mapname - # save map - mapfunc = views[mapname]["map"] - mapfile = File.join(view_dir, directory, "#{g}-map.js") # todo support non-js views - File.open(mapfile,'w') do |f| - f.write mapfunc - end - end - - reducename = vs.find {|v|views[v]["reduce"]} - if reducename - # save reduce - reducefunc = views[reducename]["reduce"] - reducefile = File.join(view_dir, directory, "#{g}-reduce.js") # todo support non-js views - File.open(reducefile,'w') do |f| - f.write reducefunc - end - end - end - end - - end - - def push_app(appdir, appname) - libs = [] - viewdir = File.join(appdir,"views") - attachdir = File.join(appdir,"_attachments") - views, lang = read_design_views(viewdir) - - docid = "_design/#{appname}" - design = @db.get(docid) rescue {} - design['_id'] = docid - design['views'] = views - design['language'] = lang if lang - @db.save(design) - push_directory(attachdir, docid) - - push_fields(appdir, docid) - end - - def push_fields(appdir, docid) - fields = {} - (Dir["#{appdir}/**/*.*"] - - Dir["#{appdir}/views/**/*.*"] - - Dir["#{appdir}/doc.json"] - - Dir["#{appdir}/_attachments/**/*.*"]).each do |file| - farray = file.sub(appdir, '').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 - if File.exists?("#{appdir}/doc.json") - default_json = JSON.parse(File.open("#{appdir}/doc.json").read) - end - design = @db.get(docid) rescue {} - design.merge!(fields) - design.merge!(default_json) if default_json - @db.save(design) - end - - # 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) - FileUtils.mkdir_p(app_dir) - FileUtils.mkdir_p(File.join(app_dir,"_attachments")) - FileUtils.mkdir_p(File.join(app_dir,"views")) - FileUtils.mkdir_p(File.join(app_dir,"foo")) - - { - "index.html" => "_attachments", - 'example-map.js' => "views", - 'example-reduce.js' => "views", - 'bar.txt' => "foo", - }.each do |filename, targetdir| - template = File.join(File.expand_path(File.dirname(__FILE__)), 'templates',filename) - dest = File.join(app_dir,targetdir,filename) - FileUtils.cp(template, dest) - end - end - private - def read_design_views(viewdir) - libs = [] - language = nil - views = {} - Dir["#{viewdir}/*.*"].each do |viewfile| - view_parts = viewfile.split('/') - viewfile_name = view_parts.last - # example-map.js - viewfile_name_parts = viewfile_name.split('.') - viewfile_ext = viewfile_name_parts.last - view_name_parts = viewfile_name_parts.first.split('-') - func_type = view_name_parts.pop - view_name = view_name_parts.join('-') - contents = File.open(viewfile).read - if /^lib\..*$/.match viewfile_name - libs.push(contents) - else - views[view_name] ||= {} - language = LANGS[viewfile_ext] - views[view_name][func_type] = contents.sub(/(\/\/|#)include-lib/,libs.join("\n")) - end - end - [views, language] + 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 /(\/\/|#)\ ?!require (.*)/ 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 /(\/\/|#)\ ?!include (.*)/ 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 + f_string.sub /(\/\/|#)\ ?!include (.*)/, varstrings.join("\n") + end + + rval + end + + def say words puts words if @loud end @@ -289,29 +225,5 @@ module CouchRest def md5 string Digest::MD5.hexdigest(string) end - - def read(file, libs=nil) - st = open(file).read - st.sub!(/(\/\/|#)include-lib/,libs) if libs - st - end - - def create_or_update(id, fields) - existing = @db.get(id) rescue nil - - if existing - updated = existing.merge(fields) - if existing != updated - say "replacing #{id}" - db.save(updated) - else - say "skipping #{id}" - end - else - say "creating #{id}" - db.save(fields.merge({"_id" => id})) - end - - end end end diff --git a/lib/couchrest/helper/templates/index.html b/lib/couchrest/helper/template-app/_attachments/index.html similarity index 100% rename from lib/couchrest/helper/templates/index.html rename to lib/couchrest/helper/template-app/_attachments/index.html diff --git a/lib/couchrest/helper/templates/bar.txt b/lib/couchrest/helper/template-app/foo/bar.txt similarity index 100% rename from lib/couchrest/helper/templates/bar.txt rename to lib/couchrest/helper/template-app/foo/bar.txt diff --git a/lib/couchrest/helper/template-app/forms/example-form.js b/lib/couchrest/helper/template-app/forms/example-form.js new file mode 100644 index 0000000..5f3079f --- /dev/null +++ b/lib/couchrest/helper/template-app/forms/example-form.js @@ -0,0 +1,17 @@ +function(doc, req) { + // !include lib.templates + + // !require lib.helpers.template + + 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/template-app/lib/helpers/math.js b/lib/couchrest/helper/template-app/lib/helpers/math.js new file mode 100644 index 0000000..2b0ee11 --- /dev/null +++ b/lib/couchrest/helper/template-app/lib/helpers/math.js @@ -0,0 +1 @@ +function stddev() {}; \ No newline at end of file diff --git a/lib/couchrest/helper/template-app/lib/helpers/template.js b/lib/couchrest/helper/template-app/lib/helpers/template.js new file mode 100644 index 0000000..03499b0 --- /dev/null +++ b/lib/couchrest/helper/template-app/lib/helpers/template.js @@ -0,0 +1,32 @@ +// 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/template-app/lib/templates/example.html b/lib/couchrest/helper/template-app/lib/templates/example.html new file mode 100644 index 0000000..6e1aa89 --- /dev/null +++ b/lib/couchrest/helper/template-app/lib/templates/example.html @@ -0,0 +1,26 @@ + + + + Generated CouchApp Form Template + + + +
+

<% doc.title %>

+
+ + + + + + + + + \ No newline at end of file diff --git a/lib/couchrest/helper/templates/example-map.js b/lib/couchrest/helper/template-app/views/example/map.js similarity index 85% rename from lib/couchrest/helper/templates/example-map.js rename to lib/couchrest/helper/template-app/views/example/map.js index 878684d..11668f5 100644 --- a/lib/couchrest/helper/templates/example-map.js +++ b/lib/couchrest/helper/template-app/views/example/map.js @@ -1,5 +1,6 @@ // an example map function, emits the doc id // and the list of keys it contains +// !require lib.helpers.math function(doc) { var k, keys = [] diff --git a/lib/couchrest/helper/templates/example-reduce.js b/lib/couchrest/helper/template-app/views/example/reduce.js similarity index 100% rename from lib/couchrest/helper/templates/example-reduce.js rename to lib/couchrest/helper/template-app/views/example/reduce.js diff --git a/spec/couchapp_spec.rb b/spec/couchapp_spec.rb index da8af52..4d7fbba 100644 --- a/spec/couchapp_spec.rb +++ b/spec/couchapp_spec.rb @@ -16,14 +16,26 @@ describe "couchapp" do 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 - `#{@run} generate my-app`.should match(/generating/i) Dir["#{@fixdir}/*"].select{|x|x =~ /my-app/}.length.should == 1 end it "should create a views directory" do - `#{@run} generate my-app`.should match(/generating/i) 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 @@ -33,26 +45,38 @@ describe "couchapp" do @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 - `#{@run} push my-app #{TESTDB}` lambda{@db.get("_design/my-app")}.should_not raise_error end it "should create the views" do - `#{@run} push my-app #{TESTDB}` - doc = @db.get("_design/my-app") - doc['views']['example']['map'].should match(/function/) + @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 - `echo 'moremap' > #{@fixdir}/my-app/views/more-map.js` + `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 - `#{@run} push my-app #{TESTDB}` - doc = @db.get("_design/my-app") - doc['_attachments']['index.html']["content_type"].should == 'text/html' + @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 diff --git a/spec/couchrest/core/couchrest_spec.rb b/spec/couchrest/core/couchrest_spec.rb index 1d4499d..f802e2d 100644 --- a/spec/couchrest/core/couchrest_spec.rb +++ b/spec/couchrest/core/couchrest_spec.rb @@ -46,48 +46,48 @@ describe CouchRest do it "should parse just a dbname" do db = CouchRest.parse "my-db" db[:database].should == "my-db" - db[:host].should == "localhost:5984" + db[:host].should == "127.0.0.1:5984" end it "should parse a host and db" do - db = CouchRest.parse "localhost/my-db" + db = CouchRest.parse "127.0.0.1/my-db" db[:database].should == "my-db" - db[:host].should == "localhost" + db[:host].should == "127.0.0.1" end it "should parse a host and db with http" do - db = CouchRest.parse "http://localhost/my-db" + db = CouchRest.parse "http://127.0.0.1/my-db" db[:database].should == "my-db" - db[:host].should == "localhost" + db[:host].should == "127.0.0.1" end it "should parse a host with a port and db" do - db = CouchRest.parse "localhost:5555/my-db" + db = CouchRest.parse "127.0.0.1:5555/my-db" db[:database].should == "my-db" - db[:host].should == "localhost:5555" + db[:host].should == "127.0.0.1:5555" end it "should parse a host with a port and db with http" do - db = CouchRest.parse "http://localhost:5555/my-db" + db = CouchRest.parse "http://127.0.0.1:5555/my-db" db[:database].should == "my-db" - db[:host].should == "localhost:5555" + db[:host].should == "127.0.0.1:5555" end it "should parse just a host" do - db = CouchRest.parse "http://localhost:5555/" + db = CouchRest.parse "http://127.0.0.1:5555/" db[:database].should be_nil - db[:host].should == "localhost:5555" + db[:host].should == "127.0.0.1:5555" end it "should parse just a host no slash" do - db = CouchRest.parse "http://localhost:5555" - db[:host].should == "localhost:5555" + db = CouchRest.parse "http://127.0.0.1:5555" + db[:host].should == "127.0.0.1:5555" db[:database].should be_nil end it "should get docid" do - db = CouchRest.parse "localhost:5555/my-db/my-doc" + db = CouchRest.parse "127.0.0.1:5555/my-db/my-doc" db[:database].should == "my-db" - db[:host].should == "localhost:5555" + db[:host].should == "127.0.0.1:5555" db[:doc].should == "my-doc" end it "should get docid with http" do - db = CouchRest.parse "http://localhost:5555/my-db/my-doc" + db = CouchRest.parse "http://127.0.0.1:5555/my-db/my-doc" db[:database].should == "my-db" - db[:host].should == "localhost:5555" + db[:host].should == "127.0.0.1:5555" db[:doc].should == "my-doc" end @@ -137,24 +137,24 @@ describe CouchRest do describe "easy initializing a database adapter" do it "should be possible without an explicit CouchRest instantiation" do - db = CouchRest.database "http://localhost:5984/couchrest-test" + db = CouchRest.database "http://127.0.0.1:5984/couchrest-test" db.should be_an_instance_of(CouchRest::Database) - db.host.should == "localhost:5984" + db.host.should == "127.0.0.1:5984" end # TODO add https support (need test environment...) # it "should work with https" # do - # db = CouchRest.database "https://localhost:5984/couchrest-test" - # db.host.should == "https://localhost:5984" + # db = CouchRest.database "https://127.0.0.1:5984/couchrest-test" + # db.host.should == "https://127.0.0.1:5984" # end it "should not create the database automatically" do - db = CouchRest.database "http://localhost:5984/couchrest-test" + db = CouchRest.database "http://127.0.0.1:5984/couchrest-test" lambda{db.info}.should raise_error(RestClient::ResourceNotFound) end end describe "ensuring the db exists" do it "should be super easy" do - db = CouchRest.database! "http://localhost:5984/couchrest-test-2" + db = CouchRest.database! "http://127.0.0.1:5984/couchrest-test-2" db.name.should == 'couchrest-test-2' db.info["db_name"].should == 'couchrest-test-2' end diff --git a/spec/couchrest/core/database_spec.rb b/spec/couchrest/core/database_spec.rb index f30ef06..1bb9e1e 100644 --- a/spec/couchrest/core/database_spec.rb +++ b/spec/couchrest/core/database_spec.rb @@ -159,7 +159,7 @@ describe CouchRest::Database do docs = [{'key' => 'value'}, {'_id' => 'totally-uniq'}] id_docs = [{'key' => 'value', '_id' => 'asdf6sgadkfhgsdfusdf'}, {'_id' => 'totally-uniq'}] - CouchRest.should_receive(:post).with("http://localhost:5984/couchrest-test/_bulk_docs", {:docs => id_docs}) + CouchRest.should_receive(:post).with("http://127.0.0.1:5984/couchrest-test/_bulk_docs", {:docs => id_docs}) @db.bulk_save(docs) end diff --git a/spec/couchrest/core/model_spec.rb b/spec/couchrest/core/model_spec.rb index 284d46e..58a57bc 100644 --- a/spec/couchrest/core/model_spec.rb +++ b/spec/couchrest/core/model_spec.rb @@ -46,7 +46,7 @@ class Course < CouchRest::Model end class Article < CouchRest::Model - use_database CouchRest.database!('http://localhost:5984/couchrest-model-test') + use_database CouchRest.database!('http://127.0.0.1:5984/couchrest-model-test') unique_id :slug view_by :date, :descending => true @@ -89,9 +89,18 @@ class Player < CouchRest::Model timestamps! end +class Event < CouchRest::Model + key_accessor :subject, :occurs_at + + cast :occurs_at, :as => 'Time', :send => 'parse' +end + describe "save bug" do + before(:each) do + CouchRest::Model.default_database = reset_test_db! + end + it "should fix" do - @db = reset_test_db! @p = Player.new @p.email = 'insane@fakestreet.com' @p.save @@ -107,8 +116,8 @@ describe CouchRest::Model do @db = @cr.create_db(TESTDB) rescue nil @adb = @cr.database('couchrest-model-test') @adb.delete! rescue nil - CouchRest.database!('http://localhost:5984/couchrest-model-test') - CouchRest::Model.default_database = CouchRest.database!('http://localhost:5984/couchrest-test') + CouchRest.database!('http://127.0.0.1:5984/couchrest-model-test') + CouchRest::Model.default_database = CouchRest.database!('http://127.0.0.1:5984/couchrest-test') end it "should use the default database" do @@ -319,6 +328,18 @@ describe CouchRest::Model do end end + describe "cast keys to any type" do + before(:all) do + event_doc = { :subject => "Some event", :occurs_at => Time.now } + e = Event.database.save event_doc + + @event = Event.get e['id'] + end + it "should cast created_at to Time" do + @event['occurs_at'].should be_an_instance_of(Time) + end + end + describe "saving a model" do before(:all) do @obj = Basic.new diff --git a/spec/couchrest/helpers/file_manager_spec.rb b/spec/couchrest/helpers/file_manager_spec.rb index 7e6d4db..995cb7c 100644 --- a/spec/couchrest/helpers/file_manager_spec.rb +++ b/spec/couchrest/helpers/file_manager_spec.rb @@ -15,12 +15,12 @@ describe CouchRest::FileManager do lambda{CouchRest::FileManager.new}.should raise_error end it "should accept a db name" do - @fm = CouchRest::FileManager.new(TESTDB, 'http://localhost') + @fm = CouchRest::FileManager.new(TESTDB, 'http://127.0.0.1') @fm.db.name.should == TESTDB end - it "should default to localhost couchdb" do + it "should default to 127.0.0.1 couchdb" do @fm = CouchRest::FileManager.new(TESTDB) - @fm.db.host.should == 'http://localhost:5984' + @fm.db.host.should == 'http://127.0.0.1:5984' end end @@ -127,16 +127,16 @@ describe CouchRest::FileManager, "pushing views" do @design["views"].should_not be_nil end it "should push a map and reduce view" do - @design["views"]["test-map"].should_not be_nil - @design["views"]["test-reduce"].should_not be_nil + @design["views"]["test"]["map"].should_not be_nil + @design["views"]["test"]["reduce"].should_not be_nil end it "should push a map only view" do - @design["views"]["only-map"].should_not be_nil - @design["views"]["only-reduce"].should be_nil + @design["views"]["only"]["map"].should_not be_nil + @design["views"]["only"]["reduce"].should be_nil end it "should include library files" do - @design["views"]["only-map"]["map"].should include("globalLib") - @design["views"]["only-map"]["map"].should include("justThisView") + @design["views"]["only"]["map"].should include("globalLib") + @design["views"]["only"]["map"].should include("justThisView") end it "should not create extra design docs" do docs = @db.documents(:startkey => '_design', :endkey => '_design/ZZZZZZ') diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4af958f..97fb985 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -5,7 +5,7 @@ require File.dirname(__FILE__) + '/../lib/couchrest' FIXTURE_PATH = File.dirname(__FILE__) + '/fixtures' -COUCHHOST = "http://localhost:5984" +COUCHHOST = "http://127.0.0.1:5984" TESTDB = 'couchrest-test' def reset_test_db! diff --git a/utils/remap.rb b/utils/remap.rb index f42c5d5..131aeb3 100644 --- a/utils/remap.rb +++ b/utils/remap.rb @@ -2,11 +2,11 @@ require 'rubygems' require 'couchrest' # set the source db and map view -source = CouchRest.new("http://localhost:5984").database('source-db') +source = CouchRest.new("http://127.0.0.1:5984").database('source-db') source_view = 'mydesign/view-map' # set the target db -target = CouchRest.new("http://localhost:5984").database('target-db') +target = CouchRest.new("http://127.0.0.1:5984").database('target-db') pager = CouchRest::Pager.new(source) diff --git a/utils/subset.rb b/utils/subset.rb index dd5d2e7..0b7adb9 100644 --- a/utils/subset.rb +++ b/utils/subset.rb @@ -5,10 +5,10 @@ require 'couchrest' # use it to create a smaller dataset on which to prototype views. # specify the source database -source = CouchRest.new("http://localhost:5984").database('source-db') +source = CouchRest.new("http://127.0.0.1:5984").database('source-db') # specify the target database -target = CouchRest.new("http://localhost:5984").database('target-db') +target = CouchRest.new("http://127.0.0.1:5984").database('target-db') # pager efficiently yields all view rows pager = CouchRest::Pager.new(source)