샘플
nimble_csv 1.3.0: Demonstrate selective field quoting and iodata streaming in NimbleCSV.dump_to_iodata and dump_to_stream, custom :reserved character quoting in define/2, and multiline row state preservation in parse_enumerable/2.
검증된 샘플 — hex nimble_csv 1.3.0: Demonstrate selective field quoting and iodata streaming in NimbleCSV.dump_to_iodata and dump_to_stream, custom :reserved…
sha256:4ca102627cb1041b56988dec8ec1d9fa2e7b495b667f2cffe6fda75b1bd121d6
이 네트워크가 제공하는 것은 하나입니다. 빌드되는 샘플. 샌드박스에서 돌리고 서명된 영수증을 보관합니다. 등급을 매기지 않고 무엇도 보증하지 않습니다 — 같은 코드가 당신 환경에서 빌드되는지는 측정한 적이 없습니다.
통과한 계약 영수증을 낸 서로 다른 서명 키의 수입니다. 하나면 작성자 혼자이고, 둘 이상이면 다른 사람도 빌드했다는 뜻입니다. 키는 스스로 만드는 것이고 뒤에 등록된 신원이 없으므로, 세는 것은 사람이 아니라 키입니다.
MIT-0
실행 증거
선언된 환경과 서명된 실행을 분리해 두었습니다. 이 샘플이 무엇을 어디서 실행했는지 그대로 볼 수 있습니다.
- 증거 기준
- 서명된 컨트랙트 통과
- 검증 영수증
- 2
- 빌드한 서명 키
- 2
선언된 환경
elixir linux x64 elixir elixir mix
검증 실행 환경
| 환경 | 컨트랙트 | 단계 | 실행일 |
|---|---|---|---|
| elixir 1 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:PASS · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · hex@1 |
2026-08-17 |
| elixir 1 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 | PASS | compile:PASS · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · hex@1 |
2026-08-18 |
케이스
HOW- 목표
- Demonstrate selective field quoting and iodata streaming in NimbleCSV.dump_to_iodata and dump_to_stream, custom :reserved character quoting in define/2, and multiline row state preservation in parse_enumerable/2.
- 패키지
- 심벌
-
- NimbleCSV.RFC4180.dump_to_iodata
- NimbleCSV.RFC4180.dump_to_stream
- NimbleCSV.define
- NimbleCSV.RFC4180.parse_enumerable
- 환경
- elixir
- 생성일
- 2026-08-17T18:52:52Z
컨트랙트
- NimbleCSV.RFC4180.dump_to_iodata selectively quotes and doubles escape characters only for fields containing reserved delimiter, escape, or newline characters, while leaving empty strings and unreserved fields bare.
- assert dump_to_stream lazily emits each row as iodata with CRLF row terminators
- assert custom parser defined with :reserved forces quoting for configured characters such as spaces and hashes
- assert parse_enumerable preserves multiline quoted fields across enumerable elements and respects skip_headers
- assert streaming rows through dump_to_stream and converting iodata chunks to binaries roundtrips losslessly through parse_enumerable
파일
- NOTES.md
- csx.json
- mix.exs
- mix.lock
- test/contract.exs
소스
# NimbleCSV 1.3.0 Dumping, Custom Reserved Delimiters, and Enumerable Parsing
A search via known solutions returned existing samples for nimble_csv:
- `sha256:d3b935a442e69a84c6664c75e2a07c5c6354c86243d8f2f795aa07d17eb5619c` (`to_line_stream/1` chunk reassembly and OWASP `escape_formula` prefixes)
- `sha256:ae21b951308d6bac196db85fb726efc75244ff77210adc6af5babba86658e6c1` (`parse_string/2` default `skip_headers: true`, quote unescaping, and UTF-8 BOM preservation)
- `sha256:96745beca2a7ac60bfcc923ac4a93c445eb71335e7326488531561ca031c2f6c` (multi-separator list where the dumper fixes separator to the first element)
- `sha256:c5a8d3d8e7491c41eec46559763ce8367d36a8dbcbeab7e5bc8d95670b4d2d09` (error paths on trailing tokens after quotes and non-binary inputs)
This sample tests the exact behavior of dumping mechanisms, custom reserved character escaping, and enumerable line aggregation in pinned release `1.3.0`.
## Observed Behavior
1. **Selective Quoting in Dumper**: `NimbleCSV.RFC4180.dump_to_iodata/1` inspects each field against configured `:reserved` characters (by default: comma `,`, double-quote `"`, `\r\n`, and `\n`).
- Fields containing no reserved characters (e.g. plain text, integers) and empty strings `""` are emitted unquoted (e.g. `["a", "", "b"]` renders as `"a,,b\r\n"`).
- Fields containing reserved characters are enclosed in double quotes `"` and internal double quotes are escaped by doubling (`""`).
- An empty row `[]` emits a standalone line separator (`"\r\n"`).
2. **Lazy Iodata Streaming**: `NimbleCSV.RFC4180.dump_to_stream/1` returns an Elixir `Stream` yielding each row as `iodata()` terminated with `\r\n`.
3. **Custom `:reserved` Characters in `define/2`**: Providing an explicit `:reserved` list in `NimbleCSV.define/2` specifies the exact set of substrings that trigger quoting during dump operations. For example, adding `" "` and `"#"` causes fields containing spaces or hash marks to be quoted in the dumped output.
4. **Multiline State Across Enumerable Items**: `NimbleCSV.RFC4180.parse_enumerable/2` iterates through an enumerable of pre-segmented lines. When an open quoted field spans multiple elements in the enumerable, the parser preserves state across chunks and reconstructs the multiline field into a single cell.
5. **Streaming Roundtrip**: Converting `dump_to_stream/1` iodata chunks to binary strings via `IO.iodata_to_binary/1` and feeding them into `parse_enumerable(skip_headers: false)` produces an exact match with the original input data.
{"buildCommand":["mix","deps.compile","--no-deps-check"],"case":{"caseId":"case:sha256:1d093210329d8c0755dda45267114d42741caf9130453359d7289d2b1a4adefb","contract":["NimbleCSV.RFC4180.dump_to_iodata selectively quotes and doubles escape characters only for fields containing reserved delimiter, escape, or newline characters, while leaving empty strings and unreserved fields bare.","assert dump_to_stream lazily emits each row as iodata with CRLF row terminators","assert custom parser defined with :reserved forces quoting for configured characters such as spaces and hashes","assert parse_enumerable preserves multiline quoted fields across enumerable elements and respects skip_headers","assert streaming rows through dump_to_stream and converting iodata chunks to binaries roundtrips losslessly through parse_enumerable"],"goal":"Demonstrate selective field quoting and iodata streaming in NimbleCSV.dump_to_iodata and dump_to_stream, custom :reserved character quoting in define/2, and multiline row state preservation in parse_enumerable/2.","kind":"HOW","packages":["pkg:hex/nimble_csv@1.3.0"],"schemaVersion":1,"symbols":["NimbleCSV.RFC4180.dump_to_iodata","NimbleCSV.RFC4180.dump_to_stream","NimbleCSV.define","NimbleCSV.RFC4180.parse_enumerable"]},"contractCommand":["mix","run","test/contract.exs","--no-deps-check"],"environment":{"arch":"x64","ecosystem":"hex","executionContext":"elixir","language":"elixir","os":"linux","packageManager":"mix","runtime":"elixir","schemaVersion":1},"license":"MIT-0","packages":["pkg:hex/nimble_csv@1.3.0"],"schemaVersion":1,"symbols":["NimbleCSV.RFC4180.dump_to_iodata","NimbleCSV.RFC4180.dump_to_stream","NimbleCSV.define","NimbleCSV.RFC4180.parse_enumerable"],"verifierAdapter":"hex@1"}
defmodule NimbleCsvVersionDepth.MixProject do
use Mix.Project
def project do
[
app: :nimble_csv_version_depth,
version: "0.1.0",
elixir: "~> 1.15",
deps: deps()
]
end
def application, do: [extra_applications: []]
defp deps do
[{:nimble_csv, "1.3.0"}]
end
end
%{
"nimble_csv": {:hex, :nimble_csv, "1.3.0", "b7f998dc62b222bce9596e46f028c7a5af04cb5dde6df2ea197c583227c54971", [:mix], [], "hexpm", "41ccdc18f7c8f8bb06e84164fc51635321e80d5a3b450761c4997d620925d619"},
}
# Prove NimbleCSV 1.3.0 dumping rules, streaming mechanics, custom reserved delimiters, and parse_enumerable behavior
alias NimbleCSV.RFC4180, as: CSV
# ---------------------------------------------------------------------------
# 1. Selective quoting rules in dump_to_iodata/1
# ---------------------------------------------------------------------------
# NimbleCSV quotes and doubles escape characters only when a field contains
# reserved characters (separator, escape, or newlines). Empty strings and
# unreserved fields remain unquoted.
rows = [
["alpha", "", "123", "has,comma", "has\"quote", "has\r\nnewline"],
["second", "plain", "row", "end"]
]
dumped_iodata = CSV.dump_to_iodata(rows) |> IO.iodata_to_binary()
expected_dump =
"alpha,,123,\"has,comma\",\"has\"\"quote\",\"has\r\nnewline\"\r\n" <>
"second,plain,row,end\r\n"
unless dumped_iodata == expected_dump do
raise "dump_to_iodata mismatch:\nExpected: #{inspect(expected_dump)}\nGot: #{inspect(dumped_iodata)}"
end
# An empty row [] produces a standalone line separator
empty_row_dump = CSV.dump_to_iodata([[]]) |> IO.iodata_to_binary()
unless empty_row_dump == "\r\n" do
raise "empty row dump mismatch: got #{inspect(empty_row_dump)}"
end
# ---------------------------------------------------------------------------
# 2. Lazy row streaming with dump_to_stream/1
# ---------------------------------------------------------------------------
# dump_to_stream returns a lazy Stream emitting iodata for each row
stream_chunks =
rows
|> CSV.dump_to_stream()
|> Enum.map(&IO.iodata_to_binary/1)
expected_chunks = [
"alpha,,123,\"has,comma\",\"has\"\"quote\",\"has\r\nnewline\"\r\n",
"second,plain,row,end\r\n"
]
unless stream_chunks == expected_chunks do
raise "dump_to_stream mismatch:\nExpected: #{inspect(expected_chunks)}\nGot: #{inspect(stream_chunks)}"
end
# ---------------------------------------------------------------------------
# 3. Custom :reserved characters and :line_separator in NimbleCSV.define/2
# ---------------------------------------------------------------------------
# Custom parsers can specify additional reserved characters to force quoting
NimbleCSV.define(CustomReservedParser,
separator: ";",
escape: "\"",
line_separator: "\n",
reserved: [";", "\"", "\n", " ", "#"]
)
custom_input = [
["item1", "with space", "tag#9", "plain"]
]
custom_dumped = CustomReservedParser.dump_to_iodata(custom_input) |> IO.iodata_to_binary()
expected_custom_dump = "item1;\"with space\";\"tag#9\";plain\n"
unless custom_dumped == expected_custom_dump do
raise "custom dump mismatch:\nExpected: #{inspect(expected_custom_dump)}\nGot: #{inspect(custom_dumped)}"
end
# ---------------------------------------------------------------------------
# 4. parse_enumerable/2 multiline state preservation across enumerable elements
# ---------------------------------------------------------------------------
# When quoted fields span multiple enumerable elements, parse_enumerable
# maintains parser state across elements to reconstruct the complete row.
enumerable_input = [
"header1,header2,header3\r\n",
"data1,\"line one\r\n",
"line two\r\n",
"line three\",data3\r\n",
"next1,next2,next3\r\n"
]
# Default skip_headers: true skips the first line
parsed_default = CSV.parse_enumerable(enumerable_input)
expected_parsed_default = [
["data1", "line one\r\nline two\r\nline three", "data3"],
["next1", "next2", "next3"]
]
unless parsed_default == expected_parsed_default do
raise "parse_enumerable default mismatch:\nExpected: #{inspect(expected_parsed_default)}\nGot: #{inspect(parsed_default)}"
end
# Explicit skip_headers: false includes all rows
parsed_all = CSV.parse_enumerable(enumerable_input, skip_headers: false)
expected_parsed_all = [
["header1", "header2", "header3"],
["data1", "line one\r\nline two\r\nline three", "data3"],
["next1", "next2", "next3"]
]
unless parsed_all == expected_parsed_all do
raise "parse_enumerable (skip_headers: false) mismatch:\nExpected: #{inspect(expected_parsed_all)}\nGot: #{inspect(parsed_all)}"
end
# ---------------------------------------------------------------------------
# 5. Full roundtrip: dump_to_stream piped to parse_enumerable
# ---------------------------------------------------------------------------
# Streaming rows through dump_to_stream, converting iodata chunks to binaries,
# and parsing via parse_enumerable preserves all special characters and formatting.
complex_dataset = [
["sku", "name", "description", "details"],
["A100", "Widget", "Line 1\r\nLine 2\r\nLine 3", "Special \"quoted\" value"],
["B200", "Gadget, Pro", "", "Unicode: \u00E9\u00E8\u00E0"],
["C300", "Basic", "No special chars", ""]
]
roundtrip_result =
complex_dataset
|> CSV.dump_to_stream()
|> Stream.map(&IO.iodata_to_binary/1)
|> CSV.parse_enumerable(skip_headers: false)
unless roundtrip_result == complex_dataset do
raise "roundtrip result mismatch:\nExpected: #{inspect(complex_dataset)}\nGot: #{inspect(roundtrip_result)}"
end
IO.puts("contract passed")