gister 0.0.1

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/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gister.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Eric Allam
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # Gister
2
+
3
+ Gister provides a way to cache gister embed code, basically creating a middleware that acts like a reverse-proxy
4
+ to the gist.github.com api.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'gister'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install gister
19
+
20
+ ## Usage
21
+
22
+ ## Contributing
23
+
24
+ 1. Fork it
25
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
26
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
27
+ 4. Push to the branch (`git push origin my-new-feature`)
28
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
data/gister.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/gister/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Eric Allam"]
6
+ gem.email = ["rubymaverick@gmail.com"]
7
+ gem.description = %q{Provides a Middleware to cache embedded gist content}
8
+ gem.summary = %q{Provides a Middleware to cache embedded gist content}
9
+ gem.homepage = ""
10
+
11
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
+ gem.files = `git ls-files`.split("\n")
13
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ gem.name = "gister"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Gister::VERSION
17
+
18
+ gem.add_development_dependency "rspec"
19
+ gem.add_development_dependency "vcr", "~> 2.0.0"
20
+ gem.add_development_dependency "webmock"
21
+
22
+ gem.add_runtime_dependency "faraday", "0.6.1"
23
+ end
data/lib/gister.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'gister/railtie' if defined?(Rails)
2
+
3
+ module Gister
4
+ def self.fetcher
5
+ @fetcher ||= Fetcher.new
6
+ end
7
+ end
@@ -0,0 +1,72 @@
1
+ require 'faraday'
2
+
3
+ module Gister
4
+ class Fetcher
5
+ ClientError = Class.new(StandardError)
6
+ GistNotFound = Class.new(ClientError)
7
+
8
+ def initialize
9
+ @store = Hash.new
10
+ end
11
+
12
+ def fetch(key)
13
+ if result = get(key)
14
+ result
15
+ else
16
+ result = fetch_result(key)
17
+ set key, result
18
+ result
19
+ end
20
+ end
21
+
22
+ def get(key)
23
+ @store[key]
24
+ end
25
+
26
+ def set(key, value)
27
+ @store[key] = value
28
+ end
29
+
30
+ private
31
+
32
+ def fetch_result(key)
33
+ path, params = parse_uri(key)
34
+
35
+ wrap_exceptions do
36
+ response = connection.get(path) do |req|
37
+ req.params = params
38
+ end
39
+ response.body
40
+ end
41
+ end
42
+
43
+ def wrap_exceptions
44
+ yield
45
+ rescue Faraday::Error::ResourceNotFound
46
+ raise GistNotFound.new($!)
47
+ rescue Faraday::Error::ClientError
48
+ raise ClientError.new($1)
49
+ end
50
+
51
+ def connection
52
+ @connection ||= Faraday.new(url: "https://gist.github.com") do |builder|
53
+ builder.use Faraday::Request::JSON
54
+ builder.use Faraday::Response::RaiseError
55
+ builder.use Faraday::Adapter::NetHttp
56
+ end
57
+ end
58
+
59
+ def parse_uri(uri)
60
+ uri = URI.parse(uri)
61
+ [uri.path, parse_params(uri.query)]
62
+ end
63
+
64
+ def parse_params(query_string)
65
+ query_string.split("&").inject(Hash.new) do |hash, kv|
66
+ key, value = kv.split("=")
67
+ hash[key] = value
68
+ hash
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,48 @@
1
+ require 'open-uri'
2
+
3
+ require_relative 'fetcher'
4
+
5
+ module Gister
6
+ class Middleware
7
+ def initialize(app, fetcher=Fetcher.new)
8
+ @app = app
9
+ @fetcher = fetcher
10
+ end
11
+
12
+ def call(env)
13
+ request = Rack::Request.new env
14
+ if request.path =~ /^\/gist\/[0-9]+.json/
15
+ respond_to_failures do
16
+ [200, {'Content-Type' => 'application/javascript'}, [get_body_content(request)]]
17
+ end
18
+ else
19
+ @app.call(env)
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def respond_to_failures
26
+ yield
27
+ rescue Fetcher::ClientError
28
+ [404, {}, [""]]
29
+ end
30
+
31
+ def get_body_content(request)
32
+ path = request.path.gsub("/gist/", '')
33
+ path = "https://gist.github.com/#{path}?file=#{request.params["file"]}"
34
+
35
+ response = fetch_by_path path
36
+ wrap_in_jsonp(request.params["callback"], response)
37
+ end
38
+
39
+ def wrap_in_jsonp(callback, response)
40
+ "#{callback}(#{response})"
41
+ end
42
+
43
+ def fetch_by_path(path)
44
+ @fetcher.fetch path
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,9 @@
1
+ require_relative 'middleware'
2
+
3
+ module Gister
4
+ class Railtie < Rails::Railtie
5
+ initializer "gister.configure_rails_initialization" do |app|
6
+ app.middleware.insert_before ActionDispatch::Cookies, Gister::Middleware, Gister.fetcher
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module Gister
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,75 @@
1
+ require 'gister/fetcher'
2
+ require 'helper'
3
+
4
+ describe Gister::Fetcher do
5
+ subject { described_class.new }
6
+ let(:key) {
7
+ "https://gist.github.com/1111.json?file=app.js"
8
+ }
9
+
10
+ describe "set" do
11
+ it "should store the object based on it's key" do
12
+ subject.set(key, "hello")
13
+ subject.get(key).should == "hello"
14
+ end
15
+ end
16
+
17
+ describe "fetch" do
18
+ use_vcr_cassette "gister", record: :new_episodes
19
+
20
+ context "when the gist is already in the cache" do
21
+ let(:cached_response) {
22
+ "jQuery({})"
23
+ }
24
+
25
+ before do
26
+ subject.set(key, cached_response)
27
+ end
28
+
29
+ it "should return the response from the cache" do
30
+ subject.fetch(key).should == cached_response
31
+ end
32
+ end
33
+
34
+ context "when the gist is not already in the cache" do
35
+
36
+ context "and there is a successful response from gist" do
37
+ let(:key) {
38
+ "https://gist.github.com/1996296.json?file=challenge-1-2.js"
39
+ }
40
+
41
+ it "should return the response gist" do
42
+ subject.fetch(key).should include("Anatomy of Backbone 1-2")
43
+ end
44
+
45
+ it "should store the response from gist into the cache" do
46
+ subject.fetch(key)
47
+ subject.get(key).should_not be_nil
48
+ end
49
+ end
50
+
51
+ context "and gist responds with a 404" do
52
+ let(:key) {
53
+ "https://gist.github.com/199629612981921.json?file=challenge-1-2.js"
54
+ }
55
+
56
+ it "should raise a GistNotFound error" do
57
+ expect { subject.fetch(key) }.to raise_error(described_class::GistNotFound)
58
+ end
59
+ end
60
+
61
+ context "and gist responds with a 500" do
62
+ let(:key) {
63
+ "https://gist.github.com/client_error122.json?file=challenge-1-2.js"
64
+ }
65
+
66
+ it "should raise a ClientError error" do
67
+ expect { subject.fetch(key) }.to raise_error(described_class::ClientError)
68
+ end
69
+ end
70
+
71
+ end
72
+ end
73
+
74
+
75
+ end
@@ -0,0 +1,308 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://gist.github.com/1996296.json?file=challenge-1-2.js
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept-Encoding:
11
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
12
+ Accept:
13
+ - ! '*/*'
14
+ User-Agent:
15
+ - Ruby
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: !binary |-
20
+ T0s=
21
+ headers:
22
+ !binary "U2VydmVy":
23
+ - !binary |-
24
+ bmdpbngvMS4wLjEy
25
+ !binary "RGF0ZQ==":
26
+ - !binary |-
27
+ TW9uLCAxMiBNYXIgMjAxMiAxNTo0MDoxMiBHTVQ=
28
+ !binary "Q29udGVudC1UeXBl":
29
+ - !binary |-
30
+ YXBwbGljYXRpb24vanNvbjsgY2hhcnNldD11dGYtOA==
31
+ !binary "VHJhbnNmZXItRW5jb2Rpbmc=":
32
+ - !binary |-
33
+ Y2h1bmtlZA==
34
+ !binary "Q29ubmVjdGlvbg==":
35
+ - !binary |-
36
+ a2VlcC1hbGl2ZQ==
37
+ !binary "U3RhdHVz":
38
+ - !binary |-
39
+ MjAwIE9L
40
+ !binary "RXRhZw==":
41
+ - !binary |-
42
+ IjU3YjRhMmIyNzE2OTBlNDEwZWRhNWI4MDdiYmRhMTEzIg==
43
+ !binary "WC1GcmFtZS1PcHRpb25z":
44
+ - !binary |-
45
+ ZGVueQ==
46
+ !binary "WC1SdW50aW1l":
47
+ - !binary |-
48
+ Njg=
49
+ !binary "Q2FjaGUtQ29udHJvbA==":
50
+ - !binary |-
51
+ cHJpdmF0ZSwgbWF4LWFnZT0wLCBtdXN0LXJldmFsaWRhdGU=
52
+ !binary "U3RyaWN0LVRyYW5zcG9ydC1TZWN1cml0eQ==":
53
+ - !binary |-
54
+ bWF4LWFnZT0yNTkyMDAw
55
+ !binary "Q29udGVudC1FbmNvZGluZw==":
56
+ - !binary |-
57
+ Z3ppcA==
58
+ body:
59
+ encoding: ASCII-8BIT
60
+ string: !binary |-
61
+ H4sIAAAAAAAAA6VUXW/aMBT9K5b7wCaROAnlK6RI3R66h+1tb2NCjnMhXhM7
62
+ sp1SVPW/7zoKrFDaPgwJgXzPuefmnuM8UWGAOyjW3NGUJlGcsGjEoimJR2l8
63
+ nY5HJIhmUUSHtGnzSgqaOtPCkBZghZGNk1oh71Zxp+s90RvyhYv7XCsgcZAg
64
+ q5APWM/wh8jiZkW30rogns8nyXyyokRU3Nr+eEWXK7VSpP90nJf1YCMr6EAH
65
+ CCGvQQV3nHQqdq8cfzwjeOoJqZTbssKvQ2DWGFi+qA4qqWDgBx98/xoPlplt
66
+ uDrOdF8g5YGbjPnjJTmtKq982zRaKleDcpdRGkE3l0tdg8M2e8ipRIOA8GKl
67
+ 4/7QBVQXyx8Q4dGBKt5kfnp6/rw4VBm6tMxYt7ju/4k7/cn7jtXg+CuXMk5K
68
+ AxuMRulcY1PGvKfhVrqyzUOha2b4jvVBYlExT/g44fl8AxMxmoyvi1HOk5zP
69
+ xrMxbGAM03w2m8ZMlLyqQG0hwHiGfyxG0Lp9BaizqTR3qfFRWHhjJewIamSM
70
+ nzwTxufD0fqxrnxg10fJdbx+R7LmZitV0OmncdQ8LoSutEmvJhO8KMvzwf9j
71
+ LOz2s5SW3OFCfRuSG92iKnGa7HVL8v3ZI3bLP+wd2XfSfWtzTw0vuX28wL37
72
+ h1zg26DbtS0B/MvmLWP/gWxnOoM6hyIU1mIHv1JL01/0fCH095DqnQKDnQUm
73
+ 34pS6yoQujUWGUM8rP099GSEGmg0Inun6PNfOWNkggkFAAA=
74
+ http_version:
75
+ recorded_at: Mon, 12 Mar 2012 15:40:12 GMT
76
+ - request:
77
+ method: get
78
+ uri: https://gist.github.com/199629612981921.json?file=challenge-1-2.js
79
+ body:
80
+ encoding: US-ASCII
81
+ string: ''
82
+ headers:
83
+ Accept-Encoding:
84
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
85
+ Accept:
86
+ - ! '*/*'
87
+ User-Agent:
88
+ - Ruby
89
+ response:
90
+ status:
91
+ code: 404
92
+ message: !binary |-
93
+ Tm90IEZvdW5k
94
+ headers:
95
+ !binary "U2VydmVy":
96
+ - !binary |-
97
+ bmdpbngvMS4wLjEy
98
+ !binary "RGF0ZQ==":
99
+ - !binary |-
100
+ TW9uLCAxMiBNYXIgMjAxMiAxNTo0MDoxMiBHTVQ=
101
+ !binary "Q29udGVudC1UeXBl":
102
+ - !binary |-
103
+ dGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04
104
+ !binary "VHJhbnNmZXItRW5jb2Rpbmc=":
105
+ - !binary |-
106
+ Y2h1bmtlZA==
107
+ !binary "Q29ubmVjdGlvbg==":
108
+ - !binary |-
109
+ a2VlcC1hbGl2ZQ==
110
+ !binary "U3RhdHVz":
111
+ - !binary |-
112
+ NDA0IE5vdCBGb3VuZA==
113
+ !binary "WC1GcmFtZS1PcHRpb25z":
114
+ - !binary |-
115
+ ZGVueQ==
116
+ !binary "WC1SdW50aW1l":
117
+ - !binary |-
118
+ MTI=
119
+ !binary "U2V0LUNvb2tpZQ==":
120
+ - !binary |-
121
+ X2doX3Nlc3M9QkFoN0J6b1FYMk56Y21aZmRHOXJaVzRpTVhkSFFsSTVSR01y
122
+ YUdoSGFGUmhlRzlQTTNJMlJVcHFZMnBQUVdKWFFtOWxNMVl4UjI1UGF6aFJV
123
+ RlU5T2c5elpYTnphVzl1WDJsa0lpVmhORFkyTkdOaFl6WTJNVFpoTWpoaU56
124
+ VTNOekZsWVdFMlpqSTFZVGhpT1ElM0QlM0QtLTdkMWYyNzlmOWQ1NDBjMmRl
125
+ MjhkZWFkZWU2YTI0Nzc5YmNjNDZlZmM7IHBhdGg9LzsgZXhwaXJlcz1TYXQs
126
+ IDAxLUphbi0yMDIyIDAwOjAwOjAwIEdNVDsgc2VjdXJlOyBIdHRwT25seQ==
127
+ !binary "Q2FjaGUtQ29udHJvbA==":
128
+ - !binary |-
129
+ bm8tY2FjaGU=
130
+ !binary "U3RyaWN0LVRyYW5zcG9ydC1TZWN1cml0eQ==":
131
+ - !binary |-
132
+ bWF4LWFnZT0yNTkyMDAw
133
+ !binary "Q29udGVudC1FbmNvZGluZw==":
134
+ - !binary |-
135
+ Z3ppcA==
136
+ body:
137
+ encoding: ASCII-8BIT
138
+ string: !binary |-
139
+ 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
177
+ +W3gRuoT9/Tjpgz1MgRMpI0eGpEgedYuAGxdLShYgmUa9DsdvansxFkT2lql
178
+ gJTPUWVGUYNJnuSRHuXn/p09du3fYv/ZR/KGySH2I3jGgt0KU3rAbOnHjMNp
179
+ dn3/GvLKJn7wOJCvrOdkyjZiU4lveoFvRg9BVYlvuZrfM/8kYDIfSVhUYaNx
180
+ ApbK9FHOnvdQ8qbDfuEee8EjD9f3E0z0rSeYAr0SwYmy3DO1CdR1tOqDNNbO
181
+ aUW8YbNETT6QSv24v0JlBneveyKBuo7KXrIxNq/oYciUVXgg0RVRLpnBb7O+
182
+ CvF19Ot9LMOKRBdXeV+Un6wqv5Kx3TPlJdjrKO/RNluh/EHK/3h1Uxe1v250
183
+ V7V/Ztn3TH3uMqwjvdvp7Zd0Wt2SPiPepoaP+FK2eynlxrei3FhHua4rcS+H
184
+ 2xQ7laJxeWMlpoZZ0ChkQUhESe5C7J69nATPlD2F/ZN+S571y2yuetJkeXKG
185
+ 7ElhtnixEMFlMiwZtYpNJfGbBu7F1O1o1pOcN11uXctQ5NJB3kelbtmPKNuE
186
+ SHj3xqOaHCXuIQH8iDLAVTCbYOQJuELaSxFzicxXMSsBwAkyEo0s98CQutmY
187
+ ReImEvHN8Tn9t5r2oaW75/X1OaMtXt4mg3UvBjJ3b4GEF+qCPebzxTP2AUsP
188
+ D+QrSEL47ngyYfgxudoGCCqaqByKANnGUBRrc9kCv8oebwkvjJAGLNX5KEEZ
189
+ CfZBPqhASTJktOOI+XmmdL3IfPR9VwnuBomhYq2IWlMeT1soKYAgXInwlJ17
190
+ 3F3+WXmu4Npk4lgVpGpECPBgVpA8RlrMuqYKMOhSN9hL3DlF7lWE4KZMo1Tp
191
+ rAGpCsohkJT1eAXzjRMiJ/XCt5F/9hxogmgrWEBvzq3aJYQnzn7i2xI5hwPr
192
+ rsjCuzCMkeMmQM7FzPfElgy78s0VSfjBN9lznwd2BcJXyMGrO6zfNoKA0vui
193
+ ljUf8KCCSc1KUV8F3Hwk0cpgPiICIv8fDypgvoKgl74Vz1MRuk8lAqeZcOvp
194
+ eosHFYTq6bLFjXDRQxGUKXuZ3mbnF++2BJWIcaHEn1QFJy6/QcXB1hC7XyPf
195
+ 49F2lO0e7HXyCBKqHm05l6y61K7pBT2pQCmuhjLe0kq3ZSo7sdKl+0UjLJ+r
196
+ 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
247
+ HaLt5jAlU3KQvqoBTdVWXzL6P/6KgBvhSAAA
248
+ http_version:
249
+ recorded_at: Mon, 12 Mar 2012 15:40:13 GMT
250
+ - request:
251
+ method: get
252
+ uri: https://gist.github.com/client_error122.json?file=challenge-1-2.js
253
+ body:
254
+ encoding: US-ASCII
255
+ string: ''
256
+ headers:
257
+ Accept-Encoding:
258
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
259
+ Accept:
260
+ - ! '*/*'
261
+ User-Agent:
262
+ - Ruby
263
+ response:
264
+ status:
265
+ code: 404
266
+ message: !binary |-
267
+ Tm90IEZvdW5k
268
+ headers:
269
+ !binary "U2VydmVy":
270
+ - !binary |-
271
+ bmdpbngvMS4wLjEy
272
+ !binary "RGF0ZQ==":
273
+ - !binary |-
274
+ TW9uLCAxMiBNYXIgMjAxMiAxNTo0MDoxMyBHTVQ=
275
+ !binary "Q29udGVudC1UeXBl":
276
+ - !binary |-
277
+ YXBwbGljYXRpb24vanNvbjsgY2hhcnNldD11dGYtOA==
278
+ !binary "VHJhbnNmZXItRW5jb2Rpbmc=":
279
+ - !binary |-
280
+ Y2h1bmtlZA==
281
+ !binary "Q29ubmVjdGlvbg==":
282
+ - !binary |-
283
+ a2VlcC1hbGl2ZQ==
284
+ !binary "U3RhdHVz":
285
+ - !binary |-
286
+ NDA0IE5vdCBGb3VuZA==
287
+ !binary "WC1GcmFtZS1PcHRpb25z":
288
+ - !binary |-
289
+ ZGVueQ==
290
+ !binary "WC1SdW50aW1l":
291
+ - !binary |-
292
+ Mw==
293
+ !binary "Q2FjaGUtQ29udHJvbA==":
294
+ - !binary |-
295
+ bm8tY2FjaGU=
296
+ !binary "U3RyaWN0LVRyYW5zcG9ydC1TZWN1cml0eQ==":
297
+ - !binary |-
298
+ bWF4LWFnZT0yNTkyMDAw
299
+ !binary "Q29udGVudC1FbmNvZGluZw==":
300
+ - !binary |-
301
+ Z3ppcA==
302
+ body:
303
+ encoding: ASCII-8BIT
304
+ string: !binary |-
305
+ H4sIAAAAAAAAA6tWSi0qyi9SslLyyy9RcMsvzUtRqgUAu/DzMBUAAAA=
306
+ http_version:
307
+ recorded_at: Mon, 12 Mar 2012 15:40:13 GMT
308
+ recorded_with: VCR 2.0.0
data/spec/helper.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'vcr'
2
+
3
+ VCR.configure do |c|
4
+ c.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
5
+ c.hook_into :webmock
6
+ end
7
+
8
+ RSpec.configure do |c|
9
+ c.extend VCR::RSpec::Macros
10
+ end
@@ -0,0 +1,83 @@
1
+ require 'gister/middleware'
2
+ require_relative 'helper'
3
+ require 'rack'
4
+
5
+ describe Gister::Middleware do
6
+ let(:app) { load_app }
7
+ let(:response) { request(app, path) }
8
+
9
+ subject { response }
10
+
11
+ describe "when responding to a request with a gist path" do
12
+ let(:path) {
13
+ "/gist/1111.json?file=app.js&callback=jQueryCallback&_=12012981921"
14
+ }
15
+
16
+ context 'and getting content from the fetcher works' do
17
+ let(:response_body) {
18
+ "{hello:'world'}"
19
+ }
20
+
21
+ before do
22
+ app.stub(:fetch_by_path).and_return(response_body)
23
+ end
24
+
25
+ it "should use the url as the key to fetcher with the callback or timestamp" do
26
+ app.should_receive(:fetch_by_path).with("https://gist.github.com/1111.json?file=app.js").and_return(response_body)
27
+
28
+ subject
29
+ end
30
+
31
+ it "should wrap the response from fetcher in the callback param" do
32
+ subject[2].should == ["jQueryCallback(#{response_body})"]
33
+ end
34
+
35
+ it "should return a 200" do
36
+ subject[0].should == 200
37
+ end
38
+
39
+ it "should have a content type of application/javascript" do
40
+ subject[1]['Content-Type'].should == "application/javascript"
41
+ end
42
+ end
43
+
44
+ context 'and getting content from the fetcher raises a ClientError' do
45
+ before do
46
+ app.stub(:fetch_by_path).and_raise(Gister::Fetcher::ClientError)
47
+ end
48
+
49
+ it "should return a 404" do
50
+ subject[0].should == 404
51
+ end
52
+
53
+ it "should have an empty body" do
54
+ subject[2].should == [""]
55
+ end
56
+ end
57
+ end
58
+
59
+ describe "when responding to a request without a gist path" do
60
+ let(:path) { "/hello" }
61
+
62
+ it "should pass through to the inner app" do
63
+ subject[2].should == 'Success'
64
+ end
65
+
66
+ end
67
+
68
+ def load_app
69
+ described_class.new inner_app, fetcher
70
+ end
71
+
72
+ def inner_app
73
+ lambda { |env| [200, {'Content-Type' => 'text/plain'}, 'Success'] }
74
+ end
75
+
76
+ def request(app, path, options = {})
77
+ app.call Rack::MockRequest.env_for(path, options)
78
+ end
79
+
80
+ def fetcher
81
+ Gister::Fetcher.new
82
+ end
83
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gister
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Eric Allam
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-03-12 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &70220136504780 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70220136504780
25
+ - !ruby/object:Gem::Dependency
26
+ name: vcr
27
+ requirement: &70220136503880 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 2.0.0
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70220136503880
36
+ - !ruby/object:Gem::Dependency
37
+ name: webmock
38
+ requirement: &70220136503320 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70220136503320
47
+ - !ruby/object:Gem::Dependency
48
+ name: faraday
49
+ requirement: &70220136502740 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - =
53
+ - !ruby/object:Gem::Version
54
+ version: 0.6.1
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *70220136502740
58
+ description: Provides a Middleware to cache embedded gist content
59
+ email:
60
+ - rubymaverick@gmail.com
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - .gitignore
66
+ - Gemfile
67
+ - LICENSE
68
+ - README.md
69
+ - Rakefile
70
+ - gister.gemspec
71
+ - lib/gister.rb
72
+ - lib/gister/fetcher.rb
73
+ - lib/gister/middleware.rb
74
+ - lib/gister/railtie.rb
75
+ - lib/gister/version.rb
76
+ - spec/fetcher_spec.rb
77
+ - spec/fixtures/vcr_cassettes/gister.yml
78
+ - spec/helper.rb
79
+ - spec/middleware_spec.rb
80
+ homepage: ''
81
+ licenses: []
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ! '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ! '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubyforge_project:
100
+ rubygems_version: 1.8.17
101
+ signing_key:
102
+ specification_version: 3
103
+ summary: Provides a Middleware to cache embedded gist content
104
+ test_files:
105
+ - spec/fetcher_spec.rb
106
+ - spec/fixtures/vcr_cassettes/gister.yml
107
+ - spec/helper.rb
108
+ - spec/middleware_spec.rb