Class: StimulusPlumbers::Password::Requirements
- Inherits:
-
Object
- Object
- StimulusPlumbers::Password::Requirements
- Defined in:
- lib/stimulus_plumbers/password/requirements.rb
Overview
Declarative password rule set: DSL + evaluation + serialization. Consumed by the form renderer, PasswordStrengthValidator, and the JS controller (via to_stimulus).
Constant Summary collapse
- LEVEL_KEYS =
%i[weak fine strong].freeze
- BUILTIN_KEYS =
%i[length uppercase lowercase digit symbol].freeze
- DEFAULT_THRESHOLDS =
{ low: 34, high: 100, optimum: 100 }.freeze
- BUILTIN_PATTERNS =
{ uppercase: "[A-Z]", lowercase: "[a-z]", digit: "\\d", symbol: "[^A-Za-z0-9]" }.freeze
Class Method Summary collapse
Instance Method Summary collapse
-
#active? ⇒ Boolean
Any rule present — built-ins (only when enforced?) or a custom rule.
- #enforce(**options) ⇒ Object
- #enforced? ⇒ Boolean
- #evaluate(password) ⇒ Object
-
#initialize ⇒ Requirements
constructor
A new instance of Requirements.
- #rule(key, label = nil, pattern: nil, min: nil, max: nil, negate: false) ⇒ Object
- #rules ⇒ Object
- #thresholds ⇒ Object
- #to_stimulus ⇒ Object
- #valid?(password) ⇒ Boolean
Constructor Details
#initialize ⇒ Requirements
Returns a new instance of Requirements.
25 26 27 28 29 |
# File 'lib/stimulus_plumbers/password/requirements.rb', line 25 def initialize @enforced_options = nil @custom = {} @overrides = {} end |
Class Method Details
.build ⇒ Object
20 21 22 |
# File 'lib/stimulus_plumbers/password/requirements.rb', line 20 def build new.tap { |req| yield req if block_given? } end |
Instance Method Details
#active? ⇒ Boolean
Any rule present — built-ins (only when enforced?) or a custom rule. Drives whether the form renders the strength UI; enforced? alone misses custom-only rule sets.
58 59 60 |
# File 'lib/stimulus_plumbers/password/requirements.rb', line 58 def active? descriptors.any? end |
#enforce(**options) ⇒ Object
31 32 33 34 |
# File 'lib/stimulus_plumbers/password/requirements.rb', line 31 def enforce(**) @enforced_options = nil end |
#enforced? ⇒ Boolean
52 53 54 |
# File 'lib/stimulus_plumbers/password/requirements.rb', line 52 def enforced? !@enforced_options.nil? end |
#evaluate(password) ⇒ Object
70 71 72 73 74 75 |
# File 'lib/stimulus_plumbers/password/requirements.rb', line 70 def evaluate(password) password = password.to_s results = descriptors.to_h { |descriptor| [descriptor[:key], satisfies?(descriptor, password)] } satisfied = results.values.count(true) { rules: results, value: score(satisfied, results.size), level: level_for(satisfied, results.size) } end |
#rule(key, label = nil, pattern: nil, min: nil, max: nil, negate: false) ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/stimulus_plumbers/password/requirements.rb', line 36 def rule(key, label = nil, pattern: nil, min: nil, max: nil, negate: false) key = key.to_sym if pattern if negate min = 0 max = 0 end @custom[key] = { pattern: source_of(pattern), min: min.nil? ? 1 : min, max: max, label: label } else raise ArgumentError, (key) unless BUILTIN_KEYS.include?(key) @overrides[key] = label end nil end |
#rules ⇒ Object
62 63 64 |
# File 'lib/stimulus_plumbers/password/requirements.rb', line 62 def rules descriptors.to_h { |descriptor| [descriptor[:key], descriptor[:label]] } end |
#thresholds ⇒ Object
66 67 68 |
# File 'lib/stimulus_plumbers/password/requirements.rb', line 66 def thresholds DEFAULT_THRESHOLDS.merge((@enforced_options || {}).slice(*DEFAULT_THRESHOLDS.keys)) end |
#to_stimulus ⇒ Object
82 83 84 |
# File 'lib/stimulus_plumbers/password/requirements.rb', line 82 def to_stimulus { rules: descriptors.map { |descriptor| serialize(descriptor) }, options: , labels: level_labels } end |
#valid?(password) ⇒ Boolean
77 78 79 80 |
# File 'lib/stimulus_plumbers/password/requirements.rb', line 77 def valid?(password) result = evaluate(password) result[:rules].any? && result[:rules].values.all? end |