gryphon_nest 3.1.0 → 4.0.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 -3
- data/lib/gryphon_nest/logging.rb +23 -0
- data/lib/gryphon_nest/processors/asset_processor.rb +5 -14
- data/lib/gryphon_nest/processors/mustache_processor.rb +24 -23
- data/lib/gryphon_nest/processors/processor_registry.rb +35 -0
- data/lib/gryphon_nest/processors/sass_processor.rb +34 -0
- data/lib/gryphon_nest/processors.rb +20 -0
- data/lib/gryphon_nest/version.rb +1 -1
- data/lib/gryphon_nest.rb +68 -26
- metadata +23 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11bbaedf3fbca0e216d16bd03a8452ee6ffc57930dac0ab8a30c3d02fef15f2e
|
4
|
+
data.tar.gz: 63ed7c032ef8478697ee0372ff569c54f3408a92dc68728f892c7a938e7e4955
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 865a4ed653820f359cd8d608e38e7f1c9c1697def2f4958ea18b11e4f4df84b701663571b10bf03eb06a2a1f9cd530a0c1f7579c613b710611b7014cd93c9851
|
7
|
+
data.tar.gz: 16838330ada34079d02f4ef629a878c2f6afdd55fa288e180a44e17b9fc8425fe3c6c5eaa27883ebb7ec900d30ce0ae2e82dd84525384e7dbbe464732f976fa6
|
data/bin/nest
CHANGED
@@ -8,7 +8,8 @@ DEFAULT_PORT = 8000
|
|
8
8
|
EXIT_FAILURE = 1
|
9
9
|
|
10
10
|
options = {
|
11
|
-
port: DEFAULT_PORT
|
11
|
+
port: DEFAULT_PORT,
|
12
|
+
watch: false
|
12
13
|
}
|
13
14
|
|
14
15
|
# @param msg [String]
|
@@ -24,6 +25,8 @@ begin
|
|
24
25
|
|
25
26
|
opts.on('-p', '--port [PORT]', Integer, 'Port to run dev server on')
|
26
27
|
|
28
|
+
opts.on('-w', '--watch', 'Watch for file changes when running the local server')
|
29
|
+
|
27
30
|
opts.on('-h', '--help', 'Show this message') do
|
28
31
|
puts opts
|
29
32
|
exit
|
@@ -41,8 +44,14 @@ begin
|
|
41
44
|
|
42
45
|
usage_error("Unknown command #{command}", parser) unless %w[build serve].include?(command)
|
43
46
|
|
44
|
-
GryphonNest.
|
45
|
-
|
47
|
+
nest = GryphonNest::Nest.new
|
48
|
+
nest.build
|
49
|
+
|
50
|
+
if command == 'serve'
|
51
|
+
nest.watch if options[:watch]
|
52
|
+
|
53
|
+
nest.serve(options[:port])
|
54
|
+
end
|
46
55
|
rescue OptionParser::ParseError => e
|
47
56
|
usage_error(e.message, parser)
|
48
57
|
rescue StandardError => e
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module GryphonNest
|
6
|
+
# Mixing module used for logging messages to the console
|
7
|
+
module Logging
|
8
|
+
class << self
|
9
|
+
# @return [Logger]
|
10
|
+
def create
|
11
|
+
logger = Logger.new($stdout)
|
12
|
+
|
13
|
+
# Create formatter that matches WebBricks log messages
|
14
|
+
logger.formatter = proc do |severity, datetime, _progname, msg|
|
15
|
+
date_format = datetime.strftime('%Y-%m-%d %H:%M:%S')
|
16
|
+
"[#{date_format}] #{severity.ljust(5)} #{msg}\n"
|
17
|
+
end
|
18
|
+
|
19
|
+
logger
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -6,22 +6,13 @@ module GryphonNest
|
|
6
6
|
module Processors
|
7
7
|
# Default file processor. Moves files from source to destination
|
8
8
|
class AssetProcessor
|
9
|
-
# @param
|
10
|
-
# @
|
11
|
-
def process(
|
12
|
-
dest
|
13
|
-
|
14
|
-
if file_modified?(file, dest)
|
15
|
-
puts "Copying #{file} to #{dest}"
|
16
|
-
dest.dirname.mkpath
|
17
|
-
FileUtils.copy_file(file, dest)
|
18
|
-
end
|
19
|
-
|
20
|
-
dest
|
9
|
+
# @param src [Pathname]
|
10
|
+
# @param dest [Pathname]
|
11
|
+
def process(src, dest)
|
12
|
+
dest.dirname.mkpath
|
13
|
+
FileUtils.copy_file(src, dest)
|
21
14
|
end
|
22
15
|
|
23
|
-
private
|
24
|
-
|
25
16
|
# @param src [Pathname]
|
26
17
|
# @return [Pathname]
|
27
18
|
def dest_name(src)
|
@@ -12,25 +12,18 @@ module GryphonNest
|
|
12
12
|
@renderer = renderer
|
13
13
|
end
|
14
14
|
|
15
|
-
# @param
|
16
|
-
# @
|
15
|
+
# @param src [Pathname]
|
16
|
+
# @param dest [Pathname]
|
17
17
|
# @raise [Errors::YamlError]
|
18
18
|
# @raise [Errors::ParseError]
|
19
|
-
def process(
|
20
|
-
dest = dest_name(file)
|
21
|
-
msg = File.exist?(dest) ? 'Recreating' : 'Creating'
|
22
|
-
puts "#{msg} #{dest}"
|
23
|
-
|
19
|
+
def process(src, dest)
|
24
20
|
@layout ||= read_layout_file
|
25
21
|
|
26
|
-
context = read_context(
|
27
|
-
content = build_output(
|
22
|
+
context = read_context(src)
|
23
|
+
content = build_output(src, context)
|
28
24
|
write_file(dest, content)
|
29
|
-
dest
|
30
25
|
end
|
31
26
|
|
32
|
-
private
|
33
|
-
|
34
27
|
# @param src [Pathname]
|
35
28
|
# @return [Pathname]
|
36
29
|
def dest_name(src)
|
@@ -43,12 +36,20 @@ module GryphonNest
|
|
43
36
|
path.join('index.html')
|
44
37
|
end
|
45
38
|
|
39
|
+
# @param _src [Pathname]
|
40
|
+
# @param _dest [Pathname]
|
41
|
+
# @return [Boolean]
|
42
|
+
def file_modified?(_src, _dest)
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
46
48
|
# @param src [Pathname]
|
47
49
|
# @return [Hash]
|
48
50
|
# @raise [Errors::YamlError]
|
49
51
|
def read_context(src)
|
50
|
-
|
51
|
-
path = "#{DATA_DIR}/#{basename}.yaml"
|
52
|
+
path = src.sub(CONTENT_DIR, DATA_DIR).sub_ext('.yaml')
|
52
53
|
YAML.safe_load_file(path, symbolize_names: true)
|
53
54
|
rescue IOError, Errno::ENOENT
|
54
55
|
{}
|
@@ -61,16 +62,17 @@ module GryphonNest
|
|
61
62
|
# @return [String]
|
62
63
|
# @raise [Errors::ParseError]
|
63
64
|
def build_output(file, context)
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
65
|
+
content =
|
66
|
+
if @layout.empty?
|
67
|
+
@renderer.render_file(file, context)
|
68
|
+
else
|
69
|
+
context[:yield] = file.basename(TEMPLATE_EXT)
|
70
|
+
@renderer.render(@layout, context)
|
71
|
+
end
|
70
72
|
|
71
73
|
HtmlBeautifier.beautify(content, stop_on_errors: true)
|
72
74
|
rescue Mustache::Parser::SyntaxError => e
|
73
|
-
raise Errors::ParseError, "Failed to process mustache template #{file}
|
75
|
+
raise Errors::ParseError, "Failed to process mustache template #{file}. Reason:\n#{e}"
|
74
76
|
rescue RuntimeError => e
|
75
77
|
raise Errors::ParseError, "Failed to beautify template output #{file}. Reason: #{e.message}"
|
76
78
|
end
|
@@ -78,8 +80,7 @@ module GryphonNest
|
|
78
80
|
# @param path [Pathname]
|
79
81
|
# @param content [String]
|
80
82
|
def write_file(path, content)
|
81
|
-
|
82
|
-
dir.mkpath
|
83
|
+
path.dirname.mkpath
|
83
84
|
path.write(content)
|
84
85
|
end
|
85
86
|
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GryphonNest
|
4
|
+
module Processors
|
5
|
+
class ProcessorRegistry
|
6
|
+
def initialize
|
7
|
+
@asset_processor = AssetProcessor.new
|
8
|
+
@processors = Hash.new(@asset_processor)
|
9
|
+
yield self
|
10
|
+
end
|
11
|
+
|
12
|
+
# @param key [String]
|
13
|
+
# @param value [Proc]
|
14
|
+
def []=(key, value)
|
15
|
+
@processors[key] = value
|
16
|
+
end
|
17
|
+
|
18
|
+
# @param key [String]
|
19
|
+
# @return [Object]
|
20
|
+
def [](key)
|
21
|
+
processor = @processors[key]
|
22
|
+
|
23
|
+
if processor.is_a?(Proc)
|
24
|
+
processor = processor.call
|
25
|
+
@processors[key] = processor
|
26
|
+
end
|
27
|
+
|
28
|
+
processor
|
29
|
+
rescue LoadError
|
30
|
+
@processors[key] = nil
|
31
|
+
@asset_processor
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sass-embedded'
|
4
|
+
|
5
|
+
module GryphonNest
|
6
|
+
module Processors
|
7
|
+
class SassProcessor
|
8
|
+
# @param src [Pathname]
|
9
|
+
# @param dest [Pathname]
|
10
|
+
# @raise [Errors::ParseError]
|
11
|
+
def process(src, dest)
|
12
|
+
result = Sass.compile(src)
|
13
|
+
File.write(dest, result.css)
|
14
|
+
rescue Sass::CompileError => e
|
15
|
+
raise Errors::ParseError, "Failed to process sass style sheet #{src}. Reason:\n#{e.full_message}"
|
16
|
+
end
|
17
|
+
|
18
|
+
# @param src [Pathname]
|
19
|
+
# @return [Pathname]
|
20
|
+
def dest_name(src)
|
21
|
+
src.sub(CONTENT_DIR, BUILD_DIR).sub_ext('.css')
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param src [Pathname]
|
25
|
+
# @param des [Pathname]
|
26
|
+
# @return [Boolean]
|
27
|
+
def file_modified?(src, dest)
|
28
|
+
return true unless dest.exist?
|
29
|
+
|
30
|
+
src.mtime > dest.mtime
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -4,5 +4,25 @@ module GryphonNest
|
|
4
4
|
module Processors
|
5
5
|
autoload :AssetProcessor, 'gryphon_nest/processors/asset_processor'
|
6
6
|
autoload :MustacheProcessor, 'gryphon_nest/processors/mustache_processor'
|
7
|
+
autoload :ProcessorRegistry, 'gryphon_nest/processors/processor_registry'
|
8
|
+
autoload :SassProcessor, 'gryphon_nest/processors/sass_processor.rb'
|
9
|
+
|
10
|
+
class << self
|
11
|
+
# @return [ProcessorRegistry]
|
12
|
+
def create
|
13
|
+
ProcessorRegistry.new do |reg|
|
14
|
+
reg[TEMPLATE_EXT] = proc {
|
15
|
+
renderer = Renderers::MustacheRenderer.new
|
16
|
+
renderer.template_path = CONTENT_DIR
|
17
|
+
Processors::MustacheProcessor.new(renderer)
|
18
|
+
}
|
19
|
+
|
20
|
+
sass_proc = proc { Processors::SassProcessor.new }
|
21
|
+
|
22
|
+
reg['.scss'] = sass_proc
|
23
|
+
reg['.sass'] = sass_proc
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
7
27
|
end
|
8
28
|
end
|
data/lib/gryphon_nest/version.rb
CHANGED
data/lib/gryphon_nest.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'listen'
|
3
4
|
require 'pathname'
|
4
5
|
require 'webrick'
|
5
6
|
|
6
7
|
module GryphonNest
|
7
8
|
autoload :Errors, 'gryphon_nest/errors'
|
9
|
+
autoload :Logging, 'gryphon_nest/logging'
|
8
10
|
autoload :Processors, 'gryphon_nest/processors'
|
9
11
|
autoload :Renderers, 'gryphon_nest/renderers'
|
10
12
|
autoload :VERSION, 'gryphon_nest/version'
|
@@ -15,21 +17,55 @@ module GryphonNest
|
|
15
17
|
TEMPLATE_EXT = '.mustache'
|
16
18
|
LAYOUT_FILE = 'layout.mustache'
|
17
19
|
|
18
|
-
class
|
20
|
+
class Nest
|
21
|
+
def initialize
|
22
|
+
@processors = Processors.create
|
23
|
+
@logger = Logging.create
|
24
|
+
end
|
25
|
+
|
19
26
|
# @raise [Errors::NotFoundError]
|
20
|
-
def
|
27
|
+
def build
|
21
28
|
raise Errors::NotFoundError, "Content directory doesn't exist in the current directory" unless Dir.exist?(CONTENT_DIR)
|
22
29
|
|
23
30
|
Dir.mkdir(BUILD_DIR) unless Dir.exist?(BUILD_DIR)
|
24
31
|
|
25
32
|
existing_files = glob("#{BUILD_DIR}/**/*")
|
26
|
-
|
27
|
-
|
33
|
+
content_files = glob("#{CONTENT_DIR}/**/*")
|
34
|
+
processed_files = content_files.collect { |src| process_file(src) }
|
35
|
+
existing_files.difference(processed_files).each { |file| delete_file(file) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def watch
|
39
|
+
@logger.info('Watching for content changes')
|
40
|
+
listener = Listen.to(CONTENT_DIR, DATA_DIR, relative: true) do |modified, added, removed|
|
41
|
+
modified.union(added).each do |file|
|
42
|
+
path = Pathname(file)
|
43
|
+
|
44
|
+
if file.start_with?(DATA_DIR)
|
45
|
+
process_data_file(path)
|
46
|
+
else
|
47
|
+
process_file(path)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
removed.each do |file|
|
52
|
+
path = Pathname(file)
|
53
|
+
|
54
|
+
if file.start_with?(DATA_DIR)
|
55
|
+
process_data_file(path)
|
56
|
+
else
|
57
|
+
path = @processors[path.extname].dest_name(path)
|
58
|
+
delete_file(path)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
listener.start
|
28
64
|
end
|
29
65
|
|
30
66
|
# @param port [Integer]
|
31
|
-
def
|
32
|
-
|
67
|
+
def serve(port)
|
68
|
+
@logger.info("Running local server on #{port}")
|
33
69
|
server = WEBrick::HTTPServer.new(Port: port, DocumentRoot: BUILD_DIR)
|
34
70
|
# Trap ctrl c so we don't get the horrible stack trace
|
35
71
|
trap('INT') { server.shutdown }
|
@@ -38,20 +74,29 @@ module GryphonNest
|
|
38
74
|
|
39
75
|
private
|
40
76
|
|
41
|
-
# @
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
glob("#{CONTENT_DIR}/**/*").map do |source_file|
|
52
|
-
processor = processors.fetch(source_file.extname, asset_processor)
|
53
|
-
processor.process(source_file)
|
77
|
+
# @param src [Pathname]
|
78
|
+
# @return [Pathname]
|
79
|
+
def process_file(src)
|
80
|
+
processor = @processors[src.extname]
|
81
|
+
dest = processor.dest_name(src)
|
82
|
+
|
83
|
+
if processor.file_modified?(src, dest)
|
84
|
+
msg = File.exist?(dest) ? 'Recreating' : 'Creating'
|
85
|
+
@logger.info("#{msg} #{dest}")
|
86
|
+
processor.process(src, dest)
|
54
87
|
end
|
88
|
+
|
89
|
+
dest
|
90
|
+
end
|
91
|
+
|
92
|
+
# @param src [Pathname]
|
93
|
+
# @return [Pathname]
|
94
|
+
def process_data_file(src)
|
95
|
+
src = src.sub(DATA_DIR, CONTENT_DIR).sub_ext(TEMPLATE_EXT)
|
96
|
+
|
97
|
+
return unless src.exist?
|
98
|
+
|
99
|
+
process_file(src)
|
55
100
|
end
|
56
101
|
|
57
102
|
# @params path [String]
|
@@ -60,13 +105,10 @@ module GryphonNest
|
|
60
105
|
Pathname.glob(path).reject(&:directory?)
|
61
106
|
end
|
62
107
|
|
63
|
-
# @param
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
f.delete
|
68
|
-
end
|
69
|
-
nil
|
108
|
+
# @param file [Pathname]
|
109
|
+
def delete_file(file)
|
110
|
+
@logger.info("Deleting #{file}")
|
111
|
+
file.delete
|
70
112
|
end
|
71
113
|
end
|
72
114
|
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:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christopher Birmingham
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-05-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: htmlbeautifier
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: listen
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.9'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.9'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: mustache
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -44,28 +58,28 @@ dependencies:
|
|
44
58
|
requirements:
|
45
59
|
- - "~>"
|
46
60
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
61
|
+
version: '5.2'
|
48
62
|
type: :runtime
|
49
63
|
prerelease: false
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
66
|
- - "~>"
|
53
67
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
68
|
+
version: '5.2'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: webrick
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
58
72
|
requirements:
|
59
73
|
- - "~>"
|
60
74
|
- !ruby/object:Gem::Version
|
61
|
-
version: '1.
|
75
|
+
version: '1.9'
|
62
76
|
type: :runtime
|
63
77
|
prerelease: false
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
65
79
|
requirements:
|
66
80
|
- - "~>"
|
67
81
|
- !ruby/object:Gem::Version
|
68
|
-
version: '1.
|
82
|
+
version: '1.9'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: bundler
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -107,9 +121,12 @@ files:
|
|
107
121
|
- bin/nest
|
108
122
|
- lib/gryphon_nest.rb
|
109
123
|
- lib/gryphon_nest/errors.rb
|
124
|
+
- lib/gryphon_nest/logging.rb
|
110
125
|
- lib/gryphon_nest/processors.rb
|
111
126
|
- lib/gryphon_nest/processors/asset_processor.rb
|
112
127
|
- lib/gryphon_nest/processors/mustache_processor.rb
|
128
|
+
- lib/gryphon_nest/processors/processor_registry.rb
|
129
|
+
- lib/gryphon_nest/processors/sass_processor.rb
|
113
130
|
- lib/gryphon_nest/renderers.rb
|
114
131
|
- lib/gryphon_nest/renderers/mustache_renderer.rb
|
115
132
|
- lib/gryphon_nest/version.rb
|