belongs_to_one_of 0.2.0

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
+ 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: []