brianmario-couchrest 0.23
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/LICENSE +176 -0
- data/README.md +95 -0
- data/Rakefile +75 -0
- data/THANKS.md +18 -0
- data/examples/model/example.rb +144 -0
- data/examples/word_count/markov +38 -0
- data/examples/word_count/views/books/chunked-map.js +3 -0
- data/examples/word_count/views/books/united-map.js +1 -0
- data/examples/word_count/views/markov/chain-map.js +6 -0
- data/examples/word_count/views/markov/chain-reduce.js +7 -0
- data/examples/word_count/views/word_count/count-map.js +6 -0
- data/examples/word_count/views/word_count/count-reduce.js +3 -0
- data/examples/word_count/word_count.rb +46 -0
- data/examples/word_count/word_count_query.rb +40 -0
- data/examples/word_count/word_count_views.rb +26 -0
- data/lib/couchrest.rb +198 -0
- data/lib/couchrest/commands/generate.rb +71 -0
- data/lib/couchrest/commands/push.rb +103 -0
- data/lib/couchrest/core/database.rb +303 -0
- data/lib/couchrest/core/design.rb +79 -0
- data/lib/couchrest/core/document.rb +87 -0
- data/lib/couchrest/core/response.rb +16 -0
- data/lib/couchrest/core/server.rb +88 -0
- data/lib/couchrest/core/view.rb +4 -0
- data/lib/couchrest/helper/pager.rb +103 -0
- data/lib/couchrest/helper/streamer.rb +44 -0
- data/lib/couchrest/helper/upgrade.rb +51 -0
- data/lib/couchrest/mixins.rb +4 -0
- data/lib/couchrest/mixins/attachments.rb +31 -0
- data/lib/couchrest/mixins/callbacks.rb +483 -0
- data/lib/couchrest/mixins/class_proxy.rb +108 -0
- data/lib/couchrest/mixins/design_doc.rb +90 -0
- data/lib/couchrest/mixins/document_queries.rb +44 -0
- data/lib/couchrest/mixins/extended_attachments.rb +68 -0
- data/lib/couchrest/mixins/extended_document_mixins.rb +7 -0
- data/lib/couchrest/mixins/properties.rb +129 -0
- data/lib/couchrest/mixins/validation.rb +242 -0
- data/lib/couchrest/mixins/views.rb +169 -0
- data/lib/couchrest/monkeypatches.rb +113 -0
- data/lib/couchrest/more/casted_model.rb +28 -0
- data/lib/couchrest/more/extended_document.rb +215 -0
- data/lib/couchrest/more/property.rb +40 -0
- data/lib/couchrest/support/blank.rb +42 -0
- data/lib/couchrest/support/class.rb +176 -0
- data/lib/couchrest/validation/auto_validate.rb +163 -0
- data/lib/couchrest/validation/contextual_validators.rb +78 -0
- data/lib/couchrest/validation/validation_errors.rb +118 -0
- data/lib/couchrest/validation/validators/absent_field_validator.rb +74 -0
- data/lib/couchrest/validation/validators/confirmation_validator.rb +99 -0
- data/lib/couchrest/validation/validators/format_validator.rb +117 -0
- data/lib/couchrest/validation/validators/formats/email.rb +66 -0
- data/lib/couchrest/validation/validators/formats/url.rb +43 -0
- data/lib/couchrest/validation/validators/generic_validator.rb +120 -0
- data/lib/couchrest/validation/validators/length_validator.rb +134 -0
- data/lib/couchrest/validation/validators/method_validator.rb +89 -0
- data/lib/couchrest/validation/validators/numeric_validator.rb +104 -0
- data/lib/couchrest/validation/validators/required_field_validator.rb +109 -0
- data/spec/couchrest/core/couchrest_spec.rb +201 -0
- data/spec/couchrest/core/database_spec.rb +699 -0
- data/spec/couchrest/core/design_spec.rb +138 -0
- data/spec/couchrest/core/document_spec.rb +267 -0
- data/spec/couchrest/core/server_spec.rb +35 -0
- data/spec/couchrest/helpers/pager_spec.rb +122 -0
- data/spec/couchrest/helpers/streamer_spec.rb +23 -0
- data/spec/couchrest/more/casted_extended_doc_spec.rb +40 -0
- data/spec/couchrest/more/casted_model_spec.rb +98 -0
- data/spec/couchrest/more/extended_doc_attachment_spec.rb +130 -0
- data/spec/couchrest/more/extended_doc_spec.rb +509 -0
- data/spec/couchrest/more/extended_doc_subclass_spec.rb +98 -0
- data/spec/couchrest/more/extended_doc_view_spec.rb +355 -0
- data/spec/couchrest/more/property_spec.rb +136 -0
- data/spec/fixtures/attachments/README +3 -0
- data/spec/fixtures/attachments/couchdb.png +0 -0
- data/spec/fixtures/attachments/test.html +11 -0
- data/spec/fixtures/more/article.rb +34 -0
- data/spec/fixtures/more/card.rb +20 -0
- data/spec/fixtures/more/course.rb +14 -0
- data/spec/fixtures/more/event.rb +6 -0
- data/spec/fixtures/more/invoice.rb +17 -0
- data/spec/fixtures/more/person.rb +8 -0
- data/spec/fixtures/more/question.rb +6 -0
- data/spec/fixtures/more/service.rb +12 -0
- data/spec/fixtures/views/lib.js +3 -0
- data/spec/fixtures/views/test_view/lib.js +3 -0
- data/spec/fixtures/views/test_view/only-map.js +4 -0
- data/spec/fixtures/views/test_view/test-map.js +3 -0
- data/spec/fixtures/views/test_view/test-reduce.js +3 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +26 -0
- data/utils/remap.rb +27 -0
- data/utils/subset.rb +30 -0
- metadata +200 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__)) + '/../../couchrest'
|
4
|
+
|
5
|
+
cr = CouchRest.new("http://127.0.0.1:5984")
|
6
|
+
@db = cr.database('word-count-example')
|
7
|
+
@word_memoizer = {}
|
8
|
+
|
9
|
+
def probable_follower_for(word)
|
10
|
+
@word_memoizer[word] ||= @db.view('markov/chain-reduce', :startkey => [word,nil], :endkey => [word,{}],:group_level => 2)
|
11
|
+
|
12
|
+
# puts
|
13
|
+
# puts "search #{word} #{wprobs[word]['rows'].length}"
|
14
|
+
# @word_memoizer[word]['rows'].sort_by{|r|r['value']}.each{|r|puts [r['value'],r['key']].inspect}
|
15
|
+
|
16
|
+
rows = @word_memoizer[word]['rows'].select{|r|(r['key'][1]!='')}.sort_by{|r|r['value']}
|
17
|
+
row = rows[(-1*[rows.length,5].min)..-1].sort_by{rand}[0]
|
18
|
+
row ? row['key'][1] : nil
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
word = ARGV[0]
|
23
|
+
words = [word]
|
24
|
+
|
25
|
+
while word
|
26
|
+
$stdout.print ' ' if words.length > 1
|
27
|
+
$stdout.print word
|
28
|
+
$stdout.flush
|
29
|
+
word = probable_follower_for(word)
|
30
|
+
words << word
|
31
|
+
end
|
32
|
+
|
33
|
+
$stdout.print '.'
|
34
|
+
$stdout.flush
|
35
|
+
puts
|
36
|
+
|
37
|
+
# `say #{words.join(' ')}`
|
38
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
function(doc){if(doc.text && doc.text.match(/united/)) emit([doc.title, doc.chunk],null)}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'couchrest'
|
3
|
+
|
4
|
+
couch = CouchRest.new("http://127.0.0.1:5984")
|
5
|
+
db = couch.database('word-count-example')
|
6
|
+
db.delete! rescue nil
|
7
|
+
db = couch.create_db('word-count-example')
|
8
|
+
|
9
|
+
books = {
|
10
|
+
'outline-of-science.txt' => 'http://www.gutenberg.org/files/20417/20417.txt',
|
11
|
+
'ulysses.txt' => 'http://www.gutenberg.org/dirs/etext03/ulyss12.txt',
|
12
|
+
'america.txt' => 'http://www.gutenberg.org/files/16960/16960.txt',
|
13
|
+
'da-vinci.txt' => 'http://www.gutenberg.org/dirs/etext04/7ldv110.txt'
|
14
|
+
}
|
15
|
+
|
16
|
+
books.each do |file, url|
|
17
|
+
pathfile = File.join(File.dirname(__FILE__),file)
|
18
|
+
`curl #{url} > #{pathfile}` unless File.exists?(pathfile)
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
books.keys.each do |book|
|
23
|
+
title = book.split('.')[0]
|
24
|
+
puts title
|
25
|
+
File.open(File.join(File.dirname(__FILE__),book),'r') do |file|
|
26
|
+
lines = []
|
27
|
+
chunk = 0
|
28
|
+
while line = file.gets
|
29
|
+
lines << line
|
30
|
+
if lines.length > 10
|
31
|
+
db.save({
|
32
|
+
:title => title,
|
33
|
+
:chunk => chunk,
|
34
|
+
:text => lines.join('')
|
35
|
+
})
|
36
|
+
chunk += 1
|
37
|
+
puts chunk
|
38
|
+
lines = []
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# 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."
|
45
|
+
|
46
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'couchrest'
|
3
|
+
|
4
|
+
couch = CouchRest.new("http://127.0.0.1:5984")
|
5
|
+
db = couch.database('word-count-example')
|
6
|
+
|
7
|
+
puts "Now that we've parsed all those books into CouchDB, the queries we can run are incredibly flexible."
|
8
|
+
puts "\nThe simplest query we can run is the total word count for all words in all documents:"
|
9
|
+
puts "this will take a few minutes the first time. if it times out, just rerun this script in a few few minutes."
|
10
|
+
puts db.view('word_count/words').inspect
|
11
|
+
|
12
|
+
puts "\nWe can also narrow the query down to just one word, across all documents. Here is the count for 'flight' in all three books:"
|
13
|
+
|
14
|
+
word = 'flight'
|
15
|
+
params = {
|
16
|
+
:startkey => [word],
|
17
|
+
:endkey => [word,{}]
|
18
|
+
}
|
19
|
+
|
20
|
+
puts db.view('word_count/words',params).inspect
|
21
|
+
|
22
|
+
puts "\nWe scope the query using startkey and endkey params to take advantage of CouchDB's collation ordering. Here are the params for the last query:"
|
23
|
+
puts params.inspect
|
24
|
+
|
25
|
+
puts "\nWe can also count words on a per-title basis."
|
26
|
+
|
27
|
+
title = 'da-vinci'
|
28
|
+
params = {
|
29
|
+
:key => [word, title]
|
30
|
+
}
|
31
|
+
|
32
|
+
puts db.view('word_count/words',params).inspect
|
33
|
+
|
34
|
+
|
35
|
+
puts "\nHere are the params for 'flight' in the da-vinci book:"
|
36
|
+
puts params.inspect
|
37
|
+
puts
|
38
|
+
puts 'The url looks like this:'
|
39
|
+
puts 'http://127.0.0.1:5984/word-count-example/_view/word_count/count?key=["flight","da-vinci"]'
|
40
|
+
puts "\nTry dropping that in your browser..."
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'couchrest'
|
3
|
+
|
4
|
+
couch = CouchRest.new("http://127.0.0.1:5984")
|
5
|
+
db = couch.database('word-count-example')
|
6
|
+
|
7
|
+
word_count = {
|
8
|
+
:map => 'function(doc){
|
9
|
+
var words = doc.text.split(/\W/);
|
10
|
+
words.forEach(function(word){
|
11
|
+
if (word.length > 0) emit([word,doc.title],1);
|
12
|
+
});
|
13
|
+
}',
|
14
|
+
:reduce => 'function(key,combine){
|
15
|
+
return sum(combine);
|
16
|
+
}'
|
17
|
+
}
|
18
|
+
|
19
|
+
db.delete db.get("_design/word_count") rescue nil
|
20
|
+
|
21
|
+
db.save({
|
22
|
+
"_id" => "_design/word_count",
|
23
|
+
:views => {
|
24
|
+
:words => word_count
|
25
|
+
}
|
26
|
+
})
|
data/lib/couchrest.rb
ADDED
@@ -0,0 +1,198 @@
|
|
1
|
+
# Copyright 2008 J. Chris Anderson
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require "rubygems"
|
16
|
+
gem 'yajl-ruby'
|
17
|
+
require 'yajl'
|
18
|
+
gem 'rest-client'
|
19
|
+
require 'rest_client'
|
20
|
+
|
21
|
+
$:.unshift File.dirname(__FILE__) unless
|
22
|
+
$:.include?(File.dirname(__FILE__)) ||
|
23
|
+
$:.include?(File.expand_path(File.dirname(__FILE__)))
|
24
|
+
|
25
|
+
$COUCHREST_DEBUG ||= false
|
26
|
+
|
27
|
+
require 'couchrest/monkeypatches'
|
28
|
+
|
29
|
+
# = CouchDB, close to the metal
|
30
|
+
module CouchRest
|
31
|
+
VERSION = '0.23' unless self.const_defined?("VERSION")
|
32
|
+
|
33
|
+
autoload :Server, 'couchrest/core/server'
|
34
|
+
autoload :Database, 'couchrest/core/database'
|
35
|
+
autoload :Response, 'couchrest/core/response'
|
36
|
+
autoload :Document, 'couchrest/core/document'
|
37
|
+
autoload :Design, 'couchrest/core/design'
|
38
|
+
autoload :View, 'couchrest/core/view'
|
39
|
+
autoload :Model, 'couchrest/core/model'
|
40
|
+
autoload :Pager, 'couchrest/helper/pager'
|
41
|
+
autoload :FileManager, 'couchrest/helper/file_manager'
|
42
|
+
autoload :Streamer, 'couchrest/helper/streamer'
|
43
|
+
autoload :Upgrade, 'couchrest/helper/upgrade'
|
44
|
+
|
45
|
+
autoload :ExtendedDocument, 'couchrest/more/extended_document'
|
46
|
+
autoload :CastedModel, 'couchrest/more/casted_model'
|
47
|
+
|
48
|
+
require File.join(File.dirname(__FILE__), 'couchrest', 'mixins')
|
49
|
+
|
50
|
+
# The CouchRest module methods handle the basic JSON serialization
|
51
|
+
# and deserialization, as well as query parameters. The module also includes
|
52
|
+
# some helpers for tasks like instantiating a new Database or Server instance.
|
53
|
+
class << self
|
54
|
+
|
55
|
+
# extracted from Extlib
|
56
|
+
#
|
57
|
+
# Constantize tries to find a declared constant with the name specified
|
58
|
+
# in the string. It raises a NameError when the name is not in CamelCase
|
59
|
+
# or is not initialized.
|
60
|
+
#
|
61
|
+
# @example
|
62
|
+
# "Module".constantize #=> Module
|
63
|
+
# "Class".constantize #=> Class
|
64
|
+
def constantize(camel_cased_word)
|
65
|
+
unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ camel_cased_word
|
66
|
+
raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!"
|
67
|
+
end
|
68
|
+
|
69
|
+
Object.module_eval("::#{$1}", __FILE__, __LINE__)
|
70
|
+
end
|
71
|
+
|
72
|
+
# extracted from Extlib
|
73
|
+
#
|
74
|
+
# Capitalizes the first word and turns underscores into spaces and strips _id.
|
75
|
+
# Like titleize, this is meant for creating pretty output.
|
76
|
+
#
|
77
|
+
# @example
|
78
|
+
# "employee_salary" #=> "Employee salary"
|
79
|
+
# "author_id" #=> "Author"
|
80
|
+
def humanize(lower_case_and_underscored_word)
|
81
|
+
lower_case_and_underscored_word.to_s.gsub(/_id$/, "").gsub(/_/, " ").capitalize
|
82
|
+
end
|
83
|
+
|
84
|
+
# todo, make this parse the url and instantiate a Server or Database instance
|
85
|
+
# depending on the specificity.
|
86
|
+
def new(*opts)
|
87
|
+
Server.new(*opts)
|
88
|
+
end
|
89
|
+
|
90
|
+
def parse url
|
91
|
+
case url
|
92
|
+
when /^http:\/\/(.*)\/(.*)\/(.*)/
|
93
|
+
host = $1
|
94
|
+
db = $2
|
95
|
+
docid = $3
|
96
|
+
when /^http:\/\/(.*)\/(.*)/
|
97
|
+
host = $1
|
98
|
+
db = $2
|
99
|
+
when /^http:\/\/(.*)/
|
100
|
+
host = $1
|
101
|
+
when /(.*)\/(.*)\/(.*)/
|
102
|
+
host = $1
|
103
|
+
db = $2
|
104
|
+
docid = $3
|
105
|
+
when /(.*)\/(.*)/
|
106
|
+
host = $1
|
107
|
+
db = $2
|
108
|
+
else
|
109
|
+
db = url
|
110
|
+
end
|
111
|
+
|
112
|
+
db = nil if db && db.empty?
|
113
|
+
|
114
|
+
{
|
115
|
+
:host => host || "127.0.0.1:5984",
|
116
|
+
:database => db,
|
117
|
+
:doc => docid
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
# set proxy for RestClient to use
|
122
|
+
def proxy url
|
123
|
+
RestClient.proxy = url
|
124
|
+
end
|
125
|
+
|
126
|
+
# ensure that a database exists
|
127
|
+
# creates it if it isn't already there
|
128
|
+
# returns it after it's been created
|
129
|
+
def database! url
|
130
|
+
parsed = parse url
|
131
|
+
cr = CouchRest.new(parsed[:host])
|
132
|
+
cr.database!(parsed[:database])
|
133
|
+
end
|
134
|
+
|
135
|
+
def database url
|
136
|
+
parsed = parse url
|
137
|
+
cr = CouchRest.new(parsed[:host])
|
138
|
+
cr.database(parsed[:database])
|
139
|
+
end
|
140
|
+
|
141
|
+
def put(uri, doc = nil)
|
142
|
+
payload = Yajl::Encoder.encode(doc) if doc
|
143
|
+
begin
|
144
|
+
Yajl::Parser.parse(RestClient.put(uri, payload))
|
145
|
+
rescue Exception => e
|
146
|
+
if $COUCHREST_DEBUG == true
|
147
|
+
raise "Error while sending a PUT request #{uri}\npayload: #{payload.inspect}\n#{e}"
|
148
|
+
else
|
149
|
+
raise e
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def get(uri)
|
155
|
+
begin
|
156
|
+
Yajl::Parser.parse(RestClient.get(uri), :max_nesting => false)
|
157
|
+
rescue => e
|
158
|
+
if $COUCHREST_DEBUG == true
|
159
|
+
raise "Error while sending a GET request #{uri}\n: #{e}"
|
160
|
+
else
|
161
|
+
raise e
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def post uri, doc = nil
|
167
|
+
payload = Yajl::Encoder.encode(doc) if doc
|
168
|
+
begin
|
169
|
+
Yajl::Parser.parse(RestClient.post(uri, payload))
|
170
|
+
rescue Exception => e
|
171
|
+
if $COUCHREST_DEBUG == true
|
172
|
+
raise "Error while sending a POST request #{uri}\npayload: #{payload.inspect}\n#{e}"
|
173
|
+
else
|
174
|
+
raise e
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def delete uri
|
180
|
+
Yajl::Parser.parse(RestClient.delete(uri))
|
181
|
+
end
|
182
|
+
|
183
|
+
def copy uri, destination
|
184
|
+
Yajl::Parser.parse(RestClient.copy(uri, {'Destination' => destination}))
|
185
|
+
end
|
186
|
+
|
187
|
+
def paramify_url url, params = {}
|
188
|
+
if params && !params.empty?
|
189
|
+
query = params.collect do |k,v|
|
190
|
+
v = Yajl::Encoder.encode(v) if %w{key startkey endkey}.include?(k.to_s)
|
191
|
+
"#{k}=#{CGI.escape(v.to_s)}"
|
192
|
+
end.join("&")
|
193
|
+
url = "#{url}?#{query}"
|
194
|
+
end
|
195
|
+
url
|
196
|
+
end
|
197
|
+
end # class << self
|
198
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module CouchRest
|
4
|
+
module Commands
|
5
|
+
module Generate
|
6
|
+
|
7
|
+
def self.run(options)
|
8
|
+
directory = options[:directory]
|
9
|
+
design_names = options[:trailing_args]
|
10
|
+
|
11
|
+
FileUtils.mkdir_p(directory)
|
12
|
+
filename = File.join(directory, "lib.js")
|
13
|
+
self.write(filename, <<-FUNC)
|
14
|
+
// Put global functions here.
|
15
|
+
// Include in your views with
|
16
|
+
//
|
17
|
+
// //include-lib
|
18
|
+
FUNC
|
19
|
+
|
20
|
+
design_names.each do |design_name|
|
21
|
+
subdirectory = File.join(directory, design_name)
|
22
|
+
FileUtils.mkdir_p(subdirectory)
|
23
|
+
filename = File.join(subdirectory, "sample-map.js")
|
24
|
+
self.write(filename, <<-FUNC)
|
25
|
+
function(doc) {
|
26
|
+
// Keys is first letter of _id
|
27
|
+
emit(doc._id[0], doc);
|
28
|
+
}
|
29
|
+
FUNC
|
30
|
+
|
31
|
+
filename = File.join(subdirectory, "sample-reduce.js")
|
32
|
+
self.write(filename, <<-FUNC)
|
33
|
+
function(keys, values) {
|
34
|
+
// Count the number of keys starting with this letter
|
35
|
+
return values.length;
|
36
|
+
}
|
37
|
+
FUNC
|
38
|
+
|
39
|
+
filename = File.join(subdirectory, "lib.js")
|
40
|
+
self.write(filename, <<-FUNC)
|
41
|
+
// Put functions specific to '#{design_name}' here.
|
42
|
+
// Include in your views with
|
43
|
+
//
|
44
|
+
// //include-lib
|
45
|
+
FUNC
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.help
|
50
|
+
helpstring = <<-GEN
|
51
|
+
|
52
|
+
Usage: couchview generate directory design1 design2 design3 ...
|
53
|
+
|
54
|
+
Couchview will create directories and example views for the design documents you specify.
|
55
|
+
|
56
|
+
GEN
|
57
|
+
helpstring.gsub(/^ /, '')
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.write(filename, contents)
|
61
|
+
puts "Writing #{filename}"
|
62
|
+
File.open(filename, "w") do |f|
|
63
|
+
# Remove leading spaces
|
64
|
+
contents.gsub!(/^ ( )?/, '')
|
65
|
+
f.write contents
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|