sawyer 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.
@@ -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
+