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 +4 -0
- data/.rvmrc +1 -0
- data/Gemfile +3 -0
- data/HISTORY.md +21 -0
- data/README.md +3 -0
- data/Rakefile +13 -0
- data/beats-client.gemspec +23 -0
- data/bin/beats +13 -0
- data/lib/beats/auth.rb +114 -0
- data/lib/beats/client.rb +98 -0
- data/lib/beats/command.rb +77 -0
- data/lib/beats/commands/account.rb +19 -0
- data/lib/beats/commands/api.rb +46 -0
- data/lib/beats/commands/auth.rb +15 -0
- data/lib/beats/commands/base.rb +54 -0
- data/lib/beats/commands/help.rb +61 -0
- data/lib/beats/commands/sentence.rb +14 -0
- data/lib/beats/commands/version.rb +12 -0
- data/lib/beats/version.rb +3 -0
- data/lib/beats.rb +6 -0
- data/test/client_test.rb +62 -0
- data/test/command_test.rb +34 -0
- data/test/test_helper.rb +9 -0
- metadata +145 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.8.7@beats-ruby-client --create
|
data/Gemfile
ADDED
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
data/Rakefile
ADDED
@@ -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
|
data/lib/beats/client.rb
ADDED
@@ -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,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
|
data/lib/beats.rb
ADDED
data/test/client_test.rb
ADDED
@@ -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
|
data/test/test_helper.rb
ADDED
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
|