bunto 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.markdown +59 -0
  4. data/bin/bunto +51 -0
  5. data/lib/bunto.rb +179 -0
  6. data/lib/bunto/cleaner.rb +105 -0
  7. data/lib/bunto/collection.rb +205 -0
  8. data/lib/bunto/command.rb +65 -0
  9. data/lib/bunto/commands/build.rb +77 -0
  10. data/lib/bunto/commands/clean.rb +42 -0
  11. data/lib/bunto/commands/doctor.rb +114 -0
  12. data/lib/bunto/commands/help.rb +31 -0
  13. data/lib/bunto/commands/new.rb +82 -0
  14. data/lib/bunto/commands/serve.rb +204 -0
  15. data/lib/bunto/commands/serve/servlet.rb +61 -0
  16. data/lib/bunto/configuration.rb +323 -0
  17. data/lib/bunto/converter.rb +48 -0
  18. data/lib/bunto/converters/identity.rb +21 -0
  19. data/lib/bunto/converters/markdown.rb +92 -0
  20. data/lib/bunto/converters/markdown/kramdown_parser.rb +117 -0
  21. data/lib/bunto/converters/markdown/rdiscount_parser.rb +33 -0
  22. data/lib/bunto/converters/markdown/redcarpet_parser.rb +102 -0
  23. data/lib/bunto/converters/smartypants.rb +34 -0
  24. data/lib/bunto/convertible.rb +297 -0
  25. data/lib/bunto/deprecator.rb +46 -0
  26. data/lib/bunto/document.rb +444 -0
  27. data/lib/bunto/drops/bunto_drop.rb +21 -0
  28. data/lib/bunto/drops/collection_drop.rb +22 -0
  29. data/lib/bunto/drops/document_drop.rb +27 -0
  30. data/lib/bunto/drops/drop.rb +176 -0
  31. data/lib/bunto/drops/site_drop.rb +38 -0
  32. data/lib/bunto/drops/unified_payload_drop.rb +25 -0
  33. data/lib/bunto/drops/url_drop.rb +83 -0
  34. data/lib/bunto/entry_filter.rb +72 -0
  35. data/lib/bunto/errors.rb +10 -0
  36. data/lib/bunto/excerpt.rb +127 -0
  37. data/lib/bunto/external.rb +59 -0
  38. data/lib/bunto/filters.rb +367 -0
  39. data/lib/bunto/frontmatter_defaults.rb +188 -0
  40. data/lib/bunto/generator.rb +3 -0
  41. data/lib/bunto/hooks.rb +101 -0
  42. data/lib/bunto/layout.rb +49 -0
  43. data/lib/bunto/liquid_extensions.rb +22 -0
  44. data/lib/bunto/liquid_renderer.rb +39 -0
  45. data/lib/bunto/liquid_renderer/file.rb +50 -0
  46. data/lib/bunto/liquid_renderer/table.rb +94 -0
  47. data/lib/bunto/log_adapter.rb +115 -0
  48. data/lib/bunto/mime.types +800 -0
  49. data/lib/bunto/page.rb +180 -0
  50. data/lib/bunto/plugin.rb +96 -0
  51. data/lib/bunto/plugin_manager.rb +95 -0
  52. data/lib/bunto/post.rb +329 -0
  53. data/lib/bunto/publisher.rb +21 -0
  54. data/lib/bunto/reader.rb +126 -0
  55. data/lib/bunto/readers/collection_reader.rb +20 -0
  56. data/lib/bunto/readers/data_reader.rb +69 -0
  57. data/lib/bunto/readers/layout_reader.rb +53 -0
  58. data/lib/bunto/readers/page_reader.rb +21 -0
  59. data/lib/bunto/readers/post_reader.rb +62 -0
  60. data/lib/bunto/readers/static_file_reader.rb +21 -0
  61. data/lib/bunto/regenerator.rb +175 -0
  62. data/lib/bunto/related_posts.rb +56 -0
  63. data/lib/bunto/renderer.rb +191 -0
  64. data/lib/bunto/site.rb +391 -0
  65. data/lib/bunto/static_file.rb +141 -0
  66. data/lib/bunto/stevenson.rb +58 -0
  67. data/lib/bunto/tags/highlight.rb +122 -0
  68. data/lib/bunto/tags/include.rb +190 -0
  69. data/lib/bunto/tags/post_url.rb +88 -0
  70. data/lib/bunto/url.rb +136 -0
  71. data/lib/bunto/utils.rb +287 -0
  72. data/lib/bunto/utils/ansi.rb +59 -0
  73. data/lib/bunto/utils/platforms.rb +30 -0
  74. data/lib/bunto/version.rb +3 -0
  75. data/lib/site_template/.gitignore +3 -0
  76. data/lib/site_template/_config.yml +21 -0
  77. data/lib/site_template/_includes/footer.html +38 -0
  78. data/lib/site_template/_includes/head.html +12 -0
  79. data/lib/site_template/_includes/header.html +27 -0
  80. data/lib/site_template/_includes/icon-github.html +1 -0
  81. data/lib/site_template/_includes/icon-github.svg +1 -0
  82. data/lib/site_template/_includes/icon-twitter.html +1 -0
  83. data/lib/site_template/_includes/icon-twitter.svg +1 -0
  84. data/lib/site_template/_layouts/default.html +20 -0
  85. data/lib/site_template/_layouts/page.html +14 -0
  86. data/lib/site_template/_layouts/post.html +15 -0
  87. data/lib/site_template/_posts/0000-00-00-welcome-to-bunto.markdown.erb +25 -0
  88. data/lib/site_template/_sass/_base.scss +206 -0
  89. data/lib/site_template/_sass/_layout.scss +242 -0
  90. data/lib/site_template/_sass/_syntax-highlighting.scss +71 -0
  91. data/lib/site_template/about.md +15 -0
  92. data/lib/site_template/css/main.scss +53 -0
  93. data/lib/site_template/feed.xml +30 -0
  94. data/lib/site_template/index.html +23 -0
  95. metadata +252 -0
@@ -0,0 +1,21 @@
1
+ module Bunto
2
+ class Publisher
3
+ def initialize(site)
4
+ @site = site
5
+ end
6
+
7
+ def publish?(thing)
8
+ can_be_published?(thing) && !hidden_in_the_future?(thing)
9
+ end
10
+
11
+ private
12
+
13
+ def can_be_published?(thing)
14
+ thing.data.fetch('published', true) || @site.unpublished
15
+ end
16
+
17
+ def hidden_in_the_future?(thing)
18
+ thing.respond_to?(:date) && !@site.future && thing.date.to_i > @site.time.to_i
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,126 @@
1
+ # encoding: UTF-8
2
+ require 'csv'
3
+
4
+ module Bunto
5
+ class Reader
6
+ attr_reader :site
7
+
8
+ def initialize(site)
9
+ @site = site
10
+ end
11
+
12
+ # Read Site data from disk and load it into internal data structures.
13
+ #
14
+ # Returns nothing.
15
+ def read
16
+ @site.layouts = LayoutReader.new(site).read
17
+ read_directories
18
+ sort_files!
19
+ @site.data = DataReader.new(site).read(site.config['data_dir'])
20
+ CollectionReader.new(site).read
21
+ end
22
+
23
+ # Sorts posts, pages, and static files.
24
+ def sort_files!
25
+ site.collections.values.each { |c| c.docs.sort! }
26
+ site.pages.sort_by!(&:name)
27
+ site.static_files.sort_by!(&:relative_path)
28
+ end
29
+
30
+ # Recursively traverse directories to find pages and static files
31
+ # that will become part of the site according to the rules in
32
+ # filter_entries.
33
+ #
34
+ # dir - The String relative path of the directory to read. Default: ''.
35
+ #
36
+ # Returns nothing.
37
+ def read_directories(dir = '')
38
+ base = site.in_source_dir(dir)
39
+
40
+ dot = Dir.chdir(base) { filter_entries(Dir.entries('.'), base) }
41
+ dot_dirs = dot.select { |file| File.directory?(@site.in_source_dir(base, file)) }
42
+ dot_files = (dot - dot_dirs)
43
+ dot_pages = dot_files.select { |file| Utils.has_yaml_header?(@site.in_source_dir(base, file)) }
44
+ dot_static_files = dot_files - dot_pages
45
+
46
+ retrieve_posts(dir)
47
+ retrieve_dirs(base, dir, dot_dirs)
48
+ retrieve_pages(dir, dot_pages)
49
+ retrieve_static_files(dir, dot_static_files)
50
+ end
51
+
52
+ # Retrieves all the posts(posts/drafts) from the given directory
53
+ # and add them to the site and sort them.
54
+ #
55
+ # dir - The String representing the directory to retrieve the posts from.
56
+ #
57
+ # Returns nothing.
58
+ def retrieve_posts(dir)
59
+ site.posts.docs.concat(PostReader.new(site).read_posts(dir))
60
+ site.posts.docs.concat(PostReader.new(site).read_drafts(dir)) if site.show_drafts
61
+ end
62
+
63
+ # Recursively traverse directories with the read_directories function.
64
+ #
65
+ # base - The String representing the site's base directory.
66
+ # dir - The String representing the directory to traverse down.
67
+ # dot_dirs - The Array of subdirectories in the dir.
68
+ #
69
+ # Returns nothing.
70
+ def retrieve_dirs(_base, dir, dot_dirs)
71
+ dot_dirs.map do |file|
72
+ dir_path = site.in_source_dir(dir, file)
73
+ rel_path = File.join(dir, file)
74
+ @site.reader.read_directories(rel_path) unless @site.dest.sub(/\/$/, '') == dir_path
75
+ end
76
+ end
77
+
78
+ # Retrieve all the pages from the current directory,
79
+ # add them to the site and sort them.
80
+ #
81
+ # dir - The String representing the directory retrieve the pages from.
82
+ # dot_pages - The Array of pages in the dir.
83
+ #
84
+ # Returns nothing.
85
+ def retrieve_pages(dir, dot_pages)
86
+ site.pages.concat(PageReader.new(site, dir).read(dot_pages))
87
+ end
88
+
89
+ # Retrieve all the static files from the current directory,
90
+ # add them to the site and sort them.
91
+ #
92
+ # dir - The directory retrieve the static files from.
93
+ # dot_static_files - The static files in the dir.
94
+ #
95
+ # Returns nothing.
96
+ def retrieve_static_files(dir, dot_static_files)
97
+ site.static_files.concat(StaticFileReader.new(site, dir).read(dot_static_files))
98
+ end
99
+
100
+ # Filter out any files/directories that are hidden or backup files (start
101
+ # with "." or "#" or end with "~"), or contain site content (start with "_"),
102
+ # or are excluded in the site configuration, unless they are web server
103
+ # files such as '.htaccess'.
104
+ #
105
+ # entries - The Array of String file/directory entries to filter.
106
+ # base_directory - The string representing the optional base directory.
107
+ #
108
+ # Returns the Array of filtered entries.
109
+ def filter_entries(entries, base_directory = nil)
110
+ EntryFilter.new(site, base_directory).filter(entries)
111
+ end
112
+
113
+ # Read the entries from a particular directory for processing
114
+ #
115
+ # dir - The String representing the relative path of the directory to read.
116
+ # subfolder - The String representing the directory to read.
117
+ #
118
+ # Returns the list of entries to process
119
+ def get_entries(dir, subfolder)
120
+ base = site.in_source_dir(dir, subfolder)
121
+ return [] unless File.exist?(base)
122
+ entries = Dir.chdir(base) { filter_entries(Dir['**/*'], base) }
123
+ entries.delete_if { |e| File.directory?(site.in_source_dir(base, e)) }
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,20 @@
1
+ module Bunto
2
+ class CollectionReader
3
+ SPECIAL_COLLECTIONS = %w(posts data).freeze
4
+
5
+ attr_reader :site, :content
6
+ def initialize(site)
7
+ @site = site
8
+ @content = {}
9
+ end
10
+
11
+ # Read in all collections specified in the configuration
12
+ #
13
+ # Returns nothing.
14
+ def read
15
+ site.collections.each do |_, collection|
16
+ collection.read unless SPECIAL_COLLECTIONS.include?(collection.label)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,69 @@
1
+ module Bunto
2
+ class DataReader
3
+ attr_reader :site, :content
4
+ def initialize(site)
5
+ @site = site
6
+ @content = {}
7
+ end
8
+
9
+ # Read all the files in <source>/<dir>/_drafts and create a new Draft
10
+ # object with each one.
11
+ #
12
+ # dir - The String relative path of the directory to read.
13
+ #
14
+ # Returns nothing.
15
+ def read(dir)
16
+ base = site.in_source_dir(dir)
17
+ read_data_to(base, @content)
18
+ @content
19
+ end
20
+
21
+ # Read and parse all yaml files under <dir> and add them to the
22
+ # <data> variable.
23
+ #
24
+ # dir - The string absolute path of the directory to read.
25
+ # data - The variable to which data will be added.
26
+ #
27
+ # Returns nothing
28
+ def read_data_to(dir, data)
29
+ return unless File.directory?(dir) && (!site.safe || !File.symlink?(dir))
30
+
31
+ entries = Dir.chdir(dir) do
32
+ Dir['*.{yaml,yml,json,csv}'] + Dir['*'].select { |fn| File.directory?(fn) }
33
+ end
34
+
35
+ entries.each do |entry|
36
+ path = @site.in_source_dir(dir, entry)
37
+ next if File.symlink?(path) && site.safe
38
+
39
+ key = sanitize_filename(File.basename(entry, '.*'))
40
+ if File.directory?(path)
41
+ read_data_to(path, data[key] = {})
42
+ else
43
+ data[key] = read_data_file(path)
44
+ end
45
+ end
46
+ end
47
+
48
+ # Determines how to read a data file.
49
+ #
50
+ # Returns the contents of the data file.
51
+ def read_data_file(path)
52
+ case File.extname(path).downcase
53
+ when '.csv'
54
+ CSV.read(path, {
55
+ :headers => true,
56
+ :encoding => site.config['encoding']
57
+ }).map(&:to_hash)
58
+ else
59
+ SafeYAML.load_file(path)
60
+ end
61
+ end
62
+
63
+ def sanitize_filename(name)
64
+ name.gsub!(/[^\w\s-]+/, '')
65
+ name.gsub!(/(^|\b\s)\s+($|\s?\b)/, '\\1\\2')
66
+ name.gsub(/\s+/, '_')
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,53 @@
1
+ module Bunto
2
+ class LayoutReader
3
+ attr_reader :site
4
+ def initialize(site)
5
+ @site = site
6
+ @layouts = {}
7
+ end
8
+
9
+ def read
10
+ layout_entries.each do |f|
11
+ @layouts[layout_name(f)] = Layout.new(site, layout_directory, f)
12
+ end
13
+
14
+ @layouts
15
+ end
16
+
17
+ def layout_directory
18
+ @layout_directory ||= (layout_directory_in_cwd || layout_directory_inside_source)
19
+ end
20
+
21
+ private
22
+
23
+ def layout_entries
24
+ entries = []
25
+ within(layout_directory) do
26
+ entries = EntryFilter.new(site).filter(Dir['**/*.*'])
27
+ end
28
+ entries
29
+ end
30
+
31
+ def layout_name(file)
32
+ file.split(".")[0..-2].join(".")
33
+ end
34
+
35
+ def within(directory)
36
+ return unless File.exist?(directory)
37
+ Dir.chdir(directory) { yield }
38
+ end
39
+
40
+ def layout_directory_inside_source
41
+ site.in_source_dir(site.config['layouts_dir'])
42
+ end
43
+
44
+ def layout_directory_in_cwd
45
+ dir = Bunto.sanitized_path(Dir.pwd, site.config['layouts_dir'])
46
+ if File.directory?(dir) && !site.safe
47
+ dir
48
+ else
49
+ nil
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,21 @@
1
+ module Bunto
2
+ class PageReader
3
+ attr_reader :site, :dir, :unfiltered_content
4
+ def initialize(site, dir)
5
+ @site = site
6
+ @dir = dir
7
+ @unfiltered_content = []
8
+ end
9
+
10
+ # Read all the files in <source>/<dir>/ for Yaml header and create a new Page
11
+ # object for each file.
12
+ #
13
+ # dir - The String relative path of the directory to read.
14
+ #
15
+ # Returns an array of static pages.
16
+ def read(files)
17
+ files.map { |page| @unfiltered_content << Page.new(@site, @site.source, @dir, page) }
18
+ @unfiltered_content.select { |page| site.publisher.publish?(page) }
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,62 @@
1
+ module Bunto
2
+ class PostReader
3
+ attr_reader :site, :unfiltered_content
4
+ def initialize(site)
5
+ @site = site
6
+ end
7
+
8
+ # Read all the files in <source>/<dir>/_drafts and create a new
9
+ # Document object with each one.
10
+ #
11
+ # dir - The String relative path of the directory to read.
12
+ #
13
+ # Returns nothing.
14
+ def read_drafts(dir)
15
+ read_publishable(dir, '_drafts', Document::DATELESS_FILENAME_MATCHER)
16
+ end
17
+
18
+ # Read all the files in <source>/<dir>/_posts and create a new Document
19
+ # object with each one.
20
+ #
21
+ # dir - The String relative path of the directory to read.
22
+ #
23
+ # Returns nothing.
24
+ def read_posts(dir)
25
+ read_publishable(dir, '_posts', Document::DATE_FILENAME_MATCHER)
26
+ end
27
+
28
+ # Read all the files in <source>/<dir>/<magic_dir> and create a new
29
+ # Document object with each one insofar as it matches the regexp matcher.
30
+ #
31
+ # dir - The String relative path of the directory to read.
32
+ #
33
+ # Returns nothing.
34
+ def read_publishable(dir, magic_dir, matcher)
35
+ read_content(dir, magic_dir, matcher).tap do |docs|
36
+ docs.each(&:read)
37
+ end.select do |doc|
38
+ site.publisher.publish?(doc)
39
+ end
40
+ end
41
+
42
+ # Read all the content files from <source>/<dir>/magic_dir
43
+ # and return them with the type klass.
44
+ #
45
+ # dir - The String relative path of the directory to read.
46
+ # magic_dir - The String relative directory to <dir>,
47
+ # looks for content here.
48
+ # klass - The return type of the content.
49
+ #
50
+ # Returns klass type of content files
51
+ def read_content(dir, magic_dir, matcher)
52
+ @site.reader.get_entries(dir, magic_dir).map do |entry|
53
+ next unless entry =~ matcher
54
+ path = @site.in_source_dir(File.join(dir, magic_dir, entry))
55
+ Document.new(path, {
56
+ :site => @site,
57
+ :collection => @site.posts
58
+ })
59
+ end.reject(&:nil?)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,21 @@
1
+ module Bunto
2
+ class StaticFileReader
3
+ attr_reader :site, :dir, :unfiltered_content
4
+ def initialize(site, dir)
5
+ @site = site
6
+ @dir = dir
7
+ @unfiltered_content = []
8
+ end
9
+
10
+ # Read all the files in <source>/<dir>/ for Yaml header and create a new Page
11
+ # object for each file.
12
+ #
13
+ # dir - The String relative path of the directory to read.
14
+ #
15
+ # Returns an array of static files.
16
+ def read(files)
17
+ files.map { |file| @unfiltered_content << StaticFile.new(@site, @site.source, @dir, file) }
18
+ @unfiltered_content
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,175 @@
1
+ module Bunto
2
+ class Regenerator
3
+ attr_reader :site, :metadata, :cache
4
+
5
+ def initialize(site)
6
+ @site = site
7
+
8
+ # Read metadata from file
9
+ read_metadata
10
+
11
+ # Initialize cache to an empty hash
12
+ clear_cache
13
+ end
14
+
15
+ # Checks if a renderable object needs to be regenerated
16
+ #
17
+ # Returns a boolean.
18
+ def regenerate?(document)
19
+ case document
20
+ when Page
21
+ document.asset_file? || document.data['regenerate'] ||
22
+ source_modified_or_dest_missing?(
23
+ site.in_source_dir(document.relative_path), document.destination(@site.dest)
24
+ )
25
+ when Document
26
+ !document.write? || document.data['regenerate'] ||
27
+ source_modified_or_dest_missing?(
28
+ document.path, document.destination(@site.dest)
29
+ )
30
+ else
31
+ source_path = document.respond_to?(:path) ? document.path : nil
32
+ dest_path = document.respond_to?(:destination) ? document.destination(@site.dest) : nil
33
+ source_modified_or_dest_missing?(source_path, dest_path)
34
+ end
35
+ end
36
+
37
+ # Add a path to the metadata
38
+ #
39
+ # Returns true, also on failure.
40
+ def add(path)
41
+ return true unless File.exist?(path)
42
+
43
+ metadata[path] = {
44
+ "mtime" => File.mtime(path),
45
+ "deps" => []
46
+ }
47
+ cache[path] = true
48
+ end
49
+
50
+ # Force a path to regenerate
51
+ #
52
+ # Returns true.
53
+ def force(path)
54
+ cache[path] = true
55
+ end
56
+
57
+ # Clear the metadata and cache
58
+ #
59
+ # Returns nothing
60
+ def clear
61
+ @metadata = {}
62
+ clear_cache
63
+ end
64
+
65
+ # Clear just the cache
66
+ #
67
+ # Returns nothing
68
+ def clear_cache
69
+ @cache = {}
70
+ end
71
+
72
+ # Checks if the source has been modified or the
73
+ # destination is missing
74
+ #
75
+ # returns a boolean
76
+ def source_modified_or_dest_missing?(source_path, dest_path)
77
+ modified?(source_path) || (dest_path && !File.exist?(dest_path))
78
+ end
79
+
80
+ # Checks if a path's (or one of its dependencies)
81
+ # mtime has changed
82
+ #
83
+ # Returns a boolean.
84
+ def modified?(path)
85
+ return true if disabled?
86
+
87
+ # objects that don't have a path are always regenerated
88
+ return true if path.nil?
89
+
90
+ # Check for path in cache
91
+ if cache.key? path
92
+ return cache[path]
93
+ end
94
+
95
+ # Check path that exists in metadata
96
+ data = metadata[path]
97
+ if data
98
+ data["deps"].each do |dependency|
99
+ if modified?(dependency)
100
+ return cache[dependency] = cache[path] = true
101
+ end
102
+ end
103
+ if File.exist?(path) && data["mtime"].eql?(File.mtime(path))
104
+ return cache[path] = false
105
+ else
106
+ return add(path)
107
+ end
108
+ end
109
+
110
+ # Path does not exist in metadata, add it
111
+ return add(path)
112
+ end
113
+
114
+ # Add a dependency of a path
115
+ #
116
+ # Returns nothing.
117
+ def add_dependency(path, dependency)
118
+ return if metadata[path].nil? || @disabled
119
+
120
+ unless metadata[path]["deps"].include? dependency
121
+ metadata[path]["deps"] << dependency
122
+ add(dependency) unless metadata.include?(dependency)
123
+ end
124
+ regenerate? dependency
125
+ end
126
+
127
+ # Write the metadata to disk
128
+ #
129
+ # Returns nothing.
130
+ def write_metadata
131
+ unless disabled?
132
+ File.binwrite(metadata_file, Marshal.dump(metadata))
133
+ end
134
+ end
135
+
136
+ # Produce the absolute path of the metadata file
137
+ #
138
+ # Returns the String path of the file.
139
+ def metadata_file
140
+ site.in_source_dir('.bunto-metadata')
141
+ end
142
+
143
+ # Check if metadata has been disabled
144
+ #
145
+ # Returns a Boolean (true for disabled, false for enabled).
146
+ def disabled?
147
+ @disabled = !site.incremental? if @disabled.nil?
148
+ @disabled
149
+ end
150
+
151
+ private
152
+
153
+ # Read metadata from the metadata file, if no file is found,
154
+ # initialize with an empty hash
155
+ #
156
+ # Returns the read metadata.
157
+ def read_metadata
158
+ @metadata =
159
+ if !disabled? && File.file?(metadata_file)
160
+ content = File.binread(metadata_file)
161
+
162
+ begin
163
+ Marshal.load(content)
164
+ rescue TypeError
165
+ SafeYAML.load(content)
166
+ rescue ArgumentError => e
167
+ Bunto.logger.warn("Failed to load #{metadata_file}: #{e}")
168
+ {}
169
+ end
170
+ else
171
+ {}
172
+ end
173
+ end
174
+ end
175
+ end