Skip to content

Instantly share code, notes, and snippets.

@msteen
Forked from DivineDominion/find_zettel_orphans.rb
Last active April 29, 2020 15:35
Show Gist options
  • Save msteen/a7362b703997a1417c297980390721b1 to your computer and use it in GitHub Desktop.
Save msteen/a7362b703997a1417c297980390721b1 to your computer and use it in GitHub Desktop.
In a directory of Zettel notes, find all those without incoming links
#!/usr/bin/env ruby
require 'set'
# Change the path here:
# ARCHIVE = '~/Archive/'
ARCHIVE = '/admin/fork/The-Archive-Demo-Notes'
EXTENSIONS = %w{.md .txt .markdown .mdown .text}
#################################################################
def zettel_id(filename)
filename[/^[0-9][0-9_\-]+[0-9]/]
end
class Zettel
@@all = {}
attr_accessor :file, :id, :outbound, :inbound
def initialize(file, id)
@file = file
@id = id
@outbound = []
@inbound = Set.new
end
def add_outbound_by_id(*ids)
other_zettel = ids.filter { |id| id != @id }
.map { |id| Zettel::by_id(id) }
.reject(&:nil?)
# Link from this Zettel to other
self.outbound.push(*other_zettel)
# Link other back to this Zettel
other_zettel.each do |outbound_zettel|
outbound_zettel.inbound.add(self)
end
end
def is_orphan?
@inbound.size === 0 || @outbound.size === 0
end
def self.by_id(id)
@@all[id]
end
def self.all
@@all.values
end
def self.each
@@all.each_value do |zettel|
yield zettel
end
end
def self.add(file)
return unless id = zettel_id(file)
@@all[id] = Zettel.new(file, id)
end
end
INPUT_DIR = File.expand_path(ARCHIVE)
Dir.entries(INPUT_DIR)
.select { |path| EXTENSIONS.include?(File.extname(path)) }
.each { |file| Zettel.add(file) }
Zettel.each do |zettel|
content = File.read(File.join(INPUT_DIR, zettel.file))
zettel.add_outbound_by_id(*content.scan(/[0-9][0-9_\-]+[0-9]/))
end
orphans = Zettel.all.filter(&:is_orphan?)
score = (1 - orphans.count.to_f / Zettel.all.count.to_f).round(2)
puts orphans.count.to_s + " of #{Zettel.all.count} notes are orphans (score: #{score})"
puts orphans.map { |o| "#{"i" if o.inbound.length == 0}#{"o" if o.outbound.length == 0}[[#{o.id}]] #{File.basename(o.file[o.id.length + 1 .. -1], File.extname(o.file))}" }
@DivineDominion
Copy link

I think zettel.outbound.count === 0 should not be needed for orphans; an orphan could have outbound links (it has no father/mother (inbound), but may produce children (outpbound). We could call the opposite a widow (hat tip to typography) or, maybe more accurately, a spinster? :) (May have incoming links, but no outgoing links; end of a chain)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment