Module: Saxxy::Activatable

Included in:
Context, Event
Defined in:
lib/saxxy/activatable.rb

Overview

Activatable contains all the logic for handling the activation of an object, whether this is a Context or an Event or any object that needs to be activated / deactivated multiple times.

Any Activatable object needs to possess an activation_rule (assuming automatic activation if activation_rule is nil) in order to use this to activate / deactivate the object. Everytime the activation_rule matches an opening node the object gets activated (by incrementing the internal @deactivation_level) and can be activated many times. Everytime the activation_rule matches a closing node the object gets deactivated (by decrementing the internal An Activatable object is considered inactive when it's @deactivation_level equals DLEVEL_MIN i.e. when it has been deactivated as many times as it has been activated.

Author:

  • rubymaniac

Constant Summary collapse

DLEVEL_MIN =

The lowest integer the deactivation level can reach before the object is considered inactive.

-1

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#activation_ruleNodeRule (readonly)


26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/saxxy/activatable.rb', line 26

module Activatable

  # The lowest integer the deactivation level can reach before the object
  # is considered inactive.
  #
  DLEVEL_MIN = -1

  # Sets an attribute reader to the receiver for the
  # activation rule.
  #
  def self.included(receiver)
    receiver.send(:attr_reader, :activation_rule)
  end

  # Initiates the activatable by setting the activation_rule to the
  # argument, setting the deactivation_level to DLEVEL_MIN and it's
  # state to inactive
  #
  # @param rule [NodeRule] an instance of NodeRule or nil to
  #   declare that this object is automatically active.
  #
  # @return [Symbol] its state (active or inactive)
  #
  def initialize_activatable(rule)
    @activation_rule = rule
    @deactivation_level = DLEVEL_MIN
    switch_to(rule ? :inactive : :active)
  end

  # Sets the callback to run when this object gets deactivated
  #
  # @param block [Proc] the code to be executed upon deactivation
  #
  # @return self
  #
  def on_deactivation(&block)
    @deactivation_callback = block
    self
  end

  # Sets the callback to run when this object gets activated
  #
  # @param block [Proc] the code to be executed upon activation
  #
  # @return self
  #
  def on_activation(&block)
    @activation_callback = block
    self
  end

  # Activates the object on an opening node if it is inactive and can be
  # activated on the node or it increments the @deactivation_level
  # if the activation_rule matches the element_name
  #
  # @param element_name [String] the nodes' element name
  # @param attributes [Hash<String, String>] the nodes' attributes
  #
  # @return self
  #
  def activate_on(element_name, attributes)
    if is(:inactive) && can_be_activated_on(element_name, attributes)
      activate!
    elsif is(:active) && rule_matches_element_name(element_name)
      increment_level
    end
    self
  end

  # Deactivates the object on a closing node. If the object is inactive
  # it does nothing, otherwise it decrements the @deactivation_level if
  # the activation_rule matches the element_name and deactivates the object
  # if the @deactivation_level is DLEVEL_MIN.
  #
  # @param element_name [String] the nodes' element name
  #
  # @return self
  #
  def deactivate_on(element_name)
    return unless is(:active)
    decrement_level if rule_matches_element_name(element_name)
    deactivate! if closed?
    self
  end

  private
  def activate!
    run_activation_callback
    increment_level
    switch_to(:active)
  end

  def deactivate!
    run_deactivation_callback
    switch_to(:inactive)
  end

  def is(mode)
    @mode == mode
  end

  def switch_to(mode)
    @mode = mode
  end

  def closed?
    @deactivation_level == DLEVEL_MIN
  end

  def increment_level
    @deactivation_level += 1
  end

  def decrement_level
    @deactivation_level -= 1
  end

  def run_activation_callback
    @activation_callback.call(self) if @activation_callback
  end

  def run_deactivation_callback
    @deactivation_callback.call(self) if @deactivation_callback
  end

  def rule_matches_element_name(element_name)
    activation_rule.nil? || activation_rule.match_element_name(element_name)
  end

  def can_be_activated_on(element_name, attributes)
    (activation_rule.nil? || activation_rule.matches(element_name, attributes)) && closed?
  end
end

Class Method Details

.included(receiver) ⇒ Object

Sets an attribute reader to the receiver for the activation rule.


36
37
38
# File 'lib/saxxy/activatable.rb', line 36

def self.included(receiver)
  receiver.send(:attr_reader, :activation_rule)
end

Instance Method Details

#activate_on(element_name, attributes) ⇒ Object

Activates the object on an opening node if it is inactive and can be activated on the node or it increments the @deactivation_level if the activation_rule matches the element_name


86
87
88
89
90
91
92
93
# File 'lib/saxxy/activatable.rb', line 86

def activate_on(element_name, attributes)
  if is(:inactive) && can_be_activated_on(element_name, attributes)
    activate!
  elsif is(:active) && rule_matches_element_name(element_name)
    increment_level
  end
  self
end

#deactivate_on(element_name) ⇒ Object

Deactivates the object on a closing node. If the object is inactive it does nothing, otherwise it decrements the @deactivation_level if the activation_rule matches the element_name and deactivates the object if the @deactivation_level is DLEVEL_MIN.


104
105
106
107
108
109
# File 'lib/saxxy/activatable.rb', line 104

def deactivate_on(element_name)
  return unless is(:active)
  decrement_level if rule_matches_element_name(element_name)
  deactivate! if closed?
  self
end

#initialize_activatable(rule) ⇒ Symbol

Initiates the activatable by setting the activation_rule to the argument, setting the deactivation_level to DLEVEL_MIN and it's state to inactive


49
50
51
52
53
# File 'lib/saxxy/activatable.rb', line 49

def initialize_activatable(rule)
  @activation_rule = rule
  @deactivation_level = DLEVEL_MIN
  switch_to(rule ? :inactive : :active)
end

#on_activation(&block) ⇒ Object

Sets the callback to run when this object gets activated


72
73
74
75
# File 'lib/saxxy/activatable.rb', line 72

def on_activation(&block)
  @activation_callback = block
  self
end

#on_deactivation(&block) ⇒ Object

Sets the callback to run when this object gets deactivated


61
62
63
64
# File 'lib/saxxy/activatable.rb', line 61

def on_deactivation(&block)
  @deactivation_callback = block
  self
end