merb-core 0.9.2 → 0.9.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.
Files changed (104) hide show
  1. data/Rakefile +61 -11
  2. data/bin/merb +5 -1
  3. data/lib/merb-core.rb +202 -25
  4. data/lib/merb-core/autoload.rb +19 -17
  5. data/lib/merb-core/bootloader.rb +84 -71
  6. data/lib/merb-core/config.rb +19 -14
  7. data/lib/merb-core/controller/abstract_controller.rb +16 -17
  8. data/lib/merb-core/controller/exceptions.rb +115 -70
  9. data/lib/merb-core/controller/merb_controller.rb +62 -38
  10. data/lib/merb-core/controller/mime.rb +1 -1
  11. data/lib/merb-core/controller/mixins/authentication.rb +87 -0
  12. data/lib/merb-core/controller/mixins/controller.rb +16 -15
  13. data/lib/merb-core/controller/mixins/render.rb +113 -19
  14. data/lib/merb-core/controller/mixins/responder.rb +8 -2
  15. data/lib/merb-core/controller/template.rb +1 -1
  16. data/lib/merb-core/core_ext.rb +1 -0
  17. data/lib/merb-core/core_ext/class.rb +113 -6
  18. data/lib/merb-core/core_ext/hash.rb +43 -39
  19. data/lib/merb-core/core_ext/kernel.rb +75 -38
  20. data/lib/merb-core/core_ext/mash.rb +4 -4
  21. data/lib/merb-core/core_ext/object.rb +18 -7
  22. data/lib/merb-core/core_ext/set.rb +9 -4
  23. data/lib/merb-core/core_ext/string.rb +29 -9
  24. data/lib/merb-core/core_ext/time.rb +13 -0
  25. data/lib/merb-core/dispatch/cookies.rb +1 -2
  26. data/lib/merb-core/dispatch/dispatcher.rb +18 -10
  27. data/lib/merb-core/dispatch/exceptions.html.erb +1 -1
  28. data/lib/merb-core/dispatch/request.rb +3 -0
  29. data/lib/merb-core/dispatch/router.rb +10 -7
  30. data/lib/merb-core/dispatch/router/behavior.rb +36 -27
  31. data/lib/merb-core/dispatch/router/route.rb +7 -2
  32. data/lib/merb-core/dispatch/session/cookie.rb +4 -4
  33. data/lib/merb-core/dispatch/session/memcached.rb +17 -5
  34. data/lib/merb-core/logger.rb +2 -2
  35. data/lib/merb-core/plugins.rb +16 -4
  36. data/lib/merb-core/rack/adapter/ebb.rb +4 -1
  37. data/lib/merb-core/rack/adapter/evented_mongrel.rb +2 -0
  38. data/lib/merb-core/rack/adapter/fcgi.rb +1 -0
  39. data/lib/merb-core/rack/adapter/mongrel.rb +1 -0
  40. data/lib/merb-core/rack/adapter/runner.rb +1 -0
  41. data/lib/merb-core/rack/adapter/thin.rb +3 -1
  42. data/lib/merb-core/rack/adapter/webrick.rb +1 -0
  43. data/lib/merb-core/rack/application.rb +17 -1
  44. data/lib/merb-core/server.rb +78 -28
  45. data/lib/merb-core/test/helpers/multipart_request_helper.rb +3 -3
  46. data/lib/merb-core/test/helpers/request_helper.rb +81 -27
  47. data/lib/merb-core/test/helpers/view_helper.rb +1 -1
  48. data/lib/merb-core/test/matchers/controller_matchers.rb +55 -5
  49. data/lib/merb-core/test/matchers/route_matchers.rb +8 -17
  50. data/lib/merb-core/test/matchers/view_matchers.rb +53 -11
  51. data/lib/merb-core/test/run_specs.rb +22 -14
  52. data/lib/merb-core/test/tasks/spectasks.rb +54 -33
  53. data/lib/merb-core/vendor/facets/inflect.rb +91 -2
  54. data/lib/merb-core/version.rb +2 -2
  55. data/spec/private/config/config_spec.rb +54 -26
  56. data/spec/private/core_ext/class_spec.rb +22 -0
  57. data/spec/private/core_ext/hash_spec.rb +70 -54
  58. data/spec/private/core_ext/kernel_spec.rb +149 -14
  59. data/spec/private/core_ext/object_spec.rb +92 -10
  60. data/spec/private/core_ext/string_spec.rb +162 -4
  61. data/spec/private/core_ext/time_spec.rb +16 -0
  62. data/spec/private/dispatch/bootloader_spec.rb +24 -0
  63. data/spec/private/dispatch/fixture/app/views/exeptions/client_error.html.erb +1 -1
  64. data/spec/private/dispatch/fixture/app/views/exeptions/internal_server_error.html.erb +1 -1
  65. data/spec/private/dispatch/fixture/app/views/exeptions/not_acceptable.html.erb +1 -1
  66. data/spec/private/dispatch/fixture/app/views/exeptions/not_found.html.erb +1 -1
  67. data/spec/private/dispatch/fixture/config/black_hole.rb +12 -0
  68. data/spec/private/dispatch/fixture/log/merb_test.log +138 -0
  69. data/spec/private/plugins/plugin_spec.rb +79 -8
  70. data/spec/private/rack/application_spec.rb +1 -1
  71. data/spec/public/abstract_controller/controllers/filters.rb +26 -0
  72. data/spec/public/abstract_controller/controllers/helpers.rb +2 -2
  73. data/spec/public/abstract_controller/controllers/partial.rb +2 -2
  74. data/spec/public/abstract_controller/controllers/render.rb +16 -4
  75. data/spec/public/abstract_controller/filter_spec.rb +8 -0
  76. data/spec/public/abstract_controller/render_spec.rb +12 -0
  77. data/spec/public/controller/authentication_spec.rb +103 -0
  78. data/spec/public/controller/base_spec.rb +4 -3
  79. data/spec/public/controller/controllers/authentication.rb +47 -0
  80. data/spec/public/controller/controllers/base.rb +1 -0
  81. data/spec/public/controller/controllers/display.rb +30 -0
  82. data/spec/public/controller/controllers/views/layout/custom_arg.html.erb +1 -0
  83. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/display_with_template_argument/index.html.erb +1 -0
  84. data/spec/public/controller/display_spec.rb +17 -0
  85. data/spec/public/controller/spec_helper.rb +1 -0
  86. data/spec/public/controller/url_spec.rb +25 -7
  87. data/spec/public/core/merb_core_spec.rb +34 -0
  88. data/spec/public/directory_structure/directory/app/controllers/custom.rb +2 -2
  89. data/spec/public/directory_structure/directory/log/merb_test.log +48 -0
  90. data/spec/public/logger/logger_spec.rb +10 -4
  91. data/spec/public/reloading/directory/app/controllers/reload.rb +1 -1
  92. data/spec/public/reloading/directory/log/merb_test.log +13 -0
  93. data/spec/public/reloading/reload_spec.rb +23 -22
  94. data/spec/public/request/request_spec.rb +2 -0
  95. data/spec/public/router/nested_resources_spec.rb +7 -0
  96. data/spec/public/router/resources_spec.rb +46 -1
  97. data/spec/public/router/special_spec.rb +5 -1
  98. data/spec/public/test/controller_matchers_spec.rb +25 -1
  99. data/spec/public/test/controllers/spec_helper_controller.rb +8 -0
  100. data/spec/public/test/request_helper_spec.rb +52 -1
  101. data/spec/public/test/route_matchers_spec.rb +27 -25
  102. data/spec/public/test/view_helper_spec.rb +1 -1
  103. data/spec/public/test/view_matchers_spec.rb +148 -72
  104. metadata +23 -3
@@ -1,5 +1,6 @@
1
1
  require 'enumerator'
2
2
  require 'merb-core/controller/mime'
3
+ require "merb-core/vendor/facets/dictionary"
3
4
  module Merb
4
5
  # The ResponderMixin adds methods that help you manage what
5
6
  # formats your controllers have available, determine what format(s)
@@ -96,7 +97,7 @@ module Merb
96
97
  # and none of the provides methods can be used.
97
98
  module ResponderMixin
98
99
 
99
- TYPES = {}
100
+ TYPES = Dictionary.new
100
101
 
101
102
  class ContentTypeAlreadySet < StandardError; end
102
103
 
@@ -294,7 +295,12 @@ module Merb
294
295
  specifics = accepts & _provided_formats
295
296
  return specifics.first unless specifics.length == 0
296
297
  return _provided_formats.first if accepts.include? :all
297
- raise Merb::ControllerExceptions::NotAcceptable
298
+ message = "A format (%s) that isn't provided (%s) has been requested. "
299
+ message += "Make sure the action provides the format, and be "
300
+ message += "careful of before filters which won't recognize "
301
+ message += "formats provided within actions."
302
+ raise Merb::ControllerExceptions::NotAcceptable,
303
+ (message % [accepts.join(', '), _provided_formats.join(', ')])
298
304
  end
299
305
 
300
306
  # Returns the output format for this request, based on the
@@ -67,7 +67,7 @@ module Merb::Template
67
67
  # The module to put the compiled method into. Defaults to
68
68
  # Merb::InlineTemplates
69
69
  #
70
- # ==== Note
70
+ # ==== Notes
71
71
  # Even though this method supports inlining into any module, the method
72
72
  # must be available to instances of AbstractController that will use it.
73
73
  #---
@@ -1,6 +1,7 @@
1
1
  corelib = File.join(File.dirname(__FILE__), "core_ext")
2
2
 
3
3
  require "#{corelib}/string"
4
+ require corelib/:time
4
5
  require corelib/:class
5
6
  require corelib/:hash
6
7
  require corelib/:kernel
@@ -4,8 +4,11 @@
4
4
  # example, an array without those additions being shared with either their
5
5
  # parent, siblings, or children, which is unlike the regular class-level
6
6
  # attributes that are shared across the entire hierarchy.
7
- class Class # :nodoc:
8
-
7
+ class Class
8
+ # Defines class-level and instance-level attribute reader.
9
+ #
10
+ # ==== Parameters
11
+ # *syms<Array>:: Array of attributes to define reader for.
9
12
  def cattr_reader(*syms)
10
13
  syms.flatten.each do |sym|
11
14
  next if sym.is_a?(Hash)
@@ -25,6 +28,13 @@ class Class # :nodoc:
25
28
  end
26
29
  end
27
30
 
31
+ # Defines class-level (and optionally instance-level) attribute writer.
32
+ #
33
+ # ==== Parameters
34
+ # *syms<Array>:: Array of attributes to define writer for.
35
+ #
36
+ # ==== Options
37
+ # :instance_writer<Boolean>:: if true, instance-level attribute writer is defined.
28
38
  def cattr_writer(*syms)
29
39
  options = syms.last.is_a?(Hash) ? syms.pop : {}
30
40
  syms.flatten.each do |sym|
@@ -47,11 +57,23 @@ class Class # :nodoc:
47
57
  end
48
58
  end
49
59
 
60
+ # Defines class-level (and optionally instance-level) attribute accessor.
61
+ #
62
+ # ==== Parameters
63
+ # *syms<Array>:: Array of attributes to define accessor for.
64
+ #
65
+ # ==== Options
66
+ # :instance_writer<Boolean>:: if true, instance-level attribute writer is defined.
50
67
  def cattr_accessor(*syms)
51
68
  cattr_reader(*syms)
52
69
  cattr_writer(*syms)
53
70
  end
54
71
 
72
+ # Defines class-level inheritable attribute reader. Attributes are available to subclasses,
73
+ # each subclass has a copy of parent's attribute.
74
+ #
75
+ # ==== Parameters
76
+ # *syms<Array>:: Array of attributes to define inheritable reader for.
55
77
  def class_inheritable_reader(*syms)
56
78
  syms.each do |sym|
57
79
  next if sym.is_a?(Hash)
@@ -68,6 +90,14 @@ class Class # :nodoc:
68
90
  end
69
91
  end
70
92
 
93
+ # Defines class-level inheritable attribute writer. Attributes are available to subclasses,
94
+ # each subclass has a copy of parent's attribute.
95
+ #
96
+ # ==== Parameters
97
+ # *syms<Array>:: Array of attributes to define inheritable writer for.
98
+ #
99
+ # ==== Options
100
+ # :instance_writer<Boolean>:: if true, instance-level inheritable attribute writer is defined.
71
101
  def class_inheritable_writer(*syms)
72
102
  options = syms.last.is_a?(Hash) ? syms.pop : {}
73
103
  syms.each do |sym|
@@ -87,6 +117,15 @@ class Class # :nodoc:
87
117
  end
88
118
  end
89
119
 
120
+ # Defines class-level inheritable array writer. Arrays are available to subclasses,
121
+ # each subclass has a copy of parent's array. Difference between other inheritable
122
+ # attributes is that array is recreated every time it is written.
123
+ #
124
+ # ==== Parameters
125
+ # *syms<Array>:: Array of array attribute names to define inheritable writer for.
126
+ #
127
+ # ==== Options
128
+ # :instance_writer<Boolean>:: if true, instance-level inheritable array attribute writer is defined.
90
129
  def class_inheritable_array_writer(*syms)
91
130
  options = syms.last.is_a?(Hash) ? syms.pop : {}
92
131
  syms.each do |sym|
@@ -106,6 +145,15 @@ class Class # :nodoc:
106
145
  end
107
146
  end
108
147
 
148
+ # Defines class-level inheritable hash writer. Hashs are available to subclasses,
149
+ # each subclass has a copy of parent's hash. Difference between other inheritable
150
+ # attributes is that hash is recreated every time it is written.
151
+ #
152
+ # ==== Parameters
153
+ # *syms<Array>:: Array of hash attribute names to define inheritable writer for.
154
+ #
155
+ # ==== Options
156
+ # :instance_writer<Boolean>:: if true, instance-level inheritable hash attribute writer is defined.
109
157
  def class_inheritable_hash_writer(*syms)
110
158
  options = syms.last.is_a?(Hash) ? syms.pop : {}
111
159
  syms.each do |sym|
@@ -125,25 +173,62 @@ class Class # :nodoc:
125
173
  end
126
174
  end
127
175
 
176
+ # Defines class-level inheritable attribute accessor. Attributes are available to subclasses,
177
+ # each subclass has a copy of parent's attribute.
178
+ #
179
+ # ==== Parameters
180
+ # *syms<Array>:: Array of attributes to define inheritable accessor for.
181
+ #
182
+ # ==== Options
183
+ # :instance_writer<Boolean>:: if true, instance-level inheritable attribute writer is defined.
128
184
  def class_inheritable_accessor(*syms)
129
185
  class_inheritable_reader(*syms)
130
186
  class_inheritable_writer(*syms)
131
187
  end
132
188
 
189
+ # Defines class-level inheritable array accessor. Arrays are available to subclasses,
190
+ # each subclass has a copy of parent's array. Difference between other inheritable
191
+ # attributes is that array is recreated every time it is written.
192
+ #
193
+ # ==== Parameters
194
+ # *syms<Array>:: Array of array attribute names to define inheritable accessor for.
195
+ #
196
+ # ==== Options
197
+ # :instance_writer<Boolean>:: if true, instance-level inheritable array attribute writer is defined.
133
198
  def class_inheritable_array(*syms)
134
199
  class_inheritable_reader(*syms)
135
200
  class_inheritable_array_writer(*syms)
136
201
  end
137
202
 
203
+ # Defines class-level inheritable hash accessor. Hashs are available to subclasses,
204
+ # each subclass has a copy of parent's hash. Difference between other inheritable
205
+ # attributes is that hash is recreated every time it is written.
206
+ #
207
+ # ==== Parameters
208
+ # *syms<Array>:: Array of hash attribute names to define inheritable accessor for.
209
+ #
210
+ # ==== Options
211
+ # :instance_writer<Boolean>:: if true, instance-level inheritable hash attribute writer is defined.
138
212
  def class_inheritable_hash(*syms)
139
213
  class_inheritable_reader(*syms)
140
214
  class_inheritable_hash_writer(*syms)
141
215
  end
142
216
 
217
+ # ==== Returns
218
+ # <Hash>:: inheritable attributes hash or it's default value, new frozen Hash.
143
219
  def inheritable_attributes
144
220
  @inheritable_attributes ||= EMPTY_INHERITABLE_ATTRIBUTES
145
221
  end
146
222
 
223
+ # Sets the attribute which copy is available to subclasses.
224
+ #
225
+ # ==== Parameters
226
+ # key<~to_s, String, Symbol>:: inheritable attribute name
227
+ # value<Anything but Array or Hash>:: value of inheritable attribute
228
+ #
229
+ # ==== Notes
230
+ # If inheritable attributes storage has it's default value,
231
+ # a new frozen hash, it is set to new Hash that is not frozen.
147
232
  def write_inheritable_attribute(key, value)
148
233
  if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
149
234
  @inheritable_attributes = {}
@@ -151,31 +236,53 @@ class Class # :nodoc:
151
236
  inheritable_attributes[key] = value
152
237
  end
153
238
 
239
+ # Sets the array attribute which copy is available to subclasses.
240
+ #
241
+ # ==== Parameters
242
+ # key<~to_s, String, Symbol>:: inheritable attribute name
243
+ # value<Array>:: value of inheritable attribute
244
+ #
245
+ # ==== Notes
246
+ # Inheritable array is re-created on each write.
154
247
  def write_inheritable_array(key, elements)
155
248
  write_inheritable_attribute(key, []) if read_inheritable_attribute(key).nil?
156
249
  write_inheritable_attribute(key, read_inheritable_attribute(key) + elements)
157
250
  end
158
251
 
252
+ # Sets the hash attribute which copy is available to subclasses.
253
+ #
254
+ # ==== Parameters
255
+ # key<~to_s, String, Symbol>:: inheritable attribute name
256
+ # value<Hash>:: value of inheritable attribute
257
+ #
258
+ # ==== Notes
259
+ # Inheritable hash is re-created on each write.
159
260
  def write_inheritable_hash(key, hash)
160
261
  write_inheritable_attribute(key, {}) if read_inheritable_attribute(key).nil?
161
262
  write_inheritable_attribute(key, read_inheritable_attribute(key).merge(hash))
162
263
  end
163
264
 
265
+ # Reads value of inheritable attributes.
266
+ #
267
+ # ==== Returns
268
+ # Inheritable attribute value. Subclasses store copies of values.
164
269
  def read_inheritable_attribute(key)
165
270
  inheritable_attributes[key]
166
271
  end
167
272
 
273
+ # Resets inheritable attributes to either EMPTY_INHERITABLE_ATTRIBUTES
274
+ # if it is defined or it's default value, new frozen Hash.
168
275
  def reset_inheritable_attributes
169
276
  @inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
170
277
  end
171
-
278
+
172
279
  private
173
280
  # Prevent this constant from being created multiple times
174
281
  EMPTY_INHERITABLE_ATTRIBUTES = {}.freeze unless const_defined?(:EMPTY_INHERITABLE_ATTRIBUTES)
175
282
 
176
283
  def inherited_with_inheritable_attributes(child)
177
284
  inherited_without_inheritable_attributes(child) if respond_to?(:inherited_without_inheritable_attributes)
178
-
285
+
179
286
  if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
180
287
  new_inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
181
288
  else
@@ -183,10 +290,10 @@ class Class # :nodoc:
183
290
  memo.update(key => (value.dup rescue value))
184
291
  end
185
292
  end
186
-
293
+
187
294
  child.instance_variable_set('@inheritable_attributes', new_inheritable_attributes)
188
295
  end
189
296
 
190
297
  alias inherited_without_inheritable_attributes inherited
191
298
  alias inherited inherited_with_inheritable_attributes
192
- end
299
+ end
@@ -14,13 +14,13 @@ class Hash
14
14
  #
15
15
  # ===== Typecasting
16
16
  # Typecasting is performed on elements that have a +type+ attribute:
17
- # integer::
17
+ # integer::
18
18
  # boolean:: Anything other than "true" evaluates to false.
19
19
  # datetime::
20
20
  # Returns a Time object. See Time documentation for valid Time strings.
21
21
  # date::
22
22
  # Returns a Date object. See Date documentation for valid Date strings.
23
- #
23
+ #
24
24
  # Keys are automatically converted to +snake_case+
25
25
  #
26
26
  # ==== Examples
@@ -34,15 +34,15 @@ class Hash
34
34
  # <is-cool type='boolean'>true</is-cool>
35
35
  # </user>
36
36
  #
37
- # evaluates to
38
- #
39
- # { "user" => {
37
+ # evaluates to
38
+ #
39
+ # { "user" => {
40
40
  # "gender" => "m",
41
41
  # "age" => 35,
42
42
  # "name" => "Home Simpson",
43
43
  # "dob" => DateObject( 1998-01-01 ),
44
44
  # "joined_at" => TimeObject( 2000-04-28 23:01),
45
- # "is_cool" => true
45
+ # "is_cool" => true
46
46
  # }
47
47
  # }
48
48
  #
@@ -54,7 +54,7 @@ class Hash
54
54
  # evaluates to
55
55
  #
56
56
  # { "story" => "A Quick <em>brown</em> Fox" }
57
- #
57
+ #
58
58
  # ====== Attributes other than type on a node containing text
59
59
  # <story is-good='false'>
60
60
  # A Quick <em>brown</em> Fox
@@ -73,15 +73,19 @@ class Hash
73
73
  ToHashParser.from_xml(xml)
74
74
  end
75
75
  end
76
-
76
+
77
77
  # ==== Returns
78
78
  # Mash:: This hash as a Mash for string or symbol key access.
79
+ #
80
+ # This class has semantics of ActiveSupport's HashWithIndifferentAccess
81
+ # and we only have it so that people can write
82
+ # params[:key] instead of params['key'].
79
83
  def to_mash
80
84
  hash = Mash.new(self)
81
85
  hash.default = default
82
86
  hash
83
87
  end
84
-
88
+
85
89
  # ==== Returns
86
90
  # String:: This hash as a query string
87
91
  #
@@ -97,7 +101,7 @@ class Hash
97
101
  def to_params
98
102
  params = ''
99
103
  stack = []
100
-
104
+
101
105
  each do |k, v|
102
106
  if v.is_a?(Hash)
103
107
  stack << [k,v]
@@ -105,7 +109,7 @@ class Hash
105
109
  params << "#{k}=#{v}&"
106
110
  end
107
111
  end
108
-
112
+
109
113
  stack.each do |parent, hash|
110
114
  hash.each do |k, v|
111
115
  if v.is_a?(Hash)
@@ -115,11 +119,11 @@ class Hash
115
119
  end
116
120
  end
117
121
  end
118
-
122
+
119
123
  params.chop! # trailing &
120
124
  params
121
125
  end
122
-
126
+
123
127
  # ==== Parameters
124
128
  # *allowed:: The hash keys to include.
125
129
  #
@@ -129,10 +133,10 @@ class Hash
129
133
  # ==== Examples
130
134
  # { :one => 1, :two => 2, :three => 3 }.only(:one)
131
135
  # #=> { :one => 1 }
132
- def only(*allowed)
136
+ def only(*allowed)
133
137
  reject { |k,v| !allowed.include?(k) }
134
138
  end
135
-
139
+
136
140
  # ==== Parameters
137
141
  # *rejected:: The hash keys to exclude.
138
142
  #
@@ -142,10 +146,10 @@ class Hash
142
146
  # ==== Examples
143
147
  # { :one => 1, :two => 2, :three => 3 }.except(:one)
144
148
  # #=> { :two => 2, :three => 3 }
145
- def except(*rejected)
149
+ def except(*rejected)
146
150
  reject { |k,v| rejected.include?(k) }
147
151
  end
148
-
152
+
149
153
  # ==== Returns
150
154
  # String:: The hash as attributes for an XML tag.
151
155
  #
@@ -154,12 +158,12 @@ class Hash
154
158
  # #=> 'one="1" two="TWO"'
155
159
  def to_xml_attributes
156
160
  map do |k,v|
157
- %{#{k.to_s.camel_case.sub(/^(.{1,1})/) { |m| m.downcase }}="#{v}"}
161
+ %{#{k.to_s.camel_case.sub(/^(.{1,1})/) { |m| m.downcase }}="#{v}"}
158
162
  end.join(' ')
159
163
  end
160
-
164
+
161
165
  alias_method :to_html_attributes, :to_xml_attributes
162
-
166
+
163
167
  # ==== Parameters
164
168
  # html_class<~to_s>::
165
169
  # The HTML class to add to the :class key. The html_class will be
@@ -178,7 +182,7 @@ class Hash
178
182
  self[:class] = html_class.to_s
179
183
  end
180
184
  end
181
-
185
+
182
186
  # Converts all keys into string values. This is used during reloading to
183
187
  # prevent problems when classes are no longer declared.
184
188
  #
@@ -188,7 +192,7 @@ class Hash
188
192
  def protect_keys!
189
193
  keys.each {|key| self[key.to_s] = delete(key) }
190
194
  end
191
-
195
+
192
196
  # Attempts to convert all string keys into Class keys. We run this after
193
197
  # reloading to convert protected hashes back into usable hashes.
194
198
  #
@@ -197,11 +201,11 @@ class Hash
197
201
  # hash = { "One" => 1, "Two" => 2 }.unproctect_keys!
198
202
  # hash # => { One => 1, Two => 2 }
199
203
  def unprotect_keys!
200
- keys.each do |key|
204
+ keys.each do |key|
201
205
  (self[Object.full_const_get(key)] = delete(key)) rescue nil
202
206
  end
203
207
  end
204
-
208
+
205
209
  # Destructively and non-recursively convert each key to an uppercase string,
206
210
  # deleting nil values along the way.
207
211
  #
@@ -218,7 +222,7 @@ class Hash
218
222
  self[key.to_s.upcase] = val
219
223
  end
220
224
  self
221
- end
225
+ end
222
226
  end
223
227
 
224
228
  require 'rexml/parsers/streamparser'
@@ -233,7 +237,7 @@ require 'rexml/light/node'
233
237
  class REXMLUtilityNode # :nodoc:
234
238
  attr_accessor :name, :attributes, :children, :type
235
239
  cattr_accessor :typecasts, :available_typecasts
236
-
240
+
237
241
  self.typecasts = {}
238
242
  self.typecasts["integer"] = lambda{|v| v.nil? ? nil : v.to_i}
239
243
  self.typecasts["boolean"] = lambda{|v| v.nil? ? nil : (v.strip != "false")}
@@ -247,14 +251,14 @@ class REXMLUtilityNode # :nodoc:
247
251
  self.typecasts["string"] = lambda{|v| v.to_s}
248
252
  self.typecasts["yaml"] = lambda{|v| v.nil? ? nil : YAML.load(v)}
249
253
  self.typecasts["base64Binary"] = lambda{|v| Base64.decode64(v)}
250
-
254
+
251
255
  self.available_typecasts = self.typecasts.keys
252
256
 
253
257
  def initialize(name, attributes = {})
254
258
  @name = name.tr("-", "_")
255
259
  # leave the type alone if we don't know what it is
256
260
  @type = self.class.available_typecasts.include?(attributes["type"]) ? attributes.delete("type") : attributes["type"]
257
-
261
+
258
262
  @nil_element = attributes.delete("nil") == "true"
259
263
  @attributes = undasherize_keys(attributes)
260
264
  @children = []
@@ -268,7 +272,7 @@ class REXMLUtilityNode # :nodoc:
268
272
 
269
273
  def to_hash
270
274
  if @type == "file"
271
- f = StringIO.new(::Base64.decode64(@children.first || ""))
275
+ f = StringIO.new(::Base64.decode64(@children.first || ""))
272
276
  class << f
273
277
  attr_accessor :original_filename, :content_type
274
278
  end
@@ -276,13 +280,13 @@ class REXMLUtilityNode # :nodoc:
276
280
  f.content_type = attributes['content_type'] || 'application/octet-stream'
277
281
  return {name => f}
278
282
  end
279
-
283
+
280
284
  if @text
281
285
  return { name => typecast_value( translate_xml_entities( inner_html ) ) }
282
286
  else
283
287
  #change repeating groups into an array
284
288
  groups = @children.inject({}) { |s,e| (s[e.name] ||= []) << e; s }
285
-
289
+
286
290
  out = nil
287
291
  if @type == "array"
288
292
  out = []
@@ -294,7 +298,7 @@ class REXMLUtilityNode # :nodoc:
294
298
  end
295
299
  end
296
300
  out = out.flatten
297
-
301
+
298
302
  else # If Hash
299
303
  out = {}
300
304
  groups.each do |k,v|
@@ -322,11 +326,11 @@ class REXMLUtilityNode # :nodoc:
322
326
  #
323
327
  # ==== Parameters
324
328
  # value<String>:: The value that is being typecast.
325
- #
329
+ #
326
330
  # ==== :type options
327
- # "integer"::
331
+ # "integer"::
328
332
  # converts +value+ to an integer with #to_i
329
- # "boolean"::
333
+ # "boolean"::
330
334
  # checks whether +value+, after removing spaces, is the literal
331
335
  # "true"
332
336
  # "datetime"::
@@ -338,7 +342,7 @@ class REXMLUtilityNode # :nodoc:
338
342
  # Integer, true, false, Time, Date, Object::
339
343
  # The result of typecasting +value+.
340
344
  #
341
- # ==== Note
345
+ # ==== Notes
342
346
  # If +self+ does not have a "type" key, or if it's not one of the
343
347
  # options specified above, the raw +value+ will be returned.
344
348
  def typecast_value(value)
@@ -388,7 +392,7 @@ class REXMLUtilityNode # :nodoc:
388
392
 
389
393
  # ==== Alias
390
394
  # #to_html
391
- def to_s
395
+ def to_s
392
396
  to_html
393
397
  end
394
398
  end
@@ -398,7 +402,7 @@ class ToHashParser # :nodoc:
398
402
  def self.from_xml(xml)
399
403
  stack = []
400
404
  parser = REXML::Parsers::BaseParser.new(xml)
401
-
405
+
402
406
  while true
403
407
  event = parser.pull
404
408
  case event[0]
@@ -419,4 +423,4 @@ class ToHashParser # :nodoc:
419
423
  end
420
424
  stack.pop.to_hash
421
425
  end
422
- end
426
+ end