kelredd-wesabe 0.0.2
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.
- data/README.rdoc +39 -0
- data/Rakefile +41 -0
- data/lib/wesabe/configuration.rb +5 -0
- data/lib/wesabe/exceptions.rb +8 -0
- data/lib/wesabe/extensions.rb +60 -0
- data/lib/wesabe/model/account.rb +50 -0
- data/lib/wesabe/model/base.rb +136 -0
- data/lib/wesabe/model/institution.rb +16 -0
- data/lib/wesabe/model/merchant.rb +16 -0
- data/lib/wesabe/model/txaction.rb +38 -0
- data/lib/wesabe/model.rb +3 -0
- data/lib/wesabe/version.rb +13 -0
- data/lib/wesabe.rb +4 -0
- data/test/test_helper.rb +10 -0
- data/test/unit/wesabe_test.rb +13 -0
- metadata +90 -0
data/README.rdoc
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
= Wesabe
|
2
|
+
|
3
|
+
== Description
|
4
|
+
|
5
|
+
A simplistic gem to assist in consuming the Wesabe API.
|
6
|
+
|
7
|
+
== Installation
|
8
|
+
|
9
|
+
sudo gem install kelredd-wesabe --source http://gems.github.com
|
10
|
+
|
11
|
+
== Usage
|
12
|
+
|
13
|
+
require 'wesabe'
|
14
|
+
# then include any wesabe helpers into your own models or scripts
|
15
|
+
|
16
|
+
== License
|
17
|
+
|
18
|
+
Copyright (c) 2009 Kelly Redding
|
19
|
+
|
20
|
+
Permission is hereby granted, free of charge, to any person
|
21
|
+
obtaining a copy of this software and associated documentation
|
22
|
+
files (the "Software"), to deal in the Software without
|
23
|
+
restriction, including without limitation the rights to use,
|
24
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
25
|
+
copies of the Software, and to permit persons to whom the
|
26
|
+
Software is furnished to do so, subject to the following
|
27
|
+
conditions:
|
28
|
+
|
29
|
+
The above copyright notice and this permission notice shall be
|
30
|
+
included in all copies or substantial portions of the Software.
|
31
|
+
|
32
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
33
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
34
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
35
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
36
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
37
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
38
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
39
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
require 'lib/wesabe/version'
|
6
|
+
|
7
|
+
task :default => :test
|
8
|
+
|
9
|
+
spec = Gem::Specification.new do |s|
|
10
|
+
s.name = 'wesabe'
|
11
|
+
s.version = Wesabe::Version.to_s
|
12
|
+
s.has_rdoc = true
|
13
|
+
s.extra_rdoc_files = %w(README.rdoc)
|
14
|
+
s.rdoc_options = %w(--main README.rdoc)
|
15
|
+
s.summary = "A simplistic gem to assist in consuming the Wesabe API."
|
16
|
+
s.author = 'Kelly Redding'
|
17
|
+
s.email = 'kelly@kelredd.com'
|
18
|
+
s.homepage = ''
|
19
|
+
s.files = %w(README.rdoc Rakefile) + Dir.glob("{lib,test}/**/*")
|
20
|
+
# s.executables = ['wesabe']
|
21
|
+
|
22
|
+
s.add_dependency('nokogiri', '> 1.2.3')
|
23
|
+
s.add_dependency('rest-client', '> 0.9.2')
|
24
|
+
end
|
25
|
+
|
26
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
27
|
+
pkg.gem_spec = spec
|
28
|
+
end
|
29
|
+
|
30
|
+
Rake::TestTask.new do |t|
|
31
|
+
t.libs << 'test'
|
32
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
33
|
+
t.verbose = true
|
34
|
+
end
|
35
|
+
|
36
|
+
desc 'Generate the gemspec to serve this Gem from Github'
|
37
|
+
task :github do
|
38
|
+
file = File.dirname(__FILE__) + "/#{spec.name}.gemspec"
|
39
|
+
File.open(file, 'w') {|f| f << spec.to_ruby }
|
40
|
+
puts "Created gemspec: #{file}"
|
41
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
module Wesabe
|
4
|
+
module Extensions
|
5
|
+
module String
|
6
|
+
|
7
|
+
module ClassMethods; end
|
8
|
+
def self.included(klass)
|
9
|
+
klass.extend(ClassMethods) if klass.kind_of?(Class)
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_datetime
|
16
|
+
DateTime.strptime(self) rescue nil
|
17
|
+
end
|
18
|
+
def to_date
|
19
|
+
Date.strptime(self) rescue nil
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module Wesabe
|
27
|
+
module Extensions
|
28
|
+
module Hash
|
29
|
+
|
30
|
+
module ClassMethods; end
|
31
|
+
def self.included(klass)
|
32
|
+
klass.extend(ClassMethods) if klass.kind_of?(Class)
|
33
|
+
end
|
34
|
+
|
35
|
+
module ClassMethods
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns string formatted for HTTP URL encoded name-value pairs.
|
39
|
+
# For example,
|
40
|
+
# {:id => 'thomas_hardy'}.to_http_str
|
41
|
+
# # => "id=thomas_hardy"
|
42
|
+
# {:id => 23423, :since => Time.now}.to_http_str
|
43
|
+
# # => "since=Thu,%2021%20Jun%202007%2012:10:05%20-0500&id=23423"
|
44
|
+
def to_http_query_str(opts = {})
|
45
|
+
opts[:prepend] ||= '?'
|
46
|
+
opts[:append] ||= ''
|
47
|
+
self.empty? ? '' : "#{opts[:prepend]}#{self.collect{|key, val| "#{key.to_s}=#{CGI.escape(val.to_s)}"}.join('&')}#{opts[:append]}"
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class String
|
55
|
+
include Wesabe::Extensions::String
|
56
|
+
end
|
57
|
+
|
58
|
+
class Hash
|
59
|
+
include Wesabe::Extensions::Hash
|
60
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
%w(base institution).each do |file|
|
2
|
+
require File.join(File.dirname(__FILE__), "#{file}.rb")
|
3
|
+
end
|
4
|
+
|
5
|
+
module Wesabe
|
6
|
+
module Model
|
7
|
+
class Account < Wesabe::Model::Base
|
8
|
+
|
9
|
+
def self.find(id)
|
10
|
+
case id
|
11
|
+
when :all
|
12
|
+
find_collection("/accounts", "//accounts/account")
|
13
|
+
else
|
14
|
+
super("/accounts/#{id}", "//account")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
attribute :id, :integer, :path => "id"
|
19
|
+
attribute :key, :string, :path => "guid"
|
20
|
+
attribute :number, :string, :path => "account-number"
|
21
|
+
attribute :name, :string, :path => "name"
|
22
|
+
attribute :account_type, :string, :path => "account-type"
|
23
|
+
attribute :balance, :float, :path => "current-balance"
|
24
|
+
attribute :last_uploaded_at, :datetime, :path => "last-uploaded-at"
|
25
|
+
attribute :oldest_transaction_on, :date, :path => "oldest-txaction"
|
26
|
+
attribute :newest_transaction_on, :date, :path => "newest-txaction"
|
27
|
+
|
28
|
+
def institution
|
29
|
+
@institution ||= Wesabe::Model::Institution.new(get_node('./financial-institution'))
|
30
|
+
end
|
31
|
+
|
32
|
+
def currency
|
33
|
+
node = get_node('./currency')
|
34
|
+
@currency ||= {
|
35
|
+
:symbol => node['symbol'],
|
36
|
+
:delimiter => node['delimiter'],
|
37
|
+
:separator => node['separator'],
|
38
|
+
:decimal_places => node['decimal_places'],
|
39
|
+
:type => node.content.to_s
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_s
|
44
|
+
self.id
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
%w(rubygems rest_client nokogiri).each do |lib|
|
2
|
+
require lib
|
3
|
+
end
|
4
|
+
%w(configuration exceptions extensions).each do |file|
|
5
|
+
require File.join(File.dirname(__FILE__), "..", "#{file}.rb")
|
6
|
+
end
|
7
|
+
|
8
|
+
module Wesabe
|
9
|
+
module Model
|
10
|
+
|
11
|
+
class Base
|
12
|
+
@@user = nil
|
13
|
+
@@password = nil
|
14
|
+
@@content_type = Wesabe::API_DEFAULT_CONTENT_TYPE
|
15
|
+
|
16
|
+
def self.resource
|
17
|
+
RestClient::Resource.new(Wesabe::API_SITE, :user => @@user, :password => @@password, :content_type => @@content_type)
|
18
|
+
end
|
19
|
+
@@api = resource
|
20
|
+
@@api_cache = {}
|
21
|
+
|
22
|
+
attr_reader :xml
|
23
|
+
|
24
|
+
def self.configure(opts={})
|
25
|
+
@@user = opts[:user]
|
26
|
+
@@password = opts[:password]
|
27
|
+
@@content_type = opts[:content_type] if opts[:content_type] && Wesabe::API_CONTENT_TYPES.include?(opts[:content_type])
|
28
|
+
@@api = resource
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.find(path, xpath)
|
32
|
+
new(get_xml(path).xpath(xpath))
|
33
|
+
end
|
34
|
+
def self.find_collection(path, xpath)
|
35
|
+
get_xml(path).xpath(xpath).collect{|item_xml| new(item_xml)}
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize(xml)
|
39
|
+
@xml = xml
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def self.get_xml(path)
|
45
|
+
self.resource_xml(:get, path)
|
46
|
+
end
|
47
|
+
def self.resource_xml(verb, path, force=false)
|
48
|
+
summary = "#{verb.to_s.upcase} #{@@api.url}#{path}"
|
49
|
+
key = cache_key(verb, path)
|
50
|
+
begin
|
51
|
+
resp = @@api_cache[key]
|
52
|
+
if resp.nil? || force
|
53
|
+
base_config_check
|
54
|
+
p "** Wesabe API: #{summary}"
|
55
|
+
resp = case verb.to_sym
|
56
|
+
when :get
|
57
|
+
@@api["#{path}"].get
|
58
|
+
end
|
59
|
+
@@api_cache[key] = resp
|
60
|
+
else
|
61
|
+
p "** Wesabe API: [cache] #{summary}."
|
62
|
+
end
|
63
|
+
rescue Exception => err
|
64
|
+
raise Wesabe::ResourceAPIError, "error with API resource: #{summary}: #{err.message}"
|
65
|
+
end
|
66
|
+
begin
|
67
|
+
xml = Nokogiri::XML(resp.to_s)
|
68
|
+
rescue Exception => err
|
69
|
+
raise Wesabe::ResourceParseError, "error parsing API resource [#{@@content_type}]: #{summary}: #{err.message}: Response: #{resp.to_s}"
|
70
|
+
end
|
71
|
+
xml
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.attribute(name, type, config)
|
75
|
+
raise Wesabe::NotConfigured, "no path provided for selecting the attribute '#{name}'." unless config[:path]
|
76
|
+
content_method = case type.to_sym
|
77
|
+
when :string
|
78
|
+
'to_s'
|
79
|
+
when :integer
|
80
|
+
'to_i'
|
81
|
+
when :float
|
82
|
+
'to_f'
|
83
|
+
when :date
|
84
|
+
'to_date'
|
85
|
+
when :datetime
|
86
|
+
'to_datetime'
|
87
|
+
else
|
88
|
+
'to_s'
|
89
|
+
end
|
90
|
+
define_method(name) do
|
91
|
+
instance_variable_get("@#{name}") || instance_variable_set("@#{name}", get_node("./#{config[:path]}").content.send(content_method))
|
92
|
+
end
|
93
|
+
end
|
94
|
+
def self.get_node(xml, path)
|
95
|
+
xml.xpath(path.to_s).first
|
96
|
+
end
|
97
|
+
def get_node(path)
|
98
|
+
self.class.get_node(@xml, path)
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.xml_root_name(xml)
|
102
|
+
xml.root.name
|
103
|
+
end
|
104
|
+
def xml_root_name
|
105
|
+
self.class.xml_root_name(@xml)
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.cache_key(path, verb)
|
109
|
+
"#{verb}_#{path}"
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.clear_cache
|
113
|
+
@@api_cache = {}
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.base_config_check
|
117
|
+
raise Wesabe::NotConfigured, "No user provided to access the Wesabe API" if blank?(@@user)
|
118
|
+
raise Wesabe::NotConfigured, "No password provided to access the Wesabe API" if blank?(@@password)
|
119
|
+
raise Wesabe::NotConfigured, "Wesabe not configured to access the API." if blank?(@@api)
|
120
|
+
end
|
121
|
+
def base_config_check
|
122
|
+
self.class.base_config_check
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.blank?(value)
|
126
|
+
value.nil? || (value.respond_to?('empty?') ? value.empty? : false)
|
127
|
+
end
|
128
|
+
def blank?(value)
|
129
|
+
self.class.blank?(value)
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
%w(base).each do |file|
|
2
|
+
require File.join(File.dirname(__FILE__), "#{file}.rb")
|
3
|
+
end
|
4
|
+
|
5
|
+
module Wesabe
|
6
|
+
module Model
|
7
|
+
|
8
|
+
class Institution < Wesabe::Model::Base
|
9
|
+
|
10
|
+
attribute :key, :string, :path => "id"
|
11
|
+
attribute :name, :string, :path => "name"
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
%w(base).each do |file|
|
2
|
+
require File.join(File.dirname(__FILE__), "#{file}.rb")
|
3
|
+
end
|
4
|
+
|
5
|
+
module Wesabe
|
6
|
+
module Model
|
7
|
+
|
8
|
+
class Merchant < Wesabe::Model::Base
|
9
|
+
|
10
|
+
attribute :key, :string, :path => "id"
|
11
|
+
attribute :name, :string, :path => "name"
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
%w(base account merchant).each do |file|
|
2
|
+
require File.join(File.dirname(__FILE__), "#{file}.rb")
|
3
|
+
end
|
4
|
+
|
5
|
+
module Wesabe
|
6
|
+
module Model
|
7
|
+
class Txaction < Wesabe::Model::Base
|
8
|
+
|
9
|
+
def self.find(opts={})
|
10
|
+
acct = opts.delete(:account)
|
11
|
+
path = (acct ? "/accounts/#{acct.to_s}.xml" : "/transactions.xml")
|
12
|
+
path += opts.to_http_query_str if opts.respond_to?('to_http_query_str')
|
13
|
+
find_collection(path, "//txactions/txaction")
|
14
|
+
end
|
15
|
+
|
16
|
+
attribute :key, :string, :path => "guid"
|
17
|
+
attribute :account_id, :string, :path => "account-id"
|
18
|
+
attribute :date, :date, :path => "date"
|
19
|
+
attribute :original_date, :date, :path => "original-date"
|
20
|
+
attribute :amount, :float, :path => "amount"
|
21
|
+
attribute :display_name, :string, :path => "display-name"
|
22
|
+
attribute :raw_name, :string, :path => "raw-name"
|
23
|
+
attribute :raw_type, :string, :path => "raw-txntype"
|
24
|
+
attribute :memo, :string, :path => "memo"
|
25
|
+
attribute :transfer_key, :string, :path => "transfer/guid"
|
26
|
+
|
27
|
+
def account
|
28
|
+
@account ||= Wesabe::Model::Account.find(self.account_id)
|
29
|
+
end
|
30
|
+
|
31
|
+
def merchant
|
32
|
+
@merchant ||= (get_node('./merchant') ? Wesabe::Model::Merchant.new(get_node('./merchant')) : nil)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
data/lib/wesabe/model.rb
ADDED
data/lib/wesabe.rb
ADDED
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kelredd-wesabe
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kelly Redding
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-06-15 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: nokogiri
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.2.3
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rest-client
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.9.2
|
34
|
+
version:
|
35
|
+
description:
|
36
|
+
email: kelly@kelredd.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- README.rdoc
|
43
|
+
files:
|
44
|
+
- README.rdoc
|
45
|
+
- Rakefile
|
46
|
+
- lib/wesabe
|
47
|
+
- lib/wesabe/configuration.rb
|
48
|
+
- lib/wesabe/exceptions.rb
|
49
|
+
- lib/wesabe/extensions.rb
|
50
|
+
- lib/wesabe/model
|
51
|
+
- lib/wesabe/model/account.rb
|
52
|
+
- lib/wesabe/model/base.rb
|
53
|
+
- lib/wesabe/model/institution.rb
|
54
|
+
- lib/wesabe/model/merchant.rb
|
55
|
+
- lib/wesabe/model/txaction.rb
|
56
|
+
- lib/wesabe/model.rb
|
57
|
+
- lib/wesabe/version.rb
|
58
|
+
- lib/wesabe.rb
|
59
|
+
- test/test_helper.rb
|
60
|
+
- test/unit
|
61
|
+
- test/unit/wesabe_test.rb
|
62
|
+
has_rdoc: true
|
63
|
+
homepage: ""
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options:
|
66
|
+
- --main
|
67
|
+
- README.rdoc
|
68
|
+
require_paths:
|
69
|
+
- lib
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: "0"
|
75
|
+
version:
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: "0"
|
81
|
+
version:
|
82
|
+
requirements: []
|
83
|
+
|
84
|
+
rubyforge_project:
|
85
|
+
rubygems_version: 1.2.0
|
86
|
+
signing_key:
|
87
|
+
specification_version: 2
|
88
|
+
summary: A simplistic gem to assist in consuming the Wesabe API.
|
89
|
+
test_files: []
|
90
|
+
|