prop_check 0.16.0 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 912a84633a6ab5b7f209555be0086e4dcafd371f337b289113003edf765fb668
4
- data.tar.gz: 92146dcaf693c20f4cb3021178e881495de8b63f3819c254aea186a3780891c0
3
+ metadata.gz: e59cf670bcc8cf9720d6278e984925c50e75ca65023459174f8b511d6421fb71
4
+ data.tar.gz: '088e0eb8d2d301bc3c03cc63bf68196969e8653cad37ff0b9d5d10f9b417a1ae'
5
5
  SHA512:
6
- metadata.gz: 192ed9c6887dc19f29fc3d8aba9278eeb0fd389aab9fae546c940e2831833ea8064ea53e1e903c599d7d7ec2a8fe5bdc04a2c3122c2374a2d1d933b2184a2ab0
7
- data.tar.gz: 63005af74e5f0d1757930f64ce031f5cc922e34b4e876cdaebbbf139280e9e923d134440f20ab63129c4fd1647d1e524b07b6ed3800828b29d22ad7e2cc5e394
6
+ metadata.gz: de5808bced970e0c474367bf125837ac0eefa4aa752acb31cd74e884fea858b98fb518e9fe15493c81f8238e5e0490f3cbc855eda3a9b687196ca7830daad0aa
7
+ data.tar.gz: 312957d1ab0f990985f43ae7e4b0793df583ff2d3d8bb95573c11fe3e4d9c5f964d91050fe9bafb98ceb92dd6790d2ffce04257b02b0c152d75d9b4772b7423a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ - 0.17.0
2
+ - Features:
3
+ - Recursive generation using `PropCheck::Generators.tree`.
1
4
  - 0.16.0
2
5
  - Features:
3
6
  - New option in `PropCheck::Property::Configuration` to resize all generators at once.
data/README.md CHANGED
@@ -64,7 +64,7 @@ Before releasing v1.0, we want to finish the following:
64
64
  - [x] Builtin generation of `Set`s
65
65
  - [x] Builtin generation of `Date`s, `Time`s and `DateTime`s.
66
66
  - [x] Configuration option to resize all generators given to a particular Property instance.
67
- - [ ] A simple way to create recursive generators
67
+ - [x] A simple way to create recursive generators
68
68
  - [ ] A usage guide.
69
69
 
70
70
  ## Nice-to-haves
@@ -872,5 +872,75 @@ module PropCheck
872
872
  end
873
873
  end
874
874
  end
875
+
876
+ ##
877
+ # Helper to build recursive generators
878
+ #
879
+ # Given a `leaf_generator`
880
+ # and a block which:
881
+ # - is given a generator that generates subtrees.
882
+ # - it should return the generator for intermediate tree nodes.
883
+ #
884
+ # This is best explained with an example.
885
+ # Say we want to generate a binary tree of integers.
886
+ #
887
+ # If we have a struct representing internal nodes:
888
+ # ```ruby
889
+ # Branch = Struct.new(:left, :right, keyword_init: true)
890
+ # ```
891
+ # we can generate trees like so:
892
+ # ```ruby
893
+ # Generators.tree(Generators.integer) do |subtree_gen|
894
+ # G.instance(Branch, left: subtree_gen, right: subtree_gen)
895
+ # end
896
+ # ```
897
+ #
898
+ # As another example, consider generating lists of integers:
899
+ #
900
+ # >> G = PropCheck::Generators
901
+ # >> G.tree(G.integer) {|child_gen| G.array(child_gen) }.sample(5, size: 37, rng: Random.new(42))
902
+ # => [[7, [2, 3], -10], [[-2], [-2, [3]], [[2, 3]]], [], [0, [-2, -3]], [[1], -19, [], [1, -1], [1], [-1, -1], [1]]]
903
+ #
904
+ # And finally, here is how one could create a simple generator for parsed JSON data:
905
+ #
906
+ # ```ruby`
907
+ # G = PropCheck::Generators
908
+ # def json
909
+ # G.tree(G.one_of(G.boolean, G.real_float, G.ascii_string)) do |json_gen|
910
+ # G.one_of(G.array(json_gen), G.hash_of(G.ascii_string, json_gen))
911
+ # end
912
+ # end
913
+ # ```
914
+ #
915
+ def tree(leaf_generator, &block)
916
+ # Implementation is based on
917
+ # https://hexdocs.pm/stream_data/StreamData.html#tree/2
918
+ Generator.new do |size:, rng:, **other_kwargs|
919
+ nodes_on_each_level = random_pseudofactors(size.pow(1.1).to_i, rng)
920
+ result = nodes_on_each_level.reduce(leaf_generator) do |subtree_generator, nodes_on_this_level|
921
+ frequency(1 => subtree_generator,
922
+ 2 => block.call(subtree_generator).resize { |_size| nodes_on_this_level })
923
+ end
924
+
925
+ result.generate(size: size, rng: rng, **other_kwargs)
926
+ end
927
+ end
928
+
929
+ private def random_pseudofactors(size, rng)
930
+ return [size].to_enum if size < 2
931
+
932
+ Enumerator.new do |yielder|
933
+ loop do
934
+ factor = rng.rand(1..(Math.log2(size).to_i))
935
+ if factor == 1
936
+ yielder << size
937
+ break
938
+ else
939
+ yielder << factor
940
+ size /= factor
941
+ end
942
+ end
943
+ end
944
+ end
875
945
  end
876
946
  end
@@ -1,3 +1,3 @@
1
1
  module PropCheck
2
- VERSION = '0.16.0'
2
+ VERSION = '0.17.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prop_check
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.0
4
+ version: 0.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Qqwy/Wiebe-Marten Wijnja