internode 1.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dee6dad4185b3955b4e8861685ae028e7408232f
4
+ data.tar.gz: 493e9b948165a5dd76fadbe9ba6fd6053b66327f
5
+ SHA512:
6
+ metadata.gz: b0f45b140ebcf0190fc4de362425b1909f112ae8698c48a32c5d2c466c15b89a78be44182ec8a61cd6071c3296764c60c7d825fbe6af1a464d1d37106575fd9a
7
+ data.tar.gz: ba93a08825d8ba959eeb057183bcc02f24697d5a59ed900c4d7bcd4258afbe882bf307ed3c3b94f5a199312478f3f129d3e3932ffba680765f39e257ff9fe68c
data/.gitignore ADDED
@@ -0,0 +1,35 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /vendor/bundle
26
+ /lib/bundler/man/
27
+
28
+ # for a library or gem, you might want to ignore these files since the code is
29
+ # intended to run in multiple environments; otherwise, check them in:
30
+ # Gemfile.lock
31
+ # .ruby-version
32
+ # .ruby-gemset
33
+
34
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
35
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,60 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ internode (1.0.0)
5
+ httpclient
6
+ oga
7
+ table_print
8
+ thor
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ addressable (2.3.8)
14
+ ansi (1.5.0)
15
+ ast (2.1.0)
16
+ crack (0.4.2)
17
+ safe_yaml (~> 1.0.0)
18
+ diff-lcs (1.2.5)
19
+ httpclient (2.6.0.1)
20
+ oga (1.2.1)
21
+ ast
22
+ ruby-ll (~> 2.1)
23
+ rake (10.4.2)
24
+ rspec (3.3.0)
25
+ rspec-core (~> 3.3.0)
26
+ rspec-expectations (~> 3.3.0)
27
+ rspec-mocks (~> 3.3.0)
28
+ rspec-core (3.3.2)
29
+ rspec-support (~> 3.3.0)
30
+ rspec-expectations (3.3.1)
31
+ diff-lcs (>= 1.2.0, < 2.0)
32
+ rspec-support (~> 3.3.0)
33
+ rspec-mocks (3.3.2)
34
+ diff-lcs (>= 1.2.0, < 2.0)
35
+ rspec-support (~> 3.3.0)
36
+ rspec-support (3.3.0)
37
+ ruby-ll (2.1.2)
38
+ ansi
39
+ ast
40
+ safe_yaml (1.0.4)
41
+ table_print (1.5.4)
42
+ thor (0.19.1)
43
+ vcr (2.9.3)
44
+ webmock (1.21.0)
45
+ addressable (>= 2.3.6)
46
+ crack (>= 0.3.2)
47
+
48
+ PLATFORMS
49
+ ruby
50
+
51
+ DEPENDENCIES
52
+ bundler (~> 1.10)
53
+ internode!
54
+ rake (~> 10.0)
55
+ rspec
56
+ vcr
57
+ webmock
58
+
59
+ BUNDLED WITH
60
+ 1.10.6
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Marty Zalega
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # Internode Ruby Client
2
+
3
+ This is an unofficial ruby client for Internode's usage and account API. A CLI is also included as a convenient way to retrieve information via the command line.
4
+
5
+ **Note** At time of writing Internode's API is unstable, 500ing quote often. This is not an issue with the client.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'internode'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install internode
22
+
23
+ ## Usage
24
+
25
+ ```ruby
26
+ require "internode"
27
+
28
+ account = Internode::Account.new(
29
+ username: "<account username>",
30
+ password: "<account password>"
31
+ )
32
+
33
+ # Get all the services for the account
34
+ account.services
35
+
36
+ service = account.services.first
37
+
38
+ # Get service plan
39
+ service.details.plan
40
+
41
+ # Get service speed (as string)
42
+ service.details.speed
43
+
44
+ # Get rollover date (as string)
45
+ service.details.rollover
46
+
47
+ # Get plan interval (usually monthly)
48
+ service.details.plan_interval
49
+
50
+ # Get plan cost (as string)
51
+ service.details.plan_cost
52
+
53
+ # Get service quota
54
+ service.usage.quota # in bytes
55
+ service.usage.quota_mb # in megabytes, not mebibytes
56
+ service.usage.quota_gb # in gigabytes, not gibibytes
57
+
58
+ # Get service total usage
59
+ service.usage.total # in bytes
60
+ service.usage.total_mb # in megabytes, not mebibytes
61
+ service.usage.total_gb # in gigabytes, not gibibytes
62
+
63
+ # Get percentage used
64
+ service.usage.percentage
65
+
66
+ # Get all details for the services
67
+ account.details # Same as account.services.map(&:details)
68
+
69
+ # Get all usage information for the services
70
+ account.usage # Same as account.services.map(&:usage)
71
+ ```
72
+
73
+ ## TODO
74
+
75
+ * Add support for service history
76
+
77
+ ## Development
78
+
79
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
80
+
81
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
82
+
83
+ ## Contributing
84
+
85
+ Bug reports and pull requests are welcome on GitHub at https://github.com/evilmarty/internode.
86
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/internode ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $: << File.expand_path("../../lib", __FILE__)
4
+
5
+ require "internode/cli"
6
+
7
+ Internode::CLI.start(ARGV)
data/internode.gemspec ADDED
@@ -0,0 +1,39 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'internode/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "internode"
8
+ spec.version = Internode::VERSION
9
+ spec.authors = ["Marty Zalega"]
10
+ spec.email = ["marty@zalega.me"]
11
+
12
+ spec.summary = %q{Internode Ruby client}
13
+ spec.description = %q{A ruby client for Internode's API}
14
+ spec.homepage = "https://github.com/evilmarty/internode.rb"
15
+
16
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
17
+ # delete this section to allow pushing this gem to any host.
18
+ if spec.respond_to?(:metadata)
19
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
20
+ else
21
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
22
+ end
23
+
24
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ spec.bindir = "bin"
26
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
27
+ spec.require_paths = ["lib"]
28
+
29
+ spec.add_development_dependency "bundler", "~> 1.10"
30
+ spec.add_development_dependency "rake", "~> 10.0"
31
+ spec.add_development_dependency "rspec"
32
+ spec.add_development_dependency "vcr"
33
+ spec.add_development_dependency "webmock"
34
+
35
+ spec.add_dependency "httpclient"
36
+ spec.add_dependency "oga"
37
+ spec.add_dependency "table_print"
38
+ spec.add_dependency "thor"
39
+ end
@@ -0,0 +1,34 @@
1
+ module Internode
2
+ class Account < Resource
3
+ PATH = "/api/v1.5"
4
+
5
+ def initialize(options = {})
6
+ client = options.fetch(:client){ Client.new(username: options[:username], password: options[:password]) }
7
+ path = options.fetch(:path){ PATH }
8
+ super(client: client, path: path)
9
+ end
10
+
11
+ def services
12
+ @services ||= content.css("services service").map do |node|
13
+ Service.new(client: client, path: node.attr("href").text)
14
+ end
15
+ end
16
+
17
+ def details
18
+ concurrent_map(&:details)
19
+ end
20
+
21
+ def usage
22
+ concurrent_map(&:usage)
23
+ end
24
+
25
+ private
26
+
27
+ # Used to allow performing API requests in parallal instead of series
28
+ def concurrent_map
29
+ threads = services.map{|s| Thread.new{ yield s } }
30
+ threads.each(&:join)
31
+ threads.map(&:value)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,40 @@
1
+ require "internode"
2
+ require "table_print"
3
+ require "thor"
4
+
5
+ module Internode
6
+ class CLI < Thor
7
+ class_option :user, aliases: :u
8
+ class_option :password, aliases: :p
9
+ class_option :human, aliases: :h, type: :boolean
10
+
11
+ desc "list", "List services"
12
+ def list
13
+ tp account.details, :id, :type, :plan, format(:quota), :speed
14
+ rescue Client::ServerError => err
15
+ print_error(err)
16
+ end
17
+
18
+ desc "usage", "Show usage for service"
19
+ def usage
20
+ tp account.usage, :id, :type, format(:total), format(:quota), :percentage, :plan_interval, :rollover
21
+ rescue Client::ServerError => err
22
+ print_error(err)
23
+ end
24
+
25
+ private
26
+
27
+ def format(name)
28
+ options[:human] ? :"#{name}_gb" : name
29
+ end
30
+
31
+ def account
32
+ Account.new(username: options[:user], password: options[:password])
33
+ end
34
+
35
+ def print_error(error)
36
+ puts "Internode: #{error}"
37
+ exit 128
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,29 @@
1
+ require "httpclient"
2
+ require "oga"
3
+
4
+ module Internode
5
+ class Client
6
+ URL = "https://customer-webtools-api.internode.on.net"
7
+
8
+ class ServerError < RuntimeError; end
9
+
10
+ def initialize(options = {})
11
+ username = options.fetch(:username){ ENV["INTERNODE_USERNAME"] }
12
+ password = options.fetch(:password){ ENV["INTERNODE_PASSWORD"] }
13
+ @url = options.fetch(:url){ URL }
14
+ @client = HTTPClient.new
15
+ @client.set_auth(@url, username, password)
16
+ @client.cookie_manager = nil
17
+ end
18
+
19
+ def get(path, *args)
20
+ url = "#{@url}#{path}"
21
+ content = @client.get_content(url)
22
+
23
+ Oga.parse_xml(content).at_css("internode api")
24
+
25
+ rescue HTTPClient::BadResponseError => err
26
+ raise ServerError.new("#{err.res.status_code} #{err.res.reason}")
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,22 @@
1
+ module Internode
2
+ class Details < Resource
3
+ content_attr :id, :username, :plan, :carrier, :speed
4
+ content_attr "usage-rating", "rollover", "excess-charged", "excess-shaped", "excess-restrict-access", "plan-interval", "plan-cost"
5
+
6
+ def type
7
+ content.at_css("service").attr("type").text
8
+ end
9
+
10
+ def quota
11
+ content.at_css("quota").text.to_i
12
+ end
13
+
14
+ def quota_mb
15
+ quota / 1000 / 1000
16
+ end
17
+
18
+ def quota_gb
19
+ quota_mb / 1000
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,27 @@
1
+ module Internode
2
+ class Resource
3
+ attr_reader :path, :client
4
+
5
+ def initialize(options = {})
6
+ @client = options.fetch(:client){ Internode.client }
7
+ @path = options[:path]
8
+ end
9
+
10
+ def content
11
+ @content ||= @client.get(path)
12
+ end
13
+
14
+ class << self
15
+ def content_attr(*names)
16
+ names.each do |name|
17
+ name = name.to_s
18
+ method_name = name.gsub(/\W+/, "_")
19
+
20
+ define_method(method_name) do
21
+ content.at_css(name).text
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,33 @@
1
+ module Internode
2
+ class Service < Resource
3
+ def id
4
+ service.text
5
+ end
6
+
7
+ def type
8
+ service.attr("type").text
9
+ end
10
+
11
+ def details
12
+ @details ||= Details.new(client: client, path: details_path)
13
+ end
14
+
15
+ def usage
16
+ @usage ||= Usage.new(client: client, path: usage_path)
17
+ end
18
+
19
+ private
20
+
21
+ def service
22
+ @service ||= content.at_css("service")
23
+ end
24
+
25
+ def details_path
26
+ content.at_css("resource[type='service']").attr("href").text
27
+ end
28
+
29
+ def usage_path
30
+ content.at_css("resource[type='usage']").attr("href").text
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,57 @@
1
+ module Internode
2
+ class Usage < Resource
3
+ def id
4
+ service.text
5
+ end
6
+
7
+ def type
8
+ service.attr("type").text
9
+ end
10
+
11
+ def total
12
+ traffic.text.to_i
13
+ end
14
+
15
+ def total_mb
16
+ total / 1000 / 1000
17
+ end
18
+
19
+ def total_gb
20
+ total_mb / 1000
21
+ end
22
+
23
+ def rollover
24
+ traffic.attr("rollover").text
25
+ end
26
+
27
+ def plan_interval
28
+ traffic.attr("plan-interval").text
29
+ end
30
+
31
+ def quota
32
+ traffic.attr("quota").text.to_i
33
+ end
34
+
35
+ def quota_mb
36
+ quota / 1000 / 1000
37
+ end
38
+
39
+ def quota_gb
40
+ quota_mb / 1000
41
+ end
42
+
43
+ def percentage
44
+ total.to_f / quota.to_f * 100.0
45
+ end
46
+
47
+ private
48
+
49
+ def service
50
+ @service ||= content.at_css("service")
51
+ end
52
+
53
+ def traffic
54
+ @traffic ||= content.at_css("traffic")
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,3 @@
1
+ module Internode
2
+ VERSION = "1.0.0"
3
+ end
data/lib/internode.rb ADDED
@@ -0,0 +1,21 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+
4
+ require "internode/version"
5
+
6
+ module Internode
7
+ autoload :Account, "internode/account"
8
+ autoload :Client, "internode/client"
9
+ autoload :Details, "internode/details"
10
+ autoload :Resource, "internode/resource"
11
+ autoload :Service, "internode/service"
12
+ autoload :Usage, "internode/usage"
13
+
14
+ def self.client
15
+ @client ||= Client.new
16
+ end
17
+
18
+ def self.client=(client)
19
+ @client = client
20
+ end
21
+ end
metadata ADDED
@@ -0,0 +1,188 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: internode
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Marty Zalega
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-08-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: vcr
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: webmock
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: httpclient
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: oga
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: table_print
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: thor
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: A ruby client for Internode's API
140
+ email:
141
+ - marty@zalega.me
142
+ executables:
143
+ - internode
144
+ extensions: []
145
+ extra_rdoc_files: []
146
+ files:
147
+ - ".gitignore"
148
+ - Gemfile
149
+ - Gemfile.lock
150
+ - LICENSE
151
+ - README.md
152
+ - Rakefile
153
+ - bin/internode
154
+ - internode.gemspec
155
+ - lib/internode.rb
156
+ - lib/internode/account.rb
157
+ - lib/internode/cli.rb
158
+ - lib/internode/client.rb
159
+ - lib/internode/details.rb
160
+ - lib/internode/resource.rb
161
+ - lib/internode/service.rb
162
+ - lib/internode/usage.rb
163
+ - lib/internode/version.rb
164
+ homepage: https://github.com/evilmarty/internode.rb
165
+ licenses: []
166
+ metadata:
167
+ allowed_push_host: https://rubygems.org
168
+ post_install_message:
169
+ rdoc_options: []
170
+ require_paths:
171
+ - lib
172
+ required_ruby_version: !ruby/object:Gem::Requirement
173
+ requirements:
174
+ - - ">="
175
+ - !ruby/object:Gem::Version
176
+ version: '0'
177
+ required_rubygems_version: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ requirements: []
183
+ rubyforge_project:
184
+ rubygems_version: 2.4.5
185
+ signing_key:
186
+ specification_version: 4
187
+ summary: Internode Ruby client
188
+ test_files: []