ronin 0.1.0 → 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.
Files changed (50) hide show
  1. data/History.txt +13 -0
  2. data/Manifest.txt +19 -17
  3. data/README.txt +9 -9
  4. data/Rakefile +1 -1
  5. data/bin/ronin +2 -2
  6. data/lib/ronin/author.rb +1 -1
  7. data/lib/ronin/cache/extension.rb +4 -12
  8. data/lib/ronin/cache/extension_cache.rb +1 -3
  9. data/lib/ronin/cache/overlay.rb +3 -3
  10. data/lib/ronin/cache/overlay_cache.rb +21 -15
  11. data/lib/ronin/chars/char_set.rb +6 -12
  12. data/lib/ronin/code/reference.rb +142 -0
  13. data/lib/ronin/code/symbol_table.rb +90 -0
  14. data/lib/ronin/context.rb +1 -1
  15. data/lib/ronin/database.rb +12 -3
  16. data/lib/ronin/extensions/string.rb +49 -0
  17. data/lib/ronin/formatting/extensions/text/string.rb +10 -5
  18. data/lib/ronin/object_context.rb +3 -9
  19. data/lib/ronin/pending_context.rb +8 -0
  20. data/lib/ronin/platform.rb +2 -2
  21. data/lib/ronin/product.rb +2 -2
  22. data/lib/ronin/program/command.rb +203 -0
  23. data/lib/ronin/program/commands/add.rb +71 -0
  24. data/lib/ronin/{runner/program → program}/commands/help.rb +14 -16
  25. data/lib/ronin/program/commands/install.rb +64 -0
  26. data/lib/ronin/program/commands/list.rb +79 -0
  27. data/lib/ronin/{runner/program/commands/update.rb → program/commands/remove.rb} +18 -18
  28. data/lib/ronin/{runner/program/commands/remove.rb → program/commands/uninstall.rb} +17 -19
  29. data/lib/ronin/{runner/program/commands/uninstall.rb → program/commands/update.rb} +17 -21
  30. data/lib/ronin/{runner/program → program}/commands.rb +9 -9
  31. data/lib/ronin/{runner/program → program}/exceptions/unknown_command.rb +2 -4
  32. data/lib/ronin/{runner.rb → program/exceptions.rb} +1 -1
  33. data/lib/ronin/{runner/program → program}/options.rb +4 -8
  34. data/lib/ronin/program/program.rb +168 -0
  35. data/lib/ronin/{runner/program/exceptions.rb → program.rb} +2 -1
  36. data/lib/ronin/rpc/client.rb +1 -1
  37. data/lib/ronin/version.rb +1 -1
  38. data/spec/code/reference_spec.rb +72 -0
  39. data/spec/code/symbol_table_spec.rb +35 -0
  40. data/spec/extensions/string_spec.rb +88 -4
  41. data/spec/formatting/text_spec.rb +2 -2
  42. data/spec/helpers.rb +0 -0
  43. metadata +25 -23
  44. data/lib/ronin/runner/program/command.rb +0 -204
  45. data/lib/ronin/runner/program/commands/add.rb +0 -73
  46. data/lib/ronin/runner/program/commands/install.rb +0 -65
  47. data/lib/ronin/runner/program/commands/list.rb +0 -81
  48. data/lib/ronin/runner/program/program.rb +0 -175
  49. data/lib/ronin/runner/program/runner.rb +0 -35
  50. data/lib/ronin/runner/program.rb +0 -26
data/History.txt CHANGED
@@ -1,3 +1,16 @@
1
+ === 0.1.1 / 2008-10-26
2
+
3
+ * Depend on the newly renamed reverse-require (>= 0.1.2) gem.
4
+ * Added Code::SymbolTable for DSLs to make use of.
5
+ * Added String#common_prefix, String#common_postfix and
6
+ String#uncommon_substring, which will be useful when testing for
7
+ successful injections.
8
+ * Added DataMapper column indexes to Author.name, Product.name, Platform.os
9
+ and Platform.version.
10
+ * Renamed String#rand_case to String#random_case.
11
+ * Removed the Runner namespace, renaming the Runner::Program namespace to
12
+ Ronin::Program.
13
+
1
14
  === 0.1.0 / 2008-09-28
2
15
 
3
16
  * Changed how Sessions are setup.
data/Manifest.txt CHANGED
@@ -83,6 +83,8 @@ lib/ronin/network/telnet.rb
83
83
  lib/ronin/network/http.rb
84
84
  lib/ronin/network/http/exceptions.rb
85
85
  lib/ronin/network/http/exceptions/unknown_request.rb
86
+ lib/ronin/code/reference.rb
87
+ lib/ronin/code/symbol_table.rb
86
88
  lib/ronin/rpc.rb
87
89
  lib/ronin/rpc/exceptions.rb
88
90
  lib/ronin/rpc/exceptions/not_implemented.rb
@@ -135,26 +137,24 @@ lib/ronin/cache/extension.rb
135
137
  lib/ronin/cache/ronin.rb
136
138
  lib/ronin/console.rb
137
139
  lib/ronin/shell.rb
138
- lib/ronin/runner.rb
139
- lib/ronin/runner/program.rb
140
- lib/ronin/runner/program/exceptions.rb
141
- lib/ronin/runner/program/exceptions/unknown_command.rb
142
- lib/ronin/runner/program/command.rb
143
- lib/ronin/runner/program/options.rb
144
- lib/ronin/runner/program/commands.rb
145
- lib/ronin/runner/program/commands/add.rb
146
- lib/ronin/runner/program/commands/install.rb
147
- lib/ronin/runner/program/commands/list.rb
148
- lib/ronin/runner/program/commands/update.rb
149
- lib/ronin/runner/program/commands/remove.rb
150
- lib/ronin/runner/program/commands/uninstall.rb
151
- lib/ronin/runner/program/commands/help.rb
152
- lib/ronin/runner/program/program.rb
153
- lib/ronin/runner/program/runner.rb
140
+ lib/ronin/program.rb
141
+ lib/ronin/program/exceptions.rb
142
+ lib/ronin/program/exceptions/unknown_command.rb
143
+ lib/ronin/program/command.rb
144
+ lib/ronin/program/options.rb
145
+ lib/ronin/program/commands.rb
146
+ lib/ronin/program/commands/add.rb
147
+ lib/ronin/program/commands/install.rb
148
+ lib/ronin/program/commands/list.rb
149
+ lib/ronin/program/commands/update.rb
150
+ lib/ronin/program/commands/remove.rb
151
+ lib/ronin/program/commands/uninstall.rb
152
+ lib/ronin/program/commands/help.rb
153
+ lib/ronin/program/program.rb
154
154
  lib/ronin/ronin.rb
155
155
  lib/ronin/version.rb
156
156
  tasks/spec.rb
157
- spec/helpers/
157
+ spec/helpers.rb
158
158
  spec/spec_helper.rb
159
159
  spec/arch_spec.rb
160
160
  spec/author_spec.rb
@@ -173,6 +173,8 @@ spec/formatting/digest_spec.rb
173
173
  spec/formatting/html_spec.rb
174
174
  spec/formatting/http_spec.rb
175
175
  spec/formatting/text_spec.rb
176
+ spec/code/reference_spec.rb
177
+ spec/code/symbol_table_spec.rb
176
178
  spec/license_spec.rb
177
179
  spec/path_spec.rb
178
180
  spec/platform_spec.rb
data/README.txt CHANGED
@@ -94,16 +94,16 @@ of Ronin.
94
94
  == REQUIREMENTS:
95
95
 
96
96
  * Hpricot
97
- * Mechanize
97
+ * WWW::Mechanize
98
98
  * DataMapper:
99
- * dm-core
100
- * data_objects
101
- * do_sqlite3
102
- * dm-types
103
- * dm-serializer
104
- * dm-aggregates
105
- * reverserequire
106
- * R'epertoire
99
+ * dm-core >= 0.9.3
100
+ * data_objects >= 0.9.3
101
+ * do_sqlite3 >= 0.9.3
102
+ * dm-types >= 0.9.3
103
+ * dm-serializer >= 0.9.3
104
+ * dm-aggregates >= 0.9.3
105
+ * reverse-require >= 0.1.0
106
+ * R'epertoire >= 0.1.2
107
107
 
108
108
  == INSTALL:
109
109
 
data/Rakefile CHANGED
@@ -18,7 +18,7 @@ Hoe.new('ronin', Ronin::VERSION) do |p|
18
18
  ['dm-serializer', '>=0.9.3'],
19
19
  ['dm-aggregates', '>=0.9.3'],
20
20
  ['dm-validations', '>=0.9.3'],
21
- ['reverserequire', '>=0.1.0'],
21
+ ['reverse-require', '>=0.1.2'],
22
22
  ['repertoire', '>=0.1.2']]
23
23
  end
24
24
 
data/bin/ronin CHANGED
@@ -7,6 +7,6 @@ unless $LOAD_PATH.include?(lib_dir)
7
7
  $LOAD_PATH << lib_dir
8
8
  end
9
9
 
10
- require 'ronin/runner/program'
10
+ require 'ronin/program'
11
11
 
12
- Ronin::Runner.program(ARGV)
12
+ Ronin::Program.run(*ARGV)
data/lib/ronin/author.rb CHANGED
@@ -37,7 +37,7 @@ module Ronin
37
37
  property :id, Serial
38
38
 
39
39
  # Name of author
40
- property :name, String
40
+ property :name, String, :index => true
41
41
 
42
42
  # Author's associated group
43
43
  property :organization, String
@@ -190,9 +190,7 @@ module Ronin
190
190
  # end
191
191
  #
192
192
  def Extension.run_from(path,&block)
193
- Extension.load_from(path) do |ext|
194
- ext.run(&block)
195
- end
193
+ Extension.load_from(path) { |ext| ext.run(&block) }
196
194
  end
197
195
 
198
196
  #
@@ -205,9 +203,7 @@ module Ronin
205
203
  # end
206
204
  #
207
205
  def Extension.load(name,&block)
208
- Extension.new(name) do |ext|
209
- ext.include(name,&block)
210
- end
206
+ Extension.new(name) { |ext| ext.include(name,&block) }
211
207
  end
212
208
 
213
209
  #
@@ -219,9 +215,7 @@ module Ronin
219
215
  # end
220
216
  #
221
217
  def Extension.run(name,&block)
222
- Extension.load(name) do |ext|
223
- ext.run(&block)
224
- end
218
+ Extension.load(name) { |ext| ext.run(&block) }
225
219
  end
226
220
 
227
221
  #
@@ -255,9 +249,7 @@ module Ronin
255
249
  #
256
250
  def include(name,&block)
257
251
  Extension.load_paths(name) do
258
- Extension.each_path_for(name) do |path|
259
- include_path(path)
260
- end
252
+ Extension.each_path_for(name) { |path| include_path(path) }
261
253
  end
262
254
 
263
255
  block.call(self) if block
@@ -38,9 +38,7 @@ module Ronin
38
38
  end
39
39
 
40
40
  catch('EXIT') do
41
- each_extension do |ext|
42
- ext.perform_teardown
43
- end
41
+ each_extension { |ext| ext.perform_teardown }
44
42
  end
45
43
 
46
44
  block.call(self) if block
@@ -146,7 +146,9 @@ module Ronin
146
146
  # <tt>:media</tt>:: The media of the Overlay.
147
147
  #
148
148
  def Overlay.install(options={},&block)
149
- Repertoire.checkout(:media => options[:media], :uri => options[:uri], :into => Config::REPOSITORY_DIR) do |path,media,uri|
149
+ options = options.merge(:into => Config::REPOSITORY_DIR)
150
+
151
+ Repertoire.checkout(options) do |path,media,uri|
150
152
  return Overlay.add(path,media,uri,&block)
151
153
  end
152
154
  end
@@ -395,8 +397,6 @@ module Ronin
395
397
  if File.file?(metadata_path)
396
398
  metadata = REXML::Document.new(open(metadata_path))
397
399
 
398
- #@authors = Author.from_xml(metadata,'/ronin-overlay/contributors/author')
399
-
400
400
  metadata.elements.each('/ronin-overlay') do |repo|
401
401
  @name = repo.elements['name'].get_text.to_s.strip
402
402
  @license = repo.elements['license'].get_text.to_s.strip
@@ -46,14 +46,12 @@ module Ronin
46
46
  @path = File.expand_path(path)
47
47
 
48
48
  if File.file?(@path)
49
- File.open(@path) do |file|
50
- descriptions = YAML.load(file)
51
-
52
- if descriptions.kind_of?(Array)
53
- descriptions.each do |repo|
54
- if repo.kind_of?(Hash)
55
- add(Overlay.new(repo[:path],repo[:media],repo[:uri]))
56
- end
49
+ descriptions = YAML.load(File.read(@path))
50
+
51
+ if descriptions.kind_of?(Array)
52
+ descriptions.each do |overlay|
53
+ if overlay.kind_of?(Hash)
54
+ add(Overlay.new(overlay[:path],overlay[:media],overlay[:uri]))
57
55
  end
58
56
  end
59
57
  end
@@ -135,11 +133,13 @@ module Ronin
135
133
  # end
136
134
  #
137
135
  def add(repo,&block)
138
- if has_overlay?(repo.name)
139
- raise(OverlayCached,"overlay #{repo.to_s.dump} already present in the cache #{self.to_s.dump}",caller)
136
+ name = repo.name.to_s
137
+
138
+ if has_overlay?(name)
139
+ raise(OverlayCached,"overlay #{name.dump} already present in the cache #{self.to_s.dump}",caller)
140
140
  end
141
141
 
142
- self[repo.name.to_s] = repo
142
+ self << repo
143
143
 
144
144
  block.call(self) if block
145
145
  return self
@@ -157,11 +157,13 @@ module Ronin
157
157
  # end
158
158
  #
159
159
  def remove(repo,&block)
160
- unless has_overlay?(repo.name)
161
- raise(OverlayNotFound,"overlay #{repo.to_s.dump} is not present in the cache #{to_s.dump}",caller)
160
+ name = repo.name.to_s
161
+
162
+ unless has_overlay?(name)
163
+ raise(OverlayNotFound,"overlay #{name.dump} is not present in the cache #{self.to_s.dump}",caller)
162
164
  end
163
165
 
164
- delete_if { |key,value| key==repo.name }
166
+ delete_if { |key,value| key == name }
165
167
 
166
168
  block.call(self) if block
167
169
  return self
@@ -200,7 +202,11 @@ module Ronin
200
202
 
201
203
  File.open(output_path,'w') do |output|
202
204
  descriptions = overlays.map do |repo|
203
- {:media_type => repo.media_type, :path => repo.path, :uri => repo.uri}
205
+ {
206
+ :media_type => repo.media_type,
207
+ :path => repo.path,
208
+ :uri => repo.uri
209
+ }
204
210
  end
205
211
 
206
212
  YAML.dump(descriptions,output)
@@ -26,26 +26,20 @@ module Ronin
26
26
  class CharSet < Array
27
27
 
28
28
  #
29
- # Creates a new CharSet object with the given _characters_.
29
+ # Creates a new CharSet object with the given _chars_.
30
30
  #
31
- def initialize(*characters)
31
+ def initialize(*chars)
32
32
  format_char = lambda { |char|
33
- if char.kind_of?(Integer)
33
+ if (char.kind_of?(Array) || char.kind_of?(Range))
34
+ char.map(&format_char)
35
+ elsif char.kind_of?(Integer)
34
36
  char.chr
35
37
  else
36
38
  char.to_s
37
39
  end
38
40
  }
39
41
 
40
- characters = characters.flatten.map do |char|
41
- if char.kind_of?(Range)
42
- char.to_a.map(&format_char)
43
- else
44
- format_char.call(char)
45
- end
46
- end
47
-
48
- super(characters.flatten.uniq)
42
+ super(chars.map(&format_char).flatten.uniq)
49
43
  end
50
44
 
51
45
  #
@@ -0,0 +1,142 @@
1
+ #
2
+ #--
3
+ # Ronin - A Ruby platform designed for information security and data
4
+ # exploration tasks.
5
+ #
6
+ # Copyright (c) 2006-2008 Hal Brodigan (postmodern.mod3 at gmail.com)
7
+ #
8
+ # This program is free software; you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation; either version 2 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with this program; if not, write to the Free Software
20
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
+ #++
22
+ #
23
+
24
+ module Ronin
25
+ module Code
26
+ class Reference
27
+
28
+ # Object that is being referenced
29
+ attr_accessor :value
30
+
31
+ #
32
+ # Creates a new Reference object with the specified _value_ that will
33
+ # be referenced.
34
+ #
35
+ def initialize(value=nil)
36
+ @value = value
37
+ end
38
+
39
+ #
40
+ # Returns the class of the referenced object.
41
+ #
42
+ def class
43
+ @value.class
44
+ end
45
+
46
+ #
47
+ # Returns +true+ if the referenced object is a kind of _base_ class,
48
+ # returns +false+ otherwise.
49
+ #
50
+ def is_a?(base)
51
+ @value.is_a?(base) || super(base)
52
+ end
53
+
54
+ #
55
+ # Returns +true+ if the referenced object is a kind of _base_ class,
56
+ # returns +false+ otherwise.
57
+ #
58
+ def kind_of?(base)
59
+ @value.kind_of?(base) || super(base)
60
+ end
61
+
62
+ #
63
+ # Returns +true+ if the referenced object is an instance of the
64
+ # specified _base_ class, returns +false+ otherwise.
65
+ #
66
+ def instance_of?(base)
67
+ @value.instance_of?(base) || super(base)
68
+ end
69
+
70
+ #
71
+ # Returns +true+ if the referenced object responds to the specified
72
+ # method _name_, returns +false+ otherwise.
73
+ #
74
+ def respond_to?(name)
75
+ @value.respond_to?(name) || super(name)
76
+ end
77
+
78
+ #
79
+ # Extends the referenced object with the specified _base_ module.
80
+ #
81
+ def extend(base)
82
+ @value.extend(base) if @value
83
+ return self
84
+ end
85
+
86
+ #
87
+ # Evaluates the given _code_ within the referenced object. If a
88
+ # _block_ is given, it will be evaluated within the referenced
89
+ # object.
90
+ #
91
+ def eval(code,&block)
92
+ @value.eval(code,&block)
93
+ end
94
+
95
+ #
96
+ # Evaluates the given _block_ within the referenced object.
97
+ #
98
+ def instance_eval(&block)
99
+ @value.instance_eval(&block)
100
+ end
101
+
102
+ #
103
+ # Returns +true+ if the referenced object equals the specified
104
+ # _value_, returns +false+ otherwise.
105
+ #
106
+ def eql?(value)
107
+ @value.eql?(value) || super(value)
108
+ end
109
+
110
+ alias == eql?
111
+ alias === eql?
112
+
113
+ #
114
+ # Returns the String form of the referenced object.
115
+ #
116
+ def to_s
117
+ @value.to_s
118
+ end
119
+
120
+ #
121
+ # Inspects the referenced object.
122
+ #
123
+ def inspect
124
+ @value.inspect
125
+ end
126
+
127
+ protected
128
+
129
+ #
130
+ # Relays method calls to the referenced object.
131
+ #
132
+ def method_missing(name,*arguments,&block)
133
+ if @value.class.public_method_defined?(name)
134
+ return @value.send(name,*arguments,&block)
135
+ end
136
+
137
+ raise(NoMethodError,name.id2name)
138
+ end
139
+
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,90 @@
1
+ #
2
+ #--
3
+ # Ronin - A Ruby platform designed for information security and data
4
+ # exploration tasks.
5
+ #
6
+ # Copyright (c) 2006-2008 Hal Brodigan (postmodern.mod3 at gmail.com)
7
+ #
8
+ # This program is free software; you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation; either version 2 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with this program; if not, write to the Free Software
20
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
+ #++
22
+ #
23
+
24
+ require 'ronin/code/reference'
25
+
26
+ module Ronin
27
+ module Code
28
+ class SymbolTable
29
+
30
+ #
31
+ # Creates a new SymbolTable object with a given Hash of symbol names
32
+ # and their initial values.
33
+ #
34
+ def initialize(symbols={})
35
+ @table = Hash.new { |hash,key| hash[key] = Reference.new }
36
+
37
+ self.symbols = symbols
38
+ end
39
+
40
+ #
41
+ # Returns +true+ if the table has the symbol with the specified
42
+ # _name_, returns +false+ otherwise.
43
+ #
44
+ def has_symbol?(name)
45
+ @table.has_key?(name.to_s)
46
+ end
47
+
48
+ #
49
+ # Returns the symbol with the specified _name_.
50
+ #
51
+ def symbol(name)
52
+ @table[name.to_s]
53
+ end
54
+
55
+ #
56
+ # Sets the symbol values en-mass using the specified _hash_ of
57
+ # symbol names and their values.
58
+ #
59
+ def symbols=(hash)
60
+ hash.each do |name,value|
61
+ self[name] = value
62
+ end
63
+ end
64
+
65
+ #
66
+ # Returns the value of the symbol with the specified _name_.
67
+ #
68
+ def [](name)
69
+ @table[name.to_s].value
70
+ end
71
+
72
+ #
73
+ # Sets the _value_ of the symbol with the specified _name_.
74
+ #
75
+ def []=(name,value)
76
+ @table[name.to_s].value = value
77
+ end
78
+
79
+ #
80
+ # Inspects the symbol table.
81
+ #
82
+ def inspect
83
+ '{' + @table.map { |name,symbol|
84
+ "#{name.inspect}=>#{symbol.inspect}"
85
+ }.join(', ') + '}'
86
+ end
87
+
88
+ end
89
+ end
90
+ end
data/lib/ronin/context.rb CHANGED
@@ -216,7 +216,7 @@ module Ronin
216
216
  new_objs = []
217
217
 
218
218
  Context.load_blocks(path) do |pending|
219
- pending.blocks.each do |name,context_block|
219
+ pending.each_block do |name,context_block|
220
220
  if Context.is_context?(name)
221
221
  new_obj = Context.contexts[name].new
222
222
  new_obj.instance_eval(&context_block)
@@ -80,6 +80,13 @@ module Ronin
80
80
  @@ronin_database_config = configuration
81
81
  end
82
82
 
83
+ #
84
+ # Returns the current Database log.
85
+ #
86
+ def Database.log
87
+ @@ronin_database_log ||= nil
88
+ end
89
+
83
90
  #
84
91
  # Setup the Database log with the given _options_.
85
92
  #
@@ -94,8 +101,7 @@ module Ronin
94
101
  stream = (options[:stream] || File.new(path,'w+'))
95
102
  level = (options[:level] || DEFAULT_LOG_LEVEL)
96
103
 
97
- DataMapper::Logger.new(stream,level)
98
- return nil
104
+ return @@ronin_database_log = DataMapper::Logger.new(stream,level)
99
105
  end
100
106
 
101
107
  #
@@ -104,7 +110,10 @@ module Ronin
104
110
  # the Database.
105
111
  #
106
112
  def Database.setup(configuration=Database.config,&block)
107
- Database.setup_log
113
+ # setup the database log
114
+ Database.setup_log unless Database.log
115
+
116
+ # setup the database repository
108
117
  DataMapper.setup(Model::REPOSITORY_NAME, configuration)
109
118
 
110
119
  block.call if block
@@ -34,4 +34,53 @@ class String
34
34
  downcase.gsub(/(::|[\s\-])/,'_')
35
35
  end
36
36
 
37
+ #
38
+ # Returns the common prefix of the string and the specified _other_
39
+ # string. If no common prefix can be found an empty string will be
40
+ # returned.
41
+ #
42
+ def common_prefix(other)
43
+ min_length = [length, other.length].min
44
+
45
+ min_length.times do |i|
46
+ if self[i] != other[i]
47
+ return self[0...i]
48
+ end
49
+ end
50
+
51
+ return self[0...min_length]
52
+ end
53
+
54
+ #
55
+ # Returns the common postfix of the string and the specified _other_
56
+ # string. If no common postfix can be found an empty string will be
57
+ # returned.
58
+ #
59
+ def common_postfix(other)
60
+ min_length = [length, other.length].min
61
+
62
+ (min_length - 1).times do |i|
63
+ index = (length - i -1)
64
+ other_index = (other.length - i -1)
65
+
66
+ if self[index] != other[other_index]
67
+ return self[(index + 1)..-1]
68
+ end
69
+ end
70
+
71
+ return ''
72
+ end
73
+
74
+ #
75
+ # Returns the uncommon substring within the specified _other_ string,
76
+ # which does not occur within the string. If no uncommon substring can be
77
+ # found, an empty string will be returned.
78
+ #
79
+ def uncommon_substring(other)
80
+ prefix = common_prefix(other)
81
+ postfix = self[prefix.length..-1].common_postfix(other[prefix.length..-1])
82
+
83
+ return self[prefix.length...(length - postfix.length)]
84
+ end
85
+
37
86
  end
@@ -39,14 +39,19 @@ class String
39
39
  excluded = (options[:excluded] || [])
40
40
 
41
41
  formatted = included - excluded
42
+ formatted = ''
43
+
44
+ self.each_byte do |b|
45
+ c = b.chr
42
46
 
43
- return self.scan(/./m).map { |c|
44
47
  if formatted.include?(c)
45
- block.call(c)
48
+ formatted_chars << block.call(c)
46
49
  else
47
- c
50
+ formatted_chars << c
48
51
  end
49
- }.join
52
+ end
53
+
54
+ return formatted
50
55
  end
51
56
 
52
57
  #
@@ -81,7 +86,7 @@ class String
81
86
  # "get out your checkbook".rand_case
82
87
  # # => "gEt Out YOur CHEckbook"
83
88
  #
84
- def rand_case(options={})
89
+ def random_case(options={})
85
90
  prob = (options[:probability] || 0.5)
86
91
 
87
92
  format_chars(options) do |c|