File: relation.rb

package info (click to toggle)
ruby-sawyer 0.9.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 280 kB
  • sloc: ruby: 1,224; sh: 17; makefile: 4
file content (272 lines) | stat: -rw-r--r-- 8,597 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
module Sawyer
  class Relation
    class Map
      # Tracks the available next actions for a resource, and
      # issues requests for them.
      def initialize
        @map = {}
      end

      # Adds a Relation to the map.
      #
      # rel - A Relation.
      #
      # Returns nothing.
      def <<(rel)
        @map[rel.name] = rel if rel
      end

      # Gets the raw Relation by its name.
      #
      # key - The Symbol name of the Relation.
      #
      # Returns a Relation.
      def [](key)
        @map[key.to_sym]
      end

      # Gets the number of mapped Relations.
      #
      # Returns an Integer.
      def size
        @map.size
      end

      # Gets a list of the Relation names.
      #
      # Returns an Array of Symbols in no specific order.
      def keys
        @map.keys
      end

      def to_hash
        pairs = @map.map do |k, v|
          [(k.to_s + "_url").to_sym, v.href]
        end
        Hash[pairs]
      end
      alias :to_h :to_hash

      def inspect
        hash = to_hash
        hash.respond_to?(:pretty_inspect) ? hash.pretty_inspect : hash.inspect
      end
    end

    attr_reader :agent,
      :name,
      :href_template,
      :method,
      :available_methods

    # Public: Builds an index of Relations from the value of a `_links`
    # property in a resource.  :get is the default method.  Any links with
    # multiple specified methods will get multiple relations created.
    #
    # index - The Hash mapping Relation names to the Hash Relation
    #         options.
    # rels  - A Relation::Map to store the Relations.
    #
    # Returns a Relation::Map
    def self.from_links(agent, index, rels = Map.new)
      if index.is_a?(Array)
        raise ArgumentError, "Links must be a hash of rel => {_href => '...'}: #{index.inspect}"
      end

      index.each do |name, options|
        rels << from_link(agent, name, options)
      end if index

      rels
    end

    # Public: Builds a single Relation from the given options.  These are
    # usually taken from a `_links` property in a resource.
    #
    # agent   - The Sawyer::Agent that made the request.
    # name    - The Symbol name of the Relation.
    # options - A Hash containing the other Relation properties.
    #           :href   - The String URL of the next action's location.
    #           :method - The optional String HTTP method.
    #
    # Returns a Relation.
    def self.from_link(agent, name, options)
      case options
      when Hash
        new agent, name, options[:href], options[:method]
      when String
        new agent, name, options
      end
    end

    # A Relation represents an available next action for a resource.
    #
    # agent  - The Sawyer::Agent that made the request.
    # name   - The Symbol name of the relation.
    # href   - The String URL of the location of the next action.
    # method - The Symbol HTTP method.  Default: :get
    def initialize(agent, name, href, method = nil)
      @agent = agent
      @name = name.to_sym
      @href = href
      @href_template = Addressable::Template.new(href.to_s)

      methods = nil

      if method.is_a? String
        if method.size.zero?
          method = nil
        else
          method.downcase!
          methods = method.split(',').map! do |m|
            m.strip!
            m.to_sym
          end
          method = methods.first
        end
      end

      @method = (method || :get).to_sym
      @available_methods = Set.new methods || [@method]
    end

    # Public: Makes an API request with the curent Relation using HEAD.
    #
    # data    - The Optional Hash or Resource body to be sent.  :get or :head
    #           requests can have no body, so this can be the options Hash
    #           instead.
    # options - Hash of option to configure the API request.
    #           :headers - Hash of API headers to set.
    #           :query   - Hash of URL query params to set.
    #           :method  - Symbol HTTP method.
    #
    # Returns a Sawyer::Response.
    def head(options = nil)
      options ||= {}
      options[:method] = :head
      call options
    end

    # Public: Makes an API request with the curent Relation using GET.
    #
    # data    - The Optional Hash or Resource body to be sent.  :get or :head
    #           requests can have no body, so this can be the options Hash
    #           instead.
    # options - Hash of option to configure the API request.
    #           :headers - Hash of API headers to set.
    #           :query   - Hash of URL query params to set.
    #           :method  - Symbol HTTP method.
    #
    # Returns a Sawyer::Response.
    def get(options = nil)
      options ||= {}
      options[:method] = :get
      call options
    end

    # Public: Makes an API request with the curent Relation using POST.
    #
    # data    - The Optional Hash or Resource body to be sent.
    # options - Hash of option to configure the API request.
    #           :headers - Hash of API headers to set.
    #           :query   - Hash of URL query params to set.
    #           :method  - Symbol HTTP method.
    #
    # Returns a Sawyer::Response.
    def post(data = nil, options = nil)
      options ||= {}
      options[:method] = :post
      call data, options
    end

    # Public: Makes an API request with the curent Relation using PUT.
    #
    # data    - The Optional Hash or Resource body to be sent.
    # options - Hash of option to configure the API request.
    #           :headers - Hash of API headers to set.
    #           :query   - Hash of URL query params to set.
    #           :method  - Symbol HTTP method.
    #
    # Returns a Sawyer::Response.
    def put(data = nil, options = nil)
      options ||= {}
      options[:method] = :put
      call data, options
    end

    # Public: Makes an API request with the curent Relation using PATCH.
    #
    # data    - The Optional Hash or Resource body to be sent.
    # options - Hash of option to configure the API request.
    #           :headers - Hash of API headers to set.
    #           :query   - Hash of URL query params to set.
    #           :method  - Symbol HTTP method.
    #
    # Returns a Sawyer::Response.
    def patch(data = nil, options = nil)
      options ||= {}
      options[:method] = :patch
      call data, options
    end

    # Public: Makes an API request with the curent Relation using DELETE.
    #
    # data    - The Optional Hash or Resource body to be sent.
    # options - Hash of option to configure the API request.
    #           :headers - Hash of API headers to set.
    #           :query   - Hash of URL query params to set.
    #           :method  - Symbol HTTP method.
    #
    # Returns a Sawyer::Response.
    def delete(data = nil, options = nil)
      options ||= {}
      options[:method] = :delete
      call data, options
    end

    # Public: Makes an API request with the curent Relation using OPTIONS.
    #
    # data    - The Optional Hash or Resource body to be sent.
    # options - Hash of option to configure the API request.
    #           :headers - Hash of API headers to set.
    #           :query   - Hash of URL query params to set.
    #           :method  - Symbol HTTP method.
    #
    # Returns a Sawyer::Response.
    def options(data = nil, opt = nil)
      opt ||= {}
      opt[:method] = :options
      call data, opt
    end

    def href(options = nil)
      return @href if @href_template.nil?
      @href_template.expand(options || {}).to_s
    end

    # Public: Makes an API request with the curent Relation.
    #
    # data    - The Optional Hash or Resource body to be sent.  :get or :head
    #           requests can have no body, so this can be the options Hash
    #           instead.
    # options - Hash of option to configure the API request.
    #           :headers - Hash of API headers to set.
    #           :query   - Hash of URL query params to set.
    #           :method  - Symbol HTTP method.
    #
    # Raises ArgumentError if the :method value is not in @available_methods.
    # Returns a Sawyer::Response.
    def call(data = nil, options = nil)
      m = options && options[:method]
      if m && !@agent.allow_undefined_methods? && !@available_methods.include?(m == :head ? :get : m)
        raise ArgumentError, "method #{m.inspect} is not available: #{@available_methods.to_a.inspect}"
      end

      @agent.call m || @method, @href_template, data, options
    end

    def inspect
      %(#<#{self.class}: #{@name}: #{@method} #{@href_template}>)
    end
  end
end