factory_girl_remote_strategy 0.0.1

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: 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