diff --git a/src/YAML.jl b/src/YAML.jl index d5a7067..1e1fd3f 100644 --- a/src/YAML.jl +++ b/src/YAML.jl @@ -113,10 +113,6 @@ end YAMLDocIterator(input::IO, more_constructors::_constructor=nothing, multi_constructors::Dict = Dict(); dicttype::_dicttype=Dict{Any, Any}, constructorType::Function = SafeConstructor) = YAMLDocIterator(input, constructorType(_patch_constructors(more_constructors, dicttype), multi_constructors)) -# It's unknown how many documents will be found. By doing this, -# functions like `collect` do not try to query the length of the -# iterator. -Base.IteratorSize(::YAMLDocIterator) = Base.SizeUnknown() # Iteration protocol. function iterate(it::YAMLDocIterator, _ = nothing) @@ -131,6 +127,14 @@ function iterate(it::YAMLDocIterator, _ = nothing) return doc, nothing end +# It's unknown how many documents will be found. By doing this, +# functions like `collect` do not try to query the length of the +# iterator. +Base.IteratorSize(::Type{YAMLDocIterator}) = Base.SizeUnknown() +# Documents can be trees of elements or just single values, so don't promise +# any particular type. +Base.IteratorEltype(::Type{YAMLDocIterator}) = Base.EltypeUnknown() + """ load_all(x::Union{AbstractString, IO}) -> YAMLDocIterator @@ -161,8 +165,8 @@ load_file(filename::AbstractString, args...; kwargs...) = Parse the YAML file `filename`, and return corresponding YAML documents. """ load_all_file(filename::AbstractString, args...; kwargs...) = - open(filename, "r") do input - load_all(input, args...; kwargs...) + open(filename, "r") do f + io = IOBuffer(read(f)) + load_all(io, args...; kwargs...) end - end # module diff --git a/test/runtests.jl b/test/runtests.jl index b3a9b09..f4b558a 100755 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -239,8 +239,7 @@ const encodings = [ @test YAML.load(IOBuffer(data)) == "test" end -@testset "multi_doc_bom" begin - iterable = YAML.load_all(""" +const multidoc_contents = """ \ufeff---\r test: 1 \ufeff--- @@ -248,16 +247,51 @@ test: 2 \ufeff--- test: 3 -""") +\ufeff--- +42 +""" + +@testset "multi_doc_bom" begin + iterable = YAML.load_all(multidoc_contents) (val, state) = iterate(iterable) @test isequal(val, Dict("test" => 1)) (val, state) = iterate(iterable, state) @test isequal(val, Dict("test" => 2)) (val, state) = iterate(iterable, state) @test isequal(val, Dict("test" => 3)) + (val, state) = iterate(iterable, state) + @test isequal(val, 42) @test iterate(iterable, state) === nothing end +@testset "multi_doc_file" begin + fname = tempname() # cleanup=true, file will be deleted on process exit + open(fname, "w") do f + write(f, multidoc_contents) + end + iterable = YAML.load_all_file(fname) + (val, state) = iterate(iterable) + @test isequal(val, Dict("test" => 1)) + (val, state) = iterate(iterable, state) + @test isequal(val, Dict("test" => 2)) + (val, state) = iterate(iterable, state) + @test isequal(val, Dict("test" => 3)) + (val, state) = iterate(iterable, state) + @test isequal(val, 42) + @test iterate(iterable, state) === nothing +end + +@testset "multi_doc_iteration_protocol" begin + fname = tempname() # cleanup=true, file will be deleted on process exit + open(fname, "w") do f + write(f, multidoc_contents) + end + iterable = YAML.load_all_file(fname) + @test Base.IteratorSize(YAML.YAMLDocIterator) == Base.SizeUnknown() + @test Base.IteratorEltype(YAML.YAMLDocIterator) == Base.EltypeUnknown() + @test length(collect(iterable)) == 4 +end + # test that an OrderedDict is written in the correct order using OrderedCollections, DataStructures @test strip(YAML.yaml(OrderedDict(:c => 3, :b => 2, :a => 1))) == join(["c: 3", "b: 2", "a: 1"], "\n")