workflow-join 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +6 -9
- data/Rakefile +9 -2
- data/lib/workflow/join.rb +55 -32
- data/lib/workflow/join/active_record.rb +43 -0
- data/lib/workflow/join/active_record/pending_callbacks.rb +31 -0
- data/lib/workflow/join/active_record/pending_transitions.rb +41 -0
- data/lib/workflow/join/simple.rb +11 -0
- data/lib/workflow/join/simple/pending_callbacks.rb +23 -0
- data/lib/workflow/join/simple/pending_transitions.rb +36 -0
- data/lib/workflow/join/version.rb +1 -1
- data/workflow-join.gemspec +2 -0
- metadata +35 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 40f7e69d9114f772e7a3057bdbbfedc974dd786d
|
4
|
+
data.tar.gz: 779672bcd9063eb69d6b5400ebe7318957df3669
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 684b92e932e55d231c37c57f49a43715b7369ad2fae41e8fca5ce1e56d64f3820b5241af20c845fc1423cc1361f428c2644b4fef82277c90edc2859b33b8fb86
|
7
|
+
data.tar.gz: 9c60b3ff584e173d0a91d9e2a9a5e7dbca12b1e707f4105081fe9882276f93de6c2f2b3944d63e99f0f952a9ec9df772043c77f196c6ab8041967e9442e43a98
|
data/.rubocop_todo.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# This configuration was generated by
|
2
2
|
# `rubocop --auto-gen-config`
|
3
|
-
# on 2016-09-
|
3
|
+
# on 2016-09-16 13:15:05 +0200 using RuboCop version 0.42.0.
|
4
4
|
# The point is for the user to remove these configuration records
|
5
5
|
# one by one as the offenses are removed from the code base.
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
@@ -16,12 +16,7 @@ Lint/BlockAlignment:
|
|
16
16
|
|
17
17
|
# Offense count: 1
|
18
18
|
Metrics/AbcSize:
|
19
|
-
Max:
|
20
|
-
|
21
|
-
# Offense count: 1
|
22
|
-
# Configuration parameters: CountComments.
|
23
|
-
Metrics/MethodLength:
|
24
|
-
Max: 46
|
19
|
+
Max: 57
|
25
20
|
|
26
21
|
# Offense count: 1
|
27
22
|
# Cop supports --auto-correct.
|
@@ -37,18 +32,20 @@ Style/MutableConstant:
|
|
37
32
|
Exclude:
|
38
33
|
- 'lib/workflow/join/version.rb'
|
39
34
|
|
40
|
-
# Offense count:
|
35
|
+
# Offense count: 2
|
41
36
|
# Cop supports --auto-correct.
|
42
37
|
# Configuration parameters: PreferredDelimiters.
|
43
38
|
Style/PercentLiteralDelimiters:
|
44
39
|
Exclude:
|
40
|
+
- 'spec/workflow/active_record_spec.rb'
|
45
41
|
- 'spec/workflow/join_spec.rb'
|
46
42
|
|
47
|
-
# Offense count:
|
43
|
+
# Offense count: 2
|
48
44
|
# Cop supports --auto-correct.
|
49
45
|
Style/RescueModifier:
|
50
46
|
Exclude:
|
51
47
|
- 'lib/workflow/join.rb'
|
48
|
+
- 'lib/workflow/join/active_record/pending_callbacks.rb'
|
52
49
|
|
53
50
|
# Offense count: 4
|
54
51
|
# Cop supports --auto-correct.
|
data/Rakefile
CHANGED
@@ -15,10 +15,17 @@ rescue Bundler::BundlerError => e
|
|
15
15
|
exit e.status_code
|
16
16
|
end
|
17
17
|
|
18
|
-
desc 'Tests'
|
18
|
+
desc 'Tests w/ActiveRecord'
|
19
19
|
RSpec::Core::RakeTask.new(:spec) do |spec|
|
20
20
|
spec.rspec_opts = '-Ispec'
|
21
21
|
# spec.rcov = true
|
22
22
|
end
|
23
23
|
|
24
|
-
|
24
|
+
desc 'Tests wo/ActiveRecord'
|
25
|
+
RSpec::Core::RakeTask.new(:spec_simple) do |spec|
|
26
|
+
ENV['USE_SIMPLE_PERSISTENCE'] = 'true'
|
27
|
+
spec.rspec_opts = '-Ispec'
|
28
|
+
# spec.rcov = true
|
29
|
+
end
|
30
|
+
|
31
|
+
task default: [:spec, :spec_simple]
|
data/lib/workflow/join.rb
CHANGED
@@ -1,57 +1,79 @@
|
|
1
1
|
require 'workflow'
|
2
2
|
require 'workflow/join/version'
|
3
3
|
|
4
|
+
if ENV['USE_SIMPLE_PERSISTENCE'] == 'true'
|
5
|
+
require 'workflow/join/simple'
|
6
|
+
puts "☆ Using simple mode (no persistence,) due to ‘ENV['USE_SIMPLE_PERSISTENCE']’"
|
7
|
+
else
|
8
|
+
begin
|
9
|
+
require 'active_record'
|
10
|
+
require 'workflow/join/active_record'
|
11
|
+
rescue LoadError => e
|
12
|
+
require 'workflow/join/simple'
|
13
|
+
puts "★ Error requiring ActiveRecord (message: “#{e.message}”.) Will run in simple mode (no persistence.)"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
4
17
|
Workflow::ClassMethods.prepend(Module.new do
|
5
18
|
def workflow(&specification)
|
6
19
|
# extend instances
|
7
20
|
prepend(Module.new do # this should be safe, since there could not be two subsequent workflow DSL
|
8
|
-
|
21
|
+
if Workflow::Join.const_defined?('ActiveRecord')
|
22
|
+
include Workflow::Join::ActiveRecord # AR pending transitions and callbacks implementation
|
23
|
+
else
|
24
|
+
include Workflow::Join::Simple # simple pending transitions and callbacks implementation
|
25
|
+
end
|
26
|
+
|
9
27
|
def guards!
|
28
|
+
spec.instance_variable_set(:@original_before_transition_proc, spec.before_transition_proc) \
|
29
|
+
unless spec.instance_variable_defined?(:@original_before_transition_proc)
|
30
|
+
|
10
31
|
λλs = spec.guards.map do |inner, outers|
|
11
32
|
outers.map do |getter, state|
|
12
33
|
guard! inner, getter, state
|
13
|
-
end
|
34
|
+
end.compact
|
14
35
|
end.flatten
|
15
|
-
|
36
|
+
|
37
|
+
(original_before_transition_proc = spec.instance_variable_get(:@original_before_transition_proc)) && \
|
38
|
+
λλs << original_before_transition_proc
|
16
39
|
spec.before_transition_proc = ->(from, to, name, *args) { λλs.each { |λ| λ.(from, to, name, *args) } }
|
17
40
|
end
|
18
41
|
|
19
42
|
def guard!(inner, getter, state)
|
20
|
-
slave = getter.call(self)
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
true
|
31
|
-
rescue
|
32
|
-
false # no transition no cry
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
super(old_state, event, *args) rescue nil # no super no cry
|
43
|
+
return if getter.nil? || (slave = getter.call(self)).nil? # I’ll be back, hasta la vista, baby :)
|
44
|
+
|
45
|
+
slave.class.send :define_method, "on_#{state}_entry".to_sym do |old_state, event, *args|
|
46
|
+
pending_callbacks.each do |master|
|
47
|
+
master.reload if master.respond_to?(:reload)
|
48
|
+
next unless master.pending_transitions?
|
49
|
+
master.try_pending_transitions!
|
50
|
+
# halted is automagically removed after successful transition
|
51
|
+
# the line below is unneeded
|
52
|
+
# master.halted = master.pending_transitions?
|
37
53
|
end
|
38
|
-
|
54
|
+
super(old_state, event, *args) rescue nil # no super no cry
|
55
|
+
end
|
56
|
+
|
39
57
|
lambda do |_, to, name, *|
|
58
|
+
slave.reload if slave.respond_to?(:reload)
|
40
59
|
if to.to_sym == inner && !slave.send("#{state}?".to_sym)
|
41
|
-
|
42
|
-
|
60
|
+
pending_transition! name
|
61
|
+
slave.pending_callback!(self)
|
43
62
|
halt("Waiting for guard workflow to enter “:#{state}” state")
|
44
63
|
end
|
45
64
|
end
|
46
65
|
end
|
47
66
|
end)
|
48
67
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
68
|
+
if respond_to?(:after_commit)
|
69
|
+
after_commit { guards! }
|
70
|
+
else
|
71
|
+
singleton_class.prepend(Module.new do
|
72
|
+
def new(*)
|
73
|
+
super.tap(&:guards!)
|
74
|
+
end
|
75
|
+
end)
|
76
|
+
end
|
55
77
|
|
56
78
|
super
|
57
79
|
end
|
@@ -61,7 +83,7 @@ module Workflow
|
|
61
83
|
module Join
|
62
84
|
GUARD_PARAMS_ERROR = 'Either guard instance variable name or a code block is required'.freeze
|
63
85
|
GUARD_POINTCUT_ERROR = 'Both :inner and :outer states are required'.freeze
|
64
|
-
GUARD_IS_NOT_WORKFLOW = 'Guard given must be a workflow instance'.freeze
|
86
|
+
GUARD_IS_NOT_WORKFLOW = 'Guard given must be a workflow instance, was: “%s”'.freeze
|
65
87
|
|
66
88
|
def guards
|
67
89
|
@guards ||= {}
|
@@ -79,10 +101,11 @@ module Workflow
|
|
79
101
|
case
|
80
102
|
when /\A@/ =~ g.to_s && host.instance_variable_defined?(g)
|
81
103
|
host.instance_variable_get(g)
|
82
|
-
when host.methods.include?(g) && host.method(g).arity
|
104
|
+
when host.methods.include?(g) && host.method(g).arity <= 0
|
83
105
|
host.send g
|
84
106
|
end.tap do |guard_instance|
|
85
|
-
fail Workflow::WorkflowDefinitionError, GUARD_IS_NOT_WORKFLOW
|
107
|
+
fail Workflow::WorkflowDefinitionError, GUARD_IS_NOT_WORKFLOW % guard_instance \
|
108
|
+
unless guard_instance.nil? || guard_instance.is_a?(Workflow)
|
86
109
|
end
|
87
110
|
end
|
88
111
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'workflow/join/active_record/pending_transitions'
|
2
|
+
require 'workflow/join/active_record/pending_callbacks'
|
3
|
+
|
4
|
+
module Workflow
|
5
|
+
module Join
|
6
|
+
module ActiveRecord
|
7
|
+
ENSURE_COLUMNS = lambda do |model, *columns|
|
8
|
+
columns.reduce(true) do |memo, column|
|
9
|
+
next memo if model.column_names.include?(column.to_s)
|
10
|
+
|
11
|
+
::ActiveRecord::Base.connection.execute(
|
12
|
+
"ALTER TABLE #{model.table_name} ADD #{column} VARCHAR(255)"
|
13
|
+
)
|
14
|
+
false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
include PendingTransitions
|
19
|
+
include PendingCallbacks
|
20
|
+
|
21
|
+
def self.included(base)
|
22
|
+
base.singleton_class.send :define_method, :prepended do |model|
|
23
|
+
fail LoadError, "This module might be included in ActiveRecord::Base instances only (#{base} given.)" \
|
24
|
+
unless model < ::ActiveRecord::Base
|
25
|
+
|
26
|
+
unless ENSURE_COLUMNS.call(model, :workflow_pending_transitions, :workflow_pending_callbacks)
|
27
|
+
fail LoadError, <<-MSG
|
28
|
+
|
29
|
+
=======================================================================================
|
30
|
+
This is an intended fail, next time the class is requested, it’ll be loaded properly!
|
31
|
+
To avoid this one should explicitly specify columns:
|
32
|
+
— workflow_pending_transitions,
|
33
|
+
— workflow_pending_callbacks
|
34
|
+
in all models, that are willing to use joined workflows.
|
35
|
+
=======================================================================================
|
36
|
+
|
37
|
+
MSG
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Workflow
|
2
|
+
module Join
|
3
|
+
module ActiveRecord
|
4
|
+
# table.column :workflow_pending_callbacks, :string
|
5
|
+
module PendingCallbacks
|
6
|
+
def pending_callbacks
|
7
|
+
workflow_pending_callbacks.to_s.split(';').map do |wpc|
|
8
|
+
c, id = wpc.split(',')
|
9
|
+
Kernel.const_get(c).find(id) rescue nil
|
10
|
+
end.compact
|
11
|
+
end
|
12
|
+
|
13
|
+
def pending_callbacks!(value)
|
14
|
+
pcs = case value
|
15
|
+
when Array then value.map { |instance| [instance.class.name, instance.id].join(',') }.join(';')
|
16
|
+
when String, Symbol then value.to_s
|
17
|
+
end
|
18
|
+
update_column :workflow_pending_callbacks, pcs
|
19
|
+
end
|
20
|
+
|
21
|
+
def pending_callbacks?
|
22
|
+
!pending_callbacks.empty?
|
23
|
+
end
|
24
|
+
|
25
|
+
def pending_callback!(value)
|
26
|
+
pending_callbacks!(pending_callbacks | [value])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Workflow
|
2
|
+
module Join
|
3
|
+
module ActiveRecord
|
4
|
+
# table.column :workflow_pending_transitions, :string
|
5
|
+
module PendingTransitions
|
6
|
+
def pending_transitions
|
7
|
+
workflow_pending_transitions.to_s.split(',').map(&:to_sym)
|
8
|
+
end
|
9
|
+
|
10
|
+
def pending_transitions!(value)
|
11
|
+
pts = case value
|
12
|
+
when Array then value.map(&:to_s).join(',')
|
13
|
+
when String, Symbol then value.to_s
|
14
|
+
end
|
15
|
+
update_column :workflow_pending_transitions, pts
|
16
|
+
end
|
17
|
+
|
18
|
+
def pending_transitions?
|
19
|
+
!pending_transitions.empty?
|
20
|
+
end
|
21
|
+
|
22
|
+
def pending_transition!(value)
|
23
|
+
pending_transitions!(pending_transitions | [value])
|
24
|
+
end
|
25
|
+
|
26
|
+
def try_pending_transitions!
|
27
|
+
pending_transitions!(pending_transitions.reject do |transition|
|
28
|
+
begin
|
29
|
+
respond_to?("can_#{transition}?") && \
|
30
|
+
public_send("can_#{transition}?") && \
|
31
|
+
public_send("#{transition}!".to_sym) && \
|
32
|
+
true
|
33
|
+
rescue
|
34
|
+
false # no transition no cry
|
35
|
+
end
|
36
|
+
end)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Workflow
|
2
|
+
module Join
|
3
|
+
module Simple
|
4
|
+
module PendingCallbacks
|
5
|
+
def pending_callbacks
|
6
|
+
@pending_callbacks ||= []
|
7
|
+
end
|
8
|
+
|
9
|
+
def pending_callbacks!(value)
|
10
|
+
@pending_callbacks = value
|
11
|
+
end
|
12
|
+
|
13
|
+
def pending_callbacks?
|
14
|
+
!pending_callbacks.empty?
|
15
|
+
end
|
16
|
+
|
17
|
+
def pending_callback!(value)
|
18
|
+
pending_callbacks!(pending_callbacks | [value])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Workflow
|
2
|
+
module Join
|
3
|
+
module Simple
|
4
|
+
module PendingTransitions
|
5
|
+
def pending_transitions
|
6
|
+
@pending_transitions ||= []
|
7
|
+
end
|
8
|
+
|
9
|
+
def pending_transitions!(value)
|
10
|
+
@pending_transitions = value
|
11
|
+
end
|
12
|
+
|
13
|
+
def pending_transitions?
|
14
|
+
!pending_transitions.empty?
|
15
|
+
end
|
16
|
+
|
17
|
+
def pending_transition!(value)
|
18
|
+
pending_transitions!(pending_transitions | [value])
|
19
|
+
end
|
20
|
+
|
21
|
+
def try_pending_transitions!
|
22
|
+
pending_transitions.reject! do |transition|
|
23
|
+
begin
|
24
|
+
respond_to?("can_#{transition}?") && \
|
25
|
+
public_send("can_#{transition}?") && \
|
26
|
+
public_send("#{transition}!".to_sym) && \
|
27
|
+
true
|
28
|
+
rescue
|
29
|
+
false # no transition no cry
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/workflow-join.gemspec
CHANGED
@@ -29,6 +29,8 @@ Gem::Specification.new do |spec|
|
|
29
29
|
spec.add_development_dependency 'rspec'
|
30
30
|
spec.add_development_dependency 'rubocop'
|
31
31
|
spec.add_development_dependency 'pry'
|
32
|
+
spec.add_development_dependency 'sqlite3'
|
32
33
|
|
33
34
|
spec.add_dependency 'workflow', '~> 1.2'
|
35
|
+
spec.add_dependency 'activerecord'
|
34
36
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: workflow-join
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aleksei Matiushkin
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: sqlite3
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: workflow
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,6 +108,20 @@ dependencies:
|
|
94
108
|
- - "~>"
|
95
109
|
- !ruby/object:Gem::Version
|
96
110
|
version: '1.2'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: activerecord
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
97
125
|
description: Workflow extension that allows to fork workflows with other workflows
|
98
126
|
and join them at specific states.
|
99
127
|
email:
|
@@ -115,6 +143,12 @@ files:
|
|
115
143
|
- bin/console
|
116
144
|
- bin/setup
|
117
145
|
- lib/workflow/join.rb
|
146
|
+
- lib/workflow/join/active_record.rb
|
147
|
+
- lib/workflow/join/active_record/pending_callbacks.rb
|
148
|
+
- lib/workflow/join/active_record/pending_transitions.rb
|
149
|
+
- lib/workflow/join/simple.rb
|
150
|
+
- lib/workflow/join/simple/pending_callbacks.rb
|
151
|
+
- lib/workflow/join/simple/pending_transitions.rb
|
118
152
|
- lib/workflow/join/version.rb
|
119
153
|
- workflow-join.gemspec
|
120
154
|
homepage: https://github.com/am-kantox/workflow-join
|