@@ -2325,6 +2325,47 @@ defmodule StreamData do
23252325 scale ( data , fn size -> trunc ( :math . pow ( size , exponent ) ) end )
23262326 end
23272327
2328+ @ doc """
2329+ Generates either `nil` or the value generated by the given `data`.
2330+
2331+ The frequency distribution can be specified using the `ratio` option.
2332+
2333+ ## Options
2334+
2335+ * `:ratio` - (float in between `0.0` and `1.0`, not included) specifies the
2336+ frequency with which `nil` should be selected. Higher means that `nil` is
2337+ more likely to be selected. Defaults to `0.5`.
2338+
2339+ ## Examples
2340+
2341+ Enum.take(StreamData.nullable(StreamData.integer()), 10)
2342+ #=> [1, -1, nil, nil, 5, 4, -3, nil, nil, 1]
2343+
2344+ Enum.take(StreamData.nullable(StreamData.integer(), ratio: 0.25), 10)
2345+ #=> [1, nil, -3, nil, 3, -3, 0, 3, nil, nil]
2346+
2347+ Enum.take(StreamData.nullable(StreamData.integer(), ratio: 0.25), 10)
2348+ #=> [0, -2, 1, nil, -2, 0, -4, 4, 6, nil]
2349+
2350+ Enum.take(StreamData.nullable(StreamData.boolean(), ratio: 0.25), 10)
2351+ #=> [false, false, false, nil, true, true, true, false, false, true]
2352+
2353+ """
2354+ @ spec nullable ( t ( a ) , keyword ( ) ) :: t ( nil | a ) when a: term ( )
2355+ def nullable ( generator , options \\ [ ] ) when is_list ( options ) do
2356+ ratio = Keyword . get ( options , :ratio , 0.5 )
2357+
2358+ { numerator , denominator } =
2359+ if 0 <= ratio and ratio <= 1.0 do
2360+ Float . ratio ( ratio )
2361+ else
2362+ raise ArgumentError ,
2363+ "expected :ratio to be greater than or equal to 0.0 and less than or equal to 1.0, got: #{ inspect ( ratio ) } "
2364+ end
2365+
2366+ StreamData . frequency ( [ { numerator , nil } , { denominator - numerator , generator } ] )
2367+ end
2368+
23282369 @ doc """
23292370 Checks the behaviour of a given function on values generated by `data`.
23302371
0 commit comments