Class: Restfully::Resource

Inherits:
Object
  • Object
show all
Includes:
HTTP::Helper
Defined in:
lib/restfully/resource.rb

Overview

This class represents a Resource, which can be accessed and manipulated via HTTP methods.

Some resources can be collection of other resources. In that case the Restfully::Collection module is included in the Restfully::Resource class. See the corresponding documentation for the list of additional methods that you can use on a collection resource.

Constant Summary collapse

HIDDEN_PROPERTIES_REGEXP =
/^\_\_(.+)\_\_$/

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from HTTP::Helper

#sanitize_head, #sanitize_query

Constructor Details

#initialize(session, response, request) ⇒ Resource

Returns a new instance of Resource.



15
16
17
18
19
20
# File 'lib/restfully/resource.rb', line 15

def initialize(session, response, request)
  @session = session
  @response = response
  @request = request
  @associations = {}
end

Instance Attribute Details

#requestObject (readonly)

Returns the value of attribute request.



9
10
11
# File 'lib/restfully/resource.rb', line 9

def request
  @request
end

#responseObject (readonly)

Returns the value of attribute response.



9
10
11
# File 'lib/restfully/resource.rb', line 9

def response
  @response
end

#sessionObject (readonly)

Returns the value of attribute session.



9
10
11
# File 'lib/restfully/resource.rb', line 9

def session
  @session
end

Instance Method Details

#[](key) ⇒ Object

Returns the value corresponding to the specified key, among the list of resource properties.

e.g.:

resource["uid"]
=> "rennes"


28
29
30
31
32
33
# File 'lib/restfully/resource.rb', line 28

def [](key)
  if !media_type.property(key) && !collection?
    expand
  end
  media_type.property(key)
end

#allow?(method) ⇒ Boolean

Returns true if the resource supports the given HTTP method (String or Symbol).

Returns:

  • (Boolean)


156
157
158
# File 'lib/restfully/resource.rb', line 156

def allow?(method)
  response.allow?(method) || reload.response.allow?(method)
end

#buildObject

Build the resource after loading.



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/restfully/resource.rb', line 207

def build
  extend Collection if collection?
  metaclass = class << self; self; end
  response.links.each do |link|
    metaclass.send(:define_method, link.id.to_sym) do |*args|
      options = args.extract_options!
      head = options.delete(:headers) || options.delete(:head) || {}
      head = sanitize_head(head)
      head['Accept'] ||= (
        link.type || media_type.class.signature.join(",")
      )
      session.get(link.href, options.merge(:head => head))
    end
  end
  self
end

#collection?Boolean

Is this resource a collection of items?

Returns:

  • (Boolean)


51
52
53
# File 'lib/restfully/resource.rb', line 51

def collection?
  media_type.collection?
end

#complete?Boolean

Does this resource contain only a fragment of the full resource?

Returns:

  • (Boolean)


46
47
48
# File 'lib/restfully/resource.rb', line 46

def complete?
  media_type.complete?
end

#delete(options = {}) ⇒ Object

Send a DELETE HTTP request on the resource URI. See #load for the list of arguments this method can take.



134
135
136
137
138
139
140
141
# File 'lib/restfully/resource.rb', line 134

def delete(options = {})
  if allow?("DELETE")
    @request.no_cache!
    session.delete(request.uri)
  else
    raise MethodNotAllowed
  end
end

#expandObject

Reload itself if the resource is not #complete?.



225
226
227
228
# File 'lib/restfully/resource.rb', line 225

def expand
  reload unless complete?
  self
end

#inspectObject



160
161
162
163
164
165
166
# File 'lib/restfully/resource.rb', line 160

def inspect
  if media_type.complete?
    properties.inspect
  else
    "{...}"
  end
end

#kindObject

Returns the resource kind: “Collection” or “Resource”.



56
57
58
# File 'lib/restfully/resource.rb', line 56

def kind
  collection? ? "Collection" : "Resource"
end

#load(options = {}) ⇒ Object

Load the resource. The options Hash can contain any number of parameters among which:

:head

a Hash of HTTP headers to pass when fetching the resource.

:query

a Hash of query parameters to add to the URI when fetching the resource.



75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/restfully/resource.rb', line 75

def load(options = {})
  # Send a GET request only if given a different set of options
  if @request.update!(options) || @request.no_cache?
    @response = @request.execute!
    @request.remove_no_cache! if @request.forced_cache?
    if session.process(@response, @request)
      @associations.clear
    else
      raise Error, "Cannot reload the resource"
    end
  end

  build
end

#media_typeObject

Returns the Restfully::MediaType object that was used to parse the response.



41
42
43
# File 'lib/restfully/resource.rb', line 41

def media_type
  response.media_type
end

#pretty_print(pp) ⇒ Object



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/restfully/resource.rb', line 168

def pretty_print(pp)
  pp.text signature(false)
  pp.nest 2 do
    if relationships.length > 0
      pp.breakable
      pp.text "RELATIONSHIPS"
      pp.nest 2 do
        pp.breakable
        pp.text "#{relationships.join(", ")}"
      end
    end
    pp.breakable
    if collection?
      # display items
      pp.text "ITEMS (#{offset}..#{offset+length})/#{total}"
      pp.nest 2 do
        self.each do |item|
          pp.breakable
          pp.text item.signature(true)
        end
      end
    else
      expand
      pp.text "PROPERTIES"
      pp.nest 2 do
        properties.each do |key, value|
          pp.breakable
          pp.text "#{key.inspect}=>"
          value.pretty_print(pp)
        end
      end
    end
    yield pp if block_given?
  end
  pp.text ">"
  nil
end

#propertiesObject

Returns the properties for this resource.



96
97
98
99
100
101
102
103
104
105
106
# File 'lib/restfully/resource.rb', line 96

def properties
  case props = media_type.property
  when Hash
    props.reject{|k,v|
      # do not return keys used for internal use
      k.to_s =~ HIDDEN_PROPERTIES_REGEXP
    }
  else
    props
  end
end

#relationshipsObject

Returns the list of relationships for this resource, extracted from the resource links (“rel” attribute).



91
92
93
# File 'lib/restfully/resource.rb', line 91

def relationships
  response.links.map(&:id).sort
end

#reloadObject

Force reloading of the resource.



114
115
116
117
# File 'lib/restfully/resource.rb', line 114

def reload
  @request.no_cache!
  load
end

#signature(closed = true) ⇒ Object

Returns the “signature” of the resource. Used for (pretty-)inspection.



61
62
63
64
65
66
67
68
69
70
# File 'lib/restfully/resource.rb', line 61

def signature(closed=true)
  s = "#<#{kind}:0x#{object_id.to_s(16)}"
  s += media_type.banner unless media_type.banner.nil?
  # Only display path if host and port are the same than session's URI:
  s += " uri=#{[uri.host, uri.port] == [
    session.uri.host, session.uri.port
  ] ? uri.request_uri.inspect : uri.to_s.inspect}"
  s += ">" if closed
  s
end

#submit(*args) ⇒ Object

POST some payload on that resource URI. Either you pass a serialized payload as first argument, followed by an optional Hash of :head and :query parameters. Or you pass your payload as a Hash, and the serialization will occur based on the Content-Type you set (and only if a corresponding MediaType can be found in the MediaType catalog).



122
123
124
125
126
127
128
129
130
# File 'lib/restfully/resource.rb', line 122

def submit(*args)
  if allow?("POST")
    @request.no_cache!
    payload, options = extract_payload_from_args(args)
    session.post(request.uri, payload, options)
  else
    raise MethodNotAllowed
  end
end

#to_hashObject

Alias for #properties



109
110
111
# File 'lib/restfully/resource.rb', line 109

def to_hash
  properties
end

#update(*args) ⇒ Object

Send a PUT HTTP request with some payload on the resource URI. See #submit for the list of arguments this method can take.



145
146
147
148
149
150
151
152
153
# File 'lib/restfully/resource.rb', line 145

def update(*args)
  if allow?("PUT")
    @request.no_cache!
    payload, options = extract_payload_from_args(args)
    session.put(request.uri, payload, options)
  else
    raise MethodNotAllowed
  end
end

#uriObject

Returns the resource URI.



36
37
38
# File 'lib/restfully/resource.rb', line 36

def uri
  request.uri
end