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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 773f8de17a88d769b28ca4a19a9f7f0f1a916b865d3363262515cee758be13d3
4
- data.tar.gz: e597a97c55f7f34ab8aa2498d608eb1b18e8363bb866549fa5cd514303f8ef1e
3
+ metadata.gz: 72b699d93837e7f59c74c2782f38526c2f6bc869d6af875bc174d13e29951560
4
+ data.tar.gz: 6150b1914e70d54e352d181c15750a57c524ae8271ce25de5bb976da4cb0bbf8
5
5
  SHA512:
6
- metadata.gz: 70b4641bc1e84078c37edf1ba0f1c06cda9ec0252133c7a05ac52264a76789c9c8cacfca2e930c631eaa938ce325c3f1a293815685ead2ee70265060e535928c
7
- data.tar.gz: 4989b444b40a22778a4b308637bca2b3630ded3ec4a87deb65ec4a231c0d3dead50f3fe5511a73d723a069907ebb85c221106b024f0b9592446003c7bddcd64a
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
- warn parser
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
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GryphonNest
4
+ class NotFoundError < StandardError; end
5
+ 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 layouts [Array]
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 render(template, layout, context)
19
- File.open(template) do |f|
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
- unless layout.nil?
24
- context[:yield] = content
25
- content = render_template(layout, context)
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
- private
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 path [String]
42
- # @return [String|null]
43
- def get_template_layout(path)
44
- return @layouts[path] if @layouts.key?(path)
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.open(path) do |file|
49
- content = file.read
50
- @layouts[path] = content
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GryphonNest
4
- VERSION = '1.1.1'
4
+ VERSION = '1.3.0'
5
5
  end
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 = filter_glob("#{BUILD_DIR}/**/*")
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
- cleanup(existing_files)
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 template_name [String]
47
- # @return [String]
48
- def get_output_name(template_name)
49
- dir = File.dirname(template_name)
50
- basename = File.basename(template_name, TEMPLATE_EXT)
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 = Pathname.new(dir)
53
- path = path.sub(CONTENT_DIR, BUILD_DIR)
57
+ path = path.join(basename) if basename.to_s != 'index'
54
58
 
55
- path = path.join(basename) if basename != 'index'
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 src [String]
84
- # @param dest [String]
85
- # @param layout_file [String]
86
- # @param context_file [String]
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 can_create_html_file?(src, dest, layout_file, context_file)
89
- return true unless File.exist?(dest)
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 File.exist?(layout_file)
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
- false
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 [String]
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 File.exist?(path)
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.to_s
88
+ return path
122
89
  end
123
90
 
124
- path.join('main.mustache').to_s
91
+ DEFAULT_LAYOUT if DEFAULT_LAYOUT.exist?
125
92
  end
126
93
 
127
- # @param path [String]
94
+ # @param path [Pathname, nil]
128
95
  # @return [Hash]
129
- def read_context_file(path)
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 [String]
140
- # @return [String]
104
+ # @param name [Pathname]
105
+ # @return [Pathname, nil]
141
106
  def get_context_file(name)
142
- basename = File.basename(name, TEMPLATE_EXT)
107
+ basename = name.basename(TEMPLATE_EXT)
108
+ FileUtil.glob("#{DATA_DIR}/#{basename}.{yaml,yml}")[0]
109
+ end
143
110
 
144
- Dir.glob("#{DATA_DIR}/#{basename}.{yaml,yml}") do |f|
145
- return f
146
- end
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
- filter_glob("#{CONTENT_DIR}/**/*").each do |template|
157
- if File.extname(template) != TEMPLATE_EXT
158
- puts "Skipping non template file #{template}"
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(template)
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
- next unless can_create_html_file?(template, dest_file, layout_file, context_file)
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
- filter_glob("#{ASSETS_DIR}/**/*").each do |asset|
192
- dest = Pathname.new(asset)
193
- dest = dest.sub(ASSETS_DIR, BUILD_DIR)
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 can_copy_asset?(asset, dest)
156
+ next unless FileUtil.file_newer?(asset, dest)
197
157
 
198
158
  puts "Copying #{asset} to #{dest}"
199
- dest_dir = File.dirname(dest)
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.1.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-04-22 00:00:00.000000000 Z
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.1.2
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: []