esod-client 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/EXAMPLES +140 -0
- data/GEM_RELEASE +19 -0
- data/README +10 -0
- data/Rakefile +14 -0
- data/VERSION +1 -0
- data/esod-client.gemspec +118 -0
- data/esod-client.rb +35 -0
- data/lib/activesupport-2.2.2/CHANGELOG +1257 -0
- data/lib/activesupport-2.2.2/README +43 -0
- data/lib/activesupport-2.2.2/README.CFT +2 -0
- data/lib/activesupport-2.2.2/lib/active_support.rb +26 -0
- data/lib/activesupport-2.2.2/lib/active_support/base64.rb +33 -0
- data/lib/activesupport-2.2.2/lib/active_support/basic_object.rb +24 -0
- data/lib/activesupport-2.2.2/lib/active_support/buffered_logger.rb +122 -0
- data/lib/activesupport-2.2.2/lib/active_support/cache.rb +223 -0
- data/lib/activesupport-2.2.2/lib/active_support/cache/compressed_mem_cache_store.rb +20 -0
- data/lib/activesupport-2.2.2/lib/active_support/cache/drb_store.rb +15 -0
- data/lib/activesupport-2.2.2/lib/active_support/cache/file_store.rb +72 -0
- data/lib/activesupport-2.2.2/lib/active_support/cache/mem_cache_store.rb +127 -0
- data/lib/activesupport-2.2.2/lib/active_support/cache/memory_store.rb +52 -0
- data/lib/activesupport-2.2.2/lib/active_support/cache/synchronized_memory_store.rb +47 -0
- data/lib/activesupport-2.2.2/lib/active_support/callbacks.rb +280 -0
- data/lib/activesupport-2.2.2/lib/active_support/core_ext.rb +6 -0
- data/lib/activesupport-2.2.2/lib/active_support/core_ext/hash.rb +14 -0
- data/lib/activesupport-2.2.2/lib/active_support/core_ext/hash/conversions.rb +259 -0
- data/lib/activesupport-2.2.2/lib/active_support/core_ext/hash/deep_merge.rb +23 -0
- data/lib/activesupport-2.2.2/lib/active_support/core_ext/hash/diff.rb +19 -0
- data/lib/activesupport-2.2.2/lib/active_support/core_ext/hash/except.rb +25 -0
- data/lib/activesupport-2.2.2/lib/active_support/core_ext/hash/indifferent_access.rb +137 -0
- data/lib/activesupport-2.2.2/lib/active_support/core_ext/hash/keys.rb +52 -0
- data/lib/activesupport-2.2.2/lib/active_support/core_ext/hash/reverse_merge.rb +35 -0
- data/lib/activesupport-2.2.2/lib/active_support/core_ext/hash/slice.rb +33 -0
- data/lib/activesupport-2.2.2/lib/active_support/vendor.rb +14 -0
- data/lib/activesupport-2.2.2/lib/active_support/vendor/builder-2.1.2/blankslate.rb +113 -0
- data/lib/activesupport-2.2.2/lib/active_support/vendor/builder-2.1.2/builder.rb +13 -0
- data/lib/activesupport-2.2.2/lib/active_support/vendor/builder-2.1.2/builder/blankslate.rb +20 -0
- data/lib/activesupport-2.2.2/lib/active_support/vendor/builder-2.1.2/builder/css.rb +250 -0
- data/lib/activesupport-2.2.2/lib/active_support/vendor/builder-2.1.2/builder/xchar.rb +115 -0
- data/lib/activesupport-2.2.2/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb +139 -0
- data/lib/activesupport-2.2.2/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb +63 -0
- data/lib/activesupport-2.2.2/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb +328 -0
- data/lib/activesupport-2.2.2/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb +1021 -0
- data/lib/activesupport-2.2.2/lib/activesupport.rb +1 -0
- data/lib/esodclient/esodclient.rb +22 -0
- data/lib/hash.rb +22 -0
- data/lib/mime-types-1.16/History.txt +107 -0
- data/lib/mime-types-1.16/Install.txt +17 -0
- data/lib/mime-types-1.16/Licence.txt +15 -0
- data/lib/mime-types-1.16/Manifest.txt +12 -0
- data/lib/mime-types-1.16/README.txt +28 -0
- data/lib/mime-types-1.16/Rakefile +316 -0
- data/lib/mime-types-1.16/lib/mime/types.rb +751 -0
- data/lib/mime-types-1.16/lib/mime/types.rb.data +1324 -0
- data/lib/mime-types-1.16/mime-types.gemspec +43 -0
- data/lib/mime-types-1.16/setup.rb +1585 -0
- data/lib/mime-types-1.16/test/test_mime_type.rb +356 -0
- data/lib/mime-types-1.16/test/test_mime_types.rb +122 -0
- data/lib/rest-client-1.2.0/README.rdoc +102 -0
- data/lib/rest-client-1.2.0/Rakefile +57 -0
- data/lib/rest-client-1.2.0/VERSION +1 -0
- data/lib/rest-client-1.2.0/bin/restclient +87 -0
- data/lib/rest-client-1.2.0/lib/rest_client.rb +2 -0
- data/lib/rest-client-1.2.0/lib/restclient.rb +108 -0
- data/lib/rest-client-1.2.0/lib/restclient/exceptions.rb +89 -0
- data/lib/rest-client-1.2.0/lib/restclient/mixin/response.rb +48 -0
- data/lib/rest-client-1.2.0/lib/restclient/net_http_ext.rb +21 -0
- data/lib/rest-client-1.2.0/lib/restclient/payload.rb +178 -0
- data/lib/rest-client-1.2.0/lib/restclient/raw_response.rb +30 -0
- data/lib/rest-client-1.2.0/lib/restclient/request.rb +287 -0
- data/lib/rest-client-1.2.0/lib/restclient/resource.rb +146 -0
- data/lib/rest-client-1.2.0/lib/restclient/response.rb +20 -0
- data/lib/rest-client-1.2.0/spec/base.rb +10 -0
- data/lib/rest-client-1.2.0/spec/exceptions_spec.rb +65 -0
- data/lib/rest-client-1.2.0/spec/master_shake.jpg +0 -0
- data/lib/rest-client-1.2.0/spec/mixin/response_spec.rb +46 -0
- data/lib/rest-client-1.2.0/spec/payload_spec.rb +131 -0
- data/lib/rest-client-1.2.0/spec/raw_response_spec.rb +17 -0
- data/lib/rest-client-1.2.0/spec/request_spec.rb +521 -0
- data/lib/rest-client-1.2.0/spec/resource_spec.rb +75 -0
- data/lib/rest-client-1.2.0/spec/response_spec.rb +21 -0
- data/lib/rest-client-1.2.0/spec/restclient_spec.rb +53 -0
- data/lib/trollop/trollop.rb +735 -0
- metadata +137 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
%w(keys indifferent_access deep_merge reverse_merge conversions diff slice except).each do |ext|
|
|
2
|
+
require "active_support/core_ext/hash/#{ext}"
|
|
3
|
+
end
|
|
4
|
+
|
|
5
|
+
class Hash #:nodoc:
|
|
6
|
+
include ActiveSupport::CoreExtensions::Hash::Keys
|
|
7
|
+
include ActiveSupport::CoreExtensions::Hash::IndifferentAccess
|
|
8
|
+
include ActiveSupport::CoreExtensions::Hash::DeepMerge
|
|
9
|
+
include ActiveSupport::CoreExtensions::Hash::ReverseMerge
|
|
10
|
+
include ActiveSupport::CoreExtensions::Hash::Conversions
|
|
11
|
+
include ActiveSupport::CoreExtensions::Hash::Diff
|
|
12
|
+
include ActiveSupport::CoreExtensions::Hash::Slice
|
|
13
|
+
include ActiveSupport::CoreExtensions::Hash::Except
|
|
14
|
+
end
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
require 'date'
|
|
2
|
+
require 'cgi'
|
|
3
|
+
require 'builder'
|
|
4
|
+
require 'xmlsimple'
|
|
5
|
+
|
|
6
|
+
# Locked down XmlSimple#xml_in_string
|
|
7
|
+
class XmlSimple
|
|
8
|
+
# Same as xml_in but doesn't try to smartly shoot itself in the foot.
|
|
9
|
+
def xml_in_string(string, options = nil)
|
|
10
|
+
handle_options('in', options)
|
|
11
|
+
|
|
12
|
+
@doc = parse(string)
|
|
13
|
+
result = collapse(@doc.root)
|
|
14
|
+
|
|
15
|
+
if @options['keeproot']
|
|
16
|
+
merge({}, @doc.root.name, result)
|
|
17
|
+
else
|
|
18
|
+
result
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.xml_in_string(string, options = nil)
|
|
23
|
+
new.xml_in_string(string, options)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# This module exists to decorate files deserialized using Hash.from_xml with
|
|
28
|
+
# the <tt>original_filename</tt> and <tt>content_type</tt> methods.
|
|
29
|
+
module FileLike #:nodoc:
|
|
30
|
+
attr_writer :original_filename, :content_type
|
|
31
|
+
|
|
32
|
+
def original_filename
|
|
33
|
+
@original_filename || 'untitled'
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def content_type
|
|
37
|
+
@content_type || 'application/octet-stream'
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
module ActiveSupport #:nodoc:
|
|
42
|
+
module CoreExtensions #:nodoc:
|
|
43
|
+
module Hash #:nodoc:
|
|
44
|
+
module Conversions
|
|
45
|
+
|
|
46
|
+
XML_TYPE_NAMES = {
|
|
47
|
+
"Symbol" => "symbol",
|
|
48
|
+
"Fixnum" => "integer",
|
|
49
|
+
"Bignum" => "integer",
|
|
50
|
+
"BigDecimal" => "decimal",
|
|
51
|
+
"Float" => "float",
|
|
52
|
+
"Date" => "date",
|
|
53
|
+
"DateTime" => "datetime",
|
|
54
|
+
"Time" => "datetime",
|
|
55
|
+
"TrueClass" => "boolean",
|
|
56
|
+
"FalseClass" => "boolean"
|
|
57
|
+
} unless defined?(XML_TYPE_NAMES)
|
|
58
|
+
|
|
59
|
+
XML_FORMATTING = {
|
|
60
|
+
"symbol" => Proc.new { |symbol| symbol.to_s },
|
|
61
|
+
"date" => Proc.new { |date| date.to_s(:db) },
|
|
62
|
+
"datetime" => Proc.new { |time| time.xmlschema },
|
|
63
|
+
"binary" => Proc.new { |binary| ActiveSupport::Base64.encode64(binary) },
|
|
64
|
+
"yaml" => Proc.new { |yaml| yaml.to_yaml }
|
|
65
|
+
} unless defined?(XML_FORMATTING)
|
|
66
|
+
|
|
67
|
+
# TODO: use Time.xmlschema instead of Time.parse;
|
|
68
|
+
# use regexp instead of Date.parse
|
|
69
|
+
unless defined?(XML_PARSING)
|
|
70
|
+
XML_PARSING = {
|
|
71
|
+
"symbol" => Proc.new { |symbol| symbol.to_sym },
|
|
72
|
+
"date" => Proc.new { |date| ::Date.parse(date) },
|
|
73
|
+
"datetime" => Proc.new { |time| ::Time.parse(time).utc rescue ::DateTime.parse(time).utc },
|
|
74
|
+
"integer" => Proc.new { |integer| integer.to_i },
|
|
75
|
+
"float" => Proc.new { |float| float.to_f },
|
|
76
|
+
"decimal" => Proc.new { |number| BigDecimal(number) },
|
|
77
|
+
"boolean" => Proc.new { |boolean| %w(1 true).include?(boolean.strip) },
|
|
78
|
+
"string" => Proc.new { |string| string.to_s },
|
|
79
|
+
"yaml" => Proc.new { |yaml| YAML::load(yaml) rescue yaml },
|
|
80
|
+
"base64Binary" => Proc.new { |bin| ActiveSupport::Base64.decode64(bin) },
|
|
81
|
+
"file" => Proc.new do |file, entity|
|
|
82
|
+
f = StringIO.new(ActiveSupport::Base64.decode64(file))
|
|
83
|
+
f.extend(FileLike)
|
|
84
|
+
f.original_filename = entity['name']
|
|
85
|
+
f.content_type = entity['content_type']
|
|
86
|
+
f
|
|
87
|
+
end
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
XML_PARSING.update(
|
|
91
|
+
"double" => XML_PARSING["float"],
|
|
92
|
+
"dateTime" => XML_PARSING["datetime"]
|
|
93
|
+
)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def self.included(klass)
|
|
97
|
+
klass.extend(ClassMethods)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Converts a hash into a string suitable for use as a URL query string. An optional <tt>namespace</tt> can be
|
|
101
|
+
# passed to enclose the param names (see example below).
|
|
102
|
+
#
|
|
103
|
+
# ==== Example:
|
|
104
|
+
# { :name => 'David', :nationality => 'Danish' }.to_query # => "name=David&nationality=Danish"
|
|
105
|
+
#
|
|
106
|
+
# { :name => 'David', :nationality => 'Danish' }.to_query('user') # => "user%5Bname%5D=David&user%5Bnationality%5D=Danish"
|
|
107
|
+
def to_query(namespace = nil)
|
|
108
|
+
collect do |key, value|
|
|
109
|
+
value.to_query(namespace ? "#{namespace}[#{key}]" : key)
|
|
110
|
+
end.sort * '&'
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
alias_method :to_param, :to_query
|
|
114
|
+
|
|
115
|
+
def to_xml(options = {})
|
|
116
|
+
options[:indent] ||= 2
|
|
117
|
+
options.reverse_merge!({ :builder => Builder::XmlMarkup.new(:indent => options[:indent]),
|
|
118
|
+
:root => "hash" })
|
|
119
|
+
options[:builder].instruct! unless options.delete(:skip_instruct)
|
|
120
|
+
dasherize = !options.has_key?(:dasherize) || options[:dasherize]
|
|
121
|
+
root = dasherize ? options[:root].to_s.dasherize : options[:root].to_s
|
|
122
|
+
|
|
123
|
+
options[:builder].__send__(:method_missing, root) do
|
|
124
|
+
each do |key, value|
|
|
125
|
+
case value
|
|
126
|
+
when ::Hash
|
|
127
|
+
value.to_xml(options.merge({ :root => key, :skip_instruct => true }))
|
|
128
|
+
when ::Array
|
|
129
|
+
value.to_xml(options.merge({ :root => key, :children => key.to_s.singularize, :skip_instruct => true}))
|
|
130
|
+
when ::Method, ::Proc
|
|
131
|
+
# If the Method or Proc takes two arguments, then
|
|
132
|
+
# pass the suggested child element name. This is
|
|
133
|
+
# used if the Method or Proc will be operating over
|
|
134
|
+
# multiple records and needs to create an containing
|
|
135
|
+
# element that will contain the objects being
|
|
136
|
+
# serialized.
|
|
137
|
+
if 1 == value.arity
|
|
138
|
+
value.call(options.merge({ :root => key, :skip_instruct => true }))
|
|
139
|
+
else
|
|
140
|
+
value.call(options.merge({ :root => key, :skip_instruct => true }), key.to_s.singularize)
|
|
141
|
+
end
|
|
142
|
+
else
|
|
143
|
+
if value.respond_to?(:to_xml)
|
|
144
|
+
value.to_xml(options.merge({ :root => key, :skip_instruct => true }))
|
|
145
|
+
else
|
|
146
|
+
type_name = XML_TYPE_NAMES[value.class.name]
|
|
147
|
+
|
|
148
|
+
key = dasherize ? key.to_s.dasherize : key.to_s
|
|
149
|
+
|
|
150
|
+
attributes = options[:skip_types] || value.nil? || type_name.nil? ? { } : { :type => type_name }
|
|
151
|
+
if value.nil?
|
|
152
|
+
attributes[:nil] = true
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
options[:builder].tag!(key,
|
|
156
|
+
XML_FORMATTING[type_name] ? XML_FORMATTING[type_name].call(value) : value,
|
|
157
|
+
attributes
|
|
158
|
+
)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
yield options[:builder] if block_given?
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
module ClassMethods
|
|
169
|
+
def from_xml(xml)
|
|
170
|
+
# TODO: Refactor this into something much cleaner that doesn't rely on XmlSimple
|
|
171
|
+
typecast_xml_value(undasherize_keys(XmlSimple.xml_in_string(xml,
|
|
172
|
+
'forcearray' => false,
|
|
173
|
+
'forcecontent' => true,
|
|
174
|
+
'keeproot' => true,
|
|
175
|
+
'contentkey' => '__content__')
|
|
176
|
+
))
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
private
|
|
180
|
+
def typecast_xml_value(value)
|
|
181
|
+
case value.class.to_s
|
|
182
|
+
when 'Hash'
|
|
183
|
+
if value['type'] == 'array'
|
|
184
|
+
child_key, entries = value.detect { |k,v| k != 'type' } # child_key is throwaway
|
|
185
|
+
if entries.nil? || (c = value['__content__'] && c.blank?)
|
|
186
|
+
[]
|
|
187
|
+
else
|
|
188
|
+
case entries.class.to_s # something weird with classes not matching here. maybe singleton methods breaking is_a?
|
|
189
|
+
when "Array"
|
|
190
|
+
entries.collect { |v| typecast_xml_value(v) }
|
|
191
|
+
when "Hash"
|
|
192
|
+
[typecast_xml_value(entries)]
|
|
193
|
+
else
|
|
194
|
+
raise "can't typecast #{entries.inspect}"
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
elsif value.has_key?("__content__")
|
|
198
|
+
content = value["__content__"]
|
|
199
|
+
if parser = XML_PARSING[value["type"]]
|
|
200
|
+
if parser.arity == 2
|
|
201
|
+
XML_PARSING[value["type"]].call(content, value)
|
|
202
|
+
else
|
|
203
|
+
XML_PARSING[value["type"]].call(content)
|
|
204
|
+
end
|
|
205
|
+
else
|
|
206
|
+
content
|
|
207
|
+
end
|
|
208
|
+
elsif value['type'] == 'string' && value['nil'] != 'true'
|
|
209
|
+
""
|
|
210
|
+
# blank or nil parsed values are represented by nil
|
|
211
|
+
elsif value.blank? || value['nil'] == 'true'
|
|
212
|
+
nil
|
|
213
|
+
# If the type is the only element which makes it then
|
|
214
|
+
# this still makes the value nil, except if type is
|
|
215
|
+
# a XML node(where type['value'] is a Hash)
|
|
216
|
+
elsif value['type'] && value.size == 1 && !value['type'].is_a?(::Hash)
|
|
217
|
+
nil
|
|
218
|
+
else
|
|
219
|
+
xml_value = value.inject({}) do |h,(k,v)|
|
|
220
|
+
h[k] = typecast_xml_value(v)
|
|
221
|
+
h
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# Turn { :files => { :file => #<StringIO> } into { :files => #<StringIO> } so it is compatible with
|
|
225
|
+
# how multipart uploaded files from HTML appear
|
|
226
|
+
xml_value["file"].is_a?(StringIO) ? xml_value["file"] : xml_value
|
|
227
|
+
end
|
|
228
|
+
when 'Array'
|
|
229
|
+
value.map! { |i| typecast_xml_value(i) }
|
|
230
|
+
case value.length
|
|
231
|
+
when 0 then nil
|
|
232
|
+
when 1 then value.first
|
|
233
|
+
else value
|
|
234
|
+
end
|
|
235
|
+
when 'String'
|
|
236
|
+
value
|
|
237
|
+
else
|
|
238
|
+
raise "can't typecast #{value.class.name} - #{value.inspect}"
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def undasherize_keys(params)
|
|
243
|
+
case params.class.to_s
|
|
244
|
+
when "Hash"
|
|
245
|
+
params.inject({}) do |h,(k,v)|
|
|
246
|
+
h[k.to_s.tr("-", "_")] = undasherize_keys(v)
|
|
247
|
+
h
|
|
248
|
+
end
|
|
249
|
+
when "Array"
|
|
250
|
+
params.map { |v| undasherize_keys(v) }
|
|
251
|
+
else
|
|
252
|
+
params
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module ActiveSupport #:nodoc:
|
|
2
|
+
module CoreExtensions #:nodoc:
|
|
3
|
+
module Hash #:nodoc:
|
|
4
|
+
# Allows for deep merging
|
|
5
|
+
module DeepMerge
|
|
6
|
+
# Returns a new hash with +self+ and +other_hash+ merged recursively.
|
|
7
|
+
def deep_merge(other_hash)
|
|
8
|
+
self.merge(other_hash) do |key, oldval, newval|
|
|
9
|
+
oldval = oldval.to_hash if oldval.respond_to?(:to_hash)
|
|
10
|
+
newval = newval.to_hash if newval.respond_to?(:to_hash)
|
|
11
|
+
oldval.class.to_s == 'Hash' && newval.class.to_s == 'Hash' ? oldval.deep_merge(newval) : newval
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Returns a new hash with +self+ and +other_hash+ merged recursively.
|
|
16
|
+
# Modifies the receiver in place.
|
|
17
|
+
def deep_merge!(other_hash)
|
|
18
|
+
replace(deep_merge(other_hash))
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module ActiveSupport #:nodoc:
|
|
2
|
+
module CoreExtensions #:nodoc:
|
|
3
|
+
module Hash #:nodoc:
|
|
4
|
+
module Diff
|
|
5
|
+
# Returns a hash that represents the difference between two hashes.
|
|
6
|
+
#
|
|
7
|
+
# Examples:
|
|
8
|
+
#
|
|
9
|
+
# {1 => 2}.diff(1 => 2) # => {}
|
|
10
|
+
# {1 => 2}.diff(1 => 3) # => {1 => 2}
|
|
11
|
+
# {}.diff(1 => 2) # => {1 => 2}
|
|
12
|
+
# {1 => 2, 3 => 4}.diff(1 => 2) # => {3 => 4}
|
|
13
|
+
def diff(h2)
|
|
14
|
+
self.dup.delete_if { |k, v| h2[k] == v }.merge(h2.dup.delete_if { |k, v| self.has_key?(k) })
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'set'
|
|
2
|
+
|
|
3
|
+
module ActiveSupport #:nodoc:
|
|
4
|
+
module CoreExtensions #:nodoc:
|
|
5
|
+
module Hash #:nodoc:
|
|
6
|
+
# Return a hash that includes everything but the given keys. This is useful for
|
|
7
|
+
# limiting a set of parameters to everything but a few known toggles:
|
|
8
|
+
#
|
|
9
|
+
# @person.update_attributes(params[:person].except(:admin))
|
|
10
|
+
module Except
|
|
11
|
+
# Returns a new hash without the given keys.
|
|
12
|
+
def except(*keys)
|
|
13
|
+
dup.except!(*keys)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Replaces the hash without the given keys.
|
|
17
|
+
def except!(*keys)
|
|
18
|
+
keys.map! { |key| convert_key(key) } if respond_to?(:convert_key)
|
|
19
|
+
keys.each { |key| delete(key) }
|
|
20
|
+
self
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# This class has dubious semantics and we only have it so that
|
|
2
|
+
# people can write params[:key] instead of params['key']
|
|
3
|
+
# and they get the same value for both keys.
|
|
4
|
+
|
|
5
|
+
class HashWithIndifferentAccess < Hash
|
|
6
|
+
def initialize(constructor = {})
|
|
7
|
+
if constructor.is_a?(Hash)
|
|
8
|
+
super()
|
|
9
|
+
update(constructor)
|
|
10
|
+
else
|
|
11
|
+
super(constructor)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def default(key = nil)
|
|
16
|
+
if key.is_a?(Symbol) && include?(key = key.to_s)
|
|
17
|
+
self[key]
|
|
18
|
+
else
|
|
19
|
+
super
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
|
|
24
|
+
alias_method :regular_update, :update unless method_defined?(:regular_update)
|
|
25
|
+
|
|
26
|
+
# Assigns a new value to the hash:
|
|
27
|
+
#
|
|
28
|
+
# hash = HashWithIndifferentAccess.new
|
|
29
|
+
# hash[:key] = "value"
|
|
30
|
+
#
|
|
31
|
+
def []=(key, value)
|
|
32
|
+
regular_writer(convert_key(key), convert_value(value))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Updates the instantized hash with values from the second:
|
|
36
|
+
#
|
|
37
|
+
# hash_1 = HashWithIndifferentAccess.new
|
|
38
|
+
# hash_1[:key] = "value"
|
|
39
|
+
#
|
|
40
|
+
# hash_2 = HashWithIndifferentAccess.new
|
|
41
|
+
# hash_2[:key] = "New Value!"
|
|
42
|
+
#
|
|
43
|
+
# hash_1.update(hash_2) # => {"key"=>"New Value!"}
|
|
44
|
+
#
|
|
45
|
+
def update(other_hash)
|
|
46
|
+
other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
|
|
47
|
+
self
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
alias_method :merge!, :update
|
|
51
|
+
|
|
52
|
+
# Checks the hash for a key matching the argument passed in:
|
|
53
|
+
#
|
|
54
|
+
# hash = HashWithIndifferentAccess.new
|
|
55
|
+
# hash["key"] = "value"
|
|
56
|
+
# hash.key? :key # => true
|
|
57
|
+
# hash.key? "key" # => true
|
|
58
|
+
#
|
|
59
|
+
def key?(key)
|
|
60
|
+
super(convert_key(key))
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
alias_method :include?, :key?
|
|
64
|
+
alias_method :has_key?, :key?
|
|
65
|
+
alias_method :member?, :key?
|
|
66
|
+
|
|
67
|
+
# Fetches the value for the specified key, same as doing hash[key]
|
|
68
|
+
def fetch(key, *extras)
|
|
69
|
+
super(convert_key(key), *extras)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Returns an array of the values at the specified indices:
|
|
73
|
+
#
|
|
74
|
+
# hash = HashWithIndifferentAccess.new
|
|
75
|
+
# hash[:a] = "x"
|
|
76
|
+
# hash[:b] = "y"
|
|
77
|
+
# hash.values_at("a", "b") # => ["x", "y"]
|
|
78
|
+
#
|
|
79
|
+
def values_at(*indices)
|
|
80
|
+
indices.collect {|key| self[convert_key(key)]}
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Returns an exact copy of the hash.
|
|
84
|
+
def dup
|
|
85
|
+
HashWithIndifferentAccess.new(self)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Merges the instantized and the specified hashes together, giving precedence to the values from the second hash
|
|
89
|
+
# Does not overwrite the existing hash.
|
|
90
|
+
def merge(hash)
|
|
91
|
+
self.dup.update(hash)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Removes a specified key from the hash.
|
|
95
|
+
def delete(key)
|
|
96
|
+
super(convert_key(key))
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def stringify_keys!; self end
|
|
100
|
+
def symbolize_keys!; self end
|
|
101
|
+
def to_options!; self end
|
|
102
|
+
|
|
103
|
+
# Convert to a Hash with String keys.
|
|
104
|
+
def to_hash
|
|
105
|
+
Hash.new(default).merge(self)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
protected
|
|
109
|
+
def convert_key(key)
|
|
110
|
+
key.kind_of?(Symbol) ? key.to_s : key
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def convert_value(value)
|
|
114
|
+
case value
|
|
115
|
+
when Hash
|
|
116
|
+
value.with_indifferent_access
|
|
117
|
+
when Array
|
|
118
|
+
value.collect { |e| e.is_a?(Hash) ? e.with_indifferent_access : e }
|
|
119
|
+
else
|
|
120
|
+
value
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
module ActiveSupport #:nodoc:
|
|
126
|
+
module CoreExtensions #:nodoc:
|
|
127
|
+
module Hash #:nodoc:
|
|
128
|
+
module IndifferentAccess #:nodoc:
|
|
129
|
+
def with_indifferent_access
|
|
130
|
+
hash = HashWithIndifferentAccess.new(self)
|
|
131
|
+
hash.default = self.default
|
|
132
|
+
hash
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|