hyphae 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/hyphae +54 -0
- data/lib/hyphae.rb +166 -0
- metadata +59 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 26fffd773e8c0b6c43d8a286fd4be72a835246377634ee003cd41adead85234c
|
4
|
+
data.tar.gz: 37abf4892e01b535f8e8585cbf616eae7bbce2d3a27663cb318f3f514d49b4b7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5aecfc870811743bcd373bbdab8942982e0781554d30f867df1045597550f29caa20bff837d1c461b89925f4632dfcd6f73a7e17b3a73dcf47a01d5aeea750ad
|
7
|
+
data.tar.gz: e09d2ac065b089110e335d556494a3fbec5eb80c6456c8f2aa6c0cf66ecd9fd6df58f4023cbe0545149adbd6ca4bcc0d1b45e59f6b60a675c23874ec713414cc
|
data/bin/hyphae
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'hyphae'
|
4
|
+
|
5
|
+
###################
|
6
|
+
### Main Script ###
|
7
|
+
###################
|
8
|
+
|
9
|
+
# The first argument given is the site input directory
|
10
|
+
input_dir = ARGV[0] || "site"
|
11
|
+
if not Dir.exist?(input_dir) then
|
12
|
+
puts "ERROR: No input directory '#{input_dir}'"
|
13
|
+
exit
|
14
|
+
end
|
15
|
+
|
16
|
+
# The second argument is the rendered html site output directory
|
17
|
+
output_dir = ARGV[1] || "_build"
|
18
|
+
|
19
|
+
# Builds the page tree of the site
|
20
|
+
if not Dir.exist?(input_dir + "/pages") then
|
21
|
+
puts "ERROR: No '/pages' directory in #{input_dir}"
|
22
|
+
exit
|
23
|
+
end
|
24
|
+
page_tree = Hyphae::SiteDir.new(input_dir + '/pages')
|
25
|
+
|
26
|
+
# Reads site template file
|
27
|
+
if not File.exist?(input_dir + "/template.html") then
|
28
|
+
puts "ERROR: No 'template.html' file in #{input_dir}"
|
29
|
+
exit
|
30
|
+
end
|
31
|
+
template = File.read(input_dir + "/template.html")
|
32
|
+
|
33
|
+
# Reads site index content file
|
34
|
+
index_content = ''
|
35
|
+
if File.exist?(input_dir + "/index.html") then
|
36
|
+
index_content = File.read(input_dir + "/template.html")
|
37
|
+
end
|
38
|
+
|
39
|
+
# Makes the output directory
|
40
|
+
FileUtils.rm_rf output_dir
|
41
|
+
FileUtils.mkdir output_dir
|
42
|
+
|
43
|
+
# Moves site's static files
|
44
|
+
if not Dir.exist?(input_dir + "/static") then
|
45
|
+
puts "ERROR: No '/static' directory in #{input_dir}"
|
46
|
+
exit
|
47
|
+
end
|
48
|
+
FileUtils.cp_r(input_dir + '/static', output_dir)
|
49
|
+
|
50
|
+
# Builds html pages
|
51
|
+
page_tree.build(output_dir, template)
|
52
|
+
|
53
|
+
# Build site index
|
54
|
+
page_tree.build_index(output_dir, template, index_content)
|
data/lib/hyphae.rb
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'kramdown'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module Hyphae
|
5
|
+
|
6
|
+
#########################
|
7
|
+
### Utility Functions ###
|
8
|
+
#########################
|
9
|
+
|
10
|
+
# Produces a URL safe version of a string
|
11
|
+
def self.sanitize(str)
|
12
|
+
str.downcase.gsub(' ', '_').gsub(/[^\d\w_]/, "")
|
13
|
+
end
|
14
|
+
|
15
|
+
# Renders an HTML tag
|
16
|
+
def self.make_tag(tag, content, attrs={})
|
17
|
+
attrs_str = ""
|
18
|
+
attrs.map { |x, y| attrs_str << " #{x}=\"#{y}\""}
|
19
|
+
"<#{tag}#{attrs_str}>#{content}</#{tag}>"
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
#############################
|
25
|
+
### Site Building Classes ###
|
26
|
+
#############################
|
27
|
+
|
28
|
+
# Site content node, all other site node classes inherit from this one
|
29
|
+
class SiteNode
|
30
|
+
attr_reader :name, :slug, :path, :parent, :order, :date
|
31
|
+
|
32
|
+
def initialize(filename, parent=nil)
|
33
|
+
@name = File.basename(filename, '.*')
|
34
|
+
@parent = parent
|
35
|
+
@hidden = false
|
36
|
+
@order = nil
|
37
|
+
@date = nil
|
38
|
+
if captures = @name.match(/^_(.+)/) then
|
39
|
+
@hidden = true
|
40
|
+
@name = captures[1]
|
41
|
+
elsif captures = @name.match(/^o(\d+)_(.+)/) then
|
42
|
+
@order = captures[1].to_i
|
43
|
+
@name = captures[2]
|
44
|
+
elsif captures = @name.match(/^ut(\d+)_(.+)/) then
|
45
|
+
@date = Time.at(captures[1].to_i)
|
46
|
+
@name = captures[2]
|
47
|
+
end
|
48
|
+
@slug = Hyphae::sanitize @name
|
49
|
+
@path = @parent ? @parent.path + [(@slug)] : []
|
50
|
+
return self
|
51
|
+
end
|
52
|
+
|
53
|
+
# Get the root SiteNode of a tree of SiteNodes
|
54
|
+
def root
|
55
|
+
return self if @parent.nil?
|
56
|
+
@parent.root
|
57
|
+
end
|
58
|
+
|
59
|
+
# Compare this SiteNode with another
|
60
|
+
def cmp(other)
|
61
|
+
if other.order then
|
62
|
+
return 1 if @order.nil?
|
63
|
+
return @order <=> other.order
|
64
|
+
end
|
65
|
+
if other.date then
|
66
|
+
return 1 if @date.nil?
|
67
|
+
return other.date <=> @date
|
68
|
+
end
|
69
|
+
@name <=> other.name
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
# A SiteDir represents a directory containing nested SiteNodes
|
75
|
+
class SiteDir < SiteNode
|
76
|
+
def initialize(filename, parent=nil)
|
77
|
+
super
|
78
|
+
@children = []
|
79
|
+
Dir.glob(filename + '/*').each do |f|
|
80
|
+
if File.directory? f then
|
81
|
+
@children.push SiteDir.new(f, self)
|
82
|
+
elsif File.extname(f) == '.md' then
|
83
|
+
@children.push SitePage.new(f, self)
|
84
|
+
elsif File.extname(f) == '.link' then
|
85
|
+
@children.push SiteLink.new(f, self)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
@children.sort! { |x, y| x.cmp(y) }
|
89
|
+
return self
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns the html for each child's nav menu link
|
93
|
+
def menu_items(open_path=[])
|
94
|
+
@children.map { |x| x.nav_link(open_path) }.join
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns the html for this SiteDir's nav menu link
|
98
|
+
def nav_link(open_path=[])
|
99
|
+
return "" if @hidden
|
100
|
+
link = Hyphae::make_tag('span', @name, {'class' => 'nav_menu_link'})
|
101
|
+
menu_attrs = { 'class' => 'nav_menu_items' }
|
102
|
+
menu_attrs['class'] += ' open' if open_path.first == @slug
|
103
|
+
menu = Hyphae::make_tag('div', menu_items(open_path[1..-1] || []), menu_attrs)
|
104
|
+
Hyphae::make_tag('div', link + menu, {'class' => 'nav_menu'})
|
105
|
+
end
|
106
|
+
|
107
|
+
# Recursively builds pages for all children
|
108
|
+
def build(build_dir, template)
|
109
|
+
@children.each { |child| child.build(build_dir, template) }
|
110
|
+
end
|
111
|
+
|
112
|
+
# Builds an index page for this SiteDir
|
113
|
+
def build_index(build_dir, template, index_content='')
|
114
|
+
page_html = template.gsub('{{navbar}}', menu_items).gsub("{{content}}", index_content).gsub('{{index_class}}', ' index_page')
|
115
|
+
File.open("#{build_dir}/index.html", 'w') { |f| f << page_html }
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
# A SitePage represents a markdown document
|
121
|
+
class SitePage < SiteNode
|
122
|
+
def initialize(filename, parent)
|
123
|
+
super
|
124
|
+
markdown = File.read filename
|
125
|
+
@html = Kramdown::Document.new(markdown).to_html
|
126
|
+
end
|
127
|
+
|
128
|
+
# Builds the nav menu tag for this page
|
129
|
+
def nav_link(open_path=[])
|
130
|
+
return "" if @hidden
|
131
|
+
attrs = { 'class' => 'nav_page', 'href' => "/#{@path.join('/')}.html" }
|
132
|
+
attrs['class'] += ' current_page' if @slug == open_path.first
|
133
|
+
Hyphae::make_tag('a', @name, attrs)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Builds html page
|
137
|
+
def build(build_dir, template)
|
138
|
+
nav = root.menu_items(@path)
|
139
|
+
page_html = template.gsub('{{navbar}}', nav).gsub("{{content}}", @html).gsub('{{index_class}}', '')
|
140
|
+
page_dir_path = "#{build_dir}/#{@parent.path.join('/')}"
|
141
|
+
FileUtils.mkdir_p page_dir_path
|
142
|
+
File.open("#{page_dir_path}/#{@slug}.html", 'w') { |f| f << page_html }
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
# A SiteLink represents an arbitrary link
|
148
|
+
class SiteLink < SiteNode
|
149
|
+
def initialize(filename, parent)
|
150
|
+
super
|
151
|
+
@link = File.read(filename).strip
|
152
|
+
end
|
153
|
+
|
154
|
+
# Builds the nav menu tag for this page
|
155
|
+
def nav_link(open_path=[])
|
156
|
+
return "" if @hidden
|
157
|
+
attrs = { 'class' => 'nav_link', 'href' => @link }
|
158
|
+
Hyphae::make_tag('a', @name, attrs)
|
159
|
+
end
|
160
|
+
|
161
|
+
# Builds html page (does nothing for a link)
|
162
|
+
def build(build_dir, template)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hyphae
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nicholas Rakita
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-10-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: kramdown
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.11.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.11.1
|
27
|
+
description: A Minimal SSG
|
28
|
+
email: rakita@protonmail.ch
|
29
|
+
executables:
|
30
|
+
- hyphae
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- bin/hyphae
|
35
|
+
- lib/hyphae.rb
|
36
|
+
homepage: https://rubygems.org/gems/hyphae
|
37
|
+
licenses:
|
38
|
+
- Unlicense
|
39
|
+
metadata: {}
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
requirements: []
|
55
|
+
rubygems_version: 3.3.7
|
56
|
+
signing_key:
|
57
|
+
specification_version: 4
|
58
|
+
summary: Hyphae
|
59
|
+
test_files: []
|