guacamole 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/.travis.yml +18 -0
- data/CONTRIBUTING.md +26 -0
- data/Gemfile +16 -0
- data/Gemfile.devtools +55 -0
- data/Guardfile +13 -0
- data/LICENSE +202 -0
- data/README.md +130 -0
- data/Rakefile +7 -0
- data/config/devtools.yml +4 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/mutant.yml +3 -0
- data/config/reek.yml +104 -0
- data/config/rubocop.yml +68 -0
- data/config/yardstick.yml +2 -0
- data/guacamole.gemspec +28 -0
- data/lib/guacamole.rb +19 -0
- data/lib/guacamole/collection.rb +246 -0
- data/lib/guacamole/configuration.rb +123 -0
- data/lib/guacamole/document_model_mapper.rb +95 -0
- data/lib/guacamole/model.rb +210 -0
- data/lib/guacamole/query.rb +72 -0
- data/lib/guacamole/railtie.rb +27 -0
- data/lib/guacamole/railtie/database.rake +5 -0
- data/lib/guacamole/version.rb +5 -0
- data/log/.gitkeep +0 -0
- data/spec/acceptance/.gitkeep +0 -0
- data/spec/acceptance/basic_spec.rb +112 -0
- data/spec/acceptance/config/guacamole.yml +11 -0
- data/spec/acceptance/spec_helper.rb +61 -0
- data/spec/fabricators/article_fabricator.rb +10 -0
- data/spec/fabricators/comment_fabricator.rb +5 -0
- data/spec/setup/arangodb.sh +65 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/unit/.gitkeep +0 -0
- data/spec/unit/collection_spec.rb +380 -0
- data/spec/unit/configuration_spec.rb +119 -0
- data/spec/unit/document_model_mapper_spec.rb +120 -0
- data/spec/unit/example_spec.rb +8 -0
- data/spec/unit/model_spec.rb +116 -0
- data/spec/unit/query_spec.rb +140 -0
- data/tasks/adjustments.rake +35 -0
- metadata +191 -0
@@ -0,0 +1,119 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'guacamole/configuration'
|
5
|
+
|
6
|
+
describe 'Guacamole.configure' do
|
7
|
+
subject { Guacamole }
|
8
|
+
|
9
|
+
it 'should yield the Configuration class' do
|
10
|
+
subject.configure do |config|
|
11
|
+
expect(config).to eq Guacamole::Configuration
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'Guacamole.configuration' do
|
17
|
+
subject { Guacamole }
|
18
|
+
|
19
|
+
it 'should return the Configuration class' do
|
20
|
+
expect(Guacamole.configuration).to eq Guacamole::Configuration
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe Guacamole::Configuration do
|
25
|
+
subject { Guacamole::Configuration }
|
26
|
+
|
27
|
+
describe 'database' do
|
28
|
+
it 'should set the logger' do
|
29
|
+
database = double('Database')
|
30
|
+
subject.database = database
|
31
|
+
|
32
|
+
expect(subject.database).to eq database
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'default_mapper' do
|
37
|
+
it 'should set the default mapper' do
|
38
|
+
default_mapper = double('Mapper')
|
39
|
+
subject.default_mapper = default_mapper
|
40
|
+
|
41
|
+
expect(subject.default_mapper).to eq default_mapper
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should return Guacamole::DocumentModelMapper as default' do
|
45
|
+
subject.default_mapper = nil
|
46
|
+
|
47
|
+
expect(subject.default_mapper).to eq Guacamole::DocumentModelMapper
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe 'logger' do
|
52
|
+
before do
|
53
|
+
subject.logger = nil
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should set the logger' do
|
57
|
+
logger = double('Logger')
|
58
|
+
allow(logger).to receive(:level=)
|
59
|
+
subject.logger = logger
|
60
|
+
|
61
|
+
expect(subject.logger).to eq logger
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should default to Logger.new(STDOUT)' do
|
65
|
+
expect(subject.logger).to be_a Logger
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should set the log level to :info for the default logger' do
|
69
|
+
expect(subject.logger.level).to eq Logger::INFO
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'load' do
|
74
|
+
let(:config) { double('Config') }
|
75
|
+
let(:current_environment) { 'development' }
|
76
|
+
|
77
|
+
before do
|
78
|
+
allow(subject).to receive(:current_environment).and_return(current_environment)
|
79
|
+
allow(subject).to receive(:database=)
|
80
|
+
allow(subject).to receive(:create_database_connection_from)
|
81
|
+
allow(config).to receive(:[]).with('development')
|
82
|
+
allow(YAML).to receive(:load_file).with('config_file.yml').and_return(config)
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should parse a YAML configuration' do
|
86
|
+
expect(YAML).to receive(:load_file).with('config_file.yml').and_return(config)
|
87
|
+
|
88
|
+
subject.load 'config_file.yml'
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should load the part for the current environment from the config file' do
|
92
|
+
expect(config).to receive(:[]).with(current_environment)
|
93
|
+
|
94
|
+
subject.load 'config_file.yml'
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should create an Ashikawa::Core::Database instance based on configuration' do
|
98
|
+
arango_config = double('ArangoConfig')
|
99
|
+
expect(arango_config).to receive(:url=).with('http://localhost:8529/_db/test_db')
|
100
|
+
expect(arango_config).to receive(:username=).with('')
|
101
|
+
expect(arango_config).to receive(:password=).with('')
|
102
|
+
expect(arango_config).to receive(:logger=).with(subject.logger)
|
103
|
+
|
104
|
+
allow(Ashikawa::Core::Database).to receive(:new).and_yield(arango_config)
|
105
|
+
|
106
|
+
allow(config).to receive(:[]).with('development').and_return(
|
107
|
+
'protocol' => 'http',
|
108
|
+
'host' => 'localhost',
|
109
|
+
'port' => 8529,
|
110
|
+
'username' => '',
|
111
|
+
'password' => '',
|
112
|
+
'database' => 'test_db'
|
113
|
+
)
|
114
|
+
allow(subject).to receive(:create_database_connection_from).and_call_original
|
115
|
+
|
116
|
+
subject.load 'config_file.yml'
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'guacamole/document_model_mapper'
|
5
|
+
|
6
|
+
class FancyModel
|
7
|
+
end
|
8
|
+
|
9
|
+
describe Guacamole::DocumentModelMapper do
|
10
|
+
subject { Guacamole::DocumentModelMapper }
|
11
|
+
|
12
|
+
it 'should be initialized with a model class' do
|
13
|
+
mapper = subject.new FancyModel
|
14
|
+
expect(mapper.model_class).to eq FancyModel
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'document_to_model' do
|
18
|
+
subject { Guacamole::DocumentModelMapper.new FancyModel }
|
19
|
+
|
20
|
+
let(:document) { double('Ashikawa::Core::Document') }
|
21
|
+
let(:document_attributes) { double('Hash') }
|
22
|
+
let(:model_instance) { double('ModelInstance').as_null_object }
|
23
|
+
let(:some_key) { double('Key') }
|
24
|
+
let(:some_rev) { double('Rev') }
|
25
|
+
|
26
|
+
before do
|
27
|
+
allow(subject.model_class).to receive(:new).and_return(model_instance)
|
28
|
+
allow(document).to receive(:hash).and_return(document_attributes)
|
29
|
+
allow(document).to receive(:key).and_return(some_key)
|
30
|
+
allow(document).to receive(:revision).and_return(some_rev)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should create a new model instance from an Ashikawa::Core::Document' do
|
34
|
+
expect(subject.model_class).to receive(:new).with(document_attributes)
|
35
|
+
|
36
|
+
model = subject.document_to_model document
|
37
|
+
expect(model).to eq model_instance
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should set the rev and key on a new model instance' do
|
41
|
+
expect(model_instance).to receive(:key=).with(some_key)
|
42
|
+
expect(model_instance).to receive(:rev=).with(some_rev)
|
43
|
+
|
44
|
+
subject.document_to_model document
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'with embedded ponies' do
|
48
|
+
# This is handled by Virtus, we just need to provide a hash
|
49
|
+
# and the coercing will be taken care of by Virtus
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe 'model_to_document' do
|
54
|
+
subject { Guacamole::DocumentModelMapper.new FancyModel }
|
55
|
+
|
56
|
+
let(:model) { double('Model') }
|
57
|
+
let(:model_attributes) { double('Hash').as_null_object }
|
58
|
+
|
59
|
+
before do
|
60
|
+
allow(model).to receive(:attributes).and_return(model_attributes)
|
61
|
+
allow(model_attributes).to receive(:dup).and_return(model_attributes)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should transform a model into a simple hash' do
|
65
|
+
expect(subject.model_to_document(model)).to eq model_attributes
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should return a copy of the model attributes hash' do
|
69
|
+
expect(model_attributes).to receive(:dup).and_return(model_attributes)
|
70
|
+
|
71
|
+
subject.model_to_document(model)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should remove the key and rev attributes from the document' do
|
75
|
+
expect(model_attributes).to receive(:except).with(:key, :rev)
|
76
|
+
|
77
|
+
subject.model_to_document(model)
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'with embedded ponies' do
|
81
|
+
let(:somepony) { double('Pony') }
|
82
|
+
let(:pony_array) { [somepony] }
|
83
|
+
let(:ponylicious_attributes) { double('Hash').as_null_object }
|
84
|
+
|
85
|
+
before do
|
86
|
+
subject.embeds :ponies
|
87
|
+
|
88
|
+
allow(model).to receive(:ponies)
|
89
|
+
.and_return pony_array
|
90
|
+
|
91
|
+
allow(somepony).to receive(:attributes)
|
92
|
+
.and_return ponylicious_attributes
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'should convert all embedded ponies to pony hashes' do
|
96
|
+
expect(somepony).to receive(:attributes)
|
97
|
+
.and_return ponylicious_attributes
|
98
|
+
|
99
|
+
subject.model_to_document(model)
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'should exclude key and rev on embedded ponies' do
|
103
|
+
expect(ponylicious_attributes).to receive(:except)
|
104
|
+
.with(:key, :rev)
|
105
|
+
|
106
|
+
subject.model_to_document(model)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe 'embed' do
|
112
|
+
subject { Guacamole::DocumentModelMapper.new FancyModel }
|
113
|
+
|
114
|
+
it 'should remember which models to embed' do
|
115
|
+
subject.embeds :ponies
|
116
|
+
|
117
|
+
expect(subject.models_to_embed).to include :ponies
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'guacamole/model'
|
5
|
+
|
6
|
+
class TestModel
|
7
|
+
include Guacamole::Model
|
8
|
+
end
|
9
|
+
|
10
|
+
class OtherModel
|
11
|
+
include Guacamole::Model
|
12
|
+
end
|
13
|
+
|
14
|
+
describe Guacamole::Model do
|
15
|
+
subject { TestModel }
|
16
|
+
let(:current_time) { Time.now }
|
17
|
+
|
18
|
+
describe 'module inclusion' do
|
19
|
+
it 'should include Virtus.model' do
|
20
|
+
expect(subject.ancestors.any? do |ancestor|
|
21
|
+
ancestor.to_s.include? 'Virtus'
|
22
|
+
end).to be_true
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should include ActiveModel::Validation' do
|
26
|
+
expect(subject.ancestors).to include ActiveModel::Validations
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should include ActiveModel::Naming' do
|
30
|
+
expect(subject.ancestors).to include ActiveModel::Naming
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should include ActiveModel::Conversion' do
|
34
|
+
expect(subject.ancestors).to include ActiveModel::Conversion
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe 'default attributes' do
|
39
|
+
subject { TestModel.new }
|
40
|
+
|
41
|
+
it 'should add the key attribute' do
|
42
|
+
subject.key = '12345'
|
43
|
+
expect(subject.key).to eq '12345'
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should add the rev attribute' do
|
47
|
+
subject.rev = '98765'
|
48
|
+
expect(subject.rev).to eq '98765'
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should add the created_at attribute' do
|
52
|
+
subject.created_at = current_time
|
53
|
+
expect(subject.created_at).to be current_time
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should add the updated_at attribute' do
|
57
|
+
subject.updated_at = current_time
|
58
|
+
expect(subject.updated_at).to be current_time
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe 'persisted?' do
|
63
|
+
subject { TestModel.new }
|
64
|
+
|
65
|
+
it 'should be persisted if it has a key' do
|
66
|
+
subject.key = 'my_key'
|
67
|
+
expect(subject.persisted?).to be_true
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should not be persisted if it doesn't have a key" do
|
71
|
+
subject.key = nil
|
72
|
+
expect(subject.persisted?).to be_false
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe 'id' do
|
77
|
+
subject { TestModel.new }
|
78
|
+
|
79
|
+
it 'should alias key to id for ActiveModel::Conversion compliance' do
|
80
|
+
subject.key = 'my_key'
|
81
|
+
expect(subject.id).to eq 'my_key'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe '==' do
|
86
|
+
let(:key) { double('Key') }
|
87
|
+
let(:rev) { double('Rev') }
|
88
|
+
let(:updated_at) { Time.now }
|
89
|
+
let(:content) { double('String') }
|
90
|
+
let(:unixy_time) { 1_445_444_940 } # If you read this line and understand it, you get a beer
|
91
|
+
let(:timestamp_without_nsecs) { Time.at(unixy_time, 0) }
|
92
|
+
let(:timestamp_with_nsecs) { Time.at(unixy_time, 42) }
|
93
|
+
|
94
|
+
subject { TestModel.new(key: key, rev: rev, updated_at: updated_at, content: content) }
|
95
|
+
let(:comparison_object) { TestModel.new(subject.attributes) }
|
96
|
+
|
97
|
+
it 'should not be equal if it is a different class' do
|
98
|
+
expect(subject).to_not eq double
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should be equal if all attributes are equal' do
|
102
|
+
expect(subject).to eq comparison_object
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should be equal if the time is equal in string representation' do
|
106
|
+
subject.updated_at = timestamp_with_nsecs
|
107
|
+
comparison_object.updated_at = timestamp_without_nsecs
|
108
|
+
|
109
|
+
expect(subject).to eq comparison_object
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should alias `eql?` to `==`' do
|
113
|
+
expect(subject).to eql comparison_object
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'guacamole/query'
|
5
|
+
|
6
|
+
describe Guacamole::Query do
|
7
|
+
let(:connection) { double('Connection') }
|
8
|
+
let(:mapper) { double('Mapper') }
|
9
|
+
|
10
|
+
subject { Guacamole::Query.new(connection, mapper) }
|
11
|
+
|
12
|
+
its(:connection) { should be connection }
|
13
|
+
its(:mapper) { should be mapper }
|
14
|
+
|
15
|
+
it 'should be enumerable' do
|
16
|
+
expect(Guacamole::Query.ancestors).to include Enumerable
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'each' do
|
20
|
+
let(:result) { double }
|
21
|
+
let(:document) { double }
|
22
|
+
let(:model) { double }
|
23
|
+
let(:limit) { double }
|
24
|
+
let(:skip) { double }
|
25
|
+
|
26
|
+
before do
|
27
|
+
allow(result).to receive(:each)
|
28
|
+
.and_yield(document)
|
29
|
+
|
30
|
+
allow(mapper).to receive(:document_to_model)
|
31
|
+
.and_return(model)
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'no example was provided' do
|
35
|
+
before do
|
36
|
+
allow(connection).to receive(:all)
|
37
|
+
.and_return(result)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should get all documents' do
|
41
|
+
expect(connection).to receive(:all)
|
42
|
+
.with({})
|
43
|
+
|
44
|
+
subject.each { }
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should iterate over the resulting documents' do
|
48
|
+
expect(result).to receive(:each)
|
49
|
+
|
50
|
+
subject.each { }
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should yield the models to the caller' do
|
54
|
+
expect { |b| subject.each(&b) }.to yield_with_args(model)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should return an enumerator when called without a block' do
|
58
|
+
expect(subject.each).to be_an Enumerator
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should accept a limit' do
|
62
|
+
expect(connection).to receive(:all)
|
63
|
+
.with(hash_including limit: limit)
|
64
|
+
|
65
|
+
subject.limit(limit).each { }
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should accept a skip' do
|
69
|
+
expect(connection).to receive(:all)
|
70
|
+
.with(hash_including skip: skip)
|
71
|
+
|
72
|
+
subject.skip(skip).each { }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'an example was provided' do
|
77
|
+
let(:example) { double }
|
78
|
+
before do
|
79
|
+
subject.example = example
|
80
|
+
|
81
|
+
allow(connection).to receive(:by_example)
|
82
|
+
.and_return(result)
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should query by the given example' do
|
86
|
+
expect(connection).to receive(:by_example)
|
87
|
+
.with(example, {})
|
88
|
+
|
89
|
+
subject.each { }
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should iterate over the resulting documents' do
|
93
|
+
expect(result).to receive(:each)
|
94
|
+
|
95
|
+
subject.each { }
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should yield the models to the caller' do
|
99
|
+
expect { |b| subject.each(&b) }.to yield_with_args(model)
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'should return an enumerator when called without a block' do
|
103
|
+
expect(subject.each).to be_an Enumerator
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should accept a limit' do
|
107
|
+
expect(connection).to receive(:by_example)
|
108
|
+
.with(example, hash_including(limit: limit))
|
109
|
+
|
110
|
+
subject.limit(limit).each { }
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'should accept a skip' do
|
114
|
+
expect(connection).to receive(:by_example)
|
115
|
+
.with(example, hash_including(skip: skip))
|
116
|
+
|
117
|
+
subject.skip(skip).each { }
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe 'first' do
|
123
|
+
context 'no example was provided' do
|
124
|
+
it 'should return the first result of the all query' do
|
125
|
+
first_result = double
|
126
|
+
first_result_as_model = double
|
127
|
+
results = [first_result]
|
128
|
+
|
129
|
+
allow(mapper).to receive(:document_to_model)
|
130
|
+
.with(first_result)
|
131
|
+
.and_return(first_result_as_model)
|
132
|
+
|
133
|
+
allow(connection).to receive(:all)
|
134
|
+
.and_return(results)
|
135
|
+
|
136
|
+
expect(subject.first).to be first_result_as_model
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|