prop_check 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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