shokkenki-support 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  module Shokkenki
2
2
  module Support
3
3
  module Version
4
- STRING = '0.0.1'
4
+ STRING = '0.0.2'
5
5
  end
6
6
  end
7
7
  end
@@ -0,0 +1,15 @@
1
+ # About StringRandom
2
+
3
+ StringRandom generate a random string based on Regexp syntax or Patterns.
4
+ StringRandom is Ruby version of String::Random written in Perl.
5
+ The original code released in http://search.cpan.org/~steve/String-Random-0.22/
6
+
7
+ # How to use
8
+
9
+ Exmaples are written in test_strrand.rb.
10
+
11
+ # Copyright
12
+
13
+ Copyright (c) 2008 Masahiro Nakagawa
14
+
15
+ This library is released under the Ruby license.
@@ -0,0 +1,302 @@
1
+ #
2
+ # = strrand.rb: Generates a random string from a pattern
3
+ #
4
+ # Author:: tama <repeatedly@gmail.com>
5
+ #
6
+ # StringRandom is derived from the String::Random written in Perl.
7
+ # See http://search.cpan.org/~steve/String-Random-0.22/
8
+ #
9
+ # == Example
10
+ #
11
+ # string_random = StringRandom.new
12
+ # string_random.random_pattern('CCcc!ccn') #=> ZIop$ab1
13
+ #
14
+ # refer to test/test_stringrandom.rb
15
+ #
16
+ # == Format
17
+ #
18
+ # === Regular expression syntax
19
+ #
20
+ # *_regex methods use this rule.
21
+ #
22
+ # The following regular expression elements are supported.
23
+ #
24
+ # [\w] Alphanumeric + "_".
25
+ # [\d] Digits.
26
+ # [\W] Printable characters other than those in \w.
27
+ # [\D] Printable characters other than those in \d.
28
+ # [.] Printable characters.
29
+ # [[]] Character classes.
30
+ # [{}] Repetition.
31
+ # [*] Same as {0,}.
32
+ # [+] Same as {1,}
33
+ # [?] Same as {0,1}.
34
+ #
35
+ # === Patterns
36
+ #
37
+ # random_pattern and random_string methods use this rule.
38
+ #
39
+ # The following patterns are pre-defined.
40
+ #
41
+ # [c] Any lowercase character [a-z]
42
+ # [C] Any uppercase character [A-Z]
43
+ # [n] Any digit [0-9]
44
+ # [!] A punctuation character [~`!@$%^&*()-_+={}[]|\:;"'.<>?/#,]
45
+ # [.] Any of the above
46
+ # [s] A "salt" character [A-Za-z0-9./]
47
+ # [b] Any binary data
48
+ #
49
+ # Pattern can modify and add as bellow.
50
+ #
51
+ # string_random['C'] = ['n']
52
+ # string_random['A'] = Array('A'..'Z') | Array('a'..'z')
53
+ #
54
+ # Pattern must be a flattened array that elements are one character.
55
+ # Other types cause undefined behavior(raise exception, success, etc...).
56
+ #
57
+ class StringRandom
58
+ Upper = Array('A'..'Z')
59
+ Lower = Array('a'..'z')
60
+ Digit = Array('0'..'9')
61
+ Punct = [33..47, 58..64, 91..96, 123..126].map { |r| r.map { |val| val.chr } }.flatten
62
+ Any = Upper | Lower | Digit | Punct
63
+ Salt = Upper | Lower | Digit | ['.', '/']
64
+ Binary = (0..255).map { |val| val.chr }
65
+
66
+ # These are the regex-based patterns.
67
+ Pattern = {
68
+ # These are the regex-equivalents.
69
+ '.' => Any,
70
+ '\d' => Digit,
71
+ '\D' => Upper | Lower | Punct,
72
+ '\w' => Upper | Lower | Digit | ['_'],
73
+ '\W' => Punct.reject { |val| val == '_' },
74
+ '\s' => [' ', "\t"],
75
+ '\S' => Upper | Lower | Digit | Punct,
76
+
77
+ # These are translated to their double quoted equivalents.
78
+ '\t' => ["\t"],
79
+ '\n' => ["\n"],
80
+ '\r' => ["\r"],
81
+ '\f' => ["\f"],
82
+ '\a' => ["\a"],
83
+ '\e' => ["\e"]
84
+ }
85
+ # These are the old patterns for random_pattern.
86
+ OldPattern = {
87
+ 'C' => Upper,
88
+ 'c' => Lower,
89
+ 'n' => Digit,
90
+ '!' => Punct,
91
+ '.' => Any,
92
+ 's' => Salt,
93
+ 'b' => Binary
94
+ }
95
+
96
+ #
97
+ # Singleton method version of random_regex.
98
+ #
99
+ def self.random_regex(patterns)
100
+ StringRandom.new.random_regex(patterns)
101
+ end
102
+
103
+ #
104
+ # Same as StringRandom#random_pattern if single argument.
105
+ # Optionally, references to lists containing
106
+ # other patterns can be passed to the function.
107
+ # Those lists will be used for 0 through 9 in the pattern.
108
+ #
109
+ def self.random_string(pattern, *pattern_list)
110
+ string_random = StringRandom.new
111
+
112
+ pattern_list.each_with_index do |new_pattern, i|
113
+ string_random[i.to_s] = new_pattern
114
+ end
115
+
116
+ string_random.random_pattern(pattern)
117
+ end
118
+
119
+ #
120
+ # _max_ is default length for creating random string
121
+ #
122
+ def initialize(max = 10)
123
+ @max = max
124
+ @map = OldPattern.clone
125
+ @regch = {
126
+ "\\" => method(:regch_slash),
127
+ '.' => method(:regch_dot),
128
+ '[' => method(:regch_bracket),
129
+ '*' => method(:regch_asterisk),
130
+ '+' => method(:regch_plus),
131
+ '?' => method(:regch_question),
132
+ '{' => method(:regch_brace)
133
+ }
134
+ end
135
+
136
+ #
137
+ # Returns a random string that will match
138
+ # the regular expression passed in the list argument.
139
+ #
140
+ def random_regex(patterns)
141
+ return _random_regex(patterns) unless patterns.instance_of?(Array)
142
+
143
+ result = []
144
+ patterns.each do |pattern|
145
+ result << _random_regex(pattern)
146
+ end
147
+ result
148
+ end
149
+
150
+ #
151
+ # Returns a random string based on the concatenation
152
+ # of all the pattern strings in the list.
153
+ #
154
+ def random_pattern(patterns)
155
+ return _random_pattern(patterns) unless patterns.instance_of?(Array)
156
+
157
+ result = []
158
+ patterns.each do |pattern|
159
+ result << _random_pattern(pattern)
160
+ end
161
+ result
162
+ end
163
+
164
+ #
165
+ # Returns a random string pattern
166
+ #
167
+ def [](key)
168
+ @map[key]
169
+ end
170
+
171
+ #
172
+ # Adds a random string pattern
173
+ #
174
+ # _pattern_ must be flattened array
175
+ #
176
+ def []=(key, pattern)
177
+ @map[key] = pattern
178
+ end
179
+
180
+ private
181
+
182
+ def _random_regex(pattern)
183
+ string = []
184
+ chars = pattern.split(//)
185
+ non_ch = /[\$\^\*\(\)\+\{\}\]\|\?]/ # not supported chars
186
+
187
+ while ch = chars.shift
188
+ if @regch.has_key?(ch)
189
+ @regch[ch].call(ch, chars, string)
190
+ else
191
+ warn "'#{ch}' not implemented. treating literally." if ch =~ non_ch
192
+ string << [ch]
193
+ end
194
+ end
195
+
196
+ result = ''
197
+ string.each do |ch|
198
+ result << ch[rand(ch.size)]
199
+ end
200
+ result
201
+ end
202
+
203
+ def _random_pattern(pattern)
204
+ string = ''
205
+
206
+ pattern.split(//).each do |ch|
207
+ raise %Q(Unknown pattern character "#{ch}"!) unless @map.has_key?(ch)
208
+ string << @map[ch][rand(@map[ch].size)]
209
+ end
210
+
211
+ string
212
+ end
213
+
214
+ #-
215
+ # The folloing methods are defined for regch.
216
+ # These characters are treated specially in random_regex.
217
+ #+
218
+
219
+ def regch_slash(ch, chars, string)
220
+ raise 'regex not terminated' if chars.empty?
221
+
222
+ tmp = chars.shift
223
+ if tmp == 'x'
224
+ # This is supposed to be a number in hex, so
225
+ # there had better be at least 2 characters left.
226
+ tmp = chars.shift + chars.shift
227
+ string << tmp.hex.chr
228
+ elsif tmp =~ /[0-7]/
229
+ warn 'octal parsing not implemented. treating literally.'
230
+ string << tmp
231
+ elsif Pattern.has_key?(ch + tmp)
232
+ string << Pattern[ch + tmp]
233
+ else
234
+ warn "'\\#{tmp}' being treated as literal '#{tmp}'"
235
+ string << tmp
236
+ end
237
+ end
238
+
239
+ def regch_dot(ch, chars, string)
240
+ string << Pattern[ch]
241
+ end
242
+
243
+ def regch_bracket(ch, chars, string)
244
+ tmp = []
245
+
246
+ while ch = chars.shift and ch != ']'
247
+ if ch == '-' and !chars.empty? and !tmp.empty?
248
+ max = chars.shift
249
+ min = tmp.last
250
+ tmp << min = min.succ while min < max
251
+ else
252
+ warn "${ch}' will be treated literally inside []" if ch =~ /\W/
253
+ tmp << ch
254
+ end
255
+ end
256
+ raise 'unmatched []' if ch != ']'
257
+
258
+ string << tmp
259
+ end
260
+
261
+ def regch_asterisk(ch, chars, string)
262
+ chars = '{0,}'.split('').concat(chars)
263
+ end
264
+
265
+ def regch_plus(ch, chars, string)
266
+ chars = '{1,}'.split('').concat(chars)
267
+ end
268
+
269
+ def regch_question(ch, chars, string)
270
+ chars = '{0,1}'.split('').concat(chars)
271
+ end
272
+
273
+ def regch_brace(ch, chars, string)
274
+ # { isn't closed, so treat it literally.
275
+ return string << ch unless chars.include?('}')
276
+
277
+ tmp = ''
278
+ while ch = chars.shift and ch != '}'
279
+ raise "'#{ch}' inside {} not supported" unless ch =~ /[\d,]/
280
+ tmp << ch
281
+ end
282
+
283
+ tmp = if tmp =~ /,/
284
+ raise "malformed range {#{tmp}}" unless tmp =~ /^(\d*),(\d*)$/
285
+
286
+ min = $1.length.nonzero? ? $1.to_i : 0
287
+ max = $2.length.nonzero? ? $2.to_i : @max
288
+ raise "bad range {#{tmp}}" if min > max
289
+
290
+ min == max ? min : min + rand(max - min + 1)
291
+ else
292
+ tmp.to_i
293
+ end
294
+
295
+ if tmp.nonzero?
296
+ last = string.last
297
+ (tmp - 1).times { string << last }
298
+ else
299
+ string.pop
300
+ end
301
+ end
302
+ end
@@ -0,0 +1,180 @@
1
+ #
2
+ # test/test_strrand.rb
3
+ #
4
+
5
+ $KCODE = 'u' if RUBY_VERSION < '1.9.0'
6
+ $LOAD_PATH << '../'
7
+
8
+ require 'lib/strrand'
9
+ require 'test/unit'
10
+
11
+ class TestStringRandom < Test::Unit::TestCase
12
+ def setup
13
+ @string_random = StringRandom.new
14
+ end
15
+
16
+ # StringRandom itself
17
+ def test_initialize
18
+ assert_not_nil(@string_random)
19
+ assert_instance_of(StringRandom, @string_random)
20
+ end
21
+
22
+ # StringRandom methods
23
+ def test_method_respond
24
+ # instance methods
25
+ assert_respond_to(@string_random, :[])
26
+ assert_respond_to(@string_random, :[]=)
27
+ assert_respond_to(@string_random, :random_regex)
28
+ assert_respond_to(@string_random, :random_pattern)
29
+
30
+ # singleton methods
31
+ assert_respond_to(StringRandom, :random_regex)
32
+ assert_respond_to(StringRandom, :random_string)
33
+ end
34
+
35
+ # StringRandom#random_regex
36
+ def test_random_regex
37
+ patterns = ['\d\d\d',
38
+ '\w\w\w',
39
+ '[ABC][abc]',
40
+ '[012][345]',
41
+ '...',
42
+ '[a-z][0-9]',
43
+ '[aw-zX][123]',
44
+ '[a-z]{5}',
45
+ '0{80}',
46
+ '[a-f][nprt]\d{3}',
47
+ '\t\n\r\f\a\e',
48
+ '\S\S\S',
49
+ '\s\s\s',
50
+ '\w{5,10}',
51
+ '\w?',
52
+ '\w+',
53
+ '\w*',
54
+ '']
55
+
56
+ patterns.each do |pattern|
57
+ result = @string_random.random_regex(pattern)
58
+ assert_match(/#{pattern}/, result, "#{result} is invalid: pattern #{pattern}")
59
+ end
60
+
61
+ result = @string_random.random_regex(patterns)
62
+ assert_equal(patterns.size, result.size)
63
+ end
64
+
65
+ # StringRandom#random_regex
66
+ def test_random_regex_invalid
67
+ patterns = ['[a-z]{a}',
68
+ '0{,,}',
69
+ '9{1,z}']
70
+
71
+ patterns.each do |pattern|
72
+ assert_raise(RuntimeError, "Non expected: #{pattern}") { @string_random.random_regex(pattern) }
73
+ end
74
+ end
75
+
76
+ # StringRandom#random_pattern
77
+ def test_random_pattern
78
+ assert_equal(0, @string_random.random_pattern('').length)
79
+
80
+ patterns = {
81
+ 'x' => ['a'],
82
+ 'y' => ['b'],
83
+ 'z' => ['c']
84
+ }
85
+
86
+ patterns.each_pair do |key, pattern|
87
+ @string_random[key] = pattern
88
+ end
89
+ assert_equal('abc', @string_random.random_pattern('xyz'))
90
+
91
+ target = patterns.keys
92
+ result = @string_random.random_pattern(target)
93
+ assert_equal(target.size, result.size)
94
+ target.each_with_index do |pattern, i|
95
+ assert_equal(@string_random[pattern][0], result[i])
96
+ end
97
+ end
98
+
99
+ # StringRandom#random_pattern
100
+ def test_random_pattern_builtin
101
+ ['C', 'c', 'n', '!', '.', 's', 'b'].each do |val|
102
+ assert_not_nil(@string_random[val])
103
+ end
104
+
105
+ range = ('A'..'Z').to_a
106
+ range.each_with_index do |val, i|
107
+ assert_equal(val, @string_random['C'][i])
108
+ end
109
+
110
+ # modify built-in pattern
111
+ @string_random['C'] = ['n']
112
+ assert_equal('n', @string_random.random_pattern('C'))
113
+
114
+ # undefined behavior
115
+ count = 0
116
+ patterns = {
117
+ 'X' => ('A'..'Z'),
118
+ 'Y' => [['foo,', 'bar'], [['baz']]],
119
+ 'Z' => [true, false],
120
+ '' => 'hogehoge' # no raise
121
+ }
122
+ patterns.each_pair do |key, pattern|
123
+ begin
124
+ @string_random[key] = pattern
125
+ @string_random.random_pattern(key)
126
+ rescue Exception
127
+ count += 1
128
+ end
129
+ end
130
+ assert_equal(patterns.keys.size - 1, count)
131
+
132
+ # No pollute other object
133
+ @other = StringRandom.new
134
+ assert_not_equal('n', @other.random_pattern('C'))
135
+ end
136
+
137
+ # StringRandom#random_pattern
138
+ def test_random_pattern_invalid
139
+ ['A', 'CZ1s', 'Hoge', '\n'].each do |pattern|
140
+ assert_raise(RuntimeError) { @string_random.random_pattern(pattern) }
141
+ end
142
+ end
143
+
144
+ # StringRandom.random_regex
145
+ def test_singleton_random_regex
146
+ patterns = ['\d\d\d',
147
+ '\w\w\w',
148
+ '[ABC][abc]',
149
+ '[012][345]',
150
+ '...',
151
+ '[a-z][0-9]',
152
+ '[aw-zX][123]',
153
+ '[a-z]{5}',
154
+ '0{80}',
155
+ '[a-f][nprt]\d{3}',
156
+ '\t\n\r\f\a\e',
157
+ '\S\S\S',
158
+ '\s\s\s',
159
+ '\w{5,10}',
160
+ '\w?',
161
+ '\w+',
162
+ '\w*',
163
+ '']
164
+
165
+ patterns.each do |pattern|
166
+ result = StringRandom.random_regex(pattern)
167
+ assert_match(/#{pattern}/, result, "#{result} is invalid: pattern #{pattern}")
168
+ end
169
+ end
170
+
171
+ # StringRandom.random_string
172
+ def test_singleton_random_string
173
+ assert_match(/\d/, StringRandom.random_string('n'))
174
+ assert_raise(RuntimeError) { StringRandom.random_string('0') }
175
+
176
+ # with optional lists
177
+ assert_equal('abc', StringRandom.random_string('012', ['a'], ['b'], ['c']))
178
+ assert_match(/[abc][def]/, StringRandom.random_string('01', ['a', 'b', 'c'], ['d', 'e', 'f']))
179
+ end
180
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shokkenki-support
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -113,6 +113,9 @@ files:
113
113
  - lib/shokkenki/term/string_term.rb
114
114
  - lib/shokkenki/term/term.rb
115
115
  - lib/shokkenki/term/term_factory.rb
116
+ - lib/shokkenki/term/ruby-string-random/lib/strrand.rb
117
+ - lib/shokkenki/term/ruby-string-random/README
118
+ - lib/shokkenki/term/ruby-string-random/test/test_strrand.rb
116
119
  homepage: http://github.com/brentsnook/shokkenki-support
117
120
  licenses:
118
121
  - GPL2
@@ -135,11 +138,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
138
  version: '0'
136
139
  segments:
137
140
  - 0
138
- hash: 328884102764703687
141
+ hash: 2074170128590300944
139
142
  requirements: []
140
143
  rubyforge_project:
141
144
  rubygems_version: 1.8.24
142
145
  signing_key:
143
146
  specification_version: 3
144
- summary: shokkenki-support-0.0.1
147
+ summary: shokkenki-support-0.0.2
145
148
  test_files: []