wrest 3.0.0 → 4.0.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.
- checksums.yaml +5 -5
- data/CHANGELOG +3 -0
- data/LICENCE +1 -1
- data/README.md +29 -28
- data/bin/wrest +2 -1
- data/bin/wrest_shell.rb +10 -8
- data/lib/wrest/async_request/event_machine_backend.rb +3 -1
- data/lib/wrest/async_request/thread_backend.rb +5 -2
- data/lib/wrest/async_request/thread_pool.rb +4 -2
- data/lib/wrest/async_request.rb +7 -6
- data/lib/wrest/cache_proxy.rb +39 -28
- data/lib/wrest/caching/memcached.rb +21 -18
- data/lib/wrest/caching/redis.rb +22 -22
- data/lib/wrest/caching.rb +16 -14
- data/lib/wrest/callback.rb +19 -16
- data/lib/wrest/components/container/alias_accessors.rb +51 -47
- data/lib/wrest/components/container/typecaster.rb +146 -96
- data/lib/wrest/components/container.rb +171 -152
- data/lib/wrest/components/mutators/base.rb +43 -34
- data/lib/wrest/components/mutators/camel_to_snake_case.rb +7 -3
- data/lib/wrest/components/mutators/{xml_mini_type_caster.rb → xml_type_caster.rb} +29 -16
- data/lib/wrest/components/mutators.rb +21 -19
- data/lib/wrest/components/translators/content_types.rb +20 -16
- data/lib/wrest/components/translators/json.rb +19 -16
- data/lib/wrest/components/translators/txt.rb +19 -15
- data/lib/wrest/components/translators/xml/conversions.rb +56 -0
- data/lib/wrest/components/translators/xml.rb +60 -18
- data/lib/wrest/components/translators.rb +7 -6
- data/lib/wrest/components.rb +11 -8
- data/lib/wrest/core_ext/hash/conversions.rb +10 -10
- data/lib/wrest/core_ext/hash.rb +4 -2
- data/lib/wrest/core_ext/string/conversions.rb +14 -13
- data/lib/wrest/core_ext/string.rb +5 -3
- data/lib/wrest/exceptions.rb +4 -2
- data/lib/wrest/hash_with_case_insensitive_access.rb +8 -8
- data/lib/wrest/hash_with_indifferent_access.rb +442 -0
- data/lib/wrest/http_codes.rb +20 -19
- data/lib/wrest/http_shared/headers.rb +2 -0
- data/lib/wrest/http_shared/standard_headers.rb +2 -2
- data/lib/wrest/http_shared/standard_tokens.rb +8 -6
- data/lib/wrest/http_shared.rb +5 -3
- data/lib/wrest/multipart.rb +20 -11
- data/lib/wrest/native/connection_factory.rb +15 -11
- data/lib/wrest/native/delete.rb +15 -11
- data/lib/wrest/native/get.rb +60 -56
- data/lib/wrest/native/options.rb +15 -11
- data/lib/wrest/native/patch.rb +16 -12
- data/lib/wrest/native/post.rb +15 -11
- data/lib/wrest/native/post_multipart.rb +22 -18
- data/lib/wrest/native/put.rb +16 -12
- data/lib/wrest/native/put_multipart.rb +22 -18
- data/lib/wrest/native/redirection.rb +13 -12
- data/lib/wrest/native/request.rb +144 -108
- data/lib/wrest/native/response.rb +87 -78
- data/lib/wrest/native/session.rb +49 -40
- data/lib/wrest/native.rb +14 -12
- data/lib/wrest/test/request_patches.rb +10 -3
- data/lib/wrest/test.rb +3 -1
- data/lib/wrest/uri/builders.rb +14 -12
- data/lib/wrest/uri.rb +70 -52
- data/lib/wrest/uri_template.rb +11 -7
- data/lib/wrest/utils.rb +129 -0
- data/lib/wrest/version.rb +3 -1
- data/lib/wrest.rb +31 -33
- data/lib/wrest_no_ext.rb +2 -0
- metadata +98 -48
- data/lib/wrest/components/mutators/xml_simple_type_caster.rb +0 -37
- data/lib/wrest/xml_mini/jdom/xpath_filter.rb +0 -17
- data/lib/wrest/xml_mini/jdom.rb +0 -6
- data/lib/wrest/xml_mini/libxml/xpath_filter.rb +0 -12
- data/lib/wrest/xml_mini/libxml.rb +0 -8
- data/lib/wrest/xml_mini/nokogiri/xpath_filter.rb +0 -15
- data/lib/wrest/xml_mini/nokogiri.rb +0 -7
- data/lib/wrest/xml_mini/rexml/xpath_filter.rb +0 -15
- data/lib/wrest/xml_mini/rexml.rb +0 -8
- data/lib/wrest/xml_mini.rb +0 -8
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright 2009 Sidu Ponnappa
|
2
4
|
|
3
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -8,56 +10,58 @@
|
|
8
10
|
# See the License for the specific language governing permissions and limitations under the License.
|
9
11
|
|
10
12
|
module Wrest
|
11
|
-
module Components
|
12
|
-
module
|
13
|
-
|
14
|
-
klass
|
15
|
-
|
13
|
+
module Components
|
14
|
+
module Container
|
15
|
+
module AliasAccessors
|
16
|
+
def self.included(klass) # :nodoc:
|
17
|
+
klass.extend AliasAccessors::ClassMethods
|
18
|
+
end
|
16
19
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
+
def self.build_aliased_attribute_getter(attribute_name, alias_name) # :nodoc:
|
21
|
+
"def #{alias_name};#{attribute_name};end;"
|
22
|
+
end
|
20
23
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
+
def self.build_aliased_attribute_setter(attribute_name, alias_name) # :nodoc:
|
25
|
+
"def #{alias_name}=(value);self.#{attribute_name}=value;end;"
|
26
|
+
end
|
24
27
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
28
|
+
def self.build_aliased_attribute_queryer(attribute_name, alias_name) # :nodoc:
|
29
|
+
"def #{alias_name}?;self.#{attribute_name}?;end;"
|
30
|
+
end
|
31
|
+
|
32
|
+
module ClassMethods
|
33
|
+
# Creates an alias set of getter, setter and query methods for
|
34
|
+
# attributes that aren't quite the way you'd like them to be; this
|
35
|
+
# is especially useful when you have no control over the source web
|
36
|
+
# sevice/resource.
|
37
|
+
#
|
38
|
+
# For example, lets say that a particular resource exposes a
|
39
|
+
# User's age as 'a' and sex as 's'. Typically, you'd have to access it as
|
40
|
+
# user.a and user.s whereas you's like to access it as user.age and user.sex.
|
41
|
+
# This is where alias_accessors comes into the picture. Your User class would
|
42
|
+
# look somethig like this:
|
43
|
+
#
|
44
|
+
# class User
|
45
|
+
# include Wrest::Components::Container
|
46
|
+
#
|
47
|
+
# alias_accessors :a => :age,
|
48
|
+
# :s => :sex
|
49
|
+
# end
|
50
|
+
# This would create the methods user.age, user.age= and user.age? which delegates
|
51
|
+
# to user.a, user.a= and user.a? respectively.
|
52
|
+
#
|
53
|
+
# See examples/wow_realm_status.rb for a working example.
|
54
|
+
#
|
55
|
+
# WARNING: If you try to create an alias with the same name as the attribute,
|
56
|
+
# and then use it, you _will_ cause an infinite loop.
|
57
|
+
def alias_accessors(alias_map)
|
58
|
+
alias_map.each do |attribute_name, alias_name|
|
59
|
+
class_eval(
|
60
|
+
AliasAccessors.build_aliased_attribute_getter(attribute_name, alias_name) +
|
61
|
+
AliasAccessors.build_aliased_attribute_setter(attribute_name, alias_name) +
|
62
|
+
AliasAccessors.build_aliased_attribute_queryer(attribute_name, alias_name)
|
63
|
+
)
|
64
|
+
end
|
61
65
|
end
|
62
66
|
end
|
63
67
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright 2009 Sidu Ponnappa
|
2
4
|
|
3
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -8,118 +10,166 @@
|
|
8
10
|
# See the License for the specific language governing permissions and limitations under the License.
|
9
11
|
|
10
12
|
module Wrest
|
11
|
-
module Components
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
13
|
+
module Components
|
14
|
+
module Container
|
15
|
+
# An extension to Container that adds support for specifying
|
16
|
+
# how the values associated with certain attribute keys
|
17
|
+
# should be typecast.
|
18
|
+
#
|
19
|
+
# This extension can be used in situations where the attributes
|
20
|
+
# hash consists of just strings with no associated tup information.
|
21
|
+
# For example, params recieved from a web browser may contain
|
22
|
+
# attributes like
|
23
|
+
# 'id' => '4', 'dateofbirth' => '1984-04-05'
|
24
|
+
# and we'd like to have these cast to an integer and a date
|
25
|
+
# respectively, rather than have to deal with them as strings.
|
26
|
+
module Typecaster
|
27
|
+
PARSING = {
|
28
|
+
'symbol' => proc { |symbol| symbol.to_s.to_sym },
|
29
|
+
'date' => proc { |date| ::Date.parse(date) },
|
30
|
+
'datetime' => proc { |time|
|
31
|
+
begin
|
32
|
+
Time.xmlschema(time).utc
|
33
|
+
rescue StandardError
|
34
|
+
::DateTime.parse(time).utc
|
35
|
+
end
|
36
|
+
},
|
37
|
+
'integer' => proc { |integer| integer.to_i },
|
38
|
+
'float' => proc { |float| float.to_f },
|
39
|
+
'decimal' => proc do |number|
|
40
|
+
if number.is_a?(String)
|
41
|
+
number.to_d
|
42
|
+
else
|
43
|
+
BigDecimal(number)
|
44
|
+
end
|
45
|
+
end,
|
46
|
+
'boolean' => proc { |boolean| %w[1 true].include?(boolean.to_s.strip) },
|
47
|
+
'string' => proc { |string| string.to_s },
|
48
|
+
'yaml' => proc { |yaml|
|
49
|
+
begin
|
50
|
+
YAML.safe_load(yaml)
|
51
|
+
rescue StandardError
|
52
|
+
yaml
|
53
|
+
end
|
54
|
+
},
|
55
|
+
'base64Binary' => proc { |bin| ::Base64.decode64(bin) },
|
56
|
+
'binary' => proc { |bin, entity| _parse_binary(bin, entity) },
|
57
|
+
'file' => proc { |file, entity| _parse_file(file, entity) },
|
58
|
+
'double' => proc { |float| float.to_f },
|
59
|
+
'dateTime' => proc { |time|
|
60
|
+
begin
|
61
|
+
Time.xmlschema(time).utc
|
62
|
+
rescue StandardError
|
63
|
+
::DateTime.parse(time).utc
|
64
|
+
end
|
65
|
+
}
|
66
|
+
}.freeze
|
30
67
|
|
31
|
-
|
32
|
-
|
33
|
-
|
68
|
+
def self.included(klass)
|
69
|
+
# :nodoc:
|
70
|
+
klass.extend Typecaster::ClassMethods
|
71
|
+
klass.class_eval { include Typecaster::InstanceMethods }
|
72
|
+
klass.send(:alias_method, :initialize_without_typecasting, :initialize)
|
73
|
+
klass.send(:alias_method, :initialize, :initialize_with_typecasting)
|
34
74
|
end
|
35
75
|
|
36
|
-
|
37
|
-
|
38
|
-
|
76
|
+
module Helpers
|
77
|
+
def as_base64_binary
|
78
|
+
PARSING['base64Binary']
|
79
|
+
end
|
39
80
|
|
40
|
-
|
41
|
-
|
42
|
-
|
81
|
+
def as_boolean
|
82
|
+
PARSING['boolean']
|
83
|
+
end
|
43
84
|
|
44
|
-
|
45
|
-
|
46
|
-
|
85
|
+
def as_decimal
|
86
|
+
PARSING['decimal']
|
87
|
+
end
|
47
88
|
|
48
|
-
|
49
|
-
|
50
|
-
|
89
|
+
def as_date
|
90
|
+
PARSING['date']
|
91
|
+
end
|
51
92
|
|
52
|
-
|
53
|
-
|
54
|
-
|
93
|
+
def as_datetime
|
94
|
+
PARSING['datetime']
|
95
|
+
end
|
55
96
|
|
56
|
-
|
57
|
-
|
58
|
-
|
97
|
+
def as_float
|
98
|
+
PARSING['float']
|
99
|
+
end
|
59
100
|
|
60
|
-
|
61
|
-
|
62
|
-
|
101
|
+
def as_integer
|
102
|
+
PARSING['integer']
|
103
|
+
end
|
63
104
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
end
|
105
|
+
def as_symbol
|
106
|
+
PARSING['symbol']
|
107
|
+
end
|
68
108
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
# Typically needed when populating an +Container+
|
73
|
-
# directly from request params. Typecasting kicks in for
|
74
|
-
# a given value _only_ if it is a String, Hash or Array, the
|
75
|
-
# three classes that deserilisation can produce.
|
76
|
-
#
|
77
|
-
# Typecast information is inherited by subclasses; however be
|
78
|
-
# aware that explicitly invoking +typecast+ in a subclass will
|
79
|
-
# discard inherited typecast information leaving only the casts
|
80
|
-
# defined in the subclass.
|
81
|
-
#
|
82
|
-
# Note that this _will_ increase the time needed to initialize
|
83
|
-
# instances.
|
84
|
-
#
|
85
|
-
# Common typecasts such as integer, float, datetime etc. are
|
86
|
-
# available through predefined helpers. See TypecastHelpers
|
87
|
-
# for a full list.
|
88
|
-
#
|
89
|
-
# Example:
|
90
|
-
#
|
91
|
-
# class Demon
|
92
|
-
# include Wrest::Components::Container
|
93
|
-
# include Wrest::Components::Container::Typecaster
|
94
|
-
#
|
95
|
-
# typecast :age => as_integer,
|
96
|
-
# :chi => lambda{|chi| Chi.new(chi)}
|
97
|
-
# end
|
98
|
-
#
|
99
|
-
# kai_wren = Demon.new('age' => '1500', 'chi' => '1024')
|
100
|
-
# kai_wren.age # => 1500
|
101
|
-
# kai_wren.chi # => #<Chi:0x113af8c @count="1024">
|
102
|
-
def typecast(cast_map)
|
103
|
-
@typecast_map = @typecast_map ? @typecast_map.merge(cast_map.symbolize_keys) : cast_map.symbolize_keys
|
109
|
+
def as_yaml
|
110
|
+
PARSING['yaml']
|
111
|
+
end
|
104
112
|
end
|
105
113
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
114
|
+
module ClassMethods
|
115
|
+
# Accepts a set of attribute-name/lambda pairs which are used
|
116
|
+
# to typecast string values injected through the constructor.
|
117
|
+
# Typically needed when populating an +Container+
|
118
|
+
# directly from request params. Typecasting kicks in for
|
119
|
+
# a given value _only_ if it is a String, Hash or Array, the
|
120
|
+
# three classes that deserilisation can produce.
|
121
|
+
#
|
122
|
+
# Typecast information is inherited by subclasses; however be
|
123
|
+
# aware that explicitly invoking +typecast+ in a subclass will
|
124
|
+
# discard inherited typecast information leaving only the casts
|
125
|
+
# defined in the subclass.
|
126
|
+
#
|
127
|
+
# Note that this _will_ increase the time needed to initialize
|
128
|
+
# instances.
|
129
|
+
#
|
130
|
+
# Common typecasts such as integer, float, datetime etc. are
|
131
|
+
# available through predefined helpers. See TypecastHelpers
|
132
|
+
# for a full list.
|
133
|
+
#
|
134
|
+
# Example:
|
135
|
+
#
|
136
|
+
# class Demon
|
137
|
+
# include Wrest::Components::Container
|
138
|
+
# include Wrest::Components::Container::Typecaster
|
139
|
+
#
|
140
|
+
# typecast :age => as_integer,
|
141
|
+
# :chi => lambda{|chi| Chi.new(chi)}
|
142
|
+
# end
|
143
|
+
#
|
144
|
+
# kai_wren = Demon.new('age' => '1500', 'chi' => '1024')
|
145
|
+
# kai_wren.age # => 1500
|
146
|
+
# kai_wren.chi # => #<Chi:0x113af8c @count="1024">
|
147
|
+
def typecast(cast_map)
|
148
|
+
@typecast_map = @typecast_map ? @typecast_map.merge(cast_map.transform_keys(&:to_sym)) : cast_map.transform_keys(&:to_sym)
|
149
|
+
end
|
150
|
+
|
151
|
+
def typecast_map # :nodoc:
|
152
|
+
if defined?(@typecast_map)
|
153
|
+
@typecast_map
|
154
|
+
elsif superclass != Object && superclass.respond_to?(:typecast_map)
|
155
|
+
superclass.typecast_map
|
156
|
+
else
|
157
|
+
{}
|
158
|
+
end
|
113
159
|
end
|
114
160
|
end
|
115
|
-
end
|
116
161
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
162
|
+
module InstanceMethods # :nodoc:
|
163
|
+
def initialize_with_typecasting(attributes = {})
|
164
|
+
# :nodoc:
|
165
|
+
initialize_without_typecasting(attributes)
|
166
|
+
self.class.typecast_map.each do |key, typecaster|
|
167
|
+
value = @attributes[key]
|
168
|
+
if value.is_a?(String) || value.is_a?(Hash) || value.is_a?(Array)
|
169
|
+
@attributes[key] =
|
170
|
+
typecaster.call(value)
|
171
|
+
end
|
172
|
+
end
|
123
173
|
end
|
124
174
|
end
|
125
175
|
end
|