her 0.3.7 → 0.3.8

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/Guardfile DELETED
@@ -1,7 +0,0 @@
1
- require "guard/guard"
2
-
3
- guard "rspec", :cli => "--colour --format=documentation" do
4
- watch(%r{^spec/.+_spec\.rb$})
5
- watch(%r{^lib/.+\.rb$}) { "spec" }
6
- watch("spec/spec_helper.rb") { "spec" }
7
- end
data/MIDDLEWARE.md DELETED
@@ -1,183 +0,0 @@
1
- # Middleware
2
-
3
- Since Her relies on [Faraday](https://github.com/technoweenie/faraday) to send HTTP requests, you can choose the middleware used 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.
4
-
5
- ## Authentication
6
-
7
- Her doesn’t support authentication by default. However, it’s easy to implement one with request middleware. Using the `connection` block, we can add it to the middleware stack.
8
-
9
- For example, to add a API token header to your requests in a Rails application, you would do something like this:
10
-
11
- ```ruby
12
- # app/controllers/application_controller.rb
13
- class ApplicationController < ActionController::Base
14
- around_filter :do_with_authenticated_user
15
-
16
- def do_with_authenticated_user
17
- Thread.current[:my_api_token] = session[:my_api_token]
18
- begin
19
- yield
20
- ensure
21
- Thread.current[:my_access_token] = nil
22
- end
23
- end
24
- end
25
-
26
- # lib/my_token_authentication.rb
27
- class MyTokenAuthentication < Faraday::Middleware
28
- def initialize(app, options={})
29
- @app = app
30
- end
31
-
32
- def call(env)
33
- env[:request_headers]["X-API-Token"] = Thread.current[:my_api_token] if Thread.current[:my_api_token].present?
34
- @app.call(env)
35
- end
36
- end
37
-
38
- # config/initializers/her.rb
39
- require "lib/my_token_authentication"
40
-
41
- Her::API.setup :url => "https://api.example.com" do |connection|
42
- connection.use MyTokenAuthentication
43
- connection.use Faraday::Request::UrlEncoded
44
- connection.use Her::Middleware::DefaultParseJSON
45
- connection.use Faraday::Adapter::NetHttp
46
- end
47
- ```
48
-
49
- Now, each HTTP request made by Her will have the `X-API-Token` header.
50
-
51
- ## Parsing JSON data
52
-
53
- By default, Her handles JSON data. It expects the resource/collection data to be returned at the first level.
54
-
55
- ```javascript
56
- // The response of GET /users/1
57
- { "id" : 1, "name" : "Tobias Fünke" }
58
-
59
- // The response of GET /users
60
- [{ "id" : 1, "name" : "Tobias Fünke" }]
61
- ```
62
-
63
- However, you can define your own parsing method using a response middleware. The middleware should set `env[:body]` to a hash with three keys: `data`, `errors` and `metadata`. The following code uses a custom middleware to parse the JSON data:
64
-
65
- ```ruby
66
- # Expects responses like:
67
- #
68
- # {
69
- # "result": {
70
- # "id": 1,
71
- # "name": "Tobias Fünke"
72
- # },
73
- # "errors" => []
74
- # }
75
- #
76
- class MyCustomParser < Faraday::Response::Middleware
77
- def on_complete(env)
78
- json = MultiJson.load(env[:body], :symbolize_keys => true)
79
- env[:body] = {
80
- :data => json[:result],
81
- :errors => json[:errors],
82
- :metadata => json[:metadata]
83
- }
84
- end
85
- end
86
-
87
- Her::API.setup :url => "https://api.example.com" do |connection|
88
- connection.use Faraday::Request::UrlEncoded
89
- connection.use MyCustomParser
90
- connection.use Faraday::Adapter::NetHttp
91
- end
92
- ```
93
-
94
- ## OAuth
95
-
96
- Using the `faraday_middleware` and `simple_oauth` gems, it’s fairly easy to use OAuth authentication with Her.
97
-
98
- In your Gemfile:
99
-
100
- ```ruby
101
- gem "her"
102
- gem "faraday_middleware"
103
- gem "simple_oauth"
104
- ```
105
-
106
- In your Ruby code:
107
-
108
- ```ruby
109
- # Create an application on `https://dev.twitter.com/apps` to set these values
110
- TWITTER_CREDENTIALS = {
111
- :consumer_key => "",
112
- :consumer_secret => "",
113
- :token => "",
114
- :token_secret => ""
115
- }
116
-
117
- Her::API.setup :url => "https://api.twitter.com/1/" do |connection|
118
- connection.use FaradayMiddleware::OAuth, TWITTER_CREDENTIALS
119
- connection.use Faraday::Request::UrlEncoded
120
- connection.use Her::Middleware::DefaultParseJSON
121
- connection.use Faraday::Adapter::NetHttp
122
- end
123
-
124
- class Tweet
125
- include Her::Model
126
- end
127
-
128
- @tweets = Tweet.get("/statuses/home_timeline.json")
129
- ```
130
-
131
- See the *Authentication* middleware section for an example of how to pass different credentials based on the current user.
132
-
133
- ## Caching
134
-
135
- Again, using the `faraday_middleware` makes it very easy to cache requests and responses:
136
-
137
- In your Gemfile:
138
-
139
- ```ruby
140
- gem "her"
141
- gem "faraday_middleware"
142
- ```
143
-
144
- In your Ruby code:
145
-
146
- ```ruby
147
- class MyCache < Hash
148
- def read(key)
149
- if cached = self[key]
150
- Marshal.load(cached)
151
- end
152
- end
153
-
154
- def write(key, data)
155
- self[key] = Marshal.dump(data)
156
- end
157
-
158
- def fetch(key)
159
- read(key) || yield.tap { |data| write(key, data) }
160
- end
161
- end
162
-
163
- # A cache system must respond to `#write`, `#read` and `#fetch`.
164
- # We should be probably using something like Memcached here, not a global object
165
- $cache = MyCache.new
166
-
167
- Her::API.setup :url => "https://api.example.com" do |connection|
168
- connection.use Faraday::Request::UrlEncoded
169
- connection.use FaradayMiddleware::Caching, $cache
170
- connection.use Her::Middleware::DefaultParseJSON
171
- connection.use Faraday::Adapter::NetHttp
172
- end
173
-
174
- class User
175
- include Her::Model
176
- end
177
-
178
- @user = User.find(1)
179
- # GET /users/1
180
-
181
- @user = User.find(1)
182
- # This request will be fetched from the cache
183
- ```
data/TESTING.md DELETED
@@ -1,88 +0,0 @@
1
- # Testing Her models
2
-
3
- Suppose we have these two models bound to your API:
4
-
5
- ```ruby
6
- # app/models/user.rb
7
- class User
8
- include Her::Model
9
- custom_get :popular
10
- end
11
-
12
- # app/models/post.rb
13
- class Post
14
- include Her::Model
15
- custom_get :recent, :archived
16
- end
17
- ```
18
-
19
- In order to test them, we’ll have to stub the remote API requests. With [RSpec](https://github.com/rspec/rspec-core), we can do this like so:
20
-
21
- ```ruby
22
- # spec/spec_helper.rb
23
- RSpec.configure do |config|
24
- config.include(Module.new do
25
- def stub_api_for(klass)
26
- klass.uses_api (api = Her::API.new)
27
-
28
- # Here, you would customize this for your own API (URL, middleware, etc)
29
- # like you have done in your application’s initializer
30
- api.setup :url => "http://api.example.com" do |connection|
31
- connection.use Her::Middleware::FirstLevelParseJSON
32
- connection.use Faraday::Request::UrlEncoded
33
- connection.adapter(:test) { |s| yield(s) }
34
- end
35
- end
36
- end)
37
- end
38
- ```
39
-
40
- Then, in your tests, we can specify what (fake) HTTP requests will return:
41
-
42
- ```ruby
43
- # spec/models/user.rb
44
- describe User do
45
- before do
46
- stub_api_for(User) do |stub|
47
- stub.get("/users/popular") { |env| [200, {}, [{ :id => 1, :name => "Tobias Fünke" }, { :id => 2, :name => "Lindsay Fünke" }].to_json] }
48
- end
49
- end
50
-
51
- describe :popular do
52
- subject { User.popular }
53
- its(:length) { should == 2 }
54
- its(:errors) { should be_empty }
55
- end
56
- end
57
- ```
58
-
59
- We can redefine the API for a model as many times as we want, like for more complex tests:
60
-
61
- ```ruby
62
- # spec/models/user.rb
63
- describe Post do
64
- describe :recent do
65
- before do
66
- stub_api_for(Post) do |stub|
67
- stub.get("/posts/recent") { |env| [200, {}, [{ :id => 1 }, { :id => 2 }].to_json] }
68
- end
69
- end
70
-
71
- subject { Post.recent }
72
- its(:length) { should == 2 }
73
- its(:errors) { should be_empty }
74
- end
75
-
76
- describe :archived do
77
- before do
78
- stub_api_for(Post) do |stub|
79
- stub.get("/posts/archived") { |env| [200, {}, [{ :id => 1 }, { :id => 2 }].to_json] }
80
- end
81
- end
82
-
83
- subject { Post.archived }
84
- its(:length) { should == 2 }
85
- its(:errors) { should be_empty }
86
- end
87
- end
88
- ```