deepl-rb 3.6.1 → 3.8.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 +4 -4
- data/.gitlab-ci.yml +8 -1
- data/CHANGELOG.md +35 -1
- data/Gemfile +0 -2
- data/README.md +165 -34
- data/Rakefile +2 -0
- data/VERSION +1 -1
- data/deepl-rb.gemspec +52 -20
- data/lib/deepl/requests/base.rb +16 -0
- data/lib/deepl/requests/document/upload.rb +6 -5
- data/lib/deepl/requests/rephrase.rb +3 -2
- data/lib/deepl/requests/style_rule/create.rb +46 -0
- data/lib/deepl/requests/style_rule/create_custom_instruction.rb +45 -0
- data/lib/deepl/requests/style_rule/destroy.rb +39 -0
- data/lib/deepl/requests/style_rule/destroy_custom_instruction.rb +40 -0
- data/lib/deepl/requests/style_rule/find.rb +40 -0
- data/lib/deepl/requests/style_rule/find_custom_instruction.rb +41 -0
- data/lib/deepl/requests/style_rule/update.rb +42 -0
- data/lib/deepl/requests/style_rule/update_configured_rules.rb +41 -0
- data/lib/deepl/requests/style_rule/update_custom_instruction.rb +47 -0
- data/lib/deepl/requests/translate.rb +17 -4
- data/lib/deepl/requests/translation_memory/list.rb +58 -0
- data/lib/deepl/resources/style_rule.rb +2 -1
- data/lib/deepl/resources/translation_memory.rb +25 -0
- data/lib/deepl/style_rule_api.rb +44 -0
- data/lib/deepl/translation_memory_api.rb +17 -0
- data/lib/deepl.rb +75 -55
- data/lib/version.rb +1 -1
- data/spec/api/deepl_spec.rb +134 -332
- data/spec/integration_tests/document_api_spec.rb +4 -18
- data/spec/integration_tests/document_error_paths_spec.rb +33 -0
- data/spec/integration_tests/glossary_api_spec.rb +114 -0
- data/spec/integration_tests/glossary_error_paths_spec.rb +107 -0
- data/spec/integration_tests/languages_api_spec.rb +54 -0
- data/spec/integration_tests/languages_error_paths_spec.rb +25 -0
- data/spec/integration_tests/rephrase_api_spec.rb +90 -0
- data/spec/integration_tests/rephrase_error_paths_spec.rb +53 -0
- data/spec/integration_tests/smoke_test_spec.rb +24 -0
- data/spec/integration_tests/style_rule_api_spec.rb +55 -17
- data/spec/integration_tests/style_rule_error_paths_spec.rb +45 -0
- data/spec/integration_tests/translate_api_spec.rb +98 -0
- data/spec/integration_tests/translate_error_paths_spec.rb +48 -0
- data/spec/integration_tests/translation_memory_api_spec.rb +54 -0
- data/spec/integration_tests/translation_memory_error_paths_spec.rb +19 -0
- data/spec/integration_tests/usage_api_spec.rb +29 -0
- data/spec/integration_tests/usage_error_paths_spec.rb +18 -0
- data/spec/requests/glossary/create_spec.rb +0 -21
- data/spec/requests/glossary/destroy_spec.rb +0 -39
- data/spec/requests/glossary/entries_spec.rb +0 -35
- data/spec/requests/glossary/find_spec.rb +0 -40
- data/spec/requests/glossary/language_pairs_spec.rb +0 -13
- data/spec/requests/glossary/list_spec.rb +0 -27
- data/spec/requests/languages_spec.rb +0 -41
- data/spec/requests/rephrase_spec.rb +13 -139
- data/spec/requests/style_rule/create_custom_instruction_spec.rb +30 -0
- data/spec/requests/style_rule/create_spec.rb +29 -0
- data/spec/requests/style_rule/destroy_custom_instruction_spec.rb +28 -0
- data/spec/requests/style_rule/destroy_spec.rb +27 -0
- data/spec/requests/style_rule/find_custom_instruction_spec.rb +29 -0
- data/spec/requests/style_rule/find_spec.rb +28 -0
- data/spec/requests/style_rule/list_spec.rb +27 -0
- data/spec/requests/style_rule/update_configured_rules_spec.rb +31 -0
- data/spec/requests/style_rule/update_custom_instruction_spec.rb +32 -0
- data/spec/requests/style_rule/update_spec.rb +29 -0
- data/spec/requests/translate_spec.rb +8 -218
- data/spec/requests/translation_memory/list_spec.rb +27 -0
- data/spec/requests/usage_spec.rb +0 -16
- data/spec/resources/custom_instruction_spec.rb +32 -0
- data/spec/resources/style_rule_spec.rb +68 -0
- data/spec/resources/translation_memory_spec.rb +35 -0
- data/spec/spec_helper.rb +15 -45
- data/spec/support/live_mock_server.rb +12 -0
- data/spec/support/managed_glossary.rb +17 -0
- data/spec/support/managed_style_rule.rb +17 -0
- data/spec/support/managed_translation_memory.rb +7 -0
- metadata +48 -19
- data/spec/fixtures/vcr_cassettes/deepl_document.yml +0 -95
- data/spec/fixtures/vcr_cassettes/deepl_document_download.yml +0 -1214
- data/spec/fixtures/vcr_cassettes/deepl_glossaries.yml +0 -1163
- data/spec/fixtures/vcr_cassettes/deepl_languages.yml +0 -54
- data/spec/fixtures/vcr_cassettes/deepl_rephrase.yml +0 -87
- data/spec/fixtures/vcr_cassettes/deepl_translate.yml +0 -358
- data/spec/fixtures/vcr_cassettes/deepl_usage.yml +0 -129
- data/spec/fixtures/vcr_cassettes/glossaries.yml +0 -1702
- data/spec/fixtures/vcr_cassettes/languages.yml +0 -229
- data/spec/fixtures/vcr_cassettes/rephrase_texts.yml +0 -401
- data/spec/fixtures/vcr_cassettes/style_rules.yml +0 -92
- data/spec/fixtures/vcr_cassettes/translate_texts.yml +0 -10630
- data/spec/fixtures/vcr_cassettes/usage.yml +0 -171
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Copyright 2026 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::GlossaryApi do
|
|
9
|
+
let(:default_glossary_args) do
|
|
10
|
+
{
|
|
11
|
+
name: 'Integration Test Glossary',
|
|
12
|
+
source_lang: 'en',
|
|
13
|
+
target_lang: 'de',
|
|
14
|
+
entries: [%w[Hello Hallo], %w[World Welt]]
|
|
15
|
+
}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe 'happy path lifecycle' do
|
|
19
|
+
it 'creates, lists, and finds a glossary' do # rubocop:disable RSpec/ExampleLength,RSpec/MultipleExpectations
|
|
20
|
+
with_managed_glossary(**default_glossary_args) do |glossary|
|
|
21
|
+
expect(glossary).to be_a(DeepL::Resources::Glossary)
|
|
22
|
+
expect(glossary.id).to be_a(String)
|
|
23
|
+
expect(glossary.name).to eq(default_glossary_args[:name])
|
|
24
|
+
expect(glossary.entry_count).to eq(2)
|
|
25
|
+
expect(glossary.source_lang).to eq(default_glossary_args[:source_lang])
|
|
26
|
+
expect(glossary.target_lang).to eq(default_glossary_args[:target_lang])
|
|
27
|
+
expect(glossary.ready).to be(true).or be(false)
|
|
28
|
+
expect { Time.iso8601(glossary.creation_time) }.not_to raise_error
|
|
29
|
+
|
|
30
|
+
listed = DeepL.glossaries.list
|
|
31
|
+
expect(listed).to be_an(Array)
|
|
32
|
+
expect(listed.map(&:id)).to include(glossary.id)
|
|
33
|
+
|
|
34
|
+
found = DeepL.glossaries.find(glossary.id)
|
|
35
|
+
expect(found).to be_a(DeepL::Resources::Glossary)
|
|
36
|
+
expect(found.id).to eq(glossary.id)
|
|
37
|
+
expect(found.name).to eq(glossary.name)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe '#language_pairs' do
|
|
43
|
+
it 'returns a non-empty list of supported source/target combos' do
|
|
44
|
+
pairs = DeepL.glossaries.language_pairs
|
|
45
|
+
expect(pairs).to be_an(Array)
|
|
46
|
+
expect(pairs).not_to be_empty
|
|
47
|
+
expect(pairs.first).to be_a(DeepL::Resources::LanguagePair)
|
|
48
|
+
expect(pairs.first.source_lang).to be_a(String)
|
|
49
|
+
expect(pairs.first.target_lang).to be_a(String)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe 'error handling' do
|
|
54
|
+
it 'raises when creating a glossary with an invalid source language code' do
|
|
55
|
+
expect do
|
|
56
|
+
DeepL.glossaries.create(
|
|
57
|
+
'Invalid Lang Glossary',
|
|
58
|
+
'zz',
|
|
59
|
+
'de',
|
|
60
|
+
[%w[Hello Hallo]]
|
|
61
|
+
)
|
|
62
|
+
end.to raise_error(DeepL::Exceptions::RequestError)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe '#destroy' do
|
|
67
|
+
it 'returns the id of the destroyed glossary' do
|
|
68
|
+
glossary = DeepL.glossaries.create(
|
|
69
|
+
default_glossary_args[:name],
|
|
70
|
+
default_glossary_args[:source_lang],
|
|
71
|
+
default_glossary_args[:target_lang],
|
|
72
|
+
default_glossary_args[:entries]
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
expect(DeepL.glossaries.destroy(glossary.id)).to eq(glossary.id)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
describe '#entries' do
|
|
80
|
+
it 'returns the glossary entries as an array of [source, target] pairs' do # rubocop:disable RSpec/ExampleLength
|
|
81
|
+
with_managed_glossary(**default_glossary_args) do |glossary|
|
|
82
|
+
entries = DeepL.glossaries.entries(glossary.id)
|
|
83
|
+
|
|
84
|
+
expect(entries).to be_an(Array)
|
|
85
|
+
expect(entries).to all(be_an(Array))
|
|
86
|
+
expect(entries.size).to eq(default_glossary_args[:entries].size)
|
|
87
|
+
entries.each do |entry|
|
|
88
|
+
expect(entry.size).to eq(2)
|
|
89
|
+
expect(entry.first).to be_a(String)
|
|
90
|
+
expect(entry.last).to be_a(String)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
describe 'edge cases' do
|
|
97
|
+
it 'accepts Unicode keys and values in glossary entries' do # rubocop:disable RSpec/ExampleLength
|
|
98
|
+
unicode_entries = [
|
|
99
|
+
['Schöne Grüße', 'Best regards'],
|
|
100
|
+
['🚀 rocket', '🚀 fusée'],
|
|
101
|
+
['日本語', 'Japanese'],
|
|
102
|
+
['café', 'kafē']
|
|
103
|
+
]
|
|
104
|
+
args = default_glossary_args.merge(
|
|
105
|
+
name: 'Unicode Glossary',
|
|
106
|
+
entries: unicode_entries
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
with_managed_glossary(**args) do |glossary|
|
|
110
|
+
expect(glossary.entry_count).to eq(unicode_entries.length)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Copyright 2026 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::GlossaryApi do # rubocop:disable RSpec/SpecFilePathFormat
|
|
9
|
+
include_context 'with a live mock server'
|
|
10
|
+
|
|
11
|
+
let(:nonexistent_glossary_id) { '00000000-0000-0000-0000-000000000000' }
|
|
12
|
+
|
|
13
|
+
let(:valid_glossary_args) do
|
|
14
|
+
{
|
|
15
|
+
name: 'Error Path Test Glossary',
|
|
16
|
+
source_lang: 'en',
|
|
17
|
+
target_lang: 'de',
|
|
18
|
+
entries: [%w[Hello Hallo]]
|
|
19
|
+
}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe 'AuthorizationFailed (401/403)' do
|
|
23
|
+
let(:unauthorized_glossaries) { described_class.new(unauthorized_api) }
|
|
24
|
+
|
|
25
|
+
it 'is raised by #list when the auth key is invalid' do
|
|
26
|
+
expect { unauthorized_glossaries.list }
|
|
27
|
+
.to raise_error(DeepL::Exceptions::AuthorizationFailed)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it 'is raised by #language_pairs when the auth key is invalid' do
|
|
31
|
+
expect { unauthorized_glossaries.language_pairs }
|
|
32
|
+
.to raise_error(DeepL::Exceptions::AuthorizationFailed)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'is raised by #create when the auth key is invalid' do
|
|
36
|
+
expect do
|
|
37
|
+
unauthorized_glossaries.create(
|
|
38
|
+
valid_glossary_args[:name],
|
|
39
|
+
valid_glossary_args[:source_lang],
|
|
40
|
+
valid_glossary_args[:target_lang],
|
|
41
|
+
valid_glossary_args[:entries]
|
|
42
|
+
)
|
|
43
|
+
end.to raise_error(DeepL::Exceptions::AuthorizationFailed)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'is raised by #find when the auth key is invalid' do
|
|
47
|
+
expect { unauthorized_glossaries.find(nonexistent_glossary_id) }
|
|
48
|
+
.to raise_error(DeepL::Exceptions::AuthorizationFailed)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'is raised by #destroy when the auth key is invalid' do
|
|
52
|
+
expect { unauthorized_glossaries.destroy(nonexistent_glossary_id) }
|
|
53
|
+
.to raise_error(DeepL::Exceptions::AuthorizationFailed)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
describe 'NotFound (404)' do
|
|
58
|
+
it 'is raised by #find for a well-formed but unknown glossary id' do
|
|
59
|
+
expect { DeepL.glossaries.find(nonexistent_glossary_id) }
|
|
60
|
+
.to raise_error(DeepL::Exceptions::NotFound)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it 'is raised by #destroy for a well-formed but unknown glossary id' do
|
|
64
|
+
expect { DeepL.glossaries.destroy(nonexistent_glossary_id) }
|
|
65
|
+
.to raise_error(DeepL::Exceptions::NotFound)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
describe 'BadRequest (400) from #create' do
|
|
70
|
+
it 'is raised for an invalid source language code' do
|
|
71
|
+
expect do
|
|
72
|
+
DeepL.glossaries.create(
|
|
73
|
+
valid_glossary_args[:name],
|
|
74
|
+
'zz',
|
|
75
|
+
valid_glossary_args[:target_lang],
|
|
76
|
+
valid_glossary_args[:entries]
|
|
77
|
+
)
|
|
78
|
+
end.to raise_error(DeepL::Exceptions::BadRequest)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
describe 'BadRequest (400) from a malformed glossary id' do
|
|
83
|
+
let(:malformed_uuid) { 'invalid-uuid' }
|
|
84
|
+
|
|
85
|
+
it 'is raised by #find for a malformed glossary id' do
|
|
86
|
+
expect { DeepL.glossaries.find(malformed_uuid) }
|
|
87
|
+
.to raise_error(DeepL::Exceptions::BadRequest)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it 'is raised by #destroy for a malformed glossary id' do
|
|
91
|
+
expect { DeepL.glossaries.destroy(malformed_uuid) }
|
|
92
|
+
.to raise_error(DeepL::Exceptions::BadRequest)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it 'is raised by #entries for a malformed glossary id' do
|
|
96
|
+
expect { DeepL.glossaries.entries(malformed_uuid) }
|
|
97
|
+
.to raise_error(DeepL::Exceptions::BadRequest)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
describe 'NotFound (404) from #entries' do
|
|
102
|
+
it 'is raised for a well-formed but unknown glossary id' do
|
|
103
|
+
expect { DeepL.glossaries.entries(nonexistent_glossary_id) }
|
|
104
|
+
.to raise_error(DeepL::Exceptions::NotFound)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Copyright 2026 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
|
+
# Covers GET /v2/languages; the SDK has no v3 languages endpoint.
|
|
9
|
+
describe 'DeepL.languages' do # rubocop:disable RSpec/DescribeClass
|
|
10
|
+
describe 'source languages' do
|
|
11
|
+
it 'returns a non-empty array of Language resources with common codes' do
|
|
12
|
+
languages = DeepL.languages
|
|
13
|
+
|
|
14
|
+
expect(languages).to be_an(Array)
|
|
15
|
+
expect(languages).not_to be_empty
|
|
16
|
+
expect(languages).to all(be_a(DeepL::Resources::Language))
|
|
17
|
+
expect(languages.first).to respond_to(:code, :name)
|
|
18
|
+
|
|
19
|
+
codes = languages.map(&:code)
|
|
20
|
+
expect(codes).to include('EN', 'DE')
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe 'target languages' do
|
|
25
|
+
it 'returns target entries that include both formality-supporting and non-supporting members' do
|
|
26
|
+
languages = DeepL.languages(type: :target)
|
|
27
|
+
|
|
28
|
+
expect(languages).to be_an(Array)
|
|
29
|
+
expect(languages).not_to be_empty
|
|
30
|
+
expect(languages).to all(be_a(DeepL::Resources::Language))
|
|
31
|
+
|
|
32
|
+
formalities = languages.map(&:supports_formality?)
|
|
33
|
+
expect(formalities).to include(true)
|
|
34
|
+
expect(formalities).to include(false)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'raises NotSupported when supports_formality? is called on a source-language entry' do
|
|
38
|
+
source_languages = DeepL.languages
|
|
39
|
+
|
|
40
|
+
expect { source_languages.first.supports_formality? }
|
|
41
|
+
.to raise_error(DeepL::Exceptions::NotSupported)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe 'source vs target counts' do
|
|
46
|
+
it 'returns sensible (>20) counts for both source and target listings' do
|
|
47
|
+
source_languages = DeepL.languages
|
|
48
|
+
target_languages = DeepL.languages(type: :target)
|
|
49
|
+
|
|
50
|
+
expect(source_languages.size).to be > 20
|
|
51
|
+
expect(target_languages.size).to be > 20
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Copyright 2026 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.languages error paths' do # rubocop:disable RSpec/DescribeClass
|
|
9
|
+
include_context 'with a live mock server'
|
|
10
|
+
|
|
11
|
+
describe 'authorization failures' do
|
|
12
|
+
it 'raises AuthorizationFailed when the auth key is invalid' do
|
|
13
|
+
request = DeepL::Requests::Languages.new(unauthorized_api)
|
|
14
|
+
|
|
15
|
+
expect { request.request }.to raise_error(DeepL::Exceptions::AuthorizationFailed)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe 'bad request errors' do
|
|
20
|
+
it 'raises BadRequest for an unsupported languages type' do
|
|
21
|
+
expect { DeepL.languages(type: :invalid) }
|
|
22
|
+
.to raise_error(DeepL::Exceptions::BadRequest)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Copyright 2026 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.rephrase' do # rubocop:disable RSpec/DescribeClass
|
|
9
|
+
describe 'happy path' do
|
|
10
|
+
it 'rephrases an English sentence into English and returns a Text resource' do
|
|
11
|
+
result = DeepL.rephrase('As Gregor Samsa awoke one morning he found himself transformed.',
|
|
12
|
+
'en')
|
|
13
|
+
|
|
14
|
+
expect(result).to be_a(DeepL::Resources::Text)
|
|
15
|
+
expect(result.text).to be_a(String)
|
|
16
|
+
expect(result.text).not_to be_empty
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe 'error path' do
|
|
21
|
+
it 'raises a bad request error for an invalid writing_style value' do
|
|
22
|
+
expect do
|
|
23
|
+
DeepL.rephrase('As Gregor Samsa awoke one morning he found himself transformed.',
|
|
24
|
+
'en', 'totally_invalid_style')
|
|
25
|
+
end.to raise_error(DeepL::Exceptions::BadRequest)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe 'edge case' do
|
|
30
|
+
it 'rephrases with a writing_style option applied' do
|
|
31
|
+
result = DeepL.rephrase('As Gregor Samsa awoke one morning he found himself transformed.',
|
|
32
|
+
'en', 'business')
|
|
33
|
+
|
|
34
|
+
expect(result).to be_a(DeepL::Resources::Text)
|
|
35
|
+
expect(result.text).to be_a(String)
|
|
36
|
+
expect(result.text).not_to be_empty
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'rephrases with a tone option applied' do
|
|
40
|
+
result = DeepL.rephrase('As Gregor Samsa awoke one morning he found himself transformed.',
|
|
41
|
+
'en', nil, 'friendly')
|
|
42
|
+
|
|
43
|
+
expect(result).to be_a(DeepL::Resources::Text)
|
|
44
|
+
expect(result.text).to be_a(String)
|
|
45
|
+
expect(result.text).not_to be_empty
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'rephrases an array of texts with a tone applied' do
|
|
49
|
+
texts = [
|
|
50
|
+
'As Gregor Samsa awoke one morning he found himself transformed.',
|
|
51
|
+
'He lay on his armour-like back, and if he lifted his head a little.'
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
results = DeepL.rephrase(texts, 'en', nil, 'friendly')
|
|
55
|
+
|
|
56
|
+
expect(results).to be_an(Array)
|
|
57
|
+
expect(results.size).to eq(2)
|
|
58
|
+
expect(results).to all(be_a(DeepL::Resources::Text))
|
|
59
|
+
expect(results.map(&:text)).to all(be_a(String).and(satisfy { |t| !t.empty? }))
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'rephrases an array of texts with a writing_style applied' do
|
|
63
|
+
texts = [
|
|
64
|
+
'As Gregor Samsa awoke one morning he found himself transformed.',
|
|
65
|
+
'He lay on his armour-like back, and if he lifted his head a little.'
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
results = DeepL.rephrase(texts, 'en', 'business')
|
|
69
|
+
|
|
70
|
+
expect(results).to be_an(Array)
|
|
71
|
+
expect(results.size).to eq(2)
|
|
72
|
+
expect(results).to all(be_a(DeepL::Resources::Text))
|
|
73
|
+
expect(results.map(&:text)).to all(be_a(String).and(satisfy { |t| !t.empty? }))
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it 'rephrases an array of texts and returns an array of Text resources' do
|
|
77
|
+
texts = [
|
|
78
|
+
'As Gregor Samsa awoke one morning he found himself transformed.',
|
|
79
|
+
'He lay on his armour-like back, and if he lifted his head a little.'
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
results = DeepL.rephrase(texts, 'en')
|
|
83
|
+
|
|
84
|
+
expect(results).to be_an(Array)
|
|
85
|
+
expect(results.size).to eq(2)
|
|
86
|
+
expect(results).to all(be_a(DeepL::Resources::Text))
|
|
87
|
+
expect(results.map(&:text)).to all(be_a(String).and(satisfy { |t| !t.empty? }))
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Copyright 2026 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 'spec_helper'
|
|
8
|
+
|
|
9
|
+
describe 'DeepL.rephrase error paths' do # rubocop:disable RSpec/DescribeClass
|
|
10
|
+
include IntegrationTestUtils
|
|
11
|
+
|
|
12
|
+
include_context 'with a live mock server'
|
|
13
|
+
|
|
14
|
+
let(:sample_text) { 'As Gregor Samsa awoke one morning he found himself transformed.' }
|
|
15
|
+
|
|
16
|
+
def rephrase_with_fresh_user(headers)
|
|
17
|
+
fresh_auth_key = "rephrase-err-#{SecureRandom.uuid}"
|
|
18
|
+
config = DeepL::Configuration.new(auth_key: fresh_auth_key)
|
|
19
|
+
config.max_network_retries = 0
|
|
20
|
+
api = DeepL::API.new(config)
|
|
21
|
+
DeepL::Requests::Rephrase.new(api, sample_text, 'en', nil, nil, {}, headers).request
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe 'authorization failures' do
|
|
25
|
+
it 'raises AuthorizationFailed when called with an invalid auth_key' do
|
|
26
|
+
request = DeepL::Requests::Rephrase.new(unauthorized_api, sample_text, 'en')
|
|
27
|
+
|
|
28
|
+
expect { request.request }.to raise_error(DeepL::Exceptions::AuthorizationFailed)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
describe 'bad request errors' do
|
|
33
|
+
it 'raises BadRequest for an unsupported target_lang code' do
|
|
34
|
+
expect do
|
|
35
|
+
DeepL.rephrase(sample_text, 'zzz')
|
|
36
|
+
end.to raise_error(DeepL::Exceptions::BadRequest)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'raises BadRequest when both writing_style and tone are provided' do
|
|
40
|
+
expect do
|
|
41
|
+
DeepL.rephrase(sample_text, 'en', 'business', 'friendly')
|
|
42
|
+
end.to raise_error(DeepL::Exceptions::BadRequest)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
describe 'rate limiting' do
|
|
47
|
+
it 'raises LimitExceeded when the server responds with 429', :mock_server_only do
|
|
48
|
+
expect do
|
|
49
|
+
rephrase_with_fresh_user(respond_with_429_header(1))
|
|
50
|
+
end.to raise_error(DeepL::Exceptions::LimitExceeded)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Copyright 2025 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 'SDK smoke test', :integration do # rubocop:disable RSpec/DescribeClass
|
|
9
|
+
it 'exercises translate, glossaries.list, and usage end-to-end' do # rubocop:disable RSpec/ExampleLength
|
|
10
|
+
source_text = 'Hello, world!'
|
|
11
|
+
result = DeepL.translate(source_text, 'EN', 'DE')
|
|
12
|
+
expect(result).to be_a(DeepL::Resources::Text)
|
|
13
|
+
expect(result.text).to be_a(String)
|
|
14
|
+
expect(result.text).not_to be_empty
|
|
15
|
+
expect(result.text).not_to eq(source_text)
|
|
16
|
+
|
|
17
|
+
glossaries = DeepL.glossaries.list
|
|
18
|
+
expect(glossaries).to be_an(Array)
|
|
19
|
+
|
|
20
|
+
usage = DeepL.usage
|
|
21
|
+
expect(usage).to be_a(DeepL::Resources::Usage)
|
|
22
|
+
expect(usage).to respond_to(:character_count, :character_limit)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -5,21 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
require 'spec_helper'
|
|
7
7
|
|
|
8
|
-
describe DeepL::StyleRuleApi 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
|
-
|
|
8
|
+
describe DeepL::StyleRuleApi, :mock_server_only do
|
|
19
9
|
describe '#translate_with_style_rules' do
|
|
20
10
|
it 'when performing a request with style_id' do
|
|
21
|
-
skip 'Only runs on mock server' if real_server?
|
|
22
|
-
|
|
23
11
|
source_lang = 'DE'
|
|
24
12
|
target_lang = 'EN-US'
|
|
25
13
|
text = 'Hallo, Welt!'
|
|
@@ -30,8 +18,6 @@ describe DeepL::StyleRuleApi do
|
|
|
30
18
|
end
|
|
31
19
|
|
|
32
20
|
it 'when performing a request with style_rule object' do
|
|
33
|
-
skip 'Only runs on mock server' if real_server?
|
|
34
|
-
|
|
35
21
|
source_lang = 'DE'
|
|
36
22
|
target_lang = 'EN-US'
|
|
37
23
|
text = 'Hallo, Welt!'
|
|
@@ -44,7 +30,6 @@ describe DeepL::StyleRuleApi do
|
|
|
44
30
|
|
|
45
31
|
describe '#list_style_rules' do
|
|
46
32
|
it 'when requesting a list of all style rules' do
|
|
47
|
-
skip 'Only runs on mock server' if real_server?
|
|
48
33
|
style_rules = DeepL.style_rules.list(page: 0, page_size: 10, detailed: true)
|
|
49
34
|
expect(style_rules).to be_an(Array)
|
|
50
35
|
expect(style_rules.length).to eq(1)
|
|
@@ -55,7 +40,6 @@ describe DeepL::StyleRuleApi do
|
|
|
55
40
|
end
|
|
56
41
|
|
|
57
42
|
it 'when requesting a list of all style rules without detailed' do
|
|
58
|
-
skip 'Only runs on mock server' if real_server?
|
|
59
43
|
style_rules = DeepL.style_rules.list
|
|
60
44
|
expect(style_rules).to be_an(Array)
|
|
61
45
|
expect(style_rules.length).to eq(1)
|
|
@@ -65,6 +49,60 @@ describe DeepL::StyleRuleApi do
|
|
|
65
49
|
end
|
|
66
50
|
end
|
|
67
51
|
|
|
52
|
+
describe 'style rule management operations' do
|
|
53
|
+
it 'when performing all management operations on style rules' do # rubocop:disable RSpec/ExampleLength,RSpec/MultipleExpectations
|
|
54
|
+
# Create a style rule
|
|
55
|
+
style_rule = DeepL.style_rules.create('Test Style Rule', 'en')
|
|
56
|
+
expect(style_rule).to be_a(DeepL::Resources::StyleRule)
|
|
57
|
+
expect(style_rule.style_id).not_to be_nil
|
|
58
|
+
style_id = style_rule.style_id
|
|
59
|
+
|
|
60
|
+
# Find the style rule
|
|
61
|
+
found_rule = DeepL.style_rules.find(style_id)
|
|
62
|
+
expect(found_rule).to be_a(DeepL::Resources::StyleRule)
|
|
63
|
+
expect(found_rule.style_id).to eq(style_id)
|
|
64
|
+
|
|
65
|
+
# Update the style rule name
|
|
66
|
+
updated_rule = DeepL.style_rules.update_name(style_id, 'Updated Style Rule')
|
|
67
|
+
expect(updated_rule).to be_a(DeepL::Resources::StyleRule)
|
|
68
|
+
|
|
69
|
+
# Update configured rules
|
|
70
|
+
configured_rules = {
|
|
71
|
+
'dates_and_times' => { 'calendar_era' => 'use_bc_and_ad' }
|
|
72
|
+
}
|
|
73
|
+
updated_rule = DeepL.style_rules.update_configured_rules(style_id, configured_rules)
|
|
74
|
+
expect(updated_rule).to be_a(DeepL::Resources::StyleRule)
|
|
75
|
+
|
|
76
|
+
# Create a custom instruction
|
|
77
|
+
custom_instruction = DeepL.style_rules.create_custom_instruction(
|
|
78
|
+
style_id, 'Test Instruction', 'Always use formal language'
|
|
79
|
+
)
|
|
80
|
+
expect(custom_instruction).to be_a(DeepL::Resources::CustomInstruction)
|
|
81
|
+
expect(custom_instruction.id).not_to be_nil
|
|
82
|
+
instruction_id = custom_instruction.id
|
|
83
|
+
|
|
84
|
+
# Find a custom instruction
|
|
85
|
+
fetched_instruction = DeepL.style_rules.find_custom_instruction(style_id, instruction_id)
|
|
86
|
+
expect(fetched_instruction).to be_a(DeepL::Resources::CustomInstruction)
|
|
87
|
+
expect(fetched_instruction.id).to eq(instruction_id)
|
|
88
|
+
|
|
89
|
+
# Update a custom instruction
|
|
90
|
+
updated_instruction = DeepL.style_rules.update_custom_instruction(
|
|
91
|
+
style_id, instruction_id, 'Updated Instruction', 'Use casual language'
|
|
92
|
+
)
|
|
93
|
+
expect(updated_instruction).to be_a(DeepL::Resources::CustomInstruction)
|
|
94
|
+
|
|
95
|
+
# Destroy the custom instruction
|
|
96
|
+
deleted_instruction_id = DeepL.style_rules.destroy_custom_instruction(style_id,
|
|
97
|
+
instruction_id)
|
|
98
|
+
expect(deleted_instruction_id).to eq(instruction_id)
|
|
99
|
+
|
|
100
|
+
# Destroy the style rule
|
|
101
|
+
deleted_style_id = DeepL.style_rules.destroy(style_id)
|
|
102
|
+
expect(deleted_style_id).to eq(style_id)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
68
106
|
def build_test_style_rule
|
|
69
107
|
style_rule_data = {
|
|
70
108
|
'style_id' => 'dca2e053-8ae5-45e6-a0d2-881156e7f4e4',
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Copyright 2026 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.md file.
|
|
4
|
+
# frozen_string_literal: true
|
|
5
|
+
|
|
6
|
+
require 'spec_helper'
|
|
7
|
+
|
|
8
|
+
describe DeepL::StyleRuleApi, :mock_server_only do # rubocop:disable RSpec/SpecFilePathFormat
|
|
9
|
+
include_context 'with a live mock server'
|
|
10
|
+
|
|
11
|
+
let(:missing_uuid) { '00000000-0000-0000-0000-000000000000' }
|
|
12
|
+
|
|
13
|
+
describe 'authorization failures' do
|
|
14
|
+
let(:unauthorized_style_rules) { described_class.new(unauthorized_api) }
|
|
15
|
+
|
|
16
|
+
it 'raises AuthorizationFailed on a read operation (list)' do
|
|
17
|
+
expect { unauthorized_style_rules.list }
|
|
18
|
+
.to raise_error(DeepL::Exceptions::AuthorizationFailed)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'raises AuthorizationFailed on a write operation (create)' do
|
|
22
|
+
expect { unauthorized_style_rules.create('Auth Failure Test', 'en') }
|
|
23
|
+
.to raise_error(DeepL::Exceptions::AuthorizationFailed)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe 'not-found failures' do
|
|
28
|
+
it 'raises NotFound when #find is called with a missing UUID' do
|
|
29
|
+
expect { DeepL.style_rules.find(missing_uuid) }
|
|
30
|
+
.to raise_error(DeepL::Exceptions::NotFound)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe 'bad-request failures' do
|
|
35
|
+
it 'raises BadRequest when create is called with a nil language' do
|
|
36
|
+
expect { DeepL.style_rules.create('Nil Lang', nil) }
|
|
37
|
+
.to raise_error(DeepL::Exceptions::BadRequest)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'raises an error when #destroy is called with a malformed UUID' do
|
|
41
|
+
expect { DeepL.style_rules.destroy('invalid-uuid') }
|
|
42
|
+
.to raise_error(DeepL::Exceptions::Error)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|