faraday_middleware 0.9.0 → 0.9.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 281f479ebac151c76b6f622d3e2d919fcba90d3e
4
+ data.tar.gz: b536b23c23f5980b7d1645b5907a0bd8401369c3
5
+ SHA512:
6
+ metadata.gz: cb1e56ae090cdf939b3b9a74b366a7d6abb787486b019cbe8f9803295bfb600f78a276d47360af69e54138d601ea2d02c02e78fe7143e1b3a0bbb5158e709cff
7
+ data.tar.gz: ba124f9959f87f44128b8b7ab782360932d068077311a2ab15de90e37b784cb71350d1d2e47df0f660051e850ea6fbcd5917c741e36bbfdf50ab4295db02b255
@@ -0,0 +1,46 @@
1
+ ## Contributing
2
+ In the spirit of [free software][free-sw], **everyone** is encouraged to help
3
+ improve this project.
4
+
5
+ [free-sw]: http://www.fsf.org/licensing/essays/free-sw.html
6
+
7
+ Here are some ways *you* can contribute:
8
+
9
+ * by using alpha, beta, and prerelease versions
10
+ * by reporting bugs
11
+ * by suggesting new features
12
+ * by writing or editing documentation
13
+ * by writing specifications
14
+ * by writing code (**no patch is too small**: fix typos, add comments, clean up
15
+ inconsistent whitespace)
16
+ * by refactoring code
17
+ * by fixing [issues][]
18
+ * by reviewing patches
19
+
20
+ [issues]: https://github.com/lostisland/faraday_middleware/issues
21
+
22
+ ## Submitting an Issue
23
+ We use the [GitHub issue tracker][issues] to track bugs and features. Before
24
+ submitting a bug report or feature request, check to make sure it hasn't
25
+ already been submitted. When submitting a bug report, please include a [Gist][]
26
+ that includes a stack trace and any details that may be necessary to reproduce
27
+ the bug, including your gem version, Ruby version, and operating system.
28
+ Ideally, a bug report should include a pull request with failing specs.
29
+
30
+ [gist]: https://gist.github.com/
31
+
32
+ ## Submitting a Pull Request
33
+ 1. [Fork the repository.][fork]
34
+ 2. [Create a topic branch.][branch]
35
+ 3. Add specs for your unimplemented feature or bug fix.
36
+ 4. Run `bundle exec rake spec`. If your specs pass, return to step 3.
37
+ 5. Implement your feature or bug fix.
38
+ 6. Run `bundle exec rake spec`. If your specs fail, return to step 5.
39
+ 7. Run `open coverage/index.html`. If your changes are not completely covered
40
+ by your tests, return to step 3.
41
+ 8. Add, commit, and push your changes.
42
+ 9. [Submit a pull request.][pr]
43
+
44
+ [fork]: http://help.github.com/fork-a-repo/
45
+ [branch]: http://learn.github.com/p/branching.html
46
+ [pr]: http://help.github.com/send-pull-requests/
data/README.md CHANGED
@@ -50,5 +50,5 @@ end
50
50
  ```
51
51
 
52
52
 
53
- [faraday]: https://github.com/technoweenie/faraday#readme
54
- [docs]: https://github.com/pengwynn/faraday_middleware/wiki
53
+ [faraday]: https://github.com/lostisland/faraday#readme
54
+ [docs]: https://github.com/lostisland/faraday_middleware/wiki
data/Rakefile CHANGED
@@ -1,7 +1,11 @@
1
- if defined? RUBY_ENGINE and 'ruby' == RUBY_ENGINE and RUBY_VERSION.index('1.9') == 0
2
- task :default => [:enable_coverage, :spec, :test, :quality]
1
+ ruby_19 = RUBY_VERSION > '1.9'
2
+ ruby_mri = !defined?(RUBY_ENGINE) || 'ruby' == RUBY_ENGINE
3
+ default_gemfile = ENV['BUNDLE_GEMFILE'] =~ /Gemfile$/
4
+
5
+ if ruby_19 && ruby_mri && default_gemfile
6
+ task :default => [:enable_coverage, :spec, :quality]
3
7
  else
4
- task :default => [:spec, :test]
8
+ task :default => [:spec]
5
9
  end
6
10
 
7
11
  require 'bundler'
@@ -14,16 +18,11 @@ task :enable_coverage do
14
18
  ENV['COVERAGE'] = 'yes'
15
19
  end
16
20
 
17
- desc %(Run Test::Unit tests)
18
- task :test do
19
- sh 'ruby', '-Ilib', 'spec/caching_test.rb'
20
- end
21
-
22
21
  desc %(Check code quality metrics with Cane)
23
22
  task :quality do
24
23
  sh 'cane',
25
24
  '--abc-max=15',
26
25
  '--style-measure=110',
27
- '--gte=coverage/covered_percent,99',
26
+ '--gte=coverage/covered_percent,98.9',
28
27
  '--max-violations=0'
29
28
  end
@@ -1,23 +1,23 @@
1
- require File.expand_path('../lib/faraday_middleware/version', __FILE__)
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'faraday_middleware/version'
2
5
 
3
- Gem::Specification.new do |gem|
4
- gem.add_dependency 'faraday', ['>= 0.7.4', '< 0.9']
5
- gem.add_development_dependency 'multi_xml', '~> 0.2'
6
- gem.add_development_dependency 'rake', '~> 0.9'
7
- gem.add_development_dependency 'hashie', '~> 1.2'
8
- gem.add_development_dependency 'rash', '~> 0.3'
9
- gem.add_development_dependency 'rspec', '~> 2.6'
10
- gem.add_development_dependency 'simple_oauth', '~> 0.1'
11
- gem.add_development_dependency 'rack-cache', '~> 1.1'
12
- gem.authors = ["Erik Michaels-Ober", "Wynn Netherland"]
13
- gem.description = %q{Various middleware for Faraday}
14
- gem.email = ['sferik@gmail.com', 'wynn.netherland@gmail.com']
15
- gem.files = `git ls-files`.split("\n")
16
- gem.homepage = 'https://github.com/pengwynn/faraday_middleware'
17
- gem.name = 'faraday_middleware'
18
- gem.require_paths = ['lib']
19
- gem.required_rubygems_version = Gem::Requirement.new('>= 1.3.6')
20
- gem.summary = gem.description
21
- gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
- gem.version = FaradayMiddleware::VERSION
6
+ Gem::Specification.new do |spec|
7
+ spec.add_dependency 'faraday', ['>= 0.7.4', '< 0.10']
8
+ spec.add_development_dependency 'bundler', '~> 1.0'
9
+ spec.authors = ["Erik Michaels-Ober", "Wynn Netherland"]
10
+ spec.description = %q{Various middleware for Faraday}
11
+ spec.email = ['sferik@gmail.com', 'wynn.netherland@gmail.com']
12
+ spec.files = %w(CHANGELOG.md CONTRIBUTING.md LICENSE.md README.md Rakefile faraday_middleware.gemspec)
13
+ spec.files += Dir.glob("lib/**/*.rb")
14
+ spec.files += Dir.glob("spec/**/*")
15
+ spec.homepage = 'https://github.com/lostisland/faraday_middleware'
16
+ spec.licenses = ['MIT']
17
+ spec.name = 'faraday_middleware'
18
+ spec.require_paths = ['lib']
19
+ spec.required_rubygems_version = '>= 1.3.5'
20
+ spec.summary = spec.description
21
+ spec.test_files += Dir.glob("spec/**/*")
22
+ spec.version = FaradayMiddleware::VERSION
23
23
  end
@@ -18,14 +18,14 @@ module FaradayMiddleware
18
18
  autoload :FollowRedirects, 'faraday_middleware/response/follow_redirects'
19
19
  autoload :Instrumentation, 'faraday_middleware/instrumentation'
20
20
 
21
- if Faraday.respond_to? :register_middleware
22
- Faraday.register_middleware :request,
21
+ if Faraday::Middleware.respond_to? :register_middleware
22
+ Faraday::Request.register_middleware \
23
23
  :oauth => lambda { OAuth },
24
24
  :oauth2 => lambda { OAuth2 },
25
25
  :json => lambda { EncodeJson },
26
26
  :method_override => lambda { MethodOverride }
27
27
 
28
- Faraday.register_middleware :response,
28
+ Faraday::Response.register_middleware \
29
29
  :mashify => lambda { Mashify },
30
30
  :rashify => lambda { Rashify },
31
31
  :json => lambda { ParseJson },
@@ -38,7 +38,7 @@ module FaradayMiddleware
38
38
  :follow_redirects => lambda { FollowRedirects },
39
39
  :chunked => lambda { Chunked }
40
40
 
41
- Faraday.register_middleware \
41
+ Faraday::Middleware.register_middleware \
42
42
  :instrumentation => lambda { Instrumentation }
43
43
  end
44
44
  end
@@ -8,8 +8,8 @@ module FaradayMiddleware
8
8
  def initialize(app, rack_handler, *args)
9
9
  # tiny middleware that decomposes a Faraday::Response to standard Rack
10
10
  # array: [status, headers, body]
11
- compatible_app = lambda do |env|
12
- restore_env(env)
11
+ compatible_app = lambda do |rack_env|
12
+ env = restore_env(rack_env)
13
13
  response = app.call(env)
14
14
  [response.status, response.headers, Array(response.body)]
15
15
  end
@@ -17,43 +17,47 @@ module FaradayMiddleware
17
17
  end
18
18
 
19
19
  def call(env)
20
- prepare_env(env)
21
- rack_response = @rack.call(env)
20
+ rack_env = prepare_env(env)
21
+ rack_response = @rack.call(rack_env)
22
22
  finalize_response(env, rack_response)
23
23
  end
24
24
 
25
25
  NonPrefixedHeaders = %w[CONTENT_LENGTH CONTENT_TYPE]
26
26
 
27
27
  # faraday to rack-compatible
28
- def prepare_env(env)
29
- headers_to_rack(env)
28
+ def prepare_env(faraday_env)
29
+ env = headers_to_rack(faraday_env)
30
30
 
31
- url = env[:url]
31
+ url = faraday_env[:url]
32
32
  env['rack.url_scheme'] = url.scheme
33
33
  env['PATH_INFO'] = url.path
34
34
  env['SERVER_PORT'] = url.respond_to?(:inferred_port) ? url.inferred_port : url.port
35
35
  env['QUERY_STRING'] = url.query
36
- env['REQUEST_METHOD'] = env[:method].to_s.upcase
36
+ env['REQUEST_METHOD'] = faraday_env[:method].to_s.upcase
37
37
 
38
38
  env['rack.errors'] ||= StringIO.new
39
+ env['faraday'] = faraday_env
39
40
 
40
41
  env
41
42
  end
42
43
 
43
44
  def headers_to_rack(env)
45
+ rack_env = {}
44
46
  env[:request_headers].each do |name, value|
45
47
  name = name.upcase.tr('-', '_')
46
48
  name = "HTTP_#{name}" unless NonPrefixedHeaders.include? name
47
- env[name] = value
49
+ rack_env[name] = value
48
50
  end
51
+ rack_env
49
52
  end
50
53
 
51
54
  # rack to faraday-compatible
52
- def restore_env(env)
55
+ def restore_env(rack_env)
56
+ env = rack_env.fetch('faraday')
53
57
  headers = env[:request_headers]
54
58
  headers.clear
55
59
 
56
- env.each do |name, value|
60
+ rack_env.each do |name, value|
57
61
  next unless String === name
58
62
  if NonPrefixedHeaders.include? name or name.index('HTTP_') == 0
59
63
  name = name.sub(/^HTTP_/, '').downcase.tr('_', '-')
@@ -61,7 +65,8 @@ module FaradayMiddleware
61
65
  end
62
66
  end
63
67
 
64
- env[:method] = env['REQUEST_METHOD'].downcase.to_sym
68
+ env[:method] = rack_env['REQUEST_METHOD'].downcase.to_sym
69
+ env[:rack_errors] = rack_env['rack.errors']
65
70
  env
66
71
  end
67
72
 
@@ -72,7 +72,7 @@ module FaradayMiddleware
72
72
  end
73
73
 
74
74
  def include_body_params?(env)
75
- # see RFC 5489, section 3.4.1.3.1 for details
75
+ # see RFC 5849, section 3.4.1.3.1 for details
76
76
  !(type = env[:request_headers][CONTENT_TYPE]) or type == TYPE_URLENCODED
77
77
  end
78
78
 
@@ -31,8 +31,9 @@ module FaradayMiddleware
31
31
 
32
32
  def call(env)
33
33
  params = { param_name => @token }.update query_params(env[:url])
34
+ token = params[param_name]
34
35
 
35
- if token = params[param_name] and !token.empty?
36
+ if token.respond_to?(:empty?) && !token.empty?
36
37
  env[:url].query = build_query params
37
38
  env[:request_headers][AUTH_HEADER] ||= %(Token token="#{token}")
38
39
  end
@@ -47,7 +47,7 @@ module FaradayMiddleware
47
47
  if url.query && params_to_ignore.any?
48
48
  params = parse_query url.query
49
49
  params.reject! {|k,| params_to_ignore.include? k }
50
- url.query = build_query params
50
+ url.query = params.any? ? build_query(params) : nil
51
51
  end
52
52
  url.normalize!
53
53
  url.request_uri
@@ -4,7 +4,7 @@ require "faraday"
4
4
  module FaradayMiddleware
5
5
  # Parse dates from response body
6
6
  class ParseDates < ::Faraday::Response::Middleware
7
- ISO_DATE_FORMAT = /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z\Z/m
7
+ ISO_DATE_FORMAT = /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z\Z/m
8
8
 
9
9
  def initialize(app, options = {})
10
10
  @regexp = options[:match] || ISO_DATE_FORMAT
@@ -75,4 +75,36 @@ module FaradayMiddleware
75
75
  env[:request].fetch(:preserve_raw, @options[:preserve_raw])
76
76
  end
77
77
  end
78
+
79
+ # DRAGONS
80
+ module OptionsExtension
81
+ attr_accessor :preserve_raw
82
+
83
+ def to_hash
84
+ super.update(:preserve_raw => preserve_raw)
85
+ end
86
+
87
+ def each
88
+ return to_enum(:each) unless block_given?
89
+ super
90
+ yield :preserve_raw, preserve_raw
91
+ end
92
+
93
+ def fetch(key, *args)
94
+ if :preserve_raw == key
95
+ value = __send__(key)
96
+ value.nil? ? args.fetch(0) : value
97
+ else
98
+ super
99
+ end
100
+ end
101
+ end
102
+
103
+ if defined?(Faraday::RequestOptions)
104
+ begin
105
+ Faraday::RequestOptions.from(:preserve_raw => true)
106
+ rescue NoMethodError
107
+ Faraday::RequestOptions.send(:include, OptionsExtension)
108
+ end
109
+ end
78
110
  end
@@ -1,3 +1,3 @@
1
1
  module FaradayMiddleware
2
- VERSION = "0.9.0"
2
+ VERSION = "0.9.1" unless defined?(FaradayMiddleware::VERSION)
3
3
  end
@@ -0,0 +1,170 @@
1
+ require 'helper'
2
+ require 'forwardable'
3
+ require 'fileutils'
4
+ require 'rack/cache'
5
+ require 'faraday'
6
+ require 'faraday_middleware/response/caching'
7
+ require 'faraday_middleware/rack_compatible'
8
+
9
+ describe FaradayMiddleware::Caching do
10
+ before do
11
+ @cache = TestCache.new
12
+ request_count = 0
13
+ response = lambda { |env|
14
+ [200, {'Content-Type' => 'text/plain'}, "request:#{request_count+=1}"]
15
+ }
16
+
17
+ @conn = Faraday.new do |b|
18
+ b.use CachingLint
19
+ b.use FaradayMiddleware::Caching, @cache, options
20
+ b.adapter :test do |stub|
21
+ stub.get('/', &response)
22
+ stub.get('/?foo=bar', &response)
23
+ stub.post('/', &response)
24
+ stub.get('/other', &response)
25
+ end
26
+ end
27
+ end
28
+
29
+ let(:options) { {} }
30
+
31
+ extend Forwardable
32
+ def_delegators :@conn, :get, :post
33
+
34
+ it 'caches get requests' do
35
+ expect(get('/').body).to eq('request:1')
36
+ expect(get('/').body).to eq('request:1')
37
+ expect(get('/other').body).to eq('request:2')
38
+ expect(get('/other').body).to eq('request:2')
39
+ end
40
+
41
+ it 'includes request params in the response' do
42
+ get('/') # make cache
43
+ response = get('/')
44
+ expect(response.env[:method]).to eq(:get)
45
+ expect(response.env[:url].request_uri).to eq('/')
46
+ end
47
+
48
+ it 'caches requests with query params' do
49
+ expect(get('/').body).to eq('request:1')
50
+ expect(get('/?foo=bar').body).to eq('request:2')
51
+ expect(get('/?foo=bar').body).to eq('request:2')
52
+ expect(get('/').body).to eq('request:1')
53
+ end
54
+
55
+ it 'does not cache post requests' do
56
+ expect(post('/').body).to eq('request:1')
57
+ expect(post('/').body).to eq('request:2')
58
+ expect(post('/').body).to eq('request:3')
59
+ end
60
+
61
+ context ":ignore_params" do
62
+ let(:options) { {:ignore_params => %w[ utm_source utm_term ]} }
63
+
64
+ it "strips ignored parameters from cache_key" do
65
+ expect(get('/').body).to eq('request:1')
66
+ expect(get('/?utm_source=a').body).to eq('request:1')
67
+ expect(get('/?utm_source=a&utm_term=b').body).to eq('request:1')
68
+ expect(get('/?utm_source=a&utm_term=b&foo=bar').body).to eq('request:2')
69
+ expect(get('/?foo=bar').body).to eq('request:2')
70
+ end
71
+ end
72
+
73
+ class TestCache < Hash
74
+ def read(key)
75
+ if cached = self[key]
76
+ Marshal.load(cached)
77
+ end
78
+ end
79
+
80
+ def write(key, data)
81
+ self[key] = Marshal.dump(data)
82
+ end
83
+
84
+ def fetch(key)
85
+ read(key) || yield.tap { |data| write(key, data) }
86
+ end
87
+ end
88
+
89
+ class CachingLint < Struct.new(:app)
90
+ def call(env)
91
+ app.call(env).on_complete do
92
+ raise "no headers" unless env[:response_headers].is_a? Hash
93
+ raise "no response" unless env[:response].is_a? Faraday::Response
94
+ # raise "env not identical" unless env[:response].env.object_id == env.object_id
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ # RackCompatible + Rack::Cache
101
+ describe FaradayMiddleware::RackCompatible, 'caching' do
102
+ include FileUtils
103
+
104
+ CACHE_DIR = File.expand_path('../../tmp/cache', __FILE__)
105
+
106
+ before do
107
+ rm_r CACHE_DIR if File.exists? CACHE_DIR
108
+ # force reinitializing cache dirs
109
+ Rack::Cache::Storage.instance.clear
110
+
111
+ request_count = 0
112
+ response = lambda { |env|
113
+ [200, { 'Content-Type' => 'text/plain',
114
+ 'Cache-Control' => 'public, max-age=900',
115
+ },
116
+ "request:#{request_count+=1}"]
117
+ }
118
+
119
+ @conn = Faraday.new do |b|
120
+ b.use RackErrorsComplainer
121
+
122
+ b.use FaradayMiddleware::RackCompatible, Rack::Cache::Context,
123
+ :metastore => "file:#{CACHE_DIR}/rack/meta",
124
+ :entitystore => "file:#{CACHE_DIR}/rack/body",
125
+ :verbose => true
126
+
127
+ b.adapter :test do |stub|
128
+ stub.get('/', &response)
129
+ stub.post('/', &response)
130
+ end
131
+ end
132
+ end
133
+
134
+ extend Forwardable
135
+ def_delegators :@conn, :get, :post
136
+
137
+ it 'caches get requests' do
138
+ response = get('/', :user_agent => 'test')
139
+ expect(response.body).to eq('request:1')
140
+ expect(response.env[:method]).to eq(:get)
141
+ expect(response.status).to eq(200)
142
+
143
+ response = get('/', :user_agent => 'test')
144
+ expect(response.body).to eq('request:1')
145
+ expect(response['content-type']).to eq('text/plain')
146
+ expect(response.env[:method]).to eq(:get)
147
+ expect(response.env[:request].respond_to?(:fetch)).to be_true
148
+ expect(response.status). to eq(200)
149
+
150
+ expect(post('/').body).to eq('request:2')
151
+ end
152
+
153
+ it 'does not cache post requests' do
154
+ expect(get('/').body).to eq('request:1')
155
+ expect(post('/').body).to eq('request:2')
156
+ expect(post('/').body).to eq('request:3')
157
+ end
158
+
159
+ # middleware to check whether "rack.errors" is free of error reports
160
+ class RackErrorsComplainer < Struct.new(:app)
161
+ def call(env)
162
+ response = app.call(env)
163
+ error_stream = env[:rack_errors]
164
+ if error_stream.respond_to?(:string) && error_stream.string.include?('error')
165
+ raise %(unexpected error in 'rack.errors': %p) % error_stream.string
166
+ end
167
+ response
168
+ end
169
+ end
170
+ end