randall 0.1.1

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.
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
+