# frozen_string_literal: true # Definitions # ======================================================================= # Abstract base class for patterns used to match {Locd::Agent} instances. # class Locd::Pattern # Factory method to construct the correct concrete subclass. # # @param [String | Locd::Pattern] object # 1. {String} - a new pattern will be constructed. # 2. {Locd::Pattern} - will just be returned. # # @param [Hash] options # Options that will be passed to the concrete class constructor when # `object` is a string. # # @option options [Boolean] full: # When `true`, pattern must match entire labels. # # When `false`, pattern may match any portion of label. # # Label patterns only. # # @option options [Boolean] ignore_case: # Case-insensitive match (label patterns only). # # @option options [Boolean] recursive: # Additionally match agents with `workdir` in subdirectories (workdir # patterns only). # # @option options [String | Pathname] cwd: # Current working directory to base relative paths from (workdir patterns # only). # # @return [Locd::Pattern::Label | Locd::Pattern::Workdir] # Pattern instance. # def self.from object, **options case object when String string = object case string when '' raise ArgumentError, "Empty string is not a valid pattern" when /\A[\.\~\/]/ Locd::Pattern::Workdir.new string, **options else Locd::Pattern::Label.new string, **options end when Locd::Pattern object else raise TypeError.new binding.erb <<-END Expected `object` to be {String} or {Locd::Pattern}, found <%= object.class %> `object` (first argument): <%= object.pretty_inspect %> Options: <%= options.pretty_inspect %> END end end # .from # Raw source string provided at initialization. # # @return [String] # attr_reader :source # Construct a new pattern. Should only be called via `super`. # # @param [String] source # Raw source string the pattern is built off. # def initialize source @source = source end # #initialize # @raise [NRSER::AbstractMethodError] # Abstract method, concrete subclasses must implement. # def match? agent raise NRSER::AbstractMethodError.new( self, __method__ ) end # #match? end # class Locd::Pattern # A {Locd::Pattern} that matches against {Locd::Agent} labels with "glob-style" # matching (like the [lunchy](https://rubygems.org/gems/lunchy) gem). # # **_Right now only handles the `*` wildcard!_** # # @see Locd::Label.regexp_for_glob # class Locd::Pattern::Label < Locd::Pattern # TODO document `string` attribute. # # @return [attr_type] # attr_reader :string # Label {Regexp} used by {#match?} # # @return [Regexp] # attr_reader :regexp # Instantiate a new `Locd::Pattern::Label`. # # @param [String] source # "Glob-style" pattern to search for in {Locd::Agent#label} strings. # # @param [Boolean] full: # When `true`, pattern must match entire label. # # When `false` (default), may match any portion. # # @param [Boolean] ignore_case: # Perform case-insensitive matching. # def initialize source, full: false, ignore_case: false super source @regexp = Locd::Label.regexp_for_glob source, full: full, ignore_case: ignore_case end # #initialize # See if this patten matches an agent. # # @param [Locd::Agent] agent # Agent to test against. # # @return [Boolean] # `true` if this pattern matches the `agent` {Locd::Agent#label}. # def match? agent agent.label =~ regexp end # #match? end # class Locd::Pattern::Label # A {Locd::Pattern} that matches against {Locd::Agent} workdir. # class Locd::Pattern::Workdir < Locd::Pattern # "Current" absolute directory path that a relative {#raw_path} would have # been expanded against. # # @return [Pathname] # attr_reader :cwd # When `true`, pattern will additionally match any agents who's # {Locd::Agent#workdir} is a subdirectory of the {#path}. # # @return [Boolean] # attr_reader :recursive # Expanded absolute path to test {Locd::Agent#workdir} against. # # @return [Pathname] # attr_reader :path # Instantiate a new `Locd::Pattern::Workdir`. # # @param [String] raw_path # Path to construct for, which may be relative to `cwd`. # # @param [Boolean] recursive: # Additionally match agents with `workdir` in subdirectories. # # See {#recursive}. # # @param [String | Pathname] cwd: # Directory to expand relative paths against. # def initialize source, recursive: false, cwd: Pathname.getwd super source @cwd = cwd.to_pn @recursive = recursive @path = Pathname.new( source ).expand_path @cwd end # #initialize # See if this patten matches an agent. # # @param [Locd::Agent] agent # Agent to test against. # # @return [Boolean] # `true` if this pattern matches the `agent` {Locd::Agent#label}. # def match? agent if recursive agent.workdir.to_s.start_with?( path.to_s + '/' ) else agent.workdir == path end end # #match? end # class Locd::Pattern::Label