beats-client 0.2.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.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm 1.8.7@beats-ruby-client --create
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/HISTORY.md ADDED
@@ -0,0 +1,21 @@
1
+
2
+ ### 0.1.1 (2012-01-31)
3
+
4
+ * Secure handling of password input
5
+ * Better handling of network errors and authentication errors
6
+
7
+ ### 0.1.0 (2012-01-31)
8
+
9
+ * Simple extensible command line interface (CLI)
10
+ * Implemented some basic commands:
11
+ - help
12
+ - version
13
+ - info
14
+ - show
15
+ - search
16
+ - auth:login
17
+ - auth:logout
18
+ - account
19
+ - account:history
20
+ * Secure authentication and credentials handling (stored in ~/.beats/credentials.yml)
21
+ * A basic Beats::Client class for programatic interaction with the Beats API
data/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # Beats Client
2
+
3
+ A CLI client and SDK for Beats API.
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ $LOAD_PATH.unshift 'lib'
5
+
6
+ task :default => [:test]
7
+
8
+ desc 'Run test suite'
9
+ task :test do
10
+ Dir.glob('test/**/*_test.rb').each do |file|
11
+ require File.expand_path(file)
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "beats/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "beats-client"
7
+ s.version = Beats::VERSION
8
+ s.authors = ["Niklas Holmgren"]
9
+ s.email = ["niklas@sutajio.se"]
10
+ s.homepage = "https://github.com/ProjectDaisy/beats-ruby-client"
11
+ s.summary = %q{A CLI client and SDK for Beats API}
12
+ s.description = %q{A CLI client and SDK for Beats API}
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_dependency 'rest-client'
20
+ s.add_dependency 'multi_json'
21
+ s.add_dependency 'json_pure'
22
+ s.add_development_dependency 'rake'
23
+ end
data/bin/beats ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ require 'beats'
7
+ require 'beats/command'
8
+
9
+ args = ARGV.dup
10
+ ARGV.clear
11
+ command = args.shift.strip rescue 'help'
12
+
13
+ Beats::Command.run(command, args)
data/lib/beats/auth.rb ADDED
@@ -0,0 +1,114 @@
1
+ module Beats
2
+ class Auth
3
+ class << self
4
+
5
+ def login
6
+ ask_for_credentials
7
+ end
8
+
9
+ def logout
10
+ delete_credentials
11
+ end
12
+
13
+ def access_token
14
+ @credentials ||= read_credentials
15
+ if @credentials
16
+ @credentials['access_token']
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def running_on_windows?
23
+ RUBY_PLATFORM =~ /mswin32|mingw32/
24
+ end
25
+
26
+ def home_directory
27
+ running_on_windows? ? ENV['USERPROFILE'].gsub('\\','/') : ENV['HOME']
28
+ end
29
+
30
+ def credentials_file
31
+ "#{home_directory}/.beats/credentials.yml"
32
+ end
33
+
34
+ def read_credentials
35
+ if File.exists?(credentials_file)
36
+ YAML.load(File.read(credentials_file))
37
+ end
38
+ end
39
+
40
+ def save_credentials(credentials)
41
+ FileUtils.mkdir_p(File.dirname(credentials_file))
42
+ f = File.open(credentials_file, 'w')
43
+ f.write(YAML.dump(credentials))
44
+ f.close
45
+ set_credentials_permissions
46
+ end
47
+
48
+ def set_credentials_permissions
49
+ FileUtils.chmod 0700, File.dirname(credentials_file)
50
+ FileUtils.chmod 0600, credentials_file
51
+ end
52
+
53
+ def delete_credentials
54
+ FileUtils.rm_f(credentials_file)
55
+ end
56
+
57
+ def get_credentials
58
+ read_credentials || ask_for_credentials
59
+ end
60
+
61
+ def ask_for_password_on_windows
62
+ require "Win32API"
63
+ char = nil
64
+ password = ''
65
+ while char = Win32API.new("crtdll", "_getch", [ ], "L").Call do
66
+ break if char == 10 || char == 13 # received carriage return or newline
67
+ if char == 127 || char == 8 # backspace and delete
68
+ password.slice!(-1, 1)
69
+ else
70
+ # windows might throw a -1 at us so make sure to handle RangeError
71
+ (password << char.chr) rescue RangeError
72
+ end
73
+ end
74
+ puts
75
+ return password
76
+ end
77
+
78
+ def ask_for_password
79
+ if running_on_windows?
80
+ ask_for_password_on_windows
81
+ else
82
+ `stty -echo`
83
+ trap('INT') do
84
+ puts
85
+ `stty echo`
86
+ exit(1)
87
+ end
88
+ password = STDIN.gets.strip
89
+ puts
90
+ `stty echo`
91
+ return password
92
+ end
93
+ end
94
+
95
+ def ask_for_credentials
96
+ check_credentials do
97
+ puts 'Please enter your credentials.'
98
+ print 'Access token: '
99
+ access_token = ask_for_password
100
+ end
101
+ end
102
+
103
+ def check_credentials(&block)
104
+ access_token = yield
105
+ Beats::Client.new(:access_token => access_token).account
106
+ save_credentials('access_token' => access_token)
107
+ rescue ::RestClient::Unauthorized
108
+ puts 'Authentication failed.'
109
+ retry
110
+ end
111
+
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,98 @@
1
+ require 'rest_client'
2
+ require 'json'
3
+ require 'multi_json'
4
+ require 'uri'
5
+ require 'base64'
6
+
7
+ module Beats
8
+ class Client
9
+
10
+ DEFAULT_OPTIONS = {
11
+ :base_url => ENV['BEATS_URL'] || 'http://prdaisy.com/'
12
+ }
13
+
14
+ # Creates a client object that can be used to interact with the Beats API
15
+ # @param [Hash] options Configuration options for the client
16
+ # @option options [String] :base_url The URL the client will use to access
17
+ # the API. Defaults to http://prdaisy.com/ or the BEATS_URL environment
18
+ # variable if it is set.
19
+ # @option options [String] :access_token The access token to use for
20
+ # requests that require authentication.
21
+ def initialize(options = {})
22
+ options = DEFAULT_OPTIONS.merge(options)
23
+ @base_url = options[:base_url]
24
+ @access_token = options[:access_token]
25
+ end
26
+
27
+ def index
28
+ get(@base_url)
29
+ rescue RestClient::MultipleChoices => e
30
+ @index ||= decode_json(e.response.body)
31
+ end
32
+
33
+ def account
34
+ decode_json(get(resolve_uri(@base_url, href(:account))))
35
+ end
36
+
37
+ def resource(uri)
38
+ decode_json(get(resolve_uri(@base_url, uri)))
39
+ end
40
+
41
+ def search(query)
42
+ decode_json(get(resolve_uri(@base_url, href(:search)),
43
+ :params => { :q => query }))
44
+ end
45
+
46
+ def add_history(uri)
47
+ post(resolve_uri(@base_url, href(:history)),
48
+ :uri => uri)
49
+ end
50
+
51
+ def sentence
52
+ decode_json(get(resolve_uri(@base_url, href(:sentence))))
53
+ end
54
+
55
+ private
56
+
57
+ def default_headers
58
+ return @default_headers if @default_headers
59
+ @default_headers = {}
60
+ @default_headers[:accept] = :json
61
+ if @access_token
62
+ @default_headers[:authorization] =
63
+ "Bearer #{Base64.encode64(@access_token)}"
64
+ end
65
+ @default_headers
66
+ end
67
+
68
+ def get(url, options = {})
69
+ RestClient.get(url, default_headers.merge(options))
70
+ end
71
+
72
+ def post(url, payload, options = {})
73
+ RestClient.post(url, payload, default_headers.merge(options))
74
+ end
75
+
76
+ def href(rel, options = {})
77
+ links = options[:links] || index['links']
78
+ links.each do |link|
79
+ return link['href'] if link['rel'] == rel.to_s
80
+ end
81
+ raise ArgumentError, "Unknown link \"#{rel}\""
82
+ end
83
+
84
+ def resolve_uri(base_uri, uri)
85
+ uri = URI.parse(uri)
86
+ if uri.relative?
87
+ URI.join(base_uri, uri).to_s
88
+ else
89
+ uri.to_s
90
+ end
91
+ end
92
+
93
+ def decode_json(json)
94
+ json.is_a?(String) ? MultiJson.decode(json) : json
95
+ end
96
+
97
+ end
98
+ end
@@ -0,0 +1,77 @@
1
+ require 'beats/commands/base'
2
+
3
+ Dir["#{File.dirname(__FILE__)}/commands/*.rb"].each { |c| require c }
4
+
5
+ module Beats
6
+ module Command
7
+ class InvalidCommand < RuntimeError; end
8
+ class CommandFailed < RuntimeError; end
9
+
10
+ DEFAULT_COMMAND = 'help'
11
+
12
+ class << self
13
+ def parse(command)
14
+ command = DEFAULT_COMMAND if command == ''
15
+ parts = command.split(':')
16
+ klass = command_class(parts.first)
17
+ if klass.has_command?(parts.last)
18
+ [klass, parts.last.to_sym]
19
+ else
20
+ raise InvalidCommand, command
21
+ end
22
+ end
23
+
24
+ def run(command, *args)
25
+ klass, method = parse(command)
26
+ klass.new(*args.flatten).send(method)
27
+ rescue RestClient::Unauthorized => e
28
+ puts '!!! AUTHENTICATION REQUIRED !!!'
29
+ run 'auth:login'
30
+ retry
31
+ rescue RestClient::RequestTimeout
32
+ error 'Request timed out. Please try again, or contact support if this issue persists.'
33
+ rescue RestClient::Exception => e
34
+ error extract_error(e)
35
+ rescue SocketError => e
36
+ error "Unable to connect to server. Your internet connection might be down."
37
+ rescue InvalidCommand => e
38
+ error "Unknown command: #{e.to_s}"
39
+ rescue CommandFailed => e
40
+ error e.message
41
+ rescue Interrupt => e
42
+ error "\n[canceled]"
43
+ end
44
+
45
+ private
46
+
47
+ def command_class(command)
48
+ eval("Beats::Command::#{command.to_s.capitalize}")
49
+ rescue NameError
50
+ Beats::Command::Api
51
+ end
52
+
53
+ def error(message)
54
+ STDERR.puts message
55
+ exit(1)
56
+ end
57
+
58
+ def extract_error(e)
59
+ return e.message if e.response.nil?
60
+ case e.response.headers[:content_type]
61
+ when 'application/json'
62
+ error = MultiJson.decode(e.http_body)
63
+ if error.is_a?(Hash) && error['error']
64
+ error['error_description'] || error['error']
65
+ else
66
+ e.message
67
+ end
68
+ when 'text/plain'
69
+ e.http_body && e.http_body != '' ? e.http_body.to_s : e.message
70
+ else
71
+ e.message
72
+ end
73
+ end
74
+
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,19 @@
1
+ module Beats
2
+ module Command
3
+ class Account < Base
4
+
5
+ def account
6
+ display YAML.dump(client.account)
7
+ end
8
+
9
+ def history
10
+ if args.empty?
11
+ raise CommandFailed, command_usage('account:history', 'URI')
12
+ else
13
+ client.add_history(CGI.escape(args.first))
14
+ end
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,46 @@
1
+ module Beats
2
+ module Command
3
+ class Api < Base
4
+
5
+ def info
6
+ display YAML.dump(client.index)
7
+ end
8
+
9
+ def show
10
+ if args.empty?
11
+ raise CommandFailed, command_usage('show', 'URI [...]')
12
+ else
13
+ display_resources(args.map { |uri|
14
+ client.resource(CGI.escape(uri))
15
+ })
16
+ end
17
+ end
18
+
19
+ def search
20
+ interactive do |args|
21
+ query = args.join(' AND ')
22
+ display "Searching for: \"#{query}\""
23
+ results = client.search(query)
24
+ display "#{results['total']} item(s) found"
25
+ %w(artists albums tracks).each do |collection|
26
+ next unless results[collection].is_a?(Array)
27
+ display_resources(results[collection])
28
+ end
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def display_resources(resources)
35
+ resources.each do |resource|
36
+ display '-'*80
37
+ display "URI: #{resource['uri']}"
38
+ display "Name: #{resource['name']}"
39
+ display "Type: #{resource['type']}"
40
+ end
41
+ display '-'*80 unless resources.empty?
42
+ end
43
+
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,15 @@
1
+ module Beats
2
+ module Command
3
+ class Auth < Base
4
+
5
+ def login
6
+ Beats::Auth.login
7
+ end
8
+
9
+ def logout
10
+ Beats::Auth.logout
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,54 @@
1
+ require 'readline'
2
+ require 'yaml'
3
+
4
+ module Beats
5
+ module Command
6
+ class Base
7
+
8
+ attr_reader :args
9
+
10
+ def initialize(*args)
11
+ @args = args
12
+ end
13
+
14
+ def self.has_command?(command)
15
+ if self.instance_methods.first.is_a?(Symbol)
16
+ self.instance_methods.include?(command.to_sym)
17
+ else
18
+ self.instance_methods.include?(command.to_s)
19
+ end
20
+ end
21
+
22
+ protected
23
+
24
+ def client
25
+ @client ||= Beats::Client.new(
26
+ :access_token => Beats::Auth.access_token)
27
+ end
28
+
29
+ def display(message)
30
+ puts message
31
+ end
32
+
33
+ def command_usage(command, options)
34
+ " ! Usage: beats #{command} #{options}"
35
+ end
36
+
37
+ def interactive(&block)
38
+ if args.empty?
39
+ display "Interactive mode. Exit with ^D."
40
+ while line = Readline.readline('> ', true)
41
+ if line
42
+ yield([line])
43
+ else
44
+ break
45
+ end
46
+ end
47
+ else
48
+ yield(args)
49
+ end
50
+ end
51
+
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,61 @@
1
+ module Beats
2
+ module Command
3
+ class Help < Base
4
+
5
+ def help
6
+ display 'Usage: beats COMMAND [command-specific-options]'
7
+ space
8
+ command_group('Help commands (type "beats help COMMAND" for more details):') do
9
+ command 'help', 'show this help text'
10
+ command 'version', 'show version information'
11
+ end
12
+ command_group('General commands:') do
13
+ command 'info', 'show detailed service info'
14
+ command 'show', 'fetch and show a resource'
15
+ command 'search', 'search in the music catalogue'
16
+ end
17
+ command_group('Account commands:') do
18
+ command 'auth:login', 'authenticate with your account credentials'
19
+ command 'auth:logout', 'clear saved credentials'
20
+ command 'account', 'show account info for current user'
21
+ command 'account:history', 'add something to a users history'
22
+ end
23
+ command_group('The sentence:') do
24
+ command 'sentence', 'show the sentence'
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ class CommandGroup
31
+ def initialize(&block)
32
+ @commands = []
33
+ instance_eval(&block)
34
+ end
35
+ def command(command, description)
36
+ @commands << [command, description]
37
+ end
38
+ def display(&block)
39
+ max_length = @commands.map {|c| c.first.size }.sort.last
40
+ @commands.each do |c|
41
+ command, description = c.first, c.last
42
+ yield(" #{command.ljust(max_length+2)}# #{description}")
43
+ end
44
+ end
45
+ end
46
+
47
+ def command_group(title = nil, &block)
48
+ display("#{title}\n\n") if title
49
+ CommandGroup.new(&block).display do |command|
50
+ display command
51
+ end
52
+ space
53
+ end
54
+
55
+ def space
56
+ display "\n"
57
+ end
58
+
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,14 @@
1
+ module Beats
2
+ module Command
3
+ class Sentence < Base
4
+
5
+ def sentence
6
+ display(client.sentence['fields'].map { |field|
7
+ option = field['options'][rand(field['options'].size)]
8
+ [option['prefix'] || field['prefix'], "{#{option['name']}}", option['suffix'] || field['suffix']]
9
+ }.flatten.compact.join(' '))
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ module Beats
2
+ module Command
3
+ class Version < Base
4
+
5
+ def version
6
+ require 'beats/version'
7
+ display "Beats v#{Beats::VERSION}"
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ module Beats
2
+ VERSION = '0.2.0'
3
+ end
data/lib/beats.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+ require 'beats/version'
3
+ require 'beats/client'
4
+ require 'beats/auth'
5
+
6
+ module Beats; end
@@ -0,0 +1,62 @@
1
+ require File.expand_path('test/test_helper')
2
+
3
+ class ClientTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @client = Beats::Client.new(:access_token => '_ojSy7QjgPJ2gUh3UeQXzAye5aoN-0QoWKmCMxFHuuI')
7
+ end
8
+
9
+ def test_can_resolve_uri
10
+ assert_equal 'http://example.com/test', @client.send(:resolve_uri, 'http://example.com/foo/', '/test')
11
+ assert_equal 'http://example.com/foo/test', @client.send(:resolve_uri, 'http://example.com/foo/', 'test')
12
+ assert_equal 'http://example.com/test', @client.send(:resolve_uri, 'http://example.com/', 'test')
13
+ assert_equal 'http://test.com/test', @client.send(:resolve_uri, 'http://example.com/foo/', 'http://test.com/test')
14
+ end
15
+
16
+ def test_can_load_index
17
+ assert @client.index
18
+ assert @client.index['links']
19
+ end
20
+
21
+ def test_can_load_account
22
+ assert_equal 'Niklas-Holmgren', @client.account['uri']
23
+ assert_equal 'Niklas Holmgren', @client.account['name']
24
+ assert_equal 'Account', @client.account['type']
25
+ end
26
+
27
+ def test_can_load_resource
28
+ resource = @client.resource('Niklas-Holmgren')
29
+ assert_equal 'Niklas-Holmgren', resource['uri']
30
+ assert_equal 'Niklas Holmgren', resource['name']
31
+ assert_equal 'Account', resource['type']
32
+ end
33
+
34
+ def test_can_search
35
+ results = @client.search('The Beatles')
36
+ assert results['total']
37
+ assert results['page']
38
+ assert results['per_page']
39
+ assert results['pages']
40
+ assert results['artists']
41
+ assert results['albums']
42
+ assert results['tracks']
43
+ end
44
+
45
+ def test_can_add_to_history
46
+ @client.add_history('The-Beatles')
47
+ end
48
+
49
+ def test_can_load_the_sentence
50
+ sentence = @client.sentence
51
+ assert_equal false, sentence['fields'].empty?
52
+ sentence['fields'].each do |field|
53
+ assert field['prefix']
54
+ assert field['options']
55
+ field['options'].each do |option|
56
+ assert option['id']
57
+ assert option['name']
58
+ end
59
+ end
60
+ end
61
+
62
+ end
@@ -0,0 +1,34 @@
1
+ require File.expand_path('test/test_helper')
2
+ require 'beats/command'
3
+
4
+ class Beats::Command::Test < Beats::Command::Base
5
+ def test; 'success'; end
6
+ def foo; "#{args[0]},#{args[1]},#{args[2]}"; end
7
+ end
8
+
9
+ class CommandTest < Test::Unit::TestCase
10
+
11
+ def test_should_resolve_commands
12
+ assert_equal [Beats::Command::Help, :help], Beats::Command.parse('')
13
+ assert_equal [Beats::Command::Test, :test], Beats::Command.parse('test')
14
+ assert_equal [Beats::Command::Test, :foo], Beats::Command.parse('test:foo')
15
+ end
16
+
17
+ def test_should_raise_exeption_if_command_could_not_be_resolved
18
+ assert_raises Beats::Command::InvalidCommand do
19
+ Beats::Command.parse('foo')
20
+ end
21
+ assert_raises Beats::Command::InvalidCommand do
22
+ Beats::Command.parse('foo:bar')
23
+ end
24
+ assert_raises Beats::Command::InvalidCommand do
25
+ Beats::Command.parse('foo:bar:baz')
26
+ end
27
+ end
28
+
29
+ def test_should_run_commands
30
+ assert_equal 'success', Beats::Command.run('test', [])
31
+ assert_equal '1,2,3', Beats::Command.run('test:foo', [1,2,3])
32
+ end
33
+
34
+ end
@@ -0,0 +1,9 @@
1
+ dir = File.dirname(File.expand_path(__FILE__))
2
+ $LOAD_PATH.unshift dir + '/../lib'
3
+
4
+ ENV['BEATS_URL'] = 'http://prdaisy.com/'
5
+
6
+ require 'rubygems'
7
+ require 'test/unit'
8
+ require 'pp'
9
+ require 'beats'
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: beats-client
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
+ platform: ruby
12
+ authors:
13
+ - Niklas Holmgren
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-02-01 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rest-client
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: multi_json
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ hash: 3
43
+ segments:
44
+ - 0
45
+ version: "0"
46
+ type: :runtime
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: json_pure
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ type: :runtime
61
+ version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ prerelease: false
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ hash: 3
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ type: :development
75
+ version_requirements: *id004
76
+ description: A CLI client and SDK for Beats API
77
+ email:
78
+ - niklas@sutajio.se
79
+ executables:
80
+ - beats
81
+ extensions: []
82
+
83
+ extra_rdoc_files: []
84
+
85
+ files:
86
+ - .gitignore
87
+ - .rvmrc
88
+ - Gemfile
89
+ - HISTORY.md
90
+ - README.md
91
+ - Rakefile
92
+ - beats-client.gemspec
93
+ - bin/beats
94
+ - lib/beats.rb
95
+ - lib/beats/auth.rb
96
+ - lib/beats/client.rb
97
+ - lib/beats/command.rb
98
+ - lib/beats/commands/account.rb
99
+ - lib/beats/commands/api.rb
100
+ - lib/beats/commands/auth.rb
101
+ - lib/beats/commands/base.rb
102
+ - lib/beats/commands/help.rb
103
+ - lib/beats/commands/sentence.rb
104
+ - lib/beats/commands/version.rb
105
+ - lib/beats/version.rb
106
+ - test/client_test.rb
107
+ - test/command_test.rb
108
+ - test/test_helper.rb
109
+ homepage: https://github.com/ProjectDaisy/beats-ruby-client
110
+ licenses: []
111
+
112
+ post_install_message:
113
+ rdoc_options: []
114
+
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ none: false
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ hash: 3
123
+ segments:
124
+ - 0
125
+ version: "0"
126
+ required_rubygems_version: !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ hash: 3
132
+ segments:
133
+ - 0
134
+ version: "0"
135
+ requirements: []
136
+
137
+ rubyforge_project:
138
+ rubygems_version: 1.8.8
139
+ signing_key:
140
+ specification_version: 3
141
+ summary: A CLI client and SDK for Beats API
142
+ test_files:
143
+ - test/client_test.rb
144
+ - test/command_test.rb
145
+ - test/test_helper.rb