Skip to content

Commit

Permalink
Parse title and section headings
Browse files Browse the repository at this point in the history
  • Loading branch information
fpsvogel committed Dec 15, 2023
1 parent 804502c commit c626d20
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 53 deletions.
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ GEM
ffi (~> 1.0)
rdoc (6.6.0)
psych (>= 4.0.0)
redcarpet (3.6.0)
reline (0.4.1)
io-console (~> 0.5)
rexml (3.2.6)
Expand Down Expand Up @@ -151,6 +152,7 @@ DEPENDENCIES
nokogiri
puma (< 7)
rails-dom-testing
redcarpet
shoulda

BUNDLED WITH
Expand Down
2 changes: 0 additions & 2 deletions plugins/builders/load_curriculum.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
require 'debug'

class Builders::LoadCurriculum < SiteBuilder
def build
hook :site, :post_read do |site|
Expand Down
88 changes: 42 additions & 46 deletions plugins/markdown_curriculum.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,54 +8,50 @@ def initialize(markdown_string, custom_config: {})

# Parses the Markdown curriculum into groups of item hashes.
# @return [Array<Hash>] nested item groups containing item hashes.
# For example, here's a snipped from a Markdown curriculum:
# ```markdown
# ## Basics
#
# ### Ruby basics
#
# - **Intro:**
# - [x] [The Odin Project - Ruby](https://www.theodinproject.com/paths/full-stack-ruby-on-rails/courses/ruby) <!-- https://avatars.githubusercontent.com/u/4441966?s=280 -->
# - [x] [GoRails - Ruby for Beginners](https://gorails.com/series/ruby-for-beginners) if you prefer videos.
# - [ ] [BigBinary Academy](https://academy.bigbinary.com/learn-ruby)
# ```
#
# From the above Markdown, this data is parsed:
# ```ruby
# [
# {
# "Basics" =>
# [
# {
# "Ruby basics" =>
# [
# {
# "Intro" =>
# [
# {
# title: "The Odin Project - Ruby",
# description: nil,
# url: "https://www.theodinproject.com/paths/full-stack-ruby-on-rails/courses/ruby",
# image: "https://avatars.githubusercontent.com/u/4441966?s=280",
# },
# {
# title: "GoRails - Ruby for Beginners",
# description: "If you prefer videos.",
# url: "https://gorails.com/series/ruby-for-beginners",
# image: nil,
# },
# ],
# },
# ],
# },
# ],
# },
# ]
# ```
# See test_markdown_curriculum.rb for examples.
def parse
markdown_string
.split("## ")
.reject(&:blank?)
# Get sections (h2).
.split("\n## ")
.map { |h2_and_content|
h2_and_content.split("\n", 2)
}
# Split out the title and top content.
.then {
title, intro = _1.shift
title = title&.delete_prefix("# ")&.strip&.presence
intro = intro&.strip&.presence

{
title:,
intro:,
content: _1,
}
}
.tap { |hash|
hash[:content] = hash[:content]
# For empty sections, add nil to form a 2-element (#to_h-able) array.
.map { |array|
(2 - array.length).times.inject(array) { |array, i| array << nil }
}
.to_h
.transform_keys(&:strip)
.transform_values { _1&.strip&.presence }
# TODO clean up below
# .reject { |k, v| k.downcase == "table of contents" }
# # Get subsections (h3).
# .transform_values.with_index { |content_under_h2, i|
# next content_under_h2 if i.zero? || !content_under_h2&.include?("\n\n### ")

# content_under_h2
# .split("\n\n### ")
# .reject(&:blank?)
# .map { |h3_and_content|
# h3_and_content.split(/(?=\n\n)/, 2)
# }
# .to_h
# }
}
end

private
Expand Down
120 changes: 115 additions & 5 deletions test/test_markdown_curriculum.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,120 @@
require_relative "./helper"

class TestHomepage < Minitest::Test
context "when the curriculum is not empty" do
should "be true" do
parsed = MarkdownCurriculum.new("## very ## simple").parse
assert_equal 2, parsed.count
class TestMarkdownCurriculum < Minitest::Test
def self.title = "My Ruby road map"

@cases = {

"blank file" => [
"\n",
{ title: nil, intro: nil, content: {} },
],

"title" => [
"# #{title}\n",
{ title:, intro: nil, content: {} },
],

"title and empty sections" => [
<<~MARKDOWN,
# #{title}
## Intro
## Basics
MARKDOWN
{
title:,
intro: nil,
content: { "Intro" => nil, "Basics" => nil },
},
],

"title and empty sections with minimal line breaks" => [
<<~MARKDOWN,
# #{title}
## Intro
## Basics
MARKDOWN
{
title:,
intro: nil,
content: { "Intro" => nil, "Basics" => nil },
},
],

}

@cases.each do |description, (markdown, expected)|
define_method "test_#{description.tr(" ", "_")}" do
actual = MarkdownCurriculum.new(markdown).parse
assert_equal expected, actual
end
end

# TODO
# <<~MARKDOWN
# # My Ruby road map

# Hi, this is my road map.

# ## Table of contents

# (This section should be omitted.)

# ## Intro

# This section might contain prose.

# ## Basics

# ### Ruby basics

# - **Intro:**
# - [x] [The Odin Project - Ruby](https://www.theodinproject.com/paths/full-stack-ruby-on-rails/courses/ruby) <!-- https://avatars.githubusercontent.com/u/4441966?s=280 -->
# - [x] [GoRails - Ruby for Beginners](https://gorails.com/series/ruby-for-beginners) if you prefer videos.
# - [ ] [BigBinary Academy](https://academy.bigbinary.com/learn-ruby)

# ## Advanced concepts

# ### Quantum computing

# - [ ] something

# ### The meaning of life

# - [ ] something else
# MARKDOWN

# expected = [
# {
# "Basics" =>
# [
# {
# "Ruby basics" =>
# [
# {
# "Intro" =>
# [
# {
# title: "The Odin Project - Ruby",
# description: nil,
# url: "https://www.theodinproject.com/paths/full-stack-ruby-on-rails/courses/ruby",
# image: "https://avatars.githubusercontent.com/u/4441966?s=280",
# },
# {
# title: "GoRails - Ruby for Beginners",
# description: "If you prefer videos.",
# url: "https://gorails.com/series/ruby-for-beginners",
# image: nil,
# },
# ],
# },
# ],
# },
# ],
# },
# ]
end

0 comments on commit c626d20

Please sign in to comment.