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.
- data/Rakefile +61 -11
- data/bin/merb +5 -1
- data/lib/merb-core.rb +202 -25
- data/lib/merb-core/autoload.rb +19 -17
- data/lib/merb-core/bootloader.rb +84 -71
- data/lib/merb-core/config.rb +19 -14
- data/lib/merb-core/controller/abstract_controller.rb +16 -17
- data/lib/merb-core/controller/exceptions.rb +115 -70
- data/lib/merb-core/controller/merb_controller.rb +62 -38
- data/lib/merb-core/controller/mime.rb +1 -1
- data/lib/merb-core/controller/mixins/authentication.rb +87 -0
- data/lib/merb-core/controller/mixins/controller.rb +16 -15
- data/lib/merb-core/controller/mixins/render.rb +113 -19
- data/lib/merb-core/controller/mixins/responder.rb +8 -2
- data/lib/merb-core/controller/template.rb +1 -1
- data/lib/merb-core/core_ext.rb +1 -0
- data/lib/merb-core/core_ext/class.rb +113 -6
- data/lib/merb-core/core_ext/hash.rb +43 -39
- data/lib/merb-core/core_ext/kernel.rb +75 -38
- data/lib/merb-core/core_ext/mash.rb +4 -4
- data/lib/merb-core/core_ext/object.rb +18 -7
- data/lib/merb-core/core_ext/set.rb +9 -4
- data/lib/merb-core/core_ext/string.rb +29 -9
- data/lib/merb-core/core_ext/time.rb +13 -0
- data/lib/merb-core/dispatch/cookies.rb +1 -2
- data/lib/merb-core/dispatch/dispatcher.rb +18 -10
- data/lib/merb-core/dispatch/exceptions.html.erb +1 -1
- data/lib/merb-core/dispatch/request.rb +3 -0
- data/lib/merb-core/dispatch/router.rb +10 -7
- data/lib/merb-core/dispatch/router/behavior.rb +36 -27
- data/lib/merb-core/dispatch/router/route.rb +7 -2
- data/lib/merb-core/dispatch/session/cookie.rb +4 -4
- data/lib/merb-core/dispatch/session/memcached.rb +17 -5
- data/lib/merb-core/logger.rb +2 -2
- data/lib/merb-core/plugins.rb +16 -4
- data/lib/merb-core/rack/adapter/ebb.rb +4 -1
- data/lib/merb-core/rack/adapter/evented_mongrel.rb +2 -0
- data/lib/merb-core/rack/adapter/fcgi.rb +1 -0
- data/lib/merb-core/rack/adapter/mongrel.rb +1 -0
- data/lib/merb-core/rack/adapter/runner.rb +1 -0
- data/lib/merb-core/rack/adapter/thin.rb +3 -1
- data/lib/merb-core/rack/adapter/webrick.rb +1 -0
- data/lib/merb-core/rack/application.rb +17 -1
- data/lib/merb-core/server.rb +78 -28
- data/lib/merb-core/test/helpers/multipart_request_helper.rb +3 -3
- data/lib/merb-core/test/helpers/request_helper.rb +81 -27
- data/lib/merb-core/test/helpers/view_helper.rb +1 -1
- data/lib/merb-core/test/matchers/controller_matchers.rb +55 -5
- data/lib/merb-core/test/matchers/route_matchers.rb +8 -17
- data/lib/merb-core/test/matchers/view_matchers.rb +53 -11
- data/lib/merb-core/test/run_specs.rb +22 -14
- data/lib/merb-core/test/tasks/spectasks.rb +54 -33
- data/lib/merb-core/vendor/facets/inflect.rb +91 -2
- data/lib/merb-core/version.rb +2 -2
- data/spec/private/config/config_spec.rb +54 -26
- data/spec/private/core_ext/class_spec.rb +22 -0
- data/spec/private/core_ext/hash_spec.rb +70 -54
- data/spec/private/core_ext/kernel_spec.rb +149 -14
- data/spec/private/core_ext/object_spec.rb +92 -10
- data/spec/private/core_ext/string_spec.rb +162 -4
- data/spec/private/core_ext/time_spec.rb +16 -0
- data/spec/private/dispatch/bootloader_spec.rb +24 -0
- data/spec/private/dispatch/fixture/app/views/exeptions/client_error.html.erb +1 -1
- data/spec/private/dispatch/fixture/app/views/exeptions/internal_server_error.html.erb +1 -1
- data/spec/private/dispatch/fixture/app/views/exeptions/not_acceptable.html.erb +1 -1
- data/spec/private/dispatch/fixture/app/views/exeptions/not_found.html.erb +1 -1
- data/spec/private/dispatch/fixture/config/black_hole.rb +12 -0
- data/spec/private/dispatch/fixture/log/merb_test.log +138 -0
- data/spec/private/plugins/plugin_spec.rb +79 -8
- data/spec/private/rack/application_spec.rb +1 -1
- data/spec/public/abstract_controller/controllers/filters.rb +26 -0
- data/spec/public/abstract_controller/controllers/helpers.rb +2 -2
- data/spec/public/abstract_controller/controllers/partial.rb +2 -2
- data/spec/public/abstract_controller/controllers/render.rb +16 -4
- data/spec/public/abstract_controller/filter_spec.rb +8 -0
- data/spec/public/abstract_controller/render_spec.rb +12 -0
- data/spec/public/controller/authentication_spec.rb +103 -0
- data/spec/public/controller/base_spec.rb +4 -3
- data/spec/public/controller/controllers/authentication.rb +47 -0
- data/spec/public/controller/controllers/base.rb +1 -0
- data/spec/public/controller/controllers/display.rb +30 -0
- data/spec/public/controller/controllers/views/layout/custom_arg.html.erb +1 -0
- data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/display_with_template_argument/index.html.erb +1 -0
- data/spec/public/controller/display_spec.rb +17 -0
- data/spec/public/controller/spec_helper.rb +1 -0
- data/spec/public/controller/url_spec.rb +25 -7
- data/spec/public/core/merb_core_spec.rb +34 -0
- data/spec/public/directory_structure/directory/app/controllers/custom.rb +2 -2
- data/spec/public/directory_structure/directory/log/merb_test.log +48 -0
- data/spec/public/logger/logger_spec.rb +10 -4
- data/spec/public/reloading/directory/app/controllers/reload.rb +1 -1
- data/spec/public/reloading/directory/log/merb_test.log +13 -0
- data/spec/public/reloading/reload_spec.rb +23 -22
- data/spec/public/request/request_spec.rb +2 -0
- data/spec/public/router/nested_resources_spec.rb +7 -0
- data/spec/public/router/resources_spec.rb +46 -1
- data/spec/public/router/special_spec.rb +5 -1
- data/spec/public/test/controller_matchers_spec.rb +25 -1
- data/spec/public/test/controllers/spec_helper_controller.rb +8 -0
- data/spec/public/test/request_helper_spec.rb +52 -1
- data/spec/public/test/route_matchers_spec.rb +27 -25
- data/spec/public/test/view_helper_spec.rb +1 -1
- data/spec/public/test/view_matchers_spec.rb +148 -72
- 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
|
-
|
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
|
-
# ====
|
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
|
#---
|
data/lib/merb-core/core_ext.rb
CHANGED
@@ -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
|
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
|
-
# ====
|
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
|