mongoid_cloneable 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +16 -0
- data/.rspec +3 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +16 -0
- data/Gemfile.lock +62 -0
- data/LICENSE.txt +22 -0
- data/README.md +54 -0
- data/Rakefile +8 -0
- data/lib/mongoid/cloneable/document_cloner.rb +58 -0
- data/lib/mongoid/cloneable/relationship_cloner.rb +52 -0
- data/lib/mongoid/cloneable/version.rb +5 -0
- data/lib/mongoid_cloneable.rb +27 -0
- data/mongoid_cloneable.gemspec +22 -0
- data/spec/fixtures/models.rb +73 -0
- data/spec/lib/mongoid/cloneable/document_cloner_spec.rb +121 -0
- data/spec/lib/mongoid/cloneable/relationship_cloner_spec.rb +5 -0
- data/spec/lib/mongoid_cloneable_spec.rb +12 -0
- data/spec/spec_helper.rb +41 -0
- data/spec/support/mongoid.yml +78 -0
- metadata +98 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MzYxMWM2ZmI5MGJkYTM4NTcwZDMxNzdiZDc3NDVlM2ZmMjY5NzVhYw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZTllZjFhMzhhZGQ4MmE1MjBjOTI3MDMwYmU5MmY2MDA1NDQxNjgzZg==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
M2I2NTg5ZmQzMmFkYjNiNmI1ZDY0YTU5NDA1YjMxNTdjMjllMzNkMjUzMTE4
|
10
|
+
MGI0MjhhNDgxMDI0YjQxMWMyYjA3NGMxYWQzNzliNDQ4YWI2ODczYTY3ZDMz
|
11
|
+
NzA0ZGY0MWY3ZDI4Yjc2ODY3OWM5YzBmYjYxYTE4YTEzMDlkMjg=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ODliZjE4NzFhMzUyMjY1ZDZkMzc2NWJkOTgzNzk1OGY4NTljOGQ4NTQ5Zjhk
|
14
|
+
ZWE5NzY3MjI3NmEyNzEyNDViZGVlNjNhZWU1ODFjNDBkNGE2NTRiMGZlZjE1
|
15
|
+
NDBkZmQ2ZGMxNzkwZjFkMjk3ZjhmMWQ4OWU2MWFiYmIyNDY4OWI=
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
mongoid_cloneable
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.9.3
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in mongoid_cloneable.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
gem 'rake'
|
7
|
+
|
8
|
+
group(:development) do
|
9
|
+
gem 'debugger'
|
10
|
+
end
|
11
|
+
|
12
|
+
group(:test) do
|
13
|
+
gem 'simplecov', require: false
|
14
|
+
gem 'rspec'
|
15
|
+
gem 'database_cleaner'
|
16
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
mongoid_cloneable (0.0.1)
|
5
|
+
activesupport (>= 3.2)
|
6
|
+
mongoid (>= 3.1)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
activemodel (3.2.16)
|
12
|
+
activesupport (= 3.2.16)
|
13
|
+
builder (~> 3.0.0)
|
14
|
+
activesupport (3.2.16)
|
15
|
+
i18n (~> 0.6, >= 0.6.4)
|
16
|
+
multi_json (~> 1.0)
|
17
|
+
builder (3.0.4)
|
18
|
+
columnize (0.3.6)
|
19
|
+
database_cleaner (1.2.0)
|
20
|
+
debugger (1.6.5)
|
21
|
+
columnize (>= 0.3.1)
|
22
|
+
debugger-linecache (~> 1.2.0)
|
23
|
+
debugger-ruby_core_source (~> 1.3.1)
|
24
|
+
debugger-linecache (1.2.0)
|
25
|
+
debugger-ruby_core_source (1.3.1)
|
26
|
+
diff-lcs (1.2.5)
|
27
|
+
docile (1.1.2)
|
28
|
+
i18n (0.6.9)
|
29
|
+
mongoid (3.1.6)
|
30
|
+
activemodel (~> 3.2)
|
31
|
+
moped (~> 1.4)
|
32
|
+
origin (~> 1.0)
|
33
|
+
tzinfo (~> 0.3.29)
|
34
|
+
moped (1.5.1)
|
35
|
+
multi_json (1.8.4)
|
36
|
+
origin (1.1.0)
|
37
|
+
rake (10.1.1)
|
38
|
+
rspec (2.14.1)
|
39
|
+
rspec-core (~> 2.14.0)
|
40
|
+
rspec-expectations (~> 2.14.0)
|
41
|
+
rspec-mocks (~> 2.14.0)
|
42
|
+
rspec-core (2.14.7)
|
43
|
+
rspec-expectations (2.14.4)
|
44
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
45
|
+
rspec-mocks (2.14.4)
|
46
|
+
simplecov (0.8.2)
|
47
|
+
docile (~> 1.1.0)
|
48
|
+
multi_json
|
49
|
+
simplecov-html (~> 0.8.0)
|
50
|
+
simplecov-html (0.8.0)
|
51
|
+
tzinfo (0.3.38)
|
52
|
+
|
53
|
+
PLATFORMS
|
54
|
+
ruby
|
55
|
+
|
56
|
+
DEPENDENCIES
|
57
|
+
database_cleaner
|
58
|
+
debugger
|
59
|
+
mongoid_cloneable!
|
60
|
+
rake
|
61
|
+
rspec
|
62
|
+
simplecov
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Vicente Mundim
|
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,54 @@
|
|
1
|
+
# Mongoid::Cloneable
|
2
|
+
|
3
|
+
[![build status][1]][2]
|
4
|
+
|
5
|
+
[1]: https://travis-ci.org/dtmtec/mongoid_cloneable.png
|
6
|
+
[2]: http://travis-ci.org/dtmtec/mongoid_cloneable
|
7
|
+
|
8
|
+
git remote add origin https://github.com/dtmtec/mongoid_cloneable.git
|
9
|
+
git push -u origin master
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
gem 'mongoid_cloneable'
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install mongoid_cloneable
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
Include `Mongoid::Cloneable` in your document and configure it with `cloneable`:
|
28
|
+
|
29
|
+
class MyDocument
|
30
|
+
include Mongoid::Document
|
31
|
+
include Mongoid::Cloneable
|
32
|
+
|
33
|
+
# whitelisting
|
34
|
+
cloneable include: [ :foo, :bar ]
|
35
|
+
|
36
|
+
# or
|
37
|
+
|
38
|
+
# blacklisting
|
39
|
+
cloneable exclude: [ :xyz, :fuzz ]
|
40
|
+
end
|
41
|
+
|
42
|
+
Then when calling `clone` it will include or exclude the specified attributes or relations.
|
43
|
+
|
44
|
+
__Mongoid__ already clones all attributes and embedded associations. If you opt to use include, then everything else will not be cloned. If you opt to use exclude it will only exclude those attributes or relations.
|
45
|
+
|
46
|
+
When it is including referenced has_many or has_one relationships it will call clone on the referenced documents, thus creating copies of them and referencing those.
|
47
|
+
|
48
|
+
## Contributing
|
49
|
+
|
50
|
+
1. Fork it
|
51
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
52
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
53
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
54
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Cloneable
|
3
|
+
class DocumentCloner
|
4
|
+
attr_accessor :document, :cloned_document, :options
|
5
|
+
|
6
|
+
def initialize(document, cloned_document)
|
7
|
+
self.document = document
|
8
|
+
self.cloned_document = cloned_document
|
9
|
+
self.options = document.class.cloneable || {}
|
10
|
+
|
11
|
+
clone_attributes
|
12
|
+
clone_relations
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def included_keys
|
18
|
+
[*options[:include]].map(&:to_s)
|
19
|
+
end
|
20
|
+
|
21
|
+
def excluded_keys
|
22
|
+
[*options[:exclude]].map(&:to_s)
|
23
|
+
end
|
24
|
+
|
25
|
+
def included_relations
|
26
|
+
cloned_document.relations.slice(*included_keys).values
|
27
|
+
end
|
28
|
+
|
29
|
+
def excluded_relations
|
30
|
+
cloned_document.relations.slice(*excluded_keys).values
|
31
|
+
end
|
32
|
+
|
33
|
+
def clone_attributes
|
34
|
+
attrs = cloned_document.attributes.except('_id', '_type')
|
35
|
+
|
36
|
+
if included_keys.present?
|
37
|
+
attrs.except(*included_keys).each do |attr, value|
|
38
|
+
cloned_document[attr] = nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
attrs.slice(*excluded_keys).each do |attr, value|
|
43
|
+
cloned_document[attr] = nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def clone_relations
|
48
|
+
included_relations.each do |relation|
|
49
|
+
Mongoid::Cloneable::RelationshipCloner.clone(document, cloned_document, relation)
|
50
|
+
end
|
51
|
+
|
52
|
+
excluded_relations.each do |relation|
|
53
|
+
Mongoid::Cloneable::RelationshipCloner.clear(cloned_document, relation)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Cloneable
|
3
|
+
class RelationshipCloner
|
4
|
+
def self.clone(document, cloned_document, relation)
|
5
|
+
if [:has_many, :has_one, :has_and_belongs_to_many].include?(relation.macro.to_sym)
|
6
|
+
klass = "mongoid/cloneable/relationship_cloner/#{relation.macro}".camelize.constantize
|
7
|
+
cloner = klass.new(document, cloned_document, relation)
|
8
|
+
|
9
|
+
cloner.clone
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.clear(cloned_document, relation)
|
14
|
+
if [:embeds_many, :embeds_one].include?(relation.macro.to_sym)
|
15
|
+
cloned_document.send(relation.setter, nil)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Base
|
20
|
+
attr_accessor :document, :cloned_document, :relation
|
21
|
+
|
22
|
+
def initialize(document, cloned_document, relation)
|
23
|
+
self.document = document
|
24
|
+
self.cloned_document = cloned_document
|
25
|
+
self.relation = relation
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class HasMany < Base
|
30
|
+
def clone
|
31
|
+
cloned_relation = document.send(relation.name).map { |model| model.clone }
|
32
|
+
cloned_document.send(relation.setter, cloned_relation)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class HasOne < Base
|
37
|
+
def clone
|
38
|
+
cloned_relation = document.send(relation.name).clone
|
39
|
+
cloned_document.send(relation.setter, cloned_relation)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class HasAndBelongsToMany < Base
|
44
|
+
def clone
|
45
|
+
document.send(relation.name).each do |target|
|
46
|
+
target.send(relation.inverse).send(:<<, cloned_document)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "mongoid/cloneable/version"
|
2
|
+
require "mongoid"
|
3
|
+
require "active_support/concern"
|
4
|
+
require "active_support/core_ext"
|
5
|
+
|
6
|
+
module Mongoid
|
7
|
+
module Cloneable
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
autoload :DocumentCloner, 'mongoid/cloneable/document_cloner'
|
11
|
+
autoload :RelationshipCloner, 'mongoid/cloneable/relationship_cloner'
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def cloneable(options=nil)
|
15
|
+
@cloneable = options if options
|
16
|
+
@cloneable
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def clone
|
21
|
+
super.tap do |cloned_document|
|
22
|
+
DocumentCloner.new(self, cloned_document)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'mongoid/cloneable/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "mongoid_cloneable"
|
8
|
+
gem.version = Mongoid::Cloneable::VERSION
|
9
|
+
gem.authors = ["Vicente Mundim"]
|
10
|
+
gem.email = ["vicente.mundim@gmail.com"]
|
11
|
+
gem.description = %q{Provides improved cloning features for Mongoid}
|
12
|
+
gem.summary = %q{Provides improved cloning features for Mongoid}
|
13
|
+
gem.homepage = ""
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency("activesupport", [">= 3.2"])
|
21
|
+
gem.add_dependency("mongoid", [">= 3.1"])
|
22
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
class Car
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Cloneable
|
4
|
+
|
5
|
+
belongs_to :person
|
6
|
+
has_many :parts
|
7
|
+
embeds_many :tires
|
8
|
+
|
9
|
+
field :brand
|
10
|
+
end
|
11
|
+
|
12
|
+
class Tire
|
13
|
+
include Mongoid::Document
|
14
|
+
include Mongoid::Cloneable
|
15
|
+
|
16
|
+
field :brand
|
17
|
+
end
|
18
|
+
|
19
|
+
class Part
|
20
|
+
include Mongoid::Document
|
21
|
+
include Mongoid::Cloneable
|
22
|
+
|
23
|
+
belongs_to :car
|
24
|
+
|
25
|
+
field :name
|
26
|
+
end
|
27
|
+
|
28
|
+
class Person
|
29
|
+
include Mongoid::Document
|
30
|
+
include Mongoid::Cloneable
|
31
|
+
|
32
|
+
has_and_belongs_to_many :books, inverse_of: :people
|
33
|
+
has_and_belongs_to_many :favorite_books, class_name: 'Book', inverse_of: :favorited_by
|
34
|
+
has_many :authored_books, class_name: 'Book', inverse_of: :author
|
35
|
+
has_one :top_book, class_name: 'Book', inverse_of: :top_of
|
36
|
+
|
37
|
+
has_many :cars
|
38
|
+
|
39
|
+
cloneable include: [:name, :authored_books, :favorite_books, :top_book]
|
40
|
+
|
41
|
+
field :name, type: String
|
42
|
+
field :birthdate, type: Date
|
43
|
+
end
|
44
|
+
|
45
|
+
class Book
|
46
|
+
include Mongoid::Document
|
47
|
+
include Mongoid::Cloneable
|
48
|
+
|
49
|
+
embeds_many :pages
|
50
|
+
embeds_one :front_page, class_name: 'Page', autobuild: true
|
51
|
+
belongs_to :author, class_name: 'Person', inverse_of: :authored_books
|
52
|
+
belongs_to :top_of, class_name: 'Person', inverse_of: :top_book
|
53
|
+
|
54
|
+
has_and_belongs_to_many :people, inverse_of: :books
|
55
|
+
has_and_belongs_to_many :favorited_by, class_name: 'Person', inverse_of: :favorite_books
|
56
|
+
|
57
|
+
cloneable exclude: [:description, :pages]
|
58
|
+
|
59
|
+
field :name
|
60
|
+
field :description
|
61
|
+
end
|
62
|
+
|
63
|
+
class Page
|
64
|
+
include Mongoid::Document
|
65
|
+
include Mongoid::Cloneable
|
66
|
+
|
67
|
+
embedded_in :book
|
68
|
+
|
69
|
+
cloneable exclude: :number
|
70
|
+
|
71
|
+
field :body
|
72
|
+
field :number
|
73
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Mongoid::Cloneable::DocumentCloner do
|
4
|
+
let(:books) { [Book.new(name: 'Some book'), Book.new(name: 'other book')] }
|
5
|
+
let(:authored_books) { [Book.new(name: 'Some authored book'), Book.new(name: 'other authored book')] }
|
6
|
+
let(:favorite_books) { [Book.new(name: 'Some favorite book'), Book.new(name: 'other favorite book')] }
|
7
|
+
let(:top_book) { Book.new(name: 'Lords of the rings') }
|
8
|
+
|
9
|
+
let(:cloneable) do
|
10
|
+
Person.new({
|
11
|
+
name: 'Tyrion',
|
12
|
+
birthdate: 33.years.ago.to_date,
|
13
|
+
books: books,
|
14
|
+
authored_books: authored_books,
|
15
|
+
favorite_books: favorite_books,
|
16
|
+
top_book: top_book
|
17
|
+
})
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:cloned_document) do
|
21
|
+
cloneable.clone
|
22
|
+
end
|
23
|
+
|
24
|
+
subject(:cloner) { described_class.new(cloneable, cloned_document) }
|
25
|
+
|
26
|
+
context "when no cloneable configuration is set" do
|
27
|
+
let(:cloneable) { Car.new(brand: 'BMW', tires: [Tire.new] * 4, person: Person.new) }
|
28
|
+
|
29
|
+
it "changes the clone id" do
|
30
|
+
expect(cloner.cloned_document.id).to_not eq(cloneable.id)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "clones the attributes" do
|
34
|
+
expect(cloner.cloned_document.brand).to eq(cloneable.brand)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "clones the embedded associations" do
|
38
|
+
expect(cloner.cloned_document.tires.size).to eq(cloneable.tires.size)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "doesn't clone has many relationships" do
|
42
|
+
expect(cloner.cloned_document.parts.size).to eq(0)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "when it is configured to include attributes or relations" do
|
47
|
+
it "clones only the included attributes" do
|
48
|
+
expect(cloner.cloned_document.name).to eq(cloneable.name)
|
49
|
+
expect(cloner.cloned_document.birthdate).to be_nil
|
50
|
+
end
|
51
|
+
|
52
|
+
it "won't clone has_* relationships that were not especified" do
|
53
|
+
expect(cloner.cloned_document.books).to be_empty
|
54
|
+
end
|
55
|
+
|
56
|
+
it "won't even clone has_* relationship ids that were not especified" do
|
57
|
+
expect(cloner.cloned_document.book_ids).to be_empty
|
58
|
+
end
|
59
|
+
|
60
|
+
it "clones specified has_many relationships" do
|
61
|
+
expect(cloner.cloned_document.authored_books.size).to eq(cloneable.authored_books.size)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "calls clone on each value of a has_many relationship" do
|
65
|
+
authored_books.each { |book| expect(book).to receive(:clone).at_least(:once) }
|
66
|
+
cloner.cloned_document
|
67
|
+
end
|
68
|
+
|
69
|
+
it "clones specified has_one relationship" do
|
70
|
+
expect(cloner.cloned_document.top_book.name).to eq(cloneable.top_book.name)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "calls clone on the has one relationship, cloning it too" do
|
74
|
+
expect(top_book).to receive(:clone).at_least(:once)
|
75
|
+
cloner.cloned_document
|
76
|
+
end
|
77
|
+
|
78
|
+
it "clones ids of has_and_belongs_to_many relationships" do
|
79
|
+
expect(cloner.cloned_document.favorite_book_ids).to eq(cloneable.favorite_book_ids)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "properly configures has_and_belongs_to_many relationships" do
|
83
|
+
cloner.cloned_document
|
84
|
+
|
85
|
+
favorite_books.each do |book|
|
86
|
+
expect(book.favorited_by_ids).to include(cloner.cloned_document.id)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "when it is configured to exclude some attributes or relations" do
|
92
|
+
let(:author) { Person.new name: "George R. R. Martin" }
|
93
|
+
let(:pages) { [Page.new(body: 'some')] * 4 }
|
94
|
+
let(:front_page) { Page.new(body: 'A song of fire') }
|
95
|
+
let(:people) { [Person.new] * 3 }
|
96
|
+
|
97
|
+
let(:cloneable) do
|
98
|
+
Book.new(name: 'Game of Thrones', description: 'A book about kings', author: author, pages: pages, front_page: front_page, people: people )
|
99
|
+
end
|
100
|
+
|
101
|
+
it "clones attributes that were not excluded" do
|
102
|
+
expect(cloner.cloned_document.name).to eq(cloneable.name)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "won't clone attributes that were excluded" do
|
106
|
+
expect(cloner.cloned_document.description).to be_nil
|
107
|
+
end
|
108
|
+
|
109
|
+
it "clones belongs_to relationship" do
|
110
|
+
expect(cloner.cloned_document.author_id).to eq(author.id)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "won't clone has_* relationships" do
|
114
|
+
expect(cloner.cloned_document.people).to be_empty
|
115
|
+
end
|
116
|
+
|
117
|
+
it "clones embedded relationships that were not excluded" do
|
118
|
+
expect(cloner.cloned_document.front_page.body).to eq(cloneable.front_page.body)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Mongoid::Cloneable do
|
4
|
+
let(:cloneable) { Person.new }
|
5
|
+
let(:cloner) { double(Mongoid::Cloneable::DocumentCloner) }
|
6
|
+
|
7
|
+
it "clones the document" do
|
8
|
+
expect(Mongoid::Cloneable::DocumentCloner).to receive(:new)
|
9
|
+
|
10
|
+
cloneable.clone
|
11
|
+
end
|
12
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
|
3
|
+
SimpleCov.start do
|
4
|
+
add_filter 'spec'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'bundler/setup'
|
8
|
+
|
9
|
+
ENV['RACK_ENV'] ||= 'test'
|
10
|
+
|
11
|
+
Bundler.require :default, ENV['RACK_ENV']
|
12
|
+
|
13
|
+
begin
|
14
|
+
require 'debugger'
|
15
|
+
rescue LoadError
|
16
|
+
end
|
17
|
+
|
18
|
+
require "active_support/core_ext"
|
19
|
+
|
20
|
+
root = File.expand_path('../..', __FILE__)
|
21
|
+
|
22
|
+
Mongoid.load!(File.join(root, "spec/support/mongoid.yml"), :test)
|
23
|
+
|
24
|
+
Dir["#{root}/spec/shared/**/*.rb"].each { |f| require f }
|
25
|
+
Dir["#{root}/spec/fixtures/**/*.rb"].each { |f| require f }
|
26
|
+
|
27
|
+
RSpec.configure do |config|
|
28
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
29
|
+
config.run_all_when_everything_filtered = true
|
30
|
+
config.filter_run :focus
|
31
|
+
|
32
|
+
# Run specs in random order to surface order dependencies. If you find an
|
33
|
+
# order dependency and want to debug it, you can fix the order by providing
|
34
|
+
# the seed, which is printed after each run.
|
35
|
+
# --seed 1234
|
36
|
+
# config.order = 'random'
|
37
|
+
|
38
|
+
config.before do
|
39
|
+
DatabaseCleaner.clean_with(:truncation)
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
default_options: &default_options
|
2
|
+
raise_not_found_error: false
|
3
|
+
|
4
|
+
session_default_options: &session_default_options
|
5
|
+
consistency: :strong
|
6
|
+
safe: true
|
7
|
+
|
8
|
+
development:
|
9
|
+
# Configure available database sessions. (required)
|
10
|
+
sessions:
|
11
|
+
# Defines the default session. (required)
|
12
|
+
default:
|
13
|
+
# Defines the name of the default database that Mongoid can connect to.
|
14
|
+
# (required).
|
15
|
+
database: mongoid_cloneable_development
|
16
|
+
# Provides the hosts the default session can connect to. Must be an array
|
17
|
+
# of host:port pairs. (required)
|
18
|
+
hosts:
|
19
|
+
- localhost:27017
|
20
|
+
options:
|
21
|
+
# Change whether the session persists in safe mode by default.
|
22
|
+
# (default: false)
|
23
|
+
# safe: false
|
24
|
+
|
25
|
+
# Change the default consistency model to :eventual or :strong.
|
26
|
+
# :eventual will send reads to secondaries, :strong sends everything
|
27
|
+
# to master. (default: :eventual)
|
28
|
+
<<: *session_default_options
|
29
|
+
# Configure Mongoid specific options. (optional)
|
30
|
+
options:
|
31
|
+
<<: *default_options
|
32
|
+
# Configuration for whether or not to allow access to fields that do
|
33
|
+
# not have a field definition on the model. (default: true)
|
34
|
+
# allow_dynamic_fields: true
|
35
|
+
|
36
|
+
# Enable the identity map, needed for eager loading. (default: false)
|
37
|
+
# identity_map_enabled: false
|
38
|
+
|
39
|
+
# Includes the root model name in json serialization. (default: false)
|
40
|
+
# include_root_in_json: false
|
41
|
+
|
42
|
+
# Include the _type field in serializaion. (default: false)
|
43
|
+
# include_type_for_serialization: false
|
44
|
+
|
45
|
+
# Preload all models in development, needed when models use
|
46
|
+
# inheritance. (default: false)
|
47
|
+
# preload_models: false
|
48
|
+
|
49
|
+
# Protect id and type from mass assignment. (default: true)
|
50
|
+
# protect_sensitive_fields: true
|
51
|
+
|
52
|
+
# Raise an error when performing a #find and the document is not found.
|
53
|
+
# (default: true)
|
54
|
+
# raise_not_found_error: false
|
55
|
+
|
56
|
+
# Raise an error when defining a scope with the same name as an
|
57
|
+
# existing method. (default: false)
|
58
|
+
# scope_overwrite_exception: false
|
59
|
+
|
60
|
+
# Skip the database version check, used when connecting to a db without
|
61
|
+
# admin access. (default: false)
|
62
|
+
# skip_version_check: false
|
63
|
+
|
64
|
+
# User Active Support's time zone in conversions. (default: true)
|
65
|
+
# use_activesupport_time_zone: true
|
66
|
+
|
67
|
+
# Ensure all times are UTC in the app side. (default: false)
|
68
|
+
# use_utc: false
|
69
|
+
test:
|
70
|
+
sessions:
|
71
|
+
default:
|
72
|
+
database: mongoid_cloneable_test
|
73
|
+
hosts:
|
74
|
+
- localhost:27017
|
75
|
+
options:
|
76
|
+
<<: *session_default_options
|
77
|
+
options:
|
78
|
+
<<: *default_options
|
metadata
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mongoid_cloneable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Vicente Mundim
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-01-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mongoid
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.1'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.1'
|
41
|
+
description: Provides improved cloning features for Mongoid
|
42
|
+
email:
|
43
|
+
- vicente.mundim@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- .gitignore
|
49
|
+
- .rspec
|
50
|
+
- .ruby-gemset
|
51
|
+
- .ruby-version
|
52
|
+
- .travis.yml
|
53
|
+
- Gemfile
|
54
|
+
- Gemfile.lock
|
55
|
+
- LICENSE.txt
|
56
|
+
- README.md
|
57
|
+
- Rakefile
|
58
|
+
- lib/mongoid/cloneable/document_cloner.rb
|
59
|
+
- lib/mongoid/cloneable/relationship_cloner.rb
|
60
|
+
- lib/mongoid/cloneable/version.rb
|
61
|
+
- lib/mongoid_cloneable.rb
|
62
|
+
- mongoid_cloneable.gemspec
|
63
|
+
- spec/fixtures/models.rb
|
64
|
+
- spec/lib/mongoid/cloneable/document_cloner_spec.rb
|
65
|
+
- spec/lib/mongoid/cloneable/relationship_cloner_spec.rb
|
66
|
+
- spec/lib/mongoid_cloneable_spec.rb
|
67
|
+
- spec/spec_helper.rb
|
68
|
+
- spec/support/mongoid.yml
|
69
|
+
homepage: ''
|
70
|
+
licenses: []
|
71
|
+
metadata: {}
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ! '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirements: []
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 2.0.6
|
89
|
+
signing_key:
|
90
|
+
specification_version: 4
|
91
|
+
summary: Provides improved cloning features for Mongoid
|
92
|
+
test_files:
|
93
|
+
- spec/fixtures/models.rb
|
94
|
+
- spec/lib/mongoid/cloneable/document_cloner_spec.rb
|
95
|
+
- spec/lib/mongoid/cloneable/relationship_cloner_spec.rb
|
96
|
+
- spec/lib/mongoid_cloneable_spec.rb
|
97
|
+
- spec/spec_helper.rb
|
98
|
+
- spec/support/mongoid.yml
|