From 5571dc766e2143e39762ff0b47c41d1c2e154f4c Mon Sep 17 00:00:00 2001 From: Benjamin Sanders Date: Sat, 11 Oct 2025 10:34:24 -0400 Subject: Vendor bundled gems for deployment --- .../3.4.0/gems/jekyll-4.4.1/lib/jekyll/site.rb | 576 +++++++++++++++++++++ 1 file changed, 576 insertions(+) create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/site.rb (limited to 'vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/site.rb') diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/site.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/site.rb new file mode 100644 index 0000000..adec4cc --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/site.rb @@ -0,0 +1,576 @@ +# frozen_string_literal: true + +module Jekyll + class Site + attr_accessor :baseurl, :converters, :data, :drafts, :exclude, + :file_read_opts, :future, :gems, :generators, :highlighter, + :include, :inclusions, :keep_files, :layouts, :limit_posts, + :lsi, :pages, :permalink_style, :plugin_manager, :plugins, + :reader, :safe, :show_drafts, :static_files, :theme, :time, + :unpublished + + attr_reader :cache_dir, :config, :dest, :filter_cache, :includes_load_paths, + :liquid_renderer, :profiler, :regenerator, :source + + # Public: Initialize a new Site. + # + # config - A Hash containing site configuration details. + def initialize(config) + # Source and destination may not be changed after the site has been created. + @source = File.expand_path(config["source"]).freeze + @dest = File.expand_path(config["destination"]).freeze + + self.config = config + + @cache_dir = in_source_dir(config["cache_dir"]) + @filter_cache = {} + + @reader = Reader.new(self) + @profiler = Profiler.new(self) + @regenerator = Regenerator.new(self) + @liquid_renderer = LiquidRenderer.new(self) + + Jekyll.sites << self + + reset + setup + + Jekyll::Hooks.trigger :site, :after_init, self + end + + # Public: Set the site's configuration. This handles side-effects caused by + # changing values in the configuration. + # + # config - a Jekyll::Configuration, containing the new configuration. + # + # Returns the new configuration. + def config=(config) + @config = config.clone + + %w(safe lsi highlighter baseurl exclude include future unpublished + show_drafts limit_posts keep_files).each do |opt| + send(:"#{opt}=", config[opt]) + end + + # keep using `gems` to avoid breaking change + self.gems = config["plugins"] + + configure_cache + configure_plugins + configure_theme + configure_include_paths + configure_file_read_opts + + self.permalink_style = config["permalink"].to_sym + + # Read in a _config.yml from the current theme-gem at the very end. + @config = load_theme_configuration(config) if theme + @config + end + + # Public: Read, process, and write this Site to output. + # + # Returns nothing. + def process + return profiler.profile_process if config["profile"] + + reset + read + generate + render + cleanup + write + end + + def print_stats + Jekyll.logger.info @liquid_renderer.stats_table + end + + # rubocop:disable Metrics/AbcSize + # rubocop:disable Metrics/MethodLength + # + # Reset Site details. + # + # Returns nothing + def reset + self.time = if config["time"] + Utils.parse_date(config["time"].to_s, "Invalid time in _config.yml.") + else + Time.now + end + self.layouts = {} + self.inclusions = {} + self.pages = [] + self.static_files = [] + self.data = {} + @post_attr_hash = {} + @site_data = nil + @collections = nil + @documents = nil + @docs_to_write = nil + @regenerator.clear_cache + @liquid_renderer.reset + @site_cleaner = nil + frontmatter_defaults.reset + + raise ArgumentError, "limit_posts must be a non-negative number" if limit_posts.negative? + + Jekyll::Cache.clear_if_config_changed config + Jekyll::Hooks.trigger :site, :after_reset, self + nil + end + # rubocop:enable Metrics/MethodLength + # rubocop:enable Metrics/AbcSize + + # Load necessary libraries, plugins, converters, and generators. + # + # Returns nothing. + def setup + ensure_not_in_dest + + plugin_manager.conscientious_require + + self.converters = instantiate_subclasses(Jekyll::Converter) + self.generators = instantiate_subclasses(Jekyll::Generator) + end + + # Check that the destination dir isn't the source dir or a directory + # parent to the source dir. + def ensure_not_in_dest + dest_pathname = Pathname.new(dest) + Pathname.new(source).ascend do |path| + if path == dest_pathname + raise Errors::FatalException, + "Destination directory cannot be or contain the Source directory." + end + end + end + + # The list of collections and their corresponding Jekyll::Collection instances. + # If config['collections'] is set, a new instance is created + # for each item in the collection, a new hash is returned otherwise. + # + # Returns a Hash containing collection name-to-instance pairs. + def collections + @collections ||= collection_names.each_with_object({}) do |name, hsh| + hsh[name] = Jekyll::Collection.new(self, name) + end + end + + # The list of collection names. + # + # Returns an array of collection names from the configuration, + # or an empty array if the `collections` key is not set. + def collection_names + case config["collections"] + when Hash + config["collections"].keys + when Array + config["collections"] + when nil + [] + else + raise ArgumentError, "Your `collections` key must be a hash or an array." + end + end + + # Read Site data from disk and load it into internal data structures. + # + # Returns nothing. + def read + reader.read + limit_posts! + Jekyll::Hooks.trigger :site, :post_read, self + nil + end + + # Run each of the Generators. + # + # Returns nothing. + def generate + generators.each do |generator| + start = Time.now + generator.generate(self) + Jekyll.logger.debug "Generating:", + "#{generator.class} finished in #{Time.now - start} seconds." + end + nil + end + + # Render the site to the destination. + # + # Returns nothing. + def render + relative_permalinks_are_deprecated + + payload = site_payload + + Jekyll::Hooks.trigger :site, :pre_render, self, payload + + render_docs(payload) + render_pages(payload) + + Jekyll::Hooks.trigger :site, :post_render, self, payload + nil + end + + # Remove orphaned files and empty directories in destination. + # + # Returns nothing. + def cleanup + site_cleaner.cleanup! + nil + end + + # Write static files, pages, and posts. + # + # Returns nothing. + def write + Jekyll::Commands::Doctor.conflicting_urls(self) + each_site_file do |item| + item.write(dest) if regenerator.regenerate?(item) + end + regenerator.write_metadata + Jekyll::Hooks.trigger :site, :post_write, self + nil + end + + def posts + collections["posts"] ||= Collection.new(self, "posts") + end + + # Construct a Hash of Posts indexed by the specified Post attribute. + # + # post_attr - The String name of the Post attribute. + # + # Examples + # + # post_attr_hash('categories') + # # => { 'tech' => [, ], + # # 'ruby' => [] } + # + # Returns the Hash: { attr => posts } where + # attr - One of the values for the requested attribute. + # posts - The Array of Posts with the given attr value. + def post_attr_hash(post_attr) + # Build a hash map based on the specified post attribute ( post attr => + # array of posts ) then sort each array in reverse order. + @post_attr_hash[post_attr] ||= begin + hash = Hash.new { |h, key| h[key] = [] } + posts.docs.each do |p| + p.data[post_attr]&.each { |t| hash[t] << p } + end + hash.each_value { |posts| posts.sort!.reverse! } + hash + end + end + + def tags + post_attr_hash("tags") + end + + def categories + post_attr_hash("categories") + end + + # Prepare site data for site payload. The method maintains backward compatibility + # if the key 'data' is already used in _config.yml. + # + # Returns the Hash to be hooked to site.data. + def site_data + @site_data ||= (config["data"] || data) + end + + # The Hash payload containing site-wide data. + # + # Returns the Hash: { "site" => data } where data is a Hash with keys: + # "time" - The Time as specified in the configuration or the + # current time if none was specified. + # "posts" - The Array of Posts, sorted chronologically by post date + # and then title. + # "pages" - The Array of all Pages. + # "html_pages" - The Array of HTML Pages. + # "categories" - The Hash of category values and Posts. + # See Site#post_attr_hash for type info. + # "tags" - The Hash of tag values and Posts. + # See Site#post_attr_hash for type info. + def site_payload + Drops::UnifiedPayloadDrop.new self + end + alias_method :to_liquid, :site_payload + + # Get the implementation class for the given Converter. + # Returns the Converter instance implementing the given Converter. + # klass - The Class of the Converter to fetch. + def find_converter_instance(klass) + @find_converter_instance ||= {} + @find_converter_instance[klass] ||= converters.find do |converter| + converter.instance_of?(klass) + end || \ + raise("No Converters found for #{klass}") + end + + # klass - class or module containing the subclasses. + # Returns array of instances of subclasses of parameter. + # Create array of instances of the subclasses of the class or module + # passed in as argument. + + def instantiate_subclasses(klass) + klass.descendants.select { |c| !safe || c.safe }.tap do |result| + result.sort! + result.map! { |c| c.new(config) } + end + end + + # Warns the user if permanent links are relative to the parent + # directory. As this is a deprecated function of Jekyll. + # + # Returns + def relative_permalinks_are_deprecated + if config["relative_permalinks"] + Jekyll.logger.abort_with "Since v3.0, permalinks for pages " \ + "in subfolders must be relative to the " \ + "site source directory, not the parent " \ + "directory. Check https://jekyllrb.com/docs/upgrading/ " \ + "for more info." + end + end + + # Get the to be written documents + # + # Returns an Array of Documents which should be written + def docs_to_write + documents.select(&:write?) + end + + # Get the to be written static files + # + # Returns an Array of StaticFiles which should be written + def static_files_to_write + static_files.select(&:write?) + end + + # Get all the documents + # + # Returns an Array of all Documents + def documents + collections.each_with_object(Set.new) do |(_, collection), set| + set.merge(collection.docs).merge(collection.files) + end.to_a + end + + def each_site_file + pages.each { |page| yield page } + static_files.each { |file| yield(file) if file.write? } + collections.each_value { |coll| coll.docs.each { |doc| yield(doc) if doc.write? } } + end + + # Returns the FrontmatterDefaults or creates a new FrontmatterDefaults + # if it doesn't already exist. + # + # Returns The FrontmatterDefaults + def frontmatter_defaults + @frontmatter_defaults ||= FrontmatterDefaults.new(self) + end + + # Whether to perform a full rebuild without incremental regeneration + # + # Returns a Boolean: true for a full rebuild, false for normal build + def incremental?(override = {}) + override["incremental"] || config["incremental"] + end + + # Returns the publisher or creates a new publisher if it doesn't + # already exist. + # + # Returns The Publisher + def publisher + @publisher ||= Publisher.new(self) + end + + # Public: Prefix a given path with the source directory. + # + # paths - (optional) path elements to a file or directory within the + # source directory + # + # Returns a path which is prefixed with the source directory. + def in_source_dir(*paths) + paths.reduce(source) do |base, path| + Jekyll.sanitized_path(base, path) + end + end + + # Public: Prefix a given path with the theme directory. + # + # paths - (optional) path elements to a file or directory within the + # theme directory + # + # Returns a path which is prefixed with the theme root directory. + def in_theme_dir(*paths) + return nil unless theme + + paths.reduce(theme.root) do |base, path| + Jekyll.sanitized_path(base, path) + end + end + + # Public: Prefix a given path with the destination directory. + # + # paths - (optional) path elements to a file or directory within the + # destination directory + # + # Returns a path which is prefixed with the destination directory. + def in_dest_dir(*paths) + paths.reduce(dest) do |base, path| + Jekyll.sanitized_path(base, path) + end + end + + # Public: Prefix a given path with the cache directory. + # + # paths - (optional) path elements to a file or directory within the + # cache directory + # + # Returns a path which is prefixed with the cache directory. + def in_cache_dir(*paths) + paths.reduce(cache_dir) do |base, path| + Jekyll.sanitized_path(base, path) + end + end + + # Public: The full path to the directory that houses all the collections registered + # with the current site. + # + # Returns the source directory or the absolute path to the custom collections_dir + def collections_path + dir_str = config["collections_dir"] + @collections_path ||= dir_str.empty? ? source : in_source_dir(dir_str) + end + + # Public + # + # Returns the object as a debug String. + def inspect + "#<#{self.class} @source=#{@source}>" + end + + private + + def load_theme_configuration(config) + return config if config["ignore_theme_config"] == true + + theme_config_file = in_theme_dir("_config.yml") + return config unless File.exist?(theme_config_file) + + # Bail out if the theme_config_file is a symlink file irrespective of safe mode + return config if File.symlink?(theme_config_file) + + theme_config = SafeYAML.load_file(theme_config_file) + return config unless theme_config.is_a?(Hash) + + Jekyll.logger.info "Theme Config file:", theme_config_file + + # theme_config should not be overriding Jekyll's defaults + theme_config.delete_if { |key, _| Configuration::DEFAULTS.key?(key) } + + # Override theme_config with existing config and return the result. + # Additionally ensure we return a `Jekyll::Configuration` instance instead of a Hash. + Utils.deep_merge_hashes(theme_config, config) + .each_with_object(Jekyll::Configuration.new) do |(key, value), conf| + conf[key] = value + end + end + + # Limits the current posts; removes the posts which exceed the limit_posts + # + # Returns nothing + def limit_posts! + if limit_posts.positive? + limit = [posts.docs.length, limit_posts].min + posts.docs = posts.docs[-limit, limit] + end + end + + # Returns the Cleaner or creates a new Cleaner if it doesn't + # already exist. + # + # Returns The Cleaner + def site_cleaner + @site_cleaner ||= Cleaner.new(self) + end + + def hide_cache_dir_from_git + @cache_gitignore_path ||= in_source_dir(config["cache_dir"], ".gitignore") + return if File.exist?(@cache_gitignore_path) + + cache_dir_path = in_source_dir(config["cache_dir"]) + FileUtils.mkdir_p(cache_dir_path) unless File.directory?(cache_dir_path) + + File.open(@cache_gitignore_path, "wb") do |file| + file.puts("# ignore everything in this directory\n*") + end + end + + # Disable Marshaling cache to disk in Safe Mode + def configure_cache + Jekyll::Cache.cache_dir = in_source_dir(config["cache_dir"], "Jekyll/Cache") + if safe || config["disable_disk_cache"] + Jekyll::Cache.disable_disk_cache! + else + hide_cache_dir_from_git + end + end + + def configure_plugins + self.plugin_manager = Jekyll::PluginManager.new(self) + self.plugins = plugin_manager.plugins_path + end + + def configure_theme + self.theme = nil + return if config["theme"].nil? + + self.theme = + if config["theme"].is_a?(String) + Jekyll::Theme.new(config["theme"]) + else + Jekyll.logger.warn "Theme:", "value of 'theme' in config should be String to use " \ + "gem-based themes, but got #{config["theme"].class}" + nil + end + end + + def configure_include_paths + @includes_load_paths = Array(in_source_dir(config["includes_dir"].to_s)) + @includes_load_paths << theme.includes_path if theme&.includes_path + end + + def configure_file_read_opts + self.file_read_opts = {} + file_read_opts[:encoding] = config["encoding"] if config["encoding"] + self.file_read_opts = Jekyll::Utils.merged_file_read_opts(self, {}) + end + + def render_docs(payload) + collections.each_value do |collection| + collection.docs.each do |document| + render_regenerated(document, payload) + end + end + end + + def render_pages(payload) + pages.each do |page| + render_regenerated(page, payload) + end + end + + def render_regenerated(document, payload) + return unless regenerator.regenerate?(document) + + document.renderer.payload = payload + document.output = document.renderer.run + document.trigger_hooks(:post_render) + end + end +end -- cgit v1.2.3