nanoc 4.4.4 → 4.4.5
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/Gemfile +1 -0
- data/Gemfile.lock +9 -8
- data/NEWS.md +10 -0
- data/lib/nanoc/base.rb +0 -3
- data/lib/nanoc/base/contracts_support.rb +55 -2
- data/lib/nanoc/base/core_ext/array.rb +0 -2
- data/lib/nanoc/base/core_ext/hash.rb +0 -2
- data/lib/nanoc/base/entities.rb +1 -0
- data/lib/nanoc/base/entities/context.rb +1 -4
- data/lib/nanoc/base/entities/directed_graph.rb +0 -10
- data/lib/nanoc/base/entities/identifiable_collection.rb +1 -2
- data/lib/nanoc/base/entities/identifier.rb +6 -8
- data/lib/nanoc/base/entities/item_rep.rb +12 -18
- data/lib/nanoc/base/{compilation → entities}/outdatedness_reasons.rb +0 -0
- data/lib/nanoc/base/entities/site.rb +3 -19
- data/lib/nanoc/base/errors.rb +9 -0
- data/lib/nanoc/base/memoization.rb +0 -2
- data/lib/nanoc/base/repos/checksum_store.rb +21 -14
- data/lib/nanoc/base/repos/compiled_content_cache.rb +11 -15
- data/lib/nanoc/base/repos/dependency_store.rb +8 -27
- data/lib/nanoc/base/services.rb +3 -0
- data/lib/nanoc/base/services/compiler.rb +379 -0
- data/lib/nanoc/base/services/compiler_loader.rb +3 -1
- data/lib/nanoc/base/services/executor.rb +27 -41
- data/lib/nanoc/base/services/item_rep_builder.rb +4 -0
- data/lib/nanoc/base/services/item_rep_writer.rb +5 -2
- data/lib/nanoc/base/{compilation → services}/outdatedness_checker.rb +1 -1
- data/lib/nanoc/base/views/post_compile_item_rep_view.rb +1 -1
- data/lib/nanoc/base/views/view_context.rb +3 -3
- data/lib/nanoc/checking/check.rb +1 -1
- data/lib/nanoc/checking/checks/external_links.rb +1 -1
- data/lib/nanoc/cli.rb +0 -4
- data/lib/nanoc/cli/commands/compile.rb +2 -2
- data/lib/nanoc/cli/commands/shell.rb +1 -1
- data/lib/nanoc/data_sources/filesystem.rb +10 -20
- data/lib/nanoc/data_sources/filesystem/errors.rb +55 -0
- data/lib/nanoc/filters/asciidoc.rb +0 -2
- data/lib/nanoc/filters/coffeescript.rb +0 -2
- data/lib/nanoc/filters/colorize_syntax.rb +0 -2
- data/lib/nanoc/filters/handlebars.rb +0 -2
- data/lib/nanoc/filters/mustache.rb +0 -2
- data/lib/nanoc/filters/redcarpet.rb +0 -4
- data/lib/nanoc/filters/slim.rb +0 -2
- data/lib/nanoc/filters/typogruby.rb +0 -2
- data/lib/nanoc/filters/xsl.rb +0 -2
- data/lib/nanoc/filters/yui_compressor.rb +0 -2
- data/lib/nanoc/helpers/capturing.rb +22 -19
- data/lib/nanoc/helpers/link_to.rb +3 -7
- data/lib/nanoc/helpers/rendering.rb +1 -1
- data/lib/nanoc/rule_dsl/action_provider.rb +2 -2
- data/lib/nanoc/rule_dsl/compiler_dsl.rb +0 -2
- data/lib/nanoc/rule_dsl/recording_executor.rb +6 -6
- data/lib/nanoc/rule_dsl/rule.rb +0 -2
- data/lib/nanoc/rule_dsl/rule_context.rb +3 -3
- data/lib/nanoc/rule_dsl/rule_memory_calculator.rb +5 -5
- data/lib/nanoc/spec.rb +1 -1
- data/lib/nanoc/version.rb +1 -1
- data/test/base/test_compiler.rb +3 -1
- data/test/base/test_dependency_tracker.rb +0 -19
- data/test/base/test_item_rep.rb +3 -0
- data/test/cli/commands/test_create_site.rb +1 -1
- data/test/data_sources/test_filesystem.rb +5 -5
- data/test/filters/test_coffeescript.rb +2 -0
- data/test/filters/test_handlebars.rb +4 -0
- data/test/filters/test_uglify_js.rb +4 -0
- data/test/filters/test_xsl.rb +1 -1
- data/test/helper.rb +6 -0
- data/test/helpers/test_capturing.rb +6 -1
- data/test/helpers/test_xml_sitemap.rb +1 -1
- metadata +6 -6
- data/lib/nanoc/base/compilation/compiler.rb +0 -295
- data/test/base/test_checksum_store.rb +0 -28
@@ -7,8 +7,10 @@ module Nanoc::Int
|
|
7
7
|
dependency_store =
|
8
8
|
Nanoc::Int::DependencyStore.new(site.items.to_a + site.layouts.to_a, env_name: site.config.env_name)
|
9
9
|
|
10
|
+
objects = site.items.to_a + site.layouts.to_a + site.code_snippets + [site.config]
|
11
|
+
|
10
12
|
checksum_store =
|
11
|
-
Nanoc::Int::ChecksumStore.new(site: site)
|
13
|
+
Nanoc::Int::ChecksumStore.new(site: site, objects: objects)
|
12
14
|
|
13
15
|
item_rep_repo = Nanoc::Int::ItemRepRepo.new
|
14
16
|
|
@@ -7,23 +7,24 @@ module Nanoc
|
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
-
def initialize(
|
11
|
-
@
|
10
|
+
def initialize(rep, compilation_context, dependency_tracker)
|
11
|
+
@rep = rep
|
12
|
+
@compilation_context = compilation_context
|
12
13
|
@dependency_tracker = dependency_tracker
|
13
14
|
end
|
14
15
|
|
15
|
-
def filter(
|
16
|
-
filter = filter_for_filtering(rep, filter_name)
|
16
|
+
def filter(filter_name, filter_args = {})
|
17
|
+
filter = filter_for_filtering(@rep, filter_name)
|
17
18
|
|
18
19
|
begin
|
19
|
-
Nanoc::Int::NotificationCenter.post(:filtering_started, rep, filter_name)
|
20
|
+
Nanoc::Int::NotificationCenter.post(:filtering_started, @rep, filter_name)
|
20
21
|
|
21
22
|
# Run filter
|
22
|
-
last = rep.snapshot_contents[:last]
|
23
|
-
source = rep.binary? ? last.filename : last.string
|
23
|
+
last = @rep.snapshot_contents[:last]
|
24
|
+
source = @rep.binary? ? last.filename : last.string
|
24
25
|
filter_args.freeze
|
25
26
|
result = filter.setup_and_run(source, filter_args)
|
26
|
-
rep.snapshot_contents[:last] =
|
27
|
+
@rep.snapshot_contents[:last] =
|
27
28
|
if filter.class.to_binary?
|
28
29
|
Nanoc::Int::BinaryContent.new(filter.output_filename).tap(&:freeze)
|
29
30
|
else
|
@@ -36,15 +37,15 @@ module Nanoc
|
|
36
37
|
end
|
37
38
|
|
38
39
|
# Create snapshot
|
39
|
-
snapshot(rep
|
40
|
+
snapshot(@rep.snapshot_contents[:post] ? :post : :pre, final: false) unless @rep.binary?
|
40
41
|
ensure
|
41
|
-
Nanoc::Int::NotificationCenter.post(:filtering_ended, rep, filter_name)
|
42
|
+
Nanoc::Int::NotificationCenter.post(:filtering_ended, @rep, filter_name)
|
42
43
|
end
|
43
44
|
end
|
44
45
|
|
45
|
-
def layout(
|
46
|
+
def layout(layout_identifier, extra_filter_args = nil)
|
46
47
|
layout = find_layout(layout_identifier)
|
47
|
-
filter_name, filter_args = *@
|
48
|
+
filter_name, filter_args = *@compilation_context.filter_name_and_args_for_layout(layout)
|
48
49
|
if filter_name.nil?
|
49
50
|
raise Nanoc::Int::Errors::Generic, "Cannot find rule for layout matching #{layout_identifier}"
|
50
51
|
end
|
@@ -52,64 +53,49 @@ module Nanoc
|
|
52
53
|
filter_args.freeze
|
53
54
|
|
54
55
|
# Check whether item can be laid out
|
55
|
-
raise Nanoc::Int::Errors::CannotLayoutBinaryItem.new(rep) if rep.binary?
|
56
|
+
raise Nanoc::Int::Errors::CannotLayoutBinaryItem.new(@rep) if @rep.binary?
|
56
57
|
|
57
58
|
# Create "pre" snapshot
|
58
|
-
if rep.snapshot_contents[:post].nil?
|
59
|
-
snapshot(
|
59
|
+
if @rep.snapshot_contents[:post].nil?
|
60
|
+
snapshot(:pre, final: true)
|
60
61
|
end
|
61
62
|
|
62
63
|
# Create filter
|
63
64
|
klass = Nanoc::Filter.named(filter_name)
|
64
65
|
raise Nanoc::Int::Errors::UnknownFilter.new(filter_name) if klass.nil?
|
65
|
-
view_context = @
|
66
|
+
view_context = @compilation_context.create_view_context(@dependency_tracker)
|
66
67
|
layout_view = Nanoc::LayoutView.new(layout, view_context)
|
67
|
-
filter = klass.new(assigns_for(rep).merge({ layout: layout_view }))
|
68
|
+
filter = klass.new(assigns_for(@rep).merge({ layout: layout_view }))
|
68
69
|
|
69
70
|
# Visit
|
70
71
|
@dependency_tracker.bounce(layout, raw_content: true)
|
71
72
|
|
72
73
|
begin
|
73
|
-
Nanoc::Int::NotificationCenter.post(:filtering_started, rep, filter_name)
|
74
|
+
Nanoc::Int::NotificationCenter.post(:filtering_started, @rep, filter_name)
|
74
75
|
|
75
76
|
# Layout
|
76
77
|
content = layout.content
|
77
78
|
arg = content.binary? ? content.filename : content.string
|
78
79
|
res = filter.setup_and_run(arg, filter_args)
|
79
|
-
rep.snapshot_contents[:last] = Nanoc::Int::TextualContent.new(res).tap(&:freeze)
|
80
|
+
@rep.snapshot_contents[:last] = Nanoc::Int::TextualContent.new(res).tap(&:freeze)
|
80
81
|
|
81
82
|
# Create "post" snapshot
|
82
|
-
snapshot(
|
83
|
+
snapshot(:post, final: false)
|
83
84
|
ensure
|
84
|
-
Nanoc::Int::NotificationCenter.post(:filtering_ended, rep, filter_name)
|
85
|
+
Nanoc::Int::NotificationCenter.post(:filtering_ended, @rep, filter_name)
|
85
86
|
end
|
86
87
|
end
|
87
88
|
|
88
|
-
def snapshot(
|
89
|
-
|
90
|
-
|
91
|
-
unless rep.binary?
|
92
|
-
rep.snapshot_contents[snapshot_name] = rep.snapshot_contents[:last]
|
93
|
-
end
|
94
|
-
|
95
|
-
if snapshot_name == :pre && final
|
96
|
-
rep.snapshot_defs << Nanoc::Int::SnapshotDef.new(:pre, true)
|
97
|
-
end
|
98
|
-
|
99
|
-
if final
|
100
|
-
raw_path = rep.raw_path(snapshot: snapshot_name)
|
101
|
-
if raw_path
|
102
|
-
ItemRepWriter.new.write(rep, raw_path)
|
103
|
-
end
|
104
|
-
end
|
89
|
+
def snapshot(snapshot_name, final: true, path: nil) # rubocop:disable Lint/UnusedMethodArgument
|
90
|
+
@rep.snapshot_contents[snapshot_name] = @rep.snapshot_contents[:last]
|
105
91
|
end
|
106
92
|
|
107
93
|
def assigns_for(rep)
|
108
|
-
@
|
94
|
+
@compilation_context.assigns_for(rep, @dependency_tracker)
|
109
95
|
end
|
110
96
|
|
111
97
|
def layouts
|
112
|
-
@
|
98
|
+
@compilation_context.site.layouts
|
113
99
|
end
|
114
100
|
|
115
101
|
def find_layout(arg)
|
@@ -140,7 +126,7 @@ module Nanoc
|
|
140
126
|
end
|
141
127
|
|
142
128
|
def use_globs?
|
143
|
-
@
|
129
|
+
@compilation_context.site.config[:string_pattern_type] == 'glob'
|
144
130
|
end
|
145
131
|
end
|
146
132
|
end
|
@@ -3,7 +3,10 @@ module Nanoc::Int
|
|
3
3
|
class ItemRepWriter
|
4
4
|
TMP_TEXT_ITEMS_DIR = 'text_items'.freeze
|
5
5
|
|
6
|
-
def write(item_rep,
|
6
|
+
def write(item_rep, snapshot_name)
|
7
|
+
raw_path = item_rep.raw_path(snapshot: snapshot_name)
|
8
|
+
return unless raw_path
|
9
|
+
|
7
10
|
# Create parent directory
|
8
11
|
FileUtils.mkdir_p(File.dirname(raw_path))
|
9
12
|
|
@@ -15,7 +18,7 @@ module Nanoc::Int
|
|
15
18
|
:will_write_rep, item_rep, raw_path
|
16
19
|
)
|
17
20
|
|
18
|
-
content = item_rep.snapshot_contents[
|
21
|
+
content = item_rep.snapshot_contents[snapshot_name]
|
19
22
|
if content.binary?
|
20
23
|
temp_path = content.filename
|
21
24
|
else
|
@@ -44,7 +44,7 @@ module Nanoc::Int
|
|
44
44
|
when Nanoc::Int::Layout
|
45
45
|
apply_rules(RULES_FOR_LAYOUT, obj)
|
46
46
|
else
|
47
|
-
raise "do not know how to check outdatedness of #{obj.inspect}"
|
47
|
+
raise Nanoc::Int::Errors::InternalInconsistency, "do not know how to check outdatedness of #{obj.inspect}"
|
48
48
|
end
|
49
49
|
end
|
50
50
|
memoize :outdatedness_status_for
|
@@ -5,7 +5,7 @@ module Nanoc
|
|
5
5
|
raise Nanoc::Int::Errors::CannotGetCompiledContentOfBinaryItem.new(unwrap)
|
6
6
|
end
|
7
7
|
|
8
|
-
snapshot_contents = @context.
|
8
|
+
snapshot_contents = @context.compilation_context.compiled_content_cache[unwrap]
|
9
9
|
snapshot_name = snapshot || (snapshot_contents[:pre] ? :pre : :last)
|
10
10
|
|
11
11
|
if snapshot_contents[snapshot_name]
|
@@ -4,13 +4,13 @@ module Nanoc
|
|
4
4
|
attr_reader :reps
|
5
5
|
attr_reader :items
|
6
6
|
attr_reader :dependency_tracker
|
7
|
-
attr_reader :
|
7
|
+
attr_reader :compilation_context
|
8
8
|
|
9
|
-
def initialize(reps:, items:, dependency_tracker:,
|
9
|
+
def initialize(reps:, items:, dependency_tracker:, compilation_context:)
|
10
10
|
@reps = reps
|
11
11
|
@items = items
|
12
12
|
@dependency_tracker = dependency_tracker
|
13
|
-
@
|
13
|
+
@compilation_context = compilation_context
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
data/lib/nanoc/checking/check.rb
CHANGED
@@ -20,7 +20,7 @@ module Nanoc::Checking
|
|
20
20
|
output_filenames = Dir[output_dir + '/**/*'].select { |f| File.file?(f) }
|
21
21
|
|
22
22
|
# FIXME: ugly
|
23
|
-
view_context = site.compiler.create_view_context(Nanoc::Int::DependencyTracker::Null.new)
|
23
|
+
view_context = site.compiler.compilation_context.create_view_context(Nanoc::Int::DependencyTracker::Null.new)
|
24
24
|
|
25
25
|
context = {
|
26
26
|
items: Nanoc::ItemCollectionWithRepsView.new(site.items, view_context),
|
data/lib/nanoc/cli.rb
CHANGED
@@ -19,8 +19,6 @@ module Nanoc::CLI
|
|
19
19
|
autoload 'ErrorHandler', 'nanoc/cli/error_handler'
|
20
20
|
|
21
21
|
# @return [Boolean] true if debug output is enabled, false if not
|
22
|
-
#
|
23
|
-
# @since 3.2.0
|
24
22
|
def self.debug?
|
25
23
|
@debug || false
|
26
24
|
end
|
@@ -29,8 +27,6 @@ module Nanoc::CLI
|
|
29
27
|
# false if it should not
|
30
28
|
#
|
31
29
|
# @return [void]
|
32
|
-
#
|
33
|
-
# @since 3.2.0
|
34
30
|
def self.debug=(boolean)
|
35
31
|
@debug = boolean
|
36
32
|
end
|
@@ -420,11 +420,11 @@ module Nanoc::CLI::Commands
|
|
420
420
|
|
421
421
|
def default_listener_classes
|
422
422
|
[
|
423
|
+
Nanoc::CLI::Commands::Compile::StackProfProfiler,
|
423
424
|
Nanoc::CLI::Commands::Compile::DiffGenerator,
|
424
425
|
Nanoc::CLI::Commands::Compile::DebugPrinter,
|
425
426
|
Nanoc::CLI::Commands::Compile::TimingRecorder,
|
426
427
|
Nanoc::CLI::Commands::Compile::FileActionPrinter,
|
427
|
-
Nanoc::CLI::Commands::Compile::StackProfProfiler,
|
428
428
|
]
|
429
429
|
end
|
430
430
|
|
@@ -449,7 +449,7 @@ module Nanoc::CLI::Commands
|
|
449
449
|
end
|
450
450
|
|
451
451
|
def teardown_listeners
|
452
|
-
@listeners.
|
452
|
+
@listeners.reverse_each(&:stop_safely)
|
453
453
|
end
|
454
454
|
|
455
455
|
def reps
|
@@ -117,7 +117,7 @@ module Nanoc::DataSources
|
|
117
117
|
|
118
118
|
ProtoDocument.new(is_binary: true, filename: content_filename, attributes: meta)
|
119
119
|
elsif is_binary && klass == Nanoc::Int::Layout
|
120
|
-
raise
|
120
|
+
raise Errors::BinaryLayout.new(content_filename)
|
121
121
|
else
|
122
122
|
parse_result = parse(content_filename, meta_filename)
|
123
123
|
|
@@ -239,11 +239,11 @@ module Nanoc::DataSources
|
|
239
239
|
|
240
240
|
# Check number of files per type
|
241
241
|
unless [0, 1].include?(meta_filenames.size)
|
242
|
-
raise
|
242
|
+
raise Errors::MultipleMetaFiles.new(meta_filenames, basename)
|
243
243
|
end
|
244
244
|
unless config[:identifier_type] == 'full'
|
245
245
|
unless [0, 1].include?(content_filenames.size)
|
246
|
-
raise
|
246
|
+
raise Errors::MultipleContentFiles.new(meta_filenames, basename)
|
247
247
|
end
|
248
248
|
end
|
249
249
|
|
@@ -352,7 +352,7 @@ module Nanoc::DataSources
|
|
352
352
|
|
353
353
|
pieces = data.split(/^(-{5}|-{3})[ \t]*\r?\n?/, 3)
|
354
354
|
if pieces.size < 4
|
355
|
-
raise
|
355
|
+
raise Errors::InvalidFormat.new(content_filename)
|
356
356
|
end
|
357
357
|
|
358
358
|
meta = parse_metadata(pieces[2], content_filename)
|
@@ -366,7 +366,7 @@ module Nanoc::DataSources
|
|
366
366
|
begin
|
367
367
|
meta = YAML.load(data) || {}
|
368
368
|
rescue => e
|
369
|
-
raise
|
369
|
+
raise Errors::UnparseableMetadata.new(filename, e)
|
370
370
|
end
|
371
371
|
|
372
372
|
verify_meta(meta, filename)
|
@@ -386,16 +386,10 @@ module Nanoc::DataSources
|
|
386
386
|
end
|
387
387
|
end
|
388
388
|
|
389
|
-
class InvalidMetadataError < Nanoc::Error
|
390
|
-
def initialize(filename, klass)
|
391
|
-
super("The file #{filename} has invalid metadata (expected key-value pairs, found #{klass} instead)")
|
392
|
-
end
|
393
|
-
end
|
394
|
-
|
395
389
|
def verify_meta(meta, filename)
|
396
390
|
return if meta.is_a?(Hash)
|
397
391
|
|
398
|
-
raise
|
392
|
+
raise Errors::InvalidMetadata.new(filename, meta.class)
|
399
393
|
end
|
400
394
|
|
401
395
|
# Reads the content of the file with the given name and returns a string
|
@@ -407,7 +401,7 @@ module Nanoc::DataSources
|
|
407
401
|
begin
|
408
402
|
data = File.read(filename)
|
409
403
|
rescue => e
|
410
|
-
raise
|
404
|
+
raise Errors::FileUnreadable.new(filename, e)
|
411
405
|
end
|
412
406
|
|
413
407
|
# Fix
|
@@ -422,11 +416,11 @@ module Nanoc::DataSources
|
|
422
416
|
begin
|
423
417
|
data.encode!('UTF-8')
|
424
418
|
rescue
|
425
|
-
|
419
|
+
raise Errors::InvalidEncoding.new(filename, original_encoding)
|
426
420
|
end
|
427
421
|
|
428
422
|
unless data.valid_encoding?
|
429
|
-
|
423
|
+
raise Errors::InvalidEncoding.new(filename, original_encoding)
|
430
424
|
end
|
431
425
|
end
|
432
426
|
|
@@ -435,12 +429,8 @@ module Nanoc::DataSources
|
|
435
429
|
|
436
430
|
data
|
437
431
|
end
|
438
|
-
|
439
|
-
# Raises an invalid encoding error for the given filename and encoding.
|
440
|
-
def raise_encoding_error(filename, encoding)
|
441
|
-
raise "Could not read #{filename} because the file is not valid #{encoding}."
|
442
|
-
end
|
443
432
|
end
|
444
433
|
end
|
445
434
|
|
446
435
|
require_relative 'filesystem/tools'
|
436
|
+
require_relative 'filesystem/errors'
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class Nanoc::DataSources::Filesystem < Nanoc::DataSource
|
2
|
+
# @api private
|
3
|
+
module Errors
|
4
|
+
class Generic < ::Nanoc::Error
|
5
|
+
end
|
6
|
+
|
7
|
+
class BinaryLayout < Generic
|
8
|
+
def initialize(content_filename)
|
9
|
+
super("The layout file '#{content_filename}' is a binary file, but layouts can only be textual")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class MultipleMetaFiles < Generic
|
14
|
+
def initialize(meta_filenames, basename)
|
15
|
+
super("Found #{meta_filenames.size} meta files for #{basename}; expected 0 or 1")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class MultipleContentFiles < Generic
|
20
|
+
def initialize(content_filenames, basename)
|
21
|
+
super("Found #{content_filenames.size} content files for #{basename}; expected 0 or 1")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class InvalidFormat < Generic
|
26
|
+
def initialize(content_filename)
|
27
|
+
super("The file '#{content_filename}' appears to start with a metadata section (three or five dashes at the top) but it does not seem to be in the correct format.")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class UnparseableMetadata < Generic
|
32
|
+
def initialize(filename, error)
|
33
|
+
super("Could not parse metadata for #{filename}: #{error.message}")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class InvalidMetadata < Generic
|
38
|
+
def initialize(filename, klass)
|
39
|
+
super("The file #{filename} has invalid metadata (expected key-value pairs, found #{klass} instead)")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class InvalidEncoding < Generic
|
44
|
+
def initialize(filename, encoding)
|
45
|
+
super("Could not read #{filename} because the file is not valid #{encoding}.")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class FileUnreadable < Generic
|
50
|
+
def initialize(filename, error)
|
51
|
+
super("Could not read #{filename}: #{error.inspect}")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|