<commit_before># require_relative 'cmless/cmless'
# If this becomes multiple files, then require a subdirectory.
# but if it's just one file, it's fine here.

require 'redcarpet'
require 'singleton'
require 'nokogiri'
require 'cgi'

# CMS alternative: Content in markdown / Extract HTML and data for display
class Cmless
  attr_reader :path
  attr_reader :title
  attr_reader :title_html
  attr_reader :toc_html

  class Cmless::Error < StandardError
  end

  private

  # You should use find_by_path rather than creating your own instances.
  def initialize(file_path)
    @path = self.class.path_from_file_path(file_path)
    Nokogiri::HTML(Markdowner.instance.render(File.read(file_path))).tap do |doc|
      html_methods = self.class.instance_methods
                     .select { |method| method.to_s.match(/\_html$/) } - [:toc_html]

      doc.xpath('//h1').first.tap do |h1|
        @title_html = h1.inner_html
        @title = h1.text
        h1.remove
        html_methods.delete(:title_html)
      end

      doc.xpath('//h3|//h4|//h5|//h6|//h7|//h8|//h9').tap do |hs|
        inner = hs.map do |h|
          escaped = CGI.escapeHTML(h.text)
          hash = '#' + CGI.escapeHTML(h.attribute('id').to_s)
          "<li class='cmless cmless-#{h.name}'><a href='#{hash}'>#{escaped}</a></li>"
        end.join("\n")
        @toc_html = inner.empty? ? '' : "<ol class='cmless'>#{inner}</ol>\n"
      end

      if html_methods.include?(:head_html)
        @head_html = Cmless.extract_head_html(doc)
        html_methods.delete(:head_html)
      end

      if html_methods.include?(:body_html)
        @body_html = Cmless.extract_body_html(doc)
        html_methods.delete(:body_html)
      end

      html_methods.each do |method|
        h2_name = method.to_s.gsub(/\_html$/, '').gsub('_', ' ').capitalize
        value = Cmless.extract_html(doc, h2_name)
        value ||= if parent # Look at parent if missing on self.
                    parent.send(method)
                  else
                    fail(Cmless::Error.new("Can't find '#{method}'"))
                  end
        instance_variable_set("@#{method}", value)
      end

      doc.text.strip.tap do |extra|
        escaped = extra.gsub("\n", '\\n').gsub("\t", '\\t')
        fail("#{file_path} has extra unused text: '#{escaped}'") unless extra == ''
      end
    end
  rescue => e
    raise(e.message + ' in ' + file_path)
  end

  public

  # Instance methods:

  def parent
    ancestors.last
  end

  def ancestors<commit_msg>Revert: Cmless::Error is only for catching problems at runtime.<commit_after># require_relative 'cmless/cmless'
# If this becomes multiple files, then require a subdirectory.
# but if it's just one file, it's fine here.

require 'redcarpet'
require 'singleton'
require 'nokogiri'
require 'cgi'

# CMS alternative: Content in markdown / Extract HTML and data for display
class Cmless
  attr_reader :path
  attr_reader :title
  attr_reader :title_html
  attr_reader :toc_html

  class Cmless::Error < StandardError
  end

  private

  # You should use find_by_path rather than creating your own instances.
  def initialize(file_path)
    @path = self.class.path_from_file_path(file_path)
    Nokogiri::HTML(Markdowner.instance.render(File.read(file_path))).tap do |doc|
      html_methods = self.class.instance_methods
                     .select { |method| method.to_s.match(/\_html$/) } - [:toc_html]

      doc.xpath('//h1').first.tap do |h1|
        @title_html = h1.inner_html
        @title = h1.text
        h1.remove
        html_methods.delete(:title_html)
      end

      doc.xpath('//h3|//h4|//h5|//h6|//h7|//h8|//h9').tap do |hs|
        inner = hs.map do |h|
          escaped = CGI.escapeHTML(h.text)
          hash = '#' + CGI.escapeHTML(h.attribute('id').to_s)
          "<li class='cmless cmless-#{h.name}'><a href='#{hash}'>#{escaped}</a></li>"
        end.join("\n")
        @toc_html = inner.empty? ? '' : "<ol class='cmless'>#{inner}</ol>\n"
      end

      if html_methods.include?(:head_html)
        @head_html = Cmless.extract_head_html(doc)
        html_methods.delete(:head_html)
      end

      if html_methods.include?(:body_html)
        @body_html = Cmless.extract_body_html(doc)
        html_methods.delete(:body_html)
      end

      html_methods.each do |method|
        h2_name = method.to_s.gsub(/\_html$/, '').gsub('_', ' ').capitalize
        value = Cmless.extract_html(doc, h2_name)
        value ||= if parent # Look at parent if missing on self.
                    parent.send(method)
                  else
                    fail(StandardError.new("Can't find '#{method}'"))
                  end
        instance_variable_set("@#{method}", value)
      end

      doc.text.strip.tap do |extra|
        escaped = extra.gsub("\n", '\\n').gsub("\t", '\\t')
        fail("#{file_path} has extra unused text: '#{escaped}'") unless extra == ''
      end
    end
  rescue => e
    raise(e.message + ' in ' + file_path)
  end

  public

  # Instance methods:

  def parent
    ancestors.last
  end

  def ancestors
{'fraction_non_alphanumeric': 0.13986566574476492, 'fraction_numerical': 0.005531410509679968, 'mean_word_length': 2.5013831258644537, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, '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': '709445', 'n_tokens_mistral': 1745, 'n_tokens_neox': 1690, 'n_words': 371}