couch_potato 1.4.0 → 1.6.3

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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -0
  3. data/.travis.yml +12 -8
  4. data/CHANGES.md +4 -0
  5. data/Gemfile +1 -1
  6. data/README.md +396 -276
  7. data/Rakefile +9 -9
  8. data/couch_potato-rspec.gemspec +20 -0
  9. data/couch_potato.gemspec +15 -16
  10. data/{active_support_4_0 → gemfiles/active_support_4_0} +3 -3
  11. data/{active_support_3_2 → gemfiles/active_support_4_1} +3 -2
  12. data/gemfiles/active_support_4_2 +11 -0
  13. data/lib/couch_potato-rspec.rb +3 -0
  14. data/lib/couch_potato.rb +3 -1
  15. data/lib/couch_potato/database.rb +42 -39
  16. data/lib/couch_potato/persistence/magic_timestamps.rb +5 -5
  17. data/lib/couch_potato/persistence/properties.rb +8 -2
  18. data/lib/couch_potato/persistence/simple_property.rb +11 -9
  19. data/lib/couch_potato/persistence/type_caster.rb +1 -1
  20. data/lib/couch_potato/railtie.rb +2 -0
  21. data/lib/couch_potato/version.rb +2 -1
  22. data/lib/couch_potato/view/base_view_spec.rb +18 -8
  23. data/lib/couch_potato/view/view_query.rb +2 -3
  24. data/spec/attachments_spec.rb +3 -3
  25. data/spec/callbacks_spec.rb +193 -113
  26. data/spec/conflict_handling_spec.rb +4 -4
  27. data/spec/create_spec.rb +5 -5
  28. data/spec/default_property_spec.rb +6 -6
  29. data/spec/destroy_spec.rb +5 -5
  30. data/spec/property_spec.rb +71 -61
  31. data/spec/rails_spec.rb +3 -3
  32. data/spec/railtie_spec.rb +12 -13
  33. data/spec/spec_helper.rb +3 -3
  34. data/spec/unit/active_model_compliance_spec.rb +16 -16
  35. data/spec/unit/attributes_spec.rb +36 -34
  36. data/spec/unit/base_view_spec_spec.rb +82 -35
  37. data/spec/unit/callbacks_spec.rb +2 -2
  38. data/spec/unit/couch_potato_spec.rb +3 -3
  39. data/spec/unit/create_spec.rb +12 -12
  40. data/spec/unit/custom_views_spec.rb +1 -1
  41. data/spec/unit/database_spec.rb +95 -95
  42. data/spec/unit/date_spec.rb +3 -3
  43. data/spec/unit/deep_dirty_attributes_spec.rb +104 -104
  44. data/spec/unit/dirty_attributes_spec.rb +19 -19
  45. data/spec/unit/forbidden_attributes_protection_spec.rb +4 -4
  46. data/spec/unit/initialize_spec.rb +37 -19
  47. data/spec/unit/json_spec.rb +4 -4
  48. data/spec/unit/lists_spec.rb +8 -8
  49. data/spec/unit/model_view_spec_spec.rb +14 -14
  50. data/spec/unit/persistence_spec.rb +6 -6
  51. data/spec/unit/properties_view_spec_spec.rb +4 -4
  52. data/spec/unit/rspec_matchers_spec.rb +73 -73
  53. data/spec/unit/rspec_stub_db_spec.rb +43 -42
  54. data/spec/unit/string_spec.rb +1 -1
  55. data/spec/unit/time_spec.rb +2 -2
  56. data/spec/unit/validation_spec.rb +1 -1
  57. data/spec/unit/view_query_spec.rb +54 -59
  58. data/spec/update_spec.rb +5 -5
  59. data/spec/view_updates_spec.rb +4 -4
  60. data/spec/views_spec.rb +43 -43
  61. metadata +18 -22
  62. data/lib/couch_potato/rspec.rb +0 -2
  63. data/lib/couch_potato/rspec/matchers.rb +0 -56
  64. data/lib/couch_potato/rspec/matchers/json2.js +0 -482
  65. data/lib/couch_potato/rspec/matchers/list_as_matcher.rb +0 -53
  66. data/lib/couch_potato/rspec/matchers/map_reduce_to_matcher.rb +0 -166
  67. data/lib/couch_potato/rspec/matchers/map_to_matcher.rb +0 -61
  68. data/lib/couch_potato/rspec/matchers/reduce_to_matcher.rb +0 -48
  69. data/lib/couch_potato/rspec/stub_db.rb +0 -57
@@ -1,53 +0,0 @@
1
- module CouchPotato
2
- module RSpec
3
- class ListAsProxy
4
- def initialize(results_ruby)
5
- @results_ruby = results_ruby
6
- end
7
-
8
- def as(expected_ruby)
9
- ListAsMatcher.new(expected_ruby, @results_ruby)
10
- end
11
- end
12
-
13
- class ListAsMatcher
14
- include RunJS
15
-
16
- def initialize(expected_ruby, results_ruby)
17
- @expected_ruby = expected_ruby
18
- @results_ruby = results_ruby
19
- end
20
-
21
- def matches?(view_spec)
22
- js = <<-JS
23
- #{File.read(File.dirname(__FILE__) + '/json2.js')}
24
- var results = #{@results_ruby.to_json};
25
- var listed = '';
26
- var list = #{view_spec.list_function};
27
-
28
- var getRow = function() {
29
- return results.rows.shift();
30
- };
31
- var send = function(text) {
32
- listed = listed + text;
33
- };
34
- list();
35
- JSON.stringify(JSON.parse(listed));
36
- JS
37
-
38
- @actual_ruby = JSON.parse(run_js(js))
39
-
40
- @expected_ruby == @actual_ruby
41
- end
42
-
43
- def failure_message_for_should
44
- "Expected to list as #{@expected_ruby.inspect} but got #{@actual_ruby.inspect}."
45
- end
46
-
47
- def failure_message_for_should_not
48
- "Expected to not list as #{@expected_ruby.inspect} but did."
49
- end
50
-
51
- end
52
- end
53
- end
@@ -1,166 +0,0 @@
1
- require 'json'
2
-
3
- module CouchPotato
4
- module RSpec
5
- class MapReduceToProxy
6
- def initialize(*input_ruby)
7
- @input_ruby, @options = input_ruby.flatten, {}
8
- end
9
-
10
- def with_options(options)
11
- @options = options
12
- self
13
- end
14
-
15
- def to(*expected_ruby)
16
- MapReduceToMatcher.new(expected_ruby, @input_ruby, @options)
17
- end
18
- end
19
-
20
- class MapReduceToMatcher
21
- include RunJS
22
-
23
- def initialize(expected_ruby, input_ruby, options)
24
- @expected_ruby = expected_ruby
25
- @input_ruby = input_ruby
26
- @options = options
27
- end
28
-
29
- def matches?(view_spec)
30
- js = <<-JS
31
- var sum = function(values) {
32
- return values.reduce(function(memo, value) { return memo + value; });
33
- };
34
- // Equivalents of couchdb built-in reduce functions whose names can be
35
- // given as the reduce function in the view_spec:
36
- var _sum = function(keys, values, rereduce) {
37
- return sum(values);
38
- }
39
- var _count = function(keys, values, rereduce) {
40
- if (rereduce) {
41
- return sum(values);
42
- } else {
43
- return values.length;
44
- }
45
- }
46
- var _stats = function(keys, values, rereduce) {
47
- var result = {sum: 0, count: 0, min: Number.MAX_VALUE, max: Number.MIN_VALUE, sumsqr: 0};
48
- if (rereduce) {
49
- for (var i in values) {
50
- var value = values[i];
51
- result.sum += value.sum;
52
- result.count += value.count;
53
- result.min = Math.min(result.min, value.min);
54
- result.max = Math.max(result.max, value.max);
55
- result.sumsqr += value.sumsqr;
56
- }
57
- } else {
58
- for (var i in values) {
59
- var value = values[i];
60
- result.sum += value;
61
- result.count += 1;
62
- result.min = Math.min(result.min, value);
63
- result.max = Math.max(result.max, value);
64
- result.sumsqr += Math.pow(value, 2);
65
- }
66
- }
67
- return result;
68
- }
69
-
70
- var docs = #{@input_ruby.to_json};
71
- var options = #{@options.to_json};
72
- var map = #{view_spec.map_function};
73
- var reduce = #{view_spec.reduce_function};
74
- var lib = #{view_spec.respond_to?(:lib) && view_spec.lib.to_json};
75
-
76
- // Map the input docs
77
- var require = function(modulePath) {
78
- var module = {exports: {}};
79
- var exports = module.exports;
80
- var pathArray = modulePath.split("/").slice(2);
81
- var result = lib;
82
- for (var i in pathArray) {
83
- result = result[pathArray[i]];
84
- }
85
- eval(result);
86
- return module.exports;
87
- }
88
-
89
- var mapResults = [];
90
- var emit = function(key, value) {
91
- mapResults.push({key: key, value: value});
92
- };
93
- for (var i in docs) {
94
- map(docs[i]);
95
- }
96
-
97
- // Group the map results, honoring the group and group_level options
98
- var grouped = [];
99
- if (options.group || options.group_level) {
100
- var groupLevel = options.group_level;
101
- if (groupLevel == "exact" || options.group == true)
102
- groupLevel = 9999;
103
- var keysEqual = function(a, b) { return !(a < b || b < a); }
104
-
105
- for (var mr in mapResults) {
106
- var mapResult = mapResults[mr];
107
- var groupedKey = mapResult.key.slice(0, groupLevel);
108
- var groupFound = false;
109
- for (var g in grouped) {
110
- var group = grouped[g];
111
- if (keysEqual(groupedKey, group.groupedKey)) {
112
- group.keys.push(mapResult.key);
113
- group.values.push(mapResult.value);
114
- groupFound = true;
115
- break;
116
- }
117
- }
118
-
119
- if (!groupFound)
120
- grouped.push({keys: [mapResult.key], groupedKey: groupedKey, values: [mapResult.value]});
121
- }
122
- } else {
123
- var group = {keys: null, groupedKey: null, values: []};
124
- for (var mr in mapResults)
125
- group.values.push(mapResults[mr].value);
126
- grouped.push(group);
127
- }
128
-
129
- // Reduce the grouped map results
130
- var results = [];
131
- for (var g in grouped) {
132
- var group = grouped[g], reduced = null;
133
- if (group.values.length >= 2) {
134
- // Split the values into two parts, reduce each part, then rereduce those results
135
- var mid = parseInt(group.values.length / 2);
136
- var keys1 = (group.keys || []).slice(0, mid),
137
- values1 = group.values.slice(0, mid);
138
- var reduced1 = reduce(keys1, values1, false);
139
- var keys2 = (group.keys || []).slice(mid, group.values.length),
140
- values2 = group.values.slice(mid, group.values.length);
141
- var reduced2 = reduce(keys2, values2, false);
142
- reduced = reduce(null, [reduced1, reduced2], true);
143
- } else {
144
- // Not enough values to split, so just reduce, and then rereduce the single result
145
- reduced = reduce(group.keys, group.values, false);
146
- reduced = reduce(null, [reduced], true);
147
- }
148
- results.push({key: group.groupedKey, value: reduced});
149
- }
150
-
151
- JSON.stringify(results);
152
- JS
153
- @actual_ruby = JSON.parse(run_js(js))
154
- @expected_ruby == @actual_ruby
155
- end
156
-
157
- def failure_message_for_should
158
- "Expected to map/reduce to #{@expected_ruby.inspect} but got #{@actual_ruby.inspect}."
159
- end
160
-
161
- def failure_message_for_should_not
162
- "Expected not to map/reduce to #{@actual_ruby.inspect} but did."
163
- end
164
- end
165
- end
166
- end
@@ -1,61 +0,0 @@
1
- require 'json'
2
-
3
-
4
- module CouchPotato
5
- module RSpec
6
- class MapToProxy
7
- def initialize(input_ruby)
8
- @input_ruby = input_ruby
9
- end
10
-
11
- def to(*expected_ruby)
12
- MapToMatcher.new(expected_ruby, @input_ruby)
13
- end
14
- end
15
-
16
- class MapToMatcher
17
- include RunJS
18
-
19
- def initialize(expected_ruby, input_ruby)
20
- @expected_ruby = expected_ruby
21
- @input_ruby = input_ruby
22
- end
23
-
24
- def matches?(view_spec)
25
- js = <<-JS
26
- var doc = #{@input_ruby.to_json};
27
- var map = #{view_spec.map_function};
28
- var lib = #{view_spec.respond_to?(:lib) && view_spec.lib.to_json};
29
- var result = [];
30
- var require = function(modulePath) {
31
- var module = {exports: {}};
32
- var exports = module.exports;
33
- var pathArray = modulePath.split("/").slice(2);
34
- var result = lib;
35
- for (var i in pathArray) {
36
- result = result[pathArray[i]];
37
- }
38
- eval(result);
39
- return module.exports;
40
- }
41
-
42
- var emit = function(key, value) {
43
- result.push([key, value]);
44
- };
45
- map(doc);
46
- JSON.stringify(result);
47
- JS
48
- @actual_ruby = JSON.parse(run_js(js))
49
- @expected_ruby == @actual_ruby
50
- end
51
-
52
- def failure_message_for_should
53
- "Expected to map to #{@expected_ruby.inspect} but got #{@actual_ruby.inspect}."
54
- end
55
-
56
- def failure_message_for_should_not
57
- "Expected not to map to #{@actual_ruby.inspect} but did."
58
- end
59
- end
60
- end
61
- end
@@ -1,48 +0,0 @@
1
- module CouchPotato
2
- module RSpec
3
- class ReduceToProxy
4
- def initialize(keys, values, rereduce = false)
5
- @keys, @values, @rereduce = keys, values, rereduce
6
- end
7
-
8
- def to(expected_ruby)
9
- ReduceToMatcher.new(expected_ruby, @keys, @values, @rereduce)
10
- end
11
- end
12
-
13
- class ReduceToMatcher
14
- include RunJS
15
-
16
- def initialize(expected_ruby, keys, values, rereduce = false)
17
- @expected_ruby, @keys, @values, @rereduce = expected_ruby, keys, values, rereduce
18
- end
19
-
20
- def matches?(view_spec)
21
- js = <<-JS
22
- sum = function(values) {
23
- var rv = 0;
24
- for (var i in values) {
25
- rv += values[i];
26
- }
27
- return rv;
28
- };
29
-
30
- var keys = #{@keys.to_json};
31
- var values = #{@values.to_json};
32
- var reduce = #{view_spec.reduce_function};
33
- JSON.stringify({result: reduce(keys, values, #{@rereduce})});
34
- JS
35
- @actual_ruby = JSON.parse(run_js(js))['result']
36
- @expected_ruby == @actual_ruby
37
- end
38
-
39
- def failure_message_for_should
40
- "Expected to reduce to #{@expected_ruby.inspect} but got #{@actual_ruby.inspect}."
41
- end
42
-
43
- def failure_message_for_should_not
44
- "Expected not to reduce to #{@actual_ruby.inspect} but did."
45
- end
46
- end
47
- end
48
- end
@@ -1,57 +0,0 @@
1
- module CouchPotato::RSpec
2
-
3
- module StubView
4
- class ViewStub
5
- def initialize(clazz, view, db)
6
- @clazz = clazz
7
- @view = view
8
- @db = db
9
- end
10
-
11
- def with(*args, &block)
12
- @args = args
13
- and_return(block.call) if block
14
- self
15
- end
16
-
17
- def and_return(return_value)
18
- view_stub = RSpec::Mocks::Mock.new("#{@clazz}.#{@view}(#{@args.try(:join, ', ')}) view")
19
- _stub = @clazz.stub(@view)
20
- _stub.with(*@args) if @args
21
- _stub.and_return(view_stub)
22
- @db.stub(:view).with(view_stub).and_return(return_value)
23
- if return_value.respond_to?(:first)
24
- @db.stub(:first).with(view_stub).and_return(return_value.first)
25
- if return_value.first
26
- @db.stub(:first!).with(view_stub).and_return(return_value.first)
27
- else
28
- @db.stub(:first!).with(view_stub).and_raise(CouchPotato::NotFound)
29
- end
30
- end
31
- end
32
- end
33
-
34
- def stub_view(clazz, view, &block)
35
- stub = ViewStub.new clazz, view, self
36
- stub.and_return(block.call) if block
37
- stub
38
- end
39
- end
40
-
41
- module StubDb
42
- def stub_db(options = {})
43
- db = double('db', options)
44
- db.extend CouchPotato::RSpec::StubView
45
- CouchPotato.stub(:database => db)
46
- db
47
- end
48
- end
49
- end
50
-
51
- module RSpec
52
- module Mocks
53
- module ExampleMethods
54
- include CouchPotato::RSpec::StubDb
55
- end
56
- end
57
- end