-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Unify
Note
and Index
classes into Page
.
Once integrated with the parser, this will be a breaking API change. - Any `Page` may contain child pages and belong to any other page. - Use `Page#is_index?` to check if it is an "index" page - i.e. a page that has children. - Page entities are considered equal if their slug is equal - Added `Page.create_root` factory method
- Loading branch information
Showing
4 changed files
with
129 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
# frozen_string_literal: true | ||
|
||
module Obsidian | ||
# A page in the vault corresponding to either a markdown document, | ||
# or a directory containing other documents. | ||
# | ||
# If a directory contains an index.md, that is used as the content of | ||
# the directory page; otherwise content will be nil. | ||
class Page | ||
def self.create_root | ||
Page.new(title: "", slug: "") | ||
end | ||
|
||
def initialize(title:, slug:, last_modified: nil, content: nil, parent: nil) | ||
# TODO: check frontmatter for titles as well | ||
@title = title | ||
@slug = slug | ||
@last_modified = last_modified | ||
@content = content | ||
@parent = parent | ||
@children = {} | ||
end | ||
|
||
def is_index? | ||
!children.empty? | ||
end | ||
|
||
def inspect | ||
"Page(title: #{title.inspect}, slug: #{slug.inspect})" | ||
end | ||
|
||
def ==(other) | ||
!slug.nil? && slug == other.slug | ||
end | ||
|
||
alias_method :eql?, :== | ||
|
||
def hash | ||
slug.hash | ||
end | ||
|
||
# Add a note to the tree based on its slug. | ||
# 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) | ||
path_components = slug.split("/") | ||
raise ArgumentError, "Expecting non-empty slug" if path_components.empty? | ||
|
||
title = path_components.pop | ||
|
||
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) | ||
end | ||
|
||
parent.get_or_create_child( | ||
title: title, | ||
slug: slug, | ||
last_modified: last_modified, | ||
content: content | ||
) | ||
end | ||
|
||
def get_or_create_child(title:, slug:, last_modified: nil, content: nil) | ||
# TODO: validate slug matches the current page slug | ||
|
||
@children[title] ||= Page.new( | ||
slug: slug, | ||
title: title, | ||
last_modified: last_modified, | ||
content: content, | ||
parent: self | ||
) | ||
end | ||
|
||
def children | ||
@children.values.sort_by { |c| [c.is_index? ? 1 : 0, c.title] } | ||
end | ||
|
||
attr_reader :title | ||
attr_reader :slug | ||
attr_reader :last_modified | ||
attr_reader :content | ||
attr_reader :parent | ||
end | ||
end |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# frozen_string_literal: true | ||
|
||
RSpec.describe Obsidian::Page do | ||
subject(:root) { described_class.create_root } | ||
|
||
describe("#add_page") do | ||
it "relates too pages" do | ||
page = root.add_page("foo") | ||
|
||
expect(page.parent).to eq(root) | ||
expect(root.children).to eq([page]) | ||
end | ||
|
||
it "assigns titles and slugs to a top level page" do | ||
page = root.add_page("foo") | ||
|
||
expect(page.slug).to eq("foo") | ||
expect(page.title).to eq("foo") | ||
end | ||
|
||
it "assigns titles and slugs to a nested page" do | ||
page = root.add_page("foo/bar/baz") | ||
|
||
expect(page.slug).to eq("foo/bar/baz") | ||
expect(page.title).to eq("baz") | ||
end | ||
|
||
it "infers missing directory pages" do | ||
page = root.add_page("foo/bar/baz") | ||
parent = page.parent | ||
grandparent = parent.parent | ||
|
||
expect(parent.slug).to eq("foo/bar") | ||
expect(grandparent.slug).to eq("foo") | ||
expect(parent.children).to eq([page]) | ||
expect(grandparent.children).to eq([parent]) | ||
expect(root.children).to eq([grandparent]) | ||
end | ||
end | ||
end |