gryphon_nest 1.1.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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: []