gryphon_nest 1.1.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/nest +12 -10
- data/lib/gryphon_nest/file_util.rb +51 -0
- data/lib/gryphon_nest/not_found_error.rb +5 -0
- data/lib/gryphon_nest/renderer.rb +17 -33
- data/lib/gryphon_nest/version.rb +1 -1
- data/lib/gryphon_nest.rb +61 -109
- metadata +22 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72b699d93837e7f59c74c2782f38526c2f6bc869d6af875bc174d13e29951560
|
4
|
+
data.tar.gz: 6150b1914e70d54e352d181c15750a57c524ae8271ce25de5bb976da4cb0bbf8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b60a684cf031ca5d37f3fa111e5b552def7d2041b723a8cca940a497db385111d2b54751501d60e0c22c7ef9f74cd14cdd5effef11b713c92fe4c0e590624eeb
|
7
|
+
data.tar.gz: 20e53c701a4bf0fa32d265d7fff95ece1a3c52eeb77439c347efd5d55a1401c2ee37ee1e2427cf575c70548220ff8640d193ef9ee5571178c06797233e3ae72b
|
data/bin/nest
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
|
4
4
|
require 'gryphon_nest'
|
5
5
|
require 'optparse'
|
6
|
+
require 'sysexits'
|
6
7
|
|
7
8
|
DEFAULT_PORT = 8000
|
8
9
|
|
@@ -10,6 +11,13 @@ options = {
|
|
10
11
|
port: DEFAULT_PORT
|
11
12
|
}
|
12
13
|
|
14
|
+
# @param msg [String]
|
15
|
+
# @param parser [OptionParser]
|
16
|
+
def usage_error(msg, parser)
|
17
|
+
warn(msg, parser)
|
18
|
+
Sysexits.exit(:usage)
|
19
|
+
end
|
20
|
+
|
13
21
|
# @param options [Hash]
|
14
22
|
# @return [Array]
|
15
23
|
begin
|
@@ -33,19 +41,13 @@ begin
|
|
33
41
|
|
34
42
|
command = ARGV.fetch(0, 'build')
|
35
43
|
|
36
|
-
unless %w[build serve].include?(command)
|
37
|
-
warn "Unknown command #{command}"
|
38
|
-
warn parser
|
39
|
-
exit(1)
|
40
|
-
end
|
44
|
+
usage_error("Unknown command #{command}", parser) unless %w[build serve].include?(command)
|
41
45
|
|
42
46
|
GryphonNest.build_website
|
43
47
|
GryphonNest.serve_website(options[:port]) if command == 'serve'
|
44
48
|
rescue OptionParser::ParseError => e
|
49
|
+
usage_error(e.message, parser)
|
50
|
+
rescue GryphonNest::NotFoundError => e
|
45
51
|
warn e.message
|
46
|
-
|
47
|
-
exit(1)
|
48
|
-
rescue StandardError => e
|
49
|
-
warn e.message
|
50
|
-
exit(1)
|
52
|
+
Sysexits.exit(:input_missing)
|
51
53
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
module GryphonNest
|
7
|
+
class FileUtil
|
8
|
+
# @params path [String]
|
9
|
+
# @return [Array]
|
10
|
+
def self.glob(path)
|
11
|
+
files = Dir.glob(path).reject do |p|
|
12
|
+
File.directory?(p)
|
13
|
+
end
|
14
|
+
|
15
|
+
files.map do |f|
|
16
|
+
Pathname.new(f)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param junk_files [Array]
|
21
|
+
def self.delete(junk_files)
|
22
|
+
junk_files.each do |f|
|
23
|
+
puts "Deleting #{f}"
|
24
|
+
FileUtils.remove_file(f)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param src [Pathname]
|
29
|
+
# @param dest [Pathname]
|
30
|
+
# @return [Boolean]
|
31
|
+
def self.file_newer?(src, dest)
|
32
|
+
return true unless dest.exist?
|
33
|
+
|
34
|
+
src.mtime > dest.mtime
|
35
|
+
end
|
36
|
+
|
37
|
+
# @param path [Pathname]
|
38
|
+
# @param content [String]
|
39
|
+
def self.write_file(path, content)
|
40
|
+
dir = path.dirname
|
41
|
+
|
42
|
+
unless dir.exist?
|
43
|
+
puts "Creating #{dir}"
|
44
|
+
dir.mkdir
|
45
|
+
end
|
46
|
+
|
47
|
+
puts "Creating #{path}"
|
48
|
+
path.write(content)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -5,51 +5,35 @@ require 'mustache'
|
|
5
5
|
|
6
6
|
module GryphonNest
|
7
7
|
# Renders mustache templates to html
|
8
|
-
class Renderer
|
9
|
-
# @param
|
10
|
-
def initialize
|
8
|
+
class Renderer < Mustache
|
9
|
+
# @param options [Hash]
|
10
|
+
def initialize(options = {})
|
11
11
|
@layouts = {}
|
12
|
+
super
|
12
13
|
end
|
13
14
|
|
14
15
|
# @param template [String]
|
15
|
-
# @param layout [String]
|
16
16
|
# @param context [Hash]
|
17
17
|
# @return [String]
|
18
|
-
def
|
19
|
-
|
20
|
-
content = render_template(f.read, context)
|
21
|
-
layout = get_template_layout(layout)
|
18
|
+
def render_file(template, context = {})
|
19
|
+
content = super
|
22
20
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
HtmlBeautifier.beautify(content)
|
21
|
+
if context.key?('layout')
|
22
|
+
context['yield'] = content
|
23
|
+
content = super(context['layout'], context)
|
29
24
|
end
|
30
|
-
end
|
31
25
|
|
32
|
-
|
33
|
-
|
34
|
-
# @param content [String]
|
35
|
-
# @param context [Hash]
|
36
|
-
# @return [String]
|
37
|
-
def render_template(content, context)
|
38
|
-
Mustache.render(content, context)
|
26
|
+
HtmlBeautifier.beautify(content)
|
39
27
|
end
|
40
28
|
|
41
|
-
# @param
|
42
|
-
# @return [String
|
43
|
-
def
|
44
|
-
return @layouts[
|
45
|
-
|
46
|
-
return unless File.exist?(path)
|
29
|
+
# @param name [String]
|
30
|
+
# @return [String]
|
31
|
+
def partial(name)
|
32
|
+
return @layouts[name] if @layouts.key?(name)
|
47
33
|
|
48
|
-
File.
|
49
|
-
|
50
|
-
|
51
|
-
return content
|
52
|
-
end
|
34
|
+
content = File.read(name)
|
35
|
+
@layouts[name] = content
|
36
|
+
content
|
53
37
|
end
|
54
38
|
end
|
55
39
|
end
|
data/lib/gryphon_nest/version.rb
CHANGED
data/lib/gryphon_nest.rb
CHANGED
@@ -6,7 +6,9 @@ require 'webrick'
|
|
6
6
|
require 'yaml'
|
7
7
|
|
8
8
|
module GryphonNest
|
9
|
+
autoload :NotFoundError, 'gryphon_nest/not_found_error'
|
9
10
|
autoload :Renderer, 'gryphon_nest/renderer'
|
11
|
+
autoload :FileUtil, 'gryphon_nest/file_util'
|
10
12
|
autoload :VERSION, 'gryphon_nest/version'
|
11
13
|
|
12
14
|
class << self
|
@@ -16,20 +18,22 @@ module GryphonNest
|
|
16
18
|
ASSETS_DIR = 'assets'
|
17
19
|
LAYOUT_DIR = 'layouts'
|
18
20
|
TEMPLATE_EXT = '.mustache'
|
21
|
+
DEFAULT_LAYOUT = Pathname.new("#{LAYOUT_DIR}/main.mustache")
|
19
22
|
|
23
|
+
# @raise [NotFoundError]
|
20
24
|
def build_website
|
21
|
-
raise "Content directory doesn't exist" unless Dir.exist?(CONTENT_DIR)
|
25
|
+
raise NotFoundError, "Content directory doesn't exist" unless Dir.exist?(CONTENT_DIR)
|
22
26
|
|
23
27
|
existing_files = []
|
24
28
|
if Dir.exist?(BUILD_DIR)
|
25
|
-
existing_files =
|
29
|
+
existing_files = FileUtil.glob("#{BUILD_DIR}/**/*")
|
26
30
|
else
|
27
31
|
Dir.mkdir(BUILD_DIR)
|
28
32
|
end
|
29
33
|
|
30
34
|
existing_files = existing_files.difference(process_content)
|
31
35
|
existing_files = existing_files.difference(copy_assets)
|
32
|
-
|
36
|
+
FileUtil.delete(existing_files)
|
33
37
|
end
|
34
38
|
|
35
39
|
# @param port [Integer]
|
@@ -43,72 +47,35 @@ module GryphonNest
|
|
43
47
|
|
44
48
|
private
|
45
49
|
|
46
|
-
# @param
|
47
|
-
# @return [
|
48
|
-
def get_output_name(
|
49
|
-
dir =
|
50
|
-
basename =
|
50
|
+
# @param source_file [Pathname]
|
51
|
+
# @return [Pathname]
|
52
|
+
def get_output_name(source_file)
|
53
|
+
dir = source_file.dirname
|
54
|
+
basename = source_file.basename(TEMPLATE_EXT)
|
55
|
+
path = dir.sub(CONTENT_DIR, BUILD_DIR)
|
51
56
|
|
52
|
-
path =
|
53
|
-
path = path.sub(CONTENT_DIR, BUILD_DIR)
|
57
|
+
path = path.join(basename) if basename.to_s != 'index'
|
54
58
|
|
55
|
-
path
|
56
|
-
|
57
|
-
path = path.join('index.html')
|
58
|
-
path.to_s
|
59
|
-
end
|
60
|
-
|
61
|
-
# @params path [String]
|
62
|
-
# @return [Array]
|
63
|
-
def filter_glob(path)
|
64
|
-
Dir.glob(path).reject do |p|
|
65
|
-
File.directory?(p)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# @param path [String]
|
70
|
-
# @param content [String]
|
71
|
-
def save_html_file(path, content)
|
72
|
-
dir = File.dirname(path)
|
73
|
-
|
74
|
-
unless Dir.exist?(dir)
|
75
|
-
puts "Creating #{dir}"
|
76
|
-
Dir.mkdir(dir)
|
77
|
-
end
|
78
|
-
|
79
|
-
puts "Creating #{path}"
|
80
|
-
File.write(path, content)
|
59
|
+
path.join('index.html')
|
81
60
|
end
|
82
61
|
|
83
|
-
# @param
|
84
|
-
# @param
|
85
|
-
# @param
|
86
|
-
# @param
|
62
|
+
# @param source_file [Pathname]
|
63
|
+
# @param dest_file [Pathname]
|
64
|
+
# @param context_file [Pathname, nil]
|
65
|
+
# @param layout_file [Pathname, nil]
|
87
66
|
# @return [Boolean]
|
88
|
-
def
|
89
|
-
return true
|
90
|
-
|
91
|
-
src_mtime = File.mtime(src)
|
92
|
-
dest_mtime = File.mtime(dest)
|
93
|
-
|
94
|
-
return true if src_mtime > dest_mtime
|
67
|
+
def resources_updated?(source_file, dest_file, context_file, layout_file)
|
68
|
+
return true if FileUtil.file_newer?(source_file, dest_file)
|
95
69
|
|
96
|
-
if
|
97
|
-
layout_mtime = File.mtime(layout_file)
|
98
|
-
return true if layout_mtime > dest_mtime
|
99
|
-
end
|
100
|
-
|
101
|
-
if File.exist?(context_file)
|
102
|
-
context_mtime = File.mtime(context_file)
|
103
|
-
return true if context_mtime > dest_mtime
|
104
|
-
end
|
70
|
+
return true if !context_file.nil? && FileUtil.file_newer?(context_file, dest_file)
|
105
71
|
|
106
|
-
|
72
|
+
!layout_file.nil? && FileUtil.file_newer?(layout_file, dest_file)
|
107
73
|
end
|
108
74
|
|
109
75
|
# @param name [String]
|
110
76
|
# @param context [Hash]
|
111
|
-
# @return [
|
77
|
+
# @return [Pathname, nil]
|
78
|
+
# @raise [NotFoundError]
|
112
79
|
def get_layout_file(name, context)
|
113
80
|
path = Pathname.new(LAYOUT_DIR)
|
114
81
|
|
@@ -116,100 +83,85 @@ module GryphonNest
|
|
116
83
|
layout = context['layout']
|
117
84
|
path = path.join(layout)
|
118
85
|
|
119
|
-
raise "#{name} requires layout file #{layout} but it doesn't exist or can't be read" unless
|
86
|
+
raise NotFoundError, "#{name} requires layout file #{layout} but it doesn't exist or can't be read" unless path.exist?
|
120
87
|
|
121
|
-
return path
|
88
|
+
return path
|
122
89
|
end
|
123
90
|
|
124
|
-
|
91
|
+
DEFAULT_LAYOUT if DEFAULT_LAYOUT.exist?
|
125
92
|
end
|
126
93
|
|
127
|
-
# @param path [
|
94
|
+
# @param path [Pathname, nil]
|
128
95
|
# @return [Hash]
|
129
|
-
def
|
130
|
-
return {} if path
|
131
|
-
|
132
|
-
return {} unless File.exist?(path)
|
96
|
+
def get_context(path)
|
97
|
+
return {} if path.nil?
|
133
98
|
|
134
99
|
File.open(path) do |yaml|
|
135
100
|
YAML.safe_load(yaml)
|
136
101
|
end
|
137
102
|
end
|
138
103
|
|
139
|
-
# @param name [
|
140
|
-
# @return [
|
104
|
+
# @param name [Pathname]
|
105
|
+
# @return [Pathname, nil]
|
141
106
|
def get_context_file(name)
|
142
|
-
basename =
|
107
|
+
basename = name.basename(TEMPLATE_EXT)
|
108
|
+
FileUtil.glob("#{DATA_DIR}/#{basename}.{yaml,yml}")[0]
|
109
|
+
end
|
143
110
|
|
144
|
-
|
145
|
-
|
146
|
-
|
111
|
+
# @param renderer [Renderer]
|
112
|
+
# @param source_file [Pathname]
|
113
|
+
# @param dest_file [Pathname]
|
114
|
+
# @raise [NotFoundError]
|
115
|
+
def process_file(renderer, source_file, dest_file)
|
116
|
+
context_file = get_context_file(source_file)
|
117
|
+
context = get_context(context_file)
|
118
|
+
layout_file = get_layout_file(source_file.basename, context)
|
119
|
+
context['layout'] = layout_file unless layout_file.nil?
|
120
|
+
|
121
|
+
return unless resources_updated?(source_file, dest_file, context_file, layout_file)
|
147
122
|
|
148
|
-
|
123
|
+
content = renderer.render_file(source_file, context)
|
124
|
+
FileUtil.write_file(dest_file, content)
|
149
125
|
end
|
150
126
|
|
151
127
|
# @return [Array]
|
128
|
+
# @raise [NotFoundError]
|
152
129
|
def process_content
|
153
130
|
created_files = []
|
154
|
-
renderer = Renderer.new
|
155
131
|
|
156
|
-
|
157
|
-
|
158
|
-
|
132
|
+
renderer = Renderer.new
|
133
|
+
FileUtil.glob("#{CONTENT_DIR}/**/*").each do |source_file|
|
134
|
+
if source_file.extname != TEMPLATE_EXT
|
135
|
+
warn "Skipping non template file #{source_file}"
|
159
136
|
next
|
160
137
|
end
|
161
138
|
|
162
|
-
dest_file = get_output_name(
|
163
|
-
context_file = get_context_file(template)
|
164
|
-
context = read_context_file(context_file)
|
165
|
-
layout_file = get_layout_file(template, context)
|
166
|
-
|
139
|
+
dest_file = get_output_name(source_file)
|
167
140
|
created_files << dest_file
|
168
|
-
|
169
|
-
|
170
|
-
content = renderer.render(template, layout_file, context)
|
171
|
-
save_html_file(dest_file, content)
|
141
|
+
process_file(renderer, source_file, dest_file)
|
172
142
|
end
|
173
143
|
|
174
144
|
created_files
|
175
145
|
end
|
176
146
|
|
177
|
-
# @param src [String]
|
178
|
-
# @param dest [String]
|
179
|
-
# @return [Boolean]
|
180
|
-
def can_copy_asset?(src, dest)
|
181
|
-
return true unless File.exist?(dest)
|
182
|
-
|
183
|
-
File.mtime(src) > File.mtime(dest)
|
184
|
-
end
|
185
|
-
|
186
147
|
# @return [Array]
|
187
148
|
def copy_assets
|
188
149
|
return [] unless Dir.exist?(ASSETS_DIR)
|
189
150
|
|
190
151
|
copied_files = []
|
191
|
-
|
192
|
-
dest =
|
193
|
-
|
194
|
-
copied_files << dest.to_s
|
152
|
+
FileUtil.glob("#{ASSETS_DIR}/**/*").each do |asset|
|
153
|
+
dest = asset.sub(ASSETS_DIR, BUILD_DIR)
|
154
|
+
copied_files << dest
|
195
155
|
|
196
|
-
next unless
|
156
|
+
next unless FileUtil.file_newer?(asset, dest)
|
197
157
|
|
198
158
|
puts "Copying #{asset} to #{dest}"
|
199
|
-
dest_dir =
|
159
|
+
dest_dir = dest.dirname
|
200
160
|
FileUtils.makedirs(dest_dir)
|
201
161
|
FileUtils.copy_file(asset, dest)
|
202
162
|
end
|
203
163
|
|
204
164
|
copied_files
|
205
165
|
end
|
206
|
-
|
207
|
-
# @param junk_files [Array]
|
208
|
-
def cleanup(junk_files)
|
209
|
-
junk_files.each do |f|
|
210
|
-
puts "Deleting #{f}"
|
211
|
-
FileUtils.remove_file(f)
|
212
|
-
end
|
213
|
-
end
|
214
166
|
end
|
215
167
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gryphon_nest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christopher Birmingham
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-09-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: htmlbeautifier
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sysexits
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.2'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.2'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: webrick
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -92,6 +106,8 @@ files:
|
|
92
106
|
- LICENSE
|
93
107
|
- bin/nest
|
94
108
|
- lib/gryphon_nest.rb
|
109
|
+
- lib/gryphon_nest/file_util.rb
|
110
|
+
- lib/gryphon_nest/not_found_error.rb
|
95
111
|
- lib/gryphon_nest/renderer.rb
|
96
112
|
- lib/gryphon_nest/version.rb
|
97
113
|
homepage: https://github.com/chrisBirmingham/gryphon_nest
|
@@ -100,7 +116,7 @@ licenses:
|
|
100
116
|
metadata:
|
101
117
|
homepage_uri: https://github.com/chrisBirmingham/gryphon_nest
|
102
118
|
source_code_uri: https://github.com/chrisBirmingham/gryphon_nest
|
103
|
-
post_install_message:
|
119
|
+
post_install_message:
|
104
120
|
rdoc_options: []
|
105
121
|
require_paths:
|
106
122
|
- lib
|
@@ -115,8 +131,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
115
131
|
- !ruby/object:Gem::Version
|
116
132
|
version: '0'
|
117
133
|
requirements: []
|
118
|
-
rubygems_version: 3.
|
119
|
-
signing_key:
|
134
|
+
rubygems_version: 3.3.7
|
135
|
+
signing_key:
|
120
136
|
specification_version: 4
|
121
137
|
summary: Yet another static site generator
|
122
138
|
test_files: []
|