deepl-rb 2.5.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/add_issues_to_kanban.yml +16 -0
  3. data/.gitlab-ci.yml +135 -0
  4. data/.rubocop.yml +27 -0
  5. data/CHANGELOG.md +34 -0
  6. data/CODE_OF_CONDUCT.md +132 -0
  7. data/CONTRIBUTING.md +37 -0
  8. data/Gemfile +3 -1
  9. data/LICENSE.md +1 -0
  10. data/README.md +115 -5
  11. data/Rakefile +7 -5
  12. data/SECURITY.md +58 -0
  13. data/VERSION +1 -1
  14. data/deepl-rb.gemspec +36 -20
  15. data/lib/deepl/api.rb +11 -1
  16. data/lib/deepl/configuration.rb +34 -3
  17. data/lib/deepl/document_api.rb +120 -0
  18. data/lib/deepl/exceptions/authorization_failed.rb +3 -0
  19. data/lib/deepl/exceptions/bad_request.rb +3 -0
  20. data/lib/deepl/exceptions/document_translation_error.rb +15 -0
  21. data/lib/deepl/exceptions/error.rb +6 -0
  22. data/lib/deepl/exceptions/limit_exceeded.rb +7 -0
  23. data/lib/deepl/exceptions/not_found.rb +3 -0
  24. data/lib/deepl/exceptions/not_supported.rb +3 -0
  25. data/lib/deepl/exceptions/quota_exceeded.rb +3 -0
  26. data/lib/deepl/exceptions/request_entity_too_large.rb +4 -1
  27. data/lib/deepl/exceptions/request_error.rb +4 -2
  28. data/lib/deepl/exceptions/server_error.rb +18 -0
  29. data/lib/deepl/glossary_api.rb +3 -0
  30. data/lib/deepl/requests/base.rb +89 -34
  31. data/lib/deepl/requests/document/download.rb +44 -0
  32. data/lib/deepl/requests/document/get_status.rb +44 -0
  33. data/lib/deepl/requests/document/upload.rb +64 -0
  34. data/lib/deepl/requests/glossary/create.rb +15 -1
  35. data/lib/deepl/requests/glossary/destroy.rb +8 -1
  36. data/lib/deepl/requests/glossary/entries.rb +8 -1
  37. data/lib/deepl/requests/glossary/find.rb +8 -1
  38. data/lib/deepl/requests/glossary/language_pairs.rb +9 -2
  39. data/lib/deepl/requests/glossary/list.rb +9 -2
  40. data/lib/deepl/requests/languages.rb +9 -2
  41. data/lib/deepl/requests/translate.rb +33 -11
  42. data/lib/deepl/requests/usage.rb +9 -2
  43. data/lib/deepl/resources/base.rb +3 -0
  44. data/lib/deepl/resources/document_handle.rb +57 -0
  45. data/lib/deepl/resources/document_translation_status.rb +54 -0
  46. data/lib/deepl/resources/glossary.rb +3 -0
  47. data/lib/deepl/resources/language.rb +3 -0
  48. data/lib/deepl/resources/language_pair.rb +3 -0
  49. data/lib/deepl/resources/text.rb +3 -0
  50. data/lib/deepl/resources/usage.rb +3 -0
  51. data/lib/deepl/utils/backoff_timer.rb +46 -0
  52. data/lib/deepl/utils/exception_builder.rb +18 -13
  53. data/lib/deepl.rb +47 -0
  54. data/lib/http_client_options.rb +22 -0
  55. data/license_checker.sh +8 -0
  56. data/spec/api/api_spec.rb +8 -4
  57. data/spec/api/configuration_spec.rb +92 -18
  58. data/spec/api/deepl_spec.rb +225 -86
  59. data/spec/fixtures/vcr_cassettes/deepl_document.yml +95 -0
  60. data/spec/fixtures/vcr_cassettes/deepl_document_download.yml +1214 -0
  61. data/spec/fixtures/vcr_cassettes/deepl_glossaries.yml +812 -23
  62. data/spec/fixtures/vcr_cassettes/deepl_languages.yml +28 -17
  63. data/spec/fixtures/vcr_cassettes/deepl_translate.yml +161 -53
  64. data/spec/fixtures/vcr_cassettes/deepl_usage.yml +93 -3
  65. data/spec/fixtures/vcr_cassettes/glossaries.yml +1237 -15
  66. data/spec/fixtures/vcr_cassettes/languages.yml +159 -44
  67. data/spec/fixtures/vcr_cassettes/translate_texts.yml +9742 -12
  68. data/spec/fixtures/vcr_cassettes/usage.yml +134 -2
  69. data/spec/integration_tests/document_api_spec.rb +143 -0
  70. data/spec/integration_tests/integration_test_utils.rb +170 -0
  71. data/spec/requests/glossary/create_spec.rb +23 -13
  72. data/spec/requests/glossary/destroy_spec.rb +33 -17
  73. data/spec/requests/glossary/entries_spec.rb +31 -17
  74. data/spec/requests/glossary/find_spec.rb +31 -17
  75. data/spec/requests/glossary/language_pairs_spec.rb +17 -7
  76. data/spec/requests/glossary/list_spec.rb +21 -11
  77. data/spec/requests/languages_spec.rb +31 -21
  78. data/spec/requests/translate_spec.rb +125 -131
  79. data/spec/requests/usage_spec.rb +17 -7
  80. data/spec/resources/glossary_spec.rb +15 -12
  81. data/spec/resources/language_pair_spec.rb +10 -7
  82. data/spec/resources/language_spec.rb +21 -18
  83. data/spec/resources/text_spec.rb +10 -7
  84. data/spec/resources/usage_spec.rb +16 -13
  85. data/spec/spec_helper.rb +63 -6
  86. metadata +32 -9
@@ -14,7 +14,7 @@ http_interactions:
14
14
  Accept:
15
15
  - "*/*"
16
16
  User-Agent:
17
- - Ruby
17
+ - deepl-ruby/2.5.3 (darwin23) ruby/3.3.3
18
18
  response:
19
19
  status:
20
20
  code: 200
@@ -36,4 +36,136 @@ http_interactions:
36
36
  encoding: UTF-8
37
37
  string: '{"character_count":353,"character_limit":500000}'
38
38
  recorded_at: Mon, 17 May 2021 14:18:32 GMT
39
- recorded_with: VCR 6.0.0
39
+ - request:
40
+ method: get
41
+ uri: https://api-free.deepl.com/v2/usage
42
+ body:
43
+ encoding: US-ASCII
44
+ string: ''
45
+ headers:
46
+ Authorization:
47
+ - DeepL-Auth-Key VALID_TOKEN
48
+ User-Agent:
49
+ - deepl-ruby/2.5.3(darwin23) ruby/3.3.3
50
+ Accept-Encoding:
51
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
52
+ Accept:
53
+ - "*/*"
54
+ response:
55
+ status:
56
+ code: 403
57
+ message: Forbidden
58
+ headers:
59
+ Date:
60
+ - Tue, 02 Jul 2024 13:54:07 GMT
61
+ Content-Type:
62
+ - application/json
63
+ Transfer-Encoding:
64
+ - chunked
65
+ Vary:
66
+ - Accept-Encoding
67
+ Access-Control-Allow-Origin:
68
+ - "*"
69
+ Strict-Transport-Security:
70
+ - max-age=63072000; includeSubDomains; preload
71
+ Server-Timing:
72
+ - l7_lb_tls;dur=101, l7_lb_idle;dur=0, l7_lb_receive;dur=0, l7_lb_total;dur=103
73
+ Access-Control-Expose-Headers:
74
+ - Server-Timing, X-Trace-ID
75
+ X-Trace-Id:
76
+ - 4dcf2a36b3f14ba89f107449f4b14919
77
+ body:
78
+ encoding: ASCII-8BIT
79
+ string: '{"message":"Wrong endpoint. Use https://api.deepl.com"}'
80
+ recorded_at: Tue, 02 Jul 2024 13:54:07 GMT
81
+ - request:
82
+ method: get
83
+ uri: https://api.deepl.com/v2/usage
84
+ body:
85
+ encoding: US-ASCII
86
+ string: ''
87
+ headers:
88
+ Authorization:
89
+ - DeepL-Auth-Key VALID_TOKEN
90
+ User-Agent:
91
+ - deepl-ruby/2.5.3 (darwin23) ruby/3.3.3
92
+ Accept-Encoding:
93
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
94
+ Accept:
95
+ - "*/*"
96
+ response:
97
+ status:
98
+ code: 200
99
+ message: OK
100
+ headers:
101
+ Date:
102
+ - Tue, 02 Jul 2024 14:52:05 GMT
103
+ Content-Type:
104
+ - application/json
105
+ Transfer-Encoding:
106
+ - chunked
107
+ Vary:
108
+ - Accept-Encoding
109
+ Access-Control-Allow-Origin:
110
+ - "*"
111
+ X-Cache-Status:
112
+ - MISS
113
+ Strict-Transport-Security:
114
+ - max-age=63072000; includeSubDomains; preload
115
+ Server-Timing:
116
+ - l7_lb_tls;dur=112, l7_lb_idle;dur=1, l7_lb_receive;dur=0, l7_lb_total;dur=115
117
+ Access-Control-Expose-Headers:
118
+ - Server-Timing, X-Trace-ID
119
+ X-Trace-Id:
120
+ - de53f558d38c43748bf83b27f4f0edc9
121
+ body:
122
+ encoding: ASCII-8BIT
123
+ string: '{"character_count":18593,"character_limit":1000000000000}'
124
+ recorded_at: Tue, 02 Jul 2024 14:52:05 GMT
125
+ - request:
126
+ method: get
127
+ uri: https://api.deepl.com/v2/usage
128
+ body:
129
+ encoding: UTF-8
130
+ string: "{}"
131
+ headers:
132
+ Authorization:
133
+ - DeepL-Auth-Key VALID_TOKEN
134
+ User-Agent:
135
+ - deepl-ruby/2.5.3 (darwin23) ruby/3.3.3
136
+ Content-Type:
137
+ - application/json
138
+ Accept-Encoding:
139
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
140
+ Accept:
141
+ - "*/*"
142
+ response:
143
+ status:
144
+ code: 200
145
+ message: OK
146
+ headers:
147
+ Date:
148
+ - Tue, 09 Jul 2024 01:35:37 GMT
149
+ Content-Type:
150
+ - application/json
151
+ Transfer-Encoding:
152
+ - chunked
153
+ Vary:
154
+ - Accept-Encoding
155
+ Access-Control-Allow-Origin:
156
+ - "*"
157
+ X-Cache-Status:
158
+ - MISS
159
+ Strict-Transport-Security:
160
+ - max-age=63072000; includeSubDomains; preload
161
+ Server-Timing:
162
+ - l7_lb_tls;dur=137, l7_lb_idle;dur=1, l7_lb_receive;dur=0, l7_lb_total;dur=140
163
+ Access-Control-Expose-Headers:
164
+ - Server-Timing, X-Trace-ID
165
+ X-Trace-Id:
166
+ - 543309f656244684bb59d30e9dc824b5
167
+ body:
168
+ encoding: ASCII-8BIT
169
+ string: '{"character_count":69328,"character_limit":1000000000000}'
170
+ recorded_at: Tue, 09 Jul 2024 01:35:37 GMT
171
+ recorded_with: VCR 6.2.0
@@ -0,0 +1,143 @@
1
+ # Copyright 2024 DeepL SE (https://www.deepl.com)
2
+ # Use of this source code is governed by an MIT
3
+ # license that can be found in the LICENSE file.
4
+ # frozen_string_literal: true
5
+
6
+ require 'spec_helper'
7
+
8
+ describe DeepL::DocumentApi do
9
+ before do
10
+ VCR.turn_off!
11
+ WebMock.allow_net_connect!
12
+ end
13
+
14
+ after do
15
+ VCR.turn_on!
16
+ WebMock.disable_net_connect!
17
+ end
18
+
19
+ default_lang_args = { source_lang: 'EN', target_lang: 'DE' }
20
+ include_context 'with temp dir'
21
+
22
+ describe '#translate_document' do
23
+ it 'Translates a document from a filepath' do
24
+ File.unlink(output_document_path)
25
+ source_lang = default_lang_args[:source_lang]
26
+ target_lang = default_lang_args[:target_lang]
27
+ example_doc_path = example_document_path(source_lang)
28
+ DeepL.document.translate_document(example_doc_path, output_document_path,
29
+ source_lang, target_lang, File.basename(example_doc_path),
30
+ {})
31
+ output_file_contents = File.read(output_document_path)
32
+
33
+ expect(example_document_translation(target_lang)).to eq(output_file_contents)
34
+ end
35
+
36
+ it 'Translates a document using the lower-level methods and returns the correct status' do # rubocop:disable RSpec/ExampleLength
37
+ File.unlink(output_document_path)
38
+ source_lang = default_lang_args[:source_lang]
39
+ target_lang = default_lang_args[:target_lang]
40
+ example_doc_path = example_document_path(source_lang)
41
+
42
+ handle = DeepL.document.upload(example_doc_path, source_lang, target_lang,
43
+ File.basename(example_doc_path), {})
44
+ doc_status = handle.wait_until_document_translation_finished
45
+ DeepL.document.download(handle, output_document_path) if doc_status.status != 'error'
46
+ output_file_contents = File.read(output_document_path)
47
+
48
+ expect(example_document_translation(target_lang)).to eq(output_file_contents)
49
+ expect(doc_status.billed_characters).to eq(example_document_translation(source_lang).length)
50
+ expect(doc_status.status).to eq('done')
51
+ end
52
+
53
+ it 'Translates a document after retrying the upload once' do # rubocop:disable RSpec/ExampleLength
54
+ skip 'Only runs on mock server' if real_server?
55
+ File.unlink(output_document_path)
56
+ source_lang = default_lang_args[:source_lang]
57
+ target_lang = default_lang_args[:target_lang]
58
+ example_doc_path = example_document_path(source_lang)
59
+ doc_status = nil
60
+ DeepL.with_session(DeepL::HTTPClientOptions.new({}, nil, enable_ssl_verification: false,
61
+ read_timeout: 1.0)) do |_session|
62
+ handle = DeepL.document.upload(example_doc_path, source_lang, target_lang,
63
+ File.basename(example_doc_path), {}, no_response_header(1))
64
+ doc_status = handle.wait_until_document_translation_finished
65
+ DeepL.document.download(handle, output_document_path) if doc_status.status != 'error'
66
+ end
67
+ output_file_contents = File.read(output_document_path)
68
+
69
+ expect(output_file_contents).to eq(example_document_translation(target_lang))
70
+ expect(doc_status.billed_characters).to eq(example_document_translation(source_lang).length)
71
+ expect(doc_status.status).to eq('done')
72
+ end
73
+ end
74
+
75
+ it 'Translates a document after waiting' do # rubocop:disable RSpec/ExampleLength
76
+ skip 'Only runs on mock server' if real_server?
77
+ File.unlink(output_document_path)
78
+ source_lang = default_lang_args[:source_lang]
79
+ target_lang = default_lang_args[:target_lang]
80
+ example_doc_path = example_document_path(source_lang)
81
+ doc_status = nil
82
+ DeepL.with_session(DeepL::HTTPClientOptions.new({}, nil,
83
+ enable_ssl_verification: false)) do |_session|
84
+ handle = DeepL.document.upload(example_doc_path, source_lang, target_lang,
85
+ File.basename(example_doc_path), {},
86
+ doc_translation_queue_time_header(2000).merge(doc_translation_translation_time_header(2000))) # rubocop:disable Layout/LineLength
87
+ doc_status = handle.wait_until_document_translation_finished
88
+ DeepL.document.download(handle, output_document_path) if doc_status.status != 'error'
89
+ end
90
+ output_file_contents = File.read(output_document_path)
91
+
92
+ expect(output_file_contents).to eq(example_document_translation(target_lang))
93
+ expect(doc_status.billed_characters).to eq(example_document_translation(source_lang).length)
94
+ expect(doc_status.status).to eq('done')
95
+ end
96
+
97
+ it 'Translates a large document' do # rubocop:disable RSpec/ExampleLength
98
+ skip 'Only runs on mock server' if real_server?
99
+ File.unlink(output_document_path)
100
+ source_lang = default_lang_args[:source_lang]
101
+ target_lang = default_lang_args[:target_lang]
102
+ example_doc_path = example_large_document_path(source_lang)
103
+ doc_status = nil
104
+ DeepL.with_session(DeepL::HTTPClientOptions.new({}, nil,
105
+ enable_ssl_verification: false)) do |_session|
106
+ handle = DeepL.document.upload(example_doc_path, source_lang, target_lang,
107
+ File.basename(example_doc_path), {})
108
+ doc_status = handle.wait_until_document_translation_finished
109
+ DeepL.document.download(handle, output_document_path) if doc_status.status != 'error'
110
+ end
111
+ output_file_contents = File.read(output_document_path)
112
+
113
+ expect(output_file_contents).to eq(example_large_document_translation(target_lang))
114
+ expect(doc_status.billed_characters).to eq(
115
+ example_large_document_translation(source_lang).length
116
+ )
117
+ expect(doc_status.status).to eq('done')
118
+ end
119
+
120
+ it 'Translates a document with formality set' do # rubocop:disable RSpec/ExampleLength
121
+ skip 'Only runs on mock server' if real_server?
122
+ File.unlink(output_document_path)
123
+ source_lang = default_lang_args[:source_lang]
124
+ target_lang = default_lang_args[:target_lang]
125
+ example_doc_path = example_large_document_path(source_lang)
126
+ doc_status = nil
127
+ DeepL.with_session(DeepL::HTTPClientOptions.new({}, nil,
128
+ enable_ssl_verification: false)) do |_session|
129
+ handle = DeepL.document.upload(example_doc_path, source_lang, target_lang,
130
+ File.basename(example_doc_path),
131
+ { 'formality' => 'prefer_more' })
132
+ doc_status = handle.wait_until_document_translation_finished
133
+ DeepL.document.download(handle, output_document_path) if doc_status.status != 'error'
134
+ end
135
+ output_file_contents = File.read(output_document_path)
136
+
137
+ expect(output_file_contents).to eq(example_large_document_translation(target_lang))
138
+ expect(doc_status.billed_characters).to eq(
139
+ example_large_document_translation(source_lang).length
140
+ )
141
+ expect(doc_status.status).to eq('done')
142
+ end
143
+ end
@@ -0,0 +1,170 @@
1
+ # Copyright 2024 DeepL SE (https://www.deepl.com)
2
+ # Use of this source code is governed by an MIT
3
+ # license that can be found in the LICENSE file.
4
+ # frozen_string_literal: true
5
+
6
+ require 'securerandom'
7
+ require 'tempfile'
8
+
9
+ module IntegrationTestUtils # rubocop:disable Metrics/ModuleLength
10
+ EXAMPLE_TEXT = {
11
+ 'BG' => 'протонен лъч',
12
+ 'CS' => 'protonový paprsek',
13
+ 'DA' => 'protonstråle',
14
+ 'DE' => 'Protonenstrahl',
15
+ 'EL' => 'δέσμη πρωτονίων',
16
+ 'EN' => 'proton beam',
17
+ 'EN-US' => 'proton beam',
18
+ 'EN-GB' => 'proton beam',
19
+ 'ES' => 'haz de protones',
20
+ 'ET' => 'prootonikiirgus',
21
+ 'FI' => 'protonisäde',
22
+ 'FR' => 'faisceau de protons',
23
+ 'HU' => 'protonnyaláb',
24
+ 'ID' => 'berkas proton',
25
+ 'IT' => 'fascio di protoni',
26
+ 'JA' => '陽子ビーム',
27
+ 'KO' => '양성자 빔',
28
+ 'LT' => 'protonų spindulys',
29
+ 'LV' => 'protonu staru kūlis',
30
+ 'NB' => 'protonstråle',
31
+ 'NL' => 'protonenbundel',
32
+ 'PL' => 'wiązka protonów',
33
+ 'PT' => 'feixe de prótons',
34
+ 'PT-BR' => 'feixe de prótons',
35
+ 'PT-PT' => 'feixe de prótons',
36
+ 'RO' => 'fascicul de protoni',
37
+ 'RU' => 'протонный луч',
38
+ 'SK' => 'protónový lúč',
39
+ 'SL' => 'protonski žarek',
40
+ 'SV' => 'protonstråle',
41
+ 'TR' => 'proton ışını',
42
+ 'UK' => 'протонний пучок',
43
+ 'ZH' => '质子束'
44
+ }.freeze
45
+
46
+ def mock_server?
47
+ ENV.key?('DEEPL_MOCK_SERVER_PORT')
48
+ end
49
+
50
+ def mock_proxy_server?
51
+ ENV.key?('DEEPL_MOCK_PROXY_SERVER_PORT')
52
+ end
53
+
54
+ def real_server?
55
+ !mock_server?
56
+ end
57
+
58
+ def setup
59
+ @input_file = nil
60
+ @input_file_extension = nil
61
+ @output_file = nil
62
+ DeepL.configure do |config|
63
+ config.auth_key = 'your-api-token'
64
+ end
65
+ end
66
+
67
+ def teardown
68
+ unless @input_file.nil?
69
+ @input_file.close
70
+ @input_file.unlink
71
+ end
72
+ return if @output_file.nil?
73
+
74
+ @output_file.close
75
+ @output_file.unlink
76
+ end
77
+
78
+ def example_document_path(document_language)
79
+ setup_example_document(EXAMPLE_TEXT[document_language])
80
+ end
81
+
82
+ def example_large_document_path(document_language)
83
+ setup_example_document("#{EXAMPLE_TEXT[document_language]}\n" * 1000)
84
+ end
85
+
86
+ def setup_example_document(file_content)
87
+ @input_file_base_name = 'example_input_document' if @input_file_base_name.nil?
88
+ @input_file_extension = '.txt' if @input_file_extension.nil?
89
+ if @input_file.nil?
90
+ @input_file = Tempfile.new([@input_file_base_name, @input_file_extension])
91
+ @input_file.write(file_content)
92
+ @input_file.close
93
+ end
94
+ @input_file.path
95
+ end
96
+
97
+ def example_document_translation(document_language)
98
+ EXAMPLE_TEXT[document_language]
99
+ end
100
+
101
+ def example_large_document_translation(document_language)
102
+ "#{EXAMPLE_TEXT[document_language]}\n" * 1000
103
+ end
104
+
105
+ def output_document_path
106
+ @output_file = Tempfile.new('example_output_document') if @output_file.nil?
107
+ @output_file.path
108
+ end
109
+
110
+ # For detailed explanations of these header, check the deepl-mock README.md
111
+ def no_response_header(no_response_count)
112
+ { 'mock-server-session-no-response-count' => no_response_count.to_s,
113
+ 'mock-server-session' => SecureRandom.uuid }
114
+ end
115
+
116
+ def respond_with_429_header(response_count)
117
+ { 'mock-server-session-429-count' => response_count.to_s,
118
+ 'mock-server-session' => SecureRandom.uuid }
119
+ end
120
+
121
+ def set_character_limit_header(response_count) # rubocop:disable Naming/AccessorMethodName
122
+ { 'mock-server-session-init-character-limit' => response_count.to_s,
123
+ 'mock-server-session' => SecureRandom.uuid }
124
+ end
125
+
126
+ def set_document_limit_header(response_count) # rubocop:disable Naming/AccessorMethodName
127
+ { 'mock-server-session-init-document-limit' => response_count.to_s,
128
+ 'mock-server-session' => SecureRandom.uuid }
129
+ end
130
+
131
+ def set_team_document_limit_header(response_count) # rubocop:disable Naming/AccessorMethodName
132
+ { 'mock-server-session-init-team-document-limit' => response_count.to_s,
133
+ 'mock-server-session' => SecureRandom.uuid }
134
+ end
135
+
136
+ def fail_docs_header(response_count)
137
+ { 'mock-server-session-doc-failure' => response_count.to_s,
138
+ 'mock-server-session' => SecureRandom.uuid }
139
+ end
140
+
141
+ def doc_translation_queue_time_header(response_count)
142
+ { 'mock-server-session-doc-queue-time' => response_count.to_s,
143
+ 'mock-server-session' => SecureRandom.uuid }
144
+ end
145
+
146
+ def doc_translation_translation_time_header(response_count)
147
+ { 'mock-server-session-doc-translate-time' => response_count.to_s,
148
+ 'mock-server-session' => SecureRandom.uuid }
149
+ end
150
+
151
+ def expect_proxy_header(response_count)
152
+ { 'mock-server-session-expect-proxy' => response_count.to_s,
153
+ 'mock-server-session' => SecureRandom.uuid }
154
+ end
155
+ end
156
+
157
+ shared_context 'with temp dir' do
158
+ around do |example|
159
+ Dir.mktmpdir('deepl-rspec-') do |dir|
160
+ @temp_dir = dir
161
+ example.run
162
+ end
163
+ end
164
+
165
+ attr_reader :temp_dir, :input_file_base_name, :input_file_extension
166
+ end
167
+
168
+ RSpec.configure do |c|
169
+ c.include IntegrationTestUtils
170
+ end
@@ -1,8 +1,21 @@
1
+ # Copyright 2022 Daniel Herzog
2
+ # Use of this source code is governed by an MIT
3
+ # license that can be found in the LICENSE.md file.
1
4
  # frozen_string_literal: true
2
5
 
3
6
  require 'spec_helper'
4
7
 
5
8
  describe DeepL::Requests::Glossary::Create do
9
+ subject(:create) do
10
+ described_class.new(api, name, source_lang, target_lang, entries, options)
11
+ end
12
+
13
+ around do |tests|
14
+ tmp_env = replace_env_preserving_deepl_vars_except_mock_server
15
+ tests.call
16
+ ENV.replace(tmp_env)
17
+ end
18
+
6
19
  let(:api) { build_deepl_api }
7
20
  let(:name) { 'Mi Glosario' }
8
21
  let(:source_lang) { 'EN' }
@@ -15,19 +28,16 @@ describe DeepL::Requests::Glossary::Create do
15
28
  end
16
29
  let(:entries_format) { 'tsv' }
17
30
  let(:options) { {} }
18
- subject do
19
- DeepL::Requests::Glossary::Create.new(api, name, source_lang, target_lang, entries, options)
20
- end
21
31
 
22
32
  describe '#initialize' do
23
- context 'When building a request' do
24
- it 'should create a request object' do
25
- expect(subject).to be_a(described_class)
33
+ context 'when building a request' do
34
+ it 'creates a request object' do
35
+ expect(create).to be_a(described_class)
26
36
  end
27
37
 
28
- it 'should set the default value for the entries format if not specified' do
29
- request = DeepL::Requests::Glossary::Create.new(api, name, source_lang, target_lang,
30
- entries, options)
38
+ it 'sets the default value for the entries format if not specified' do
39
+ request = described_class.new(api, name, source_lang, target_lang,
40
+ entries, options)
31
41
  expect(request.entries_format).to eq('tsv')
32
42
  end
33
43
  end
@@ -38,11 +48,11 @@ describe DeepL::Requests::Glossary::Create do
38
48
  VCR.use_cassette('glossaries') { example.call }
39
49
  end
40
50
 
41
- context 'When performing a valid request with two glossary entries' do
42
- it 'should return a glossaries object' do
43
- glossary = subject.request
51
+ context 'when performing a valid request with two glossary entries' do
52
+ it 'returns a glossaries object' do
53
+ glossary = create.request
44
54
  expect(glossary).to be_a(DeepL::Resources::Glossary)
45
- expect(glossary.id).to be_kind_of(String)
55
+ expect(glossary.id).to be_a(String)
46
56
  expect(glossary.name).to eq('Mi Glosario')
47
57
  expect(glossary.ready).to be(true).or be(false)
48
58
  expect(glossary.source_lang).to eq('en')
@@ -1,16 +1,26 @@
1
+ # Copyright 2022 Daniel Herzog
2
+ # Use of this source code is governed by an MIT
3
+ # license that can be found in the LICENSE.md file.
1
4
  # frozen_string_literal: true
2
5
 
3
6
  require 'spec_helper'
4
7
 
5
8
  describe DeepL::Requests::Glossary::Destroy do
9
+ subject(:destroy) { described_class.new(api, id) }
10
+
11
+ around do |tests|
12
+ tmp_env = replace_env_preserving_deepl_vars_except_mock_server
13
+ tests.call
14
+ ENV.replace(tmp_env)
15
+ end
16
+
6
17
  let(:api) { build_deepl_api }
7
- let(:id) { '367eef44-b533-4d95-be19-74950c7760e9' }
8
- subject { DeepL::Requests::Glossary::Destroy.new(api, id) }
18
+ let(:id) { '9ab5dac2-b7b2-4b4a-808a-e8e305df5ecb' }
9
19
 
10
20
  describe '#initialize' do
11
- context 'When building a request' do
12
- it 'should create a request object' do
13
- expect(subject).to be_a(described_class)
21
+ context 'when building a request' do
22
+ it 'creates a request object' do
23
+ expect(destroy).to be_a(described_class)
14
24
  end
15
25
  end
16
26
  end
@@ -20,30 +30,36 @@ describe DeepL::Requests::Glossary::Destroy do
20
30
  VCR.use_cassette('glossaries') { example.call }
21
31
  end
22
32
 
23
- context 'When performing a valid request' do
33
+ context 'when performing a valid request' do
34
+ subject(:destroy) { described_class.new(api, new_glossary.id) }
35
+
24
36
  let(:new_glossary) do
25
37
  DeepL::Requests::Glossary::Create.new(api, 'fixture', 'EN', 'ES', [%w[Hello Hola]]).request
26
38
  end
27
- subject { DeepL::Requests::Glossary::Destroy.new(api, new_glossary.id) }
28
- it 'should return an empty object' do
29
- response = subject.request
39
+
40
+ it 'returns an empty object' do
41
+ response = destroy.request
30
42
  expect(response).to eq(new_glossary.id)
31
43
  end
32
44
  end
33
45
 
34
- context 'When deleting a non existing glossary with a valid id' do
46
+ context 'when deleting a non existing glossary with a valid id' do
47
+ subject(:destroy) { described_class.new(api, id) }
48
+
35
49
  let(:id) { '00000000-0000-0000-0000-000000000000' }
36
- subject { DeepL::Requests::Glossary::Destroy.new(api, id) }
37
- it 'should raise a not found error' do
38
- expect { subject.request }.to raise_error(DeepL::Exceptions::NotFound)
50
+
51
+ it 'raises a not found error' do
52
+ expect { destroy.request }.to raise_error(DeepL::Exceptions::NotFound)
39
53
  end
40
54
  end
41
55
 
42
- context 'When deleting a non existing glossary with an invalid id' do
56
+ context 'when deleting a non existing glossary with an invalid id' do
57
+ subject(:destroy) { described_class.new(api, id) }
58
+
43
59
  let(:id) { 'invalid-uuid' }
44
- subject { DeepL::Requests::Glossary::Destroy.new(api, id) }
45
- it 'should raise a bad request error' do
46
- expect { subject.request }.to raise_error(DeepL::Exceptions::BadRequest)
60
+
61
+ it 'raises a bad request error' do
62
+ expect { destroy.request }.to raise_error(DeepL::Exceptions::BadRequest)
47
63
  end
48
64
  end
49
65
  end
@@ -1,16 +1,26 @@
1
+ # Copyright 2022 Daniel Herzog
2
+ # Use of this source code is governed by an MIT
3
+ # license that can be found in the LICENSE.md file.
1
4
  # frozen_string_literal: true
2
5
 
3
6
  require 'spec_helper'
4
7
 
5
8
  describe DeepL::Requests::Glossary::Entries do
9
+ subject(:entries_obj) { described_class.new(api, id) }
10
+
11
+ around do |tests|
12
+ tmp_env = replace_env_preserving_deepl_vars_except_mock_server
13
+ tests.call
14
+ ENV.replace(tmp_env)
15
+ end
16
+
6
17
  let(:api) { build_deepl_api }
7
- let(:id) { '012a5576-b551-4d4c-b917-ce01bc8debb6' }
8
- subject { DeepL::Requests::Glossary::Entries.new(api, id) }
18
+ let(:id) { '9ab5dac2-b7b2-4b4a-808a-e8e305df5ecb' }
9
19
 
10
20
  describe '#initialize' do
11
- context 'When building a request' do
12
- it 'should create a request object' do
13
- expect(subject).to be_a(described_class)
21
+ context 'when building a request' do
22
+ it 'creates a request object' do
23
+ expect(entries_obj).to be_a(described_class)
14
24
  end
15
25
  end
16
26
  end
@@ -20,28 +30,32 @@ describe DeepL::Requests::Glossary::Entries do
20
30
  VCR.use_cassette('glossaries') { example.call }
21
31
  end
22
32
 
23
- context 'When performing a valid request' do
24
- it 'should return a list of entries in TSV format' do
25
- entries = subject.request
26
- expect(entries).to be_kind_of(Array)
33
+ context 'when performing a valid request' do
34
+ it 'returns a list of entries in TSV format' do
35
+ entries = entries_obj.request
36
+ expect(entries).to be_a(Array)
27
37
  expect(entries).to all(be_a(Array))
28
38
  expect(entries.size).to eq(2)
29
39
  end
30
40
  end
31
41
 
32
- context 'When requesting entries with a valid but non existing glossary id' do
42
+ context 'when requesting entries with a valid but non existing glossary id' do
43
+ subject(:entries_obj) { described_class.new(api, id) }
44
+
33
45
  let(:id) { '00000000-0000-0000-0000-000000000000' }
34
- subject { DeepL::Requests::Glossary::Entries.new(api, id) }
35
- it 'should raise a not found error' do
36
- expect { subject.request }.to raise_error(DeepL::Exceptions::NotFound)
46
+
47
+ it 'raises a not found error' do
48
+ expect { entries_obj.request }.to raise_error(DeepL::Exceptions::NotFound)
37
49
  end
38
50
  end
39
51
 
40
- context 'When requesting entries with an invalid glossary id' do
52
+ context 'when requesting entries with an invalid glossary id' do
53
+ subject(:entries_obj) { described_class.new(api, id) }
54
+
41
55
  let(:id) { 'invalid-uuid' }
42
- subject { DeepL::Requests::Glossary::Entries.new(api, id) }
43
- it 'should raise a bad request error' do
44
- expect { subject.request }.to raise_error(DeepL::Exceptions::BadRequest)
56
+
57
+ it 'raises a bad request error' do
58
+ expect { entries_obj.request }.to raise_error(DeepL::Exceptions::BadRequest)
45
59
  end
46
60
  end
47
61
  end