daisybill_api 0.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.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +20 -0
  4. data/lib/daisybill_api.rb +53 -0
  5. data/lib/daisybill_api/configuration.rb +46 -0
  6. data/lib/daisybill_api/data.rb +7 -0
  7. data/lib/daisybill_api/data/client.rb +66 -0
  8. data/lib/daisybill_api/data/rest_client/payload.rb +30 -0
  9. data/lib/daisybill_api/data/url.rb +26 -0
  10. data/lib/daisybill_api/ext.rb +20 -0
  11. data/lib/daisybill_api/ext/associations.rb +39 -0
  12. data/lib/daisybill_api/ext/attributes.rb +103 -0
  13. data/lib/daisybill_api/ext/attributes/attribute.rb +60 -0
  14. data/lib/daisybill_api/ext/attributes/type_castings.rb +78 -0
  15. data/lib/daisybill_api/ext/crud.rb +147 -0
  16. data/lib/daisybill_api/ext/crud/create.rb +107 -0
  17. data/lib/daisybill_api/ext/crud/destroy.rb +28 -0
  18. data/lib/daisybill_api/ext/crud/index.rb +41 -0
  19. data/lib/daisybill_api/ext/crud/show.rb +22 -0
  20. data/lib/daisybill_api/ext/crud/update.rb +37 -0
  21. data/lib/daisybill_api/ext/links.rb +65 -0
  22. data/lib/daisybill_api/ext/links/link.rb +35 -0
  23. data/lib/daisybill_api/ext/pageable_collection.rb +124 -0
  24. data/lib/daisybill_api/models.rb +22 -0
  25. data/lib/daisybill_api/models/address.rb +16 -0
  26. data/lib/daisybill_api/models/attachment.rb +22 -0
  27. data/lib/daisybill_api/models/base.rb +29 -0
  28. data/lib/daisybill_api/models/bill.rb +42 -0
  29. data/lib/daisybill_api/models/bill_payment.rb +22 -0
  30. data/lib/daisybill_api/models/bill_submission.rb +18 -0
  31. data/lib/daisybill_api/models/billing_provider.rb +25 -0
  32. data/lib/daisybill_api/models/claims_administrator.rb +13 -0
  33. data/lib/daisybill_api/models/contact.rb +19 -0
  34. data/lib/daisybill_api/models/employer.rb +13 -0
  35. data/lib/daisybill_api/models/injury.rb +30 -0
  36. data/lib/daisybill_api/models/patient.rb +32 -0
  37. data/lib/daisybill_api/models/place_of_service.rb +29 -0
  38. data/lib/daisybill_api/models/referring_provider.rb +21 -0
  39. data/lib/daisybill_api/models/rendering_provider.rb +23 -0
  40. data/lib/daisybill_api/models/service_line_item.rb +27 -0
  41. data/lib/daisybill_api/version.rb +3 -0
  42. data/spec/daisybill_api/configuration_spec.rb +16 -0
  43. data/spec/daisybill_api/data/client_spec.rb +47 -0
  44. data/spec/daisybill_api/data/rest_client/payload_spec.rb +17 -0
  45. data/spec/daisybill_api/data/url_spec.rb +13 -0
  46. data/spec/daisybill_api/ext/attributes/attribute_spec.rb +120 -0
  47. data/spec/daisybill_api/ext/attributes/type_castings_spec.rb +50 -0
  48. data/spec/daisybill_api/ext/links/link_spec.rb +50 -0
  49. data/spec/daisybill_api/ext/pageable_collection_spec.rb +145 -0
  50. data/spec/daisybill_api/models/address_spec.rb +7 -0
  51. data/spec/daisybill_api/models/attachment_spec.rb +9 -0
  52. data/spec/daisybill_api/models/bill_payment_spec.rb +11 -0
  53. data/spec/daisybill_api/models/bill_spec.rb +22 -0
  54. data/spec/daisybill_api/models/bill_submission_spec.rb +9 -0
  55. data/spec/daisybill_api/models/billing_provider_spec.rb +13 -0
  56. data/spec/daisybill_api/models/claims_administrator_spec.rb +7 -0
  57. data/spec/daisybill_api/models/contact_spec.rb +6 -0
  58. data/spec/daisybill_api/models/employer_spec.rb +7 -0
  59. data/spec/daisybill_api/models/injury_spec.rb +13 -0
  60. data/spec/daisybill_api/models/patient_spec.rb +14 -0
  61. data/spec/daisybill_api/models/place_of_service_spec.rb +14 -0
  62. data/spec/daisybill_api/models/referring_provider_spec.rb +11 -0
  63. data/spec/daisybill_api/models/rendering_provider_spec.rb +12 -0
  64. data/spec/daisybill_api/models/service_line_item_spec.rb +11 -0
  65. data/spec/daisybill_api_spec.rb +35 -0
  66. metadata +289 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7e8269993c99548a07b1677f02fe24b0adeaaecc
4
+ data.tar.gz: db4a9a11d1b9809c664d96e85c4d06e65422fd79
5
+ SHA512:
6
+ metadata.gz: ff52d15f1e5243952fe6dd7b479ca0e06a1b552891bae4da761a1187cfd6537e0baadf7d0260d14d7579f5fd601a720dc29c62f5d3a7b46fd1971dd107f7821f
7
+ data.tar.gz: c3318559d318c167a6fe403d5e72681ead3541751a5152e85d491a260f899bebfaa32f0db4396ee010ff444657be8b3151421017121456becfcb4d6f9a094b4a
@@ -0,0 +1,20 @@
1
+ Copyright 2015 DaisyBill LLC
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,20 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require "yard"
8
+
9
+ Bundler::GemHelper.install_tasks
10
+
11
+ require 'rake/testtask'
12
+
13
+ Rake::TestTask.new(:test) do |t|
14
+ t.libs << 'lib'
15
+ t.libs << 'test'
16
+ t.pattern = 'test/**/*_test.rb'
17
+ t.verbose = false
18
+ end
19
+
20
+ task default: :test
@@ -0,0 +1,53 @@
1
+ require 'daisybill_api/data'
2
+ require 'daisybill_api/configuration'
3
+ require 'daisybill_api/ext'
4
+ require 'daisybill_api/models'
5
+
6
+ module DaisybillApi
7
+ # @private
8
+ ROOT = File.expand_path('../..', __FILE__)
9
+
10
+ class << self
11
+ attr_writer :configuration
12
+
13
+
14
+ # Returns the current configuration
15
+ #
16
+ # DaisybillApi.configuration
17
+ # # => #<DaisybillApi::Configuration:0x007fbf85e64e88 @host="go.daisybill.com", @port=443>
18
+ #
19
+ # @return [DaisybillApi::Configuration]
20
+ def configuration
21
+ @configuration ||= DaisybillApi::Configuration.new
22
+ end
23
+
24
+ # Allows configuration with a block
25
+ #
26
+ # DaisybillApi.configure do |config|
27
+ # config.host = "localhost"
28
+ # config.port = 3000
29
+ # config.api_token = "123abc"
30
+ # end
31
+ def configure
32
+ yield configuration
33
+ end
34
+
35
+ # Resets the configuration
36
+ #
37
+ # DaisybillApi.configuration.host = "localhost" # => "localhost"
38
+ # DaisybillApi.configuration.port = 3000 # => 3000
39
+ #
40
+ # DaisybillApi.reset_configuration # => nil
41
+ # DaisybillApi.configuration.host # => "go.daisybill.com"
42
+ #
43
+ # @return [nil]
44
+ def reset_configuration
45
+ @configuration = nil
46
+ end
47
+
48
+ # @private
49
+ def logger
50
+ configuration.logger
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,46 @@
1
+ require 'logger'
2
+
3
+ module DaisybillApi
4
+ class Configuration
5
+
6
+ # Sets and gets the API Token
7
+ #
8
+ # DaisybillApi.configuration.api_token # => "987654321zyxwvu"
9
+ # DaisybillApi.configuration.api_token = "123456789abcdef" # => "123456789abcdef"
10
+ # DaisybillApi.configuration.api_token # => "123456789abcdef"'
11
+ #
12
+ # @return [String]
13
+ attr_accessor :api_token
14
+
15
+ # Sets and gets the host
16
+ #
17
+ # DaisybillApi.configuration.host # => "go.daisybill.com"
18
+ # DaisybillApi.configuration.host = "localhost" # => "localhost"
19
+ # DaisybillApi.configuration.host # => "localhost"
20
+ #
21
+ # @return [String]
22
+ attr_accessor :host
23
+
24
+ # Sets and gets the port
25
+ #
26
+ # DaisybillApi.configuration.port # => 443
27
+ # DaisybillApi.configuration.port = 3000 # => 3000
28
+ # DaisybillApi.configuration.port # => 3000
29
+ #
30
+ # @return [Integer]
31
+ attr_accessor :port
32
+
33
+ # @private
34
+ attr_writer :logger
35
+
36
+ def initialize
37
+ @port = 443
38
+ @host = 'go.daisybill.com'
39
+ end
40
+
41
+ # @private
42
+ def logger
43
+ @logger ||= Logger.new nil
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,7 @@
1
+ require 'daisybill_api/data/url'
2
+ require 'daisybill_api/data/client'
3
+
4
+ module DaisybillApi
5
+ module Data
6
+ end
7
+ end
@@ -0,0 +1,66 @@
1
+ require 'rest-client'
2
+ require 'daisybill_api/data/rest_client/payload'
3
+
4
+ module DaisybillApi
5
+ # @private
6
+ module Data
7
+ class Client
8
+ class InternalServerError < Exception; end
9
+
10
+ class UnauthorizedError < Exception; end
11
+
12
+ def self.build(method, path, params = {})
13
+ client = new method, path, params
14
+ raise InternalServerError.new(client.response['error']) if client.error?
15
+ raise UnauthorizedError.new(client.response['error']) if client.unauthorized?
16
+ client
17
+ end
18
+
19
+ attr_reader :response, :request, :headers
20
+
21
+ def initialize(method, path, params = {})
22
+ DaisybillApi.logger.info "#{method.to_s.upcase} #{path}"
23
+ DaisybillApi.logger.debug params.inspect
24
+ url = DaisybillApi::Data::Url.build(path).to_s
25
+ data = {
26
+ method: method,
27
+ url: url,
28
+ payload: params,
29
+ headers: { 'Content-Type' => 'application/json' }
30
+ }
31
+ RestClient::Request.execute(data) { |response, request, status|
32
+ @headers = response.headers
33
+ @response = JSON.parse response
34
+ @request = request
35
+ @status = status
36
+ DaisybillApi.logger.info "Response status #{self.status}"
37
+ DaisybillApi.logger.debug @response.inspect
38
+ }
39
+ end
40
+
41
+ def status
42
+ @status.code
43
+ end
44
+
45
+ def success?
46
+ status == '200' || status == '201'
47
+ end
48
+
49
+ def bad_request?
50
+ status == '400'
51
+ end
52
+
53
+ def unauthorized?
54
+ status == '401'
55
+ end
56
+
57
+ def not_found?
58
+ status == '404'
59
+ end
60
+
61
+ def error?
62
+ status == '500'
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,30 @@
1
+ # @private
2
+ module RestClient
3
+ module Payload
4
+ class Base
5
+ def flatten_params_array(value, calculated_key)
6
+ result = []
7
+ key = "#{calculated_key}[]"
8
+ value.each do |elem|
9
+ if elem.is_a? Hash
10
+ result += flatten_params(elem, key)
11
+ elsif elem.is_a? Array
12
+ result += flatten_params_array(elem, key)
13
+ else
14
+ result << [key, elem]
15
+ end
16
+ end
17
+ result
18
+ end
19
+ end
20
+
21
+ class UrlEncoded
22
+ def build_stream(params = nil)
23
+ @stream = StringIO.new(flatten_params(params).collect do |entry|
24
+ entry[1].nil? ? entry[0] : "#{entry[0]}=#{handle_key(entry[1])}"
25
+ end.join("&"))
26
+ @stream.seek(0)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,26 @@
1
+ require 'uri/http'
2
+
3
+ module DaisybillApi
4
+ module Data
5
+ module Url
6
+ DEFAULT_PATH = '/api/v1'
7
+
8
+ class << self
9
+ def build(path, params = {})
10
+ port = DaisybillApi.configuration.port
11
+ builder = port == 443 ? URI::HTTPS : URI::HTTP
12
+ builder.build({
13
+ host: DaisybillApi.configuration.host,
14
+ port: port,
15
+ path: "#{DEFAULT_PATH}#{path}",
16
+ query: to_query(params.merge api_token: DaisybillApi.configuration.api_token)
17
+ })
18
+ end
19
+
20
+ def to_query(hash)
21
+ URI.encode_www_form hash
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,20 @@
1
+ require 'daisybill_api/ext/attributes'
2
+ require 'daisybill_api/ext/links'
3
+ require 'daisybill_api/ext/crud'
4
+ require 'daisybill_api/ext/associations'
5
+ require 'daisybill_api/ext/pageable_collection'
6
+
7
+ module DaisybillApi
8
+ module Ext
9
+ class << self
10
+ def extended(base)
11
+ base.class_eval do
12
+ include DaisybillApi::Ext::Attributes
13
+ include DaisybillApi::Ext::Links
14
+ include DaisybillApi::Ext::CRUD
15
+ include DaisybillApi::Ext::Associations
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,39 @@
1
+ module DaisybillApi
2
+ module Ext
3
+ # @private
4
+ module Associations
5
+ module ClassMethods #TODO: Think about creating Association classes or Routing class
6
+ def foreign_key=(value)
7
+ @foreign_key = value
8
+ end
9
+
10
+ def foreign_key
11
+ @foreign_key
12
+ end
13
+
14
+ def has_many(name, options = {})
15
+ clazz = modulize options[:class]
16
+ define_method name do |params = {}|
17
+ params.merge!(:"#{self.class.singular_key}_id" => self.id)
18
+ clazz.constantize.all(params)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def modulize(name)
25
+ "DaisybillApi::Models::#{name}"
26
+ end
27
+ end
28
+
29
+ def self.included(base)
30
+ base.class_eval do
31
+ include DaisybillApi::Ext::Associations::InstanceMethods
32
+ extend DaisybillApi::Ext::Associations::ClassMethods
33
+ end
34
+ end
35
+
36
+ module InstanceMethods; end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,103 @@
1
+ require 'daisybill_api/ext/attributes/type_castings'
2
+ require 'daisybill_api/ext/attributes/attribute'
3
+
4
+ module DaisybillApi
5
+ module Ext
6
+ # @private
7
+ module Attributes
8
+ module ClassMethods
9
+ def attribute(name, type, options = {})
10
+ attrs[name.to_s] = Attribute.new(name, type, options)
11
+ class_eval do
12
+ define_method(name) { read_attribute name }
13
+ define_method(:"#{name}=") { |value| write_attribute name, value }
14
+ end
15
+ end
16
+
17
+ def attributes(attrs)
18
+ options = extract_options(attrs)
19
+ attrs.each { |name, type| attribute(name, type, options) }
20
+ attribute :created_at, :datetime, readonly: true
21
+ attribute :updated_at, :datetime, readonly: true
22
+ end
23
+
24
+ def attrs
25
+ @attrs ||= {}
26
+ end
27
+
28
+ def inspect
29
+ "<#{name} #{attrs.map{ |k, v| "#{k}: #{v.type}"}.join(', ')}>"
30
+ end
31
+
32
+ private
33
+
34
+ OPTION_KEYS = [:readonly]
35
+
36
+ def extract_options(attributes)
37
+ OPTION_KEYS.each_with_object({}) { |key, result|
38
+ result[key] = attributes.delete key
39
+ }
40
+ end
41
+ end
42
+
43
+ module InstanceMethods
44
+ def initialize(attributes = {})
45
+ class_attrs.each { |a| attrs[a.name.to_sym] = a.clone }
46
+ self.attributes = attributes
47
+ end
48
+
49
+ def attributes
50
+ class_attrs.each_with_object({}) { |attr, result|
51
+ result[attr.name] = read_attribute(attr.name)
52
+ }
53
+ end
54
+
55
+ def attributes=(attributes)
56
+ attributes.each { |name, value|
57
+ if attrs[name.to_sym]
58
+ write_attribute name, value
59
+ else
60
+ message = "Was trying to set non-existent attribute #{name.inspect} to #{value.inspect}"
61
+ DaisybillApi.logger.debug message
62
+ end
63
+ }
64
+ end
65
+
66
+ def to_params
67
+ attrs.values.each_with_object({}) { |attr, result|
68
+ result.merge! attr.to_param
69
+ }
70
+ end
71
+
72
+ def inspect
73
+ "<#{self.class.name} #{attributes.map { |k, v| "#{k}: #{v.inspect}" }.join(', ')}>"
74
+ end
75
+
76
+ private
77
+
78
+ def read_attribute(name)
79
+ attrs[name.to_sym].value
80
+ end
81
+
82
+ def write_attribute(name, value)
83
+ attrs[name.to_sym].value = value
84
+ end
85
+
86
+ def class_attrs
87
+ @class_attrs ||= self.class.attrs.values
88
+ end
89
+
90
+ def attrs
91
+ @attrs ||= {}
92
+ end
93
+ end
94
+
95
+ def self.included(base)
96
+ base.class_eval do
97
+ include DaisybillApi::Ext::Attributes::InstanceMethods
98
+ extend DaisybillApi::Ext::Attributes::ClassMethods
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end