rantly 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source :rubygems
2
+ group :development, :test do
3
+ gem 'jeweler'
4
+ gem 'shoulda'
5
+ end
@@ -9,53 +9,44 @@ Its implementation has no alien mathematics inside. Completely side-effect-free-
9
9
  h1. Install
10
10
 
11
11
  <pre><code>
12
- $ gem install hayeah-rant --source http://gems.github.com
12
+ $ gem install rantly
13
13
  </code></pre>
14
14
 
15
15
  <pre><code>
16
- $ irb
17
- > gem 'rant'
18
- > require 'rant'
19
- > Rant.gen.value { [integer,float] }
16
+ $ irb -rrantly
17
+ > Rantly { [integer,float] } # same as Rantly.value { integer }
20
18
  => [20991307, 0.025756845811823]
21
- > Rant.gen.value { [integer,float]}
19
+ > Rantly { [integer,float]}
22
20
  => [-376856492, 0.452245765751706]
21
+ > Rantly(5) { integer } # same as Rantly.map(5) { integer }
22
+ => [-1843396915550491870, -1683855015308353854, -2291347782549033959, -951461511269053584, 483265231542292652]
23
23
  </code></pre>
24
24
 
25
-
26
25
  h1. Data Generation
27
26
 
28
- You can create random generators from the Rant class. Rant.gen is just returns a class instance of Rant.
29
-
30
- <pre><code>
31
- > gen = Rant.new
32
- > gen.value { [integer,float] }
33
- => [-163260081, 0.356075765934108]
34
- </code></pre>
35
-
36
27
  h2. Getting Random Data Values
37
28
 
38
29
  <pre><code>
39
- Rant#map(n,limit=10)
30
+ Rantly#map(n,limit=10,&block)
40
31
  call the generator n times, and collect values
41
- Rant#each(n,limit=10)
32
+ Rantly#each(n,limit=10,&block)
42
33
  call a random block n times
43
- Rant#value(limit=10)
34
+ Rantly#value(limit=10,&block)
44
35
  call a random block once, and get its value.
45
36
  </code></pre>
46
37
 
47
38
  To collect an array of random data,
48
39
 
49
40
  <pre><code>
50
- # we want 5
51
- > gen.map(5) { integer }
41
+ # we want 5 random integers
42
+ > Rantly(5) { integer }
52
43
  => [-380638946, -29645239, 344840868, 308052180, -154360970]
53
44
  </code></pre>
54
45
 
55
46
  To iterate over random data,
56
47
 
57
48
  <pre><code>
58
- > gen.each(5) { puts integer }
49
+ > Rantly.each(5) { puts integer }
59
50
  296971291
60
51
  504994512
61
52
  -402790444
@@ -67,7 +58,7 @@ To iterate over random data,
67
58
  To get one value of random data,
68
59
 
69
60
  <pre><code>
70
- > gen.value { integer }
61
+ > Rantly { integer }
71
62
  => 278101042
72
63
  </code></pre>
73
64
 
@@ -76,15 +67,15 @@ The optional argument @limit@ is used with generator guard. By default, if you w
76
67
  This almost always succeeds,
77
68
 
78
69
  <pre><code>
79
- > gen.map(5) { i = integer; guard i > 0; i }
70
+ > Rantly(5) { i = integer; guard i > 0; i }
80
71
  => [511765059, 250554234, 305947804, 127809156, 285960387]
81
72
  </code></pre>
82
73
 
83
74
  This always fails,
84
75
 
85
76
  <pre><code>
86
- > gen.map(10) { guard integer.is_a?(Float) }
87
- Rant::TooManyTries: Exceed gen limit 100: 101 failed guards)
77
+ > Rantly(10) { guard integer.is_a?(Float) }
78
+ Rantly::TooManyTries: Exceed gen limit 100: 101 failed guards)
88
79
  </code></pre>
89
80
 
90
81
  h2. Random Generating Methods
@@ -94,17 +85,17 @@ The API is similiar to QuickCheck, but not exactly the same. In particular @choo
94
85
  h3. Simple Randomness
95
86
 
96
87
  <pre><code>
97
- Rant#integer(n=nil)
88
+ Rantly#integer(n=nil)
98
89
  random positive or negative integer. Fixnum only.
99
- Rant#range(lo,hi)
90
+ Rantly#range(lo,hi)
100
91
  random integer between lo and hi.
101
- Rant#float
92
+ Rantly#float
102
93
  random float
103
- Rant#bool
94
+ Rantly#bool
104
95
  true or false
105
- Rant#literal(value)
96
+ Rantly#literal(value)
106
97
  No-op. returns value.
107
- Rant#choose(*vals)
98
+ Rantly#choose(*vals)
108
99
  Pick one value from among vals.
109
100
  </code></pre>
110
101
 
@@ -113,40 +104,40 @@ h3. Meta Randomness
113
104
  A rant generator is just a mini interpreter. It's often useful to go meta,
114
105
 
115
106
  <pre><code>
116
- Rant#call(gen)
107
+ Rantly#call(gen)
117
108
  If gen is a Symbol, just do a method call with send.
118
109
  If gen is an Array, the first element of the array is the method name, the rest are args.
119
110
  If gen is a Proc, instance_eval it with the generator.
120
111
  </code></pre>
121
112
 
122
113
  <pre><code>
123
- > gen.value { call(:integer) }
114
+ > Rantly { call(:integer) }
124
115
  => -240998958
125
116
  </code></pre>
126
117
 
127
118
  <pre><code>
128
- > gen.value { call([:range,0,10]) }
119
+ > Rantly { call([:range,0,10]) }
129
120
  => 2
130
121
  </code></pre>
131
122
 
132
123
  <pre><code>
133
- > gen.value { call(Proc.new { [integer] })}
124
+ > Rantly { call(Proc.new { [integer] })}
134
125
  => [522807620]
135
126
  </code></pre>
136
127
 
137
128
  The @call@ method is useful to implement other abstractions (See next subsection).
138
129
 
139
130
  <pre><code>
140
- Rant#branch(*args)
141
- Pick a random arg among args, and Rant#call it.
131
+ Rantly#branch(*args)
132
+ Pick a random arg among args, and Rantly#call it.
142
133
  </code></pre>
143
134
 
144
135
  50-50 chance getting an integer or float,
145
136
 
146
137
  <pre><code>
147
- > gen.value { branch :integer, :float }
138
+ > Rantly { branch :integer, :float }
148
139
  => 0.0489446702931332
149
- > gen.value { branch :integer, :float }
140
+ > Rantly { branch :integer, :float }
150
141
  => 494934533
151
142
  </code></pre>
152
143
 
@@ -154,50 +145,52 @@ Rant#branch(*args)
154
145
  h3. Frequencies
155
146
 
156
147
  <pre><code>
157
- Rant#freq(*pairs)
158
- 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.
148
+ Rantly#freq(*pairs)
149
+ 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.
159
150
  </code></pre>
160
151
 
161
152
  Twice as likely to get a float than integer. Never gets a ranged integer.
162
153
 
163
154
  <pre><code>
164
- > gen.value { freq [1,:integer], [2,:float], [0,:range,0,10] }
155
+ > Rantly { freq [1,:integer], [2,:float], [0,:range,0,10] }
165
156
  </code></pre>
166
157
 
167
158
  If the "pair" is not an array, but just a symbol, @freq@ assumes that the weight is 1.
168
159
 
169
160
  <pre><code>
170
161
  # 50-50 between integer and float
171
- > gen.value { freq :integer, :float }
162
+ > Rantly { freq :integer, :float }
172
163
  </code></pre>
173
164
 
174
- 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.
165
+ 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.
175
166
 
176
167
  <pre><code>
177
168
  # 50-50 chance generating integer limited by 10, or by 20.
178
- > gen.value { freq [:integer,10], [:integer 20] }
169
+ > Rantly { freq [:integer,10], [:integer 20] }
179
170
  </code></pre>
180
171
 
181
172
 
182
173
 
183
174
  h3. Sized Structure
184
175
 
185
- A Rant generator keeps track of how large a datastructure it should generate with its @size@ attribute.
176
+ A Rantly generator keeps track of how large a datastructure it should generate with its @size@ attribute.
186
177
 
187
178
  <pre><code>
188
- Rant#size
179
+ Rantly#size
189
180
  returns the current size
190
- Rant#sized(n,&block)
181
+ Rantly#sized(n,&block)
191
182
  sets the size for the duration of recursive call of block. Block is instance_eval with the generator.
192
183
  </code></pre>
193
184
 
194
- Rant provides two methods that depends on the size
185
+ Rantly provides two methods that depends on the size
195
186
 
196
187
  <pre><code>
197
- Rant#array(size=default_size)
198
- returns a sized array consisted of elements by Rant#calling random branches.
199
- Rant#string(char_class=:print)
188
+ Rantly#array(size=default_size,&block)
189
+ returns a sized array consisted of elements by Rantly#calling random branches.
190
+ Rantly#string(char_class=:print)
200
191
  returns a sized random string, consisted of only chars from a char_class.
192
+ Rantly#dict(size=default_size,&block)
193
+ 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).
201
194
  </code></pre>
202
195
 
203
196
  The avaiable char classes for strings are:
@@ -219,36 +212,47 @@ The avaiable char classes for strings are:
219
212
  </code></pre>
220
213
 
221
214
  <pre><code>
222
- # sized 10 array of integer or float
223
- > gen.value { array(10) { branch(:integer,:float)}}
215
+ # sized 10 array of integers
216
+ > Rantly { array(10) { integer }}
224
217
  => [417733046, -375385433, 0.967812380000118, 26478621, 0.888588160450082, 250944144, 305584916, -151858342, 0.308123867823313, 0.316824642414253]
225
218
  </code></pre>
226
219
 
227
220
  If you set the size once, it applies to all subsequent recursive structures. Here's a sized 10 array of sized 10 strings,
228
221
 
229
222
  <pre><code>
230
- > gen.value { sized(10) { array(:string)} }
223
+ > Rantly { sized(10) { array {string}} }
231
224
  => ["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"]
232
225
  </code></pre>
233
226
 
234
227
  Or a sized 10 array of sized 5 strings,
235
228
 
236
229
  <pre><code>
237
- > gen.value { array(10) { array(5) { string}}}
230
+ > Rantly {array(10){sized(5) {string}}}
238
231
  => ["S\"jf ", "d\\F-$", "-_8pa", "IN0iF", "SxRV$", ".{kQ7", "6>;fo", "}.D8)", "P(tS'", "y0v/v"]
239
232
  </code></pre>
240
233
 
241
- Rant#array actually just delegate to Rant#freq, so you can use freq pairs:
234
+ Generate a hash that has 5 elements,
242
235
 
243
236
  <pre><code>
244
- > gen.value { sized(10) {array [1,:integer],[2,:float] }}
245
- => [0.983334733158678, -418176338, 0.976947175363592, 0.703390570421286, -478680395, 5483631, 0.966944106783513, 110469205, 0.540859146793544, 0.521813810037025]
237
+ > Rantly { dict { [string,integer] }}
238
+ {"bR\\qHn"=>247003509502595457,
239
+ "-Mp '."=>653206579583741142,
240
+ "gY%<SV"=>-888111605212388599,
241
+ "+SMn:r"=>-1159506450084197716,
242
+ "^3gYfQ"=>-2154064981943219558,
243
+ "= :/\\,"=>433790301059833691}
246
244
  </code></pre>
247
245
 
246
+ 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:
247
+
248
+ <pre><code>
249
+ > Rantly { dict { ["a",integer] }}
250
+ Rantly::TooManyTries: Exceed gen limit 60: 60 failed guards)
251
+ </code></pre>
248
252
 
249
253
  h1. Property Testing
250
254
 
251
- Rant extends Test::Unit for property testing. The extension is in its own module. So you need to require it.
255
+ Rantly extends Test::Unit for property testing. The extension is in its own module. So you need to require it.
252
256
 
253
257
  <pre><code>
254
258
  require 'rant/check'
@@ -258,7 +262,7 @@ It defines,
258
262
 
259
263
  <pre><code>
260
264
  Test::Unit::Assertions#property_of(&block)
261
- The block is used to generate random data with a generator. The method returns a Rant::Property instance, that has the method 'check'.
265
+ The block is used to generate random data with a generator. The method returns a Rantly::Property instance, that has the method 'check'.
262
266
  </code></pre>
263
267
 
264
268
  It's like this, using the gem 'shoulda'
@@ -270,7 +274,7 @@ should "generate Fixnum only" do
270
274
  end
271
275
  </code></pre>
272
276
 
273
- 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,
277
+ 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,
274
278
 
275
279
  <pre><code>
276
280
  should "generate right sized array" do
data/Rakefile CHANGED
@@ -41,6 +41,7 @@ task :default => :test
41
41
 
42
42
  require 'rake/rdoctask'
43
43
  Rake::RDocTask.new do |rdoc|
44
+ require 'yaml'
44
45
  if File.exist?('VERSION.yml')
45
46
  config = YAML.load(File.read('VERSION.yml'))
46
47
  version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
@@ -1,5 +1,5 @@
1
- ---
2
- :build:
1
+ ---
3
2
  :major: 0
4
3
  :minor: 3
5
- :patch: 0
4
+ :patch: 1
5
+ :build:
@@ -101,7 +101,11 @@ class Rantly
101
101
  end
102
102
 
103
103
  def guard(test)
104
- raise GuardFailure.new unless test
104
+ unless test
105
+ raise GuardFailure.new
106
+ else
107
+ true
108
+ end
105
109
  end
106
110
 
107
111
  def size
@@ -205,9 +209,16 @@ class Rantly
205
209
  end
206
210
 
207
211
  def array(n=self.size,&block)
208
- acc = []
209
- n.times { acc << self.instance_eval(&block) }
210
- acc
212
+ n.times.map { self.instance_eval(&block) }
213
+ end
214
+
215
+ def dict(n=self.size,&block)
216
+ h = {}
217
+ each(n) do
218
+ k,v = instance_eval(&block)
219
+ h[k] = v if guard(!h.has_key?(k))
220
+ end
221
+ h
211
222
  end
212
223
 
213
224
  module Chars
@@ -219,7 +230,7 @@ class Rantly
219
230
  end
220
231
 
221
232
  def of(regexp)
222
- ASCII.scan(regexp).to_a.map! { |char| char[0] }
233
+ ASCII.scan(regexp).to_a.map! { |char| char[0].ord }
223
234
  end
224
235
  end
225
236
 
@@ -48,3 +48,13 @@ module Test::Unit::Assertions
48
48
  end
49
49
  end
50
50
 
51
+ begin
52
+ require 'rspec'
53
+ class RSpec::Core::ExampleGroup
54
+ def property_of(&block)
55
+ Rantly::Property.new(block)
56
+ end
57
+ end
58
+ rescue LoadError
59
+ "No RSpec loaded. Oh, well."
60
+ end
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Howard Yeh"]
12
- s.date = %q{2010-01-12}
12
+ s.date = %q{2010-01-22}
13
13
  s.email = %q{hayeah@gmail.com}
14
14
  s.extra_rdoc_files = [
15
15
  "LICENSE",
metadata CHANGED
@@ -1,30 +1,48 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: rantly
3
- version: !ruby/object:Gem::Version
4
- version: 0.3.0
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.1
5
+ prerelease:
5
6
  platform: ruby
6
- authors:
7
+ authors:
7
8
  - Howard Yeh
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
-
12
- date: 2010-01-12 00:00:00 -08:00
13
- default_executable:
14
- dependencies: []
15
-
12
+ date: 2011-12-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: jeweler
16
+ requirement: &2156578960 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *2156578960
25
+ - !ruby/object:Gem::Dependency
26
+ name: shoulda
27
+ requirement: &2156578420 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2156578420
16
36
  description:
17
37
  email: hayeah@gmail.com
18
38
  executables: []
19
-
20
39
  extensions: []
21
-
22
- extra_rdoc_files:
40
+ extra_rdoc_files:
23
41
  - LICENSE
24
42
  - README.textile
25
- files:
43
+ files:
26
44
  - .document
27
- - .gitignore
45
+ - Gemfile
28
46
  - LICENSE
29
47
  - README.textile
30
48
  - Rakefile
@@ -38,34 +56,28 @@ files:
38
56
  - rantly.gemspec
39
57
  - test/rantly_test.rb
40
58
  - test/test_helper.rb
41
- has_rdoc: true
42
59
  homepage: http://github.com/hayeah/rantly
43
60
  licenses: []
44
-
45
61
  post_install_message:
46
- rdoc_options:
47
- - --charset=UTF-8
48
- require_paths:
62
+ rdoc_options: []
63
+ require_paths:
49
64
  - lib
50
- required_ruby_version: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: "0"
55
- version:
56
- required_rubygems_version: !ruby/object:Gem::Requirement
57
- requirements:
58
- - - ">="
59
- - !ruby/object:Gem::Version
60
- version: "0"
61
- version:
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
62
77
  requirements: []
63
-
64
78
  rubyforge_project:
65
- rubygems_version: 1.3.5
79
+ rubygems_version: 1.8.11
66
80
  signing_key:
67
81
  specification_version: 3
68
82
  summary: Ruby Imperative Random Data Generator and Quickcheck
69
- test_files:
70
- - test/rantly_test.rb
71
- - test/test_helper.rb
83
+ test_files: []
data/.gitignore DELETED
@@ -1,5 +0,0 @@
1
- *.sw?
2
- .DS_Store
3
- coverage
4
- rdoc
5
- pkg