bunto 1.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.
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