radagen 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cb56ff6848be1ab3ca322e0c45067323eba296f6
4
+ data.tar.gz: 83a447038d9980169a5d206f17e083721ef40890
5
+ SHA512:
6
+ metadata.gz: c0f94c3d19faf7cc4fe6e2fb1fd4b154289fb3ce21ac4bb12056297f54ce2a9c5cf1b9e147bb13bad35ee607a8b143b85b9bccd2554e02e2f58caac0fe837fc2
7
+ data.tar.gz: 3f29be3edea5dd05fe6586247f591b358d6a61b15f68e654459a4a8cfefcce687ed41971ea77f9806aec4a16107a0825383026596562d764a12fefcce8d7876b
data/.gitignore ADDED
@@ -0,0 +1,120 @@
1
+ # Created by https://www.gitignore.io/api/ruby,rubymine
2
+
3
+ ### Ruby ###
4
+ *.gem
5
+ *.rbc
6
+ /.config
7
+ /coverage/
8
+ /InstalledFiles
9
+ /pkg/
10
+ /spec/reports/
11
+ /spec/examples.txt
12
+ /test/tmp/
13
+ /test/version_tmp/
14
+ /tmp/
15
+
16
+ # Used by dotenv library to load environment variables.
17
+ # .env
18
+
19
+ ## Specific to RubyMotion:
20
+ .dat*
21
+ .repl_history
22
+ build/
23
+ *.bridgesupport
24
+ build-iPhoneOS/
25
+ build-iPhoneSimulator/
26
+
27
+ ## Specific to RubyMotion (use of CocoaPods):
28
+ #
29
+ # We recommend against adding the Pods directory to your .gitignore. However
30
+ # you should judge for yourself, the pros and cons are mentioned at:
31
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
32
+ #
33
+ # vendor/Pods/
34
+
35
+ ## Documentation cache and generated files:
36
+ /.yardoc/
37
+ /_yardoc/
38
+ /doc/
39
+ /rdoc/
40
+
41
+ ## Environment normalization:
42
+ /.bundle/
43
+ /vendor/bundle
44
+ /lib/bundler/man/
45
+
46
+ # for a library or gem, you might want to ignore these files since the code is
47
+ # intended to run in multiple environments; otherwise, check them in:
48
+ Gemfile.lock
49
+ .ruby-version
50
+ .ruby-gemset
51
+
52
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
53
+ .rvmrc
54
+
55
+ ### RubyMine ###
56
+ # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
57
+ # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
58
+
59
+ # User-specific stuff:
60
+ .idea
61
+ .idea/**/workspace.xml
62
+ .idea/**/tasks.xml
63
+ .idea/dictionaries
64
+
65
+ # Sensitive or high-churn files:
66
+ .idea/**/dataSources/
67
+ .idea/**/dataSources.ids
68
+ .idea/**/dataSources.xml
69
+ .idea/**/dataSources.local.xml
70
+ .idea/**/sqlDataSources.xml
71
+ .idea/**/dynamic.xml
72
+ .idea/**/uiDesigner.xml
73
+
74
+ # Gradle:
75
+ .idea/**/gradle.xml
76
+ .idea/**/libraries
77
+
78
+ # CMake
79
+ cmake-build-debug/
80
+
81
+ # Mongo Explorer plugin:
82
+ .idea/**/mongoSettings.xml
83
+
84
+ ## File-based project format:
85
+ *.iws
86
+
87
+ ## Plugin-specific files:
88
+
89
+ # IntelliJ
90
+ /out/
91
+
92
+ # mpeltonen/sbt-idea plugin
93
+ .idea_modules/
94
+
95
+ # JIRA plugin
96
+ atlassian-ide-plugin.xml
97
+
98
+ # Cursive Clojure plugin
99
+ .idea/replstate.xml
100
+
101
+ # Crashlytics plugin (for Android Studio and IntelliJ)
102
+ com_crashlytics_export_strings.xml
103
+ crashlytics.properties
104
+ crashlytics-build.properties
105
+ fabric.properties
106
+
107
+ ### RubyMine Patch ###
108
+ # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
109
+
110
+ # *.iml
111
+ # modules.xml
112
+ # .idea/misc.xml
113
+ # *.ipr
114
+
115
+ # Sonarlint plugin
116
+ .idea/sonarlint
117
+
118
+ # End of https://www.gitignore.io/api/ruby,rubymine
119
+
120
+ .DS_Store
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --order rand
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ sudo: false
3
+ os:
4
+ - linux
5
+ rvm:
6
+ - 2.0.0
7
+ - 2.1.1
8
+ - 2.2.6
9
+ - 2.3.4
10
+ - 2.4.1
11
+ before_install: gem install bundler -v 1.12.5
data/.yardopts ADDED
@@ -0,0 +1,3 @@
1
+ --markup-provider=redcarpet
2
+ --markup=markdown
3
+ --title 'Radagen -- Random data generation library for the Ruby language.'
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in radagen.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Nathan Smith
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,254 @@
1
+ # Radagen
2
+
3
+ [![Build Status](https://travis-ci.org/smidas/radagen.svg?branch=master)](https://travis-ci.org/smidas/radagen)
4
+
5
+ Radagen is a psuedo random data generator library for the Ruby language built with two primary design goals: *composition* and *sizing*. These two properties allow this library to be used in a range of different applications from simple test data generation, model checking, fuzz testing, database seeding to the foundation of a generative/property based testing framework.
6
+
7
+ ## Requirements
8
+ - Ruby 2.0+
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'radagen'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install radagen
25
+
26
+ ## API Documentation
27
+
28
+ ## Usage
29
+
30
+ The main use case for Radagen is to create data generators that produce arbitrarily complex values. These generators can then be used in many different contexts. Lets start with a few of the `scalar` generators provided by Radagen.
31
+
32
+ ```ruby
33
+ require 'radagen'
34
+ gen = Radagen
35
+
36
+ my_fixnum = gen.fixnum
37
+ my_string = gen.string_alphanumeric
38
+ ```
39
+
40
+ So far we required the Radagen gem and "namespaced" the Radagen module to `gen`. Throughout the rest of this documentation it will be assume `Radagen` is namespaced to `gen`. Let's take look at what values these generators can produce.
41
+
42
+ ```ruby
43
+ my_fixnum.sample => [0, 0, -1, 1, -3, -4, -5, -1, -2, -7]
44
+ my_string.sample => ["", "", "jV", "", "7zS", "2", "U9O84Q", "4S", "6Ccw66", "0Sip741V"]
45
+ ```
46
+
47
+ `sample` above is a utility method on the `Radagen::Generator` object that allows you to interact with your generator seeing what type of values it will produce. As shown above `sample` returns a sampling of 10 values by default. You can change this number sampled by providing a count.
48
+
49
+ ```ruby
50
+ my_string.sample(30) => ["",
51
+ "",
52
+ "Qo",
53
+ "T",
54
+ "X",
55
+ "qy10O",
56
+ "Vh",
57
+ "0omZ",
58
+ "l30fB",
59
+ "r08yruW",
60
+ "27q7zGR",
61
+ "6jSEk1r",
62
+ "k667",
63
+ "v9VUZYnn",
64
+ "M2K8Hd",
65
+ "",
66
+ "4Lu82vRMviY",
67
+ "LB",
68
+ "lB",
69
+ "H0aBry87ykl",
70
+ "",
71
+ "8JMjNC",
72
+ "Gr6lxA",
73
+ "",
74
+ "1VfvdCjA9t2PL72Xa",
75
+ "vI",
76
+ "lUabvF4Rg06RWl71V27fi53",
77
+ "qw2Uo71ADT",
78
+ "550EbA0UX9f9Sc4I",
79
+ "9QbchgbZtY7C57Eq"]
80
+ ```
81
+
82
+ There is something to be noticed about the values produced by `my_string` generator. The values grow in *size* and *complexity* because as `sample` calls the generator it passes a larger and larger *size* value. This is a very important aspect of all Radagen generators and will be detailed further in `sizing`.
83
+
84
+ ### Composition
85
+
86
+ `scalar` generators are interesting but can only take you so far. We now will explore the ideas around composition. Lets build on the previous generators.
87
+
88
+ ```ruby
89
+ my_hash = gen.hash(:fixnum => my_fixnum, :string => my_strings)
90
+ my_hash.sample => [{:fixnum=>0, :string=>""},
91
+ {:fixnum=>1, :string=>"9"},
92
+ {:fixnum=>-1, :string=>"1"},
93
+ {:fixnum=>2, :string=>"2F2"},
94
+ {:fixnum=>1, :string=>""},
95
+ {:fixnum=>3, :string=>""},
96
+ {:fixnum=>5, :string=>""},
97
+ {:fixnum=>1, :string=>"4V9yx"},
98
+ {:fixnum=>8, :string=>""},
99
+ {:fixnum=>-1, :string=>"Dy443"}]
100
+ ```
101
+
102
+ Above we have built a `hash` generator which uses values taken from previous generators. There is of course little difference between the above and the following:
103
+
104
+ ```ruby
105
+ my_hash = gen.hash(:fixnum => gen.fixnum, :string => gen.string_alphanumeric)
106
+ my_hash.sample => [{:fixnum=>0, :string=>""},
107
+ {:fixnum=>0, :string=>""},
108
+ {:fixnum=>0, :string=>""},
109
+ {:fixnum=>2, :string=>"W9"},
110
+ {:fixnum=>-1, :string=>"79BG"},
111
+ {:fixnum=>2, :string=>"YEF0"},
112
+ {:fixnum=>0, :string=>"IQDe"},
113
+ {:fixnum=>-2, :string=>"mRo"},
114
+ {:fixnum=>-7, :string=>"F958K0"},
115
+ {:fixnum=>7, :string=>"18T"}]
116
+ ```
117
+
118
+ However the following becomes more interesting.
119
+
120
+ ```ruby
121
+ meta = gen.hash(:fixnum => gen.fixnum, :string => gen.string_alphanumeric)
122
+ individual_account = gen.hash(:account_id => gen.uuid, :type => gen.return('individual'), :meta => meta)
123
+ individual_account.sample => [{:account_id=>"d4f6a194-d2d8-4c4f-9a89-df3f477f3dfc", :type=>"individual", :meta=>{:fixnum=>0, :string=>""}},
124
+ {:account_id=>"e6da491f-0af3-4ab4-9529-00a5025cbbde", :type=>"individual", :meta=>{:fixnum=>-1, :string=>""}},
125
+ {:account_id=>"4c3a3ebb-0aa3-4fc7-9c66-022ef2c1b77a", :type=>"individual", :meta=>{:fixnum=>-1, :string=>""}},
126
+ {:account_id=>"2a21493e-5ea7-4ae4-b813-bfe7052c5ba0", :type=>"individual", :meta=>{:fixnum=>-2, :string=>""}},
127
+ {:account_id=>"54a06f43-35bf-4b86-af36-499164fdec0e", :type=>"individual", :meta=>{:fixnum=>2, :string=>"lYnP"}},
128
+ {:account_id=>"17d42c28-c9a2-484d-a54f-3063fba893a2",
129
+ :type=>"individual",
130
+ :meta=>{:fixnum=>-4, :string=>"92e8k"}},
131
+ {:account_id=>"c77a7dc6-7c13-4d68-b5ff-dd4d4d22366f", :type=>"individual", :meta=>{:fixnum=>4, :string=>"gEDq"}},
132
+ {:account_id=>"f0e2b910-70c7-4b65-9dd1-9e89ef03ec00",
133
+ :type=>"individual",
134
+ :meta=>{:fixnum=>3, :string=>"e2EYLzk"}},
135
+ {:account_id=>"7bce02de-6d77-4e4e-91c9-8f518cc73223",
136
+ :type=>"individual",
137
+ :meta=>{:fixnum=>4, :string=>"Qnh5Z"}},
138
+ {:account_id=>"8781bf21-85f0-40f4-b407-85805da60ba6", :type=>"individual", :meta=>{:fixnum=>-1, :string=>"Z"}}]
139
+ ```
140
+
141
+ The `hash` generator combinator conveniently will nest any generator. But what if you would like to make your own combinators? There are two primitives to work with; `bind` and `fmap`.
142
+
143
+ ```ruby
144
+ domain = gen.elements(['gmail.com', 'mailinator.com'])
145
+ name = gen.string_ascii
146
+
147
+ email_account = gen.fmap(gen.tuple(name, domain)) do |name, domain|
148
+ "#{name}@#{domain}"
149
+ end
150
+
151
+ email_account.sample => ["@gmail.com", "r@gmail.com", "U@gmail.com", "mj@gmail.com", "z^@mailinator.com", "B_@mailinator.com", "(t-f;@gmail.com", "@gmail.com", ")3-@mailinator.com", "n@mailinator.com"]
152
+ ```
153
+
154
+ Lets walk thru the above example. `elements` will randomly select an element from the array you pass it (ex. 'gmail.com' or 'mailinator.com'). `string_ascii` will produce strings containing the *ascii* band of characters. `fmap` will take values from a generator, which in this case was a two `tuple` with the first value taken from the *name* generator and the second taken from the *domain* generator, and passes those values to a `block`. Within the block we do some destructuring to the tuple and with string interpolation we return an email account string. Note the block passed to `fmap` requires you return a *value* NOT another generator.
155
+
156
+ The first example you noticed has an *empty* name which isn't a valid email address. We see our first example of how a 'stocastic' like tool can challenge our assumptions, or at least forces you to consider the domain you are working a little deeper.
157
+
158
+ If you don't want the generator to produce *empty* names you could do the following:
159
+
160
+ ```ruby
161
+ name = gen.not_empty(gen.string_ascii)
162
+ name.sample => ["1", "G", "y", "K", "<xv", "|5`", "u4GgC", "^", "n(]yZ2", "V7-"]
163
+ ```
164
+
165
+ Using `not_empty` here takes the `string_ascii` generator, returning another generator that won't produce empty strings.
166
+
167
+ `bind` is similar to `fmap` but the block instead of returning a *value* needs to return a `Radagen::Generator`.
168
+
169
+ ```ruby
170
+ account = gen.hash({:id => gen.uuid, :name => gen.string_alpha, :comment_count => gen.fixnum_pos})
171
+ accounts = gen.not_empty(gen.array(account)) #an array of non-empty accounts
172
+
173
+ accounts_and_selection = gen.bind(accounts) do |accounts|
174
+ gen.tuple(gen.identity(accounts), gen.elements(accounts))
175
+ end
176
+
177
+ accounts_and_selection.sample => [[[{:id=>"8f9308be-976f-447b-b207-3e4f3391d8da", :name=>"f", :comment_count=>1}], {:id=>"8f9308be-976f-447b-b207-3e4f3391d8da", :name=>"f", :comment_count=>1}],
178
+ [[{:id=>"f28cde53-4f8f-4548-9192-57c3b44af73c", :name=>"Ry", :comment_count=>2}, {:id=>"5b45b99a-1a8a-4674-9ad5-f5c706d27315", :name=>"Hl", :comment_count=>2}], {:id=>"5b45b99a-1a8a-4674-9ad5-f5c706d27315", :name=>"Hl", :comment_count=>2}],
179
+ [[{:id=>"3e97741d-107d-4cab-ae11-323b1ef42668", :name=>"Y", :comment_count=>2}], {:id=>"3e97741d-107d-4cab-ae11-323b1ef42668", :name=>"Y", :comment_count=>2}],
180
+ [[{:id=>"63e812b2-e1b2-4528-acd2-f36d0f323dbd", :name=>"", :comment_count=>1}], {:id=>"63e812b2-e1b2-4528-acd2-f36d0f323dbd", :name=>"", :comment_count=>1}]]
181
+ ```
182
+
183
+ `accounts_and_selection` will create an array of accounts and then randomly select one of those accounts returning a two-tuple of that representation. This type of pattern is very helpful when you want to setup state in a system and then interact with one or more of the objects. Why create a generator that does the selection for you and not just select an element after the values from the generator that have been produced? Reproducibility. Being able to rerun the same generator with the same *seed*, producing the same array of accounts and selection is important when using this library in a testing context or in any context really.
184
+
185
+ ### Seeding
186
+
187
+ *Seeding* the generator is simply providing a starting state to the [pseudo random number generator](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) so that you can repeatably produce the same values from your generator.
188
+
189
+ #### gen
190
+ ```ruby
191
+ seed = 5647326586234654723645
192
+
193
+ accounts_and_selection.gen(5, seed) => [[{:id=>"0cc609b8-7ada-4192-be41-1f2b29369b14", :name=>"Kiq", :comment_count=>5}, {:id=>"cc8e373b-1a06-4d2c-adad-bb18f9d9b10f", :name=>"vU", :comment_count=>3}], {:id=>"0cc609b8-7ada-4192-be41-1f2b29369b14", :name=>"Kiq", :comment_count=>5}]
194
+
195
+ accounts_and_selection.gen(5, seed) => [[{:id=>"0cc609b8-7ada-4192-be41-1f2b29369b14", :name=>"Kiq", :comment_count=>5}, {:id=>"cc8e373b-1a06-4d2c-adad-bb18f9d9b10f", :name=>"vU", :comment_count=>3}], {:id=>"0cc609b8-7ada-4192-be41-1f2b29369b14", :name=>"Kiq", :comment_count=>5}]
196
+ ```
197
+
198
+ Taking our `account_and_selection` generator we created above, providing a *seed* value and a size we were able to reproduce the same generated value. In this example using the `gen` method, we can pass in the *size* and *seed* to the generator. Note the *size* value should also be seen as a state value as it will influence the value produced. The `sample` method does NOT provide this level of interactively and is intended for exploratory interaction in a console.
199
+
200
+ #### to_enum
201
+ ```ruby
202
+ accounts_and_selection.to_enum(seed: 5647326586234654723645).take(6).to_a => [[[{:id=>"609b87ad-a192-4be4-91f2-b29369b14eee", :name=>"Kiq", :comment_count=>4},
203
+ {:id=>"cc8e373b-1a06-4d2c-adad-bb18f9d9b10f", :name=>"vU", :comment_count=>4},
204
+ {:id=>"004839da-0ea1-4545-bf74-211b1515e3c1", :name=>"OI", :comment_count=>2},
205
+ {:id=>"d59b453c-da7e-45d6-8d44-5a39123c1ce6", :name=>"", :comment_count=>1}],
206
+ {:id=>"d59b453c-da7e-45d6-8d44-5a39123c1ce6", :name=>"", :comment_count=>1}],
207
+ [[{:id=>"1f11bc82-c45a-4ab6-8528-eaf0a0b565f3", :name=>"sC", :comment_count=>4}, {:id=>"b2fa4c7b-0bb6-4ff0-9f69-ac709f703b02", :name=>"x", :comment_count=>3}], {:id=>"1f11bc82-c45a-4ab6-8528-eaf0a0b565f3", :name=>"sC", :comment_count=>4}],
208
+ [[{:id=>"f68e86b3-6b64-4e0d-a184-be9a04dd1101", :name=>"q", :comment_count=>1}, {:id=>"371fe60e-7cd8-40e0-bf8d-d06762978271", :name=>"", :comment_count=>1}], {:id=>"371fe60e-7cd8-40e0-bf8d-d06762978271", :name=>"", :comment_count=>1}],
209
+ [[{:id=>"30fa9545-b504-443d-8bb5-0a0a87acd2a3", :name=>"TZ", :comment_count=>4}, {:id=>"f8778a9b-2030-45ee-a82f-a7eddbad06c9", :name=>"b", :comment_count=>2}], {:id=>"f8778a9b-2030-45ee-a82f-a7eddbad06c9", :name=>"b", :comment_count=>2}],
210
+ [[{:id=>"d29f472d-55ea-4464-8b93-91d741b69db5", :name=>"oQc", :comment_count=>2}, {:id=>"448ae1c8-c6c6-40d5-a8ed-cd96dcf05c83", :name=>"", :comment_count=>1}], {:id=>"448ae1c8-c6c6-40d5-a8ed-cd96dcf05c83", :name=>"", :comment_count=>1}]]
211
+ ```
212
+
213
+ You can also leverage the `to_enum` method which will return an enumerable representing a lazy infinite sequence of values taken from the generator. Seen above with a provided *seed*, `to_enum` also has the ability to control the sequence of sizes passed to the generator when called. See the API docs for more details.
214
+
215
+ ### Sizing
216
+
217
+ Sizing provides the ability for a generator to produce values of varying degrees of well, *size*. Size has different meaning depending on the context of the generator being used. In some cases generators don't honor the size parameter at all. Examples being `uuid` and `identity`. When a generator is called to produce a value the *size* that is passed in represents the *upper bound* of all possible sizes starting from zero that could be generated. Why? This is so that methods like `to_enum`, `sample` and `gen` don't return a predictable linear growth of values as they are passed ever increasing size values. It is also why this library and libraries like it seem to have the ability to walk thru progressively more complex values "randomly", perhaps challenging boundary assumptions of a model.
218
+
219
+ ```ruby
220
+ 5.times { p gen.fixnum.gen(size: 2) } => 2 0 -1 1 -2
221
+
222
+ 5.times { p gen.string.gen(size: 300) } => "oysO930W8B4QU02J05qEWPn6R6H7xTZKFGbG6Hpo28b"
223
+ "R021N1tw0927BXZP7GbzgRE4rA5t46785g27jsztMRlaz571XzHoi6yBv22ec97194yByN3KIYM3EX1XiRrA08Y32S5i2AvkevMRLClA8Xsb0N7R"
224
+ "3zFiC25U5495KY52FcB1B12txoA6xlFc83TJ97j9ytKSfi0rs1EwSILytRyMy2S5F70TrT6H457teJkVk5fr"
225
+ "VaLYheY512yh2qsj2MV31dl7oV56kWmmLlPSDIJwd74mOcyYfQft8N9756VfM5ExtBHql9TnRWl15j3beLww4p176G48s5q8bEWS0Nwcx7RX0WBz2nO412k7fWGi3nmxn8i156C45AHS27ttTB34sT0MiY63HWG0rbXLXnt41d3m5HiWmbnyh9yL36KH3TL4NMwK4vV0A9gZ6DpLrvPUWYaNYgEqQ0MGll1d2009l388upimkl71xaglmK97r7EDA491"
226
+ "82Q78FWpl1992nXtPUP2cF0rnM7jUPo0M6F8VgvbrQjHY4Var31H0aY94OF0Np6mlxM648S38LBvTrjZObsGn2eB9RPqzqWOlzMD0j71UKRZU90L7B95B5MdZMviaj5vml3JkkIODi6QZQWUobQt4Gr6b0mqR69UQ77897BuK2VjmFdNPLx4z8we7Bk0vU5o6DcJQgxOu7ZP"
227
+
228
+ ```
229
+
230
+ There a few methods that can be used to have finer grained control over the size being passed to a generator. See `resize`, `scale`, and for some generators `not_empty` in the API docs.
231
+
232
+ ## Development
233
+
234
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt with pry that will allow you to experiment.
235
+
236
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
237
+
238
+ ## Contributing
239
+
240
+ Bug reports and pull requests are welcome on GitHub at https://github.com/smidas/radagen.
241
+
242
+ ## Attribution
243
+
244
+ Radagen was greatly influenced by the generator API found in [test.check](https://github.com/clojure/test.check) and shares many of the same naming conventions. I have a great deal of gratitude to the contributors and maintainers of that library.
245
+
246
+ ## TODO
247
+ - More example documentation
248
+ - Make the `set` generator honor *min* elements
249
+ - Implement a Bignum generator with a good enough sampling distribution.
250
+ - Explore and implement the need for a splittable PRNG.
251
+
252
+ ## License
253
+
254
+ Radagen is released under the [MIT License](https://github.com/smidas/radagen/blob/master/LICENSE).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "radagen"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ require "pry"
11
+ Pry.start
12
+
13
+ # require "irb"
14
+ # IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,76 @@
1
+ module Radagen
2
+
3
+ class Generator
4
+
5
+ def initialize(&gen_proc)
6
+ @gen_proc = gen_proc
7
+ end
8
+
9
+ # Realize a value from the generator.
10
+ #
11
+ # @param prng [Object] psuedo random number generator
12
+ # @param size [Fixnum] size used in the generation of the value
13
+ # @return [Object]
14
+ #
15
+ def call(prng, size)
16
+ @gen_proc.call(prng, size)
17
+ end
18
+
19
+ # Generate n samples from the generator. Sizing is linear
20
+ # and starts at 0. Max size is defined by #to_enum. This is
21
+ # to *see* what type of values your generator will make.
22
+ #
23
+ # @note max size on samples is set by #to_enum
24
+ # @param n [Fixnum] sample generated values from generator
25
+ # @return [Array<Object>]
26
+ # @see #to_enum
27
+ #
28
+ # @example
29
+ # fixnum.sample(3) #=> [0, 1, 1]
30
+ #
31
+ def sample(n=10)
32
+ self.to_enum.take(n).to_a
33
+ end
34
+
35
+ # Generate a single value from the generator.
36
+ #
37
+ # @param size [Fixnum] *size* passed to the generator
38
+ # @param seed [Fixnum] seed used as the initial state of the generator
39
+ # @return [Object]
40
+ #
41
+ # @example
42
+ # string_alpha.gen => "Qwad"
43
+ #
44
+ # @example
45
+ # string_alpha.gen(200, 45362642634632684368) => "IaxBvRLxDIvLBhKezMdMmVZBCGzSJZvVjHkcLHsEchCpZWOmLAUQ"
46
+ #
47
+ def gen(size=30, seed=Random.new_seed)
48
+ prng = Random.new(seed)
49
+ @gen_proc.call(prng, size)
50
+ end
51
+
52
+ # Create a lazy enumerable of generator values. Size cycles from *size_min* to *size_max*
53
+ #
54
+ # @note the *size* value is the upper bound of the sizes that could be generated
55
+ # @param opts [Hash] options hash to control behavior of enumerator
56
+ # @option opts [Fixnum] :size_min (0) minimum *size* passed to generator in size cycles
57
+ # @option opts [Fixnum] :size_max (300) maximum *size* passed to generator in size cycles
58
+ # @option opts [Fixnum] :seed initial state passed to the pseudo random number generator
59
+ # @return [Enumerator::Lazy]
60
+ #
61
+ # @example
62
+ # string_ascii.to_enum.take(10).to_a #=> ["", "", ")", "{?", "wE&", "h*hq", "9gm>dG", "9Ljn,(Z", "", "1q7:\\q{"]
63
+ #
64
+ def to_enum(opts={})
65
+ default_opts = {size_min: 0, size_max: 300, seed: Random.new_seed}
66
+ size_min, size_max, seed = default_opts.merge(opts).values_at(:size_min, :size_max, :seed)
67
+ prng = Random.new(seed)
68
+
69
+ (size_min...size_max).cycle.lazy.map do |size|
70
+ @gen_proc.call(prng, size)
71
+ end
72
+ end
73
+
74
+ end
75
+
76
+ end
@@ -0,0 +1,3 @@
1
+ module Radagen
2
+ VERSION = "0.3.3"
3
+ end