her 0.2.5 → 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +2 -0
- data/README.md +83 -37
- data/Rakefile +0 -1
- data/UPGRADE.md +13 -13
- data/examples/twitter-oauth/app.rb +6 -5
- data/examples/twitter-search/app.rb +10 -8
- data/her.gemspec +13 -13
- data/lib/her.rb +7 -4
- data/lib/her/api.rb +20 -12
- data/lib/her/collection.rb +12 -0
- data/lib/her/middleware.rb +4 -3
- data/lib/her/middleware/accept_json.rb +15 -0
- data/lib/her/model.rb +8 -8
- data/lib/her/model/hooks.rb +24 -0
- data/lib/her/model/http.rb +19 -19
- data/lib/her/model/orm.rb +59 -46
- data/lib/her/model/relationships.rb +40 -27
- data/lib/her/version.rb +1 -1
- data/spec/api_spec.rb +41 -15
- data/spec/middleware/accept_json_spec.rb +10 -0
- data/spec/model/hooks_spec.rb +7 -7
- data/spec/model/http_spec.rb +44 -59
- data/spec/model/introspection_spec.rb +6 -5
- data/spec/model/orm_spec.rb +128 -23
- data/spec/model/paths_spec.rb +8 -10
- data/spec/model/relationships_spec.rb +54 -10
- data/spec/spec_helper.rb +0 -1
- metadata +59 -69
data/.rspec
ADDED
data/README.md
CHANGED
@@ -1,9 +1,7 @@
|
|
1
|
-
# Her
|
1
|
+
# Her [![Build Status](https://secure.travis-ci.org/remiprev/her.png)](http://travis-ci.org/remiprev/her) [![Gem dependency status](https://gemnasium.com/remiprev/her.png?travis)](https://gemnasium.com/remiprev/her)
|
2
2
|
|
3
3
|
Her is an ORM (Object Relational Mapper) that maps REST resources to Ruby objects. It is designed to build applications that are powered by a RESTful API instead of a database.
|
4
4
|
|
5
|
-
[![Build Status](https://secure.travis-ci.org/remiprev/her.png)](http://travis-ci.org/remiprev/her)
|
6
|
-
|
7
5
|
## Installation
|
8
6
|
|
9
7
|
In your Gemfile, add:
|
@@ -24,10 +22,10 @@ First, you have to define which API your models will be bound to. For example, w
|
|
24
22
|
|
25
23
|
```ruby
|
26
24
|
# config/initializers/her.rb
|
27
|
-
Her::API.setup :
|
28
|
-
|
29
|
-
|
30
|
-
|
25
|
+
Her::API.setup :url => "https://api.example.com" do |connection|
|
26
|
+
connection.use Faraday::Request::UrlEncoded
|
27
|
+
connection.use Her::Middleware::DefaultParseJSON
|
28
|
+
connection.use Faraday::Adapter::NetHttp
|
31
29
|
end
|
32
30
|
```
|
33
31
|
|
@@ -62,13 +60,15 @@ User.find(1)
|
|
62
60
|
# PUT https://api.example.com/users/1 with the data and return+update the User object
|
63
61
|
```
|
64
62
|
|
63
|
+
You can look into the `examples` directory for sample applications using Her.
|
64
|
+
|
65
65
|
## Middleware
|
66
66
|
|
67
|
-
Since Her relies on [Faraday](https://github.com/technoweenie/faraday) to send HTTP requests, you can add additional middleware to handle requests and responses. Using the block in the `setup` call, you have access to Faraday’s `
|
67
|
+
Since Her relies on [Faraday](https://github.com/technoweenie/faraday) to send HTTP requests, you can add additional middleware to handle requests and responses. Using the block in the `setup` call, you have access to Faraday’s `connection` object and are able to customize the middleware stack used on each request and response.
|
68
68
|
|
69
69
|
### Authentication
|
70
70
|
|
71
|
-
Her doesn’t support any kind of authentication. However, it’s very easy to implement one with a request middleware. Using the
|
71
|
+
Her doesn’t support any kind of authentication. However, it’s very easy to implement one with a request middleware. Using the connection block, we add it to the default list of middleware.
|
72
72
|
|
73
73
|
```ruby
|
74
74
|
class MyAuthentication < Faraday::Middleware
|
@@ -82,13 +82,13 @@ class MyAuthentication < Faraday::Middleware
|
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
|
-
Her::API.setup :
|
85
|
+
Her::API.setup :url => "https://api.example.com" do |connection|
|
86
86
|
# This token could be stored in the client session
|
87
|
-
|
87
|
+
connection.use MyAuthentication, :token => "bb2b2dd75413d32c1ac421d39e95b978d1819ff611f68fc2fdd5c8b9c7331192"
|
88
88
|
|
89
|
-
|
90
|
-
|
91
|
-
|
89
|
+
connection.use Faraday::Request::UrlEncoded
|
90
|
+
connection.use Her::Middleware::DefaultParseJSON
|
91
|
+
connection.use Faraday::Adapter::NetHttp
|
92
92
|
end
|
93
93
|
```
|
94
94
|
|
@@ -106,7 +106,7 @@ By default, Her handles JSON data. It expects the resource/collection data to be
|
|
106
106
|
[{ "id" : 1, "name" : "Tobias Fünke" }]
|
107
107
|
```
|
108
108
|
|
109
|
-
However, you can define your own parsing method, using a response middleware. The middleware is expected to set `env[:body]` to a hash with three keys: `data`, `errors` and `metadata`. The following code enables parsing JSON data and treating the result as first-level properties. Using the
|
109
|
+
However, you can define your own parsing method, using a response middleware. The middleware is expected to set `env[:body]` to a hash with three keys: `data`, `errors` and `metadata`. The following code enables parsing JSON data and treating the result as first-level properties. Using the connection block, we then replace the default parser with our custom parser.
|
110
110
|
|
111
111
|
```ruby
|
112
112
|
class MyCustomParser < Faraday::Response::Middleware
|
@@ -120,10 +120,10 @@ class MyCustomParser < Faraday::Response::Middleware
|
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
123
|
-
Her::API.setup :
|
124
|
-
|
125
|
-
|
126
|
-
|
123
|
+
Her::API.setup :url => "https://api.example.com" do |connection|
|
124
|
+
connection.use Faraday::Request::UrlEncoded
|
125
|
+
connection.use MyCustomParser
|
126
|
+
connection.use Faraday::Adapter::NetHttp
|
127
127
|
end
|
128
128
|
# User.find(1) will now expect "https://api.example.com/users/1" to return something like '{ "result" => { "id": 1, "name": "Tobias Fünke" }, "errors" => [] }'
|
129
129
|
```
|
@@ -151,11 +151,11 @@ TWITTER_CREDENTIALS = {
|
|
151
151
|
:token_secret => ""
|
152
152
|
}
|
153
153
|
|
154
|
-
Her::API.setup :
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
154
|
+
Her::API.setup :url => "https://api.twitter.com/1/" do |connection|
|
155
|
+
connection.use FaradayMiddleware::OAuth, TWITTER_CREDENTIALS
|
156
|
+
connection.use Faraday::Request::UrlEncoded
|
157
|
+
connection.use Her::Middleware::DefaultParseJSON
|
158
|
+
connection.use Faraday::Adapter::NetHttp
|
159
159
|
end
|
160
160
|
|
161
161
|
class Tweet
|
@@ -199,11 +199,11 @@ end
|
|
199
199
|
# We should be probably using something like Memcached here, not a global object
|
200
200
|
$cache = MyCache.new
|
201
201
|
|
202
|
-
Her::API.setup :
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
202
|
+
Her::API.setup :url => "https://api.example.com" do |connection|
|
203
|
+
connection.use Faraday::Request::UrlEncoded
|
204
|
+
connection.use FaradayMiddleware::Caching, $cache
|
205
|
+
connection.use Her::Middleware::DefaultParseJSON
|
206
|
+
connection.use Faraday::Adapter::NetHttp
|
207
207
|
end
|
208
208
|
|
209
209
|
class User
|
@@ -403,17 +403,17 @@ It is possible to use different APIs for different models. Instead of calling `H
|
|
403
403
|
```ruby
|
404
404
|
# config/initializers/her.rb
|
405
405
|
$my_api = Her::API.new
|
406
|
-
$my_api.setup :
|
407
|
-
|
408
|
-
|
409
|
-
|
406
|
+
$my_api.setup :url => "https://my_api.example.com" do |connection|
|
407
|
+
connection.use Faraday::Request::UrlEncoded
|
408
|
+
connection.use Her::Middleware::DefaultParseJSON
|
409
|
+
connection.use Faraday::Adapter::NetHttp
|
410
410
|
end
|
411
411
|
|
412
412
|
$other_api = Her::API.new
|
413
|
-
$other_api.setup :
|
414
|
-
|
415
|
-
|
416
|
-
|
413
|
+
$other_api.setup :url => "https://other_api.example.com" do |connection|
|
414
|
+
connection.use Faraday::Request::UrlEncoded
|
415
|
+
connection.use Her::Middleware::DefaultParseJSON
|
416
|
+
connection.use Faraday::Adapter::NetHttp
|
417
417
|
end
|
418
418
|
```
|
419
419
|
|
@@ -437,6 +437,51 @@ Category.all
|
|
437
437
|
# GET https://other_api.example.com/categories
|
438
438
|
```
|
439
439
|
|
440
|
+
## SSL
|
441
|
+
|
442
|
+
When initializing `Her::API`, you can pass any parameter supported by `Faraday.new`. So [to use HTTPS](https://github.com/technoweenie/faraday/wiki/Setting-up-SSL-certificates), you can use Faraday’s `:ssl` option.
|
443
|
+
|
444
|
+
```ruby
|
445
|
+
ssl_options = { :ca_path => "/usr/lib/ssl/certs" }
|
446
|
+
Her::API.setup :url => "https://api.example.com", :ssl => ssl_options do |connection|
|
447
|
+
connection.use Faraday::Request::UrlEncoded
|
448
|
+
connection.use Her::Middleware::DefaultParseJSON
|
449
|
+
connection.use Faraday::Adapter::NetHttp
|
450
|
+
end
|
451
|
+
```
|
452
|
+
|
453
|
+
## Testing
|
454
|
+
|
455
|
+
Using Faraday stubbing feature, it’s very easy to write tests for our models. For example, using [RSpec](https://github.com/rspec/rspec-core):
|
456
|
+
|
457
|
+
```ruby
|
458
|
+
# app/models/post.rb
|
459
|
+
class Post
|
460
|
+
include Her::Model
|
461
|
+
custom_get :popular
|
462
|
+
end
|
463
|
+
|
464
|
+
# spec/models/post.rb
|
465
|
+
describe Post do
|
466
|
+
before do
|
467
|
+
Her::API.setup :url => "http://api.example.com" do |connection|
|
468
|
+
connection.use Her::Middleware::FirstLevelParseJSON
|
469
|
+
connection.use Faraday::Request::UrlEncoded
|
470
|
+
connection.adapter :test do |stub|
|
471
|
+
stub.get("/users/popular") { |env| [200, {}, [{ :id => 1, :name => "Tobias Fünke" }, { :id => 2, :name => "Lindsay Fünke" }].to_json] }
|
472
|
+
end
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
describe ".popular" do
|
477
|
+
it "should fetch all popular posts" do
|
478
|
+
@posts = Post.popular
|
479
|
+
@posts.length.should == 2
|
480
|
+
end
|
481
|
+
end
|
482
|
+
end
|
483
|
+
```
|
484
|
+
|
440
485
|
## Things to be done
|
441
486
|
|
442
487
|
* Better error handling
|
@@ -464,6 +509,7 @@ These fine folks helped with Her:
|
|
464
509
|
* [@rafaelss](https://github.com/rafaelss)
|
465
510
|
* [@tysontate](https://github.com/tysontate)
|
466
511
|
* [@nfo](https://github.com/nfo)
|
512
|
+
* [@simonprevost](https://github.com/simonprevost)
|
467
513
|
|
468
514
|
## License
|
469
515
|
|
data/Rakefile
CHANGED
data/UPGRADE.md
CHANGED
@@ -1,20 +1,20 @@
|
|
1
|
-
Here is a list of backward-incompatible changes that were introduced while Her is
|
1
|
+
Here is a list of backward-incompatible changes that were introduced while Her is pre-1.0. After reaching 1.0, it will follow the [Semantic Versioning](http://semver.org/) system.
|
2
2
|
|
3
3
|
## 0.2.4
|
4
4
|
|
5
5
|
* Her no longer includes default middleware when making HTTP requests. The user has now to define all the needed middleware. Before:
|
6
6
|
|
7
|
-
Her::API.setup :
|
8
|
-
|
7
|
+
Her::API.setup :url => "https://api.example.com" do |connection|
|
8
|
+
connection.insert(0, FaradayMiddle::OAuth)
|
9
9
|
end
|
10
10
|
|
11
11
|
Now:
|
12
|
-
|
13
|
-
Her::API.setup :
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
|
13
|
+
Her::API.setup :url => "https://api.example.com" do |connection|
|
14
|
+
connection.use FaradayMiddle::OAuth
|
15
|
+
connection.use Her::Middleware::FirstLevelParseJSON
|
16
|
+
connection.use Faraday::Request::UrlEncoded
|
17
|
+
connection.use Faraday::Adapter::NetHttp
|
18
18
|
end
|
19
19
|
|
20
20
|
## 0.2
|
@@ -22,9 +22,9 @@ Here is a list of backward-incompatible changes that were introduced while Her i
|
|
22
22
|
* The default parser middleware has been replaced to treat first-level JSON data as the resource or collection data. Before it expected this:
|
23
23
|
|
24
24
|
{ "data": { "id": 1, "name": "Foo" }, "errors": [] }
|
25
|
-
|
25
|
+
|
26
26
|
Now it expects this (the `errors` key is not treated as resource data):
|
27
|
-
|
27
|
+
|
28
28
|
{ "id": 1, "name": "Foo", "errors": [] }
|
29
|
-
|
30
|
-
If you still want to get the old behavior, you can use `Her::Middleware::SecondLevelParseJSON` instead of `Her::Middleware::FirstLevelParseJSON` in your middleware stack.
|
29
|
+
|
30
|
+
If you still want to get the old behavior, you can use `Her::Middleware::SecondLevelParseJSON` instead of `Her::Middleware::FirstLevelParseJSON` in your middleware stack.
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# Create custom parser
|
2
2
|
class TwitterParser < Faraday::Response::Middleware
|
3
|
-
METADATA_KEYS = [:completed_in, :max_id, :max_id_str, :next_page, :page, :query, :refresh_url, :results_per_page, :since_id, :since_id_str]
|
4
|
-
|
5
3
|
def on_complete(env)
|
6
4
|
json = MultiJson.load(env[:body], :symbolize_keys => true)
|
7
5
|
errors = [json.delete(:error)]
|
@@ -13,6 +11,7 @@ class TwitterParser < Faraday::Response::Middleware
|
|
13
11
|
end
|
14
12
|
end
|
15
13
|
|
14
|
+
# See https://dev.twitter.com/apps
|
16
15
|
TWITTER_CREDENTIALS = {
|
17
16
|
:consumer_key => "",
|
18
17
|
:consumer_secret => "",
|
@@ -21,9 +20,11 @@ TWITTER_CREDENTIALS = {
|
|
21
20
|
}
|
22
21
|
|
23
22
|
# Initialize API
|
24
|
-
Her::API.setup :
|
25
|
-
builder.
|
26
|
-
builder.
|
23
|
+
Her::API.setup :url => "https://api.twitter.com/1/" do |builder|
|
24
|
+
builder.use FaradayMiddleware::OAuth, TWITTER_CREDENTIALS
|
25
|
+
builder.use Faraday::Request::UrlEncoded
|
26
|
+
builder.use TwitterParser
|
27
|
+
builder.use Faraday::Adapter::NetHttp
|
27
28
|
end
|
28
29
|
|
29
30
|
# Define classes
|
@@ -4,10 +4,12 @@ class TwitterSearchParser < Faraday::Response::Middleware
|
|
4
4
|
|
5
5
|
def on_complete(env)
|
6
6
|
json = MultiJson.load(env[:body], :symbolize_keys => true)
|
7
|
+
data = json.delete(:results)
|
8
|
+
errors = [json.delete(:error)].compact
|
7
9
|
env[:body] = {
|
8
|
-
:data =>
|
9
|
-
:errors =>
|
10
|
-
:metadata => json
|
10
|
+
:data => data,
|
11
|
+
:errors => errors,
|
12
|
+
:metadata => json
|
11
13
|
}
|
12
14
|
end
|
13
15
|
end
|
@@ -31,11 +33,11 @@ end
|
|
31
33
|
$cache = MyCache.new
|
32
34
|
|
33
35
|
# Initialize API
|
34
|
-
Her::API.setup :
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
Her::API.setup :url => "http://search.twitter.com" do |connection|
|
37
|
+
connection.use Faraday::Request::UrlEncoded
|
38
|
+
connection.use FaradayMiddleware::Caching, $cache
|
39
|
+
connection.use TwitterSearchParser
|
40
|
+
connection.use Faraday::Adapter::NetHttp
|
39
41
|
end
|
40
42
|
|
41
43
|
# Define classes
|
data/her.gemspec
CHANGED
@@ -8,6 +8,7 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.authors = ["Rémi Prévost"]
|
9
9
|
s.email = ["remi@exomel.com"]
|
10
10
|
s.homepage = "http://remiprev.github.com/her"
|
11
|
+
s.license = "MIT"
|
11
12
|
s.summary = "A simple Representational State Transfer-based Hypertext Transfer Protocol-powered Object Relational Mapper. Her?"
|
12
13
|
s.description = "Her is an ORM that maps REST resources and collections to Ruby objects"
|
13
14
|
|
@@ -16,18 +17,17 @@ Gem::Specification.new do |s|
|
|
16
17
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
18
|
s.require_paths = ["lib"]
|
18
19
|
|
19
|
-
s.add_development_dependency "rake", "0.9.2
|
20
|
-
s.add_development_dependency "rspec", "2.
|
21
|
-
s.add_development_dependency "yard", "0.
|
22
|
-
s.add_development_dependency "redcarpet", "1
|
23
|
-
s.add_development_dependency "mocha", "0.11
|
24
|
-
s.add_development_dependency "
|
25
|
-
s.add_development_dependency "guard", "
|
26
|
-
s.add_development_dependency "
|
27
|
-
s.add_development_dependency "
|
28
|
-
s.add_development_dependency "growl", "1.0.3"
|
20
|
+
s.add_development_dependency "rake", "~> 0.9.2"
|
21
|
+
s.add_development_dependency "rspec", "~> 2.10"
|
22
|
+
s.add_development_dependency "yard", "~> 0.8"
|
23
|
+
s.add_development_dependency "redcarpet", "~> 2.1"
|
24
|
+
s.add_development_dependency "mocha", "~> 0.11"
|
25
|
+
s.add_development_dependency "guard", "~> 1.0"
|
26
|
+
s.add_development_dependency "guard-rspec", "~> 0.7"
|
27
|
+
s.add_development_dependency "rb-fsevent", "~> 0.9"
|
28
|
+
s.add_development_dependency "growl", "~> 1.0"
|
29
29
|
|
30
|
-
s.add_runtime_dependency "activesupport", "3.2
|
31
|
-
s.add_runtime_dependency "faraday", "0.8
|
32
|
-
s.add_runtime_dependency "multi_json", "1.3
|
30
|
+
s.add_runtime_dependency "activesupport", "~> 3.2"
|
31
|
+
s.add_runtime_dependency "faraday", "~> 0.8"
|
32
|
+
s.add_runtime_dependency "multi_json", "~> 1.3"
|
33
33
|
end
|
data/lib/her.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
require "her/version"
|
2
|
+
|
2
3
|
require "multi_json"
|
3
4
|
require "faraday"
|
4
5
|
require "active_support"
|
5
6
|
require "active_support/inflector"
|
6
7
|
|
8
|
+
require "her/model"
|
9
|
+
require "her/api"
|
10
|
+
require "her/middleware"
|
11
|
+
require "her/errors"
|
12
|
+
require "her/collection"
|
13
|
+
|
7
14
|
module Her
|
8
|
-
autoload :Model, "her/model"
|
9
|
-
autoload :API, "her/api"
|
10
|
-
autoload :Middleware, "her/middleware"
|
11
|
-
autoload :Errors, "her/errors"
|
12
15
|
end
|
data/lib/her/api.rb
CHANGED
@@ -3,7 +3,7 @@ module Her
|
|
3
3
|
# so it knows where to make those requests. In Rails, this is usually done in `config/initializers/her.rb`:
|
4
4
|
class API
|
5
5
|
# @private
|
6
|
-
attr_reader :base_uri, :connection
|
6
|
+
attr_reader :base_uri, :connection, :options
|
7
7
|
|
8
8
|
# Setup a default API connection. Accepted arguments and options are the same as {API#setup}.
|
9
9
|
def self.setup(attrs={}, &block) # {{{
|
@@ -13,13 +13,14 @@ module Her
|
|
13
13
|
|
14
14
|
# Setup the API connection.
|
15
15
|
#
|
16
|
-
# @param [Hash] attrs the options
|
17
|
-
# @option attrs [String] :
|
16
|
+
# @param [Hash] attrs the Faraday options
|
17
|
+
# @option attrs [String] :url The main HTTP API root (eg. `https://api.example.com`)
|
18
|
+
# @option attrs [String] :ssl A hash containing [SSL options](https://github.com/technoweenie/faraday/wiki/Setting-up-SSL-certificates)
|
18
19
|
#
|
19
20
|
# @return Faraday::Connection
|
20
21
|
#
|
21
22
|
# @example Setting up the default API connection
|
22
|
-
# Her::API.setup :
|
23
|
+
# Her::API.setup :url => "https://api.example"
|
23
24
|
#
|
24
25
|
# @example A custom middleware added to the default list
|
25
26
|
# class MyAuthentication < Faraday::Middleware
|
@@ -28,8 +29,10 @@ module Her
|
|
28
29
|
# @all.call(env)
|
29
30
|
# end
|
30
31
|
# end
|
31
|
-
# Her::API.setup :
|
32
|
-
#
|
32
|
+
# Her::API.setup :url => "https://api.example.com" do |connection|
|
33
|
+
# connection.use Faraday::Request::UrlEncoded
|
34
|
+
# connection.use Her::Middleware::DefaultParseJSON
|
35
|
+
# connection.use Faraday::Adapter::NetHttp
|
33
36
|
# end
|
34
37
|
#
|
35
38
|
# @example A custom parse middleware
|
@@ -41,14 +44,17 @@ module Her
|
|
41
44
|
# env[:body] = { :data => json, :errors => errors, :metadata => metadata }
|
42
45
|
# end
|
43
46
|
# end
|
44
|
-
# Her::API.setup :
|
45
|
-
#
|
46
|
-
#
|
47
|
+
# Her::API.setup :url => "https://api.example.com" do |connection|
|
48
|
+
# connection.use Faraday::Request::UrlEncoded
|
49
|
+
# connection.use MyCustomParser
|
50
|
+
# connection.use Faraday::Adapter::NetHttp
|
47
51
|
# end
|
48
52
|
def setup(attrs={}) # {{{
|
49
|
-
|
50
|
-
@
|
51
|
-
|
53
|
+
attrs[:url] = attrs.delete(:base_uri) if attrs.include?(:base_uri) # Support legacy :base_uri option
|
54
|
+
@base_uri = attrs[:url]
|
55
|
+
@options = attrs
|
56
|
+
@connection = Faraday.new(attrs) do |connection|
|
57
|
+
yield connection if block_given?
|
52
58
|
end
|
53
59
|
end # }}}
|
54
60
|
|
@@ -60,8 +66,10 @@ module Her
|
|
60
66
|
def request(attrs={}) # {{{
|
61
67
|
method = attrs.delete(:_method)
|
62
68
|
path = attrs.delete(:_path)
|
69
|
+
headers = attrs.delete(:_headers)
|
63
70
|
attrs.delete_if { |key, value| key.to_s =~ /^_/ } # Remove all internal parameters
|
64
71
|
response = @connection.send method do |request|
|
72
|
+
request.headers.merge!(headers) if headers
|
65
73
|
if method == :get
|
66
74
|
# For GET requests, treat additional parameters as querystring data
|
67
75
|
request.url path, attrs
|