boffinio 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +29 -0
  6. data/Rakefile +2 -0
  7. data/boffinio.gemspec +31 -0
  8. data/lib/boffinio/api_operations/create.rb +16 -0
  9. data/lib/boffinio/api_operations/delete.rb +11 -0
  10. data/lib/boffinio/api_operations/list.rb +16 -0
  11. data/lib/boffinio/api_operations/update.rb +57 -0
  12. data/lib/boffinio/api_resource.rb +33 -0
  13. data/lib/boffinio/boffinio_object.rb +190 -0
  14. data/lib/boffinio/customer.rb +36 -0
  15. data/lib/boffinio/errors/api_error.rb +4 -0
  16. data/lib/boffinio/errors/authentication_error.rb +4 -0
  17. data/lib/boffinio/errors/boffinio_error.rb +20 -0
  18. data/lib/boffinio/errors/invalid_request_error.rb +4 -0
  19. data/lib/boffinio/list_object.rb +35 -0
  20. data/lib/boffinio/plan.rb +7 -0
  21. data/lib/boffinio/subscription.rb +10 -0
  22. data/lib/boffinio/util.rb +87 -0
  23. data/lib/boffinio/version.rb +3 -0
  24. data/lib/boffinio.rb +229 -0
  25. data/test/customer/customer_test.rb +149 -0
  26. data/test/fixtures/all_customers.yml +62 -0
  27. data/test/fixtures/cancel_subscription.yml +62 -0
  28. data/test/fixtures/create_customer.yml +66 -0
  29. data/test/fixtures/create_subscription.yml +66 -0
  30. data/test/fixtures/customer_subscriptions.yml +62 -0
  31. data/test/fixtures/one_customer.yml +67 -0
  32. data/test/fixtures/update_customer.yml +64 -0
  33. data/test/fixtures/update_named_subscription.yml +64 -0
  34. data/test/fixtures/update_subscription.yml +66 -0
  35. data/test/subscription/subscription_test.rb +0 -0
  36. data/test/test_helper.rb +13 -0
  37. metadata +210 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cc5e3dd39ced57fc37476164d47fa27484c0d44f
4
+ data.tar.gz: c6580ad97f7899de92e4e43e347a599bdeb3b69b
5
+ SHA512:
6
+ metadata.gz: 5c5798f070896462537939c5337c8d2308dd1f8927146757793f75e258cdc20db969b08fa94dfa5dfadee64b115e378c8036a142b77eb774bffeeccbc5859b70
7
+ data.tar.gz: 3f189982b3af8be9e9ccc467aa8832a28312820157679b0693e877ee96eff3426aafe9211a7af340f449105f28ca8b5d5057062b414a98aedaecd45ed3e228d3
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in boffinio.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Tim Williams
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,29 @@
1
+ # Boffinio
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'boffinio'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install boffinio
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( https://github.com/[my-github-username]/boffinio/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/boffinio.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'boffinio/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "boffinio"
8
+ spec.version = BoffinIO::VERSION
9
+ spec.authors = ["Tim Williams"]
10
+ spec.email = ["tim@teachmatic.com"]
11
+ spec.summary = %q{Gem wrapper for the Boffin.io API}
12
+ spec.description = %q{Gem wrapper for the Boffin.io API. Officially supported and maintained by the Boffin.io team }
13
+ spec.homepage = "http://www.boffin.io"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split("\n")
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_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "minitest", "~> 5.4"
24
+ spec.add_development_dependency "vcr", '~> 2.9'
25
+ spec.add_development_dependency "webmock",'~> 1.20'
26
+
27
+ spec.add_dependency('rest-client', '~> 1.4')
28
+ spec.add_dependency('json', '~> 1.8')
29
+ spec.add_dependency('mime-types', '>= 1.25', '< 3.0')
30
+
31
+ end
@@ -0,0 +1,16 @@
1
+ module BoffinIO
2
+ module APIOperations
3
+ module Create
4
+ module ClassMethods
5
+ def create(params={}, api_key=nil)
6
+ response, api_key = BoffinIO.request(:post, self.url, api_key, params)
7
+ Util.convert_to_boffinio_object(response, api_key)
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 BoffinIO
2
+ module APIOperations
3
+ module Delete
4
+ def delete(params = {})
5
+ response, api_key = BoffinIO.request(:delete, url, @api_key, params)
6
+ refresh_from(response, api_key)
7
+ self
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ module BoffinIO
2
+ module APIOperations
3
+ module List
4
+ module ClassMethods
5
+ def all(filters={}, api_key=nil)
6
+ response, api_key = BoffinIO.request(:get, url, api_key, filters)
7
+ Util.convert_to_boffinio_object(response, api_key)
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,57 @@
1
+ module BoffinIO
2
+ module APIOperations
3
+ module Update
4
+ def save(opts={})
5
+ values = serialize_params(self).merge(opts)
6
+
7
+ if @values[:metadata]
8
+ values[:metadata] = serialize_metadata
9
+ end
10
+
11
+ if values.length > 0
12
+ values.delete(:id)
13
+
14
+ response, api_key = BoffinIO.request(:put, url, @api_key, values)
15
+ refresh_from(response, api_key)
16
+ end
17
+ self
18
+ end
19
+
20
+ def serialize_metadata
21
+ if @unsaved_values.include?(:metadata)
22
+ # the metadata object has been reassigned
23
+ # i.e. as object.metadata = {key => val}
24
+ metadata_update = @values[:metadata] # new hash
25
+ new_keys = metadata_update.keys.map(&:to_sym)
26
+ # remove keys at the server, but not known locally
27
+ keys_to_unset = @previous_metadata.keys - new_keys
28
+ keys_to_unset.each {|key| metadata_update[key] = ''}
29
+
30
+ metadata_update
31
+ else
32
+ # metadata is a BoffinIOObject, and can be serialized normally
33
+ serialize_params(@values[:metadata])
34
+ end
35
+ end
36
+
37
+ def serialize_params(obj)
38
+ case obj
39
+ when nil
40
+ ''
41
+ when BoffinIOObject
42
+ unsaved_keys = obj.instance_variable_get(:@unsaved_values)
43
+ obj_values = obj.instance_variable_get(:@values)
44
+ update_hash = {}
45
+
46
+ unsaved_keys.each do |k|
47
+ update_hash[k] = serialize_params(obj_values[k])
48
+ end
49
+
50
+ update_hash
51
+ else
52
+ obj
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,33 @@
1
+ module BoffinIO
2
+ class APIResource < BoffinIOObject
3
+ def self.class_name
4
+ self.name.split('::')[-1]
5
+ end
6
+
7
+ def self.url()
8
+ if self == APIResource
9
+ raise NotImplementedError.new('APIResource is an abstract class. You should perform actions on its subclasses (Charge, Customer, etc.)')
10
+ end
11
+ "/v1/#{CGI.escape(class_name.downcase)}s"
12
+ end
13
+
14
+ def url
15
+ unless id = self['id']
16
+ raise InvalidRequestError.new("Could not determine which URL to request: #{self.class} instance has invalid ID: #{id.inspect}", 'id')
17
+ end
18
+ "#{self.class.url}/#{CGI.escape(id)}"
19
+ end
20
+
21
+ def refresh
22
+ response, api_key = BoffinIO.request(:get, url, @api_key, @retrieve_options)
23
+ refresh_from(response, api_key)
24
+ self
25
+ end
26
+
27
+ def self.retrieve(id, api_key=nil)
28
+ instance = self.new(id, api_key)
29
+ instance.refresh
30
+ instance
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,190 @@
1
+ module BoffinIO
2
+ class BoffinIOObject
3
+ include Enumerable
4
+
5
+ attr_accessor :api_key
6
+ @@permanent_attributes = Set.new([:api_key, :id])
7
+
8
+ # The default :id method is deprecated and isn't useful to us
9
+ if method_defined?(:id)
10
+ undef :id
11
+ end
12
+
13
+ def initialize(id=nil, api_key=nil)
14
+ # parameter overloading!
15
+ if id.kind_of?(Hash)
16
+ @retrieve_options = id.dup
17
+ @retrieve_options.delete(:id)
18
+ id = id[:id]
19
+ else
20
+ @retrieve_options = {}
21
+ end
22
+
23
+ @api_key = api_key
24
+ @values = {}
25
+ # This really belongs in APIResource, but not putting it there allows us
26
+ # to have a unified inspect method
27
+ @unsaved_values = Set.new
28
+ @transient_values = Set.new
29
+ @values[:id] = id if id
30
+ end
31
+
32
+ def self.construct_from(values, api_key=nil)
33
+ obj = self.new(values[:id], api_key)
34
+ obj.refresh_from(values, api_key)
35
+ obj
36
+ end
37
+
38
+ def to_s(*args)
39
+ JSON.pretty_generate(@values)
40
+ end
41
+
42
+ def inspect()
43
+ id_string = (self.respond_to?(:id) && !self.id.nil?) ? " id=#{self.id}" : ""
44
+ "#<#{self.class}:0x#{self.object_id.to_s(16)}#{id_string}> JSON: " + JSON.pretty_generate(@values)
45
+ end
46
+
47
+ def refresh_from(values, api_key, partial=false)
48
+ @api_key = api_key
49
+
50
+ @previous_metadata = values[:metadata]
51
+ removed = partial ? Set.new : Set.new(@values.keys - values.keys)
52
+ added = Set.new(values.keys - @values.keys)
53
+ # Wipe old state before setting new. This is useful for e.g. updating a
54
+ # customer, where there is no persistent card parameter. Mark those values
55
+ # which don't persist as transient
56
+
57
+ instance_eval do
58
+ remove_accessors(removed)
59
+ add_accessors(added)
60
+ end
61
+ removed.each do |k|
62
+ @values.delete(k)
63
+ @transient_values.add(k)
64
+ @unsaved_values.delete(k)
65
+ end
66
+ values.each do |k, v|
67
+ @values[k] = Util.convert_to_boffinio_object(v, api_key)
68
+ @transient_values.delete(k)
69
+ @unsaved_values.delete(k)
70
+ end
71
+ end
72
+
73
+ def [](k)
74
+ @values[k.to_sym]
75
+ end
76
+
77
+ def []=(k, v)
78
+ send(:"#{k}=", v)
79
+ end
80
+
81
+ def keys
82
+ @values.keys
83
+ end
84
+
85
+ def values
86
+ @values.values
87
+ end
88
+
89
+ def to_json(*a)
90
+ JSON.generate(@values)
91
+ end
92
+
93
+ def as_json(*a)
94
+ @values.as_json(*a)
95
+ end
96
+
97
+ def to_hash
98
+ @values.inject({}) do |acc, (key, value)|
99
+ acc[key] = value.respond_to?(:to_hash) ? value.to_hash : value
100
+ acc
101
+ end
102
+ end
103
+
104
+ def each(&blk)
105
+ @values.each(&blk)
106
+ end
107
+
108
+ def _dump(level)
109
+ Marshal.dump([@values, @api_key])
110
+ end
111
+
112
+ def self._load(args)
113
+ values, api_key = Marshal.load(args)
114
+ construct_from(values, api_key)
115
+ end
116
+
117
+ if RUBY_VERSION < '1.9.2'
118
+ def respond_to?(symbol)
119
+ @values.has_key?(symbol) || super
120
+ end
121
+ end
122
+
123
+ protected
124
+
125
+ def metaclass
126
+ class << self; self; end
127
+ end
128
+
129
+ def remove_accessors(keys)
130
+ metaclass.instance_eval do
131
+ keys.each do |k|
132
+ next if @@permanent_attributes.include?(k)
133
+ k_eq = :"#{k}="
134
+ remove_method(k) if method_defined?(k)
135
+ remove_method(k_eq) if method_defined?(k_eq)
136
+ end
137
+ end
138
+ end
139
+
140
+ def add_accessors(keys)
141
+ metaclass.instance_eval do
142
+ keys.each do |k|
143
+ next if @@permanent_attributes.include?(k)
144
+ k_eq = :"#{k}="
145
+ define_method(k) { @values[k] }
146
+ define_method(k_eq) do |v|
147
+ if v == ""
148
+ raise ArgumentError.new(
149
+ "You cannot set #{k} to an empty string." +
150
+ "We interpret empty strings as nil in requests." +
151
+ "You may set #{self}.#{k} = nil to delete the property.")
152
+ end
153
+ @values[k] = v
154
+ @unsaved_values.add(k)
155
+ end
156
+ end
157
+ end
158
+ end
159
+
160
+ def method_missing(name, *args)
161
+ # TODO: only allow setting in updateable classes.
162
+ if name.to_s.end_with?('=')
163
+ attr = name.to_s[0...-1].to_sym
164
+ add_accessors([attr])
165
+ begin
166
+ mth = method(name)
167
+ rescue NameError
168
+ raise NoMethodError.new("Cannot set #{attr} on this object. HINT: you can't set: #{@@permanent_attributes.to_a.join(', ')}")
169
+ end
170
+ return mth.call(args[0])
171
+ else
172
+ return @values[name] if @values.has_key?(name)
173
+ end
174
+
175
+ begin
176
+ super
177
+ rescue NoMethodError => e
178
+ if @transient_values.include?(name)
179
+ 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 BoffinIO's API, probably as a result of a save(). The attributes currently available on this object are: #{@values.keys.join(', ')}")
180
+ else
181
+ raise
182
+ end
183
+ end
184
+ end
185
+
186
+ def respond_to_missing?(symbol, include_private = false)
187
+ @values && @values.has_key?(symbol) || super
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,36 @@
1
+ API_URL = "customers"
2
+
3
+ module BoffinIO
4
+ class Customer < APIResource
5
+ include BoffinIO::APIOperations::List
6
+ include BoffinIO::APIOperations::Create
7
+ include BoffinIO::APIOperations::Update
8
+
9
+ def cancel_subscription(params={})
10
+ response, api_key = BoffinIO.request(:delete, subscriptions_url, @api_key, params)
11
+ refresh_from({ :subscription => response }, api_key, true)
12
+ subscription
13
+ end
14
+
15
+ def update_subscription(params)
16
+ response, api_key = BoffinIO.request(:post, subscriptions_url, @api_key, params)
17
+ refresh_from({ :subscription => response }, api_key, true)
18
+ subscription
19
+ end
20
+
21
+ def create_subscription(params)
22
+ response, api_key = BoffinIO.request(:post, subscriptions_url, @api_key, params)
23
+ refresh_from({ :subscription => response }, api_key, true)
24
+ subscription
25
+ end
26
+
27
+ private
28
+ def subscription_url
29
+ url + '/subscription'
30
+ end
31
+
32
+ def subscriptions_url
33
+ url + '/subscriptions'
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,4 @@
1
+ module BoffinIO
2
+ class APIError < BoffinIOError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module BoffinIO
2
+ class AuthenticationError < BoffinIOError
3
+ end
4
+ end
@@ -0,0 +1,20 @@
1
+ module BoffinIO
2
+ class BoffinIOError < StandardError
3
+ attr_reader :message
4
+ attr_reader :http_status
5
+ attr_reader :http_body
6
+ attr_reader :json_body
7
+
8
+ def initialize(message=nil, http_status=nil, http_body=nil, json_body=nil)
9
+ @message = message
10
+ @http_status = http_status
11
+ @http_body = http_body
12
+ @json_body = json_body
13
+ end
14
+
15
+ def to_s
16
+ status_string = @http_status.nil? ? "" : "(Status #{@http_status}) "
17
+ "#{status_string}#{@message}"
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,4 @@
1
+ module BoffinIO
2
+ class InvalidRequestError < BoffinIOError
3
+ end
4
+ end
@@ -0,0 +1,35 @@
1
+ module BoffinIO
2
+ class ListObject < BoffinIOObject
3
+
4
+ def [](k)
5
+ case k
6
+ when String, Symbol
7
+ super
8
+ else
9
+ raise ArgumentError.new("You tried to access the #{k.inspect} index, but ListObject types only support String keys. (HINT: List calls return an object with a 'data' (which is the data array). You likely want to call #data[#{k.inspect}])")
10
+ end
11
+ end
12
+
13
+ def each(&blk)
14
+ self.data.each(&blk)
15
+ end
16
+
17
+ def retrieve(id, api_key=nil)
18
+ api_key ||= @api_key
19
+ response, api_key = BoffinIO.request(:get,"#{url}/#{CGI.escape(id)}", api_key)
20
+ Util.convert_to_boffinio_object(response, api_key)
21
+ end
22
+
23
+ def create(params={}, api_key=nil)
24
+ api_key ||= @api_key
25
+ response, api_key = BoffinIO.request(:post, url, api_key, params)
26
+ Util.convert_to_boffinio_object(response, api_key)
27
+ end
28
+
29
+ def all(params={}, api_key=nil)
30
+ api_key ||= @api_key
31
+ response, api_key = BoffinIO.request(:get, url, api_key, params)
32
+ Util.convert_to_boffinio_object(response, api_key)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,7 @@
1
+ module BoffinIO
2
+ class Plan < APIResource
3
+ include BoffinIO::APIOperations::List
4
+ include BoffinIO::APIOperations::Create
5
+
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ module BoffinIO
2
+ class Subscription < APIResource
3
+ include BoffinIO::APIOperations::Create
4
+ include BoffinIO::APIOperations::Update
5
+
6
+ def url
7
+ "#{Customer.url}/#{CGI.escape(customer)}/subscriptions/#{CGI.escape(id)}"
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,87 @@
1
+ module BoffinIO
2
+ module Util
3
+
4
+ def self.objects_to_ids(h)
5
+ case h
6
+ when Hash
7
+ res = {}
8
+ h.each { |k, v| res[k] = objects_to_ids(v) unless v.nil? }
9
+ res
10
+ when Array
11
+ h.map { |v| objects_to_ids(v) }
12
+ else
13
+ h
14
+ end
15
+ end
16
+
17
+ def self.object_classes
18
+ @object_classes ||= {
19
+ 'list' => ListObject,
20
+ 'customer' => Customer,
21
+ 'subscription' => Subscription,
22
+ 'plan' => Plan
23
+ }
24
+ end
25
+
26
+ def self.symbolize_names(object)
27
+ case object
28
+ when Hash
29
+ new = {}
30
+ object.each do |key, value|
31
+ key = (key.to_sym rescue key) || key
32
+ new[key] = symbolize_names(value)
33
+ end
34
+ new
35
+ when Array
36
+ object.map { |value| symbolize_names(value) }
37
+ else
38
+ object
39
+ end
40
+ end
41
+
42
+ def self.url_encode(key)
43
+ URI.escape(key.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
44
+ end
45
+
46
+ def self.flatten_params(params, parent_key=nil)
47
+ result = []
48
+ params.each do |key, value|
49
+ calculated_key = parent_key ? "#{parent_key}[#{url_encode(key)}]" : url_encode(key)
50
+ if value.is_a?(Hash)
51
+ result += flatten_params(value, calculated_key)
52
+ elsif value.is_a?(Array)
53
+ result += flatten_params_array(value, calculated_key)
54
+ else
55
+ result << [calculated_key, value]
56
+ end
57
+ end
58
+ result
59
+ end
60
+
61
+ def self.flatten_params_array(value, calculated_key)
62
+ result = []
63
+ value.each do |elem|
64
+ if elem.is_a?(Hash)
65
+ result += flatten_params(elem, calculated_key)
66
+ elsif elem.is_a?(Array)
67
+ result += flatten_params_array(elem, calculated_key)
68
+ else
69
+ result << ["#{calculated_key}[]", elem]
70
+ end
71
+ end
72
+ result
73
+ end
74
+
75
+ def self.convert_to_boffinio_object(resp, api_key)
76
+ case resp
77
+ when Array
78
+ resp.map { |i| convert_to_boffinio_object(i, api_key) }
79
+ when Hash
80
+ # Try converting to a known object class. If none available, fall back to generic BoffinIOObject
81
+ object_classes.fetch(resp[:object], BoffinIOObject).construct_from(resp, api_key)
82
+ else
83
+ resp
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,3 @@
1
+ module BoffinIO
2
+ VERSION = "0.0.1"
3
+ end