mongoid7-rspec-callbacks 1.0.0.pre.816289031

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in evostream-event.gemspec
6
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,14 @@
1
+ Copyright (c) 2013 Luis Ciudad
2
+
3
+ This program is free software: you can redistribute it and/or modify
4
+ it under the terms of the GNU General Public License as published by
5
+ the Free Software Foundation, either version 3 of the License, or
6
+ (at your option) any later version.
7
+
8
+ This program is distributed in the hope that it will be useful,
9
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ GNU General Public License for more details.
12
+
13
+ You should have received a copy of the GNU General Public License
14
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
data/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # Mongoid::Rspec::Callbacks
2
+ [![RSpec](https://github.com/dazzl-tv/mongoid-rspec-callbacks/actions/workflows/rspec.yml/badge.svg?branch=develop&event=pull_request)](https://github.com/dazzl-tv/mongoid-rspec-callbacks/actions/workflows/rspec.yml)
3
+ [![Linter](https://github.com/dazzl-tv/mongoid-rspec-callbacks/actions/workflows/linter.yml/badge.svg)](https://github.com/dazzl-tv/mongoid-rspec-callbacks/actions/workflows/linter.yml)
4
+ [![Gem Version](https://badge.fury.io/rb/mongoid-rspec-callbacks.svg)](https://badge.fury.io/rb/mongoid-rspec-callbacks)
5
+ [![Docs](https://inch-ci.org/github/dazzl-tv/mongoid-rspec-callbacks.svg)](https://inch-ci.org/github/dazzl-tv/mongoid-rspec-callbacks)
6
+ [![Maintainability](https://api.codeclimate.com/v1/badges/2538546ea7419c1d5ea1/maintainability)](https://codeclimate.com/github/dazzl-tv/mongoid-rspec-callbacks/maintainability)
7
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/2538546ea7419c1d5ea1/test_coverage)](https://codeclimate.com/github/dazzl-tv/mongoid-rspec-callbacks/test_coverage)
8
+ [![Known Vulnerabilities](https://snyk.io/test/github/dazzl-tv/mongoid-rspec-callbacks/badge.svg)](https://snyk.io/test/github/dazzl-tv/mongoid-rspec-callbacks)
9
+
10
+ http://rubygems.org/gems/mongoid-rspec-callbacks
11
+
12
+ RSpec Callbacks matchers for Mongoid 7.x and ActiveSupport 6.x
13
+
14
+ This gem is meant to be use with [mongoid-rpsec](http://rubygems.org/gems/mongoid-rspec), altought it works by itself.
15
+
16
+ Syntax is the same as [shoulda-callback-matchers](https://github.com/beatrichartz/shoulda-callback-matchers).
17
+
18
+ By now, only ``on`` option is supported.
19
+
20
+ ## Installation
21
+
22
+ Add to your Gemfile
23
+
24
+ ```
25
+ gem 'mongoid-rspec-callbacks'
26
+ ```
27
+
28
+ Drop in existing or dedicated support file in spec/support (spec/support/mongoid.rb)
29
+
30
+ ```
31
+ RSpec.configure do |configuration|
32
+ configuration.include Mongoid::Matchers
33
+ end
34
+ ```
35
+
36
+ ## Callbacks Matchers
37
+
38
+ ```
39
+ describe User do
40
+ it { should callback(:method).before(:save) }
41
+ it { should callback(:method).after(:save) }
42
+ it { should callback(:method, :method2).before(:validation) }
43
+ it { should callback(:method).after(:validation).on(:create) }
44
+ end
45
+ ```
46
+
47
+ ## Set Callbacks Matchers
48
+
49
+ ```
50
+ describe User do
51
+ it { is_expected.to set_callback(:save, :arround) }
52
+ it { is_expected.to set_callback(:validation, :after) }
53
+ end
54
+ ```
55
+
56
+ ## Association Callbacks Matchers
57
+
58
+ ```
59
+ describe User do
60
+ it { is_expected.to association_callback(:has_many,
61
+ :add,
62
+ :after,
63
+ :send_email_to_subscribers) }
64
+ end
65
+ ```
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mongoid
4
+ module Matchers
5
+ # Create an matcher for set_callback method
6
+ #
7
+ # Usage:
8
+ #
9
+ # it { is_expected.to association_callback(:has_many,
10
+ # :add,
11
+ # :after,
12
+ # :send_email_to_subscribers) }
13
+ class HaveAssociationCallbackMatcher
14
+ CONTEXTS = %i[before after].freeze
15
+ OPERATIONS = %i[add remove].freeze
16
+ RELATIONS = %i[embeds_many has_many and has_and_belongs_to_many].freeze
17
+
18
+ def initialize(*args)
19
+ @relation = args[0]
20
+ @type = args[1]
21
+ @hook = args[2]
22
+ @method = args[3]
23
+ end
24
+
25
+ def matches?(klass)
26
+ @model = klass
27
+
28
+ return false unless \
29
+ relation_is_correct? ||
30
+ context_is_correct? ||
31
+ operation_is_correct? ||
32
+ callback_is_correct?
33
+
34
+ testings_presence_method_callback
35
+ end
36
+
37
+ def description
38
+ "be association_callback(:#{@type}, :#{@hook})"
39
+ end
40
+
41
+ def failure_message
42
+ message_error
43
+ end
44
+
45
+ def failure_message_when_negated
46
+ message_error
47
+ end
48
+
49
+ private
50
+
51
+ def relation_is_correct?
52
+ RELATIONS.include?(@relation)
53
+ end
54
+
55
+ def context_is_correct?
56
+ CONTEXTS.include?(@hook)
57
+ end
58
+
59
+ def operation_is_correct?
60
+ OPERATIONS.include?(@type)
61
+ end
62
+
63
+ def callback_is_correct?
64
+ @model.class.respond_to?(:"_#{@type}_callbacks")
65
+ end
66
+
67
+ def testings_presence_method_callback
68
+ @model.methods.include?(:"#{@method}")
69
+ end
70
+
71
+ def message_error
72
+ <<-ERROR
73
+ expected #{@model} have method callback to association :
74
+ has_many <relation>, #{@hook}: :#{@method}
75
+
76
+ def #{@method}
77
+ end
78
+ ERROR
79
+ end
80
+ end
81
+
82
+ def association_callback(*args)
83
+ HaveAssociationCallbackMatcher.new(*args)
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mongoid
4
+ module Matchers
5
+ # Create an matcher for callback method
6
+ #
7
+ # Usage:
8
+ #
9
+ # it { is_expected.to callback(:callback1).before(:save) }
10
+ # it { is_expected.to callback(:callback2).after(:save) }
11
+ # it { is_expected.to callback(:callback1, :callback2).before(:validation) }
12
+ # it { is_expected.to callback(:callback3).after(:validation).on(:create) }
13
+ class HaveCallbackMatcher
14
+ KINDS = %w[before around after].freeze
15
+
16
+ # Set methods to look for
17
+ def initialize(*args)
18
+ @methods = args || []
19
+ end
20
+
21
+ # Set when callback is fired using @kind and @operation
22
+ KINDS.each do |kind|
23
+ define_method(kind.to_sym) do |op|
24
+ @operation = op
25
+ @kind = kind.to_sym
26
+ self
27
+ end
28
+ end
29
+
30
+ # Set on condition
31
+ def on(action)
32
+ @context = action
33
+ self
34
+ end
35
+
36
+ def matches?(klass)
37
+ return false unless @kind
38
+ if @no_op == !klass.class.respond_to?(:"_#{@operation}_callbacks")
39
+ return false
40
+ end
41
+
42
+ @guess = nil
43
+ @methods.each do |method|
44
+ filter = filters_method(klass, method)
45
+
46
+ return false unless filter
47
+ end
48
+ end
49
+
50
+ def failure_message
51
+ message(true)
52
+ end
53
+
54
+ def failure_message_when_negated
55
+ message(false)
56
+ end
57
+
58
+ def description
59
+ methods = @methods
60
+
61
+ "be callback(:#{methods.join(', ')})#{expl_operation}#{expl_context}"
62
+ end
63
+
64
+ protected
65
+
66
+ def expl_operation
67
+ @operation ? ".#{@kind}(:#{@operation})" : ''
68
+ end
69
+
70
+ def expl_context
71
+ @context ? ".on(:#{@context})" : ''
72
+ end
73
+
74
+ def message(should)
75
+ return msg_op_invalid if @no_op
76
+
77
+ @kind ? message_kind(should) : message_not_kind
78
+ end
79
+
80
+ def msg_op_invalid
81
+ 'Invalid operation. Use :initialize, :build, :validation,' \
82
+ ':create, :find, :update, :upsert, :save or :destroy'
83
+ end
84
+
85
+ def message_kind(should)
86
+ <<-MESSAGE
87
+ Expected method#{@methods.size > 1 ? 's' : ''}#{expr_called(should)}
88
+ #{"#{@kind}" "#{@operation}" if @operation}
89
+ #{"on #{@context}" if @context}
90
+ #{msg_guess}
91
+ #{"#{@guess.kind} #{@operation}" if @guess}
92
+ #{'on another context' if @guess && !@context_match}
93
+ MESSAGE
94
+ end
95
+
96
+ def expr_called(should)
97
+ "#{@methods.join(', ')} #{should ? '' : 'not '}to be called"
98
+ end
99
+
100
+ def msg_guess
101
+ if @guess
102
+ ", but got method #{@guess.filter} called"
103
+ else
104
+ ', but no callback found'
105
+ end
106
+ end
107
+
108
+ def message_not_kind
109
+ <<-MESSAGE
110
+ Callback#{@methods.size > 1 ? 's' : ''} #{@methods.join(', ')} can
111
+ not be tested against undefined lifecycle.
112
+ Use .before, .after or .around
113
+ MESSAGE
114
+ end
115
+
116
+ private
117
+
118
+ def filters_method(klass, method)
119
+ klass.class.send(:"_#{@operation}_callbacks").detect do |callback|
120
+ # Save callback instance in order to print information
121
+ # about it in case of failure
122
+ @guess = callback if callback.filter == method
123
+ check_filter?(callback,
124
+ method) and check_kind?(callback,
125
+ @kind) and check_context?(
126
+ callback, @context
127
+ )
128
+ end
129
+ end
130
+
131
+ def check_filter?(callback, method)
132
+ callback.filter == method
133
+ end
134
+
135
+ def check_kind?(callback, kind)
136
+ callback.kind == kind
137
+ end
138
+
139
+ def check_context?(callback, context)
140
+ return true unless context
141
+
142
+ options = callback.instance_variable_get(:@if)
143
+ @context_match = options.select { |option| option.is_a?(Proc) }
144
+
145
+ @context_match.detect do |option|
146
+ option.call(ValidationContext.new(context))
147
+ end
148
+ end
149
+ end
150
+
151
+ ValidationContext = Struct.new :validation_context
152
+
153
+ def callback(*args)
154
+ HaveCallbackMatcher.new(*args)
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mongoid
4
+ module Matchers
5
+ # Create an matcher for set_callback method
6
+ #
7
+ # Usage:
8
+ #
9
+ # it { is_expected.to set_callback(:save, :arround) }
10
+ # it { is_expected.to set_callback(:validation, :after) }
11
+ class HaveSetCallbackMatcher
12
+ CONTEXTS = %i[before arround after].freeze
13
+ OPERATIONS = %i[initialize build validation create
14
+ find update upsert save destroy].freeze
15
+
16
+ def initialize(*args)
17
+ @type = args[0]
18
+ @hook = args[1]
19
+ end
20
+
21
+ def matches?(klass)
22
+ @model = klass
23
+
24
+ return false unless \
25
+ context_is_correct? ||
26
+ operation_is_correct? ||
27
+ callback_is_correct?
28
+
29
+ testings_presence_callback
30
+ end
31
+
32
+ def description
33
+ "be set_callback(:#{@type}, :#{@hook})"
34
+ end
35
+
36
+ def failure_message
37
+ message_error
38
+ end
39
+
40
+ def failure_message_when_negated
41
+ message_error
42
+ end
43
+
44
+ private
45
+
46
+ def context_is_correct?
47
+ CONTEXTS.include?(@hook)
48
+ end
49
+
50
+ def operation_is_correct?
51
+ OPERATIONS.include?(@type)
52
+ end
53
+
54
+ def callback_is_correct?
55
+ @model.class.respond_to?(:"_#{@type}_callbacks")
56
+ end
57
+
58
+ def testings_presence_callback
59
+ @model.class.send("_#{@type}_callbacks".to_sym).select do |cb|
60
+ cb.filter.eql?(@hook.to_sym)
61
+ end
62
+ end
63
+
64
+ def message_error
65
+ <<-ERROR
66
+ expected #{@model} have method callback :
67
+ set_callback(:#{@type}, :#{@hook}) |document|
68
+ # My callback execution ...
69
+ end
70
+ ERROR
71
+ end
72
+ end
73
+
74
+ def set_callback(*args)
75
+ HaveSetCallbackMatcher.new(*args)
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mongoid
4
+ module Rspec
5
+ module Callbacks
6
+ # Define version to gem
7
+ VERSION = '1.0.0'
8
+
9
+ # Name to gem
10
+ GEM_NAME = 'mongoid7-rspec-callbacks'
11
+
12
+ # Authors
13
+ AUTHORS = ['VAILLANT Jeremy'].freeze
14
+
15
+ # Emails
16
+ EMAILS = ['jeremy@dazzl.tv'].freeze
17
+
18
+ # Licence
19
+ LICENSE = 'GPL-3.0'
20
+
21
+ # Define a summary description to gem
22
+ SUMMARY = 'RSpec Callbacks matchers for Mongoid'
23
+
24
+ # Define a long description to gem
25
+ DESCRIPTION = <<-DESC
26
+ This gem is meant to be use with mongoid-rpsec,
27
+ altought it works by itself. Syntax is the same
28
+ as shoulda-callback-matchers.
29
+ DESC
30
+
31
+ # Define homepage
32
+ HOMEPAGE = 'http://github.com/dazzl-tv/mongoid-rspec-callbacks'
33
+ end
34
+ end
35
+ end