extlib 0.9.8 → 0.9.9

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of extlib might be problematic. Click here for more details.

Files changed (54) hide show
  1. data/History.txt +22 -0
  2. data/LICENSE +1 -1
  3. data/README +0 -0
  4. data/Rakefile +17 -12
  5. data/lib/extlib.rb +1 -1
  6. data/lib/extlib/blank.rb +51 -21
  7. data/lib/extlib/boolean.rb +1 -1
  8. data/lib/extlib/class.rb +12 -12
  9. data/lib/extlib/datetime.rb +20 -2
  10. data/lib/extlib/dictionary.rb +2 -2
  11. data/lib/extlib/hash.rb +57 -34
  12. data/lib/extlib/inflection.rb +0 -1
  13. data/lib/extlib/lazy_array.rb +327 -36
  14. data/lib/extlib/logger.rb +8 -8
  15. data/lib/extlib/mash.rb +45 -45
  16. data/lib/extlib/module.rb +1 -1
  17. data/lib/extlib/nil.rb +1 -1
  18. data/lib/extlib/numeric.rb +1 -1
  19. data/lib/extlib/object.rb +8 -21
  20. data/lib/extlib/object_space.rb +3 -3
  21. data/lib/extlib/pathname.rb +10 -0
  22. data/lib/extlib/pooling.rb +9 -17
  23. data/lib/extlib/rubygems.rb +7 -7
  24. data/lib/extlib/simple_set.rb +35 -8
  25. data/lib/extlib/string.rb +85 -42
  26. data/lib/extlib/struct.rb +10 -1
  27. data/lib/extlib/symbol.rb +11 -7
  28. data/lib/extlib/time.rb +31 -9
  29. data/lib/extlib/version.rb +1 -1
  30. data/lib/extlib/virtual_file.rb +1 -1
  31. data/spec/blank_spec.rb +85 -0
  32. data/spec/class_spec.rb +141 -0
  33. data/spec/datetime_spec.rb +22 -0
  34. data/spec/hash_spec.rb +537 -0
  35. data/spec/hook_spec.rb +1198 -0
  36. data/spec/inflection/plural_spec.rb +564 -0
  37. data/spec/inflection/singular_spec.rb +497 -0
  38. data/spec/inflection_extras_spec.rb +93 -0
  39. data/spec/lazy_array_spec.rb +1869 -0
  40. data/spec/mash_spec.rb +286 -0
  41. data/spec/module_spec.rb +58 -0
  42. data/spec/object_space_spec.rb +9 -0
  43. data/spec/object_spec.rb +114 -0
  44. data/spec/pooling_spec.rb +499 -0
  45. data/spec/simple_set_spec.rb +57 -0
  46. data/spec/spec_helper.rb +7 -0
  47. data/spec/string_spec.rb +220 -0
  48. data/spec/struct_spec.rb +12 -0
  49. data/spec/symbol_spec.rb +8 -0
  50. data/spec/time_spec.rb +22 -0
  51. data/spec/try_dup_spec.rb +45 -0
  52. data/spec/virtual_file_spec.rb +21 -0
  53. metadata +51 -26
  54. data/README.txt +0 -3
@@ -0,0 +1,22 @@
1
+ === 0.9.9 / 2008-12-07
2
+
3
+ * 1 major enhancement:
4
+
5
+ * Updated LazyArray to have a tail/head so that it can append/prepend
6
+ without lazy-loading. This will eliminate some too-eager loading
7
+ from DataMapper::Collection, and (in certain cases) will boost
8
+ performance significantly.
9
+
10
+ * 3 minor enhancements:
11
+
12
+ * Minor Ruby 1.9.1 fixes. RSpec still needs to be updated to support
13
+ 1.9.1 before everything can be verified completely.
14
+ * Updated Extlib::Inflection so that the plural of "cow" is now
15
+ "cows" instead of "kine".
16
+ * Misc documentation updates.
17
+
18
+ * 2 bug fixes:
19
+
20
+ * Fixed Extlib::Pooling Threading issue on JRuby and Windows.
21
+ * Removed Object#encoded_hash. It was not used by DataMapper or Merb,
22
+ and the specs were failing for JRuby.
data/LICENSE CHANGED
@@ -17,4 +17,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
17
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
18
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
19
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
File without changes
data/Rakefile CHANGED
@@ -28,6 +28,14 @@ GEM_VERSION = Extlib::VERSION + PKG_BUILD
28
28
 
29
29
  RELEASE_NAME = "REL #{GEM_VERSION}"
30
30
 
31
+ WINDOWS = (RUBY_PLATFORM =~ /win32|mingw|bccwin|cygwin/) rescue nil
32
+ JRUBY = (RUBY_PLATFORM =~ /java/) rescue nil
33
+
34
+ # sudo is used by default, except on Windows, or if SUDOLESS env is true
35
+ SUDO = WINDOWS ? '' : ('sudo' unless ENV['SUDOLESS'])
36
+ # RCov is run by default, except on the JRuby platform, or if NO_RCOV env is true
37
+ RUN_RCOV = JRUBY ? false : (ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true)
38
+
31
39
  require "lib/extlib/tasks/release"
32
40
 
33
41
  spec = Gem::Specification.new do |s|
@@ -39,12 +47,12 @@ spec = Gem::Specification.new do |s|
39
47
  s.homepage = PROJECT_URL
40
48
  s.summary = PROJECT_SUMMARY
41
49
  s.description = PROJECT_DESCRIPTION
42
- s.require_path = "lib"
43
- s.files = ["LICENSE", "README.txt", "Rakefile"] + Dir["lib/**/*"]
50
+ s.require_path = 'lib'
51
+ s.files = %w[ LICENSE README Rakefile History.txt ] + Dir['lib/**/*'] + Dir['spec/**/*']
44
52
 
45
53
  # rdoc
46
54
  s.has_rdoc = false
47
- s.extra_rdoc_files = ["LICENSE", "README.txt"]
55
+ s.extra_rdoc_files = %w[ LICENSE README History.txt ]
48
56
 
49
57
  # Dependencies
50
58
  # s.add_dependency "english", ">=0.2.0"
@@ -70,11 +78,12 @@ namespace :extlib do
70
78
  t.spec_files = Pathname.glob(ENV['FILES'] || 'spec/**/*_spec.rb')
71
79
 
72
80
  begin
73
- t.rcov = ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true
81
+ gem 'rcov'
82
+ t.rcov = RUN_RCOV
74
83
  t.rcov_opts << '--exclude' << 'spec'
75
84
  t.rcov_opts << '--text-summary'
76
85
  t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
77
- rescue Exception
86
+ rescue LoadError
78
87
  # rcov not installed
79
88
  end
80
89
  end
@@ -95,10 +104,6 @@ task :doc do
95
104
  end
96
105
  end
97
106
 
98
- WINDOWS = (RUBY_PLATFORM =~ /win32|mingw|bccwin|cygwin/) rescue nil
99
- SUDO = WINDOWS ? '' : ('sudo' unless ENV['SUDOLESS'])
100
-
101
-
102
107
  desc "Install #{GEM_NAME}"
103
108
  task :install => :package do
104
109
  sh %{#{SUDO} gem install --local pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources}
@@ -106,7 +111,7 @@ end
106
111
 
107
112
  if WINDOWS
108
113
  namespace :dev do
109
- desc 'Install for development (for windows)'
114
+ desc 'Install for development (for Windows)'
110
115
  task :winstall => :gem do
111
116
  system %{gem install --no-rdoc --no-ri -l pkg/#{GEM_NAME}-#{GEM_VERSION}.gem}
112
117
  end
@@ -169,9 +174,9 @@ namespace :benchmark do
169
174
  desc "Runs benchmarks"
170
175
  task :run do
171
176
  files = Dir["benchmarks/**/*.rb"]
172
-
177
+
173
178
  files.each do |f|
174
179
  system "ruby #{f}"
175
180
  end
176
- end
181
+ end
177
182
  end
@@ -53,4 +53,4 @@ module Extlib
53
53
  @exiting
54
54
  end
55
55
 
56
- end
56
+ end
@@ -1,58 +1,88 @@
1
1
  class Object
2
- # @return <TrueClass, FalseClass>
3
- #
4
- # @example [].blank? #=> true
5
- # @example [1].blank? #=> false
6
- # @example [nil].blank? #=> false
7
- #
2
+ ##
8
3
  # Returns true if the object is nil or empty (if applicable)
4
+ #
5
+ # [].blank? #=> true
6
+ # [1].blank? #=> false
7
+ # [nil].blank? #=> false
8
+ #
9
+ # @return [TrueClass, FalseClass]
10
+ #
11
+ # @api public
9
12
  def blank?
10
13
  nil? || (respond_to?(:empty?) && empty?)
11
14
  end
12
15
  end # class Object
13
16
 
14
17
  class Numeric
15
- # @return <TrueClass, FalseClass>
16
- #
17
- # Numerics can't be blank
18
+ ##
19
+ # Numerics are never blank
20
+ #
21
+ # 0.blank? #=> false
22
+ # 1.blank? #=> false
23
+ # 6.54321.blank? #=> false
24
+ #
25
+ # @return [FalseClass]
26
+ #
27
+ # @api public
18
28
  def blank?
19
29
  false
20
30
  end
21
31
  end # class Numeric
22
32
 
23
33
  class NilClass
24
- # @return <TrueClass, FalseClass>
25
- #
26
- # Nils are always blank
34
+ ##
35
+ # Nil is always blank
36
+ #
37
+ # nil.blank? #=> true
38
+ #
39
+ # @return [TrueClass]
40
+ #
41
+ # @api public
27
42
  def blank?
28
43
  true
29
44
  end
30
45
  end # class NilClass
31
46
 
32
47
  class TrueClass
33
- # @return <TrueClass, FalseClass>
34
- #
35
- # True is not blank.
48
+ ##
49
+ # True is never blank.
50
+ #
51
+ # true.blank? #=> false
52
+ #
53
+ # @return [FalseClass]
54
+ #
55
+ # @api public
36
56
  def blank?
37
57
  false
38
58
  end
39
59
  end # class TrueClass
40
60
 
41
61
  class FalseClass
62
+ ##
42
63
  # False is always blank.
64
+ #
65
+ # false.blank? #=> true
66
+ #
67
+ # @return [TrueClass]
68
+ #
69
+ # @api public
43
70
  def blank?
44
71
  true
45
72
  end
46
73
  end # class FalseClass
47
74
 
48
75
  class String
49
- # @example "".blank? #=> true
50
- # @example " ".blank? #=> true
51
- # @example " hey ho ".blank? #=> false
52
- #
53
- # @return <TrueClass, FalseClass>
54
- #
76
+ ##
55
77
  # Strips out whitespace then tests if the string is empty.
78
+ #
79
+ # "".blank? #=> true
80
+ # " ".blank? #=> true
81
+ # " hey ho ".blank? #=> false
82
+ #
83
+ # @return [TrueClass, FalseClass]
84
+ #
85
+ # @api public
56
86
  def blank?
57
87
  strip.empty?
58
88
  end
@@ -8,4 +8,4 @@ class FalseClass
8
8
  def try_dup
9
9
  self
10
10
  end
11
- end
11
+ end
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2004-2008 David Heinemeier Hansson
2
- #
2
+ #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
5
5
  # "Software"), to deal in the Software without restriction, including
@@ -7,10 +7,10 @@
7
7
  # distribute, sublicense, and/or sell copies of the Software, and to
8
8
  # permit persons to whom the Software is furnished to do so, subject to
9
9
  # the following conditions:
10
- #
10
+ #
11
11
  # The above copyright notice and this permission notice shall be
12
12
  # included in all copies or substantial portions of the Software.
13
- #
13
+ #
14
14
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
15
  # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
16
  # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -73,7 +73,7 @@ class Class
73
73
  @@#{sym} = obj
74
74
  end
75
75
  RUBY
76
-
76
+
77
77
  unless options[:instance_writer] == false
78
78
  class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
79
79
  def #{sym}=(obj)
@@ -111,14 +111,14 @@ class Class
111
111
  # less useful.
112
112
  def class_inheritable_reader(*ivars)
113
113
  instance_reader = ivars.pop[:reader] if ivars.last.is_a?(Hash)
114
-
114
+
115
115
  ivars.each do |ivar|
116
116
  self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
117
117
  def self.#{ivar}
118
- return @#{ivar} if self == #{self} || defined?(@#{ivar})
118
+ return @#{ivar} if self.object_id == #{self.object_id} || defined?(@#{ivar})
119
119
  ivar = superclass.#{ivar}
120
120
  return nil if ivar.nil? && !#{self}.instance_variable_defined?("@#{ivar}")
121
- @#{ivar} = ivar && !ivar.is_a?(Module) && !ivar.is_a?(Numeric) ? ivar.dup : ivar
121
+ @#{ivar} = ivar && !ivar.is_a?(Module) && !ivar.is_a?(Numeric) && !ivar.is_a?(TrueClass) && !ivar.is_a?(FalseClass) ? ivar.dup : ivar
122
122
  end
123
123
  RUBY
124
124
  unless instance_reader == false
@@ -130,7 +130,7 @@ class Class
130
130
  end
131
131
  end
132
132
  end
133
-
133
+
134
134
  # Defines class-level inheritable attribute writer. Attributes are available to subclasses,
135
135
  # each subclass has a copy of parent's attribute.
136
136
  #
@@ -141,14 +141,14 @@ class Class
141
141
  #
142
142
  # @api public
143
143
  #
144
- # @todo We need a style for class_eval <<-HEREDOC. I'd like to make it
144
+ # @todo We need a style for class_eval <<-HEREDOC. I'd like to make it
145
145
  # class_eval(<<-RUBY, __FILE__, __LINE__), but we should codify it somewhere.
146
146
  def class_inheritable_writer(*ivars)
147
147
  instance_writer = ivars.pop[:instance_writer] if ivars.last.is_a?(Hash)
148
148
  ivars.each do |ivar|
149
149
  self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
150
150
  def self.#{ivar}=(obj)
151
- @#{ivar} = obj
151
+ @#{ivar} = obj
152
152
  end
153
153
  RUBY
154
154
  unless instance_writer == false
@@ -158,11 +158,11 @@ class Class
158
158
  end
159
159
  end
160
160
  end
161
-
161
+
162
162
  # Defines class-level inheritable attribute accessor. Attributes are available to subclasses,
163
163
  # each subclass has a copy of parent's attribute.
164
164
  #
165
- # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
165
+ # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
166
166
  # define inheritable accessor for.
167
167
  # @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined.
168
168
  # @return <Array[#to_s]> An Array of attributes turned into inheritable accessors.
@@ -1,9 +1,27 @@
1
+ require "date"
2
+
1
3
  class DateTime
4
+ ##
5
+ # Convert to Time object (for DateTime/Time conversion protocol).
6
+ #
7
+ # DateTime.now.to_time #=> Wed Nov 19 20:04:51 -0800 2008
8
+ #
9
+ # @return [Time] Time object representing the same moment as receiver
10
+ #
11
+ # @api public
2
12
  def to_time
3
13
  Time.parse self.to_s
4
14
  end
5
-
15
+
16
+ ##
17
+ # Return receiver (for DateTime/Time conversion protocol).
18
+ #
19
+ # DateTime.now.to_datetime #=> #<DateTime: 212093913977/86400,-1/3,2299161>
20
+ #
21
+ # @return [DateTime] Receiver
22
+ #
23
+ # @api public
6
24
  def to_datetime
7
25
  self
8
26
  end
9
- end
27
+ end
@@ -407,7 +407,7 @@ class Dictionary
407
407
  each { |k,v| ary << [k,v] }
408
408
  ary
409
409
  end
410
-
410
+
411
411
  def to_json
412
412
  buf = "["
413
413
  map do |k,v|
@@ -430,4 +430,4 @@ class Dictionary
430
430
  def to_h
431
431
  @hash.dup
432
432
  end
433
- end
433
+ end
@@ -2,15 +2,13 @@ class Hash
2
2
  class << self
3
3
  # Converts valid XML into a Ruby Hash structure.
4
4
  #
5
- # @param xml<String> A string representation of valid XML.
5
+ # Mixed content is treated as text and any tags in it are left unparsed
6
6
  #
7
- # @note Mixed content is treated as text and any tags in it are left unparsed
8
- # @note Any attributes other than type on a node containing a text node will be
9
- # discarded
7
+ # Any attributes other than type on a node containing a text node will be
8
+ # discarded
10
9
  #
11
- # @details [Typecasting]
12
- # Typecasting is performed on elements that have a +type+ attribute:
13
- # integer::
10
+ # [Typecasting is performed on elements that have a +type+ attribute:]
11
+ # integer:: Returns an Integer
14
12
  # boolean:: Anything other than "true" evaluates to false.
15
13
  # datetime::
16
14
  # Returns a Time object. See Time documentation for valid Time strings.
@@ -19,7 +17,8 @@ class Hash
19
17
  #
20
18
  # Keys are automatically converted to +snake_case+
21
19
  #
22
- # @example [Simple]
20
+ # [Simple]
21
+ #
23
22
  # <user gender='m'>
24
23
  # <age type='integer'>35</age>
25
24
  # <name>Home Simpson</name>
@@ -28,7 +27,7 @@ class Hash
28
27
  # <is-cool type='boolean'>true</is-cool>
29
28
  # </user>
30
29
  #
31
- # evaluates to
30
+ # Becomes:
32
31
  #
33
32
  # { "user" => {
34
33
  # "gender" => "m",
@@ -40,48 +39,56 @@ class Hash
40
39
  # }
41
40
  # }
42
41
  #
43
- # @example [Mixed Content]
42
+ # [Mixed Content]
43
+ #
44
44
  # <story>
45
45
  # A Quick <em>brown</em> Fox
46
46
  # </story>
47
47
  #
48
- # evaluates to
48
+ # Evaluates to:
49
49
  #
50
50
  # { "story" => "A Quick <em>brown</em> Fox" }
51
51
  #
52
- # @details [Attributes other than type on a node containing text]
52
+ # [Attributes other than type on a node containing text]
53
+ #
53
54
  # <story is-good='false'>
54
55
  # A Quick <em>brown</em> Fox
55
56
  # </story>
56
57
  #
57
- # evaluates to
58
+ # Are ignored:
58
59
  #
59
60
  # { "story" => "A Quick <em>brown</em> Fox" }
60
61
  #
62
+ # [Other attributes in addition to +type+]
63
+ #
61
64
  # <bicep unit='inches' type='integer'>60</bicep>
62
65
  #
63
- # evaluates with a typecast to an integer. But unit attribute is ignored.
66
+ # Evaluates with a typecast to an integer. But unit attribute is ignored:
64
67
  #
65
68
  # { "bicep" => 60 }
69
+ #
70
+ # @param [String] xml A string representation of valid XML.
71
+ #
72
+ # @return [Hash] A hash created by parsing +xml+
66
73
  def from_xml( xml )
67
74
  ToHashParser.from_xml(xml)
68
75
  end
69
76
  end
70
-
71
- # This class has semantics of ActiveSupport's HashWithIndifferentAccess
72
- # and we only have it so that people can write
77
+
78
+ # Convert to Mash. This class has semantics of ActiveSupport's
79
+ # HashWithIndifferentAccess and we only have it so that people can write
73
80
  # params[:key] instead of params['key'].
74
81
  #
75
- # @return <Mash> This hash as a Mash for string or symbol key access.
82
+ # @return [Mash] This hash as a Mash for string or symbol key access.
76
83
  def to_mash
77
84
  hash = Mash.new(self)
78
85
  hash.default = default
79
86
  hash
80
87
  end
81
88
 
82
- # @return <String> This hash as a query string
89
+ ##
90
+ # Convert to URL query param string
83
91
  #
84
- # @example
85
92
  # { :name => "Bob",
86
93
  # :address => {
87
94
  # :street => '111 Ruby Ave.',
@@ -90,18 +97,27 @@ class Hash
90
97
  # }
91
98
  # }.to_params
92
99
  # #=> "name=Bob&address[city]=Ruby Central&address[phones][]=111-111-1111&address[phones][]=222-222-2222&address[street]=111 Ruby Ave."
100
+ #
101
+ # @return [String] This hash as a query string
102
+ #
103
+ # @api public
93
104
  def to_params
94
105
  params = self.map { |k,v| normalize_param(k,v) }.join
95
106
  params.chop! # trailing &
96
107
  params
97
108
  end
98
109
 
99
- # @param key<Object> The key for the param.
100
- # @param value<Object> The value for the param.
110
+ ##
111
+ # Convert a key, value pair into a URL query param string
112
+ #
113
+ # normalize_param(:name, "Bob") #=> "name=Bob&"
114
+ #
115
+ # @param [Object] key The key for the param.
116
+ # @param [Object] value The value for the param.
101
117
  #
102
118
  # @return <String> This key value pair as a param
103
119
  #
104
- # @example normalize_param(:name, "Bob") #=> "name=Bob&"
120
+ # @api public
105
121
  def normalize_param(key, value)
106
122
  param = ''
107
123
  stack = []
@@ -127,26 +143,33 @@ class Hash
127
143
  param
128
144
  end
129
145
 
130
- # @param *allowed<Array[(String, Symbol)]> The hash keys to include.
146
+ ##
147
+ # Create a hash with *only* key/value pairs in receiver and +allowed+
131
148
  #
132
- # @return <Hash> A new hash with only the selected keys.
149
+ # { :one => 1, :two => 2, :three => 3 }.only(:one) #=> { :one => 1 }
133
150
  #
134
- # @example
135
- # { :one => 1, :two => 2, :three => 3 }.only(:one)
136
- # #=> { :one => 1 }
151
+ # @param [Array[String, Symbol]] *allowed The hash keys to include.
152
+ #
153
+ # @return [Hash] A new hash with only the selected keys.
154
+ #
155
+ # @api public
137
156
  def only(*allowed)
138
157
  hash = {}
139
158
  allowed.each {|k| hash[k] = self[k] if self.has_key?(k) }
140
159
  hash
141
160
  end
142
161
 
143
- # @param *rejected<Array[(String, Symbol)] The hash keys to exclude.
144
- #
145
- # @return <Hash> A new hash without the selected keys.
162
+ ##
163
+ # Create a hash with all key/value pairs in receiver *except* +rejected+
146
164
  #
147
- # @example
148
- # { :one => 1, :two => 2, :three => 3 }.except(:one)
165
+ # { :one => 1, :two => 2, :three => 3 }.except(:one)
149
166
  # #=> { :two => 2, :three => 3 }
167
+ #
168
+ # @param [Array[String, Symbol]] *rejected The hash keys to exclude.
169
+ #
170
+ # @return [Hash] A new hash without the selected keys.
171
+ #
172
+ # @api public
150
173
  def except(*rejected)
151
174
  hash = self.dup
152
175
  rejected.each {|k| hash.delete(k) }
@@ -188,7 +211,7 @@ class Hash
188
211
  #
189
212
  # @return <Array> An array of they hash's keys
190
213
  #
191
- # @example
214
+ # @example
192
215
  # hash = { One => 1, Two => 2 }.proctect_keys!
193
216
  # hash # => { "One" => 1, "Two" => 2 }
194
217
  def protect_keys!