Skip to content

Commit

Permalink
Start refactor
Browse files Browse the repository at this point in the history
The Page class is getting complicated, so extract out
the tree structure into its own class, and introduce a simple
struct to represent the pages themselves.
  • Loading branch information
MatMoore committed Jun 20, 2024
1 parent c8c5b93 commit 712efda
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 3 deletions.
26 changes: 23 additions & 3 deletions lib/obsidian/parser/page.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,25 @@

# TODO: remove this dependency
require "tilt/erb"
require_relative "tree"

module Obsidian
# WIP
PageNode = Struct.new(
:title,
:slug,
:last_modified,
:source_path,
:content_type,
keyword_init: true
) do
def raw_content
end

def html
end
end

# A page in the vault corresponding to either a markdown document,
# or a directory containing other documents.
#
Expand Down Expand Up @@ -71,7 +88,7 @@ def hash
# Call this method on the root page.
# When calling this method, you must ensure that anscestor pages
# are added before their descendents.
def add_page(slug, last_modified: nil, content: nil, content_type: nil, media_root: nil, source_path: nil)
def add_page(slug, last_modified: nil, content: nil, content_type: nil, media_root: nil, source_path: nil, strip_numeric_prefix: true)
path_components = slug.split("/")

if path_components.empty?
Expand All @@ -80,10 +97,13 @@ def add_page(slug, last_modified: nil, content: nil, content_type: nil, media_ro
end

title = path_components.pop
if strip_numeric_prefix
title = title.sub(/^\d+ - /, "")
end

parent = path_components.reduce(self) do |index, anscestor_title|
anscestor_slug = Obsidian.build_slug(anscestor_title, index.slug)
index.get_or_create_child(slug: anscestor_slug, title: anscestor_title)
index.get_or_create_child(slug: anscestor_slug, title: anscestor_title.sub(/^\d+ - /, ""))
end

parent.get_or_create_child(
Expand Down Expand Up @@ -120,7 +140,7 @@ def update_content(content:, last_modified:)
end

def children
@children.values.sort_by { |c| [c.is_index? ? 0 : 1, c.title] }
@children.values.sort_by { |c| [c.is_index? ? 0 : 1, c.slug] }
end

def walk_tree(&block)
Expand Down
47 changes: 47 additions & 0 deletions lib/obsidian/parser/tree.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# frozen_string_literal: true

module Obsidian
class Tree
def initialize(value)
@value = value
@children = []
end

attr_reader :children
attr_reader :value

def inspect
"Tree(#{value.inspect}) [#{children.length} children]"
end

def add_child(value)
node = Tree.new(value)
children << node
node
end

def remove_child(value)
children.delete_if { |node| node.value == value }
end

def is_index?
children.length > 0
end

def find(&block)
walk_tree do |page|
return page if block.call(page)
end

nil
end

def walk_tree(&block)
block.call(self)

children.each do |page|
page.walk_tree(&block)
end
end
end
end
39 changes: 39 additions & 0 deletions spec/obsidian/parser/tree_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# frozen_string_literal: true

RSpec.describe Obsidian::Tree do
subject(:root) { described_class.new(:root) }

describe("creating, retrieving, and removing nodes") do
before do
foo = root.add_child(:foo)
foo.add_child(:bar)
foo.add_child(:baz)
end

it "can find a node from the root" do
a = root.find { |node| node.value == :baz }

expect(a&.value).to eq(:baz)
end

it "can list the children of a node" do
foo = root.children.first

expect(root.children.map(&:value)).to eq([:foo])
expect(foo.children.map(&:value)).to eq([:bar, :baz])
end

it "can remove nodes" do
root.remove_child(:foo)
expect(root.children).to be_empty
end

it "can tell if a node is non-terminal" do
foo = root.children.first
bar = foo.children.first
expect(root.is_index?).to eq(true)
expect(foo.is_index?).to eq(true)
expect(bar.is_index?).to eq(false)
end
end
end

0 comments on commit 712efda

Please sign in to comment.