wrest 0.0.5-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/README.rdoc +101 -0
  2. data/Rakefile +243 -0
  3. data/VERSION.yml +4 -0
  4. data/bin/jwrest +3 -0
  5. data/bin/wrest +3 -0
  6. data/bin/wrest_shell.rb +21 -0
  7. data/lib/wrest.rb +41 -0
  8. data/lib/wrest/components.rb +19 -0
  9. data/lib/wrest/components/attributes_container.rb +123 -0
  10. data/lib/wrest/components/mutators.rb +21 -0
  11. data/lib/wrest/components/mutators/base.rb +27 -0
  12. data/lib/wrest/components/mutators/xml_simple_type_caster.rb +31 -0
  13. data/lib/wrest/core_ext/hash.rb +5 -0
  14. data/lib/wrest/core_ext/hash/conversions.rb +25 -0
  15. data/lib/wrest/core_ext/string.rb +5 -0
  16. data/lib/wrest/core_ext/string/conversions.rb +23 -0
  17. data/lib/wrest/exceptions.rb +1 -0
  18. data/lib/wrest/exceptions/unsupported_content_type_exception.rb +15 -0
  19. data/lib/wrest/resource.rb +18 -0
  20. data/lib/wrest/resource/base.rb +69 -0
  21. data/lib/wrest/resource/collection.rb +12 -0
  22. data/lib/wrest/response.rb +38 -0
  23. data/lib/wrest/translators.rb +25 -0
  24. data/lib/wrest/translators/content_types.rb +20 -0
  25. data/lib/wrest/translators/json.rb +21 -0
  26. data/lib/wrest/translators/xml.rb +24 -0
  27. data/lib/wrest/uri.rb +74 -0
  28. data/lib/wrest/uri_template.rb +32 -0
  29. data/lib/wrest/version.rb +22 -0
  30. data/spec/custom_matchers/custom_matchers.rb +2 -0
  31. data/spec/rcov.opts +4 -0
  32. data/spec/spec.opts +6 -0
  33. data/spec/spec_helper.rb +18 -0
  34. data/spec/wrest/components/attributes_container_spec.rb +184 -0
  35. data/spec/wrest/components/mutators/base_spec.rb +18 -0
  36. data/spec/wrest/components/mutators/xml_simple_type_caster_spec.rb +41 -0
  37. data/spec/wrest/core_ext/hash/conversions_spec.rb +22 -0
  38. data/spec/wrest/core_ext/string/conversions_spec.rb +16 -0
  39. data/spec/wrest/resource/base_spec.rb +158 -0
  40. data/spec/wrest/response_spec.rb +21 -0
  41. data/spec/wrest/translators/xml_spec.rb +12 -0
  42. data/spec/wrest/translators_spec.rb +9 -0
  43. data/spec/wrest/uri_spec.rb +131 -0
  44. data/spec/wrest/uri_template_spec.rb +28 -0
  45. metadata +139 -0
@@ -0,0 +1,123 @@
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::Components #:nodoc:
11
+
12
+ # Adds behaviour allowing a class to
13
+ # contain attributes and providing support
14
+ # for dynamic getters, setters and query methods.
15
+ # These methods are added at runtime, on the first
16
+ # invocation and on a per instance basis.
17
+ # <tt>respond_to?</tt> however will respond as though
18
+ # they are all already present.
19
+ # This means that two different instances of the same
20
+ # <tt>AttributesContainer</tt> could well have
21
+ # different attribute getters/setters/query methods.
22
+ #
23
+ # Note that this means the first call to a particular
24
+ # method will be slower because the method is defined
25
+ # at that point; subsequent calls will be much faster.
26
+ #
27
+ # If you're implementing your own initialize method
28
+ # remember to delegate to the default initialize
29
+ # of AttributesContainer by invoking <tt>super(attributes)</tt>
30
+ # Also keep in mind that attribute getter/setter/query methods
31
+ # will _not_ override any existing methods on the class.
32
+ #
33
+ # In situations where this is a problem, such as a client consuming Rails
34
+ # REST services where <tt>id</tt> is a common attribute and clashes with
35
+ # Object#id it is recommended to create getter/setter/query methods
36
+ # on the class (which affects all instances) using the <tt>has_attributes</tt> macro.
37
+ module AttributesContainer
38
+ def self.included(klass) #:nodoc:
39
+ klass.extend AttributesContainer::ClassMethods
40
+ klass.class_eval{ include AttributesContainer::InstanceMethods }
41
+ end
42
+
43
+ def self.build_attribute_getter(attribute_name) #:nodoc:
44
+ "def #{attribute_name};@attributes[:#{attribute_name}];end;"
45
+ end
46
+
47
+ def self.build_attribute_setter(attribute_name) #:nodoc:
48
+ "def #{attribute_name}=(value);@attributes[:#{attribute_name}] = value;end;"
49
+ end
50
+
51
+ def self.build_attribute_queryer(attribute_name) #:nodoc:
52
+ "def #{attribute_name}?;not @attributes[:#{attribute_name}].nil?;end;"
53
+ end
54
+
55
+ module ClassMethods
56
+ # This macro explicitly creates getter, setter and query methods on
57
+ # a class, overriding any exisiting methods with the same names.
58
+ # This can be used when attribute names clash with method names;
59
+ # an example would be Rails REST services which frequently make use
60
+ # an attribute named <tt>id</tt> which clashes with Object#id. Also,
61
+ # this can be used as a performance optimisation if the incoming
62
+ # attributes are known beforehand, as defining methods on the first
63
+ # invocation is no longer necessary.
64
+ def has_attributes(*attribute_names)
65
+ attribute_names.each do |attribute_name|
66
+ self.class_eval(
67
+ AttributesContainer.build_attribute_getter(attribute_name) +
68
+ AttributesContainer.build_attribute_setter(attribute_name) +
69
+ AttributesContainer.build_attribute_queryer(attribute_name)
70
+ )
71
+ end
72
+ end
73
+ end
74
+
75
+ module InstanceMethods
76
+ # Sets up any class to act like
77
+ # an attributes container by creating
78
+ # two variables, @attributes and @interface.
79
+ # Remember not to use these two variable names
80
+ # when using AttributesContainer in your
81
+ # own class.
82
+ def initialize(attributes = {})
83
+ @attributes = attributes.symbolize_keys
84
+ @interface = Module.new
85
+ self.extend @interface
86
+ end
87
+
88
+ def [](key)
89
+ @attributes[key.to_sym]
90
+ end
91
+
92
+ def []=(key, value)
93
+ @attributes[key.to_sym] = value
94
+ end
95
+
96
+ def respond_to?(method_name, include_private = false)
97
+ super(method_name, include_private) ? true : @attributes.include?(method_name.to_s.gsub(/(\?$)|(=$)/, '').to_sym)
98
+ end
99
+
100
+ # Creates getter, setter and query methods for
101
+ # attributes on the first call.
102
+ def method_missing(method_sym, *arguments)
103
+ method_name = method_sym.to_s
104
+ attribute_name = method_name.gsub(/(\?$)|(=$)/, '')
105
+
106
+ if @attributes.include?(attribute_name.to_sym) || method_name.last == '='
107
+ case method_name.last
108
+ when '='
109
+ @interface.module_eval AttributesContainer.build_attribute_setter(attribute_name)
110
+ when '?'
111
+ @interface.module_eval AttributesContainer.build_attribute_queryer(attribute_name)
112
+ else
113
+ @interface.module_eval AttributesContainer.build_attribute_getter(attribute_name)
114
+ end
115
+ send(method_sym, *arguments)
116
+ else
117
+ super(method_sym, *arguments)
118
+ end
119
+ end
120
+
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,21 @@
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 #:nodoc:
11
+ module Components
12
+ # A mutator understands how to transform
13
+ # one tuple(key/value pair) from a hash
14
+ # into another
15
+ module Mutators
16
+ end
17
+ end
18
+ end
19
+
20
+ require "#{WREST_ROOT}/wrest/components/mutators/base"
21
+ require "#{WREST_ROOT}/wrest/components/mutators/xml_simple_type_caster"
@@ -0,0 +1,27 @@
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
+ # This is a Null Object implementation of a
11
+ # hash mutator that will leave the contents
12
+ # of any hash it is applied to unchanged.
13
+ class Wrest::Components::Mutators::Base
14
+ # This method operates on a tuple (well, pair)
15
+ # from a hash map.
16
+ # Iterating over any hash using each injects
17
+ # each key/value pair from the hash in the
18
+ # form of an array.
19
+ # Thus the tuple this method expects
20
+ # is simply [:key, :value]
21
+ #
22
+ # Since this is a Null Object, this method
23
+ # simply returns the tuple unchanged
24
+ def mutate(tuple)
25
+ tuple
26
+ end
27
+ end
@@ -0,0 +1,31 @@
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
+ # 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
+ class Wrest::Components::Mutators::XmlSimpleTypeCaster
15
+ def mutate(tuple)
16
+ out_key = tuple.first.underscore
17
+ in_value = tuple.last[0]
18
+ out_value = in_value
19
+
20
+ case in_value
21
+ when Hash
22
+ if in_value["nil"] == "true"
23
+ out_value = nil
24
+ elsif in_value["type"] == "integer"
25
+ out_value = in_value["content"].to_i
26
+ end
27
+ end
28
+
29
+ [out_key, out_value]
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ require "#{WREST_ROOT}/wrest/core_ext/hash/conversions"
2
+
3
+ class Hash #:nodoc:
4
+ include Wrest::CoreExt::Hash::Conversions
5
+ end
@@ -0,0 +1,25 @@
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 CoreExt #:nodoc:
12
+ module Hash #:nodoc:
13
+ # Makes it easier to build other objects from a String
14
+ module Conversions
15
+
16
+ # A convenience method equivalent to Wrest::Uri.new(string)
17
+ def to_mutated_hash(mutator)
18
+ returning({})do |mutated_hash|
19
+ self.each{|tuple| mutated_hash.store(*mutator.mutate(tuple))}
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,5 @@
1
+ require "#{WREST_ROOT}/wrest/core_ext/string/conversions"
2
+
3
+ class String #:nodoc:
4
+ include Wrest::CoreExt::String::Conversions
5
+ end
@@ -0,0 +1,23 @@
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 CoreExt #:nodoc:
12
+ module String #:nodoc:
13
+ # Makes it easier to build other objects from a String
14
+ module Conversions
15
+
16
+ # A convenience method equivalent to Wrest::Uri.new(string)
17
+ def to_uri
18
+ Wrest::Uri.new(self)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1 @@
1
+ require "#{WREST_ROOT}/wrest/exceptions/unsupported_content_type_exception"
@@ -0,0 +1,15 @@
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
+ # Raised when a translator for an unregisterd response content type
12
+ # is requested. See Translators.
13
+ class UnsupportedContentTypeException < StandardError
14
+ end
15
+ end
@@ -0,0 +1,18 @@
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
+ # Wrest::Resource is a re-implementation
12
+ # of ActiveResource using Wrest::Components
13
+ # and with some of the rough edges removed
14
+ module Resource
15
+ end
16
+ end
17
+
18
+ require "#{WREST_ROOT}/wrest/resource/base"
@@ -0,0 +1,69 @@
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::Resource #:nodoc:
11
+ # Resource::Base is the equivalent of ActiveResource::Base.
12
+ # It is a REST client targetted at Rails REST apps.
13
+ class Base
14
+ include Wrest::Components::AttributesContainer
15
+
16
+ has_attributes :id
17
+ attr_reader :attributes
18
+
19
+ class << self
20
+ def inherited(klass)
21
+ klass.set_resource_name klass.name
22
+ end
23
+
24
+ # Allows the resource name to be configured and creates
25
+ # a getter method for it.
26
+ # This is a useful feature when using anonymous classes like
27
+ # we often do while writing tests.
28
+ # By default, the resource name is set to the name of the class.
29
+ def set_resource_name(resource_name)
30
+ self.class_eval "def self.resource_name; '#{resource_name}';end"
31
+ end
32
+
33
+ # Allows the host url at which the resource is found to be configured
34
+ # and creates a getter method for it.
35
+ # For example in the url
36
+ # http://localhost:3000/users/1/settings
37
+ # you would set
38
+ # http://localhost:3000
39
+ # as the host url.
40
+ def set_host(host)
41
+ self.class_eval "def self.host; '#{host}';end"
42
+ end
43
+
44
+ def resource_path
45
+ @resource_path ||= "/#{resource_name.underscore.pluralize}"
46
+ end
47
+
48
+ def resource_url
49
+ "#{host}#{resource_path}"
50
+ end
51
+
52
+ def find_all
53
+ end
54
+
55
+ def find(id)
56
+ response_hash = "#{resource_url}/#{id}".to_uri.get.deserialise
57
+ resource_type = response_hash.keys.first
58
+ if(resource_type.underscore.camelize == self.name)
59
+ self.new(response_hash[resource_type].first)
60
+ else
61
+ response_hash
62
+ end
63
+ end
64
+
65
+ def objectify(hash)
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,12 @@
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
+ # Understands how to contain a collection of Wrest::Resources
11
+ class Wrest::Resource::Collection
12
+ end
@@ -0,0 +1,38 @@
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 #:nodoc:
11
+ # Decorates a response providing support for deserialisation.
12
+ #
13
+ # The following methods are also available (unlisted by rdoc because they're forwarded):
14
+ #
15
+ # <tt>:@http_response, :code, :message, :body, :http_version,
16
+ # :[], :content_length, :content_type, :each_header, :each_name, :each_value, :fetch,
17
+ # :get_fields, :key?, :type_params</tt>
18
+ #
19
+ # They behave exactly like their Net::HTTPResponse equivalents.
20
+ class Response
21
+ extend Forwardable
22
+ def_delegators :@http_response, :code, :message, :body, :http_version,
23
+ :[], :content_length, :content_type, :each_header, :each_name, :each_value, :fetch,
24
+ :get_fields, :key?, :type_params
25
+
26
+ def initialize(http_response)
27
+ @http_response = http_response
28
+ end
29
+
30
+ def deserialise
31
+ deserialise_using(Wrest::Translators.load(@http_response.content_type))
32
+ end
33
+
34
+ def deserialise_using(translator)
35
+ translator.call(@http_response)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,25 @@
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
+ # 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.load(content_type)
17
+ translator = CONTENT_TYPES[content_type]
18
+ translator || (raise UnsupportedContentTypeException.new("Unsupported content type #{content_type}"))
19
+ end
20
+ end
21
+ end
22
+
23
+ require "#{WREST_ROOT}/wrest/translators/xml"
24
+ require "#{WREST_ROOT}/wrest/translators/json"
25
+ require "#{WREST_ROOT}/wrest/translators/content_types"