From c7cc36abdb59c161037cc36b6816cc53952a3841 Mon Sep 17 00:00:00 2001 From: Parker Moore Date: Sat, 12 Jul 2014 13:47:59 -0700 Subject: [PATCH] Put errors/exceptions into Jekyll::Errors module --- lib/jekyll/command.rb | 2 +- lib/jekyll/converters/markdown.rb | 27 +- .../converters/markdown/kramdown_parser.rb | 2 +- .../converters/markdown/maruku_parser.rb | 2 +- lib/jekyll/converters/textile.rb | 2 +- lib/jekyll/errors.rb | 5 +- lib/jekyll/excerpt.rb | 1 - lib/jekyll/frontmatter_defaults.rb | 252 +++++++++--------- lib/jekyll/post.rb | 2 +- lib/jekyll/site.rb | 4 +- test/test_command.rb | 2 +- test/test_post.rb | 2 +- test/test_site.rb | 8 +- 13 files changed, 165 insertions(+), 146 deletions(-) diff --git a/lib/jekyll/command.rb b/lib/jekyll/command.rb index 654f0ae3..d11631d8 100644 --- a/lib/jekyll/command.rb +++ b/lib/jekyll/command.rb @@ -51,7 +51,7 @@ module Jekyll # Returns nothing def process_site(site) site.process - rescue Jekyll::FatalException => e + rescue Jekyll::Errors::FatalException => e Jekyll.logger.error "ERROR:", "YOUR SITE COULD NOT BE BUILT:" Jekyll.logger.error "", "------------------------------------" Jekyll.logger.error "", e.message diff --git a/lib/jekyll/converters/markdown.rb b/lib/jekyll/converters/markdown.rb index f68af673..687b0eca 100644 --- a/lib/jekyll/converters/markdown.rb +++ b/lib/jekyll/converters/markdown.rb @@ -11,22 +11,41 @@ module Jekyll @parser = case @config['markdown'].downcase when 'redcarpet' then RedcarpetParser.new(@config) - when 'kramdown' then KramdownParser.new(@config) + when 'kramdown' then KramdownParser.new(@config) when 'rdiscount' then RDiscountParser.new(@config) - when 'maruku' then MarukuParser.new(@config) + when 'maruku' then MarukuParser.new(@config) else # So they can't try some tricky bullshit or go down the ancestor chain, I hope. if allowed_custom_class?(@config['markdown']) self.class.const_get(@config['markdown']).new(@config) else Jekyll.logger.error "Invalid Markdown Processor:", "#{@config['markdown']}" - Jekyll.logger.error "", "Valid options are [ maruku | rdiscount | kramdown | redcarpet ]" - raise FatalException, "Invalid Markdown Processor: #{@config['markdown']}" + Jekyll.logger.error "", "Valid options are [ #{valid_processors.join(" | ")} ]" + raise Errors::FatalException, "Invalid Markdown Processor: #{@config['markdown']}" end end @setup = true end + def valid_processors + %w[ + maruku + rdiscount + kramdown + redcarpet + ] + third_party_processors + end + + def third_party_processors + self.class.constants - %w[ + KramdownParser + MarukuParser + RDiscountParser + RedcarpetParser + PRIORITIES + ].map(&:to_sym) + end + def matches(ext) rgx = '^\.(' + @config['markdown_ext'].gsub(',','|') +')$' ext =~ Regexp.new(rgx, Regexp::IGNORECASE) diff --git a/lib/jekyll/converters/markdown/kramdown_parser.rb b/lib/jekyll/converters/markdown/kramdown_parser.rb index cd1fdf9a..9dd086e4 100644 --- a/lib/jekyll/converters/markdown/kramdown_parser.rb +++ b/lib/jekyll/converters/markdown/kramdown_parser.rb @@ -8,7 +8,7 @@ module Jekyll rescue LoadError STDERR.puts 'You are missing a library required for Markdown. Please run:' STDERR.puts ' $ [sudo] gem install kramdown' - raise FatalException.new("Missing dependency: kramdown") + raise Errors::FatalException.new("Missing dependency: kramdown") end def convert(content) diff --git a/lib/jekyll/converters/markdown/maruku_parser.rb b/lib/jekyll/converters/markdown/maruku_parser.rb index 7d14c8a5..7be577c8 100644 --- a/lib/jekyll/converters/markdown/maruku_parser.rb +++ b/lib/jekyll/converters/markdown/maruku_parser.rb @@ -15,7 +15,7 @@ module Jekyll rescue LoadError STDERR.puts 'You are missing a library required for Markdown. Please run:' STDERR.puts ' $ [sudo] gem install maruku' - raise FatalException.new("Missing dependency: maruku") + raise Errors::FatalException.new("Missing dependency: maruku") end def load_divs_library diff --git a/lib/jekyll/converters/textile.rb b/lib/jekyll/converters/textile.rb index d05b2169..85e0e355 100644 --- a/lib/jekyll/converters/textile.rb +++ b/lib/jekyll/converters/textile.rb @@ -13,7 +13,7 @@ module Jekyll rescue LoadError STDERR.puts 'You are missing a library required for Textile. Please run:' STDERR.puts ' $ [sudo] gem install RedCloth' - raise FatalException.new("Missing dependency: RedCloth") + raise Errors::FatalException.new("Missing dependency: RedCloth") end def matches(ext) diff --git a/lib/jekyll/errors.rb b/lib/jekyll/errors.rb index 6801f9b5..dc5238a0 100644 --- a/lib/jekyll/errors.rb +++ b/lib/jekyll/errors.rb @@ -1,5 +1,8 @@ module Jekyll - class FatalException < StandardError + module Errors + class FatalException < RuntimeError + end + class MissingDependencyException < FatalException end end diff --git a/lib/jekyll/excerpt.rb b/lib/jekyll/excerpt.rb index 130b2880..958e3f3c 100644 --- a/lib/jekyll/excerpt.rb +++ b/lib/jekyll/excerpt.rb @@ -1,4 +1,3 @@ -require 'jekyll/convertible' require 'forwardable' module Jekyll diff --git a/lib/jekyll/frontmatter_defaults.rb b/lib/jekyll/frontmatter_defaults.rb index 42b85ed5..e747143b 100644 --- a/lib/jekyll/frontmatter_defaults.rb +++ b/lib/jekyll/frontmatter_defaults.rb @@ -1,147 +1,145 @@ module Jekyll - class Configuration - # This class handles custom defaults for YAML frontmatter settings. - # These are set in _config.yml and apply both to internal use (e.g. layout) - # and the data available to liquid. + # This class handles custom defaults for YAML frontmatter settings. + # These are set in _config.yml and apply both to internal use (e.g. layout) + # and the data available to liquid. + # + # It is exposed via the frontmatter_defaults method on the site class. + class FrontmatterDefaults + # Initializes a new instance. + def initialize(site) + @site = site + end + + # Finds a default value for a given setting, filtered by path and type # - # It is exposed via the frontmatter_defaults method on the site class. - class FrontmatterDefaults - # Initializes a new instance. - def initialize(site) - @site = site - end + # path - the path (relative to the source) of the page, post or :draft the default is used in + # type - a symbol indicating whether a :page, a :post or a :draft calls this method + # + # Returns the default value or nil if none was found + def find(path, type, setting) + value = nil + old_scope = nil - # Finds a default value for a given setting, filtered by path and type - # - # path - the path (relative to the source) of the page, post or :draft the default is used in - # type - a symbol indicating whether a :page, a :post or a :draft calls this method - # - # Returns the default value or nil if none was found - def find(path, type, setting) - value = nil - old_scope = nil - - matching_sets(path, type).each do |set| - if set['values'].has_key?(setting) && has_precedence?(old_scope, set['scope']) - value = set['values'][setting] - old_scope = set['scope'] - end - end - value - end - - # Collects a hash with all default values for a page or post - # - # path - the relative path of the page or post - # type - a symbol indicating the type (:post, :page or :draft) - # - # Returns a hash with all default values (an empty hash if there are none) - def all(path, type) - defaults = {} - old_scope = nil - matching_sets(path, type).each do |set| - if has_precedence?(old_scope, set['scope']) - defaults = Utils.deep_merge_hashes(defaults, set['values']) - old_scope = set['scope'] - else - defaults = Utils.deep_merge_hashes(set['values'], defaults) - end - end - defaults - end - - private - - # Checks if a given default setting scope matches the given path and type - # - # scope - the hash indicating the scope, as defined in _config.yml - # path - the path to check for - # type - the type (:post, :page or :draft) to check for - # - # Returns true if the scope applies to the given path and type - def applies?(scope, path, type) - applies_path?(scope, path) && applies_type?(scope, type) - end - - def applies_path?(scope, path) - return true if scope['path'].empty? - - scope_path = Pathname.new(scope['path']) - Pathname.new(sanitize_path(path)).ascend do |path| - if path == scope_path - return true - end + matching_sets(path, type).each do |set| + if set['values'].has_key?(setting) && has_precedence?(old_scope, set['scope']) + value = set['values'][setting] + old_scope = set['scope'] end end + value + end - def applies_type?(scope, type) - !scope.has_key?('type') || scope['type'] == type.to_s - end - - # Checks if a given set of default values is valid - # - # set - the default value hash, as defined in _config.yml - # - # Returns true if the set is valid and can be used in this class - def valid?(set) - set.is_a?(Hash) && set['scope'].is_a?(Hash) && set['scope']['path'].is_a?(String) && set['values'].is_a?(Hash) - end - - # Determines if a new scope has precedence over an old one - # - # old_scope - the old scope hash, or nil if there's none - # new_scope - the new scope hash - # - # Returns true if the new scope has precedence over the older - def has_precedence?(old_scope, new_scope) - return true if old_scope.nil? - - new_path = sanitize_path(new_scope['path']) - old_path = sanitize_path(old_scope['path']) - - if new_path.length != old_path.length - new_path.length >= old_path.length - elsif new_scope.has_key? 'type' - true + # Collects a hash with all default values for a page or post + # + # path - the relative path of the page or post + # type - a symbol indicating the type (:post, :page or :draft) + # + # Returns a hash with all default values (an empty hash if there are none) + def all(path, type) + defaults = {} + old_scope = nil + matching_sets(path, type).each do |set| + if has_precedence?(old_scope, set['scope']) + defaults = Utils.deep_merge_hashes(defaults, set['values']) + old_scope = set['scope'] else - !old_scope.has_key? 'type' + defaults = Utils.deep_merge_hashes(set['values'], defaults) end end + defaults + end - # Collects a list of sets that match the given path and type - # - # Returns an array of hashes - def matching_sets(path, type) - valid_sets.select do |set| - applies?(set['scope'], path, type) + private + + # Checks if a given default setting scope matches the given path and type + # + # scope - the hash indicating the scope, as defined in _config.yml + # path - the path to check for + # type - the type (:post, :page or :draft) to check for + # + # Returns true if the scope applies to the given path and type + def applies?(scope, path, type) + applies_path?(scope, path) && applies_type?(scope, type) + end + + def applies_path?(scope, path) + return true if scope['path'].empty? + + scope_path = Pathname.new(scope['path']) + Pathname.new(sanitize_path(path)).ascend do |path| + if path == scope_path + return true end end + end - # Returns a list of valid sets - # - # This is not cached to allow plugins to modify the configuration - # and have their changes take effect - # - # Returns an array of hashes - def valid_sets - sets = @site.config['defaults'] - return [] unless sets.is_a?(Array) + def applies_type?(scope, type) + !scope.has_key?('type') || scope['type'] == type.to_s + end - sets.select do |set| - unless valid?(set) - Jekyll.logger.warn "Default:", "An invalid default set was found" - end - valid?(set) - end + # Checks if a given set of default values is valid + # + # set - the default value hash, as defined in _config.yml + # + # Returns true if the set is valid and can be used in this class + def valid?(set) + set.is_a?(Hash) && set['scope'].is_a?(Hash) && set['scope']['path'].is_a?(String) && set['values'].is_a?(Hash) + end + + # Determines if a new scope has precedence over an old one + # + # old_scope - the old scope hash, or nil if there's none + # new_scope - the new scope hash + # + # Returns true if the new scope has precedence over the older + def has_precedence?(old_scope, new_scope) + return true if old_scope.nil? + + new_path = sanitize_path(new_scope['path']) + old_path = sanitize_path(old_scope['path']) + + if new_path.length != old_path.length + new_path.length >= old_path.length + elsif new_scope.has_key? 'type' + true + else + !old_scope.has_key? 'type' end + end - # Sanitizes the given path by removing a leading and addding a trailing slash - def sanitize_path(path) - if path.nil? || path.empty? - "" - else - path.gsub(/\A\//, '').gsub(/([^\/])\z/, '\1/') + # Collects a list of sets that match the given path and type + # + # Returns an array of hashes + def matching_sets(path, type) + valid_sets.select do |set| + applies?(set['scope'], path, type) + end + end + + # Returns a list of valid sets + # + # This is not cached to allow plugins to modify the configuration + # and have their changes take effect + # + # Returns an array of hashes + def valid_sets + sets = @site.config['defaults'] + return [] unless sets.is_a?(Array) + + sets.select do |set| + unless valid?(set) + Jekyll.logger.warn "Default:", "An invalid default set was found" end + valid?(set) + end + end + + # Sanitizes the given path by removing a leading and addding a trailing slash + def sanitize_path(path) + if path.nil? || path.empty? + "" + else + path.gsub(/\A\//, '').gsub(/([^\/])\z/, '\1/') end end end diff --git a/lib/jekyll/post.rb b/lib/jekyll/post.rb index f13d8b2c..82ed696f 100644 --- a/lib/jekyll/post.rb +++ b/lib/jekyll/post.rb @@ -166,7 +166,7 @@ module Jekyll path = File.join(@dir || "", name) msg = "Post '#{path}' does not have a valid date.\n" msg << "Fix the date, or exclude the file or directory from being processed" - raise FatalException.new(msg) + raise Errors::FatalException.new(msg) end # The generated directory into which the post will be placed diff --git a/lib/jekyll/site.rb b/lib/jekyll/site.rb index 1015d5d9..15bacb14 100644 --- a/lib/jekyll/site.rb +++ b/lib/jekyll/site.rb @@ -80,7 +80,7 @@ module Jekyll dest_pathname = Pathname.new(dest) Pathname.new(source).ascend do |path| if path == dest_pathname - raise FatalException.new "Destination directory cannot be or contain the Source directory." + raise Errors::FatalException.new "Destination directory cannot be or contain the Source directory." end end end @@ -443,7 +443,7 @@ module Jekyll end def frontmatter_defaults - @frontmatter_defaults ||= Configuration::FrontmatterDefaults.new(self) + @frontmatter_defaults ||= FrontmatterDefaults.new(self) end private diff --git a/test/test_command.rb b/test/test_command.rb index 23f23379..8d1a751d 100644 --- a/test/test_command.rb +++ b/test/test_command.rb @@ -44,7 +44,7 @@ class TestCommand < Test::Unit::TestCase context "when fatal error occurs" do should "exit with non-zero error code" do site = Object.new - stub(site).process { raise Jekyll::FatalException } + stub(site).process { raise Jekyll::Errors::FatalException } error = assert_raise(SystemExit) { Command.process_site(site) } assert_not_equal 0, error.status end diff --git a/test/test_post.rb b/test/test_post.rb index 5e264ea7..28c6366b 100644 --- a/test/test_post.rb +++ b/test/test_post.rb @@ -83,7 +83,7 @@ class TestPost < Test::Unit::TestCase end should "raise a good error on invalid post date" do - assert_raise Jekyll::FatalException do + assert_raise Jekyll::Errors::FatalException do @post.process("2009-27-03-foo-bar.textile") end end diff --git a/test/test_site.rb b/test/test_site.rb index 48290d45..a343b1c9 100644 --- a/test/test_site.rb +++ b/test/test_site.rb @@ -225,7 +225,7 @@ class TestSite < Test::Unit::TestCase Jekyll::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => source_dir}) end - assert_raise Jekyll::FatalException do + assert_raise Jekyll::Errors::FatalException do site = Site.new(Jekyll.configuration) end end @@ -235,7 +235,7 @@ class TestSite < Test::Unit::TestCase Jekyll::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => File.join(source_dir, "..")}) end - assert_raise Jekyll::FatalException do + assert_raise Jekyll::Errors::FatalException do site = Site.new(Jekyll.configuration) end end @@ -332,7 +332,7 @@ class TestSite < Test::Unit::TestCase bad_processor = "Custom::Markdown" s = Site.new(Jekyll.configuration.merge({ 'markdown' => bad_processor })) - assert_raise Jekyll::FatalException do + assert_raise Jekyll::Errors::FatalException do s.process end @@ -352,7 +352,7 @@ class TestSite < Test::Unit::TestCase should 'throw FatalException at process time' do bad_processor = 'not a processor name' s = Site.new(Jekyll.configuration.merge({ 'markdown' => bad_processor })) - assert_raise Jekyll::FatalException do + assert_raise Jekyll::Errors::FatalException do s.process end end