hyphae 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +7 -0
  2. data/bin/hyphae +54 -0
  3. data/lib/hyphae.rb +166 -0
  4. 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: []