baabedo 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 61434ffedb6433c45f9108a0109cee173e3c54b8
4
+ data.tar.gz: 5f0caa4785b0db8160ab5ac3a6ec475a5ac14377
5
+ SHA512:
6
+ metadata.gz: 5334eab942b46b1d8ed382da70675a092919b42628c0ab999a61e755f6516065d68225a181f29da4a424451ea4bec5c7cc0736df1e5f3fc9e23d229fd54cc245
7
+ data.tar.gz: d28741c3992fa960b5700ec5dc30402feb59ea6b4a253b775af71b8368fdfd25af6ec4b5ef0a46fab3868a0e46cff014432423e132241952b682088297d63fad
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in baabedo-public.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,77 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ ## Uncomment and set this to only include directories you want to watch
5
+ # directories %w(app lib config test spec features)
6
+
7
+ ## Uncomment to clear the screen before every task
8
+ # clearing :on
9
+
10
+ ## Guard internally checks for changes in the Guardfile and exits.
11
+ ## If you want Guard to automatically start up again, run guard in a
12
+ ## shell loop, e.g.:
13
+ ##
14
+ ## $ while bundle exec guard; do echo "Restarting Guard..."; done
15
+ ##
16
+ ## Note: if you are using the `directories` clause above and you are not
17
+ ## watching the project directory ('.'), then you will want to move
18
+ ## the Guardfile to a watched dir and symlink it back, e.g.
19
+ #
20
+ # $ mkdir config
21
+ # $ mv Guardfile config/
22
+ # $ ln -s config/Guardfile .
23
+ #
24
+ # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
25
+
26
+ # Note: The cmd option is now required due to the increasing number of ways
27
+ # rspec may be run, below are examples of the most common uses.
28
+ # * bundler: 'bundle exec rspec'
29
+ # * bundler binstubs: 'bin/rspec'
30
+ # * spring: 'bin/rspec' (This will use spring if running and you have
31
+ # installed the spring binstubs per the docs)
32
+ # * zeus: 'zeus rspec' (requires the server to be started separately)
33
+ # * 'just' rspec: 'rspec'
34
+
35
+ guard :rspec, cmd: "bundle exec rspec" do
36
+ require "guard/rspec/dsl"
37
+ dsl = Guard::RSpec::Dsl.new(self)
38
+
39
+ # Feel free to open issues for suggestions and improvements
40
+
41
+ # RSpec files
42
+ rspec = dsl.rspec
43
+ watch(rspec.spec_helper) { rspec.spec_dir }
44
+ watch(rspec.spec_support) { rspec.spec_dir }
45
+ watch(rspec.spec_files)
46
+
47
+ # Ruby files
48
+ ruby = dsl.ruby
49
+ dsl.watch_spec_files_for(ruby.lib_files)
50
+
51
+ # Rails files
52
+ rails = dsl.rails(view_extensions: %w(erb haml slim))
53
+ dsl.watch_spec_files_for(rails.app_files)
54
+ dsl.watch_spec_files_for(rails.views)
55
+
56
+ watch(rails.controllers) do |m|
57
+ [
58
+ rspec.spec.("routing/#{m[1]}_routing"),
59
+ rspec.spec.("controllers/#{m[1]}_controller"),
60
+ rspec.spec.("acceptance/#{m[1]}")
61
+ ]
62
+ end
63
+
64
+ # Rails config changes
65
+ watch(rails.spec_helper) { rspec.spec_dir }
66
+ watch(rails.routes) { "#{rspec.spec_dir}/routing" }
67
+ watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
68
+
69
+ # Capybara features specs
70
+ watch(rails.view_dirs) { |m| rspec.spec.("features/#{m[1]}") }
71
+
72
+ # Turnip features and steps
73
+ watch(%r{^spec/acceptance/(.+)\.feature$})
74
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m|
75
+ Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance"
76
+ end
77
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Storeness UG(haftungsbeschraenkt)
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # Baabedo Ruby bindings
2
+
3
+ Ruby bindings for the Baabedo API
4
+
5
+ **still under construction**
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'baabedo'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install baabedo
22
+
23
+ ## Usage
24
+
25
+ Simple usage:
26
+
27
+ ```
28
+ Baabedo.access_token = 'xxxxxxxxxxxxx'
29
+
30
+ Baabedo::Channel.all # list all channels
31
+ ```
32
+
33
+ Advanced usage if you need to handle different access_tokens
34
+
35
+ ```
36
+ client = Baabedo::Client.new
37
+ client.access_token = 'xxxxxxxxxxxxx'
38
+
39
+ # the access_token and any other configuration made on the client will only be used inside this block
40
+ client.use do
41
+ Baabedo::Channel.all
42
+ end
43
+
44
+ ```
45
+
46
+ ## Contributing
47
+
48
+ ### For bugfixes:
49
+
50
+ 1. Fork it ( https://github.com/[my-github-username]/baabedo-ruby/fork )
51
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
52
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
53
+ 4. Push to the branch (`git push origin my-new-feature`)
54
+ 5. Create a new Pull Request
55
+
56
+ ### For new features:
57
+
58
+ If you want to request a new feature in the API, please create an issue first. :)
59
+
60
+ ## Thank you
61
+
62
+ A huge thank you to the Stripe team for stripe-ruby!
63
+
64
+ This gem is based on [stripe-ruby](https://github.com/stripe/stripe-ruby)
65
+ at [8ba1a0e4908cccf20198791aa8f72acc63575589](https://github.com/stripe/stripe-ruby/tree/8ba1a0e4908cccf20198791aa8f72acc63575589)
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/baabedo.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'baabedo/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "baabedo"
8
+ spec.version = Baabedo::VERSION
9
+ spec.authors = ["Maximilian Goisser"]
10
+ spec.email = ["maximilian.goiser@baabedo.com"]
11
+ spec.summary = %q{Ruby bindings for the Baabedo API}
12
+ spec.description = %q{Baabedo is an easy to use price optimization AI. See https://baabedo.com}
13
+ spec.homepage = "https://baabedo.com/api"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency('rest-client', '~> 1.4')
22
+ spec.add_dependency('json', '~> 1.8.1')
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.7"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec", "~> 3.2"
27
+ spec.add_development_dependency "guard-rspec", "~> 4.5"
28
+ end
@@ -0,0 +1,263 @@
1
+ module Baabedo
2
+ class APIObject
3
+ include Enumerable
4
+
5
+ @@permanent_attributes = Set.new([:id])
6
+
7
+ # The default :id method is deprecated and isn't useful to us
8
+ if method_defined?(:id)
9
+ undef :id
10
+ end
11
+
12
+ def initialize(id=nil, opts={})
13
+ # parameter overloading!
14
+ if id.kind_of?(Hash)
15
+ @retrieve_params = id.dup
16
+ @retrieve_params.delete(:id)
17
+ id = id[:id]
18
+ else
19
+ @retrieve_params = {}
20
+ end
21
+
22
+ @opts = opts
23
+ @values = {}
24
+ # This really belongs in APIResource, but not putting it there allows us
25
+ # to have a unified inspect method
26
+ @unsaved_values = Set.new
27
+ @transient_values = Set.new
28
+ @values[:id] = id if id
29
+ end
30
+
31
+ def self.construct_from(values, opts={})
32
+ self.new(values[:id]).refresh_from(values, opts)
33
+ end
34
+
35
+ def to_s(*args)
36
+ JSON.pretty_generate(@values)
37
+ end
38
+
39
+ def inspect
40
+ id_string = (self.respond_to?(:id) && !self.id.nil?) ? " id=#{self.id}" : ""
41
+ "#<#{self.class}:0x#{self.object_id.to_s(16)}#{id_string}> JSON: " + JSON.pretty_generate(@values)
42
+ end
43
+
44
+ def refresh_from(values, opts, partial=false)
45
+ @opts = opts
46
+ @original_values = Marshal.load(Marshal.dump(values)) # deep copy
47
+ removed = partial ? Set.new : Set.new(@values.keys - values.keys)
48
+ added = Set.new(values.keys - @values.keys)
49
+ # Wipe old state before setting new. This is useful for e.g. updating a
50
+ # customer, where there is no persistent card parameter. Mark those values
51
+ # which don't persist as transient
52
+
53
+ instance_eval do
54
+ remove_accessors(removed)
55
+ add_accessors(added)
56
+ end
57
+ removed.each do |k|
58
+ @values.delete(k)
59
+ @transient_values.add(k)
60
+ @unsaved_values.delete(k)
61
+ end
62
+ values.each do |k, v|
63
+ @values[k] = Util.convert_to_api_object(v, @opts)
64
+ @transient_values.delete(k)
65
+ @unsaved_values.delete(k)
66
+ end
67
+
68
+ return self
69
+ end
70
+
71
+ def [](k)
72
+ @values[k.to_sym]
73
+ end
74
+
75
+ def []=(k, v)
76
+ send(:"#{k}=", v)
77
+ end
78
+
79
+ def keys
80
+ @values.keys
81
+ end
82
+
83
+ def values
84
+ @values.values
85
+ end
86
+
87
+ def to_json(*a)
88
+ JSON.generate(@values)
89
+ end
90
+
91
+ def as_json(*a)
92
+ @values.as_json(*a)
93
+ end
94
+
95
+ def to_hash
96
+ @values.inject({}) do |acc, (key, value)|
97
+ acc[key] = value.respond_to?(:to_hash) ? value.to_hash : value
98
+ acc
99
+ end
100
+ end
101
+
102
+ def each(&blk)
103
+ @values.each(&blk)
104
+ end
105
+
106
+ def _dump(level)
107
+ Marshal.dump([@values, @opts])
108
+ end
109
+
110
+ def self._load(args)
111
+ values, opts = Marshal.load(args)
112
+ construct_from(values, opts)
113
+ end
114
+
115
+ if RUBY_VERSION < '1.9.2'
116
+ def respond_to?(symbol)
117
+ @values.has_key?(symbol) || super
118
+ end
119
+ end
120
+
121
+ def serialize_nested_object(key)
122
+ new_value = @values[key]
123
+ if new_value.is_a?(APIResource)
124
+ return {}
125
+ end
126
+
127
+ if @unsaved_values.include?(key)
128
+ # the object has been reassigned
129
+ # e.g. as object.key = {foo => bar}
130
+ update = new_value
131
+ new_keys = update.keys.map(&:to_sym)
132
+
133
+ # remove keys at the server, but not known locally
134
+ if @original_values.include?(key)
135
+ keys_to_unset = @original_values[key].keys - new_keys
136
+ keys_to_unset.each {|key| update[key] = ''}
137
+ end
138
+
139
+ update
140
+ else
141
+ # can be serialized normally
142
+ self.class.serialize_params(new_value)
143
+ end
144
+ end
145
+
146
+ def self.serialize_params(obj, original_value=nil)
147
+ case obj
148
+ when nil
149
+ ''
150
+ when APIObject
151
+ unsaved_keys = obj.instance_variable_get(:@unsaved_values)
152
+ obj_values = obj.instance_variable_get(:@values)
153
+ update_hash = {}
154
+
155
+ unsaved_keys.each do |k|
156
+ update_hash[k] = serialize_params(obj_values[k])
157
+ end
158
+
159
+ obj_values.each do |k, v|
160
+ if v.is_a?(APIObject) || v.is_a?(Hash)
161
+ update_hash[k] = obj.serialize_nested_object(k)
162
+ elsif v.is_a?(Array)
163
+ original_value = obj.instance_variable_get(:@original_values)[k]
164
+ if original_value && original_value.length > v.length
165
+ # url params provide no mechanism for deleting an item in an array,
166
+ # just overwriting the whole array or adding new items. So let's not
167
+ # allow deleting without a full overwrite until we have a solution.
168
+ raise ArgumentError.new(
169
+ "You cannot delete an item from an array, you must instead set a new array"
170
+ )
171
+ end
172
+ update_hash[k] = serialize_params(v, original_value)
173
+ end
174
+ end
175
+
176
+ update_hash
177
+ when Array
178
+ update_hash = {}
179
+ obj.each_with_index do |value, index|
180
+ update = serialize_params(value)
181
+ if update != {} && (!original_value || update != original_value[index])
182
+ update_hash[index] = update
183
+ end
184
+ end
185
+
186
+ if update_hash == {}
187
+ nil
188
+ else
189
+ update_hash
190
+ end
191
+ else
192
+ obj
193
+ end
194
+ end
195
+
196
+ protected
197
+
198
+ def metaclass
199
+ class << self; self; end
200
+ end
201
+
202
+ def remove_accessors(keys)
203
+ metaclass.instance_eval do
204
+ keys.each do |k|
205
+ next if @@permanent_attributes.include?(k)
206
+ k_eq = :"#{k}="
207
+ remove_method(k) if method_defined?(k)
208
+ remove_method(k_eq) if method_defined?(k_eq)
209
+ end
210
+ end
211
+ end
212
+
213
+ def add_accessors(keys)
214
+ metaclass.instance_eval do
215
+ keys.each do |k|
216
+ next if @@permanent_attributes.include?(k)
217
+ k_eq = :"#{k}="
218
+ define_method(k) { @values[k] }
219
+ define_method(k_eq) do |v|
220
+ if v == ""
221
+ raise ArgumentError.new(
222
+ "You cannot set #{k} to an empty string." \
223
+ "We interpret empty strings as nil in requests." \
224
+ "You may set #{self}.#{k} = nil to delete the property.")
225
+ end
226
+ @values[k] = v
227
+ @unsaved_values.add(k)
228
+ end
229
+ end
230
+ end
231
+ end
232
+
233
+ def method_missing(name, *args)
234
+ # TODO: only allow setting in updateable classes.
235
+ if name.to_s.end_with?('=')
236
+ attr = name.to_s[0...-1].to_sym
237
+ add_accessors([attr])
238
+ begin
239
+ mth = method(name)
240
+ rescue NameError
241
+ raise NoMethodError.new("Cannot set #{attr} on this object. HINT: you can't set: #{@@permanent_attributes.to_a.join(', ')}")
242
+ end
243
+ return mth.call(args[0])
244
+ else
245
+ return @values[name] if @values.has_key?(name)
246
+ end
247
+
248
+ begin
249
+ super
250
+ rescue NoMethodError => e
251
+ if @transient_values.include?(name)
252
+ raise NoMethodError.new(e.message + ". HINT: The '#{name}' attribute was set in the past, however. It was then wiped when refreshing the object with the result returned by Baabedo's API, probably as a result of a save(). The attributes currently available on this object are: #{@values.keys.join(', ')}")
253
+ else
254
+ raise
255
+ end
256
+ end
257
+ end
258
+
259
+ def respond_to_missing?(symbol, include_private = false)
260
+ @values && @values.has_key?(symbol) || super
261
+ end
262
+ end
263
+ end
@@ -0,0 +1,16 @@
1
+ module Baabedo
2
+ module APIOperations
3
+ module Create
4
+ module ClassMethods
5
+ def create(params={}, opts={})
6
+ response, opts = request(:post, url, params, opts)
7
+ Util.convert_to_api_object(response, opts)
8
+ end
9
+ end
10
+
11
+ def self.included(base)
12
+ base.extend(ClassMethods)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+ module Baabedo
2
+ module APIOperations
3
+ module Delete
4
+ def delete(params={}, opts={})
5
+ opts = Util.normalize_opts(opts)
6
+ response, opts = request(:delete, url, params, opts)
7
+ refresh_from(response, opts)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ module Baabedo
2
+ module APIOperations
3
+ module List
4
+ module ClassMethods
5
+ def all(filters={}, opts={})
6
+ opts = Util.normalize_opts(opts)
7
+ response, opts = request(:get, url, filters, opts)
8
+ Util.convert_to_api_object(response, opts)
9
+ end
10
+ end
11
+
12
+ def self.included(base)
13
+ base.extend(ClassMethods)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,41 @@
1
+ module Baabedo
2
+ module APIOperations
3
+ module Request
4
+ module ClassMethods
5
+ OPTS_KEYS_TO_PERSIST = Set[:access_token, :api_base, :api_version]
6
+
7
+ def request(method, url, params={}, opts={})
8
+ opts = Util.normalize_opts(opts)
9
+
10
+ headers = opts.clone
11
+ access_token = headers.delete(:access_token)
12
+ api_base = headers.delete(:api_base)
13
+ # Assume all remaining opts must be headers
14
+
15
+ response, opts[:access_token] = Baabedo.request(method, url, access_token, params, headers, api_base)
16
+
17
+ # Hash#select returns an array before 1.9
18
+ opts_to_persist = {}
19
+ opts.each do |k, v|
20
+ if OPTS_KEYS_TO_PERSIST.include?(k)
21
+ opts_to_persist[k] = v
22
+ end
23
+ end
24
+
25
+ [response, opts_to_persist]
26
+ end
27
+ end
28
+
29
+ def self.included(base)
30
+ base.extend(ClassMethods)
31
+ end
32
+
33
+ protected
34
+
35
+ def request(method, url, params={}, opts={})
36
+ opts = @opts.merge(Util.normalize_opts(opts))
37
+ self.class.request(method, url, params, opts)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,17 @@
1
+ module Baabedo
2
+ module APIOperations
3
+ module Update
4
+ def save(params={})
5
+ values = self.class.serialize_params(self).merge(params)
6
+
7
+ if values.length > 0
8
+ values.delete(:id)
9
+
10
+ response, opts = request(:post, url, values)
11
+ refresh_from(response, opts)
12
+ end
13
+ self
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,37 @@
1
+ module Baabedo
2
+ class APIResource < APIObject
3
+ include Baabedo::APIOperations::Request
4
+
5
+ def self.class_name
6
+ self.name.split('::')[-1]
7
+ end
8
+
9
+ def self.url
10
+ if self == APIResource
11
+ raise NotImplementedError.new('APIResource is an abstract class. You should perform actions on its subclasses (Charge, Customer, etc.)')
12
+ end
13
+ type_endpoint = CGI.escape(class_name.downcase)
14
+ type_endpoint = type_endpoint.gsub(/y$/, 'ies') # pluralize for companies
15
+ "/#{Baabedo.api_version}/#{type_endpoint}"
16
+ end
17
+
18
+ def url
19
+ unless id = self['id']
20
+ raise InvalidRequestError.new("Could not determine which URL to request: #{self.class} instance has invalid ID: #{id.inspect}", 'id')
21
+ end
22
+ "#{self.class.url}/#{CGI.escape(id)}"
23
+ end
24
+
25
+ def refresh
26
+ response, opts = request(:get, url, @retrieve_params)
27
+ refresh_from(response, opts)
28
+ end
29
+
30
+ def self.retrieve(id, opts={})
31
+ opts = Util.normalize_opts(opts)
32
+ instance = self.new(id, opts)
33
+ instance.refresh
34
+ instance
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,29 @@
1
+ module Baabedo
2
+ class Client
3
+ attr_accessor :access_token, :api_base, :api_version, :verify_ssl_certs
4
+
5
+ def use
6
+ Baabedo.with_mutex do
7
+ begin
8
+ save = {}
9
+ save[:access_token] = Baabedo.access_token
10
+ save[:api_base] = Baabedo.api_base
11
+ save[:api_version] = Baabedo.api_version
12
+ save[:verify_ssl_certs] = Baabedo.verify_ssl_certs
13
+
14
+ Baabedo.access_token = access_token if access_token
15
+ Baabedo.api_base = api_base if api_base
16
+ Baabedo.api_version = api_version if api_version
17
+ Baabedo.verify_ssl_certs = verify_ssl_certs if verify_ssl_certs
18
+
19
+ yield
20
+ ensure
21
+ Baabedo.access_token = save[:access_token]
22
+ Baabedo.api_base = save[:api_base]
23
+ Baabedo.api_version = save[:api_version]
24
+ Baabedo.verify_ssl_certsapi_version = save[:verify_ssl_certs]
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,4 @@
1
+ module Baabedo
2
+ class APIConnectionError < BaabedoError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Baabedo
2
+ class APIError < BaabedoError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Baabedo
2
+ class AuthenticationError < BaabedoError
3
+ end
4
+ end