mongoid-embedded_copy 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d7c96aa95743c9b0ce42fe49cb82fb0b2a906f63
4
+ data.tar.gz: 5c32ab4b11fa8a0c1cb8bfb4e9c5af1a6fb88697
5
+ SHA512:
6
+ metadata.gz: 6a8d8bdf66cf2cd8b5bc0e9fd46eb2b4a25a8ef4ab3f54a1cf15e279182e2f803b157d852f4b7ba7c2486e4271b213a19f3e716ce2bf73779ad536449a314b99
7
+ data.tar.gz: e887b5ccbf3979d8d0700d863f436b0a4dbe0290c331930ecd7649f0d18f01fed71642914a78c77c496a09fa601ab0bc05e237d1876f03182961f246c65cf135
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2014 Geoffroy Planquart
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require "rake/testtask"
4
+
5
+ desc 'Default: run unit tests'
6
+ task :default => :test
7
+
8
+ desc 'Run tests'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.libs << 'test'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
@@ -0,0 +1,6 @@
1
+ module Mongoid
2
+ module EmbeddedCopy
3
+ VERSION = '1.0.0'
4
+ end
5
+ end
6
+
@@ -0,0 +1,122 @@
1
+ module Mongoid
2
+ module EmbeddedCopy
3
+ extend ActiveSupport::Concern
4
+
5
+ class_methods do
6
+ def embeds_copy(name, opts = {})
7
+ klass = opts[:class_name] || name.to_s.camelize
8
+ embedded_class = EmbeddedCopy.embedded_class(self, opts, klass)
9
+ EmbeddedCopy.for(klass, opts.merge({:in => self, inverse_of: name}))
10
+ mongoid_options = Mongoid::Relations::Embedded::One.valid_options +
11
+ Mongoid::Relations::Options::COMMON
12
+ embeds_one name, opts.merge({class_name: embedded_class}).slice(*mongoid_options)
13
+
14
+ define_method("#{name}_with_copy=") do |value|
15
+ value = embedded_class.constantize.new(value) if value.class.name == klass
16
+ self.public_send("#{name}_without_copy=", value)
17
+ end
18
+ alias_method_chain "#{name}=", :copy
19
+ end
20
+ end
21
+
22
+ def self.embedded_class(klass, opts, prefix = nil)
23
+ embedded_class = opts[:embedded_class] || "CopyFor#{klass}".gsub('::', '')
24
+ [prefix, embedded_class].compact.join('::')
25
+ end
26
+
27
+ def self.for(klass, opts = {})
28
+ klass = klass.constantize if klass.is_a?(String)
29
+ raise ArgumentError.new('Requires :in options to specify the document in which this one is embedded') if !opts.has_key?(:in)
30
+ raise ArgumentError.new("Can't create an embedded copy of non-mongoid document class #{klass}") if !(klass < Mongoid::Document)
31
+ skipped = Array(opts[:skip]).map{|f| f.to_s}
32
+ skipped.push('deleted_at')
33
+
34
+ embed_opts = opts[:in]
35
+ embed_opts = {class_name: embed_opts.to_s, as: embed_opts.to_s.underscore} if embed_opts.is_a?(Class)
36
+ embed_opts[:inverse_of] = opts[:inverse_of]
37
+ embedded_class = self.embedded_class(embed_opts[:class_name], opts)
38
+ embed_name = embed_opts.delete(:as)
39
+ skipped.push(embed_name).push("#{embed_name}_id")
40
+
41
+ return if klass.const_defined?(embedded_class) && [klass, embedded_class].join('::').constantize.respond_to?(:original_class)
42
+ klass.send(:include, equality_module_for(klass))
43
+
44
+ document_module = Module.new do
45
+ extend ActiveSupport::Concern
46
+
47
+ included do
48
+ include Mongoid::Document
49
+ include Mongoid::EmbeddedCopy.equality_module_for(klass)
50
+
51
+ class_attribute :original_class, instance_writer: false
52
+ class_attribute :skipped_attributes, instance_writer: false
53
+ class_attribute :embed_name
54
+
55
+ self.original_class = klass
56
+ self.embed_name = embed_name
57
+ self.skipped_attributes = skipped
58
+
59
+ def initialize(*attrs)
60
+ if attrs.first.is_a?(original_class)
61
+ attrs = attrs.first.attributes.to_h.dup
62
+ skipped_attributes.each {|n| attrs.delete(n) }
63
+ end
64
+ super(attrs)
65
+ end
66
+
67
+ embedded_in embed_name, embed_opts
68
+
69
+ klass.fields.each do |name, f|
70
+ next if skipped.include?(name) || name == '_id'
71
+ options = f.options.dup
72
+ options.delete(:klass)
73
+ field name, options
74
+
75
+ if opts[:update_original]
76
+ define_method("#{name}_with_update_original=") do |value|
77
+ load_original.set(name => value)
78
+ public_send("#{name}_without_update_original=", value)
79
+ end
80
+ alias_method_chain "#{name}=", :update_original
81
+ end
82
+ end
83
+ end
84
+
85
+ def load_original
86
+ @original ||= original_class.find(id)
87
+ end
88
+ end
89
+
90
+ if klass.const_defined?(embedded_class)
91
+ klass.const_get(embedded_class).send(:include, document_module)
92
+ else
93
+ klass.const_set(embedded_class, Class.new do
94
+ include document_module
95
+ end)
96
+ end
97
+ end
98
+
99
+ def self.equality_module_for(klass)
100
+ Module.new do
101
+ extend ActiveSupport::Concern
102
+
103
+ included do
104
+ class_attribute :acts_as_method, instance_writer: false
105
+ self.acts_as_method = "acts_as_#{klass.to_s.underscore}"
106
+
107
+ define_method(acts_as_method) { true }
108
+ end
109
+
110
+ def ==(rhs)
111
+ if rhs.respond_to?(acts_as_method) && rhs.public_send(acts_as_method)
112
+ id == rhs.id
113
+ else
114
+ super
115
+ end
116
+ end
117
+ alias_method :eql?, :==
118
+ end
119
+ end
120
+ end
121
+ end
122
+
@@ -0,0 +1,2 @@
1
+ require 'mongoid/embedded_copy'
2
+
@@ -0,0 +1,77 @@
1
+ require 'test_helper'
2
+
3
+ class EmbeddedCopyTest < BaseTest
4
+ test 'should raise if given class is not a Mongoid::Document' do
5
+ assert_raises(ArgumentError) do
6
+ Mongoid::EmbeddedCopy.for(BaseTest, in: User)
7
+ end
8
+ end
9
+
10
+ test 'should raise if no :in argument is given' do
11
+ assert_raises(ArgumentError) do
12
+ Mongoid::EmbeddedCopy.for(User)
13
+ end
14
+ end
15
+
16
+ test 'should access embedded copy' do
17
+ user = User.create({firstname: 'Geoffroy', lastname: 'Planquart'})
18
+ post = Post.create({title: 'Hello', content: 'Hello World', user: user, u: user})
19
+
20
+ assert_equal User::CopyForPost, post.u.class
21
+ assert_equal user, post.u.load_original
22
+ assert_operator user, :==, post.u
23
+ assert_operator post.u, :==, user
24
+ assert post.u.eql?(user)
25
+ end
26
+
27
+ test 'should embeds copy of document embedding a copy of self' do
28
+ class ::User
29
+ embeds_copy :last_post, class_name: 'Post', skip: :u
30
+ end
31
+
32
+ user = User.create({firstname: 'Geoffroy', lastname: 'Planquart'})
33
+ post = Post.create({title: 'Hello', content: 'Hello World', user: user, u: user})
34
+ user.set(last_post: post)
35
+
36
+ assert_operator post, :==, user.last_post
37
+ end
38
+
39
+ test 'load_original should return new value if copy is changed' do
40
+ user1 = User.create({firstname: 'Geoffroy', lastname: 'Planquart'})
41
+ user2 = User.create({firstname: 'John', lastname: 'Doe'})
42
+
43
+ post = Post.create({title: 'Hello', content: 'Hello World', user: user1, u: user1})
44
+ assert_equal user1, post.u.load_original
45
+ post.set(u: user2)
46
+ assert_equal user2, post.u.load_original
47
+ end
48
+
49
+ test 'should update original' do
50
+ class ::User
51
+ embeds_copy :first_post, class_name: 'Post', skip: :u, update_original: true, embedded_class: 'Copy'
52
+ end
53
+
54
+ post = Post.create({title: 'Hello', content: 'Hello World'})
55
+ user = User.create({firstname: 'Geoffroy', lastname: 'Planquart', first_post: post})
56
+ user.first_post.set(title: 'World')
57
+
58
+ assert_equal Post::Copy, user.first_post.class
59
+
60
+ assert_equal 'World', post.reload.title
61
+ end
62
+
63
+ test 'should use predefined class and add attributes once' do
64
+ class ::User
65
+ embeds_copy :a_post, class_name: 'Post', skip: :u, embedded_class: 'SpecializedCopy'
66
+ end
67
+
68
+ post = Post.create({title: 'Hello', content: 'Hello World'})
69
+ user = User.create({firstname: 'Geoffroy', lastname: 'Planquart', a_post: post})
70
+
71
+ assert_equal Post::SpecializedCopy, user.a_post.class
72
+ assert_nothing_raised(NoMethodError) do
73
+ user.a_post.some_method
74
+ end
75
+ end
76
+ end
77
+
@@ -0,0 +1,17 @@
1
+ class Post
2
+ include Mongoid::Document
3
+ include Mongoid::EmbeddedCopy
4
+
5
+ field :title
6
+ field :content
7
+
8
+ embeds_copy :u, class_name: 'User'
9
+ belongs_to :user
10
+
11
+ class SpecializedCopy
12
+ def some_method
13
+ true
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,10 @@
1
+ class User
2
+ include Mongoid::Document
3
+ include Mongoid::Timestamps
4
+
5
+ field :firstname
6
+ field :lastname
7
+
8
+ has_many :posts
9
+ end
10
+
data/test/mongoid.yml ADDED
@@ -0,0 +1,6 @@
1
+ test:
2
+ sessions:
3
+ default:
4
+ database: mongoid_embedded_copy_test
5
+ hosts:
6
+ - localhost:27017
@@ -0,0 +1,25 @@
1
+ require 'bundler/setup'
2
+ require 'simplecov'
3
+ require 'pry'
4
+ SimpleCov.configure do
5
+ add_filter '/test/'
6
+ end
7
+ SimpleCov.start if ENV['COVERAGE']
8
+
9
+ require 'minitest/autorun'
10
+ require 'mongoid'
11
+
12
+ require File.expand_path("../../lib/mongoid-embedded_copy", __FILE__)
13
+
14
+ Mongoid.load!("#{File.dirname(__FILE__)}/mongoid.yml", "test")
15
+
16
+ Dir["#{File.dirname(__FILE__)}/models/*.rb"].each { |f| require f }
17
+
18
+ ActiveSupport::TestCase.test_order = :random
19
+
20
+ class BaseTest < ActiveSupport::TestCase
21
+ def teardown
22
+ Mongoid::Sessions.default.use('mongoid_embedded_copy_test').drop
23
+ end
24
+ end
25
+
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mongoid-embedded_copy
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Geoffroy Planquart
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mongoid
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '4.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '4.0'
41
+ description: Create a mimic of a root document to use as a copy embedded in another
42
+ document
43
+ email:
44
+ - geoffroy@planquart.fr
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - MIT-LICENSE
50
+ - Rakefile
51
+ - lib/mongoid-embedded_copy.rb
52
+ - lib/mongoid/embedded_copy.rb
53
+ - lib/mongoid/embedded_copy/version.rb
54
+ - test/embedded_copy_test.rb
55
+ - test/models/post.rb
56
+ - test/models/user.rb
57
+ - test/mongoid.yml
58
+ - test/test_helper.rb
59
+ homepage: https://github.com/Aethelflaed/mongoid-embedded_copy
60
+ licenses:
61
+ - MIT
62
+ metadata: {}
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubyforge_project:
79
+ rubygems_version: 2.4.5
80
+ signing_key:
81
+ specification_version: 4
82
+ summary: Mimic a given root document to use as embedded copy
83
+ test_files:
84
+ - test/models/user.rb
85
+ - test/models/post.rb
86
+ - test/mongoid.yml
87
+ - test/test_helper.rb
88
+ - test/embedded_copy_test.rb
89
+ has_rdoc: