couch_potato 1.4.0 → 1.6.3

Sign up to get free protection for your applications and to get access to all the features.
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