kashflow 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.
data/kashflow.gemspec ADDED
@@ -0,0 +1,80 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{kashflow}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Pogodan"]
12
+ s.date = %q{2010-12-31}
13
+ s.description = %q{A Ruby wrapper for the Kashflow Accouting SOAP API}
14
+ s.email = %q{paul@pogodan.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.mkd"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ "Gemfile",
22
+ "Gemfile.lock",
23
+ "LICENSE.txt",
24
+ "README.mkd",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "config/kf_api_methods.yml",
28
+ "kashflow.gemspec",
29
+ "lib/kashflow.rb",
30
+ "lib/kashflow/api.rb",
31
+ "lib/kashflow/api_method.rb",
32
+ "lib/kashflow/client.rb",
33
+ "test/helper.rb",
34
+ "test/test_kashflow.rb"
35
+ ]
36
+ s.homepage = %q{https://github.com/pogodan/kashflow}
37
+ s.licenses = ["MIT"]
38
+ s.require_paths = ["lib"]
39
+ s.rubygems_version = %q{1.3.7}
40
+ s.summary = %q{A Ruby wrapper for the Kashflow SOAP API}
41
+ s.test_files = [
42
+ "test/helper.rb",
43
+ "test/test_kashflow.rb"
44
+ ]
45
+
46
+ if s.respond_to? :specification_version then
47
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
51
+ s.add_runtime_dependency(%q<savon>, ["~> 0.7.9"])
52
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
53
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
54
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
55
+ s.add_development_dependency(%q<rcov>, [">= 0"])
56
+ s.add_development_dependency(%q<nokogiri>, [">= 0"])
57
+ s.add_development_dependency(%q<i18n>, [">= 0"])
58
+ s.add_development_dependency(%q<activesupport>, [">= 0"])
59
+ else
60
+ s.add_dependency(%q<savon>, ["~> 0.7.9"])
61
+ s.add_dependency(%q<shoulda>, [">= 0"])
62
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
63
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
64
+ s.add_dependency(%q<rcov>, [">= 0"])
65
+ s.add_dependency(%q<nokogiri>, [">= 0"])
66
+ s.add_dependency(%q<i18n>, [">= 0"])
67
+ s.add_dependency(%q<activesupport>, [">= 0"])
68
+ end
69
+ else
70
+ s.add_dependency(%q<savon>, ["~> 0.7.9"])
71
+ s.add_dependency(%q<shoulda>, [">= 0"])
72
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
73
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
74
+ s.add_dependency(%q<rcov>, [">= 0"])
75
+ s.add_dependency(%q<nokogiri>, [">= 0"])
76
+ s.add_dependency(%q<i18n>, [">= 0"])
77
+ s.add_dependency(%q<activesupport>, [">= 0"])
78
+ end
79
+ end
80
+
@@ -0,0 +1,64 @@
1
+ require 'open-uri'
2
+ require 'nokogiri'
3
+ require 'active_support/core_ext/object'
4
+ require 'active_support/core_ext/hash'
5
+
6
+ ## Kashflow.export_yaml will scrape the public API site for methods and
7
+ ## dump them into the YAML config we use. we probably can/should just get this
8
+ ## from the WSDL directly, but Savon wasn't working right, so this is the stopgap measure
9
+ module Kashflow
10
+ class Api
11
+ class << self
12
+
13
+ def api_page(path)
14
+ cache_path = File.join(Kashflow.root, 'tmp', 'kf_api_pages', path)
15
+
16
+ unless File.exists?(cache_path)
17
+ File.open(cache_path, 'w'){ |f| f << open("http://accountingapi.com/#{path}").read }
18
+ end
19
+
20
+ Nokogiri::HTML(open(cache_path))
21
+ end
22
+
23
+ def apis_from_web
24
+ main_page = api_page('manual_class_customer.asp')
25
+
26
+ main_page.search('#mr_manual_inner a').select do |node|
27
+ node['href'] =~ /manual_methods/ and
28
+ node['href'] != 'manual_methods_overview.asp'
29
+
30
+ end.map{|n| new(n.content, n['href']) }
31
+ end
32
+
33
+ def export_yaml
34
+ api_methods = apis_from_web.map { |a| ApiMethod.new(a.name, a.import) }
35
+
36
+ File.open(Client.yaml_path, 'w') do |f|
37
+ YAML.dump(api_methods, f)
38
+ end
39
+ end
40
+
41
+ end
42
+
43
+ attr_reader :name, :page
44
+ def initialize(name, page)
45
+ @name = name
46
+ @page = page
47
+ end
48
+
49
+ def api_page
50
+ @api_page ||= self.class.api_page(page)
51
+ end
52
+
53
+ def import
54
+ @fields ||= api_page.search('.mnl_tbl1 tr').map do |row|
55
+ {
56
+ :name => row.search('span.mnl_varName').first.try(:content),
57
+ :type => row.search('span.mnl_varType').first.try(:content),
58
+ :direction => row.search('td strong').first.try(:content),
59
+ :desc => row.search('td').last.try(:content)
60
+ }
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,19 @@
1
+ module Kashflow
2
+ class ApiMethod
3
+ attr_accessor :name, :request_attrs, :response_attrs
4
+
5
+ def initialize(name, fields)
6
+ @name = name
7
+
8
+ # split into request/response attrs
9
+ @request_attrs, @response_attrs = fields.partition{|f| f[:direction] == 'IN' }.map do |arr|
10
+ arr.map do |fields|
11
+ # get rid of the :direction and cleanup the description text
12
+ fields.slice!(:type, :desc, :name)
13
+ fields[:desc].try(:strip!)
14
+ fields
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,97 @@
1
+ module Kashflow
2
+ class Client
3
+ attr_reader :service
4
+
5
+ def self.yaml_path
6
+ File.join(Kashflow.root, 'config', 'kf_api_methods.yml')
7
+ end
8
+
9
+ def self.api_methods
10
+ @@api_methods ||= YAML.load_file(yaml_path)
11
+ end
12
+
13
+ def initialize(login, password)
14
+ raise "missing login/password" unless login and password
15
+
16
+ @login, @password = login, password
17
+ @service = Savon::Client.new "https://securedwebapp.com/api/service.asmx?wsdl"
18
+ end
19
+
20
+ def lookup_api_method(name)
21
+ self.class.api_methods.detect{ |api_method| api_method.name.underscore == name.to_s }
22
+ end
23
+
24
+ def method_missing(m, *args, &block)
25
+ api_method = lookup_api_method(m)
26
+
27
+ if api_method
28
+ #puts "found api_method #{api_method.name} for #{m}: #{api_method.request_attrs.inspect}"
29
+ #puts "you're calling with #{args.inspect}"
30
+
31
+ api_call(m, api_method.name, args)
32
+ else
33
+ raise "method_missing: No method for #{m}"
34
+ end
35
+ end
36
+
37
+ def api_call(name, method, args)
38
+ soap_return = soap_call(name, method, args)
39
+ response = soap_return["#{name}_response".to_sym]
40
+ #puts "got response: " + response.inspect
41
+
42
+ raise "API call failed: [#{response[:status_detail]}]\n\n #{response.inspect}" unless response[:status] == 'OK'
43
+
44
+ r = response["#{name}_result".to_sym]
45
+
46
+ if r.is_a?(Enumerable)
47
+ if r.values.all?{|v| v.is_a?(Array) }# || r.keys.size == 1
48
+ object_type, attrs = r.first
49
+ else
50
+ #puts "arrayifying #{r.inspect}"
51
+ object_type = lookup_api_method(name).response_attrs.first[:type]
52
+ attrs = r.first.last.is_a?(Hash) ? [r.first.last] : [r]
53
+ end
54
+
55
+ #puts "it's an enumerable... #{object_type} | #{attrs.inspect}"
56
+
57
+ ostructs = attrs.map do |record_attrs|
58
+ #puts "making new ostruct with #{record_attrs.inspect}"
59
+ OpenStruct.new(record_attrs.merge(:object_type => object_type.to_s))
60
+ end
61
+ #r.first.last
62
+ else
63
+ #puts "it's a #{r.class}"
64
+ r
65
+ end
66
+ end
67
+
68
+ # called with CamelCase version of method name
69
+ def soap_call(name, method, params = {})
70
+ begin
71
+ result = @service.send(name) do |soap|
72
+ soap.action = "KashFlow/#{method}"
73
+
74
+ params = params.pop if params.is_a?(Array)
75
+ params_xml = params.map do |field, value|
76
+ xml_tag = field.to_s.camelize
77
+ "<#{xml_tag}>#{value}</#{xml_tag}>"
78
+ end.join("\n") unless params.blank?
79
+
80
+ soap.xml = %[<?xml version="1.0" encoding="utf-8"?>
81
+ <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
82
+ <soap:Body>
83
+ <#{method} xmlns="KashFlow">
84
+ <UserName>#{@login}</UserName>
85
+ <Password>#{@password}</Password>
86
+ #{params_xml}
87
+ </#{method}>
88
+ </soap:Body>
89
+ </soap:Envelope>]
90
+ end.to_hash
91
+ rescue Savon::SOAPFault => e
92
+ puts "soap fault:" + e.inspect
93
+ return false
94
+ end
95
+ end
96
+ end
97
+ end
data/lib/kashflow.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'ostruct'
2
+ require 'savon'
3
+
4
+ require File.expand_path('../kashflow/client', __FILE__)
5
+ require File.expand_path('../kashflow/api_method', __FILE__)
6
+ require File.expand_path('../kashflow/api', __FILE__)
7
+
8
+ module Kashflow
9
+ def self.client(login, password)
10
+ @client ||= Kashflow::Client.new(login, password)
11
+ end
12
+
13
+ def self.method_missing(method, *args, &block)
14
+ return super unless client.respond_to?(method)
15
+ client.send(method, *args, &block)
16
+ end
17
+
18
+ def self.root
19
+ File.dirname(File.expand_path('..', __FILE__))
20
+ end
21
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'kashflow'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestKashflow < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,200 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kashflow
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Pogodan
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-12-31 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ prerelease: false
23
+ type: :runtime
24
+ name: savon
25
+ version_requirements: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ hash: 17
31
+ segments:
32
+ - 0
33
+ - 7
34
+ - 9
35
+ version: 0.7.9
36
+ requirement: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ prerelease: false
39
+ type: :development
40
+ name: shoulda
41
+ version_requirements: &id002 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ hash: 3
47
+ segments:
48
+ - 0
49
+ version: "0"
50
+ requirement: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ prerelease: false
53
+ type: :development
54
+ name: bundler
55
+ version_requirements: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ hash: 23
61
+ segments:
62
+ - 1
63
+ - 0
64
+ - 0
65
+ version: 1.0.0
66
+ requirement: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ prerelease: false
69
+ type: :development
70
+ name: jeweler
71
+ version_requirements: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ hash: 7
77
+ segments:
78
+ - 1
79
+ - 5
80
+ - 2
81
+ version: 1.5.2
82
+ requirement: *id004
83
+ - !ruby/object:Gem::Dependency
84
+ prerelease: false
85
+ type: :development
86
+ name: rcov
87
+ version_requirements: &id005 !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ hash: 3
93
+ segments:
94
+ - 0
95
+ version: "0"
96
+ requirement: *id005
97
+ - !ruby/object:Gem::Dependency
98
+ prerelease: false
99
+ type: :development
100
+ name: nokogiri
101
+ version_requirements: &id006 !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ hash: 3
107
+ segments:
108
+ - 0
109
+ version: "0"
110
+ requirement: *id006
111
+ - !ruby/object:Gem::Dependency
112
+ prerelease: false
113
+ type: :development
114
+ name: i18n
115
+ version_requirements: &id007 !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ hash: 3
121
+ segments:
122
+ - 0
123
+ version: "0"
124
+ requirement: *id007
125
+ - !ruby/object:Gem::Dependency
126
+ prerelease: false
127
+ type: :development
128
+ name: activesupport
129
+ version_requirements: &id008 !ruby/object:Gem::Requirement
130
+ none: false
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ hash: 3
135
+ segments:
136
+ - 0
137
+ version: "0"
138
+ requirement: *id008
139
+ description: A Ruby wrapper for the Kashflow Accouting SOAP API
140
+ email: paul@pogodan.com
141
+ executables: []
142
+
143
+ extensions: []
144
+
145
+ extra_rdoc_files:
146
+ - LICENSE.txt
147
+ - README.mkd
148
+ files:
149
+ - .document
150
+ - Gemfile
151
+ - Gemfile.lock
152
+ - LICENSE.txt
153
+ - README.mkd
154
+ - Rakefile
155
+ - VERSION
156
+ - config/kf_api_methods.yml
157
+ - kashflow.gemspec
158
+ - lib/kashflow.rb
159
+ - lib/kashflow/api.rb
160
+ - lib/kashflow/api_method.rb
161
+ - lib/kashflow/client.rb
162
+ - test/helper.rb
163
+ - test/test_kashflow.rb
164
+ has_rdoc: true
165
+ homepage: https://github.com/pogodan/kashflow
166
+ licenses:
167
+ - MIT
168
+ post_install_message:
169
+ rdoc_options: []
170
+
171
+ require_paths:
172
+ - lib
173
+ required_ruby_version: !ruby/object:Gem::Requirement
174
+ none: false
175
+ requirements:
176
+ - - ">="
177
+ - !ruby/object:Gem::Version
178
+ hash: 3
179
+ segments:
180
+ - 0
181
+ version: "0"
182
+ required_rubygems_version: !ruby/object:Gem::Requirement
183
+ none: false
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ hash: 3
188
+ segments:
189
+ - 0
190
+ version: "0"
191
+ requirements: []
192
+
193
+ rubyforge_project:
194
+ rubygems_version: 1.3.7
195
+ signing_key:
196
+ specification_version: 3
197
+ summary: A Ruby wrapper for the Kashflow SOAP API
198
+ test_files:
199
+ - test/helper.rb
200
+ - test/test_kashflow.rb