Merge pull request #1633 from dg-ratiodata/feature/preven_crash_due_to_invalid_data_file

Refactor Data Loader to prevent middleman from crashing due to invalid…
v3-stable
Thomas Reynolds 2015-10-09 12:41:26 -07:00
commit 58e794645b
3 changed files with 103 additions and 8 deletions

View File

@ -51,3 +51,31 @@ Feature: Local Data API
Then I should see "title1:Hello"
Then I should see "title2:More"
Then I should see "title3:Stuff"
Scenario: Invalid YAML
Given a fixture app "basic-data-app"
And the default aruba timeout is 30 seconds
And a file named "data/test.yml" with:
"""
'ASDSFDa:
-asdf asdf
"""
When I run `middleman build`
Then the output should contain:
"""
failed due to an error:
"""
Scenario: Invalid JSON
Given a fixture app "basic-data-app"
And the default aruba timeout is 30 seconds
And a file named "data/test.json" with:
"""
'ASDSFDa:
-asdf asdf
"""
When I run `middleman build`
Then the output should contain:
"""
failed due to an error:
"""

View File

@ -7,9 +7,7 @@ module Middleman
class << self
# @private
def registered(app)
# Data formats
require 'yaml'
require 'json'
require 'middleman-core/core_extensions/data/file_loader'
app.config.define_setting :data_dir, 'data', 'The directory data files are stored in'
app.send :include, InstanceMethods
@ -95,11 +93,9 @@ module Middleman
data_path = full_path.relative_path_from(root + @app.config[:data_dir])
if %w(.yaml .yml).include?(extension)
data = YAML.load_file(full_path)
elsif extension == '.json'
data = JSON.parse(full_path.read)
else
begin
data = FileLoader.new.load(full_path)
rescue FileLoader::NoFileLoaderFoundError
return
end

View File

@ -0,0 +1,71 @@
require 'yaml'
require 'json'
module Middleman
module CoreExtensions
module Data
# Load data files
class FileLoader
# No parser available
class NoFileLoaderFoundError < StandardError; end
# Load yaml files
class YamlFileLoader
def match?(file)
%w(.yaml .yml).include? File.extname(file)
end
# @param [Pathname] file
def load(file)
YAML.load_file(file)
rescue Psych::SyntaxError, StandardError => e
$stderr.puts %(Loading data file "#{file}" failed due to an error: #{e.message})
{}
end
end
# Load json files
class JsonFileLoader
def match?(file)
'.json' == File.extname(file)
end
# @param [Pathname] file
def load(file)
JSON.parse(file.read)
rescue => e
$stderr.puts %(Loading data file "#{file}" failed due to an error: #{e.message})
{}
end
end
# Default loader
#
# Always fails
class NilFileLoader
def match?(file)
raise NoFileLoaderFoundError
end
end
private
attr_reader :loaders
public
def initialize
@loaders = []
@loaders << YamlFileLoader.new
@loaders << JsonFileLoader.new
@loaders << NilFileLoader.new
end
# Load file using loader
def load(file)
loaders.find { |l| l.match? file }.load(file)
end
end
end
end
end