randall 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+
2
+ copyright (c) 2010, Diego Che
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in
12
+ all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,87 @@
1
+ = Randall
2
+
3
+ *{Randomly generates instances of any class}*
4
+
5
+ == Dependencies
6
+
7
+ Beautiful treetop[http://treetop.rubyforge.org/] is needed for parsing
8
+ regular expressions, so we can generate random character strings matching
9
+ a regexp.
10
+
11
+ Slim bacon[http://rubygems.org/gems/bacon/] is used for executing specs.
12
+ You need not install bacon to use Randall.
13
+
14
+ == Install
15
+
16
+ gem install randall
17
+
18
+ Randall uses Fiber, so can be used on Ruby 1.9 or JRuby only.
19
+
20
+ Tested on:
21
+ - ruby 1.9.1 p378
22
+ - jruby 1.5.0 with option --1.9
23
+
24
+ == Examples
25
+
26
+ === Canonical approach
27
+
28
+ === Numbers
29
+
30
+ === String
31
+
32
+ === Array and Hash
33
+
34
+
35
+ === Objects
36
+
37
+
38
+
39
+ === Syntax sugars
40
+
41
+ Some methods are provided to specify the type and restrictions.
42
+
43
+ r = Randall
44
+ r.integers.less_than(100) # Same as r.generate(Integer, :less_than => 100)
45
+ r.floats.gt(100) # => r.generate(Float, :greater_than => 100)
46
+ r.floats.clost_to(0)
47
+ r.integers.in_range(1..2)
48
+
49
+ For generating strings.
50
+ number = Randall.strings.that.match(/[0-9]+/)
51
+
52
+ Above example has the same effect as
53
+ <code>number = Randall.new(String, :like => /[0-9]+/)</code>.
54
+
55
+ Generate Arrays whose elements are generated by +number+.
56
+ Randall.arrays.of(number).size(100)
57
+ Generate Hashes whose keys are
58
+ Randall.hashes.from(number).to(String).size(10)
59
+
60
+ ==== Some monkey patching
61
+
62
+ - +Array#pick+ randomly pick an element from the receiver.
63
+ - +Regexp#rand+ generates a String that matches the receiver.
64
+
65
+ Monkey patching is disabled by default. You must patch explicitly, by calling
66
+ +RandallMonkey.patch+.
67
+
68
+ == Limitations on Generating Strings for Regular Expressions
69
+
70
+ * Anchors, except +^+ and +$+, are ignored.
71
+ * +\p{*}+ and +\P{*}+ are not supported.
72
+ * Unicode characters are not supported.
73
+ * +(?*)+ extension is not supported.
74
+ * Back-reference is not supported.
75
+
76
+ == License
77
+
78
+ The MIT license.
79
+
80
+ Copyright (2010), Diego Che (chekenan@gmail.com)
81
+
82
+ == Links
83
+
84
+ * randexp[http://github.com/benburkert/randexp] - generates random data from a Regular Expression. The +Array#pick+ is from here.
85
+
86
+ * {Source Repository}[http://github.com/benburkert/randexp] - You can also report bugs to the {github issue tracker}[http://github.com/dche/randall/issues].
87
+
@@ -0,0 +1,186 @@
1
+ # encoding: utf-8
2
+ #
3
+ # charclass.rb -- Character classes parsing for treetop parser.
4
+ #
5
+ # copyright (c) 2010, Diego Che (chekenan@gmail.com)
6
+ #
7
+
8
+ # The grammar module.
9
+ module RandallRegExp # :nodoc: all
10
+ module CharSets
11
+
12
+ def strseq(from, to)
13
+ (from..to).map(&:chr)
14
+ end
15
+
16
+ def all_chars
17
+ @@ascii ||= strseq(0, 0x7f)
18
+ end
19
+ alias :ascii :all_chars
20
+
21
+ def graph
22
+ @@graph ||= strseq(0x21, 0x7e)
23
+ end
24
+
25
+ def control
26
+ @@control ||= strseq(0, 0x1f) << 0x7f
27
+ end
28
+
29
+ def decimal_number
30
+ @@decimal_number ||= (0..9).to_a.map(&:to_s)
31
+ end
32
+ alias :digit :decimal_number
33
+
34
+ def lower_letter
35
+ @@lower_letter ||= 26.times.map do |i|
36
+ ('a'.ord + i).chr
37
+ end
38
+ end
39
+
40
+ def upper_letter
41
+ @@upper_letter ||= self.lower_letter.map(&:upcase)
42
+ end
43
+
44
+ def letter
45
+ @@letter ||= self.lower_letter + self.upper_letter
46
+ end
47
+
48
+ def space
49
+ @@space ||= ["\s", "\t", "\r", "\n", "\v", "\f"]
50
+ end
51
+
52
+ def punctuation
53
+ # CHECK: which chars belong to this set?
54
+ @@punct ||= ['!', "\"", '#', #'$',
55
+ '%', '&', "'", '(', ')',
56
+ '*', #'+',
57
+ '-', '.', '/', ':', ';', '<', #'=', '>',
58
+ '?', '@', '[', '\\', ']', #'^',
59
+ '_', #'`',
60
+ '{', #'|',
61
+ '}', #'~'
62
+ ]
63
+ end
64
+
65
+ def xchar
66
+ c = ['a', 'b', 'c', 'd', 'e']
67
+ c += c.map(&:upcase)
68
+ end
69
+
70
+ def xdigit
71
+ @@xdigit ||= self.digit + self.xchar
72
+ end
73
+
74
+ def word
75
+ @@word ||= self.letter + self.digit << '_'
76
+ end
77
+ end
78
+
79
+ class CharClass < Treetop::Runtime::SyntaxNode
80
+ include CharSets
81
+
82
+ # '[' neg:'^'? comp:(cc_comp / char_class)+ amps:('&&' char_class)? ']'
83
+ def chars
84
+ return @chars if @chars
85
+
86
+ # build charset
87
+ @chars = comp.elements.map(&:chars).reduce([], :+).uniq
88
+ @chars &= amps.elements[1].chars unless amps.empty?
89
+ @chars = self.all_chars - @chars unless neg.empty?
90
+
91
+ @chars
92
+ end
93
+
94
+ def rand
95
+ self.chars
96
+ @chars.empty? ? '' : @chars[Kernel.rand(@chars.size)]
97
+ end
98
+ end
99
+
100
+ class PosixCharClass < CharClass
101
+
102
+ def chars
103
+ return @chars if @chars
104
+
105
+ @chars = case pcc_name.text_value
106
+ when 'alnum'
107
+ self.letter + self.digit
108
+ when 'alpha'
109
+ self.letter
110
+ when 'ascii'
111
+ self.ascii
112
+ when 'blank'
113
+ ["\s", "\t"]
114
+ when 'cntrl'
115
+ self.control
116
+ when 'digit'
117
+ self.digit
118
+ when 'graph'
119
+ self.graph
120
+ when 'lower'
121
+ self.lower
122
+ when 'print'
123
+ self.graph << "\s"
124
+ when 'punct'
125
+ self.punctuation
126
+ when 'space'
127
+ self.space
128
+ when 'upper'
129
+ self.upper
130
+ when 'xdigit'
131
+ self.xdigit
132
+ when 'word'
133
+ self.word
134
+ else
135
+ []
136
+ end
137
+
138
+ @chars = self.all_chars - @chars unless neg.empty?
139
+ @chars
140
+ end
141
+ end
142
+
143
+ class PerlCharClass < CharClass
144
+ def chars
145
+ @chars ||= case self.text_value
146
+ when '\s'
147
+ self.space
148
+ when '\S'
149
+ self.all_chars - self.space
150
+ when '\d'
151
+ self.digit
152
+ when '\D'
153
+ self.all_chars - self.digit
154
+ when '\h'
155
+ self.xdigit
156
+ when '\H'
157
+ self.all_chars - self.xdigit
158
+ when '\w'
159
+ self.word
160
+ when '\W'
161
+ self.all_chars - self.word
162
+ else
163
+ []
164
+ end
165
+ end
166
+ end
167
+
168
+ class SpanCharClass < CharClass
169
+
170
+ def chars
171
+ @chars ||= case self.text_value
172
+ when /([0-9a-zA-Z])\-([0-9a-zA-Z])/
173
+ $1 <= $2 ? self.strseq($1, $2) : ''
174
+ else
175
+ self.text_value.split('').uniq
176
+ end
177
+ end
178
+
179
+ def strseq(from, to)
180
+ (to.ord - from.ord).times.map do |i|
181
+ (from.ord + i).chr
182
+ end
183
+ end
184
+ end
185
+
186
+ end
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+ #
3
+ # copyright (c) 2010, Diego Che
4
+ #
5
+
6
+ module RandallMonkey
7
+
8
+ module PickableArray
9
+ # Randomly pick an element from the receiver.
10
+ def pick
11
+ self[Kernel.rand(self.size)]
12
+ end
13
+ end
14
+
15
+ module RandableRegexp
16
+ # Generate a String that matches the receiver.
17
+ def rand
18
+ @randall ||= Randall.new(String, :like => self)
19
+ @randall.next
20
+ end
21
+ end
22
+
23
+ # Enable the monkey patch.
24
+ # After this message, you have +Array#pick+ and +Regexp#rand+.
25
+ def self.patch
26
+ Array.class_eval do
27
+ include PickableArray
28
+ end
29
+
30
+ Regexp.class_eval do
31
+ include RandableRegexp
32
+ end
33
+ end
34
+
35
+ end
@@ -0,0 +1,149 @@
1
+ # encoding: utf-8
2
+ #
3
+ # copyright (c) 2010, Diego Che
4
+ #
5
+
6
+ module RandallClassSugar
7
+ def strings
8
+ self.new(String)
9
+ end
10
+
11
+ def integers
12
+ self.new(Integer)
13
+ end
14
+
15
+ def floats
16
+ self.new(Float)
17
+ end
18
+
19
+ def arrays
20
+ self.new(Array)
21
+ end
22
+
23
+ def hashes
24
+ self.new(Hash)
25
+ end
26
+
27
+ def instances_of(cls)
28
+ self.new(cls)
29
+ end
30
+ end
31
+
32
+ module RandallInstanceSugar
33
+ def that
34
+ self
35
+ end
36
+ alias :with :that
37
+ alias :and :that
38
+
39
+ def match(re)
40
+ unless @type == String then
41
+ raise ArgumentError, 'Applied to generator for String only.'
42
+ end
43
+
44
+ self.restrict :like => re
45
+ end
46
+
47
+ def less_than(number)
48
+ unless @type == Float or @type == Integer then
49
+ raise ArgumentError, 'Applied to generator for String only.'
50
+ end
51
+
52
+ @options[:less_than] = number
53
+ self
54
+ end
55
+ alias :lt :less_than
56
+
57
+ def greater_than(number)
58
+ unless @type == Float or @type == Integer then
59
+ raise ArgumentError, 'Applied to generator for number only.'
60
+ end
61
+
62
+ @options[:greater_than] = number
63
+ self
64
+ end
65
+ alias :gt :greater_than
66
+
67
+ def close_to(f)
68
+ unless @type == Float then
69
+ raise ArgumentError, 'Applied to generator for number only.'
70
+ end
71
+
72
+ @options[:close_to] = f
73
+ self
74
+ end
75
+
76
+ def in_range(rg)
77
+ unless @type == Float or @type == Integer then
78
+ raise ArgumentError, 'Applied to generator for number only.'
79
+ end
80
+
81
+ @options[:range] = rg
82
+ self
83
+ end
84
+ alias :between :in_range
85
+
86
+ def of(type)
87
+ unless @type == Array then
88
+ raise ArgumentError, 'Applied to generator for Array only.'
89
+ end
90
+
91
+ case type
92
+ when Randall
93
+ @options[:item] = type
94
+ when Class
95
+ @options[:type] = type
96
+ else
97
+ @options[:type] = type.class
98
+ end
99
+
100
+ self
101
+ end
102
+
103
+ def with_size(number)
104
+ unless @type == Hash or @type == Array then
105
+ raise ArgumentError, 'Applied to generator for Hash and Array only.'
106
+ end
107
+
108
+ @options[:size] = number
109
+ self
110
+ end
111
+
112
+ def from(type)
113
+ unless @type == Hash then
114
+ raise ArgumentError, 'Applied to generator for Hash only.'
115
+ end
116
+
117
+ case type
118
+ when Class
119
+ @options[:key_type] = type
120
+ when Randall
121
+ @options[:key] = type
122
+ else
123
+ @options[:key_type] = type.class
124
+ end
125
+ self
126
+ end
127
+
128
+ def to(type)
129
+ unless @type == Hash then
130
+ raise ArgumentError, 'Applied to generator for Hash only.'
131
+ end
132
+
133
+ case type
134
+ when Class
135
+ @options[:value_type] = type
136
+ when Randall
137
+ @options[:value] = type
138
+ else
139
+ @options[:value_type] = type.class
140
+ end
141
+
142
+ self
143
+ end
144
+
145
+ def with_arguments(*args)
146
+ self.restrict :args => args
147
+ end
148
+
149
+ end
data/lib/randall.rb ADDED
@@ -0,0 +1,195 @@
1
+ # encoding: utf-8
2
+ #
3
+ # randall.rb
4
+ #
5
+ # copyright (c) 2010, Diego Che (chekenan@gmail.com)
6
+ #
7
+
8
+ require 'treetop'
9
+
10
+ require File.join(File.dirname(__FILE__), 'randall/charclass')
11
+ Treetop.load File.join(File.dirname(__FILE__), 'regexp')
12
+
13
+ require File.join(File.dirname(__FILE__), 'randall/sugar')
14
+ require File.join(File.dirname(__FILE__), 'randall/monkey_patch')
15
+
16
+ # A random value generator.
17
+ #
18
+ #
19
+ class Randall
20
+ include RandallInstanceSugar
21
+ class <<self; self; end.class_eval do
22
+ include RandallClassSugar
23
+ end
24
+
25
+ # The generated random value. It is changed after +rand+ or +next+ are
26
+ # called.
27
+ attr_reader :value
28
+ # The +Class+ for which the receiver should generate instances.
29
+ attr_reader :type
30
+
31
+ # The regexp parser for generating random String.
32
+ @@reparser = RandallRegExpParser.new
33
+
34
+ # Creates a Randall object.
35
+ #
36
+ # [type] Type of the values the Randall object should generate.
37
+ # [opts] Optional. The restrictions the generated random values should
38
+ # satisfy. See documents of +Randall+ for restrictions
39
+ # of each supported types, and how this arguments is
40
+ # specified.
41
+ def initialize(type = Integer, opts = {})
42
+ @type = type
43
+
44
+ self.restrict opts
45
+
46
+ @worker = Fiber.new do
47
+ loop do
48
+ if String == @type
49
+ @value = g_str
50
+ elsif Integer == @type
51
+ @value = g_int
52
+ elsif Float == @type
53
+ @value = g_float
54
+ elsif Array == @type
55
+ @value = g_array
56
+ elsif Hash == @type
57
+ @value = g_hash
58
+ elsif Class === @type
59
+ @value = g_any
60
+ else
61
+ @value = nil
62
+ end
63
+
64
+ Fiber.yield @value
65
+ end
66
+ end
67
+ end
68
+
69
+ # Same as +self.value+.
70
+ def v
71
+ self.value
72
+ end
73
+
74
+ # Generates value for given type and restrictions.
75
+ # This method is used when you want to reuse a Randall object to generate
76
+ # values for alternate type.
77
+ def rand(type, opts = {})
78
+ @type = type
79
+
80
+ self.restrict opts
81
+ @worker.resume
82
+ end
83
+ alias :r :rand
84
+
85
+ # Set the restriction. You use this method to change the restrictions
86
+ # the generated values should satisfy.
87
+ def restrict(opts)
88
+ @options = opts
89
+ parse_regexp if @type == String
90
+
91
+ self
92
+ end
93
+
94
+ # Generate another value under current type and restrictions.
95
+ def next
96
+ @worker.resume
97
+ end
98
+ alias :n :next
99
+
100
+ private
101
+
102
+ def g_str
103
+ @str_gen.rand
104
+ end
105
+
106
+ def g_int
107
+ @options.delete :close_to
108
+ Integer(g_float)
109
+ end
110
+
111
+ def g_float
112
+ if @options[:close_to]
113
+ epsilon = @options[:epsilon] || 1e-3
114
+ @options[:close_to] - epsilon + Kernel.rand * (2 * epsilon)
115
+ elsif @options[:range]
116
+ min = @options[:range].min
117
+ max = @options[:range].max
118
+
119
+ min + Kernel.rand * (max - min)
120
+ elsif @options[:greater_than] or @options[:less_than]
121
+ max = @options[:less_than] || 10 ** 24
122
+ min = @options[:greater_than] || max - 10 ** 24
123
+
124
+ if min >= max
125
+ if @options[:greater_than] and @options[:less_than]
126
+ raise ArgumentError, ":less_than(#{max}) should be greater than :grater_than(#{min})."
127
+ elsif @options[:greater_than]
128
+ max = min + 10 ** 24
129
+ end
130
+ end
131
+ min + Kernel.rand * (max - min)
132
+ else
133
+ Kernel.rand * (10 ** 6)
134
+ end
135
+ end
136
+
137
+ def g_array
138
+ sz = @options[:size] || rand_size
139
+ item_gen = @options[:item] || self.class.new(@options[:type] || rand_type)
140
+
141
+ v = []
142
+ sz.times do
143
+ v << item_gen.next
144
+ end
145
+ v
146
+ end
147
+
148
+ def g_hash
149
+ sz = @options[:size] || rand_size
150
+ key_gen = @options[:key] || self.class.new(@options[:key_type] || rand_type)
151
+ value_gen = @options[:value] || self.class.new(@options[:value_type] || rand_type)
152
+
153
+ v = {}
154
+ dup_retry = 3
155
+ sz.times do
156
+ k = key_gen.next while v[k] && (dup_retry -= 1) > 0
157
+ v[key_gen.next] = value_gen.next
158
+ end
159
+ if v.size < sz && @options[:size]
160
+ $stderr.puts "[Warning]: The key space is too small to generate #{sz} pairs."
161
+ $stderr.puts key_gen.type
162
+ end
163
+ v
164
+ end
165
+
166
+ # Generate an Object.
167
+ def g_any
168
+ begin
169
+ args = @options[:args] || []
170
+ args = [] unless args.is_a? Array
171
+
172
+ @type.new *args
173
+ rescue Exception # catch all exceptions
174
+ nil
175
+ end
176
+ end
177
+
178
+ def rand_size(max = 100)
179
+ Kernel.rand max
180
+ end
181
+
182
+ def rand_type
183
+ [Integer, Float, String][Kernel.rand 3]
184
+ end
185
+
186
+ def parse_regexp
187
+ return self unless @type == String
188
+ re = @options[:like].is_a?(Regexp) ? @options[:like] : /.+/
189
+
190
+ @str_gen = @@reparser.parse re.source
191
+ raise RuntimeError, "Randall is not strong enough (yet) to handle regexp: #{re.inspect}" if @str_gen.nil?
192
+
193
+ self
194
+ end
195
+ end
@@ -0,0 +1,180 @@
1
+ # encoding: utf-8
2
+ #
3
+ # copyright (c) 2010, Diego Che (chekenan@gmail.com)
4
+ #
5
+
6
+ grammar RandallRegExp
7
+ rule regexp
8
+ pre:'^'? exp_body post:'$'? {
9
+ include CharSets
10
+
11
+ def rand
12
+ (pre.empty? ? self.any_str : '') +
13
+ exp_body.rand +
14
+ (post.empty? ? self.any_str : '')
15
+ end
16
+
17
+ def any_str
18
+ ''
19
+ end
20
+ }
21
+ end
22
+
23
+ rule exp_body
24
+ clause rc:clause* sel:choice? {
25
+ def rand
26
+ head = clause.rand + rc.elements.map(&:rand).reduce('', :+)
27
+ unless sel.empty? then
28
+ Kernel.rand(2) == 0 ? head : sel.rand
29
+ else
30
+ head
31
+ end
32
+ end
33
+ }
34
+ end
35
+
36
+ rule clause
37
+ distinguishable q:quantifier? opt:'?'? {
38
+ def rand
39
+ (q.empty? ? 1 : q.repeatition).times.map do
40
+ distinguishable.rand
41
+ end.reduce('', :+)
42
+ end
43
+ }
44
+ end
45
+
46
+ rule distinguishable
47
+ group / constants / char_class / escapes / '.' {
48
+ include CharSets
49
+
50
+ def rand
51
+ g = self.graph
52
+ g[Kernel.rand(g.size)]
53
+ end
54
+ }
55
+ end
56
+
57
+ rule group
58
+ '(' exp_body ')' {
59
+ def rand
60
+ exp_body.rand
61
+ end
62
+ }
63
+ end
64
+
65
+ rule choice
66
+ '|' exp_body {
67
+ def rand
68
+ exp_body.rand
69
+ end
70
+ }
71
+ end
72
+
73
+ rule constants
74
+ [^\\\[\(\{\*\.\+\?\]\}\)\^\$\|] {
75
+ def rand
76
+ self.text_value
77
+ end
78
+ }
79
+ end
80
+
81
+ rule char_class
82
+ '\\' char_class_escape <PerlCharClass>
83
+ / '[' neg:'^'? comp:(cc_comp / char_class)+ amps:('&&' char_class)? ']' <CharClass>
84
+ end
85
+
86
+ rule char_class_escape
87
+ 'd' / 'D' / 'h' / 'H' / 's' / 'S' / 'w' / 'W' / encoding_property
88
+ end
89
+
90
+ rule encoding_property
91
+ ('p' / 'P') '{' neg:'^'? encoding '}'
92
+ end
93
+
94
+ rule encoding
95
+ 'Alnum' / 'Alpha' / 'Blank' / 'Cntrl' / 'Digit' / 'Graph'
96
+ / 'Lower' / 'Print' / 'Punct' / 'Space' / 'Upper' / 'XDigit'
97
+ / 'Word' / 'ASCII' / [a-zA-Z]+
98
+ end
99
+
100
+ rule cc_comp
101
+ posix_char_class / span_char_class / escaped_chars
102
+ end
103
+
104
+ rule posix_char_class
105
+ '[:' neg:'^'? pcc_name ':]' <PosixCharClass>
106
+ end
107
+
108
+ rule pcc_name
109
+ 'alnum' / 'alpha' / 'ascii' / 'blank' / 'cntrl' / 'digit'/ 'graph'
110
+ / 'lower' / 'print' / 'punct' / 'space' / 'uppder' / 'xdigit' / 'word'
111
+ end
112
+
113
+ rule span_char_class
114
+ [0-9] '-' [0-9] <SpanCharClass>
115
+ / [a-z] '-' [a-z] <SpanCharClass>
116
+ / [A-Z] '-' [A-Z] <SpanCharClass>
117
+ / [0-9a-zA-Z^$.+*(){}]+ <SpanCharClass> # TODO: incomplete chars.
118
+ end
119
+
120
+ rule escaped_chars
121
+ ('\[' / '\]' / '\-' / '\/') {
122
+ def chars
123
+ [self.text_value]
124
+ end
125
+
126
+ def rand
127
+ self.chars
128
+ self.text_value[1]
129
+ end
130
+ }
131
+ end
132
+
133
+ rule escapes
134
+ '\\' [^dDhHsSwWpPx] {
135
+ def rand
136
+ case self.text_value
137
+ when /\\[aAzZbB]/
138
+ ''
139
+ when /\\x(\d+)/
140
+ # TODO: ascii only. To support unicode.
141
+ $1.to_a.chr
142
+ when '\r'
143
+ "\r"
144
+ when '\n'
145
+ "\n"
146
+ when '\t'
147
+ "\t"
148
+ else
149
+ self.text_value[1]
150
+ end
151
+ end
152
+ }
153
+ end
154
+
155
+ rule quantifier
156
+ ('*' / '+' / '?' / '{' ','? [0-9]+ '}' / '{' [0-9]+ ',' ([0-9]+)? '}') {
157
+ def repeatition
158
+ case self.text_value
159
+ when '*'
160
+ Kernel.rand(20)
161
+ when '+'
162
+ 1 + Kernel.rand(20)
163
+ when '?'
164
+ Kernel.rand(2)
165
+ when /\{\,([0-9]+)\}/
166
+ Kernel.rand($1.to_i + 1)
167
+ when /\{([0-9]+)\}/
168
+ $1.to_i
169
+ when /\{([0-9]+)\,\}/
170
+ $1.to_i + Kernel.rand(20)
171
+ when /\{([0-9]+)\,([0-9]+)\}/
172
+ # TODO: ensure $2 >= $1
173
+ $1.to_i + Kernel.rand($2.to_i - $1.to_i + 1)
174
+ else
175
+ 0
176
+ end
177
+ end
178
+ }
179
+ end
180
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: randall
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 1
10
+ version: 0.1.1
11
+ platform: ruby
12
+ authors:
13
+ - Diego Che
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-06-03 00:00:00 +08:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: treetop
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 9
30
+ segments:
31
+ - 1
32
+ - 4
33
+ - 7
34
+ version: 1.4.7
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: bacon
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 19
46
+ segments:
47
+ - 1
48
+ - 1
49
+ - 0
50
+ version: 1.1.0
51
+ type: :development
52
+ version_requirements: *id002
53
+ description: Generate random instances of any classes.
54
+ email: chekenan@gmail.com
55
+ executables: []
56
+
57
+ extensions: []
58
+
59
+ extra_rdoc_files: []
60
+
61
+ files:
62
+ - README.rdoc
63
+ - LICENSE
64
+ - lib/regexp.treetop
65
+ - lib/randall/charclass.rb
66
+ - lib/randall/monkey_patch.rb
67
+ - lib/randall/sugar.rb
68
+ - lib/randall.rb
69
+ has_rdoc: true
70
+ homepage:
71
+ licenses: []
72
+
73
+ post_install_message:
74
+ rdoc_options:
75
+ - --title
76
+ - Randall
77
+ - --main
78
+ - README.rdoc
79
+ - --line-numbers
80
+ - --exclude="spec/*"
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ hash: 29
89
+ segments:
90
+ - 1
91
+ - 9
92
+ version: "1.9"
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ hash: 3
99
+ segments:
100
+ - 0
101
+ version: "0"
102
+ requirements: []
103
+
104
+ rubyforge_project:
105
+ rubygems_version: 1.3.7
106
+ signing_key:
107
+ specification_version: 3
108
+ summary: Generate random instances of any classes.
109
+ test_files: []
110
+