Merge branch 'master' of git://github.com/jchris/couchrest
* 'master' of git://github.com/jchris/couchrest: (21 commits) require before include require system deep include change it to !include use the lib dir lib not library more reorg for couchapp remove couchview modernizing couchapp simpler mappings simplyfy couchapp push extract method removed doc.json special case hand merge mattly time patch removed the suffix and duplication when importing views added possibility to cast any key to any type using any method push forms/ into _design/$this/forms push forms/ into _design/$this/forms Fixed the "save bug should fix" spec add txt mimetype ...
This commit is contained in:
commit
189cd910a3
|
@ -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
|
||||
|
|
3
Rakefile
3
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")
|
||||
|
|
|
@ -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
|
|
@ -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",
|
||||
|
|
|
@ -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 = {}
|
||||
|
||||
|
|
|
@ -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."
|
||||
#
|
||||
|
||||
|
|
|
@ -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..."
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
17
lib/couchrest/helper/template-app/forms/example-form.js
Normal file
17
lib/couchrest/helper/template-app/forms/example-form.js
Normal file
|
@ -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 : <xml><node value={doc.title}/></xml>
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
1
lib/couchrest/helper/template-app/lib/helpers/math.js
Normal file
1
lib/couchrest/helper/template-app/lib/helpers/math.js
Normal file
|
@ -0,0 +1 @@
|
|||
function stddev() {};
|
32
lib/couchrest/helper/template-app/lib/helpers/template.js
Normal file
32
lib/couchrest/helper/template-app/lib/helpers/template.js
Normal file
|
@ -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;
|
||||
};
|
26
lib/couchrest/helper/template-app/lib/templates/example.html
Normal file
26
lib/couchrest/helper/template-app/lib/templates/example.html
Normal file
|
@ -0,0 +1,26 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Generated CouchApp Form Template</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">
|
||||
<h2><a href="index.html">Back to index</a></h2>
|
||||
</div>
|
||||
<div id="content">
|
||||
<h1><% doc.title %></h1>
|
||||
</div>
|
||||
</body>
|
||||
<script src="/_utils/script/json2.js"></script>
|
||||
<script src="/_utils/script/jquery.js?1.2.6"></script>
|
||||
<script src="/_utils/script/jquery.couch.js?0.8.0"></script>
|
||||
<script src="jquery.couchapp.js"></script>
|
||||
<script src="blog.js"></script>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
$.CouchApp(function(app) {
|
||||
var docid = document.location.pathname.split('/').pop();
|
||||
// hey you could run a query to load more information from views
|
||||
});
|
||||
</script>
|
||||
<script src="showdown.js"></script>
|
||||
</html>
|
|
@ -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 = []
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue