gemagent 0.0.1.pre

Sign up to get free protection for your applications and to get access to all the features.
data/CONTRIBUTORS ADDED
@@ -0,0 +1 @@
1
+ Ryan Stenhouse <ryan@ryanstenhouse.eu>
data/HACKING ADDED
@@ -0,0 +1,8 @@
1
+ The process for accepting patches is as follows:
2
+
3
+ 1. Fork the repository
4
+ 2. Make your changes (bonus points for feature branches)
5
+ 3. Have some tests for your changes
6
+ 4. Submit a pull request
7
+
8
+ Do not change the version number in the GemSpec.
data/LICENCE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2011 Ryan Stenhouse and CONTRIBUTORS
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ Gemagent
2
+ ========
3
+
4
+ By Ryan Stenhouse http://ryanstenhouse.eu
5
+
6
+ What is it?
7
+ -----------
8
+
9
+ Gemagent is a purely Standard Ruby implementation of a consumer of
10
+ the FreeAgent Central API.
11
+
12
+ The goal of this project was not to build a 'fast' API consumer, but
13
+ instead to build a 'correct' one. All published API features of the
14
+ FreeAgent application are implemented.
15
+
16
+ If it's fast, it's a bonus!
17
+
18
+ Installation
19
+ ------------
20
+
21
+ Install via rubygems:
22
+
23
+ $ gem install gemagent
24
+
25
+ It requires OpenSSL in order to create the HTTPS connection to the
26
+ FreeAgent API.
27
+
28
+ Extension
29
+ ---------
30
+
31
+ The main purpose of this gem was to allow me to become more familiar
32
+ with the FreeAgent API and to shake out some cobwebs when it came to
33
+ my knowledge of Ruby's Standard Library.
34
+
35
+ Because of this, some parts (like local data storage) are sub-optimal.
36
+
37
+ I have, however, build some abstraction on top of the data storage,
38
+ HTTP requests and XML parsing to allow for some or all of these
39
+ components to be replaced at a later date.
40
+
41
+ See the documentation online for more information.
42
+
43
+
@@ -0,0 +1,13 @@
1
+ # GemAgent API Interface
2
+ # Ryan Stenhouse, 20 January 2011
3
+
4
+ # Longhand representation of connecting to the FreeAgent API
5
+ #
6
+ ga = GemAgent::NetHttpConnection.new 'you.freeagentcentral.com', GemAgent::HttpBasicAuthentication.new('username','password')
7
+ ga.verify # => { :user_id => 1, :permission_level => 8, :company_type => UK_LIMITED }
8
+
9
+ # Sexy sugary version of the above.
10
+ #
11
+ GemAgent::Api.connect 'you.freeagentcentral.com', 'username', 'password' do |api|
12
+ api.verify # => { :user_id => 1, :permission_level => 8, :company_type => UK_LIMITED }
13
+ end
data/gemagent.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ summary = "GemAgent is a clean and light way to interact with the FreeAgent API. "
2
+ description = <<-TXT
3
+ GemAgent lets users of FreeAgent Central's online accounting software
4
+ to interact with the API simply and cleanly by only using functionality
5
+ provided by Ruby's Standard Library.
6
+ TXT
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = "gemagent"
10
+ spec.version = '0.0.1.pre'
11
+ spec.platform = Gem::Platform::RUBY
12
+ spec.files = Dir.glob("{bin,lib,.}/**/**/*") +
13
+ ["gemagent.rb","README.md","HACKING",'LICENCE','CONTRIBUTORS', "gemagent.gemspec"]
14
+ spec.require_path = "lib"
15
+ spec.required_ruby_version = '>= 1.8.4'
16
+ spec.required_rubygems_version = ">= 1.3.0"
17
+ spec.test_files = Dir[ "test/*_test.rb" ]
18
+ spec.has_rdoc = false
19
+ spec.author = "Ryan Stenhouse"
20
+ spec.email = "ryan@ryanstenhouse.eu"
21
+ spec.rubyforge_project = "gemagemt"
22
+ spec.homepage = "http://ryanstenhouse.eu"
23
+ spec.summary = summary
24
+ spec.description = description
25
+ end
data/gemagent.rb ADDED
@@ -0,0 +1,8 @@
1
+ GEMAGENT_ROOT = File.expand_path(File.dirname(__FILE__))
2
+ require GEMAGENT_ROOT + '/lib/connection.rb'
3
+ require GEMAGENT_ROOT + '/lib/authentication.rb'
4
+ require GEMAGENT_ROOT + '/lib/api_classes.rb'
5
+ require GEMAGENT_ROOT + '/lib/api_handler.rb'
6
+
7
+ module GemAgent
8
+ end
@@ -0,0 +1,36 @@
1
+ require "rexml/document"
2
+
3
+ module GemAgent
4
+ module Api
5
+
6
+ def self.connect(freeagent_url, username, password, connection = GemAgent::NetHttpConnection,
7
+ authenticator = GemAgent::HttpBasicAuthentication,
8
+ api_version = GemAgent::ApiHandler)
9
+ if !block_given?
10
+ raise "I need to have a block" and return
11
+ end
12
+ api = connection.new(freeagent_url, authenticator.new(username, password), api_version)
13
+ yield api
14
+ end
15
+
16
+ class ApiBase
17
+ def method
18
+ 'GET'
19
+ end
20
+
21
+ def path
22
+ end
23
+
24
+ def expected_status
25
+ '200'
26
+ end
27
+
28
+ end
29
+
30
+ class Verify < ApiBase
31
+ def path
32
+ '/verify'
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,28 @@
1
+ require File.dirname(__FILE__) + '/api_classes.rb'
2
+ module GemAgent
3
+ class ApiHandler
4
+
5
+ def initialize(connection)
6
+ @connection = connection
7
+ end
8
+
9
+ def verify
10
+ verify = GemAgent::Api::Verify.new
11
+ response = @connection.send_request(verify)
12
+ unless response.has_error?
13
+ {
14
+ :company_type => response.headers['company-type'],
15
+ :user_id => response.headers['user-id'].to_i,
16
+ :permission_level => response.headers['user-permission-level'].to_i
17
+ }
18
+ else
19
+ {
20
+ :error => response.headers[:error],
21
+ :body => response.body,
22
+ :company_type => 'ERROR'
23
+ }
24
+ end
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,23 @@
1
+ module GemAgent
2
+ class ApiAuthentication
3
+ def authenticate_for(obj)
4
+ end
5
+ end
6
+
7
+ class HttpBasicAuthentication < ApiAuthentication
8
+
9
+ def initialize(username, password)
10
+ @username = username
11
+ @password = password
12
+ end
13
+
14
+ def authenticate_for(obj)
15
+ if obj.respond_to?(:basic_auth)
16
+ obj.basic_auth @username, @password
17
+ else
18
+ raise "Can't do basic authentication with this, I expect a NetHTTP request"
19
+ end
20
+ end
21
+
22
+ end
23
+ end
data/lib/connection.rb ADDED
@@ -0,0 +1,116 @@
1
+ require 'net/https'
2
+ require 'uri'
3
+
4
+ module GemAgent
5
+
6
+ # ConnectionMethod implements the basic interface all child
7
+ # classes must implement to allow connection to the FreeAgent
8
+ # API.
9
+ #
10
+ class ConnectionMethod
11
+
12
+ attr_reader :freeagent_url
13
+ attr_reader :api
14
+ attr_reader :authenticator
15
+
16
+ @@method_map = {}
17
+
18
+ def initialize(freeagent_url, authenticator, api_handler = GemAgent::ApiHandler)
19
+ @freeagent_url = freeagent_url
20
+ @authenticator = authenticator
21
+ @api = api_handler.new(self)
22
+ end
23
+
24
+ def send_request(request)
25
+ raise "Subclasses of ConnectionMethod must implement their own send_request method"
26
+ end
27
+
28
+ def wrap_response(response)
29
+ raise "Subclasses of ConnectionMethod must implement their own wrap_response method"
30
+ end
31
+
32
+ # Proxies all undefined method to the API handler
33
+ # associated with the connection.
34
+ #
35
+ def method_missing(method, *args)
36
+ unless args.empty?
37
+ @api.send(method, args)
38
+ else
39
+ @api.send(method)
40
+ end
41
+ end
42
+ end
43
+
44
+ # The ResponseWrapper is used to present a consistant way
45
+ # for the various API classes to process messages returned
46
+ # by the API server.
47
+ #
48
+ # If you write your own ConnectionMethod subclass, ensure that
49
+ # your send_request method returns a ResponseWrapper correctly
50
+ # set with the correct values for headers and body.
51
+ #
52
+ class ResponseWrapper
53
+ attr_reader :headers, :body
54
+ def initialize(headers, body)
55
+ @headers = headers
56
+ @body = body
57
+ end
58
+
59
+ def has_error?
60
+ !headers[:error].nil?
61
+ end
62
+ end
63
+
64
+ # NetHttpConnection is the default method to connect to the
65
+ # FreeAgent API. It uses the Standard Ruby library net/http
66
+ # to create an SSL connection to the FreeAgent server specified
67
+ # by +@freeagent_url+ and authenticates your request with the
68
+ # ApiAuthentication subclass you pass thorugh as +authenticator+.
69
+ #
70
+ # The last last optional value takes a API Handler class, which
71
+ # defaults to the standard one which ships with this gem.
72
+ #
73
+ class NetHttpConnection < ConnectionMethod
74
+
75
+ @@method_map = {
76
+ 'GET' => Net::HTTP::Get,
77
+ 'POST' => Net::HTTP::Post,
78
+ 'PUT' => Net::HTTP::Put,
79
+ 'DELETE' => Net::HTTP::Delete
80
+ }
81
+
82
+ # Sends the +request+ to +@freeagent_url+ over HTTPS. The class
83
+ # instance variable +@@method_map+ maps each HTTP verb required
84
+ # to the correct class for instantiation.
85
+ #
86
+ def send_request(request)
87
+ https = Net::HTTP.new(@freeagent_url, Net::HTTP.https_default_port)
88
+ https.use_ssl = true
89
+ https.verify_mode = OpenSSL::SSL::VERIFY_NONE
90
+ req = @@method_map[request.method].new(request.path)
91
+ req['content-type'] = 'application/xml'
92
+ req['accept'] = 'application/xml'
93
+ authenticator.authenticate_for req
94
+ resp = nil
95
+ https.start do |http|
96
+ resp = http.request(req)
97
+ end
98
+ if resp.code == request.expected_status
99
+ wrap_response(resp)
100
+ else
101
+ ResponseWrapper.new({ :error => resp.code, :status => resp.code }, resp.body)
102
+ end
103
+ end
104
+
105
+ # Wraps the response from net/http in a ResponseWrapper object
106
+ # so the API classes are able to work with it to do their work.
107
+ #
108
+ def wrap_response(response)
109
+ headers = {}
110
+ response.each_header { |k,v| headers[k] = v }
111
+ ResponseWrapper.new(headers, response.body)
112
+ end
113
+
114
+ end
115
+
116
+ end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gemagent
3
+ version: !ruby/object:Gem::Version
4
+ hash: 961915968
5
+ prerelease: 6
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ - pre
11
+ version: 0.0.1.pre
12
+ platform: ruby
13
+ authors:
14
+ - Ryan Stenhouse
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2011-04-29 00:00:00 +01:00
20
+ default_executable:
21
+ dependencies: []
22
+
23
+ description: " GemAgent lets users of FreeAgent Central's online accounting software\n to interact with the API simply and cleanly by only using functionality\n provided by Ruby's Standard Library.\n"
24
+ email: ryan@ryanstenhouse.eu
25
+ executables: []
26
+
27
+ extensions: []
28
+
29
+ extra_rdoc_files: []
30
+
31
+ files:
32
+ - lib/api_classes.rb
33
+ - lib/api_handler.rb
34
+ - lib/authentication.rb
35
+ - lib/connection.rb
36
+ - ./CONTRIBUTORS
37
+ - ./example/example.rb
38
+ - ./gemagent.gemspec
39
+ - ./gemagent.rb
40
+ - ./HACKING
41
+ - ./lib/api_classes.rb
42
+ - ./lib/api_handler.rb
43
+ - ./lib/authentication.rb
44
+ - ./lib/connection.rb
45
+ - ./LICENCE
46
+ - ./README.md
47
+ - gemagent.rb
48
+ - README.md
49
+ - HACKING
50
+ - LICENCE
51
+ - CONTRIBUTORS
52
+ - gemagent.gemspec
53
+ has_rdoc: true
54
+ homepage: http://ryanstenhouse.eu
55
+ licenses: []
56
+
57
+ post_install_message:
58
+ rdoc_options: []
59
+
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ hash: 63
68
+ segments:
69
+ - 1
70
+ - 8
71
+ - 4
72
+ version: 1.8.4
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ hash: 27
79
+ segments:
80
+ - 1
81
+ - 3
82
+ - 0
83
+ version: 1.3.0
84
+ requirements: []
85
+
86
+ rubyforge_project: gemagemt
87
+ rubygems_version: 1.6.1
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: GemAgent is a clean and light way to interact with the FreeAgent API.
91
+ test_files: []
92
+