bookbindery 6.0.0 → 7.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.
- checksums.yaml +4 -4
- data/bookbinder.gemspec +2 -2
- data/lib/bookbinder/commands/bind.rb +2 -1
- data/lib/bookbinder/commands/bind/directory_preparer.rb +3 -12
- data/lib/bookbinder/commands/bind/layout_preparer.rb +23 -0
- data/lib/bookbinder/commands/collection.rb +22 -8
- data/lib/bookbinder/commands/watch.rb +2 -1
- data/lib/bookbinder/config/checkers/subnavs_checker.rb +49 -0
- data/lib/bookbinder/config/checkers/topics_checker.rb +37 -0
- data/lib/bookbinder/config/configuration.rb +14 -1
- data/lib/bookbinder/config/fetcher.rb +27 -8
- data/lib/bookbinder/config/section_config.rb +4 -0
- data/lib/bookbinder/config/subnav_config.rb +41 -0
- data/lib/bookbinder/config/topic_config.rb +29 -0
- data/lib/bookbinder/config/validator.rb +5 -1
- data/lib/bookbinder/dita_command_creator.rb +2 -2
- data/lib/bookbinder/dita_html_to_middleman_formatter.rb +2 -2
- data/lib/bookbinder/ingest/section_repository.rb +1 -2
- data/lib/bookbinder/local_filesystem_accessor.rb +14 -0
- data/lib/bookbinder/preprocessing/dita_preprocessor.rb +2 -2
- data/lib/bookbinder/preprocessing/link_to_site_gen_dir.rb +15 -3
- data/lib/bookbinder/server_director.rb +1 -1
- data/lib/bookbinder/subnav/json_from_config.rb +77 -0
- data/lib/bookbinder/subnav/json_from_html.rb +38 -0
- data/lib/bookbinder/subnav/json_props_creator.rb +35 -0
- data/lib/bookbinder/subnav/pdf_config_creator.rb +52 -0
- data/lib/bookbinder/subnav/subnav_generator.rb +19 -0
- data/lib/bookbinder/subnav/subnav_generator_factory.rb +35 -0
- data/lib/bookbinder/subnav/template_creator.rb +41 -0
- data/lib/bookbinder/values/output_locations.rb +4 -0
- data/lib/bookbinder/values/section.rb +2 -1
- data/lib/bookbinder/values/{subnav.rb → subnav_template.rb} +2 -2
- data/master_middleman/archive_drop_down_menu.rb +4 -0
- data/master_middleman/bookbinder_helpers.rb +4 -3
- data/master_middleman/compass_runner.rb +0 -0
- metadata +17 -5
- data/lib/bookbinder/subnav_formatter.rb +0 -37
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 0fb5495aa9aaa1b4337177fd9659ff1770edb7d1
         | 
| 4 | 
            +
              data.tar.gz: 6aaa6711faed7f97fb649b8f0a7d76b259fdbc6d
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: d9d3278fb5effbab9c2591a5700685a78af34d9095a28d16dd1eb95144188fa498607a920cbc30224347ae972ec7e870a6a88be060e7091e7961fd609762865b
         | 
| 7 | 
            +
              data.tar.gz: ae8ebb4008aedf58c261ce94ab0569ea8bec4caacf367ce9c2b5f611523b5793cc9650b9f987579cb95b507fd64f20d5a5ed5b1d5b688e345c75a656ee6cd98b
         | 
    
        data/bookbinder.gemspec
    CHANGED
    
    | @@ -2,7 +2,7 @@ require 'base64' | |
| 2 2 |  | 
| 3 3 | 
             
            Gem::Specification.new do |s|
         | 
| 4 4 | 
             
              s.name        = 'bookbindery'
         | 
| 5 | 
            -
              s.version     = ' | 
| 5 | 
            +
              s.version     = '7.0.0'
         | 
| 6 6 | 
             
              s.summary     = 'Markdown to Rackup application documentation generator'
         | 
| 7 7 | 
             
              s.description = 'A command line utility to be run in Book repositories to stitch together their constituent Markdown repos into a static-HTML-serving application'
         | 
| 8 8 | 
             
              s.authors     = ['Mike Grafton', 'Lucas Marks', 'Gavin Morgan', 'Nikhil Gajwani', 'Dan Wendorf', 'Brenda Chan', 'Matthew Boedicker', 'Frank Kotsianas', 'Elena Sharma', 'Christa Hartsock']
         | 
| @@ -14,7 +14,7 @@ Gem::Specification.new do |s| | |
| 14 14 | 
             
              s.bindir      = 'install_bin'
         | 
| 15 15 | 
             
              s.executable  = 'bookbinder'
         | 
| 16 16 |  | 
| 17 | 
            -
              s.required_ruby_version = ' | 
| 17 | 
            +
              s.required_ruby_version = '>= 2.0'
         | 
| 18 18 | 
             
              s.add_runtime_dependency 'fog-aws', ['~> 0.7.1']
         | 
| 19 19 | 
             
              s.add_runtime_dependency 'ansi', ['~> 1.4']
         | 
| 20 20 | 
             
              s.add_runtime_dependency 'unf', ['~> 0.1']
         | 
| @@ -68,7 +68,8 @@ module Bookbinder | |
| 68 68 | 
             
                      sections,
         | 
| 69 69 | 
             
                      output_locations,
         | 
| 70 70 | 
             
                      options: bind_options.options,
         | 
| 71 | 
            -
                      output_streams: bind_options.streams
         | 
| 71 | 
            +
                      output_streams: bind_options.streams,
         | 
| 72 | 
            +
                      config: bind_config
         | 
| 72 73 | 
             
                    )
         | 
| 73 74 | 
             
                    if file_system_accessor.file_exist?('redirects.rb')
         | 
| 74 75 | 
             
                      file_system_accessor.copy('redirects.rb', output_locations.final_app_dir)
         | 
| @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            require_relative 'layout_preparer'
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Bookbinder
         | 
| 2 4 | 
             
              module Commands
         | 
| 3 5 | 
             
                module BindComponents
         | 
| @@ -13,8 +15,7 @@ module Bookbinder | |
| 13 15 | 
             
                      copy_directory_from_gem(gem_root, 'template_app', output_locations.final_app_dir)
         | 
| 14 16 | 
             
                      copy_directory_from_gem(gem_root, 'master_middleman', output_locations.site_generator_home)
         | 
| 15 17 |  | 
| 16 | 
            -
                       | 
| 17 | 
            -
                      fs.copy_contents(layout_repo_path, output_locations.site_generator_home)
         | 
| 18 | 
            +
                      LayoutPreparer.new(fs).prepare(output_locations, cloner, config)
         | 
| 18 19 | 
             
                    end
         | 
| 19 20 |  | 
| 20 21 | 
             
                    private
         | 
| @@ -24,16 +25,6 @@ module Bookbinder | |
| 24 25 | 
             
                    def copy_directory_from_gem(gem_root, dir, output_dir)
         | 
| 25 26 | 
             
                      fs.copy_contents(File.join(gem_root, dir), output_dir)
         | 
| 26 27 | 
             
                    end
         | 
| 27 | 
            -
             | 
| 28 | 
            -
                    def fetch_layout_repo(config, cloner)
         | 
| 29 | 
            -
                      if config.has_option?('layout_repo')
         | 
| 30 | 
            -
                        cloned_repo = cloner.call(source_repo_name: config.layout_repo,
         | 
| 31 | 
            -
                                      destination_parent_dir: Dir.mktmpdir)
         | 
| 32 | 
            -
                        cloned_repo.path
         | 
| 33 | 
            -
                      else
         | 
| 34 | 
            -
                        File.absolute_path('master_middleman')
         | 
| 35 | 
            -
                      end
         | 
| 36 | 
            -
                    end
         | 
| 37 28 | 
             
                  end
         | 
| 38 29 | 
             
                end
         | 
| 39 30 | 
             
              end
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            module Bookbinder
         | 
| 2 | 
            +
              module Commands
         | 
| 3 | 
            +
                module BindComponents
         | 
| 4 | 
            +
                  class LayoutPreparer
         | 
| 5 | 
            +
                    def initialize(fs)
         | 
| 6 | 
            +
                      @fs = fs
         | 
| 7 | 
            +
                    end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                    attr_reader :fs
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                    def prepare(output_locations, cloner, config)
         | 
| 12 | 
            +
                      if config.has_option?('layout_repo')
         | 
| 13 | 
            +
                        cloned_repo = cloner.call(source_repo_name: config.layout_repo,
         | 
| 14 | 
            +
                                                  destination_parent_dir: Dir.mktmpdir)
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                        fs.copy_contents(cloned_repo.path, output_locations.site_generator_home)
         | 
| 17 | 
            +
                      end
         | 
| 18 | 
            +
                      fs.copy_contents(File.absolute_path('master_middleman'), output_locations.site_generator_home)
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| @@ -19,8 +19,9 @@ require_relative '../postprocessing/sitemap_writer' | |
| 19 19 | 
             
            require_relative '../preprocessing/dita_preprocessor'
         | 
| 20 20 | 
             
            require_relative '../preprocessing/link_to_site_gen_dir'
         | 
| 21 21 | 
             
            require_relative '../preprocessing/preprocessor'
         | 
| 22 | 
            +
            require_relative '../subnav/subnav_generator_factory'
         | 
| 22 23 | 
             
            require_relative '../sheller'
         | 
| 23 | 
            -
            require_relative '../ | 
| 24 | 
            +
            require_relative '../subnav/json_from_html'
         | 
| 24 25 | 
             
            require_relative '../values/output_locations'
         | 
| 25 26 |  | 
| 26 27 | 
             
            module Bookbinder
         | 
| @@ -87,7 +88,7 @@ module Bookbinder | |
| 87 88 | 
             
                  def bind
         | 
| 88 89 | 
             
                    @bind ||= Commands::Bind.new(
         | 
| 89 90 | 
             
                      streams,
         | 
| 90 | 
            -
                       | 
| 91 | 
            +
                      output_locations,
         | 
| 91 92 | 
             
                      configuration_fetcher,
         | 
| 92 93 | 
             
                      Config::ArchiveMenuConfiguration.new(loader: config_loader, config_filename: 'bookbinder.yml'),
         | 
| 93 94 | 
             
                      local_filesystem_accessor,
         | 
| @@ -95,12 +96,12 @@ module Bookbinder | |
| 95 96 | 
             
                      Postprocessing::SitemapWriter.build(logger, final_app_directory, sitemap_port),
         | 
| 96 97 | 
             
                      Preprocessing::Preprocessor.new(
         | 
| 97 98 | 
             
                        Preprocessing::DitaPreprocessor.new(
         | 
| 98 | 
            -
                          DitaHtmlToMiddlemanFormatter.new(local_filesystem_accessor,  | 
| 99 | 
            +
                          DitaHtmlToMiddlemanFormatter.new(local_filesystem_accessor, dita_json_generator, html_document_manipulator),
         | 
| 99 100 | 
             
                          local_filesystem_accessor,
         | 
| 100 101 | 
             
                          DitaCommandCreator.new(ENV['PATH_TO_DITA_OT_LIBRARY']),
         | 
| 101 102 | 
             
                          sheller
         | 
| 102 103 | 
             
                        ),
         | 
| 103 | 
            -
                        Preprocessing::LinkToSiteGenDir.new(local_filesystem_accessor) | 
| 104 | 
            +
                        Preprocessing::LinkToSiteGenDir.new(local_filesystem_accessor, subnav_generator_factory)
         | 
| 104 105 | 
             
                      ),
         | 
| 105 106 | 
             
                      Ingest::ClonerFactory.new(streams, local_filesystem_accessor, version_control_system),
         | 
| 106 107 | 
             
                      Ingest::SectionRepository.new,
         | 
| @@ -112,11 +113,11 @@ module Bookbinder | |
| 112 113 | 
             
                    @watch ||= Commands::Watch.new(
         | 
| 113 114 | 
             
                      streams,
         | 
| 114 115 | 
             
                      middleman_runner: runner,
         | 
| 115 | 
            -
                      output_locations:  | 
| 116 | 
            +
                      output_locations: output_locations,
         | 
| 116 117 | 
             
                      config_fetcher: configuration_fetcher,
         | 
| 117 118 | 
             
                      config_decorator: Config::ArchiveMenuConfiguration.new(loader: config_loader, config_filename: 'bookbinder.yml'),
         | 
| 118 119 | 
             
                      file_system_accessor: local_filesystem_accessor,
         | 
| 119 | 
            -
                      preprocessor: Preprocessing::Preprocessor.new(Preprocessing::LinkToSiteGenDir.new(local_filesystem_accessor)),
         | 
| 120 | 
            +
                      preprocessor: Preprocessing::Preprocessor.new(Preprocessing::LinkToSiteGenDir.new(local_filesystem_accessor, subnav_generator_factory)),
         | 
| 120 121 | 
             
                      cloner: local_file_system_cloner,
         | 
| 121 122 | 
             
                      section_repository: Ingest::SectionRepository.new,
         | 
| 122 123 | 
             
                      directory_preparer: directory_preparer
         | 
| @@ -146,6 +147,7 @@ module Bookbinder | |
| 146 147 | 
             
                      Config::RemoteYamlCredentialProvider.new(logger, version_control_system)
         | 
| 147 148 | 
             
                    ).tap do |fetcher|
         | 
| 148 149 | 
             
                      fetcher.set_config_file_path './config.yml'
         | 
| 150 | 
            +
                      fetcher.set_config_dir_path './config/'
         | 
| 149 151 | 
             
                    end
         | 
| 150 152 | 
             
                  end
         | 
| 151 153 |  | 
| @@ -153,16 +155,28 @@ module Bookbinder | |
| 153 155 | 
             
                    @config_loader ||= Config::YAMLLoader.new
         | 
| 154 156 | 
             
                  end
         | 
| 155 157 |  | 
| 158 | 
            +
                  def subnav_generator_factory
         | 
| 159 | 
            +
                    Subnav::SubnavGeneratorFactory.new(local_filesystem_accessor, output_locations)
         | 
| 160 | 
            +
                  end
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                  def json_generator
         | 
| 163 | 
            +
                    Subnav::JsonFromConfig.new
         | 
| 164 | 
            +
                  end
         | 
| 165 | 
            +
             | 
| 156 166 | 
             
                  def directory_preparer
         | 
| 157 167 | 
             
                    Commands::BindComponents::DirectoryPreparer.new(local_filesystem_accessor)
         | 
| 158 168 | 
             
                  end
         | 
| 159 169 |  | 
| 170 | 
            +
                  def output_locations
         | 
| 171 | 
            +
                    OutputLocations.new(final_app_dir: final_app_directory, context_dir: File.absolute_path('.'))
         | 
| 172 | 
            +
                  end
         | 
| 173 | 
            +
             | 
| 160 174 | 
             
                  def final_app_directory
         | 
| 161 175 | 
             
                    @final_app_directory ||= File.absolute_path('final_app')
         | 
| 162 176 | 
             
                  end
         | 
| 163 177 |  | 
| 164 | 
            -
                  def  | 
| 165 | 
            -
                     | 
| 178 | 
            +
                  def dita_json_generator
         | 
| 179 | 
            +
                    Subnav::JsonFromHtml.new
         | 
| 166 180 | 
             
                  end
         | 
| 167 181 |  | 
| 168 182 | 
             
                  def html_document_manipulator
         | 
| @@ -51,7 +51,8 @@ module Bookbinder | |
| 51 51 | 
             
                    preprocessor.preprocess(
         | 
| 52 52 | 
             
                      sections,
         | 
| 53 53 | 
             
                      output_locations,
         | 
| 54 | 
            -
                      output_streams: streams
         | 
| 54 | 
            +
                      output_streams: streams,
         | 
| 55 | 
            +
                      config: watch_config
         | 
| 55 56 | 
             
                    )
         | 
| 56 57 | 
             
                    if file_system_accessor.file_exist?('redirects.rb')
         | 
| 57 58 | 
             
                      file_system_accessor.copy('redirects.rb', output_locations.final_app_dir)
         | 
| @@ -0,0 +1,49 @@ | |
| 1 | 
            +
            module Bookbinder
         | 
| 2 | 
            +
              module Config
         | 
| 3 | 
            +
                module Checkers
         | 
| 4 | 
            +
                  class SubnavsChecker
         | 
| 5 | 
            +
                    MissingRequiredKeyError = Class.new(RuntimeError)
         | 
| 6 | 
            +
                    MissingSubnavsKeyError = Class.new(RuntimeError)
         | 
| 7 | 
            +
                    MissingSubnavNameError = Class.new(RuntimeError)
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                    def check(config)
         | 
| 10 | 
            +
                      @config = config
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                      if section_subnav_names.count > 0
         | 
| 13 | 
            +
                        if config.subnavs.empty?
         | 
| 14 | 
            +
                           MissingSubnavsKeyError.new("You must specify at least one subnav under the subnavs key in config.yml")
         | 
| 15 | 
            +
                        elsif missing_subnavs.count != 0
         | 
| 16 | 
            +
                          MissingSubnavNameError.new("Your config.yml is missing required subnav names under the subnavs key. Required subnav names are #{missing_subnavs.join(", ")}.")
         | 
| 17 | 
            +
                        elsif invalid_subnavs.any?
         | 
| 18 | 
            +
                          MissingRequiredKeyError.new("Your config.yml is missing required key(s) for subnavs #{invalid_subnav_names}. Required keys are #{required_subnav_keys.join(", ")}.")
         | 
| 19 | 
            +
                        end
         | 
| 20 | 
            +
                      end
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                    attr_reader :config
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    private
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    def invalid_subnavs
         | 
| 28 | 
            +
                      config.subnavs.map {|subnav_config| subnav_config unless subnav_config.valid? }
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    def invalid_subnav_names
         | 
| 32 | 
            +
                      invalid_subnavs.map(&:name).join(", ")
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    def missing_subnavs
         | 
| 36 | 
            +
                      section_subnav_names - config.subnavs.map(&:name)
         | 
| 37 | 
            +
                    end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                    def required_subnav_keys
         | 
| 40 | 
            +
                      Bookbinder::Config::SubnavConfig::CONFIG_REQUIRED_KEYS
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                    def section_subnav_names
         | 
| 44 | 
            +
                      config.sections.map(&:subnav_name).compact.uniq
         | 
| 45 | 
            +
                    end
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
              end
         | 
| 49 | 
            +
            end
         | 
| @@ -0,0 +1,37 @@ | |
| 1 | 
            +
            module Bookbinder
         | 
| 2 | 
            +
              module Config
         | 
| 3 | 
            +
                module Checkers
         | 
| 4 | 
            +
                  class TopicsChecker
         | 
| 5 | 
            +
                    MissingRequiredKeyError = Class.new(RuntimeError)
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                    def check(config)
         | 
| 8 | 
            +
                      @config = config
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                      if invalid_subnavs.any?
         | 
| 11 | 
            +
                        MissingRequiredKeyError.new("Your config.yml is missing required key(s) for subnav(s) #{invalid_subnav_names}. Required keys are #{required_topic_keys.join(", ")}.")
         | 
| 12 | 
            +
                      end
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                    attr_reader :config
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                    private
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                    def invalid_subnavs
         | 
| 20 | 
            +
                      config.subnavs.select { |subnav_config| invalid_topics(subnav_config.topics).any? }
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                    def invalid_topics(topics)
         | 
| 24 | 
            +
                      topics.map {|topic| topic unless topic.valid? }
         | 
| 25 | 
            +
                    end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    def invalid_subnav_names
         | 
| 28 | 
            +
                      invalid_subnavs.map(&:name).join(', ')
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    def required_topic_keys
         | 
| 32 | 
            +
                      Bookbinder::Config::TopicConfig::CONFIG_REQUIRED_KEYS
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
            end
         | 
| @@ -1,6 +1,7 @@ | |
| 1 1 | 
             
            require_relative '../ingest/destination_directory'
         | 
| 2 2 | 
             
            require_relative '../ingest/repo_identifier'
         | 
| 3 3 | 
             
            require_relative 'section_config'
         | 
| 4 | 
            +
            require_relative 'subnav_config'
         | 
| 4 5 |  | 
| 5 6 | 
             
            module Bookbinder
         | 
| 6 7 | 
             
              module Config
         | 
| @@ -65,10 +66,11 @@ module Bookbinder | |
| 65 66 |  | 
| 66 67 | 
             
                  def initialize(config)
         | 
| 67 68 | 
             
                    @config = config
         | 
| 69 | 
            +
                    @subnavs = assemble_subnavs || []
         | 
| 68 70 | 
             
                  end
         | 
| 69 71 |  | 
| 70 72 | 
             
                  CONFIG_REQUIRED_KEYS = %w(book_repo public_host)
         | 
| 71 | 
            -
                  CONFIG_OPTIONAL_KEYS = %w(archive_menu book_repo_url cred_repo cred_repo_url layout_repo layout_repo_url sections)
         | 
| 73 | 
            +
                  CONFIG_OPTIONAL_KEYS = %w(archive_menu book_repo_url cred_repo cred_repo_url layout_repo layout_repo_url sections subnav_exclusions)
         | 
| 72 74 |  | 
| 73 75 | 
             
                  CONFIG_REQUIRED_KEYS.each do |method_name|
         | 
| 74 76 | 
             
                    define_method(method_name) do
         | 
| @@ -108,8 +110,19 @@ module Bookbinder | |
| 108 110 |  | 
| 109 111 | 
             
                  alias_method :eql?, :==
         | 
| 110 112 |  | 
| 113 | 
            +
                  attr_reader :subnavs
         | 
| 114 | 
            +
             | 
| 111 115 | 
             
                  private
         | 
| 112 116 |  | 
| 117 | 
            +
                  def assemble_subnavs
         | 
| 118 | 
            +
                    if config[:subnavs]
         | 
| 119 | 
            +
                      config[:subnavs].map do |subnav|
         | 
| 120 | 
            +
                        subnav.merge!({'subnav_exclusions' => subnav_exclusions})
         | 
| 121 | 
            +
                        Config::SubnavConfig.new(subnav)
         | 
| 122 | 
            +
                      end
         | 
| 123 | 
            +
                    end
         | 
| 124 | 
            +
                  end
         | 
| 125 | 
            +
             | 
| 113 126 | 
             
                  attr_reader :config
         | 
| 114 127 | 
             
                end
         | 
| 115 128 | 
             
              end
         | 
| @@ -13,7 +13,10 @@ module Bookbinder | |
| 13 13 | 
             
                  end
         | 
| 14 14 |  | 
| 15 15 | 
             
                  def fetch_config
         | 
| 16 | 
            -
                    @ | 
| 16 | 
            +
                    @base_config ||= read_config_file
         | 
| 17 | 
            +
                    @optional_configs ||= read_optional_configs
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                    @config ||= validate(@base_config, @optional_configs)
         | 
| 17 20 | 
             
                  end
         | 
| 18 21 |  | 
| 19 22 | 
             
                  def fetch_credentials(environment = 'null-environment')
         | 
| @@ -29,13 +32,17 @@ module Bookbinder | |
| 29 32 | 
             
                    }
         | 
| 30 33 | 
             
                  end
         | 
| 31 34 |  | 
| 32 | 
            -
                  def  | 
| 33 | 
            -
                    @ | 
| 35 | 
            +
                  def set_config_dir_path(config_dir_path)
         | 
| 36 | 
            +
                    @config_dir_path = File.expand_path(config_dir_path)
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  def set_config_file_path(config_file_path)
         | 
| 40 | 
            +
                    @config_file_path = File.expand_path(config_file_path)
         | 
| 34 41 | 
             
                  end
         | 
| 35 42 |  | 
| 36 43 | 
             
                  private
         | 
| 37 44 |  | 
| 38 | 
            -
                  attr_reader(:loader, :configuration_validator, :config, :config_file_path,
         | 
| 45 | 
            +
                  attr_reader(:loader, :configuration_validator, :config, :config_file_path, :config_dir_path,
         | 
| 39 46 | 
             
                              :credentials_provider)
         | 
| 40 47 |  | 
| 41 48 | 
             
                  def read_config_file
         | 
| @@ -44,17 +51,29 @@ module Bookbinder | |
| 44 51 | 
             
                  rescue FileNotFoundError => e
         | 
| 45 52 | 
             
                    raise "The configuration file specified does not exist. Please create a config #{e} file at #{config_file_path} and try again."
         | 
| 46 53 | 
             
                  rescue InvalidSyntaxError => e
         | 
| 47 | 
            -
                    raise  | 
| 54 | 
            +
                    raise syntax_error(e)
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  def read_optional_configs
         | 
| 58 | 
            +
                    Dir["#{config_dir_path}/*.yml"].map do |config_file|
         | 
| 59 | 
            +
                      loader.load(File.expand_path(config_file)) || {}
         | 
| 60 | 
            +
                    end.reduce({}, :merge)
         | 
| 61 | 
            +
                  rescue InvalidSyntaxError => e
         | 
| 62 | 
            +
                    raise syntax_error(e)
         | 
| 48 63 | 
             
                  end
         | 
| 49 64 |  | 
| 50 | 
            -
                  def validate( | 
| 51 | 
            -
                    raise 'Your config.yml appears to be empty. Please check and try again.' unless  | 
| 65 | 
            +
                  def validate(base_hash, optional_hash)
         | 
| 66 | 
            +
                    raise 'Your config.yml appears to be empty. Please check and try again.' unless base_hash
         | 
| 52 67 |  | 
| 53 | 
            -
                    Configuration.parse( | 
| 68 | 
            +
                    Configuration.parse(base_hash.merge(optional_hash)).tap do |config|
         | 
| 54 69 | 
             
                      errors = configuration_validator.exceptions(config)
         | 
| 55 70 | 
             
                      raise errors.first if errors.any?
         | 
| 56 71 | 
             
                    end
         | 
| 57 72 | 
             
                  end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                  def syntax_error(e)
         | 
| 75 | 
            +
                    "There is a syntax error in your config file: \n #{e}"
         | 
| 76 | 
            +
                  end
         | 
| 58 77 | 
             
                end
         | 
| 59 78 | 
             
              end
         | 
| 60 79 | 
             
            end
         | 
| @@ -0,0 +1,41 @@ | |
| 1 | 
            +
            require_relative '../config/topic_config'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Bookbinder
         | 
| 4 | 
            +
              module Config
         | 
| 5 | 
            +
                class SubnavConfig
         | 
| 6 | 
            +
                  def initialize(config)
         | 
| 7 | 
            +
                    @config = config
         | 
| 8 | 
            +
                    @topics = assemble_topics || []
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def name
         | 
| 12 | 
            +
                    config['name']
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def pdf_config
         | 
| 16 | 
            +
                    config['pdf_config']
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def subnav_exclusions
         | 
| 20 | 
            +
                    config['subnav_exclusions'] || []
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  def valid?
         | 
| 24 | 
            +
                    (CONFIG_REQUIRED_KEYS - config.keys).empty?
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  CONFIG_REQUIRED_KEYS = %w(name topics)
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  attr_reader :topics
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  private
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  attr_reader :config
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  def assemble_topics
         | 
| 36 | 
            +
                    config['topics'].map{|topic| Config::TopicConfig.new(topic)} if config['topics']
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
            end
         | 
| 41 | 
            +
             | 
| @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            module Bookbinder
         | 
| 2 | 
            +
              module Config
         | 
| 3 | 
            +
                class TopicConfig
         | 
| 4 | 
            +
                  def initialize(config)
         | 
| 5 | 
            +
                    @config = config
         | 
| 6 | 
            +
                  end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  def title
         | 
| 9 | 
            +
                    config['title']
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  def toc_path
         | 
| 13 | 
            +
                    Pathname(config['toc_path'])
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def toc_nav_name
         | 
| 17 | 
            +
                    config['toc_nav_name'] || title
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  def valid?
         | 
| 21 | 
            +
                    (CONFIG_REQUIRED_KEYS - config.keys).empty?
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  CONFIG_REQUIRED_KEYS = %w(title toc_path)
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  attr_reader :config
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
            end
         | 
| @@ -3,6 +3,8 @@ require_relative 'checkers/archive_menu_checker' | |
| 3 3 | 
             
            require_relative 'checkers/required_keys_checker'
         | 
| 4 4 | 
             
            require_relative 'checkers/repository_name_presence_checker'
         | 
| 5 5 | 
             
            require_relative 'checkers/dita_section_checker'
         | 
| 6 | 
            +
            require_relative 'checkers/subnavs_checker'
         | 
| 7 | 
            +
            require_relative 'checkers/topics_checker'
         | 
| 6 8 |  | 
| 7 9 | 
             
            module Bookbinder
         | 
| 8 10 | 
             
              module Config
         | 
| @@ -17,7 +19,9 @@ module Bookbinder | |
| 17 19 | 
             
                      Checkers::DuplicateSectionNameChecker.new,
         | 
| 18 20 | 
             
                      Checkers::RepositoryNamePresenceChecker.new,
         | 
| 19 21 | 
             
                      Checkers::DitaSectionChecker.new,
         | 
| 20 | 
            -
                      Checkers::ArchiveMenuChecker.new(@file_system_accessor)
         | 
| 22 | 
            +
                      Checkers::ArchiveMenuChecker.new(@file_system_accessor),
         | 
| 23 | 
            +
                      Checkers::SubnavsChecker.new,
         | 
| 24 | 
            +
                      Checkers::TopicsChecker.new
         | 
| 21 25 | 
             
                    ].map do |checker|
         | 
| 22 26 | 
             
                      checker.check(config)
         | 
| 23 27 | 
             
                    end
         | 
| @@ -24,13 +24,13 @@ module Bookbinder | |
| 24 24 | 
             
                      write_to: write_to,
         | 
| 25 25 | 
             
                      dita_flags: dita_flags,
         | 
| 26 26 | 
             
                      ditamap_path: dita_section.path_to_preprocessor_attribute('ditamap_location'),
         | 
| 27 | 
            -
                      ditaval_path: dita_section.path_to_preprocessor_attribute('ditaval_location') | 
| 27 | 
            +
                      ditaval_path: dita_section.path_to_preprocessor_attribute('ditaval_location')
         | 
| 28 28 | 
             
                  )
         | 
| 29 29 | 
             
                end
         | 
| 30 30 |  | 
| 31 31 | 
             
                private
         | 
| 32 32 |  | 
| 33 | 
            -
                def unduplicated_flags(write_to: nil, ditamap_path: nil, ditaval_path: nil, dita_flags:  | 
| 33 | 
            +
                def unduplicated_flags(write_to: nil, ditamap_path: nil, ditaval_path: nil, dita_flags: nil)
         | 
| 34 34 | 
             
                  arg_flags = {
         | 
| 35 35 | 
             
                      'output.dir' => write_to,
         | 
| 36 36 | 
             
                      'args.input' => ditamap_path,
         | 
| @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            require_relative 'values/ | 
| 1 | 
            +
            require_relative 'values/subnav_template'
         | 
| 2 2 |  | 
| 3 3 | 
             
            module Bookbinder
         | 
| 4 4 |  | 
| @@ -40,7 +40,7 @@ module Bookbinder | |
| 40 40 | 
             
                                                                     selector: 'div.nav-content',
         | 
| 41 41 | 
             
                                                                     attribute: 'data-props-location',
         | 
| 42 42 | 
             
                                                                     value: json_props_location)
         | 
| 43 | 
            -
                   | 
| 43 | 
            +
                  SubnavTemplate.new(formatted_json_links, nav_text)
         | 
| 44 44 | 
             
                end
         | 
| 45 45 |  | 
| 46 46 | 
             
                private
         | 
| @@ -1,5 +1,3 @@ | |
| 1 | 
            -
            require 'tmpdir'
         | 
| 2 | 
            -
            require_relative '../deprecated_logger'
         | 
| 3 1 | 
             
            require_relative '../values/section'
         | 
| 4 2 |  | 
| 5 3 | 
             
            module Bookbinder
         | 
| @@ -21,6 +19,7 @@ module Bookbinder | |
| 21 19 | 
             
                        working_copy.full_name,
         | 
| 22 20 | 
             
                        section_config.desired_directory_name,
         | 
| 23 21 | 
             
                        section_config.subnav_template,
         | 
| 22 | 
            +
                        section_config.subnav_name,
         | 
| 24 23 | 
             
                        section_config.preprocessor_config
         | 
| 25 24 | 
             
                      )
         | 
| 26 25 | 
             
                    end
         | 
| @@ -20,6 +20,11 @@ module Bookbinder | |
| 20 20 | 
             
                  to
         | 
| 21 21 | 
             
                end
         | 
| 22 22 |  | 
| 23 | 
            +
                def overwrite(to: nil, text: nil)
         | 
| 24 | 
            +
                  File.delete(to) if file_exist?(to)
         | 
| 25 | 
            +
                  write(to: to, text: text)
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 23 28 | 
             
                def read(path)
         | 
| 24 29 | 
             
                  File.read(path)
         | 
| 25 30 | 
             
                end
         | 
| @@ -80,5 +85,14 @@ module Bookbinder | |
| 80 85 | 
             
                    reject {|p| p.to_s.match %r{/\.}}.
         | 
| 81 86 | 
             
                    reject(&:directory?)
         | 
| 82 87 | 
             
                end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                def find_files_extension_agnostically(pattern, directory='.')
         | 
| 90 | 
            +
                  extensionless_pattern = pattern.to_s.split('.').first
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                  `find -L #{directory} -path '*/#{extensionless_pattern}.*'`.
         | 
| 93 | 
            +
                    lines.
         | 
| 94 | 
            +
                    map(&:chomp).
         | 
| 95 | 
            +
                    map(&Pathname.method(:new))
         | 
| 96 | 
            +
                end
         | 
| 83 97 | 
             
              end
         | 
| 84 98 | 
             
            end
         | 
| @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            require_relative '../values/ | 
| 1 | 
            +
            require_relative '../values/subnav_template'
         | 
| 2 2 |  | 
| 3 3 | 
             
            module Bookbinder
         | 
| 4 4 | 
             
              module Preprocessing
         | 
| @@ -18,7 +18,7 @@ module Bookbinder | |
| 18 18 | 
             
                    section.subnav_template.include?('dita_subnav') if section.subnav_template
         | 
| 19 19 | 
             
                  end
         | 
| 20 20 |  | 
| 21 | 
            -
                  def preprocess(dita_sections, output_locations, options: [], output_streams: nil)
         | 
| 21 | 
            +
                  def preprocess(dita_sections, output_locations, options: [], output_streams: nil, **_)
         | 
| 22 22 | 
             
                    dita_options = dita_flags(options)
         | 
| 23 23 | 
             
                    dita_sections.each do |dita_section|
         | 
| 24 24 | 
             
                      if dita_section.path_to_preprocessor_attribute('ditamap_location')
         | 
| @@ -1,26 +1,38 @@ | |
| 1 | 
            +
            require_relative '../subnav/subnav_generator'
         | 
| 2 | 
            +
            require_relative '../subnav/json_from_config'
         | 
| 3 | 
            +
             | 
| 1 4 | 
             
            module Bookbinder
         | 
| 2 5 | 
             
              module Preprocessing
         | 
| 3 6 | 
             
                class LinkToSiteGenDir
         | 
| 4 | 
            -
                  def initialize(filesystem)
         | 
| 7 | 
            +
                  def initialize(filesystem, subnav_generator_factory)
         | 
| 5 8 | 
             
                    @filesystem = filesystem
         | 
| 9 | 
            +
                    @subnav_generator_factory = subnav_generator_factory
         | 
| 6 10 | 
             
                  end
         | 
| 7 11 |  | 
| 8 12 | 
             
                  def applicable_to?(section)
         | 
| 9 13 | 
             
                    filesystem.file_exist?(section.path_to_repository)
         | 
| 10 14 | 
             
                  end
         | 
| 11 15 |  | 
| 12 | 
            -
                  def preprocess(sections, output_locations,  | 
| 16 | 
            +
                  def preprocess(sections, output_locations, config: nil, **_)
         | 
| 13 17 | 
             
                    sections.each do |section|
         | 
| 14 18 | 
             
                      filesystem.link_creating_intermediate_dirs(
         | 
| 15 19 | 
             
                        section.path_to_repository,
         | 
| 16 20 | 
             
                        output_locations.source_for_site_generator.join(section.destination_directory)
         | 
| 17 21 | 
             
                      )
         | 
| 18 22 | 
             
                    end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                    config.subnavs.each do |subnav|
         | 
| 25 | 
            +
                      subnav_generator.generate(subnav)
         | 
| 26 | 
            +
                    end
         | 
| 19 27 | 
             
                  end
         | 
| 20 28 |  | 
| 21 29 | 
             
                  private
         | 
| 22 30 |  | 
| 23 | 
            -
                   | 
| 31 | 
            +
                  def subnav_generator
         | 
| 32 | 
            +
                    @subnav_generator ||= subnav_generator_factory.produce(Subnav::JsonFromConfig.new(filesystem))
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  attr_reader :filesystem, :subnav_generator_factory
         | 
| 24 36 | 
             
                end
         | 
| 25 37 | 
             
              end
         | 
| 26 38 | 
             
            end
         | 
| @@ -0,0 +1,77 @@ | |
| 1 | 
            +
            require 'json'
         | 
| 2 | 
            +
            require 'nokogiri'
         | 
| 3 | 
            +
            require 'redcarpet'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Bookbinder
         | 
| 6 | 
            +
              module Subnav
         | 
| 7 | 
            +
                class JsonFromConfig
         | 
| 8 | 
            +
                  def initialize(fs)
         | 
| 9 | 
            +
                    @fs = fs
         | 
| 10 | 
            +
                    @renderer = Redcarpet::Markdown.new(Redcarpet::Render::HTML.new)
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def get_links(subnav_config, source_for_site_gen)
         | 
| 14 | 
            +
                    @source_for_site_gen = source_for_site_gen
         | 
| 15 | 
            +
                    @config = subnav_config
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                    { links: get_links_and_headers }.to_json
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  attr_reader :fs, :source_for_site_gen, :renderer, :config
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  private
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def get_links_and_headers
         | 
| 25 | 
            +
                    menu_items = []
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    config.topics.map do |topic|
         | 
| 28 | 
            +
                      menu_items << { text: topic.title, title: true }
         | 
| 29 | 
            +
                      menu_items << { url: "/#{topic.toc_path}.html", text: topic.toc_nav_name }
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                      links_from_toc_page = parse_toc_file(topic)
         | 
| 32 | 
            +
                      links_from_toc_page.each {|link| menu_items << link}
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    menu_items
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  def parse_toc_file(topic)
         | 
| 39 | 
            +
                    toc_files = fs.find_files_extension_agnostically(topic.toc_path, source_for_site_gen)
         | 
| 40 | 
            +
                    toc_md = fs.read(toc_files.first)
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                    toc_html = get_html(toc_md)
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                    gather_urls_and_texts(toc_html.css('html'), topic)
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  def get_html(md)
         | 
| 48 | 
            +
                    Nokogiri::HTML(renderer.render(md))
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  def gather_urls_and_texts(base_node, topic)
         | 
| 52 | 
            +
                    nav_items(base_node).map do |element|
         | 
| 53 | 
            +
                      if element.name == 'h2' && !frontmatter_header?(element)
         | 
| 54 | 
            +
                        {text: element.inner_html}
         | 
| 55 | 
            +
                      else
         | 
| 56 | 
            +
                        list_elements = element.css('li > a', 'li > p > a')
         | 
| 57 | 
            +
                        list_elements.map do |li|
         | 
| 58 | 
            +
                          { url: "/#{topic.toc_path.dirname.join(li['href'])}", text: li.inner_text }
         | 
| 59 | 
            +
                        end
         | 
| 60 | 
            +
                      end
         | 
| 61 | 
            +
                    end.flatten
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  def nav_items(base_node)
         | 
| 65 | 
            +
                    base_node.css('h2, ul') - base_node.css(*exclusions)
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  def exclusions
         | 
| 69 | 
            +
                    @exclusions ||= config.subnav_exclusions << '.nav-exclude'
         | 
| 70 | 
            +
                  end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                  def frontmatter_header?(element)
         | 
| 73 | 
            +
                    element.inner_html.include?('title: ')
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
            end
         | 
| @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            require 'nokogiri'
         | 
| 2 | 
            +
            require 'active_support/all'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Bookbinder
         | 
| 5 | 
            +
              module Subnav
         | 
| 6 | 
            +
                class JsonFromHtml
         | 
| 7 | 
            +
                  def get_links_as_json(raw_subnav_text, base_dirname)
         | 
| 8 | 
            +
                    doc = Nokogiri::XML(raw_subnav_text)
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                    all_anchors = doc.css('a')
         | 
| 11 | 
            +
                    all_anchors.each do |anchor|
         | 
| 12 | 
            +
                      anchor['href'] = "/#{base_dirname}/#{anchor['href']}"
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                    {
         | 
| 16 | 
            +
                      links: gather_urls_and_texts(doc.css('body > ul'))
         | 
| 17 | 
            +
                    }.to_json
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  private
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  def gather_urls_and_texts(base_node)
         | 
| 23 | 
            +
                    top_level_li = base_node.css("> li")
         | 
| 24 | 
            +
                    top_level_li.map do |li|
         | 
| 25 | 
            +
                      anchor = li.css('a')[0]
         | 
| 26 | 
            +
                      href = anchor['href']
         | 
| 27 | 
            +
                      text = anchor.inner_text
         | 
| 28 | 
            +
                      ul = li.css('> ul')
         | 
| 29 | 
            +
                      if ul.size > 0
         | 
| 30 | 
            +
                        {url: href, text: text, nestedLinks: gather_urls_and_texts(ul)}
         | 
| 31 | 
            +
                      else
         | 
| 32 | 
            +
                        {url: href, text: text}
         | 
| 33 | 
            +
                      end
         | 
| 34 | 
            +
                    end
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
            end
         | 
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            module Bookbinder
         | 
| 2 | 
            +
              module Subnav
         | 
| 3 | 
            +
                class JsonPropsCreator
         | 
| 4 | 
            +
                  def initialize(fs, output_locations, json_generator)
         | 
| 5 | 
            +
                    @fs = fs
         | 
| 6 | 
            +
                    @output_locations = output_locations
         | 
| 7 | 
            +
                    @json_generator = json_generator
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def create(subnav_config)
         | 
| 11 | 
            +
                    json_links = json_generator.get_links(subnav_config, output_locations.source_for_site_generator)
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    fs.write(text: json_links, to: props_path(subnav_config.name))
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                    filename(subnav_config.name)
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  attr_reader :fs, :output_locations, :json_generator
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  private
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  def filename(name)
         | 
| 23 | 
            +
                    "#{name}-props.json"
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  def subnavs_path
         | 
| 27 | 
            +
                    output_locations.subnavs_for_layout_dir
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  def props_path(name)
         | 
| 31 | 
            +
                    subnavs_path.join(filename(name))
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
| @@ -0,0 +1,52 @@ | |
| 1 | 
            +
            require 'yaml'
         | 
| 2 | 
            +
            require "json"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Bookbinder
         | 
| 5 | 
            +
              module Subnav
         | 
| 6 | 
            +
                class PdfConfigCreator
         | 
| 7 | 
            +
                  def initialize(fs, output_locations)
         | 
| 8 | 
            +
                    @fs = fs
         | 
| 9 | 
            +
                    @output_locations = output_locations
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  def create(props_filename, subnav_config)
         | 
| 13 | 
            +
                    json = JSON.parse(fs.read(props_location(props_filename)))
         | 
| 14 | 
            +
                    @links = format_links(json['links'])
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                    fs.overwrite(to: output_locations.pdf_config_dir.join(subnav_config.pdf_config),
         | 
| 17 | 
            +
                                 text: config_content)
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  attr_reader :fs, :output_locations
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  private
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def props_location(filename)
         | 
| 25 | 
            +
                    output_locations.subnavs_for_layout_dir.join(filename)
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def format_links(links)
         | 
| 29 | 
            +
                    links.map{|item| item['url'] }.compact.map{|link| link.sub(/^\//, '')}
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  def config_content
         | 
| 33 | 
            +
                    config_keys.inject({}) do |hash, key|
         | 
| 34 | 
            +
                      hash[key] = content_for(key)
         | 
| 35 | 
            +
                      hash
         | 
| 36 | 
            +
                    end.to_yaml
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  def config_keys
         | 
| 40 | 
            +
                    %w{copyright_notice header executable pages}
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  def content_for(key)
         | 
| 44 | 
            +
                    key == 'pages' ? @links : default_content
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  def default_content
         | 
| 48 | 
            +
                    'REPLACE ME'
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            module Bookbinder
         | 
| 2 | 
            +
              module Subnav
         | 
| 3 | 
            +
                class SubnavGenerator
         | 
| 4 | 
            +
                  def initialize(json_props_creator, template_creator, pdf_config_creator)
         | 
| 5 | 
            +
                    @json_props_creator = json_props_creator
         | 
| 6 | 
            +
                    @template_creator = template_creator
         | 
| 7 | 
            +
                    @pdf_config_creator = pdf_config_creator
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def generate(subnav_config)
         | 
| 11 | 
            +
                    filename = json_props_creator.create(subnav_config)
         | 
| 12 | 
            +
                    template_creator.create(filename, subnav_config)
         | 
| 13 | 
            +
                    pdf_config_creator.create(filename, subnav_config) if subnav_config.pdf_config
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  attr_reader :json_props_creator, :template_creator, :pdf_config_creator
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            require_relative 'json_props_creator'
         | 
| 2 | 
            +
            require_relative 'template_creator'
         | 
| 3 | 
            +
            require_relative 'pdf_config_creator'
         | 
| 4 | 
            +
            require_relative '../html_document_manipulator'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Bookbinder
         | 
| 7 | 
            +
              module Subnav
         | 
| 8 | 
            +
                class SubnavGeneratorFactory
         | 
| 9 | 
            +
                  def initialize(fs, output_locations)
         | 
| 10 | 
            +
                    @fs = fs
         | 
| 11 | 
            +
                    @output_locations = output_locations
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def produce(json_generator)
         | 
| 15 | 
            +
                    SubnavGenerator.new(json_props_creator(json_generator), template_creator, pdf_config_creator)
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  attr_reader :fs, :output_locations
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  private
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  def json_props_creator(json_generator)
         | 
| 23 | 
            +
                    @json_props_creator ||= JsonPropsCreator.new(fs, output_locations, json_generator)
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  def template_creator
         | 
| 27 | 
            +
                    @template_creator ||= TemplateCreator.new(fs, output_locations, HtmlDocumentManipulator.new)
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  def pdf_config_creator
         | 
| 31 | 
            +
                    @pdf_config_creator ||= PdfConfigCreator.new(fs, output_locations)
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
| @@ -0,0 +1,41 @@ | |
| 1 | 
            +
            module Bookbinder
         | 
| 2 | 
            +
              module Subnav
         | 
| 3 | 
            +
                class TemplateCreator
         | 
| 4 | 
            +
                  def initialize(fs, output_locations, html_doc_manipulator)
         | 
| 5 | 
            +
                    @fs = fs
         | 
| 6 | 
            +
                    @output_locations = output_locations
         | 
| 7 | 
            +
                    @html_doc_manipulator = html_doc_manipulator
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def create(props_filename, subnav_config)
         | 
| 11 | 
            +
                    template_content = fs.read(template_path)
         | 
| 12 | 
            +
                    nav_content = html_doc_manipulator.set_attribute(document: template_content,
         | 
| 13 | 
            +
                                                                     selector: 'div.nav-content',
         | 
| 14 | 
            +
                                                                     attribute: 'data-props-location',
         | 
| 15 | 
            +
                                                                     value: props_filename)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                    fs.write(text: nav_content, to: subnav_destination(subnav_config.name))
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  attr_reader :fs, :output_locations, :html_doc_manipulator
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  private
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def subnavs_path
         | 
| 25 | 
            +
                    output_locations.subnavs_for_layout_dir
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def filename(name)
         | 
| 29 | 
            +
                    "#{name}.erb"
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  def template_path
         | 
| 33 | 
            +
                    subnavs_path.join('subnav_template.erb')
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  def subnav_destination(name)
         | 
| 37 | 
            +
                    subnavs_path.join(filename(name))
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
            end
         | 
| @@ -6,6 +6,7 @@ module Bookbinder | |
| 6 6 | 
             
                                   :full_name,
         | 
| 7 7 | 
             
                                   :desired_directory_name,
         | 
| 8 8 | 
             
                                   :subnav_templ,
         | 
| 9 | 
            +
                                   :subnav_name,
         | 
| 9 10 | 
             
                                   :preprocessor_config) do
         | 
| 10 11 | 
             
                def path_to_repository
         | 
| 11 12 | 
             
                  Pathname(self[:path_to_repository].to_s)
         | 
| @@ -21,7 +22,7 @@ module Bookbinder | |
| 21 22 |  | 
| 22 23 | 
             
                def subnav
         | 
| 23 24 | 
             
                  namespace = destination_directory.to_s.gsub('/', '_')
         | 
| 24 | 
            -
                  template = subnav_template || 'default'
         | 
| 25 | 
            +
                  template = subnav_template || subnav_name || 'default'
         | 
| 25 26 | 
             
                  {namespace => template}
         | 
| 26 27 | 
             
                end
         | 
| 27 28 |  | 
| @@ -48,9 +48,10 @@ module Bookbinder | |
| 48 48 | 
             
                      config[:archive_menu],
         | 
| 49 49 | 
             
                      current_path: current_page.path
         | 
| 50 50 | 
             
                    )
         | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 51 | 
            +
                    unless menu.empty?
         | 
| 52 | 
            +
                      partial 'archive_menus/default', locals: { menu_title: menu.title,
         | 
| 53 | 
            +
                                                                 dropdown_links: menu.dropdown_links }
         | 
| 54 | 
            +
                    end
         | 
| 54 55 | 
             
                  end
         | 
| 55 56 |  | 
| 56 57 | 
             
                  def modified_date(format="%B %-d, %Y")
         | 
| 
            File without changes
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: bookbindery
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version:  | 
| 4 | 
            +
              version: 7.0.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Mike Grafton
         | 
| @@ -17,7 +17,7 @@ authors: | |
| 17 17 | 
             
            autorequire: 
         | 
| 18 18 | 
             
            bindir: install_bin
         | 
| 19 19 | 
             
            cert_chain: []
         | 
| 20 | 
            -
            date: 2015- | 
| 20 | 
            +
            date: 2015-10-10 00:00:00.000000000 Z
         | 
| 21 21 | 
             
            dependencies:
         | 
| 22 22 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 23 23 | 
             
              name: fog-aws
         | 
| @@ -301,6 +301,7 @@ files: | |
| 301 301 | 
             
            - lib/bookbinder/command_validator.rb
         | 
| 302 302 | 
             
            - lib/bookbinder/commands/bind/bind_options.rb
         | 
| 303 303 | 
             
            - lib/bookbinder/commands/bind/directory_preparer.rb
         | 
| 304 | 
            +
            - lib/bookbinder/commands/bind/layout_preparer.rb
         | 
| 304 305 | 
             
            - lib/bookbinder/commands/bind.rb
         | 
| 305 306 | 
             
            - lib/bookbinder/commands/build_and_push_tarball.rb
         | 
| 306 307 | 
             
            - lib/bookbinder/commands/chain.rb
         | 
| @@ -322,10 +323,14 @@ files: | |
| 322 323 | 
             
            - lib/bookbinder/config/checkers/duplicate_section_name_checker.rb
         | 
| 323 324 | 
             
            - lib/bookbinder/config/checkers/repository_name_presence_checker.rb
         | 
| 324 325 | 
             
            - lib/bookbinder/config/checkers/required_keys_checker.rb
         | 
| 326 | 
            +
            - lib/bookbinder/config/checkers/subnavs_checker.rb
         | 
| 327 | 
            +
            - lib/bookbinder/config/checkers/topics_checker.rb
         | 
| 325 328 | 
             
            - lib/bookbinder/config/configuration.rb
         | 
| 326 329 | 
             
            - lib/bookbinder/config/fetcher.rb
         | 
| 327 330 | 
             
            - lib/bookbinder/config/remote_yaml_credential_provider.rb
         | 
| 328 331 | 
             
            - lib/bookbinder/config/section_config.rb
         | 
| 332 | 
            +
            - lib/bookbinder/config/subnav_config.rb
         | 
| 333 | 
            +
            - lib/bookbinder/config/topic_config.rb
         | 
| 329 334 | 
             
            - lib/bookbinder/config/validator.rb
         | 
| 330 335 | 
             
            - lib/bookbinder/config/yaml_loader.rb
         | 
| 331 336 | 
             
            - lib/bookbinder/css_link_checker.rb
         | 
| @@ -370,11 +375,17 @@ files: | |
| 370 375 | 
             
            - lib/bookbinder/spider.rb
         | 
| 371 376 | 
             
            - lib/bookbinder/stabilimentum.rb
         | 
| 372 377 | 
             
            - lib/bookbinder/streams/colorized_stream.rb
         | 
| 373 | 
            -
            - lib/bookbinder/ | 
| 378 | 
            +
            - lib/bookbinder/subnav/json_from_config.rb
         | 
| 379 | 
            +
            - lib/bookbinder/subnav/json_from_html.rb
         | 
| 380 | 
            +
            - lib/bookbinder/subnav/json_props_creator.rb
         | 
| 381 | 
            +
            - lib/bookbinder/subnav/pdf_config_creator.rb
         | 
| 382 | 
            +
            - lib/bookbinder/subnav/subnav_generator.rb
         | 
| 383 | 
            +
            - lib/bookbinder/subnav/subnav_generator_factory.rb
         | 
| 384 | 
            +
            - lib/bookbinder/subnav/template_creator.rb
         | 
| 374 385 | 
             
            - lib/bookbinder/terminal.rb
         | 
| 375 386 | 
             
            - lib/bookbinder/values/output_locations.rb
         | 
| 376 387 | 
             
            - lib/bookbinder/values/section.rb
         | 
| 377 | 
            -
            - lib/bookbinder/values/ | 
| 388 | 
            +
            - lib/bookbinder/values/subnav_template.rb
         | 
| 378 389 | 
             
            - lib/bookbinder/values/user_message.rb
         | 
| 379 390 | 
             
            - template_app/app.rb
         | 
| 380 391 | 
             
            - template_app/config.ru
         | 
| @@ -385,6 +396,7 @@ files: | |
| 385 396 | 
             
            - template_app/rack_app.rb
         | 
| 386 397 | 
             
            - master_middleman/archive_drop_down_menu.rb
         | 
| 387 398 | 
             
            - master_middleman/bookbinder_helpers.rb
         | 
| 399 | 
            +
            - master_middleman/compass_runner.rb
         | 
| 388 400 | 
             
            - master_middleman/config.rb
         | 
| 389 401 | 
             
            - master_middleman/quicklinks_renderer.rb
         | 
| 390 402 | 
             
            - master_middleman/subdirectory_aware_assets.rb
         | 
| @@ -400,7 +412,7 @@ require_paths: | |
| 400 412 | 
             
            - lib
         | 
| 401 413 | 
             
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 402 414 | 
             
              requirements:
         | 
| 403 | 
            -
              - -  | 
| 415 | 
            +
              - - '>='
         | 
| 404 416 | 
             
                - !ruby/object:Gem::Version
         | 
| 405 417 | 
             
                  version: '2.0'
         | 
| 406 418 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| @@ -1,37 +0,0 @@ | |
| 1 | 
            -
            require 'nokogiri'
         | 
| 2 | 
            -
            require 'active_support/all'
         | 
| 3 | 
            -
             | 
| 4 | 
            -
            module Bookbinder
         | 
| 5 | 
            -
              class SubnavFormatter
         | 
| 6 | 
            -
             | 
| 7 | 
            -
                def get_links_as_json(raw_subnav_text, base_dirname)
         | 
| 8 | 
            -
                  doc = Nokogiri::XML(raw_subnav_text)
         | 
| 9 | 
            -
             | 
| 10 | 
            -
                  all_anchors = doc.css('a')
         | 
| 11 | 
            -
                  all_anchors.each do |anchor|
         | 
| 12 | 
            -
                    anchor['href'] = "/#{base_dirname}/#{anchor['href']}"
         | 
| 13 | 
            -
                  end
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                  {
         | 
| 16 | 
            -
                    links: gather_urls_and_texts(doc.css('body > ul'))
         | 
| 17 | 
            -
                  }.to_json
         | 
| 18 | 
            -
                end
         | 
| 19 | 
            -
             | 
| 20 | 
            -
                private
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                def gather_urls_and_texts(base_node)
         | 
| 23 | 
            -
                  top_level_li = base_node.css("> li")
         | 
| 24 | 
            -
                  top_level_li.map do |li|
         | 
| 25 | 
            -
                    anchor = li.css('a')[0]
         | 
| 26 | 
            -
                    href = anchor['href']
         | 
| 27 | 
            -
                    text = anchor.inner_text
         | 
| 28 | 
            -
                    ul = li.css('> ul')
         | 
| 29 | 
            -
                    if ul.size > 0
         | 
| 30 | 
            -
                      {url: href, text: text, nestedLinks: gather_urls_and_texts(ul)}
         | 
| 31 | 
            -
                    else
         | 
| 32 | 
            -
                      {url: href, text: text}
         | 
| 33 | 
            -
                    end
         | 
| 34 | 
            -
                  end
         | 
| 35 | 
            -
                end
         | 
| 36 | 
            -
              end
         | 
| 37 | 
            -
            end
         |