belongs_to_one_of 0.2.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
+ SHA256:
3
+ metadata.gz: 98bf15abb668273f22d84ff9bf834806e66994533eb2393ae07929f2dd675789
4
+ data.tar.gz: d53da88da80da202fb3cc65f041f8dbeffb2a388017dc667694452ef8182d6b8
5
+ SHA512:
6
+ metadata.gz: 8b06bcea6fa1f26f0791829451d3eedf8f82737e7710502a0222ca3bb94a97ed6402aef8fd935165bb664a45602a5c1e4a7bc529ff650bbf9d48e7e548010276
7
+ data.tar.gz: b1b2a1fbf7b60889cad46f9a97b61cbfb0dde782f1a11ff90b1efd189e225d2bfe94a01fbb186e99d2ce7ea31d9d2236b1b438bca23c55ff5875326ed5e35151
@@ -0,0 +1,53 @@
1
+ version: 2.1
2
+
3
+ jobs:
4
+ test:
5
+ parameters:
6
+ ruby-version:
7
+ type: string
8
+ rails-version:
9
+ type: string
10
+
11
+ docker:
12
+ - image: ruby:<<parameters.ruby-version>>
13
+ environment:
14
+ - RAILS_VERSION=<<parameters.rails-version>>
15
+ steps:
16
+ - checkout
17
+
18
+ - run: gem install bundler
19
+ - run: bundle install
20
+
21
+ - run: |
22
+ bundle exec rspec --profile 10 \
23
+ --format RspecJunitFormatter \
24
+ --out /tmp/test-results/rspec.xml \
25
+ --format progress \
26
+ spec
27
+ - store_test_results:
28
+ path: /tmp/test-results
29
+
30
+ rubocop:
31
+ docker:
32
+ - image: ruby:2.7
33
+ steps:
34
+ - checkout
35
+ - run: gem install bundler -v 2.1.4
36
+ - run: bundle install
37
+ - run:
38
+ name: Rubocop
39
+ command: bundle exec rubocop --parallel --extra-details --display-style-guide
40
+
41
+ workflows:
42
+ version: 2
43
+ tests:
44
+ jobs:
45
+ - test:
46
+ matrix:
47
+ parameters:
48
+ ruby-version: ["2.6", "2.7", "3.0"]
49
+ rails-version: ["5.2", "6.0", "6.1"]
50
+ exclude:
51
+ - ruby-version: "3.0"
52
+ rails-version: "5.2"
53
+ - rubocop
@@ -0,0 +1,6 @@
1
+ ---
2
+ version: 1
3
+ update_configs:
4
+ - package_manager: "ruby:bundler"
5
+ directory: "/"
6
+ update_schedule: "weekly"
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ Gemfile.lock
data/.rubocop.yml ADDED
@@ -0,0 +1,10 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ inherit_gem:
4
+ gc_ruboconfig: rubocop.yml
5
+
6
+ AllCops:
7
+ TargetRubyVersion: 2.6
8
+
9
+ Style/CaseLikeIf:
10
+ Enabled: false
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,16 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2020-04-17 14:28:59 +0100 using RuboCop version 0.80.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 2
10
+ Metrics/AbcSize:
11
+ Max: 22
12
+
13
+ # Offense count: 3
14
+ # Configuration parameters: CountComments, ExcludedMethods.
15
+ Metrics/MethodLength:
16
+ Max: 37
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.7.1
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
6
+
7
+ gem "activerecord", "~> #{ENV['RAILS_VERSION']}" if ENV["RAILS_VERSION"]
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2021 GoCardless
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,178 @@
1
+ # belongs_to_one_of
2
+ Gem to support activemodel relations where one model can be a child of one of many models.
3
+ In our examples, we will be targeting a class `Competitor` which can either belong to a `School` or a `College`.
4
+ We will consider this more general concept an `organisation`.
5
+
6
+ The gem provides a simple method to declare this relationship, some validators to enforce the relationships,
7
+ and some helper functions to safely set and get the associated model.
8
+
9
+ ## What about rails polymorphic relations?
10
+
11
+ Unlike rails polymorphic relations, this supports having a separate `id` column for each parent
12
+ model type (e.g. `school_id` and `college_id` instead of just `organisation_id`). This is desirable
13
+ (in some cases) to enable the database to use foreign keys.
14
+
15
+ The gem will also error if you try to set a resource which isn't one of the specified classes, unlike
16
+ a rails polymorphic relation which will accept any model class.
17
+
18
+
19
+ ## Installation
20
+
21
+ Install the package from Rubygems:
22
+ ```shell script
23
+ gem install belongs_to_one_of
24
+ ```
25
+
26
+ Or add it to your gemfile
27
+ ```
28
+ gem 'belongs_to_one_of'
29
+ ```
30
+
31
+ For our policy on compatibility with Ruby versions, see [COMPATIBILITY.md](docs/COMPATIBILITY.md).
32
+
33
+ ## Quick Start
34
+
35
+ Our code will say:
36
+
37
+ > This model belongs to an organisation, which might be a School or might be a College
38
+
39
+ This allows us to store the association in the columns `school_id` and `college_id`, which can use foreign keys,
40
+ but for the 99% of your code which doesn't care which is which, they can just call a method `organisation` or
41
+ `organisation_id` to access the resource.
42
+
43
+ The library adds a new association to `ActiveRecord` called `belongs_to_one_of :organisation, `. To use it, simply call this
44
+ hook in your `ActiveRecord` class:
45
+
46
+ ```ruby
47
+ class Competitor < ActiveRecord::Base
48
+ belongs_to_one_of :organisation, %i[school college]
49
+ end
50
+
51
+ class School < ActiveRecord::Base
52
+ has_many :competitors
53
+ end
54
+
55
+ class College < ActiveRecord::Base
56
+ has_many :competitors
57
+ end
58
+
59
+ school = School.new
60
+
61
+ my_competitor = Competitor.create(name: 'jack', organisation: school)
62
+
63
+ my_competitor.organisation
64
+ # => school
65
+
66
+ my_competitor.organisation_id == school.id
67
+ # => true
68
+ ```
69
+
70
+ Note that this helper calls `belongs_to :school, optional:true` and `belongs_to :college, optional:true`, so you don't have to.
71
+
72
+ ## Available methods
73
+
74
+ The hook defines a few methods on your class. The names are dynamic, we will use 'organisation' as our example
75
+ (as per above):
76
+
77
+ ### Validators
78
+
79
+ #### `belongs_to_exactly_one_[organisation]`
80
+ A validator that can be used to check that a model belongs to exactly one organisation
81
+
82
+ #### `belongs_to_at_most_one_[organisation]`
83
+ A validator that can be used to check that a model belongs to either no organisations or one organisation
84
+
85
+ #### `[organisation_type]_matches_[organisation]`
86
+ A validator that can be used to check that the type of model matches the model. Only relevant when
87
+ `include_type_column` is true
88
+
89
+ ### Getters & Setters
90
+
91
+ #### `[organisation]=`
92
+ Allows you to create a new instance of the model with the interface:
93
+
94
+ ```ruby
95
+ Competitor.new(
96
+ organisation: my_school,
97
+ name: "Joe Bloggs"
98
+ )
99
+ ```
100
+
101
+ This will raise a `ModelNotFound` exception if the organisation is not one of the permitted model types
102
+
103
+ #### `[organisation]`
104
+ Allows you to get the linked resource via `.organisation` e.g.:
105
+ ```ruby
106
+ my_competitor.organisation
107
+ ```
108
+ #### `[organisation]_id`
109
+ Allows you to get the linked resource's id via `.organisation_id` e.g.:
110
+ ```ruby
111
+ my_competitor.organisation_id
112
+ ```
113
+
114
+ #### `[organisation]_type`
115
+ This is only set when the associations are configured with `include_type_column` (see below). This allows you to access the resource type via
116
+ `.organisation_type` e.g.:
117
+ ```ruby
118
+ my_competitor.organisation_type
119
+ # => 'School'
120
+ ```
121
+
122
+ ## Configuration Options
123
+
124
+ ### `include_type_column`
125
+
126
+ By default, the library assumes that the underlying table looks like:
127
+
128
+ `id` | `name` | `school_id` | `college_id`
129
+ ----|----|---|---
130
+ 1 | Aaron J Aaronson | | COL123
131
+ 2 | Betty F Parker | SCH456 |
132
+
133
+ however you can set `include_type_column: true` to explicitly store what type of model is connected, e.g.:
134
+
135
+ ```ruby
136
+ belongs_to_one_of :organisation, %i[school college], include_type_column: true
137
+ ```
138
+
139
+ `id` | `name` | `organisation_type` | `school_id` | `college_id`
140
+ ----|----|---|---|---
141
+ 1 | Aaron J Aaronson | College | | COL123
142
+ 2 | Betty F Parker | School | SCH456 |
143
+
144
+ if the column is not called `[organisation]_type`, you can specify the column name e.g.
145
+
146
+ ```ruby
147
+ belongs_to_one_of :organisation, %i[school college], include_type_column: :type_of_organisation
148
+ ```
149
+
150
+ `id` | `name` | `type_of_organisation` | `school_id` | `college_id`
151
+ ----|----|---|---|---
152
+ 1 | Aaron J Aaronson | College | | COL123
153
+ 2 | Betty F Parker | School | SCH456 |
154
+
155
+
156
+ ### `type_column_value`
157
+
158
+ If you have `include_type_column: true` set, by default we assume you want to store the classname in the db.
159
+ However, there may be some logic that you want to apply. If you pass a Proc to `type_column_value`
160
+ you can add your own logic to determine what goes into the db.
161
+
162
+ ```ruby
163
+ belongs_to_one_of :organisation, %i[school college], include_type_column: true,
164
+ type_column_value: ->(resource) { resource.class.downcase }
165
+ ```
166
+
167
+ `id` | `name` | `organisation_type` | `school_id` | `college_id`
168
+ ----|----|---|---|---
169
+ 1 | Aaron J Aaronson | college | | COL123
170
+ 2 | Betty F Parker | school | SCH456 |
171
+
172
+
173
+ ## License & Contributing
174
+
175
+ * BelongsToOneOf is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
176
+ * Bug reports and pull requests are welcome on GitHub at https://github.com/gocardless/belongs-to-one-of.
177
+
178
+ GoCardless ♥ open source. If you do too, come [join us](https://gocardless.com/about/careers/).
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("lib", __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require "belongs_to_one_of/version"
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = "belongs_to_one_of"
10
+ spec.version = BelongsToOneOf::VERSION
11
+ spec.authors = ["GoCardless Engineering"]
12
+ spec.email = ["engineering@gocardless.com"]
13
+
14
+ spec.summary = "A small library that helps with models which can have " \
15
+ "multiple parent model types"
16
+ spec.homepage = "https://github.com/gocardless/belongs-to-one-of"
17
+ spec.license = "MIT"
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
22
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
+ end
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.required_ruby_version = ">= 2.6"
27
+
28
+ spec.add_development_dependency "bundler"
29
+ spec.add_development_dependency "gc_ruboconfig", "~> 2.25.0"
30
+ spec.add_development_dependency "pry-byebug"
31
+ spec.add_development_dependency "rspec", "~> 3.9"
32
+ spec.add_development_dependency "rspec_junit_formatter", "~> 0.4"
33
+
34
+ # For integration testing
35
+ spec.add_development_dependency "sqlite3", "~> 1.4.1"
36
+
37
+ spec.add_dependency "activerecord", ">= 5.2", "< 6.2"
38
+ spec.add_dependency "activesupport", ">= 5.2", "< 6.2"
39
+ end
@@ -0,0 +1,26 @@
1
+ # Compatibility
2
+
3
+ Our goal as maintainers is for the library to be compatible with all supported
4
+ versions of Ruby.
5
+
6
+ Specifically, any CRuby/MRI version that has not received an End of Life notice
7
+ ([e.g. this notice for Ruby 2.1](https://www.ruby-lang.org/en/news/2017/04/01/support-of-ruby-2-1-has-ended/))
8
+ is supported.
9
+
10
+ To that end, [our build matrix](../.circleci/config.yml) includes all these versions.
11
+
12
+ Any time BelongsToOneOf doesn't work on a supported version of Ruby, it's a bug, and can be
13
+ reported [here](https://github.com/gocardless/belongs-to-one-of/issues).
14
+
15
+ # Deprecation
16
+
17
+ Whenever a version of Ruby falls out of support, we will mirror that change in BelongsToOneOf
18
+ by updating the build matrix and releasing a new major version.
19
+
20
+ At that point, we will close any issues that only affect the unsupported version, and may
21
+ choose to remove any workarounds from the code that are only necessary for the unsupported
22
+ version.
23
+
24
+ We will then bump the major version of BelongsToOneOf, to indicate the break in compatibility.
25
+ Even if the new version of BelongsToOneOf happens to work on the unsupported version of Ruby, we
26
+ consider compatibility to be broken at this point.
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record"
4
+ require "active_record/associations"
5
+ require_relative "belongs_to_one_of/belongs_to_one_of_model"
6
+
7
+ # We assume that the connected model is called a 'resource',
8
+ # for the purposes of naming variables in this file
9
+
10
+ module ActiveRecord
11
+ module Associations
12
+ module ClassMethods
13
+ include BelongsToOneOf
14
+
15
+ def belongs_to_one_of(
16
+ resource_key,
17
+ raw_possible_resource_types,
18
+ include_type_column: false
19
+ )
20
+ resource_type_field = "#{resource_key}_type"
21
+ unless [true, false].include?(include_type_column)
22
+ resource_type_field =
23
+ include_type_column
24
+ end
25
+
26
+ config_model = BelongsToOneOfModel.new(
27
+ resource_key,
28
+ raw_possible_resource_types,
29
+ include_type_column,
30
+ resource_type_field,
31
+ self,
32
+ )
33
+
34
+ # validators
35
+ define_method "belongs_to_exactly_one_#{resource_key}" do
36
+ config_model.validate_exactly_one_resource(self)
37
+ end
38
+
39
+ define_method "belongs_to_at_most_one_#{resource_key}" do
40
+ config_model.validate_at_most_one_resource(self)
41
+ end
42
+
43
+ if include_type_column
44
+ define_method "#{resource_type_field}_matches_#{resource_key}" do
45
+ config_model.validate_correct_resource_type(self)
46
+ end
47
+ end
48
+
49
+ # setters
50
+ define_method "#{resource_key}=" do |resource|
51
+ config_model.resource_setter(resource, self)
52
+ end
53
+
54
+ # getters
55
+ define_method resource_key do
56
+ config_model.resource_getter(self)
57
+ end
58
+
59
+ define_method "#{resource_key}_id" do
60
+ config_model.resource_id_getter(self)
61
+ end
62
+
63
+ unless include_type_column
64
+ define_method "#{resource_key}_type" do
65
+ config_model.resource_type_getter(self)
66
+ end
67
+ end
68
+ end
69
+
70
+ def self.included(base)
71
+ base.extend(ClassMethods)
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BelongsToOneOf
4
+ class BelongsToOneOfModel
5
+ class InvalidParamsException < ArgumentError; end
6
+
7
+ def initialize(
8
+ resource_key,
9
+ raw_possible_resource_types,
10
+ include_type_column,
11
+ resource_type_field,
12
+ model_class
13
+ )
14
+ @resource_key = resource_key
15
+ @possible_resource_types = normalise_resource_types(raw_possible_resource_types)
16
+ @include_type_column = include_type_column
17
+ @resource_type_field = resource_type_field
18
+ @model_class = model_class
19
+ validate_config
20
+ initialize_associations
21
+ end
22
+
23
+ attr_reader :resource_key, :possible_resource_types, :include_type_column,
24
+ :resource_type_field, :model_class
25
+
26
+ # TODO: I18n the error messages (provide translations??)
27
+ def validate_exactly_one_resource(model)
28
+ return if number_of_resources(model) == 1
29
+
30
+ model.errors.add(:base, "model must belong to exactly one #{resource_key}")
31
+ end
32
+
33
+ def validate_at_most_one_resource(model)
34
+ return unless number_of_resources(model) > 1
35
+
36
+ model.errors.add(:base, "model must belong to at most one #{resource_key}")
37
+ end
38
+
39
+ def validate_correct_resource_type(model)
40
+ resource = model.send(resource_key)
41
+ return unless resource
42
+
43
+ actual_resource_type = resource_type_getter(model)
44
+ specified_resource_type = model.send(resource_type_field)
45
+
46
+ unless actual_resource_type == specified_resource_type
47
+ model.errors.add(
48
+ resource_type_field,
49
+ "#{resource_type_field} must match the type of #{resource_key}",
50
+ )
51
+ end
52
+ end
53
+
54
+ def resource_setter(resource, model)
55
+ return if resource.nil?
56
+
57
+ possible_resource_types.each_key do |resource_type|
58
+ model.public_send("#{resource_type}=", nil)
59
+ end
60
+
61
+ model.instance_variable_set("@#{resource_key}", resource)
62
+ resource_type_accessor = find_resource_accessor(resource, model)
63
+
64
+ unless resource_type_accessor
65
+ message = "one of #{possible_resource_types.keys.join(', ')} expected, "\
66
+ "got #{resource.inspect} which is an instance of "\
67
+ "#{resource.class}(##{resource.class.object_id})"
68
+ raise ActiveRecord::AssociationTypeMismatch, message
69
+ end
70
+
71
+ resource_setter_method = "#{resource_type_accessor}="
72
+ model.public_send(resource_setter_method, resource)
73
+
74
+ if include_type_column
75
+ resource_type_setter_method = "#{resource_type_field}="
76
+ resource_type_to_store = find_resource_type(resource, model)
77
+ model.public_send(resource_type_setter_method, resource_type_to_store)
78
+ end
79
+ end
80
+
81
+ def resource_getter(model)
82
+ possible_resource_types.keys.detect do |resource_type|
83
+ return model.send(resource_type) if model.send(resource_type)
84
+ end
85
+ end
86
+
87
+ def resource_id_getter(model)
88
+ possible_resource_types.values.detect do |id_column|
89
+ return model.send(id_column) if model.send(id_column)
90
+ end
91
+ end
92
+
93
+ def resource_type_getter(model)
94
+ resource = model.send(resource_key)
95
+ return unless resource
96
+
97
+ possible_resource_types.keys.detect do |resource_type_accessor|
98
+ reflection = model.class.reflect_on_association(resource_type_accessor)
99
+ return reflection.class_name if resource.is_a?(reflection.klass)
100
+ end
101
+ end
102
+
103
+ private
104
+
105
+ def validate_config
106
+ unless resource_key.is_a?(Symbol)
107
+ raise InvalidParamsException,
108
+ "expected resource_key to be a symbol, received #{resource_key.class}"
109
+ end
110
+ end
111
+
112
+ def initialize_associations
113
+ possible_resource_types.each do |resource_type_accessor, resource_id_column|
114
+ opts = { optional: true }
115
+
116
+ # Only set :foreign_key for a complex relation. Simple relations can be safely
117
+ # "inflected" (i.e. Rails knows these objects are the same...)
118
+ # foo = Foo.find(1)
119
+ # foo.bar.foo == foo
120
+ if resource_id_column.to_s.gsub!(/_id$/, "") != resource_type_accessor.to_s
121
+ opts[:foreign_key] = resource_id_column
122
+ end
123
+
124
+ model_class.belongs_to(resource_type_accessor, **opts)
125
+ end
126
+ end
127
+
128
+ def normalise_resource_types(raw_possible_resource_types)
129
+ if raw_possible_resource_types.is_a?(Array)
130
+ raw_possible_resource_types.each_with_object({}) do |classname, hash|
131
+ unless classname.is_a?(Symbol)
132
+ raise InvalidParamsException, "expected a symbol, received #{classname}"
133
+ end
134
+
135
+ hash[classname] = "#{classname.to_s.underscore}_id".to_sym
136
+ end
137
+ elsif raw_possible_resource_types.is_a?(Hash)
138
+ raw_possible_resource_types
139
+ else
140
+ raise InvalidParamsException,
141
+ "possible_resource_types must be an Array or a Hash, " \
142
+ "received #{raw_possible_resource_types.class}"
143
+ end
144
+ end
145
+
146
+ def number_of_resources(model)
147
+ possible_resource_types.keys.count do |resource_type_accessor|
148
+ model.send(resource_type_accessor)
149
+ end
150
+ end
151
+
152
+ def find_resource_accessor(resource, model)
153
+ possible_resource_types.keys.detect do |resource_type_accessor|
154
+ reflection = model.class.reflect_on_association(resource_type_accessor)
155
+ return resource_type_accessor if resource.is_a?(reflection.klass)
156
+ end
157
+ end
158
+
159
+ def find_resource_type(resource, model)
160
+ possible_resource_types.keys.detect do |resource_type_accessor|
161
+ reflection = model.class.reflect_on_association(resource_type_accessor)
162
+ return reflection.class_name if resource.is_a?(reflection.klass)
163
+ end
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BelongsToOneOf
4
+ VERSION = "0.2.0"
5
+ end
metadata ADDED
@@ -0,0 +1,182 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: belongs_to_one_of
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - GoCardless Engineering
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-06-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: gc_ruboconfig
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.25.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.25.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry-byebug
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
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: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.9'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.9'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec_junit_formatter
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.4'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.4'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sqlite3
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 1.4.1
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 1.4.1
97
+ - !ruby/object:Gem::Dependency
98
+ name: activerecord
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '5.2'
104
+ - - "<"
105
+ - !ruby/object:Gem::Version
106
+ version: '6.2'
107
+ type: :runtime
108
+ prerelease: false
109
+ version_requirements: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '5.2'
114
+ - - "<"
115
+ - !ruby/object:Gem::Version
116
+ version: '6.2'
117
+ - !ruby/object:Gem::Dependency
118
+ name: activesupport
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '5.2'
124
+ - - "<"
125
+ - !ruby/object:Gem::Version
126
+ version: '6.2'
127
+ type: :runtime
128
+ prerelease: false
129
+ version_requirements: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '5.2'
134
+ - - "<"
135
+ - !ruby/object:Gem::Version
136
+ version: '6.2'
137
+ description:
138
+ email:
139
+ - engineering@gocardless.com
140
+ executables: []
141
+ extensions: []
142
+ extra_rdoc_files: []
143
+ files:
144
+ - ".circleci/config.yml"
145
+ - ".dependabot/config.yml"
146
+ - ".gitignore"
147
+ - ".rubocop.yml"
148
+ - ".rubocop_todo.yml"
149
+ - ".ruby-version"
150
+ - Gemfile
151
+ - LICENSE.txt
152
+ - README.md
153
+ - belongs_to_one_of.gemspec
154
+ - docs/COMPATABILITY.md
155
+ - lib/belongs_to_one_of.rb
156
+ - lib/belongs_to_one_of/belongs_to_one_of_model.rb
157
+ - lib/belongs_to_one_of/version.rb
158
+ homepage: https://github.com/gocardless/belongs-to-one-of
159
+ licenses:
160
+ - MIT
161
+ metadata: {}
162
+ post_install_message:
163
+ rdoc_options: []
164
+ require_paths:
165
+ - lib
166
+ required_ruby_version: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - ">="
169
+ - !ruby/object:Gem::Version
170
+ version: '2.6'
171
+ required_rubygems_version: !ruby/object:Gem::Requirement
172
+ requirements:
173
+ - - ">="
174
+ - !ruby/object:Gem::Version
175
+ version: '0'
176
+ requirements: []
177
+ rubygems_version: 3.1.3
178
+ signing_key:
179
+ specification_version: 4
180
+ summary: A small library that helps with models which can have multiple parent model
181
+ types
182
+ test_files: []