finance_sync 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/.gitignore +5 -0
- data/Gemfile +4 -0
- data/LICENSE.rdoc +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +1 -0
- data/finance_sync.gemspec +23 -0
- data/lib/finance_sync/version.rb +3 -0
- data/lib/finance_sync.rb +68 -0
- data/spec/finance_sync_spec.rb +287 -0
- data/spec/spec_helper.rb +4 -0
- metadata +83 -0
data/Gemfile
ADDED
data/LICENSE.rdoc
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Vanderson Mota
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
= finance_sync
|
2
|
+
|
3
|
+
Como usar:
|
4
|
+
|
5
|
+
require 'finance_sync'
|
6
|
+
|
7
|
+
Instancie a classe FinanceSync::Client passando a url do servidor e a versão dos dados que estão na máquina cliente:
|
8
|
+
|
9
|
+
@client = FinanceSync::Client.new(:services_url=>"https://services.myfreecomm.com.br/, :version=>22)
|
10
|
+
|
11
|
+
Para sincronizar, você deve mandar um hash com os dados que você alterou desde a última versão:
|
12
|
+
|
13
|
+
@client.synchronize({:dados=>'alterados'})
|
14
|
+
|
15
|
+
Para maiores detalhes de como funciona a API do FinanceSync, veja em: git@github.com:myfreecomm/Snakepit.git
|
16
|
+
|
17
|
+
Testado apenas com Ruby 1.9.2p180.
|
18
|
+
|
19
|
+
Copyright (c) 2010 Vanderson Mota. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "finance_sync/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "finance_sync"
|
7
|
+
s.version = FinanceSync::VERSION
|
8
|
+
s.authors = ["Vanderson Mota", "Rodrigo Tassinari"]
|
9
|
+
s.email = ["vanderson.mota@myfreecomm.com.br", "rodrigo.tassinari@myfreecomm.com.br"]
|
10
|
+
s.homepage = "https://github.com/myfreecomm/finance_sync"
|
11
|
+
s.summary = %q{Ruby client to the FinanceSync API}
|
12
|
+
s.description = %q{Ruby client to the FinanceSync API}
|
13
|
+
|
14
|
+
s.rubyforge_project = "finance_sync"
|
15
|
+
|
16
|
+
s.add_development_dependency "rspec", "~> 2.6.0"
|
17
|
+
s.add_development_dependency "fakeweb", "~> 1.3.0"
|
18
|
+
|
19
|
+
s.files = `git ls-files`.split("\n")
|
20
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
21
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
|
+
s.require_paths = ["lib"]
|
23
|
+
end
|
data/lib/finance_sync.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require "finance_sync/version"
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'json'
|
6
|
+
require 'net/http'
|
7
|
+
|
8
|
+
module FinanceSync
|
9
|
+
|
10
|
+
class Client
|
11
|
+
attr_reader :version, :entities, :conflicts, :error
|
12
|
+
|
13
|
+
def initialize(params)
|
14
|
+
@services_url = params[:services_url]
|
15
|
+
@version = params[:version]
|
16
|
+
@user = params[:user]
|
17
|
+
@password = params[:password]
|
18
|
+
raise ArgumentError if @user.nil? or @password.nil?
|
19
|
+
raise TypeError unless @version.is_a? Fixnum
|
20
|
+
|
21
|
+
@error = nil
|
22
|
+
@conflicts = []
|
23
|
+
end
|
24
|
+
|
25
|
+
def synchronize(data)
|
26
|
+
data = request_sync(data)
|
27
|
+
return false if data == false
|
28
|
+
@version = data['version']
|
29
|
+
@entities = data['data']
|
30
|
+
@conflicts = data['conflicts']
|
31
|
+
return true
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
def assemble_data(entities)
|
37
|
+
return {"version" => @version, "data" => entities}
|
38
|
+
end
|
39
|
+
|
40
|
+
def request_sync(entities)
|
41
|
+
data = assemble_data(entities)
|
42
|
+
errors = {"400"=>"bad data", "500"=>"sync server error",
|
43
|
+
"423"=>"locked", "401"=> "login error"}
|
44
|
+
|
45
|
+
put = Net::HTTP::Put.new("/financedesktop/sync/synchronize")
|
46
|
+
put.basic_auth(@user, @password)
|
47
|
+
put.content_type = 'application/json'
|
48
|
+
begin
|
49
|
+
response = Net::HTTP.start(@services_url) {|http|
|
50
|
+
http.request(put, data.to_json)
|
51
|
+
}
|
52
|
+
rescue SocketError, URI::InvalidURIError
|
53
|
+
@error = 'invalid url'
|
54
|
+
return false
|
55
|
+
end
|
56
|
+
|
57
|
+
case response
|
58
|
+
when Net::HTTPSuccess
|
59
|
+
return JSON.parse(response.body)
|
60
|
+
else
|
61
|
+
@error = errors[response.code]
|
62
|
+
return false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,287 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
ENTITIES = [
|
5
|
+
{"entity"=>
|
6
|
+
{"currency"=> "BRL", "payee"=> nil, "amount"=> "100.00000000",
|
7
|
+
"imported"=> false, "description"=> "Novo lançamento",
|
8
|
+
"payer"=> "Rendimento aplicação", "base_date"=> "2010-03-16T11=>29=>02.354014",
|
9
|
+
"document_number"=> 1, "guid"=> "ffffffffffffffffffffffffffffffff"
|
10
|
+
}
|
11
|
+
}
|
12
|
+
]
|
13
|
+
|
14
|
+
|
15
|
+
UPDATED_VERSION = '{"conflicts": [], "version": 49, "data": [{"entity": {"imported": "true",
|
16
|
+
"description": "roupa", "document-number": 111, "amount": "200.00000000",
|
17
|
+
"date": "2010-10-11", "guid": "22a648b0-2fe1-4888-96a4-caa27a4c27d7",
|
18
|
+
"type": "transaction"}}]}'
|
19
|
+
|
20
|
+
USER = 'jalim'
|
21
|
+
PASSWORD = 'habei'
|
22
|
+
|
23
|
+
describe FinanceSync::Client do
|
24
|
+
|
25
|
+
def fake_sync_response(response, user='', password='')
|
26
|
+
if not (user.empty? and password.empty?)
|
27
|
+
credentials = "#{user}:#{password}@"
|
28
|
+
else
|
29
|
+
credentials = ""
|
30
|
+
end
|
31
|
+
FakeWeb.register_uri(
|
32
|
+
:put,
|
33
|
+
"http://#{credentials}services.myfreecomm.com.br/financedesktop/sync/synchronize",
|
34
|
+
response)
|
35
|
+
end
|
36
|
+
|
37
|
+
before(:each) do
|
38
|
+
@services_url = "services.myfreecomm.com.br"
|
39
|
+
@finance_sync = FinanceSync::Client.new(:services_url => @services_url, :version => 2,
|
40
|
+
:user=>USER, :password=>PASSWORD)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should have .version" do
|
44
|
+
@finance_sync = FinanceSync::Client.new(:services_url=>@services_url, :version => 4,
|
45
|
+
:user=>USER, :password=>PASSWORD)
|
46
|
+
@finance_sync.version.should == 4
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "initializer" do
|
50
|
+
it "should store version" do
|
51
|
+
@finance_sync.instance_variable_get(:@version).should == 2
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should store services_url" do
|
55
|
+
@finance_sync.instance_variable_get(:@services_url).should == 'services.myfreecomm.com.br'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
describe "synchronizer" do
|
61
|
+
it "should send the params formed correctly" do
|
62
|
+
@finance_sync = FinanceSync::Client.new(:services_url => @services_url, :version => 48,
|
63
|
+
:user=>USER, :password=>PASSWORD)
|
64
|
+
correct_json = {"version"=>@finance_sync.version, "data"=>ENTITIES}.to_json
|
65
|
+
|
66
|
+
put = mock(Net::HTTP::Put)
|
67
|
+
Net::HTTP::Put.should_receive(:new).with("/financedesktop/sync/synchronize").once.and_return(put)
|
68
|
+
put.should_receive(:basic_auth).with(USER, PASSWORD)
|
69
|
+
put.should_receive(:content_type=).with('application/json')
|
70
|
+
|
71
|
+
http = mock()
|
72
|
+
http.should_receive(:request).with(put, correct_json)
|
73
|
+
|
74
|
+
http_success_mock = mock(Net::HTTPSuccess)
|
75
|
+
http_success_mock.stub!(:code).and_return("200")
|
76
|
+
http_success_mock.stub!(:body).and_return(UPDATED_VERSION)
|
77
|
+
|
78
|
+
Net::HTTP.should_receive(:start).with(@services_url).and_yield(http).and_return(http_success_mock)
|
79
|
+
@finance_sync.synchronize(ENTITIES)
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "with not found url" do
|
83
|
+
before(:each) do
|
84
|
+
@invalid_url = 'invalid_url'
|
85
|
+
@finance_sync = FinanceSync::Client.new(:services_url => @invalid_url, :version => 48,
|
86
|
+
:user=>USER, :password=>PASSWORD)
|
87
|
+
@correct_json = {"version"=>@finance_sync.version, "data"=>ENTITIES}.to_json
|
88
|
+
|
89
|
+
@put = mock(Net::HTTP::Put)
|
90
|
+
Net::HTTP::Put.should_receive(:new).with("/financedesktop/sync/synchronize").once.and_return(@put)
|
91
|
+
@put.should_receive(:basic_auth).with(USER, PASSWORD)
|
92
|
+
@put.should_receive(:content_type=).with('application/json')
|
93
|
+
http = mock()
|
94
|
+
Net::HTTP.should_receive(:start).with(@invalid_url).and_raise(SocketError)
|
95
|
+
end
|
96
|
+
it "should return false" do
|
97
|
+
@finance_sync.synchronize(ENTITIES).should be_false
|
98
|
+
end
|
99
|
+
it "should return set 'invalid url' error" do
|
100
|
+
@finance_sync.synchronize(ENTITIES)
|
101
|
+
@finance_sync.error.should == 'invalid url'
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "with invalid url" do
|
106
|
+
before(:each) do
|
107
|
+
@finance_sync = FinanceSync::Client.new(:services_url => nil, :version => 48,
|
108
|
+
:user=>USER, :password=>PASSWORD)
|
109
|
+
end
|
110
|
+
it "should return false" do
|
111
|
+
@finance_sync.synchronize(ENTITIES).should be_false
|
112
|
+
end
|
113
|
+
it "should set 'invalid url' error" do
|
114
|
+
@finance_sync.synchronize(ENTITIES)
|
115
|
+
@finance_sync.error.should == 'invalid url'
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "with invalid version specified" do
|
120
|
+
it "should raise TypeError if a non integer is passed " do
|
121
|
+
wrong_params = {:services_url => "services.myfreecomm.com.br",
|
122
|
+
:version => "abcsd", :user=>USER, :password=>PASSWORD}
|
123
|
+
lambda {
|
124
|
+
FinanceSync::Client.new(wrong_params)
|
125
|
+
}.should raise_exception(TypeError)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe "with wrong credentials provided" do
|
130
|
+
before(:each) do
|
131
|
+
fake_sync_response({:status=>[401, "unauthorized"]}, 'wrong', 'credential' )
|
132
|
+
@finance_sync = FinanceSync::Client.new(:services_url => @services_url, :version => 48,
|
133
|
+
:user=>'wrong', :password=>'credential')
|
134
|
+
end
|
135
|
+
it "should return false " do
|
136
|
+
@finance_sync.synchronize(ENTITIES).should be_false
|
137
|
+
end
|
138
|
+
it "should set 'login error'" do
|
139
|
+
@finance_sync.synchronize(ENTITIES).should be_false
|
140
|
+
@finance_sync.error.should == 'login error'
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe "with no credentials provided" do
|
145
|
+
it "should raise 'Argument Error'" do
|
146
|
+
lambda {
|
147
|
+
FinanceSync::Client.new(:services_url => @services_url, :version => 48)
|
148
|
+
}.should raise_exception(ArgumentError)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe "with no conflicts and no new data" do
|
153
|
+
before(:each) do
|
154
|
+
@finance_sync = FinanceSync::Client.new(:services_url => "services.myfreecomm.com.br",
|
155
|
+
:version => 48, :user=>'wrong',
|
156
|
+
:password=>'credentials' )
|
157
|
+
fake_sync_response({:status=>[200, "OK"],
|
158
|
+
:body=>'{"conflicts": [], "version": 48, "data": []}'},
|
159
|
+
'wrong', 'credentials')
|
160
|
+
end
|
161
|
+
it "should not update version" do
|
162
|
+
lambda {
|
163
|
+
@finance_sync.synchronize(ENTITIES)
|
164
|
+
}.should_not change(@finance_sync, :version)
|
165
|
+
end
|
166
|
+
it "should not populate conflicts" do
|
167
|
+
lambda {
|
168
|
+
@finance_sync.synchronize(ENTITIES)
|
169
|
+
}.should_not change(@finance_sync, :conflicts)
|
170
|
+
end
|
171
|
+
it "should return true" do
|
172
|
+
@finance_sync.synchronize(ENTITIES).should be_true
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe "with no conflicts and new data from sync server" do
|
177
|
+
before(:each) do
|
178
|
+
@finance_sync = FinanceSync::Client.new(:services_url => "services.myfreecomm.com.br",
|
179
|
+
:version => 48, :user=>'wrong',
|
180
|
+
:password=>'credentials')
|
181
|
+
fake_sync_response({:status=>[200, "OK"], :body=>UPDATED_VERSION},
|
182
|
+
'wrong', 'credentials')
|
183
|
+
end
|
184
|
+
it "should populate entities" do
|
185
|
+
@finance_sync.synchronize(ENTITIES)
|
186
|
+
@finance_sync.entities.should_not be_empty
|
187
|
+
end
|
188
|
+
it "should update version" do
|
189
|
+
@finance_sync.synchronize(ENTITIES)
|
190
|
+
@finance_sync.version.should == 49
|
191
|
+
end
|
192
|
+
it "should not have conflicts" do
|
193
|
+
@finance_sync.synchronize(ENTITIES)
|
194
|
+
@finance_sync.conflicts.should be_empty
|
195
|
+
end
|
196
|
+
it "should return true" do
|
197
|
+
@finance_sync.synchronize(@old_transaction).should be_true
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
202
|
+
|
203
|
+
describe "with bad data" do
|
204
|
+
before(:each) do
|
205
|
+
fake_sync_response({:status=>[400, "Bad request"], :body=>"invalid data"},
|
206
|
+
USER, PASSWORD)
|
207
|
+
@bad_data = '{"version": 47, "entity":}'
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should set error 'bad data'" do
|
211
|
+
@finance_sync.synchronize(@bad_data)
|
212
|
+
@finance_sync.error.should == "bad data"
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should return false" do
|
216
|
+
@finance_sync.synchronize(@bad_data).should be_false
|
217
|
+
end
|
218
|
+
|
219
|
+
end
|
220
|
+
|
221
|
+
describe "on sync server error" do
|
222
|
+
|
223
|
+
before(:each) do
|
224
|
+
fake_sync_response({:status=>[500, "Server Error"], :body=>"Server Error"},
|
225
|
+
USER, PASSWORD)
|
226
|
+
@valid_data = '{"valid": "data"}'
|
227
|
+
end
|
228
|
+
|
229
|
+
it "should set error 'sync server error'" do
|
230
|
+
@finance_sync.synchronize(@valid_data)
|
231
|
+
@finance_sync.error.should == "sync server error"
|
232
|
+
end
|
233
|
+
|
234
|
+
it "should return false" do
|
235
|
+
@finance_sync.synchronize(@valid_data).should be_false
|
236
|
+
end
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
describe "on sync server lock" do
|
241
|
+
|
242
|
+
before(:each) do
|
243
|
+
fake_sync_response({:status=>[423, "Locked"], :body=>"Locked"}, USER, PASSWORD)
|
244
|
+
@valid_data = '{"valid": "data"}'
|
245
|
+
end
|
246
|
+
|
247
|
+
it "should set error 'sync server error'" do
|
248
|
+
@finance_sync.synchronize(@valid_data)
|
249
|
+
@finance_sync.error.should == "locked"
|
250
|
+
end
|
251
|
+
|
252
|
+
it "should return false" do
|
253
|
+
@finance_sync.synchronize(@valid_data).should be_false
|
254
|
+
end
|
255
|
+
|
256
|
+
end
|
257
|
+
|
258
|
+
describe "with any error" do
|
259
|
+
before(:each) do
|
260
|
+
@finance_sync.stub!(:request_sync).and_return(false)
|
261
|
+
end
|
262
|
+
|
263
|
+
it "should not alter sync version" do
|
264
|
+
lambda {
|
265
|
+
@finance_sync.synchronize(@valid_data)
|
266
|
+
}.should_not change(@finance_sync, :version)
|
267
|
+
end
|
268
|
+
|
269
|
+
it "should not populate conflicts" do
|
270
|
+
lambda {
|
271
|
+
@finance_sync.synchronize(@valid_data)
|
272
|
+
}.should_not change(@finance_sync, :conflicts)
|
273
|
+
end
|
274
|
+
|
275
|
+
it "should not update entities" do
|
276
|
+
lambda {
|
277
|
+
@finance_sync.synchronize(@valid_data)
|
278
|
+
}.should_not change(@finance_sync, :entities)
|
279
|
+
end
|
280
|
+
|
281
|
+
it "should return false" do
|
282
|
+
@finance_sync.synchronize(@valid_data).should be_false
|
283
|
+
end
|
284
|
+
|
285
|
+
end
|
286
|
+
|
287
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: finance_sync
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Vanderson Mota
|
9
|
+
- Rodrigo Tassinari
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2011-06-08 00:00:00.000000000 -03:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rspec
|
18
|
+
requirement: &2157289460 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ~>
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.6.0
|
24
|
+
type: :development
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: *2157289460
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: fakeweb
|
29
|
+
requirement: &2157288960 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ~>
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 1.3.0
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: *2157288960
|
38
|
+
description: Ruby client to the FinanceSync API
|
39
|
+
email:
|
40
|
+
- vanderson.mota@myfreecomm.com.br
|
41
|
+
- rodrigo.tassinari@myfreecomm.com.br
|
42
|
+
executables: []
|
43
|
+
extensions: []
|
44
|
+
extra_rdoc_files: []
|
45
|
+
files:
|
46
|
+
- .gitignore
|
47
|
+
- Gemfile
|
48
|
+
- LICENSE.rdoc
|
49
|
+
- README.rdoc
|
50
|
+
- Rakefile
|
51
|
+
- finance_sync.gemspec
|
52
|
+
- lib/finance_sync.rb
|
53
|
+
- lib/finance_sync/version.rb
|
54
|
+
- spec/finance_sync_spec.rb
|
55
|
+
- spec/spec_helper.rb
|
56
|
+
has_rdoc: true
|
57
|
+
homepage: https://github.com/myfreecomm/finance_sync
|
58
|
+
licenses: []
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options: []
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ! '>='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
requirements: []
|
76
|
+
rubyforge_project: finance_sync
|
77
|
+
rubygems_version: 1.6.2
|
78
|
+
signing_key:
|
79
|
+
specification_version: 3
|
80
|
+
summary: Ruby client to the FinanceSync API
|
81
|
+
test_files:
|
82
|
+
- spec/finance_sync_spec.rb
|
83
|
+
- spec/spec_helper.rb
|