nanoc / features

Collection of feature requests
2 stars 1 forks source link

Multiple preprocess directives #64

Open bbukh opened 1 year ago

bbukh commented 1 year ago

While it is possible to have several route and compile commands, only one preprocess command is permitted. That has become a problem for my project which has two distinct parts. Each has a separate section in the Rules file with its own set of route and compile commands. However, I cannot achieve a clean separation of the preprocessing steps. The best I have managed is

preprocess_A = proc { |obj|
  obj.instance_exec() {
     # code for preprocessing A-related items 
  }
}

preprocess_B = proc { |obj|
  obj.instance_exec() {
     # code for preprocessing B-related items 
  }
}

preprocess do
  preprocess_A.call(self)
  preprocess_B.call(self)
end

Possible fixes (in order of descending desirability):

  1. Add support for multiple preprocess commands.
  2. Add documentation to https://nanoc.app/doc/troubleshooting/ or to https://nanoc.app/doc/rules/#preprocessing explaining how to achieve this functionality (kludge above or something better).
  3. Fix the typo in the warning message in compiler_dsl.rb: it should say "another postprocess block overrides the previously SUPPLIED one".

Finally, let me express great thanks for the wonderful tool! I have used nanoc for years, and was silent about it only because it has been doing everything I needed so well that I did not need to say anything :-)

denisdefreyne commented 1 year ago

FWIW, the approach I use to structure the preprocess step in my own site (https://denisdefreyne.com/) is by defining functions inside it, like this:

preprocess do
  def hide_specials
    # …
  end

  def assign_cachebuster_id
    # …
  end

  def find_backlinks
    # …
  end

  def delete_drafts
    @items.delete_if { |i| i[:draft] && i[:draft] != 'soft' }
  end

  def add_created_at
    # …
  end

  def add_weeknotes_meta
    notes = @items.find_all('/notes/*')
    notes.select { weeknote?(_1) }.each do |weeknotes|
      match = weeknotes[:title].match(/\AWeeknotes (20\d{2}) W(\d{1,2})/)
      year, week = Integer(match[1], 10), Integer(match[2], 10)
      weeknotes[:year] = year
      weeknotes[:week] = week
    end
  end

  delete_drafts
  hide_specials
  assign_cachebuster_id
  find_backlinks
  add_created_at
  add_weeknotes_meta
end

These functions are all top-level ones that don’t take arguments, but I could imagine creating helper functions too. You’d be able to use include to mix in modules in the preprocess block, too. Would either of those solutions work for you too?

In the mean time, I’ll move this to the nanoc/features repository, where feature requests are collected.

bbukh commented 1 year ago

Your approach is nice, but I prefer mine as it allows me to keep different top-level functions in different parts of Rules file. In your example, it would correspond to keeping all weeknotes-related preprocessing code near weeknotes-related routing and compiling code, and similar to the other sections of the website etc.

I do not quite understand how include-based solution would look like. Do you mean that I could split Rules into several Rules.1, Rules.2 each of which with the same syntax as the main Rules and then write include Rules.num in the main file? If yes, that indeed would be nice.

Either way, thank you for considering this (obviously non-urgent) feature request.