ronin-support 0.2.0 → 0.3.0

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 (62) hide show
  1. data/.gitignore +11 -0
  2. data/ChangeLog.md +42 -1
  3. data/README.md +4 -1
  4. data/gemspec.yml +2 -1
  5. data/lib/ronin/extensions.rb +2 -0
  6. data/lib/ronin/extensions/enumerable.rb +54 -0
  7. data/lib/ronin/extensions/file.rb +70 -2
  8. data/lib/ronin/extensions/ip_addr.rb +45 -45
  9. data/lib/ronin/extensions/regexp.rb +45 -0
  10. data/lib/ronin/extensions/resolv.rb +80 -0
  11. data/lib/ronin/extensions/string.rb +35 -32
  12. data/lib/ronin/formatting/extensions/binary/integer.rb +12 -5
  13. data/lib/ronin/formatting/extensions/binary/string.rb +44 -16
  14. data/lib/ronin/formatting/extensions/html/integer.rb +51 -31
  15. data/lib/ronin/formatting/extensions/html/string.rb +50 -31
  16. data/lib/ronin/formatting/extensions/http/integer.rb +10 -2
  17. data/lib/ronin/formatting/extensions/sql.rb +20 -0
  18. data/lib/ronin/formatting/extensions/sql/string.rb +98 -0
  19. data/lib/ronin/formatting/extensions/text/array.rb +11 -9
  20. data/lib/ronin/formatting/extensions/text/string.rb +213 -29
  21. data/lib/ronin/formatting/sql.rb +20 -0
  22. data/lib/ronin/network/extensions/http.rb +1 -0
  23. data/lib/ronin/network/extensions/http/net.rb +2 -2
  24. data/lib/ronin/network/extensions/http/uri/http.rb +226 -0
  25. data/lib/ronin/network/extensions/imap/net.rb +1 -1
  26. data/lib/ronin/network/extensions/ssl/net.rb +7 -1
  27. data/lib/ronin/network/http/proxy.rb +20 -21
  28. data/lib/ronin/network/mixins.rb +27 -0
  29. data/lib/ronin/network/mixins/esmtp.rb +165 -0
  30. data/lib/ronin/network/mixins/http.rb +723 -0
  31. data/lib/ronin/network/mixins/imap.rb +151 -0
  32. data/lib/ronin/network/mixins/pop3.rb +141 -0
  33. data/lib/ronin/network/mixins/smtp.rb +159 -0
  34. data/lib/ronin/network/mixins/tcp.rb +331 -0
  35. data/lib/ronin/network/mixins/telnet.rb +199 -0
  36. data/lib/ronin/network/mixins/udp.rb +227 -0
  37. data/lib/ronin/network/ssl.rb +17 -11
  38. data/lib/ronin/path.rb +3 -3
  39. data/lib/ronin/spec/ui/output.rb +28 -0
  40. data/lib/ronin/support.rb +3 -0
  41. data/lib/ronin/support/version.rb +1 -1
  42. data/lib/ronin/ui/output.rb +21 -0
  43. data/lib/ronin/ui/output/helpers.rb +248 -0
  44. data/lib/ronin/ui/output/output.rb +146 -0
  45. data/lib/ronin/ui/output/terminal.rb +21 -0
  46. data/lib/ronin/ui/output/terminal/color.rb +118 -0
  47. data/lib/ronin/ui/output/terminal/raw.rb +103 -0
  48. data/lib/ronin/ui/shell.rb +219 -0
  49. data/ronin-support.gemspec +1 -1
  50. data/spec/extensions/enumerable_spec.rb +24 -0
  51. data/spec/extensions/file_spec.rb +39 -0
  52. data/spec/extensions/ip_addr_spec.rb +6 -0
  53. data/spec/extensions/resolv_spec.rb +18 -0
  54. data/spec/formatting/html/integer_spec.rb +2 -2
  55. data/spec/formatting/html/string_spec.rb +1 -1
  56. data/spec/formatting/sql/string_spec.rb +55 -0
  57. data/spec/formatting/text/string_spec.rb +110 -0
  58. data/spec/network/ssl_spec.rb +10 -4
  59. data/spec/ui/classes/test_shell.rb +22 -0
  60. data/spec/ui/output_spec.rb +32 -0
  61. data/spec/ui/shell_spec.rb +79 -0
  62. metadata +132 -90
@@ -41,6 +41,10 @@ class String
41
41
  # @return [String]
42
42
  # The HTML escaped String.
43
43
  #
44
+ # @example
45
+ # "one & two".html_escape
46
+ # # => "one & two"
47
+ #
44
48
  # @see http://rubydoc.info/stdlib/cgi/1.9.2/CGI.escapeHTML
45
49
  #
46
50
  # @since 0.2.0
@@ -57,6 +61,10 @@ class String
57
61
  # @return [String]
58
62
  # The unescaped String.
59
63
  #
64
+ # @example
65
+ # "<p>one <span>two</span></p>".html_unescape
66
+ # # => "<p>one <span>two</span></p>"
67
+ #
60
68
  # @see http://rubydoc.info/stdlib/cgi/1.9.2/CGI.unescapeHTML
61
69
  #
62
70
  # @since 0.2.0
@@ -76,6 +84,10 @@ class String
76
84
  # @return [String]
77
85
  # The formatted HTML String.
78
86
  #
87
+ # @example
88
+ # "abc".format_html
89
+ # # => "&#97;&#98;&#99;"
90
+ #
79
91
  # @see Integer#format_html
80
92
  #
81
93
  # @since 0.2.0
@@ -83,12 +95,14 @@ class String
83
95
  # @api public
84
96
  #
85
97
  def format_html(options={})
86
- if RUBY_VERSION < '1.9.'
87
- # String#ord was not backported to Rub 1.8.7
88
- format_chars(options) { |c| c[0].format_html }
89
- else
90
- format_chars(options) { |c| c.ord.format_html }
91
- end
98
+ formatter = if RUBY_VERSION < '1.9.'
99
+ # String#ord was not backported to Ruby 1.8.7
100
+ lambda { |c| c[0].format_html }
101
+ else
102
+ lambda { |c| c.ord.format_html }
103
+ end
104
+
105
+ format_chars(options,&formatter)
92
106
  end
93
107
 
94
108
  #
@@ -101,8 +115,8 @@ class String
101
115
  # The JavaScript escaped String.
102
116
  #
103
117
  # @example
104
- # "hello".js_escape
105
- # # => "%u0068%u0065%u006C%u006C%u006F"
118
+ # "hello\nworld\n".js_escape
119
+ # # => "hello\\nworld\\n"
106
120
  #
107
121
  # @see Integer#js_escape
108
122
  #
@@ -111,12 +125,14 @@ class String
111
125
  # @api public
112
126
  #
113
127
  def js_escape(options={})
114
- if RUBY_VERSION < '1.9.'
115
- # String#ord was not backported to Rub 1.8.7
116
- format_chars(options) { |c| c[0].js_escape }
117
- else
118
- format_chars(options) { |c| c.ord.js_escape }
119
- end
128
+ formatter = if RUBY_VERSION < '1.9.'
129
+ # String#ord was not backported to Rub 1.8.7
130
+ lambda { |c| c[0].js_escape }
131
+ else
132
+ lambda { |c| c.ord.js_escape }
133
+ end
134
+
135
+ format_chars(options,&formatter)
120
136
  end
121
137
 
122
138
  #
@@ -126,7 +142,7 @@ class String
126
142
  # The unescaped JavaScript String.
127
143
  #
128
144
  # @example
129
- # "%u0068%u0065%u006C%u006C%u006F world".js_unescape
145
+ # "\\u0068\\u0065\\u006C\\u006C\\u006F world".js_unescape
130
146
  # # => "hello world"
131
147
  #
132
148
  # @since 0.2.0
@@ -139,15 +155,16 @@ class String
139
155
  scan(/([\\%]u[0-9a-fA-F]{4}|[\\%][0-9a-fA-F]{2}|\\[btnfr"\\]|.)/).each do |match|
140
156
  c = match[0]
141
157
 
142
- if c.length == 6
143
- unescaped << c[2,4].to_i(16)
144
- elsif c.length == 3
145
- unescaped << c[1,2].to_i(16)
146
- elsif c.length == 2
147
- unescaped << JS_BACKSLASHED_CHARS[c]
148
- else
149
- unescaped << c
150
- end
158
+ unescaped << case c.length
159
+ when 6
160
+ c[2,4].to_i(16)
161
+ when 3
162
+ c[1,2].to_i(16)
163
+ when 2
164
+ JS_BACKSLASHED_CHARS[c]
165
+ else
166
+ c
167
+ end
151
168
  end
152
169
 
153
170
  return unescaped
@@ -164,7 +181,7 @@ class String
164
181
  #
165
182
  # @example
166
183
  # "hello".js_escape
167
- # # => "%u0068%u0065%u006C%u006C%u006F"
184
+ # # => "\\u0068\\u0065\\u006C\\u006C\\u006F"
168
185
  #
169
186
  # @see Integer#js_escape
170
187
  #
@@ -173,12 +190,14 @@ class String
173
190
  # @api public
174
191
  #
175
192
  def format_js(options={})
176
- if RUBY_VERSION < '1.9.'
177
- # String#ord was not backported to Rub 1.8.7
178
- format_chars(options) { |c| c[0].format_js }
179
- else
180
- format_chars(options) { |c| c.ord.format_js }
181
- end
193
+ formatter = if RUBY_VERSION < '1.9.'
194
+ # String#ord was not backported to Rub 1.8.7
195
+ lambda { |c| c[0].format_js }
196
+ else
197
+ lambda { |c| c.ord.format_js }
198
+ end
199
+
200
+ format_chars(options,&formatter)
182
201
  end
183
202
 
184
203
  end
@@ -31,7 +31,7 @@ class Integer
31
31
  # @api public
32
32
  #
33
33
  def uri_encode
34
- URI.encode(self.chr)
34
+ URI.encode(chr)
35
35
  end
36
36
 
37
37
  #
@@ -40,10 +40,14 @@ class Integer
40
40
  # @return [String]
41
41
  # The URI escaped byte.
42
42
  #
43
+ # @example
44
+ # 0x3d.uri_escape
45
+ # # => "%3D"
46
+ #
43
47
  # @api public
44
48
  #
45
49
  def uri_escape
46
- CGI.escape(self.chr)
50
+ CGI.escape(chr)
47
51
  end
48
52
 
49
53
  #
@@ -52,6 +56,10 @@ class Integer
52
56
  # @return [String]
53
57
  # The formatted byte.
54
58
  #
59
+ # @example
60
+ # 0x41.format_http
61
+ # # => "%41"
62
+ #
55
63
  # @api public
56
64
  #
57
65
  def format_http
@@ -0,0 +1,20 @@
1
+ #
2
+ # Copyright (c) 2006-2011 Hal Brodigan (postmodern.mod3 at gmail.com)
3
+ #
4
+ # This file is part of Ronin Support.
5
+ #
6
+ # Ronin Support is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Lesser General Public License as published
8
+ # by the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Ronin Support is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with Ronin Support. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+
20
+ require 'ronin/formatting/extensions/sql/string'
@@ -0,0 +1,98 @@
1
+ #
2
+ # Copyright (c) 2006-2011 Hal Brodigan (postmodern.mod3 at gmail.com)
3
+ #
4
+ # This file is part of Ronin Support.
5
+ #
6
+ # Ronin Support is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Lesser General Public License as published
8
+ # by the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Ronin Support is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with Ronin Support. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+
20
+ class String
21
+
22
+ #
23
+ # Escapes an String for SQL.
24
+ #
25
+ # @param [Symbol] quotes (:single)
26
+ # Specifies whether to create a single or double quoted string.
27
+ # May be either `:single` or `:double`.
28
+ #
29
+ # @return [String]
30
+ # The escaped String.
31
+ #
32
+ # @raise [ArgumentError]
33
+ # The quotes argument was neither `:single` nor `:double`.
34
+ #
35
+ # @example
36
+ # "O'Brian".sql_escape
37
+ # # => "'O''Brian'"
38
+ #
39
+ # @since 0.3.0
40
+ #
41
+ def sql_escape(quotes=:single)
42
+ case quotes
43
+ when :single
44
+ "'#{gsub(/'/,"''")}'"
45
+ when :double
46
+ "\"#{gsub(/"/,'""')}\""
47
+ else
48
+ raise(ArgumentError,"invalid quoting style #{quotes.inspect}")
49
+ end
50
+ end
51
+
52
+ #
53
+ # Returns the SQL hex-string encoded form of the String.
54
+ #
55
+ # @example
56
+ # "/etc/passwd".sql_encode
57
+ # # => "0x2f6574632f706173737764"
58
+ #
59
+ def sql_encode
60
+ return '' if empty?
61
+
62
+ hex_string = '0x'
63
+
64
+ each_byte do |b|
65
+ hex_string << ('%.2x' % b)
66
+ end
67
+
68
+ return hex_string
69
+ end
70
+
71
+ #
72
+ # Returns the SQL decoded form of the String.
73
+ #
74
+ # @example
75
+ # "'Conan O''Brian'".sql_decode
76
+ # # => "Conan O'Brian"
77
+ #
78
+ # @example
79
+ # "0x2f6574632f706173737764".sql_decode
80
+ # # => "/etc/passwd"
81
+ #
82
+ def sql_decode
83
+ if ((self[0...2] == '0x') && (length % 2 == 0))
84
+ raw = ''
85
+
86
+ self[2..-1].scan(/[0-9a-fA-F]{2}/).each do |hex_char|
87
+ raw << hex_char.hex.chr
88
+ end
89
+
90
+ return raw
91
+ elsif (self[0..0] == "'" && self[-1..-1] == "'")
92
+ self[1..-2].gsub("\\'","'").gsub("''","'")
93
+ else
94
+ return self
95
+ end
96
+ end
97
+
98
+ end
@@ -37,15 +37,17 @@ class Array
37
37
  # @api public
38
38
  #
39
39
  def bytes
40
- self.inject([]) do |accum,elem|
41
- if elem.kind_of?(Integer)
42
- accum << elem
40
+ bytes = []
41
+
42
+ each do |element|
43
+ if element.kind_of?(Integer)
44
+ bytes << element
43
45
  else
44
- elem.to_s.each_byte { |b| accum << b }
46
+ element.to_s.each_byte { |b| bytes << b }
45
47
  end
46
-
47
- accum
48
48
  end
49
+
50
+ return bytes
49
51
  end
50
52
 
51
53
  #
@@ -62,7 +64,7 @@ class Array
62
64
  # @api public
63
65
  #
64
66
  def chars
65
- array_bytes = self.bytes
67
+ array_bytes = bytes
66
68
 
67
69
  array_bytes.map! { |b| b.chr }
68
70
  return array_bytes
@@ -100,7 +102,7 @@ class Array
100
102
  # @api public
101
103
  #
102
104
  def hex_chars
103
- array_bytes = self.bytes
105
+ array_bytes = bytes
104
106
 
105
107
  array_bytes.map! { |b| '\x%x' % b }
106
108
  return array_bytes
@@ -124,7 +126,7 @@ class Array
124
126
  # @api public
125
127
  #
126
128
  def hex_integers
127
- array_bytes = self.bytes
129
+ array_bytes = bytes
128
130
 
129
131
  array_bytes.map! { |b| '0x%x' % b }
130
132
  return array_bytes
@@ -17,10 +17,190 @@
17
17
  # along with Ronin Support. If not, see <http://www.gnu.org/licenses/>.
18
18
  #
19
19
 
20
+ require 'combinatorics/list_comprehension'
21
+ require 'combinatorics/generator'
22
+ require 'chars'
20
23
  require 'set'
21
24
 
22
25
  class String
23
26
 
27
+ #
28
+ # Generate permutations of Strings from a format template.
29
+ #
30
+ # @param [Array(<String, Symbol, Enumerable>, <Integer, Enumerable>)] template
31
+ # The template which defines the string or character sets which will
32
+ # make up parts of the String.
33
+ #
34
+ # @yield [string]
35
+ # The given block will be passed each unique String.
36
+ #
37
+ # @yieldparam [String] string
38
+ # A newly generated String.
39
+ #
40
+ # @return [Enumerator]
41
+ # If no block is given, an Enumerator will be returned.
42
+ #
43
+ # @raise [ArgumentError]
44
+ # A given character set name was unknown.
45
+ #
46
+ # @raise [TypeError]
47
+ # A given string set was not a String, Symbol or Enumerable.
48
+ # A given string set length was not an Integer or Enumerable.
49
+ #
50
+ # @example Generate Strings with ranges of repeating sub-strings.
51
+ #
52
+ # @example Generate Strings with three alpha chars and one numeric chars.
53
+ # String.generate([:alpha, 3], :numeric) do |password|
54
+ # puts password
55
+ # end
56
+ #
57
+ # @example Generate Strings with two to four alpha chars.
58
+ # String.generate([:alpha, 2..4]) do |password|
59
+ # puts password
60
+ # end
61
+ #
62
+ # @example Generate Strings using alpha and punctuation chars.
63
+ # String.generate([Chars.alpha + Chars.punctuation, 4]) do |password|
64
+ # puts password
65
+ # end
66
+ #
67
+ # @example Generate Strings from a custom char set.
68
+ # String.generate([['a', 'b', 'c'], 3], [['1', '2', '3'], 3]) do |password|
69
+ # puts password
70
+ # end
71
+ #
72
+ # @example Generate Strings containing known Strings.
73
+ # String.generate("rock", [:numeric, 4]) do |password|
74
+ # puts password
75
+ # end
76
+ #
77
+ # @example Generate Strings with ranges of repeating sub-strings.
78
+ # String.generate(['/AA', (1..100).step(5)]) do |path|
79
+ # puts path
80
+ # end
81
+ #
82
+ # @since 0.3.0
83
+ #
84
+ # @api public
85
+ #
86
+ def self.generate(*template)
87
+ return enum_for(:generate,*template) unless block_given?
88
+
89
+ sets = []
90
+
91
+ template.each do |pattern|
92
+ set, length = pattern
93
+ set = case set
94
+ when String
95
+ [set].each
96
+ when Symbol
97
+ name = set.to_s.upcase
98
+
99
+ unless Chars.const_defined?(name)
100
+ raise(ArgumentError,"unknown charset #{set.inspect}")
101
+ end
102
+
103
+ Chars.const_get(name).each_char
104
+ when Enumerable
105
+ Chars::CharSet.new(set).each_char
106
+ else
107
+ raise(TypeError,"set must be a String, Symbol or Enumerable")
108
+ end
109
+
110
+ case length
111
+ when Integer
112
+ length.times { sets << set.dup }
113
+ when Enumerable
114
+ sets << Combinatorics::Generator.new do |g|
115
+ length.each do |sublength|
116
+ superset = Array.new(sublength) { set.dup }
117
+
118
+ superset.comprehension { |strings| g.yield strings.join }
119
+ end
120
+ end
121
+ when nil
122
+ sets << set
123
+ else
124
+ raise(TypeError,"length must be an Integer or Enumerable")
125
+ end
126
+ end
127
+
128
+ sets.comprehension { |strings| yield strings.join }
129
+ return nil
130
+ end
131
+
132
+ #
133
+ # Incrementally fuzzes the String.
134
+ #
135
+ # @param [Hash{Regexp,String,Integer,Enumerable => #each}] mutations
136
+ # Patterns and their substitutions.
137
+ #
138
+ # @yield [fuzz]
139
+ # The given block will be passed every fuzzed String.
140
+ #
141
+ # @yieldparam [String] fuzz
142
+ # A fuzzed String.
143
+ #
144
+ # @return [Enumerator]
145
+ # If no block is given, an Enumerator will be returned.
146
+ #
147
+ # @example Replace every `e`, `i`, `o`, `u` with `(`, 100 `A`s and a `\0`:
148
+ # "the quick brown fox".fuzz(/[eiou]/ => ['(', ('A' * 100), "\0"]) do |str|
149
+ # p str
150
+ # end
151
+ #
152
+ # @example {String.generate} with {String.fuzz}:
153
+ # "GET /".fuzz('/' => String.generate(['A', 1..100])) do |str|
154
+ # p str
155
+ # end
156
+ #
157
+ # @since 0.3.0
158
+ #
159
+ # @api public
160
+ #
161
+ def fuzz(mutations={})
162
+ return enum_for(:fuzz,mutations) unless block_given?
163
+
164
+ mutations.each do |pattern,substitution|
165
+ pattern = case pattern
166
+ when Regexp
167
+ pattern
168
+ when String
169
+ Regexp.new(Regexp.escape(pattern))
170
+ when Integer
171
+ Regexp.new(pattern.chr)
172
+ when Enumerable
173
+ Regexp.union(pattern.map { |s| Regexp.escape(s.to_s) })
174
+ else
175
+ raise(TypeError,"cannot convert #{pattern.inspect} to a Regexp")
176
+ end
177
+
178
+ scanner = StringScanner.new(self)
179
+ indices = []
180
+
181
+ while scanner.scan_until(pattern)
182
+ indices << [scanner.pos - scanner.matched_size, scanner.matched_size]
183
+ end
184
+
185
+ indices.each do |index,length|
186
+ substitution.each do |substitute|
187
+ substitute = case substitute
188
+ when Proc
189
+ substitute.call(self[index,length])
190
+ when Integer
191
+ substitute.chr
192
+ else
193
+ substitute.to_s
194
+ end
195
+
196
+ fuzzed = dup
197
+ fuzzed[index,length] = substitute
198
+ yield fuzzed
199
+ end
200
+ end
201
+ end
202
+ end
203
+
24
204
  #
25
205
  # Creates a new String by formatting each byte.
26
206
  #
@@ -43,20 +223,23 @@ class String
43
223
  # @return [String]
44
224
  # The formatted version of the String.
45
225
  #
226
+ # @example
227
+ # "hello".format_bytes { |b| "%x" % b }
228
+ # # => "68656c6c6f"
229
+ #
46
230
  # @api public
47
231
  #
48
232
  def format_bytes(options={})
49
- included = options.fetch(:include,(0x00..0xff))
50
- excluded = options.fetch(:exclude,Set[])
51
-
233
+ included = (options[:include] || (0x00..0xff))
234
+ excluded = (options[:exclude] || Set[])
52
235
  formatted = ''
53
236
 
54
- self.each_byte do |b|
55
- if (included.include?(b) && !excluded.include?(b))
56
- formatted << yield(b)
57
- else
58
- formatted << b
59
- end
237
+ each_byte do |b|
238
+ formatted << if (included.include?(b) && !excluded.include?(b))
239
+ yield(b)
240
+ else
241
+ b
242
+ end
60
243
  end
61
244
 
62
245
  return formatted
@@ -84,12 +267,15 @@ class String
84
267
  # @return [String]
85
268
  # The formatted version of the String.
86
269
  #
270
+ # @example
271
+ # "hello".format_chars { |c| c * 3 }
272
+ # # => "hhheeellllllooo"
273
+ #
87
274
  # @api public
88
275
  #
89
276
  def format_chars(options={})
90
- included = options.fetch(:include,/./m)
91
- excluded = options.fetch(:exclude,Set[])
92
-
277
+ included = (options[:include] || /./m)
278
+ excluded = (options[:exclude] || Set[])
93
279
  formatted = ''
94
280
 
95
281
  matches = lambda { |filter,c|
@@ -97,17 +283,15 @@ class String
97
283
  filter.include?(c)
98
284
  elsif filter.kind_of?(Regexp)
99
285
  c =~ filter
100
- else
101
- false
102
286
  end
103
287
  }
104
288
 
105
- self.each_char do |c|
106
- if (matches[included,c] && !matches[excluded,c])
107
- formatted << yield(c)
108
- else
109
- formatted << c
110
- end
289
+ each_char do |c|
290
+ formatted << if (matches[included,c] && !matches[excluded,c])
291
+ yield(c)
292
+ else
293
+ c
294
+ end
111
295
  end
112
296
 
113
297
  return formatted
@@ -162,8 +346,8 @@ class String
162
346
  # @api public
163
347
  #
164
348
  def insert_before(pattern,data)
165
- string = self.dup
166
- index = string.index(pattern)
349
+ string = dup
350
+ index = string.index(pattern)
167
351
 
168
352
  string.insert(index,data) if index
169
353
  return string
@@ -184,8 +368,8 @@ class String
184
368
  # @api public
185
369
  #
186
370
  def insert_after(pattern,data)
187
- string = self.dup
188
- match = string.match(pattern)
371
+ string = dup
372
+ match = string.match(pattern)
189
373
 
190
374
  if match
191
375
  index = match.end(match.length - 1)
@@ -215,19 +399,19 @@ class String
215
399
  #
216
400
  # @api public
217
401
  #
218
- def pad(padding,max_length=self.length)
402
+ def pad(padding,max_length=length)
219
403
  padding = padding.to_s
220
404
 
221
- if max_length >= self.length
222
- max_length -= self.length
405
+ if max_length > length
406
+ max_length -= length
223
407
  else
224
408
  max_length = 0
225
409
  end
226
410
 
227
411
  padded = self + (padding * (max_length / padding.length))
228
412
 
229
- unless (remaining = max_length % padding.length) == 0
230
- padded << padding[0...remaining]
413
+ unless (remaining = (max_length % padding.length)) == 0
414
+ padded << padding[0,remaining]
231
415
  end
232
416
 
233
417
  return padded