chars 0.1.1 → 0.2.3

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a22fd4d88e24c4f378880de5e324ac4acc4ff197c541baa1b840a8852d420afa
4
+ data.tar.gz: ad9c7a38b080490366aaf4142eb642224d551da165ddeedfb4fc1fd0e6bf0728
5
+ SHA512:
6
+ metadata.gz: 5886283079f3bfcf060facf0b0520a51f75066b0301a87750d262e1e4326fad164e541c9580aad1a3f86810430732b2e1933b2ccee26eda6667d0da2aaf2bf00
7
+ data.tar.gz: 0313dcedc0872cc15f84804bdea985bf726040b48d48018084800c8e07f4224267b5802df4da9d68c5ce79ff0239e4af7138db522fa8523647251524d51e6ba1
@@ -0,0 +1,4 @@
1
+ lib/**/*.rb
2
+ -
3
+ ChangeLog.md
4
+ LICENSE.txt
File without changes
@@ -0,0 +1,28 @@
1
+ name: CI
2
+
3
+ on: [ push, pull_request ]
4
+
5
+ jobs:
6
+ tests:
7
+ runs-on: ubuntu-latest
8
+ strategy:
9
+ fail-fast: false
10
+ matrix:
11
+ ruby:
12
+ - 2.4
13
+ - 2.5
14
+ - 2.6
15
+ - 2.7
16
+ - 3.0
17
+ - jruby
18
+ name: Ruby ${{ matrix.ruby }}
19
+ steps:
20
+ - uses: actions/checkout@v2
21
+ - name: Set up Ruby
22
+ uses: ruby/setup-ruby@v1
23
+ with:
24
+ ruby-version: ${{ matrix.ruby }}
25
+ - name: Install dependencies
26
+ run: bundle install --jobs 4 --retry 3
27
+ - name: Run tests
28
+ run: bundle exec rake test
@@ -0,0 +1,8 @@
1
+ /Gemfile.lock
2
+ /doc/
3
+ /pkg/
4
+ /vendor/bundle
5
+ .DS_Store
6
+ .yardoc
7
+ *.swp
8
+ *~
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
@@ -0,0 +1 @@
1
+ --markup markdown --title 'Chars Documentation' --protected --quiet
@@ -0,0 +1,68 @@
1
+ ### 0.2.3 / 2020-12-25
2
+
3
+ * Change {Chars::CharSet} to inherit from `Set`, instead of `SortedSet`.
4
+
5
+ ### 0.2.2 / 2012-05-28
6
+
7
+ * {Chars::CharSet#initialize} now raises a TypeError when given arguments
8
+ that were neither a `String`, `Integer` or `Enumerable`.
9
+ * Allow {Chars::CharSet#strings_in} to yield results as they are found.
10
+ * Improved the performance of {Chars::CharSet#strings_in} when operating on
11
+ small Strings.
12
+ * Replaced ore-tasks with
13
+ [rubygems-tasks](https://github.com/postmodern/rubygems-tasks#readme).
14
+
15
+ ### 0.2.1 / 2011-06-22
16
+
17
+ * Added {Chars::CharSet.[]}
18
+ * Added {Chars::CharSet#<<}.
19
+ * Added {Chars::CharSet#byte_to_char}.
20
+ * Added {Chars::CharSet#char_to_byte}.
21
+ * Added a cache of characters of the bytes within {Chars::CharSet}.
22
+ * Use `String#each_char` to distinguish Unicode from ASCII.
23
+
24
+ ### 0.2.0 / 2010-10-27
25
+
26
+ * Make sure all enumerable methods in {Chars::CharSet} return an
27
+ `Enumerator` object if no block is given.
28
+
29
+ ### 0.1.2 / 2009-09-21
30
+
31
+ * Require Hoe >= 2.3.3.
32
+ * Require YARD >= 0.2.3.5.
33
+ * Require RSpec >= 1.2.8.
34
+ * Added Chars.visibile and Chars::VISIBLE (thanks flatline).
35
+ * Added CharSet#random_distinct_bytes, CharSet#random_distinct_chars,
36
+ and CharSet#random_distinct_string (thanks flatline).
37
+ * Use 'hoe/signing' for signed RubyGems.
38
+ * Moved to YARD based documentation.
39
+ * All specs now pass on JRuby 1.3.1.
40
+
41
+ ### 0.1.1 / 2009-04-01
42
+
43
+ * Renamed CharSet#=~ to CharSet#===.
44
+ * Added an alias from CharSet#=~ to CharSet#===.
45
+
46
+ ### 0.1.0 / 2009-03-16
47
+
48
+ * Initial release.
49
+ * Provides character sets for:
50
+ * Numeric
51
+ * Octal
52
+ * Uppercase Hexadecimal
53
+ * Lowercase Hexadecimal
54
+ * Hexadecimal
55
+ * Uppercase Alpha
56
+ * Lowercase Alpha
57
+ * Alpha
58
+ * Alpha-numeric
59
+ * Punctuation
60
+ * Symbols
61
+ * Space
62
+ * Printable
63
+ * Control
64
+ * ASCII
65
+ * Provides convenience methods for testing wether a String or Integer
66
+ belongs to a certain character set.
67
+ * Supports random text generation using specific character sets.
68
+
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'rake'
7
+ gem 'rubygems-tasks', '~> 0.2'
8
+ gem 'rspec', '~> 3.0'
9
+ gem 'kramdown'
10
+ gem 'yard', '~> 0.9'
11
+ end
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2009-2012 Hal Brodigan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,98 @@
1
+ # Chars
2
+
3
+ * [Source](https://github.com/postmodern/chars#readme)
4
+ * [Issues](https://github.com/postmodern/chars/issues)
5
+ * [Documentation](http://rubydoc.info/gems/chars)
6
+ * [Email](mailto:postmodern.mod3 at gmail.com)
7
+
8
+ ## Description
9
+
10
+ Chars is a Ruby library for working with various character sets,
11
+ recognizing text and generating random text from specific character sets.
12
+
13
+ ## Features
14
+
15
+ * Provides character sets for:
16
+ * Numeric ('0' - '9')
17
+ * Octal ('0' - '7')
18
+ * Uppercase Hexadecimal ('0' - '9', 'A' - 'F')
19
+ * Lowercase Hexadecimal ('0' - '9', 'a' - 'f')
20
+ * Hexadecimal ('0' - '9', 'a' - 'f', 'A' - 'F')
21
+ * Uppercase Alpha ('A' - 'Z')
22
+ * Lowercase Alpha ('a' - 'z')
23
+ * Alpha ('a' - 'z', 'A' - 'Z')
24
+ * Alpha-numeric ('0' - '9', 'a' - 'z', 'A' - 'Z')
25
+ * Punctuation (' ', '\'', '"', '`', ',', ';', ':', '~', '-', '(', ')',
26
+ '[', ']', '{', '}', '.', '?', '!')
27
+ * Symbols (' ', '\'', '"', '`', ',', ';', ':', '~', '-', '(', ')',
28
+ '[', ']', '{', '}', '.', '?', '!', '@', '#', '$', '%', '^', '&', '*',
29
+ '_', '+', '=', '|', '\\', '<', '>', '/')
30
+ * Space (' ', '\f', '\n', '\r', '\t', '\v')
31
+ * Visible ('0' - '9', 'a' - 'z', 'A' - 'Z', '\'', '"', '`', ',',
32
+ ';', ':', '~', '-', '(', ')', '[', ']', '{', '}', '.', '?', '!', '@',
33
+ '#', '$', '%', '^', '&', '*', '_', '+', '=', '|', '\\', '<', '>', '/',)
34
+ * Printable ('0' - '9', 'a' - 'z', 'A' - 'Z', ' ', '\'', '"', '`', ',',
35
+ ';', ':', '~', '-', '(', ')', '[', ']', '{', '}', '.', '?', '!', '@',
36
+ '#', '$', '%', '^', '&', '*', '_', '+', '=', '|', '\\', '<', '>', '/',
37
+ '\f', '\n', '\r', '\t', '\v')
38
+ * Control ('\x00' - '\x1f', '\x7f')
39
+ * Signed ASCII ('\x00' - '\x7f')
40
+ * ASCII ('\x00' - '\xff')
41
+
42
+ ## Examples
43
+
44
+ Determine whether a byte belongs to a character set:
45
+
46
+ 0x41.alpha?
47
+ # => true
48
+
49
+ Determine whether a String belongs to a character set:
50
+
51
+ "22e1c0".hex?
52
+ # => true
53
+
54
+ Find all sub-strings that belong to a character set within a String:
55
+
56
+ ls = File.read('/bin/ls')
57
+ Chars.printable.strings_in(ls)
58
+ # => ["/lib64/ld-linux-x86-64.so.2", "KIq/", "5J~!", "%L~!", ...]
59
+
60
+ Return a random character from the set of all characters:
61
+
62
+ Chars.all.random_char
63
+ # => "\x94"
64
+
65
+ Return a random Array of characters from the alpha-numeric character set:
66
+
67
+ Chars.alpha_numeric.random_chars(10)
68
+ # => ["Q", "N", "S", "4", "x", "z", "3", "M", "F", "F"]
69
+
70
+ Return a random Array of a random length of unique characters from the
71
+ visible character set:
72
+
73
+ Chars.visible.random_distinct_chars(1..10)
74
+ # => ["S", "l", "o", "8", "'", "q"]
75
+
76
+ Return a random String from the set of all characters:
77
+
78
+ Chars.all.random_string(10)
79
+ # => "\xc2h\xad\xccm7\x1e6J\x13"
80
+
81
+ Return a random String with a random length between 5 and 10, from the
82
+ set of space characters:
83
+
84
+ Chars.space.random_string(5..10)
85
+ # => "\r\v\n\t\n\f"
86
+
87
+ ## Requirements
88
+
89
+ * [ruby](http://www.ruby-lang.org/) >= 1.8.7
90
+
91
+ ## Install
92
+
93
+ $ sudo gem install chars
94
+
95
+ ## License
96
+
97
+ See {file:LICENSE.txt} for license information.
98
+
data/Rakefile CHANGED
@@ -1,14 +1,12 @@
1
- # -*- ruby -*-
2
-
3
1
  require 'rubygems'
4
- require 'hoe'
5
- require './tasks/spec.rb'
6
- require './lib/chars/version.rb'
7
2
 
8
- Hoe.new('chars', Chars::VERSION) do |p|
9
- p.rubyforge_name = 'chars'
10
- p.developer('Postmodern','postmodern.mod3@gmail.com')
11
- p.remote_rdoc_dir = '/'
12
- end
3
+ require 'rubygems/tasks'
4
+ Gem::Tasks.new
5
+
6
+ require 'rspec/core/rake_task'
7
+ RSpec::Core::RakeTask.new
8
+ task :test => :spec
9
+ task :default => :spec
13
10
 
14
- # vim: syntax=Ruby
11
+ require 'yard'
12
+ YARD::Rake::YardocTask.new
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__),'..','lib'))
4
+
5
+ require 'chars'
6
+ require 'benchmark'
7
+
8
+ CHARSET = Chars::ALPHA_NUMERIC
9
+ N = 1_000_000
10
+ STRING = ('A' * N) + '!'
11
+ ENUM = (['A', 0x42] * (N / 2)) << '!'
12
+
13
+ Benchmark.bm(12) do |b|
14
+ b.report('String') { CHARSET === STRING }
15
+ b.report('Enumerable') { CHARSET === ENUM }
16
+ end
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__),'..','lib'))
4
+
5
+ require 'chars'
6
+ require 'benchmark'
7
+
8
+ CHARSET = Chars::ALPHA_NUMERIC
9
+ STRING = File.open('/usr/bin/openssl','rb') do |file|
10
+ file.read
11
+ end
12
+
13
+ Benchmark.bm(24) do |b|
14
+ b.report('strings_in') do
15
+ CHARSET.strings_in(STRING) { |offset,string| }
16
+ end
17
+
18
+ (5..20).step(5) do |n|
19
+ b.report("strings_in (length=#{n})") do
20
+ CHARSET.strings_in(STRING, :length => n) { |offset,string| }
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+
3
+ require 'yaml'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gemspec = YAML.load_file('gemspec.yml')
7
+
8
+ gem.name = gemspec.fetch('name')
9
+ gem.version = gemspec.fetch('version') do
10
+ lib_dir = File.join(File.dirname(__FILE__),'lib')
11
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
12
+
13
+ require 'chars/version'
14
+ Chars::VERSION
15
+ end
16
+
17
+ gem.summary = gemspec['summary']
18
+ gem.description = gemspec['description']
19
+ gem.licenses = Array(gemspec['license'])
20
+ gem.authors = Array(gemspec['authors'])
21
+ gem.email = gemspec['email']
22
+ gem.homepage = gemspec['homepage']
23
+
24
+ glob = lambda { |patterns| gem.files & Dir[*patterns] }
25
+
26
+ gem.files = `git ls-files`.split($/)
27
+ gem.files = glob[gemspec['files']] if gemspec['files']
28
+
29
+ gem.executables = gemspec.fetch('executables') do
30
+ glob['bin/*'].map { |path| File.basename(path) }
31
+ end
32
+ gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
33
+
34
+ gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
35
+ gem.test_files = glob[gemspec['test_files'] || '{test/{**/}*_test.rb']
36
+ gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
37
+
38
+ gem.require_paths = Array(gemspec.fetch('require_paths') {
39
+ %w[ext lib].select { |dir| File.directory?(dir) }
40
+ })
41
+
42
+ gem.requirements = gemspec['requirements']
43
+ gem.required_ruby_version = gemspec['required_ruby_version']
44
+ gem.required_rubygems_version = gemspec['required_rubygems_version']
45
+ gem.post_install_message = gemspec['post_install_message']
46
+
47
+ split = lambda { |string| string.split(/,\s*/) }
48
+
49
+ if gemspec['dependencies']
50
+ gemspec['dependencies'].each do |name,versions|
51
+ gem.add_dependency(name,split[versions])
52
+ end
53
+ end
54
+
55
+ if gemspec['development_dependencies']
56
+ gemspec['development_dependencies'].each do |name,versions|
57
+ gem.add_development_dependency(name,split[versions])
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,16 @@
1
+ name: chars
2
+ summary: A Ruby library for working with various character sets
3
+ description:
4
+ Chars is a Ruby library for working with various character sets,
5
+ recognizing text and generating random text from specific character sets.
6
+
7
+ license: MIT
8
+ homepage: https://github.com/postmodern/chars#readme
9
+ authors: Postmodern
10
+ email: postmodern.mod3@gmail.com
11
+ has_yard: true
12
+
13
+ required_ruby_version: ">= 1.8.7"
14
+
15
+ development_dependencies:
16
+ bundler: ~> 2.0
@@ -1,25 +1,75 @@
1
1
  require 'set'
2
2
 
3
3
  module Chars
4
- class CharSet < SortedSet
4
+ class CharSet < Set
5
5
 
6
6
  #
7
- # Creates a new CharSet object with the given _chars_.
7
+ # Creates a new CharSet object.
8
8
  #
9
- def initialize(*chars)
9
+ # @param [Array<String, Integer, Enumerable>] arguments
10
+ # The chars for the CharSet.
11
+ #
12
+ # @raise [TypeError]
13
+ # One of the arguments was not a {String}, {Integer} or `Enumerable`.
14
+ #
15
+ def initialize(*arguments)
10
16
  super()
11
17
 
12
- merge_chars = lambda { |element|
13
- if element.kind_of?(String)
14
- element.each_byte(&merge_chars)
15
- elsif element.kind_of?(Integer)
16
- self << element
17
- elsif element.kind_of?(Enumerable)
18
- element.each(&merge_chars)
18
+ @chars = Hash.new { |hash,key| hash[key] = byte_to_char(key) }
19
+
20
+ arguments.each do |subset|
21
+ case subset
22
+ when String, Integer
23
+ self << subset
24
+ when Enumerable
25
+ subset.each { |char| self << char }
26
+ else
27
+ raise(TypeError,"arguments must be a String, Integer or Enumerable")
28
+ end
29
+ end
30
+ end
31
+
32
+ #
33
+ # Creates a new character set.
34
+ #
35
+ # @see #initialize
36
+ #
37
+ # @since 0.2.1
38
+ #
39
+ def self.[](*arguments)
40
+ new(*arguments)
41
+ end
42
+
43
+ #
44
+ # Adds a character to the set.
45
+ #
46
+ # @param [String, Integer] other
47
+ # The character(s) or byte to add.
48
+ #
49
+ # @return [CharSet]
50
+ # The modified character set.
51
+ #
52
+ # @raise [TypeError]
53
+ # The argument was not a {String} or {Integer}.
54
+ #
55
+ # @since 0.2.1
56
+ #
57
+ def <<(other)
58
+ case other
59
+ when String
60
+ other.each_char do |char|
61
+ byte = char_to_byte(char)
62
+
63
+ @chars[byte] = char
64
+ super(byte)
19
65
  end
20
- }
21
66
 
22
- merge_chars.call(chars)
67
+ return self
68
+ when Integer
69
+ super(other)
70
+ else
71
+ raise(TypeError,"can only append Strings and Integers")
72
+ end
23
73
  end
24
74
 
25
75
  alias include_byte? include?
@@ -29,181 +79,361 @@ module Chars
29
79
  alias map_bytes map
30
80
 
31
81
  #
32
- # Returns +true+ if the character set includes the specified _char_,
33
- # returns +false+ otherwise.
82
+ # Determines if a character is contained within the character set.
83
+ #
84
+ # @param [String] char
85
+ # The character to search for.
86
+ #
87
+ # @return [Boolean]
88
+ # Specifies whether the character is contained within the
89
+ # character set.
34
90
  #
35
91
  def include_char?(char)
36
- return false unless char.respond_to?(:each_byte)
37
-
38
- char.each_byte do |b|
39
- return include?(b)
92
+ unless char.empty?
93
+ @chars.has_value?(char) || include_byte?(char_to_byte(char))
94
+ else
95
+ false
40
96
  end
41
97
  end
42
98
 
43
99
  #
44
- # Returns all the characters within the character set as Strings.
100
+ # The characters within the character set.
101
+ #
102
+ # @return [Array<String>]
103
+ # All the characters within the character set.
45
104
  #
46
105
  def chars
47
- map { |b| b.chr }
106
+ map { |byte| @chars[byte] }
48
107
  end
49
108
 
50
109
  #
51
- # Iterates over every character within the character set, passing
52
- # each to the given _block_.
110
+ # Iterates over every character within the character set.
111
+ #
112
+ # @yield [char]
113
+ # If a block is given, it will be passed each character in the
114
+ # character set.
53
115
  #
54
- def each_char(&block)
55
- each { |b| block.call(b.chr) } if block
116
+ # @yieldparam [String] char
117
+ # Each character in the character set.
118
+ #
119
+ # @return [Enumerator]
120
+ # If no block is given, an enumerator object will be returned.
121
+ #
122
+ def each_char
123
+ return enum_for(__method__) unless block_given?
124
+
125
+ each { |byte| yield @chars[byte] }
56
126
  end
57
127
 
58
128
  #
59
- # Selects an Array of characters from the character set that match
60
- # the given _block_.
129
+ # Selects characters from the character set.
130
+ #
131
+ # @yield [char]
132
+ # If a block is given, it will be used to select the characters
133
+ # from the character set.
134
+ #
135
+ # @yieldparam [String] char
136
+ # The character to select or reject.
137
+ #
138
+ # @return [Array<String>]
139
+ # The selected characters from the character set.
61
140
  #
62
141
  def select_chars(&block)
63
- chars.select(&block)
142
+ each_char.select(&block)
64
143
  end
65
144
 
66
145
  #
67
- # Maps the characters of the character set using the given _block_.
146
+ # Maps the characters of the character set.
147
+ #
148
+ # @yield [char]
149
+ # The given block will be used to transform the characters within
150
+ # the character set.
151
+ #
152
+ # @yieldparam [String] char
153
+ # Each character in the character set.
154
+ #
155
+ # @return [Array<String>]
156
+ # The mapped characters of the character set.
68
157
  #
69
158
  def map_chars(&block)
70
- chars.map(&block)
159
+ each_char.map(&block)
71
160
  end
72
161
 
73
162
  #
74
- # Returns a random byte from the character set.
163
+ # @return [Integer]
164
+ # A random byte from the character set.
75
165
  #
76
166
  def random_byte
77
167
  self.entries[rand(self.length)]
78
168
  end
79
169
 
80
170
  #
81
- # Returns a random char from the character set.
171
+ # @return [String]
172
+ # A random char from the character set.
82
173
  #
83
174
  def random_char
84
- random_byte.chr
175
+ @chars[random_byte]
85
176
  end
86
177
 
87
178
  #
88
- # Pass a random byte to the specified _block_, _n_ times.
179
+ # Pass random bytes to a given block.
180
+ #
181
+ # @param [Integer] n
182
+ # Specifies how many times to pass a random byte to the block.
183
+ #
184
+ # @yield [byte]
185
+ # The block will receive the random bytes.
186
+ #
187
+ # @yieldparam [Integer] byte
188
+ # The random byte from the character set.
189
+ #
190
+ # @return [Enumerator]
191
+ # If no block is given, an enumerator object will be returned.
89
192
  #
90
193
  def each_random_byte(n,&block)
91
- n.times { block.call(random_byte) }
194
+ return enum_for(__method__,n) unless block_given?
195
+
196
+ n.times { yield random_byte }
197
+ return nil
92
198
  end
93
199
 
94
200
  #
95
- # Pass a random character to the specified _block_, _n_ times.
201
+ # Pass random characters to a given block.
202
+ #
203
+ # @param [Integer] n
204
+ # Specifies how many times to pass a random character to the block.
205
+ #
206
+ # @yield [char]
207
+ # The block will receive the random characters.
208
+ #
209
+ # @yieldparam [String] char
210
+ # The random character from the character set.
211
+ #
212
+ # @return [Enumerator]
213
+ # If no block is given, an enumerator object will be returned.
96
214
  #
97
215
  def each_random_char(n,&block)
98
- each_random_byte(n) { |b| block.call(b.chr) }
216
+ return enum_for(__method__,n) unless block_given?
217
+
218
+ each_random_byte(n) { |byte| yield @chars[byte] }
99
219
  end
100
220
 
101
221
  #
102
- # Returns an Array of the specified _length_ containing
103
- # random bytes from the character set. The specified _length_ may
104
- # be an Integer, Array or a Range of lengths.
222
+ # Creates an Array of random bytes from the character set.
223
+ #
224
+ # @param [Integer, Array, Range] length
225
+ # The length of the Array of random bytes.
226
+ #
227
+ # @return [Array<Integer>]
228
+ # The randomly selected bytes.
105
229
  #
106
230
  def random_bytes(length)
107
231
  if (length.kind_of?(Array) || length.kind_of?(Range))
108
- return Array.new(length.sort_by { rand }.first) { random_byte }
232
+ Array.new(length.sort_by { rand }.first) { random_byte }
109
233
  else
110
- return Array.new(length) { random_byte }
234
+ Array.new(length) { random_byte }
111
235
  end
112
236
  end
113
237
 
114
238
  #
115
- # Returns an Array of the specified _length_ containing
116
- # random characters from the character set. The specified _length_
117
- # may be an Integer, Array or a Range of lengths.
239
+ # Creates an Array of random non-repeating bytes from the character set.
240
+ #
241
+ # @param [Integer, Array, Range] length
242
+ # The length of the Array of random non-repeating bytes.
243
+ #
244
+ # @return [Array<Integer>]
245
+ # The randomly selected non-repeating bytes.
246
+ #
247
+ def random_distinct_bytes(length)
248
+ if (length.kind_of?(Array) || length.kind_of?(Range))
249
+ self.entries.sort_by { rand }.slice(0...(length.sort_by { rand }.first))
250
+ else
251
+ self.entries.sort_by { rand }.slice(0...length)
252
+ end
253
+ end
254
+
255
+ #
256
+ # Creates an Array of random characters from the character set.
257
+ #
258
+ # @param [Integer, Array, Range] length
259
+ # The length of the Array of random characters.
260
+ #
261
+ # @return [Array<String>]
262
+ # The randomly selected characters.
118
263
  #
119
264
  def random_chars(length)
120
- random_bytes(length).map { |b| b.chr }
265
+ random_bytes(length).map { |byte| @chars[byte] }
121
266
  end
122
267
 
123
268
  #
124
- # Returns a String of the specified _length_ containing
125
- # random characters from the character set.
269
+ # Creates a String containing randomly selected characters from the
270
+ # character set.
271
+ #
272
+ # @param [Integer, Array, Range] length
273
+ # The length of the String of random characters.
274
+ #
275
+ # @return [String]
276
+ # The String of randomly selected characters.
277
+ #
278
+ # @see random_chars
126
279
  #
127
280
  def random_string(length)
128
281
  random_chars(length).join
129
282
  end
130
283
 
131
284
  #
132
- # Finds sub-strings within the specified _data_ that are part of the
133
- # character set, using the given _options_.
285
+ # Creates an Array of random non-repeating characters from the
286
+ # character set.
287
+ #
288
+ # @param [Integer, Array, Range] length
289
+ # The length of the Array of random non-repeating characters.
134
290
  #
135
- # _options_ may contain the following keys:
136
- # <tt>:length</tt>:: The minimum length of matching sub-strings
137
- # within the _data_. Defaults to 4, if not
138
- # specified.
139
- # <tt>:offsets</tt>:: Specifies wether to return a Hash of the
140
- # offsets within the _data_ and the matched
141
- # sub-strings. If not specified a simple
142
- # Array will be returned of the matched
143
- # sub-strings.
291
+ # @return [Array<Integer>]
292
+ # The randomly selected non-repeating characters.
144
293
  #
145
- def strings_in(data,options={})
146
- min_length = (options[:length] || 4)
294
+ def random_distinct_chars(length)
295
+ random_distinct_bytes(length).map { |byte| @chars[byte] }
296
+ end
147
297
 
148
- if options[:offsets]
149
- found = {}
150
- found_substring = lambda { |offset,substring|
151
- found[offset] = substring
152
- }
153
- else
154
- found = []
155
- found_substring = lambda { |offset,substring|
156
- found << substring
157
- }
298
+ #
299
+ # Creates a String containing randomly selected non-repeating
300
+ # characters from the character set.
301
+ #
302
+ # @param [Integer, Array, Range] length
303
+ # The length of the String of random non-repeating characters.
304
+ #
305
+ # @return [String]
306
+ # The String of randomly selected non-repeating characters.
307
+ #
308
+ # @see random_distinct_chars
309
+ #
310
+ def random_distinct_string(length)
311
+ random_distinct_chars(length).join
312
+ end
313
+
314
+ #
315
+ # Finds sub-strings within given data that are made of characters within
316
+ # the character set.
317
+ #
318
+ # @param [String] data
319
+ # The data to find sub-strings within.
320
+ #
321
+ # @param [Hash] options
322
+ # Additional options.
323
+ #
324
+ # @option options [Integer] :length (4)
325
+ # The minimum length of sub-strings found within the given data.
326
+ #
327
+ # @option options [Boolean] :offsets (false)
328
+ # Specifies whether to return a Hash of offsets and matched
329
+ # sub-strings within the data, or to just return the matched
330
+ # sub-strings themselves.
331
+ #
332
+ # @yield [match,(index)]
333
+ # The given block will be passed every matched sub-string, and the
334
+ # optional index.
335
+ #
336
+ # @yield [String] match
337
+ # A sub-string containing the characters from the character set.
338
+ #
339
+ # @yield [Integer] index
340
+ # The index the sub-string was found at.
341
+ #
342
+ # @return [Array, Hash]
343
+ # If no block is given, an Array or Hash of sub-strings is returned.
344
+ #
345
+ def strings_in(data,options={},&block)
346
+ unless block
347
+ if options[:offsets]
348
+ found = {}
349
+ block = lambda { |offset,substring| found[offset] = substring }
350
+ else
351
+ found = []
352
+ block = lambda { |substring| found << substring }
353
+ end
354
+
355
+ strings_in(data,options,&block)
356
+ return found
158
357
  end
159
358
 
160
- return found if data.length < min_length
359
+ min_length = options.fetch(:length,4)
360
+ return if data.length < min_length
161
361
 
162
362
  index = 0
163
363
 
164
364
  while index <= (data.length - min_length)
165
- if self === data[index...(index + min_length)]
365
+ if self === data[index,min_length]
166
366
  sub_index = (index + min_length)
167
367
 
168
- while self.include_char?(data[sub_index..sub_index])
368
+ while self.include_char?(data[sub_index,1])
169
369
  sub_index += 1
170
370
  end
171
371
 
172
- found_substring.call(index,data[index...sub_index])
372
+ match = data[index...sub_index]
373
+
374
+ case block.arity
375
+ when 2
376
+ yield match, index
377
+ else
378
+ yield match
379
+ end
380
+
173
381
  index = sub_index
174
382
  else
175
383
  index += 1
176
384
  end
177
385
  end
178
-
179
- return found
180
386
  end
181
387
 
182
388
  #
183
- # Creates a new CharSet object containing the both the characters
184
- # of the character set and the specified _other_set_.
389
+ # Creates a new CharSet object by unioning the character set with
390
+ # another character set.
391
+ #
392
+ # @param [CharSet, Array, Range] set
393
+ # The other character set to union with.
185
394
  #
186
- def |(other_set)
187
- super(CharSet.new(other_set))
395
+ # @return [CharSet]
396
+ # The unioned character sets.
397
+ #
398
+ def |(set)
399
+ set = CharSet.new(set) unless set.kind_of?(CharSet)
400
+
401
+ return super(set)
188
402
  end
189
403
 
190
404
  alias + |
191
405
 
192
406
  #
193
- # Returns +true+ if all of the bytes within the specified _string_
194
- # are included in the character set, returns +false+ otherwise.
407
+ # Compares the bytes within a given string with the bytes of the
408
+ # character set.
195
409
  #
410
+ # @param [String, Enumerable] other
411
+ # The string to compare with the character set.
412
+ #
413
+ # @return [Boolean]
414
+ # Specifies whether all of the bytes within the given string are
415
+ # included in the character set.
416
+ #
417
+ # @example
196
418
  # Chars.alpha === "hello"
197
419
  # # => true
198
420
  #
199
- def ===(string)
200
- return false unless string.respond_to?(:each_byte)
201
-
202
- string.each_byte do |b|
203
- return false unless include?(b)
421
+ def ===(other)
422
+ case other
423
+ when String
424
+ other.each_char.all? { |char| include_char?(char) }
425
+ when Enumerable
426
+ other.all? do |element|
427
+ case element
428
+ when String
429
+ include_char?(element)
430
+ when Integer
431
+ include_byte?(element)
432
+ end
433
+ end
434
+ else
435
+ false
204
436
  end
205
-
206
- return true
207
437
  end
208
438
 
209
439
  alias =~ ===
@@ -211,20 +441,87 @@ module Chars
211
441
  #
212
442
  # Inspects the character set.
213
443
  #
444
+ # @return [String]
445
+ # The inspected character set.
446
+ #
214
447
  def inspect
215
- "#<#{self.class.name}: {" + map { |b|
216
- case b
448
+ "#<#{self.class.name}: {" + map { |byte|
449
+ case byte
217
450
  when (0x07..0x0d), (0x20..0x7e)
218
- b.chr.dump
451
+ @chars[byte].dump
219
452
  when 0x00
220
453
  # sly hack to make char-sets more friendly
221
454
  # to us C programmers
222
455
  '"\0"'
223
456
  else
224
- "0x%02x" % b
457
+ "0x%02x" % byte
225
458
  end
226
459
  }.join(', ') + "}>"
227
460
  end
228
461
 
462
+ protected
463
+
464
+ if RUBY_VERSION > '1.9.'
465
+ #
466
+ # Converts a byte to a character.
467
+ #
468
+ # @param [Integer] byte
469
+ # The byte to convert.
470
+ #
471
+ # @return [String]
472
+ # The character.
473
+ #
474
+ # @since 0.2.1
475
+ #
476
+ def byte_to_char(byte)
477
+ byte.chr(Encoding::UTF_8)
478
+ end
479
+
480
+ #
481
+ # Converts a character to a byte.
482
+ #
483
+ # @param [String] char
484
+ # The character to convert.
485
+ #
486
+ # @return [Integer]
487
+ # The byte.
488
+ #
489
+ # @since 0.2.1
490
+ #
491
+ def char_to_byte(char)
492
+ char.ord
493
+ end
494
+ else
495
+ #
496
+ # Converts a byte to a character.
497
+ #
498
+ # @param [Integer] byte
499
+ # The byte to convert.
500
+ #
501
+ # @return [String]
502
+ # The character.
503
+ #
504
+ # @since 0.2.1
505
+ #
506
+ def byte_to_char(byte)
507
+ byte.chr
508
+ end
509
+
510
+ #
511
+ # Converts a character to a byte.
512
+ #
513
+ # @param [String] char
514
+ # The character to convert.
515
+ #
516
+ # @return [Integer]
517
+ # The byte.
518
+ #
519
+ # @since 0.2.1
520
+ #
521
+ def char_to_byte(char)
522
+ char[0]
523
+ end
524
+ end
525
+
229
526
  end
230
527
  end