restfolia 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ tags
6
+ .rvmrc*
7
+ .yardoc*
8
+ doc/
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ rvm:
2
+ - 1.8.7
3
+ - 1.9.3
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --plugin yard-tomdoc -r Readme.md - MIT-LICENSE ReadmeDeveloper.md
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in librarian.gemspec
4
+ gemspec
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Roger Leite http://1up4dev.org
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs.push "lib"
6
+ t.libs.push "test"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ t.verbose = true
9
+ end
10
+
11
+ task :default => :test
data/Readme.md ADDED
@@ -0,0 +1,101 @@
1
+ # Restfolia [![Build Status][travis_status]][travis]
2
+
3
+ [travis_status]: https://secure.travis-ci.org/rogerleite/restfolia.png
4
+ [travis]: http://travis-ci.org/rogerleite/restfolia
5
+
6
+ REST client to consume and interact with Hypermedia API, using JSON as Media Type.
7
+
8
+ ## Description
9
+
10
+ Restfolia is a REST client and it's main goal is help you **consume and interact** with Hypermedia APIs.
11
+
12
+ Against the grain, Restfolia is very opinionated about some REST's concepts:
13
+
14
+ * Aims only **JSON Media Type**.
15
+ * All responses are parsed and returned as Restfolia::Resource.
16
+ * Less is more. Restfolia is very proud to be small, easy to maintain and evolve. You can compare Restfolia's code with "Similar Projects" at page's bottom.
17
+ * Restfolia::Resource is Ruby object with attributes from JSON and can optionally contains **hypermedia links** which have to be a specific format. See the examples below.
18
+ * All code is very well documented, using [TomDoc](http://tomdoc.org style).
19
+
20
+ Obs: This is a draft version. Not ready for production (yet!).
21
+
22
+ ## References
23
+
24
+ You can find more information about arquitecture REST below:
25
+
26
+ * [Roy Fielding's](http://roy.gbiv.com/untangled) see this post for example: [REST APIs must be hypertext-driven](http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven).
27
+ * [Rest in Practice](http://restinpractice.com), especially the chapter titled "Hypermedia Formats".
28
+ * [Mike Amundsen's Blog](http://amundsen.com/blog)
29
+ * ROAR - [Resource Oriented Arquitectures in Ruby](https://github.com/apotonick/roar) it seems really good to build a hypermedia API, of course you can go with Sinatra+rabl solutions too.
30
+
31
+ ## Examples of use
32
+
33
+ ```js
34
+ // GET http://localhost:9292/recursos/busca
35
+ { "itens_por_pagina" : 10,
36
+ "paginal_atual" : 1,
37
+ "paginas_totais" : 1,
38
+ "query" : "",
39
+ "total_resultado" : 100,
40
+ "resultado" : [ { "id" : 1,
41
+ "name" : "Test1",
42
+ "links" : [ { "href" : "http://localhost:9292/recursos/id/1",
43
+ "rel" : "recurso",
44
+ "type" : "application/json"
45
+ } ]
46
+ },
47
+ { "id" : 2,
48
+ "name" : "Test2",
49
+ "links" : [ { "href" : "http://localhost:9292/recursos/id/2",
50
+ "rel" : "recurso",
51
+ "type" : "application/json"
52
+ } ]
53
+ }
54
+ ],
55
+ "links" : { "href" : "http://localhost:9292/recursos/busca",
56
+ "rel" : "self",
57
+ "type" : "application/json"
58
+ },
59
+ }
60
+ ```
61
+
62
+ ```js
63
+ // GET http://localhost:9292/recursos/id/1
64
+ { "id" : 1,
65
+ "name" : "Test1",
66
+ "links" : { "href" : "http://localhost:9292/recursos/id/1",
67
+ "rel" : "self",
68
+ "type" : "application/json"
69
+ }
70
+ }
71
+ ```
72
+
73
+ ```ruby
74
+ # getting a resource
75
+ resource = Restfolia.at('http://localhost:9292/recursos/busca').get
76
+ resource.pagina_atual # => 1
77
+ resource.resultado # => [#<Resource ...>, #<Resource ...>]
78
+
79
+ # example of hypermedia navigation
80
+ r1 = resource.resultado.first
81
+ r1 = r1.links("recurso").get # => #<Resource ...>
82
+ r1.name # => "Test1"
83
+ ```
84
+
85
+ ## Similar Projects
86
+
87
+ * [ROAR](https://github.com/apotonick/roar)
88
+ * [Leadlight](https://github.com/avdi/leadlight)
89
+ * [Frenetic](https://github.com/dlindahl/frenetic)
90
+ * [Restfulie](https://github.com/caelum/restfulie)
91
+
92
+ ## What is "folia"?
93
+
94
+ Folia is a portuguese word and a simple translation in English can be:
95
+
96
+ > sf merry-making, merriment, revelry. que folia! what a fun!
97
+
98
+ ## License
99
+
100
+ Restfolia is copyright 2012 Roger Leite and contributors. It is licensed under the MIT license. See the include MIT-LICENSE file for details.
101
+
@@ -0,0 +1,30 @@
1
+ ## Steps to generate doc
2
+
3
+ ```
4
+ # dependencies
5
+ $ gem install yard
6
+ $ gem install yard-tomdoc
7
+ $ gem install redcarpet
8
+
9
+ # use params from .yardopts file
10
+ $ yard
11
+ $ open doc/index.html
12
+ ```
13
+ **Obs:** ignore errors :X, until my [pull request](https://github.com/rubyworks/yard-tomdoc/pull/5) be accepted.
14
+
15
+ ## TODO:
16
+
17
+ Improvements:
18
+
19
+ * Add "events" before and after request. This could be
20
+ cool to make projects that extends Restfolia features.
21
+
22
+ Resource & EntryPoint
23
+
24
+ * facilitate cache (Cache Control, ETag, Last-Modified).
25
+ This could be another project like restfolia-cazuza.
26
+
27
+ Future Ideas
28
+
29
+ * Support to JSON HAL
30
+ * Another project, to Restfolia be a "Restfulie like". Main mission: migrate old projects
@@ -0,0 +1,156 @@
1
+ module Restfolia
2
+
3
+
4
+ # Public: Responsible for request and validate a Resource.
5
+ # Abstract details of how to deal with HTTP, like headers,
6
+ # cookies, auth etc.
7
+ # The correct form to create an EntryPoint, is using Restfolia.at
8
+ # or links from some instance of Restfolia::Resource. See the
9
+ # examples for more details.
10
+ #
11
+ # Examples
12
+ #
13
+ # ep = Restfolia.at("http://fakeurl.com/some/service")
14
+ # # => #<EntryPoint ...>
15
+ #
16
+ # resource = Restfolia.at("http://fakeurl.com/service/id/1").get
17
+ # resource.links("contacts")
18
+ # # => #<EntryPoint ...> to "contacts" from this resource
19
+ class EntryPoint
20
+
21
+ include Restfolia::HTTP::Configuration
22
+
23
+ # Public: Returns the String url of EntryPoint.
24
+ attr_reader :url
25
+
26
+ # Public: Returns String that represents the relation of EntryPoint.
27
+ attr_reader :rel
28
+
29
+ # Public: Creates an EntryPoint.
30
+ #
31
+ # url - A String address of some API service.
32
+ # rel - An optional String that represents the relation of EntryPoint.
33
+ def initialize(url, rel = nil)
34
+ @url = url
35
+ @rel = rel
36
+ end
37
+
38
+ # Public: Get the Resource from this EntryPoint's url.
39
+ #
40
+ # params - an optional query String or Hash object. String parameter
41
+ # is passed direct as query. Hash object, before mounting query,
42
+ # URI.encode is used on values.
43
+ #
44
+ # Examples
45
+ #
46
+ # # GET on http://service.com/search
47
+ # resource = Restfolia.at("http://service.com/search").get
48
+ #
49
+ # # GET on http://service.com/search?q=test
50
+ # resource = Restfolia.at("http://service.com/search").get(:q => "test")
51
+ # # or if you want to control your query, you can send a String
52
+ # resource = Restfolia.at("http://service.com/search").get("q=test")
53
+ #
54
+ # Returns depends on http code from response. For each "range"
55
+ # (ex. 2xx, 3xx ... etc) you can have a different return value.
56
+ # For 2xx range, you can expect an instance of Restfolia::Resource.
57
+ # You can see Restfolia::HttpBehaviour for more details.
58
+ #
59
+ # Raises Restfolia::ResponseError for unexpected conditions. See
60
+ # Restfolia::HTTP::Behaviour methods for more details.
61
+ # Raises URI::InvalidURIError if url attribute is invalid.
62
+ def get(params = nil)
63
+ query = if params && params.is_a?(String)
64
+ params
65
+ elsif params && params.is_a?(Hash)
66
+ params.map { |k, v| "#{k}=#{URI.encode(v)}" }.join
67
+ end
68
+
69
+ args = self.configuration.merge(:query => query)
70
+ http_resp = Restfolia::HTTP::Request.do_request(:get, self.url, args)
71
+ Restfolia::HTTP.response_by_status_code(http_resp)
72
+ end
73
+
74
+ # Public: Post data to EntryPoint's url.
75
+ #
76
+ # params - Hash object with data to be encoded as JSON and send as
77
+ # request body.
78
+ #
79
+ # Examples
80
+ #
81
+ # # Expecting API respond with 201 and Location header
82
+ # data = {:name => "Test"}
83
+ # resource = Restfolia.at("http://service.com/resource/1").post(data)
84
+ #
85
+ # Returns depends on http code from response. For each "range"
86
+ # (ex. 2xx, 3xx ... etc) you can have a different return value.
87
+ # For 2xx range, you can expect an instance of Restfolia::Resource.
88
+ # You can see Restfolia::HttpBehaviour for more details.
89
+ #
90
+ # Raises Restfolia::ResponseError for unexpected conditions. See
91
+ # Restfolia::HTTP::Behaviour methods for more details.
92
+ # Raises URI::InvalidURIError if url attribute is invalid.
93
+ def post(params)
94
+ body = MultiJson.dump(params)
95
+
96
+ args = self.configuration.merge(:body => body)
97
+ http_resp = Restfolia::HTTP::Request.do_request(:post, self.url, args)
98
+ Restfolia::HTTP.response_by_status_code(http_resp)
99
+ end
100
+
101
+ # Public: Put data to EntryPoint's url.
102
+ #
103
+ # params - Hash object with data to be encoded as JSON and send as
104
+ # request body.
105
+ #
106
+ # Examples
107
+ #
108
+ # # Expecting API respond with 201 and Location header
109
+ # data = {:name => "Test"}
110
+ # resource = Restfolia.at("http://service.com/resource/1").put(data)
111
+ #
112
+ # Returns depends on http code from response. For each "range"
113
+ # (ex. 2xx, 3xx ... etc) you can have a different return value.
114
+ # For 2xx range, you can expect an instance of Restfolia::Resource.
115
+ # You can see Restfolia::HttpBehaviour for more details.
116
+ #
117
+ # Raises Restfolia::ResponseError for unexpected conditions. See
118
+ # Restfolia::HTTP::Behaviour methods for more details.
119
+ # Raises URI::InvalidURIError if url attribute is invalid.
120
+ def put(params)
121
+ body = MultiJson.dump(params)
122
+
123
+ args = self.configuration.merge(:body => body)
124
+ http_resp = Restfolia::HTTP::Request.do_request(:put, self.url, args)
125
+ Restfolia::HTTP.response_by_status_code(http_resp)
126
+ end
127
+
128
+ # Public: Send Delete verb to EntryPoint's url.
129
+ #
130
+ # Examples
131
+ #
132
+ # # Expecting API respond with 204 and empty body
133
+ # resource = Restfolia.at("http://service.com/resource/1").delete
134
+ #
135
+ # Returns depends on http code from response. For each "range"
136
+ # (ex. 2xx, 3xx ... etc) you can have a different return value.
137
+ # For 2xx range, you can expect an instance of Restfolia::Resource.
138
+ # You can see Restfolia::HttpBehaviour for more details.
139
+ #
140
+ # Raises Restfolia::ResponseError for unexpected conditions. See
141
+ # Restfolia::HTTP::Behaviour methods for more details.
142
+ # Raises URI::InvalidURIError if url attribute is invalid.
143
+ def delete
144
+ http_resp = Restfolia::HTTP::Request.do_request(:delete, self.url, self.configuration)
145
+ Restfolia::HTTP.response_by_status_code(http_resp)
146
+ end
147
+
148
+ # Returns url and rel for inspecting.
149
+ def inspect
150
+ "#<#{self.class} @url=\"#{@url}\" @rel=\"#{@rel}\">"
151
+ end
152
+
153
+ end
154
+
155
+
156
+ end
@@ -0,0 +1,109 @@
1
+ module Restfolia
2
+
3
+ # Public: Exception to represent an invalid HTTP response.
4
+ #
5
+ # Examples
6
+ #
7
+ # begin
8
+ # # assuming http_response is 404 response
9
+ # raise ResponseError.new("message", caller, http_response)
10
+ # rescue Restfolia::ResponseError => ex
11
+ # ex.http_code # => 404
12
+ # ex.http_message # => "Not Found"
13
+ # ex.http_object # => http_response object
14
+ # end
15
+ #
16
+ class ResponseError < StandardError
17
+
18
+ # Returns nil or #code from http_response instance
19
+ attr_reader :http_code
20
+
21
+ # Returns nil or status code definition from #http_code
22
+ attr_reader :http_message
23
+
24
+ # List of HTTP Status code definitions.
25
+ # Source http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
26
+ HTTP_CODE_MSG = {
27
+ # 2xx
28
+ 200 => 'OK',
29
+ 201 => 'Created',
30
+ 202 => 'Accepted',
31
+ 203 => 'Non-Authoritative Information',
32
+ 204 => 'No Content',
33
+ 205 => 'Reset Content',
34
+ 206 => 'Partial Content',
35
+ # 3xx
36
+ 300 => 'Multiple Choices',
37
+ 301 => 'MovedPermanently',
38
+ 302 => 'Found',
39
+ 303 => 'SeeOther',
40
+ 304 => 'NotModified',
41
+ 305 => 'UseProxy',
42
+ 306 => '(Unused)',
43
+ 307 => 'TemporaryRedirect',
44
+ # 4xx
45
+ 400 => 'Bad Request',
46
+ 401 => 'Unauthorized',
47
+ 402 => 'Payment Required',
48
+ 403 => 'Forbidden',
49
+ 404 => 'Not Found',
50
+ 405 => 'Method Not Allowed',
51
+ 406 => 'Not Acceptable',
52
+ 407 => 'Proxy Authentication Required',
53
+ 408 => 'Request Timeout',
54
+ 409 => 'Conflict',
55
+ 410 => 'Gone',
56
+ 411 => 'Length Required',
57
+ 412 => 'Precondition Failed',
58
+ 413 => 'Request Entity Too Large',
59
+ 414 => 'Request-URI Too Long',
60
+ 415 => 'Unsupported Media Type',
61
+ 416 => 'Requested Range Not Satisfiable',
62
+ 417 => 'Expectation Failed',
63
+ # 5xx
64
+ 500 => 'Internal Server Error',
65
+ 501 => 'Not Implemented',
66
+ 502 => 'Bad Gateway',
67
+ 503 => 'Service Unavailable',
68
+ 504 => 'Gateway Timeout',
69
+ 505 => 'HTTP Version Not Supported'
70
+ }
71
+
72
+ # Public: Creates a ResponseError.
73
+ #
74
+ # message - String to describe the error.
75
+ # backtrace - Array, usually mounted by Kernel#caller.
76
+ # http_response - Net::HTTPResponse with error.
77
+ #
78
+ # Examples
79
+ #
80
+ # begin
81
+ # # assuming http_response is 404 response
82
+ # raise ResponseError.new("message", caller, http_response)
83
+ # rescue Restfolia::ResponseError => ex
84
+ # ex.http_code # => 404
85
+ # ex.http_message # => "Not Found"
86
+ # ex.http_object # => http_response object
87
+ # end
88
+ #
89
+ def initialize(message, backtrace, http_response)
90
+ super(message)
91
+ self.set_backtrace(backtrace)
92
+
93
+ @http_response = http_response
94
+ @http_code, @http_message = nil
95
+ if http_response.respond_to?(:code)
96
+ @http_code = http_response.code.to_i
97
+ @http_message = HTTP_CODE_MSG[@http_code] \
98
+ || "Unknown HTTP code (#{@http_code})"
99
+ end
100
+ end
101
+
102
+ # Returns nil or Net::HTTPResponse instance.
103
+ def http_object
104
+ @http_response
105
+ end
106
+
107
+ end
108
+
109
+ end
@@ -0,0 +1,164 @@
1
+ module Restfolia::HTTP
2
+
3
+ # Public: Separated methods to handle HTTP response by status code.
4
+ module Behaviour
5
+
6
+ # Returns Restfolia::HTTP::Behaviour::Store instance.
7
+ def self.store
8
+ @store ||= Store.new
9
+ end
10
+
11
+ # Internal: Helpers Available to behaviours blocks
12
+ #
13
+ # Examples
14
+ #
15
+ # Restfolia::HTTP.behaviours do
16
+ # on(200) do |http_response|
17
+ # helpers.parse_json(http_response.body)
18
+ # end
19
+ # end
20
+ class Helpers
21
+
22
+ # Internal: Parse response body, checking for errors.
23
+ #
24
+ # http_response - HTTP Response with body. Expected to be a JSON.
25
+ #
26
+ # Returns Hash who represents JSON parsed.
27
+ # Raises Restfolia::ResponseError if body seens invalid somehow.
28
+ def parse_json(http_response)
29
+ body = http_response.body
30
+ begin
31
+ MultiJson.load(body, :symbolize_keys => true)
32
+ rescue MultiJson::DecodeError => ex
33
+ msg = "Body should be a valid json. #{ex.message}"
34
+ raise Restfolia::ResponseError.new(msg, caller, http_response)
35
+ end
36
+ end
37
+
38
+ # Public: Request url with GET and forwards to Restfolia::HTTP.
39
+ #
40
+ # url - String. Ex: http://service.com/resources
41
+ #
42
+ # Returns what Restfolia::HTTP.response_by_status_code returns.
43
+ def follow_url(url)
44
+ http_resp = Request.do_request(:get, url)
45
+ Restfolia::HTTP.response_by_status_code(http_resp)
46
+ end
47
+
48
+ end
49
+
50
+ # Public: Responsible to store behaviours. See #behaviours for details.
51
+ class Store
52
+
53
+ # Returns Restfolia::HTTP::Behaviour::Helpers instance.
54
+ attr_reader :helpers
55
+
56
+ # Public: Creates a Store.
57
+ def initialize
58
+ self.clear
59
+ @helpers = Helpers.new
60
+ end
61
+
62
+ # Public: clear all defined behaviours.
63
+ # Returns nothing.
64
+ def clear
65
+ @behaviours = {}
66
+ @behaviours_range = {}
67
+ nil
68
+ end
69
+
70
+ # Public: It's a nice way to define configurations for
71
+ # your behaves using a block.
72
+ #
73
+ # block - Required block to customize your behaves. Below are
74
+ # the methods available inside block:
75
+ # #on - See #on
76
+ #
77
+ # Examples
78
+ #
79
+ # store = Restfolia::HTTP::Behaviour::Store.new
80
+ # store.behaviours do
81
+ # on(200) { '200 behaviour' }
82
+ # on([201, 204]) { 'behaviour for 201 and 204 codes' }
83
+ # on(300...400) { '3xx range' }
84
+ # end
85
+ #
86
+ # Returns nothing.
87
+ def behaviours(&block)
88
+ self.instance_eval(&block)
89
+ nil
90
+ end
91
+
92
+ # Public: Add behaviour on this store. See #behaviours for
93
+ # examples.
94
+ #
95
+ # code - Integer or any object that respond to #include?
96
+ # block - Required block with behaviour for this code.
97
+ #
98
+ # Returns nothing.
99
+ def on(code, &block)
100
+ if code.is_a?(Integer)
101
+ @behaviours[code] = block
102
+ elsif code.respond_to?(:include?)
103
+ @behaviours_range[code] = block
104
+ end
105
+ nil
106
+ end
107
+
108
+ # Public: Method called by #execute in case of 'not found' http code.
109
+ #
110
+ # http_response - Net::HTTPResponse object.
111
+ #
112
+ # Examples
113
+ #
114
+ # store = Restfolia::HTTP::Behaviour::Store.new
115
+ # store.behaviours do
116
+ # on(200) { '200 ok' }
117
+ # end
118
+ # http_resp = OpenStruct.new(:code => 201) #simulate response 201
119
+ # store.execute(http_resp)
120
+ # # => #<Restfolia::ResponseError "Undefined behaviour for 201" ...>
121
+ #
122
+ # Returns nothing.
123
+ # Raises Restfolia::ResponseError
124
+ def default_behaviour(http_response)
125
+ msg = "Undefined behaviour for #{http_response.code}"
126
+ raise Restfolia::ResponseError.new(msg, caller, http_response)
127
+ end
128
+
129
+ # Public: Look for defined behaviour, based on HTTP code.
130
+ # If behaviour not found, call #default_behaviour.
131
+ #
132
+ # http_response - Net::HTTPResponse.
133
+ # Returns Result from Proc behaviour or default_behaviour method.
134
+ def execute(http_response)
135
+ code = http_response.code.to_i
136
+ if (behaviour = find(code))
137
+ behaviour.call(http_response)
138
+ else
139
+ default_behaviour(http_response)
140
+ end
141
+ end
142
+
143
+ protected
144
+
145
+ # Internal: Search for defined behaviour.
146
+ #
147
+ # code - Integer or object that respond to #include?
148
+ #
149
+ # Returns nil or Proc
150
+ def find(code)
151
+ behaviour = @behaviours[code]
152
+ if behaviour.nil?
153
+ _, behaviour = @behaviours_range.detect do |range, proc|
154
+ range.include?(code)
155
+ end
156
+ end
157
+ behaviour
158
+ end
159
+
160
+ end
161
+
162
+ end
163
+
164
+ end
@@ -0,0 +1,74 @@
1
+ module Restfolia::HTTP
2
+
3
+ # Internal: Simply a bag of HTTP options like headers, cookies, auth ... etc.
4
+ module Configuration
5
+
6
+ # Public: Sets/Returns cookies values as String.
7
+ attr_accessor :cookies
8
+
9
+ # Public: Returns Hash to be used as Headers on request.
10
+ def headers
11
+ @headers ||= {}
12
+ end
13
+
14
+ # Public: A fluent way to add Cookies to Request.
15
+ #
16
+ # cookies - String in cookie format.
17
+ #
18
+ # Examples
19
+ #
20
+ # # setting cookie from Google Translate
21
+ # cookies = "PREF=ID=07eb...; expires=Sat, 26-Apr-2014 19:19:36 GMT; path=/; domain=.google.com, NID=59...; expires=Fri, 26-Oct-2012 19:19:36 GMT; path=/; domain=.google.com; HttpOnly"
22
+ # resource = Restfolia.at("http://fake.com").
23
+ # set_cookies(cookies).get
24
+ #
25
+ # Returns self, always!
26
+ def set_cookies(cookies)
27
+ self.cookies = cookies
28
+ self
29
+ end
30
+
31
+ # Public: A fluent way to add HTTP headers.
32
+ # Headers informed here are merged with headers attribute.
33
+ #
34
+ # new_headers - Hash with headers.
35
+ #
36
+ # Examples
37
+ #
38
+ # entry_point = Restfolia.at("http://fake.com")
39
+ # entry_point.with_headers("X-Custom1" => "value",
40
+ # "X-Custom2" => "value2").get
41
+ #
42
+ # Returns self, always!
43
+ # Raises ArgumentError unless new_headers is a Hash.
44
+ def with_headers(new_headers)
45
+ unless new_headers.is_a?(Hash)
46
+ raise ArgumentError, "New Headers should Hash object."
47
+ end
48
+
49
+ headers.merge!(new_headers)
50
+ self
51
+ end
52
+
53
+ # Public: A fluent way to add Content-Type and Accept headers.
54
+ #
55
+ # content_type - String value. Ex: "application/json"
56
+ #
57
+ # Returns self, always!
58
+ def as(content_type)
59
+ headers["Content-Type"] = content_type
60
+ headers["Accept"] = content_type
61
+ self
62
+ end
63
+
64
+ protected
65
+
66
+ # Returns Hash with headers, cookies, auth ... etc.
67
+ def configuration
68
+ {:headers => headers,
69
+ :cookies => cookies}
70
+ end
71
+
72
+ end
73
+
74
+ end