factory_girl_remote_strategy 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f47dcf78670bdee4078ffdf889289242a8f702d8
4
+ data.tar.gz: 21586d574f443b5241782bb89c60a1f8987a868d
5
+ SHA512:
6
+ metadata.gz: 0989d5b79f3bdd5eb330804cbc486b7932d80c5255c22f403767e7583ef97366527cfef3b932f43bcac5f78efb8e16f0cd4983e8c715485ac7e6b7c12d4da068
7
+ data.tar.gz: 95a068b0278b69480af3eeab4b9dd7de5fbb457e9c684412a5f98bab630c85c930c80cde726f1d3a57e4981675590268267f39c832c6c49ab8b294b5f6fad12e
data/.gitignore ADDED
@@ -0,0 +1,17 @@
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
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format doc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in factory_girl_remote_strategy.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Alex Avoyants
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,29 @@
1
+ # factory_girl_remote_strategy
2
+
3
+ FactoryGirl strategy for ActiveResource models.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'factory_girl_remote_strategy'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install factory_girl_remote_strategy
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( http://github.com/shhavel/factory_girl_remote_strategy/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require "rspec/core/rake_task"
4
+ RSpec::Core::RakeTask.new do |t|
5
+ t.rspec_opts = ["-c", "-f documentation", "-r ./spec/spec_helper.rb"]
6
+ t.pattern = 'spec/**/*_spec.rb'
7
+ end
8
+ task default: :spec
@@ -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 "factory_girl_remote_strategy/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "factory_girl_remote_strategy"
8
+ spec.version = FactoryGirlRemoteStrategy::VERSION
9
+ spec.authors = ["Alex Avoyants"]
10
+ spec.email = ["shhavel@gmail.com"]
11
+ spec.summary = %q{FactoryGirl strategy for ActiveResource models.}
12
+ spec.description = %q{FactoryGirl strategy for ActiveResource models.}
13
+ spec.homepage = ""
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 "activesupport", '~> 3.2'
22
+ spec.add_dependency "activeresource", '~> 3.2'
23
+ spec.add_dependency "factory_girl"
24
+ spec.add_dependency "fakeweb"
25
+ spec.add_development_dependency "bundler", "~> 1.5"
26
+ spec.add_development_dependency "rake"
27
+ spec.add_development_dependency "rspec"
28
+ end
@@ -0,0 +1,86 @@
1
+ require "active_support/core_ext/module/delegation"
2
+ require "factory_girl"
3
+ require "active_resource"
4
+ ##
5
+ # FactoryGirl strategy for remote entities
6
+ #
7
+ # - FactoryGirl.remote(:incident) builds incident and registers get url with FakeWeb;
8
+ # - remote associations are added to response json:
9
+ # FactoryGirl.remote(:incident, victims: FactoryGirl.remote_list(:victim, 2))
10
+ # - also allows to create has_many association with <assotiation(s)>_ids option:
11
+ # FactoryGirl.remote(:incident, victim_ids: [2, 3])
12
+ # - belongs_to association id is added to response json:
13
+ # FactoryGirl.remote(:membership, group: group) # group_id is added to serialized hash
14
+ # - after(:remote) callback in factories.
15
+ #
16
+ module FactoryGirl
17
+ class RemoteStrategy
18
+ def initialize
19
+ @strategy = FactoryGirl.strategy_by_name(:build).new
20
+ end
21
+
22
+ delegate :association, to: :@strategy
23
+
24
+ def result(evaluation)
25
+ @strategy.result(evaluation).tap do |e|
26
+ FakeWeb.register_uri(:get, self.class.entity_url(e), body: self.class.entity_hash(e).to_json)
27
+ evaluation.notify(:after_remote, e) # runs after(:remote) callback
28
+ end
29
+ end
30
+
31
+ class << self
32
+ def entity_hash(entity)
33
+ raise ArgumentError, "cann't construct hash for non ActiveResource::Base object" unless entity.is_a?(ActiveResource::Base)
34
+ attributes = entity.attributes
35
+ # Set belongs_to <association>_id instead of each <association>.
36
+ attributes.select { |k, v| v.is_a?(ActiveResource::Base) }.each do |k, v|
37
+ attributes[:"#{k}_id"] = v.id
38
+ attributes.delete(k)
39
+ end
40
+ # Set has_many <association> instead of each <association(s)>_ids.
41
+ attributes.map do |k, v|
42
+ next unless k.to_s =~ /^(\w+)_ids$/ && FactoryGirl.factories.map(&:name).include?(f = $1.singularize.to_sym) && v.is_a?(Array)
43
+ [k, v, f, $1.pluralize.to_sym]
44
+ end.compact.each do |k, v, f, r|
45
+ attributes[r] = v.map { |id| FactoryGirl.remote(f, id: id) }
46
+ attributes.delete(k)
47
+ end
48
+ # Serilaize has_many associations.
49
+ attributes.each do |k, v|
50
+ if v.is_a?(Array) && v.first.is_a?(ActiveResource::Base)
51
+ attributes[k] = v.map { |e| entity_hash(e) }
52
+ end
53
+ end
54
+ { entity.class.element_name => attributes, _metadata: { abilities: %w(update destroy) } }
55
+ end
56
+
57
+ def entity_url(entity)
58
+ "#{entity.class.site}#{entity.class.prefix}#{entity.class.collection_name}/#{entity.id}.json"
59
+ end
60
+
61
+ def collection_url(collection)
62
+ collection.first.class.instance_eval { "#{site}#{prefix}#{collection_name}.json" }
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ FactoryGirl.register_strategy(:remote, FactoryGirl::RemoteStrategy)
69
+
70
+ module RemoteStrategySearchHelper
71
+ ##
72
+ # Helper method for register search url with provided params and serialized collection as response.
73
+ #
74
+ def remote_search(*args)
75
+ params = args.extract_options!
76
+ collection = args.flatten
77
+ FakeWeb.register_uri(:get, "#{FactoryGirl::RemoteStrategy.collection_url(collection)}?#{params.to_query}",
78
+ body: collection.map { |e| FactoryGirl::RemoteStrategy.entity_hash(e) }.to_json)
79
+ end
80
+ end
81
+
82
+ module FactoryGirl::Syntax::Methods
83
+ include RemoteStrategySearchHelper
84
+ end
85
+
86
+ FactoryGirl.extend RemoteStrategySearchHelper
@@ -0,0 +1,3 @@
1
+ module FactoryGirlRemoteStrategy
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,5 @@
1
+ FactoryGirl.define do
2
+ factory :group do
3
+ sequence(:id)
4
+ end
5
+ end
@@ -0,0 +1,13 @@
1
+ FactoryGirl.define do
2
+ factory :incident do
3
+ sequence(:id)
4
+ victims []
5
+ reported_by nil
6
+
7
+ after(:remote) do |incident, evaluator|
8
+ if incident.reported_by
9
+ FactoryGirl.remote(:user, id: incident.reported_by, full_name: 'Reporter Name')
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ FactoryGirl.define do
2
+ factory :membership do
3
+ sequence(:id)
4
+ group_id nil
5
+
6
+ after(:build) do |membership, evaluator|
7
+ if !evaluator.group_id && !evaluator.respond_to?(:group)
8
+ membership.group = FactoryGirl.remote(:group)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ FactoryGirl.define do
2
+ factory :user do
3
+ sequence(:id)
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ FactoryGirl.define do
2
+ factory :victim do
3
+ sequence(:id)
4
+ end
5
+ end
@@ -0,0 +1,67 @@
1
+ require "spec_helper"
2
+
3
+ describe FactoryGirl::RemoteStrategy do
4
+ # - FactoryGirl.remote(:incident) builds incident and registers get url with FakeWeb;
5
+ # - remote associations are added to response json:
6
+ # FactoryGirl.remote(:incident, victims: FactoryGirl.remote_list(:victim, 2))
7
+ # - also allows to create has_many association with <assotiation(s)>_ids option:
8
+ # FactoryGirl.remote(:incident, victim_ids: [2, 3])
9
+ # - belongs_to association id is added to response json:
10
+ # FactoryGirl.remote(:membership, group: group) # group_id is added to serialized hash
11
+ # - after(:remote) callback in factories.
12
+ describe "basic usage" do
13
+ it "builds instance and registers get url with FakeWeb" do
14
+ FactoryGirl.remote(:incident, id: 1)
15
+ expect { Incident.find(1) }.not_to raise_error
16
+ incident = Incident.find(1)
17
+ incident.should be_kind_of Incident
18
+ end
19
+ end
20
+
21
+ describe "Associations in JSON response" do
22
+ let(:victims) { FactoryGirl.remote_list(:victim, 2) }
23
+ let(:group) { FactoryGirl.remote(:group) }
24
+
25
+ it "remote associations are added to response json" do
26
+ FactoryGirl.remote(:incident, id: 3, victims: victims)
27
+ incident = Incident.find(3)
28
+ incident.victims.should be_kind_of Array
29
+ incident.victims.first.should be_kind_of Victim
30
+ end
31
+
32
+ it "allows to create has_many association with <assotiation(s)>_ids option" do
33
+ FactoryGirl.remote(:incident, id: 4, victim_ids: [2, 3])
34
+ incident = Incident.find(4)
35
+ incident.victims.should be_kind_of Array
36
+ incident.victims.first.should be_kind_of Victim
37
+
38
+ expect { Victim.find(2) }.not_to raise_error
39
+ victim = Victim.find(2)
40
+ victim.should eq incident.victims.first
41
+ end
42
+
43
+ it "belongs_to association id is added to response json" do
44
+ membership = FactoryGirl.remote(:membership, group: group)
45
+ membership.group_id.should == group.id
46
+ end
47
+ end
48
+
49
+ describe "after(:remote) callback in factories" do
50
+ it "invokes after(:remote) callback" do
51
+ incident = FactoryGirl.remote(:incident, reported_by: 4)
52
+ expect { User.find(4) }.not_to raise_error
53
+ user = User.find(4)
54
+ user.should be_kind_of User
55
+ end
56
+ end
57
+
58
+ describe "FactoryGirl.remote_search" do
59
+ it "registers search url with FakeWeb" do
60
+ remote_search FactoryGirl.remote_list(:membership, 2), search: { premises_id_in: [4] }
61
+ expect { Membership.find(:all, params: { search: { premises_id_in: [4] } }) }.not_to raise_error
62
+ memberships = Membership.find(:all, params: { search: { premises_id_in: [4] } })
63
+ memberships.should be_kind_of Array
64
+ memberships.first.should be_kind_of Membership
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,12 @@
1
+ require "factory_girl_remote_strategy"
2
+ require "fakeweb"
3
+
4
+ FakeWeb.allow_net_connect = false
5
+
6
+ FactoryGirl.find_definitions
7
+
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].sort.each {|f| require f}
9
+
10
+ RSpec.configure do |config|
11
+ config.include FactoryGirl::Syntax::Methods
12
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "json_with_metadata_formatter"
2
+
3
+ class Group < ActiveResource::Base
4
+ self.element_name = "group"
5
+ self.collection_name = "groups"
6
+ self.format = JsonWithMetadataFormatter.new
7
+ self.site = "http://example.com"
8
+ self.prefix = "/api/v1/"
9
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "json_with_metadata_formatter"
2
+
3
+ class Incident < ActiveResource::Base
4
+ self.element_name = "incident"
5
+ self.collection_name = "incidents"
6
+ self.format = JsonWithMetadataFormatter.new
7
+ self.site = "http://example.com"
8
+ self.prefix = "/api/v1/"
9
+ end
@@ -0,0 +1,42 @@
1
+ class JsonWithMetadataFormatter
2
+ include ActiveResource::Formats::JsonFormat
3
+
4
+ ##
5
+ # Since usual JSON from Facewatch has multiple root keys, such as object and _metadata
6
+ #
7
+ # {
8
+ # "incident": {"id": 1, ...},
9
+ # "_metadata": {"abilities": ['eat_cookies']}
10
+ # }
11
+ #
12
+ # To be able to get object with its params just after AResObject.find(..), we remove _metadata
13
+ # root key for now since we do not use it internally in APIs
14
+ #
15
+ def decode(json)
16
+ decoded_json = ActiveSupport::JSON.decode(json)
17
+ iterate_by_nodes(decoded_json)
18
+ ActiveResource::Formats.remove_root(decoded_json)
19
+ end
20
+
21
+ def iterate_by_nodes(json)
22
+ iterate_by_array(json) if json.is_a? Array
23
+
24
+ iterate_by_hash(json) if json.is_a? Hash
25
+ end
26
+
27
+ private
28
+
29
+ def iterate_by_hash(hash)
30
+ hash.delete('_metadata')
31
+
32
+ hash.each_pair do |k, v|
33
+ iterate_by_nodes(v)
34
+ end
35
+ end
36
+
37
+ def iterate_by_array(array)
38
+ array.each do |item|
39
+ iterate_by_nodes(item)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "json_with_metadata_formatter"
2
+
3
+ class Membership < ActiveResource::Base
4
+ self.element_name = "membership"
5
+ self.collection_name = "memberships"
6
+ self.format = JsonWithMetadataFormatter.new
7
+ self.site = "http://example.com"
8
+ self.prefix = "/api/v1/"
9
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "json_with_metadata_formatter"
2
+
3
+ class User < ActiveResource::Base
4
+ self.element_name = "user"
5
+ self.collection_name = "users"
6
+ self.format = JsonWithMetadataFormatter.new
7
+ self.site = "http://example.com"
8
+ self.prefix = "/api/v1/"
9
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "json_with_metadata_formatter"
2
+
3
+ class Victim < ActiveResource::Base
4
+ self.element_name = "victim"
5
+ self.collection_name = "victims"
6
+ self.format = JsonWithMetadataFormatter.new
7
+ self.site = "http://example.com"
8
+ self.prefix = "/api/v1/"
9
+ end
metadata ADDED
@@ -0,0 +1,177 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: factory_girl_remote_strategy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Alex Avoyants
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-08 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: activeresource
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '3.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '3.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: factory_girl
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: fakeweb
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '1.5'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '1.5'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
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
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: FactoryGirl strategy for ActiveResource models.
112
+ email:
113
+ - shhavel@gmail.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - .gitignore
119
+ - .rspec
120
+ - Gemfile
121
+ - LICENSE.txt
122
+ - README.md
123
+ - Rakefile
124
+ - factory_girl_remote_strategy.gemspec
125
+ - lib/factory_girl_remote_strategy.rb
126
+ - lib/factory_girl_remote_strategy/version.rb
127
+ - spec/factories/group.rb
128
+ - spec/factories/incident.rb
129
+ - spec/factories/membership.rb
130
+ - spec/factories/user.rb
131
+ - spec/factories/victim.rb
132
+ - spec/factory_girl_remote_strategy_spec.rb
133
+ - spec/spec_helper.rb
134
+ - spec/support/group.rb
135
+ - spec/support/incident.rb
136
+ - spec/support/json_with_metadata_formatter.rb
137
+ - spec/support/membership.rb
138
+ - spec/support/user.rb
139
+ - spec/support/victim.rb
140
+ homepage: ''
141
+ licenses:
142
+ - MIT
143
+ metadata: {}
144
+ post_install_message:
145
+ rdoc_options: []
146
+ require_paths:
147
+ - lib
148
+ required_ruby_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ required_rubygems_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ requirements: []
159
+ rubyforge_project:
160
+ rubygems_version: 2.2.2
161
+ signing_key:
162
+ specification_version: 4
163
+ summary: FactoryGirl strategy for ActiveResource models.
164
+ test_files:
165
+ - spec/factories/group.rb
166
+ - spec/factories/incident.rb
167
+ - spec/factories/membership.rb
168
+ - spec/factories/user.rb
169
+ - spec/factories/victim.rb
170
+ - spec/factory_girl_remote_strategy_spec.rb
171
+ - spec/spec_helper.rb
172
+ - spec/support/group.rb
173
+ - spec/support/incident.rb
174
+ - spec/support/json_with_metadata_formatter.rb
175
+ - spec/support/membership.rb
176
+ - spec/support/user.rb
177
+ - spec/support/victim.rb