restfulie 0.5.0 → 0.6.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.
- data/Rakefile +2 -2
- data/lib/restfulie/client/atom_media_type.rb +19 -2
- data/lib/restfulie/client/base.rb +36 -31
- data/lib/restfulie/client/cache.rb +103 -0
- data/lib/restfulie/client/entry_point.rb +19 -2
- data/lib/restfulie/client/extensions/http.rb +116 -0
- data/lib/restfulie/client/helper.rb +17 -0
- data/lib/restfulie/client/instance.rb +138 -114
- data/lib/restfulie/client/request_execution.rb +255 -65
- data/lib/restfulie/client/state.rb +18 -1
- data/lib/restfulie/client.rb +29 -4
- data/lib/restfulie/logger.rb +13 -0
- data/lib/restfulie/media_type.rb +25 -6
- data/lib/restfulie/media_type_control.rb +40 -1
- data/lib/restfulie/media_type_defaults.rb +19 -2
- data/lib/restfulie/server/atom_media_type.rb +18 -5
- data/lib/restfulie/server/base.rb +18 -1
- data/lib/restfulie/server/controller.rb +73 -20
- data/lib/restfulie/server/instance.rb +96 -44
- data/lib/restfulie/server/marshalling.rb +16 -0
- data/lib/restfulie/server/opensearch/description.rb +54 -0
- data/lib/restfulie/server/opensearch.rb +18 -0
- data/lib/restfulie/server/restfulie_controller.rb +44 -1
- data/lib/restfulie/server/transition.rb +32 -1
- data/lib/restfulie/unmarshalling.rb +84 -42
- data/lib/restfulie.rb +27 -2
- data/lib/vendor/jeokkarak/hashi.rb +23 -19
- data/lib/vendor/jeokkarak/jeokkarak.rb +16 -0
- metadata +18 -4
data/Rakefile
CHANGED
@@ -5,7 +5,7 @@ require 'rake/gempackagetask'
|
|
5
5
|
require 'spec/rake/spectask'
|
6
6
|
|
7
7
|
GEM = "restfulie"
|
8
|
-
GEM_VERSION = "0.
|
8
|
+
GEM_VERSION = "0.6.0"
|
9
9
|
SUMMARY = "Hypermedia aware resource based library in ruby (client side) and ruby on rails (server side)."
|
10
10
|
AUTHOR = "Guilherme Silveira, Caue Guerra"
|
11
11
|
EMAIL = "guilherme.silveira@caelum.com.br"
|
@@ -18,7 +18,7 @@ spec = Gem::Specification.new do |s|
|
|
18
18
|
s.summary = SUMMARY
|
19
19
|
s.require_paths = ['lib']
|
20
20
|
s.files = FileList['lib/**/*.rb', '[A-Z]*'].to_a
|
21
|
-
|
21
|
+
s.add_dependency("ratom", [">= 0.6.3"])
|
22
22
|
# s.add_dependency("jeokkarak", [">= 1.0.3"])
|
23
23
|
|
24
24
|
# s.add_dependency(%q<rubigen>, [">= 1.3.4"])
|
@@ -1,3 +1,20 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2009 Caelum - www.caelum.com.br/opensource
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
1
18
|
module Restfulie
|
2
19
|
|
3
20
|
# TODO break media type registering for DECODING and ENCODING appart, so we can have two files
|
@@ -23,7 +40,7 @@ module Restfulie
|
|
23
40
|
# retrieves the nth element from an atom feed
|
24
41
|
def [](position)
|
25
42
|
|
26
|
-
hash = entry[position].content.
|
43
|
+
hash = entry[position].content.internal_hash
|
27
44
|
hash = hash.dup
|
28
45
|
hash.delete("type")
|
29
46
|
result = Restfulie::MediaType::DefaultMediaTypeDecoder.from_hash(hash)
|
@@ -36,7 +53,7 @@ module Restfulie
|
|
36
53
|
private
|
37
54
|
|
38
55
|
def add_links_to(result, entry)
|
39
|
-
links = entry.link.
|
56
|
+
links = entry.link.internal_hash
|
40
57
|
links = [links] if links.kind_of? Hash
|
41
58
|
self_definition = self_from(links)
|
42
59
|
links << {:rel => "destroy", :method => "delete", :href => self_definition["href"]} unless self_definition.nil?
|
@@ -1,3 +1,20 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2009 Caelum - www.caelum.com.br/opensource
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
1
18
|
class Hash
|
2
19
|
def to_object(body)
|
3
20
|
if keys.length>1
|
@@ -15,46 +32,34 @@ module Restfulie
|
|
15
32
|
|
16
33
|
# will execute some action in a specific URI
|
17
34
|
def self.at(uri)
|
18
|
-
Client::RequestExecution.new(nil).at uri
|
35
|
+
Client::RequestExecution.new(nil, nil).at uri
|
19
36
|
end
|
20
|
-
|
37
|
+
|
21
38
|
module Client
|
22
|
-
module
|
39
|
+
module Config
|
40
|
+
BASIC_MAPPING = { :delete => Net::HTTP::Delete, :put => Net::HTTP::Put, :get => Net::HTTP::Get, :post => Net::HTTP::Post}
|
41
|
+
DEFAULTS = { :destroy => Net::HTTP::Delete, :delete => Net::HTTP::Delete, :cancel => Net::HTTP::Delete,
|
42
|
+
:refresh => Net::HTTP::Get, :reload => Net::HTTP::Get, :show => Net::HTTP::Get, :latest => Net::HTTP::Get, :self => Net::HTTP::Get}
|
23
43
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
return
|
30
|
-
|
31
|
-
raise UnsupportedContentType.new("unsupported content type '#{res.content_type}' '#{res.code}'") unless res.content_type=="application/xml"
|
32
|
-
|
33
|
-
# TODO this method should use the RequestExecution process to parse the content type and body
|
34
|
-
# TODO add default html parser: do nothin
|
35
|
-
|
36
|
-
body = res.body
|
37
|
-
return {} if body.empty?
|
38
|
-
|
39
|
-
hash = Hash.from_xml body
|
40
|
-
hash.to_object(body)
|
41
|
-
|
44
|
+
def self.self_retrieval
|
45
|
+
[:latest, :refresh, :reload, :self]
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.requisition_method_for(overriden_option,name)
|
49
|
+
return BASIC_MAPPING[overriden_option.to_sym] if overriden_option
|
50
|
+
DEFAULTS[name.to_sym] || Net::HTTP::Post
|
42
51
|
end
|
43
52
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
:refresh => Net::HTTP::Get, :reload => Net::HTTP::Get, :show => Net::HTTP::Get, :latest => Net::HTTP::Get, :self => Net::HTTP::Get}
|
53
|
+
end
|
54
|
+
|
55
|
+
module Base
|
48
56
|
|
49
|
-
return basic_mapping[overriden_option.to_sym] if overriden_option
|
50
|
-
defaults[name.to_sym] || Net::HTTP::Post
|
51
|
-
end
|
52
|
-
|
53
57
|
def is_self_retrieval?(name)
|
54
58
|
name = name.to_sym if name.kind_of? String
|
55
|
-
|
59
|
+
Restfulie::Client::Config.self_retrieval.include? name
|
56
60
|
end
|
57
|
-
|
61
|
+
|
58
62
|
end
|
63
|
+
|
59
64
|
end
|
60
65
|
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2009 Caelum - www.caelum.com.br/opensource
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
# Basic cache implementation for restfulie.
|
19
|
+
#
|
20
|
+
# It uses the request headers and uri to store it in memory.
|
21
|
+
# This cache might not be optimal for long running clients, which should use a memcached based one.
|
22
|
+
# Use Restfulie.cache_provider to change the provider
|
23
|
+
class Restfulie::BasicCache
|
24
|
+
|
25
|
+
def put(url, req, response)
|
26
|
+
if Restfulie::Cache::Restrictions.may_cache?(req, response)
|
27
|
+
Restfulie.logger.debug "caching #{url} #{req} #{response}"
|
28
|
+
cache[key_for(url, req)] = response
|
29
|
+
end
|
30
|
+
response
|
31
|
+
end
|
32
|
+
|
33
|
+
def get(url, req)
|
34
|
+
|
35
|
+
response = cache[key_for(url, req)]
|
36
|
+
return nil if response.nil?
|
37
|
+
|
38
|
+
if response.has_expired_cache?
|
39
|
+
remove(key_for(url, req))
|
40
|
+
else
|
41
|
+
Restfulie.logger.debug "RETURNING cache #{url} #{req}"
|
42
|
+
response
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
# removes all elements from the cache
|
48
|
+
def clear
|
49
|
+
cache.clear
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def remove(what)
|
55
|
+
@cache.delete(what)
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
|
59
|
+
def cache
|
60
|
+
@cache ||= {}
|
61
|
+
end
|
62
|
+
|
63
|
+
def key_for(url, req)
|
64
|
+
[url, req.class]
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
# Fake cache that does not cache anything
|
70
|
+
# Use Restfulie.cache_provider = Restfulie::FakeCache.new
|
71
|
+
class Restfulie::FakeCache
|
72
|
+
|
73
|
+
def put(url, req, response)
|
74
|
+
response
|
75
|
+
end
|
76
|
+
|
77
|
+
def get(url, req)
|
78
|
+
end
|
79
|
+
|
80
|
+
def clear
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
module Restfulie::Cache
|
86
|
+
module Restrictions
|
87
|
+
|
88
|
+
class << self
|
89
|
+
|
90
|
+
# checks whether this request verb and its cache headers allow caching
|
91
|
+
def may_cache?(request,response)
|
92
|
+
may_cache_method?(request) && response.may_cache?
|
93
|
+
end
|
94
|
+
|
95
|
+
# only Post and Get requests are cacheable so far
|
96
|
+
def may_cache_method?(verb)
|
97
|
+
verb.kind_of?(Net::HTTP::Post) || verb.kind_of?(Net::HTTP::Get)
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
@@ -1,3 +1,20 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2009 Caelum - www.caelum.com.br/opensource
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
1
18
|
module Restfulie
|
2
19
|
module Client
|
3
20
|
module Base
|
@@ -22,12 +39,12 @@ module Restfulie
|
|
22
39
|
|
23
40
|
# retrieves a resource form a specific uri
|
24
41
|
def from_web(uri, options = {})
|
25
|
-
RequestExecution.new(self).at(uri).get(options)
|
42
|
+
RequestExecution.new(self, nil).at(uri).get(options)
|
26
43
|
end
|
27
44
|
|
28
45
|
private
|
29
46
|
def remote_post(content)
|
30
|
-
RequestExecution.new(self).at(entry_point_for.create.uri).post(content)
|
47
|
+
RequestExecution.new(self, nil).at(entry_point_for.create.uri).post(content)
|
31
48
|
end
|
32
49
|
|
33
50
|
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2009 Caelum - www.caelum.com.br/opensource
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
require 'time'
|
19
|
+
|
20
|
+
# an extesion to http responses
|
21
|
+
module Restfulie::Client::HTTPResponse
|
22
|
+
|
23
|
+
attr_accessor :previous
|
24
|
+
|
25
|
+
# determines if this response code was successful (according to http specs: 200~299)
|
26
|
+
def is_successful?
|
27
|
+
code.to_i >= 200 && code.to_i <= 299
|
28
|
+
end
|
29
|
+
|
30
|
+
# determines if this response code was successful (according to http specs: 100~199)
|
31
|
+
def is_informational?
|
32
|
+
code.to_i >= 100 && code.to_i <= 199
|
33
|
+
end
|
34
|
+
|
35
|
+
# determines if this response code was successful (according to http specs: 300~399)
|
36
|
+
def is_redirection?
|
37
|
+
code.to_i >= 300 && code.to_i <= 399
|
38
|
+
end
|
39
|
+
|
40
|
+
# determines if this response code was successful (according to http specs: 400~499)
|
41
|
+
def is_client_error?
|
42
|
+
code.to_i >= 400 && code.to_i <= 499
|
43
|
+
end
|
44
|
+
|
45
|
+
# determines if this response code was successful (according to http specs: 500~599)
|
46
|
+
def is_server_error?
|
47
|
+
code.to_i >= 500 && code.to_i <= 599
|
48
|
+
end
|
49
|
+
|
50
|
+
def etag
|
51
|
+
self['Etag']
|
52
|
+
end
|
53
|
+
|
54
|
+
def last_modified
|
55
|
+
self['Last-Modified']
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
module Restfulie::Client::HTTPResponse
|
61
|
+
|
62
|
+
def cache_max_age
|
63
|
+
val = header_value_from('Cache-control', /^\s*max-age=(\d+)/)
|
64
|
+
if val
|
65
|
+
val.to_i
|
66
|
+
else
|
67
|
+
0
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def header_value_from(header, expression)
|
72
|
+
h = value_for(get_fields(header)[0], expression)
|
73
|
+
return nil if h.nil?
|
74
|
+
h.match(expression)[1]
|
75
|
+
end
|
76
|
+
|
77
|
+
def has_expired_cache?
|
78
|
+
return true if self['Date'].nil?
|
79
|
+
Time.now > Time.rfc2822(self['Date']) + cache_max_age.seconds
|
80
|
+
end
|
81
|
+
|
82
|
+
# checks if the header's max-age is available and no no-store if available.
|
83
|
+
def may_cache?
|
84
|
+
may_cache_field?(get_fields('Cache-control'))
|
85
|
+
end
|
86
|
+
|
87
|
+
def may_cache_field?(field)
|
88
|
+
return false if field.nil?
|
89
|
+
|
90
|
+
if field.kind_of? Array
|
91
|
+
field.each do |f|
|
92
|
+
return false if !may_cache_field?(f)
|
93
|
+
end
|
94
|
+
return true
|
95
|
+
end
|
96
|
+
|
97
|
+
max_age_header = value_for(field, /^max-age=(\d+)/)
|
98
|
+
return false if max_age_header.nil?
|
99
|
+
max_age = max_age_header[1]
|
100
|
+
|
101
|
+
return false if value_for(field, /^no-store/)
|
102
|
+
|
103
|
+
true
|
104
|
+
end
|
105
|
+
|
106
|
+
# extracts the header value for an specific expression, which can be located at the start or in the middle
|
107
|
+
# of the expression
|
108
|
+
def value_for(value, expression)
|
109
|
+
value.split(",").find { |obj| obj.strip =~ expression }
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
class Net::HTTPResponse
|
115
|
+
include Restfulie::Client::HTTPResponse
|
116
|
+
end
|
@@ -1,3 +1,20 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2009 Caelum - www.caelum.com.br/opensource
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
1
18
|
module Restfulie
|
2
19
|
module Client
|
3
20
|
module Helper
|
@@ -1,134 +1,158 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
#
|
2
|
+
# Copyright (c) 2009 Caelum - www.caelum.com.br/opensource
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
module Restfulie::Client::Instance
|
4
19
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
# which content-type generated this data
|
11
|
-
attr_accessor :_came_from
|
12
|
-
|
13
|
-
def invoke_remote_transition(name, options, block)
|
14
|
-
|
15
|
-
method = self.class.requisition_method_for options[:method], name
|
16
|
-
|
17
|
-
state = self._possible_states[name]
|
18
|
-
url = URI.parse(state["href"] || state[:href])
|
19
|
-
req = method.new(url.path)
|
20
|
-
req.body = options[:data] if options[:data]
|
21
|
-
add_request_headers(req, name)
|
22
|
-
|
23
|
-
response = Net::HTTP.new(url.host, url.port).request(req)
|
20
|
+
# list of possible states to access
|
21
|
+
def existing_relations
|
22
|
+
@existing_relations ||= {}
|
23
|
+
end
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
25
|
+
# which content-type generated this data
|
26
|
+
attr_reader :_came_from
|
27
|
+
|
28
|
+
# prepares a new request
|
29
|
+
def request
|
30
|
+
Restfulie::Client::RequestExecution.new(self.class, self)
|
31
|
+
end
|
32
|
+
|
33
|
+
# parse arguments from a transition invocation (or relation)
|
34
|
+
# it will receive either zero, one or two args, if there are two args, return them
|
35
|
+
# if there is one hash arg, its the options, add a data = nil
|
36
|
+
# if there is one arg (not a hash), its the data, add a options = {}
|
37
|
+
# if there are no args, data is nil and options = {}
|
38
|
+
def parse_args_from_transition(args)
|
39
|
+
data = nil
|
40
|
+
if args.nil? || args.size==0
|
41
|
+
options = {}
|
42
|
+
elsif args.size==1
|
43
|
+
if args[0].kind_of?(Hash)
|
44
|
+
options = args[0]
|
45
|
+
else
|
46
|
+
data = args[0]
|
47
|
+
options = {}
|
35
48
|
end
|
49
|
+
elsif args.size==2
|
50
|
+
data = args[0]
|
51
|
+
options = args[1] || {}
|
52
|
+
end
|
53
|
+
[data, options]
|
54
|
+
end
|
55
|
+
|
56
|
+
def invoke_remote_transition(name, args, block = nil)
|
57
|
+
|
58
|
+
data, options = parse_args_from_transition(args)
|
59
|
+
|
60
|
+
method = Restfulie::Client::Config.requisition_method_for options[:method], name
|
61
|
+
state = self.existing_relations[name]
|
62
|
+
|
63
|
+
request = Restfulie::Client::RequestExecution.new(self.class, self).at(state["href"] || state[:href]).with(options[:headers])
|
64
|
+
request.do method, name, data
|
36
65
|
|
37
|
-
|
66
|
+
end
|
38
67
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
self.extend Restfulie::Client::State
|
48
|
-
end
|
68
|
+
# inserts all links from this object as can_xxx and xxx methods
|
69
|
+
def add_transitions(links)
|
70
|
+
links.each do |t|
|
71
|
+
self.existing_relations[t["rel"] || t[:rel]] = t
|
72
|
+
self.add_state(t)
|
73
|
+
end
|
74
|
+
self.extend Restfulie::Client::State
|
75
|
+
end
|
49
76
|
|
77
|
+
# adds the specific information for one state change or related resource
|
78
|
+
def add_state(transition)
|
79
|
+
name = transition["rel"] || transition[:rel]
|
80
|
+
|
81
|
+
# TODO: wrong, should be instance_eval
|
82
|
+
self.class.module_eval do
|
50
83
|
|
51
|
-
def
|
52
|
-
|
53
|
-
|
54
|
-
# TODO: wrong, should be instance_eval
|
55
|
-
self.class.module_eval do
|
56
|
-
|
57
|
-
def temp_method(options = {}, &block)
|
58
|
-
self.invoke_remote_transition(Restfulie::Client::Helper.current_method, options, block)
|
59
|
-
end
|
60
|
-
|
61
|
-
alias_method name, :temp_method
|
62
|
-
undef :temp_method
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
# returns a list of extended fields for this instance.
|
67
|
-
# extended fields are those unknown to this model but kept in a hash
|
68
|
-
# to allow forward-compatibility.
|
69
|
-
def extended_fields
|
70
|
-
@hash ||= {}
|
71
|
-
@hash
|
84
|
+
def temp_method(*args, &block)
|
85
|
+
self.invoke_remote_transition(Restfulie::Client::Helper.current_method, args, block)
|
72
86
|
end
|
87
|
+
|
88
|
+
alias_method name, :temp_method
|
89
|
+
undef :temp_method
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# returns a list of extended fields for this instance.
|
94
|
+
# extended fields are those unknown to this model but kept in a hash
|
95
|
+
# to allow forward-compatibility.
|
96
|
+
def extended_fields
|
97
|
+
@extended_fields ||= {}
|
98
|
+
@extended_fields
|
99
|
+
end
|
73
100
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
101
|
+
def method_missing(name, *args)
|
102
|
+
name = name.to_s if name.kind_of? Symbol
|
103
|
+
|
104
|
+
if name[-1,1] == "="
|
105
|
+
extended_fields[name.chop] = args[0]
|
106
|
+
elsif name[-1,1] == "?"
|
107
|
+
found = extended_fields[name.chop]
|
108
|
+
return super(name,args) if found.nil?
|
109
|
+
parse(found)
|
110
|
+
else
|
111
|
+
found = extended_fields[name]
|
112
|
+
return super(name,args) if found.nil?
|
113
|
+
parse(transform(found))
|
114
|
+
end
|
88
115
|
|
89
|
-
|
116
|
+
end
|
90
117
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
end
|
118
|
+
def respond_to?(sym)
|
119
|
+
extended_fields[sym.to_s].nil? ? super(sym) : true
|
120
|
+
end
|
95
121
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
end
|
104
|
-
end
|
105
|
-
super(values)
|
122
|
+
# redefines attribute definition allowing the invocation of method_missing
|
123
|
+
# when an attribute does not exist
|
124
|
+
def attributes=(values)
|
125
|
+
values.each do |key, value|
|
126
|
+
unless attributes.include? key
|
127
|
+
method_missing("#{key}=", value)
|
128
|
+
values.delete key
|
106
129
|
end
|
130
|
+
end
|
131
|
+
super(values)
|
132
|
+
end
|
107
133
|
|
108
134
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
end
|
115
|
-
end
|
135
|
+
# serializes the extended fields with the existing fields
|
136
|
+
def to_xml(options={})
|
137
|
+
super(options) do |xml|
|
138
|
+
extended_fields.each do |key,value|
|
139
|
+
xml.tag! key, value
|
116
140
|
end
|
141
|
+
end
|
142
|
+
end
|
117
143
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
144
|
+
private
|
145
|
+
|
146
|
+
# transforms a value in a custom hash
|
147
|
+
def transform(value)
|
148
|
+
return CustomHash.new(value) if value.kind_of?(Hash) || value.kind_of?(Array)
|
149
|
+
value
|
150
|
+
end
|
151
|
+
|
152
|
+
def parse(val)
|
153
|
+
raise "undefined method: '#{val}'" if val.nil?
|
154
|
+
val
|
155
|
+
end
|
130
156
|
|
131
157
|
|
132
|
-
end
|
133
|
-
end
|
134
158
|
end
|