ngage 0.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.
Files changed (109) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/exe/ngage +55 -0
  4. data/lib/ngage.rb +3 -0
  5. data/lib/ngage/jekyll.rb +204 -0
  6. data/lib/ngage/jekyll/cleaner.rb +111 -0
  7. data/lib/ngage/jekyll/collection.rb +235 -0
  8. data/lib/ngage/jekyll/command.rb +103 -0
  9. data/lib/ngage/jekyll/commands/build.rb +93 -0
  10. data/lib/ngage/jekyll/commands/clean.rb +45 -0
  11. data/lib/ngage/jekyll/commands/doctor.rb +173 -0
  12. data/lib/ngage/jekyll/commands/help.rb +34 -0
  13. data/lib/ngage/jekyll/commands/new.rb +157 -0
  14. data/lib/ngage/jekyll/commands/new_theme.rb +42 -0
  15. data/lib/ngage/jekyll/commands/serve.rb +354 -0
  16. data/lib/ngage/jekyll/commands/serve/live_reload_reactor.rb +122 -0
  17. data/lib/ngage/jekyll/commands/serve/livereload_assets/livereload.js +1183 -0
  18. data/lib/ngage/jekyll/commands/serve/servlet.rb +203 -0
  19. data/lib/ngage/jekyll/commands/serve/websockets.rb +81 -0
  20. data/lib/ngage/jekyll/configuration.rb +391 -0
  21. data/lib/ngage/jekyll/converter.rb +54 -0
  22. data/lib/ngage/jekyll/converters/identity.rb +41 -0
  23. data/lib/ngage/jekyll/converters/markdown.rb +116 -0
  24. data/lib/ngage/jekyll/converters/markdown/kramdown_parser.rb +122 -0
  25. data/lib/ngage/jekyll/converters/smartypants.rb +70 -0
  26. data/lib/ngage/jekyll/convertible.rb +253 -0
  27. data/lib/ngage/jekyll/deprecator.rb +50 -0
  28. data/lib/ngage/jekyll/document.rb +503 -0
  29. data/lib/ngage/jekyll/drops/collection_drop.rb +20 -0
  30. data/lib/ngage/jekyll/drops/document_drop.rb +69 -0
  31. data/lib/ngage/jekyll/drops/drop.rb +209 -0
  32. data/lib/ngage/jekyll/drops/excerpt_drop.rb +15 -0
  33. data/lib/ngage/jekyll/drops/jekyll_drop.rb +32 -0
  34. data/lib/ngage/jekyll/drops/site_drop.rb +56 -0
  35. data/lib/ngage/jekyll/drops/static_file_drop.rb +14 -0
  36. data/lib/ngage/jekyll/drops/unified_payload_drop.rb +26 -0
  37. data/lib/ngage/jekyll/drops/url_drop.rb +89 -0
  38. data/lib/ngage/jekyll/entry_filter.rb +127 -0
  39. data/lib/ngage/jekyll/errors.rb +20 -0
  40. data/lib/ngage/jekyll/excerpt.rb +180 -0
  41. data/lib/ngage/jekyll/external.rb +76 -0
  42. data/lib/ngage/jekyll/filters.rb +390 -0
  43. data/lib/ngage/jekyll/filters/date_filters.rb +110 -0
  44. data/lib/ngage/jekyll/filters/grouping_filters.rb +64 -0
  45. data/lib/ngage/jekyll/filters/url_filters.rb +68 -0
  46. data/lib/ngage/jekyll/frontmatter_defaults.rb +233 -0
  47. data/lib/ngage/jekyll/generator.rb +5 -0
  48. data/lib/ngage/jekyll/hooks.rb +106 -0
  49. data/lib/ngage/jekyll/layout.rb +62 -0
  50. data/lib/ngage/jekyll/liquid_extensions.rb +22 -0
  51. data/lib/ngage/jekyll/liquid_renderer.rb +63 -0
  52. data/lib/ngage/jekyll/liquid_renderer/file.rb +56 -0
  53. data/lib/ngage/jekyll/liquid_renderer/table.rb +98 -0
  54. data/lib/ngage/jekyll/log_adapter.rb +151 -0
  55. data/lib/ngage/jekyll/mime.types +825 -0
  56. data/lib/ngage/jekyll/page.rb +185 -0
  57. data/lib/ngage/jekyll/page_without_a_file.rb +14 -0
  58. data/lib/ngage/jekyll/plugin.rb +92 -0
  59. data/lib/ngage/jekyll/plugin_manager.rb +115 -0
  60. data/lib/ngage/jekyll/publisher.rb +23 -0
  61. data/lib/ngage/jekyll/reader.rb +154 -0
  62. data/lib/ngage/jekyll/readers/collection_reader.rb +22 -0
  63. data/lib/ngage/jekyll/readers/data_reader.rb +75 -0
  64. data/lib/ngage/jekyll/readers/layout_reader.rb +70 -0
  65. data/lib/ngage/jekyll/readers/page_reader.rb +25 -0
  66. data/lib/ngage/jekyll/readers/post_reader.rb +72 -0
  67. data/lib/ngage/jekyll/readers/static_file_reader.rb +25 -0
  68. data/lib/ngage/jekyll/readers/theme_assets_reader.rb +51 -0
  69. data/lib/ngage/jekyll/regenerator.rb +195 -0
  70. data/lib/ngage/jekyll/related_posts.rb +52 -0
  71. data/lib/ngage/jekyll/renderer.rb +266 -0
  72. data/lib/ngage/jekyll/site.rb +476 -0
  73. data/lib/ngage/jekyll/static_file.rb +169 -0
  74. data/lib/ngage/jekyll/stevenson.rb +60 -0
  75. data/lib/ngage/jekyll/tags/highlight.rb +108 -0
  76. data/lib/ngage/jekyll/tags/include.rb +226 -0
  77. data/lib/ngage/jekyll/tags/link.rb +40 -0
  78. data/lib/ngage/jekyll/tags/post_url.rb +104 -0
  79. data/lib/ngage/jekyll/theme.rb +73 -0
  80. data/lib/ngage/jekyll/theme_builder.rb +121 -0
  81. data/lib/ngage/jekyll/url.rb +160 -0
  82. data/lib/ngage/jekyll/utils.rb +370 -0
  83. data/lib/ngage/jekyll/utils/ansi.rb +57 -0
  84. data/lib/ngage/jekyll/utils/exec.rb +26 -0
  85. data/lib/ngage/jekyll/utils/internet.rb +37 -0
  86. data/lib/ngage/jekyll/utils/platforms.rb +82 -0
  87. data/lib/ngage/jekyll/utils/thread_event.rb +31 -0
  88. data/lib/ngage/jekyll/utils/win_tz.rb +75 -0
  89. data/lib/ngage/site_template/.gitignore +5 -0
  90. data/lib/ngage/site_template/404.html +25 -0
  91. data/lib/ngage/site_template/_config.yml +47 -0
  92. data/lib/ngage/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +29 -0
  93. data/lib/ngage/site_template/about.markdown +18 -0
  94. data/lib/ngage/site_template/index.markdown +6 -0
  95. data/lib/ngage/theme_template/CODE_OF_CONDUCT.md.erb +74 -0
  96. data/lib/ngage/theme_template/Gemfile +4 -0
  97. data/lib/ngage/theme_template/LICENSE.txt.erb +21 -0
  98. data/lib/ngage/theme_template/README.md.erb +52 -0
  99. data/lib/ngage/theme_template/_layouts/default.html +1 -0
  100. data/lib/ngage/theme_template/_layouts/page.html +5 -0
  101. data/lib/ngage/theme_template/_layouts/post.html +5 -0
  102. data/lib/ngage/theme_template/example/_config.yml.erb +1 -0
  103. data/lib/ngage/theme_template/example/_post.md +12 -0
  104. data/lib/ngage/theme_template/example/index.html +14 -0
  105. data/lib/ngage/theme_template/example/style.scss +7 -0
  106. data/lib/ngage/theme_template/gitignore.erb +6 -0
  107. data/lib/ngage/theme_template/theme.gemspec.erb +19 -0
  108. data/lib/ngage/version.rb +5 -0
  109. metadata +328 -0
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ class RelatedPosts
5
+ class << self
6
+ attr_accessor :lsi
7
+ end
8
+
9
+ attr_reader :post, :site
10
+
11
+ def initialize(post)
12
+ @post = post
13
+ @site = post.site
14
+ Jekyll::External.require_with_graceful_fail("classifier-reborn") if site.lsi
15
+ end
16
+
17
+ def build
18
+ return [] unless site.posts.docs.size > 1
19
+
20
+ if site.lsi
21
+ build_index
22
+ lsi_related_posts
23
+ else
24
+ most_recent_posts
25
+ end
26
+ end
27
+
28
+ def build_index
29
+ self.class.lsi ||= begin
30
+ lsi = ClassifierReborn::LSI.new(:auto_rebuild => false)
31
+ Jekyll.logger.info("Populating LSI...")
32
+
33
+ site.posts.docs.each do |x|
34
+ lsi.add_item(x)
35
+ end
36
+
37
+ Jekyll.logger.info("Rebuilding index...")
38
+ lsi.build_index
39
+ Jekyll.logger.info("")
40
+ lsi
41
+ end
42
+ end
43
+
44
+ def lsi_related_posts
45
+ self.class.lsi.find_related(post, 11)
46
+ end
47
+
48
+ def most_recent_posts
49
+ @most_recent_posts ||= (site.posts.docs.last(11).reverse - [post]).first(10)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,266 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ class Renderer
5
+ attr_reader :document, :site
6
+ attr_writer :layouts, :payload
7
+
8
+ def initialize(site, document, site_payload = nil)
9
+ @site = site
10
+ @document = document
11
+ @payload = site_payload
12
+ end
13
+
14
+ # Fetches the payload used in Liquid rendering.
15
+ # It can be written with #payload=(new_payload)
16
+ # Falls back to site.site_payload if no payload is set.
17
+ #
18
+ # Returns a Jekyll::Drops::UnifiedPayloadDrop
19
+ def payload
20
+ @payload ||= site.site_payload
21
+ end
22
+
23
+ # The list of layouts registered for this Renderer.
24
+ # It can be written with #layouts=(new_layouts)
25
+ # Falls back to site.layouts if no layouts are registered.
26
+ #
27
+ # Returns a Hash of String => Jekyll::Layout identified
28
+ # as basename without the extension name.
29
+ def layouts
30
+ @layouts || site.layouts
31
+ end
32
+
33
+ # Determine which converters to use based on this document's
34
+ # extension.
35
+ #
36
+ # Returns Array of Converter instances.
37
+ def converters
38
+ @converters ||= site.converters.select { |c| c.matches(document.extname) }.sort
39
+ end
40
+
41
+ # Determine the extname the outputted file should have
42
+ #
43
+ # Returns String the output extname including the leading period.
44
+ def output_ext
45
+ @output_ext ||= (permalink_ext || converter_output_ext)
46
+ end
47
+
48
+ # Prepare payload and render the document
49
+ #
50
+ # Returns String rendered document output
51
+ def run
52
+ Jekyll.logger.debug "Rendering:", document.relative_path
53
+
54
+ assign_pages!
55
+ assign_current_document!
56
+ assign_highlighter_options!
57
+ assign_layout_data!
58
+
59
+ Jekyll.logger.debug "Pre-Render Hooks:", document.relative_path
60
+ document.trigger_hooks(:pre_render, payload)
61
+
62
+ render_document
63
+ end
64
+
65
+ # Render the document.
66
+ #
67
+ # Returns String rendered document output
68
+ # rubocop: disable AbcSize
69
+ def render_document
70
+ info = {
71
+ :registers => { :site => site, :page => payload["page"] },
72
+ :strict_filters => liquid_options["strict_filters"],
73
+ :strict_variables => liquid_options["strict_variables"],
74
+ }
75
+
76
+ output = document.content
77
+ if document.render_with_liquid?
78
+ Jekyll.logger.debug "Rendering Liquid:", document.relative_path
79
+ output = render_liquid(output, payload, info, document.path)
80
+ end
81
+
82
+ Jekyll.logger.debug "Rendering Markup:", document.relative_path
83
+ output = convert(output.to_s)
84
+ document.content = output
85
+
86
+ if document.place_in_layout?
87
+ Jekyll.logger.debug "Rendering Layout:", document.relative_path
88
+ output = place_in_layouts(output, payload, info)
89
+ end
90
+
91
+ output
92
+ end
93
+ # rubocop: enable AbcSize
94
+
95
+ # Convert the document using the converters which match this renderer's document.
96
+ #
97
+ # Returns String the converted content.
98
+ def convert(content)
99
+ converters.reduce(content) do |output, converter|
100
+ begin
101
+ converter.convert output
102
+ rescue StandardError => e
103
+ Jekyll.logger.error "Conversion error:",
104
+ "#{converter.class} encountered an error while "\
105
+ "converting '#{document.relative_path}':"
106
+ Jekyll.logger.error("", e.to_s)
107
+ raise e
108
+ end
109
+ end
110
+ end
111
+
112
+ # Render the given content with the payload and info
113
+ #
114
+ # content -
115
+ # payload -
116
+ # info -
117
+ # path - (optional) the path to the file, for use in ex
118
+ #
119
+ # Returns String the content, rendered by Liquid.
120
+ def render_liquid(content, payload, info, path = nil)
121
+ template = site.liquid_renderer.file(path).parse(content)
122
+ template.warnings.each do |e|
123
+ Jekyll.logger.warn "Liquid Warning:",
124
+ LiquidRenderer.format_error(e, path || document.relative_path)
125
+ end
126
+ template.render!(payload, info)
127
+ # rubocop: disable RescueException
128
+ rescue Exception => e
129
+ Jekyll.logger.error "Liquid Exception:",
130
+ LiquidRenderer.format_error(e, path || document.relative_path)
131
+ raise e
132
+ end
133
+ # rubocop: enable RescueException
134
+
135
+ # Checks if the layout specified in the document actually exists
136
+ #
137
+ # layout - the layout to check
138
+ #
139
+ # Returns Boolean true if the layout is invalid, false if otherwise
140
+ def invalid_layout?(layout)
141
+ !document.data["layout"].nil? && layout.nil? && !(document.is_a? Jekyll::Excerpt)
142
+ end
143
+
144
+ # Render layouts and place document content inside.
145
+ #
146
+ # Returns String rendered content
147
+ def place_in_layouts(content, payload, info)
148
+ output = content.dup
149
+ layout = layouts[document.data["layout"].to_s]
150
+ validate_layout(layout)
151
+
152
+ used = Set.new([layout])
153
+
154
+ # Reset the payload layout data to ensure it starts fresh for each page.
155
+ payload["layout"] = nil
156
+
157
+ while layout
158
+ output = render_layout(output, layout, info)
159
+ add_regenerator_dependencies(layout)
160
+
161
+ next unless (layout = site.layouts[layout.data["layout"]])
162
+ break if used.include?(layout)
163
+
164
+ used << layout
165
+ end
166
+ output
167
+ end
168
+
169
+ private
170
+
171
+ # Checks if the layout specified in the document actually exists
172
+ #
173
+ # layout - the layout to check
174
+ # Returns nothing
175
+ def validate_layout(layout)
176
+ if invalid_layout?(layout)
177
+ Jekyll.logger.warn(
178
+ "Build Warning:",
179
+ "Layout '#{document.data["layout"]}' requested "\
180
+ "in #{document.relative_path} does not exist."
181
+ )
182
+ elsif !layout.nil?
183
+ layout_source = layout.path.start_with?(site.source) ? :site : :theme
184
+ Jekyll.logger.debug "Layout source:", layout_source
185
+ end
186
+ end
187
+
188
+ # Render layout content into document.output
189
+ #
190
+ # Returns String rendered content
191
+ def render_layout(output, layout, info)
192
+ payload["content"] = output
193
+ payload["layout"] = Utils.deep_merge_hashes(layout.data, payload["layout"] || {})
194
+
195
+ render_liquid(
196
+ layout.content,
197
+ payload,
198
+ info,
199
+ layout.relative_path
200
+ )
201
+ end
202
+
203
+ def add_regenerator_dependencies(layout)
204
+ return unless document.write?
205
+
206
+ site.regenerator.add_dependency(
207
+ site.in_source_dir(document.path),
208
+ layout.path
209
+ )
210
+ end
211
+
212
+ # Set page content to payload and assign pager if document has one.
213
+ #
214
+ # Returns nothing
215
+ def assign_pages!
216
+ payload["page"] = document.to_liquid
217
+ payload["paginator"] = (document.pager.to_liquid if document.respond_to?(:pager))
218
+ end
219
+
220
+ # Set related posts to payload if document is a post.
221
+ #
222
+ # Returns nothing
223
+ def assign_current_document!
224
+ payload["site"].current_document = document
225
+ end
226
+
227
+ # Set highlighter prefix and suffix
228
+ #
229
+ # Returns nothing
230
+ def assign_highlighter_options!
231
+ payload["highlighter_prefix"] = converters.first.highlighter_prefix
232
+ payload["highlighter_suffix"] = converters.first.highlighter_suffix
233
+ end
234
+
235
+ def assign_layout_data!
236
+ layout = layouts[document.data["layout"]]
237
+ payload["layout"] = Utils.deep_merge_hashes(layout.data, payload["layout"] || {}) if layout
238
+ end
239
+
240
+ def permalink_ext
241
+ document_permalink = document.permalink
242
+ if document_permalink && !document_permalink.end_with?("/")
243
+ permalink_ext = File.extname(document_permalink)
244
+ permalink_ext unless permalink_ext.empty?
245
+ end
246
+ end
247
+
248
+ def converter_output_ext
249
+ if output_exts.size == 1
250
+ output_exts.last
251
+ else
252
+ output_exts[-2]
253
+ end
254
+ end
255
+
256
+ def output_exts
257
+ @output_exts ||= converters.map do |c|
258
+ c.output_ext(document.extname)
259
+ end.compact
260
+ end
261
+
262
+ def liquid_options
263
+ @liquid_options ||= site.config["liquid"]
264
+ end
265
+ end
266
+ end
@@ -0,0 +1,476 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ class Site
5
+ attr_reader :source, :dest, :config
6
+ attr_accessor :layouts, :pages, :static_files, :drafts,
7
+ :exclude, :include, :lsi, :highlighter, :permalink_style,
8
+ :time, :future, :unpublished, :safe, :plugins, :limit_posts,
9
+ :show_drafts, :keep_files, :baseurl, :data, :file_read_opts,
10
+ :gems, :plugin_manager, :theme
11
+
12
+ attr_accessor :converters, :generators, :reader
13
+ attr_reader :regenerator, :liquid_renderer, :includes_load_paths
14
+
15
+ # Public: Initialize a new Site.
16
+ #
17
+ # config - A Hash containing site configuration details.
18
+ def initialize(config)
19
+ # Source and destination may not be changed after the site has been created.
20
+ @source = File.expand_path(config["source"]).freeze
21
+ @dest = File.expand_path(config["destination"]).freeze
22
+
23
+ self.config = config
24
+
25
+ @reader = Reader.new(self)
26
+ @regenerator = Regenerator.new(self)
27
+ @liquid_renderer = LiquidRenderer.new(self)
28
+
29
+ Jekyll.sites << self
30
+
31
+ reset
32
+ setup
33
+
34
+ Jekyll::Hooks.trigger :site, :after_init, self
35
+ end
36
+
37
+ # Public: Set the site's configuration. This handles side-effects caused by
38
+ # changing values in the configuration.
39
+ #
40
+ # config - a Jekyll::Configuration, containing the new configuration.
41
+ #
42
+ # Returns the new configuration.
43
+ def config=(config)
44
+ @config = config.clone
45
+
46
+ %w(safe lsi highlighter baseurl exclude include future unpublished
47
+ show_drafts limit_posts keep_files).each do |opt|
48
+ send("#{opt}=", config[opt])
49
+ end
50
+
51
+ # keep using `gems` to avoid breaking change
52
+ self.gems = config["plugins"]
53
+
54
+ configure_plugins
55
+ configure_theme
56
+ configure_include_paths
57
+ configure_file_read_opts
58
+
59
+ self.permalink_style = config["permalink"].to_sym
60
+
61
+ @config
62
+ end
63
+
64
+ # Public: Read, process, and write this Site to output.
65
+ #
66
+ # Returns nothing.
67
+ def process
68
+ reset
69
+ read
70
+ generate
71
+ render
72
+ cleanup
73
+ write
74
+ print_stats if config["profile"]
75
+ end
76
+
77
+ def print_stats
78
+ Jekyll.logger.info @liquid_renderer.stats_table
79
+ end
80
+
81
+ # Reset Site details.
82
+ #
83
+ # Returns nothing
84
+ def reset
85
+ self.time = if config["time"]
86
+ Utils.parse_date(config["time"].to_s, "Invalid time in _config.yml.")
87
+ else
88
+ Time.now
89
+ end
90
+ self.layouts = {}
91
+ self.pages = []
92
+ self.static_files = []
93
+ self.data = {}
94
+ @site_data = nil
95
+ @collections = nil
96
+ @docs_to_write = nil
97
+ @regenerator.clear_cache
98
+ @liquid_renderer.reset
99
+ @site_cleaner = nil
100
+
101
+ raise ArgumentError, "limit_posts must be a non-negative number" if limit_posts.negative?
102
+
103
+ Jekyll::Hooks.trigger :site, :after_reset, self
104
+ end
105
+
106
+ # Load necessary libraries, plugins, converters, and generators.
107
+ #
108
+ # Returns nothing.
109
+ def setup
110
+ ensure_not_in_dest
111
+
112
+ plugin_manager.conscientious_require
113
+
114
+ self.converters = instantiate_subclasses(Jekyll::Converter)
115
+ self.generators = instantiate_subclasses(Jekyll::Generator)
116
+ end
117
+
118
+ # Check that the destination dir isn't the source dir or a directory
119
+ # parent to the source dir.
120
+ def ensure_not_in_dest
121
+ dest_pathname = Pathname.new(dest)
122
+ Pathname.new(source).ascend do |path|
123
+ if path == dest_pathname
124
+ raise Errors::FatalException,
125
+ "Destination directory cannot be or contain the Source directory."
126
+ end
127
+ end
128
+ end
129
+
130
+ # The list of collections and their corresponding Jekyll::Collection instances.
131
+ # If config['collections'] is set, a new instance is created
132
+ # for each item in the collection, a new hash is returned otherwise.
133
+ #
134
+ # Returns a Hash containing collection name-to-instance pairs.
135
+ def collections
136
+ @collections ||= Hash[collection_names.map do |coll|
137
+ [coll, Jekyll::Collection.new(self, coll)]
138
+ end]
139
+ end
140
+
141
+ # The list of collection names.
142
+ #
143
+ # Returns an array of collection names from the configuration,
144
+ # or an empty array if the `collections` key is not set.
145
+ def collection_names
146
+ case config["collections"]
147
+ when Hash
148
+ config["collections"].keys
149
+ when Array
150
+ config["collections"]
151
+ when nil
152
+ []
153
+ else
154
+ raise ArgumentError, "Your `collections` key must be a hash or an array."
155
+ end
156
+ end
157
+
158
+ # Read Site data from disk and load it into internal data structures.
159
+ #
160
+ # Returns nothing.
161
+ def read
162
+ reader.read
163
+ limit_posts!
164
+ Jekyll::Hooks.trigger :site, :post_read, self
165
+ end
166
+
167
+ # Run each of the Generators.
168
+ #
169
+ # Returns nothing.
170
+ def generate
171
+ generators.each do |generator|
172
+ start = Time.now
173
+ generator.generate(self)
174
+ Jekyll.logger.debug "Generating:",
175
+ "#{generator.class} finished in #{Time.now - start} seconds."
176
+ end
177
+ end
178
+
179
+ # Render the site to the destination.
180
+ #
181
+ # Returns nothing.
182
+ def render
183
+ relative_permalinks_are_deprecated
184
+
185
+ payload = site_payload
186
+
187
+ Jekyll::Hooks.trigger :site, :pre_render, self, payload
188
+
189
+ render_docs(payload)
190
+ render_pages(payload)
191
+
192
+ Jekyll::Hooks.trigger :site, :post_render, self, payload
193
+ end
194
+
195
+ # Remove orphaned files and empty directories in destination.
196
+ #
197
+ # Returns nothing.
198
+ def cleanup
199
+ site_cleaner.cleanup!
200
+ end
201
+
202
+ # Write static files, pages, and posts.
203
+ #
204
+ # Returns nothing.
205
+ def write
206
+ each_site_file do |item|
207
+ item.write(dest) if regenerator.regenerate?(item)
208
+ end
209
+ regenerator.write_metadata
210
+ Jekyll::Hooks.trigger :site, :post_write, self
211
+ end
212
+
213
+ def posts
214
+ collections["posts"] ||= Collection.new(self, "posts")
215
+ end
216
+
217
+ # Construct a Hash of Posts indexed by the specified Post attribute.
218
+ #
219
+ # post_attr - The String name of the Post attribute.
220
+ #
221
+ # Examples
222
+ #
223
+ # post_attr_hash('categories')
224
+ # # => { 'tech' => [<Post A>, <Post B>],
225
+ # # 'ruby' => [<Post B>] }
226
+ #
227
+ # Returns the Hash: { attr => posts } where
228
+ # attr - One of the values for the requested attribute.
229
+ # posts - The Array of Posts with the given attr value.
230
+ def post_attr_hash(post_attr)
231
+ # Build a hash map based on the specified post attribute ( post attr =>
232
+ # array of posts ) then sort each array in reverse order.
233
+ hash = Hash.new { |h, key| h[key] = [] }
234
+ posts.docs.each do |p|
235
+ p.data[post_attr]&.each { |t| hash[t] << p }
236
+ end
237
+ hash.each_value { |posts| posts.sort!.reverse! }
238
+ hash
239
+ end
240
+
241
+ def tags
242
+ post_attr_hash("tags")
243
+ end
244
+
245
+ def categories
246
+ post_attr_hash("categories")
247
+ end
248
+
249
+ # Prepare site data for site payload. The method maintains backward compatibility
250
+ # if the key 'data' is already used in _config.yml.
251
+ #
252
+ # Returns the Hash to be hooked to site.data.
253
+ def site_data
254
+ @site_data ||= (config["data"] || data)
255
+ end
256
+
257
+ # The Hash payload containing site-wide data.
258
+ #
259
+ # Returns the Hash: { "site" => data } where data is a Hash with keys:
260
+ # "time" - The Time as specified in the configuration or the
261
+ # current time if none was specified.
262
+ # "posts" - The Array of Posts, sorted chronologically by post date
263
+ # and then title.
264
+ # "pages" - The Array of all Pages.
265
+ # "html_pages" - The Array of HTML Pages.
266
+ # "categories" - The Hash of category values and Posts.
267
+ # See Site#post_attr_hash for type info.
268
+ # "tags" - The Hash of tag values and Posts.
269
+ # See Site#post_attr_hash for type info.
270
+ def site_payload
271
+ Drops::UnifiedPayloadDrop.new self
272
+ end
273
+ alias_method :to_liquid, :site_payload
274
+
275
+ # Get the implementation class for the given Converter.
276
+ # Returns the Converter instance implementing the given Converter.
277
+ # klass - The Class of the Converter to fetch.
278
+ def find_converter_instance(klass)
279
+ @find_converter_instance ||= {}
280
+ @find_converter_instance[klass] ||= begin
281
+ converters.find { |converter| converter.instance_of?(klass) } || \
282
+ raise("No Converters found for #{klass}")
283
+ end
284
+ end
285
+
286
+ # klass - class or module containing the subclasses.
287
+ # Returns array of instances of subclasses of parameter.
288
+ # Create array of instances of the subclasses of the class or module
289
+ # passed in as argument.
290
+
291
+ def instantiate_subclasses(klass)
292
+ klass.descendants.select { |c| !safe || c.safe }.sort.map do |c|
293
+ c.new(config)
294
+ end
295
+ end
296
+
297
+ # Warns the user if permanent links are relative to the parent
298
+ # directory. As this is a deprecated function of Jekyll.
299
+ #
300
+ # Returns
301
+ def relative_permalinks_are_deprecated
302
+ if config["relative_permalinks"]
303
+ Jekyll.logger.abort_with "Since v3.0, permalinks for pages" \
304
+ " in subfolders must be relative to the" \
305
+ " site source directory, not the parent" \
306
+ " directory. Check https://jekyllrb.com/docs/upgrading/"\
307
+ " for more info."
308
+ end
309
+ end
310
+
311
+ # Get the to be written documents
312
+ #
313
+ # Returns an Array of Documents which should be written
314
+ def docs_to_write
315
+ @docs_to_write ||= documents.select(&:write?)
316
+ end
317
+
318
+ # Get all the documents
319
+ #
320
+ # Returns an Array of all Documents
321
+ def documents
322
+ collections.reduce(Set.new) do |docs, (_, collection)|
323
+ docs + collection.docs + collection.files
324
+ end.to_a
325
+ end
326
+
327
+ def each_site_file
328
+ %w(pages static_files docs_to_write).each do |type|
329
+ send(type).each do |item|
330
+ yield item
331
+ end
332
+ end
333
+ end
334
+
335
+ # Returns the FrontmatterDefaults or creates a new FrontmatterDefaults
336
+ # if it doesn't already exist.
337
+ #
338
+ # Returns The FrontmatterDefaults
339
+ def frontmatter_defaults
340
+ @frontmatter_defaults ||= FrontmatterDefaults.new(self)
341
+ end
342
+
343
+ # Whether to perform a full rebuild without incremental regeneration
344
+ #
345
+ # Returns a Boolean: true for a full rebuild, false for normal build
346
+ def incremental?(override = {})
347
+ override["incremental"] || config["incremental"]
348
+ end
349
+
350
+ # Returns the publisher or creates a new publisher if it doesn't
351
+ # already exist.
352
+ #
353
+ # Returns The Publisher
354
+ def publisher
355
+ @publisher ||= Publisher.new(self)
356
+ end
357
+
358
+ # Public: Prefix a given path with the source directory.
359
+ #
360
+ # paths - (optional) path elements to a file or directory within the
361
+ # source directory
362
+ #
363
+ # Returns a path which is prefixed with the source directory.
364
+ def in_source_dir(*paths)
365
+ paths.reduce(source) do |base, path|
366
+ Jekyll.sanitized_path(base, path)
367
+ end
368
+ end
369
+
370
+ # Public: Prefix a given path with the theme directory.
371
+ #
372
+ # paths - (optional) path elements to a file or directory within the
373
+ # theme directory
374
+ #
375
+ # Returns a path which is prefixed with the theme root directory.
376
+ def in_theme_dir(*paths)
377
+ return nil unless theme
378
+
379
+ paths.reduce(theme.root) do |base, path|
380
+ Jekyll.sanitized_path(base, path)
381
+ end
382
+ end
383
+
384
+ # Public: Prefix a given path with the destination directory.
385
+ #
386
+ # paths - (optional) path elements to a file or directory within the
387
+ # destination directory
388
+ #
389
+ # Returns a path which is prefixed with the destination directory.
390
+ def in_dest_dir(*paths)
391
+ paths.reduce(dest) do |base, path|
392
+ Jekyll.sanitized_path(base, path)
393
+ end
394
+ end
395
+
396
+ # Public: The full path to the directory that houses all the collections registered
397
+ # with the current site.
398
+ #
399
+ # Returns the source directory or the absolute path to the custom collections_dir
400
+ def collections_path
401
+ dir_str = config["collections_dir"]
402
+ @collections_path ||= dir_str.empty? ? source : in_source_dir(dir_str)
403
+ end
404
+
405
+ private
406
+
407
+ # Limits the current posts; removes the posts which exceed the limit_posts
408
+ #
409
+ # Returns nothing
410
+ def limit_posts!
411
+ if limit_posts.positive?
412
+ limit = posts.docs.length < limit_posts ? posts.docs.length : limit_posts
413
+ posts.docs = posts.docs[-limit, limit]
414
+ end
415
+ end
416
+
417
+ # Returns the Cleaner or creates a new Cleaner if it doesn't
418
+ # already exist.
419
+ #
420
+ # Returns The Cleaner
421
+ def site_cleaner
422
+ @site_cleaner ||= Cleaner.new(self)
423
+ end
424
+
425
+ def configure_plugins
426
+ self.plugin_manager = Jekyll::PluginManager.new(self)
427
+ self.plugins = plugin_manager.plugins_path
428
+ end
429
+
430
+ def configure_theme
431
+ self.theme = nil
432
+ return if config["theme"].nil?
433
+
434
+ self.theme =
435
+ if config["theme"].is_a?(String)
436
+ Jekyll::Theme.new(config["theme"])
437
+ else
438
+ Jekyll.logger.warn "Theme:", "value of 'theme' in config should be " \
439
+ "String to use gem-based themes, but got #{config["theme"].class}"
440
+ nil
441
+ end
442
+ end
443
+
444
+ def configure_include_paths
445
+ @includes_load_paths = Array(in_source_dir(config["includes_dir"].to_s))
446
+ @includes_load_paths << theme.includes_path if theme&.includes_path
447
+ end
448
+
449
+ def configure_file_read_opts
450
+ self.file_read_opts = {}
451
+ file_read_opts[:encoding] = config["encoding"] if config["encoding"]
452
+ self.file_read_opts = Jekyll::Utils.merged_file_read_opts(self, {})
453
+ end
454
+
455
+ def render_docs(payload)
456
+ collections.each_value do |collection|
457
+ collection.docs.each do |document|
458
+ render_regenerated(document, payload)
459
+ end
460
+ end
461
+ end
462
+
463
+ def render_pages(payload)
464
+ pages.flatten.each do |page|
465
+ render_regenerated(page, payload)
466
+ end
467
+ end
468
+
469
+ def render_regenerated(document, payload)
470
+ return unless regenerator.regenerate?(document)
471
+
472
+ document.output = Jekyll::Renderer.new(self, document, payload).run
473
+ document.trigger_hooks(:post_render)
474
+ end
475
+ end
476
+ end