haveapi-client 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 411ee5aebf1042dcb0532fcfde75bb90a71a6a99
4
+ data.tar.gz: 81323b4e42c302b2030b051308082dca268556a1
5
+ SHA512:
6
+ metadata.gz: 8fde9de9cdd152dca98d07b1f6fd74dbeb599c202a3031df0158b803e213047ee648b38077f8270c86d8b0bc0272a03e57c57a3a06354f5a0b44556c582ba613
7
+ data.tar.gz: 4265a74df48c07c9dc3ae1a706f833cc2be1a9eb7be40fa54abedeb00808e1e588a98a1543d8da318c73dfe007dbf1bdd6d71f5d9dc64e46c806a67702ef8d5d
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,67 @@
1
+ HaveAPI-Client
2
+ --------------
3
+ HaveAPI-Client is a Ruby CLI and client library for APIs built with
4
+ [HaveAPI framework](https://github.com/vpsfreecz/haveapi).
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'haveapi-client'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install haveapi-client
19
+
20
+ ## Usage
21
+ ### CLI
22
+ $ haveapi-cli -h
23
+ Usage: haveapi-cli [options] <resource> <action> [objects ids] [-- [parameters]]
24
+ -a, --api URL API URL
25
+ --list-versions List all available API versions
26
+ --list-resources VERSION List all resource in API version
27
+ --list-actions VERSION List all resources and actions in API version
28
+ -r, --raw Print raw response as is
29
+ -u, --username USER User name
30
+ -p, --password PASSWORD Password
31
+ -v, --[no-]verbose Run verbosely
32
+ -h, --help Show this message
33
+
34
+ Using the API example from
35
+ [HaveAPI README](https://github.com/vpsfreecz/haveapi/blob/master/README.md#example),
36
+ users would be listed with:
37
+
38
+ $ haveapi-cli -a https://your.api.tld user index -u yourname -p yourpassword
39
+
40
+ Nested resources and object IDs:
41
+
42
+ $ haveapi-cli -a https://your.api.tld user.invoice index 10 -u yourname -p yourpassword
43
+
44
+ where `10` is user ID.
45
+
46
+ ### Client library
47
+ ```ruby
48
+ require 'haveapi/client'
49
+
50
+ api = HaveAPI::Client::Client.new('https://your.api.tld')
51
+ api.login('yourname', 'yourpassword')
52
+
53
+ response = api.user.index
54
+ p response.ok?
55
+ p response.response
56
+
57
+ p api.user(10).invoice
58
+ p api.user(10).delete
59
+ p api.user(10).delete!
60
+ p api.user.delete(10)
61
+
62
+ p api.user.create({
63
+ login: 'mylogin',
64
+ full_name: 'Very Full Name',
65
+ role: 'user'
66
+ })
67
+ ```
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler/gem_tasks'
2
+
data/bin/haveapi-cli ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'haveapi/cli'
4
+
5
+ HaveAPI::CLI::Cli.run
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'haveapi/client/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'haveapi-client'
8
+ spec.version = HaveAPI::Client::VERSION
9
+ spec.authors = ['Jakub Skokan']
10
+ spec.email = ['jakub.skokan@vpsfree.cz']
11
+ spec.summary =
12
+ spec.description = 'Ruby API and CLI for HaveAPI'
13
+ spec.homepage = ''
14
+ spec.license = 'GPL'
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_development_dependency 'bundler', '~> 1.6'
22
+ spec.add_development_dependency 'rake'
23
+
24
+ spec.add_runtime_dependency 'activesupport', '~> 4.1.0'
25
+ spec.add_runtime_dependency 'require_all', '~> 1.3.0'
26
+ spec.add_runtime_dependency 'rest_client', '~> 1.7.3'
27
+ spec.add_runtime_dependency 'json', '~> 1.8.1'
28
+ spec.add_runtime_dependency 'highline', '~> 1.6.21'
29
+ spec.add_runtime_dependency 'table_print', '~> 1.5.1'
30
+ end
@@ -0,0 +1,2 @@
1
+ require 'haveapi/client'
2
+ require 'haveapi/cli/cli'
@@ -0,0 +1,290 @@
1
+ require 'optparse'
2
+ require 'pp'
3
+ require 'highline/import'
4
+ require 'table_print'
5
+
6
+ module HaveAPI
7
+ module CLI
8
+ class Cli
9
+ def self.run
10
+ c = new
11
+ end
12
+
13
+ def initialize
14
+ args, @opts = options
15
+ @api = HaveAPI::Client::Communicator.new(api_url)
16
+
17
+ if @action
18
+ method(@action.first).call( * @action[1..-1] )
19
+ exit
20
+ end
21
+
22
+ if @opts[:help] || args.empty?
23
+ puts @global_opt.help
24
+ exit(true)
25
+ end
26
+
27
+ resources = args[0].split('.')
28
+ action = translate_action(args[1].to_sym)
29
+
30
+ action = @api.get_action(resources, action, args[2..-1])
31
+
32
+ @input_params = parameters(action)
33
+
34
+ if action
35
+ unless params_valid?(action)
36
+ warn 'Missing required parameters'
37
+ end
38
+
39
+ ret = action.execute(@input_params, raw: @opts[:raw])
40
+
41
+ if ret[:status]
42
+ format_output(action, ret[:response])
43
+ else
44
+ warn "Action failed: #{ret[:message]}"
45
+
46
+ if ret[:errors].any?
47
+ puts 'Errors:'
48
+ ret[:errors].each do |param, e|
49
+ puts "\t#{param}: #{e.join('; ')}"
50
+ end
51
+ end
52
+ end
53
+
54
+ else
55
+ warn "Action #{ARGV[0]}##{ARGV[1]} not valid"
56
+ exit(false)
57
+ end
58
+ end
59
+
60
+ def api_url
61
+ @opts[:client]
62
+ end
63
+
64
+ def options
65
+ options = {
66
+ client: default_url,
67
+ verbose: false,
68
+ }
69
+
70
+ @global_opt = OptionParser.new do |opts|
71
+ opts.banner = "Usage: #{$0} [options] <resource> <action> [objects ids] [-- [parameters]]"
72
+
73
+ opts.on('-a', '--api URL', 'API URL') do |url|
74
+ options[:client] = url
75
+ end
76
+
77
+ opts.on('--list-versions', 'List all available API versions') do
78
+ @action = [:list_versions]
79
+ end
80
+
81
+ opts.on('--list-resources VERSION', 'List all resource in API version') do |v|
82
+ @action = [:list_resources, v.sub(/^v/, '')]
83
+ end
84
+
85
+ opts.on('--list-actions VERSION', 'List all resources and actions in API version') do |v|
86
+ @action = [:list_actions, v.sub(/^v/, '')]
87
+ end
88
+
89
+ opts.on('-r', '--raw', 'Print raw response as is') do
90
+ options[:raw] = true
91
+ end
92
+
93
+ opts.on('-u', '--username USER', 'User name') do |u|
94
+ options[:user] = u
95
+ end
96
+
97
+ opts.on('-p', '--password PASSWORD', 'Password') do |p|
98
+ options[:password] = p
99
+ end
100
+
101
+ opts.on('-v', '--[no-]verbose', 'Run verbosely') do |v|
102
+ options[:verbose] = v
103
+ end
104
+
105
+ opts.on('-h', '--help', 'Show this message') do
106
+ options[:help] = true
107
+ end
108
+ end
109
+
110
+ args = []
111
+
112
+ ARGV.each do |arg|
113
+ if arg == '--'
114
+ break
115
+ else
116
+ args << arg
117
+ end
118
+ end
119
+
120
+ @global_opt.parse!(args)
121
+
122
+ # p options
123
+ #p ARGV
124
+
125
+ [args, options]
126
+ end
127
+
128
+ def parameters(action)
129
+ options = {}
130
+ sep = ARGV.index('--')
131
+
132
+ @action_opt = OptionParser.new do |opts|
133
+ opts.banner = ''
134
+
135
+ action.input[:parameters].each do |name, p|
136
+ opts.on(param_option(name, p), p[:description] || p[:label] || '') do |*args|
137
+ options[name] = args.first
138
+ end
139
+ end
140
+
141
+ opts.on('-h', '--help', 'Show this message') do
142
+ @opts[:help] = true
143
+ end
144
+ end
145
+
146
+ if @opts[:help]
147
+ puts @global_opt.help
148
+ puts ''
149
+ print 'Action parameters:'
150
+ puts @action_opt.help
151
+ exit
152
+ end
153
+
154
+ return {} unless sep
155
+
156
+ @action_opt.parse!(ARGV[sep+1..-1])
157
+
158
+ options
159
+ end
160
+
161
+ def param_option(name, p)
162
+ ret = '--'
163
+ name = name.to_s.dasherize
164
+
165
+ if p[:type] == 'Boolean'
166
+ ret += "[no-]#{name}"
167
+
168
+ else
169
+ ret += "#{name} #{name.underscore.upcase}"
170
+ end
171
+
172
+ ret
173
+ end
174
+
175
+ def translate_action(action)
176
+ tr = {
177
+ list: :index,
178
+ new: :create,
179
+ change: :update
180
+ }
181
+
182
+ if tr.has_key?(action)
183
+ return tr[action]
184
+ end
185
+
186
+ action
187
+ end
188
+
189
+ def list_versions
190
+ desc = @api.describe_api
191
+
192
+ desc[:versions].each do |v, _|
193
+ next if v == :default
194
+
195
+ v_int = v.to_s.to_i
196
+
197
+ puts "#{v_int == desc[:default_version] ? '*' : ' '} v#{v}"
198
+ end
199
+ end
200
+
201
+ def list_resources(v)
202
+ @api.describe_api(v)[:resources].each do |resource, children|
203
+ nested_resource(resource, children, false)
204
+ end
205
+ end
206
+
207
+ def list_actions(v)
208
+ @api.describe_api(v)[:resources].each do |resource, children|
209
+ nested_resource(resource, children, true)
210
+ end
211
+ end
212
+
213
+ def nested_resource(prefix, children, actions=false)
214
+ if actions
215
+ children[:actions].each do |action, _|
216
+ puts "#{prefix}##{action}"
217
+ end
218
+ else
219
+ puts prefix
220
+ end
221
+
222
+ children[:resources].each do |resource, children|
223
+ nested_resource("#{prefix}.#{resource}", children, actions)
224
+ end
225
+ end
226
+
227
+ def format_output(action, response)
228
+ if @opts[:raw]
229
+ puts response
230
+ return
231
+ end
232
+
233
+ return if response.empty?
234
+
235
+ s = action.structure
236
+ namespace = action.namespace(:output).to_sym
237
+
238
+ case action.layout.to_sym
239
+ when :list
240
+ tp response[namespace]
241
+
242
+
243
+ when :object
244
+ response[namespace].each do |k, v|
245
+ puts "#{k}: #{v}"
246
+ end
247
+
248
+
249
+ when :custom
250
+ pp response[namespace]
251
+
252
+ end
253
+ end
254
+
255
+ def header_for(action, param)
256
+ params = action.params
257
+
258
+ if params.has_key?(param) && params[param][:label]
259
+ params[param][:label]
260
+ else
261
+ param.to_s.upcase
262
+ end
263
+ end
264
+
265
+ def params_valid?(action)
266
+ if action.auth?
267
+ @opts[:user] ||= ask('User name: ') { |q| q.default = nil }
268
+
269
+ @opts[:password] ||= ask('Password: ') do |q|
270
+ q.default = nil
271
+ q.echo = false
272
+ end
273
+ end
274
+
275
+ if action.auth? && !(@opts[:user] || @opts[:password])
276
+ return false
277
+ end
278
+
279
+ @api.login(@opts[:user], @opts[:password])
280
+
281
+ true
282
+ end
283
+
284
+ protected
285
+ def default_url
286
+ 'http://localhost:4567'
287
+ end
288
+ end
289
+ end
290
+ end
@@ -0,0 +1,2 @@
1
+ require 'require_all'
2
+ require_rel 'client'
@@ -0,0 +1,81 @@
1
+ module HaveAPI
2
+ module Client
3
+ class Action
4
+ def initialize(api, name, spec, args)
5
+ @api = api
6
+ @name = name
7
+ @spec = spec
8
+
9
+ apply_args(args)
10
+ end
11
+
12
+ def execute(*args)
13
+ ret = @api.call(self, *args)
14
+ @prepared_url = nil
15
+ ret
16
+ end
17
+
18
+ def name
19
+ @name
20
+ end
21
+
22
+ def auth?
23
+ @spec[:auth]
24
+ end
25
+
26
+ def input
27
+ @spec[:input]
28
+ end
29
+
30
+ def output
31
+ @spec[:output]
32
+ end
33
+
34
+ def layout
35
+ @spec[:output][:layout]
36
+ end
37
+
38
+ def structure
39
+ @spec[:output][:format]
40
+ end
41
+
42
+ def namespace(src)
43
+ @spec[src][:namespace]
44
+ end
45
+
46
+ def params
47
+ @spec[:output][:parameters]
48
+ end
49
+
50
+ def url
51
+ @spec[:url]
52
+ end
53
+
54
+ # Url with resolved parameters.
55
+ def prepared_url
56
+ @prepared_url || @spec[:url]
57
+ end
58
+
59
+ def http_method
60
+ @spec[:method]
61
+ end
62
+
63
+ def unresolved_args?
64
+ prepared_url =~ /:[a-zA-Z\-_]+/
65
+ end
66
+
67
+ def provide_args(*args)
68
+ apply_args(args)
69
+ end
70
+
71
+ private
72
+ def apply_args(args)
73
+ @prepared_url ||= @spec[:url].dup
74
+
75
+ args.each do |arg|
76
+ @prepared_url.sub!(/:[a-zA-Z\-_]+/, arg.to_s)
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,37 @@
1
+ require 'pp'
2
+
3
+ class HaveAPI::Client::Client
4
+ attr_reader :resources
5
+
6
+ def initialize(url, v=nil)
7
+ @version = v
8
+ @api = VpsAdmin::API::Communicator.new(url)
9
+
10
+ setup_api(@api.describe_api)
11
+ end
12
+
13
+ def login(*credentials)
14
+ @api.login(*credentials)
15
+ end
16
+
17
+ private
18
+ def setup_api(description)
19
+ v = @version || description[:default_version]
20
+
21
+ @resources = {}
22
+
23
+ description[:versions][v.to_s.to_sym][:resources].each do |name, desc|
24
+ r = VpsAdmin::API::Resource.new(@api, name)
25
+ r.setup(desc)
26
+
27
+ define_singleton_method(name) do |*args|
28
+ tmp = r.dup
29
+ tmp.prepared_args = args
30
+ tmp.setup_from_clone(r)
31
+ tmp
32
+ end
33
+
34
+ @resources[name] = r
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,115 @@
1
+ require 'rest_client'
2
+ require 'json'
3
+ require 'active_support/inflections'
4
+ require 'active_support/inflector'
5
+ require_rel '../../restclient_ext'
6
+
7
+ module HaveAPI
8
+ module Client
9
+ class Communicator
10
+ def initialize(url)
11
+ @url = url
12
+ @rest = RestClient::Resource.new(@url)
13
+ @version = 1
14
+ end
15
+
16
+ def login(user, password)
17
+ @rest = RestClient::Resource.new(@url, user, password)
18
+ end
19
+
20
+ def describe_api(v=nil)
21
+ description_for(path_for(v))
22
+ end
23
+
24
+ def describe_action(v, r)
25
+
26
+ end
27
+
28
+ def get_action(resources, action, args)
29
+ @spec ||= describe_api(@version)
30
+
31
+ tmp = @spec
32
+
33
+ resources.each do |r|
34
+ tmp = tmp[:resources][r.to_sym]
35
+
36
+ return false unless tmp
37
+ end
38
+
39
+ a = tmp[:actions][action]
40
+
41
+ if a
42
+ Action.new(self, action, a, args)
43
+ else
44
+ false
45
+ end
46
+ end
47
+
48
+ def call(action, params, raw: false)
49
+ args = []
50
+ input_namespace = action.namespace(:input)
51
+
52
+ if %w(POST PUT).include?(action.http_method)
53
+ args << {input_namespace => params}.to_json
54
+ args << {:content_type => :json, :accept => :json}
55
+
56
+ elsif %w(GET DELETE).include?(action.http_method)
57
+ get_params = {}
58
+
59
+ params.each do |k, v|
60
+ get_params["#{input_namespace}[#{k}]"] = v
61
+ end
62
+
63
+ args << {params: get_params, accept: :json}
64
+ end
65
+
66
+ begin
67
+ response = parse(@rest[action.prepared_url].method(action.http_method.downcase.to_sym).call(*args))
68
+
69
+ rescue RestClient::Forbidden
70
+ return error('Access forbidden. Bad user name or password? Not authorized?')
71
+
72
+ rescue => e
73
+ return error("Fatal API error: #{e.inspect}")
74
+ end
75
+
76
+ if response[:status]
77
+ if raw
78
+ ok(JSON.pretty_generate(response[:response]))
79
+ else
80
+ ok(response[:response])
81
+ end
82
+
83
+ else
84
+ error(response[:message], response[:errors])
85
+ end
86
+ end
87
+
88
+ private
89
+ def ok(response)
90
+ {status: true, response: response}
91
+ end
92
+
93
+ def error(msg, errors={})
94
+ {status: false, message: msg, errors: errors}
95
+ end
96
+
97
+ def path_for(v=nil, r=nil)
98
+ ret = '/'
99
+
100
+ ret += "v#{v}/" if v
101
+ ret += r if r
102
+
103
+ ret
104
+ end
105
+
106
+ def description_for(path)
107
+ parse(@rest[path].get_options)
108
+ end
109
+
110
+ def parse(str)
111
+ JSON.parse(str, symbolize_names: true)
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,13 @@
1
+ module HaveAPI
2
+ module Client
3
+ class ActionFailed < Exception
4
+ def initialize(response)
5
+ @response = response
6
+ end
7
+
8
+ def message
9
+ "#{@response.action.name} failed: #{@response.message}"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ ActiveSupport::Inflector.inflections(:en) do |inflect|
2
+ inflect.irregular 'vps', 'vpses'
3
+ end
@@ -0,0 +1,78 @@
1
+ class HaveAPI::Client::Resource
2
+ attr_reader :actions, :resources, :name
3
+ attr_accessor :prepared_args
4
+
5
+ def initialize(api, name)
6
+ @api = api
7
+ @name = name
8
+ @prepared_args = []
9
+ end
10
+
11
+ def setup(description)
12
+ @actions = {}
13
+ @resources = {}
14
+
15
+ description[:actions].each do |name, desc|
16
+ action = HaveAPI::Client::Action.new(@api, name, desc, [])
17
+ define_action(action)
18
+ @actions[name] = action
19
+ end
20
+
21
+ description[:resources].each do |name, desc|
22
+ r = HaveAPI::Client::Resource.new(@api, name)
23
+ r.setup(desc)
24
+ define_resource(r)
25
+ @resources[name] = r
26
+ end
27
+ end
28
+
29
+ def setup_from_clone(original)
30
+ original.actions.each_value do |action|
31
+ define_action(action)
32
+ end
33
+
34
+ original.resources.each_value do |resource|
35
+ define_resource(resource)
36
+ end
37
+ end
38
+
39
+ private
40
+ def define_action(action)
41
+ define_singleton_method(action.name) do |*args|
42
+ all_args = @prepared_args + args
43
+
44
+ if action.unresolved_args?
45
+ all_args.delete_if do |arg|
46
+ break unless action.unresolved_args?
47
+
48
+ action.provide_args(arg)
49
+ true
50
+ end
51
+
52
+ if action.unresolved_args?
53
+ raise ArgumentError.new('One or more object ids missing')
54
+ end
55
+ end
56
+
57
+ all_args << {} if all_args.empty?
58
+
59
+ HaveAPI::Client::Response.new(action, action.execute(*all_args))
60
+ end
61
+
62
+ define_singleton_method("#{action.name}!".to_sym) do |*args|
63
+ ret = method(action.name).call(*args)
64
+ raise HaveAPI::Client::ActionFailed.new(ret) unless ret.ok?
65
+
66
+ ret
67
+ end
68
+ end
69
+
70
+ def define_resource(resource)
71
+ define_singleton_method(resource.name) do |*args|
72
+ tmp = resource.dup
73
+ tmp.prepared_args = @prepared_args + args
74
+ tmp.setup_from_clone(resource)
75
+ tmp
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,33 @@
1
+ class HaveAPI::Client::Response
2
+ attr_reader :action
3
+
4
+ def initialize(action, response)
5
+ @action = action
6
+ @response = response
7
+ end
8
+
9
+ def ok?
10
+ @response[:status]
11
+ end
12
+
13
+ def failed?
14
+ !ok?
15
+ end
16
+
17
+ def response
18
+ case @action.layout.to_sym
19
+ when :object, :list
20
+ @response[:response][@action.namespace(:output).to_sym]
21
+ else
22
+ @response[:response]
23
+ end
24
+ end
25
+
26
+ def message
27
+ @response[:message]
28
+ end
29
+
30
+ def errors
31
+ @response[:errors]
32
+ end
33
+ end
@@ -0,0 +1,5 @@
1
+ module HaveAPI
2
+ module Client
3
+ VERSION = '0.1.0'
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ module RestClient
2
+ class Request
3
+ def self.execute_options(args, &block)
4
+ new(args).execute_options(&block)
5
+ end
6
+
7
+ def execute_options(&block)
8
+ uri = parse_url_with_auth(url)
9
+ http_request = Net::HTTPGenericRequest.new(method.to_s.upcase, false, true, uri.request_uri, processed_headers)
10
+
11
+ transmit uri, http_request, payload, & block
12
+ ensure
13
+ payload.close if payload
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+ module RestClient
2
+ class Resource
3
+ def get_options(additional_headers={}, &block)
4
+ headers = (options[:headers] || {}).merge(additional_headers)
5
+ Request.execute_options(options.merge(
6
+ :method => :options,
7
+ :url => url,
8
+ :headers => headers), &(block || @block))
9
+ end
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,175 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: haveapi-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jakub Skokan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-19 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.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activesupport
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 4.1.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 4.1.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: require_all
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.3.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 1.3.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: rest_client
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: 1.7.3
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: 1.7.3
83
+ - !ruby/object:Gem::Dependency
84
+ name: json
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: 1.8.1
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: 1.8.1
97
+ - !ruby/object:Gem::Dependency
98
+ name: highline
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: 1.6.21
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: 1.6.21
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: 1.5.1
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ~>
123
+ - !ruby/object:Gem::Version
124
+ version: 1.5.1
125
+ description: Ruby API and CLI for HaveAPI
126
+ email:
127
+ - jakub.skokan@vpsfree.cz
128
+ executables:
129
+ - haveapi-cli
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - Gemfile
134
+ - README.md
135
+ - Rakefile
136
+ - bin/haveapi-cli
137
+ - haveapi-client.gemspec
138
+ - lib/haveapi/cli.rb
139
+ - lib/haveapi/cli/cli.rb
140
+ - lib/haveapi/client.rb
141
+ - lib/haveapi/client/action.rb
142
+ - lib/haveapi/client/client.rb
143
+ - lib/haveapi/client/communicator.rb
144
+ - lib/haveapi/client/exceptions.rb
145
+ - lib/haveapi/client/inflections.rb
146
+ - lib/haveapi/client/resource.rb
147
+ - lib/haveapi/client/response.rb
148
+ - lib/haveapi/client/version.rb
149
+ - lib/restclient_ext/request.rb
150
+ - lib/restclient_ext/resource.rb
151
+ homepage: ''
152
+ licenses:
153
+ - GPL
154
+ metadata: {}
155
+ post_install_message:
156
+ rdoc_options: []
157
+ require_paths:
158
+ - lib
159
+ required_ruby_version: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - '>='
162
+ - !ruby/object:Gem::Version
163
+ version: '0'
164
+ required_rubygems_version: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - '>='
167
+ - !ruby/object:Gem::Version
168
+ version: '0'
169
+ requirements: []
170
+ rubyforge_project:
171
+ rubygems_version: 2.1.11
172
+ signing_key:
173
+ specification_version: 4
174
+ summary: Ruby API and CLI for HaveAPI
175
+ test_files: []