shiftable 0.3.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 15d27c7c2706faf797241101fa5229f4bf707b06f4d1b7c839cc66fd7ab2ecf8
4
- data.tar.gz: 0fa0fbe15096d109c2d63568101ad0589b4c684775b69b95e831289b8bfdac3d
3
+ metadata.gz: 8bad3e2f27677202648655a227fa9f251a595910db9146c9fdb72952657053d3
4
+ data.tar.gz: 481fede6aa751831cec5c19fe8849b61b081f51cfd4e5aa0a7522ecbb31b38bf
5
5
  SHA512:
6
- metadata.gz: fa80c525bb2a0cfa99a82350da151412972f86a6699e1091e520d9cec40466f07789e5d1e593f8e3b720cc9e447d742acf28f2c09f5b02c61745cf8ca79084cf
7
- data.tar.gz: 4abc0b5c410ba1748646122914ac768829984934e1f57b4d0483db18d0d5985b1976d69deeceabb3bf04fc5b4e3b6307056e3eeae2cffbd89e8099059cb32c07
6
+ metadata.gz: 050f4afb2b1ad1e81cd9209dfee0a0f1270745a02bfea84dcaff3914794349c4e6b53b01fb21873731ad05693ae0d02639ee3ade2a0f0d1b5b103fc30952e362
7
+ data.tar.gz: 5bfc201b247b3082a0a1836c164133f73f59f317de9664934f08bc28a6b3d00140e2c2a3fe0ed7da2a0450fcabb67c66eb28e28c3787403517eadd28fb8d8114
data/CHANGELOG.md CHANGED
@@ -1,9 +1,44 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.3.0] - 2021-10-26
3
+ ### Added
4
+
4
5
 
5
6
  ### Changed
6
7
 
8
+
9
+ ### Fixed
10
+
11
+
12
+ ### Removed
13
+
14
+
15
+ ## [0.5.1] - 2021-11-12
16
+ ### Fixed
17
+
18
+ - Documentation typos in README
19
+
20
+ ## [0.5.0] - 2021-11-12
21
+ ### Added
22
+
23
+ - Support for Polymorphic associations (see examples in specs or README)
24
+
25
+ ## [0.4.1] - 2021-11-10
26
+ ### Fixed
27
+
28
+ - Documentation typos in README
29
+
30
+ ## [0.4.0] - 2021-10-27
31
+ ### Changed
32
+
33
+ - option :preflight_checks renamed to :precheck
34
+
35
+ ### Added
36
+
37
+ - Even more 100% spec coverage
38
+
39
+ ## [0.3.0] - 2021-10-26
40
+ ### Changed
41
+
7
42
  - Internal rewrite to improve maintainability
8
43
  - Extreme edge cases involving incorrect configuration will raise slightly different errors.
9
44
 
@@ -12,7 +47,6 @@
12
47
  - Even more 100% spec coverage
13
48
 
14
49
  ## [0.2.0] - 2021-10-24
15
-
16
50
  ### Changed
17
51
 
18
52
  - option `before_save` is now `before_shift` as originally documented
@@ -24,7 +58,6 @@
24
58
  - Documentation
25
59
 
26
60
  ## [0.1.1] - 2021-10-23
27
-
28
61
  ### Fixed
29
62
 
30
63
  - Github Actions build
@@ -34,7 +67,6 @@
34
67
  - Linting
35
68
 
36
69
  ## [0.1.0] - 2021-10-23
37
-
38
70
  ### Added
39
71
 
40
72
  - Initial release
@@ -42,4 +74,11 @@
42
74
  - 100% test coverage
43
75
 
44
76
  [0.1.0]: https://github.com/pboling/shiftable/releases/tag/v0.1.0
45
- [0.1.1]: https://github.com/pboling/shiftable/releases/tag/v0.1.1
77
+
78
+ [0.1.1]: https://github.com/pboling/shiftable/releases/tag/v0.1.1
79
+
80
+ [0.2.0]: https://github.com/pboling/shiftable/releases/tag/v0.2.0
81
+
82
+ [0.3.0]: https://github.com/pboling/shiftable/releases/tag/v0.3.0
83
+
84
+ [0.4.0]: https://github.com/pboling/shiftable/releases/tag/v0.4.0
data/CODE_OF_CONDUCT.md CHANGED
File without changes
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,25 @@
1
+ ## Contributing
2
+
3
+ Bug reports and pull requests are welcome on GitHub at [https://github.com/pboling/activerecord-transactionable][source]
4
+ . This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to
5
+ the [code of conduct][conduct].
6
+
7
+ To submit a patch, please fork the project and create a patch with tests. Once you're happy with it send a pull request!
8
+
9
+ ## Contributors
10
+
11
+ [![Contributors](https://contrib.rocks/image?repo=pboling/activerecord-transactionable)][contributors]
12
+
13
+ Made with [contributors-img][contrib-rocks].
14
+
15
+ [comment]: <> (Following links are used by README, CONTRIBUTING)
16
+
17
+ [conduct]: https://github.com/pboling/activerecord-transactionable/blob/master/CODE_OF_CONDUCT.md
18
+
19
+ [contrib-rocks]: https://contrib.rocks
20
+
21
+ [contributors]: https://github.com/pboling/activerecord-transactionable/graphs/contributors
22
+
23
+ [comment]: <> (Following links are used by README, CONTRIBUTING, Homepage)
24
+
25
+ [source]: https://github.com/pboling/activerecord-transactionable/
data/LICENSE.txt CHANGED
File without changes
data/README.md CHANGED
@@ -5,31 +5,23 @@ Do your Spaceships belong to Captains, but sometimes a Captain will retire, and
5
5
  We've all been there. This gem provides structure around the process of "shifting" your records from one associated
6
6
  record to a new record.
7
7
 
8
- | Project | Shiftable |
9
- |------------------------ | ----------------------- |
10
- | gem name | [shiftable](https://rubygems.org/gems/shiftable) |
11
- | license | [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT) |
12
- | download rank | [![Downloads Today](https://img.shields.io/gem/rd/shiftable.svg)](https://github.com/pboling/shiftable) |
13
- | version | [![Version](https://img.shields.io/gem/v/shiftable.svg)](https://rubygems.org/gems/shiftable) |
14
- | dependencies | [![Depfu](https://badges.depfu.com/badges/0412727b7e3b740b950a683eebc708e2/count.svg)](https://depfu.com/github/pboling/shiftable?project_id=32594) |
15
- | unit tests | [![unit tests](https://github.com/pboling/shiftable/actions/workflows/test.yml/badge.svg)](https://github.com/pboling/shiftable/actions) |
16
- | lint status | [![lint status](https://github.com/pboling/shiftable/actions/workflows/style.yml/badge.svg)](https://github.com/pboling/shiftable/actions) |
17
- | unsupported status | [![unsupported status](https://github.com/pboling/shiftable/actions/workflows/unsupported.yml/badge.svg)](https://github.com/pboling/shiftable/actions) |
18
- | test coverage | [![Test Coverage](https://api.codeclimate.com/v1/badges/a53aa8b7c413b950d519/test_coverage)](https://codeclimate.com/github/pboling/shiftable/test_coverage) |
19
- | maintainability | [![Maintainability](https://api.codeclimate.com/v1/badges/a53aa8b7c413b950d519/maintainability)](https://codeclimate.com/github/pboling/shiftable/maintainability) |
20
- | code triage | [![Open Source Helpers](https://www.codetriage.com/pboling/shiftable/badges/users.svg)](https://www.codetriage.com/pboling/shiftable) |
21
- | homepage | [on Github.com][homepage], [on Railsbling.com][blogpage] |
22
- | documentation | [on RDoc.info][documentation] |
23
- | Spread ~♡ⓛⓞⓥⓔ♡~ | [🌏][aboutme], [👼][angelme], [💻][coderme], [![Tweet @ Peter][followme-img]][tweetme], [🌹][politicme] |
8
+ | Project | Shiftable |
9
+ |--------------------------- | ----------------------- |
10
+ | name, license, docs | [![RubyGems.org](https://img.shields.io/badge/name-shiftable-brightgreen.svg?style=flat)][rubygems] [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)][license-ref] [![RubyDoc.info](https://img.shields.io/badge/documentation-rubydoc-brightgreen.svg?style=flat)][documentation] |
11
+ | version & downloads | [![Version](https://img.shields.io/gem/v/shiftable.svg)][rubygems] [![Total Downloads](https://img.shields.io/gem/dt/shiftable.svg)][rubygems] [![Downloads Today](https://img.shields.io/gem/rd/shiftable.svg)][rubygems] [![Homepage](https://img.shields.io/badge/source-github-brightgreen.svg?style=flat)][source] |
12
+ | dependencies & linting | [![Depfu](https://badges.depfu.com/badges/0412727b7e3b740b950a683eebc708e2/count.svg)][depfu] [![lint status](https://github.com/pboling/shiftable/actions/workflows/style.yml/badge.svg)][actions] |
13
+ | unit tests | [![supported rubies](https://github.com/pboling/shiftable/actions/workflows/supported.yml/badge.svg)][actions] [![unsupported status](https://github.com/pboling/shiftable/actions/workflows/unsupported.yml/badge.svg)][actions] |
14
+ | coverage & maintainability | [![Test Coverage](https://api.codeclimate.com/v1/badges/a53aa8b7c413b950d519/test_coverage)][climate_coverage] [![codecov](https://codecov.io/gh/pboling/shiftable/branch/main/graph/badge.svg?token=J1542PYN2Z)][codecov_coverage] [![Maintainability](https://api.codeclimate.com/v1/badges/a53aa8b7c413b950d519/maintainability)][climate_maintainability] [![Security Policy](https://img.shields.io/badge/security-policy-brightgreen.svg?style=flat)][security] |
15
+ | resources | [![Discussion](https://img.shields.io/badge/discussions-github-brightgreen.svg?style=flat)][gh_discussions] [![Get help on Codementor](https://cdn.codementor.io/badges/get_help_github.svg)](https://www.codementor.io/peterboling?utm_source=github&utm_medium=button&utm_term=peterboling&utm_campaign=github) [![Join the chat at https://gitter.im/pboling/shiftable](https://badges.gitter.im/Join%20Chat.svg)][chat] [![Blog](https://img.shields.io/badge/blog-railsbling-brightgreen.svg?style=flat)][blogpage] |
16
+ | Spread ~♡ⓛⓞⓥⓔ♡~ | [![Open Source Helpers](https://www.codetriage.com/pboling/shiftable/badges/users.svg)][code_triage] [![Liberapay Patrons](https://img.shields.io/liberapay/patrons/pboling.svg?logo=liberapay)][liberapay_donate] [![Sponsor Me](https://img.shields.io/badge/sponsor-pboling.svg?style=social&logo=github)][gh_sponsors] [🌏][aboutme] [👼][angelme] [💻][coderme] [🌹][politicme] [![Tweet @ Peter][followme-img]][tweetme] |
24
17
 
25
18
  ## Compatibility
26
19
 
27
20
  Targeted ruby compatibility is non-EOL versions of Ruby, currently 2.6, 2.7, and 3.0, but may work on older Rubies back
28
21
  to 2.0, though it is limited to 2.5 in the gemspec. Feel free to fork if you need something older! Targeted ActiveRecord
29
22
  (Rails not required) compatibility follows the same scheme
30
- as [Rails Security Issue maintenance policy](https://guides.rubyonrails.org/maintenance_policy.html#security-issues),
31
- currently 6.1, 6.0, 5.2, but it is highly likely that this code will work in any version of ActiveRecord/Rails that runs
32
- on Ruby 2+.
23
+ as [Rails Security Issue maintenance policy][maintenancee_policy], currently 6.1, 6.0, 5.2, but it is highly likely that
24
+ this code will work in any version of ActiveRecord/Rails that runs on Ruby 2+.
33
25
 
34
26
  ## Installation
35
27
 
@@ -87,7 +79,7 @@ But how can you accomplish this? If you used the `shiftable` gem, won't take but
87
79
 
88
80
  class Spaceship < ActiveRecord::Base
89
81
  belongs_to :captain
90
- extend Shiftable::Single.new belongs_to: :captain, has_one: :spaceship, preflight_checks: true,
82
+ extend Shiftable::Single.new belongs_to: :captain, has_one: :spaceship, precheck: true,
91
83
  before_shift: ->(shifting:, shift_to:, shift_from:) { shifting.ownership_changes += 1 }
92
84
  end
93
85
  ```
@@ -100,8 +92,10 @@ class Spaceship < ActiveRecord::Base
100
92
  belongs_to :captain
101
93
 
102
94
  class << self
103
- include Shiftable::Single.new belongs_to: :captain, has_one: :spaceship, preflight_checks: true,
104
- before_shift: ->(shifting:, shift_to:, shift_from:) { shifting.ownership_changes += 1 }
95
+ include Shiftable::Single.new belongs_to: :captain, has_one: :spaceship, precheck: true,
96
+ before_shift: lambda { |shifting:, shift_to:, shift_from:|
97
+ shifting.ownership_changes += 1
98
+ }
105
99
  end
106
100
  end
107
101
  ```
@@ -110,7 +104,7 @@ end
110
104
 
111
105
  This works as you would expect with STI (single table inheritance) classes, i.e. when defined on a subclass, only the records of that class get shifted.
112
106
 
113
- ### Multiple association on a single class
107
+ ### Multiple associations on a single class
114
108
 
115
109
  What if the captain and the spaceship have a boss... the space
116
110
  federation! And in a run-in with their arch-Nemesis the Plinth-inth,
@@ -120,10 +114,10 @@ all federation spaceships are commandeered! You are ruined!
120
114
 
121
115
  class Spaceship < ActiveRecord::Base
122
116
  belongs_to :space_federation
123
- extend Shiftable::Collection.new belongs_to: :space_federation, has_one: :spaceship,
124
- before_shift: lambda do |shifting_rel:, shift_to:, shift_from:|
125
- shifting_rel.each { |spaceship| spaceship.federation_changes += 1 }
126
- end
117
+ extend Shiftable::Collection.new belongs_to: :space_federation, has_many: :spaceships,
118
+ before_shift: lambda { |shifting_rel:, shift_to:, shift_from:|
119
+ shifting_rel.each { |spaceship| spaceship.federation_changes += 1 }
120
+ }
127
121
  end
128
122
 
129
123
  class SpaceFederation < ActiveRecord::Base
@@ -135,6 +129,68 @@ class SpaceFederation < ActiveRecord::Base
135
129
  end
136
130
  ```
137
131
 
132
+ ### Polymorphism and has_many through
133
+
134
+ ```ruby
135
+ class SpaceTreaty < ActiveRecord::Base
136
+ has_many :space_treaty_signature
137
+ end
138
+
139
+ class SpaceTreatySignature < ActiveRecord::Base
140
+ belongs_to :space_treaty
141
+ belongs_to :signatory, polymorphic: true
142
+ # When two space federations assimilate (i.e. merge) to form a single larger federation,
143
+ # they become party to (i.e. signatories of) all the treaties that had been signed by either.
144
+ # In practical terms, this means:
145
+ #
146
+ # surviving_federation = SpaceFederation.find(1)
147
+ # assimilated_federation = SpaceFederation.find(2)
148
+ # SpaceTreatySignature.where(
149
+ # signatory_id: assimilated_federation_id,
150
+ # signatory_type: "SpaceFederation"
151
+ # ).update_all(
152
+ # signatory_id: surviving_federation.id
153
+ # )
154
+ extend Shiftable::Collection.new(
155
+ belongs_to: :signatory, has_many: :space_treaty_signature,
156
+ polymorphic: { type: "SpaceFederation", as: :signatory },
157
+ method_prefix: "space_federation_",
158
+ before_shift: lambda { |shifting_rel:, shift_to:, shift_from:|
159
+ # Each item in shifting_rel is an instance of the class where Shiftable::Collection is defined,
160
+ # in this case: SpaceTreatySignature
161
+ # And each of them has a signatory which is of type "SpaceFederation",
162
+ # because a polymorphic collection only targets one type.
163
+ # shifting_rel.each { |signature| signature.signatory == "SpaceFederation" }
164
+ }
165
+ )
166
+ end
167
+
168
+ class SpaceFederation < ActiveRecord::Base
169
+ has_many :space_treaty_signature, as: :signatory
170
+ has_many :space_treaties, through: :space_treaty_signatures, as: :signatory
171
+ has_many :treaty_planets, class_name: "Planet", through: :space_treaty_signatures, as: :signatory
172
+ has_many :treaty_stations, class_name: "SpaceStation", through: :space_treaty_signatures, as: :signatory
173
+ def assimilate_from(other_federation)
174
+ SpaceTreatySignature.space_federation_shift_pcx(shift_to: self, shift_from: other_federation)
175
+ end
176
+ end
177
+
178
+ # Including Planet and SpaceStation, for completeness of the example as the other "types" of polymorphic signatories
179
+ class Planet < ActiveRecord::Base
180
+ has_many :space_treaty_signature, as: :signatory
181
+ has_many :space_treaties, through: :space_treaty_signatures
182
+ has_many :treaty_federations, class_name: "SpaceFederation", through: :space_treaty_signatures, as: :signatory
183
+ has_many :treaty_stations, class_name: "SpaceStation", through: :space_treaty_signatures, as: :signatory
184
+ end
185
+
186
+ class SpaceStation < ActiveRecord::Base
187
+ has_many :space_treaty_signature, as: :signatory
188
+ has_many :space_treaties, through: :space_treaty_signatures
189
+ has_many :treaty_federations, class_name: "SpaceFederation", through: :space_treaty_signatures, as: :signatory
190
+ has_many :treaty_planets, class_name: "Planet", through: :space_treaty_signatures, as: :signatory
191
+ end
192
+ ```
193
+
138
194
  ### Complete example
139
195
 
140
196
  Putting it all together...
@@ -150,28 +206,79 @@ end
150
206
 
151
207
  class Spaceship < ActiveRecord::Base
152
208
  belongs_to :captain
153
- extend Shiftable::Single.new belongs_to: :captain, has_one: :spaceship, preflight_checks: true,
209
+ extend Shiftable::Single.new belongs_to: :captain, has_one: :spaceship, precheck: true,
154
210
  before_shift: ->(shifting:, shift_to:, shift_from:) { shifting.ownership_changes += 1 }
155
211
 
156
212
  belongs_to :space_federation
157
- extend Shiftable::Collection.new belongs_to: :space_federation, has_one: :spaceship,
158
- before_shift: lambda do |shifting_rel:, shift_to:, shift_from:|
159
- shifting_rel.each { |spaceship| spaceship.federation_changes += 1 }
160
- end
213
+ extend Shiftable::Collection.new belongs_to: :space_federation, has_many: :spaceships,
214
+ before_shift: lambda { |shifting_rel:, shift_to:, shift_from:|
215
+ shifting_rel.each { |spaceship| spaceship.federation_changes += 1 }
216
+ }
161
217
  end
162
218
 
163
219
  class SpaceFederation < ActiveRecord::Base
164
220
  has_many :captains
165
221
  has_many :spaceships
222
+ has_many :space_treaty_signature, as: :signatory
223
+ has_many :space_treaties, through: :space_treaty_signatures, as: :signatory
224
+ has_many :treaty_planets, class_name: "Planet", through: :space_treaty_signatures, as: :signatory
225
+ has_many :treaty_stations, class_name: "SpaceStation", through: :space_treaty_signatures, as: :signatory
226
+
227
+ def assimilate_from(other_federation)
228
+ SpaceTreatySignature.space_federation_shift_cx(shift_to: self, shift_from: other_federation)
229
+ end
166
230
 
167
231
  def all_spaceships_commandeered_by(nemesis_federation)
168
232
  Spaceship.shift_cx(shift_to: nemesis_federation, shift_from: self)
169
233
  end
170
234
  end
235
+ class SpaceTreaty < ActiveRecord::Base
236
+ has_many :space_treaty_signatures
237
+ end
238
+
239
+ class SpaceTreatySignature < ActiveRecord::Base
240
+ belongs_to :space_treaty
241
+ belongs_to :signatory, polymorphic: true
242
+ extend Shiftable::Collection.new(
243
+ belongs_to: :signatory, has_many: :space_treaty_signatures,
244
+ polymorphic: { type: "SpaceFederation", as: :signatory },
245
+ method_prefix: "space_federation_"
246
+ )
247
+ end
248
+
249
+ # Including Planet and SpaceStation, for completeness of the example as the other "types" of polymorphic signatories
250
+ class Planet < ActiveRecord::Base
251
+ has_many :space_treaty_signatures, as: :signatory
252
+ has_many :space_treaties, through: :space_treaty_signatures
253
+ has_many :treaty_federations, class_name: "SpaceFederation", through: :space_treaty_signatures, as: :signatory
254
+ has_many :treaty_stations, class_name: "SpaceStation", through: :space_treaty_signatures, as: :signatory
255
+ end
256
+
257
+ class SpaceStation < ActiveRecord::Base
258
+ has_many :space_treaty_signature, as: :signatory
259
+ has_many :space_treaties, through: :space_treaty_signatures
260
+ has_many :treaty_federations, class_name: "SpaceFederation", through: :space_treaty_signatures, as: :signatory
261
+ has_many :treaty_planets, class_name: "Planet", through: :space_treaty_signatures, as: :signatory
262
+ end
171
263
  ```
172
264
 
173
265
  ... stay tuned!
174
266
 
267
+ ## More Information
268
+
269
+ * RubyDoc
270
+ Documentation: [![RubyDoc.info](https://img.shields.io/badge/documentation-rubydoc-brightgreen.svg?style=flat)][documentation]
271
+ * GitHub
272
+ Discussions: [![Discussion](https://img.shields.io/badge/discussions-github-brightgreen.svg?style=flat)][gh_discussions]
273
+ * Live Chat on
274
+ Gitter: [![Join the chat at https://gitter.im/pboling/activerecord-transactionable](https://badges.gitter.im/Join%20Chat.svg)][chat]
275
+ * Maintainer's Blog: [![Blog](https://img.shields.io/badge/blog-railsbling-brightgreen.svg?style=flat)][blogpage]
276
+
277
+ ## Code of Conduct
278
+
279
+ Everyone interacting in the Shiftable project's codebases, issue trackers, chat rooms and mailing lists is expected to
280
+ follow the [code of conduct][conduct].
281
+
175
282
  ## Development
176
283
 
177
284
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can
@@ -183,14 +290,13 @@ push git commits and the created tag, and push the `.gem` file to [rubygems.org]
183
290
 
184
291
  ## Contributing
185
292
 
186
- Bug reports and pull requests are welcome on GitHub at https://github.com/pboling/shiftable. This project is intended to
187
- be a safe, welcoming space for collaboration, and contributors are expected to adhere to
188
- the [code of conduct](https://github.com/pboling/shiftable/blob/master/CODE_OF_CONDUCT.md).
293
+ See [CONTRIBUTING.md][contributing]
189
294
 
190
- ## Code of Conduct
295
+ ## Contributors
191
296
 
192
- Everyone interacting in the Shiftable project's codebases, issue trackers, chat rooms and mailing lists is expected to
193
- follow the [code of conduct](https://github.com/pboling/shiftable/blob/master/CODE_OF_CONDUCT.md).
297
+ [![Contributors](https://contrib.rocks/image?repo=pboling/shiftable)]("https://github.com/pboling/shiftable/graphs/contributors")
298
+
299
+ Made with [contributors-img](https://contrib.rocks).
194
300
 
195
301
  ## Versioning
196
302
 
@@ -205,18 +311,36 @@ the [Pessimistic Version Constraint][pvc] with two digits of precision.
205
311
  For example:
206
312
 
207
313
  ```ruby
208
- spec.add_dependency "shiftable", "~> 0.2"
314
+ spec.add_dependency "shiftable", "~> 0.4"
209
315
  ```
210
316
 
317
+ ## Contact
318
+
319
+ Author and maintainer is Peter Boling ([@pboling][gh_sponsors]).
320
+
321
+ Comments are welcome in the [GitHub Discussions][gh_discussions] board.
322
+
323
+ For security-related issues see [SECURITY][security].
324
+
211
325
  ## License
212
326
 
213
327
  The gem is available as open source under the terms of
214
- the [MIT License](https://opensource.org/licenses/MIT) [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
215
- .
328
+ the [MIT License][license] [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)][license-ref].
329
+ See [LICENSE][license] for the official [Copyright Notice][copyright-notice-explainer].
216
330
 
217
331
  * Copyright (c) 2021 [Peter H. Boling][peterboling] of [Rails Bling][railsbling]
218
332
 
219
- [license]: LICENSE
333
+ [copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
334
+
335
+ [gh_discussions]: https://github.com/pboling/shiftable/discussions
336
+
337
+ [conduct]: https://github.com/pboling/shiftable/blob/master/CODE_OF_CONDUCT.md
338
+
339
+ [security]: https://github.com/pboling/shiftable/blob/master/SECURITY.md
340
+
341
+ [license]: https://github.com/pboling/shiftable/blob/master/LICENSE.txt
342
+
343
+ [license-ref]: https://opensource.org/licenses/MIT
220
344
 
221
345
  [semver]: http://semver.org/
222
346
 
@@ -238,8 +362,32 @@ the [MIT License](https://opensource.org/licenses/MIT) [![License: MIT](https://
238
362
 
239
363
  [politicme]: https://nationalprogressiveparty.org
240
364
 
241
- [documentation]: http://rdoc.info/github/pboling/shiftable/frames
365
+ [documentation]: https://rubydoc.info/github/pboling/shiftable/main
366
+
367
+ [source]: https://github.com/pboling/shiftable/
368
+
369
+ [actions]: https://github.com/pboling/shiftable/actions
370
+
371
+ [issues]: https://github.com/pboling/shiftable/issues
372
+
373
+ [climate_maintainability]: https://codeclimate.com/github/pboling/shiftable/maintainability
374
+
375
+ [climate_coverage]: https://codeclimate.com/github/pboling/shiftable/test_coverage
242
376
 
243
- [homepage]: https://github.com/pboling/shiftable/
377
+ [codecov_coverage]: https://codecov.io/gh/pboling/shiftable
378
+
379
+ [code_triage]: https://www.codetriage.com/pboling/shiftable
380
+
381
+ [depfu]: https://depfu.com/github/pboling/shiftable?project_id=32594
244
382
 
245
383
  [blogpage]: http://www.railsbling.com/tags/shiftable/
384
+
385
+ [rubygems]: https://rubygems.org/gems/shiftable
386
+
387
+ [chat]: https://gitter.im/pboling/shiftable?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
388
+
389
+ [maintenancee_policy]: https://guides.rubyonrails.org/maintenance_policy.html#security-issues
390
+
391
+ [liberapay_donate]: https://liberapay.com/pboling/donate
392
+
393
+ [gh_sponsors]: https://github.com/sponsors/pboling
@@ -16,7 +16,7 @@ module Shiftable
16
16
  class Collection < Module
17
17
  # associations: belongs_to, has_many
18
18
  # options: method_prefix, before_shift
19
- def initialize(belongs_to:, has_many:, method_prefix: nil, before_shift: nil)
19
+ def initialize(belongs_to:, has_many:, polymorphic: nil, method_prefix: nil, before_shift: nil)
20
20
  # Ruby's Module initializer doesn't take any arguments
21
21
  super()
22
22
 
@@ -35,12 +35,13 @@ module Shiftable
35
35
  has_many: has_many.to_s.to_sym
36
36
  },
37
37
  options: {
38
+ polymorphic: polymorphic,
38
39
  method_prefix: method_prefix,
39
40
  # will prevent the save if it returns false
40
41
  # allows for any custom logic to be run, such as setting attributes, prior to the shift (save).
41
42
  before_shift: before_shift
42
43
  },
43
- type: :cx
44
+ type: polymorphic ? :pcx : :cx
44
45
  )
45
46
  end
46
47
 
@@ -61,11 +62,13 @@ module Shiftable
61
62
  # Creates anonymous Ruby Modules, containing dynamically built methods
62
63
  module ShiftCollectionModulizer
63
64
  def to_mod(signature)
65
+ prefix = signature.method_prefix
66
+ type = signature.type
64
67
  Module.new do
65
- define_method(:"#{signature.mepr}shift_cx_column") do
66
- signature.shift_column
68
+ define_method(:"#{prefix}shift_#{type}_column") do
69
+ signature.send("shift_#{type}_column")
67
70
  end
68
- define_method(:"#{signature.mepr}shift_cx") do |shift_to:, shift_from:|
71
+ define_method(:"#{prefix}shift_#{type}") do |shift_to:, shift_from:|
69
72
  signature.shift_data!(shift_to: shift_to, shift_from: shift_from)
70
73
  end
71
74
  end
@@ -2,13 +2,10 @@
2
2
 
3
3
  module Shiftable
4
4
  class ModSignature
5
- VALID_TYPES = %i[sg cx].freeze
6
- VALID_ASSOCIATIONS = {
7
- sg: %i[belongs_to has_one],
8
- cx: %i[belongs_to has_many]
9
- }.freeze
10
- attr_accessor :associations, :options, :type
11
- attr_reader :base
5
+ VALID_ASSOCIATIONS = { sg: %i[belongs_to has_one], cx: %i[belongs_to has_many], pcx: %i[belongs_to has_many] }.freeze
6
+ VALID_TYPES = VALID_ASSOCIATIONS.keys.dup.freeze
7
+ DEFAULT_BEFORE_SHIFT = ->(*_) { true }
8
+ attr_reader :associations, :options, :type, :base
12
9
 
13
10
  # Imagine you are a Spaceship Captain, the Spaceship belongs_to you, and it has only one Captain.
14
11
  # But you have to sell it to your nemesis!
@@ -22,12 +19,29 @@ module Shiftable
22
19
  end
23
20
 
24
21
  def validate
25
- raise ArgumentError, "type must be one of: #{VALID_TYPES}, provided: #{type}" unless VALID_TYPES.include?(type)
26
- raise ArgumentError, "associations must be symbols" if associations.keys.detect { |a| !a.is_a?(Symbol) }
27
- raise ArgumentError, "exactly two distinct associations must be provided" unless associations.keys.uniq.length == 2
22
+ raise ArgumentError, "type must be one of: #{VALID_TYPES}, provided: #{type}" if invalid_type?
23
+ raise ArgumentError, "associations must be symbols" if invalid_association_key_type?
24
+ raise ArgumentError, "exactly two distinct associations must be provided" if invalid_number_of_associations?
25
+ end
26
+
27
+ def polymorphic_type
28
+ options.dig(:polymorphic, :type)
29
+ end
30
+
31
+ def polymorphic_as
32
+ options.dig(:polymorphic, :as)
33
+ end
34
+
35
+ def invalid_type?
36
+ !VALID_TYPES.include?(type)
37
+ end
38
+
39
+ def invalid_association_key_type?
40
+ associations.keys.detect { |key| !key.is_a?(Symbol) }
41
+ end
28
42
 
29
- invalid_tokens = associations.keys - VALID_ASSOCIATIONS[type]
30
- raise ArgumentError, "valid associations: #{VALID_ASSOCIATIONS[type]}, invalid: #{invalid_tokens}" if invalid_tokens.any?
43
+ def invalid_number_of_associations?
44
+ associations.keys.uniq.length != 2
31
45
  end
32
46
 
33
47
  # @note Chainable
@@ -42,84 +56,82 @@ module Shiftable
42
56
  end
43
57
 
44
58
  def validate_relationships
45
- bt = base.reflect_on_association(belongs_to)
46
- raise ArgumentError, "Unable to find belongs_to: :#{belongs_to} in #{base}" unless bt
47
-
48
- hr = bt.klass.reflect_on_association(has_rel)
49
- raise ArgumentError, "Unable to find #{has_rel_name}: :#{has_rel} in #{bt.klass}" unless hr
59
+ bt_reflection = base.reflect_on_association(belongs_to)
60
+ raise ArgumentError, "Unable to find belongs_to: :#{belongs_to} in #{base}" unless bt_reflection
61
+ # We can't validate any further if the reflection is polymorphic
62
+ return true if bt_reflection.polymorphic?
63
+
64
+ klass = bt_reflection.klass
65
+ has_reflection = klass.reflect_on_association(has_rel)
66
+ raise ArgumentError, "Unable to find #{has_rel_name}: :#{has_rel} in #{klass}" unless has_reflection
50
67
  end
51
68
 
52
69
  module CxMethods
53
- def has_many
70
+ def has_rel
54
71
  associations[:has_many]
55
72
  end
56
73
 
57
- alias has_rel has_many
58
-
59
- # returns nil or ActiveRecord::Relation object
60
- def data_for_shift(id)
61
- base.where(send("shift_column") => id) if super
74
+ def shift_data!(shift_to:, shift_from:)
75
+ validate_relationships
76
+ shifting_rel = ShiftingRelation.new(
77
+ to: shift_to,
78
+ from: shift_from,
79
+ column: shift_column,
80
+ base: base
81
+ )
82
+ shifting_rel.shift do |result|
83
+ before_shift&.call(shifting_rel: result, shift_to: shift_to, shift_from: shift_from)
84
+ end
62
85
  end
86
+ end
63
87
 
64
- # returns false, nil or ActiveRecord::Relation object
65
- def data_for_shift_safe(shift_to:, shift_from:)
66
- return false unless super
67
-
68
- data_for_shift(shift_from.id)
69
- end
88
+ module PcxMethods
89
+ # This method could be defined for parity, but it is never used.
90
+ # def has_rel
91
+ # associations[:has_many]
92
+ # end
70
93
 
71
94
  def shift_data!(shift_to:, shift_from:)
72
95
  validate_relationships
73
-
74
- shifting_rel = data_for_shift_safe(shift_to: shift_to, shift_from: shift_from)
75
- return false unless shifting_rel && shifting_rel.any?
76
-
77
- shifting_rel.each do |shifting|
78
- shifting.send("#{send(:shift_column)}=", shift_to.id)
96
+ shifting_rel = ShiftingPolymorphicRelation.new(
97
+ to: shift_to,
98
+ from: shift_from,
99
+ column: {
100
+ type: polymorphic_type,
101
+ as: polymorphic_as,
102
+ id_column: shift_pcx_column
103
+ },
104
+ base: base
105
+ )
106
+ shifting_rel.shift do |result|
107
+ before_shift&.call(shifting_rel: result, shift_to: shift_to, shift_from: shift_from)
79
108
  end
80
- before_shift&.call(shifting_rel: shifting_rel, shift_to: shift_to, shift_from: shift_from)
81
- shifting_rel.each(&:save)
82
- shifting_rel
83
109
  end
84
110
  end
85
111
 
86
112
  module SgMethods
87
- def has_one
113
+ def has_rel
88
114
  associations[:has_one]
89
115
  end
90
116
 
91
- alias has_rel has_one
92
-
93
117
  # Do not move record if a record already exists (we are shifting a "has_one" association, after all)
94
- def preflight_checks
95
- options[:preflight_checks]
96
- end
97
-
98
- # returns nil or ActiveRecord object
99
- def data_for_shift(id)
100
- base.find_by(send("shift_column") => id) if super
101
- end
102
-
103
- # returns false, nil or ActiveRecord object
104
- def data_for_shift_safe(shift_to:, shift_from:)
105
- return false unless super
106
-
107
- if preflight_checks
108
- already_exists = shift_to.send(has_one)
109
- return false if already_exists
110
- end
111
- data_for_shift(shift_from.id)
118
+ def precheck
119
+ options[:precheck]
112
120
  end
113
121
 
114
122
  def shift_data!(shift_to:, shift_from:)
115
123
  validate_relationships
116
-
117
- shifting = data_for_shift_safe(shift_to: shift_to, shift_from: shift_from)
118
- return false unless shifting
119
-
120
- shifting.send("#{send(:shift_column)}=", shift_to.id)
121
- shifting.save if before_shift.nil? || before_shift.call(shifting: shifting, shift_to: shift_to,
122
- shift_from: shift_from)
124
+ shifting = ShiftingRecord.new(
125
+ to: shift_to,
126
+ from: shift_from,
127
+ column: shift_column,
128
+ base: base
129
+ ) do
130
+ !precheck || !shift_to.send(has_rel)
131
+ end
132
+ shifting.shift do |result|
133
+ before_shift&.call(shifting: result, shift_to: shift_to, shift_from: shift_from)
134
+ end
123
135
  end
124
136
  end
125
137
 
@@ -134,12 +146,14 @@ module Shiftable
134
146
  options[:method_prefix]
135
147
  end
136
148
 
137
- alias mepr method_prefix
138
-
139
149
  # will prevent the save if it returns false
140
150
  # allows for any custom logic to be run, such as setting shift_from attributes, prior to the shift is saved.
141
151
  def before_shift
142
- options[:before_shift]
152
+ options[:before_shift] || DEFAULT_BEFORE_SHIFT
153
+ end
154
+
155
+ def shift_pcx_column
156
+ "#{polymorphic_as}_id"
143
157
  end
144
158
 
145
159
  def shift_column
@@ -147,18 +161,7 @@ module Shiftable
147
161
  reflection.foreign_key
148
162
  end
149
163
 
150
- # Effect is to short-circuit data_for_shift method prior to executing the ActiveRecord query
151
- # if there is no ID, to avoid a full table scan when no id provided,
152
- # e.g. where(id: nil).
153
- def data_for_shift(id)
154
- true if id
155
- end
156
-
157
- # Effect is to short-circuit data_for_shift_safe method prior to executing the ActiveRecord query
158
- # if there is no ID, to avoid a full table scan when no id provided,
159
- # e.g. where(id: nil).
160
- def data_for_shift_safe(shift_to:, shift_from:)
161
- true if shift_from&.id && shift_to&.id
162
- end
164
+ alias shift_sg_column shift_column
165
+ alias shift_cx_column shift_column
163
166
  end
164
167
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shiftable
4
+ # Gets data to be shifted
5
+ class Shifting
6
+ attr_reader :to, :from, :column, :base, :result, :run_save
7
+
8
+ def initialize(to:, from:, column:, base:)
9
+ @to = to
10
+ @from = from
11
+ @column = column
12
+ @base = base
13
+ validate
14
+ do_query = block_given? ? yield : true
15
+ @result = do_query ? query : nil
16
+ @run_save = true
17
+ end
18
+
19
+ # def found?
20
+ # raise "found? must be defined in a subclass"
21
+ # end
22
+
23
+ # def shift
24
+ # raise "shift must be defined in a subclass"
25
+ # end
26
+
27
+ private
28
+
29
+ def validate
30
+ raise ArgumentError, "shift_to must have an id (primary key) value, but is: #{to&.id}" unless to&.id
31
+ raise ArgumentError, "shift_from must have an id (primary key) value, but is: #{from&.id}" unless from&.id
32
+ end
33
+
34
+ # def query
35
+ # raise "query must be defined in a subclass"
36
+ # end
37
+ end
38
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shiftable
4
+ # Gets data to be shifted
5
+ class ShiftingPolymorphicRelation < Shifting
6
+ include Enumerable
7
+
8
+ def polymorphic_id_column
9
+ column[:id_column]
10
+ end
11
+
12
+ def polymorphic_type_column
13
+ "#{column[:as]}_type"
14
+ end
15
+
16
+ def found?
17
+ result.any?
18
+ end
19
+
20
+ def each(&block)
21
+ result.each(&block)
22
+ end
23
+
24
+ # @return result (once it is shifted)
25
+ def shift
26
+ return false unless found?
27
+
28
+ each do |record|
29
+ record.send("#{polymorphic_id_column}=", to.id)
30
+ end
31
+ @run_save = yield result if block_given?
32
+ each(&:save) if run_save
33
+ result
34
+ end
35
+
36
+ private
37
+
38
+ def query
39
+ base.where(
40
+ polymorphic_type_column => column[:type],
41
+ polymorphic_id_column => from.id
42
+ )
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shiftable
4
+ # Gets data to be shifted
5
+ class ShiftingRecord < Shifting
6
+ def found?
7
+ !!result
8
+ end
9
+
10
+ # @return true, false
11
+ def shift
12
+ return false unless found?
13
+
14
+ result.send("#{column}=", to.id)
15
+ @run_save = yield result if block_given?
16
+ result.save if run_save
17
+ end
18
+
19
+ private
20
+
21
+ def query
22
+ base.find_by(column => from.id)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shiftable
4
+ # Gets data to be shifted
5
+ class ShiftingRelation < Shifting
6
+ include Enumerable
7
+
8
+ def found?
9
+ result.any?
10
+ end
11
+
12
+ def each(&block)
13
+ result.each(&block)
14
+ end
15
+
16
+ # @return result (once it is shifted)
17
+ def shift
18
+ return false unless found?
19
+
20
+ each do |record|
21
+ record.send("#{column}=", to.id)
22
+ end
23
+ @run_save = yield result if block_given?
24
+ each(&:save) if run_save
25
+ result
26
+ end
27
+
28
+ private
29
+
30
+ def query
31
+ base.where(column => from.id)
32
+ end
33
+ end
34
+ end
@@ -13,7 +13,7 @@
13
13
  # extend Shiftable::Single.new(
14
14
  # belongs_to: :captain,
15
15
  # has_one: :spaceship,
16
- # preflight_checks: true,
16
+ # precheck: true,
17
17
  # before_shift: ->(shifting:, shift_to:, shift_from:) { shifting.ownership_changes += 1 }
18
18
  # )
19
19
  # end
@@ -21,7 +21,7 @@
21
21
  module Shiftable
22
22
  # Inheriting from Module is a powerful pattern. If you like it checkout the debug_logging gem!
23
23
  class Single < Module
24
- def initialize(belongs_to:, has_one:, method_prefix: nil, preflight_checks: true, before_shift: nil)
24
+ def initialize(belongs_to:, has_one:, method_prefix: nil, precheck: true, before_shift: nil)
25
25
  # Ruby's Module initializer doesn't take any arguments
26
26
  super()
27
27
 
@@ -40,7 +40,7 @@ module Shiftable
40
40
  },
41
41
  options: {
42
42
  # Do not move record if a record already exists (we are shifting a "has_one" association, after all)
43
- preflight_checks: preflight_checks,
43
+ precheck: precheck,
44
44
  method_prefix: method_prefix,
45
45
  # will prevent the save if it returns false
46
46
  # allows for any custom logic to be run, such as setting attributes, prior to the shift (save).
@@ -67,11 +67,12 @@ module Shiftable
67
67
  # Creates anonymous Ruby Modules, containing dynamically built methods
68
68
  module ShiftSingleModulizer
69
69
  def to_mod(signature)
70
+ prefix = signature.method_prefix
70
71
  Module.new do
71
- define_method(:"#{signature.mepr}shift_column") do
72
- signature.shift_column
72
+ define_method(:"#{prefix}shift_column") do
73
+ signature.send("shift_#{signature.type}_column")
73
74
  end
74
- define_method(:"#{signature.mepr}shift_single") do |shift_to:, shift_from:|
75
+ define_method(:"#{prefix}shift_single") do |shift_to:, shift_from:|
75
76
  signature.shift_data!(shift_to: shift_to, shift_from: shift_from)
76
77
  end
77
78
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Shiftable
4
- VERSION = "0.3.0"
4
+ VERSION = "0.5.1"
5
5
  end
data/lib/shiftable.rb CHANGED
@@ -1,6 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "shiftable/version"
4
+ require_relative "shiftable/shifting"
5
+ require_relative "shiftable/shifting_record"
6
+ require_relative "shiftable/shifting_polymorphic_relation"
7
+ require_relative "shiftable/shifting_relation"
4
8
  require_relative "shiftable/mod_signature"
5
9
  require_relative "shiftable/collection"
6
10
  require_relative "shiftable/single"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shiftable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Boling
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-10-26 00:00:00.000000000 Z
11
+ date: 2021-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1'
19
+ version: '5'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1'
26
+ version: '5'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: byebug
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -109,105 +109,7 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: '3.10'
111
111
  - !ruby/object:Gem::Dependency
112
- name: rspec-block_is_expected
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - "~>"
116
- - !ruby/object:Gem::Version
117
- version: '1.0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - "~>"
123
- - !ruby/object:Gem::Version
124
- version: '1.0'
125
- - !ruby/object:Gem::Dependency
126
- name: rubocop
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "~>"
130
- - !ruby/object:Gem::Version
131
- version: '1.2'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - "~>"
137
- - !ruby/object:Gem::Version
138
- version: '1.2'
139
- - !ruby/object:Gem::Dependency
140
- name: rubocop-faker
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - "~>"
144
- - !ruby/object:Gem::Version
145
- version: '1.1'
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - "~>"
151
- - !ruby/object:Gem::Version
152
- version: '1.1'
153
- - !ruby/object:Gem::Dependency
154
- name: rubocop-md
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - "~>"
158
- - !ruby/object:Gem::Version
159
- version: '1.0'
160
- type: :development
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - "~>"
165
- - !ruby/object:Gem::Version
166
- version: '1.0'
167
- - !ruby/object:Gem::Dependency
168
- name: rubocop-minitest
169
- requirement: !ruby/object:Gem::Requirement
170
- requirements:
171
- - - "~>"
172
- - !ruby/object:Gem::Version
173
- version: '0.15'
174
- type: :development
175
- prerelease: false
176
- version_requirements: !ruby/object:Gem::Requirement
177
- requirements:
178
- - - "~>"
179
- - !ruby/object:Gem::Version
180
- version: '0.15'
181
- - !ruby/object:Gem::Dependency
182
- name: rubocop-packaging
183
- requirement: !ruby/object:Gem::Requirement
184
- requirements:
185
- - - "~>"
186
- - !ruby/object:Gem::Version
187
- version: '0.5'
188
- type: :development
189
- prerelease: false
190
- version_requirements: !ruby/object:Gem::Requirement
191
- requirements:
192
- - - "~>"
193
- - !ruby/object:Gem::Version
194
- version: '0.5'
195
- - !ruby/object:Gem::Dependency
196
- name: rubocop-performance
197
- requirement: !ruby/object:Gem::Requirement
198
- requirements:
199
- - - "~>"
200
- - !ruby/object:Gem::Version
201
- version: '1.11'
202
- type: :development
203
- prerelease: false
204
- version_requirements: !ruby/object:Gem::Requirement
205
- requirements:
206
- - - "~>"
207
- - !ruby/object:Gem::Version
208
- version: '1.11'
209
- - !ruby/object:Gem::Dependency
210
- name: rubocop-rake
112
+ name: rspec-benchmark
211
113
  requirement: !ruby/object:Gem::Requirement
212
114
  requirements:
213
115
  - - "~>"
@@ -221,21 +123,7 @@ dependencies:
221
123
  - !ruby/object:Gem::Version
222
124
  version: '0.6'
223
125
  - !ruby/object:Gem::Dependency
224
- name: rubocop-rspec
225
- requirement: !ruby/object:Gem::Requirement
226
- requirements:
227
- - - "~>"
228
- - !ruby/object:Gem::Version
229
- version: '2.5'
230
- type: :development
231
- prerelease: false
232
- version_requirements: !ruby/object:Gem::Requirement
233
- requirements:
234
- - - "~>"
235
- - !ruby/object:Gem::Version
236
- version: '2.5'
237
- - !ruby/object:Gem::Dependency
238
- name: rubocop-rspec-focused
126
+ name: rspec-block_is_expected
239
127
  requirement: !ruby/object:Gem::Requirement
240
128
  requirements:
241
129
  - - "~>"
@@ -248,34 +136,6 @@ dependencies:
248
136
  - - "~>"
249
137
  - !ruby/object:Gem::Version
250
138
  version: '1.0'
251
- - !ruby/object:Gem::Dependency
252
- name: rubocop-thread_safety
253
- requirement: !ruby/object:Gem::Requirement
254
- requirements:
255
- - - "~>"
256
- - !ruby/object:Gem::Version
257
- version: '0.4'
258
- type: :development
259
- prerelease: false
260
- version_requirements: !ruby/object:Gem::Requirement
261
- requirements:
262
- - - "~>"
263
- - !ruby/object:Gem::Version
264
- version: '0.4'
265
- - !ruby/object:Gem::Dependency
266
- name: simplecov
267
- requirement: !ruby/object:Gem::Requirement
268
- requirements:
269
- - - "~>"
270
- - !ruby/object:Gem::Version
271
- version: '0.21'
272
- type: :development
273
- prerelease: false
274
- version_requirements: !ruby/object:Gem::Requirement
275
- requirements:
276
- - - "~>"
277
- - !ruby/object:Gem::Version
278
- version: '0.21'
279
139
  - !ruby/object:Gem::Dependency
280
140
  name: sqlite3
281
141
  requirement: !ruby/object:Gem::Requirement
@@ -314,11 +174,16 @@ extra_rdoc_files: []
314
174
  files:
315
175
  - CHANGELOG.md
316
176
  - CODE_OF_CONDUCT.md
177
+ - CONTRIBUTING.md
317
178
  - LICENSE.txt
318
179
  - README.md
319
180
  - lib/shiftable.rb
320
181
  - lib/shiftable/collection.rb
321
182
  - lib/shiftable/mod_signature.rb
183
+ - lib/shiftable/shifting.rb
184
+ - lib/shiftable/shifting_polymorphic_relation.rb
185
+ - lib/shiftable/shifting_record.rb
186
+ - lib/shiftable/shifting_relation.rb
322
187
  - lib/shiftable/single.rb
323
188
  - lib/shiftable/version.rb
324
189
  homepage: https://railsbling.com/tags/shiftable
@@ -336,14 +201,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
336
201
  requirements:
337
202
  - - ">="
338
203
  - !ruby/object:Gem::Version
339
- version: '2.5'
204
+ version: 2.5.0
340
205
  required_rubygems_version: !ruby/object:Gem::Requirement
341
206
  requirements:
342
207
  - - ">="
343
208
  - !ruby/object:Gem::Version
344
209
  version: '0'
345
210
  requirements: []
346
- rubygems_version: 3.2.22
211
+ rubygems_version: 3.0.3.1
347
212
  signing_key:
348
213
  specification_version: 4
349
214
  summary: Easily shift record associations