couch_potato 0.2.12 → 0.2.13
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/CHANGES.md +8 -0
- data/README.md +33 -4
- data/VERSION.yml +2 -2
- data/lib/couch_potato/database.rb +31 -14
- data/lib/couch_potato/persistence/json.rb +1 -1
- data/lib/couch_potato/persistence/properties.rb +30 -1
- data/lib/couch_potato/persistence/simple_property.rb +5 -5
- data/lib/couch_potato/persistence/validation.rb +7 -1
- data/lib/couch_potato/rspec/matchers/map_to_matcher.rb +125 -0
- data/lib/couch_potato/rspec/matchers/print_r.js +60 -0
- data/lib/couch_potato/rspec/matchers/reduce_to_matcher.rb +6 -0
- data/lib/couch_potato/rspec/matchers.rb +2 -0
- data/lib/couch_potato/view/custom_view_spec.rb +5 -1
- data/lib/couch_potato/view/custom_views.rb +12 -3
- data/lib/couch_potato/view/model_view_spec.rb +1 -3
- data/lib/couch_potato/view/view_query.rb +1 -1
- data/lib/couch_potato.rb +2 -1
- data/spec/attachments_spec.rb +1 -1
- data/spec/callbacks_spec.rb +34 -0
- data/spec/create_spec.rb +1 -1
- data/spec/custom_view_spec.rb +17 -0
- data/spec/fixtures/person.rb +2 -2
- data/spec/property_spec.rb +55 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/unit/database_spec.rb +164 -7
- data/spec/unit/dirty_attributes_spec.rb +3 -3
- data/spec/unit/json_create_id_spec.rb +14 -0
- data/spec/unit/rspec_matchers_spec.rb +97 -0
- data/spec/update_spec.rb +1 -1
- metadata +10 -2
data/CHANGES.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
## Changes
|
2
2
|
|
3
|
+
### 0.2.13
|
4
|
+
|
5
|
+
* support adding errors in before_validation callbacks (mattmatt)
|
6
|
+
* support for inheritance (mattmatt)
|
7
|
+
* support for save without validations (mattmatt)
|
8
|
+
* improved (de)serialization now supports deserializing nested objects (railsbros, specs by hagenburger)
|
9
|
+
* RSpec matchers for testing map/reduce functions (langalex)
|
10
|
+
|
3
11
|
### 0.2.10
|
4
12
|
* fixed bug with hardcoded timezone
|
5
13
|
|
data/README.md
CHANGED
@@ -22,13 +22,11 @@ Lastly Couch Potato aims to provide a seamless integration with Ruby on Rails, e
|
|
22
22
|
|
23
23
|
Couch Potato is hosted as a gem on github which you can install like this:
|
24
24
|
|
25
|
-
sudo gem
|
26
|
-
sudo gem install langalex-couch_potato
|
25
|
+
sudo gem install couch_potato --source http://gemcutter.org
|
27
26
|
|
28
27
|
#### Using with your ruby application:
|
29
28
|
|
30
29
|
require 'rubygems'
|
31
|
-
gem 'langalex-couch_potato'
|
32
30
|
require 'couch_potato'
|
33
31
|
|
34
32
|
Alternatively you can download or clone the source repository and then require lib/couch_potato.rb.
|
@@ -45,7 +43,8 @@ The server URL will default to http://localhost:5984/ unless specified:
|
|
45
43
|
|
46
44
|
Add to your config/environment.rb:
|
47
45
|
|
48
|
-
config.gem '
|
46
|
+
config.gem 'couch_potato', :source => 'http://gemcutter.org'
|
47
|
+
config.frameworks -= [:active_record] # if you switch completely
|
49
48
|
|
50
49
|
Then create a config/couchdb.yml:
|
51
50
|
|
@@ -282,6 +281,36 @@ To make testing easier and faster database logic has been put into its own class
|
|
282
281
|
|
283
282
|
By creating you own instances of CouchPotato::Database and passing them a fake CouchRest database instance you can completely disconnect your unit tests/spec from the database.
|
284
283
|
|
284
|
+
##### Testing map/reduce functions
|
285
|
+
|
286
|
+
Couch Potato provides custom RSpec matchers for testing the map and reduce functions of your views. For example you can do this:
|
287
|
+
|
288
|
+
Class User
|
289
|
+
include CouchPotato::Persistence
|
290
|
+
|
291
|
+
view :by_name, :key => :name
|
292
|
+
view :by_age, :key => :age
|
293
|
+
end
|
294
|
+
|
295
|
+
#RSpec
|
296
|
+
describe User, 'by_name' do
|
297
|
+
it "should map users to their name" do
|
298
|
+
User.by_name.should map({:name => 'bill', :age => 23}).to([['bill', null]])
|
299
|
+
end
|
300
|
+
|
301
|
+
it "should reduce the users to the sum of their age" do
|
302
|
+
User.by_age.should reduce([], [[23], [22]]).to(45)
|
303
|
+
end
|
304
|
+
|
305
|
+
it "should rereduce" do
|
306
|
+
User.by_age.should rereduce([], [[23], [22]]).to(45)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
This will actually run your map/reduce functions in a JavaScript interpreter, passing the arguments as JSON and converting the results back to Ruby.
|
311
|
+
|
312
|
+
In order for this to work you must have the `js` executable in your PATH. This is usually part of the _spidermonkey_ package/port. (On MacPorts that's _spidemonkey_, on Linux it could be one of _libjs_, _libmozjs_ or _libspidermonkey_). When you installed CouchDB via your packet manager Spidermonkey should already be there.
|
313
|
+
|
285
314
|
### Helping out
|
286
315
|
|
287
316
|
Please fix bugs, add more specs, implement new features by forking the github repo at http://github.com/langalex/couch_potato.
|
data/VERSION.yml
CHANGED
@@ -19,12 +19,13 @@ module CouchPotato
|
|
19
19
|
spec.process_results results
|
20
20
|
end
|
21
21
|
|
22
|
-
|
22
|
+
|
23
|
+
def save_document(document, validate = true)
|
23
24
|
return true unless document.dirty?
|
24
25
|
if document.new?
|
25
|
-
create_document
|
26
|
+
create_document(document, validate)
|
26
27
|
else
|
27
|
-
update_document
|
28
|
+
update_document(document, validate)
|
28
29
|
end
|
29
30
|
end
|
30
31
|
alias_method :save, :save_document
|
@@ -47,9 +48,7 @@ module CouchPotato
|
|
47
48
|
def load_document(id)
|
48
49
|
raise "Can't load a document without an id (got nil)" if id.nil?
|
49
50
|
begin
|
50
|
-
|
51
|
-
klass = json['ruby_class'].split('::').inject(Class){|scope, const| scope.const_get(const)}
|
52
|
-
instance = klass.json_create json
|
51
|
+
instance = database.get(id)
|
53
52
|
instance.database = self
|
54
53
|
instance
|
55
54
|
rescue(RestClient::ResourceNotFound)
|
@@ -70,11 +69,16 @@ module CouchPotato
|
|
70
69
|
end
|
71
70
|
end
|
72
71
|
|
73
|
-
def create_document(document)
|
72
|
+
def create_document(document, validate)
|
74
73
|
document.database = self
|
75
|
-
|
76
|
-
|
77
|
-
|
74
|
+
|
75
|
+
if validate
|
76
|
+
document.errors.clear
|
77
|
+
document.run_callbacks :before_validation_on_save
|
78
|
+
document.run_callbacks :before_validation_on_create
|
79
|
+
return false unless valid_document?(document)
|
80
|
+
end
|
81
|
+
|
78
82
|
document.run_callbacks :before_save
|
79
83
|
document.run_callbacks :before_create
|
80
84
|
res = database.save_doc clean_hash(document.to_hash)
|
@@ -85,10 +89,14 @@ module CouchPotato
|
|
85
89
|
true
|
86
90
|
end
|
87
91
|
|
88
|
-
def update_document(document)
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
+
def update_document(document, validate)
|
93
|
+
if validate
|
94
|
+
document.errors.clear
|
95
|
+
document.run_callbacks :before_validation_on_save
|
96
|
+
document.run_callbacks :before_validation_on_update
|
97
|
+
return false unless valid_document?(document)
|
98
|
+
end
|
99
|
+
|
92
100
|
document.run_callbacks :before_save
|
93
101
|
document.run_callbacks :before_update
|
94
102
|
res = database.save_doc clean_hash(document.to_hash)
|
@@ -98,6 +106,15 @@ module CouchPotato
|
|
98
106
|
true
|
99
107
|
end
|
100
108
|
|
109
|
+
def valid_document?(document)
|
110
|
+
errors = document.errors.errors.dup
|
111
|
+
document.valid?
|
112
|
+
errors.each do |k, v|
|
113
|
+
v.each {|message| document.errors.add(k, message)}
|
114
|
+
end
|
115
|
+
document.errors.empty?
|
116
|
+
end
|
117
|
+
|
101
118
|
def database
|
102
119
|
@database
|
103
120
|
end
|
@@ -15,7 +15,7 @@ module CouchPotato
|
|
15
15
|
(self.class.properties).inject({}) do |props, property|
|
16
16
|
property.serialize(props, self)
|
17
17
|
props
|
18
|
-
end.merge(
|
18
|
+
end.merge(JSON.create_id => self.class.name).merge(id_and_rev_json)
|
19
19
|
end
|
20
20
|
|
21
21
|
private
|
@@ -3,12 +3,41 @@ require File.dirname(__FILE__) + '/simple_property'
|
|
3
3
|
module CouchPotato
|
4
4
|
module Persistence
|
5
5
|
module Properties
|
6
|
+
class PropertyList
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
attr_accessor :list
|
10
|
+
|
11
|
+
def initialize(clazz)
|
12
|
+
@clazz = clazz
|
13
|
+
@list = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def each
|
17
|
+
(list + inherited_properties).each {|property| yield property}
|
18
|
+
end
|
19
|
+
|
20
|
+
def <<(property)
|
21
|
+
@list << property
|
22
|
+
end
|
23
|
+
|
24
|
+
def inherited_properties
|
25
|
+
superclazz = @clazz.superclass
|
26
|
+
properties = []
|
27
|
+
while superclazz && superclazz.respond_to?(:properties)
|
28
|
+
properties << superclazz.properties.list
|
29
|
+
superclazz = superclazz.superclass
|
30
|
+
end
|
31
|
+
properties.flatten
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
6
35
|
def self.included(base)
|
7
36
|
base.extend ClassMethods
|
8
37
|
base.class_eval do
|
9
38
|
def self.properties
|
10
39
|
@properties ||= {}
|
11
|
-
@properties[
|
40
|
+
@properties[name] ||= PropertyList.new(self)
|
12
41
|
end
|
13
42
|
end
|
14
43
|
end
|
@@ -12,11 +12,11 @@ module CouchPotato
|
|
12
12
|
|
13
13
|
def build(object, json)
|
14
14
|
value = json[name.to_s] || json[name.to_sym]
|
15
|
-
typecast_value = if type
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
typecast_value = if type && !value.instance_of?(type)
|
16
|
+
type.json_create value
|
17
|
+
else
|
18
|
+
value
|
19
|
+
end
|
20
20
|
object.send "#{name}=", typecast_value
|
21
21
|
end
|
22
22
|
|
@@ -8,8 +8,14 @@ module CouchPotato
|
|
8
8
|
base.class_eval do
|
9
9
|
# Override the validate method to first run before_validation callback
|
10
10
|
def valid?
|
11
|
-
|
11
|
+
errors.clear
|
12
|
+
run_callbacks :before_validation
|
13
|
+
before_validation_errors = errors.errors.dup
|
12
14
|
super
|
15
|
+
before_validation_errors.each do |k, v|
|
16
|
+
v.each {|message| errors.add(k, message)}
|
17
|
+
end
|
18
|
+
errors.empty?
|
13
19
|
end
|
14
20
|
end
|
15
21
|
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Spec
|
4
|
+
module Matchers
|
5
|
+
def map(document)
|
6
|
+
CouchPotato::RSpec::MapToProxy.new(document)
|
7
|
+
end
|
8
|
+
|
9
|
+
def reduce(docs, keys)
|
10
|
+
CouchPotato::RSpec::ReduceToProxy.new(docs, keys)
|
11
|
+
end
|
12
|
+
|
13
|
+
def rereduce(docs, keys)
|
14
|
+
CouchPotato::RSpec::ReduceToProxy.new(docs, keys, true)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module CouchPotato
|
20
|
+
module RSpec
|
21
|
+
|
22
|
+
module RunJS
|
23
|
+
private
|
24
|
+
|
25
|
+
def run_js(js)
|
26
|
+
path = 'couch_potato_js_runner.js'
|
27
|
+
File.open(path, 'w') {|f| f << js}
|
28
|
+
`js #{path}`
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
class MapToProxy
|
34
|
+
def initialize(input_ruby)
|
35
|
+
@input_ruby = input_ruby
|
36
|
+
end
|
37
|
+
|
38
|
+
def to(expected_ruby)
|
39
|
+
MapToMatcher.new(expected_ruby, @input_ruby)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class MapToMatcher
|
44
|
+
include RunJS
|
45
|
+
|
46
|
+
def initialize(expected_ruby, input_ruby)
|
47
|
+
@expected_ruby = expected_ruby
|
48
|
+
@input_ruby = input_ruby
|
49
|
+
end
|
50
|
+
|
51
|
+
def matches?(view_spec)
|
52
|
+
js = <<-JS
|
53
|
+
#{File.read(File.dirname(__FILE__) + '/print_r.js')}
|
54
|
+
var doc = #{@input_ruby.to_json};
|
55
|
+
var map = #{view_spec.map_function};
|
56
|
+
var result = [];
|
57
|
+
var emit = function(key, value) {
|
58
|
+
result.push([key, value]);
|
59
|
+
};
|
60
|
+
map(doc);
|
61
|
+
print(print_r(result));
|
62
|
+
JS
|
63
|
+
@actual_ruby = JSON.parse(run_js(js))
|
64
|
+
@expected_ruby == @actual_ruby
|
65
|
+
end
|
66
|
+
|
67
|
+
def failure_message_for_should
|
68
|
+
"Expected to map to #{@expected_ruby.inspect} but got #{@actual_ruby.inspect}."
|
69
|
+
end
|
70
|
+
|
71
|
+
def failure_message_for_should_not
|
72
|
+
"Expected not to map to #{@actual_ruby.inspect} but did."
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class ReduceToProxy
|
77
|
+
def initialize(docs, keys, rereduce = false)
|
78
|
+
@docs, @keys, @rereduce = docs, keys, rereduce
|
79
|
+
end
|
80
|
+
|
81
|
+
def to(expected_ruby)
|
82
|
+
ReduceToMatcher.new(expected_ruby, @docs, @keys, @rereduce)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class ReduceToMatcher
|
87
|
+
include RunJS
|
88
|
+
|
89
|
+
def initialize(expected_ruby, docs, keys, rereduce = false)
|
90
|
+
@expected_ruby, @docs, @keys, @rereduce = expected_ruby, docs, keys, rereduce
|
91
|
+
end
|
92
|
+
|
93
|
+
def matches?(view_spec)
|
94
|
+
js = <<-JS
|
95
|
+
#{File.read(File.dirname(__FILE__) + '/print_r.js')}
|
96
|
+
|
97
|
+
sum = function(values) {
|
98
|
+
var rv = 0;
|
99
|
+
for (var i in values) {
|
100
|
+
rv += values[i];
|
101
|
+
}
|
102
|
+
return rv;
|
103
|
+
};
|
104
|
+
|
105
|
+
var docs = #{@docs.to_json};
|
106
|
+
var keys = #{@keys.to_json};
|
107
|
+
var reduce = #{view_spec.reduce_function};
|
108
|
+
print(print_r({result: reduce(docs, keys, #{@rereduce})}));
|
109
|
+
JS
|
110
|
+
@actual_ruby = JSON.parse(run_js(js))['result']
|
111
|
+
@expected_ruby == @actual_ruby
|
112
|
+
end
|
113
|
+
|
114
|
+
def failure_message_for_should
|
115
|
+
"Expected to reduce to #{@expected_ruby.inspect} but got #{@actual_ruby.inspect}."
|
116
|
+
end
|
117
|
+
|
118
|
+
def failure_message_for_should_not
|
119
|
+
"Expected not to reduce to #{@actual_ruby.inspect} but did."
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
// taken and adapted from http://scriptnode.com/article/javascript-print_r-or-var_dump-equivalent/
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Concatenates the values of a variable into an easily readable string
|
5
|
+
* by Matt Hackett [scriptnode.com]
|
6
|
+
* @param {Object} x The variable to debug
|
7
|
+
* @param {Number} max The maximum number of recursions allowed (keep low, around 5 for HTML elements to prevent errors) [default: 10]
|
8
|
+
* @param {String} sep The separator to use between [default: a single space ' ']
|
9
|
+
* @param {Number} l The current level deep (amount of recursion). Do not use this parameter: it's for the function's own use
|
10
|
+
*/
|
11
|
+
function print_r(x, max, sep, l) {
|
12
|
+
|
13
|
+
l = l || 0;
|
14
|
+
max = max || 10;
|
15
|
+
sep = sep || ' ';
|
16
|
+
|
17
|
+
if (l > max) {
|
18
|
+
throw("Too much recursion");
|
19
|
+
};
|
20
|
+
|
21
|
+
var r = '';
|
22
|
+
|
23
|
+
if (x === null) {
|
24
|
+
r += "null";
|
25
|
+
} else if (is_array(x)) {
|
26
|
+
r += '[' + x.map(function(i) {
|
27
|
+
return print_r(i, max, sep, (l + 1));
|
28
|
+
}).join(', ') + ']';
|
29
|
+
} else if(is_object(x)) {
|
30
|
+
r += '{'
|
31
|
+
var pairs = [];
|
32
|
+
for (i in x) {
|
33
|
+
pairs.push('"' + i + '": ' + print_r(x[i], max, sep, (l + 1)));
|
34
|
+
}
|
35
|
+
r += pairs.join(', ');
|
36
|
+
r += '}';
|
37
|
+
} else if(is_string(x)) {
|
38
|
+
r += '"' + x + "\"";
|
39
|
+
} else {
|
40
|
+
r += x;
|
41
|
+
};
|
42
|
+
|
43
|
+
return r;
|
44
|
+
|
45
|
+
function is_string(a) {
|
46
|
+
return typeof a === 'string';
|
47
|
+
};
|
48
|
+
|
49
|
+
function is_array(a) {
|
50
|
+
return (a &&
|
51
|
+
typeof a === 'object' &&
|
52
|
+
a.constructor === Array);
|
53
|
+
};
|
54
|
+
|
55
|
+
function is_object(a) {
|
56
|
+
return a && typeof a == 'object'
|
57
|
+
};
|
58
|
+
|
59
|
+
};
|
60
|
+
|
@@ -19,7 +19,11 @@ module CouchPotato
|
|
19
19
|
|
20
20
|
def process_results(results)
|
21
21
|
results['rows'].map do |row|
|
22
|
-
|
22
|
+
if row['doc'].instance_of?(klass)
|
23
|
+
row['doc']
|
24
|
+
else
|
25
|
+
klass.json_create row['doc'] || row['value'].merge(:_id => row['id'] || row['key'])
|
26
|
+
end
|
23
27
|
end
|
24
28
|
end
|
25
29
|
end
|
@@ -15,12 +15,16 @@ module CouchPotato
|
|
15
15
|
|
16
16
|
module ClassMethods
|
17
17
|
# Declare a CouchDB view, for examples on how to use see the *ViewSpec classes in CouchPotato::View
|
18
|
-
def views
|
19
|
-
|
18
|
+
def views(view_name = nil)
|
19
|
+
if view_name
|
20
|
+
_find_view(view_name)
|
21
|
+
else
|
22
|
+
@views ||= {}
|
23
|
+
end
|
20
24
|
end
|
21
25
|
|
22
26
|
def execute_view(view_name, view_parameters)
|
23
|
-
view_spec_class(views
|
27
|
+
view_spec_class(views(view_name)[:type]).new(self, view_name, views(view_name), view_parameters)
|
24
28
|
end
|
25
29
|
|
26
30
|
def view(view_name, options)
|
@@ -38,6 +42,11 @@ module CouchPotato
|
|
38
42
|
CouchPotato::View.const_get("#{name}ViewSpec")
|
39
43
|
end
|
40
44
|
end
|
45
|
+
|
46
|
+
def _find_view(view)
|
47
|
+
return @views[view] if @views && @views[view]
|
48
|
+
superclass._find_view(view) if superclass && superclass.respond_to?(:_find_view)
|
49
|
+
end
|
41
50
|
end
|
42
51
|
end
|
43
52
|
end
|
@@ -23,7 +23,7 @@ module CouchPotato
|
|
23
23
|
|
24
24
|
def create_view
|
25
25
|
design_doc = @database.get "_design/#{@design_document_name}" rescue nil
|
26
|
-
design_doc ||= {'views' => {}, "_id" => "_design/#{@design_document_name}"}
|
26
|
+
design_doc ||= {'views' => {}, "_id" => "_design/#{@design_document_name}", "language" => "javascript"}
|
27
27
|
design_doc['views'][@view_name.to_s] = {
|
28
28
|
'map' => @map_function,
|
29
29
|
'reduce' => @reduce_function
|
data/lib/couch_potato.rb
CHANGED
@@ -5,6 +5,7 @@ require 'json/add/rails'
|
|
5
5
|
|
6
6
|
require 'ostruct'
|
7
7
|
|
8
|
+
JSON.create_id = 'ruby_class'
|
8
9
|
|
9
10
|
module CouchPotato
|
10
11
|
Config = Struct.new(:database_name).new
|
@@ -23,7 +24,7 @@ module CouchPotato
|
|
23
24
|
|
24
25
|
def self.full_url_to_database
|
25
26
|
raise('No Database configured. Set CouchPotato::Config.database_name') unless CouchPotato::Config.database_name
|
26
|
-
if CouchPotato::Config.database_name
|
27
|
+
if CouchPotato::Config.database_name.match(%r{https?://})
|
27
28
|
CouchPotato::Config.database_name
|
28
29
|
else
|
29
30
|
"http://127.0.0.1:5984/#{CouchPotato::Config.database_name}"
|
data/spec/attachments_spec.rb
CHANGED
@@ -13,7 +13,7 @@ describe CouchPotato, 'attachments' do
|
|
13
13
|
comment._attachments = {'body' => {'data' => 'a useful comment', 'content_type' => 'text/plain'}}
|
14
14
|
CouchPotato.database.save! comment
|
15
15
|
comment_reloaded = CouchPotato.database.load comment.id
|
16
|
-
comment_reloaded._attachments
|
16
|
+
comment_reloaded._attachments["body"].should include({"content_type" => "text/plain", "stub" => true, "length" => 16})
|
17
17
|
end
|
18
18
|
|
19
19
|
it "should have an empty array for a new object" do
|
data/spec/callbacks_spec.rb
CHANGED
@@ -268,4 +268,38 @@ describe "lambda callbacks" do
|
|
268
268
|
recorder.run_callbacks :before_create
|
269
269
|
recorder.lambda_works.should be_true
|
270
270
|
end
|
271
|
+
end
|
272
|
+
|
273
|
+
describe "validation callbacks" do
|
274
|
+
class ValidatedUser
|
275
|
+
include CouchPotato::Persistence
|
276
|
+
|
277
|
+
property :name
|
278
|
+
before_validation :check_name
|
279
|
+
validates_presence_of :name
|
280
|
+
|
281
|
+
def check_name
|
282
|
+
errors.add(:name, 'should be Paul') unless name == "Paul"
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
it "should keep error messages set in custom before_validation filters" do
|
287
|
+
user = ValidatedUser.new(:name => "john")
|
288
|
+
user.valid?.should == false
|
289
|
+
user.errors.on(:name).should == "should be Paul"
|
290
|
+
end
|
291
|
+
|
292
|
+
it "should combine the errors from validations and callbacks" do
|
293
|
+
user = ValidatedUser.new(:name => nil)
|
294
|
+
user.valid?.should == false
|
295
|
+
user.errors.on(:name).should == ["can't be empty", "should be Paul"]
|
296
|
+
end
|
297
|
+
|
298
|
+
it "should clear the errors on subsequent calls to valid?" do
|
299
|
+
user = ValidatedUser.new(:name => nil)
|
300
|
+
user.valid?.should == false
|
301
|
+
user.name = 'Paul'
|
302
|
+
user.valid?.should == true
|
303
|
+
user.errors.on(:name).should == nil
|
304
|
+
end
|
271
305
|
end
|
data/spec/create_spec.rb
CHANGED
@@ -8,7 +8,7 @@ describe "create" do
|
|
8
8
|
it "should store the class" do
|
9
9
|
@comment = Comment.new :title => 'my_title'
|
10
10
|
CouchPotato.database.save_document! @comment
|
11
|
-
CouchPotato.couchrest_database.get(@comment.id)
|
11
|
+
CouchPotato.couchrest_database.get(@comment.id).ruby_class.should == 'Comment'
|
12
12
|
end
|
13
13
|
end
|
14
14
|
describe "fails" do
|
data/spec/custom_view_spec.rb
CHANGED
@@ -18,6 +18,9 @@ class Build
|
|
18
18
|
view :with_view_options, :group => true, :key => :time
|
19
19
|
end
|
20
20
|
|
21
|
+
class CustomBuild < Build
|
22
|
+
end
|
23
|
+
|
21
24
|
describe 'view' do
|
22
25
|
before(:each) do
|
23
26
|
recreate_db
|
@@ -108,6 +111,13 @@ describe 'view' do
|
|
108
111
|
CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
|
109
112
|
CouchPotato.database.view(Build.custom_timeline_returns_docs).map(&:state).should == ['success']
|
110
113
|
end
|
114
|
+
|
115
|
+
it "should still return instance of class if document included 'ruby_class'" do
|
116
|
+
CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01', :ruby_class => "Build"})
|
117
|
+
view_data = CouchPotato.database.view(Build.custom_timeline_returns_docs)
|
118
|
+
view_data.map(&:class).should == [Build]
|
119
|
+
view_data.map(&:state).should == ['success']
|
120
|
+
end
|
111
121
|
end
|
112
122
|
|
113
123
|
describe "additional reduce function given" do
|
@@ -146,4 +156,11 @@ describe 'view' do
|
|
146
156
|
end
|
147
157
|
end
|
148
158
|
|
159
|
+
describe "inherited views" do
|
160
|
+
it "should support parent views for objects of the subclass" do
|
161
|
+
CouchPotato.database.save_document CustomBuild.new(:state => 'success', :time => '2008-01-01')
|
162
|
+
CouchPotato.database.view(CustomBuild.timeline).should have(1).item
|
163
|
+
CouchPotato.database.view(CustomBuild.timeline).first.should be_kind_of(CustomBuild)
|
164
|
+
end
|
165
|
+
end
|
149
166
|
end
|
data/spec/fixtures/person.rb
CHANGED
data/spec/property_spec.rb
CHANGED
@@ -18,6 +18,9 @@ class Watch
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
+
class CuckooClock < Watch
|
22
|
+
property :cuckoo
|
23
|
+
end
|
21
24
|
|
22
25
|
describe 'properties' do
|
23
26
|
before(:all) do
|
@@ -57,6 +60,45 @@ describe 'properties' do
|
|
57
60
|
c.title.should == {'key' => 'value'}
|
58
61
|
end
|
59
62
|
|
63
|
+
def it_should_persist value
|
64
|
+
c = Comment.new :title => value
|
65
|
+
CouchPotato.database.save_document! c
|
66
|
+
c = CouchPotato.database.load_document c.id
|
67
|
+
c.title.should == value
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should persist a child class" do
|
71
|
+
it_should_persist Child.new('text' => 'some text')
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should persist a hash with a child class" do
|
75
|
+
it_should_persist 'child' => Child.new('text' => 'some text')
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should persist an array with a child class" do
|
79
|
+
it_should_persist [Child.new('text' => 'some text')]
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should persist something very complex" do
|
83
|
+
something_very_complex = [
|
84
|
+
[
|
85
|
+
[
|
86
|
+
{
|
87
|
+
'what' => [
|
88
|
+
{
|
89
|
+
'ever' => Child.new('text' => 'some text')
|
90
|
+
}
|
91
|
+
],
|
92
|
+
'number' => 3
|
93
|
+
},
|
94
|
+
"string"
|
95
|
+
],
|
96
|
+
Child.new('text' => 'nothing')
|
97
|
+
]
|
98
|
+
]
|
99
|
+
it_should_persist something_very_complex
|
100
|
+
end
|
101
|
+
|
60
102
|
it "should persist a Time object" do
|
61
103
|
w = Watch.new :time => Time.now
|
62
104
|
CouchPotato.database.save_document! w
|
@@ -98,4 +140,17 @@ describe 'properties' do
|
|
98
140
|
Comment.new(:title => '').title?.should be_false
|
99
141
|
end
|
100
142
|
end
|
143
|
+
|
144
|
+
describe "with subclasses" do
|
145
|
+
it "should include properties of superclasses" do
|
146
|
+
CuckooClock.properties.map(&:name).should include(:time)
|
147
|
+
CuckooClock.properties.map(&:name).should include(:cuckoo)
|
148
|
+
end
|
149
|
+
|
150
|
+
it "should return attributes of superclasses" do
|
151
|
+
clock = CuckooClock.new(:time => Time.now, :cuckoo => 'bavarian')
|
152
|
+
clock.attributes[:time].should_not == nil
|
153
|
+
clock.attributes[:cuckoo].should == 'bavarian'
|
154
|
+
end
|
155
|
+
end
|
101
156
|
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/unit/database_spec.rb
CHANGED
@@ -18,6 +18,32 @@ describe CouchPotato::Database, 'new' do
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
+
describe CouchPotato::Database, 'full_url_to_database' do
|
22
|
+
before(:all) do
|
23
|
+
@database_url = CouchPotato::Config.database_name
|
24
|
+
end
|
25
|
+
|
26
|
+
after(:all) do
|
27
|
+
CouchPotato::Config.database_name = @database_url
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should return the full URL when it starts with https" do
|
31
|
+
CouchPotato::Config.database_name = "https://example.com/database"
|
32
|
+
CouchPotato.full_url_to_database.should == 'https://example.com/database'
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should return the full URL when it starts with http" do
|
36
|
+
CouchPotato::Config.database_name = "http://example.com/database"
|
37
|
+
CouchPotato.full_url_to_database.should == 'http://example.com/database'
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should use localhost when no protocol was specified" do
|
41
|
+
CouchPotato::Config.database_name = "database"
|
42
|
+
CouchPotato.full_url_to_database.should == 'http://127.0.0.1:5984/database'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
21
47
|
describe CouchPotato::Database, 'load' do
|
22
48
|
it "should raise an exception if nil given" do
|
23
49
|
db = CouchPotato::Database.new(stub('couchrest db', :info => nil))
|
@@ -29,22 +55,153 @@ describe CouchPotato::Database, 'load' do
|
|
29
55
|
it "should set itself on the model" do
|
30
56
|
user = mock 'user'
|
31
57
|
DbTestUser.stub!(:new).and_return(user)
|
32
|
-
db = CouchPotato::Database.new(stub('couchrest db', :info => nil, :get => {'ruby_class' => 'DbTestUser'}))
|
58
|
+
db = CouchPotato::Database.new(stub('couchrest db', :info => nil, :get => DbTestUser.json_create({'ruby_class' => 'DbTestUser'})))
|
33
59
|
user.should_receive(:database=).with(db)
|
34
60
|
db.load '1'
|
35
61
|
end
|
36
62
|
|
37
63
|
it "should load namespaced models" do
|
38
|
-
db = CouchPotato::Database.new(stub('couchrest db', :info => nil, :get => {'ruby_class' => 'Parent::Child'}))
|
64
|
+
db = CouchPotato::Database.new(stub('couchrest db', :info => nil, :get => Parent::Child.json_create({'ruby_class' => 'Parent::Child'})))
|
39
65
|
db.load('1').class.should == Parent::Child
|
40
66
|
end
|
41
67
|
end
|
42
68
|
|
43
69
|
describe CouchPotato::Database, 'save_document' do
|
70
|
+
before(:each) do
|
71
|
+
@db = CouchPotato::Database.new(stub('couchrest db').as_null_object)
|
72
|
+
end
|
73
|
+
|
44
74
|
it "should set itself on the model for a new object before doing anything else" do
|
45
|
-
db
|
46
|
-
user = stub('user', :new? => true
|
47
|
-
user.should_receive(:database=).with(db)
|
48
|
-
db.save_document user
|
75
|
+
@db.stub(:valid_document?).and_return false
|
76
|
+
user = stub('user', :new? => true).as_null_object
|
77
|
+
user.should_receive(:database=).with(@db)
|
78
|
+
@db.save_document user
|
79
|
+
end
|
80
|
+
|
81
|
+
class Category
|
82
|
+
include CouchPotato::Persistence
|
83
|
+
property :name
|
84
|
+
validates_presence_of :name
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should return false when creating a new document and the validations failed" do
|
88
|
+
CouchPotato.database.save_document(Category.new).should == false
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should return false when saving an existing document and the validations failed" do
|
92
|
+
category = Category.new(:name => "pizza")
|
93
|
+
CouchPotato.database.save_document(category).should == true
|
94
|
+
category.name = nil
|
95
|
+
CouchPotato.database.save_document(category).should == false
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "when creating with validate options" do
|
99
|
+
it "should not run the validations when saved with false" do
|
100
|
+
category = Category.new
|
101
|
+
@db.save_document(category, false)
|
102
|
+
category.new?.should == false
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should run the validations when saved with true" do
|
106
|
+
category = Category.new
|
107
|
+
@db.save_document(category, true)
|
108
|
+
category.new?.should == true
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should run the validations when saved with default" do
|
112
|
+
category = Category.new
|
113
|
+
@db.save_document(category)
|
114
|
+
category.new?.should == true
|
115
|
+
end
|
49
116
|
end
|
50
|
-
|
117
|
+
|
118
|
+
describe "when updating with validate options" do
|
119
|
+
it "should not run the validations when saved with false" do
|
120
|
+
category = Category.new(:name => 'food')
|
121
|
+
@db.save_document(category)
|
122
|
+
category.new?.should == false
|
123
|
+
category.name = nil
|
124
|
+
@db.save_document(category, false)
|
125
|
+
category.dirty?.should == false
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should run the validations when saved with true" do
|
129
|
+
category = Category.new(:name => "food")
|
130
|
+
@db.save_document(category)
|
131
|
+
category.new?.should == false
|
132
|
+
category.name = nil
|
133
|
+
@db.save_document(category, true)
|
134
|
+
category.dirty?.should == true
|
135
|
+
category.valid?.should == false
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should run the validations when saved with default" do
|
139
|
+
category = Category.new(:name => "food")
|
140
|
+
@db.save_document(category)
|
141
|
+
category.new?.should == false
|
142
|
+
category.name = nil
|
143
|
+
@db.save_document(category)
|
144
|
+
category.dirty?.should == true
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe "when saving documents with errors set in callbacks" do
|
149
|
+
class Vulcan
|
150
|
+
include CouchPotato::Persistence
|
151
|
+
before_validation_on_create :set_errors
|
152
|
+
before_validation_on_update :set_errors
|
153
|
+
|
154
|
+
property :name
|
155
|
+
validates_presence_of :name
|
156
|
+
|
157
|
+
def set_errors
|
158
|
+
errors.add(:validation, "failed")
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should keep errors added in before_validation_on_* callbacks when creating a new object" do
|
163
|
+
spock = Vulcan.new(:name => 'spock')
|
164
|
+
@db.save_document(spock)
|
165
|
+
spock.errors.on(:validation).should == 'failed'
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should keep errors added in before_validation_on_* callbacks when creating a new object" do
|
169
|
+
spock = Vulcan.new(:name => 'spock')
|
170
|
+
@db.save_document(spock, false)
|
171
|
+
spock.new_record?.should == false
|
172
|
+
spock.name = "spock's father"
|
173
|
+
@db.save_document(spock)
|
174
|
+
spock.errors.on(:validation).should == 'failed'
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should keep errors generated from normal validations together with errors set in normal validations" do
|
178
|
+
spock = Vulcan.new
|
179
|
+
@db.save_document(spock)
|
180
|
+
spock.errors.on(:validation).should == 'failed'
|
181
|
+
spock.errors.on(:name).should == "can't be empty"
|
182
|
+
end
|
183
|
+
|
184
|
+
it "should clear errors on subsequent, valid saves when creating" do
|
185
|
+
spock = Vulcan.new
|
186
|
+
@db.save_document(spock)
|
187
|
+
|
188
|
+
spock.name = 'Spock'
|
189
|
+
@db.save_document(spock)
|
190
|
+
spock.errors.on(:name).should == nil
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should clear errors on subsequent, valid saves when updating" do
|
194
|
+
spock = Vulcan.new(:name => 'spock')
|
195
|
+
@db.save_document(spock, false)
|
196
|
+
|
197
|
+
spock.name = nil
|
198
|
+
@db.save_document(spock)
|
199
|
+
spock.errors.on(:name).should == "can't be empty"
|
200
|
+
|
201
|
+
spock.name = 'Spock'
|
202
|
+
@db.save_document(spock)
|
203
|
+
spock.errors.on(:name).should == nil
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
end
|
@@ -86,7 +86,7 @@ describe 'dirty attribute tracking' do
|
|
86
86
|
|
87
87
|
describe "object loaded from database" do
|
88
88
|
before(:each) do
|
89
|
-
couchrest_db = stub('database', :get => {'_id' => '1', '_rev' => '2', 'food' => 'sushi', 'ruby_class' => 'Plate'}, :info => nil)
|
89
|
+
couchrest_db = stub('database', :get => Plate.json_create({'_id' => '1', '_rev' => '2', 'food' => 'sushi', 'ruby_class' => 'Plate'}), :info => nil)
|
90
90
|
@plate = CouchPotato::Database.new(couchrest_db).load_document '1'
|
91
91
|
end
|
92
92
|
|
@@ -104,7 +104,7 @@ describe 'dirty attribute tracking' do
|
|
104
104
|
end
|
105
105
|
|
106
106
|
it "should return true if array attribute changed" do
|
107
|
-
couchrest_db = stub('database', :get => {'_id' => '1', '_rev' => '2', 'food' => ['sushi'], 'ruby_class' => 'Plate'}, :info => nil)
|
107
|
+
couchrest_db = stub('database', :get => Plate.json_create({'_id' => '1', '_rev' => '2', 'food' => ['sushi'], 'ruby_class' => 'Plate'}), :info => nil)
|
108
108
|
plate = CouchPotato::Database.new(couchrest_db).load_document '1'
|
109
109
|
plate.food << 'burger'
|
110
110
|
plate.should be_food_changed
|
@@ -119,7 +119,7 @@ describe 'dirty attribute tracking' do
|
|
119
119
|
|
120
120
|
describe "after save" do
|
121
121
|
it "should reset all attributes to not dirty" do
|
122
|
-
couchrest_db = stub('database', :get => {'_id' => '1', '_rev' => '2', 'food' => 'sushi', 'ruby_class' => 'Plate'}, :info => nil, :save_doc => {})
|
122
|
+
couchrest_db = stub('database', :get => Plate.json_create({'_id' => '1', '_rev' => '2', 'food' => 'sushi', 'ruby_class' => 'Plate'}), :info => nil, :save_doc => {})
|
123
123
|
db = CouchPotato::Database.new(couchrest_db)
|
124
124
|
@plate = db.load_document '1'
|
125
125
|
@plate.food = 'burger'
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
class Drink
|
4
|
+
include CouchPotato::Persistence
|
5
|
+
|
6
|
+
property :alcohol
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "json module" do
|
10
|
+
it "should inject JSON.create_id into hash representation of a persistence object" do
|
11
|
+
sake = Drink.new(:alcohol => "18%")
|
12
|
+
sake.to_hash[JSON.create_id].should eql("Drink")
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
require 'couch_potato/rspec/matchers'
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
describe CouchPotato::RSpec::MapToMatcher do
|
6
|
+
|
7
|
+
describe "basic map function" do
|
8
|
+
before(:each) do
|
9
|
+
@view_spec = OpenStruct.new(:map_function => "function(doc) {emit(doc.name, doc.tags.length);}")
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should pass if the given function emits the expected javascript" do
|
13
|
+
@view_spec.should map({:name => 'horst', :tags => ['person', 'male']}).to([['horst', 2]])
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should not pass if the given function emits different javascript" do
|
17
|
+
@view_spec.should_not map({:name => 'horst', :tags => ['person', 'male']}).to([['horst', 3]])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "functions emitting multiple times" do
|
22
|
+
before(:each) do
|
23
|
+
@view_spec = OpenStruct.new(:map_function => "function(doc) {emit(doc.name, doc.tags.length); emit(doc.tags[0], doc.tags[1])};")
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should pass if the given function emits the expected javascript" do
|
27
|
+
@view_spec.should map({:name => 'horst', :tags => ['person', 'male']}).to([['horst', 2], ['person', 'male']])
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should return false if the given function emits different javascript" do
|
31
|
+
@view_spec.should_not map({:name => 'horst', :tags => ['person', 'male']}).to([['horst', 2], ['male', 'person']])
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "failing specs" do
|
36
|
+
before(:each) do
|
37
|
+
@view_spec = OpenStruct.new(:map_function => "function(doc) {emit(doc.name, null)}")
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should have a nice error message for failing should" do
|
41
|
+
lambda {
|
42
|
+
@view_spec.should map({:name => 'bill'}).to([['linus', nil]])
|
43
|
+
}.should raise_error('Expected to map to [["linus", nil]] but got [["bill", nil]].')
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should have a nice error message for failing should not" do
|
47
|
+
lambda {
|
48
|
+
@view_spec.should_not map({:name => 'bill'}).to([['bill', nil]])
|
49
|
+
}.should raise_error('Expected not to map to [["bill", nil]] but did.')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe CouchPotato::RSpec::ReduceToMatcher do
|
55
|
+
before(:each) do
|
56
|
+
@view_spec = OpenStruct.new(:reduce_function => "function(docs, keys, rereduce) {
|
57
|
+
if(rereduce) {
|
58
|
+
return(sum(keys) * 2);
|
59
|
+
} else {
|
60
|
+
return(sum(keys));
|
61
|
+
};
|
62
|
+
}")
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should pass if the given function return the expected javascript" do
|
66
|
+
@view_spec.should reduce([], [1, 2, 3]).to(6)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should not pass if the given function returns different javascript" do
|
70
|
+
@view_spec.should_not reduce([], [1, 2, 3]).to(7)
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "rereduce" do
|
74
|
+
it "should pass if the given function return the expected javascript" do
|
75
|
+
@view_spec.should rereduce([], [1, 2, 3]).to(12)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should not pass if the given function returns different javascript" do
|
79
|
+
@view_spec.should_not rereduce([], [1, 2, 3]).to(13)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe 'failing specs' do
|
84
|
+
|
85
|
+
it "should have a nice error message for failing should" do
|
86
|
+
lambda {
|
87
|
+
@view_spec.should reduce([], [1, 2, 3]).to(7)
|
88
|
+
}.should raise_error('Expected to reduce to 7 but got 6.')
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should have a nice error message for failing should not" do
|
92
|
+
lambda {
|
93
|
+
@view_spec.should_not reduce([], [1, 2, 3]).to(6)
|
94
|
+
}.should raise_error('Expected not to reduce to 6 but did.')
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/spec/update_spec.rb
CHANGED
@@ -35,6 +35,6 @@ describe "create" do
|
|
35
35
|
it "should update the attributes" do
|
36
36
|
@comment.title = 'new title'
|
37
37
|
CouchPotato.database.save_document! @comment
|
38
|
-
CouchPotato.couchrest_database.get("#{@comment.id}")
|
38
|
+
CouchPotato.couchrest_database.get("#{@comment.id}").title.should == 'new title'
|
39
39
|
end
|
40
40
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: couch_potato
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Lang
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-10-30 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -73,6 +73,10 @@ files:
|
|
73
73
|
- lib/couch_potato/persistence/properties.rb
|
74
74
|
- lib/couch_potato/persistence/simple_property.rb
|
75
75
|
- lib/couch_potato/persistence/validation.rb
|
76
|
+
- lib/couch_potato/rspec/matchers.rb
|
77
|
+
- lib/couch_potato/rspec/matchers/map_to_matcher.rb
|
78
|
+
- lib/couch_potato/rspec/matchers/print_r.js
|
79
|
+
- lib/couch_potato/rspec/matchers/reduce_to_matcher.rb
|
76
80
|
- lib/couch_potato/view/base_view_spec.rb
|
77
81
|
- lib/couch_potato/view/custom_view_spec.rb
|
78
82
|
- lib/couch_potato/view/custom_views.rb
|
@@ -99,6 +103,8 @@ files:
|
|
99
103
|
- spec/unit/customs_views_spec.rb
|
100
104
|
- spec/unit/database_spec.rb
|
101
105
|
- spec/unit/dirty_attributes_spec.rb
|
106
|
+
- spec/unit/json_create_id_spec.rb
|
107
|
+
- spec/unit/rspec_matchers_spec.rb
|
102
108
|
- spec/unit/string_spec.rb
|
103
109
|
- spec/unit/view_query_spec.rb
|
104
110
|
- spec/update_spec.rb
|
@@ -148,6 +154,8 @@ test_files:
|
|
148
154
|
- spec/unit/customs_views_spec.rb
|
149
155
|
- spec/unit/database_spec.rb
|
150
156
|
- spec/unit/dirty_attributes_spec.rb
|
157
|
+
- spec/unit/json_create_id_spec.rb
|
158
|
+
- spec/unit/rspec_matchers_spec.rb
|
151
159
|
- spec/unit/string_spec.rb
|
152
160
|
- spec/unit/view_query_spec.rb
|
153
161
|
- spec/update_spec.rb
|