knuverse-knufactor 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 +11 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +14 -0
  5. data/.travis.yml +14 -0
  6. data/CONTRIBUTING.md +16 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE +22 -0
  9. data/README.md +125 -0
  10. data/Rakefile +10 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/knuverse-knufactor.gemspec +42 -0
  14. data/lib/core_extensions/string/transformations.rb +28 -0
  15. data/lib/knuverse/knufactor.rb +42 -0
  16. data/lib/knuverse/knufactor/api_client.rb +30 -0
  17. data/lib/knuverse/knufactor/api_client_base.rb +112 -0
  18. data/lib/knuverse/knufactor/api_exception.rb +7 -0
  19. data/lib/knuverse/knufactor/exceptions/api_client_not_configured.rb +9 -0
  20. data/lib/knuverse/knufactor/exceptions/immutable_modification.rb +9 -0
  21. data/lib/knuverse/knufactor/exceptions/invalid_arguments.rb +9 -0
  22. data/lib/knuverse/knufactor/exceptions/invalid_options.rb +9 -0
  23. data/lib/knuverse/knufactor/exceptions/invalid_property.rb +9 -0
  24. data/lib/knuverse/knufactor/exceptions/invalid_where_query.rb +9 -0
  25. data/lib/knuverse/knufactor/exceptions/missing_path.rb +9 -0
  26. data/lib/knuverse/knufactor/exceptions/new_instance_with_id.rb +9 -0
  27. data/lib/knuverse/knufactor/helpers/api_client.rb +36 -0
  28. data/lib/knuverse/knufactor/helpers/resource.rb +112 -0
  29. data/lib/knuverse/knufactor/helpers/resource_class.rb +49 -0
  30. data/lib/knuverse/knufactor/resource.rb +207 -0
  31. data/lib/knuverse/knufactor/resource_collection.rb +189 -0
  32. data/lib/knuverse/knufactor/resources/client.rb +44 -0
  33. data/lib/knuverse/knufactor/simple_api_client.rb +20 -0
  34. data/lib/knuverse/knufactor/validations/api_client.rb +42 -0
  35. data/lib/knuverse/knufactor/validations/resource.rb +17 -0
  36. data/lib/knuverse/knufactor/version.rb +10 -0
  37. metadata +220 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 224e08737aef33c81546244ee7b5c61ee4dee62d
4
+ data.tar.gz: abd0db60daee18081303470062a4f120b5300e0c
5
+ SHA512:
6
+ metadata.gz: bbc6a2bdc236889d73413e8ebc55b0de64404c457eb522c028f217000f7de000d82088af673bf998a2fe08569864002d7cc43f81838cfcec234fee366bf260a2
7
+ data.tar.gz: 5c7d09db089ebf5517c98a3c97a145e134c627f8ca551954318cbb231d6e78cb2358330835c28b66c09d51a508180c370ae448443ebc3851183380f5cb14d76f
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ # Ignore Mac stuff
11
+ .DS_Store
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,14 @@
1
+ Metrics/LineLength:
2
+ Max: 100
3
+
4
+ Metrics/ClassLength:
5
+ Max: 150
6
+
7
+ Metrics/AbcSize:
8
+ Max: 22
9
+
10
+ Metrics/MethodLength:
11
+ Max: 20
12
+
13
+ Metrics/CyclomaticComplexity:
14
+ Max: 10
data/.travis.yml ADDED
@@ -0,0 +1,14 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.1.10
5
+ - 2.2.5
6
+ - 2.3.1
7
+ cache: bundler
8
+ deploy:
9
+ provider: rubygems
10
+ api_key:
11
+ secure: A9iVmtSsR9iJsjGMXfKHNVuZn13QVdnnRAmAwXQvCSXmDaZQyHLejYnAGQ3WjZc2XbLxSn/787MUTJC2yxG9pJy+Nnyr6L9ZtoBD3F5/q+iqklJXIXtuVV/wOcknG+m71kEIIntZv+g2hVjHo/CfAbm10ycqlJDw/MMoPGxkwXHkj9qGEft6jXygzGEDGxnmqyBRAHZ/BI0vjojdTLM8yO/0RFF1X2cs55YRGyicmE8V/ZYwL5cOVfwCqYNtVp4Pce4GxWfX+Dp1PceI4jnX9hq/kMa+0mTkLWPdMQLYVjyIaZ7eso8RQb9yVPdIGZKp2vQqN1t+s/EHgmiriv/tHluvLnIWjHIwYFuX0Bd9wttp7Sb1K7HhqP0T/Ymny41KLr4Nnx3PqIcm9dz57x6zvq1bIykVlG3sZNthVPKAwbX6lj6X/HCyYaDr65EwFPDWsOxt78zJdbZuV0pdg4rEJaF8MHKy3lOfwm52AfIC4iMsnshhSylDETjwG7P556ZHzutODB3JPSKwmJriGihVBiG5V5TpdrPD9oZPs6rg8XWZs9bdhroIk9FcfE5MZJ0UDUdcV3dpcdJI109G3SR2rxSHaozfeaggsBa4QMD9gPP+Tx2DiD4eOntxo3zhoylISeKIJptLEOqz+vPEWcj/J25+iXbotvlFB1khibVWn0c=
12
+ gem: knuverse-knufactor
13
+ on:
14
+ tags: true
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,16 @@
1
+ ## Welcome!
2
+
3
+ We're so glad you're thinking about contributing to a KnuEdge open source project! If you're unsure about anything, just ask -- or submit the issue or pull request anyway. The worst that can happen is you'll be politely asked to change something. We love all friendly contributions.
4
+
5
+ We want to ensure a welcoming environment for all of our projects. Our IT staff encourage ethical contribution to our open source projects and all contributors should do the same.
6
+
7
+ We encourage you to read this project's CONTRIBUTING policy (you are here), its [LICENSE](LICENSE), and its [README](README.md).
8
+
9
+ If you have any questions just [shoot us an email](mailto:opensource@knuedge.com).
10
+
11
+ ## Licensing
12
+
13
+ This project and all code contained within it are released under the [MIT License](https://opensource.org/licenses/MIT).
14
+
15
+ All contributions to this project will be released under the [MIT License](https://opensource.org/licenses/MIT). By submitting a pull request, you are agreeing to comply
16
+ with this license and for any contributions to be released under it.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in knuverse-knufactor.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2016 KnuEdge
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,125 @@
1
+ The KnuVerse Knufactor SDK for Ruby
2
+ ====================
3
+
4
+ About
5
+ ----
6
+ This project is a Ruby SDK that allows developers to create apps that use Knuverse's Knufactor Cloud APIs.
7
+
8
+ Documentation for the API can be found [here](https://cloud.knuverse.com/docs/)
9
+
10
+ Note that this SDK isn't a direct port of the [Python SDK](https://github.com/KnuVerse/knuverse-sdk-python), though it is based heavily on the work done there. This SDK uses a Object-Oriented pattern, which is likely more familiar to Ruby developers than a collection of functions may be.
11
+
12
+ Building and Installing
13
+ ----
14
+ Building the gem requires a modern Ruby:
15
+
16
+ # highly recommend using RVM here, and Ruby 2.x or above
17
+ gem build knuverse-knufactor.gemspec
18
+ # install what you just built
19
+ gem install knuverse-knufactor-*.gem
20
+
21
+ That said, recent releases should be available on [rubygems.org](https://rubygems.org/) so building is probably not necessary.
22
+
23
+ Just add the following to your Gemfile:
24
+
25
+ gem 'knuverse/knufactor'
26
+
27
+ Then run:
28
+
29
+ bundle install
30
+
31
+ If you're not using [bundler](http://bundler.io/) for some reason (shame on you!), you can manually install like so:
32
+
33
+ gem install knuverse-knufactor
34
+
35
+ If you see a message like this:
36
+
37
+ Thanks for installing the KnuVerse Knufactor Ruby SDK!
38
+
39
+ You should be all set!
40
+
41
+ Usage
42
+ ------
43
+ Check back, because this file will be updated with a lot more usage examples.
44
+
45
+ For a typical custom ruby application, you'll need to do something like the following to get started:
46
+
47
+ ```ruby
48
+ require 'knuverse/knufactor'
49
+
50
+ # configure the API client singleton
51
+ KnuVerse::Knufactor::APIClient.configure(
52
+ apikey: 'b1b71d68cffea1d43257fff9deadbeef',
53
+ secret: '34d04e5f05a194444e9c26358a94eaf2'
54
+ )
55
+ ```
56
+
57
+ From here, the SDK will automatically rely on this configuration singleton unless you tell it otherwise. Here are some examples of interacting with the API:
58
+
59
+ ```ruby
60
+ # pull some data
61
+ KnuVerse::Knufactor::APIClient.about_service
62
+ # => {"company"=>"KnuVerse", "version"=>"1.4.0", "multi_tenant"=>true, "service"=>"audiopin", "name"=>"KnuVerse"}
63
+
64
+ # Make working with resources easier
65
+ include KnuVerse::Knufactor::Resources
66
+
67
+ # Find some clients
68
+ clients = Client.all
69
+
70
+ # Take a look at the last client
71
+ client = clients.last
72
+ client.name
73
+ # => "user75"
74
+
75
+ # Make a change
76
+ client.bypass_limit = 10
77
+
78
+ # Now persist it
79
+ client.save
80
+
81
+ # Verify the change worked
82
+ client.reload
83
+ client.bypass_limit
84
+ # => 10
85
+
86
+ # Find some specific clients... all locked out clients
87
+ locked_clients = Client.where(:password_lock?, true)
88
+ # => #<KnuVerse::Knufactor::ResourceCollection:...
89
+
90
+ # Find clients that are either enrolled or installed
91
+ happy_clients = Client.where(:state, 'enrolled').or(:state, 'installed')
92
+
93
+ # Find clients with a name that starts with "z"
94
+ z_clients = Client.where(:name, /^z/i)
95
+ ```
96
+
97
+ For some more complex situations, you may want a specialized API Client (interact with it as an instance, or have a thread-local or context-specific client):
98
+
99
+ ```ruby
100
+ # interact with the singleton as a client instance for simplicity
101
+ api_client = KnuVerse::Knufactor::APIClient.instance
102
+
103
+ # In complex, multi-user systems, using a singleton class might not work.
104
+ # For this reason, there is a regular class version of the API client that is not tied to the singleton
105
+ local_api_client1 = KnuVerse::Knufactor::SimpleAPIClient.new(
106
+ apikey: 'b1b71d68cffea1d43257fff9deadbeef', secret: '57838344acf7f5876226ede247c5881a'
107
+ )
108
+ local_api_client2 = KnuVerse::Knufactor::SimpleAPIClient.new(
109
+ apikey: '33371d68cffea1d43257fff9deadf00d', secret: 'e7d1c88825dc96a05bc38c39cca4a1ca'
110
+ )
111
+ local_api_client1 == local_api_client2
112
+ # => false
113
+
114
+ # Perform an operation with a specific instance of the API Client
115
+ Client.all(api_client: local_api_client1)
116
+ # All finder methods work this way, allowing the 'api_client' option to be passed
117
+ Client.where(:name, 'bobby', api_client: local_api_client2)
118
+
119
+ ```
120
+
121
+ License
122
+ -------
123
+ This project and all code contained within it are released under the [MIT License](https://opensource.org/licenses/MIT). As stated in [CONTRIBUTING](CONTRIBUTING.md):
124
+
125
+ > All contributions to this project will be released under the [MIT License](https://opensource.org/licenses/MIT). By submitting a pull request, you are agreeing to comply with this license and for any contributions to be released under it.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
4
+ require 'yard'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+ RuboCop::RakeTask.new(:rubocop)
8
+ YARD::Rake::YardocTask.new
9
+
10
+ task default: [:spec, :rubocop, :yard]
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'knuverse/knufactor'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,42 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'knuverse/knufactor/version'
5
+
6
+ # rubocop:disable Metrics/BlockLength
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'knuverse-knufactor'
9
+ spec.version = KnuVerse::Knufactor::VERSION
10
+ spec.date = Time.now.strftime('%Y-%m-%d')
11
+ spec.authors = ['Jonathan Gnagy']
12
+ spec.email = ['jgnagy@knuedge.com']
13
+
14
+ spec.summary = 'KnuVerse Knufactor Ruby SDK'
15
+ spec.homepage = 'https://github.com/KnuVerse/knuverse-knufactor-sdk-ruby'
16
+ spec.license = 'MIT'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
+ f.match(%r{^(test|spec|features)/})
20
+ end
21
+ spec.bindir = 'exe'
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ['lib']
24
+
25
+ spec.metadata['yard.run'] = 'yri'
26
+
27
+ spec.required_ruby_version = '~> 2.0'
28
+ spec.post_install_message = 'Thanks for installing the KnuVerse Knufactor Ruby SDK!'
29
+ spec.platform = Gem::Platform::RUBY
30
+
31
+ spec.add_runtime_dependency 'linguistics', '~> 2.1'
32
+ spec.add_runtime_dependency 'rest-client', '~> 2.0'
33
+ spec.add_runtime_dependency 'will_paginate', '~> 3.1'
34
+
35
+ spec.add_development_dependency 'bundler', '~> 1.12'
36
+ spec.add_development_dependency 'rake', '~> 10.0'
37
+ spec.add_development_dependency 'rspec', '~> 3.1'
38
+ spec.add_development_dependency 'rubocop', '~> 0.35'
39
+ spec.add_development_dependency 'yard', '~> 0.8'
40
+ spec.add_development_dependency 'simplecov'
41
+ spec.add_development_dependency 'travis', '~> 1.8'
42
+ end
@@ -0,0 +1,28 @@
1
+ module CoreExtensions
2
+ module String
3
+ # Monkey-patches for String to add some simple missing transformations
4
+ module Transformations
5
+ # Convert CamelCase to underscored_text
6
+ # @return [String]
7
+ def to_underscore
8
+ gsub(/::/, '/')
9
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
10
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
11
+ .tr('-', '_')
12
+ .downcase
13
+ end
14
+
15
+ # Convert underscored_text to CamelCase
16
+ # @return [String]
17
+ def to_camel
18
+ split('_').map(&:capitalize).join
19
+ end
20
+
21
+ # Attempt to guess a more human-like view of a string
22
+ # @return [String]
23
+ def humanize
24
+ gsub(/_id$/, '').tr('_', ' ').capitalize
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,42 @@
1
+ # Standard Library Requirements
2
+ require 'json'
3
+ require 'singleton'
4
+
5
+ # External Library Requirements
6
+ require 'linguistics'
7
+ Linguistics.use(:en)
8
+ require 'rest-client'
9
+ require 'will_paginate'
10
+ require 'will_paginate/array'
11
+
12
+ # Internal Requirements
13
+ require 'core_extensions/string/transformations'
14
+ String.include CoreExtensions::String::Transformations
15
+
16
+ require 'knuverse/knufactor/version'
17
+ require 'knuverse/knufactor/api_exception'
18
+ require 'knuverse/knufactor/exceptions/api_client_not_configured'
19
+ require 'knuverse/knufactor/exceptions/immutable_modification'
20
+ require 'knuverse/knufactor/exceptions/invalid_arguments'
21
+ require 'knuverse/knufactor/exceptions/invalid_options'
22
+ require 'knuverse/knufactor/exceptions/invalid_property'
23
+ require 'knuverse/knufactor/exceptions/invalid_where_query'
24
+ require 'knuverse/knufactor/exceptions/missing_path'
25
+ require 'knuverse/knufactor/exceptions/new_instance_with_id'
26
+ require 'knuverse/knufactor/helpers/api_client'
27
+ require 'knuverse/knufactor/validations/api_client'
28
+ require 'knuverse/knufactor/api_client_base'
29
+ require 'knuverse/knufactor/api_client'
30
+ require 'knuverse/knufactor/simple_api_client'
31
+ require 'knuverse/knufactor/resource_collection'
32
+ require 'knuverse/knufactor/helpers/resource'
33
+ require 'knuverse/knufactor/helpers/resource_class'
34
+ require 'knuverse/knufactor/validations/resource'
35
+ require 'knuverse/knufactor/resource'
36
+ require 'knuverse/knufactor/resources/client'
37
+
38
+ module KnuVerse
39
+ # The SDK for interacting with the KnuVerse Knufactor Cloud API
40
+ module Knufactor
41
+ end
42
+ end
@@ -0,0 +1,30 @@
1
+ module KnuVerse
2
+ module Knufactor
3
+ # The API Client Singleton class
4
+ class APIClient < APIClientBase
5
+ include Singleton
6
+
7
+ def self.configure(opts = {})
8
+ instance.configure(opts)
9
+ end
10
+
11
+ def self.about_service
12
+ instance.about_service
13
+ end
14
+
15
+ def configure(opts = {})
16
+ # validations
17
+ validate_opts(opts)
18
+
19
+ # Set up the client's state
20
+ @server = opts[:server] || 'https://cloud.knuverse.com'
21
+ @apikey = opts[:apikey]
22
+ @secret = opts[:secret]
23
+ @base_uri = opts[:base_uri] || '/api/v1/'
24
+ @last_auth = nil
25
+ @auth_token = nil
26
+ @configured = true
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,112 @@
1
+ module KnuVerse
2
+ module Knufactor
3
+ # The API Client Base class
4
+ class APIClientBase
5
+ attr_reader :server, :base_uri
6
+ attr_accessor :apikey, :secret, :account
7
+
8
+ include Validations::APIClient
9
+ include Helpers::APIClient
10
+
11
+ def about_service
12
+ get 'about'
13
+ end
14
+
15
+ def api_uri
16
+ @api_uri ||= URI.parse(server)
17
+ @api_uri.path = base_uri
18
+ @api_uri
19
+ end
20
+
21
+ def authenticated?
22
+ raise Exceptions::APIClientNotConfigured unless configured?
23
+ @auth_token && @last_auth && ((Time.now.utc - @last_auth) < (60 * 14)) ? true : false
24
+ end
25
+
26
+ def configured?
27
+ @configured ? true : false
28
+ end
29
+
30
+ def json_headers
31
+ base = { content_type: :json, accept: :json }
32
+ authenticated? ? base.merge(authorization: auth_header) : base
33
+ end
34
+
35
+ def refresh_auth_bearer
36
+ auth_data = {
37
+ key_id: @apikey,
38
+ secret: @secret
39
+ }
40
+ resp = post('auth', auth_data)
41
+ resp['jwt']
42
+ end
43
+
44
+ def refresh_auth
45
+ @auth_token = refresh_auth_bearer
46
+ @last_auth = Time.now.utc
47
+ true
48
+ end
49
+
50
+ def get(uri, data = nil)
51
+ refresh_auth unless authenticated?
52
+
53
+ client_action do |client|
54
+ if data
55
+ JSON.parse client[uri].get(json_headers.merge(params: data))
56
+ else
57
+ JSON.parse client[uri].get(json_headers)
58
+ end
59
+ end
60
+ end
61
+
62
+ def post(uri, data = nil)
63
+ refresh_auth unless authenticated? || uri == 'auth'
64
+
65
+ client_action do |client|
66
+ if data
67
+ JSON.parse client[uri].post(json_escape(data.to_json), json_headers)
68
+ else
69
+ JSON.parse client[uri].post(nil, json_headers)
70
+ end
71
+ end
72
+ end
73
+
74
+ def patch(uri, data)
75
+ refresh_auth unless authenticated?
76
+
77
+ client_action do |client|
78
+ response = client[uri].patch(json_escape(data.to_json), json_headers)
79
+ if response && !response.empty?
80
+ JSON.parse(response)
81
+ else
82
+ true
83
+ end
84
+ end
85
+ end
86
+
87
+ def put(uri, data)
88
+ refresh_auth unless authenticated?
89
+
90
+ client_action do |client|
91
+ client[uri].put(json_escape(data.to_json), json_headers)
92
+ end
93
+ end
94
+
95
+ private
96
+
97
+ def auth_header
98
+ authenticated? ? "Bearer #{@auth_token}" : nil
99
+ end
100
+
101
+ def client_action
102
+ raise Exceptions::APIClientNotConfigured unless configured?
103
+ yield connection
104
+ end
105
+
106
+ # Don't bother creating a connection until we need one
107
+ def connection
108
+ @connection ||= RestClient::Resource.new(api_uri.to_s)
109
+ end
110
+ end
111
+ end
112
+ end