lib/prop_check/generator.rb in prop_check-0.11.0 vs lib/prop_check/generator.rb in prop_check-0.11.1

- old
+ new

@@ -9,26 +9,28 @@ # to be used during the shrinking phase. class Generator @@default_size = 10 @@default_rng = Random.new @@max_consecutive_attempts = 100 + @@default_kwargs = {size: @@default_size, rng: @@default_rng, max_consecutive_attempts: @@max_consecutive_attempts} ## # Being a special kind of Proc, a Generator wraps a block. def initialize(&block) @block = block end ## # Given a `size` (integer) and a random number generator state `rng`, # generate a LazyTree. - def generate(size = @@default_size, rng = @@default_rng, max_consecutive_attempts = @@max_consecutive_attempts) - (0..max_consecutive_attempts).each do - res = @block.call(size, rng) - next if res == :"PropCheck.filter_me" + def generate(**kwargs) + kwargs = @@default_kwargs.merge(kwargs) + max_consecutive_attempts = kwargs[:max_consecutive_attempts] - return res + (0..max_consecutive_attempts).each do + res = @block.call(**kwargs) + return res unless res.root == :"_PropCheck.filter_me" end raise Errors::GeneratorExhaustedError, """ Exhausted #{max_consecutive_attempts} consecutive generation attempts. @@ -38,89 +40,83 @@ ## # Generates a value, and only return this value # (drop information for shrinking) # - # >> Generators.integer.call(1000, Random.new(42)) + # >> Generators.integer.call(size: 1000, rng: Random.new(42)) # => 126 - def call(size = @@default_size, rng = @@default_rng) - generate(size, rng).root + def call(**kwargs) + generate(**@@default_kwargs.merge(kwargs)).root end ## # Returns `num_of_samples` values from calling this Generator. # This is mostly useful for debugging if a generator behaves as you intend it to. - def sample(num_of_samples = 10, size: @@default_size, rng: @@default_rng) + def sample(num_of_samples = 10, **kwargs) num_of_samples.times.map do - call(size, rng) + call(**@@default_kwargs.merge(kwargs)) end end ## # Creates a 'constant' generator that always returns the same value, # regardless of `size` or `rng`. # # Keen readers may notice this as the Monadic 'pure'/'return' implementation for Generators. # - # >> Generators.integer.bind { |a| Generators.integer.bind { |b| Generator.wrap([a , b]) } }.call(100, Random.new(42)) + # >> Generators.integer.bind { |a| Generators.integer.bind { |b| Generator.wrap([a , b]) } }.call(size: 100, rng: Random.new(42)) # => [2, 79] def self.wrap(val) - Generator.new { |_size, _rng| LazyTree.wrap(val) } + Generator.new { LazyTree.wrap(val) } end ## # Create a generator whose implementation depends on the output of another generator. # this allows us to compose multiple generators. # # Keen readers may notice this as the Monadic 'bind' (sometimes known as '>>=') implementation for Generators. # - # >> Generators.integer.bind { |a| Generators.integer.bind { |b| Generator.wrap([a , b]) } }.call(100, Random.new(42)) + # >> Generators.integer.bind { |a| Generators.integer.bind { |b| Generator.wrap([a , b]) } }.call(size: 100, rng: Random.new(42)) # => [2, 79] def bind(&generator_proc) # Generator.new do |size, rng| # outer_result = generate(size, rng) # outer_result.map do |outer_val| # inner_generator = generator_proc.call(outer_val) # inner_generator.generate(size, rng) # end.flatten # end - Generator.new do |size, rng| - outer_result = self.generate(size, rng) + Generator.new do |**kwargs| + outer_result = self.generate(**kwargs) outer_result.bind do |outer_val| inner_generator = generator_proc.call(outer_val) - inner_generator.generate(size, rng) + inner_generator.generate(**kwargs) end end end ## # Creates a new Generator that returns a value by running `proc` on the output of the current Generator. # - # >> Generators.choose(32..128).map(&:chr).call(10, Random.new(42)) + # >> Generators.choose(32..128).map(&:chr).call(size: 10, rng: Random.new(42)) # => "S" def map(&proc) - Generator.new do |size, rng| - result = self.generate(size, rng) + Generator.new do |**kwargs| + result = self.generate(**kwargs) result.map(&proc) end end ## # Creates a new Generator that only produces a value when the block `condition` returns a truthy value. def where(&condition) self.map do |result| - if condition.call(result) + # if condition.call(*result) + if PropCheck::Helper.call_splatted(result, &condition) result else :"_PropCheck.filter_me" end end - # self.map do |*result| - # if condition.call(*result) - # result - # else - # :'_PropCheck.filter_me' - # end - # end end end end