deepl-rb 2.2.1 → 2.5.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 (66) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +1 -13
  3. data/.rubocop.yml +8 -4
  4. data/Gemfile +6 -0
  5. data/README.md +133 -25
  6. data/Rakefile +2 -0
  7. data/VERSION +1 -1
  8. data/deepl-rb.gemspec +38 -10
  9. data/lib/deepl/api.rb +2 -0
  10. data/lib/deepl/configuration.rb +4 -2
  11. data/lib/deepl/exceptions/authorization_failed.rb +2 -0
  12. data/lib/deepl/exceptions/bad_request.rb +4 -0
  13. data/lib/deepl/exceptions/error.rb +2 -0
  14. data/lib/deepl/exceptions/limit_exceeded.rb +2 -0
  15. data/lib/deepl/exceptions/not_found.rb +13 -0
  16. data/lib/deepl/exceptions/not_supported.rb +11 -0
  17. data/lib/deepl/exceptions/quota_exceeded.rb +2 -0
  18. data/lib/deepl/exceptions/request_entity_too_large.rb +12 -0
  19. data/lib/deepl/exceptions/request_error.rb +4 -1
  20. data/lib/deepl/glossary_api.rb +35 -0
  21. data/lib/deepl/requests/base.rb +23 -11
  22. data/lib/deepl/requests/glossary/create.rb +45 -0
  23. data/lib/deepl/requests/glossary/destroy.rb +30 -0
  24. data/lib/deepl/requests/glossary/entries.rb +30 -0
  25. data/lib/deepl/requests/glossary/find.rb +31 -0
  26. data/lib/deepl/requests/glossary/language_pairs.rb +31 -0
  27. data/lib/deepl/requests/glossary/list.rb +30 -0
  28. data/lib/deepl/requests/languages.rb +30 -0
  29. data/lib/deepl/requests/translate.rb +8 -2
  30. data/lib/deepl/requests/usage.rb +2 -0
  31. data/lib/deepl/resources/base.rb +2 -0
  32. data/lib/deepl/resources/glossary.rb +25 -0
  33. data/lib/deepl/resources/language.rb +27 -0
  34. data/lib/deepl/resources/language_pair.rb +20 -0
  35. data/lib/deepl/resources/text.rb +2 -0
  36. data/lib/deepl/resources/usage.rb +2 -0
  37. data/lib/deepl/utils/exception_builder.rb +29 -0
  38. data/lib/deepl.rb +28 -0
  39. data/spec/api/api_spec.rb +2 -0
  40. data/spec/api/configuration_spec.rb +4 -2
  41. data/spec/api/deepl_spec.rb +213 -0
  42. data/spec/fixtures/vcr_cassettes/deepl_glossaries.yml +374 -0
  43. data/spec/fixtures/vcr_cassettes/deepl_languages.yml +43 -0
  44. data/spec/fixtures/vcr_cassettes/deepl_translate.yml +215 -5
  45. data/spec/fixtures/vcr_cassettes/deepl_usage.yml +12 -7
  46. data/spec/fixtures/vcr_cassettes/glossaries.yml +480 -0
  47. data/spec/fixtures/vcr_cassettes/languages.yml +114 -0
  48. data/spec/fixtures/vcr_cassettes/translate_texts.yml +199 -33
  49. data/spec/fixtures/vcr_cassettes/usage.yml +12 -7
  50. data/spec/requests/glossary/create_spec.rb +55 -0
  51. data/spec/requests/glossary/destroy_spec.rb +50 -0
  52. data/spec/requests/glossary/entries_spec.rb +48 -0
  53. data/spec/requests/glossary/find_spec.rb +54 -0
  54. data/spec/requests/glossary/language_pairs_spec.rb +30 -0
  55. data/spec/requests/glossary/list_spec.rb +44 -0
  56. data/spec/requests/languages_spec.rb +58 -0
  57. data/spec/requests/translate_spec.rb +139 -4
  58. data/spec/requests/usage_spec.rb +2 -0
  59. data/spec/resources/glossary_spec.rb +35 -0
  60. data/spec/resources/language_pair_spec.rb +20 -0
  61. data/spec/resources/language_spec.rb +42 -0
  62. data/spec/resources/text_spec.rb +4 -2
  63. data/spec/resources/usage_spec.rb +5 -3
  64. data/spec/spec_helper.rb +6 -4
  65. metadata +49 -8
  66. data/Gemfile.lock +0 -113
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeepL
4
+ module Requests
5
+ module Glossary
6
+ class Create < Base
7
+ attr_reader :name, :source_lang, :target_lang, :entries, :entries_format
8
+
9
+ def initialize(api, name, source_lang, target_lang, entries, options = {})
10
+ super(api, options)
11
+ @name = name
12
+ @source_lang = source_lang
13
+ @target_lang = target_lang
14
+ @entries = entries
15
+ @entries_format = delete_option(:entries_format) || 'tsv'
16
+ end
17
+
18
+ def request
19
+ payload = {
20
+ name: name, source_lang: source_lang, target_lang: target_lang, entries: entries_to_tsv,
21
+ entries_format: entries_format
22
+ }
23
+ build_glossary(*post(payload))
24
+ end
25
+
26
+ private
27
+
28
+ def entries_to_tsv
29
+ return entries if entries.is_a?(String)
30
+
31
+ entries.reduce('') { |tsv, entry| "#{tsv}#{entry.first}\t#{entry.last}\n" }
32
+ end
33
+
34
+ def build_glossary(request, response)
35
+ glossary = JSON.parse(response.body)
36
+ Resources::Glossary.new(glossary, request, response)
37
+ end
38
+
39
+ def path
40
+ 'glossaries'
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeepL
4
+ module Requests
5
+ module Glossary
6
+ class Destroy < Base
7
+ attr_reader :id
8
+
9
+ def initialize(api, id, options = {})
10
+ super(api, options)
11
+ @id = id
12
+ end
13
+
14
+ def request
15
+ build_response(*delete)
16
+ end
17
+
18
+ private
19
+
20
+ def build_response(_, _)
21
+ id
22
+ end
23
+
24
+ def path
25
+ "glossaries/#{id}"
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeepL
4
+ module Requests
5
+ module Glossary
6
+ class Entries < Base
7
+ attr_reader :id
8
+
9
+ def initialize(api, id, options = {})
10
+ super(api, options)
11
+ @id = id
12
+ end
13
+
14
+ def request
15
+ build_entries(*get)
16
+ end
17
+
18
+ private
19
+
20
+ def build_entries(_, response)
21
+ response.body.split("\n").map { |entry| entry.split("\t") }
22
+ end
23
+
24
+ def path
25
+ "glossaries/#{id}/entries"
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeepL
4
+ module Requests
5
+ module Glossary
6
+ class Find < Base
7
+ attr_reader :id
8
+
9
+ def initialize(api, id, options = {})
10
+ super(api, options)
11
+ @id = id
12
+ end
13
+
14
+ def request
15
+ build_glossary(*get)
16
+ end
17
+
18
+ private
19
+
20
+ def build_glossary(request, response)
21
+ glossary = JSON.parse(response.body)
22
+ Resources::Glossary.new(glossary, request, response)
23
+ end
24
+
25
+ def path
26
+ "glossaries/#{id}"
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeepL
4
+ module Requests
5
+ module Glossary
6
+ class LanguagePairs < Base
7
+ def initialize(api, options = {})
8
+ super(api, options)
9
+ end
10
+
11
+ def request
12
+ build_language_pair_list(*get)
13
+ end
14
+
15
+ private
16
+
17
+ def build_language_pair_list(request, response)
18
+ data = JSON.parse(response.body)
19
+ data['supported_languages'].map do |language_pair|
20
+ Resources::LanguagePair.new(language_pair['source_lang'], language_pair['target_lang'],
21
+ request, response)
22
+ end
23
+ end
24
+
25
+ def path
26
+ 'glossary-language-pairs'
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeepL
4
+ module Requests
5
+ module Glossary
6
+ class List < Base
7
+ def initialize(api, options = {})
8
+ super(api, options)
9
+ end
10
+
11
+ def request
12
+ build_glossary_list(*get)
13
+ end
14
+
15
+ private
16
+
17
+ def build_glossary_list(request, response)
18
+ data = JSON.parse(response.body)
19
+ data['glossaries'].map do |glossary|
20
+ Resources::Glossary.new(glossary, request, response)
21
+ end
22
+ end
23
+
24
+ def path
25
+ 'glossaries'
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeepL
4
+ module Requests
5
+ class Languages < Base
6
+ def initialize(api, options = {})
7
+ super(api, options)
8
+ end
9
+
10
+ def request
11
+ build_languages(*get)
12
+ end
13
+
14
+ private
15
+
16
+ def build_languages(request, response)
17
+ data = JSON.parse(response.body)
18
+ data.map do |language|
19
+ Resources::Language.new(language['language'], language['name'],
20
+ language['supports_formality'],
21
+ request, response)
22
+ end
23
+ end
24
+
25
+ def path
26
+ 'languages'
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,16 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepL
2
4
  module Requests
3
5
  class Translate < Base
4
6
  BOOLEAN_CONVERSION = { true => '1', false => '0' }.freeze
5
- ARRAY_CONVERSION = ->(value) { value.is_a?(Array) ? value.join(', ') : value }.freeze
7
+ ARRAY_CONVERSION = ->(value) { value.is_a?(Array) ? value.join(',') : value }.freeze
6
8
  OPTIONS_CONVERSIONS = {
7
9
  split_sentences: BOOLEAN_CONVERSION,
8
10
  preserve_formatting: BOOLEAN_CONVERSION,
11
+ outline_detection: BOOLEAN_CONVERSION,
12
+ splitting_tags: ARRAY_CONVERSION,
9
13
  non_splitting_tags: ARRAY_CONVERSION,
10
14
  ignore_tags: ARRAY_CONVERSION
11
15
  }.freeze
12
16
 
13
- attr_reader :text, :source_lang, :target_lang, :ignore_tags, :non_splitting_tags
17
+ attr_reader :text, :source_lang, :target_lang, :ignore_tags, :splitting_tags,
18
+ :non_splitting_tags
14
19
 
15
20
  def initialize(api, text, source_lang, target_lang, options = {})
16
21
  super(api, options)
@@ -31,6 +36,7 @@ module DeepL
31
36
  def tweak_parameters!
32
37
  OPTIONS_CONVERSIONS.each do |param, converter|
33
38
  next unless option?(param) && converter[option(param)]
39
+
34
40
  set_option(param, converter[option(param)])
35
41
  end
36
42
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepL
2
4
  module Requests
3
5
  class Usage < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepL
2
4
  module Resources
3
5
  class Base
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeepL
4
+ module Resources
5
+ class Glossary < Base
6
+ attr_reader :id, :name, :ready, :source_lang, :target_lang, :creation_time, :entry_count
7
+
8
+ def initialize(glossary, *args)
9
+ super(*args)
10
+
11
+ @id = glossary['glossary_id']
12
+ @name = glossary['name']
13
+ @ready = glossary['ready']
14
+ @source_lang = glossary['source_lang']
15
+ @target_lang = glossary['target_lang']
16
+ @creation_time = glossary['creation_time']
17
+ @entry_count = glossary['entry_count']
18
+ end
19
+
20
+ def to_s
21
+ "#{id} - #{name}"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeepL
4
+ module Resources
5
+ class Language < Base
6
+ attr_reader :code, :name
7
+
8
+ def initialize(code, name, supports_formality, *args)
9
+ super(*args)
10
+
11
+ @code = code
12
+ @name = name
13
+ @supports_formality = supports_formality
14
+ end
15
+
16
+ def to_s
17
+ "#{code} - #{name}"
18
+ end
19
+
20
+ def supports_formality?
21
+ return @supports_formality unless @supports_formality.nil?
22
+
23
+ raise Exceptions::NotSupported, 'Support formality is only available on target languages'
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeepL
4
+ module Resources
5
+ class LanguagePair < Base
6
+ attr_reader :source_lang, :target_lang
7
+
8
+ def initialize(source_lang, target_lang, *args)
9
+ super(*args)
10
+
11
+ @source_lang = source_lang
12
+ @target_lang = target_lang
13
+ end
14
+
15
+ def to_s
16
+ "#{source_lang} - #{target_lang}"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepL
2
4
  module Resources
3
5
  class Text < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepL
2
4
  module Resources
3
5
  class Usage < Base
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeepL
4
+ module Utils
5
+ class ExceptionBuilder
6
+ attr_reader :request, :response
7
+
8
+ ERROR_CODE_CLASS_MAP = {
9
+ '400' => Exceptions::BadRequest,
10
+ '401' => Exceptions::AuthorizationFailed,
11
+ '403' => Exceptions::AuthorizationFailed,
12
+ '404' => Exceptions::NotFound,
13
+ '413' => Exceptions::RequestEntityTooLarge,
14
+ '429' => Exceptions::LimitExceeded,
15
+ '456' => Exceptions::QuotaExceeded
16
+ }.freeze
17
+
18
+ def initialize(request, response)
19
+ @request = request
20
+ @response = response
21
+ end
22
+
23
+ def build
24
+ error_class = ERROR_CODE_CLASS_MAP[response.code.to_s] || Exceptions::RequestError
25
+ error_class.new(request, response)
26
+ end
27
+ end
28
+ end
29
+ end
data/lib/deepl.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # -- Dependencies
2
4
  require 'json'
3
5
  require 'net/http'
@@ -9,20 +11,37 @@ require 'deepl/exceptions/authorization_failed'
9
11
  require 'deepl/exceptions/bad_request'
10
12
  require 'deepl/exceptions/limit_exceeded'
11
13
  require 'deepl/exceptions/quota_exceeded'
14
+ require 'deepl/exceptions/not_found'
15
+ require 'deepl/exceptions/not_supported'
16
+ require 'deepl/exceptions/request_entity_too_large'
12
17
 
13
18
  # -- Requests
14
19
  require 'deepl/requests/base'
20
+ require 'deepl/requests/glossary/create'
21
+ require 'deepl/requests/glossary/destroy'
22
+ require 'deepl/requests/glossary/entries'
23
+ require 'deepl/requests/glossary/find'
24
+ require 'deepl/requests/glossary/language_pairs'
25
+ require 'deepl/requests/glossary/list'
26
+ require 'deepl/requests/languages'
15
27
  require 'deepl/requests/translate'
16
28
  require 'deepl/requests/usage'
17
29
 
18
30
  # -- Responses and resources
19
31
  require 'deepl/resources/base'
32
+ require 'deepl/resources/glossary'
33
+ require 'deepl/resources/language'
34
+ require 'deepl/resources/language_pair'
20
35
  require 'deepl/resources/text'
21
36
  require 'deepl/resources/usage'
22
37
 
38
+ # -- Utils
39
+ require 'deepl/utils/exception_builder'
40
+
23
41
  # -- Other wrappers
24
42
  require 'deepl/api'
25
43
  require 'deepl/configuration'
44
+ require 'deepl/glossary_api'
26
45
 
27
46
  # -- Gem interface
28
47
  module DeepL
@@ -34,11 +53,20 @@ module DeepL
34
53
  @api ||= API.new(configuration)
35
54
  end
36
55
 
56
+ def languages(options = {})
57
+ Requests::Languages.new(api, options).request
58
+ end
59
+
37
60
  def translate(text, source_lang, target_lang, options = {})
38
61
  configure if @configuration.nil?
39
62
  Requests::Translate.new(api, text, source_lang, target_lang, options).request
40
63
  end
41
64
 
65
+ def glossaries(options = {})
66
+ configure if @configuration.nil?
67
+ GlossaryApi.new(api, options)
68
+ end
69
+
42
70
  def usage(options = {})
43
71
  configure if @configuration.nil?
44
72
  Requests::Usage.new(api, options).request
data/spec/api/api_spec.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe DeepL::API do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe DeepL::Configuration do
@@ -7,14 +9,14 @@ describe DeepL::Configuration do
7
9
  describe '#initialize' do
8
10
  context 'When using default configuration attributes' do
9
11
  it 'should use default attributes' do
10
- expect(subject.auth_key).to eq(ENV['DEEPL_AUTH_KEY'])
12
+ expect(subject.auth_key).to eq(ENV.fetch('DEEPL_AUTH_KEY', nil))
11
13
  expect(subject.host).to eq('https://api.deepl.com')
12
14
  expect(subject.version).to eq('v2')
13
15
  end
14
16
  end
15
17
 
16
18
  context 'When using custom configuration attributes' do
17
- let(:attributes) { { auth_key: 'SAMPLE', host: 'http://www.example.org', version: 'v1' } }
19
+ let(:attributes) { { auth_key: 'SAMPLE', host: 'https://api-free.deepl.com', version: 'v1' } }
18
20
 
19
21
  it 'should use custom attributes' do
20
22
  expect(subject.auth_key).to eq(attributes[:auth_key])