acts_as_living 0.1.0 → 0.1.6
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 +2 -3
- data/lib/acts_as_living.rb +3 -2
- data/lib/acts_as_living/acts_as_living.rb +25 -0
- data/lib/acts_as_living/callbacks_definer.rb +33 -33
- data/lib/acts_as_living/enum_definer.rb +4 -4
- data/lib/acts_as_living/methods_definer.rb +217 -0
- data/lib/acts_as_living/railtie.rb +6 -1
- data/lib/acts_as_living/scopes_definer.rb +9 -9
- data/lib/acts_as_living/validations_definer.rb +12 -12
- data/lib/acts_as_living/version.rb +1 -1
- data/lib/tasks/acts_as_living.rake +18 -0
- metadata +8 -7
- data/lib/acts_as_living/class_methods.rb +0 -97
- data/lib/acts_as_living/instance_methods_definer.rb +0 -141
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1886e30cb7c12fb80faac2bb6268651d19770843f332ad8daa8c0283d4654ecb
|
4
|
+
data.tar.gz: 344f2f3cb2dd39378f757440e812eb192d818352776a044e3e684835d54ef1a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce3a6411127363f0635cc966dca7b04de9d5e504189c3bc1aa2a9d774ae7e12c66b2a771493c3260568b2673916af48633271f5fce44af3e53e74d3b2ba36381
|
7
|
+
data.tar.gz: cb8b39466ae50ddc3735101587c540e03d7369b89d7d36026dbf5f3888df78c7e655bc3f4c7abf9fa9f762041a595dd7930de72ae17f8be5414652972445eabe
|
data/Changelog.md
CHANGED
@@ -6,7 +6,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
-
## [0.1.
|
9
|
+
## [0.1.3] - 2020-07-12
|
10
10
|
### Added
|
11
|
-
-
|
12
|
-
- FlyJob included
|
11
|
+
- Fixed namespacing of the api endpoint
|
data/lib/acts_as_living.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'active_support'
|
4
|
+
|
4
5
|
require 'acts_as_living/version'
|
5
|
-
require 'acts_as_living/
|
6
|
+
require 'acts_as_living/acts_as_living'
|
7
|
+
require 'acts_as_living/methods_definer'
|
6
8
|
require 'acts_as_living/enum_definer'
|
7
9
|
require 'acts_as_living/callbacks_definer'
|
8
|
-
require 'acts_as_living/instance_methods_definer'
|
9
10
|
require 'acts_as_living/scopes_definer'
|
10
11
|
require 'acts_as_living/validations_definer'
|
11
12
|
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
require 'active_support/concern'
|
3
|
+
|
4
|
+
module ActsAsLiving::ActsAsLiving
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
class_methods do
|
8
|
+
def acts_as_living(keys, phases: [], lock_on: [], death: :cancelled, spread: 1)
|
9
|
+
@stage_keys = keys
|
10
|
+
@phases = phases
|
11
|
+
@locked_stages = lock_on
|
12
|
+
@death = death
|
13
|
+
@spread = spread
|
14
|
+
|
15
|
+
run_definers
|
16
|
+
end
|
17
|
+
|
18
|
+
def run_definers
|
19
|
+
ActsAsLiving::MethodsDefiner.call(self)
|
20
|
+
ActsAsLiving::EnumDefiner.call(self)
|
21
|
+
ActsAsLiving::ScopesDefiner.call(self)
|
22
|
+
ActsAsLiving::ValidationsDefiner.call(self)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -7,10 +7,10 @@
|
|
7
7
|
# ->(_target, result) { result == false }
|
8
8
|
# end
|
9
9
|
|
10
|
-
# # defines before, after and around callbaks for each
|
10
|
+
# # defines before, after and around callbaks for each phase of the acts_as_living
|
11
11
|
# # e.g. before_cancelled { do_something }
|
12
12
|
# # e.g. after_activated :run_method
|
13
|
-
# # e.g.
|
13
|
+
# # e.g. after_stage_change :run_method
|
14
14
|
|
15
15
|
# def self.call(klass)
|
16
16
|
# klass.class_eval do
|
@@ -18,78 +18,78 @@
|
|
18
18
|
# extend ClassMethods
|
19
19
|
# include InstanceMethods
|
20
20
|
|
21
|
-
# callbacks_for(:
|
22
|
-
# callbacks_for(:
|
23
|
-
#
|
24
|
-
# @
|
21
|
+
# callbacks_for(:stage_change)
|
22
|
+
# callbacks_for(:phase_change)
|
23
|
+
# stage_keys.each(&method(:stage_callbacks_for))
|
24
|
+
# @phases.keys.each(&method(:lifephase_callbacks_for))
|
25
25
|
# end
|
26
26
|
# end
|
27
27
|
|
28
28
|
# module InstanceMethods
|
29
29
|
# def save(*args)
|
30
|
-
# return super(*args) unless valid? &&
|
30
|
+
# return super(*args) unless valid? && stage_changed? || valid? && new_record?
|
31
31
|
|
32
|
-
#
|
33
|
-
# run_callbacks("
|
32
|
+
# _run_stage_change_callbacks do
|
33
|
+
# run_callbacks("stage_change_to_#{stage}") do
|
34
34
|
# binding.pry if notice_of_termination_received?
|
35
|
-
#
|
35
|
+
# phase_changed? ? run_phase_callbacks { binding.pry; 'hey'; super(*args) } : super(*args)
|
36
36
|
# end
|
37
37
|
# end
|
38
38
|
# end
|
39
39
|
|
40
40
|
# def save!(*args)
|
41
|
-
# return super(*args) unless valid? &&
|
41
|
+
# return super(*args) unless valid? && stage_changed? || valid? && new_record?
|
42
42
|
|
43
|
-
#
|
44
|
-
# run_callbacks("
|
45
|
-
#
|
43
|
+
# _run_stage_change_callbacks do
|
44
|
+
# run_callbacks("stage_change_to_#{stage}") do
|
45
|
+
# phase_changed? ? run_phase_callbacks { binding.pry; 'hey'; super(*args) } : super(*args)
|
46
46
|
# end
|
47
47
|
# end
|
48
48
|
# end
|
49
49
|
|
50
50
|
# protected
|
51
51
|
|
52
|
-
# def
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
52
|
+
# def run_phase_callbacks(&block)
|
53
|
+
# _run_phase_change_callbacks do
|
54
|
+
# _run_phase_started_callbacks do
|
55
|
+
# _run_phase_ended_callbacks(&block)
|
56
56
|
# end
|
57
57
|
# end
|
58
58
|
# end
|
59
59
|
|
60
|
-
# def
|
61
|
-
#
|
62
|
-
#
|
60
|
+
# def _run_phase_started_callbacks(&block)
|
61
|
+
# phases_started.inject(block) do |blk, phase|
|
62
|
+
# _run_phase_started_callbacks(phase, &blk)
|
63
63
|
# end
|
64
64
|
# end
|
65
65
|
|
66
|
-
# def
|
67
|
-
#
|
68
|
-
#
|
66
|
+
# def _run_phase_ended_callbacks(&block)
|
67
|
+
# phases_ended.inject(block) do |blk, phase|
|
68
|
+
# _run_phase_ended_callbacks(phase, &blk)
|
69
69
|
# end
|
70
70
|
# end
|
71
71
|
|
72
|
-
# def
|
73
|
-
# run_callbacks("#{
|
72
|
+
# def _run_phase_started_callbacks(phase, &block)
|
73
|
+
# run_callbacks("#{phase}_started".to_sym, &block)
|
74
74
|
# end
|
75
75
|
|
76
|
-
# def
|
77
|
-
# run_callbacks("#{
|
76
|
+
# def _run_phase_ended_callbacks(phase, &block)
|
77
|
+
# run_callbacks("#{phase}_ended".to_sym, &block)
|
78
78
|
# end
|
79
79
|
# end
|
80
80
|
|
81
81
|
# module ClassMethods
|
82
|
-
# def
|
83
|
-
# define_callback_methods_for("#{
|
84
|
-
# define_callback_methods_for("#{
|
82
|
+
# def lifephase_callbacks_for(phase)
|
83
|
+
# define_callback_methods_for("#{phase}_started".to_sym)
|
84
|
+
# define_callback_methods_for("#{phase}_ended".to_sym)
|
85
85
|
# end
|
86
86
|
|
87
87
|
# def callbacks_for(callback_name)
|
88
88
|
# define_callback_methods_for(callback_name)
|
89
89
|
# end
|
90
90
|
|
91
|
-
# def
|
92
|
-
# define_callback_methods_for("
|
91
|
+
# def stage_callbacks_for(stage_name)
|
92
|
+
# define_callback_methods_for("stage_change_to_#{stage_name}")
|
93
93
|
# end
|
94
94
|
|
95
95
|
# def _normalize_callback_options(options)
|
@@ -11,12 +11,12 @@ module ActsAsLiving::EnumDefiner
|
|
11
11
|
|
12
12
|
module ClassMethods
|
13
13
|
def enum_options
|
14
|
-
|
15
|
-
|
14
|
+
stages = @stage_keys.map.with_index(&method(:to_enum_map)).to_h
|
15
|
+
stages.merge(@death => @spread * -1)
|
16
16
|
end
|
17
17
|
|
18
|
-
def to_enum_map(
|
19
|
-
[
|
18
|
+
def to_enum_map(stage, index)
|
19
|
+
[stage, index * @spread]
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActsAsLiving::MethodsDefiner
|
4
|
+
def self.call(klass)
|
5
|
+
klass.class_eval do
|
6
|
+
extend ClassMethods
|
7
|
+
include InstanceMethods
|
8
|
+
|
9
|
+
@stage_keys.each(&method(:define_stage_queries))
|
10
|
+
@phases.each(&method(:define_phase_queries))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module InstanceMethods
|
15
|
+
def stage_after(stage)
|
16
|
+
self.class.stage_after(stage)
|
17
|
+
end
|
18
|
+
|
19
|
+
def stages
|
20
|
+
self.class.stages
|
21
|
+
end
|
22
|
+
|
23
|
+
def stage_before(stage)
|
24
|
+
self.class.stage_before(stage)
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_next_stage
|
28
|
+
update(stage: next_stage)
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_next_stage!
|
32
|
+
update!(stage: next_stage)
|
33
|
+
end
|
34
|
+
|
35
|
+
def next_stage
|
36
|
+
stage_after(stage) if stage
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_previous_stage
|
40
|
+
update(stage: previous_stage)
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_previous_stage!
|
44
|
+
update!(stage: previous_stage)
|
45
|
+
end
|
46
|
+
|
47
|
+
def previous_stage
|
48
|
+
stage_before(stage)
|
49
|
+
end
|
50
|
+
|
51
|
+
def dying?
|
52
|
+
self.class.dying?(stage)
|
53
|
+
end
|
54
|
+
|
55
|
+
def newborn?
|
56
|
+
self.class.newborn?(stage)
|
57
|
+
end
|
58
|
+
|
59
|
+
def dead?
|
60
|
+
self.class.death == stage
|
61
|
+
end
|
62
|
+
|
63
|
+
def dead_or_dying?
|
64
|
+
dead? || dying?
|
65
|
+
end
|
66
|
+
|
67
|
+
def klass_phases_with_ranges
|
68
|
+
self.class.phases_with_ranges
|
69
|
+
end
|
70
|
+
|
71
|
+
def klass_phases_for(stage)
|
72
|
+
self.class.phases_for(stage)
|
73
|
+
end
|
74
|
+
|
75
|
+
def klass_stages
|
76
|
+
self.class.stages
|
77
|
+
end
|
78
|
+
|
79
|
+
def locked?(&block)
|
80
|
+
return unless block
|
81
|
+
|
82
|
+
@locked_on.to_set.intersect? [stage, stage_was].to_set
|
83
|
+
end
|
84
|
+
|
85
|
+
def phases
|
86
|
+
klass_phases_for(stage)
|
87
|
+
end
|
88
|
+
|
89
|
+
def phase_changed?
|
90
|
+
klass_phases_for(stage) != klass_phases_for(stage_was)
|
91
|
+
end
|
92
|
+
|
93
|
+
def phases_started
|
94
|
+
klass_phases_for(stage) - klass_phases_for(stage_was)
|
95
|
+
end
|
96
|
+
|
97
|
+
def phases_ended
|
98
|
+
klass_phases_for(stage_was) - klass_phases_for(stage)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
module ClassMethods
|
103
|
+
def alive_stages
|
104
|
+
stages.except(@death).keys
|
105
|
+
end
|
106
|
+
|
107
|
+
def stage_keys
|
108
|
+
stages.keys
|
109
|
+
end
|
110
|
+
|
111
|
+
def stages_after(stage)
|
112
|
+
return [] if dying?(stage)
|
113
|
+
|
114
|
+
stages[stage_after(stage)..]
|
115
|
+
end
|
116
|
+
|
117
|
+
def stages_before(stage)
|
118
|
+
return [] if newborn?(stage)
|
119
|
+
|
120
|
+
index = stage_keys.find_index(stage)
|
121
|
+
stage_keys[0...index]
|
122
|
+
end
|
123
|
+
|
124
|
+
def stage_after(stage)
|
125
|
+
return if dying?(stage)
|
126
|
+
|
127
|
+
index = stage_keys.find_index(stage)
|
128
|
+
stage_keys[index + 1]
|
129
|
+
end
|
130
|
+
|
131
|
+
def stage_before(stage)
|
132
|
+
return if newborn?(stage)
|
133
|
+
|
134
|
+
index = stage_keys.find_index(stage)
|
135
|
+
stage_keys[index - 1]
|
136
|
+
end
|
137
|
+
|
138
|
+
def final_stage
|
139
|
+
stage_keys.last
|
140
|
+
end
|
141
|
+
|
142
|
+
def dying?(stage)
|
143
|
+
final_stage == stage
|
144
|
+
end
|
145
|
+
|
146
|
+
def newborn_stage
|
147
|
+
stages.key(0)
|
148
|
+
end
|
149
|
+
|
150
|
+
def death
|
151
|
+
@death
|
152
|
+
end
|
153
|
+
|
154
|
+
def newborn?(stage)
|
155
|
+
initial_stage == stage
|
156
|
+
end
|
157
|
+
|
158
|
+
def phases_with_ranges
|
159
|
+
@phases.map(&method(:to_phase_with_range)).to_h
|
160
|
+
end
|
161
|
+
|
162
|
+
def to_phase_with_range(phase, delimiter)
|
163
|
+
[phase, (stages[delimiter.first]..stages[delimiter.last])]
|
164
|
+
end
|
165
|
+
|
166
|
+
def phases
|
167
|
+
@phases
|
168
|
+
end
|
169
|
+
|
170
|
+
def phases_for(stage)
|
171
|
+
phases_with_ranges.keys.select do |phase|
|
172
|
+
phases_with_ranges[phase].include? stages[stage]
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def define_phase_queries(phase, delimiters)
|
177
|
+
define_method("#{phase}?") do
|
178
|
+
if delimiters.length == 1
|
179
|
+
klass_stages[stage] == klass_stages[delimiters]
|
180
|
+
else
|
181
|
+
klass_stages[stage] >= klass_stages[delimiters.first] &&
|
182
|
+
klass_stages[stage] <= klass_stages[delimiters.second]
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
define_method("pre_#{phase}?") do
|
187
|
+
klass_stages[stage] < klass_stages[delimiters.first] unless cancelled?
|
188
|
+
end
|
189
|
+
|
190
|
+
define_method("past_#{phase}?") do
|
191
|
+
klass_stages[stage] > klass_stages[delimiters.last] || cancelled?
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def define_stage_queries(stage_key)
|
196
|
+
define_method("stage_changed_to_#{stage_key}?") do
|
197
|
+
stage_changed? && stage_was == stage_key
|
198
|
+
end
|
199
|
+
|
200
|
+
define_method("stage_saved_to_#{stage_key}?") do
|
201
|
+
saved_change_to_stage? && stage == stage_key
|
202
|
+
end
|
203
|
+
|
204
|
+
define_method("pre_#{stage_key}?") do
|
205
|
+
klass_stages[stage] < klass_stages[stage_key] unless cancelled?
|
206
|
+
end
|
207
|
+
|
208
|
+
define_method("past_#{stage_key}?") do
|
209
|
+
klass_stages[stage] > klass_stages[stage_key] || cancelled?
|
210
|
+
end
|
211
|
+
|
212
|
+
define_method("cancelled_from_#{stage_key}?") do
|
213
|
+
stage == 'cancelled' && stage_was == stage_key
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
@@ -2,13 +2,18 @@
|
|
2
2
|
|
3
3
|
require 'active_support'
|
4
4
|
require 'rails/railtie'
|
5
|
+
require 'acts_as_living'
|
5
6
|
|
6
7
|
module ActsAsLiving
|
7
8
|
class Railtie < Rails::Railtie
|
8
9
|
config.to_prepare do
|
9
10
|
ActiveSupport.on_load(:active_record) do
|
10
|
-
|
11
|
+
include ::ActsAsLiving::ActsAsLiving
|
11
12
|
end
|
12
13
|
end
|
14
|
+
|
15
|
+
rake_tasks do
|
16
|
+
load 'tasks/acts_as_living.rake'
|
17
|
+
end
|
13
18
|
end
|
14
19
|
end
|
@@ -1,20 +1,20 @@
|
|
1
1
|
module ActsAsLiving::ScopesDefiner
|
2
2
|
def self.call(klass)
|
3
3
|
klass.class_eval do
|
4
|
-
|
5
|
-
scope "past_#{
|
6
|
-
scope "pre_#{
|
7
|
-
scope "not_#{
|
4
|
+
stages.each do |stage, _num|
|
5
|
+
scope "past_#{stage}", -> { where('stage >= ?', stages[stage]) }
|
6
|
+
scope "pre_#{stage}", -> { where('stage < ?', stages[stage]) }
|
7
|
+
scope "not_#{stage}", -> { where.not(stage: stage) }
|
8
8
|
end
|
9
9
|
|
10
|
-
scope :cancelled, -> { where('
|
10
|
+
scope :cancelled, -> { where('stage < 0') }
|
11
11
|
|
12
|
-
@
|
12
|
+
@phases.each do |phase, delimiters|
|
13
13
|
if delimiters.length == 1
|
14
|
-
scope
|
14
|
+
scope phase, -> { where(stage: delimiters.first) }
|
15
15
|
else
|
16
|
-
scope
|
17
|
-
where('
|
16
|
+
scope phase, lambda {
|
17
|
+
where('stage >= ? AND stage <= ?', stages[delimiters.first], stages[delimiters.second])
|
18
18
|
}
|
19
19
|
end
|
20
20
|
end
|
@@ -3,30 +3,30 @@ module ActsAsLiving::ValidationsDefiner
|
|
3
3
|
klass.class_eval do
|
4
4
|
include InstanceMethods
|
5
5
|
|
6
|
-
validates :
|
6
|
+
validates :stage, presence: true
|
7
7
|
|
8
|
-
validate :
|
9
|
-
validate :
|
8
|
+
validate :stage_progression, on: :update, if: :stage_changed?
|
9
|
+
validate :initialized_stage, on: :create, if: :stage_changed?
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
13
|
module InstanceMethods
|
14
|
-
def
|
15
|
-
return if
|
14
|
+
def stage_progression
|
15
|
+
return if stage.to_s == self.class.death.to_s || stage == stage_after(stage_was)
|
16
16
|
|
17
|
-
message = if
|
18
|
-
"The contract can only be updated to '#{self.class.
|
17
|
+
message = if stage_was == self.class.final_stage
|
18
|
+
"The contract can only be updated to '#{self.class.death}'"
|
19
19
|
else
|
20
|
-
"The contract can only be updated to '#{self.class.
|
20
|
+
"The contract can only be updated to '#{self.class.death}' or '#{stage_after(stage_was)}'"
|
21
21
|
end
|
22
22
|
|
23
|
-
errors.add(:
|
23
|
+
errors.add(:stage, message)
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
27
|
-
return if
|
26
|
+
def initialized_stage
|
27
|
+
return if stage == self.class.initial_stage
|
28
28
|
|
29
|
-
errors.add(:
|
29
|
+
errors.add(:stage, "Contract has to be initialized with '#{self.class.initial_stage}' stage")
|
30
30
|
end
|
31
31
|
end
|
32
32
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
namespace :acts_as_living do
|
2
|
+
desc 'Install'
|
3
|
+
task install_migration: :environment do
|
4
|
+
options = {}
|
5
|
+
OptionParser.new do |opts|
|
6
|
+
opts.banner = 'Usage: rake add [options]'
|
7
|
+
opts.on('-m', '--model ARG', String) { |model| options[:model] = model }
|
8
|
+
opts.on('-s', '--stages ARG', Array) { |stages| options[:stages] = stages }
|
9
|
+
end.parse!
|
10
|
+
|
11
|
+
migration_name = "add_life_stages_to_#{options[:model]}"
|
12
|
+
timestamps_code = stages.map { |stage| "#{stage}_at:datetime" }.join(' ')
|
13
|
+
stages_code = 'stage:integer past_stages:string{array: true, default: []}'
|
14
|
+
|
15
|
+
system "rails g migration #{migration_name} #{stages_code} #{timestamps_code}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acts_as_living
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Guilherme Andrade
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-07-
|
11
|
+
date: 2020-07-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -70,7 +70,7 @@ dependencies:
|
|
70
70
|
- - ">="
|
71
71
|
- !ruby/object:Gem::Version
|
72
72
|
version: 6.0.3
|
73
|
-
description: An ActiveRecord plugin that assists in acts_as_living
|
73
|
+
description: An ActiveRecord plugin that assists in acts_as_living stage progressions.
|
74
74
|
email:
|
75
75
|
- guilherme.andrade.ao@gmail.com
|
76
76
|
executables: []
|
@@ -80,14 +80,15 @@ files:
|
|
80
80
|
- Changelog.md
|
81
81
|
- README.md
|
82
82
|
- lib/acts_as_living.rb
|
83
|
+
- lib/acts_as_living/acts_as_living.rb
|
83
84
|
- lib/acts_as_living/callbacks_definer.rb
|
84
|
-
- lib/acts_as_living/class_methods.rb
|
85
85
|
- lib/acts_as_living/enum_definer.rb
|
86
|
-
- lib/acts_as_living/
|
86
|
+
- lib/acts_as_living/methods_definer.rb
|
87
87
|
- lib/acts_as_living/railtie.rb
|
88
88
|
- lib/acts_as_living/scopes_definer.rb
|
89
89
|
- lib/acts_as_living/validations_definer.rb
|
90
90
|
- lib/acts_as_living/version.rb
|
91
|
+
- lib/tasks/acts_as_living.rake
|
91
92
|
homepage: https://github.com/guilherme-andrade/acts_as_living
|
92
93
|
licenses:
|
93
94
|
- MIT
|
@@ -103,7 +104,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
103
104
|
requirements:
|
104
105
|
- - ">="
|
105
106
|
- !ruby/object:Gem::Version
|
106
|
-
version:
|
107
|
+
version: 2.5.0
|
107
108
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
109
|
requirements:
|
109
110
|
- - ">="
|
@@ -113,5 +114,5 @@ requirements: []
|
|
113
114
|
rubygems_version: 3.0.3
|
114
115
|
signing_key:
|
115
116
|
specification_version: 4
|
116
|
-
summary: An ActiveRecord plugin that assists in acts_as_living
|
117
|
+
summary: An ActiveRecord plugin that assists in acts_as_living stage progressions.
|
117
118
|
test_files: []
|
@@ -1,97 +0,0 @@
|
|
1
|
-
|
2
|
-
module ActsAsLiving::ClassMethods
|
3
|
-
# validates :status, presence: true
|
4
|
-
|
5
|
-
def acts_as_living(keys, **options)
|
6
|
-
@status_keys = keys
|
7
|
-
@life_stages = options.dig(:life_stages)
|
8
|
-
@locked_statuses = options.dig(:lock_on)
|
9
|
-
@death = options.dig(:death)
|
10
|
-
@spread = options.dig(:spread)
|
11
|
-
@column = options.dig(:column)
|
12
|
-
|
13
|
-
ActsAsLiving::EnumDefiner.call(self)
|
14
|
-
|
15
|
-
run_definers
|
16
|
-
end
|
17
|
-
|
18
|
-
def run_definers
|
19
|
-
ActsAsLiving::ScopesDefiner.call(self)
|
20
|
-
ActsAsLiving::InstanceMethodsDefiner.call(self)
|
21
|
-
# ActsAsLiving::CallbacksDefiner.call(self)
|
22
|
-
ActsAsLiving::ValidationsDefiner.call(self)
|
23
|
-
end
|
24
|
-
|
25
|
-
def alive_statuses
|
26
|
-
statuses.except(@death).keys
|
27
|
-
end
|
28
|
-
|
29
|
-
def status_keys
|
30
|
-
statuses.keys
|
31
|
-
end
|
32
|
-
|
33
|
-
def statuses_after(status)
|
34
|
-
return [] if final_status?(status)
|
35
|
-
|
36
|
-
statuses[status_after(status)..]
|
37
|
-
end
|
38
|
-
|
39
|
-
def statuses_before(status)
|
40
|
-
return [] if initial_status?(status)
|
41
|
-
|
42
|
-
index = status_keys.find_index(status)
|
43
|
-
status_keys[0...index]
|
44
|
-
end
|
45
|
-
|
46
|
-
def status_after(status)
|
47
|
-
return if final_status?(status)
|
48
|
-
|
49
|
-
index = status_keys.find_index(status)
|
50
|
-
status_keys[index + 1]
|
51
|
-
end
|
52
|
-
|
53
|
-
def status_before(status)
|
54
|
-
return if initial_status?(status)
|
55
|
-
|
56
|
-
index = status_keys.find_index(status)
|
57
|
-
status_keys[index - 1]
|
58
|
-
end
|
59
|
-
|
60
|
-
def final_status
|
61
|
-
status_keys.last
|
62
|
-
end
|
63
|
-
|
64
|
-
def final_status?(status)
|
65
|
-
final_status == status
|
66
|
-
end
|
67
|
-
|
68
|
-
def initial_status
|
69
|
-
statuses.key(0)
|
70
|
-
end
|
71
|
-
|
72
|
-
def dead_status
|
73
|
-
@death
|
74
|
-
end
|
75
|
-
|
76
|
-
def initial_status?(status)
|
77
|
-
initial_status == status
|
78
|
-
end
|
79
|
-
|
80
|
-
def stages_with_ranges
|
81
|
-
@life_stages.map(&method(:to_stage_with_range)).to_h
|
82
|
-
end
|
83
|
-
|
84
|
-
def to_stage_with_range(stage, delimiter)
|
85
|
-
[stage, (statuses[delimiter.first]..statuses[delimiter.last])]
|
86
|
-
end
|
87
|
-
|
88
|
-
def life_stages
|
89
|
-
@life_stages
|
90
|
-
end
|
91
|
-
|
92
|
-
def life_stages_for(status)
|
93
|
-
stages_with_ranges.keys.select do |stage|
|
94
|
-
stages_with_ranges[stage].include? statuses[status]
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
@@ -1,141 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ActsAsLiving::InstanceMethodsDefiner
|
4
|
-
def self.call(klass)
|
5
|
-
klass.class_eval do
|
6
|
-
extend ClassMethods
|
7
|
-
include InstanceMethods
|
8
|
-
|
9
|
-
@life_stages.each(&method(:define_stage_queries))
|
10
|
-
|
11
|
-
@status_keys.each(&method(:define_changed_queries))
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
module InstanceMethods
|
16
|
-
def status_after(status)
|
17
|
-
self.class.status_after(status)
|
18
|
-
end
|
19
|
-
|
20
|
-
def statuses
|
21
|
-
self.class.statuses
|
22
|
-
end
|
23
|
-
|
24
|
-
def status_before(status)
|
25
|
-
self.class.status_before(status)
|
26
|
-
end
|
27
|
-
|
28
|
-
def to_next_status
|
29
|
-
update(status: next_status)
|
30
|
-
end
|
31
|
-
|
32
|
-
def to_next_status!
|
33
|
-
update!(status: next_status)
|
34
|
-
end
|
35
|
-
|
36
|
-
def next_status
|
37
|
-
status_after(status) if status
|
38
|
-
end
|
39
|
-
|
40
|
-
def to_previous_status
|
41
|
-
update(status: previous_status)
|
42
|
-
end
|
43
|
-
|
44
|
-
def to_previous_status!
|
45
|
-
update!(status: previous_status)
|
46
|
-
end
|
47
|
-
|
48
|
-
def previous_status
|
49
|
-
status_before(status)
|
50
|
-
end
|
51
|
-
|
52
|
-
def final_status?
|
53
|
-
self.class.final_status?(status)
|
54
|
-
end
|
55
|
-
|
56
|
-
def initial_status?
|
57
|
-
self.class.initial_status?(status)
|
58
|
-
end
|
59
|
-
|
60
|
-
def dead_status?
|
61
|
-
self.class.dead_status == status
|
62
|
-
end
|
63
|
-
|
64
|
-
def dead_or_finalized?
|
65
|
-
dead_status? || final_status?
|
66
|
-
end
|
67
|
-
|
68
|
-
def klass_stages_with_ranges
|
69
|
-
self.class.stages_with_ranges
|
70
|
-
end
|
71
|
-
|
72
|
-
def klass_life_stages_for(status)
|
73
|
-
self.class.life_stages_for(status)
|
74
|
-
end
|
75
|
-
|
76
|
-
def klass_statuses
|
77
|
-
self.class.statuses
|
78
|
-
end
|
79
|
-
|
80
|
-
def locked?(&block)
|
81
|
-
return unless block
|
82
|
-
|
83
|
-
@locked_on.to_set.intersect? [status, status_was].to_set
|
84
|
-
end
|
85
|
-
|
86
|
-
def life_stages
|
87
|
-
klass_life_stages_for(status)
|
88
|
-
end
|
89
|
-
|
90
|
-
def life_stage_changed?
|
91
|
-
klass_life_stages_for(status) != klass_life_stages_for(status_was)
|
92
|
-
end
|
93
|
-
|
94
|
-
def life_stages_started
|
95
|
-
klass_life_stages_for(status) - klass_life_stages_for(status_was)
|
96
|
-
end
|
97
|
-
|
98
|
-
def life_stages_ended
|
99
|
-
klass_life_stages_for(status_was) - klass_life_stages_for(status)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
module ClassMethods
|
104
|
-
def define_stage_queries(stage, delimiters)
|
105
|
-
define_method("#{stage}?") do
|
106
|
-
if delimiters.length == 1
|
107
|
-
klass_statuses[status] == klass_statuses[delimiters]
|
108
|
-
else
|
109
|
-
klass_statuses[status] >= klass_statuses[delimiters.first] &&
|
110
|
-
klass_statuses[status] <= klass_statuses[delimiters.second]
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
define_method("pre_#{stage}?") do
|
115
|
-
klass_statuses[status] < klass_statuses[delimiters.first] unless cancelled?
|
116
|
-
end
|
117
|
-
|
118
|
-
define_method("past_#{stage}?") do
|
119
|
-
klass_statuses[status] > klass_statuses[delimiters.last] || cancelled?
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def define_changed_queries(status_key)
|
124
|
-
define_method("status_changed_to_#{status_key}?") do
|
125
|
-
status_changed? && status_was == status_key
|
126
|
-
end
|
127
|
-
|
128
|
-
define_method("pre_#{status_key}?") do
|
129
|
-
klass_statuses[status] < klass_statuses[status_key] unless cancelled?
|
130
|
-
end
|
131
|
-
|
132
|
-
define_method("past_#{status_key}?") do
|
133
|
-
klass_statuses[status] > klass_statuses[status_key] || cancelled?
|
134
|
-
end
|
135
|
-
|
136
|
-
define_method("cancelled_from_#{status_key}?") do
|
137
|
-
status == 'cancelled' && status_was == status_key
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|