deepl-rb 2.5.3 → 3.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 +4 -4
 - data/.github/workflows/add_issues_to_kanban.yml +16 -0
 - data/.gitlab-ci.yml +135 -0
 - data/.rubocop.yml +27 -0
 - data/CHANGELOG.md +34 -0
 - data/CODE_OF_CONDUCT.md +132 -0
 - data/CONTRIBUTING.md +37 -0
 - data/Gemfile +3 -1
 - data/LICENSE.md +1 -0
 - data/README.md +115 -5
 - data/Rakefile +7 -5
 - data/SECURITY.md +58 -0
 - data/VERSION +1 -1
 - data/deepl-rb.gemspec +36 -20
 - data/lib/deepl/api.rb +11 -1
 - data/lib/deepl/configuration.rb +34 -3
 - data/lib/deepl/document_api.rb +120 -0
 - data/lib/deepl/exceptions/authorization_failed.rb +3 -0
 - data/lib/deepl/exceptions/bad_request.rb +3 -0
 - data/lib/deepl/exceptions/document_translation_error.rb +15 -0
 - data/lib/deepl/exceptions/error.rb +6 -0
 - data/lib/deepl/exceptions/limit_exceeded.rb +7 -0
 - data/lib/deepl/exceptions/not_found.rb +3 -0
 - data/lib/deepl/exceptions/not_supported.rb +3 -0
 - data/lib/deepl/exceptions/quota_exceeded.rb +3 -0
 - data/lib/deepl/exceptions/request_entity_too_large.rb +3 -0
 - data/lib/deepl/exceptions/request_error.rb +4 -2
 - data/lib/deepl/exceptions/server_error.rb +18 -0
 - data/lib/deepl/glossary_api.rb +3 -0
 - data/lib/deepl/requests/base.rb +89 -34
 - data/lib/deepl/requests/document/download.rb +44 -0
 - data/lib/deepl/requests/document/get_status.rb +44 -0
 - data/lib/deepl/requests/document/upload.rb +64 -0
 - data/lib/deepl/requests/glossary/create.rb +15 -1
 - data/lib/deepl/requests/glossary/destroy.rb +8 -1
 - data/lib/deepl/requests/glossary/entries.rb +8 -1
 - data/lib/deepl/requests/glossary/find.rb +8 -1
 - data/lib/deepl/requests/glossary/language_pairs.rb +9 -2
 - data/lib/deepl/requests/glossary/list.rb +9 -2
 - data/lib/deepl/requests/languages.rb +9 -2
 - data/lib/deepl/requests/translate.rb +33 -11
 - data/lib/deepl/requests/usage.rb +9 -2
 - data/lib/deepl/resources/base.rb +3 -0
 - data/lib/deepl/resources/document_handle.rb +57 -0
 - data/lib/deepl/resources/document_translation_status.rb +54 -0
 - data/lib/deepl/resources/glossary.rb +3 -0
 - data/lib/deepl/resources/language.rb +3 -0
 - data/lib/deepl/resources/language_pair.rb +3 -0
 - data/lib/deepl/resources/text.rb +3 -0
 - data/lib/deepl/resources/usage.rb +3 -0
 - data/lib/deepl/utils/backoff_timer.rb +46 -0
 - data/lib/deepl/utils/exception_builder.rb +18 -13
 - data/lib/deepl.rb +47 -0
 - data/lib/http_client_options.rb +22 -0
 - data/license_checker.sh +8 -0
 - data/spec/api/api_spec.rb +8 -4
 - data/spec/api/configuration_spec.rb +92 -18
 - data/spec/api/deepl_spec.rb +225 -86
 - data/spec/fixtures/vcr_cassettes/deepl_document.yml +95 -0
 - data/spec/fixtures/vcr_cassettes/deepl_document_download.yml +1214 -0
 - data/spec/fixtures/vcr_cassettes/deepl_glossaries.yml +812 -23
 - data/spec/fixtures/vcr_cassettes/deepl_languages.yml +28 -17
 - data/spec/fixtures/vcr_cassettes/deepl_translate.yml +161 -53
 - data/spec/fixtures/vcr_cassettes/deepl_usage.yml +93 -3
 - data/spec/fixtures/vcr_cassettes/glossaries.yml +1237 -15
 - data/spec/fixtures/vcr_cassettes/languages.yml +159 -44
 - data/spec/fixtures/vcr_cassettes/translate_texts.yml +9742 -12
 - data/spec/fixtures/vcr_cassettes/usage.yml +134 -2
 - data/spec/integration_tests/document_api_spec.rb +143 -0
 - data/spec/integration_tests/integration_test_utils.rb +170 -0
 - data/spec/requests/glossary/create_spec.rb +23 -13
 - data/spec/requests/glossary/destroy_spec.rb +33 -17
 - data/spec/requests/glossary/entries_spec.rb +31 -17
 - data/spec/requests/glossary/find_spec.rb +31 -17
 - data/spec/requests/glossary/language_pairs_spec.rb +17 -7
 - data/spec/requests/glossary/list_spec.rb +21 -11
 - data/spec/requests/languages_spec.rb +31 -21
 - data/spec/requests/translate_spec.rb +125 -131
 - data/spec/requests/usage_spec.rb +17 -7
 - data/spec/resources/glossary_spec.rb +15 -12
 - data/spec/resources/language_pair_spec.rb +10 -7
 - data/spec/resources/language_spec.rb +21 -18
 - data/spec/resources/text_spec.rb +10 -7
 - data/spec/resources/usage_spec.rb +16 -13
 - data/spec/spec_helper.rb +63 -6
 - metadata +32 -9
 
| 
         @@ -0,0 +1,54 @@ 
     | 
|
| 
      
 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 
     | 
    
         
            +
            module DeepL
         
     | 
| 
      
 7 
     | 
    
         
            +
              module Resources
         
     | 
| 
      
 8 
     | 
    
         
            +
                class DocumentTranslationStatus < Base
         
     | 
| 
      
 9 
     | 
    
         
            +
                  attr_reader :document_id, :status, :seconds_remaining, :billed_characters, :error_message
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  def initialize(response, *args)
         
     | 
| 
      
 12 
     | 
    
         
            +
                    super(*args)
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                    @document_id = response['document_id']
         
     | 
| 
      
 15 
     | 
    
         
            +
                    @status = response['status']
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @seconds_remaining = response['seconds_remaining']
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @billed_characters = response['billed_characters']
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @error_message = response['error_message']
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  def to_s
         
     | 
| 
      
 22 
     | 
    
         
            +
                    "DocumentTranslationStatus: ID: #{document_id} - Status: #{status} " \
         
     | 
| 
      
 23 
     | 
    
         
            +
                      "- Error message: #{error_message}"
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 27 
     | 
    
         
            +
                  # Checks if the translation finished successfully
         
     | 
| 
      
 28 
     | 
    
         
            +
                  #
         
     | 
| 
      
 29 
     | 
    
         
            +
                  # @return [true] if so
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  def successful?
         
     | 
| 
      
 32 
     | 
    
         
            +
                    status == 'done'
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 36 
     | 
    
         
            +
                  # Checks if there was an error during translation
         
     | 
| 
      
 37 
     | 
    
         
            +
                  #
         
     | 
| 
      
 38 
     | 
    
         
            +
                  # @return [true] if so
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  def error?
         
     | 
| 
      
 41 
     | 
    
         
            +
                    status == 'error'
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 45 
     | 
    
         
            +
                  # Checks if the translation process terminated. Note that this could be due to an error as
         
     | 
| 
      
 46 
     | 
    
         
            +
                  # well, but means no further waiting is necessary.
         
     | 
| 
      
 47 
     | 
    
         
            +
                  #
         
     | 
| 
      
 48 
     | 
    
         
            +
                  # @return [true] if so
         
     | 
| 
      
 49 
     | 
    
         
            +
                  def finished?
         
     | 
| 
      
 50 
     | 
    
         
            +
                    successful? || error?
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
              end
         
     | 
| 
      
 54 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/deepl/resources/text.rb
    CHANGED
    
    
| 
         @@ -0,0 +1,46 @@ 
     | 
|
| 
      
 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 
     | 
    
         
            +
            module DeepL
         
     | 
| 
      
 7 
     | 
    
         
            +
              module Utils
         
     | 
| 
      
 8 
     | 
    
         
            +
                class BackoffTimer
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # Implements exponential-backoff strategy.
         
     | 
| 
      
 10 
     | 
    
         
            +
                  # This strategy is based on the GRPC Connection Backoff Protocol:
         
     | 
| 
      
 11 
     | 
    
         
            +
                  # https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  BACKOFF_INITIAL = 1.0
         
     | 
| 
      
 14 
     | 
    
         
            +
                  BACKOFF_MAX = 120.0
         
     | 
| 
      
 15 
     | 
    
         
            +
                  BACKOFF_JITTER = 0.23
         
     | 
| 
      
 16 
     | 
    
         
            +
                  BACKOFF_MULTIPLIER = 1.6
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  attr_reader :num_retries
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  def initialize(min_connection_timeout = 10.0)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    @num_retries = 0
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @backoff = BACKOFF_INITIAL
         
     | 
| 
      
 23 
     | 
    
         
            +
                    @deadline = Time.now.to_f + @backoff
         
     | 
| 
      
 24 
     | 
    
         
            +
                    @min_connection_timeout = min_connection_timeout
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  def current_request_timeout
         
     | 
| 
      
 28 
     | 
    
         
            +
                    [time_until_deadline, @min_connection_timeout].max
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  def time_until_deadline
         
     | 
| 
      
 32 
     | 
    
         
            +
                    [@deadline - Time.now.to_f, 0.0].max
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  def sleep_until_deadline
         
     | 
| 
      
 36 
     | 
    
         
            +
                    sleep(time_until_deadline)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    # Apply multiplier to current backoff time
         
     | 
| 
      
 38 
     | 
    
         
            +
                    @backoff = [@backoff * BACKOFF_MULTIPLIER, BACKOFF_MAX].min
         
     | 
| 
      
 39 
     | 
    
         
            +
                    # Get deadline by applying jitter as a proportion of backoff:
         
     | 
| 
      
 40 
     | 
    
         
            +
                    # if jitter is 0.1, then multiply backoff by random value in [0.9, 1.1]
         
     | 
| 
      
 41 
     | 
    
         
            +
                    @deadline = Time.now.to_f + (@backoff * (1 + (BACKOFF_JITTER * rand(-1.0..1.0))))
         
     | 
| 
      
 42 
     | 
    
         
            +
                    @num_retries += 1
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
              end
         
     | 
| 
      
 46 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,3 +1,6 @@ 
     | 
|
| 
      
 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 
     | 
    
         
             
            module DeepL
         
     | 
| 
         @@ -5,24 +8,26 @@ module DeepL 
     | 
|
| 
       5 
8 
     | 
    
         
             
                class ExceptionBuilder
         
     | 
| 
       6 
9 
     | 
    
         
             
                  attr_reader :request, :response
         
     | 
| 
       7 
10 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
                   
     | 
| 
       9 
     | 
    
         
            -
                     
     | 
| 
       10 
     | 
    
         
            -
                     
     | 
| 
       11 
     | 
    
         
            -
                     
     | 
| 
       12 
     | 
    
         
            -
                     
     | 
| 
       13 
     | 
    
         
            -
                     
     | 
| 
       14 
     | 
    
         
            -
                     
     | 
| 
       15 
     | 
    
         
            -
                     
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
      
 11 
     | 
    
         
            +
                  def self.error_class_from_response_code(code) # rubocop:disable Metrics/CyclomaticComplexity
         
     | 
| 
      
 12 
     | 
    
         
            +
                    case code
         
     | 
| 
      
 13 
     | 
    
         
            +
                    when 400 then Exceptions::BadRequest
         
     | 
| 
      
 14 
     | 
    
         
            +
                    when 401, 403 then Exceptions::AuthorizationFailed
         
     | 
| 
      
 15 
     | 
    
         
            +
                    when 404 then Exceptions::NotFound
         
     | 
| 
      
 16 
     | 
    
         
            +
                    when 413 then Exceptions::RequestEntityTooLarge
         
     | 
| 
      
 17 
     | 
    
         
            +
                    when 429 then Exceptions::LimitExceeded
         
     | 
| 
      
 18 
     | 
    
         
            +
                    when 456 then Exceptions::QuotaExceeded
         
     | 
| 
      
 19 
     | 
    
         
            +
                    when 500..599 then Exceptions::ServerError
         
     | 
| 
      
 20 
     | 
    
         
            +
                    else Exceptions::RequestError
         
     | 
| 
      
 21 
     | 
    
         
            +
                    end
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
       17 
23 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
                  def initialize( 
     | 
| 
       19 
     | 
    
         
            -
                    @request = request
         
     | 
| 
      
 24 
     | 
    
         
            +
                  def initialize(response)
         
     | 
| 
       20 
25 
     | 
    
         
             
                    @response = response
         
     | 
| 
       21 
26 
     | 
    
         
             
                  end
         
     | 
| 
       22 
27 
     | 
    
         | 
| 
       23 
28 
     | 
    
         
             
                  def build
         
     | 
| 
       24 
     | 
    
         
            -
                    error_class =  
     | 
| 
       25 
     | 
    
         
            -
                    error_class.new( 
     | 
| 
      
 29 
     | 
    
         
            +
                    error_class = self.class.error_class_from_response_code(response.code.to_i)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    error_class.new(response)
         
     | 
| 
       26 
31 
     | 
    
         
             
                  end
         
     | 
| 
       27 
32 
     | 
    
         
             
                end
         
     | 
| 
       28 
33 
     | 
    
         
             
              end
         
     | 
    
        data/lib/deepl.rb
    CHANGED
    
    | 
         @@ -1,3 +1,6 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Copyright 2018 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 
     | 
    
         
             
            # -- Dependencies
         
     | 
| 
         @@ -14,9 +17,14 @@ require 'deepl/exceptions/quota_exceeded' 
     | 
|
| 
       14 
17 
     | 
    
         
             
            require 'deepl/exceptions/not_found'
         
     | 
| 
       15 
18 
     | 
    
         
             
            require 'deepl/exceptions/not_supported'
         
     | 
| 
       16 
19 
     | 
    
         
             
            require 'deepl/exceptions/request_entity_too_large'
         
     | 
| 
      
 20 
     | 
    
         
            +
            require 'deepl/exceptions/document_translation_error'
         
     | 
| 
      
 21 
     | 
    
         
            +
            require 'deepl/exceptions/server_error'
         
     | 
| 
       17 
22 
     | 
    
         | 
| 
       18 
23 
     | 
    
         
             
            # -- Requests
         
     | 
| 
       19 
24 
     | 
    
         
             
            require 'deepl/requests/base'
         
     | 
| 
      
 25 
     | 
    
         
            +
            require 'deepl/requests/document/download'
         
     | 
| 
      
 26 
     | 
    
         
            +
            require 'deepl/requests/document/get_status'
         
     | 
| 
      
 27 
     | 
    
         
            +
            require 'deepl/requests/document/upload'
         
     | 
| 
       20 
28 
     | 
    
         
             
            require 'deepl/requests/glossary/create'
         
     | 
| 
       21 
29 
     | 
    
         
             
            require 'deepl/requests/glossary/destroy'
         
     | 
| 
       22 
30 
     | 
    
         
             
            require 'deepl/requests/glossary/entries'
         
     | 
| 
         @@ -29,6 +37,8 @@ require 'deepl/requests/usage' 
     | 
|
| 
       29 
37 
     | 
    
         | 
| 
       30 
38 
     | 
    
         
             
            # -- Responses and resources
         
     | 
| 
       31 
39 
     | 
    
         
             
            require 'deepl/resources/base'
         
     | 
| 
      
 40 
     | 
    
         
            +
            require 'deepl/resources/document_handle'
         
     | 
| 
      
 41 
     | 
    
         
            +
            require 'deepl/resources/document_translation_status'
         
     | 
| 
       32 
42 
     | 
    
         
             
            require 'deepl/resources/glossary'
         
     | 
| 
       33 
43 
     | 
    
         
             
            require 'deepl/resources/language'
         
     | 
| 
       34 
44 
     | 
    
         
             
            require 'deepl/resources/language_pair'
         
     | 
| 
         @@ -37,10 +47,15 @@ require 'deepl/resources/usage' 
     | 
|
| 
       37 
47 
     | 
    
         | 
| 
       38 
48 
     | 
    
         
             
            # -- Utils
         
     | 
| 
       39 
49 
     | 
    
         
             
            require 'deepl/utils/exception_builder'
         
     | 
| 
      
 50 
     | 
    
         
            +
            require 'deepl/utils/backoff_timer'
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
            # -- HTTP Utils
         
     | 
| 
      
 53 
     | 
    
         
            +
            require 'http_client_options'
         
     | 
| 
       40 
54 
     | 
    
         | 
| 
       41 
55 
     | 
    
         
             
            # -- Other wrappers
         
     | 
| 
       42 
56 
     | 
    
         
             
            require 'deepl/api'
         
     | 
| 
       43 
57 
     | 
    
         
             
            require 'deepl/configuration'
         
     | 
| 
      
 58 
     | 
    
         
            +
            require 'deepl/document_api'
         
     | 
| 
       44 
59 
     | 
    
         
             
            require 'deepl/glossary_api'
         
     | 
| 
       45 
60 
     | 
    
         | 
| 
       46 
61 
     | 
    
         
             
            # -- Gem interface
         
     | 
| 
         @@ -62,6 +77,11 @@ module DeepL 
     | 
|
| 
       62 
77 
     | 
    
         
             
                Requests::Translate.new(api, text, source_lang, target_lang, options).request
         
     | 
| 
       63 
78 
     | 
    
         
             
              end
         
     | 
| 
       64 
79 
     | 
    
         | 
| 
      
 80 
     | 
    
         
            +
              def document(options = {})
         
     | 
| 
      
 81 
     | 
    
         
            +
                configure if @configuration.nil?
         
     | 
| 
      
 82 
     | 
    
         
            +
                DocumentApi.new(api, options)
         
     | 
| 
      
 83 
     | 
    
         
            +
              end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
       65 
85 
     | 
    
         
             
              def glossaries(options = {})
         
     | 
| 
       66 
86 
     | 
    
         
             
                configure if @configuration.nil?
         
     | 
| 
       67 
87 
     | 
    
         
             
                GlossaryApi.new(api, options)
         
     | 
| 
         @@ -72,6 +92,33 @@ module DeepL 
     | 
|
| 
       72 
92 
     | 
    
         
             
                Requests::Usage.new(api, options).request
         
     | 
| 
       73 
93 
     | 
    
         
             
              end
         
     | 
| 
       74 
94 
     | 
    
         | 
| 
      
 95 
     | 
    
         
            +
              def http_client
         
     | 
| 
      
 96 
     | 
    
         
            +
                @http_client
         
     | 
| 
      
 97 
     | 
    
         
            +
              end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
              def with_session(client_options = HTTPClientOptions.new()) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
         
     | 
| 
      
 100 
     | 
    
         
            +
                raise ArgumentError 'This method requires a block to be passed in which contains the actual API calls, see README for example usage.' unless block_given? # rubocop:disable Layout/LineLength
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                has_proxy = client_options.proxy.key?('proxy_addr') and client_options.proxy.key?('proxy_port')
         
     | 
| 
      
 103 
     | 
    
         
            +
                begin
         
     | 
| 
      
 104 
     | 
    
         
            +
                  uri = URI(configuration.host)
         
     | 
| 
      
 105 
     | 
    
         
            +
                  http = Net::HTTP.new(uri.host, uri.port, has_proxy ? client_options.proxy['proxy_addr'] : nil,
         
     | 
| 
      
 106 
     | 
    
         
            +
                                       has_proxy ? client_options.proxy['proxy_port'] : nil)
         
     | 
| 
      
 107 
     | 
    
         
            +
                  http.use_ssl = client_options.enable_ssl_verification
         
     | 
| 
      
 108 
     | 
    
         
            +
                  http.ca_file = client_options.cert_path if client_options.cert_path
         
     | 
| 
      
 109 
     | 
    
         
            +
                  http.open_timeout = client_options.open_timeout unless client_options.open_timeout.nil?
         
     | 
| 
      
 110 
     | 
    
         
            +
                  http.read_timeout = client_options.read_timeout unless client_options.read_timeout.nil?
         
     | 
| 
      
 111 
     | 
    
         
            +
                  http.write_timeout = client_options.write_timeout unless client_options.write_timeout.nil?
         
     | 
| 
      
 112 
     | 
    
         
            +
                  http.ssl_timeout = client_options.ssl_timeout unless client_options.ssl_timeout.nil?
         
     | 
| 
      
 113 
     | 
    
         
            +
                  http.start
         
     | 
| 
      
 114 
     | 
    
         
            +
                  @http_client = http
         
     | 
| 
      
 115 
     | 
    
         
            +
                  api.update_http_client(http)
         
     | 
| 
      
 116 
     | 
    
         
            +
                  yield
         
     | 
| 
      
 117 
     | 
    
         
            +
                ensure
         
     | 
| 
      
 118 
     | 
    
         
            +
                  http.finish
         
     | 
| 
      
 119 
     | 
    
         
            +
                end
         
     | 
| 
      
 120 
     | 
    
         
            +
              end
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
       75 
122 
     | 
    
         
             
              # -- Configuration
         
     | 
| 
       76 
123 
     | 
    
         | 
| 
       77 
124 
     | 
    
         
             
              def configuration
         
     | 
| 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 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 
     | 
    
         
            +
            module DeepL
         
     | 
| 
      
 7 
     | 
    
         
            +
              class HTTPClientOptions
         
     | 
| 
      
 8 
     | 
    
         
            +
                attr_reader :proxy, :send_platform_info, :enable_ssl_verification, :cert_path, :open_timeout,
         
     | 
| 
      
 9 
     | 
    
         
            +
                            :read_timeout, :write_timeout, :ssl_timeout
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def initialize(proxy, cert_path, enable_ssl_verification: true, open_timeout: nil, # rubocop:disable Metrics/ParameterLists
         
     | 
| 
      
 12 
     | 
    
         
            +
                               read_timeout: nil, write_timeout: nil, ssl_timeout: nil)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @proxy = proxy
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @enable_ssl_verification = enable_ssl_verification
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @cert_path = cert_path
         
     | 
| 
      
 16 
     | 
    
         
            +
                  @open_timeout = open_timeout
         
     | 
| 
      
 17 
     | 
    
         
            +
                  @read_timeout = read_timeout
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @write_timeout = write_timeout
         
     | 
| 
      
 19 
     | 
    
         
            +
                  @ssl_timeout = ssl_timeout
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
            end
         
     | 
    
        data/license_checker.sh
    ADDED
    
    | 
         @@ -0,0 +1,8 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env bash
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            # Usage: ./license_checker.sh source_code_pattern
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Example: ./license_checker.sh '*.rb'
         
     | 
| 
      
 5 
     | 
    
         
            +
            # This will search all .rb files, ignoring anything not tracked in your git tree
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            git ls-files -z $1 | xargs -0 -n 10 -I{} sh -c 'RES=$(head -n 3 "{}" | grep "Copyright 20[0-9][0-9] DeepL SE (https://www.deepl.com)\|Copyright 20[0-9][0-9] Daniel Herzog"); if [ ! "${RES}" ] ; then echo "Lacking copyright header in" "{}" ; fi'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
    
        data/spec/api/api_spec.rb
    CHANGED
    
    | 
         @@ -1,15 +1,19 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Copyright 2018 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::API do
         
     | 
| 
      
 9 
     | 
    
         
            +
              subject(:api) { described_class.new(configuration) }
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
       6 
11 
     | 
    
         
             
              let(:configuration) { DeepL::Configuration.new }
         
     | 
| 
       7 
     | 
    
         
            -
              subject { DeepL::API.new(configuration) }
         
     | 
| 
       8 
12 
     | 
    
         | 
| 
       9 
13 
     | 
    
         
             
              describe '#initialize' do
         
     | 
| 
       10 
     | 
    
         
            -
                context ' 
     | 
| 
       11 
     | 
    
         
            -
                  it ' 
     | 
| 
       12 
     | 
    
         
            -
                    expect( 
     | 
| 
      
 14 
     | 
    
         
            +
                context 'when building an API object' do
         
     | 
| 
      
 15 
     | 
    
         
            +
                  it 'saves the configuration' do
         
     | 
| 
      
 16 
     | 
    
         
            +
                    expect(api.configuration).to be(configuration)
         
     | 
| 
       13 
17 
     | 
    
         
             
                  end
         
     | 
| 
       14 
18 
     | 
    
         
             
                end
         
     | 
| 
       15 
19 
     | 
    
         
             
              end
         
     | 
| 
         @@ -1,27 +1,101 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Copyright 2018 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 
     | 
    
         | 
| 
      
 6 
     | 
    
         
            +
            require 'logger'
         
     | 
| 
       3 
7 
     | 
    
         
             
            require 'spec_helper'
         
     | 
| 
       4 
8 
     | 
    
         | 
| 
       5 
9 
     | 
    
         
             
            describe DeepL::Configuration do
         
     | 
| 
      
 10 
     | 
    
         
            +
              subject(:config) { described_class.new(attributes) }
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
       6 
12 
     | 
    
         
             
              let(:attributes) { {} }
         
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              around do |tests|
         
     | 
| 
      
 15 
     | 
    
         
            +
                tmp_env = ENV.to_hash
         
     | 
| 
      
 16 
     | 
    
         
            +
                ENV.clear
         
     | 
| 
      
 17 
     | 
    
         
            +
                tests.call
         
     | 
| 
      
 18 
     | 
    
         
            +
                ENV.replace(tmp_env)
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
       8 
20 
     | 
    
         | 
| 
       9 
21 
     | 
    
         
             
              describe '#initialize' do
         
     | 
| 
       10 
     | 
    
         
            -
                context ' 
     | 
| 
       11 
     | 
    
         
            -
                  it ' 
     | 
| 
       12 
     | 
    
         
            -
                    expect( 
     | 
| 
       13 
     | 
    
         
            -
                    expect( 
     | 
| 
       14 
     | 
    
         
            -
                    expect( 
     | 
| 
      
 22 
     | 
    
         
            +
                context 'when using default configuration attributes' do
         
     | 
| 
      
 23 
     | 
    
         
            +
                  it 'uses default attributes' do
         
     | 
| 
      
 24 
     | 
    
         
            +
                    expect(config.auth_key).to eq(ENV.fetch('DEEPL_AUTH_KEY', nil))
         
     | 
| 
      
 25 
     | 
    
         
            +
                    expect(config.host).to eq('https://api.deepl.com')
         
     | 
| 
      
 26 
     | 
    
         
            +
                    expect(config.max_doc_status_queries).to be_nil
         
     | 
| 
      
 27 
     | 
    
         
            +
                    expect(config.version).to eq('v2')
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  it 'sends platform information' do
         
     | 
| 
      
 31 
     | 
    
         
            +
                    expect(config.user_agent).to include('deepl-ruby/')
         
     | 
| 
      
 32 
     | 
    
         
            +
                    expect(config.user_agent).to include('(')
         
     | 
| 
      
 33 
     | 
    
         
            +
                    expect(config.user_agent).to include(')')
         
     | 
| 
      
 34 
     | 
    
         
            +
                    expect(config.user_agent).to include(' ruby/')
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                context 'when using custom configuration attributes' do
         
     | 
| 
      
 39 
     | 
    
         
            +
                  let(:logger) { Logger.new($stdout) }
         
     | 
| 
      
 40 
     | 
    
         
            +
                  let(:attributes) { { auth_key: 'SAMPLE', host: 'https://api-free.deepl.com', logger: logger, max_doc_status_queries: 42, max_network_retries: 43, version: 'v1' } }
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                  it 'uses custom attributes' do
         
     | 
| 
      
 43 
     | 
    
         
            +
                    expect(config.auth_key).to eq(attributes[:auth_key])
         
     | 
| 
      
 44 
     | 
    
         
            +
                    expect(config.host).to eq(attributes[:host])
         
     | 
| 
      
 45 
     | 
    
         
            +
                    expect(config.max_doc_status_queries).to eq(attributes[:max_doc_status_queries])
         
     | 
| 
      
 46 
     | 
    
         
            +
                    expect(config.max_network_retries).to eq(attributes[:max_network_retries])
         
     | 
| 
      
 47 
     | 
    
         
            +
                    expect(config.version).to eq(attributes[:version])
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                context 'when using a free key' do
         
     | 
| 
      
 52 
     | 
    
         
            +
                  let(:attributes) { { auth_key: '123e4567-e89b-12d3-a456-426614174000:fx' } }
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  it 'uses the free API URL' do
         
     | 
| 
      
 55 
     | 
    
         
            +
                    expect(config.host).to eq('https://api-free.deepl.com')
         
     | 
| 
      
 56 
     | 
    
         
            +
                  end
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                context 'when using a pro key' do
         
     | 
| 
      
 60 
     | 
    
         
            +
                  let(:attributes) { { auth_key: '123e4567-e89b-12d3-a456-426614174000' } }
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                  it 'uses the pro API URL' do
         
     | 
| 
      
 63 
     | 
    
         
            +
                    expect(config.host).to eq('https://api.deepl.com')
         
     | 
| 
      
 64 
     | 
    
         
            +
                  end
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                context 'when opting out of sending platform info' do
         
     | 
| 
      
 68 
     | 
    
         
            +
                  subject(:config) { described_class.new(attributes, nil, nil, false) }
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                  it 'does not send platform information' do
         
     | 
| 
      
 71 
     | 
    
         
            +
                    expect(config.user_agent).to include('deepl-ruby/')
         
     | 
| 
      
 72 
     | 
    
         
            +
                    expect(config.user_agent).not_to include('(')
         
     | 
| 
      
 73 
     | 
    
         
            +
                    expect(config.user_agent).not_to include(')')
         
     | 
| 
      
 74 
     | 
    
         
            +
                    expect(config.user_agent).not_to include(' ruby/')
         
     | 
| 
      
 75 
     | 
    
         
            +
                  end
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                context 'when registering an app and sending platform info' do
         
     | 
| 
      
 79 
     | 
    
         
            +
                  subject(:config) { described_class.new(attributes, 'MyTestApp', '0.1.3', true) }
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                  it 'sends platform and app info' do
         
     | 
| 
      
 82 
     | 
    
         
            +
                    expect(config.user_agent).to include('deepl-ruby/')
         
     | 
| 
      
 83 
     | 
    
         
            +
                    expect(config.user_agent).to include('(')
         
     | 
| 
      
 84 
     | 
    
         
            +
                    expect(config.user_agent).to include(')')
         
     | 
| 
      
 85 
     | 
    
         
            +
                    expect(config.user_agent).to include(' ruby/')
         
     | 
| 
      
 86 
     | 
    
         
            +
                    expect(config.user_agent).to include('MyTestApp/0.1.3')
         
     | 
| 
       15 
87 
     | 
    
         
             
                  end
         
     | 
| 
       16 
88 
     | 
    
         
             
                end
         
     | 
| 
       17 
89 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
                context ' 
     | 
| 
       19 
     | 
    
         
            -
                   
     | 
| 
      
 90 
     | 
    
         
            +
                context 'when registering an app and not sending platform info' do
         
     | 
| 
      
 91 
     | 
    
         
            +
                  subject(:config) { described_class.new(attributes, 'MyTestApp', '0.1.3', false) }
         
     | 
| 
       20 
92 
     | 
    
         | 
| 
       21 
     | 
    
         
            -
                  it ' 
     | 
| 
       22 
     | 
    
         
            -
                    expect( 
     | 
| 
       23 
     | 
    
         
            -
                    expect( 
     | 
| 
       24 
     | 
    
         
            -
                    expect( 
     | 
| 
      
 93 
     | 
    
         
            +
                  it 'sends app, but not platform info' do
         
     | 
| 
      
 94 
     | 
    
         
            +
                    expect(config.user_agent).to include('deepl-ruby/')
         
     | 
| 
      
 95 
     | 
    
         
            +
                    expect(config.user_agent).not_to include('(')
         
     | 
| 
      
 96 
     | 
    
         
            +
                    expect(config.user_agent).not_to include(')')
         
     | 
| 
      
 97 
     | 
    
         
            +
                    expect(config.user_agent).not_to include(' ruby/')
         
     | 
| 
      
 98 
     | 
    
         
            +
                    expect(config.user_agent).to include('MyTestApp/0.1.3')
         
     | 
| 
       25 
99 
     | 
    
         
             
                  end
         
     | 
| 
       26 
100 
     | 
    
         
             
                end
         
     | 
| 
       27 
101 
     | 
    
         
             
              end
         
     | 
| 
         @@ -29,19 +103,19 @@ describe DeepL::Configuration do 
     | 
|
| 
       29 
103 
     | 
    
         
             
              describe '#validate!' do
         
     | 
| 
       30 
104 
     | 
    
         
             
                let(:auth_message) { 'auth_key not provided' }
         
     | 
| 
       31 
105 
     | 
    
         | 
| 
       32 
     | 
    
         
            -
                context ' 
     | 
| 
      
 106 
     | 
    
         
            +
                context 'when providing a valid auth key' do
         
     | 
| 
       33 
107 
     | 
    
         
             
                  let(:attributes) { { auth_key: '' } }
         
     | 
| 
       34 
108 
     | 
    
         | 
| 
       35 
     | 
    
         
            -
                  it ' 
     | 
| 
       36 
     | 
    
         
            -
                    expect {  
     | 
| 
      
 109 
     | 
    
         
            +
                  it 'raises an error' do
         
     | 
| 
      
 110 
     | 
    
         
            +
                    expect { config.validate! }.to raise_error(DeepL::Exceptions::Error, auth_message)
         
     | 
| 
       37 
111 
     | 
    
         
             
                  end
         
     | 
| 
       38 
112 
     | 
    
         
             
                end
         
     | 
| 
       39 
113 
     | 
    
         | 
| 
       40 
     | 
    
         
            -
                context ' 
     | 
| 
      
 114 
     | 
    
         
            +
                context 'when providing an invalid auth key' do
         
     | 
| 
       41 
115 
     | 
    
         
             
                  let(:attributes) { { auth_key: 'not-empty' } }
         
     | 
| 
       42 
116 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
                  it ' 
     | 
| 
       44 
     | 
    
         
            -
                    expect {  
     | 
| 
      
 117 
     | 
    
         
            +
                  it 'does not raise an error' do
         
     | 
| 
      
 118 
     | 
    
         
            +
                    expect { config.validate! }.not_to raise_error
         
     | 
| 
       45 
119 
     | 
    
         
             
                  end
         
     | 
| 
       46 
120 
     | 
    
         
             
                end
         
     | 
| 
       47 
121 
     | 
    
         
             
              end
         
     |