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.
@@ -0,0 +1,10 @@
1
+ module DeepL
2
+ class API
3
+ attr_reader :configuration
4
+
5
+ def initialize(configuration)
6
+ @configuration = configuration
7
+ configuration.validate!
8
+ end
9
+ end
10
+ end
@@ -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,9 @@
1
+ module DeepL
2
+ module Exceptions
3
+ class AuthorizationFailed < RequestError
4
+ def message
5
+ 'Authorization failed. Please supply a valid auth_key parameter.'
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module DeepL
2
+ module Exceptions
3
+ class BadRequest < RequestError
4
+ def message
5
+ JSON.parse(response.body)['message']
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ module DeepL
2
+ module Exceptions
3
+ class Error < StandardError
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ module DeepL
2
+ module Exceptions
3
+ class LimitExceeded < RequestError
4
+ def message
5
+ 'Limit exceeded. Please wait and send your request once again.'
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ module DeepL
2
+ module Exceptions
3
+ class RequestError < Error
4
+ attr_reader :request, :response
5
+
6
+ def initialize(request, response)
7
+ @request = request
8
+ @response = response
9
+ end
10
+
11
+ def message
12
+ 'Unkown error.'
13
+ end
14
+ end
15
+ end
16
+ 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,12 @@
1
+ module DeepL
2
+ module Resources
3
+ class Base
4
+ attr_reader :request, :response
5
+
6
+ def initialize(request, response)
7
+ @request = request
8
+ @response = response
9
+ end
10
+ end
11
+ end
12
+ 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