Module: MarkdownServer::Unhide

Defined in:
lib/markdown_server/unhide.rb

Defined Under Namespace

Classes: CompileError, Rule

Class Method Summary collapse

Class Method Details

.compile(raw_entries) ⇒ Object



7
8
9
# File 'lib/markdown_server/unhide.rb', line 7

def self.compile(raw_entries)
  Array(raw_entries).compact.map { |e| compile_one(e) }.uniq
end

.compile_one(raw) ⇒ Object

Raises:



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/markdown_server/unhide.rb', line 11

def self.compile_one(raw)
  entry = raw.to_s.strip
  raise CompileError, "unhide entry is empty" if entry.empty?

  if entry.start_with?("@/")
    path = entry.sub(%r{^@/+}, "")
    raise CompileError, "unhide entry '#{raw}' has no path after '@/'" if path.empty?
    segments = normalize_segments(path)
    raise CompileError, "unhide entry '#{raw}' has no usable segments" if segments.empty?
    Rule.new(:anchored, segments)
  else
    if entry.start_with?("/")
      raise CompileError,
            "unhide entry '#{raw}' has a leading '/'. " \
            "Use '@/...' for project-root-anchored, or omit the slash for any-depth match."
    end
    segments = normalize_segments(entry)
    raise CompileError, "unhide entry '#{raw}' has no usable segments" if segments.empty?
    Rule.new(segments.length == 1 ? :basename : :suffix, segments)
  end
end

.entry_step(parent_mode, parent_segs, entry_name, rules) ⇒ Object

Amortized step for an enumeration. parent_mode and parent_segs are known from the enclosing recursion; this checks one entry. Returns [visible, child_mode].



87
88
89
90
# File 'lib/markdown_server/unhide.rb', line 87

def self.entry_step(parent_mode, parent_segs, entry_name, rules)
  path_segs = parent_segs + [entry_name]
  step(parent_mode, path_segs, path_segs.length - 1, entry_name, rules)
end

.match_at(path_segs, i, rules) ⇒ Object

Returns :leaf if any rule matches segment i as its leaf, :prefix if any rule matches segment i as a navigational prefix, :none otherwise.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/markdown_server/unhide.rb', line 45

def self.match_at(path_segs, i, rules)
  best = :none
  rules.each do |r|
    case r.kind
    when :basename
      return :leaf if r.segments[0] == path_segs[i]
    when :suffix
      r.segments.length.times do |k|
        next unless i >= k
        next unless path_segs[(i - k)..i] == r.segments[0..k]
        if k + 1 == r.segments.length
          return :leaf
        else
          best = :prefix
        end
      end
    when :anchored
      if i < r.segments.length && path_segs[0..i] == r.segments[0..i]
        if i + 1 == r.segments.length
          return :leaf
        else
          best = :prefix
        end
      end
    end
  end
  best
end

.normalize_segments(path) ⇒ Object



33
34
35
# File 'lib/markdown_server/unhide.rb', line 33

def self.normalize_segments(path)
  path.split("/").reject(&:empty?)
end

.restricted?(name) ⇒ Boolean

Returns:

  • (Boolean)


37
38
39
40
# File 'lib/markdown_server/unhide.rb', line 37

def self.restricted?(name)
  return false if name.nil? || name.empty?
  name.start_with?(".") || MarkdownServer::EXCLUDED.include?(name)
end

.step(mode, path_segs, i, seg, rules) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/markdown_server/unhide.rb', line 92

def self.step(mode, path_segs, i, seg, rules)
  restricted = restricted?(seg)

  if restricted
    case match_at(path_segs, i, rules)
    when :leaf   then [true, :open]
    when :prefix then [true, :narrow]
    else              [false, nil]
    end
  else
    if mode == :open
      [true, :open]
    else
      case match_at(path_segs, i, rules)
      when :leaf   then [true, :open]
      when :prefix then [true, :narrow]
      else              [false, nil]
      end
    end
  end
end

.visible?(path_segments, rules) ⇒ Boolean

Cold check: walks segment by segment from root, tracking mode. Returns true iff every segment of path_segments is admitted.

Returns:

  • (Boolean)


76
77
78
79
80
81
82
83
# File 'lib/markdown_server/unhide.rb', line 76

def self.visible?(path_segments, rules)
  mode = :open
  path_segments.each_with_index do |seg, i|
    visible, mode = step(mode, path_segments, i, seg, rules)
    return false unless visible
  end
  true
end