shiftable 0.5.1 → 0.6.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 +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +71 -9
- data/lib/shiftable/collection.rb +7 -2
- data/lib/shiftable/mod_signature.rb +16 -9
- data/lib/shiftable/shifting.rb +26 -2
- data/lib/shiftable/shifting_polymorphic_relation.rb +4 -2
- data/lib/shiftable/shifting_record.rb +24 -2
- data/lib/shiftable/shifting_relation.rb +4 -2
- data/lib/shiftable/single.rb +4 -3
- data/lib/shiftable/version.rb +1 -1
- metadata +29 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 03d919c64ab0be03ba40c5474cfa7971dda6158ab01df20940bb644c32482b19
|
|
4
|
+
data.tar.gz: 3246e28e7578ea7b56ae905c23c675e121a8c71556d127b8ee4a0fbeedcce15b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b3721c0d437b1ab45deb99f71f7a199fe4c37aae31f86f8443eb2effd1bd07c9d930aa64c4a4b824c7371863c9cb219251e59dc673d9ef40a73551e75c7efc67
|
|
7
|
+
data.tar.gz: c0d40a890f89fda5137575d9052131605f33e6a861e6b9e55b6681d89cfeba4f9ac5547cb09c4ab68cb69bafa50a9c6ebc75412152cf8c3bf9e76f90ce80f823
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
|
@@ -80,7 +80,7 @@ But how can you accomplish this? If you used the `shiftable` gem, won't take but
|
|
|
80
80
|
class Spaceship < ActiveRecord::Base
|
|
81
81
|
belongs_to :captain
|
|
82
82
|
extend Shiftable::Single.new belongs_to: :captain, has_one: :spaceship, precheck: true,
|
|
83
|
-
before_shift: ->(
|
|
83
|
+
before_shift: ->(shifting_rel) { shifting_rel.result.ownership_changes += 1 }
|
|
84
84
|
end
|
|
85
85
|
```
|
|
86
86
|
|
|
@@ -111,11 +111,10 @@ federation! And in a run-in with their arch-Nemesis the Plinth-inth,
|
|
|
111
111
|
all federation spaceships are commandeered! You are ruined!
|
|
112
112
|
|
|
113
113
|
```ruby
|
|
114
|
-
|
|
115
114
|
class Spaceship < ActiveRecord::Base
|
|
116
115
|
belongs_to :space_federation
|
|
117
116
|
extend Shiftable::Collection.new belongs_to: :space_federation, has_many: :spaceships,
|
|
118
|
-
before_shift: lambda { |shifting_rel
|
|
117
|
+
before_shift: lambda { |shifting_rel|
|
|
119
118
|
shifting_rel.each { |spaceship| spaceship.federation_changes += 1 }
|
|
120
119
|
}
|
|
121
120
|
end
|
|
@@ -155,7 +154,7 @@ class SpaceTreatySignature < ActiveRecord::Base
|
|
|
155
154
|
belongs_to: :signatory, has_many: :space_treaty_signature,
|
|
156
155
|
polymorphic: { type: "SpaceFederation", as: :signatory },
|
|
157
156
|
method_prefix: "space_federation_",
|
|
158
|
-
before_shift: lambda { |shifting_rel
|
|
157
|
+
before_shift: lambda { |shifting_rel|
|
|
159
158
|
# Each item in shifting_rel is an instance of the class where Shiftable::Collection is defined,
|
|
160
159
|
# in this case: SpaceTreatySignature
|
|
161
160
|
# And each of them has a signatory which is of type "SpaceFederation",
|
|
@@ -191,6 +190,50 @@ class SpaceStation < ActiveRecord::Base
|
|
|
191
190
|
end
|
|
192
191
|
```
|
|
193
192
|
|
|
193
|
+
### Wrapping a shift
|
|
194
|
+
|
|
195
|
+
For example, in a transaction. Let's update the nemesis foundation example from above with a transaction shift_each_wrapper,
|
|
196
|
+
which we'll pull from the [`activerecord-transactionable`](https://github.com/pboling/activerecord-transactionable) gem, which provides best practice framing around transactions.
|
|
197
|
+
|
|
198
|
+
```ruby
|
|
199
|
+
class Spaceship < ActiveRecord::Base
|
|
200
|
+
belongs_to :space_federation
|
|
201
|
+
extend Shiftable::Collection.new(
|
|
202
|
+
belongs_to: :space_federation,
|
|
203
|
+
has_many: :spaceships,
|
|
204
|
+
before_shift: lambda { |shifting_rel|
|
|
205
|
+
shifting_rel.each { |spaceship| spaceship.federation_changes += 1 }
|
|
206
|
+
},
|
|
207
|
+
wrapper: {
|
|
208
|
+
each: lambda { |record, &block|
|
|
209
|
+
tresult = record.transaction_wrapper(outside_rescued_errors: ActiveRecord::RecordNotUnique) do
|
|
210
|
+
puts "melon #{record.name} honey"
|
|
211
|
+
block.call # does the actual saving!
|
|
212
|
+
end
|
|
213
|
+
# NOTE: The value returned by the wrapper will also be returned by the call to `shift_cx`.
|
|
214
|
+
# You could return the whole tresult object here, instead of just true/false!
|
|
215
|
+
tresult.success?
|
|
216
|
+
},
|
|
217
|
+
all: lambda { |rel, &block|
|
|
218
|
+
tresult = Spaceship.transaction_wrapper do
|
|
219
|
+
puts "can you eat #{rel.count} shoes"
|
|
220
|
+
block.call
|
|
221
|
+
end
|
|
222
|
+
tresult.success?
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
class SpaceFederation < ActiveRecord::Base
|
|
229
|
+
has_many :spaceships
|
|
230
|
+
|
|
231
|
+
def all_spaceships_commandeered_by(nemesis_federation)
|
|
232
|
+
Spaceship.shift_cx(shift_to: nemesis_federation, shift_from: self)
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
```
|
|
236
|
+
|
|
194
237
|
### Complete example
|
|
195
238
|
|
|
196
239
|
Putting it all together...
|
|
@@ -207,13 +250,32 @@ end
|
|
|
207
250
|
class Spaceship < ActiveRecord::Base
|
|
208
251
|
belongs_to :captain
|
|
209
252
|
extend Shiftable::Single.new belongs_to: :captain, has_one: :spaceship, precheck: true,
|
|
210
|
-
before_shift: ->(
|
|
253
|
+
before_shift: ->(shifting_rel) { shifting_rel.result.ownership_changes += 1 }
|
|
211
254
|
|
|
212
255
|
belongs_to :space_federation
|
|
213
|
-
extend Shiftable::Collection.new
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
256
|
+
extend Shiftable::Collection.new(
|
|
257
|
+
belongs_to: :space_federation,
|
|
258
|
+
has_many: :spaceships,
|
|
259
|
+
before_shift: lambda { |shifting_rel|
|
|
260
|
+
shifting_rel.each { |spaceship| spaceship.federation_changes += 1 }
|
|
261
|
+
},
|
|
262
|
+
wrapper: {
|
|
263
|
+
each: lambda { |record, &block|
|
|
264
|
+
tresult = record.transaction_wrapper(outside_rescued_errors: ActiveRecord::RecordNotUnique) do
|
|
265
|
+
puts "melon #{record.name} honey"
|
|
266
|
+
block.call # does the actual saving!
|
|
267
|
+
end
|
|
268
|
+
tresult.success?
|
|
269
|
+
},
|
|
270
|
+
all: lambda { |rel, &block|
|
|
271
|
+
tresult = Spaceship.transaction_wrapper do
|
|
272
|
+
puts "can you eat #{rel.count} shoes"
|
|
273
|
+
block.call
|
|
274
|
+
end
|
|
275
|
+
tresult.success?
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
)
|
|
217
279
|
end
|
|
218
280
|
|
|
219
281
|
class SpaceFederation < ActiveRecord::Base
|
data/lib/shiftable/collection.rb
CHANGED
|
@@ -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:, polymorphic: nil, method_prefix: nil, before_shift: nil)
|
|
19
|
+
def initialize(belongs_to:, has_many:, polymorphic: nil, method_prefix: nil, before_shift: nil, wrapper: nil)
|
|
20
20
|
# Ruby's Module initializer doesn't take any arguments
|
|
21
21
|
super()
|
|
22
22
|
|
|
@@ -39,7 +39,12 @@ module Shiftable
|
|
|
39
39
|
method_prefix: method_prefix,
|
|
40
40
|
# will prevent the save if it returns false
|
|
41
41
|
# allows for any custom logic to be run, such as setting attributes, prior to the shift (save).
|
|
42
|
-
before_shift: before_shift
|
|
42
|
+
before_shift: before_shift,
|
|
43
|
+
# wrapper: {
|
|
44
|
+
# all: ->() { klass.transaction_wrapper { yield } },
|
|
45
|
+
# each: ->() { klass.transaction_wrapper { yield } },
|
|
46
|
+
# }
|
|
47
|
+
wrapper: wrapper
|
|
43
48
|
},
|
|
44
49
|
type: polymorphic ? :pcx : :cx
|
|
45
50
|
)
|
|
@@ -24,6 +24,10 @@ module Shiftable
|
|
|
24
24
|
raise ArgumentError, "exactly two distinct associations must be provided" if invalid_number_of_associations?
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
def wrapper
|
|
28
|
+
options[:wrapper] || {}
|
|
29
|
+
end
|
|
30
|
+
|
|
27
31
|
def polymorphic_type
|
|
28
32
|
options.dig(:polymorphic, :type)
|
|
29
33
|
end
|
|
@@ -77,10 +81,11 @@ module Shiftable
|
|
|
77
81
|
to: shift_to,
|
|
78
82
|
from: shift_from,
|
|
79
83
|
column: shift_column,
|
|
80
|
-
base: base
|
|
84
|
+
base: base,
|
|
85
|
+
wrapper: wrapper
|
|
81
86
|
)
|
|
82
|
-
shifting_rel.shift do
|
|
83
|
-
before_shift&.call(shifting_rel
|
|
87
|
+
shifting_rel.shift do
|
|
88
|
+
before_shift&.call(shifting_rel)
|
|
84
89
|
end
|
|
85
90
|
end
|
|
86
91
|
end
|
|
@@ -101,10 +106,11 @@ module Shiftable
|
|
|
101
106
|
as: polymorphic_as,
|
|
102
107
|
id_column: shift_pcx_column
|
|
103
108
|
},
|
|
104
|
-
base: base
|
|
109
|
+
base: base,
|
|
110
|
+
wrapper: wrapper
|
|
105
111
|
)
|
|
106
|
-
shifting_rel.shift do
|
|
107
|
-
before_shift&.call(shifting_rel
|
|
112
|
+
shifting_rel.shift do
|
|
113
|
+
before_shift&.call(shifting_rel)
|
|
108
114
|
end
|
|
109
115
|
end
|
|
110
116
|
end
|
|
@@ -125,12 +131,13 @@ module Shiftable
|
|
|
125
131
|
to: shift_to,
|
|
126
132
|
from: shift_from,
|
|
127
133
|
column: shift_column,
|
|
128
|
-
base: base
|
|
134
|
+
base: base,
|
|
135
|
+
wrapper: wrapper
|
|
129
136
|
) do
|
|
130
137
|
!precheck || !shift_to.send(has_rel)
|
|
131
138
|
end
|
|
132
|
-
shifting.shift do
|
|
133
|
-
before_shift&.call(shifting
|
|
139
|
+
shifting.shift do
|
|
140
|
+
before_shift&.call(shifting)
|
|
134
141
|
end
|
|
135
142
|
end
|
|
136
143
|
end
|
data/lib/shiftable/shifting.rb
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
module Shiftable
|
|
4
4
|
# Gets data to be shifted
|
|
5
5
|
class Shifting
|
|
6
|
-
attr_reader :to, :from, :column, :base, :result, :run_save
|
|
6
|
+
attr_reader :to, :from, :column, :base, :result, :run_save, :shift_all_wrapper, :shift_each_wrapper
|
|
7
7
|
|
|
8
|
-
def initialize(to:, from:, column:, base:)
|
|
8
|
+
def initialize(to:, from:, column:, base:, wrapper:)
|
|
9
9
|
@to = to
|
|
10
10
|
@from = from
|
|
11
11
|
@column = column
|
|
@@ -14,6 +14,8 @@ module Shiftable
|
|
|
14
14
|
do_query = block_given? ? yield : true
|
|
15
15
|
@result = do_query ? query : nil
|
|
16
16
|
@run_save = true
|
|
17
|
+
@shift_all_wrapper = wrapper[:all]
|
|
18
|
+
@shift_each_wrapper = wrapper[:each]
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
# def found?
|
|
@@ -31,6 +33,28 @@ module Shiftable
|
|
|
31
33
|
raise ArgumentError, "shift_from must have an id (primary key) value, but is: #{from&.id}" unless from&.id
|
|
32
34
|
end
|
|
33
35
|
|
|
36
|
+
def run_save!
|
|
37
|
+
if shift_all_wrapper
|
|
38
|
+
shift_all_wrapper.call(self) do
|
|
39
|
+
do_saves
|
|
40
|
+
end
|
|
41
|
+
else
|
|
42
|
+
do_saves
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def do_saves
|
|
47
|
+
if shift_each_wrapper
|
|
48
|
+
each do |rec|
|
|
49
|
+
shift_each_wrapper.call(rec) do
|
|
50
|
+
rec.save
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
else
|
|
54
|
+
each(&:save)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
34
58
|
# def query
|
|
35
59
|
# raise "query must be defined in a subclass"
|
|
36
60
|
# end
|
|
@@ -28,8 +28,10 @@ module Shiftable
|
|
|
28
28
|
each do |record|
|
|
29
29
|
record.send("#{polymorphic_id_column}=", to.id)
|
|
30
30
|
end
|
|
31
|
-
@run_save = yield
|
|
32
|
-
|
|
31
|
+
@run_save = yield if block_given?
|
|
32
|
+
return result unless run_save
|
|
33
|
+
|
|
34
|
+
run_save!
|
|
33
35
|
result
|
|
34
36
|
end
|
|
35
37
|
|
|
@@ -12,12 +12,34 @@ module Shiftable
|
|
|
12
12
|
return false unless found?
|
|
13
13
|
|
|
14
14
|
result.send("#{column}=", to.id)
|
|
15
|
-
@run_save = yield
|
|
16
|
-
|
|
15
|
+
@run_save = yield if block_given?
|
|
16
|
+
return nil unless run_save
|
|
17
|
+
|
|
18
|
+
run_save!
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
private
|
|
20
22
|
|
|
23
|
+
def run_save!
|
|
24
|
+
if shift_all_wrapper
|
|
25
|
+
shift_all_wrapper.call(self) do
|
|
26
|
+
do_save
|
|
27
|
+
end
|
|
28
|
+
else
|
|
29
|
+
do_save
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def do_save
|
|
34
|
+
if shift_each_wrapper
|
|
35
|
+
shift_each_wrapper.call(result) do
|
|
36
|
+
result.save
|
|
37
|
+
end
|
|
38
|
+
else
|
|
39
|
+
result.save
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
21
43
|
def query
|
|
22
44
|
base.find_by(column => from.id)
|
|
23
45
|
end
|
|
@@ -20,8 +20,10 @@ module Shiftable
|
|
|
20
20
|
each do |record|
|
|
21
21
|
record.send("#{column}=", to.id)
|
|
22
22
|
end
|
|
23
|
-
@run_save = yield
|
|
24
|
-
|
|
23
|
+
@run_save = yield if block_given?
|
|
24
|
+
return result unless run_save
|
|
25
|
+
|
|
26
|
+
run_save!
|
|
25
27
|
result
|
|
26
28
|
end
|
|
27
29
|
|
data/lib/shiftable/single.rb
CHANGED
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
# belongs_to: :captain,
|
|
15
15
|
# has_one: :spaceship,
|
|
16
16
|
# precheck: true,
|
|
17
|
-
# before_shift: ->(
|
|
17
|
+
# before_shift: ->(shifting_rel) { shifting_rel.result..ownership_changes += 1 }
|
|
18
18
|
# )
|
|
19
19
|
# end
|
|
20
20
|
#
|
|
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, precheck: true, before_shift: nil)
|
|
24
|
+
def initialize(belongs_to:, has_one:, method_prefix: nil, precheck: true, before_shift: nil, wrapper: nil)
|
|
25
25
|
# Ruby's Module initializer doesn't take any arguments
|
|
26
26
|
super()
|
|
27
27
|
|
|
@@ -44,7 +44,8 @@ module Shiftable
|
|
|
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).
|
|
47
|
-
before_shift: before_shift
|
|
47
|
+
before_shift: before_shift,
|
|
48
|
+
wrapper: wrapper
|
|
48
49
|
},
|
|
49
50
|
type: :sg
|
|
50
51
|
)
|
data/lib/shiftable/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: shiftable
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter Boling
|
|
@@ -24,6 +24,20 @@ dependencies:
|
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '5'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: activerecord-transactionable
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '3'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '3'
|
|
27
41
|
- !ruby/object:Gem::Dependency
|
|
28
42
|
name: byebug
|
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -136,6 +150,20 @@ dependencies:
|
|
|
136
150
|
- - "~>"
|
|
137
151
|
- !ruby/object:Gem::Version
|
|
138
152
|
version: '1.0'
|
|
153
|
+
- !ruby/object:Gem::Dependency
|
|
154
|
+
name: silent_stream
|
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
|
156
|
+
requirements:
|
|
157
|
+
- - "~>"
|
|
158
|
+
- !ruby/object:Gem::Version
|
|
159
|
+
version: '1'
|
|
160
|
+
type: :development
|
|
161
|
+
prerelease: false
|
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
163
|
+
requirements:
|
|
164
|
+
- - "~>"
|
|
165
|
+
- !ruby/object:Gem::Version
|
|
166
|
+
version: '1'
|
|
139
167
|
- !ruby/object:Gem::Dependency
|
|
140
168
|
name: sqlite3
|
|
141
169
|
requirement: !ruby/object:Gem::Requirement
|