Class: Sxn::Rules::BaseRule
- Inherits:
-
Object
- Object
- Sxn::Rules::BaseRule
- Includes:
- States
- Defined in:
- lib/sxn/rules/base_rule.rb
Overview
BaseRule is the abstract base class for all rule types in the sxn system. It defines the common interface that all rules must implement and provides shared functionality for validation, dependency management, and error handling.
Rules are the building blocks of session setup automation. They can copy files, execute commands, process templates, or perform other project initialization tasks.
Direct Known Subclasses
Defined Under Namespace
Modules: States Classes: RuleChange
Constant Summary
Constants included from States
States::APPLIED, States::APPLYING, States::FAILED, States::PENDING, States::ROLLED_BACK, States::ROLLING_BACK, States::VALIDATED, States::VALIDATING
Instance Attribute Summary collapse
-
#changes ⇒ Object
readonly
Returns the value of attribute changes.
-
#config ⇒ Object
readonly
Returns the value of attribute config.
-
#dependencies ⇒ Object
readonly
Returns the value of attribute dependencies.
-
#errors ⇒ Object
readonly
Returns the value of attribute errors.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#project_path ⇒ Object
readonly
Returns the value of attribute project_path.
-
#session_path ⇒ Object
readonly
Returns the value of attribute session_path.
-
#state ⇒ Object
readonly
Returns the value of attribute state.
Instance Method Summary collapse
-
#applied? ⇒ Boolean
Check if rule has been successfully applied.
-
#apply(context = {}) ⇒ Boolean
Apply the rule’s action This method must be overridden by subclasses to implement the actual rule logic.
-
#can_execute?(completed_rules) ⇒ Boolean
Check if this rule can be executed (all dependencies are satisfied).
-
#description ⇒ String
Get rule description.
-
#duration ⇒ Float?
Get rule execution duration in seconds.
-
#failed? ⇒ Boolean
Check if rule has failed.
-
#initialize(arg1 = nil, arg2 = nil, arg3 = nil, arg4 = nil, dependencies: []) ⇒ BaseRule
constructor
Initialize a new rule instance.
-
#required? ⇒ Boolean
Check if rule is required.
-
#rollback ⇒ Boolean
Rollback the rule’s changes This method should be overridden by subclasses to implement rollback logic.
-
#rollbackable? ⇒ Boolean
Check if rule can be rolled back.
-
#to_h ⇒ Hash
Get a hash representation of the rule for serialization.
-
#type ⇒ String
Get rule type.
-
#validate ⇒ Boolean
Validate the rule configuration and dependencies This method should be overridden by subclasses to implement specific validation logic.
-
#validate_config_hash(config = @config) ⇒ Boolean
Validate rule configuration (public method expected by tests).
Constructor Details
#initialize(arg1 = nil, arg2 = nil, arg3 = nil, arg4 = nil, dependencies: []) ⇒ BaseRule
Initialize a new rule instance
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 |
# File 'lib/sxn/rules/base_rule.rb', line 53 def initialize(arg1 = nil, arg2 = nil, arg3 = nil, arg4 = nil, dependencies: []) # Handle both old and new initialization formats if (arg1.is_a?(String) || arg1.nil?) && arg2.is_a?(Hash) && arg3.is_a?(String) && arg4.is_a?(String) # Old format: (name, config, project_path, session_path, dependencies: []) @name = arg1 || "base_rule" @config = arg2.dup.freeze @project_path = File.realpath(arg3) @session_path = File.realpath(arg4) elsif arg1.is_a?(Hash) && arg2.is_a?(String) && arg3.is_a?(String) # Special format: (config, project_path, session_path, name) @name = arg4 || "base_rule" @config = arg1.dup.freeze @project_path = File.realpath(arg2) @session_path = File.realpath(arg3) elsif arg1.is_a?(String) && arg2.is_a?(String) # New format: (project_path, session_path, config = {}, dependencies: []) @name = "base_rule" # Store the config as-is for validation, only freeze if it's a Hash @config = if arg3.nil? {}.freeze elsif arg3.is_a?(Hash) arg3.dup.freeze else # Store non-hash config as-is for validation to catch arg3 end @project_path = File.realpath(arg1) @session_path = File.realpath(arg2) else raise ArgumentError, "Invalid arguments. Expected (name, config, project_path, session_path) or (project_path, session_path, config={})" end @dependencies = dependencies.freeze @state = PENDING @changes = [] @errors = [] @start_time = nil @end_time = nil validate_paths! rescue Errno::ENOENT => e raise ArgumentError, "Invalid path provided: #{e.message}" end |
Instance Attribute Details
#changes ⇒ Object (readonly)
Returns the value of attribute changes.
44 45 46 |
# File 'lib/sxn/rules/base_rule.rb', line 44 def changes @changes end |
#config ⇒ Object (readonly)
Returns the value of attribute config.
44 45 46 |
# File 'lib/sxn/rules/base_rule.rb', line 44 def config @config end |
#dependencies ⇒ Object (readonly)
Returns the value of attribute dependencies.
44 45 46 |
# File 'lib/sxn/rules/base_rule.rb', line 44 def dependencies @dependencies end |
#errors ⇒ Object (readonly)
Returns the value of attribute errors.
44 45 46 |
# File 'lib/sxn/rules/base_rule.rb', line 44 def errors @errors end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
44 45 46 |
# File 'lib/sxn/rules/base_rule.rb', line 44 def name @name end |
#project_path ⇒ Object (readonly)
Returns the value of attribute project_path.
44 45 46 |
# File 'lib/sxn/rules/base_rule.rb', line 44 def project_path @project_path end |
#session_path ⇒ Object (readonly)
Returns the value of attribute session_path.
44 45 46 |
# File 'lib/sxn/rules/base_rule.rb', line 44 def session_path @session_path end |
#state ⇒ Object (readonly)
Returns the value of attribute state.
44 45 46 |
# File 'lib/sxn/rules/base_rule.rb', line 44 def state @state end |
Instance Method Details
#applied? ⇒ Boolean
Check if rule has been successfully applied
202 203 204 |
# File 'lib/sxn/rules/base_rule.rb', line 202 def applied? @state == APPLIED end |
#apply(context = {}) ⇒ Boolean
Apply the rule’s action This method must be overridden by subclasses to implement the actual rule logic
126 127 128 |
# File 'lib/sxn/rules/base_rule.rb', line 126 def apply(context = {}) raise NotImplementedError, "#{self.class} must implement #apply" end |
#can_execute?(completed_rules) ⇒ Boolean
Check if this rule can be executed (all dependencies are satisfied)
155 156 157 |
# File 'lib/sxn/rules/base_rule.rb', line 155 def can_execute?(completed_rules) @dependencies.all? { |dep| completed_rules.include?(dep) } end |
#description ⇒ String
Get rule description
195 196 197 |
# File 'lib/sxn/rules/base_rule.rb', line 195 def description "Base rule for #{type} operations" end |
#duration ⇒ Float?
Get rule execution duration in seconds
162 163 164 165 166 |
# File 'lib/sxn/rules/base_rule.rb', line 162 def duration return nil unless @start_time && @end_time @end_time - @start_time end |
#failed? ⇒ Boolean
Check if rule has failed
209 210 211 |
# File 'lib/sxn/rules/base_rule.rb', line 209 def failed? @state == FAILED end |
#required? ⇒ Boolean
Check if rule is required
178 179 180 |
# File 'lib/sxn/rules/base_rule.rb', line 178 def required? true end |
#rollback ⇒ Boolean
Rollback the rule’s changes This method should be overridden by subclasses to implement rollback logic
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/sxn/rules/base_rule.rb', line 135 def rollback return true if @state == PENDING || @state == FAILED change_state!(ROLLING_BACK) begin rollback_changes! change_state!(ROLLED_BACK) true rescue StandardError => e @errors << e change_state!(FAILED) raise Sxn::Rules::RollbackError, "Failed to rollback rule #{@name}: #{e.message}" end end |
#rollbackable? ⇒ Boolean
Check if rule can be rolled back
216 217 218 |
# File 'lib/sxn/rules/base_rule.rb', line 216 def rollbackable? @state == APPLIED && @changes.any? end |
#to_h ⇒ Hash
Get a hash representation of the rule for serialization
223 224 225 226 227 228 229 230 231 232 233 234 235 |
# File 'lib/sxn/rules/base_rule.rb', line 223 def to_h { name: @name, type: self.class.name.split("::").last, state: @state, config: @config, dependencies: @dependencies, changes: @changes.map(&:to_h), errors: @errors.map(&:message), duration: duration, applied_at: @end_time&.iso8601 } end |
#type ⇒ String
Get rule type
171 172 173 |
# File 'lib/sxn/rules/base_rule.rb', line 171 def type self.class.name.split("::").last.downcase.gsub(/rule$/, "") end |
#validate ⇒ Boolean
Validate the rule configuration and dependencies This method should be overridden by subclasses to implement specific validation logic
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/sxn/rules/base_rule.rb', line 103 def validate change_state!(VALIDATING) begin validate_config! validate_dependencies! validate_rule_specific! change_state!(VALIDATED) true rescue StandardError => e @errors << e change_state!(FAILED) raise end end |
#validate_config_hash(config = @config) ⇒ Boolean
Validate rule configuration (public method expected by tests)
186 187 188 189 190 |
# File 'lib/sxn/rules/base_rule.rb', line 186 def validate_config_hash(config = @config) return true if config.nil? || config.empty? config.is_a?(Hash) end |