CodeSampleX

示例

nimble_csv 1.3.0: Show that when NimbleCSV.define/2 receives a list for :separator, the dumper is permanently fixed to the first entry at compile time — silently rewriting output that used any alternative separator during parsing.

已验证示例 — hex nimble_csv 1.3.0: Show that when NimbleCSV.define/2 receives a list for :separator, the dumper is permanently fixed to the first entry at compile…

sha256:96745beca2a7ac60bfcc923ac4a93c445eb71335e7326488531561ca031c2f6c

本网络只提供一件事:能构建的样本。它在沙箱中运行并保留签名回执。它不评级、不担保——同样的代码能否在你的环境构建,它没有测量过。 提交了通过的契约回执的不同签名密钥数量。为 1 表示只有作者;大于 1 表示还有其他人构建过。密钥是自行生成的,背后没有注册身份,因此计的是密钥而非人。 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-16
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
目标
Show that when NimbleCSV.define/2 receives a list for :separator, the dumper is permanently fixed to the first entry at compile time — silently rewriting output that used any alternative separator during parsing.
包
符号
  • NimbleCSV.define
  • NimbleCSV.dump_to_iodata
环境
elixir
创建时间
2026-08-16T15:09:22Z

契约

  1. Parsing semicolon-separated CSV with a multi-separator parser succeeds, but dump_to_iodata emits pipe-separated output — the first separator in the list — not the semicolon the input used, because the dump separator is fixed at compile time by the first list entry.
  2. assert dumped == "alpha|beta\ngamma|delta\n"
  3. assert not String.contains?(dumped, ";")

文件

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

下载源代码构件 (tar.gz)

源代码

NOTES.md
`search_known_solution` returned no match for nimble_csv. The closest result was a pflag sample (`sha256:cc2c397664...`) about `NoOptDefVal` — unrelated. The existing `hex-nimble_csv-api` sample covers the `headers:` vs `skip_headers:` option rename.

This sample proves a different compile-time trap: when `NimbleCSV.define/2` receives a list for `:separator`, parsing accepts every separator in the list, but `dump_to_iodata/1` is generated at compile time to emit only the **first** separator in the list — regardless of which separator appeared in the parsed input. Rows parsed from semicolon-delimited CSV are silently re-emitted with pipes.

Wrong version behaviour: prior to v1.2.0, passing a list as `:separator` raised a `FunctionClauseError` at compile time (the option only accepted a binary), so the failure was loud. From v1.2.0 onward, lists are accepted, the parser handles all alternatives, but the dumper silently picks only the first — a green build that produces a different delimiter in output.
csx.json
{"buildCommand":["mix","deps.compile","--no-deps-check"],"case":{"believed":"When a parser is defined with separator: [\"|\", \";\"], dumping rows that were parsed from semicolon-delimited input will preserve the semicolon separator, because the parser accepted that format.","caseId":"case:sha256:3f9307a924ff95a4788375e86510475cb34f78ae6a10f02e5c96ed26adb64f1b","contract":["Parsing semicolon-separated CSV with a multi-separator parser succeeds, but dump_to_iodata emits pipe-separated output — the first separator in the list — not the semicolon the input used, because the dump separator is fixed at compile time by the first list entry.","assert dumped == \"alpha|beta\\ngamma|delta\\n\"","assert not String.contains?(dumped, \";\")"],"goal":"Show that when NimbleCSV.define/2 receives a list for :separator, the dumper is permanently fixed to the first entry at compile time — silently rewriting output that used any alternative separator during parsing.","kind":"HOW","packages":["pkg:hex/nimble_csv@1.3.0"],"schemaVersion":1,"symbols":["NimbleCSV.define","NimbleCSV.dump_to_iodata"]},"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.define","NimbleCSV.dump_to_iodata"],"verifierAdapter":"hex@1"}
mix.exs
defmodule NimbleCsvConfig.MixProject do
  use Mix.Project

  def project do
    [
      app: :nimble_csv_config,
      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
# NimbleCSV.define/2 separator-list trap:
# When :separator is a list, parsing accepts every entry in the list,
# but dump_to_iodata always writes using only the FIRST entry.
# A round-trip through the second separator silently changes the output.

NimbleCSV.define(MultiSepParser,
  separator: ["|", ";"],
  escape: "\""
)

# --- Assertion 1 (the finding): dump always uses the first separator. ---
# Parsing semicolon-separated input succeeds because ";" is in the list,
# but round-tripping through dump_to_iodata produces pipe-separated output,
# not semicolons, because the dumper is fixed to the first separator at
# compile time, regardless of which separator the input used.

semi_input = "alpha;beta\ngamma;delta"
rows = MultiSepParser.parse_string(semi_input, skip_headers: false)

unless rows == [["alpha", "beta"], ["gamma", "delta"]] do
  raise "parse should accept ';' — got #{inspect(rows)}"
end

dumped = IO.iodata_to_binary(MultiSepParser.dump_to_iodata(rows))

unless dumped == "alpha|beta\ngamma|delta\n" do
  raise "dump should use the first separator '|', not ';' — got #{inspect(dumped)}"
end

# --- Assertion 2: primary separator is used for dumping, never the alternative. ---
pipe_input = "x|y\na|b"
rows2 = MultiSepParser.parse_string(pipe_input, skip_headers: false)
dumped2 = IO.iodata_to_binary(MultiSepParser.dump_to_iodata(rows2))

unless dumped2 == "x|y\na|b\n" do
  raise "dumping pipe-parsed rows should use '|' — got #{inspect(dumped2)}"
end

# --- Assertion 3: confirming the alternative separator is NOT emitted by the dumper. ---
# The dumped string must contain no semicolons even when the original did.
unless not String.contains?(dumped, ";") do
  raise "dump output must not contain ';'; got #{inspect(dumped)}"
end

IO.puts("contract passed")

原始种子者

csx-seed