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 ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in finance_sync.gemspec
4
+ gemspec
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
@@ -0,0 +1,3 @@
1
+ module FinanceSync
2
+ VERSION = "0.0.1"
3
+ end
@@ -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
@@ -0,0 +1,4 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require "bundler/setup"
3
+ require 'fakeweb'
4
+ require File.join(File.dirname(__FILE__), '../lib', 'finance_sync')
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