CodeSampleX

Exemplo

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.

Amostra verificada para hex nimble_csv 1.3.0: Demonstrate selective field quoting and iodata streaming in NimbleCSV.dump_to_iodata and dump_to_stream, custom…

sha256:4ca102627cb1041b56988dec8ec1d9fa2e7b495b667f2cffe6fda75b1bd121d6

Esta rede oferece uma coisa: uma amostra que compila. Ela a executou em um sandbox e guardou o recibo assinado. Não classifica nem garante nada — se o mesmo código compila onde você está, ela não mediu. Quantas chaves de assinatura distintas enviaram um recibo de contrato aprovado. Uma é só o autor; mais de uma significa que outra pessoa também o compilou. Uma chave é gerada por conta própria e não tem identidade registrada por trás, então conta chaves, não pessoas. MIT-0

Evidência de execução

O ambiente declarado e as execuções assinadas ficam separados, para você ver exatamente o que esta amostra executou e onde.

Base da evidência
Contrato assinado aprovado
Recibos de verificação
2
Chaves de assinatura que o compilaram
2
Ambiente declarado elixir linux x64 elixir elixir mix

Ambientes das execuções de verificação

Ambiente Contrato Etapas Execução
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

Caso

HOW
Objetivo
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.
Pacotes
Símbolos
  • NimbleCSV.RFC4180.dump_to_iodata
  • NimbleCSV.RFC4180.dump_to_stream
  • NimbleCSV.define
  • NimbleCSV.RFC4180.parse_enumerable
Ambiente
elixir
Criado
2026-08-17T18:52:52Z

Contrato

  1. 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.
  2. assert dump_to_stream lazily emits each row as iodata with CRLF row terminators
  3. assert custom parser defined with :reserved forces quoting for configured characters such as spaces and hashes
  4. assert parse_enumerable preserves multiline quoted fields across enumerable elements and respects skip_headers
  5. assert streaming rows through dump_to_stream and converting iodata chunks to binaries roundtrips losslessly through parse_enumerable

Arquivos

  • NOTES.md
  • csx.json
  • mix.exs
  • mix.lock
  • test/contract.exs

Baixar o artefato de código-fonte (tar.gz)

Código-fonte

NOTES.md
# 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.
csx.json
{"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"}
mix.exs
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
mix.lock
%{
  "nimble_csv": {:hex, :nimble_csv, "1.3.0", "b7f998dc62b222bce9596e46f028c7a5af04cb5dde6df2ea197c583227c54971", [:mix], [], "hexpm", "41ccdc18f7c8f8bb06e84164fc51635321e80d5a3b450761c4997d620925d619"},
}
test/contract.exs
# 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")

Seeder de origem

csx-seed