<commit_before>module Middleman
  class BlogExtension < Extension
    self.supports_multiple_instances = true

    option :name, nil, 'Unique ID for telling multiple blogs apart'
    option :prefix, nil, 'Prefix to mount the blog at'
    option :permalink, "/:year/:month/:day/:title.html", 'HTTP path to host articles at'
    option :sources, ":year-:month-:day-:title.html", 'How to extract metadata from on-disk files'
    option :taglink, "tags/:tag.html", 'HTTP path to host tag pages at'
    option :layout, "layout", 'Article-specific layout'
    option :summary_separator, /(READMORE)/, 'How to split article summaries around a delimeter'
    option :summary_length, 250, 'Length of words in automatic summaries'
    option :summary_generator, nil, 'Block to definte how summaries are extracted'
    option :year_link, "/:year.html", 'HTTP path for yearly archives'
    option :month_link, "/:year/:month.html", 'HTTP path for monthly archives'
    option :day_link, "/:year/:month/:day.html", 'HTTP path for daily archives'
    option :default_extension, ".markdown", 'Default article extension'
    option :calendar_template, nil, 'Template for calendar pages'
    option :year_template, nil, 'Template for yearly archive pages'
    option :month_template, nil, 'Template for monthyl archive pages'
    option :day_template, nil, 'Template for daily archive pages'
    option :tag_template, nil, 'Template for tag archive pages'
    option :paginate, false, 'Whether to paginate pages'
    option :per_page, 10, 'Articles per page when paginating'
    option :page_link, "page/:num", 'HTTP path for paging'
    option :publish_future_dated, false, 'Whether to pubish articles dated in the future'
    option :custom_collections, {}, 'Hash of custom frontmatter properties to collect articles on and their options'

    attr_accessor :data, :uid

    def initialize(app, options_hash={}, &block)
      super

      @uid = options.name

      require 'middleman-blog/blog_data'
      require 'middleman-blog/blog_article'
      require 'active_support/core_ext/time/zones'

      # app.set :time_zone, 'UTC'

      # optional: :tag_template
      # optional: :year_template
      # optional: :month_template
      # optional: :day_template
      # Allow one setting to set all the calendar templates
      if options.calendar_template
        options.year_template  ||= options.calendar_template
        options.month_template ||= options.calendar_template
        options.day_template   ||= options.calendar_template
      end

      # If "prefix" option is specified, all other paths are relative to it.
      if options.prefix
        options.prefix = "/#{options.prefix}" unless options.prefix.start_with? '/'
        options.permalink = File.join(options.prefix, options.permalink)
        options.sources = File.join(options.prefix, options.sources)
        options.taglink = File.join(options.prefix, options.taglink)
        options.year_link = File.join(options.prefix, options.year_link)
        options.month_link = File.join(options.prefix, options.month_link)
        options.day_link = File.join(options.prefix, options.day_link)

        options.custom_collections.each do |key, opts|
          opts[:link] = File.join(options.prefix, opts[:link])
        end
      end
    end

    def after_configuration
      @uid ||= "blog#{@app.blog_instances.keys.length}"

      @app.ignore(options.calendar_template) if options.calendar_template
      @app.ignore(options.year_template) if options.year_template
      @app.ignore(options.month_template) if options.month_template
      @app.ignore(options.day_template) if options.day_template

      @app.blog_instances[@uid.to_sym] = self

      # Make sure ActiveSupport's TimeZone stuff has something to work with,
      # allowing people to set their desired time zone via Time.zone or
      # set :time_zone
      Time.zone = app.config[:time_zone] if app.config[:time_zone]
      time_zone = Time.zone if Time.zone
      zone_default = Time.find_zone!(time_zone || 'UTC')
      unless zone_default
        raise 'Value assigned to time_zone not recognized.'
      end
      Time.zone_default = zone_default

      # Initialize blog with options

      @data = ::Middleman::Blog::BlogData.new(@app, options, self)

      @app.sitemap.register_resource_list_manipulator(
        :"blog_#{uid}_articles",
        @data,
        false
      )

      if options.tag_template
        @app.ignore options.tag_template

        require 'middleman-blog/tag_pages'
        @app.sitemap.register_resource_list_manipulator(
          :"blog_#{uid}_tags",
          ::Middleman::Blog::TagPages.new(@app, self),
          false
        )
      end

      if options.year_template || options.month_template || options.day_template
        require 'middleman-blog/calendar_pages'
        @app.sitemap.register_resource_list_manipulator(
          :"blog_#{uid}_calendar",
          ::Middleman::Blog::CalendarPages.new(@app, self),
          false
        )
      end

      if options.paginate
        require 'middleman-blog/paginator'
        @app.sitemap.register_resource_list_manipulator(
          :"blog_#{uid}_paginate",
          ::Middleman::Blog::Paginator.new(@app, self),
          false
        )
      end

      if options.custom_collections
        require 'middleman-blog/custom_pages'
        register_custom_pages
      end
    end

    # Register any custom page collections that may be set in the config
    #
    # A custom resource list manipulator will be generated for each key in the
    # custom collections hash.
    #
    # The following will collect posts on the "category" frontmatter property:
    #   ```
    #   activate :blog do |blog|
    #     blog.custom_collections = {
    #       link: "/categories/:category.html",
    #       template: "/category.html"
    #     }
    #   end
    #   ```
    #
    # Category pages in the example above will use the category.html as a template file
    # and it will be ignored when building.
    def register_custom_pages
      options.custom_collections.each do |property, options|
        @app.ignore options[:template]
        @app.sitemap.register_resource_list_manipulator(
          :"blog_#{uid}_#{property}",
          ::Middleman::Blog::CustomPages.new(property, @app, self),
          false
        )

        generate_custom_helper(property)
      end
    end

    # Generate helpers to access the path to a custom collection.
    #
    # For example, when using a custom property called "category" to collect articles on
    # the method **category_path** will be generated.
    #
    # @param [Symbol] custom_property Custom property which is being used to collect articles on
    def generate_custom_helper(custom_property)
      m = Module.new
      m.module_eval(%Q{
        def #{custom_property}_path(value, key = nil)
          sitemap.find_resource_by_path(::Middleman::Blog::CustomPages.link(blog_controller(key).options, :#{custom_property}, value)).try(:url)
        end
      })

      app.class.send(:include, m)
    end

    # Helpers for use within templates and layouts.
    helpers do
      def blog_instances
        @blog_instances ||= {}
      end

      def blog_controller(key=nil)
        if !key && current_resource
          key ||= current_resource.metadata[:page]["blog"]
        end

        # In multiblog situations, force people to specify the blog
        if !key && blog_instances.size > 1
          raise "You must either specify the blog name in calling this method or in your page frontmatter (using the 'blog' key)"
        end

        key ||= blog_instances.keys.first
        blog_instances[key.to_sym]<commit_msg>Look for blog controller on the resource if it has one.<commit_after>module Middleman
  class BlogExtension < Extension
    self.supports_multiple_instances = true

    option :name, nil, 'Unique ID for telling multiple blogs apart'
    option :prefix, nil, 'Prefix to mount the blog at'
    option :permalink, "/:year/:month/:day/:title.html", 'HTTP path to host articles at'
    option :sources, ":year-:month-:day-:title.html", 'How to extract metadata from on-disk files'
    option :taglink, "tags/:tag.html", 'HTTP path to host tag pages at'
    option :layout, "layout", 'Article-specific layout'
    option :summary_separator, /(READMORE)/, 'How to split article summaries around a delimeter'
    option :summary_length, 250, 'Length of words in automatic summaries'
    option :summary_generator, nil, 'Block to definte how summaries are extracted'
    option :year_link, "/:year.html", 'HTTP path for yearly archives'
    option :month_link, "/:year/:month.html", 'HTTP path for monthly archives'
    option :day_link, "/:year/:month/:day.html", 'HTTP path for daily archives'
    option :default_extension, ".markdown", 'Default article extension'
    option :calendar_template, nil, 'Template for calendar pages'
    option :year_template, nil, 'Template for yearly archive pages'
    option :month_template, nil, 'Template for monthyl archive pages'
    option :day_template, nil, 'Template for daily archive pages'
    option :tag_template, nil, 'Template for tag archive pages'
    option :paginate, false, 'Whether to paginate pages'
    option :per_page, 10, 'Articles per page when paginating'
    option :page_link, "page/:num", 'HTTP path for paging'
    option :publish_future_dated, false, 'Whether to pubish articles dated in the future'
    option :custom_collections, {}, 'Hash of custom frontmatter properties to collect articles on and their options'

    attr_accessor :data, :uid

    def initialize(app, options_hash={}, &block)
      super

      @uid = options.name

      require 'middleman-blog/blog_data'
      require 'middleman-blog/blog_article'
      require 'active_support/core_ext/time/zones'

      # app.set :time_zone, 'UTC'

      # optional: :tag_template
      # optional: :year_template
      # optional: :month_template
      # optional: :day_template
      # Allow one setting to set all the calendar templates
      if options.calendar_template
        options.year_template  ||= options.calendar_template
        options.month_template ||= options.calendar_template
        options.day_template   ||= options.calendar_template
      end

      # If "prefix" option is specified, all other paths are relative to it.
      if options.prefix
        options.prefix = "/#{options.prefix}" unless options.prefix.start_with? '/'
        options.permalink = File.join(options.prefix, options.permalink)
        options.sources = File.join(options.prefix, options.sources)
        options.taglink = File.join(options.prefix, options.taglink)
        options.year_link = File.join(options.prefix, options.year_link)
        options.month_link = File.join(options.prefix, options.month_link)
        options.day_link = File.join(options.prefix, options.day_link)

        options.custom_collections.each do |key, opts|
          opts[:link] = File.join(options.prefix, opts[:link])
        end
      end
    end

    def after_configuration
      @uid ||= "blog#{@app.blog_instances.keys.length}"

      @app.ignore(options.calendar_template) if options.calendar_template
      @app.ignore(options.year_template) if options.year_template
      @app.ignore(options.month_template) if options.month_template
      @app.ignore(options.day_template) if options.day_template

      @app.blog_instances[@uid.to_sym] = self

      # Make sure ActiveSupport's TimeZone stuff has something to work with,
      # allowing people to set their desired time zone via Time.zone or
      # set :time_zone
      Time.zone = app.config[:time_zone] if app.config[:time_zone]
      time_zone = Time.zone if Time.zone
      zone_default = Time.find_zone!(time_zone || 'UTC')
      unless zone_default
        raise 'Value assigned to time_zone not recognized.'
      end
      Time.zone_default = zone_default

      # Initialize blog with options

      @data = ::Middleman::Blog::BlogData.new(@app, options, self)

      @app.sitemap.register_resource_list_manipulator(
        :"blog_#{uid}_articles",
        @data,
        false
      )

      if options.tag_template
        @app.ignore options.tag_template

        require 'middleman-blog/tag_pages'
        @app.sitemap.register_resource_list_manipulator(
          :"blog_#{uid}_tags",
          ::Middleman::Blog::TagPages.new(@app, self),
          false
        )
      end

      if options.year_template || options.month_template || options.day_template
        require 'middleman-blog/calendar_pages'
        @app.sitemap.register_resource_list_manipulator(
          :"blog_#{uid}_calendar",
          ::Middleman::Blog::CalendarPages.new(@app, self),
          false
        )
      end

      if options.paginate
        require 'middleman-blog/paginator'
        @app.sitemap.register_resource_list_manipulator(
          :"blog_#{uid}_paginate",
          ::Middleman::Blog::Paginator.new(@app, self),
          false
        )
      end

      if options.custom_collections
        require 'middleman-blog/custom_pages'
        register_custom_pages
      end
    end

    # Register any custom page collections that may be set in the config
    #
    # A custom resource list manipulator will be generated for each key in the
    # custom collections hash.
    #
    # The following will collect posts on the "category" frontmatter property:
    #   ```
    #   activate :blog do |blog|
    #     blog.custom_collections = {
    #       link: "/categories/:category.html",
    #       template: "/category.html"
    #     }
    #   end
    #   ```
    #
    # Category pages in the example above will use the category.html as a template file
    # and it will be ignored when building.
    def register_custom_pages
      options.custom_collections.each do |property, options|
        @app.ignore options[:template]
        @app.sitemap.register_resource_list_manipulator(
          :"blog_#{uid}_#{property}",
          ::Middleman::Blog::CustomPages.new(property, @app, self),
          false
        )

        generate_custom_helper(property)
      end
    end

    # Generate helpers to access the path to a custom collection.
    #
    # For example, when using a custom property called "category" to collect articles on
    # the method **category_path** will be generated.
    #
    # @param [Symbol] custom_property Custom property which is being used to collect articles on
    def generate_custom_helper(custom_property)
      m = Module.new
      m.module_eval(%Q{
        def #{custom_property}_path(value, key = nil)
          sitemap.find_resource_by_path(::Middleman::Blog::CustomPages.link(blog_controller(key).options, :#{custom_property}, value)).try(:url)
        end
      })

      app.class.send(:include, m)
    end

    # Helpers for use within templates and layouts.
    helpers do
      def blog_instances
        @blog_instances ||= {}
      end

      def blog_controller(key=nil)
        if !key && current_resource
          key = current_resource.metadata[:page]["blog"]

          if !key && current_resource.respond_to?(:blog_controller) && current_resource.blog_controller
            return current_resource.blog_controller
          end
        end

        # In multiblog situations, force people to specify the blog
        if !key && blog_instances.size > 1
          raise "You must either specify the blog name in calling this method or in your page frontmatter (using the 'blog' key)"
        end

        key ||= blog_instances.keys.first
        blog_instances[key.to_sym]
{'fraction_non_alphanumeric': 0.09574127441562601, 'fraction_numerical': 0.0007684918347742555, 'mean_word_length': 2.9186951066499374, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7230688', 'n_tokens_mistral': 4464, 'n_tokens_neox': 4360, 'n_words': 1250}