ibm_watson 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 +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
|