sawyer 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,42 @@
1
+ require 'yajl'
2
+
3
+ module Sawyer
4
+ class Response
5
+ attr_reader :agent,
6
+ :status,
7
+ :headers,
8
+ :data,
9
+ :rels
10
+
11
+ # Builds a Response after a completed request.
12
+ #
13
+ # agent - The Sawyer::Agent that is managing the API connection.
14
+ # res - A Faraday::Response.
15
+ def initialize(agent, res)
16
+ @agent = agent
17
+ @status = res.status
18
+ @headers = res.headers
19
+ @data = process_data(@agent.decode_body(res.body))
20
+ end
21
+
22
+ # Turns parsed contents from an API response into a Resource or
23
+ # collection of Resources.
24
+ #
25
+ # data - Either an Array or Hash parsed from JSON.
26
+ #
27
+ # Returns either a Resource or Array of Resources.
28
+ def process_data(data)
29
+ case data
30
+ when Hash then Resource.new(agent, data)
31
+ when Array then data.map { |hash| process_data(hash) }
32
+ when nil then nil
33
+ else
34
+ raise ArgumentError, "Unable to process #{data.inspect}. Want a Hash or Array"
35
+ end
36
+ end
37
+
38
+ def inspect
39
+ %(#<#{self.class}: #{@status} @rels=#{@rels.inspect} @data=#{@data.inspect}>)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,78 @@
1
+ ## This is the rakegem gemspec template. Make sure you read and understand
2
+ ## all of the comments. Some sections require modification, and others can
3
+ ## be deleted if you don't need them. Once you understand the contents of
4
+ ## this file, feel free to delete any comments that begin with two hash marks.
5
+ ## You can find comprehensive Gem::Specification documentation, at
6
+ ## http://docs.rubygems.org/read/chapter/20
7
+ Gem::Specification.new do |s|
8
+ s.specification_version = 2 if s.respond_to? :specification_version=
9
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
10
+ s.rubygems_version = '1.3.5'
11
+
12
+ ## Leave these as is they will be modified for you by the rake gemspec task.
13
+ ## If your rubyforge_project name is different, then edit it and comment out
14
+ ## the sub! line in the Rakefile
15
+ s.name = 'sawyer'
16
+ s.version = '0.0.1'
17
+ s.date = '2012-09-25'
18
+ s.rubyforge_project = 'sawyer'
19
+
20
+ ## Make sure your summary is short. The description may be as long
21
+ ## as you like.
22
+ s.summary = "Secret User Agent of HTTP"
23
+ s.description = "#{s.summary} built on Faraday"
24
+
25
+ ## List the primary authors. If there are a bunch of authors, it's probably
26
+ ## better to set the email to an email list or something. If you don't have
27
+ ## a custom homepage, consider using your GitHub URL or the like.
28
+ s.authors = ["Rick Olson"]
29
+ s.email = 'technoweenie@gmail.com'
30
+ s.homepage = 'https://github.com/technoweenie/sawyer'
31
+
32
+ ## This gets added to the $LOAD_PATH so that 'lib/NAME.rb' can be required as
33
+ ## require 'NAME.rb' or'/lib/NAME/file.rb' can be as require 'NAME/file.rb'
34
+ s.require_paths = %w[lib]
35
+
36
+ ## List your runtime dependencies here. Runtime dependencies are those
37
+ ## that are needed for an end user to actually USE your code.
38
+ s.add_dependency('faraday', ['~> 0.8.4'])
39
+ s.add_dependency('uri_template', ['~> 0.5.0'])
40
+ s.add_dependency('yajl-ruby', ['~> 1.1.0'])
41
+
42
+ ## List your development dependencies here. Development dependencies are
43
+ ## those that are only needed during development
44
+ #s.add_development_dependency('DEVDEPNAME', [">= 1.1.0", "< 2.0.0"])
45
+
46
+ ## Leave this section as-is. It will be automatically generated from the
47
+ ## contents of your Git repository via the gemspec task. DO NOT REMOVE
48
+ ## THE MANIFEST COMMENTS, they are used as delimiters by the task.
49
+ # = MANIFEST =
50
+ s.files = %w[
51
+ Gemfile
52
+ LICENSE.md
53
+ README.md
54
+ Rakefile
55
+ SPEC.md
56
+ example/client.rb
57
+ example/nigiri.schema.json
58
+ example/server.rb
59
+ example/user.schema.json
60
+ lib/sawyer.rb
61
+ lib/sawyer/agent.rb
62
+ lib/sawyer/relation.rb
63
+ lib/sawyer/resource.rb
64
+ lib/sawyer/response.rb
65
+ sawyer.gemspec
66
+ test/agent_test.rb
67
+ test/helper.rb
68
+ test/relation_test.rb
69
+ test/resource_test.rb
70
+ test/response_test.rb
71
+ ]
72
+ # = MANIFEST =
73
+
74
+ ## Test files will be grabbed from the file list. Make sure the path glob
75
+ ## matches what you actually use.
76
+ s.test_files = s.files.select { |path| path =~ /^test\/.*_test\.rb/ }
77
+ end
78
+
@@ -0,0 +1,60 @@
1
+ require File.expand_path("../helper", __FILE__)
2
+
3
+ module Sawyer
4
+ class AgentTest < TestCase
5
+ def setup
6
+ @stubs = Faraday::Adapter::Test::Stubs.new
7
+ @agent = Sawyer::Agent.new "http://foo.com/a/" do |conn|
8
+ conn.builder.handlers.delete(Faraday::Adapter::NetHttp)
9
+ conn.adapter :test, @stubs
10
+ end
11
+ end
12
+
13
+ def test_starts_a_session
14
+ @stubs.get '/a/' do |env|
15
+ assert_equal 'foo.com', env[:url].host
16
+
17
+ [200, {}, Yajl.dump(
18
+ :_links => {
19
+ :users => {:href => '/users'}})]
20
+ end
21
+
22
+ res = @agent.start
23
+
24
+ assert_equal 200, res.status
25
+ assert_kind_of Sawyer::Resource, resource = res.data
26
+
27
+ assert_equal '/users', resource.rels[:users].href
28
+ assert_equal :get, resource.rels[:users].method
29
+ end
30
+
31
+ def test_requests_with_body_and_options
32
+ @stubs.post '/a/b/c' do |env|
33
+ assert_equal '{"a":1}', env[:body]
34
+ assert_equal 'abc', env[:request_headers]['x-test']
35
+ assert_equal 'foo=bar', env[:url].query
36
+ [200, {}, "{}"]
37
+ end
38
+
39
+ res = @agent.call :post, 'b/c' , {:a => 1},
40
+ :headers => {"X-Test" => "abc"},
41
+ :query => {:foo => 'bar'}
42
+ assert_equal 200, res.status
43
+ end
44
+
45
+ def test_requests_with_body_and_options_to_get
46
+ @stubs.get '/a/b/c' do |env|
47
+ assert_nil env[:body]
48
+ assert_equal 'abc', env[:request_headers]['x-test']
49
+ assert_equal 'foo=bar', env[:url].query
50
+ [200, {}, "{}"]
51
+ end
52
+
53
+ res = @agent.call :get, 'b/c' , {:a => 1},
54
+ :headers => {"X-Test" => "abc"},
55
+ :query => {:foo => 'bar'}
56
+ assert_equal 200, res.status
57
+ end
58
+ end
59
+ end
60
+
@@ -0,0 +1,7 @@
1
+ require 'test/unit'
2
+ require File.expand_path('../../lib/sawyer', __FILE__)
3
+
4
+ class Sawyer::TestCase < Test::Unit::TestCase
5
+ def default_test
6
+ end
7
+ end
@@ -0,0 +1,109 @@
1
+ require File.expand_path("../helper", __FILE__)
2
+
3
+ module Sawyer
4
+ class RelationTest < TestCase
5
+ def test_builds_relation_from_hash
6
+ hash = {:href => '/users/1', :method => 'post'}
7
+ rel = Sawyer::Relation.from_link(nil, :self, hash)
8
+
9
+ assert_equal :self, rel.name
10
+ assert_equal '/users/1', rel.href
11
+ assert_equal :post, rel.method
12
+ assert_equal [:post], rel.available_methods.to_a
13
+ end
14
+
15
+ def test_builds_multiple_rels_from_multiple_methods
16
+ index = {
17
+ 'comments' => {:href => '/comments', :method => 'get,post'}
18
+ }
19
+
20
+ rels = Sawyer::Relation.from_links(nil, index)
21
+ assert_equal 1, rels.size
22
+ assert_equal [:comments], rels.keys
23
+
24
+ assert rel = rels[:comments]
25
+ assert_equal '/comments', rel.href
26
+ assert_equal :get, rel.method
27
+ assert_equal [:get, :post], rel.available_methods.to_a
28
+ end
29
+
30
+ def test_builds_rels_from_hash_index
31
+ index = {
32
+ 'self' => {:href => '/users/1'}
33
+ }
34
+
35
+ rels = Sawyer::Relation.from_links(nil, index)
36
+
37
+ assert_equal 1, rels.size
38
+ assert_equal [:self], rels.keys
39
+ assert rel = rels[:self]
40
+ assert_equal :self, rel.name
41
+ assert_equal '/users/1', rel.href
42
+ assert_equal :get, rel.method
43
+ assert_equal [:get], rel.available_methods.to_a
44
+ end
45
+
46
+ def test_builds_rels_from_nil
47
+ rels = Sawyer::Relation.from_links nil, nil
48
+ assert_equal 0, rels.size
49
+ assert_equal [], rels.keys
50
+ end
51
+
52
+ def test_relation_api_calls
53
+ agent = Sawyer::Agent.new "http://foo.com/a/" do |conn|
54
+ conn.builder.handlers.delete(Faraday::Adapter::NetHttp)
55
+ conn.adapter :test do |stubs|
56
+ stubs.get '/a/1' do
57
+ [200, {}, '{}']
58
+ end
59
+ stubs.delete '/a/1' do
60
+ [204, {}, '{}']
61
+ end
62
+ end
63
+ end
64
+
65
+ rel = Sawyer::Relation.new agent, :self, "/a/1", "get,put,delete"
66
+ assert_equal :get, rel.method
67
+ [:get, :put, :delete].each do |m|
68
+ assert rel.available_methods.include?(m), "#{m.inspect} is not available: #{rel.available_methods.inspect}"
69
+ end
70
+
71
+ assert_equal 200, rel.call.status
72
+ assert_equal 200, rel.call(:method => :head).status
73
+ assert_equal 204, rel.call(nil, :method => :delete).status
74
+ assert_raises ArgumentError do
75
+ rel.call nil, :method => :post
76
+ end
77
+
78
+ assert_equal 200, rel.head.status
79
+ assert_equal 200, rel.get.status
80
+ assert_equal 204, rel.delete.status
81
+
82
+ assert_raises ArgumentError do
83
+ rel.post
84
+ end
85
+ end
86
+
87
+ def test_relation_api_calls_with_uri_tempate
88
+ agent = Sawyer::Agent.new "http://foo.com/a/" do |conn|
89
+ conn.builder.handlers.delete(Faraday::Adapter::NetHttp)
90
+ conn.adapter :test do |stubs|
91
+ stubs.get '/octocat/hello' do |env|
92
+ assert_equal "a=1&b=2", env[:url].query
93
+ [200, {}, '{}']
94
+ end
95
+
96
+ stubs.get '/a' do
97
+ [404, {}, '{}']
98
+ end
99
+ end
100
+ end
101
+
102
+ rel = Sawyer::Relation.new agent, :repo, "{/user,repo}{?a,b}"
103
+
104
+ assert_equal 404, rel.get.status
105
+ assert_equal 200, rel.get(:uri => {'user' => 'octocat', 'repo' => 'hello', 'a' => 1, 'b' => 2}).status
106
+ end
107
+ end
108
+ end
109
+
@@ -0,0 +1,99 @@
1
+ require File.expand_path("../helper", __FILE__)
2
+
3
+ module Sawyer
4
+ class ResourceTest < TestCase
5
+ def test_accessible_keys
6
+ res = Resource.new :agent, :a => 1,
7
+ :_links => {:self => {:href => '/'}}
8
+
9
+ assert_equal 1, res.a
10
+ assert res.rels[:self]
11
+ assert_equal :agent, res.agent
12
+ assert_equal 1, res.fields.size
13
+ assert res.fields.include?(:a)
14
+ end
15
+
16
+ def test_clashing_keys
17
+ res = Resource.new :agent, :agent => 1, :rels => 2, :fields => 3,
18
+ :_links => {:self => {:href => '/'}}
19
+
20
+ assert_equal 1, res.agent
21
+ assert_equal 2, res.rels
22
+ assert_equal 3, res.fields
23
+
24
+ assert res._rels[:self]
25
+ assert_equal :agent, res._agent
26
+ assert_equal 3, res._fields.size
27
+ [:agent, :rels, :fields].each do |f|
28
+ assert res._fields.include?(f)
29
+ end
30
+ end
31
+
32
+ def test_nested_object
33
+ res = Resource.new :agent,
34
+ :user => {:id => 1, :_links => {:self => {:href => '/users/1'}}},
35
+ :_links => {:self => {:href => '/'}}
36
+
37
+ assert_equal '/', res.rels[:self].href
38
+ assert_kind_of Resource, res.user
39
+ assert_equal 1, res.user.id
40
+ assert_equal '/users/1', res.user.rels[:self].href
41
+ end
42
+
43
+ def test_nested_collection
44
+ res = Resource.new :agent,
45
+ :users => [{:id => 1, :_links => {:self => {:href => '/users/1'}}}],
46
+ :_links => {:self => {:href => '/'}}
47
+
48
+ assert_equal '/', res.rels[:self].href
49
+ assert_kind_of Array, res.users
50
+
51
+ assert user = res.users.first
52
+ assert_kind_of Resource, user
53
+ assert_equal 1, user.id
54
+ assert_equal '/users/1', user.rels[:self].href
55
+ end
56
+
57
+ def test_attribute_predicates
58
+ res = Resource.new :agent, :a => 1, :b => true, :c => nil, :d => false
59
+
60
+ assert res.a?
61
+ assert res.b?
62
+ assert !res.c?
63
+ assert !res.d?
64
+ end
65
+
66
+ def test_attribute_setter
67
+ res = Resource.new :agent, :a => 1
68
+ assert_equal 1, res.a
69
+ assert !res.key?(:b)
70
+
71
+ res.b = 2
72
+ assert_equal 2, res.b
73
+ assert res.key?(:b)
74
+ end
75
+
76
+ def test_dynamic_attribute_methods_from_getter
77
+ res = Resource.new :agent, :a => 1
78
+ assert res.key?(:a)
79
+ assert !res.respond_to?(:a)
80
+ assert !res.respond_to?(:a=)
81
+
82
+ assert_equal 1, res.a
83
+ assert res.respond_to?(:a)
84
+ assert res.respond_to?(:a=)
85
+ end
86
+
87
+ def test_dynamic_attribute_methods_from_setter
88
+ res = Resource.new :agent, :a => 1
89
+ assert !res.key?(:b)
90
+ assert !res.respond_to?(:b)
91
+ assert !res.respond_to?(:b=)
92
+
93
+ res.b = 1
94
+ assert res.key?(:b)
95
+ assert res.respond_to?(:b)
96
+ assert res.respond_to?(:b=)
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,54 @@
1
+ require File.expand_path("../helper", __FILE__)
2
+
3
+ module Sawyer
4
+ class ResponseTest < TestCase
5
+ def setup
6
+ @stubs = Faraday::Adapter::Test::Stubs.new
7
+ @agent = Sawyer::Agent.new "http://foo.com" do |conn|
8
+ conn.builder.handlers.delete(Faraday::Adapter::NetHttp)
9
+ conn.adapter :test, @stubs do |stub|
10
+ stub.get '/' do
11
+ [200, {'Content-Type' => 'application/json'}, Yajl.dump(
12
+ :a => 1,
13
+ :_links => {
14
+ :self => {:href => '/a', :method => 'POST'}
15
+ }
16
+ )]
17
+ end
18
+ end
19
+ end
20
+
21
+ @res = @agent.start
22
+ assert_kind_of Sawyer::Response, @res
23
+ end
24
+
25
+ def test_gets_status
26
+ assert_equal 200, @res.status
27
+ end
28
+
29
+ def test_gets_headers
30
+ assert_equal 'application/json', @res.headers['content-type']
31
+ end
32
+
33
+ def test_gets_body
34
+ assert_equal 1, @res.data.a
35
+ assert_equal [:a], @res.data.fields.to_a
36
+ end
37
+
38
+ def test_gets_rels
39
+ assert_equal '/a', @res.data.rels[:self].href
40
+ assert_equal :post, @res.data.rels[:self].method
41
+ end
42
+
43
+ def test_makes_request_from_relation
44
+ @stubs.post '/a' do
45
+ [201, {}, ""]
46
+ end
47
+
48
+ res = @res.data.rels[:self].call
49
+ assert_equal 201, res.status
50
+ assert_nil res.data
51
+ end
52
+ end
53
+ end
54
+