Class: Pvectl::Selectors::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/pvectl/selectors/base.rb,
sig/pvectl/selectors/base.rbs

Overview

Base class for parsing and applying selectors.

Selectors use kubectl-style syntax to filter resources:

-l key=value        # equality
-l key!=value       # inequality
-l key=~pattern     # wildcard pattern
-l key in (a,b,c)   # one of many

Examples:

Parsing selectors

selector = Base.parse("status=running,tags=prod")
selector.conditions
#=> [{field: "status", operator: :eq, value: "running"},
#    {field: "tags", operator: :eq, value: "prod"}]

Applying selectors (subclass responsibility)

selector = Vm.parse("status=running")
filtered = selector.apply(vms)

Direct Known Subclasses

Container, Disk, Vm, Volume

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(conditions = []) ⇒ Base

Creates selector with parsed conditions.



48
49
50
# File 'lib/pvectl/selectors/base.rb', line 48

def initialize(conditions = [])
  @conditions = conditions
end

Instance Attribute Details

#conditionsArray<Hash> (readonly)

Parsed conditions



26
27
28
# File 'lib/pvectl/selectors/base.rb', line 26

def conditions
  @conditions
end

Class Method Details

.parse(selector_string) ⇒ Base

Parses selector string into Base instance.



32
33
34
# File 'lib/pvectl/selectors/base.rb', line 32

def self.parse(selector_string)
  new(parse_conditions(selector_string))
end

.parse_all(selector_strings) ⇒ Base

Parses multiple selector strings (from multiple -l flags).



40
41
42
43
# File 'lib/pvectl/selectors/base.rb', line 40

def self.parse_all(selector_strings)
  conditions = selector_strings.flat_map { |s| parse_conditions(s) }
  new(conditions)
end

Instance Method Details

#apply(collection) ⇒ Array

Applies selector to collection (subclass responsibility).

Raises:

  • (NotImplementedError)

    if not implemented by subclass



64
65
66
# File 'lib/pvectl/selectors/base.rb', line 64

def apply(collection)
  raise NotImplementedError, "#{self.class}#apply must be implemented"
end

#compare_value(actual, operator, expected) ⇒ Boolean

Compares actual value against expected using operator.



105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/pvectl/selectors/base.rb', line 105

def compare_value(actual, operator, expected)
  case operator
  when :eq
    actual.to_s == expected.to_s
  when :neq
    actual.to_s != expected.to_s
  when :match
    wildcard_match?(actual.to_s, expected.to_s)
  when :in
    expected.any? { |v| actual.to_s == v.to_s }
  else
    false
  end
end

#empty?Boolean

Checks if selector is empty (no conditions).



55
56
57
# File 'lib/pvectl/selectors/base.rb', line 55

def empty?
  @conditions.empty?
end

#extract_value(item, field) ⇒ Object

Extracts field value from item (subclass responsibility).

Raises:

  • (NotImplementedError)

    if not implemented by subclass



95
96
97
# File 'lib/pvectl/selectors/base.rb', line 95

def extract_value(item, field)
  raise NotImplementedError, "#{self.class}#extract_value must be implemented"
end

#match_condition?(item, condition) ⇒ Boolean

Checks if item matches a single condition. Subclasses should override to extract field values from items.



84
85
86
87
# File 'lib/pvectl/selectors/base.rb', line 84

def match_condition?(item, condition)
  actual_value = extract_value(item, condition[:field])
  compare_value(actual_value, condition[:operator], condition[:value])
end

#matches?(item) ⇒ Boolean

Checks if a single item matches all conditions.



72
73
74
# File 'lib/pvectl/selectors/base.rb', line 72

def matches?(item)
  @conditions.all? { |cond| match_condition?(item, cond) }
end

#wildcard_match?(value, pattern) ⇒ Boolean

Matches string against wildcard pattern. Converts * to regex .* for matching.



126
127
128
129
# File 'lib/pvectl/selectors/base.rb', line 126

def wildcard_match?(value, pattern)
  regex = Regexp.new("\\A" + Regexp.escape(pattern).gsub("\\*", ".*") + "\\z")
  regex.match?(value)
end