merb-core 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
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