couch_tomato 0.1.5 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +166 -37
- data/README.md_old +96 -0
- data/lib/couch_tomato.rb +3 -0
- data/lib/couch_tomato/config.rb +11 -0
- data/lib/couch_tomato/database.rb +28 -55
- data/lib/couch_tomato/js_view_source.rb +102 -29
- data/lib/tasks/couch_tomato.thor +241 -0
- data/rails/init.rb +0 -4
- metadata +6 -2
data/README.md
CHANGED
@@ -1,88 +1,108 @@
|
|
1
|
-
Couch Tomato
|
2
|
-
|
1
|
+
#Couch Tomato
|
2
|
+
*A Ruby persistence layer for CouchDB, inspired by and forked from Couch Potato*
|
3
3
|
|
4
|
-
##
|
4
|
+
##Quick Start
|
5
|
+
###Installing Couch Tomato
|
6
|
+
Couch Tomato is hosted on [gemcutter.org](http://gemcutter.org), and can be installed as follows:
|
5
7
|
|
6
|
-
|
8
|
+
sudo gem install couch_tomato --source http://gemcutter.org
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
-
- Rake tasks that facilitate replication of local and remote CouchDB databases
|
11
|
-
- Removed model property dirty tracking (added significant complexity and we haven't needed it...yet?)
|
12
|
-
- Shoulda instead of RSpec
|
13
|
-
- RR for mocks/stubs
|
10
|
+
###Post Installation Requirements
|
11
|
+
`root` in a path refers to `Rails.root` if you are using Rails, and the root level of any Ruby project if you are not using Rails. With the couch\_tomato gem installed, enable the Thor tasks by creating a file `couch_tomato.thor` as shown below:
|
14
12
|
|
15
|
-
|
13
|
+
####couch\_tomato.thor
|
16
14
|
|
17
|
-
|
15
|
+
couch_tomato_gem = Gem.searcher.find('couch_tomato')
|
16
|
+
Dir["#{couch_tomato_gem.full_gem_path}/lib/tasks/*.thor"].each { |ext| load ext } if couch_tomato_gem
|
18
17
|
|
18
|
+
`couch_tomato.thor` can be saved to `Rails.root/lib/tasks` for Rails projects or to the root level of a regular Ruby app. Thor tasks associated with Couch Tomato are available under the `ct` namespace. To setup the Couch Tomato folder structure and config file in a Rails project, run the following:
|
19
19
|
|
20
|
-
|
20
|
+
thor ct:init
|
21
|
+
|
22
|
+
The above will create a folder `couchdb` in `root`, along with `root/couchdb/migrate` and `root/couchdb/views`. The init task will also generate a sample Couch Tomato config file `couch_tomato.yml.example` in `root/config` as given below:
|
21
23
|
|
22
|
-
|
24
|
+
####couch\_tomato.yml.example
|
23
25
|
|
24
|
-
|
26
|
+
defaults: &defaults
|
27
|
+
couchdb_address: 127.0.0.1
|
28
|
+
couchdb_port: 5984
|
29
|
+
couchdb_basename: your_project_name
|
30
|
+
|
31
|
+
development:
|
32
|
+
<<: *defaults
|
33
|
+
|
34
|
+
test:
|
35
|
+
<<: *defaults
|
36
|
+
|
37
|
+
production:
|
38
|
+
<<: *defaults
|
39
|
+
|
40
|
+
Modify `couchdb_address`, `couchdb_port`, and `couchdb_basename` to correspond to the ip/address, port number, and name of your project respectively. You can optionally choose to suffix all your databases names by adding a `couchdb_suffix` field. Rename/copy `couch_tomato.yml.example` to `couch_tomato.yml`.
|
41
|
+
|
42
|
+
Finally, you will need to populate the values in CouchTomato::Config. Put
|
25
43
|
|
44
|
+
CouchTomato::Config.set_config_yml path
|
45
|
+
|
46
|
+
somewhere in your app (i.e. in an initializer for Rails). This will load `couch_tomato.yml` into CouchTomato::Config. If path is not specified, Couch Tomato will look for the default `root/config/couch_tomato.yml`. If you chose to not create a `couch_tomato.yml`, you can populate the fields of `CouchTomato::Config` manually. Couch Tomato is now ready to be used.
|
47
|
+
|
48
|
+
##Using Couch Tomato
|
49
|
+
### Multi-Database Support
|
26
50
|
CouchDB makes it dead-simple to manage multiple databases. For large data-sets, it's very important to separate unrelated documents into separate databases. Couch Tomato assumes (but doesn't force) the use of multiple databases.
|
27
51
|
|
28
52
|
class UserDb < CouchTomato::Database
|
29
53
|
name "users"
|
30
|
-
|
54
|
+
...
|
31
55
|
end
|
32
56
|
|
33
57
|
class StatDb < CouchTomato::Database
|
34
|
-
|
35
|
-
server "http://#{APP_CONFIG["couchdb_address"]}:#{APP_CONFIG["couchdb_port"]}"
|
58
|
+
...
|
36
59
|
end
|
37
60
|
|
38
61
|
UserDb.save_doc(User.new({:name => 'Joe'}))
|
39
62
|
5_000.times { StatDb.save_doc(Stat.new({:metric => 10_000 * rand})) }
|
40
63
|
|
41
|
-
|
64
|
+
A name can be specified for a specific database as shown in UserDb, otherwise, the class name is used.
|
42
65
|
|
66
|
+
###Each view determines the model for its values
|
43
67
|
Views return arbitrary hashes. Often a view's value is an entire document (or more correctly, utilize `emit(key, null)` combined with `:include_docs => true`). But, a view's value is also often completely independent of the structure of the underlying documents.
|
44
68
|
|
45
69
|
Define views on the database rather than inside a model (this is arguably more Couch-like). Each views declaration stipulates whether their results should be 'raw' hashes or a particular model type.
|
46
70
|
|
47
71
|
class UserDb < CouchTomato::Database
|
48
72
|
name "users"
|
49
|
-
server "http://#{APP_CONFIG["couchdb_address"]}:#{APP_CONFIG["couchdb_port"]}"
|
50
73
|
|
51
74
|
view :by_created_at, User
|
52
75
|
view :count # raw
|
53
76
|
end
|
54
77
|
|
55
|
-
###
|
56
|
-
|
78
|
+
###Store view definitions on the file system
|
57
79
|
Rather than having Ruby generate JavaScript or writing JavaScript in our Ruby code as a string, define views in files on the file system:
|
58
80
|
|
59
|
-
|
60
|
-
|
81
|
+
root/couchdb/views/users/*-map.js
|
82
|
+
root/couchdb/views/users/*-reduce.js
|
61
83
|
|
62
84
|
The reduce is optional. If you want to define views in a specific design document (called 'lazy'), you can do so:
|
63
85
|
|
64
|
-
|
86
|
+
root/couchdb/views/users/lazy/*.js
|
65
87
|
|
66
88
|
There's a handy generator:
|
67
89
|
|
68
|
-
script/generate
|
69
|
-
script/generate
|
70
|
-
script/generate
|
71
|
-
|
72
|
-
Rake tasks apply the views on the file system to Couch, skipping views that aren't dirty:
|
90
|
+
script/generate couch_view users by_created_at
|
91
|
+
script/generate couch_view users/lazy by_birthday
|
92
|
+
script/generate couch_view users by_created_on map reduce
|
73
93
|
|
74
|
-
|
94
|
+
Thor tasks apply the views on the file system to CouchDb, skipping views that aren't dirty:
|
75
95
|
|
76
|
-
|
96
|
+
thor ct:push
|
77
97
|
|
78
|
-
|
98
|
+
You can also view the differences between the views in CouchDb and those on the file system:
|
79
99
|
|
80
|
-
|
100
|
+
thor ct:diff
|
81
101
|
|
102
|
+
###Remove dynamically generated views
|
82
103
|
We almost always need to write JavaScript to get the view behavior we need, and, for both conceptual and implementation complexity reasons, we value having all the views contained in one place--the file system. This also simplifies deployment and collaboration workflows.
|
83
104
|
|
84
|
-
###
|
85
|
-
|
105
|
+
###Multiple design documents per database
|
86
106
|
CouchDB supports multiple design documents per database. There's an important semantic consideration: all views in a design document are updated if any one view needs to be updated. To improve the read performance of couch views under high-volume reads and writes, you could organize views that don't need to be as timely into a separate design document named 'lazy', and always include the `stale=true` couch option in queries to views defined in the 'lazy' design document. You could then have a script that ran periodically to trigger the 'lazy' views to update.
|
87
107
|
|
88
108
|
class UserDb > CouchTomato::Database
|
@@ -93,4 +113,113 @@ CouchDB supports multiple design documents per database. There's an important se
|
|
93
113
|
view 'lazy/count_created_by_date'
|
94
114
|
end
|
95
115
|
|
96
|
-
|
116
|
+
###Migrations
|
117
|
+
Couch Tomato migrations are similar to ActiveRecord migrations, however, Couch Tomato migrations modify existing fields of documents instead of a "schema". There is a handy generator available for migrators as well.
|
118
|
+
|
119
|
+
script/generate couch_migration users by_created_at
|
120
|
+
|
121
|
+
Migration come with two methods, up and down, each with a document hash. Up/down method will be run on every document in a database, with changes to the document hash committed to a database if the method does not return false. A migration can be accessed by thor ct:migrate and the -v (version) option. The version is simply the prefixed number in front of the generated view file.
|
122
|
+
|
123
|
+
##Thor Tasks
|
124
|
+
All Thor tasks associated with Couch Tomato are available under the namespace "ct". The `-e` option specifies an environment (i.e. for Rails)
|
125
|
+
|
126
|
+
###ct:init
|
127
|
+
The init task creates the folder structure required for managing views and migrations and a sample `couch_tomato.yml`.
|
128
|
+
|
129
|
+
Example:
|
130
|
+
|
131
|
+
thor ct:init
|
132
|
+
|
133
|
+
###ct:push
|
134
|
+
The push tasks syncs CouchDB with the view structure present on the file system.
|
135
|
+
|
136
|
+
Example:
|
137
|
+
|
138
|
+
thor ct:push -e development
|
139
|
+
|
140
|
+
###ct:diff
|
141
|
+
The diff tasks `git status` type diff between the filesystem view structure and the current structure in CouchDB. The diff is with respect to the file system, that is, the file system is always assumed to be the most up to date.
|
142
|
+
|
143
|
+
Example:
|
144
|
+
|
145
|
+
thor ct:diff -e development
|
146
|
+
|
147
|
+
###ct:drop
|
148
|
+
The drop task will remove a specified database within the given environment from CouchDB. The -r option can be specified to remove via regex, and no arguments can be supplied to remove all databases.
|
149
|
+
|
150
|
+
Examples:
|
151
|
+
|
152
|
+
# Remove all databases (you will be prompted first)
|
153
|
+
thor ct:drop -e development
|
154
|
+
|
155
|
+
# Remove all databases ending "\_bak"
|
156
|
+
thor ct:drop -e development -r .*\_bak
|
157
|
+
|
158
|
+
###ct:migrate
|
159
|
+
The migrate tasks runs migrations from your `couchdb/migrate` folder.
|
160
|
+
|
161
|
+
Examples:
|
162
|
+
|
163
|
+
# Apply all migrations
|
164
|
+
thor ct:migrate -e development
|
165
|
+
|
166
|
+
# Undo migration "20090911201227"
|
167
|
+
thor ct:migrate -e development --down -v 20090911201227
|
168
|
+
|
169
|
+
# Redo the last 5 migrations
|
170
|
+
thor ct:migrate -e development --redo -s 5
|
171
|
+
|
172
|
+
# Reset all databases using all available migrations to the "development" environment
|
173
|
+
thor ct:migrate -e development --reset
|
174
|
+
|
175
|
+
###ct:rollback
|
176
|
+
The rollback tasks will revert to a previous migration from the current version. Specify the number of steps with the -s option.
|
177
|
+
|
178
|
+
Examples:
|
179
|
+
|
180
|
+
# Undo the previous migration
|
181
|
+
thor ct:rollback -e development
|
182
|
+
|
183
|
+
# Undo the last 5 migrations
|
184
|
+
thor ct:rollback -e development -s 5
|
185
|
+
|
186
|
+
###ct:forward
|
187
|
+
The forward task will roll forward to the next version. Specify the number of steps with the -s option.
|
188
|
+
|
189
|
+
Example:
|
190
|
+
|
191
|
+
# Roll forward to the next migration
|
192
|
+
thor ct:forward -e development
|
193
|
+
|
194
|
+
###ct:replicate
|
195
|
+
The replicate task facilitates the duplication of databases across application environments. The source and target server are always required for replication. Replicate operates in three different functions:
|
196
|
+
|
197
|
+
1. If a source and destination database are provided, then the source database from the source server will be copied onto the destination database on the target server. Note that the destination database needs to already have been created.
|
198
|
+
2. If not 1., but the the source and target servers are the same, then all databases on the common server are duplicated; the duplicate databases are postfixed with a "\_bak".
|
199
|
+
3. If neither 1. or 2., then the assumption is that the user wants to clone all databases from the remote source server onto the specified target server.
|
200
|
+
|
201
|
+
Examples:
|
202
|
+
|
203
|
+
# Copy database "example" from source server "11.11.11.11" to "example_1" in localhost
|
204
|
+
thor ct:replicate -e development -s 11.11.11.11 -t localhost -c example -v example_1
|
205
|
+
|
206
|
+
# Back up all databases in localhost
|
207
|
+
thor ct:replicate -e development -s localhost -t localhost
|
208
|
+
|
209
|
+
# Duplicate databases from "11.11.11.11" to localhost
|
210
|
+
thor ct:replicate -e development -s 11.11.11.11 -t localhost
|
211
|
+
|
212
|
+
###ct:touch
|
213
|
+
The touch task will initiate the building of views for a given database. Touch will query the first view of the each design doc in a db which will cause all remaining views to be built as well.
|
214
|
+
|
215
|
+
Examples:
|
216
|
+
|
217
|
+
# Build all design documents in databases "example" and "test"
|
218
|
+
thor ct:touch -e development -d example test
|
219
|
+
|
220
|
+
# Build all design documents in "example" and specify a 24 hours timeout
|
221
|
+
thor ct:touch -e development -d example -t 86400
|
222
|
+
|
223
|
+
# Build all design documents in "example" asynchronously
|
224
|
+
thor ct:touch -e development -d example --async
|
225
|
+
|
data/README.md_old
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
Couch Tomato
|
2
|
+
============
|
3
|
+
|
4
|
+
## TODO
|
5
|
+
|
6
|
+
### Documentation
|
7
|
+
|
8
|
+
- Quick start
|
9
|
+
- Data migration mechanism for managing (implicit) schema and data changes between team members and deployed systems, complete with generator and Rake tasks
|
10
|
+
- Rake tasks that facilitate replication of local and remote CouchDB databases
|
11
|
+
- Removed model property dirty tracking (added significant complexity and we haven't needed it...yet?)
|
12
|
+
- Shoulda instead of RSpec
|
13
|
+
- RR for mocks/stubs
|
14
|
+
|
15
|
+
### Code
|
16
|
+
|
17
|
+
- default "server" to `http://localhost:5984`
|
18
|
+
|
19
|
+
|
20
|
+
## Potato/Tomato
|
21
|
+
|
22
|
+
We're huge fans of Couch Potato. We love it's advocacy for using Couch naturally (not trying to make it look like a SQL database). Originally a Couch Potato fork, Couch Tomato supports our own production needs.
|
23
|
+
|
24
|
+
### Multi-Database Support
|
25
|
+
|
26
|
+
CouchDB makes it dead-simple to manage multiple databases. For large data-sets, it's very important to separate unrelated documents into separate databases. Couch Tomato assumes (but doesn't force) the use of multiple databases.
|
27
|
+
|
28
|
+
class UserDb < CouchTomato::Database
|
29
|
+
name "users"
|
30
|
+
server "http://#{APP_CONFIG["couchdb_address"]}:#{APP_CONFIG["couchdb_port"]}"
|
31
|
+
end
|
32
|
+
|
33
|
+
class StatDb < CouchTomato::Database
|
34
|
+
name "stats"
|
35
|
+
server "http://#{APP_CONFIG["couchdb_address"]}:#{APP_CONFIG["couchdb_port"]}"
|
36
|
+
end
|
37
|
+
|
38
|
+
UserDb.save_doc(User.new({:name => 'Joe'}))
|
39
|
+
5_000.times { StatDb.save_doc(Stat.new({:metric => 10_000 * rand})) }
|
40
|
+
|
41
|
+
### Each view determines the model for its values
|
42
|
+
|
43
|
+
Views return arbitrary hashes. Often a view's value is an entire document (or more correctly, utilize `emit(key, null)` combined with `:include_docs => true`). But, a view's value is also often completely independent of the structure of the underlying documents.
|
44
|
+
|
45
|
+
Define views on the database rather than inside a model (this is arguably more Couch-like). Each views declaration stipulates whether their results should be 'raw' hashes or a particular model type.
|
46
|
+
|
47
|
+
class UserDb < CouchTomato::Database
|
48
|
+
name "users"
|
49
|
+
server "http://#{APP_CONFIG["couchdb_address"]}:#{APP_CONFIG["couchdb_port"]}"
|
50
|
+
|
51
|
+
view :by_created_at, User
|
52
|
+
view :count # raw
|
53
|
+
end
|
54
|
+
|
55
|
+
### Store view definitions on the file system
|
56
|
+
|
57
|
+
Rather than having Ruby generate JavaScript or writing JavaScript in our Ruby code as a string, define views in files on the file system:
|
58
|
+
|
59
|
+
RAILS_ROOT/couchdb/views/users/*-map.js
|
60
|
+
RAILS_ROOT/couchdb/views/users/*-reduce.js
|
61
|
+
|
62
|
+
The reduce is optional. If you want to define views in a specific design document (called 'lazy'), you can do so:
|
63
|
+
|
64
|
+
RAILS_ROOT/couchdb/views/users/lazy/*.js
|
65
|
+
|
66
|
+
There's a handy generator:
|
67
|
+
|
68
|
+
script/generate view users by_created_at
|
69
|
+
script/generate view users/lazy by_birthday
|
70
|
+
script/generate view users by_created_on map reduce
|
71
|
+
|
72
|
+
Rake tasks apply the views on the file system to Couch, skipping views that aren't dirty:
|
73
|
+
|
74
|
+
rake couch_tomato:push
|
75
|
+
|
76
|
+
You can also view the differences between the views in Couch and those on the file system:
|
77
|
+
|
78
|
+
rake couch_tomato:diff
|
79
|
+
|
80
|
+
### Remove dynamically generated views
|
81
|
+
|
82
|
+
We almost always need to write JavaScript to get the view behavior we need, and, for both conceptual and implementation complexity reasons, we value having all the views contained in one place--the file system. This also simplifies deployment and collaboration workflows.
|
83
|
+
|
84
|
+
### Multiple design documents per database
|
85
|
+
|
86
|
+
CouchDB supports multiple design documents per database. There's an important semantic consideration: all views in a design document are updated if any one view needs to be updated. To improve the read performance of couch views under high-volume reads and writes, you could organize views that don't need to be as timely into a separate design document named 'lazy', and always include the `stale=true` couch option in queries to views defined in the 'lazy' design document. You could then have a script that ran periodically to trigger the 'lazy' views to update.
|
87
|
+
|
88
|
+
class UserDb > CouchTomato::Database
|
89
|
+
name :users
|
90
|
+
|
91
|
+
view :by_created_at, User
|
92
|
+
view :count # raw
|
93
|
+
view 'lazy/count_created_by_date'
|
94
|
+
end
|
95
|
+
|
96
|
+
We have not had a use for this, nor have we demonstrated that the claimed performance benefit actually exists (it originated from the CouchDB docs, wiki or list or some-such). But, it is instance where this approach to representing views maps fairly directly to CouchDB functionality.
|
data/lib/couch_tomato.rb
CHANGED
@@ -2,6 +2,7 @@ require 'couchrest'
|
|
2
2
|
require 'json'
|
3
3
|
require 'json/add/core'
|
4
4
|
require 'json/add/rails'
|
5
|
+
require 'active_support'
|
5
6
|
|
6
7
|
# require 'ostruct'
|
7
8
|
|
@@ -42,5 +43,7 @@ require File.dirname(__FILE__) + '/core_ext/symbol'
|
|
42
43
|
require File.dirname(__FILE__) + '/core_ext/extract_options'
|
43
44
|
require File.dirname(__FILE__) + '/core_ext/duplicable'
|
44
45
|
require File.dirname(__FILE__) + '/core_ext/inheritable_attributes'
|
46
|
+
require File.dirname(__FILE__) + '/couch_tomato/config'
|
45
47
|
require File.dirname(__FILE__) + '/couch_tomato/persistence'
|
46
48
|
require File.dirname(__FILE__) + '/couch_tomato/js_view_source'
|
49
|
+
|
@@ -1,73 +1,48 @@
|
|
1
|
-
require
|
2
|
-
require 'pp'
|
1
|
+
require "couchrest"
|
3
2
|
|
4
3
|
module CouchTomato
|
5
4
|
class Database
|
6
|
-
|
7
5
|
class ValidationsFailedError < ::StandardError; end
|
8
6
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
7
|
+
class << self
|
8
|
+
attr_accessor :url
|
9
|
+
attr_accessor :prefix
|
10
|
+
attr_accessor :suffix
|
11
|
+
attr_accessor :name
|
12
|
+
attr_accessor :views
|
15
13
|
|
16
|
-
|
17
|
-
|
14
|
+
attr_accessor :couchrest_db
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.inherited(c)
|
18
|
+
c.url = CouchTomato::Config.url
|
19
|
+
c.prefix = CouchTomato::Config.prefix
|
20
|
+
c.suffix = CouchTomato::Config.suffix
|
21
|
+
c.name = c.to_s.underscore
|
22
|
+
c.views = {}
|
23
|
+
end
|
18
24
|
|
19
25
|
def self.database
|
20
26
|
return self.couchrest_db if self.couchrest_db
|
21
|
-
|
22
|
-
self.prefix_string ||= ''
|
23
27
|
|
24
|
-
|
25
|
-
|
26
|
-
|
28
|
+
path = "#{self.url.gsub(/\/\s*$/, "")}/#{([self.prefix.to_s, self.name, self.suffix.to_s] - [""]).join("_")}"
|
29
|
+
|
30
|
+
self.couchrest_db = CouchRest.database(path)
|
27
31
|
|
28
|
-
self.couchrest_db = CouchRest.database("#{tmp_server}#{tmp_prefix}#{self.database_name}#{tmp_suffix}")
|
29
32
|
begin
|
30
33
|
self.couchrest_db.info
|
31
34
|
rescue RestClient::ResourceNotFound
|
32
|
-
raise "Database '#{
|
35
|
+
raise "Database '#{path}' does not exist."
|
33
36
|
end
|
34
|
-
|
35
|
-
self.couchrest_db
|
36
|
-
end
|
37
37
|
|
38
|
-
|
39
|
-
self.prefix_string = name || ''
|
38
|
+
return self.couchrest_db
|
40
39
|
end
|
41
|
-
def self.name (name)
|
42
|
-
raise 'You need to provide a database name' if name.nil?
|
43
|
-
self.database_name = (name.class == Symbol)? name.to_s : name
|
44
|
-
end
|
45
|
-
|
46
|
-
# TODO: specify db=>host mapping in yaml, and allow to differ per environment
|
47
|
-
def self.server (route='http://127.0.0.1:5984/')
|
48
|
-
self.database_server = route
|
49
|
-
|
50
|
-
# self.prefix_string ||= ''
|
51
|
-
#
|
52
|
-
# tmp_prefix = self.prefix_string + '_' unless self.prefix_string.empty?
|
53
|
-
# tmp_server = self.database_server + '/' unless self.database_server.match(/\/$/)
|
54
|
-
# tmp_suffix = '_' + Rails.env if defined?(Rails)
|
55
|
-
#
|
56
|
-
#
|
57
|
-
# self.couchrest_db ||= CouchRest.database("#{tmp_server}#{tmp_prefix}#{self.database_name}#{tmp_suffix}")
|
58
|
-
# begin
|
59
|
-
# self.couchrest_db.info
|
60
|
-
# rescue RestClient::ResourceNotFound
|
61
|
-
# raise "Database '#{tmp_prefix}#{self.database_name}#{tmp_suffix}' does not exist."
|
62
|
-
# end
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
40
|
|
67
41
|
def self.view(name, options={})
|
68
|
-
raise
|
42
|
+
raise "A View nemonic must be specified" if name.nil?
|
43
|
+
|
69
44
|
self.views[name] = {}
|
70
|
-
self.views[name][:design_doc] = !options[:design_doc] ? self.
|
45
|
+
self.views[name][:design_doc] = !options[:design_doc] ? self.name.to_sym : options.delete(:design_doc).to_sym
|
71
46
|
self.views[name][:view_name] = options.delete(:view_name) || name.to_s
|
72
47
|
self.views[name][:model] = options.delete(:model)
|
73
48
|
self.views[name][:couch_options] = options
|
@@ -149,11 +124,9 @@ module CouchTomato
|
|
149
124
|
end
|
150
125
|
|
151
126
|
def self.inspect
|
152
|
-
|
153
|
-
puts
|
154
|
-
puts
|
155
|
-
puts 'Views:'
|
156
|
-
pp self.views
|
127
|
+
puts "Database server: #{self.url || "nil"}"
|
128
|
+
puts "Database name: #{self.name || "nil"}"
|
129
|
+
puts "Views: #{self.views.inspect}"
|
157
130
|
end
|
158
131
|
|
159
132
|
def self.query_view!(name, options={})
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'digest/sha1'
|
2
|
+
require 'patron'
|
2
3
|
|
4
|
+
STDOUT.sync = true
|
3
5
|
module CouchTomato
|
4
6
|
class JsViewSource
|
5
7
|
# todo: provide a 'dirty?' method that can be called in an initializer and warn the developer that view are out of sync
|
@@ -22,11 +24,11 @@ module CouchTomato
|
|
22
24
|
|
23
25
|
if fs_doc['views'].empty?
|
24
26
|
next unless fs_doc['_rev']
|
25
|
-
puts "DELETE #{fs_doc['_id']}" unless silent
|
27
|
+
puts "DELETE #{database_name}/#{fs_doc['_id']}" unless silent
|
26
28
|
db.delete_doc(fs_doc)
|
27
29
|
else
|
28
30
|
if changed_views?(fs_doc, db_doc)
|
29
|
-
puts "UPDATE #{fs_doc['_id']}" unless silent
|
31
|
+
puts "UPDATE #{database_name}/#{fs_doc['_id']}" unless silent
|
30
32
|
db.save_doc(fs_doc)
|
31
33
|
end
|
32
34
|
end
|
@@ -48,22 +50,36 @@ module CouchTomato
|
|
48
50
|
end
|
49
51
|
|
50
52
|
def self.diff
|
53
|
+
status_dict = {
|
54
|
+
:NEW_DOC => "new design:", :NEW_VIEW => "new view:",
|
55
|
+
:MOD_VIEW => "modified:", :DEL_DOC => "deleted:",
|
56
|
+
:DEL_VIEW => "deleted:", :NEW_DB => "new db:"
|
57
|
+
}
|
58
|
+
types = ["map", "reduce"]
|
59
|
+
puts "# Changes with respect to the filesystem:"
|
60
|
+
|
51
61
|
fs_database_names.each do |database_name|
|
52
|
-
db = database
|
53
|
-
|
62
|
+
db = database(database_name)
|
63
|
+
puts "#\t#{setw(status_dict[:NEW_DB], 14)}#{database_name}" unless is_db?(db)
|
64
|
+
|
54
65
|
fs_docs = fs_design_docs(database_name)
|
55
|
-
db_docs = db_design_docs(db)
|
66
|
+
db_docs = is_db?(db) ? db_design_docs(db) : {}
|
56
67
|
|
68
|
+
diff = []
|
57
69
|
# design docs on fs but not in db
|
58
70
|
(fs_docs.keys - db_docs.keys).each do |design_name|
|
59
71
|
unless fs_docs[design_name]['views'].empty?
|
60
|
-
|
72
|
+
diff.push [:NEW_DOC, "#{database_name}/_#{design_name}"]
|
73
|
+
fs_docs[design_name]['views'].keys.each do |view|
|
74
|
+
(fs_docs[design_name]['views'][view].keys & types).each {|type|
|
75
|
+
diff.push [:NEW_VIEW, "#{database_name}/_#{design_name}/#{view}-#{type}"]}
|
76
|
+
end
|
61
77
|
end
|
62
78
|
end
|
63
79
|
|
64
80
|
# design docs in db but not on fs
|
65
81
|
(db_docs.keys - fs_docs.keys).each do |design_name|
|
66
|
-
|
82
|
+
diff.push [:DEL_DOC, "#{database_name}/_#{design_name}"] unless (design_name.to_s.include? "migrations")
|
67
83
|
end
|
68
84
|
|
69
85
|
# design docs in both db and fs
|
@@ -74,16 +90,16 @@ module CouchTomato
|
|
74
90
|
|
75
91
|
unless fs_only_view_keys.empty?
|
76
92
|
methods = fs_only_view_keys.map do |key|
|
77
|
-
%w(map reduce).map {|method| fs_docs[design_name]['views'][key][method].nil? ? nil : "#{key}
|
93
|
+
%w(map reduce).map {|method| fs_docs[design_name]['views'][key][method].nil? ? nil : "#{key}-#{method}"}.compact
|
78
94
|
end.flatten
|
79
|
-
|
95
|
+
methods.each {|method| diff.push [:NEW_VIEW, "#{database_name}/_#{design_name}/#{method}"] }
|
80
96
|
end
|
81
97
|
|
82
98
|
unless db_only_view_keys.empty?
|
83
99
|
methods = db_only_view_keys.map do |key|
|
84
|
-
%w(map reduce).map {|method| db_docs[design_name]['views'][key][method] ? "#{key}
|
100
|
+
%w(map reduce).map {|method| db_docs[design_name]['views'][key][method] ? "#{key}-#{method}" : nil}.compact
|
85
101
|
end
|
86
|
-
|
102
|
+
methods.each {|method| diff.push [:DEL_VIEW, "#{database_name}/_#{design_name}/#{method}"] }
|
87
103
|
end
|
88
104
|
|
89
105
|
common_view_keys.each do |common_key|
|
@@ -95,28 +111,36 @@ module CouchTomato
|
|
95
111
|
# has either the map or reduce been added or removed
|
96
112
|
%w(map reduce).each do |method|
|
97
113
|
if db_view[method] && !fs_view[method]
|
98
|
-
|
114
|
+
diff.push [:DEL_VIEW, "#{database_name}/_#{design_name}/#{common_key}-#{method}"] and next
|
99
115
|
end
|
100
116
|
|
101
117
|
if fs_view[method] && !db_view[method]
|
102
|
-
|
118
|
+
diff.push [:NEW_VIEW, "#{database_name}/_#{design_name}/#{common_key}-#{method}"] and next
|
103
119
|
end
|
104
120
|
|
105
121
|
if fs_view["sha1-#{method}"] != db_view["sha1-#{method}"]
|
106
|
-
|
122
|
+
diff.push [:MOD_VIEW, "#{database_name}/_#{design_name}/#{common_key}-#{method}"] and next
|
107
123
|
end
|
108
124
|
end
|
109
125
|
end
|
110
|
-
|
111
126
|
end
|
112
|
-
|
127
|
+
|
128
|
+
diff.uniq!
|
129
|
+
diff.each do |status|
|
130
|
+
puts "#\t#{setw(status_dict[status.first], 14)}#{status.last}"
|
131
|
+
end
|
113
132
|
end
|
114
133
|
end
|
115
134
|
|
116
135
|
private
|
136
|
+
|
137
|
+
def self.setw(str, w)
|
138
|
+
spaces = w - str.length
|
139
|
+
(spaces > 0) ? str + (" " * spaces) : str
|
140
|
+
end
|
117
141
|
|
118
142
|
def self.path(db_name="")
|
119
|
-
"#{Rails.root}/couchdb/views/#{db_name}"
|
143
|
+
"#{Rails.root rescue nil || "."}/couchdb/views/#{db_name}"
|
120
144
|
end
|
121
145
|
|
122
146
|
def self.fs_database_names
|
@@ -136,14 +160,17 @@ module CouchTomato
|
|
136
160
|
# :clicks => {'by_date' => {'map' => ..., 'reduce' => ..., sha1-map => ..., sha1-reduce => ...} }
|
137
161
|
def self.fs_design_docs(db_name)
|
138
162
|
design_docs = {}
|
139
|
-
|
140
|
-
path = "#{
|
141
|
-
Dir[path
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
163
|
+
|
164
|
+
path = "#{Rails.root rescue nil || "."}/couchdb/views/#{db_name}"
|
165
|
+
doc_folders = Dir["#{path}/**/"].map {|ddoc| ddoc.chop! }
|
166
|
+
doc_folders.each do |design_doc|
|
167
|
+
(Dir["#{design_doc}/**"] - doc_folders).each do |file|
|
168
|
+
throw "Invalid filename '#{File.basename(file)}': expecting '-map.js' or '-reduce.js' suffix" unless file.match(/-((map)|(reduce))\.js$/)
|
169
|
+
|
170
|
+
design_name = File.basename(design_doc)
|
171
|
+
design_docs[design_name.to_sym] ||= {'_id' => "_design/#{design_name}", 'views' => {}}
|
172
|
+
fs_view(design_docs[design_name.to_sym], file)
|
173
|
+
end
|
147
174
|
end
|
148
175
|
|
149
176
|
design_docs.each do |db, design|
|
@@ -172,12 +199,58 @@ module CouchTomato
|
|
172
199
|
design_doc['views'][name]["sha1-#{type}"] = sha1
|
173
200
|
design_doc
|
174
201
|
end
|
202
|
+
|
203
|
+
def self.touch(dbs, async=false, timeout=nil)
|
204
|
+
s = Patron::Session.new
|
205
|
+
s.timeout = timeout.nil? ? 86400 : timeout.to_i
|
206
|
+
s.timeout = 1 if async
|
207
|
+
|
208
|
+
dbs.each do |db_str|
|
209
|
+
db = database(db_str)
|
210
|
+
design_docs = db_design_docs(db)
|
211
|
+
|
212
|
+
design_docs.each do |ddoc_sym, ddoc|
|
213
|
+
puts ddoc_sym.to_s
|
214
|
+
next if ddoc_sym.to_s == "migrations"
|
215
|
+
doc_id = ddoc["_id"]
|
216
|
+
view = ddoc["views"].keys.first
|
217
|
+
|
218
|
+
print "Building #{db_str}/#{doc_id}... "
|
219
|
+
begin
|
220
|
+
s.get("#{db_url(db_str)}/#{doc_id}/_view/#{view}?limit=0")
|
221
|
+
puts "finished!"
|
222
|
+
rescue Patron::TimeoutError
|
223
|
+
if async
|
224
|
+
puts "task started asynchronously."
|
225
|
+
else
|
226
|
+
puts "the view could not be built within the specified timeout (#{s.timeout} seconds). The view is still being built in the background."
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
175
232
|
|
176
|
-
|
177
|
-
|
178
|
-
CouchRest.database!("http://" + APP_CONFIG["couchdb_address"] + ":" + APP_CONFIG["couchdb_port"].to_s \
|
179
|
-
+ "/" + APP_CONFIG["couchdb_basename"] + "_" + database_name + "_" + RAILS_ENV)
|
233
|
+
def self.db_url(name)
|
234
|
+
"#{CouchTomato::Config.url.gsub(/\/\s*$/, "")}/#{([CouchTomato::Config.prefix.to_s, name, CouchTomato::Config.suffix.to_s] - [""]).join("_")}"
|
180
235
|
end
|
181
236
|
|
237
|
+
def self.database(database_name, force=false)
|
238
|
+
raise "Database names (#{database_name}) cannot contain uppercase letters." unless database_name == database_name.downcase
|
239
|
+
url = db_url(database_name)
|
240
|
+
force ? CouchRest.database!(url) : CouchRest.database(url)
|
241
|
+
end
|
242
|
+
|
243
|
+
def self.database!(database_name)
|
244
|
+
database(database_name, true);
|
245
|
+
end
|
246
|
+
|
247
|
+
def self.is_db?(db)
|
248
|
+
begin
|
249
|
+
db.info
|
250
|
+
rescue
|
251
|
+
return false
|
252
|
+
end
|
253
|
+
return true
|
254
|
+
end
|
182
255
|
end
|
183
256
|
end
|
@@ -0,0 +1,241 @@
|
|
1
|
+
Ct_Yml_Example = %(defaults: &defaults
|
2
|
+
couchdb_address: 127.0.0.1
|
3
|
+
couchdb_port: 5984
|
4
|
+
couchdb_basename: your_project_name
|
5
|
+
|
6
|
+
development:
|
7
|
+
<<: *defaults
|
8
|
+
|
9
|
+
test:
|
10
|
+
<<: *defaults
|
11
|
+
|
12
|
+
production:
|
13
|
+
<<: *defaults
|
14
|
+
)
|
15
|
+
|
16
|
+
STDOUT.sync = true
|
17
|
+
class CouchTomatoApp < Thor
|
18
|
+
include Thor::Actions
|
19
|
+
namespace :ct
|
20
|
+
|
21
|
+
desc 'init', 'Sets up the required structure for Couch Tomato'
|
22
|
+
def init
|
23
|
+
load_env
|
24
|
+
project_root = ::Rails.root rescue nil || "."
|
25
|
+
|
26
|
+
ct_yml_path = "#{project_root}/config/couch_tomato.yml.example"
|
27
|
+
couch_folder = "#{project_root}/couchdb"
|
28
|
+
|
29
|
+
print "Generating a sample couch_tomato yml... "
|
30
|
+
unless File.exist?(ct_yml_path)
|
31
|
+
FileUtils.mkdir "#{project_root}/config"
|
32
|
+
File.open(ct_yml_path, 'w') {|f| f.write(Ct_Yml_Example) }
|
33
|
+
puts "#{ct_yml_path} created"
|
34
|
+
else
|
35
|
+
puts "#{ct_yml_path} already exists"
|
36
|
+
end
|
37
|
+
|
38
|
+
print "Generating the couchdb folder.......... "
|
39
|
+
puts (File.directory? couch_folder) ? "#{couch_folder} already exists" : "#{FileUtils.mkdir "#{couch_folder}"} created"
|
40
|
+
print "Generating couchdb/migrate............. "
|
41
|
+
puts (File.directory? "#{couch_folder}/migrate") ? "#{couch_folder}/migrate already exists" : "#{FileUtils.mkdir "#{couch_folder}/migrate"} created"
|
42
|
+
print "Generating couchdb/views............... "
|
43
|
+
puts (File.directory? "#{couch_folder}/views") ? "#{couch_folder}/views already exists" : "#{FileUtils.mkdir "#{couch_folder}/views"} created"
|
44
|
+
end
|
45
|
+
|
46
|
+
desc 'push', 'Inserts the views into CouchDB'
|
47
|
+
method_options %w(RAILS_ENV -e) => :string
|
48
|
+
def push
|
49
|
+
load_env(options)
|
50
|
+
CouchTomato::JsViewSource.push
|
51
|
+
end
|
52
|
+
|
53
|
+
desc 'diff', 'Compares views in DB and the File System'
|
54
|
+
method_options %w(RAILS_ENV -e) => :string
|
55
|
+
def diff
|
56
|
+
load_env(options)
|
57
|
+
CouchTomato::JsViewSource.diff
|
58
|
+
end
|
59
|
+
|
60
|
+
desc 'drop', 'Drops databases for the current RAILS_ENV; ' +
|
61
|
+
'If no databases are specified, user will be prompted if all databases should be removed; ' +
|
62
|
+
'If the -r option is specified, all databases matching the regex will be dropped.'
|
63
|
+
method_options %w(RAILS_ENV -e) => :string, %w(DBS -d) => :array, %w(REGEX -r) => :string
|
64
|
+
def drop
|
65
|
+
load_env(options)
|
66
|
+
dbs = options["DBS"]
|
67
|
+
rm_all = false
|
68
|
+
rm_all = (yes? "Drop all databases?") if (options['REGEX'].nil? && dbs.nil?)
|
69
|
+
|
70
|
+
regex = Regexp.new(options['REGEX'].to_s)
|
71
|
+
databases(dbs) do |db, dir|
|
72
|
+
if (rm_all || db.name == db.name[regex]) && is_db?(db)
|
73
|
+
db.delete!
|
74
|
+
puts "Dropped #{db.name}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
desc 'migrate', 'Runs migrations'
|
80
|
+
method_options %w(RAILS_ENV -e) => :string, %w(VERSION -v) => :string, %w(STEP -s) => :string,
|
81
|
+
:redo => :boolean, :reset => :boolean, :up => :boolean, :down => :boolean
|
82
|
+
def migrate
|
83
|
+
load_env(options)
|
84
|
+
supported_args = %w(redo reset up down)
|
85
|
+
action = supported_args & options.keys
|
86
|
+
raise "Cannot provide more than one action." if action.length > 1
|
87
|
+
|
88
|
+
action = (action.empty?) ? nil : action.first
|
89
|
+
case action
|
90
|
+
when nil
|
91
|
+
migrate_helper
|
92
|
+
#Rollbacks the database one migration and re migrate up. If you want to rollback more than one step, define STEP=x. Target specific version with VERSION=x.
|
93
|
+
when "redo"
|
94
|
+
if ENV['VERSION']
|
95
|
+
down_helper
|
96
|
+
up_helper
|
97
|
+
else
|
98
|
+
rollback_helper
|
99
|
+
migrate_helper
|
100
|
+
end
|
101
|
+
#Resets your database using your migrations for the current environment
|
102
|
+
when "reset"
|
103
|
+
invoke :drop
|
104
|
+
invoke :push
|
105
|
+
migrate_helper
|
106
|
+
#Runs the "up" for a given migration VERSION.
|
107
|
+
when "up"
|
108
|
+
up_helper
|
109
|
+
#Runs the "down" for a given migration VERSION.
|
110
|
+
when "down"
|
111
|
+
down_helper
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
desc 'rollback', 'Rolls back to the previous version. Specify the number of steps with STEP=n'
|
116
|
+
method_options %w(RAILS_ENV -e) => :string, %w(STEP -s) => :string
|
117
|
+
def rollback
|
118
|
+
load_env(options)
|
119
|
+
rollback_helper
|
120
|
+
end
|
121
|
+
|
122
|
+
desc 'forward', 'Rolls forward to the next version. Specify the number of steps with STEP=n'
|
123
|
+
method_options %w(RAILS_ENV -e) => :string, %w(STEP -s) => :string
|
124
|
+
def forward
|
125
|
+
load_env(options)
|
126
|
+
databases do |db, dir|
|
127
|
+
CouchTomato::Migrator.forward(db, dir, ENV['STEP'] ? ENV['STEP'].to_i : 1)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
desc 'replicate', 'Replicate databases between app environments'
|
132
|
+
method_options %w(RAILS_ENV -e) => :string, %w(SRC_DB -c) => :string,
|
133
|
+
%w(DST_DB -v) => :string , %w(SRC_SERVER -s) => :string , %w(DST_SERVER -t) => :string
|
134
|
+
def replicate
|
135
|
+
load_env(options)
|
136
|
+
src_server, dst_server = servers
|
137
|
+
|
138
|
+
src_db = options['SRC_DB']
|
139
|
+
dst_db = options['DST_DB'] || (src_server == dst_server ? "#{src_db}_bak" : src_db)
|
140
|
+
|
141
|
+
replicator = CouchTomato::Replicator.new(src_server, dst_server)
|
142
|
+
|
143
|
+
if src_db
|
144
|
+
puts "== Replicating '#{src_server}/#{src_db}' to '#{dst_server}/#{dst_db}'"
|
145
|
+
replicator.replicate(src_db, dst_db)
|
146
|
+
elsif src_server == dst_server
|
147
|
+
puts "== Replicating all databases at '#{src_server}' using '_bak' suffix for replicated database names"
|
148
|
+
replicator.replicate_all('_bak')
|
149
|
+
else
|
150
|
+
puts "== Replicating all databases from '#{src_server}' to '#{dst_server}'"
|
151
|
+
replicator.replicate_all
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
desc 'touch', 'Initiates the building of a design document'
|
156
|
+
method_options %w(RAILS_ENV -e) => :string, %w(DBS -d) => :array, :async => :boolean, %w(TIMEOUT -t) => :numeric
|
157
|
+
def touch
|
158
|
+
load_env(options)
|
159
|
+
view_path = "couchdb/views"
|
160
|
+
valid_dbs = options["DBS"] & (Dir["couchdb/views/**"].map {|db| File.basename(db) })
|
161
|
+
CouchTomato::JsViewSource.touch(valid_dbs, options.async?, options['TIMEOUT'])
|
162
|
+
end
|
163
|
+
|
164
|
+
private
|
165
|
+
def up_helper
|
166
|
+
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
|
167
|
+
raise 'VERSION is required' unless version
|
168
|
+
|
169
|
+
databases do |db, dir|
|
170
|
+
CouchTomato::Migrator.run(:up, db, dir, version)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def down_helper
|
175
|
+
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
|
176
|
+
raise 'VERSION is required' unless version
|
177
|
+
|
178
|
+
databases do |db, dir|
|
179
|
+
CouchTomato::Migrator.run(:down, db, dir, version)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def rollback_helper
|
184
|
+
databases do |db, dir|
|
185
|
+
CouchTomato::Migrator.rollback(db, dir, ENV['STEP'] ? ENV['STEP'].to_i : 1)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def migrate_helper
|
190
|
+
databases do |db, dir|
|
191
|
+
CouchTomato::Migrator.migrate(db, dir, ENV['VERSION'] ? ENV['VERSION'].to_i : nil)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def load_env(options=nil)
|
196
|
+
unless (Rails rescue nil)
|
197
|
+
print "Loading enviornment... "
|
198
|
+
%w(RAILS_ENV VERSION SRC_SERVER DST_SERVER STEP).each {|var| ENV[var] =
|
199
|
+
options[var] unless options[var].nil? } unless options.nil?
|
200
|
+
|
201
|
+
begin
|
202
|
+
require(File.join(ENV['PWD'], 'config', 'boot'))
|
203
|
+
require(File.join(ENV['PWD'], 'config', 'environment'))
|
204
|
+
puts "done."
|
205
|
+
rescue LoadError
|
206
|
+
puts "could not find environment files. Assuming direct use."
|
207
|
+
ensure
|
208
|
+
CouchTomato::Config.set_config_yml unless CouchTomato::Config.loaded?
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def servers
|
214
|
+
local_server = "http://#{CouchTomato::Config.couch_address}:#{CouchTomato::Config.couch_port}"
|
215
|
+
src_server = (ENV['SRC_SERVER'] || local_server).gsub(/\s*\/\s*$/, '')
|
216
|
+
dst_server = (ENV['DST_SERVER'] || local_server).gsub(/\s*\/\s*$/, '')
|
217
|
+
|
218
|
+
return src_server, dst_server
|
219
|
+
end
|
220
|
+
|
221
|
+
def databases(db_names=nil)
|
222
|
+
dirs = Dir['couchdb/migrate/*']
|
223
|
+
|
224
|
+
db_map = dirs.inject({}) {|map, dir| map[File.basename(dir)] = dir; map }
|
225
|
+
db_names ||= db_map.keys
|
226
|
+
db_names.each do |db_name|
|
227
|
+
db = CouchTomato::JsViewSource.database(db_name)
|
228
|
+
yield db, db_map[db_name]
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def is_db?(db)
|
233
|
+
begin
|
234
|
+
db.info
|
235
|
+
rescue
|
236
|
+
return false
|
237
|
+
end
|
238
|
+
return true
|
239
|
+
end
|
240
|
+
|
241
|
+
end
|
data/rails/init.rb
CHANGED
@@ -1,7 +1,3 @@
|
|
1
1
|
# this is for rails only
|
2
|
-
|
3
2
|
require File.dirname(__FILE__) + '/../lib/couch_tomato'
|
4
|
-
|
5
|
-
# CouchTomato::Config.database_name = YAML::load(File.read(Rails.root.to_s + '/config/couchdb.yml'))[RAILS_ENV]
|
6
|
-
|
7
3
|
RAILS_DEFAULT_LOGGER.info "** couch_tomato: initialized from #{__FILE__}"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: couch_tomato
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Plastic Trophy
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-01-21 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -50,9 +50,11 @@ extensions: []
|
|
50
50
|
|
51
51
|
extra_rdoc_files:
|
52
52
|
- README.md
|
53
|
+
- README.md_old
|
53
54
|
files:
|
54
55
|
- MIT-LICENSE.txt
|
55
56
|
- README.md
|
57
|
+
- README.md_old
|
56
58
|
- generators/couch_migration/couch_migration_generator.rb
|
57
59
|
- generators/couch_migration/templates/migration.rb
|
58
60
|
- generators/couch_view/couch_view_generator.rb
|
@@ -68,6 +70,7 @@ files:
|
|
68
70
|
- lib/core_ext/symbol.rb
|
69
71
|
- lib/core_ext/time.rb
|
70
72
|
- lib/couch_tomato.rb
|
73
|
+
- lib/couch_tomato/config.rb
|
71
74
|
- lib/couch_tomato/database.rb
|
72
75
|
- lib/couch_tomato/js_view_source.rb
|
73
76
|
- lib/couch_tomato/migration.rb
|
@@ -84,6 +87,7 @@ files:
|
|
84
87
|
- lib/couch_tomato/persistence/validation.rb
|
85
88
|
- lib/couch_tomato/replicator.rb
|
86
89
|
- lib/tasks/couch_tomato.rake
|
90
|
+
- lib/tasks/couch_tomato.thor
|
87
91
|
- rails/init.rb
|
88
92
|
has_rdoc: true
|
89
93
|
homepage: http://github.com/plastictrophy/couch_tomato
|