README.textile in rantly-0.3.0 vs README.textile in rantly-0.3.1
- old
+ new
@@ -7,57 +7,48 @@
Its implementation has no alien mathematics inside. Completely side-effect-free-free.
h1. Install
<pre><code>
-$ gem install hayeah-rant --source http://gems.github.com
+$ gem install rantly
</code></pre>
<pre><code>
-$ irb
-> gem 'rant'
-> require 'rant'
-> Rant.gen.value { [integer,float] }
+$ irb -rrantly
+> Rantly { [integer,float] } # same as Rantly.value { integer }
=> [20991307, 0.025756845811823]
-> Rant.gen.value { [integer,float]}
+> Rantly { [integer,float]}
=> [-376856492, 0.452245765751706]
+> Rantly(5) { integer } # same as Rantly.map(5) { integer }
+=> [-1843396915550491870, -1683855015308353854, -2291347782549033959, -951461511269053584, 483265231542292652]
</code></pre>
-
h1. Data Generation
-You can create random generators from the Rant class. Rant.gen is just returns a class instance of Rant.
-
-<pre><code>
-> gen = Rant.new
-> gen.value { [integer,float] }
-=> [-163260081, 0.356075765934108]
-</code></pre>
-
h2. Getting Random Data Values
<pre><code>
-Rant#map(n,limit=10)
+Rantly#map(n,limit=10,&block)
call the generator n times, and collect values
-Rant#each(n,limit=10)
+Rantly#each(n,limit=10,&block)
call a random block n times
-Rant#value(limit=10)
+Rantly#value(limit=10,&block)
call a random block once, and get its value.
</code></pre>
To collect an array of random data,
<pre><code>
-# we want 5
-> gen.map(5) { integer }
+# we want 5 random integers
+> Rantly(5) { integer }
=> [-380638946, -29645239, 344840868, 308052180, -154360970]
</code></pre>
To iterate over random data,
<pre><code>
-> gen.each(5) { puts integer }
+> Rantly.each(5) { puts integer }
296971291
504994512
-402790444
113152364
502842783
@@ -65,141 +56,143 @@
</code></pre>
To get one value of random data,
<pre><code>
-> gen.value { integer }
+> Rantly { integer }
=> 278101042
</code></pre>
The optional argument @limit@ is used with generator guard. By default, if you want to generate n items, the generator tries at most n * 10 times.
This almost always succeeds,
<pre><code>
-> gen.map(5) { i = integer; guard i > 0; i }
+> Rantly(5) { i = integer; guard i > 0; i }
=> [511765059, 250554234, 305947804, 127809156, 285960387]
</code></pre>
This always fails,
<pre><code>
-> gen.map(10) { guard integer.is_a?(Float) }
-Rant::TooManyTries: Exceed gen limit 100: 101 failed guards)
+> Rantly(10) { guard integer.is_a?(Float) }
+Rantly::TooManyTries: Exceed gen limit 100: 101 failed guards)
</code></pre>
h2. Random Generating Methods
The API is similiar to QuickCheck, but not exactly the same. In particular @choose@ picks a random element from an array, and @range@ picks a integer from an interval.
h3. Simple Randomness
<pre><code>
-Rant#integer(n=nil)
+Rantly#integer(n=nil)
random positive or negative integer. Fixnum only.
-Rant#range(lo,hi)
+Rantly#range(lo,hi)
random integer between lo and hi.
-Rant#float
+Rantly#float
random float
-Rant#bool
+Rantly#bool
true or false
-Rant#literal(value)
+Rantly#literal(value)
No-op. returns value.
-Rant#choose(*vals)
+Rantly#choose(*vals)
Pick one value from among vals.
</code></pre>
h3. Meta Randomness
A rant generator is just a mini interpreter. It's often useful to go meta,
<pre><code>
-Rant#call(gen)
+Rantly#call(gen)
If gen is a Symbol, just do a method call with send.
If gen is an Array, the first element of the array is the method name, the rest are args.
If gen is a Proc, instance_eval it with the generator.
</code></pre>
<pre><code>
-> gen.value { call(:integer) }
+> Rantly { call(:integer) }
=> -240998958
</code></pre>
<pre><code>
-> gen.value { call([:range,0,10]) }
+> Rantly { call([:range,0,10]) }
=> 2
</code></pre>
<pre><code>
-> gen.value { call(Proc.new { [integer] })}
+> Rantly { call(Proc.new { [integer] })}
=> [522807620]
</code></pre>
The @call@ method is useful to implement other abstractions (See next subsection).
<pre><code>
-Rant#branch(*args)
- Pick a random arg among args, and Rant#call it.
+Rantly#branch(*args)
+ Pick a random arg among args, and Rantly#call it.
</code></pre>
50-50 chance getting an integer or float,
<pre><code>
-> gen.value { branch :integer, :float }
+> Rantly { branch :integer, :float }
=> 0.0489446702931332
-> gen.value { branch :integer, :float }
+> Rantly { branch :integer, :float }
=> 494934533
</code></pre>
h3. Frequencies
<pre><code>
-Rant#freq(*pairs)
- Takes a list of 2-tuples, the first of which is the weight, and the second a Rant#callable value, and returns a random value picked from the pairs. Follows the distribution pattern specified by the weights.
+Rantly#freq(*pairs)
+ Takes a list of 2-tuples, the first of which is the weight, and the second a Rantly#callable value, and returns a random value picked from the pairs. Follows the distribution pattern specified by the weights.
</code></pre>
Twice as likely to get a float than integer. Never gets a ranged integer.
<pre><code>
-> gen.value { freq [1,:integer], [2,:float], [0,:range,0,10] }
+> Rantly { freq [1,:integer], [2,:float], [0,:range,0,10] }
</code></pre>
If the "pair" is not an array, but just a symbol, @freq@ assumes that the weight is 1.
<pre><code>
# 50-50 between integer and float
-> gen.value { freq :integer, :float }
+> Rantly { freq :integer, :float }
</code></pre>
-If a "pair" is an Array, but the first element is not an Integer, @freq@ assumes that it's a Rant method-call with arguments, and the weight is one.
+If a "pair" is an Array, but the first element is not an Integer, @freq@ assumes that it's a Rantly method-call with arguments, and the weight is one.
<pre><code>
# 50-50 chance generating integer limited by 10, or by 20.
-> gen.value { freq [:integer,10], [:integer 20] }
+> Rantly { freq [:integer,10], [:integer 20] }
</code></pre>
h3. Sized Structure
-A Rant generator keeps track of how large a datastructure it should generate with its @size@ attribute.
+A Rantly generator keeps track of how large a datastructure it should generate with its @size@ attribute.
<pre><code>
-Rant#size
+Rantly#size
returns the current size
-Rant#sized(n,&block)
+Rantly#sized(n,&block)
sets the size for the duration of recursive call of block. Block is instance_eval with the generator.
</code></pre>
-Rant provides two methods that depends on the size
+Rantly provides two methods that depends on the size
<pre><code>
-Rant#array(size=default_size)
- returns a sized array consisted of elements by Rant#calling random branches.
-Rant#string(char_class=:print)
+Rantly#array(size=default_size,&block)
+ returns a sized array consisted of elements by Rantly#calling random branches.
+Rantly#string(char_class=:print)
returns a sized random string, consisted of only chars from a char_class.
+Rantly#dict(size=default_size,&block)
+ returns a sized random hash. The generator block should generate tuples of keys and values (arrays that have two elements, the first one is used as key, and the second as value).
</code></pre>
The avaiable char classes for strings are:
<pre><code>
@@ -217,50 +210,61 @@
:xdigit
:ascii
</code></pre>
<pre><code>
-# sized 10 array of integer or float
-> gen.value { array(10) { branch(:integer,:float)}}
+# sized 10 array of integers
+> Rantly { array(10) { integer }}
=> [417733046, -375385433, 0.967812380000118, 26478621, 0.888588160450082, 250944144, 305584916, -151858342, 0.308123867823313, 0.316824642414253]
</code></pre>
If you set the size once, it applies to all subsequent recursive structures. Here's a sized 10 array of sized 10 strings,
<pre><code>
-> gen.value { sized(10) { array(:string)} }
+> Rantly { sized(10) { array {string}} }
=> ["1c}C/,9I#}", "hpA/UWPJ\\j", "H'~ERtI`|]", "%OUaW\\%uQZ", "Z2QdY=G~G!", "H<o|<FARGQ", "g>ojnxGDT3", "]a:L[B>bhb", "_Kl=&{tH^<", "ly]Yfb?`6c"]
</code></pre>
Or a sized 10 array of sized 5 strings,
<pre><code>
-> gen.value { array(10) { array(5) { string}}}
+> Rantly {array(10){sized(5) {string}}}
=> ["S\"jf ", "d\\F-$", "-_8pa", "IN0iF", "SxRV$", ".{kQ7", "6>;fo", "}.D8)", "P(tS'", "y0v/v"]
</code></pre>
-Rant#array actually just delegate to Rant#freq, so you can use freq pairs:
+Generate a hash that has 5 elements,
<pre><code>
-> gen.value { sized(10) {array [1,:integer],[2,:float] }}
-=> [0.983334733158678, -418176338, 0.976947175363592, 0.703390570421286, -478680395, 5483631, 0.966944106783513, 110469205, 0.540859146793544, 0.521813810037025]
+> Rantly { dict { [string,integer] }}
+{"bR\\qHn"=>247003509502595457,
+ "-Mp '."=>653206579583741142,
+ "gY%<SV"=>-888111605212388599,
+ "+SMn:r"=>-1159506450084197716,
+ "^3gYfQ"=>-2154064981943219558,
+ "= :/\\,"=>433790301059833691}
</code></pre>
+The @dict@ generator retries if a key is duplicated. If it fails to generate a unique key after too many tries, it gives up by raising an error:
+<pre><code>
+> Rantly { dict { ["a",integer] }}
+Rantly::TooManyTries: Exceed gen limit 60: 60 failed guards)
+</code></pre>
+
h1. Property Testing
-Rant extends Test::Unit for property testing. The extension is in its own module. So you need to require it.
+Rantly extends Test::Unit for property testing. The extension is in its own module. So you need to require it.
<pre><code>
require 'rant/check'
</code></pre>
It defines,
<pre><code>
Test::Unit::Assertions#property_of(&block)
- The block is used to generate random data with a generator. The method returns a Rant::Property instance, that has the method 'check'.
+ The block is used to generate random data with a generator. The method returns a Rantly::Property instance, that has the method 'check'.
</code></pre>
It's like this, using the gem 'shoulda'
<pre><code>
@@ -268,10 +272,10 @@
should "generate Fixnum only" do
property_of { integer }.check { |i| assert i.is_a?(Integer) }
end
</code></pre>
-The check block takes the generated data as its argument. One idiom I find useful is to include a parameter of the random data for the check argument. For example, if I want to check that Rant#array generates the right sized array, I could say,
+The check block takes the generated data as its argument. One idiom I find useful is to include a parameter of the random data for the check argument. For example, if I want to check that Rantly#array generates the right sized array, I could say,
<pre><code>
should "generate right sized array" do
property_of {
len = integer