deepl-rb 0.0.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/.circleci/config.yml +39 -0
- data/.rubocop.yml +17 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +113 -0
- data/LICENSE.md +25 -0
- data/README.md +102 -0
- data/Rakefile +43 -0
- data/VERSION +1 -0
- data/deepl-rb.gemspec +69 -0
- data/lib/deepl.rb +56 -0
- data/lib/deepl/api.rb +10 -0
- data/lib/deepl/configuration.rb +25 -0
- data/lib/deepl/exceptions/authorization_failed.rb +9 -0
- data/lib/deepl/exceptions/bad_request.rb +9 -0
- data/lib/deepl/exceptions/error.rb +6 -0
- data/lib/deepl/exceptions/limit_exceeded.rb +9 -0
- data/lib/deepl/exceptions/request_error.rb +16 -0
- data/lib/deepl/requests/base.rb +72 -0
- data/lib/deepl/requests/translate_text.rb +36 -0
- data/lib/deepl/resources/base.rb +12 -0
- data/lib/deepl/resources/text.rb +18 -0
- data/spec/api/api_spec.rb +14 -0
- data/spec/api/configuration_spec.rb +44 -0
- data/spec/api/deepl_spec.rb +59 -0
- data/spec/fixtures/vcr_cassettes/deepl_translate.yml +110 -0
- data/spec/fixtures/vcr_cassettes/translate_texts.yml +177 -0
- data/spec/requests/translate_text_spec.rb +80 -0
- data/spec/resources/text_spec.rb +18 -0
- data/spec/spec_helper.rb +22 -0
- metadata +89 -0
data/lib/deepl/api.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module DeepL
|
2
|
+
class Configuration
|
3
|
+
ATTRIBUTES = %i[auth_key host].freeze
|
4
|
+
|
5
|
+
attr_accessor(*ATTRIBUTES)
|
6
|
+
|
7
|
+
def initialize(data = {})
|
8
|
+
data.each { |key, value| send("#{key}=", value) }
|
9
|
+
@auth_key ||= ENV['DEEPL_AUTH_KEY']
|
10
|
+
@host ||= 'https://api.deepl.com'
|
11
|
+
end
|
12
|
+
|
13
|
+
def validate!
|
14
|
+
raise Exceptions::Error, 'auth_key not provided' if auth_key.nil? || auth_key.empty?
|
15
|
+
end
|
16
|
+
|
17
|
+
def attributes
|
18
|
+
ATTRIBUTES.map { |attr| [attr, send(attr)] }.to_h
|
19
|
+
end
|
20
|
+
|
21
|
+
def ==(other)
|
22
|
+
attributes == other.attributes
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module DeepL
|
2
|
+
module Requests
|
3
|
+
class Base
|
4
|
+
API_VERSION = 'v1'.freeze
|
5
|
+
|
6
|
+
attr_reader :api, :response
|
7
|
+
|
8
|
+
def initialize(api)
|
9
|
+
@api = api
|
10
|
+
end
|
11
|
+
|
12
|
+
def request
|
13
|
+
raise NotImplementedError
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def post(payload)
|
19
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
20
|
+
request.set_form_data(payload.compact)
|
21
|
+
response = http.request(request)
|
22
|
+
|
23
|
+
validate_response!(request, response)
|
24
|
+
[request, response]
|
25
|
+
end
|
26
|
+
|
27
|
+
def http
|
28
|
+
@http ||= begin
|
29
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
30
|
+
http.use_ssl = uri.scheme == 'https'
|
31
|
+
http
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def validate_response!(request, response)
|
36
|
+
return if response.is_a?(Net::HTTPSuccess)
|
37
|
+
|
38
|
+
case response.code
|
39
|
+
when '400' then raise Exceptions::BadRequest.new(request, response)
|
40
|
+
when '403' then raise Exceptions::AuthorizationFailed.new(request, response)
|
41
|
+
when '429' then raise Exceptions::LimitExceeded.new(request, response)
|
42
|
+
else raise Exceptions::RequestError.new(request, response)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def path
|
47
|
+
raise NotImplementedError
|
48
|
+
end
|
49
|
+
|
50
|
+
def url
|
51
|
+
"#{host}/#{API_VERSION}/#{path}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def uri
|
55
|
+
@uri ||= begin
|
56
|
+
uri = URI(url)
|
57
|
+
new_query = URI.decode_www_form(uri.query || '') + query_params.to_a
|
58
|
+
uri.query = URI.encode_www_form(new_query)
|
59
|
+
uri
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def host
|
64
|
+
api.configuration.host
|
65
|
+
end
|
66
|
+
|
67
|
+
def query_params
|
68
|
+
{ auth_key: api.configuration.auth_key }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module DeepL
|
2
|
+
module Requests
|
3
|
+
class TranslateText < Base
|
4
|
+
attr_reader :text, :source_lang, :target_lang
|
5
|
+
|
6
|
+
def initialize(api, text, source_lang, target_lang)
|
7
|
+
super(api)
|
8
|
+
@text = text
|
9
|
+
@source_lang = source_lang
|
10
|
+
@target_lang = target_lang
|
11
|
+
end
|
12
|
+
|
13
|
+
def request
|
14
|
+
payload = { text: text, source_lang: source_lang, target_lang: target_lang }
|
15
|
+
build_texts(*post(payload))
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def build_texts(request, response)
|
21
|
+
data = JSON.parse(response.body)
|
22
|
+
|
23
|
+
texts = data['translations'].map do |translation|
|
24
|
+
Resources::Text.new(translation['text'], translation['detected_source_language'],
|
25
|
+
request, response)
|
26
|
+
end
|
27
|
+
|
28
|
+
texts.size == 1 ? texts.first : texts
|
29
|
+
end
|
30
|
+
|
31
|
+
def path
|
32
|
+
'translate'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module DeepL
|
2
|
+
module Resources
|
3
|
+
class Text < Base
|
4
|
+
attr_reader :text, :detected_source_language
|
5
|
+
|
6
|
+
def initialize(text, detected_source_language, *args)
|
7
|
+
super(*args)
|
8
|
+
|
9
|
+
@text = text
|
10
|
+
@detected_source_language = detected_source_language
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
text
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DeepL::API do
|
4
|
+
let(:configuration) { DeepL::Configuration.new }
|
5
|
+
subject { DeepL::API.new(configuration) }
|
6
|
+
|
7
|
+
describe '#initialize' do
|
8
|
+
context 'When building an API object' do
|
9
|
+
it 'should save the configuration' do
|
10
|
+
expect(subject.configuration).to be(configuration)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DeepL::Configuration do
|
4
|
+
let(:attributes) { {} }
|
5
|
+
subject { DeepL::Configuration.new(attributes) }
|
6
|
+
|
7
|
+
describe '#initialize' do
|
8
|
+
context 'When using default configuration attributes' do
|
9
|
+
it 'should use default attributes' do
|
10
|
+
expect(subject.auth_key).to eq(ENV['DEEPL_AUTH_KEY'])
|
11
|
+
expect(subject.host).to eq('https://api.deepl.com')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'When using custom configuration attributes' do
|
16
|
+
let(:attributes) { { auth_key: 'SAMPLE', host: 'http://www.example.org' } }
|
17
|
+
|
18
|
+
it 'should use custom attributes' do
|
19
|
+
expect(subject.auth_key).to eq(attributes[:auth_key])
|
20
|
+
expect(subject.host).to eq(attributes[:host])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#validate!' do
|
26
|
+
let(:auth_message) { 'auth_key not provided' }
|
27
|
+
|
28
|
+
context 'When providing a valid auth key' do
|
29
|
+
let(:attributes) { { auth_key: '' } }
|
30
|
+
|
31
|
+
it 'should raise an error' do
|
32
|
+
expect { subject.validate! }.to raise_error(DeepL::Exceptions::Error, auth_message)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'When providing an invalid auth key' do
|
37
|
+
let(:attributes) { { auth_key: 'not-empty' } }
|
38
|
+
|
39
|
+
it 'should not raise an error' do
|
40
|
+
expect { subject.validate! }.not_to raise_error
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DeepL do
|
4
|
+
subject { DeepL.dup }
|
5
|
+
|
6
|
+
describe '#configure' do
|
7
|
+
context 'When providing no block' do
|
8
|
+
let(:configuration) { DeepL::Configuration.new }
|
9
|
+
before { subject.configure }
|
10
|
+
|
11
|
+
it 'should use default configuration' do
|
12
|
+
expect(subject.configuration).to eq(configuration)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'When providing a valid configuration' do
|
17
|
+
let(:configuration) do
|
18
|
+
DeepL::Configuration.new(auth_key: 'VALID', host: 'http://www.example.org')
|
19
|
+
end
|
20
|
+
before do
|
21
|
+
subject.configure do |config|
|
22
|
+
config.auth_key = configuration.auth_key
|
23
|
+
config.host = configuration.host
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should use the provided configuration' do
|
28
|
+
expect(subject.configuration).to eq(configuration)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'When providing an invalid configuration' do
|
33
|
+
it 'should raise an error' do
|
34
|
+
expect { subject.configure { |c| c.auth_key = '' } }
|
35
|
+
.to raise_error(DeepL::Exceptions::Error)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#translate' do
|
41
|
+
let(:input) { 'Sample' }
|
42
|
+
let(:source_lang) { 'EN' }
|
43
|
+
let(:target_lang) { 'ES' }
|
44
|
+
|
45
|
+
around do |example|
|
46
|
+
VCR.use_cassette('deepl_translate') { example.call }
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'When translating a text' do
|
50
|
+
it 'should create and call a request object' do
|
51
|
+
expect(DeepL::Requests::TranslateText).to receive(:new)
|
52
|
+
.with(subject.api, input, source_lang, target_lang).and_call_original
|
53
|
+
|
54
|
+
text = subject.translate(input, source_lang: source_lang, target_lang: target_lang)
|
55
|
+
expect(text).to be_a(DeepL::Resources::Text)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://api.deepl.com/v1/translate?auth_key=VALID_TOKEN
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: source_lang=EN&target_lang=ES
|
9
|
+
headers:
|
10
|
+
Accept-Encoding:
|
11
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
12
|
+
Accept:
|
13
|
+
- "*/*"
|
14
|
+
User-Agent:
|
15
|
+
- Ruby
|
16
|
+
Content-Type:
|
17
|
+
- application/x-www-form-urlencoded
|
18
|
+
response:
|
19
|
+
status:
|
20
|
+
code: 400
|
21
|
+
message: Bad Request
|
22
|
+
headers:
|
23
|
+
Server:
|
24
|
+
- nginx
|
25
|
+
Date:
|
26
|
+
- Sun, 10 Dec 2017 21:20:25 GMT
|
27
|
+
Content-Length:
|
28
|
+
- '45'
|
29
|
+
Connection:
|
30
|
+
- keep-alive
|
31
|
+
body:
|
32
|
+
encoding: UTF-8
|
33
|
+
string: '{"message":"Parameter ''text'' not specified."}'
|
34
|
+
http_version:
|
35
|
+
recorded_at: Sun, 10 Dec 2017 21:20:25 GMT
|
36
|
+
- request:
|
37
|
+
method: post
|
38
|
+
uri: https://api.deepl.com/v1/translate?auth_key=VALID_TOKEN
|
39
|
+
body:
|
40
|
+
encoding: US-ASCII
|
41
|
+
string: text=Abc&source_lang=EN&target_lang=ES
|
42
|
+
headers:
|
43
|
+
Accept-Encoding:
|
44
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
45
|
+
Accept:
|
46
|
+
- "*/*"
|
47
|
+
User-Agent:
|
48
|
+
- Ruby
|
49
|
+
Content-Type:
|
50
|
+
- application/x-www-form-urlencoded
|
51
|
+
response:
|
52
|
+
status:
|
53
|
+
code: 200
|
54
|
+
message: OK
|
55
|
+
headers:
|
56
|
+
Server:
|
57
|
+
- nginx
|
58
|
+
Date:
|
59
|
+
- Sun, 10 Dec 2017 21:21:23 GMT
|
60
|
+
Content-Type:
|
61
|
+
- application/json
|
62
|
+
Content-Length:
|
63
|
+
- '65'
|
64
|
+
Connection:
|
65
|
+
- keep-alive
|
66
|
+
Access-Control-Allow-Origin:
|
67
|
+
- "*"
|
68
|
+
body:
|
69
|
+
encoding: UTF-8
|
70
|
+
string: '{"translations":[{"detected_source_language":"EN","text":"ABC"}]}'
|
71
|
+
http_version:
|
72
|
+
recorded_at: Sun, 10 Dec 2017 21:21:23 GMT
|
73
|
+
- request:
|
74
|
+
method: post
|
75
|
+
uri: https://api.deepl.com/v1/translate?auth_key=VALID_TOKEN
|
76
|
+
body:
|
77
|
+
encoding: US-ASCII
|
78
|
+
string: text=Sample&source_lang=EN&target_lang=ES
|
79
|
+
headers:
|
80
|
+
Accept-Encoding:
|
81
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
82
|
+
Accept:
|
83
|
+
- "*/*"
|
84
|
+
User-Agent:
|
85
|
+
- Ruby
|
86
|
+
Content-Type:
|
87
|
+
- application/x-www-form-urlencoded
|
88
|
+
response:
|
89
|
+
status:
|
90
|
+
code: 200
|
91
|
+
message: OK
|
92
|
+
headers:
|
93
|
+
Server:
|
94
|
+
- nginx
|
95
|
+
Date:
|
96
|
+
- Sun, 10 Dec 2017 21:22:11 GMT
|
97
|
+
Content-Type:
|
98
|
+
- application/json
|
99
|
+
Content-Length:
|
100
|
+
- '69'
|
101
|
+
Connection:
|
102
|
+
- keep-alive
|
103
|
+
Access-Control-Allow-Origin:
|
104
|
+
- "*"
|
105
|
+
body:
|
106
|
+
encoding: UTF-8
|
107
|
+
string: '{"translations":[{"detected_source_language":"EN","text":"Muestra"}]}'
|
108
|
+
http_version:
|
109
|
+
recorded_at: Sun, 10 Dec 2017 21:22:11 GMT
|
110
|
+
recorded_with: VCR 4.0.0
|