wrest 0.0.6-java → 0.0.7-java

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 (34) hide show
  1. data/README.rdoc +51 -19
  2. data/Rakefile +2 -3
  3. data/VERSION.yml +1 -1
  4. data/lib/wrest.rb +11 -2
  5. data/lib/wrest/components.rb +1 -2
  6. data/lib/wrest/components/attributes_container.rb +31 -69
  7. data/lib/wrest/components/attributes_container/typecaster.rb +121 -0
  8. data/lib/wrest/components/mutators.rb +18 -1
  9. data/lib/wrest/components/mutators/base.rb +52 -39
  10. data/lib/wrest/components/mutators/camel_to_snake_case.rb +7 -5
  11. data/lib/wrest/components/mutators/xml_mini_type_caster.rb +43 -0
  12. data/lib/wrest/components/mutators/xml_simple_type_caster.rb +22 -20
  13. data/lib/wrest/components/translators.rb +20 -17
  14. data/lib/wrest/components/translators/content_types.rb +2 -2
  15. data/lib/wrest/components/translators/json.rb +11 -8
  16. data/lib/wrest/components/translators/xml.rb +9 -12
  17. data/lib/wrest/core_ext/hash/conversions.rb +1 -1
  18. data/lib/wrest/resource/base.rb +25 -13
  19. data/lib/wrest/resource/state.rb +6 -0
  20. data/lib/wrest/response.rb +4 -0
  21. data/lib/wrest/uri.rb +5 -1
  22. data/lib/wrest/version.rb +1 -1
  23. data/spec/spec.opts +1 -1
  24. data/spec/spec_helper.rb +8 -1
  25. data/spec/wrest/components/attributes_container/typecaster_spec.rb +63 -0
  26. data/spec/wrest/components/attributes_container_spec.rb +6 -61
  27. data/spec/wrest/components/mutators/base_spec.rb +5 -1
  28. data/spec/wrest/components/mutators/xml_mini_type_caster_spec.rb +75 -0
  29. data/spec/wrest/components/mutators_spec.rb +21 -0
  30. data/spec/wrest/components/translators/xml_spec.rb +1 -1
  31. data/spec/wrest/components/translators_spec.rb +9 -0
  32. data/spec/wrest/uri_spec.rb +16 -4
  33. metadata +14 -15
  34. data/lib/wrest/components/typecast_helpers.rb +0 -41
@@ -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
@@ -7,20 +7,17 @@
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
- require 'xmlsimple'
10
+ module Wrest
11
+ module Components::Translators
12
+ module Xml
13
+ extend self
11
14
 
12
- module Wrest::Components::Translators
13
- module Xml
14
- extend self
15
+ def deserialise(response)
16
+ ActiveSupport::XmlMini.parse(response.body)
17
+ end
15
18
 
16
- def deserialise(response)
17
- XmlSimple.xml_in(
18
- response.body,
19
- 'keeproot' => true
20
- )
21
- end
22
-
23
- def serialise(hash)
19
+ def serialise(hash)
20
+ end
24
21
  end
25
22
  end
26
23
  end
@@ -22,7 +22,7 @@ module Wrest
22
22
  # Yes, the name is misleading in that respect. However, one
23
23
  # hopes the absence of an exclamation mark will increase clarity.
24
24
  #
25
- # Uses include mutating the hash produced by xml-simple
25
+ # Uses include mutating the hash produced by deserialising xml
26
26
  # by using the meta data in the hash to type cast values.
27
27
  #
28
28
  # Example:
@@ -12,55 +12,67 @@ module Wrest::Resource #:nodoc:
12
12
  # It is a REST client targetted at Rails REST apps.
13
13
  class Base
14
14
  include Wrest::Components::AttributesContainer
15
-
16
- has_attributes :id
15
+ include Wrest::Components::AttributesContainer::Typecaster
16
+
17
+ always_has :id
17
18
  typecast :id => as_integer
18
19
  attr_reader :attributes
19
-
20
+
20
21
  class << self
21
22
  def inherited(klass)
22
23
  klass.set_resource_name klass.name
23
24
  end
24
-
25
+
25
26
  # Allows the resource name to be configured and creates
26
- # a getter method for it.
27
+ # a getter method for it.
27
28
  # This is a useful feature when using anonymous classes like
28
29
  # we often do while writing tests.
29
30
  # By default, the resource name is set to the name of the class.
30
31
  def set_resource_name(resource_name)
31
32
  self.class_eval "def self.resource_name; '#{resource_name}';end"
32
33
  end
33
-
34
+
34
35
  # Allows the host url at which the resource is found to be configured
35
- # and creates a getter method for it.
36
+ # and creates a getter method for it.
36
37
  # For example in the url
37
38
  # http://localhost:3000/users/1/settings
38
- # you would set
39
+ # you would set
39
40
  # http://localhost:3000
40
41
  # as the host url.
41
42
  def set_host(host)
42
43
  self.class_eval "def self.host; '#{host}';end"
43
44
  end
44
45
 
45
- def set_redirect_handler(method_object)
46
+ def set_default_format(format)
47
+ self.class_eval "def self.default_format; '#{format.to_s}';end"
46
48
  end
47
49
 
50
+ def set_redirect_handler(method_object)
51
+ end
52
+
48
53
  def resource_path
49
54
  @resource_path ||= "/#{resource_name.underscore.pluralize}"
50
55
  end
51
56
 
52
- def resource_url
57
+ def resource_collection_url
53
58
  "#{host}#{resource_path}"
54
59
  end
55
-
60
+
56
61
  def find_all
57
62
  end
58
63
 
64
+ def find(resource_type = [:one, :collection, :singleton], from = "")
65
+ end
66
+
59
67
  def find(id)
60
- response_hash = "#{resource_url}/#{id}".to_uri.get.deserialise
68
+ response_hash = "#{resource_collection_url}/#{id}.#{default_format}".to_uri.get.deserialise.mutate_using(
69
+ Wrest::Components::Mutators.chain(
70
+ :xml_mini_type_caster, :camel_to_snake_case
71
+ )
72
+ )
61
73
  resource_type = response_hash.keys.first
62
74
  if(resource_type.underscore.camelize == self.name)
63
- self.new(response_hash[resource_type].first)
75
+ self.new(response_hash[resource_type])
64
76
  else
65
77
  response_hash
66
78
  end