rmodel 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 +22 -0
- data/.rspec +3 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +165 -0
- data/Rakefile +2 -0
- data/examples/user.rb +48 -0
- data/lib/rmodel/errors.rb +7 -0
- data/lib/rmodel/mongo/repository.rb +65 -0
- data/lib/rmodel/mongo/repository_ext/query.rb +34 -0
- data/lib/rmodel/mongo/repository_ext/queryable.rb +34 -0
- data/lib/rmodel/mongo/setup.rb +17 -0
- data/lib/rmodel/mongo/simple_factory.rb +28 -0
- data/lib/rmodel/setup.rb +33 -0
- data/lib/rmodel/version.rb +3 -0
- data/lib/rmodel.rb +10 -0
- data/rmodel.gemspec +28 -0
- data/spec/rmodel/mongo/repository_crud_spec.rb +115 -0
- data/spec/rmodel/mongo/repository_initialize_spec.rb +140 -0
- data/spec/rmodel/mongo/repository_queryable_spec.rb +107 -0
- data/spec/rmodel/mongo/simple_factory_spec.rb +55 -0
- data/spec/rmodel/setup_spec.rb +54 -0
- data/spec/shared/clean_moped.rb +10 -0
- data/spec/spec_helper.rb +100 -0
- metadata +160 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: deb9462cdda8354cf1ae328254df31b82ddd3a74
|
4
|
+
data.tar.gz: 98e72a0ff775b44114b7c90383046806f15948db
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dd4006a1d057a592bac459e31f39039c496a89d9c379c7953bea129bc8e3acbd92f13b7cd6d2c32a5ad8ee8a71caebdd8b72a9cd328de1ed41f697ab033b8be3
|
7
|
+
data.tar.gz: d3e1d56effdceeb17d3978b8242f35aaf9689b2eddf5b71fffc30e6665aea25972672bddcf1d1d3f4053559ffe59cc7d74362cacb5d7877befcaf10cf5c33279
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Alexei
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
[](https://travis-ci.org/alexei-lexx/rmodel)
|
2
|
+
|
3
|
+
# Rmodel
|
4
|
+
|
5
|
+
Rmodel is an ORM library, which tends to follow the SOLID principles.
|
6
|
+
|
7
|
+
The main thoughts behind it are:
|
8
|
+
|
9
|
+
* let you models be simple and independent of the persistent layer,
|
10
|
+
* be able to switch the persistent layer at any moment,
|
11
|
+
* keep the simplicity of the Active Record pattern by default,
|
12
|
+
* be able to implement any type of persistence: SQL, NoSQL, files, HTTP etc.
|
13
|
+
|
14
|
+
It consists of 3 major components:
|
15
|
+
|
16
|
+
1. **Entities**; ex.: User, Order etc.
|
17
|
+
2. **Repositories**, which are used to fetch, save and delete entities; ex.: UserRepository, OrderRepository
|
18
|
+
3. **Factories**, which play the role of mappers.
|
19
|
+
|
20
|
+
Basic implemented features:
|
21
|
+
|
22
|
+
1. CRUD operations: `find`, `insert`, `update`, `remove`;
|
23
|
+
2. Scopes: `userRepository.query.recent.sorted`
|
24
|
+
3. Based on query operations: `userRepository.query.recent.remove`
|
25
|
+
|
26
|
+
## Installation
|
27
|
+
|
28
|
+
Add this line to your application's Gemfile:
|
29
|
+
|
30
|
+
gem 'rmodel'
|
31
|
+
|
32
|
+
And then execute:
|
33
|
+
|
34
|
+
$ bundle
|
35
|
+
|
36
|
+
Or install it yourself as:
|
37
|
+
|
38
|
+
$ gem install rmodel
|
39
|
+
|
40
|
+
## Usage
|
41
|
+
|
42
|
+
Let's define an entity
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
class User
|
46
|
+
attr_accessor :id, :name, :email
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
As you see it's a plain ruby class with attributes. It must have either the zero-argument `#initialize` method or no `#initialize` at all.
|
51
|
+
|
52
|
+
Of course we need a repository to save users.
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
require 'rmodel' # dont forget to require the gem
|
56
|
+
|
57
|
+
class User
|
58
|
+
attr_accessor :id, :name, :email
|
59
|
+
end
|
60
|
+
|
61
|
+
class UserRepository < Rmodel::Mongo::Repository
|
62
|
+
end
|
63
|
+
|
64
|
+
userRepository = UserRepository.new
|
65
|
+
```
|
66
|
+
The code above raises the exception *Client driver is not setup (ArgumentError)*. UserRepository derives from Rmodel::Mongo::Repository, which uses the ruby mongo driver to access the database. We must provide the appropriate connection options. To do this we use the following code:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
require 'rmodel'
|
70
|
+
|
71
|
+
Rmodel.setup do
|
72
|
+
client :default, { hosts: [ 'localhost' ], database: 'test' }
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
The `:default` client is used by every repository that doesn't specify it's client explicitly.
|
77
|
+
|
78
|
+
Run the code again and get another error *Factory can not be guessed (ArgumentError)*. The factory is used to convert the array of database tuples (hashes) to the array of User objects.
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
class UserRepository < Rmodel::Mongo::Repository
|
82
|
+
simple_factory User, :name, :email
|
83
|
+
end
|
84
|
+
```
|
85
|
+
|
86
|
+
The `simple_factory` class macro says that every database tuple will be straightforwardly converted to an instance of User with attributes :id, :name and :email. There is no need to specify :id, because it's required.
|
87
|
+
|
88
|
+
### CRUD
|
89
|
+
|
90
|
+
Let's create and insert several users.
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
john = User.new('John', 'john@example.com')
|
94
|
+
bill = User.new('Bill', 'bill@example.com')
|
95
|
+
bob = User.new('Bob', 'bob@example.com')
|
96
|
+
|
97
|
+
userRepository.insert(john)
|
98
|
+
userRepository.insert(bill)
|
99
|
+
userRepository.insert(bob)
|
100
|
+
```
|
101
|
+
|
102
|
+
Now you can check you `test` database. There are 3 new users there. Print the `john`. As you can see it's got the `@id`.
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
p john
|
106
|
+
#<User:0x00... @name="John", @email="john@example.com", @id=BSON::ObjectId('562a...')>
|
107
|
+
```
|
108
|
+
|
109
|
+
Let's update John and remove Bob.
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
john.name = 'John Smith'
|
113
|
+
userRepository.update(john)
|
114
|
+
|
115
|
+
userRepository.remove(bob)
|
116
|
+
|
117
|
+
p userRepository.find(john.id) # #<User:0x000000037237d0 @name="John Smith" ... >
|
118
|
+
p userRepository.find(bob.id) # nil
|
119
|
+
p userRepository.find!(bob.id) # nil
|
120
|
+
```
|
121
|
+
|
122
|
+
### Scopes
|
123
|
+
|
124
|
+
Scopes are defined inside the repository.
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
class UserRepository < Rmodel::Mongo::Repository
|
128
|
+
simple_factory User, :name, :email
|
129
|
+
|
130
|
+
scope :have_email do
|
131
|
+
where(email: { '$exists' => true })
|
132
|
+
end
|
133
|
+
|
134
|
+
scope :start_with do |letter|
|
135
|
+
where(name: { '$regex' => "^#{letter}", '$options' => 'i' })
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
userRepository.query.start_with('b').to_a
|
140
|
+
```
|
141
|
+
|
142
|
+
Of course you can chain scopes.
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
userRepository.query.start_with('b').have_email
|
146
|
+
```
|
147
|
+
|
148
|
+
The result of the scope is Enumerable, so you can apply the #each method and others (map, select etc).
|
149
|
+
|
150
|
+
Inside the scopes you can use any methods supported by the driver (database client). In our case we use Origin (https://github.com/mongoid/origin) as a query builder for mongo.
|
151
|
+
|
152
|
+
Also it's possible to use scopes to run the multi-row operations.
|
153
|
+
|
154
|
+
```ruby
|
155
|
+
userRepository.query.have_email.remove
|
156
|
+
p userRepository.query.count # 0
|
157
|
+
```
|
158
|
+
|
159
|
+
## Contributing
|
160
|
+
|
161
|
+
1. Fork it ( https://github.com/alexei-lexx/rmodel/fork )
|
162
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
163
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
164
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
165
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/examples/user.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rmodel'
|
2
|
+
|
3
|
+
Rmodel.setup do
|
4
|
+
client :default, { hosts: [ 'localhost' ], database: 'test' }
|
5
|
+
end
|
6
|
+
|
7
|
+
class User
|
8
|
+
attr_accessor :id, :name, :email
|
9
|
+
|
10
|
+
def initialize(name = nil, email = nil)
|
11
|
+
self.name = name
|
12
|
+
self.email = email
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class UserRepository < Rmodel::Mongo::Repository
|
17
|
+
simple_factory User, :name, :email
|
18
|
+
|
19
|
+
scope :have_email do
|
20
|
+
where(email: { '$exists' => true })
|
21
|
+
end
|
22
|
+
|
23
|
+
scope :start_with do |letter|
|
24
|
+
where(name: { '$regex' => "^#{letter}", '$options' => 'i' })
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
userRepository = UserRepository.new
|
29
|
+
userRepository.query.remove
|
30
|
+
|
31
|
+
john = User.new('John', 'john@example.com')
|
32
|
+
bill = User.new('Bill', 'bill@example.com')
|
33
|
+
bob = User.new('Bob', 'bob@example.com')
|
34
|
+
|
35
|
+
userRepository.insert(john)
|
36
|
+
userRepository.insert(bill)
|
37
|
+
userRepository.insert(bob)
|
38
|
+
|
39
|
+
john.name = 'John Smith'
|
40
|
+
userRepository.update(john)
|
41
|
+
|
42
|
+
userRepository.remove(bob)
|
43
|
+
|
44
|
+
p userRepository.find(john.id)
|
45
|
+
p userRepository.find(bob.id)
|
46
|
+
|
47
|
+
userRepository.query.have_email.remove
|
48
|
+
p userRepository.query.count
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'mongo'
|
2
|
+
require 'active_support/inflector'
|
3
|
+
require 'rmodel/mongo/repository_ext/queryable'
|
4
|
+
|
5
|
+
module Rmodel::Mongo
|
6
|
+
class Repository
|
7
|
+
include RepositoryExt::Queryable
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@client = Rmodel.setup.establish_mongo_client(self.class.client_name || :default) or
|
11
|
+
raise ArgumentError.new('Client driver is not setup')
|
12
|
+
|
13
|
+
@collection = self.class.setting_collection ||
|
14
|
+
self.class.collection_by_convention or
|
15
|
+
raise ArgumentError.new('Collection can not be guessed')
|
16
|
+
|
17
|
+
@factory = self.class.setting_factory or
|
18
|
+
raise ArgumentError.new('Factory can not be guessed')
|
19
|
+
end
|
20
|
+
|
21
|
+
def find(id)
|
22
|
+
result = @client[@collection].find(_id: id).first
|
23
|
+
result && @factory.fromHash(result)
|
24
|
+
end
|
25
|
+
|
26
|
+
def find!(id)
|
27
|
+
find(id) or raise Rmodel::NotFound.new(self, { id: id })
|
28
|
+
end
|
29
|
+
|
30
|
+
def insert(object)
|
31
|
+
object.id ||= BSON::ObjectId.new
|
32
|
+
@client[@collection].insert_one(@factory.toHash(object, true))
|
33
|
+
end
|
34
|
+
|
35
|
+
def update(object)
|
36
|
+
@client[@collection].find(_id: object.id).update_one(@factory.toHash(object, false))
|
37
|
+
end
|
38
|
+
|
39
|
+
def remove(object)
|
40
|
+
@client[@collection].find(_id: object.id).delete_one
|
41
|
+
end
|
42
|
+
|
43
|
+
class << self
|
44
|
+
attr_reader :client_name, :setting_collection, :setting_factory
|
45
|
+
|
46
|
+
def client(name)
|
47
|
+
@client_name = name
|
48
|
+
end
|
49
|
+
|
50
|
+
def collection(name)
|
51
|
+
@setting_collection = name
|
52
|
+
end
|
53
|
+
|
54
|
+
def collection_by_convention
|
55
|
+
if name =~ /(.*)Repository$/
|
56
|
+
ActiveSupport::Inflector.tableize($1).to_sym
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def simple_factory(klass, *attributes)
|
61
|
+
@setting_factory = SimpleFactory.new(klass, *attributes)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'origin'
|
2
|
+
|
3
|
+
module Rmodel::Mongo
|
4
|
+
module RepositoryExt
|
5
|
+
class Query
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
class Queryable
|
9
|
+
include Origin::Queryable
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(repo, queryable = nil)
|
13
|
+
@repo = repo
|
14
|
+
@queryable = queryable || Queryable.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def each(&block)
|
18
|
+
@repo.find_by_query(@queryable.selector, @queryable.options).each(&block)
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def remove
|
23
|
+
@repo.execute_query(@queryable.selector, @queryable.options).delete_many
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.define_scope(name, &block)
|
27
|
+
define_method name do |*args|
|
28
|
+
new_queryable = @queryable.instance_exec(*args, &block)
|
29
|
+
self.class.new(@repo, new_queryable)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rmodel/mongo/repository_ext/query'
|
2
|
+
|
3
|
+
module Rmodel::Mongo
|
4
|
+
module RepositoryExt
|
5
|
+
module Queryable
|
6
|
+
def self.included(base)
|
7
|
+
base.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
def query
|
11
|
+
(self.class.query_klass ||= Class.new(Query)).new(self)
|
12
|
+
end
|
13
|
+
|
14
|
+
def find_by_query(selector, options)
|
15
|
+
execute_query(selector, options).map do |hash|
|
16
|
+
@factory.fromHash(hash)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def execute_query(selector, options)
|
21
|
+
@client[@collection].find(selector, options)
|
22
|
+
end
|
23
|
+
|
24
|
+
module ClassMethods
|
25
|
+
attr_accessor :query_klass
|
26
|
+
|
27
|
+
def scope(name, &block)
|
28
|
+
self.query_klass ||= Class.new(Query)
|
29
|
+
self.query_klass.define_scope(name, &block)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Rmodel::Mongo
|
2
|
+
module Setup
|
3
|
+
def establish_mongo_client(name)
|
4
|
+
config = @clients_config[name]
|
5
|
+
if config
|
6
|
+
options = config.dup
|
7
|
+
options.delete :hosts
|
8
|
+
|
9
|
+
establish_client(name) { Mongo::Client.new(config[:hosts], options) }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Rmodel::Setup
|
16
|
+
include Rmodel::Mongo::Setup
|
17
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Rmodel::Mongo
|
2
|
+
class SimpleFactory
|
3
|
+
def initialize(klass, *attributes)
|
4
|
+
@klass = klass
|
5
|
+
@attributes = attributes
|
6
|
+
end
|
7
|
+
|
8
|
+
def fromHash(hash)
|
9
|
+
object = @klass.new
|
10
|
+
object.id = hash['_id']
|
11
|
+
@attributes.each do |attribute|
|
12
|
+
object.public_send "#{attribute}=", hash[attribute.to_s]
|
13
|
+
end
|
14
|
+
object
|
15
|
+
end
|
16
|
+
|
17
|
+
def toHash(object, id_included)
|
18
|
+
hash = {}
|
19
|
+
@attributes.each do |attribute|
|
20
|
+
hash[attribute.to_s] = object.public_send(attribute)
|
21
|
+
end
|
22
|
+
if id_included
|
23
|
+
hash['_id'] = object.id
|
24
|
+
end
|
25
|
+
hash
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/rmodel/setup.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module Rmodel
|
4
|
+
class Setup
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@clients_config = {}
|
9
|
+
@established_clients = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def client(name, config)
|
13
|
+
@clients_config[name] = config
|
14
|
+
end
|
15
|
+
|
16
|
+
def clear
|
17
|
+
@clients_config.clear
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def establish_client(name)
|
23
|
+
@established_clients[name] ||= yield
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.setup(&block)
|
28
|
+
if block
|
29
|
+
Setup.instance.instance_eval &block
|
30
|
+
end
|
31
|
+
Setup.instance
|
32
|
+
end
|
33
|
+
end
|
data/lib/rmodel.rb
ADDED
data/rmodel.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rmodel/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'rmodel'
|
8
|
+
spec.version = Rmodel::VERSION
|
9
|
+
spec.authors = ['Alexei']
|
10
|
+
spec.email = ['alexei.lexx@gmail.com']
|
11
|
+
spec.summary = %q{Rmodel is an ORM library, which tends to follow the SOLID principles.}
|
12
|
+
spec.description = %q{Rmodel is an ORM library, which tends to follow the SOLID principles.}
|
13
|
+
spec.homepage = 'https://github.com/alexei-lexx/rmodel'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_dependency 'mongo', '~> 2.1'
|
22
|
+
spec.add_dependency 'activesupport'
|
23
|
+
spec.add_dependency 'origin'
|
24
|
+
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
26
|
+
spec.add_development_dependency 'rake'
|
27
|
+
spec.add_development_dependency 'rspec'
|
28
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
RSpec.describe Rmodel::Mongo::Repository do
|
2
|
+
include_context 'clean Mongo database'
|
3
|
+
|
4
|
+
before do
|
5
|
+
stub_const('User', Struct.new(:id, :name, :email))
|
6
|
+
stub_const('UserRepository', Class.new(Rmodel::Mongo::Repository) {
|
7
|
+
simple_factory User, :name, :email
|
8
|
+
})
|
9
|
+
Rmodel.setup do
|
10
|
+
client :default, hosts: [ 'localhost' ], database: 'rmodel_test'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:factory) { Rmodel::Mongo::SimpleFactory.new(User, :name, :email) }
|
15
|
+
subject(:repo) { UserRepository.new }
|
16
|
+
|
17
|
+
describe '#find' do
|
18
|
+
context 'when an existent id is given' do
|
19
|
+
before do
|
20
|
+
mongo_session[:users].insert_one(_id: 1, name: 'John', email: 'john@example.com')
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'returns the instance of correct type' do
|
24
|
+
expect(repo.find(1)).to be_an_instance_of User
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when a non-existent id is given' do
|
29
|
+
it 'returns nil' do
|
30
|
+
expect(repo.find(1)).to be_nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#find!' do
|
36
|
+
context 'when an existent id is given' do
|
37
|
+
before do
|
38
|
+
mongo_session[:users].insert_one(_id: 1, name: 'John', email: 'john@example.com')
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'returns the right instance' do
|
42
|
+
expect(repo.find!(1)).not_to be_nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'when a non-existent id is given' do
|
47
|
+
it 'raises the NotFound error' do
|
48
|
+
expect {
|
49
|
+
repo.find!(1)
|
50
|
+
}.to raise_error Rmodel::NotFound
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '#insert' do
|
56
|
+
context 'when the id is not provided' do
|
57
|
+
let(:user) { User.new(nil, 'John', 'john@example.com') }
|
58
|
+
|
59
|
+
it 'sets the id before insert' do
|
60
|
+
repo.insert(user)
|
61
|
+
expect(user.id).not_to be_nil
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'persists the object' do
|
65
|
+
repo.insert(user)
|
66
|
+
found = mongo_session[:users].find(name: 'John', email: 'john@example.com').count
|
67
|
+
expect(found).to eq 1
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when the id is provided' do
|
72
|
+
let(:user) { User.new(1, 'John', 'john@example.com') }
|
73
|
+
|
74
|
+
it 'uses the existent id' do
|
75
|
+
repo.insert(user)
|
76
|
+
expect(user.id).to eq 1
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'when the given id already exists' do
|
81
|
+
let(:user) { User.new(nil, 'John', 'john@example.com') }
|
82
|
+
before { repo.insert(user) }
|
83
|
+
|
84
|
+
it 'raises the error' do
|
85
|
+
expect { repo.insert(user) }.to raise_error Mongo::Error::OperationFailure
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe '#update' do
|
91
|
+
let(:user) { User.new(nil, 'John', 'john@example.com') }
|
92
|
+
|
93
|
+
before do
|
94
|
+
repo.insert(user)
|
95
|
+
user.name = 'John Smith'
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'updates the record' do
|
99
|
+
repo.update(user)
|
100
|
+
found = mongo_session[:users].find(name: 'John Smith').count
|
101
|
+
expect(found).to eq 1
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe '#remove' do
|
106
|
+
let(:user) { User.new(nil, 'John', 'john@example.com') }
|
107
|
+
before { repo.insert(user) }
|
108
|
+
|
109
|
+
it 'removes the record' do
|
110
|
+
repo.remove(user)
|
111
|
+
found = mongo_session[:users].find(name: 'John').count
|
112
|
+
expect(found).to eq 0
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
RSpec.describe Rmodel::Mongo::Repository do
|
2
|
+
before do
|
3
|
+
Rmodel.setup.clear
|
4
|
+
stub_const('User', Struct.new(:id, :name, :email))
|
5
|
+
end
|
6
|
+
|
7
|
+
subject { UserRepository.new }
|
8
|
+
|
9
|
+
describe '.client(name)' do
|
10
|
+
before do
|
11
|
+
Rmodel::Setup.send :public, :client
|
12
|
+
end
|
13
|
+
context 'when it is called with an existent name' do
|
14
|
+
before do
|
15
|
+
Rmodel.setup do
|
16
|
+
client :mongo, { hosts: [ 'localhost' ] }
|
17
|
+
end
|
18
|
+
|
19
|
+
stub_const('UserRepository', Class.new(Rmodel::Mongo::Repository) {
|
20
|
+
client :mongo
|
21
|
+
simple_factory User, :name, :email
|
22
|
+
attr_reader :client
|
23
|
+
})
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'sets the appropriate #client' do
|
27
|
+
expect(subject.client).to be_an_instance_of Mongo::Client
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'when it is called with a non-existent name' do
|
32
|
+
before do
|
33
|
+
stub_const('UserRepository', Class.new(Rmodel::Mongo::Repository) {
|
34
|
+
client :mongo
|
35
|
+
simple_factory User, :name, :email
|
36
|
+
attr_reader :client
|
37
|
+
})
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'makes #client raise the ArgumentError' do
|
41
|
+
expect { subject.client }.to raise_error ArgumentError
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when it is not called' do
|
46
|
+
before do
|
47
|
+
stub_const('UserRepository', Class.new(Rmodel::Mongo::Repository) {
|
48
|
+
simple_factory User, :name, :email
|
49
|
+
attr_reader :client
|
50
|
+
})
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'when the :default client is set' do
|
54
|
+
before do
|
55
|
+
Rmodel.setup do
|
56
|
+
client :default, { hosts: [ 'localhost' ] }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'sets #client to be default' do
|
61
|
+
expect(subject.client).to be_an_instance_of Mongo::Client
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'when the :default client is not set' do
|
66
|
+
it 'makes #client raise the ArgumentError' do
|
67
|
+
expect { subject.client }.to raise_error ArgumentError
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '.collection(name)' do
|
74
|
+
before do
|
75
|
+
Rmodel.setup do
|
76
|
+
client :default, { hosts: [ 'localhost' ] }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'when the :people collection is given' do
|
81
|
+
before do
|
82
|
+
stub_const('UserRepository', Class.new(Rmodel::Mongo::Repository) {
|
83
|
+
collection :people
|
84
|
+
simple_factory User, :name, :email
|
85
|
+
attr_reader :collection
|
86
|
+
})
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'uses the :people' do
|
90
|
+
expect(subject.collection).to eq :people
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'when no collection is given' do
|
95
|
+
before do
|
96
|
+
stub_const('UserRepository', Class.new(Rmodel::Mongo::Repository) {
|
97
|
+
simple_factory User, :name, :email
|
98
|
+
attr_reader :collection
|
99
|
+
})
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'gets the right name by convention' do
|
103
|
+
expect(subject.collection).to eq :users
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe '.simple_factory(klass, attribute1, attribute2, ...)' do
|
109
|
+
before do
|
110
|
+
Rmodel.setup do
|
111
|
+
client :default, { hosts: [ 'localhost' ] }
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'when it is called' do
|
116
|
+
before do
|
117
|
+
stub_const('UserRepository', Class.new(Rmodel::Mongo::Repository) {
|
118
|
+
simple_factory User, :name, :email
|
119
|
+
attr_reader :factory
|
120
|
+
})
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'sets the appropriate #factory' do
|
124
|
+
expect(subject.factory).to be_an_instance_of Rmodel::Mongo::SimpleFactory
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'when it is not called' do
|
129
|
+
before do
|
130
|
+
stub_const('UserRepository', Class.new(Rmodel::Mongo::Repository))
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'make #initialize raise an error' do
|
134
|
+
expect {
|
135
|
+
UserRepository.new
|
136
|
+
}.to raise_error ArgumentError
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
RSpec.describe Rmodel::Mongo::Repository do
|
2
|
+
include_context 'clean Mongo database'
|
3
|
+
|
4
|
+
before do
|
5
|
+
Rmodel.setup do
|
6
|
+
client :default, hosts: [ 'localhost' ], database: 'rmodel_test'
|
7
|
+
end
|
8
|
+
stub_const('Thing', Struct.new(:id, :a, :b))
|
9
|
+
stub_const('ThingRepository', Class.new(Rmodel::Mongo::Repository) {
|
10
|
+
simple_factory Thing, :a, :b
|
11
|
+
})
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:repo) { ThingRepository.new }
|
15
|
+
|
16
|
+
before do
|
17
|
+
repo.insert(Thing.new(nil, 2, 3))
|
18
|
+
repo.insert(Thing.new(nil, 2, 4))
|
19
|
+
repo.insert(Thing.new(nil, 5, 6))
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '.scope' do
|
23
|
+
context 'when a scope w/o arguments is defined' do
|
24
|
+
before do
|
25
|
+
ThingRepository.class_eval do
|
26
|
+
scope :a_equals_2 do
|
27
|
+
where(a: 2)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'works!' do
|
33
|
+
expect(repo.query.a_equals_2.count).to eq 2
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'returns an array of instances of the appropriate class' do
|
37
|
+
expect(repo.query.a_equals_2.first).to be_an_instance_of Thing
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when a scope w/ arguments is defined' do
|
42
|
+
before do
|
43
|
+
ThingRepository.class_eval do
|
44
|
+
scope :a_equals do |n|
|
45
|
+
where(a: n)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'works!' do
|
51
|
+
expect(repo.query.a_equals(2).count).to eq 2
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'when two scopes are defined and chained' do
|
56
|
+
before do
|
57
|
+
ThingRepository.class_eval do
|
58
|
+
scope :a_equals do |n|
|
59
|
+
where(a: n)
|
60
|
+
end
|
61
|
+
|
62
|
+
scope :b_equals do |n|
|
63
|
+
where(b: n)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'works!' do
|
69
|
+
expect(repo.query.a_equals(2).b_equals(4).count).to eq 1
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'when an unknown scope is used' do
|
74
|
+
it 'raises the NoMethodError' do
|
75
|
+
expect {
|
76
|
+
repo.query.something
|
77
|
+
}.to raise_error NoMethodError
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '.query' do
|
83
|
+
describe '#remove' do
|
84
|
+
context 'when no scope is given' do
|
85
|
+
it 'removes all objects' do
|
86
|
+
repo.query.remove
|
87
|
+
expect(repo.query.count).to eq 0
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'when the scope filters 2 objects from 3' do
|
92
|
+
before do
|
93
|
+
ThingRepository.class_eval do
|
94
|
+
scope :a_equals_2 do
|
95
|
+
where(a: 2)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'removes 2 objects' do
|
101
|
+
repo.query.a_equals_2.remove
|
102
|
+
expect(repo.query.count).to eq 1
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
RSpec.describe Rmodel::Mongo::SimpleFactory do
|
2
|
+
context 'when the User(id, name, email) class is defined' do
|
3
|
+
before { stub_const('User', Struct.new(:id, :name, :email)) }
|
4
|
+
|
5
|
+
subject(:factory) { Rmodel::Mongo::SimpleFactory.new(User, :name, :email) }
|
6
|
+
|
7
|
+
describe '#fromHash' do
|
8
|
+
context 'when the hash with _id, name and email is given' do
|
9
|
+
let(:hash) { { '_id' => 1, 'name' => 'John', 'email' => 'john@example.com' } }
|
10
|
+
let(:result) { factory.fromHash(hash) }
|
11
|
+
|
12
|
+
it 'returns an instance of User' do
|
13
|
+
expect(result).to be_an_instance_of User
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'sets the attributes correctly' do
|
17
|
+
expect(result.name).to eq 'John'
|
18
|
+
expect(result.email).to eq 'john@example.com'
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'sets the User#id correctly' do
|
22
|
+
expect(result.id).to eq 1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#toHash' do
|
28
|
+
let(:user) { User.new(1, 'John', 'john@example.com') }
|
29
|
+
context 'when id_included is false' do
|
30
|
+
let(:result) { factory.toHash(user, false) }
|
31
|
+
|
32
|
+
it 'returns an instance of Hash' do
|
33
|
+
expect(result).to be_an_instance_of Hash
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'sets the keys correctly' do
|
37
|
+
expect(result['name']).to eq 'John'
|
38
|
+
expect(result['email']).to eq 'john@example.com'
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'has no the "_id" key' do
|
42
|
+
expect(result.has_key?('_id')).to be false
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'when id_included is true' do
|
47
|
+
let(:result) { factory.toHash(user, true) }
|
48
|
+
|
49
|
+
it 'sets the "_id" key' do
|
50
|
+
expect(result['_id']).to eq 1
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
RSpec.describe Rmodel do
|
2
|
+
describe '.setup' do
|
3
|
+
before { Rmodel::Setup.instance.clear }
|
4
|
+
context 'when no block is passed' do
|
5
|
+
it 'returns Rmodel::Setup.instance' do
|
6
|
+
expect(Rmodel.setup).to equal Rmodel::Setup.instance
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'when the block is passed' do
|
11
|
+
let(:clients_config) { Rmodel::Setup.instance.instance_variable_get('@clients_config') }
|
12
|
+
|
13
|
+
it 'returns Rmodel::Setup.instance' do
|
14
|
+
expect(Rmodel.setup).to equal Rmodel::Setup.instance
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'runs setup methods within the block' do
|
18
|
+
Rmodel.setup do
|
19
|
+
client :default, {}
|
20
|
+
end
|
21
|
+
expect(clients_config[:default]).to eq({})
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe Rmodel::Setup do
|
27
|
+
subject { Rmodel::Setup.instance }
|
28
|
+
let(:clients_config) { subject.instance_variable_get('@clients_config') }
|
29
|
+
|
30
|
+
describe '#new' do
|
31
|
+
it 'raises the NoMethodError' do
|
32
|
+
expect { Rmodel::Setup.new }.to raise_error NoMethodError
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#client(name, config)' do
|
37
|
+
it 'makes config available via #clients[name]' do
|
38
|
+
subject.client :default, { host: 'localhost' }
|
39
|
+
expect(clients_config[:default]).to eq( host: 'localhost' )
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#clear' do
|
44
|
+
context 'when one client is set' do
|
45
|
+
before { subject.client :default, { host: 'localhost' } }
|
46
|
+
|
47
|
+
it 'removes all clients' do
|
48
|
+
subject.clear
|
49
|
+
expect(clients_config).to be_empty
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
RSpec.shared_context 'clean Mongo database' do
|
2
|
+
let(:mongo_session) { Mongo::Client.new([ '127.0.0.1:27017' ], database: 'rmodel_test') }
|
3
|
+
|
4
|
+
before(:all) do
|
5
|
+
Mongo::Logger.logger.level = Logger::ERROR
|
6
|
+
mongo_session = Mongo::Client.new([ '127.0.0.1:27017' ], database: 'rmodel_test')
|
7
|
+
mongo_session.database.drop
|
8
|
+
end
|
9
|
+
after { mongo_session.database.drop }
|
10
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'rmodel'
|
2
|
+
|
3
|
+
Dir[File.dirname(__FILE__) + '/shared/**/*.rb'].each { |f| require f }
|
4
|
+
|
5
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
6
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
7
|
+
# The generated `.rspec` file contains `--require spec_helper` which will cause
|
8
|
+
# this file to always be loaded, without a need to explicitly require it in any
|
9
|
+
# files.
|
10
|
+
#
|
11
|
+
# Given that it is always loaded, you are encouraged to keep this file as
|
12
|
+
# light-weight as possible. Requiring heavyweight dependencies from this file
|
13
|
+
# will add to the boot time of your test suite on EVERY test run, even for an
|
14
|
+
# individual file that may not need all of that loaded. Instead, consider making
|
15
|
+
# a separate helper file that requires the additional dependencies and performs
|
16
|
+
# the additional setup, and require it from the spec files that actually need
|
17
|
+
# it.
|
18
|
+
#
|
19
|
+
# The `.rspec` file also contains a few flags that are not defaults but that
|
20
|
+
# users commonly want.
|
21
|
+
#
|
22
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
23
|
+
RSpec.configure do |config|
|
24
|
+
# rspec-expectations config goes here. You can use an alternate
|
25
|
+
# assertion/expectation library such as wrong or the stdlib/minitest
|
26
|
+
# assertions if you prefer.
|
27
|
+
config.expect_with :rspec do |expectations|
|
28
|
+
# This option will default to `true` in RSpec 4. It makes the `description`
|
29
|
+
# and `failure_message` of custom matchers include text for helper methods
|
30
|
+
# defined using `chain`, e.g.:
|
31
|
+
# be_bigger_than(2).and_smaller_than(4).description
|
32
|
+
# # => "be bigger than 2 and smaller than 4"
|
33
|
+
# ...rather than:
|
34
|
+
# # => "be bigger than 2"
|
35
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
36
|
+
end
|
37
|
+
|
38
|
+
# rspec-mocks config goes here. You can use an alternate test double
|
39
|
+
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
40
|
+
config.mock_with :rspec do |mocks|
|
41
|
+
# Prevents you from mocking or stubbing a method that does not exist on
|
42
|
+
# a real object. This is generally recommended, and will default to
|
43
|
+
# `true` in RSpec 4.
|
44
|
+
mocks.verify_partial_doubles = true
|
45
|
+
end
|
46
|
+
|
47
|
+
# The settings below are suggested to provide a good initial experience
|
48
|
+
# with RSpec, but feel free to customize to your heart's content.
|
49
|
+
=begin
|
50
|
+
# These two settings work together to allow you to limit a spec run
|
51
|
+
# to individual examples or groups you care about by tagging them with
|
52
|
+
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
|
53
|
+
# get run.
|
54
|
+
config.filter_run :focus
|
55
|
+
config.run_all_when_everything_filtered = true
|
56
|
+
|
57
|
+
# Allows RSpec to persist some state between runs in order to support
|
58
|
+
# the `--only-failures` and `--next-failure` CLI options. We recommend
|
59
|
+
# you configure your source control system to ignore this file.
|
60
|
+
config.example_status_persistence_file_path = "spec/examples.txt"
|
61
|
+
|
62
|
+
# Limits the available syntax to the non-monkey patched syntax that is
|
63
|
+
# recommended. For more details, see:
|
64
|
+
# - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
|
65
|
+
# - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
66
|
+
# - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
|
67
|
+
config.disable_monkey_patching!
|
68
|
+
|
69
|
+
# This setting enables warnings. It's recommended, but in some cases may
|
70
|
+
# be too noisy due to issues in dependencies.
|
71
|
+
config.warnings = true
|
72
|
+
|
73
|
+
# Many RSpec users commonly either run the entire suite or an individual
|
74
|
+
# file, and it's useful to allow more verbose output when running an
|
75
|
+
# individual spec file.
|
76
|
+
if config.files_to_run.one?
|
77
|
+
# Use the documentation formatter for detailed output,
|
78
|
+
# unless a formatter has already been configured
|
79
|
+
# (e.g. via a command-line flag).
|
80
|
+
config.default_formatter = 'doc'
|
81
|
+
end
|
82
|
+
|
83
|
+
# Print the 10 slowest examples and example groups at the
|
84
|
+
# end of the spec run, to help surface which specs are running
|
85
|
+
# particularly slow.
|
86
|
+
config.profile_examples = 10
|
87
|
+
|
88
|
+
# Run specs in random order to surface order dependencies. If you find an
|
89
|
+
# order dependency and want to debug it, you can fix the order by providing
|
90
|
+
# the seed, which is printed after each run.
|
91
|
+
# --seed 1234
|
92
|
+
config.order = :random
|
93
|
+
|
94
|
+
# Seed global randomization in this process using the `--seed` CLI option.
|
95
|
+
# Setting this allows you to use `--seed` to deterministically reproduce
|
96
|
+
# test failures related to randomization by passing the same `--seed` value
|
97
|
+
# as the one that triggered the failure.
|
98
|
+
Kernel.srand config.seed
|
99
|
+
=end
|
100
|
+
end
|
metadata
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rmodel
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alexei
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-10-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: mongo
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: origin
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.6'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.6'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: Rmodel is an ORM library, which tends to follow the SOLID principles.
|
98
|
+
email:
|
99
|
+
- alexei.lexx@gmail.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- ".gitignore"
|
105
|
+
- ".rspec"
|
106
|
+
- ".travis.yml"
|
107
|
+
- Gemfile
|
108
|
+
- LICENSE.txt
|
109
|
+
- README.md
|
110
|
+
- Rakefile
|
111
|
+
- examples/user.rb
|
112
|
+
- lib/rmodel.rb
|
113
|
+
- lib/rmodel/errors.rb
|
114
|
+
- lib/rmodel/mongo/repository.rb
|
115
|
+
- lib/rmodel/mongo/repository_ext/query.rb
|
116
|
+
- lib/rmodel/mongo/repository_ext/queryable.rb
|
117
|
+
- lib/rmodel/mongo/setup.rb
|
118
|
+
- lib/rmodel/mongo/simple_factory.rb
|
119
|
+
- lib/rmodel/setup.rb
|
120
|
+
- lib/rmodel/version.rb
|
121
|
+
- rmodel.gemspec
|
122
|
+
- spec/rmodel/mongo/repository_crud_spec.rb
|
123
|
+
- spec/rmodel/mongo/repository_initialize_spec.rb
|
124
|
+
- spec/rmodel/mongo/repository_queryable_spec.rb
|
125
|
+
- spec/rmodel/mongo/simple_factory_spec.rb
|
126
|
+
- spec/rmodel/setup_spec.rb
|
127
|
+
- spec/shared/clean_moped.rb
|
128
|
+
- spec/spec_helper.rb
|
129
|
+
homepage: https://github.com/alexei-lexx/rmodel
|
130
|
+
licenses:
|
131
|
+
- MIT
|
132
|
+
metadata: {}
|
133
|
+
post_install_message:
|
134
|
+
rdoc_options: []
|
135
|
+
require_paths:
|
136
|
+
- lib
|
137
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
138
|
+
requirements:
|
139
|
+
- - ">="
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
requirements: []
|
148
|
+
rubyforge_project:
|
149
|
+
rubygems_version: 2.4.5
|
150
|
+
signing_key:
|
151
|
+
specification_version: 4
|
152
|
+
summary: Rmodel is an ORM library, which tends to follow the SOLID principles.
|
153
|
+
test_files:
|
154
|
+
- spec/rmodel/mongo/repository_crud_spec.rb
|
155
|
+
- spec/rmodel/mongo/repository_initialize_spec.rb
|
156
|
+
- spec/rmodel/mongo/repository_queryable_spec.rb
|
157
|
+
- spec/rmodel/mongo/simple_factory_spec.rb
|
158
|
+
- spec/rmodel/setup_spec.rb
|
159
|
+
- spec/shared/clean_moped.rb
|
160
|
+
- spec/spec_helper.rb
|