beats-client 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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