ibm_watson 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +258 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/ibm_watson.rb +16 -0
- data/lib/ibm_watson/assistant_v1.rb +1997 -0
- data/lib/ibm_watson/detailed_response.rb +21 -0
- data/lib/ibm_watson/discovery_v1.rb +2039 -0
- data/lib/ibm_watson/iam_token_manager.rb +166 -0
- data/lib/ibm_watson/language_translator_v3.rb +411 -0
- data/lib/ibm_watson/natural_language_classifier_v1.rb +309 -0
- data/lib/ibm_watson/natural_language_understanding_v1.rb +297 -0
- data/lib/ibm_watson/personality_insights_v3.rb +260 -0
- data/lib/ibm_watson/speech_to_text_v1.rb +2153 -0
- data/lib/ibm_watson/text_to_speech_v1.rb +716 -0
- data/lib/ibm_watson/tone_analyzer_v3.rb +287 -0
- data/lib/ibm_watson/version.rb +3 -0
- data/lib/ibm_watson/visual_recognition_v3.rb +579 -0
- data/lib/ibm_watson/watson_api_exception.rb +41 -0
- data/lib/ibm_watson/watson_service.rb +180 -0
- data/lib/ibm_watson/websocket/recognize_callback.rb +32 -0
- data/lib/ibm_watson/websocket/speech_to_text_websocket_listener.rb +162 -0
- data/rakefile +45 -0
- data/test/integration/test_assistant_v1.rb +645 -0
- data/test/integration/test_discovery_v1.rb +200 -0
- data/test/integration/test_iam_assistant_v1.rb +707 -0
- data/test/integration/test_language_translator_v3.rb +81 -0
- data/test/integration/test_natural_language_classifier_v1.rb +69 -0
- data/test/integration/test_natural_language_understanding_v1.rb +98 -0
- data/test/integration/test_personality_insights_v3.rb +95 -0
- data/test/integration/test_speech_to_text_v1.rb +187 -0
- data/test/integration/test_text_to_speech_v1.rb +81 -0
- data/test/integration/test_tone_analyzer_v3.rb +72 -0
- data/test/integration/test_visual_recognition_v3.rb +64 -0
- data/test/test_helper.rb +22 -0
- data/test/unit/test_assistant_v1.rb +1598 -0
- data/test/unit/test_discovery_v1.rb +1144 -0
- data/test/unit/test_iam_token_manager.rb +165 -0
- data/test/unit/test_language_translator_v3.rb +461 -0
- data/test/unit/test_natural_language_classifier_v1.rb +187 -0
- data/test/unit/test_natural_language_understanding_v1.rb +132 -0
- data/test/unit/test_personality_insights_v3.rb +172 -0
- data/test/unit/test_speech_to_text_v1.rb +755 -0
- data/test/unit/test_text_to_speech_v1.rb +336 -0
- data/test/unit/test_tone_analyzer_v3.rb +200 -0
- data/test/unit/test_vcap_using_personality_insights.rb +150 -0
- data/test/unit/test_visual_recognition_v3.rb +345 -0
- metadata +302 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require("json")
|
4
|
+
# Custom exception class for errors returned from Watson APIs
|
5
|
+
class WatsonApiException < StandardError
|
6
|
+
attr_reader :code, :error, :info, :transaction_id, :global_transaction_id
|
7
|
+
# :param HTTP::Response response: The response object from the Watson API
|
8
|
+
def initialize(code: nil, error: nil, info: nil, transaction_id: nil, global_transaction_id: nil, response: nil)
|
9
|
+
if code.nil? || error.nil?
|
10
|
+
@code = response.code
|
11
|
+
@error = response.reason
|
12
|
+
unless response.body.empty?
|
13
|
+
body_hash = JSON.parse(response.body.to_s)
|
14
|
+
@code = body_hash["code"] || body_hash["error_code"]
|
15
|
+
@error = body_hash["error"] || body_hash["error_message"]
|
16
|
+
%w[code error_code error error_message].each { |k| body_hash.delete(k) }
|
17
|
+
@info = body_hash
|
18
|
+
end
|
19
|
+
@transaction_id = transaction_id
|
20
|
+
@global_transaction_id = global_transaction_id
|
21
|
+
@transaction_id = response.headers["X-DP-Watson-Tran-ID"] if response.headers.include?("X-DP-Watson-Tran-ID")
|
22
|
+
@global_transaction_id = response.headers["X-Global-Transaction-ID"] if response.headers.include?("X-Global-Transaction-ID")
|
23
|
+
else
|
24
|
+
# :nocov:
|
25
|
+
@code = code
|
26
|
+
@error = error
|
27
|
+
@info = info
|
28
|
+
@transaction_id = transaction_id
|
29
|
+
@global_transaction_id = global_transaction_id
|
30
|
+
# :nocov:
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
msg = "Error: #{@error}, Code: #{@code}"
|
36
|
+
msg += ", Information: #{@info}" unless @info.nil?
|
37
|
+
msg += ", X-dp-watson-tran-id: #{@transaction_id}" unless @transaction_id.nil?
|
38
|
+
msg += ", X-global-transaction-id: #{@global_transaction_id}" unless @global_transaction_id.nil?
|
39
|
+
msg
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require("http")
|
4
|
+
require("rbconfig")
|
5
|
+
require("stringio")
|
6
|
+
require("json")
|
7
|
+
require_relative("./detailed_response.rb")
|
8
|
+
require_relative("./watson_api_exception.rb")
|
9
|
+
require_relative("./iam_token_manager.rb")
|
10
|
+
require_relative("./version.rb")
|
11
|
+
# require("httplog")
|
12
|
+
# HttpLog.configure do |config|
|
13
|
+
# config.log_connect = true
|
14
|
+
# config.log_request = true
|
15
|
+
# config.log_headers = true
|
16
|
+
# config.log_data = true
|
17
|
+
# config.log_status = true
|
18
|
+
# config.log_response = true
|
19
|
+
# end
|
20
|
+
|
21
|
+
# Class for interacting with the Watson API
|
22
|
+
class WatsonService
|
23
|
+
attr_accessor :password, :url, :username
|
24
|
+
attr_reader :conn
|
25
|
+
def initialize(vars)
|
26
|
+
defaults = {
|
27
|
+
vcap_services_name: nil,
|
28
|
+
username: nil,
|
29
|
+
password: nil,
|
30
|
+
use_vcap_services: true,
|
31
|
+
api_key: nil,
|
32
|
+
x_watson_learning_opt_out: false,
|
33
|
+
iam_api_key: nil,
|
34
|
+
iam_access_token: nil,
|
35
|
+
iam_url: nil
|
36
|
+
}
|
37
|
+
vars = defaults.merge(vars)
|
38
|
+
@url = vars[:url]
|
39
|
+
@username = nil
|
40
|
+
@password = nil
|
41
|
+
@token_manager = nil
|
42
|
+
@temp_headers = nil
|
43
|
+
|
44
|
+
user_agent_string = "watson-apis-ruby-sdk-" + IBMWatson::VERSION
|
45
|
+
user_agent_string += " #{RbConfig::CONFIG["host"]}"
|
46
|
+
user_agent_string += " #{RbConfig::CONFIG["RUBY_BASE_NAME"]}-#{RbConfig::CONFIG["RUBY_PROGRAM_VERSION"]}"
|
47
|
+
|
48
|
+
headers = {
|
49
|
+
"User-Agent" => user_agent_string
|
50
|
+
}
|
51
|
+
headers["x-watson-learning-opt-out"] = true if vars[:x_watson_learning_opt_out]
|
52
|
+
if vars[:use_vcap_services]
|
53
|
+
@vcap_service_credentials = load_from_vcap_services(service_name: vars[:vcap_services_name])
|
54
|
+
if !@vcap_service_credentials.nil? && @vcap_service_credentials.instance_of?(Hash)
|
55
|
+
@url = @vcap_service_credentials["url"]
|
56
|
+
@username = @vcap_service_credentials["username"] if @vcap_service_credentials.key?("username")
|
57
|
+
@password = @vcap_service_credentials["password"] if @vcap_service_credentials.key?("password")
|
58
|
+
@iam_api_key = @vcap_service_credentials["iam_api_key"] if @vcap_service_credentials.key?("iam_api_key")
|
59
|
+
@iam_access_token = @vcap_service_credentials["iam_access_token"] if @vcap_service_credentials.key?("iam_access_token")
|
60
|
+
@iam_url = @vcap_service_credentials["iam_url"] if @vcap_service_credentials.key?("iam_url")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
if !vars[:iam_access_token].nil? || !vars[:iam_api_key].nil?
|
65
|
+
_token_manager(iam_api_key: vars[:iam_api_key], iam_access_token: vars[:iam_access_token], iam_url: vars[:iam_url])
|
66
|
+
elsif !vars[:username].nil? && !vars[:password].nil?
|
67
|
+
if vars[:username] == "apikey"
|
68
|
+
_iam_api_key(iam_api_key: vars[:password])
|
69
|
+
else
|
70
|
+
@username = vars[:username]
|
71
|
+
@password = vars[:password]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
@conn = HTTP::Client.new(
|
76
|
+
headers: headers
|
77
|
+
).timeout(
|
78
|
+
:per_operation,
|
79
|
+
read: 60,
|
80
|
+
write: 60,
|
81
|
+
connect: 60
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
def load_from_vcap_services(service_name:)
|
86
|
+
vcap_services = ENV["VCAP_SERVICES"]
|
87
|
+
unless vcap_services.nil?
|
88
|
+
services = JSON.parse(vcap_services)
|
89
|
+
return services[service_name][0]["credentials"] if services.key?(service_name)
|
90
|
+
end
|
91
|
+
nil
|
92
|
+
end
|
93
|
+
|
94
|
+
def add_default_headers(headers: {})
|
95
|
+
raise TypeError unless headers.instance_of?(Hash)
|
96
|
+
headers.each_pair { |k, v| @conn.default_options.headers.add(k, v) }
|
97
|
+
end
|
98
|
+
|
99
|
+
def _token_manager(iam_api_key: nil, iam_access_token: nil, iam_url: nil)
|
100
|
+
@iam_api_key = iam_api_key
|
101
|
+
@iam_access_token = iam_access_token
|
102
|
+
@iam_url = iam_url
|
103
|
+
@token_manager = IAMTokenManager.new(iam_api_key: iam_api_key, iam_access_token: iam_access_token, iam_url: iam_url)
|
104
|
+
end
|
105
|
+
|
106
|
+
def _iam_access_token(iam_access_token:)
|
107
|
+
@token_manager._access_token(iam_access_token: iam_access_token) unless @token_manager.nil?
|
108
|
+
@token_manager = IAMTokenManager.new(iam_access_token: iam_access_token) if @token_manager.nil?
|
109
|
+
@iam_access_token = iam_access_token
|
110
|
+
end
|
111
|
+
|
112
|
+
def _iam_api_key(iam_api_key:)
|
113
|
+
@token_manager._iam_api_key(iam_api_key: iam_api_key) unless @token_manager.nil?
|
114
|
+
@token_manager = IAMTokenManager.new(iam_api_key: iam_api_key) if @token_manager.nil?
|
115
|
+
@iam_api_key = iam_api_key
|
116
|
+
end
|
117
|
+
|
118
|
+
# @return [DetailedResponse]
|
119
|
+
def request(args)
|
120
|
+
defaults = { method: nil, url: nil, accept_json: false, headers: nil, params: nil, json: {}, data: nil }
|
121
|
+
args = defaults.merge(args)
|
122
|
+
args[:data].delete_if { |_k, v| v.nil? } if args[:data].instance_of?(Hash)
|
123
|
+
args[:json] = args[:data].merge(args[:json]) if args[:data].respond_to?(:merge)
|
124
|
+
args[:json] = args[:data] if args[:json].empty? || (args[:data].instance_of?(String) && !args[:data].empty?)
|
125
|
+
args[:json].delete_if { |_k, v| v.nil? } if args[:json].instance_of?(Hash)
|
126
|
+
args[:headers]["Accept"] = "application/json" if args[:accept_json]
|
127
|
+
args[:headers]["Content-Type"] = "application/json" unless args[:headers].key?("Content-Type")
|
128
|
+
args[:json] = args[:json].to_json if args[:json].instance_of?(Hash)
|
129
|
+
args[:headers].delete_if { |_k, v| v.nil? } if args[:headers].instance_of?(Hash)
|
130
|
+
args[:params].delete_if { |_k, v| v.nil? } if args[:params].instance_of?(Hash)
|
131
|
+
args[:form].delete_if { |_k, v| v.nil? } if args.key?(:form)
|
132
|
+
args.delete_if { |_, v| v.nil? }
|
133
|
+
args[:headers].delete("Content-Type") if args.key?(:form) || args[:json].nil?
|
134
|
+
|
135
|
+
if @username == "apikey"
|
136
|
+
_iam_api_key(iam_api_key: @password)
|
137
|
+
@username = nil
|
138
|
+
end
|
139
|
+
|
140
|
+
conn = @conn
|
141
|
+
if !@token_manager.nil?
|
142
|
+
access_token = @token_manager._token
|
143
|
+
args[:headers]["Authorization"] = "Bearer #{access_token}"
|
144
|
+
elsif !@username.nil? && !@password.nil?
|
145
|
+
conn = @conn.basic_auth(user: @username, pass: @password)
|
146
|
+
end
|
147
|
+
|
148
|
+
args[:headers] = args[:headers].merge(@temp_headers) unless @temp_headers.nil?
|
149
|
+
@temp_headers = nil unless @temp_headers.nil?
|
150
|
+
|
151
|
+
if args.key?(:form)
|
152
|
+
response = conn.follow.request(
|
153
|
+
args[:method],
|
154
|
+
HTTP::URI.parse(@url + args[:url]),
|
155
|
+
headers: conn.default_options.headers.merge(HTTP::Headers.coerce(args[:headers])),
|
156
|
+
params: args[:params],
|
157
|
+
form: args[:form]
|
158
|
+
)
|
159
|
+
else
|
160
|
+
response = conn.follow.request(
|
161
|
+
args[:method],
|
162
|
+
HTTP::URI.parse(@url + args[:url]),
|
163
|
+
headers: conn.default_options.headers.merge(HTTP::Headers.coerce(args[:headers])),
|
164
|
+
body: args[:json],
|
165
|
+
params: args[:params]
|
166
|
+
)
|
167
|
+
end
|
168
|
+
return DetailedResponse.new(response: response) if (200..299).cover?(response.code)
|
169
|
+
raise WatsonApiException.new(response: response)
|
170
|
+
end
|
171
|
+
|
172
|
+
# @note Chainable
|
173
|
+
# @param headers [Hash] Custom headers to be sent with the request
|
174
|
+
# @return [self]
|
175
|
+
def headers(headers)
|
176
|
+
raise TypeError("Expected Hash type, received #{headers.class}") unless headers.instance_of?(Hash)
|
177
|
+
@temp_headers = headers
|
178
|
+
self
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IBMWatson
|
4
|
+
# Abstract class for Recognize Callbacks
|
5
|
+
class RecognizeCallback
|
6
|
+
def initialize(*); end
|
7
|
+
|
8
|
+
# Called when an interim result is received
|
9
|
+
def on_transcription(transcript:); end
|
10
|
+
|
11
|
+
# Called when a WebSocket connection is made
|
12
|
+
def on_connected; end
|
13
|
+
|
14
|
+
# Called when there is an error in the WebSocket connection
|
15
|
+
def on_error(error:); end
|
16
|
+
|
17
|
+
# Called when there is an inactivity timeout
|
18
|
+
def on_inactivity_timeout(error:); end
|
19
|
+
|
20
|
+
# Called when the service is listening for audio
|
21
|
+
def on_listening; end
|
22
|
+
|
23
|
+
# Called after the service returns the final result for the transcription
|
24
|
+
def on_transcription_complete; end
|
25
|
+
|
26
|
+
# Called when the service returns the final hypothesis
|
27
|
+
def on_hypothesis(hypothesis:); end
|
28
|
+
|
29
|
+
# Called when the service returns results. The data is returned unparsed
|
30
|
+
def on_data(data:); end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require("eventmachine")
|
4
|
+
require("faye/websocket")
|
5
|
+
require("json")
|
6
|
+
|
7
|
+
ONE_KB = 1024
|
8
|
+
TIMEOUT_PREFIX = "No speech detected for".freeze
|
9
|
+
CLOSE_SIGNAL = 1000
|
10
|
+
TEN_MILLISECONDS = 0.01
|
11
|
+
|
12
|
+
# Class for interacting with the WebSocket API
|
13
|
+
class WebSocketClient
|
14
|
+
def initialize(audio: nil, chunk_data:, options:, recognize_callback:, url:, headers:)
|
15
|
+
@audio = audio
|
16
|
+
@options = options
|
17
|
+
@callback = recognize_callback
|
18
|
+
@bytes_sent = 0
|
19
|
+
@headers = headers
|
20
|
+
@is_listening = false
|
21
|
+
@url = url
|
22
|
+
@timer = nil
|
23
|
+
@chunk_data = chunk_data
|
24
|
+
@mic_running = false
|
25
|
+
@data_size = audio.nil? ? 0 : @audio.size
|
26
|
+
@queue = Queue.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def start
|
30
|
+
on_open = lambda do |event|
|
31
|
+
on_connect(event)
|
32
|
+
@client.send(build_start_message(options: @options))
|
33
|
+
@mic_running = true if @chunk_data
|
34
|
+
send_audio(data: @audio)
|
35
|
+
end
|
36
|
+
|
37
|
+
on_message = lambda do |event|
|
38
|
+
json_object = JSON.parse(event.data)
|
39
|
+
if json_object.key?("error")
|
40
|
+
error = json_object["error"]
|
41
|
+
if error.start_with?(TIMEOUT_PREFIX)
|
42
|
+
@callback.on_inactivity_timeout(error: error)
|
43
|
+
else
|
44
|
+
@callback.on_error(error: error)
|
45
|
+
end
|
46
|
+
elsif json_object.key?("state")
|
47
|
+
if !@is_listening
|
48
|
+
@is_listening = true
|
49
|
+
else
|
50
|
+
@client.send(build_close_message)
|
51
|
+
@callback.on_transcription_complete
|
52
|
+
@client.close(CLOSE_SIGNAL)
|
53
|
+
end
|
54
|
+
elsif json_object.key?("results") || json_object.key?("speaker_labels")
|
55
|
+
hypothesis = ""
|
56
|
+
unless json_object["results"].nil?
|
57
|
+
hypothesis = json_object.dig("results", 0, "alternatives", 0, "transcript")
|
58
|
+
b_final = json_object.dig("results", 0, "final")
|
59
|
+
transcripts = extract_transcripts(alternatives: json_object.dig("results", 0, "alternatives"))
|
60
|
+
|
61
|
+
@callback.on_hypothesis(hypothesis: hypothesis) if b_final
|
62
|
+
|
63
|
+
@callback.on_transcription(transcript: transcripts)
|
64
|
+
@callback.on_data(data: json_object)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
on_close = lambda do |_event|
|
70
|
+
@client = nil
|
71
|
+
EM.stop_event_loop
|
72
|
+
end
|
73
|
+
|
74
|
+
on_error = lambda do |event|
|
75
|
+
p event.message
|
76
|
+
end
|
77
|
+
|
78
|
+
EM.reactor_thread.join unless EM.reactor_thread.nil?
|
79
|
+
EM.run do
|
80
|
+
@client = Faye::WebSocket::Client.new(@url, nil, headers: @headers)
|
81
|
+
@client.onclose = on_close
|
82
|
+
@client.onerror = on_error
|
83
|
+
@client.onmessage = on_message
|
84
|
+
@client.onopen = on_open
|
85
|
+
@client.add_listener(Faye::WebSocket::API::Event.create("open"))
|
86
|
+
@client.add_listener(Faye::WebSocket::API::Event.create("message"))
|
87
|
+
@client.add_listener(Faye::WebSocket::API::Event.create("close"))
|
88
|
+
@client.add_listener(Faye::WebSocket::API::Event.create("error"))
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def add_audio_chunk(chunk:)
|
93
|
+
@data_size += chunk.size
|
94
|
+
@queue << chunk
|
95
|
+
end
|
96
|
+
|
97
|
+
def stop_audio
|
98
|
+
@mic_running = false
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def on_connect(_response)
|
104
|
+
@callback.on_connected
|
105
|
+
end
|
106
|
+
|
107
|
+
def build_start_message(options:)
|
108
|
+
options["action"] = "start"
|
109
|
+
options.to_json
|
110
|
+
end
|
111
|
+
|
112
|
+
def build_close_message
|
113
|
+
{ "action" => "close" }.to_json
|
114
|
+
end
|
115
|
+
|
116
|
+
def send_audio(data:)
|
117
|
+
if @chunk_data
|
118
|
+
if @mic_running
|
119
|
+
@queue.empty? ? send_chunk(chunk: nil, final: false) : send_chunk(chunk: @queue.pop(true), final: false)
|
120
|
+
elsif @queue.length == 1
|
121
|
+
send_chunk(chunk: @queue.pop(true), final: true)
|
122
|
+
@queue.close
|
123
|
+
@timer.cancel if @timer.respond_to?(:cancel)
|
124
|
+
return
|
125
|
+
else
|
126
|
+
send_chunk(chunk: @queue.pop(true), final: false) unless @queue.empty?
|
127
|
+
end
|
128
|
+
else
|
129
|
+
if @bytes_sent + ONE_KB >= @data_size
|
130
|
+
if @data_size > @bytes_sent
|
131
|
+
send_chunk(chunk: data.read(ONE_KB), final: true)
|
132
|
+
@timer.cancel if @timer.respond_to?(:cancel)
|
133
|
+
return
|
134
|
+
end
|
135
|
+
@timer.cancel if @timer.respond_to?(:cancel)
|
136
|
+
end
|
137
|
+
send_chunk(chunk: data.read(ONE_KB), final: false)
|
138
|
+
end
|
139
|
+
@timer = EventMachine::Timer.new(TEN_MILLISECONDS) { send_audio(data: data) }
|
140
|
+
end
|
141
|
+
|
142
|
+
def extract_transcripts(alternatives:)
|
143
|
+
transcripts = []
|
144
|
+
unless alternatives.nil?
|
145
|
+
alternatives.each do |alternative|
|
146
|
+
transcript = {}
|
147
|
+
transcript["confidence"] = alternative["confidence"] if alternative.key?("confidence")
|
148
|
+
transcript["transcript"] = alternative["transcript"]
|
149
|
+
transcripts << transcript
|
150
|
+
end
|
151
|
+
end
|
152
|
+
transcripts
|
153
|
+
end
|
154
|
+
|
155
|
+
def send_chunk(chunk:, final: false)
|
156
|
+
return if chunk.nil?
|
157
|
+
@bytes_sent += chunk.size
|
158
|
+
@client.send(chunk.bytes)
|
159
|
+
@client.send({ "action" => "stop" }.to_json) if final
|
160
|
+
@timer.cancel if @timer.respond_to?(:cancel) && final
|
161
|
+
end
|
162
|
+
end
|
data/rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dotenv/tasks"
|
4
|
+
require "rake/testtask"
|
5
|
+
require "rubocop/rake_task"
|
6
|
+
|
7
|
+
task default: %w[def]
|
8
|
+
|
9
|
+
RuboCop::RakeTask.new
|
10
|
+
|
11
|
+
namespace :test do
|
12
|
+
Rake::TestTask.new do |t|
|
13
|
+
t.name = "unit"
|
14
|
+
t.description = "Run unit tests"
|
15
|
+
t.libs << "test"
|
16
|
+
t.test_files = FileList["test/unit/*.rb"]
|
17
|
+
t.verbose = true
|
18
|
+
t.warning = true
|
19
|
+
end
|
20
|
+
|
21
|
+
Rake::TestTask.new do |t|
|
22
|
+
t.name = "integration"
|
23
|
+
t.description = "Run integration tests (put credentials in a .env file)"
|
24
|
+
t.libs << "test"
|
25
|
+
t.test_files = FileList["test/integration/*.rb"]
|
26
|
+
t.verbose = true
|
27
|
+
t.warning = true
|
28
|
+
t.deps = [:dotenv]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "Run unit & integration tests"
|
33
|
+
task :test do
|
34
|
+
Rake::Task["test:unit"].invoke
|
35
|
+
Rake::Task["test:integration"].invoke
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "Run tests and generate a code coverage report"
|
39
|
+
task :coverage do
|
40
|
+
ENV["COVERAGE"] = "true"
|
41
|
+
Rake::Task["test"].execute
|
42
|
+
end
|
43
|
+
|
44
|
+
task def: %i[rubocop coverage] do
|
45
|
+
end
|