class CheckPlease::Path
TODO: this class is getting a bit large; maybe split out some of the stuff that uses flags?
Constants
- SEPARATOR
Attributes
segments[R]
to_s[R]
Public Class Methods
new(name_or_segments = [])
click to toggle source
# File lib/check_please/path.rb, line 17 def initialize(name_or_segments = []) case name_or_segments when String, Symbol, Numeric, nil string = name_or_segments.to_s if string =~ %r(//) raise InvalidPath, "paths cannot have empty segments" end names = string.split(SEPARATOR) names.shift until names.empty? || names.first =~ /\S/ segments = PathSegment.reify(names) when Array segments = PathSegment.reify(name_or_segments) else raise InvalidPath, "not sure what to do with #{name_or_segments.inspect}" end @segments = Array(segments) @to_s = SEPARATOR + @segments.join(SEPARATOR) freeze rescue InvalidPathSegment => e raise InvalidPath, e.message end
root()
click to toggle source
# File lib/check_please/path.rb, line 10 def self.root new('/') end
Public Instance Methods
+(new_basename)
click to toggle source
# File lib/check_please/path.rb, line 42 def +(new_basename) new_segments = self.segments.dup new_segments << new_basename # don't reify here; it'll get done on Path#initialize self.class.new(new_segments) end
==(other)
click to toggle source
# File lib/check_please/path.rb, line 48 def ==(other) self.to_s == other.to_s end
ancestors()
click to toggle source
# File lib/check_please/path.rb, line 52 def ancestors list = [] p = self loop do break if p.root? p = p.parent list.unshift p end list.reverse end
basename()
click to toggle source
# File lib/check_please/path.rb, line 63 def basename segments.last.to_s end
depth()
click to toggle source
# File lib/check_please/path.rb, line 67 def depth 1 + segments.length end
excluded?(flags)
click to toggle source
# File lib/check_please/path.rb, line 71 def excluded?(flags) return false if root? # that would just be silly return true if too_deep?(flags) return true if explicitly_excluded?(flags) return true if implicitly_excluded?(flags) false end
inspect()
click to toggle source
# File lib/check_please/path.rb, line 81 def inspect "<#{self.class.name} '#{to_s}'>" end
key_to_match_by(flags)
click to toggle source
# File lib/check_please/path.rb, line 85 def key_to_match_by(flags) key_exprs = unpack_key_exprs(flags.match_by_key) # NOTE: match on parent because if self.to_s == '/foo', MBK '/foo/:id' should return 'id' matches = key_exprs.select { |e| e.parent.match?(self) } case matches.length when 0 ; nil when 1 ; matches.first.segments.last.key else ; raise "More than one match_by_key expression for path '#{self}': #{matches.map(&:to_s).inspect}" end end
match?(path_or_string)
click to toggle source
# File lib/check_please/path.rb, line 101 def match?(path_or_string) # If the strings are literally equal, we're good.. return true if self == path_or_string # Otherwise, compare segments: do we have the same number, and do they all #match? other = reify(path_or_string) return false if other.depth != self.depth seg_pairs = self.segments.zip(other.segments) seg_pairs.all? { |a, b| a.match?(b) } end
match_by_value?(flags)
click to toggle source
# File lib/check_please/path.rb, line 97 def match_by_value?(flags) flags.match_by_value.any? { |e| e.match?(self) } end
parent()
click to toggle source
# File lib/check_please/path.rb, line 113 def parent return nil if root? # TODO: consider the Null Object pattern self.class.new(segments[0..-2]) end
root?()
click to toggle source
# File lib/check_please/path.rb, line 118 def root? @segments.empty? end
Private Instance Methods
ancestor_on_list?(paths)
click to toggle source
O(n^2) check to see if any of the path's ancestors are on a list (as of this writing, this should never actually happen, but I'm being thorough)
# File lib/check_please/path.rb, line 126 def ancestor_on_list?(paths) paths.any? { |path| ancestors.any? { |ancestor| ancestor.match?(path) } } end
explicitly_excluded?(flags)
click to toggle source
# File lib/check_please/path.rb, line 132 def explicitly_excluded?(flags) return false if flags.reject_paths.empty? return true if self_on_list?(flags.reject_paths) return true if ancestor_on_list?(flags.reject_paths) false end
implicitly_excluded?(flags)
click to toggle source
# File lib/check_please/path.rb, line 139 def implicitly_excluded?(flags) return false if flags.select_paths.empty? return false if self_on_list?(flags.select_paths) return false if ancestor_on_list?(flags.select_paths) true end
key_exprs()
click to toggle source
A path of “/foo/:id/bar/:name” has two key expressions:
-
“/foo/:id”
-
“/foo/:id/bar/:name”
# File lib/check_please/path.rb, line 149 def key_exprs ( [self] + ancestors ) .reject { |path| path.root? } .select { |path| path.segments.last&.key_expr? } end
self_on_list?(paths)
click to toggle source
O(n) check to see if the path itself is on a list
# File lib/check_please/path.rb, line 156 def self_on_list?(paths) paths.any? { |path| self.match?(path) } end
too_deep?(flags)
click to toggle source
# File lib/check_please/path.rb, line 160 def too_deep?(flags) return false if flags.max_depth.nil? depth > flags.max_depth end
unpack_key_exprs(path_list)
click to toggle source
# File lib/check_please/path.rb, line 165 def unpack_key_exprs(path_list) path_list .map { |path| path.send(:key_exprs) } .flatten .uniq { |e| e.to_s } # use the block form so we don't have to implement #hash and #eql? in horrible ways end