require_relative './util/stdio' require_relative './util/interop' require_relative './util/bundler' require 'nrser' using NRSER module QB module Util # split a string into 'words' for word-based matching def self.words string string.split(/[\W_\-\/]+/).reject {|w| w.empty?} end # .words # see if words from an input match words def self.words_start_with? full_string, input # QB.debug "does #{ input } match #{ full_string }?" input_words = words input # short-circuit if there are no input words ('./' for example) return false if input_words.empty? full_string_words = words full_string QB.debug "HERE", input_words: input_words, full_string_words: full_string_words full_string_words.each_with_index {|word, start_index| # compute the end index in full_string_words end_index = start_index + input_words.length - 1 # short-circuit if can't match (more input words than full words left) if end_index >= full_string_words.length return false end # create the slice to test against slice = full_string_words[start_index..end_index] # see if every word in the slice starts with the corresponding word # in the input if slice.zip(input_words).all? {|full_word, input_word| full_word.start_with? input_word } # got a match! return true end } # no match false end # .match_words? # @return [Pathname] absolute resolved path. def self.resolve *segments joined = Pathname.new '' ([Dir.pwd] + segments).reverse.each_with_index {|segment, index| joined = Pathname.new(segment).join joined return joined if joined.absolute? } # shouldn't ever happen raise "resolution failed: #{ segments.inspect }" end # do kind of the opposite of File.expand_path -- turn the home dir into ~ # and the current dir into . # # @param [Pathname | String] # path to contract. # # @return [Pathname] # contracted path. # def self.contract_path path contracted = if path.start_with? Dir.pwd path.sub Dir.pwd, '.' elsif path.start_with? ENV['HOME'] path.sub ENV['HOME'], '~' else path end Pathname.new contracted end # find `filename` in `from` or closest parent directory. # # @param [String] filename # name of file to search for. # # @param [Pathname] from (Pathname.pwd) # directory to start from. # # @param [Boolean] raise_on_not_found: # When `true`, a {QB::FSStateError} will be raised if no file is found # (default behavior). # # This is something of a legacy behavior - I think it would be better # to have {find_up} return `nil` in that case and add a `find_up!` # method that raises on not found. But I'm not going to do it right now. # # @return [Pathname] # Pathname of found file. # # @return [nil] # If no file is found and the `raise_on_not_found` option is `false`. # # @raise [QB::FSStateError] # If file is not found in `from` or any of it's parent directories # and the `raise_on_not_found` option is `true` (default behavior). # def self.find_up filename, from = Pathname.pwd, raise_on_not_found: true path = from + filename return from if path.exist? parent = from.parent if from == parent if raise_on_not_found raise "not found in current or any parent directories: #{ filename }" else return nil end end return find_up filename, parent, raise_on_not_found: raise_on_not_found end # .find_up end # Util end # QB