sequins 0.1.1 → 0.1.2

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
  SHA1:
3
- metadata.gz: 4262d19a9cf34f35abf9368c79c98c496a6e84a9
4
- data.tar.gz: a7dce47d5edd4c0f1c6091b2f55fba96c0bc58fd
3
+ metadata.gz: 056e21b0bc192d4c206223492dde4f2e0b77f6e9
4
+ data.tar.gz: 994041d33fec1c90138ce71579e042dd57e144b5
5
5
  SHA512:
6
- metadata.gz: 481a85ea6424756081c5c23ba00f7f5284cfc880b252725b558d7a9ecceebfa5f8b4da4b6d2a4ab4f9998bfca4c6f430956d15dfbbe8caaaff455ca55580905f
7
- data.tar.gz: b6256a9b9989104f070fde84cf3f2482170f834bb0ff055695e18a5aa4360718f33105cdd72308dac5e8998832839cadedddf83f2441225d200b3fde01625c51
6
+ metadata.gz: 1ae876d988d4817e944b75ff1119f593cc43d10eb8efbaac3c023639044a0d07dbf7093fe0232009c269aa2098aef3a501e3b9f412e1b4f6fdb019610c2ab662
7
+ data.tar.gz: 7ae79622feb2eb4af69937592eeff9c04dcf6189c7c9ea234f33b7d3922b95d3834f9146a26bfa3a39051c79fc23b6793708c8160c2912ca19a9955b5eb98974
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sequins (0.1.0)
4
+ sequins (0.1.1)
5
5
  autoloaded (~> 2)
6
6
  docile
7
7
  rails (>= 5.0)
data/README.md CHANGED
@@ -42,13 +42,59 @@ class ExampleSequence < Sequins::Base
42
42
  end
43
43
  ```
44
44
 
45
+ ### Steps
46
+
47
+ A step is a Ruby block. It has the following attributes available:
48
+
49
+ * `target` is the target object that you pass into `trigger` or `run_step_for_target`
50
+ * `step_name` is the step that's currently running
51
+ * `sequence` is an instance of `Sequins::Sequence`. From this you have access to the sequence class via `sequence.klass`
52
+
53
+ You also have direct access to class methods on your `Sequence::Base` subclass. For example:
54
+
55
+ ```ruby
56
+ class Example2Sequence < Sequins::Base
57
+ sequence do
58
+ step :start, initial: true do
59
+ send_message target, "hi there"
60
+ end
61
+ end
62
+
63
+ def self.send_message(target, text)
64
+ SomeMailer.send_message(target.id, text).deliver_later
65
+ end
66
+ end
67
+ ```
68
+
69
+ You can also send arguments to `trigger` or `run_step_for_target` which will be passed as block arguments. Example:
70
+
71
+ ```ruby
72
+ class Example3Sequence < Sequins::Base
73
+ sequence do
74
+ step :start, initial: true do |something|
75
+ if something.present?
76
+ delay 3.days, then: :next_step
77
+ else
78
+ end_sequence
79
+ end
80
+ end
81
+
82
+ step :next_step do
83
+ # something interesting
84
+ end
85
+ end
86
+ end
87
+
88
+ Example3Sequence.trigger(User.first, "this will trigger a delay")
89
+ ```
90
+
45
91
  ### Delay Options
46
92
 
47
93
  The first argument to `delay` is always an interval, usually expressed as a number of days. Ex: `3.days`.
48
94
  In addition, it can take these arguments:
49
95
 
50
96
  * `then` (always required) this tells delay which step to run next
51
- * `at` specifies a time relative to the user's local timezone to run the next step
97
+ * `at` specifies a time relative to the target's local timezone to run the next step
52
98
  * `only` limits what days to send on. Currently the only valid option is `:weekdays`
53
99
 
54
100
  ### Trigger a Sequence
@@ -66,11 +112,12 @@ Sequences can define hooks. The available hooks are:
66
112
 
67
113
  ```
68
114
  before_each_step # runs before every step.
115
+ after_each_step # runs after each step
69
116
  before_sequence # runs before the sequence starts.
70
117
  after_sequence # runs after the sequence ends with an explicit `end_sequence`
71
118
  ```
72
119
 
73
- Hooks are run in the same way steps are, so you have access to the `user` object if you want it.
120
+ Hooks are run in the same way steps are, so you have access to all of the same attributes as a step. Within `before_each_step` and `after_each_step`, `step_name` will be set to the step that is about to or just finished running. Within `before_sequence` and `after_sequence` `step_name` has no meaning.
74
121
 
75
122
  ## Configuration
76
123
 
data/lib/sequins.rb CHANGED
@@ -24,3 +24,5 @@ module Sequins
24
24
  yield configuration
25
25
  end
26
26
  end
27
+
28
+ require 'sequins/errors'
data/lib/sequins/base.rb CHANGED
@@ -13,16 +13,16 @@ module Sequins
13
13
  self.to_s.underscore.gsub(/_sequence$/, '')
14
14
  end
15
15
 
16
- def self.trigger(target)
17
- sequence.trigger(target)
16
+ def self.trigger(target, *args)
17
+ sequence.trigger(target, *args)
18
18
  end
19
19
 
20
- def trigger(target)
21
- self.class.trigger(target)
20
+ def trigger(target, *args)
21
+ self.class.trigger(target, *args)
22
22
  end
23
23
 
24
- def run_step_for_target(step_name, target)
25
- self.class.sequence.run_step_for_target(step_name, target)
24
+ def run_step_for_target(step_name, target, *args)
25
+ self.class.sequence.run_step_for_target(step_name, target, *args)
26
26
  end
27
27
  end
28
28
  end
@@ -1,4 +1,5 @@
1
1
  module Sequins
2
2
  class UnknownStepError < StandardError; end
3
+ class NoInitialStepError < StandardError; end
3
4
  end
4
5
 
@@ -7,60 +7,42 @@ module Sequins
7
7
  def initialize(klass)
8
8
  @klass = klass
9
9
  @steps = {}
10
- @before_each_step_hooks = []
11
- @before_sequence_hooks = []
12
- @after_sequence_hooks = []
10
+ @hooks = {}
13
11
  end
14
12
 
15
13
  def add_step(name, options={}, &block)
16
14
  @steps[name] = StepProxy.new(options, block)
17
15
  end
18
16
 
19
- def add_before_each_step_hook(&block)
20
- @before_each_step_hooks << StepProxy.new({}, block)
17
+ def add_hook(stage, &block)
18
+ @hooks[stage] ||= []
19
+ @hooks[stage] << StepProxy.new({}, block)
21
20
  end
22
21
 
23
- def add_before_sequence_hook(&block)
24
- @before_sequence_hooks << StepProxy.new({}, block)
25
- end
26
-
27
- def add_after_sequence_hook(&block)
28
- @after_sequence_hooks << StepProxy.new({}, block)
29
- end
30
-
31
- def run_step_for_target(step_name, target)
22
+ def run_step_for_target(step_name, target, *args)
32
23
  proxy = @steps[step_name]
33
24
  raise UnknownStepError.new(step_name) if proxy.nil?
34
25
 
35
- unless run_before_each_step_hooks_for_target(target)
36
- run_after_sequence_hooks_for_target(target)
26
+ unless run_hooks_for_target(:before_each_step, target, step_name)
27
+ run_hooks_for_target(:after_sequence, target, :_after_sequence)
37
28
  return false
38
29
  end
39
30
 
40
- step = Docile.dsl_eval(Step.new(target, self), &(proxy.block))
41
- if step.sequence_ended?
42
- run_after_sequence_hooks_for_target(target)
43
- return false
44
- end
45
- end
31
+ step = Docile.dsl_eval(Step.new(target, self, step_name), args, &(proxy.block))
46
32
 
47
- def run_before_each_step_hooks_for_target(target)
48
- @before_each_step_hooks.each do |hook|
49
- step = Docile.dsl_eval(Step.new(target, self), &(hook.block))
50
- return false if step.sequence_ended?
33
+ ended_after_each = !run_hooks_for_target(:after_each_step, target, step_name)
34
+
35
+ if step.sequence_ended? || ended_after_each
36
+ run_hooks_for_target(:after_sequence, target, :_after_sequence)
37
+ return false
51
38
  end
52
39
  end
53
40
 
54
- def run_before_sequence_hooks_for_target(target)
55
- @before_sequence_hooks.each do |hook|
56
- step = Docile.dsl_eval(Step.new(target, self), &(hook.block))
57
- return false if step.sequence_ended?
58
- end
59
- end
41
+ def run_hooks_for_target(stage, target, step_name)
42
+ return if @hooks[stage].nil? || @hooks[stage].empty?
60
43
 
61
- def run_after_sequence_hooks_for_target(target)
62
- @after_sequence_hooks.each do |hook|
63
- step = Docile.dsl_eval(Step.new(target, self), &(hook.block))
44
+ @hooks[stage].each do |hook|
45
+ step = Docile.dsl_eval(Step.new(target, self, step_name), &(hook.block))
64
46
  return false if step.sequence_ended?
65
47
  end
66
48
  end
@@ -94,14 +76,16 @@ module Sequins
94
76
  Sequins::DelayWorker.set(wait_until: delay_until).perform_later(@klass.to_s, target.class.to_s, target.id, next_step.to_s)
95
77
  end
96
78
 
97
- def trigger(target)
98
- unless run_before_sequence_hooks_for_target(target)
99
- run_after_sequence_hooks_for_target(target)
79
+ def trigger(target, *args)
80
+ step_name, _ = @steps.detect { |_, s| s.options[:initial] }
81
+ raise NoInitialStepError.new unless step_name.present?
82
+
83
+ unless run_hooks_for_target(:before_sequence, target, :_before_sequence)
84
+ run_hooks_for_target(:after_sequence, target, :_after_sequence)
100
85
  return false
101
86
  end
102
87
 
103
- step_name, _ = @steps.detect { |_, s| s.options[:initial] }
104
- run_step_for_target(step_name, target)
88
+ run_step_for_target(step_name, target, *args)
105
89
  end
106
90
 
107
91
  end
@@ -11,15 +11,19 @@ module Sequins
11
11
  end
12
12
 
13
13
  def before_each_step(&block)
14
- @seq.add_before_each_step_hook(&block)
14
+ @seq.add_hook(:before_each_step, &block)
15
+ end
16
+
17
+ def after_each_step(&block)
18
+ @seq.add_hook(:after_each_step, &block)
15
19
  end
16
20
 
17
21
  def before_sequence(&block)
18
- @seq.add_before_sequence_hook(&block)
22
+ @seq.add_hook(:before_sequence, &block)
19
23
  end
20
24
 
21
25
  def after_sequence(&block)
22
- @seq.add_after_sequence_hook(&block)
26
+ @seq.add_hook(:after_sequence, &block)
23
27
  end
24
28
 
25
29
  def build
data/lib/sequins/step.rb CHANGED
@@ -1,10 +1,11 @@
1
1
  module Sequins
2
2
  class Step
3
- attr_reader :target
3
+ attr_reader :target, :step_name
4
4
 
5
- def initialize(target, sequence)
5
+ def initialize(target, sequence, step_name)
6
6
  @target = target
7
7
  @sequence = sequence
8
+ @step_name = step_name
8
9
  end
9
10
 
10
11
  def end_sequence
@@ -1,3 +1,3 @@
1
1
  module Sequins
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequins
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pete Keen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-08-23 00:00:00.000000000 Z
11
+ date: 2018-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: docile