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.
Files changed (76) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG +3 -0
  3. data/LICENCE +1 -1
  4. data/README.md +29 -28
  5. data/bin/wrest +2 -1
  6. data/bin/wrest_shell.rb +10 -8
  7. data/lib/wrest/async_request/event_machine_backend.rb +3 -1
  8. data/lib/wrest/async_request/thread_backend.rb +5 -2
  9. data/lib/wrest/async_request/thread_pool.rb +4 -2
  10. data/lib/wrest/async_request.rb +7 -6
  11. data/lib/wrest/cache_proxy.rb +39 -28
  12. data/lib/wrest/caching/memcached.rb +21 -18
  13. data/lib/wrest/caching/redis.rb +22 -22
  14. data/lib/wrest/caching.rb +16 -14
  15. data/lib/wrest/callback.rb +19 -16
  16. data/lib/wrest/components/container/alias_accessors.rb +51 -47
  17. data/lib/wrest/components/container/typecaster.rb +146 -96
  18. data/lib/wrest/components/container.rb +171 -152
  19. data/lib/wrest/components/mutators/base.rb +43 -34
  20. data/lib/wrest/components/mutators/camel_to_snake_case.rb +7 -3
  21. data/lib/wrest/components/mutators/{xml_mini_type_caster.rb → xml_type_caster.rb} +29 -16
  22. data/lib/wrest/components/mutators.rb +21 -19
  23. data/lib/wrest/components/translators/content_types.rb +20 -16
  24. data/lib/wrest/components/translators/json.rb +19 -16
  25. data/lib/wrest/components/translators/txt.rb +19 -15
  26. data/lib/wrest/components/translators/xml/conversions.rb +56 -0
  27. data/lib/wrest/components/translators/xml.rb +60 -18
  28. data/lib/wrest/components/translators.rb +7 -6
  29. data/lib/wrest/components.rb +11 -8
  30. data/lib/wrest/core_ext/hash/conversions.rb +10 -10
  31. data/lib/wrest/core_ext/hash.rb +4 -2
  32. data/lib/wrest/core_ext/string/conversions.rb +14 -13
  33. data/lib/wrest/core_ext/string.rb +5 -3
  34. data/lib/wrest/exceptions.rb +4 -2
  35. data/lib/wrest/hash_with_case_insensitive_access.rb +8 -8
  36. data/lib/wrest/hash_with_indifferent_access.rb +442 -0
  37. data/lib/wrest/http_codes.rb +20 -19
  38. data/lib/wrest/http_shared/headers.rb +2 -0
  39. data/lib/wrest/http_shared/standard_headers.rb +2 -2
  40. data/lib/wrest/http_shared/standard_tokens.rb +8 -6
  41. data/lib/wrest/http_shared.rb +5 -3
  42. data/lib/wrest/multipart.rb +20 -11
  43. data/lib/wrest/native/connection_factory.rb +15 -11
  44. data/lib/wrest/native/delete.rb +15 -11
  45. data/lib/wrest/native/get.rb +60 -56
  46. data/lib/wrest/native/options.rb +15 -11
  47. data/lib/wrest/native/patch.rb +16 -12
  48. data/lib/wrest/native/post.rb +15 -11
  49. data/lib/wrest/native/post_multipart.rb +22 -18
  50. data/lib/wrest/native/put.rb +16 -12
  51. data/lib/wrest/native/put_multipart.rb +22 -18
  52. data/lib/wrest/native/redirection.rb +13 -12
  53. data/lib/wrest/native/request.rb +144 -108
  54. data/lib/wrest/native/response.rb +87 -78
  55. data/lib/wrest/native/session.rb +49 -40
  56. data/lib/wrest/native.rb +14 -12
  57. data/lib/wrest/test/request_patches.rb +10 -3
  58. data/lib/wrest/test.rb +3 -1
  59. data/lib/wrest/uri/builders.rb +14 -12
  60. data/lib/wrest/uri.rb +70 -52
  61. data/lib/wrest/uri_template.rb +11 -7
  62. data/lib/wrest/utils.rb +129 -0
  63. data/lib/wrest/version.rb +3 -1
  64. data/lib/wrest.rb +31 -33
  65. data/lib/wrest_no_ext.rb +2 -0
  66. metadata +98 -48
  67. data/lib/wrest/components/mutators/xml_simple_type_caster.rb +0 -37
  68. data/lib/wrest/xml_mini/jdom/xpath_filter.rb +0 -17
  69. data/lib/wrest/xml_mini/jdom.rb +0 -6
  70. data/lib/wrest/xml_mini/libxml/xpath_filter.rb +0 -12
  71. data/lib/wrest/xml_mini/libxml.rb +0 -8
  72. data/lib/wrest/xml_mini/nokogiri/xpath_filter.rb +0 -15
  73. data/lib/wrest/xml_mini/nokogiri.rb +0 -7
  74. data/lib/wrest/xml_mini/rexml/xpath_filter.rb +0 -15
  75. data/lib/wrest/xml_mini/rexml.rb +0 -8
  76. 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::Container
12
- module AliasAccessors
13
- def self.included(klass) #:nodoc:
14
- klass.extend AliasAccessors::ClassMethods
15
- end
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
- def self.build_aliased_attribute_getter(attribute_name, alias_name) #:nodoc:
18
- "def #{alias_name};#{attribute_name};end;"
19
- end
20
+ def self.build_aliased_attribute_getter(attribute_name, alias_name) # :nodoc:
21
+ "def #{alias_name};#{attribute_name};end;"
22
+ end
20
23
 
21
- def self.build_aliased_attribute_setter(attribute_name, alias_name) #:nodoc:
22
- "def #{alias_name}=(value);self.#{attribute_name}=value;end;"
23
- end
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
- def self.build_aliased_attribute_queryer(attribute_name, alias_name) #:nodoc:
26
- "def #{alias_name}?;self.#{attribute_name}?;end;"
27
- end
28
-
29
- module ClassMethods
30
- # Creates an alias set of getter, setter and query methods for
31
- # attributes that aren't quite the way you'd like them to be; this
32
- # is especially useful when you have no control over the source web
33
- # sevice/resource.
34
- #
35
- # For example, lets say that a particular resource exposes a
36
- # User's age as 'a' and sex as 's'. Typically, you'd have to access it as
37
- # user.a and user.s whereas you's like to access it as user.age and user.sex.
38
- # This is where alias_accessors comes into the picture. Your User class would
39
- # look somethig like this:
40
- #
41
- # class User
42
- # include Wrest::Components::Container
43
- #
44
- # alias_accessors :a => :age,
45
- # :s => :sex
46
- # end
47
- # This would create the methods user.age, user.age= and user.age? which delegates
48
- # to user.a, user.a= and user.a? respectively.
49
- #
50
- # See examples/wow_realm_status.rb for a working example.
51
- #
52
- # WARNING: If you try to create an alias with the same name as the attribute,
53
- # and then use it, you _will_ cause an infinite loop.
54
- def alias_accessors(alias_map)
55
- alias_map.each do |attribute_name, alias_name|
56
- self.class_eval(
57
- AliasAccessors.build_aliased_attribute_getter(attribute_name, alias_name) +
58
- AliasAccessors.build_aliased_attribute_setter(attribute_name, alias_name) +
59
- AliasAccessors.build_aliased_attribute_queryer(attribute_name, alias_name)
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::Container
12
- # An extension to Container that adds support for specifying
13
- # how the values associated with certain attribute keys
14
- # should be typecast.
15
- #
16
- # This extension can be used in situations where the attributes
17
- # hash consists of just strings with no associated tup information.
18
- # For example, params recieved from a web browser may contain
19
- # attributes like
20
- # 'id' => '4', 'dateofbirth' => '1984-04-05'
21
- # and we'd like to have these cast to an integer and a date
22
- # respectively, rather than have to deal with them as strings.
23
- module Typecaster
24
- def self.included(klass) #:nodoc:
25
- klass.extend Typecaster::ClassMethods
26
- klass.class_eval{ include Typecaster::InstanceMethods }
27
- klass.send(:alias_method, :initialize_without_typecasting, :initialize)
28
- klass.send(:alias_method, :initialize, :initialize_with_typecasting)
29
- end
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
- module Helpers
32
- def as_base64Binary
33
- ActiveSupport::XmlMini::PARSING['base64Binary']
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
- def as_boolean
37
- ActiveSupport::XmlMini::PARSING['boolean']
38
- end
76
+ module Helpers
77
+ def as_base64_binary
78
+ PARSING['base64Binary']
79
+ end
39
80
 
40
- def as_decimal
41
- ActiveSupport::XmlMini::PARSING['decimal']
42
- end
81
+ def as_boolean
82
+ PARSING['boolean']
83
+ end
43
84
 
44
- def as_date
45
- ActiveSupport::XmlMini::PARSING['date']
46
- end
85
+ def as_decimal
86
+ PARSING['decimal']
87
+ end
47
88
 
48
- def as_datetime
49
- ActiveSupport::XmlMini::PARSING['datetime']
50
- end
89
+ def as_date
90
+ PARSING['date']
91
+ end
51
92
 
52
- def as_float
53
- ActiveSupport::XmlMini::PARSING['float']
54
- end
93
+ def as_datetime
94
+ PARSING['datetime']
95
+ end
55
96
 
56
- def as_integer
57
- ActiveSupport::XmlMini::PARSING['integer']
58
- end
97
+ def as_float
98
+ PARSING['float']
99
+ end
59
100
 
60
- def as_symbol
61
- ActiveSupport::XmlMini::PARSING['symbol']
62
- end
101
+ def as_integer
102
+ PARSING['integer']
103
+ end
63
104
 
64
- def as_yaml
65
- ActiveSupport::XmlMini::PARSING['yaml']
66
- end
67
- end
105
+ def as_symbol
106
+ PARSING['symbol']
107
+ end
68
108
 
69
- module ClassMethods
70
- # Accepts a set of attribute-name/lambda pairs which are used
71
- # to typecast string values injected through the constructor.
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
- def typecast_map #:nodoc:
107
- if defined?(@typecast_map)
108
- @typecast_map
109
- elsif superclass != Object && superclass.respond_to?(:typecast_map)
110
- superclass.typecast_map
111
- else
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
- module InstanceMethods # :nodoc:
118
- def initialize_with_typecasting(attributes = {}) # :nodoc:
119
- initialize_without_typecasting(attributes)
120
- self.class.typecast_map.each do |key, typecaster|
121
- value = @attributes[key]
122
- @attributes[key] = typecaster.call(value) if (value.is_a?(String) || value.is_a?(Hash) || value.is_a?(Array))
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