Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add Request

  • Loading branch information...
commit 70c4be1ef872b3dbe322a02619848a4fd603a671 1 parent 22c0cdd
@avdi authored
View
6 Gemfile
@@ -1,3 +1,9 @@
source 'http://rubygems.org'
gemspec
+
+# I fear there's no reasonable way to do conditional dependencies like this in
+# a gemspec.
+gem 'rb-inotify' if RUBY_PLATFORM =~ /linux/i
+gem 'libnotify' if RUBY_PLATFORM =~ /linux/i
+
View
22 Gemfile.lock
@@ -4,6 +4,7 @@ PATH
leadlight (0.0.1)
faraday
fattr
+ hookr
link_header
mime-types
multi_json
@@ -13,16 +14,31 @@ GEM
specs:
addressable (2.2.6)
diff-lcs (1.1.3)
+ fail-fast (1.0.0)
faraday (0.7.5)
addressable (~> 2.2.6)
multipart-post (~> 1.1.3)
rack (< 2, >= 1.1.0)
fattr (2.2.0)
+ ffi (1.0.11)
+ guard (0.10.0)
+ ffi (>= 0.5.0)
+ thor (~> 0.14.6)
+ guard-bundler (0.1.3)
+ bundler (>= 1.0.0)
+ guard (>= 0.2.2)
+ guard-rspec (0.6.0)
+ guard (>= 0.10.0)
+ hookr (1.1.1)
+ fail-fast (= 1.0.0)
+ libnotify (0.7.1)
link_header (0.0.5)
mime-types (1.17.2)
multi_json (1.0.4)
multipart-post (1.1.4)
rack (1.4.0)
+ rb-inotify (0.8.8)
+ ffi (>= 0.5.0)
rspec (2.7.0)
rspec-core (~> 2.7.0)
rspec-expectations (~> 2.7.0)
@@ -31,12 +47,18 @@ GEM
rspec-expectations (2.7.0)
diff-lcs (~> 1.1.2)
rspec-mocks (2.7.0)
+ thor (0.14.6)
vcr (2.0.0.rc1)
PLATFORMS
ruby
DEPENDENCIES
+ guard
+ guard-bundler
+ guard-rspec
leadlight!
+ libnotify
+ rb-inotify
rspec
vcr (~> 2.0.0.rc1)
View
19 Guardfile
@@ -0,0 +1,19 @@
+# A sample Guardfile
+# More info at https://github.com/guard/guard#readme
+
+guard 'rspec', :version => 2 do
+ watch(%r{^spec/.+_spec\.rb$})
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
+ watch('spec/spec_helper.rb') { "spec" }
+
+ # Rails example
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
+ watch('config/routes.rb') { "spec/routing" }
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
+ # Capybara request specs
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
+end
+
View
4 leadlight.gemspec
@@ -46,12 +46,16 @@ Gem::Specification.new do |s|
s.add_dependency 'link_header'
s.add_dependency 'multi_json'
s.add_dependency 'mime-types'
+ s.add_dependency 'hookr'
## List your development dependencies here. Development dependencies are
## those that are only needed during development
## s.add_development_dependency('DEVDEPNAME', [">= 1.1.0", "< 2.0.0"])
s.add_development_dependency 'rspec'
s.add_development_dependency 'vcr', '~> 2.0.0.rc1'
+ s.add_development_dependency 'guard'
+ s.add_development_dependency 'guard-rspec'
+ s.add_development_dependency 'guard-bundler'
## Leave this section as-is. It will be automatically generated from the
## contents of your Git repository via the gemspec task. DO NOT REMOVE
View
56 lib/leadlight/request.rb
@@ -0,0 +1,56 @@
+require 'monitor'
+require 'fattr'
+require 'hookr'
+
+module Leadlight
+ class Request
+ include HookR::Hooks
+ include MonitorMixin
+
+ fattr(:http_method)
+ fattr(:url)
+ fattr(:connection)
+ fattr(:body)
+
+ define_hook :on_prepare_request, :request
+ define_hook :on_complete, :response
+
+ def initialize(connection, url, method, body=nil)
+ self.connection = connection
+ self.url = url
+ self.http_method = method
+ self.body = body
+ @completed = new_cond
+ @state = :initialized
+ @env = nil
+ super
+ end
+
+ def submit
+ connection.run_request(http_method, url, body, {}) do |request|
+ execute_hook(:on_prepare_request, request)
+ end.on_complete do |env|
+ execute_hook :on_complete, Faraday::Response.new(env)
+ @env = env
+ synchronize do
+ @state = :completed
+ @completed.broadcast
+ end
+ end
+ end
+
+ def wait
+ synchronize do
+ @completed.wait_until{:completed == @state}
+ end
+ yield(@env.fetch(:leadlight_representation)) if block_given?
+ self
+ end
+
+ def submit_and_wait(&block)
+ submit
+ wait(&block)
+ end
+ alias_method :then, :submit_and_wait
+ end
+end
View
210 spec/leadlight/request_spec.rb
@@ -0,0 +1,210 @@
+require 'spec_helper_lite'
+require 'leadlight/request'
+require 'timeout'
+
+module Leadlight
+ describe Request do
+ include Timeout
+
+
+ # The Faraday connection API works like this:
+ #
+ # connection.run_request(:get, ...).on_complete do |env|
+ # ...
+ # end
+ #
+ # TODO stick a facade over Faraday instead of stubbing stuff I
+ # don't own
+ class FakeFaradayResponse
+ fattr(:completion_handlers) { Queue.new }
+ attr_reader :env
+
+ def initialize(env)
+ @env = env
+ end
+
+ def on_complete(&block)
+ completion_handlers << block
+ end
+
+ def run_completion_handlers(n=1)
+ n.times do
+ completion_handlers.pop.call(@env)
+ end
+ end
+ end
+
+ subject { Request.new(connection, url, http_method, body) }
+ let(:connection) { stub(:connection, :run_request => faraday_response) }
+ let(:url) { stub(:url) }
+ let(:http_method){ :get }
+ let(:body) { stub(:body) }
+ let(:faraday_request) {stub(:faraday_request)}
+ let(:on_complete_handlers) { [] }
+ let(:faraday_response) { FakeFaradayResponse.new(faraday_env) }
+ let(:faraday_env) { {:leadlight_representation => representation} }
+ let(:representation) { stub(:representation) }
+
+ def run_completion_handlers
+ faraday_response.run_completion_handlers
+ end
+
+ def do_it_and_complete(&block)
+ t = Thread.new do
+ do_it(&block)
+ end
+ run_completion_handlers
+ t.join.value
+ end
+
+ context "for GET" do
+ let(:http_method) { :get }
+
+ its(:http_method) { should eq(:get) }
+ end
+
+
+ context "for POST" do
+ let(:http_method) { :post }
+
+ its(:http_method) { should eq(:post) }
+ end
+
+ describe "#submit" do
+ it "starts a request runnning" do
+ connection.should_receive(:run_request).
+ with(http_method, url, body, {}).
+ and_return(faraday_response)
+ subject.submit
+ end
+
+ it "triggers the on_prepare_request hook in the block passed to #run_request" do
+ yielded = :nothing
+ faraday_request = stub
+ connection.stub(:run_request).
+ and_yield(faraday_request).
+ and_return(faraday_response)
+ subject.on_prepare_request do |request|
+ yielded = request
+ end
+ subject.submit
+ yielded.should equal(faraday_request)
+ end
+
+ end
+
+ shared_examples_for "synchronous methods" do
+ it "returns once the request has completed" do
+ timeout(1) do
+ trace = Queue.new
+ thread = Thread.new do
+ do_it
+ trace << "wait finished"
+ end
+ trace << "completing request"
+ faraday_response.run_completion_handlers
+ thread.join
+ trace << "request completed"
+ trace.pop.should eq("completing request")
+ trace.pop.should eq("wait finished")
+ trace.pop.should eq("request completed")
+ end
+ end
+ end
+
+ describe "#wait" do
+ context "before a submit" do
+ it "doesn't return until after the submit" do
+ timeout(1) do
+ trace = Queue.new
+ thread = Thread.new do
+ subject.wait
+ trace << "wait finished"
+ end
+ trace << "submit"
+ subject.submit
+ trace << "completing request"
+ faraday_response.run_completion_handlers
+ thread.join
+ trace << "request completed"
+ trace.pop.should eq("submit")
+ trace.pop.should eq("completing request")
+ trace.pop.should eq("wait finished")
+ trace.pop.should eq("request completed")
+ end
+ end
+ end
+
+ context "after a submit" do
+ before do
+ subject.submit
+ end
+
+ def do_it
+ subject.wait
+ end
+
+ it_should_behave_like "synchronous methods"
+
+ it "returns self" do
+ do_it_and_complete.should equal(subject)
+ end
+ end
+
+ end
+
+ describe "#submit_and_wait" do
+ def do_it(&block)
+ subject.submit_and_wait(&block)
+ end
+
+ it_should_behave_like "synchronous methods"
+
+ it "returns self" do
+ do_it_and_complete.should equal(subject)
+ end
+
+ it "yields the response representation" do
+ yielded = :nothing
+ do_it_and_complete do |rep|
+ yielded = rep
+ end
+ yielded.should equal(representation)
+ end
+ end
+
+ describe "#on_complete" do
+ def submit_and_complete
+ t = Thread.new do
+ subject.submit
+ subject.wait
+ end
+ run_completion_handlers
+ t.join
+ end
+
+ it "queues hooks to be run on completion" do
+ run_hooks = []
+ subject.on_complete do |response|
+ run_hooks << "hook 1"
+ end
+ subject.on_complete do |response|
+ run_hooks << "hook 2"
+ end
+ submit_and_complete
+ run_hooks.should eq(["hook 1", "hook 2"])
+ end
+
+ it "calls hooks with the faraday response" do
+ Faraday::Response.should_receive(:new).with(faraday_env).
+ and_return(faraday_response)
+ yielded = :nothing
+ subject.on_complete do |response|
+ yielded = response
+ end
+ submit_and_complete
+ yielded.should equal(faraday_response)
+ end
+ end
+ end
+end
View
16 spec/leadlight/service_spec.rb
@@ -3,14 +3,14 @@
module Leadlight
describe Service do
- subject { klass.new(options) }
- let(:klass) { Class.new do include Service end }
- let(:connection) { stub(:connection, get: response) }
- let(:representation) { stub(:representation) }
- let(:response) { stub(:response, env: env) }
- let(:env) { {leadlight_representation: representation} }
- let(:options) { {codec: codec} }
- let(:codec) { stub(:codec) }
+ subject { klass.new(options) }
+ let(:klass) { Class.new do include Service end }
+ let(:connection) { stub(:connection, get: response) }
+ let(:representation) { stub(:representation) }
+ let(:response) { stub(:response, env: env) }
+ let(:env) { {leadlight_representation: representation} }
+ let(:options) { {codec: codec} }
+ let(:codec) { stub(:codec) }
before do
subject.stub(connection: connection, url: nil)
Please sign in to comment.
Something went wrong with that request. Please try again.