Class: Sxn::Rules::RulesEngine
- Inherits:
-
Object
- Object
- Sxn::Rules::RulesEngine
- Defined in:
- lib/sxn/rules/rules_engine.rb
Overview
RulesEngine manages the loading, validation, dependency resolution, and execution of project setup rules. It provides transactional execution with rollback capabilities and supports parallel execution of independent rules.
Defined Under Namespace
Classes: ExecutionResult
Constant Summary collapse
- RULE_TYPES =
Rule type registry mapping type names to classes
{ "copy_files" => CopyFilesRule, "setup_commands" => SetupCommandsRule, "template" => TemplateRule }.freeze
Instance Attribute Summary collapse
-
#logger ⇒ Object
readonly
Returns the value of attribute logger.
-
#project_path ⇒ Object
readonly
Returns the value of attribute project_path.
-
#session_path ⇒ Object
readonly
Returns the value of attribute session_path.
Instance Method Summary collapse
-
#apply_rules(rules_config, options = {}) ⇒ ExecutionResult
Apply a set of rules with dependency resolution and parallel execution.
-
#available_rule_types ⇒ Array<String>
Get available rule types.
-
#initialize(project_path, session_path, logger: nil) ⇒ RulesEngine
constructor
Initialize the rules engine.
-
#rollback_rules ⇒ Boolean
Rollback all applied rules in reverse order.
-
#validate_rules_config(rules_config) ⇒ Array<BaseRule>
Validate rules configuration without executing.
-
#validate_rules_strict(rules) ⇒ Object
Strict validation that raises errors on any validation failure.
Constructor Details
#initialize(project_path, session_path, logger: nil) ⇒ RulesEngine
Initialize the rules engine
112 113 114 115 116 117 118 119 120 121 |
# File 'lib/sxn/rules/rules_engine.rb', line 112 def initialize(project_path, session_path, logger: nil) @project_path = File.realpath(project_path) @session_path = File.realpath(session_path) @logger = logger || Sxn.logger @applied_rules = [] validate_paths! rescue Errno::ENOENT => e raise ArgumentError, "Invalid path provided: #{e.message}" end |
Instance Attribute Details
#logger ⇒ Object (readonly)
Returns the value of attribute logger.
105 106 107 |
# File 'lib/sxn/rules/rules_engine.rb', line 105 def logger @logger end |
#project_path ⇒ Object (readonly)
Returns the value of attribute project_path.
105 106 107 |
# File 'lib/sxn/rules/rules_engine.rb', line 105 def project_path @project_path end |
#session_path ⇒ Object (readonly)
Returns the value of attribute session_path.
105 106 107 |
# File 'lib/sxn/rules/rules_engine.rb', line 105 def session_path @session_path end |
Instance Method Details
#apply_rules(rules_config, options = {}) ⇒ ExecutionResult
Apply a set of rules with dependency resolution and parallel execution
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 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/sxn/rules/rules_engine.rb', line 132 def apply_rules(rules_config, = {}) = .merge() result = ExecutionResult.new result.start! begin # Load and validate all rules all_rules = load_rules(rules_config) valid_rules = validate_rules(all_rules) # Track skipped rules (those that failed validation) skipped_rules = all_rules - valid_rules skipped_rules.each do |rule| result.add_skipped_rule(rule, "Failed validation") end return result.tap(&:finish!) if [:validate_only] # Resolve execution order based on dependencies execution_order = resolve_execution_order(valid_rules) @logger&.info("Executing #{valid_rules.size} rules in #{execution_order.size} phases") # Execute rules in phases (each phase can run in parallel) execution_order.each_with_index do |phase_rules, phase_index| execute_phase(phase_rules, phase_index, result, ) # Stop if we have failures and not continuing on failure break if ![:continue_on_failure] && !result.failed_rules.empty? end rescue ValidationError => e @logger&.error("Rules validation error: #{e.message}") raise rescue StandardError => e @logger&.error("Rules engine error: #{e.message}") result.add_engine_error(e) ensure result.finish! end result end |
#available_rule_types ⇒ Array<String>
Get available rule types
226 227 228 |
# File 'lib/sxn/rules/rules_engine.rb', line 226 def available_rule_types RULE_TYPES.keys end |
#rollback_rules ⇒ Boolean
Rollback all applied rules in reverse order
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/sxn/rules/rules_engine.rb', line 178 def rollback_rules return true if @applied_rules.empty? @logger&.info("Rolling back #{@applied_rules.size} applied rules") @applied_rules.reverse_each do |rule| if rule.rollbackable? rule.rollback @logger&.debug("Rolled back rule: #{rule.name}") else @logger&.debug("Rule not rollbackable: #{rule.name}") end rescue StandardError => e @logger&.error("Failed to rollback rule #{rule.name}: #{e.message}") end @applied_rules.clear true end |
#validate_rules_config(rules_config) ⇒ Array<BaseRule>
Validate rules configuration without executing
202 203 204 205 206 |
# File 'lib/sxn/rules/rules_engine.rb', line 202 def validate_rules_config(rules_config) all_rules = load_rules(rules_config) validate_rules_strict(all_rules) all_rules end |
#validate_rules_strict(rules) ⇒ Object
Strict validation that raises errors on any validation failure
209 210 211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/sxn/rules/rules_engine.rb', line 209 def validate_rules_strict(rules) rules.each do |rule| rule.validate rescue StandardError => e raise ValidationError, "Rule '#{rule.name}' validation failed: #{e.message}" end # Validate dependencies exist validate_dependencies(rules) # Check for circular dependencies check_circular_dependencies(rules) end |