Forked from DivineDominion/find_zettel_orphans.rb
Last active
April 29, 2020 15:35
-
-
Save msteen/a7362b703997a1417c297980390721b1 to your computer and use it in GitHub Desktop.
In a directory of Zettel notes, find all those without incoming links
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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))}" } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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)