guacamole 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +3 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +18 -0
  6. data/CONTRIBUTING.md +26 -0
  7. data/Gemfile +16 -0
  8. data/Gemfile.devtools +55 -0
  9. data/Guardfile +13 -0
  10. data/LICENSE +202 -0
  11. data/README.md +130 -0
  12. data/Rakefile +7 -0
  13. data/config/devtools.yml +4 -0
  14. data/config/flay.yml +3 -0
  15. data/config/flog.yml +2 -0
  16. data/config/mutant.yml +3 -0
  17. data/config/reek.yml +104 -0
  18. data/config/rubocop.yml +68 -0
  19. data/config/yardstick.yml +2 -0
  20. data/guacamole.gemspec +28 -0
  21. data/lib/guacamole.rb +19 -0
  22. data/lib/guacamole/collection.rb +246 -0
  23. data/lib/guacamole/configuration.rb +123 -0
  24. data/lib/guacamole/document_model_mapper.rb +95 -0
  25. data/lib/guacamole/model.rb +210 -0
  26. data/lib/guacamole/query.rb +72 -0
  27. data/lib/guacamole/railtie.rb +27 -0
  28. data/lib/guacamole/railtie/database.rake +5 -0
  29. data/lib/guacamole/version.rb +5 -0
  30. data/log/.gitkeep +0 -0
  31. data/spec/acceptance/.gitkeep +0 -0
  32. data/spec/acceptance/basic_spec.rb +112 -0
  33. data/spec/acceptance/config/guacamole.yml +11 -0
  34. data/spec/acceptance/spec_helper.rb +61 -0
  35. data/spec/fabricators/article_fabricator.rb +10 -0
  36. data/spec/fabricators/comment_fabricator.rb +5 -0
  37. data/spec/setup/arangodb.sh +65 -0
  38. data/spec/spec_helper.rb +19 -0
  39. data/spec/unit/.gitkeep +0 -0
  40. data/spec/unit/collection_spec.rb +380 -0
  41. data/spec/unit/configuration_spec.rb +119 -0
  42. data/spec/unit/document_model_mapper_spec.rb +120 -0
  43. data/spec/unit/example_spec.rb +8 -0
  44. data/spec/unit/model_spec.rb +116 -0
  45. data/spec/unit/query_spec.rb +140 -0
  46. data/tasks/adjustments.rake +35 -0
  47. metadata +191 -0
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'guacamole'
4
+ require 'guacamole/configuration'
5
+
6
+ require 'rails'
7
+
8
+ module Guacamole
9
+ # Class to hook into Rails configuration and initializer
10
+ # @api private
11
+ class Railtie < Rails::Railtie
12
+
13
+ rake_tasks do
14
+ load 'guacamole/railtie/database.rake'
15
+ end
16
+
17
+ config.guacamole = ::Guacamole::Configuration
18
+
19
+ initializer 'guacamole.load-config' do
20
+ config_file = Rails.root.join('config', 'guacamole.yml')
21
+ if config_file.file?
22
+ Guacamole::Configuration.load config_file
23
+ end
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,5 @@
1
+ namespace :db do
2
+ # TODO: Add all the Rails-tasks.
3
+ # If we cannot do something meaningful provide a noop.
4
+ # Foremost the creation of databases should be provided.
5
+ end
@@ -0,0 +1,5 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Guacamole
3
+ # Current version of the gem
4
+ VERSION = '0.0.1'
5
+ end
data/log/.gitkeep ADDED
File without changes
File without changes
@@ -0,0 +1,112 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'guacamole'
3
+ require 'acceptance/spec_helper'
4
+
5
+ class Comment
6
+ include Guacamole::Model
7
+
8
+ attribute :text, String
9
+ end
10
+
11
+ class Article
12
+ include Guacamole::Model
13
+
14
+ attribute :title, String
15
+ attribute :comments, Array[Comment]
16
+
17
+ validates :title, presence: true
18
+ end
19
+
20
+ class ArticlesCollection
21
+ include Guacamole::Collection
22
+
23
+ map do
24
+ embeds :comments
25
+ end
26
+ end
27
+
28
+ describe 'ModelBasics' do
29
+
30
+ describe Article do
31
+ it 'should allow setting its title' do
32
+ subject.title = 'This is my fancy article'
33
+
34
+ expect(subject.title).to eq('This is my fancy article')
35
+ end
36
+
37
+ it 'should have key and rev attributes' do
38
+ expect(subject.key).to be_nil
39
+ expect(subject.rev).to be_nil
40
+ end
41
+
42
+ it 'should have timestamp attributes which are empty' do
43
+ expect(subject.created_at).to be_nil
44
+ expect(subject.updated_at).to be_nil
45
+ end
46
+
47
+ it 'should validate its attributes' do
48
+ expect(subject.valid?).to be_false
49
+ subject.title = 'The Legend of Zelda'
50
+ expect(subject.valid?).to be_true
51
+ end
52
+
53
+ it 'should know its model name' do
54
+ # This test passes when you only require ActiveModel::Validations
55
+ expect(subject.class.model_name).to eq 'Article'
56
+ end
57
+
58
+ it 'should convert itself to params' do
59
+ subject.key = 'random_number'
60
+ expect(subject.to_param).to eq 'random_number'
61
+ end
62
+ end
63
+
64
+ end
65
+
66
+ describe 'CollectionBasics' do
67
+
68
+ describe ArticlesCollection do
69
+ subject { ArticlesCollection }
70
+
71
+ let(:some_article) { Fabricate(:article) }
72
+
73
+ it 'should provide a method to find documents by key and return the appropriate model' do
74
+ found_model = subject.by_key some_article.key
75
+ expect(found_model).to eq some_article
76
+ end
77
+
78
+ it 'should save models to the database' do
79
+ new_article = Fabricate.build(:article)
80
+ subject.save new_article
81
+
82
+ expect(subject.by_key(new_article.key)).to eq new_article
83
+ end
84
+
85
+ it 'should update models in the database' do
86
+ some_article.title = 'Has been updated'
87
+ subject.replace some_article
88
+
89
+ updated_article = subject.by_key(some_article.key)
90
+
91
+ expect(updated_article.title).to eq 'Has been updated'
92
+ end
93
+
94
+ it 'should receive all documents by title' do
95
+ subject.save Fabricate.build(:article, title: 'Disturbed')
96
+ subject.save Fabricate.build(:article, title: 'Not so Disturbed')
97
+
98
+ result = subject.by_example(title: 'Disturbed').first
99
+
100
+ expect(result.title).to eq 'Disturbed'
101
+ end
102
+
103
+ it 'should allow to nest models' do
104
+ article_with_comments = Fabricate(:article_with_two_comments)
105
+ found_article = subject.by_key(article_with_comments.key)
106
+
107
+ expect(found_article.comments.first).to be_a Comment
108
+ expect(found_article.comments).to eq article_with_comments.comments
109
+ end
110
+ end
111
+
112
+ end
@@ -0,0 +1,11 @@
1
+ # FIXME: This is copied from Ashikawa::Core for now but is not recommended. This
2
+ # setup uses the default database instead of a custom DB. Due to this we're deleting
3
+ # all collections in the default database each time we run the specs.
4
+ # => This is not good!
5
+ test:
6
+ protocol: 'http'
7
+ host: 'localhost'
8
+ port: 8529
9
+ password: ''
10
+ username: ''
11
+ database: '_system'
@@ -0,0 +1,61 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
4
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
5
+
6
+ require 'fabrication'
7
+ require 'logging'
8
+ require 'ashikawa-core'
9
+
10
+ begin
11
+ require 'debugger'
12
+ rescue LoadError
13
+ puts "Debugger is not available. Maybe you're Travis."
14
+ end
15
+
16
+ class Fabrication::Generator::Guacamole < Fabrication::Generator::Base
17
+
18
+ def self.supports?(klass)
19
+ defined?(Guacamole) && klass.ancestors.include?(Guacamole::Model)
20
+ end
21
+
22
+ def persist
23
+ collection = [_instance.class.name.pluralize, 'Collection'].join.constantize
24
+ collection.save _instance
25
+ end
26
+
27
+ def validate_instance
28
+ _instance.valid?
29
+ end
30
+
31
+ end
32
+
33
+ Fabrication::Schematic::Definition::GENERATORS.unshift Fabrication::Generator::Guacamole
34
+
35
+ ENV['GUACAMOLE_ENV'] = 'test'
36
+
37
+ Guacamole.configure do |config|
38
+ logger = Logging.logger['guacamole_logger']
39
+ logger.add_appenders(
40
+ Logging.appenders.file('log/acceptance.log')
41
+ )
42
+ logger.level = :info
43
+
44
+ config.logger = logger
45
+
46
+ config.load File.join(File.dirname(__FILE__), 'config', 'guacamole.yml')
47
+ end
48
+
49
+ RSpec.configure do |config|
50
+ config.expect_with :rspec do |c|
51
+ c.syntax = :expect
52
+ end
53
+
54
+ config.mock_with :rspec do |c|
55
+ c.syntax = :expect
56
+ end
57
+
58
+ config.before(:each) do
59
+ Guacamole.configuration.database.collections.each { |collection| collection.truncate! }
60
+ end
61
+ end
@@ -0,0 +1,10 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Fabricator(:article) do
4
+ title 'And then there was silence'
5
+ end
6
+
7
+ Fabricator(:article_with_two_comments, from: Article) do
8
+ title 'I have two comments'
9
+ comments(count: 2) { |attrs, i| Fabricate.build(:comment, text: "I'm comment number #{i}") }
10
+ end
@@ -0,0 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Fabricator(:comment) do
4
+ text 'This article is super awesome'
5
+ end
@@ -0,0 +1,65 @@
1
+ #!/bin/bash
2
+
3
+ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
4
+ cd $DIR
5
+
6
+ # VERSION=1.4.devel
7
+ NAME=ArangoDB-$VERSION
8
+
9
+ if [ ! -d "$DIR/$NAME" ]; then
10
+ # download ArangoDB
11
+ echo "wget http://www.arangodb.org/travisCI/$NAME.tar.gz"
12
+ wget http://www.arangodb.org/travisCI/$NAME.tar.gz
13
+ echo "tar zxf $NAME.tar.gz"
14
+ tar zvxf $NAME.tar.gz
15
+ fi
16
+
17
+ ARCH=$(arch)
18
+ PID=$(echo $PPID)
19
+ TMP_DIR="/tmp/arangodb.$PID"
20
+ PID_FILE="/tmp/arangodb.$PID.pid"
21
+ ARANGODB_DIR="$DIR/$NAME"
22
+
23
+ ARANGOD="${ARANGODB_DIR}/bin/arangod"
24
+ if [ "$ARCH" == "x86_64" ]; then
25
+ ARANGOD="${ARANGOD}_x86_64"
26
+ fi
27
+
28
+ # create database directory
29
+ mkdir ${TMP_DIR}
30
+
31
+ echo "Starting arangodb '${ARANGOD}'"
32
+
33
+ ${ARANGOD} \
34
+ --database.directory ${TMP_DIR} \
35
+ --configuration none \
36
+ --server.endpoint tcp://127.0.0.1:8529 \
37
+ --javascript.startup-directory ${ARANGODB_DIR}/js \
38
+ --server.admin-directory ${ARANGODB_DIR}/html/admin \
39
+ --javascript.modules-path ${ARANGODB_DIR}/js/server/modules:${ARANGODB_DIR}/js/common/modules:${ARANGODB_DIR}/js/node \
40
+ --javascript.package-path ${ARANGODB_DIR}/js/npm:${ARANGODB_DIR}/js/common/test-data/modules \
41
+ --javascript.action-directory ${ARANGODB_DIR}/js/actions \
42
+ --javascript.app-path ${ARANGODB_DIR}/js/apps \
43
+ --database.maximal-journal-size 1048576 \
44
+ --server.disable-admin-interface ${ARANGODB_DISABLE_AUTHENTIFICATION} \
45
+ --server.disable-authentication true \
46
+ --javascript.gc-interval 1 &
47
+
48
+ sleep 2
49
+
50
+ echo "Check for arangod process"
51
+ process=$(ps auxww | grep "bin/arangod" | grep -v grep)
52
+
53
+ if [ "x$process" == "x" ]; then
54
+ echo "no 'arangod' process found"
55
+ echo "ARCH = $ARCH"
56
+ exit 1
57
+ fi
58
+
59
+ echo "Waiting until ArangoDB is ready on port 8529"
60
+ while [[ -z `curl -s 'http://127.0.0.1:8529/_api/version' ` ]] ; do
61
+ echo -n "."
62
+ sleep 2s
63
+ done
64
+
65
+ echo "ArangoDB is up"
@@ -0,0 +1,19 @@
1
+ # -*- encoding : utf-8 -*-
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+
5
+ begin
6
+ require 'debugger'
7
+ rescue LoadError
8
+ puts "Debugger is not available. Maybe you're Travis."
9
+ end
10
+
11
+ RSpec.configure do |config|
12
+ config.expect_with :rspec do |c|
13
+ c.syntax = :expect
14
+ end
15
+
16
+ config.mock_with :rspec do |c|
17
+ c.syntax = :expect
18
+ end
19
+ end
File without changes
@@ -0,0 +1,380 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+ require 'guacamole/collection'
5
+
6
+ class Test
7
+ end
8
+
9
+ class TestCollection
10
+ include Guacamole::Collection
11
+ end
12
+
13
+ describe Guacamole::Collection do
14
+ subject { TestCollection }
15
+
16
+ describe 'Configuration' do
17
+ it 'should set the connection to the ArangoDB collection' do
18
+ mock_collection_connection = double('ConnectionToCollection')
19
+ subject.connection = mock_collection_connection
20
+
21
+ expect(subject.connection).to eq mock_collection_connection
22
+ end
23
+
24
+ it 'should set the Mapper instance to map documents to models and vice versa' do
25
+ mock_mapper = double('Mapper')
26
+ subject.mapper = mock_mapper
27
+
28
+ expect(subject.mapper).to eq mock_mapper
29
+ end
30
+
31
+ it 'should set the connection to ArangoDB' do
32
+ mock_db = double('Ashikawa::Core::Database')
33
+ subject.database = mock_db
34
+
35
+ expect(subject.database).to eq mock_db
36
+ end
37
+
38
+ it 'should know the name of the collection in ArangoDB' do
39
+ expect(subject.collection_name).to eq 'test'
40
+ end
41
+
42
+ it 'should know the class of the model to manage' do
43
+ expect(subject.model_class).to eq Test
44
+ end
45
+ end
46
+
47
+ describe 'database' do
48
+ before do
49
+ subject.database = nil
50
+ end
51
+
52
+ it 'should default to Guacamole.configuration.database' do
53
+ default_database = double('Database')
54
+ configuration = double('Configuration', database: default_database)
55
+ allow(Guacamole).to receive(:configuration).and_return(configuration)
56
+
57
+ expect(subject.database).to eq default_database
58
+ end
59
+ end
60
+
61
+ describe 'connection' do
62
+ before do
63
+ subject.connection = nil
64
+ end
65
+
66
+ it 'should default to the collection "collection_name" in the database' do
67
+ database = double('Database')
68
+ allow(subject).to receive(:database).and_return(database)
69
+
70
+ expect(database).to receive(:[]).with(subject.collection_name)
71
+
72
+ subject.connection
73
+ end
74
+ end
75
+
76
+ describe 'mapper' do
77
+ before do
78
+ subject.mapper = nil
79
+ end
80
+
81
+ it 'should default to Guacamole.configuration.default_mapper' do
82
+ default_mapper = double('Mapper')
83
+ mapper_instance = double('MapperInstance')
84
+ configuration = double('Configuration', default_mapper: default_mapper)
85
+ allow(Guacamole).to receive(:configuration).and_return(configuration)
86
+ allow(default_mapper).to receive(:new).with(subject.model_class).and_return(mapper_instance)
87
+
88
+ expect(subject.mapper).to eq mapper_instance
89
+ end
90
+ end
91
+
92
+ let(:connection) { double('Connection') }
93
+ let(:mapper) { double('Mapper') }
94
+
95
+ before do
96
+ subject.connection = connection
97
+ subject.mapper = mapper
98
+ end
99
+
100
+ describe 'by_key' do
101
+ it 'should get mapped documents by key from the database' do
102
+ document = { data: 'foo' }
103
+ model = double('Model')
104
+
105
+ expect(connection).to receive(:fetch).with('some_key').and_return(document)
106
+ expect(mapper).to receive(:document_to_model).with(document).and_return(model)
107
+
108
+ expect(subject.by_key('some_key')).to eq model
109
+ end
110
+
111
+ it 'should raise a Ashikawa::Core::DocumentNotFoundException exception for nil' do
112
+ expect { subject.by_key(nil) }.to raise_error(Ashikawa::Core::DocumentNotFoundException)
113
+ end
114
+ end
115
+
116
+ describe 'save' do
117
+
118
+ before do
119
+ allow(connection).to receive(:create_document).with(document).and_return(document)
120
+ allow(mapper).to receive(:model_to_document).with(model).and_return(document)
121
+ end
122
+
123
+ let(:key) { double('Key') }
124
+ let(:rev) { double('Rev') }
125
+ let(:document) { double('Document', key: key, revision: rev).as_null_object }
126
+ let(:model) { double('Model').as_null_object }
127
+
128
+ context 'a valid model' do
129
+ before do
130
+ allow(model).to receive(:valid?).and_return(true)
131
+ end
132
+
133
+ it 'should create a document' do
134
+ expect(connection).to receive(:create_document).with(document).and_return(document)
135
+ expect(mapper).to receive(:model_to_document).with(model).and_return(document)
136
+
137
+ subject.save model
138
+ end
139
+
140
+ it 'should return the model after calling save' do
141
+ expect(subject.save(model)).to eq model
142
+ end
143
+
144
+ it 'should set timestamps before creating the document' do
145
+ now = double('Time.now')
146
+
147
+ allow(Time).to receive(:now).once.and_return(now)
148
+
149
+ expect(model).to receive(:created_at=).with(now).ordered
150
+ expect(model).to receive(:updated_at=).with(now).ordered
151
+
152
+ allow(connection).to receive(:create_document).with(document).and_return(document).ordered
153
+
154
+ subject.save model
155
+ end
156
+
157
+ it 'should add key to model' do
158
+ expect(model).to receive(:key=).with(key)
159
+
160
+ subject.save model
161
+ end
162
+
163
+ it 'should add rev to model' do
164
+ expect(model).to receive(:rev=).with(rev)
165
+
166
+ subject.save model
167
+ end
168
+ end
169
+
170
+ context 'an invalid model' do
171
+
172
+ before do
173
+ expect(model).to receive(:valid?).and_return(false)
174
+ end
175
+
176
+ it 'should not be used to create the document' do
177
+ expect(connection).to receive(:create_document).never
178
+
179
+ subject.save model
180
+ end
181
+
182
+ it 'should not be changed' do
183
+ expect(model).to receive(:created_at=).never
184
+ expect(model).to receive(:updated_at=).never
185
+ expect(model).to receive(:key=).never
186
+ expect(model).to receive(:rev=).never
187
+
188
+ subject.save model
189
+ end
190
+
191
+ it 'should return false' do
192
+ expect(subject.save(model)).to be false
193
+ end
194
+ end
195
+ end
196
+
197
+ describe 'delete' do
198
+ let(:document) { double('Document') }
199
+ let(:key) { double('Key') }
200
+ let(:model) { double('Model', key: key) }
201
+
202
+ before do
203
+ allow(connection).to receive(:fetch).with(key).and_return(document)
204
+ allow(document).to receive(:delete)
205
+ end
206
+
207
+ context 'a key was provided' do
208
+ it 'should delete the according document' do
209
+ expect(document).to receive(:delete)
210
+
211
+ subject.delete key
212
+ end
213
+
214
+ it 'should return the according key' do
215
+ expect(subject.delete(key)).to eq key
216
+ end
217
+ end
218
+
219
+ context 'a model was provided' do
220
+ it 'should delete the according document' do
221
+ expect(document).to receive(:delete)
222
+
223
+ subject.delete model
224
+ end
225
+
226
+ it 'should return the according key' do
227
+ expect(subject.delete(model)).to eq key
228
+ end
229
+ end
230
+ end
231
+
232
+ describe 'replace' do
233
+ let(:key) { double('Key') }
234
+ let(:rev) { double('Rev') }
235
+ let(:model) { double('Model', key: key).as_null_object }
236
+ let(:document) { double('Document').as_null_object }
237
+ let(:response) { double('Hash') }
238
+
239
+ before do
240
+ allow(mapper).to receive(:model_to_document).with(model).and_return(document)
241
+ allow(connection).to receive(:replace).and_return(response)
242
+ allow(response).to receive(:[]).with('_rev').and_return(rev)
243
+ end
244
+
245
+ context 'a valid model' do
246
+ before do
247
+ allow(model).to receive(:valid?).and_return(true)
248
+ end
249
+
250
+ it 'should set the updated_at timestamp before replacing the document' do
251
+ now = double('Time.now')
252
+
253
+ allow(Time).to receive(:now).once.and_return(now)
254
+ expect(model).to receive(:updated_at=).with(now)
255
+
256
+ subject.replace model
257
+ end
258
+
259
+ it 'should replace the document by key via the connection' do
260
+ expect(connection).to receive(:replace).with(key, document)
261
+
262
+ subject.replace model
263
+ end
264
+
265
+ it 'should update the revision after replacing the document' do
266
+ allow(connection).to receive(:replace).and_return(response).ordered
267
+ expect(model).to receive(:rev=).with(rev).ordered
268
+
269
+ subject.replace model
270
+ end
271
+
272
+ it 'should return the model' do
273
+ expect(subject.replace(model)).to eq model
274
+ end
275
+
276
+ it 'should not update created_at' do
277
+ expect(model).to receive(:created_at=).never
278
+
279
+ subject.replace model
280
+ end
281
+ end
282
+
283
+ context 'an invalid model' do
284
+ before do
285
+ allow(model).to receive(:valid?).and_return(false)
286
+ end
287
+
288
+ it 'should not be used to replace the document' do
289
+ expect(connection).to receive(:replace).never
290
+
291
+ subject.replace model
292
+ end
293
+
294
+ it 'should not be changed' do
295
+ expect(model).to receive(:rev=).never
296
+ expect(model).to receive(:updated_at=).never
297
+
298
+ subject.replace model
299
+ end
300
+
301
+ it 'should return false' do
302
+ expect(subject.replace(model)).to be false
303
+ end
304
+ end
305
+ end
306
+
307
+ describe 'by_example' do
308
+ let(:example) { double }
309
+ let(:query_connection) { double }
310
+ let(:query) { double }
311
+
312
+ before do
313
+ allow(connection).to receive(:query)
314
+ .and_return(query_connection)
315
+
316
+ allow(Guacamole::Query).to receive(:new)
317
+ .and_return(query)
318
+
319
+ allow(query).to receive(:example=)
320
+ end
321
+
322
+ it 'should create a new query with the query connection and mapper' do
323
+ expect(Guacamole::Query).to receive(:new)
324
+ .with(query_connection, mapper)
325
+
326
+ subject.by_example(example)
327
+ end
328
+
329
+ it 'should set the example for the query' do
330
+ expect(query).to receive(:example=)
331
+ .with(example)
332
+
333
+ subject.by_example(example)
334
+ end
335
+
336
+ it 'should return the query' do
337
+ expect(subject.by_example(example)).to be query
338
+ end
339
+ end
340
+
341
+ describe 'all' do
342
+ let(:query_connection) { double }
343
+ let(:query) { double }
344
+
345
+ before do
346
+ allow(connection).to receive(:query)
347
+ .and_return(query_connection)
348
+
349
+ allow(Guacamole::Query).to receive(:new)
350
+ .and_return(query)
351
+ end
352
+
353
+ it 'should create a new query with the query connection and mapper' do
354
+ expect(Guacamole::Query).to receive(:new)
355
+ .with(query_connection, mapper)
356
+
357
+ subject.all
358
+ end
359
+
360
+ it 'should return the query' do
361
+ expect(subject.all).to be query
362
+ end
363
+ end
364
+
365
+ describe 'map' do
366
+ let(:mapper) { double('Mapper') }
367
+
368
+ before do
369
+ subject.mapper = mapper
370
+ end
371
+
372
+ it 'should evaluate the block on the mapper instance' do
373
+ expect(mapper).to receive(:method_to_call_on_mapper)
374
+
375
+ subject.map do
376
+ method_to_call_on_mapper
377
+ end
378
+ end
379
+ end
380
+ end