web_translate_it 3.2.1 → 3.2.3

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/bin/wti +8 -10
  3. data/history.md +35 -0
  4. data/lib/web_translate_it/api_resource.rb +137 -0
  5. data/lib/web_translate_it/auto_fetch.rb +1 -1
  6. data/lib/web_translate_it/commands/add.rb +58 -0
  7. data/lib/web_translate_it/commands/addlocale.rb +39 -0
  8. data/lib/web_translate_it/commands/base.rb +58 -0
  9. data/lib/web_translate_it/commands/diff.rb +71 -0
  10. data/lib/web_translate_it/commands/init.rb +112 -0
  11. data/lib/web_translate_it/commands/match.rb +30 -0
  12. data/lib/web_translate_it/commands/mv.rb +67 -0
  13. data/lib/web_translate_it/commands/pull.rb +62 -0
  14. data/lib/web_translate_it/commands/push.rb +50 -0
  15. data/lib/web_translate_it/commands/rm.rb +67 -0
  16. data/lib/web_translate_it/commands/rmlocale.rb +43 -0
  17. data/lib/web_translate_it/commands/status.rb +52 -0
  18. data/lib/web_translate_it/configuration.rb +31 -21
  19. data/lib/web_translate_it/connection.rb +30 -3
  20. data/lib/web_translate_it/project.rb +13 -72
  21. data/lib/web_translate_it/runner.rb +75 -0
  22. data/lib/web_translate_it/string.rb +26 -265
  23. data/lib/web_translate_it/term.rb +15 -255
  24. data/lib/web_translate_it/term_translation.rb +16 -69
  25. data/lib/web_translate_it/translation.rb +12 -50
  26. data/lib/web_translate_it/translation_base.rb +38 -0
  27. data/lib/web_translate_it/translation_file.rb +58 -109
  28. data/lib/web_translate_it/util/concurrency.rb +46 -0
  29. data/lib/web_translate_it/util/hash_util.rb +0 -2
  30. data/lib/web_translate_it/util/http_response.rb +66 -0
  31. data/lib/web_translate_it/util/prompt.rb +49 -0
  32. data/lib/web_translate_it/util/spinner.rb +51 -0
  33. data/lib/web_translate_it/util/string_util.rb +4 -10
  34. data/lib/web_translate_it/util.rb +0 -75
  35. data/lib/web_translate_it.rb +21 -3
  36. metadata +21 -4
  37. data/lib/web_translate_it/command_line.rb +0 -521
  38. data/lib/web_translate_it/util/hash_extensions.rb +0 -13
@@ -2,39 +2,12 @@
2
2
 
3
3
  module WebTranslateIt
4
4
 
5
- class TermTranslation
5
+ class TermTranslation < TranslationBase
6
6
 
7
- attr_accessor :id, :locale, :text, :description, :status, :new_record, :term_id, :connection
7
+ attr_accessor :description, :new_record, :term_id
8
8
 
9
- # Initialize a new WebTranslateIt::TermTranslation
10
- #
11
- # Implementation Example:
12
- #
13
- # WebTranslateIt::TermTranslation.new({ :text => "Super!" })
14
- #
15
- # to instantiate a new TermTranslation.
16
- #
17
-
18
- def initialize(params = {})
19
- params.stringify_keys!
20
- self.id = params['id'] || nil
21
- self.locale = params['locale'] || nil
22
- self.text = params['text'] || nil
23
- self.description = params['description'] || nil
24
- self.status = params['status'] || nil
25
- self.term_id = params['term_id'] || nil
26
- self.new_record = true
27
- end
28
-
29
- # Update or Create a WebTranslateIt::TermTranslation
30
- #
31
- # Implementation Example:
32
- #
33
- # translation = WebTranslateIt::TermTranslation.new({ :term_id => "1234", :text => "Super!" })
34
- # WebTranslateIt::Connection.new('secret_api_token') do
35
- # translation.save
36
- # end
37
- #
9
+ def self.parent_resource_path = 'terms'
10
+ def parent_id = term_id
38
11
 
39
12
  def save
40
13
  new_record ? create : update
@@ -50,54 +23,28 @@ module WebTranslateIt
50
23
  }
51
24
  end
52
25
 
53
- def to_json(*_args)
54
- MultiJson.dump(to_hash)
55
- end
56
-
57
26
  protected
58
27
 
59
- def create # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
60
- success = true
61
- tries ||= 3
62
- request = Net::HTTP::Post.new("/api/projects/#{connection.api_key}/terms/#{term_id}/locales/#{locale}/translations")
63
- WebTranslateIt::Util.add_fields(request)
64
- request.body = to_json
28
+ def assign_attributes(params)
29
+ self.description = params['description']
30
+ self.term_id = params['term_id']
31
+ self.new_record = true
32
+ end
65
33
 
66
- begin
67
- response = JSON.parse(Util.handle_response(connection.http_connection.request(request), true, true))
34
+ def create
35
+ Concurrency.with_retries do
36
+ raw = connection.post(translation_path, body: to_json)
37
+ response = JSON.parse(HttpResponse.handle_response(raw))
68
38
  self.id = response['id']
69
39
  self.new_record = false
70
40
  return true
71
- rescue Timeout::Error
72
- puts 'Request timeout. Will retry in 5 seconds.'
73
- if (tries -= 1).positive?
74
- sleep(5)
75
- retry
76
- else
77
- success = false
78
- end
79
41
  end
80
- success
81
42
  end
82
43
 
83
- def update # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
84
- success = true
85
- tries ||= 3
86
- request = Net::HTTP::Put.new("/api/projects/#{connection.api_key}/terms/#{id}/locales/#{locale}/translations/#{id}")
87
- WebTranslateIt::Util.add_fields(request)
88
- request.body = to_json
89
- begin
90
- Util.handle_response(connection.http_connection.request(request), true, true)
91
- rescue Timeout::Error
92
- puts 'Request timeout. Will retry in 5 seconds.'
93
- if (tries -= 1).positive?
94
- sleep(5)
95
- retry
96
- else
97
- success = false
98
- end
44
+ def update
45
+ Concurrency.with_retries do
46
+ HttpResponse.handle_response(connection.put("/api/projects/#{connection.api_key}/terms/#{id}/locales/#{locale}/translations/#{id}", body: to_json))
99
47
  end
100
- success
101
48
  end
102
49
 
103
50
  end
@@ -2,56 +2,12 @@
2
2
 
3
3
  module WebTranslateIt
4
4
 
5
- class Translation
5
+ class Translation < TranslationBase
6
6
 
7
- attr_accessor :id, :locale, :text, :status, :created_at, :updated_at, :version, :string_id, :connection
7
+ attr_accessor :created_at, :updated_at, :version, :string_id
8
8
 
9
- # Initialize a new WebTranslateIt::Translation
10
- #
11
- # Implementation Example:
12
- #
13
- # WebTranslateIt::Translation.new({ :string_id => "1234", :text => "Super!" })
14
- #
15
- # to instantiate a new Translation without any text.
16
- #
17
-
18
- def initialize(params = {}) # rubocop:todo Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
19
- params.stringify_keys!
20
- self.id = params['id'] || nil
21
- self.locale = params['locale'] || nil
22
- self.text = params['text'] || nil
23
- self.status = params['status'] || 'status_unproofread'
24
- self.created_at = params['created_at'] || nil
25
- self.updated_at = params['updated_at'] || nil
26
- self.version = params['version'] || nil
27
- self.string_id = (params['string']['id'] if params['string'])
28
- end
29
-
30
- # Save a WebTranslateIt::Translation
31
- #
32
- # Implementation Example:
33
- #
34
- # translation = WebTranslateIt::Translation.new({ :string_id => "1234", :text => "Super!" })
35
- # WebTranslateIt::Connection.new('secret_api_token') do
36
- # translation.save
37
- # end
38
- #
39
-
40
- def save # rubocop:todo Metrics/MethodLength
41
- tries ||= 3
42
- request = Net::HTTP::Post.new("/api/projects/#{connection.api_key}/strings/#{string_id}/locales/#{locale}/translations")
43
- WebTranslateIt::Util.add_fields(request)
44
- request.body = to_json
45
- begin
46
- Util.handle_response(connection.http_connection.request(request), true, true)
47
- rescue Timeout::Error
48
- puts 'Request timeout. Will retry in 5 seconds.'
49
- if (tries -= 1).positive?
50
- sleep(5)
51
- retry
52
- end
53
- end
54
- end
9
+ def self.parent_resource_path = 'strings'
10
+ def parent_id = string_id
55
11
 
56
12
  def to_hash
57
13
  {
@@ -61,8 +17,14 @@ module WebTranslateIt
61
17
  }
62
18
  end
63
19
 
64
- def to_json(*_args)
65
- MultiJson.dump(to_hash)
20
+ protected
21
+
22
+ def assign_attributes(params)
23
+ self.status ||= 'status_unproofread'
24
+ self.created_at = params['created_at']
25
+ self.updated_at = params['updated_at']
26
+ self.version = params['version']
27
+ self.string_id = params['string']['id'] if params['string']
66
28
  end
67
29
 
68
30
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WebTranslateIt
4
+
5
+ class TranslationBase
6
+
7
+ attr_accessor :id, :locale, :text, :status, :connection
8
+
9
+ def initialize(params = {})
10
+ params = params.transform_keys(&:to_s)
11
+ self.id = params['id']
12
+ self.locale = params['locale']
13
+ self.text = params['text']
14
+ self.status = params['status']
15
+ assign_attributes(params)
16
+ end
17
+
18
+ def save
19
+ Concurrency.with_retries do
20
+ HttpResponse.handle_response(connection.post(translation_path, body: to_json))
21
+ end
22
+ end
23
+
24
+ def to_json(*_args)
25
+ MultiJson.dump(to_hash)
26
+ end
27
+
28
+ protected
29
+
30
+ def assign_attributes(_params); end
31
+
32
+ def translation_path
33
+ "/api/projects/#{connection.api_key}/#{self.class.parent_resource_path}/#{parent_id}/locales/#{locale}/translations"
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -12,7 +12,22 @@ module WebTranslateIt
12
12
 
13
13
  attr_accessor :id, :file_path, :locale, :api_key, :updated_at, :remote_checksum, :master_id, :fresh
14
14
 
15
- def initialize(id, file_path, locale, api_key, updated_at = nil, remote_checksum = '', master_id = nil, fresh = nil) # rubocop:todo Metrics/ParameterLists
15
+ Result = Struct.new(:success, :output)
16
+
17
+ def self.from_api(project_file, api_key)
18
+ new(
19
+ project_file['id'],
20
+ project_file['name'],
21
+ project_file['locale_code'],
22
+ api_key,
23
+ updated_at: project_file['updated_at'],
24
+ remote_checksum: project_file['hash_file'],
25
+ master_id: project_file['master_project_file_id'],
26
+ fresh: project_file['fresh']
27
+ )
28
+ end
29
+
30
+ def initialize(id, file_path, locale, api_key, updated_at: nil, remote_checksum: '', master_id: nil, fresh: nil)
16
31
  self.id = id
17
32
  self.file_path = file_path
18
33
  self.locale = locale
@@ -35,9 +50,7 @@ module WebTranslateIt
35
50
  # file.fetch # returns nothing, with a status 304 Not Modified
36
51
  # file.fetch(true) # force to re-download the file, will return the content of the file with a 200 OK
37
52
  #
38
- def fetch(http_connection, force = false) # rubocop:todo Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
39
- success = true
40
- tries ||= 3
53
+ def fetch(connection, force = false) # rubocop:todo Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
41
54
  display = []
42
55
  if fresh
43
56
  display.push(file_path)
@@ -47,37 +60,22 @@ module WebTranslateIt
47
60
  display.push "#{StringUtil.checksumify(local_checksum.to_s)}..#{StringUtil.checksumify(remote_checksum.to_s)}"
48
61
  if !File.exist?(file_path) || force || (remote_checksum != local_checksum)
49
62
 
50
- request = Net::HTTP::Get.new(api_url)
51
- WebTranslateIt::Util.add_fields(request)
52
- FileUtils.mkpath(file_path.split('/')[0..-2].join('/')) unless File.exist?(file_path) || (file_path.split('/')[0..-2].join('/') == '')
53
- begin
54
- response = http_connection.request(request)
63
+ dir = File.dirname(file_path)
64
+ FileUtils.mkpath(dir) unless File.exist?(file_path) || dir == '.'
65
+ with_display(display) do
66
+ response = connection.get(api_url)
55
67
  File.open(file_path, 'wb') { |file| file << response.body } if response.code.to_i == 200
56
- display.push Util.handle_response(response)
57
- rescue Timeout::Error
58
- puts StringUtil.failure('Request timeout. Will retry in 5 seconds.')
59
- if (tries -= 1).positive?
60
- sleep(5)
61
- retry
62
- else
63
- success = false
64
- end
65
- rescue StandardError
66
- display.push StringUtil.failure("An error occured: #{$ERROR_INFO}")
67
- success = false
68
+ response
68
69
  end
69
70
 
70
71
  else
71
72
  display.push StringUtil.success('Skipped')
73
+ Result.new(true, display)
72
74
  end
73
- print StringUtil.array_to_columns(display)
74
- success
75
75
  end
76
76
 
77
- def fetch_remote_content(http_connection)
78
- request = Net::HTTP::Get.new(api_url)
79
- WebTranslateIt::Util.add_fields(request)
80
- response = http_connection.request(request)
77
+ def fetch_remote_content(connection)
78
+ response = connection.get(api_url)
81
79
  response.body if response.code.to_i == 200
82
80
  end
83
81
 
@@ -92,13 +90,9 @@ module WebTranslateIt
92
90
  #
93
91
  # Note that the request might or might not eventually be acted upon, as it might be disallowed when processing
94
92
  # actually takes place. This is due to the fact that language file imports are handled by background processing.
95
- # rubocop:todo Metrics/PerceivedComplexity
96
- # rubocop:todo Metrics/ParameterLists
97
- # rubocop:todo Metrics/MethodLength
98
93
  # rubocop:todo Metrics/AbcSize
99
- def upload(http_connection, merge = false, ignore_missing = false, label = nil, minor_changes = false, force = false, rename_others = false, destination_path = nil) # rubocop:todo Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/MethodLength, Metrics/ParameterLists, Metrics/PerceivedComplexity
100
- success = true
101
- tries ||= 3
94
+ # rubocop:todo Metrics/MethodLength
95
+ def upload(connection, merge: false, ignore_missing: false, label: nil, minor_changes: false, force: false, rename_others: false, destination_path: nil) # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
102
96
  display = []
103
97
  display.push(file_path)
104
98
  display.push "#{StringUtil.checksumify(local_checksum.to_s)}..#{StringUtil.checksumify(remote_checksum.to_s)}"
@@ -114,126 +108,68 @@ module WebTranslateIt
114
108
  ['file', file]
115
109
  ]
116
110
  params += [['name', destination_path]] unless destination_path.nil?
117
- request = Net::HTTP::Put.new(api_url)
118
- WebTranslateIt::Util.add_fields(request)
119
- request.set_form params, 'multipart/form-data'
120
- display.push Util.handle_response(http_connection.request(request))
121
- rescue Timeout::Error
122
- puts StringUtil.failure('Request timeout. Will retry in 5 seconds.')
123
- if (tries -= 1).positive? # rubocop:todo Metrics/BlockNesting
124
- sleep(5)
125
- retry
126
- else
127
- success = false
111
+ return with_display(display) do
112
+ connection.put(api_url) { |req| req.set_form params, 'multipart/form-data' }
128
113
  end
129
- rescue StandardError
130
- display.push StringUtil.failure("An error occured: #{$ERROR_INFO}")
131
- success = false
132
114
  end
133
115
  else
134
116
  display.push StringUtil.success('Skipped')
135
117
  end
136
- puts StringUtil.array_to_columns(display)
137
118
  else
138
- puts StringUtil.failure("Can't push #{file_path}. File doesn't exist locally.")
119
+ display.push StringUtil.failure("Can't push #{file_path}. File doesn't exist locally.")
139
120
  end
140
- success
121
+ Result.new(true, display)
141
122
  end
142
- # rubocop:enable Metrics/AbcSize
143
- # rubocop:enable Metrics/MethodLength
144
- # rubocop:enable Metrics/ParameterLists
145
- # rubocop:enable Metrics/PerceivedComplexity
146
123
 
124
+ # rubocop:enable Metrics/MethodLength
125
+ # rubocop:enable Metrics/AbcSize
147
126
  # Create a master language file to Web Translate It by performing a POST Request.
148
127
  #
149
128
  # Example of implementation:
150
129
  #
151
130
  # configuration = WebTranslateIt::Configuration.new
152
131
  # file = TranslationFile.new(nil, file_path, nil, configuration.api_key)
153
- # file.create # should respond the HTTP code 201 Created
132
+ # file.create(http_connection) # should respond the HTTP code 201 Created
154
133
  #
155
134
  # Note that the request might or might not eventually be acted upon, as it might be disallowed when processing
156
135
  # actually takes place. This is due to the fact that language file imports are handled by background processing.
157
136
  #
158
- def create(http_connection) # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
159
- success = true
160
- tries ||= 3
137
+ def create(connection) # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
161
138
  display = []
162
139
  display.push file_path
163
140
  display.push "#{StringUtil.checksumify(local_checksum.to_s)}..[ ]"
164
141
  if File.exist?(file_path)
165
142
  File.open(file_path) do |file|
166
- params = [['name', file_path]]
167
- params += [['file', file]]
168
- request = Net::HTTP::Post.new(api_url_for_create)
169
- WebTranslateIt::Util.add_fields(request)
170
- request.set_form params, 'multipart/form-data'
171
- display.push Util.handle_response(http_connection.request(request))
172
- puts StringUtil.array_to_columns(display)
173
- rescue Timeout::Error
174
- puts StringUtil.failure('Request timeout. Will retry in 5 seconds.')
175
- if (tries -= 1).positive?
176
- sleep(5)
177
- retry
178
- else
179
- success = false
143
+ params = [['name', file_path], ['file', file]]
144
+ return with_display(display) do
145
+ connection.post(api_url_for_create) { |req| req.set_form params, 'multipart/form-data' }
180
146
  end
181
- rescue StandardError
182
- display.push StringUtil.failure("An error occured: #{$ERROR_INFO}")
183
- success = false
184
147
  end
185
148
  else
186
- puts StringUtil.failure("\nFile #{file_path} doesn't exist locally!")
149
+ display.push StringUtil.failure("File #{file_path} doesn't exist locally!")
187
150
  end
188
- success
151
+ Result.new(true, display)
189
152
  end
190
153
 
191
154
  # Delete a master language file from Web Translate It by performing a DELETE Request.
192
155
  #
193
- def delete(http_connection) # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
194
- success = true
195
- tries ||= 3
156
+ def delete(connection)
196
157
  display = []
197
158
  display.push file_path
198
159
  if File.exist?(file_path)
199
- begin
200
- request = Net::HTTP::Delete.new(api_url_for_delete)
201
- WebTranslateIt::Util.add_fields(request)
202
- display.push Util.handle_response(http_connection.request(request))
203
- puts StringUtil.array_to_columns(display)
204
- rescue Timeout::Error
205
- puts StringUtil.failure('Request timeout. Will retry in 5 seconds.')
206
- if (tries -= 1).positive?
207
- sleep(5)
208
- retry
209
- else
210
- success = false
211
- end
212
- rescue StandardError
213
- display.push StringUtil.failure("An error occured: #{$ERROR_INFO}")
214
- success = false
215
- end
160
+ with_display(display) { connection.delete(api_url_for_delete) }
216
161
  else
217
- puts StringUtil.failure("\nMaster file #{file_path} doesn't exist locally!")
162
+ display.push StringUtil.failure("Master file #{file_path} doesn't exist locally!")
163
+ Result.new(true, display)
218
164
  end
219
- success
220
165
  end
221
166
 
222
167
  def exists?
223
168
  File.exist?(file_path)
224
169
  end
225
170
 
226
- def modified_remotely?
227
- fetch == '200 OK'
228
- end
229
-
230
171
  protected
231
172
 
232
- # Convenience method which returns the date of last modification of a language file.
233
- def last_modification
234
- File.mtime(File.new(file_path, 'r'))
235
- end
236
-
237
173
  # Convenience method which returns the URL of the API endpoint for a locale.
238
174
  def api_url
239
175
  "/api/projects/#{api_key}/files/#{id}/locales/#{locale}"
@@ -249,10 +185,23 @@ module WebTranslateIt
249
185
 
250
186
  def local_checksum
251
187
  Digest::SHA1.hexdigest(File.read(file_path))
252
- rescue StandardError
188
+ rescue StandardError => _e
253
189
  ''
254
190
  end
255
191
 
192
+ private
193
+
194
+ def with_display(display)
195
+ Concurrency.with_retries do
196
+ response = yield
197
+ display.push HttpResponse.status_label(response)
198
+ end
199
+ Result.new(true, display)
200
+ rescue StandardError => e
201
+ display.push StringUtil.failure("An error occured: #{e.message}")
202
+ Result.new(false, display)
203
+ end
204
+
256
205
  end
257
206
 
258
207
  end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WebTranslateIt
4
+
5
+ module Concurrency
6
+
7
+ # Execute a block with automatic retry on Timeout::Error and RateLimitError.
8
+ # Returns the block's return value on success, or re-raises after retries are exhausted.
9
+ def self.with_retries(retries: 3, delay: 5)
10
+ yield
11
+ rescue Timeout::Error
12
+ raise unless (retries -= 1).positive?
13
+
14
+ log_retry('Request timeout', delay)
15
+ retry
16
+ rescue RateLimitError => e
17
+ raise unless (retries -= 1).positive?
18
+
19
+ log_retry('Rate limited', e.retry_after || delay)
20
+ retry
21
+ end
22
+
23
+ def self.log_retry(message, wait)
24
+ puts "#{message}. Will retry in #{wait} seconds."
25
+ sleep(wait)
26
+ end
27
+ private_class_method :log_retry
28
+
29
+ # Process items in parallel using a thread pool.
30
+ # Yields each batch (array of items) to the block; collects return values.
31
+ # Returns [results, n_threads] where results is a flat array of block return values.
32
+ def self.concurrent_batch(items, batch_size: 3, max_threads: 10, &block)
33
+ n_threads = [(items.size.to_f / batch_size).ceil, max_threads].min
34
+ n_threads = 1 if n_threads < 1
35
+ threads = items.each_slice((items.size.to_f / n_threads).ceil).filter_map do |slice|
36
+ next if slice.empty?
37
+
38
+ Thread.new(slice, &block)
39
+ end
40
+ results = threads.flat_map(&:value)
41
+ [results, n_threads]
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -29,5 +29,3 @@ class HashUtil
29
29
  end
30
30
 
31
31
  end
32
-
33
- require_relative 'hash_extensions'
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WebTranslateIt
4
+
5
+ class RateLimitError < StandardError
6
+
7
+ attr_reader :retry_after
8
+
9
+ def initialize(retry_after: nil)
10
+ @retry_after = retry_after
11
+ super("Rate limited#{", retry after #{retry_after}s" if retry_after}")
12
+ end
13
+
14
+ end
15
+
16
+ module HttpResponse
17
+
18
+ STATUS_LABELS = {
19
+ 200 => 'OK',
20
+ 201 => 'Created',
21
+ 202 => 'Accepted',
22
+ 304 => 'Not Modified'
23
+ }.freeze
24
+
25
+ def self.handle_response(response)
26
+ raise_on_error!(response)
27
+ response.body
28
+ end
29
+
30
+ def self.status_label(response)
31
+ raise_on_error!(response)
32
+ label = STATUS_LABELS[response.code.to_i]
33
+ StringUtil.success(label || 'OK')
34
+ rescue RuntimeError => e
35
+ StringUtil.failure(e.message)
36
+ end
37
+
38
+ def self.add_fields(request)
39
+ request.add_field('User-Agent', "wti v#{Util.version}")
40
+ request.add_field('Content-Type', 'application/json')
41
+ end
42
+
43
+ def self.raise_on_error!(response)
44
+ code = response.code.to_i
45
+ raise_on_rate_limit!(response) if code == 429
46
+ raise "Error: #{error_message(response)}" if code >= 400 && code < 500
47
+ raise 'Error: Server temporarily unavailable (Error 500).' if code == 500
48
+ raise 'Error: Locked (another import in progress)' if code == 503
49
+ end
50
+
51
+ def self.raise_on_rate_limit!(response)
52
+ retry_after = response['Retry-After']&.to_i
53
+ raise RateLimitError.new(retry_after: retry_after)
54
+ end
55
+
56
+ def self.error_message(response)
57
+ MultiJson.load(response.body)['error']
58
+ rescue StandardError
59
+ response.body.to_s
60
+ end
61
+
62
+ private_class_method :raise_on_error!, :raise_on_rate_limit!, :error_message
63
+
64
+ end
65
+
66
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WebTranslateIt
4
+
5
+ module Prompt
6
+
7
+ # Ask a question. Returns a true for yes, false for no, default for nil.
8
+ def self.ask_yes_no(question, default = nil) # rubocop:todo Metrics/MethodLength
9
+ qstr = case default
10
+ when nil
11
+ 'yn'
12
+ when true
13
+ 'Yn'
14
+ else
15
+ 'yN'
16
+ end
17
+
18
+ result = nil
19
+
20
+ while result.nil?
21
+ result = ask("#{question} [#{qstr}]")
22
+ result = case result
23
+ when /^[Yy].*/
24
+ true
25
+ when /^[Nn].*/
26
+ false
27
+ when '', nil
28
+ default
29
+ end
30
+ end
31
+
32
+ result
33
+ end
34
+
35
+ # Ask a question. Returns an answer.
36
+ def self.ask(question, default = nil)
37
+ question += " (Default: #{default})" unless default.nil?
38
+ print("#{question} ")
39
+ $stdout.flush
40
+
41
+ result = $stdin.gets
42
+ result&.chomp!
43
+ result = default if result.nil? || (result == '')
44
+ result
45
+ end
46
+
47
+ end
48
+
49
+ end