@@ -91,6 +91,27 @@ defmodule NimbleCSV do
9191 defexception [ :message ]
9292 end
9393
94+ @ doc """
95+ Returns the options used to define this parser/dumper module.
96+
97+ This function allows you to retrieve the original options and use them
98+ as a base for defining new modules with modified options.
99+
100+ ## Examples
101+
102+ # Create a new parser based on RFC4180 but with formula escaping
103+ NimbleCSV.define(
104+ MyApp.CSV,
105+ NimbleCSV.RFC4180.options()
106+ |> Keyword.merge(
107+ escape_formula: %{~w(@ + - = \\ t \\ r) => "'"},
108+ moduledoc: "RFC4180 with formula escaping"
109+ )
110+ )
111+
112+ """
113+ @ callback options ( ) :: keyword ( )
114+
94115 @ doc """
95116 Eagerly dumps an enumerable into iodata (a list of binaries and bytes and other lists).
96117 """
@@ -207,10 +228,10 @@ defmodule NimbleCSV do
207228 * `:dump_bom` - includes BOM (byte order marker) in the dumped document
208229 * `:reserved` - the list of characters to be escaped, defaults to the
209230 `:separator`, `:newlines`, and `:escape` characters above
210- * `:escape_formula` - the formula prefix(es) and formula escape sequence,
211- defaults to `nil`, which disabled formula escaping
212- `%{["@", "+", "-", "=", "\t", "\r"] => "'"}` would escape all fields starting
213- with `@`, `+`, `-`, `=`, tab or carriage return using the `'` character.
231+ * `:escape_formula` - an optional map of formula prefixes to escape sequences.
232+ When `nil` (the default), formula escaping is disabled. For example,
233+ `%{~w(@ + - = \t \r) => "'"}` escapes fields starting with `@`, `+`, `-`, `=`,
234+ tab, or carriage return by prefixing them with `'`
214235
215236 Although parsing may support multiple newline delimiters, when
216237 dumping, only one of them must be picked, which is controlled by
@@ -239,17 +260,27 @@ defmodule NimbleCSV do
239260 `@`, `+`, `-`, `=`, tab or carriage return). Use the following config to
240261 follow the [OWASP recommendations](https://owasp.org/www-community/attacks/CSV_Injection):
241262
242- escape_formula: %{["@", "+", "-", "=", "\t", "\r"] => "'"}
263+ escape_formula: %{~w(@ + - = \t \r) => "'"}
243264
244265 Applications that want more control over this process, to allow formulas in specific
245266 cases, or possibly minimize false positives, should leave this option disabled and
246267 escape the value, as necessary, within their code.
268+
269+ ## Extending existing CSV modules
270+
271+ Each module defined with `define/2` includes an `c:options/0` function that
272+ returns the original options used to create the CSV module. This allows you
273+ to easily create new modules based on existing ones. For example, you can
274+ extend an existing CSV module to add formula escaping or customize other
275+ options as needed.
247276 """
248277 def define ( module , options ) do
249278 defmodule module do
250279 @ behaviour NimbleCSV
251280 @ moduledoc Keyword . get ( options , :moduledoc )
252281
282+ @ original_options options
283+
253284 @ escape Keyword . get ( options , :escape , "\" " )
254285 @ escape_formula Enum . to_list ( Keyword . get ( options , :escape_formula , [ ] ) )
255286
@@ -342,6 +373,8 @@ defmodule NimbleCSV do
342373 @ compile { :inline ,
343374 maybe_dump_bom: 1 , maybe_trim_bom: 1 , maybe_to_utf8: 1 , maybe_to_encoding: 1 }
344375
376+ def options , do: @ original_options
377+
345378 ## Parser
346379
347380 def parse_stream ( stream , opts \\ [ ] ) when is_list ( opts ) do
0 commit comments