schet 1.1.0

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/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Dieinzige
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.
@@ -0,0 +1,17 @@
1
+ = schet
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
13
+ * Send me a pull request. Bonus points for topic branches.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2010 Dieinzige. See LICENSE for details.
@@ -0,0 +1,52 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "schet"
8
+ gem.summary = %Q{Public api wrapper for schet.ru}
9
+ gem.description = %Q{Public api wrapper for e-invoice schet.ru}
10
+ gem.email = "dieinzige@me.com"
11
+ gem.homepage = "http://github.com/Dieinzige/schet"
12
+ gem.authors = ["dieinzige"]
13
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+ end
15
+ Jeweler::GemcutterTasks.new
16
+ rescue LoadError
17
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
18
+ end
19
+
20
+ require 'rake/testtask'
21
+ Rake::TestTask.new(:test) do |test|
22
+ test.libs << 'lib' << 'test'
23
+ test.pattern = 'test/**/test_*.rb'
24
+ test.verbose = true
25
+ end
26
+
27
+ begin
28
+ require 'rcov/rcovtask'
29
+ Rcov::RcovTask.new do |test|
30
+ test.libs << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+ rescue LoadError
35
+ task :rcov do
36
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
37
+ end
38
+ end
39
+
40
+ task :test => :check_dependencies
41
+
42
+ task :default => :test
43
+
44
+ require 'rake/rdoctask'
45
+ Rake::RDocTask.new do |rdoc|
46
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
47
+
48
+ rdoc.rdoc_dir = 'rdoc'
49
+ rdoc.title = "schet #{version}"
50
+ rdoc.rdoc_files.include('README*')
51
+ rdoc.rdoc_files.include('lib/**/*.rb')
52
+ end
@@ -0,0 +1,53 @@
1
+ require 'forwardable'
2
+ require 'rubygems'
3
+
4
+ gem 'hashie'
5
+ require 'hashie'
6
+
7
+ gem 'httparty'
8
+ require 'httparty'
9
+
10
+ module Schet
11
+ class SchetError < StandardError
12
+ attr_reader :data
13
+
14
+ def initialize(data)
15
+ @data = data
16
+ super
17
+ end
18
+ end
19
+
20
+ class RateLimitExceeded < SchetError; end
21
+ class Unauthorized < SchetError; end
22
+ class General < SchetError; end
23
+
24
+ class Unavailable < SchetError; end
25
+ class InformSchet < SchetError; end
26
+ class NotFound < SchetError; end
27
+
28
+
29
+ end
30
+
31
+ module Hashie
32
+ class Mash
33
+
34
+ # Converts all of the keys to strings, optionally formatting key name
35
+ def rubyify_keys!
36
+ keys.each{|k|
37
+ v = delete(k)
38
+ new_key = k.to_s.underscore
39
+ self[new_key] = v
40
+ v.rubyify_keys! if v.is_a?(Hash)
41
+ v.each{|p| p.rubyify_keys! if p.is_a?(Hash)} if v.is_a?(Array)
42
+ }
43
+ self
44
+ end
45
+
46
+ end
47
+ end
48
+
49
+ directory = File.expand_path(File.dirname(__FILE__))
50
+
51
+ require File.join(directory, 'schet', 'token_auth')
52
+ require File.join(directory, 'schet', 'request')
53
+ require File.join(directory, 'schet', 'base')
@@ -0,0 +1,72 @@
1
+ module Schet
2
+ class Base
3
+ extend Forwardable
4
+
5
+ def_delegators :client, :get, :post, :put, :delete
6
+
7
+ attr_reader :client
8
+
9
+ def initialize(client)
10
+ @client = client
11
+ end
12
+
13
+
14
+ def process_invoices(options = {})
15
+ perform_post("/api/invoices.json", :body => options)
16
+ end
17
+
18
+
19
+
20
+ protected
21
+ def self.mime_type(file)
22
+ case
23
+ when file =~ /\.jpg/ then 'image/jpg'
24
+ when file =~ /\.gif$/ then 'image/gif'
25
+ when file =~ /\.png$/ then 'image/png'
26
+ else 'application/octet-stream'
27
+ end
28
+ end
29
+ def mime_type(f) self.class.mime_type(f) end
30
+
31
+ CRLF = "\r\n"
32
+ def self.build_multipart_bodies(parts)
33
+ boundary = Time.now.to_i.to_s(16)
34
+ body = ""
35
+ parts.each do |key, value|
36
+ esc_key = CGI.escape(key.to_s)
37
+ body << "--#{boundary}#{CRLF}"
38
+ if value.respond_to?(:read)
39
+ body << "Content-Disposition: form-data; name=\"#{esc_key}\"; filename=\"#{File.basename(value.path)}\"#{CRLF}"
40
+ body << "Content-Type: #{mime_type(value.path)}#{CRLF*2}"
41
+ body << value.read
42
+ else
43
+ body << "Content-Disposition: form-data; name=\"#{esc_key}\"#{CRLF*2}#{value}"
44
+ end
45
+ body << CRLF
46
+ end
47
+ body << "--#{boundary}--#{CRLF*2}"
48
+ {
49
+ :body => body,
50
+ :headers => {"Content-Type" => "multipart/form-data; boundary=#{boundary}"}
51
+ }
52
+ end
53
+ def build_multipart_bodies(parts) self.class.build_multipart_bodies(parts) end
54
+
55
+ private
56
+ def perform_get(path, options={})
57
+ Schet::Request.get(self, path, options)
58
+ end
59
+
60
+ def perform_post(path, options={})
61
+ Schet::Request.post(self, path, options)
62
+ end
63
+
64
+ def perform_put(path, options={})
65
+ Schet::Request.put(self, path, options)
66
+ end
67
+
68
+ def perform_delete(path, options={})
69
+ Schet::Request.delete(self, path, options)
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,118 @@
1
+ module Schet
2
+ class Request
3
+ extend Forwardable
4
+
5
+ def self.get(client, path, options={})
6
+ new(client, :get, path, options).perform
7
+ end
8
+
9
+ def self.post(client, path, options={})
10
+ new(client, :post, path, options).perform
11
+ end
12
+
13
+ def self.put(client, path, options={})
14
+ new(client, :put, path, options).perform
15
+ end
16
+
17
+ def self.delete(client, path, options={})
18
+ new(client, :delete, path, options).perform
19
+ end
20
+
21
+ attr_reader :client, :method, :path, :options
22
+
23
+ def_delegators :client, :get, :post, :put, :delete
24
+
25
+ def initialize(client, method, path, options={})
26
+ @client, @method, @path, @options = client, method, path, {:mash => true}.merge(options)
27
+ end
28
+
29
+ def uri
30
+ @uri ||= begin
31
+ uri = URI.parse(path)
32
+
33
+ if options[:query] && options[:query] != {}
34
+ uri.query = to_query(options[:query])
35
+ end
36
+
37
+ uri.to_s
38
+ end
39
+ end
40
+
41
+ def perform
42
+ make_friendly(send("perform_#{method}"))
43
+ end
44
+
45
+ private
46
+ def perform_get
47
+ send(:get, uri, options[:headers])
48
+ end
49
+
50
+ def perform_post
51
+ send(:post, uri, options[:body], options[:headers])
52
+ end
53
+
54
+ def perform_put
55
+ send(:put, uri, options[:body], options[:headers])
56
+ end
57
+
58
+ def perform_delete
59
+ send(:delete, uri, options[:headers])
60
+ end
61
+
62
+ def make_friendly(response)
63
+ raise_errors(response)
64
+ data = parse(response)
65
+ options[:mash] ? mash(data) : data
66
+ end
67
+
68
+ def raise_errors(response)
69
+ case response.code.to_i
70
+ when 400
71
+ data = parse(response)
72
+ raise RateLimitExceeded.new(data), "(#{response.code}): #{response.message} - #{data['error'] if data}"
73
+ when 401
74
+ data = parse(response)
75
+ raise Unauthorized.new(data), "(#{response.code}): #{response.message} - #{data['error'] if data}"
76
+ when 403
77
+ data = parse(response)
78
+ raise General.new(data), "(#{response.code}): #{response.message} - #{data['error'] if data}"
79
+ when 404
80
+ raise NotFound, "(#{response.code}): #{response.message}"
81
+ when 500
82
+ raise InformSchet, "Schet.ru had an internal error. Please let them know in the group. (#{response.code}): #{response.message}"
83
+ when 502..503
84
+ raise Unavailable, "(#{response.code}): #{response.message}"
85
+ end
86
+ end
87
+
88
+ def parse(response)
89
+ Crack::JSON.parse(response.body)
90
+ end
91
+
92
+ def mash(obj)
93
+ if obj.is_a?(Array)
94
+ obj.map { |item| make_mash_with_consistent_hash(item) }
95
+ elsif obj.is_a?(Hash)
96
+ make_mash_with_consistent_hash(obj)
97
+ else
98
+ obj
99
+ end
100
+ end
101
+
102
+ # Lame workaround for the fact that mash doesn't hash correctly
103
+ def make_mash_with_consistent_hash(obj)
104
+ m = Hashie::Mash.new(obj)
105
+ def m.hash
106
+ inspect.hash
107
+ end
108
+ return m
109
+ end
110
+
111
+ def to_query(options)
112
+ options.inject([]) do |collection, opt|
113
+ collection << "#{opt[0]}=#{opt[1]}"
114
+ collection
115
+ end * '&'
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,37 @@
1
+ module Schet
2
+ class TokenAuth
3
+ include HTTParty
4
+ format :plain
5
+
6
+ attr_reader :username, :password, :options
7
+
8
+ def initialize(username, password, options={})
9
+ @username, @password = username, password
10
+ @options = {:ssl => false}.merge(options)
11
+ options[:api_endpoint] ||= "localhost:3000"
12
+ self.class.base_uri "http#{'s' if options[:ssl]}://#{options[:api_endpoint]}"
13
+ end
14
+
15
+ def get(uri, headers={})
16
+ self.class.get(uri, :headers => headers, :basic_auth => basic_auth)
17
+ end
18
+
19
+ def post(uri, body={}, headers={})
20
+ self.class.post(uri, :body => body.merge(:token => @options[:token]), :headers => headers, :basic_auth => basic_auth)
21
+ end
22
+
23
+ def put(uri, body={}, headers={})
24
+ self.class.put(uri, :body => body.merge(:token => @options[:token]), :headers => headers, :basic_auth => basic_auth)
25
+ end
26
+
27
+ def delete(uri, body={}, headers={})
28
+ self.class.delete(uri, :body => body.merge(:token => @options[:token]), :headers => headers, :basic_auth => basic_auth)
29
+ end
30
+
31
+
32
+ private
33
+ def basic_auth
34
+ @basic_auth ||= {:username => @username, :password => @password}
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'schet'
8
+
9
+ class Test::Unit::TestCase
10
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: schet
3
+ version: !ruby/object:Gem::Version
4
+ hash: 19
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 1
9
+ - 0
10
+ version: 1.1.0
11
+ platform: ruby
12
+ authors:
13
+ - dieinzige
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-05-24 00:00:00 +04:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Public api wrapper for e-invoice schet.ru
23
+ email: dieinzige@me.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - LICENSE
30
+ - README.rdoc
31
+ files:
32
+ - LICENSE
33
+ - README.rdoc
34
+ - Rakefile
35
+ - lib/schet.rb
36
+ - lib/schet/base.rb
37
+ - lib/schet/request.rb
38
+ - lib/schet/token_auth.rb
39
+ - test/helper.rb
40
+ has_rdoc: true
41
+ homepage: http://github.com/Dieinzige/schet
42
+ licenses: []
43
+
44
+ post_install_message:
45
+ rdoc_options:
46
+ - --charset=UTF-8
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ hash: 3
55
+ segments:
56
+ - 0
57
+ version: "0"
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ hash: 3
64
+ segments:
65
+ - 0
66
+ version: "0"
67
+ requirements: []
68
+
69
+ rubyforge_project:
70
+ rubygems_version: 1.3.7
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: Public api wrapper for schet.ru
74
+ test_files:
75
+ - test/helper.rb