kaiwren-wrest 0.0.6 → 0.0.8

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 (51) hide show
  1. data/README.rdoc +83 -31
  2. data/Rakefile +29 -13
  3. data/VERSION.yml +1 -1
  4. data/examples/delicious.rb +58 -0
  5. data/examples/wow_realm_status.rb +57 -0
  6. data/lib/wrest.rb +11 -2
  7. data/lib/wrest/components.rb +1 -2
  8. data/lib/wrest/components/attributes_container.rb +34 -74
  9. data/lib/wrest/components/attributes_container/typecaster.rb +121 -0
  10. data/lib/wrest/components/mutators.rb +18 -1
  11. data/lib/wrest/components/mutators/base.rb +52 -39
  12. data/lib/wrest/components/mutators/camel_to_snake_case.rb +7 -5
  13. data/lib/wrest/components/mutators/xml_mini_type_caster.rb +43 -0
  14. data/lib/wrest/components/mutators/xml_simple_type_caster.rb +22 -20
  15. data/lib/wrest/components/translators.rb +20 -17
  16. data/lib/wrest/components/translators/content_types.rb +2 -2
  17. data/lib/wrest/components/translators/json.rb +11 -8
  18. data/lib/wrest/components/translators/xml.rb +9 -12
  19. data/lib/wrest/core_ext/hash/conversions.rb +1 -1
  20. data/lib/wrest/core_ext/string/conversions.rb +2 -2
  21. data/lib/wrest/http.rb +24 -0
  22. data/lib/wrest/http/delete.rb +23 -0
  23. data/lib/wrest/http/get.rb +23 -0
  24. data/lib/wrest/http/options.rb +23 -0
  25. data/lib/wrest/http/post.rb +23 -0
  26. data/lib/wrest/http/put.rb +23 -0
  27. data/lib/wrest/http/request.rb +48 -0
  28. data/lib/wrest/http/response.rb +44 -0
  29. data/lib/wrest/resource/base.rb +52 -25
  30. data/lib/wrest/resource/state.rb +6 -0
  31. data/lib/wrest/uri.rb +85 -29
  32. data/lib/wrest/uri_template.rb +18 -1
  33. data/lib/wrest/version.rb +1 -1
  34. data/spec/spec.opts +1 -1
  35. data/spec/spec_helper.rb +8 -1
  36. data/spec/wrest/components/attributes_container/typecaster_spec.rb +63 -0
  37. data/spec/wrest/components/attributes_container_spec.rb +17 -61
  38. data/spec/wrest/components/mutators/base_spec.rb +5 -1
  39. data/spec/wrest/components/mutators/xml_mini_type_caster_spec.rb +75 -0
  40. data/spec/wrest/components/mutators_spec.rb +21 -0
  41. data/spec/wrest/components/translators/xml_spec.rb +1 -1
  42. data/spec/wrest/components/translators_spec.rb +9 -0
  43. data/spec/wrest/core_ext/string/conversions_spec.rb +9 -0
  44. data/spec/wrest/http/request_spec.rb +22 -0
  45. data/spec/wrest/{response_spec.rb → http/response_spec.rb} +4 -4
  46. data/spec/wrest/resource/base_spec.rb +126 -11
  47. data/spec/wrest/uri_spec.rb +124 -20
  48. data/spec/wrest/uri_template_spec.rb +11 -1
  49. metadata +33 -20
  50. data/lib/wrest/components/typecast_helpers.rb +0 -41
  51. data/lib/wrest/response.rb +0 -38
@@ -0,0 +1,121 @@
1
+ # Copyright 2009 Sidu Ponnappa
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ # Unless required by applicable law or agreed to in writing, software distributed under the License
7
+ # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
+ # See the License for the specific language governing permissions and limitations under the License.
9
+
10
+ module Wrest
11
+ module Components::AttributesContainer
12
+ # An extension to AttributesContainer that adds support for
13
+ # specifying 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.alias_method_chain :initialize, :typecasting
28
+ end
29
+
30
+ module ClassMethods
31
+ # Accepts a set of attribute-name/lambda pairs which are used
32
+ # to typecast string values injected through the constructor.
33
+ # Typically needed when populating an +AttributesContainer+
34
+ # directly from request params. Typecasting kicks in for
35
+ # a given value _only_ if it is a string.
36
+ #
37
+ # Typecast information is inherited by subclasses; however be
38
+ # aware that explicitly invoking +typecast+ in a subclass will
39
+ # discard inherited typecast information leaving only the casts
40
+ # defined in the subclass.
41
+ #
42
+ # Common typecasts such as integer, float, datetime etc. are
43
+ # available through predefined helpers. See TypecastHelpers
44
+ # for a full list.
45
+ #
46
+ # Example:
47
+ #
48
+ # class Demon
49
+ # include Wrest::Components::AttributesContainer
50
+ # include Wrest::Components::AttributesContainer::Typecaster
51
+ #
52
+ # typecast :age => as_integer,
53
+ # :chi => lambda{|chi| Chi.new(chi)}
54
+ # end
55
+ #
56
+ # kai_wren = Demon.new('age' => '1500', 'chi' => '1024')
57
+ # kai_wren.age # => 1500
58
+ # kai_wren.chi # => #<Chi:0x113af8c @count="1024">
59
+ def typecast(cast_map)
60
+ @typecast_map = @typecast_map ? @typecast_map.merge(cast_map.symbolize_keys) : cast_map.symbolize_keys
61
+ end
62
+
63
+ def typecast_map #:nodoc:
64
+ if defined?(@typecast_map)
65
+ @typecast_map
66
+ elsif superclass != Object && superclass.respond_to?(:typecast_map)
67
+ superclass.typecast_map
68
+ else
69
+ {}
70
+ end
71
+ end
72
+
73
+ def as_base64Binary
74
+ ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['base64Binary']
75
+ end
76
+
77
+ def as_boolean
78
+ ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['boolean']
79
+ end
80
+
81
+ def as_decimal
82
+ ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['decimal']
83
+ end
84
+
85
+ def as_date
86
+ ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['date']
87
+ end
88
+
89
+ def as_datetime
90
+ ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['datetime']
91
+ end
92
+
93
+ def as_float
94
+ ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['float']
95
+ end
96
+
97
+ def as_integer
98
+ ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['integer']
99
+ end
100
+
101
+ def as_symbol
102
+ ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['symbol']
103
+ end
104
+
105
+ def as_yaml
106
+ ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING['yaml']
107
+ end
108
+ end
109
+
110
+ module InstanceMethods # :nodoc:
111
+ def initialize_with_typecasting(attributes = {}) # :nodoc:
112
+ initialize_without_typecasting(attributes)
113
+ self.class.typecast_map.each do |key, typecaster|
114
+ value = @attributes[key]
115
+ @attributes[key] = typecaster.call(value) if value.is_a?(String)
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -7,16 +7,33 @@
7
7
  # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
8
  # See the License for the specific language governing permissions and limitations under the License.
9
9
 
10
- module Wrest #:nodoc:
10
+ module Wrest
11
11
  module Components
12
12
  # A mutator understands how to transform
13
13
  # one tuple(key/value pair) from a hash
14
14
  # into another
15
15
  module Mutators
16
+ # All sublasses of Mutators::Base are automatically
17
+ # registered here by underscored, symbolised class name.
18
+ REGISTRY = {}
19
+
20
+ # Makes referencing and chaining mutators easy.
21
+ #
22
+ # Example:
23
+ # Mutators.chain(:xml_mini_type_caster, :camel_to_snake_case)
24
+ # is equivalent to
25
+ # Wrest::Components::Mutators::XmlMiniTypeCaster.new(Wrest::Components::Mutators::CamelToSnakeCase.new)
26
+ def self.chain(*mutator_keys)
27
+ mutator_key = mutator_keys.pop
28
+ mutator_keys.reverse.inject(REGISTRY[mutator_key].new) do |next_instance, next_key|
29
+ REGISTRY[next_key].new(next_instance)
30
+ end
31
+ end
16
32
  end
17
33
  end
18
34
  end
19
35
 
20
36
  require "#{WREST_ROOT}/wrest/components/mutators/base"
21
37
  require "#{WREST_ROOT}/wrest/components/mutators/xml_simple_type_caster"
38
+ require "#{WREST_ROOT}/wrest/components/mutators/xml_mini_type_caster"
22
39
  require "#{WREST_ROOT}/wrest/components/mutators/camel_to_snake_case"
@@ -1,43 +1,56 @@
1
1
  # Copyright 2009 Sidu Ponnappa
2
2
 
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
- # Unless required by applicable law or agreed to in writing, software distributed under the License
7
- # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
- # See the License for the specific language governing permissions and limitations under the License.
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ # Unless required by applicable law or agreed to in writing, software distributed under the License
7
+ # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
+ # See the License for the specific language governing permissions and limitations under the License.
9
9
 
10
- # This is a base implementation of a
11
- # hash mutator that ensures that the <tt>mutate</tt> method
12
- # will chain to the next mutator by using a
13
- # template method.
14
- class Wrest::Components::Mutators::Base
15
- attr_reader :next_mutator
16
-
17
- def initialize(next_mutator = nil)
18
- @next_mutator = next_mutator
19
- end
20
-
21
- # This is a template method which operates on a tuple (well, pair)
22
- # from a hash map and guarantees mutator chaining.
23
- #
24
- # Iterating over any hash using <tt>each</tt> injects
25
- # each key/value pair from the hash in the
26
- # form of an array.
27
- # This method expects of this form as an argument, i.e.
28
- # an array with the structure [:key, :value]
29
- #
30
- # The implementation of the mutation is achieved by
31
- # overriding the <tt>do_mutate</tt> method in a subclass.
32
- # Note that failing to do so will result in an exception
33
- # at runtime.
34
- def mutate(tuple)
35
- out_tuple = do_mutate(tuple)
36
- next_mutator ? next_mutator.mutate(out_tuple) : out_tuple
37
- end
38
-
39
- protected
40
- def do_mutate(tuple)
41
- raise Wrest::Exceptions::MethodNotOverriddenException
10
+ module Wrest
11
+ module Components
12
+ # This is a base implementation of a
13
+ # hash mutator that ensures that the <tt>mutate</tt> method
14
+ # will chain to the next mutator by using a
15
+ # template method.
16
+ class Mutators::Base
17
+ attr_reader :next_mutator
18
+
19
+ # Registers all subclasses of Mutators::Base in
20
+ # Mutators::REGISTRY making it easy to reference
21
+ # and chain them later.
22
+ #
23
+ # See Mutators#chain for more information.
24
+ def self.inherited(subklass)
25
+ Wrest::Components::Mutators::REGISTRY[subklass.name.demodulize.underscore.to_sym] = subklass unless subklass.name.blank?
26
+ end
27
+
28
+ def initialize(next_mutator = nil)
29
+ @next_mutator = next_mutator
30
+ end
31
+
32
+ # This is a template method which operates on a tuple (well, pair)
33
+ # from a hash map and guarantees mutator chaining.
34
+ #
35
+ # Iterating over any hash using <tt>each</tt> injects
36
+ # each key/value pair from the hash in the
37
+ # form of an array.
38
+ # This method expects of this form as an argument, i.e.
39
+ # an array with the structure [:key, :value]
40
+ #
41
+ # The implementation of the mutation is achieved by
42
+ # overriding the <tt>do_mutate</tt> method in a subclass.
43
+ # Note that failing to do so will result in an exception
44
+ # at runtime.
45
+ def mutate(tuple)
46
+ out_tuple = do_mutate(tuple)
47
+ next_mutator ? next_mutator.mutate(out_tuple) : out_tuple
48
+ end
49
+
50
+ protected
51
+ def do_mutate(tuple)
52
+ raise Wrest::Exceptions::MethodNotOverriddenException
53
+ end
54
+ end
42
55
  end
43
- end
56
+ end
@@ -7,14 +7,16 @@
7
7
  # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
8
  # See the License for the specific language governing permissions and limitations under the License.
9
9
 
10
- module Wrest::Components
11
- class Mutators::CamelToSnakeCase < Mutators::Base
10
+ module Wrest
11
+ module Components
12
12
  # Converts the key to snake case
13
13
  #
14
14
  # Example:
15
- # Mutators::CamelToSnakeCase.new.mutate(['Spirit-Sword', 'true']) # => ['spirit_sword', 'true']
16
- def do_mutate(tuple)
17
- [tuple.first.underscore, tuple.last]
15
+ # Mutators::CamelToSnakeCase.new.mutate(['Spirit-Sword', 'true']) # => ['spirit_sword', 'true']**
16
+ class Mutators::CamelToSnakeCase < Mutators::Base
17
+ def do_mutate(tuple)
18
+ [tuple.first.underscore, tuple.last]
19
+ end
18
20
  end
19
21
  end
20
22
  end
@@ -0,0 +1,43 @@
1
+ # Copyright 2009 Sidu Ponnappa
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ # Unless required by applicable law or agreed to in writing, software distributed under the License
7
+ # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
+ # See the License for the specific language governing permissions and limitations under the License.
9
+
10
+
11
+ module Wrest
12
+ module Components
13
+ # This mutator undertands how do type casting
14
+ # using the type data embedded in a hash
15
+ # created by deserialising an xml using
16
+ # ActiveSupport::XmlMini
17
+ class Mutators::XmlMiniTypeCaster < Mutators::Base
18
+ def do_mutate(tuple)
19
+ out_key, in_value = tuple
20
+
21
+ case in_value
22
+ when Hash
23
+ if in_value['nil'] == 'true'
24
+ out_value = nil
25
+ elsif in_value.key?('type')
26
+ caster = ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING[in_value['type']]
27
+ out_value = caster ? caster.call(in_value['__content__']) : in_value
28
+ elsif in_value.key?('__content__')
29
+ out_value = in_value['__content__']
30
+ else
31
+ out_value = in_value.mutate_using(self)
32
+ end
33
+ when Array
34
+ out_value = in_value.collect{|hash| hash.mutate_using(self)}
35
+ else
36
+ out_value = in_value
37
+ end
38
+
39
+ [out_key, out_value]
40
+ end
41
+ end
42
+ end
43
+ end
@@ -7,29 +7,31 @@
7
7
  # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
8
  # See the License for the specific language governing permissions and limitations under the License.
9
9
 
10
- # This mutator undertands how do type casting
11
- # using the type data embedded in a hash
12
- # created by deserialising an xml using
13
- # xml-simple
14
- module Wrest::Components
15
- class Mutators::XmlSimpleTypeCaster < Mutators::Base
16
- def do_mutate(tuple)
17
- out_key = tuple.first
18
- in_value = tuple.last[0]
19
- out_value = in_value
10
+ module Wrest
11
+ module Components
12
+ # This mutator undertands how do type casting
13
+ # using the type data embedded in a hash
14
+ # created by deserialising an xml using
15
+ # xml-simple
16
+ class Mutators::XmlSimpleTypeCaster < Mutators::Base
17
+ def do_mutate(tuple)
18
+ out_key = tuple.first
19
+ in_value = tuple.last[0]
20
+ out_value = in_value
20
21
 
21
- case in_value
22
- when Hash
23
- if in_value['nil'] == 'true'
24
- out_value = nil
25
- elsif in_value.key?('type')
26
- out_value = ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING[in_value['type']].call(in_value['content'])
27
- else
28
- out_value = in_value.mutate_using(self)
22
+ case in_value
23
+ when Hash
24
+ if in_value['nil'] == 'true'
25
+ out_value = nil
26
+ elsif in_value.key?('type')
27
+ out_value = ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING[in_value['type']].call(in_value['content'])
28
+ else
29
+ out_value = in_value.mutate_using(self)
30
+ end
29
31
  end
30
- end
31
32
 
32
- [out_key, out_value]
33
+ [out_key, out_value]
34
+ end
33
35
  end
34
36
  end
35
37
  end
@@ -1,25 +1,28 @@
1
1
  # Copyright 2009 Sidu Ponnappa
2
2
 
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
- # Unless required by applicable law or agreed to in writing, software distributed under the License
7
- # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
- # See the License for the specific language governing permissions and limitations under the License.
9
-
10
- module Wrest::Components #:nodoc:
11
- # Contains strategies/lambdas which know how to deserialise
12
- # different content types.
13
- module Translators
14
- # Loads the appropriate desirialisation strategy based on
15
- # the content type
16
- def self.lookup(content_type)
17
- translator = CONTENT_TYPES[content_type]
18
- translator || (raise Wrest::Exceptions::UnsupportedContentTypeException.new("Unsupported content type #{content_type}"))
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ # Unless required by applicable law or agreed to in writing, software distributed under the License
7
+ # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
+ # See the License for the specific language governing permissions and limitations under the License.
9
+
10
+
11
+ module Wrest
12
+ module Components
13
+ # Contains strategies/lambdas which know how to deserialise
14
+ # different content types.
15
+ module Translators
16
+ # Loads the appropriate desirialisation strategy based on
17
+ # the content type
18
+ def self.lookup(content_type)
19
+ translator = CONTENT_TYPES[content_type]
20
+ translator || (raise Wrest::Exceptions::UnsupportedContentTypeException.new("Unsupported content type #{content_type}"))
21
+ end
19
22
  end
20
23
  end
21
24
  end
22
25
 
23
26
  require "#{WREST_ROOT}/wrest/components/translators/xml"
24
27
  require "#{WREST_ROOT}/wrest/components/translators/json"
25
- require "#{WREST_ROOT}/wrest/components/translators/content_types"
28
+ require "#{WREST_ROOT}/wrest/components/translators/content_types"
@@ -7,8 +7,8 @@
7
7
  # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
8
  # See the License for the specific language governing permissions and limitations under the License.
9
9
 
10
- module Wrest::Components
11
- module Translators
10
+ module Wrest
11
+ module Components::Translators
12
12
  # Maps content types to deserialisers
13
13
  CONTENT_TYPES = {
14
14
  'application/xml' => Wrest::Components::Translators::Xml,
@@ -7,16 +7,19 @@
7
7
  # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
8
  # See the License for the specific language governing permissions and limitations under the License.
9
9
 
10
- module Wrest::Components::Translators
11
- module Json
12
- extend self
13
10
 
14
- def deserialise(response)
15
- ActiveSupport::JSON.decode(response.body)
16
- end
11
+ module Wrest
12
+ module Components
13
+ module Translators::Json
14
+ extend self
15
+
16
+ def deserialise(response)
17
+ ActiveSupport::JSON.decode(response.body)
18
+ end
17
19
 
18
- def serialise(hash)
19
- ActiveSupport::JSON.encode(hash)
20
+ def serialise(hash)
21
+ ActiveSupport::JSON.encode(hash)
22
+ end
20
23
  end
21
24
  end
22
25
  end