abbyy-cloud 0.0.3 → 0.0.4

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +24 -0
  4. data/README.md +60 -33
  5. data/abbyy-cloud.gemspec +1 -1
  6. data/lib/abbyy/cloud.rb +10 -16
  7. data/lib/abbyy/cloud/connection.rb +31 -17
  8. data/lib/abbyy/cloud/models/direction.rb +4 -2
  9. data/lib/abbyy/cloud/models/discount.rb +12 -0
  10. data/lib/abbyy/cloud/models/engine.rb +4 -1
  11. data/lib/abbyy/cloud/models/locale.rb +23 -0
  12. data/lib/abbyy/cloud/models/price.rb +22 -0
  13. data/lib/abbyy/cloud/models/source_segment.rb +14 -0
  14. data/lib/abbyy/cloud/models/source_tag.rb +15 -0
  15. data/lib/abbyy/cloud/models/transfer_data.rb +14 -0
  16. data/lib/abbyy/cloud/models/translation.rb +1 -1
  17. data/lib/abbyy/cloud/models/translation_segment.rb +16 -0
  18. data/lib/abbyy/cloud/models/unit_price.rb +13 -0
  19. data/lib/abbyy/cloud/namespaces/machine_translations.rb +47 -1
  20. data/lib/abbyy/cloud/namespaces/prices.rb +29 -0
  21. data/lib/abbyy/cloud/operations/base.rb +20 -6
  22. data/lib/abbyy/cloud/operations/engines.rb +3 -1
  23. data/lib/abbyy/cloud/operations/prices.rb +23 -0
  24. data/lib/abbyy/cloud/operations/translate.rb +5 -3
  25. data/lib/abbyy/cloud/operations/translate_segments.rb +22 -0
  26. data/lib/abbyy/cloud/settings.rb +4 -5
  27. data/lib/abbyy/cloud/types.rb +14 -10
  28. data/spec/abbyy/cloud/connection_spec.rb +1 -1
  29. data/spec/abbyy/cloud/models/discount_spec.rb +32 -0
  30. data/spec/abbyy/cloud/models/locale_spec.rb +55 -0
  31. data/spec/abbyy/cloud/models/price_spec.rb +107 -0
  32. data/spec/abbyy/cloud/models/source_segment_spec.rb +37 -0
  33. data/spec/abbyy/cloud/models/source_tag_spec.rb +56 -0
  34. data/spec/abbyy/cloud/models/transfer_data_spec.rb +40 -0
  35. data/spec/abbyy/cloud/models/translation_segment_spec.rb +38 -0
  36. data/spec/abbyy/cloud/models/unit_price_spec.rb +48 -0
  37. data/spec/abbyy/cloud/settings_spec.rb +2 -24
  38. data/spec/abbyy/cloud_spec.rb +3 -4
  39. data/spec/feature/abbyy/mt_default_engine_spec.rb +12 -0
  40. data/spec/feature/abbyy/mt_engine_spec.rb +15 -0
  41. data/spec/feature/abbyy/mt_translate_segments_spec.rb +136 -0
  42. data/spec/feature/abbyy/{order_translate_spec.rb → mt_translate_spec.rb} +2 -2
  43. data/spec/feature/abbyy/prices_details_spec.rb +70 -0
  44. metadata +39 -5
  45. data/lib/abbyy/cloud/namespaces/orders.rb +0 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 19c1ff610b7210be89b61f821ff6642ce0d149c3
4
- data.tar.gz: 896dbcb70a0796ef0445b7184d703bba31c2259e
3
+ metadata.gz: 86781ecddc4c6d75b7eca75244bb940bf82c0df1
4
+ data.tar.gz: 4fbafddffeab9bbbbc23d8e951e7f04bf5ece6c0
5
5
  SHA512:
6
- metadata.gz: ca702183cde764f614c77f26bb5bafa17a2f96614d230efccf97775f7f839fea047c35ea6bdb67b24fb270cada0402f89caefe0fcc8f7264fd295218e43f4a95
7
- data.tar.gz: f4ec867431b3eab6e736700831db4f62aaa047289c90ee81847347bdf933331a1c742973c1ed96557a8f5f69fd4206577253a628d3fd4049049ae7f07f35dcb4
6
+ metadata.gz: 46fdfc138c2b78f7e555ee80dc19c2b971cf12768e10569ee6eda8c6529030e9401d6d35ab50dc08266862b60af5e70f4a725bd6ff9df00c7caea2ff4cb355e0
7
+ data.tar.gz: ca541399867b4f463ce81f261f2e189afff31b218a7d8532008a78bbc9849ddd6f2d7b10c111396fb4b43245acb88d62b963ba3b8b3d698b3b900f816a6cefed
data/.rubocop.yml CHANGED
@@ -78,6 +78,9 @@ Style/StringLiterals:
78
78
  Style/StringLiteralsInInterpolation:
79
79
  EnforcedStyle: double_quotes
80
80
 
81
+ Style/TernaryParentheses:
82
+ Enabled: false
83
+
81
84
  Style/TrivialAccessors:
82
85
  Exclude:
83
86
  - spec/**/*_spec.rb
data/CHANGELOG.md CHANGED
@@ -1,3 +1,27 @@
1
+ # [v0.0.4 2016-08-23](https://github.com/nepalez/abbyy-cloud/tree/v0.0.4)
2
+
3
+ ### Added
4
+
5
+ * Operation `mt.engine(name)` (nepalez)
6
+ * Operation `mt.default_engine` (nepalez)
7
+ * Operation `mt.translate` instead of `orders.translate` (nepalez)
8
+ * Operation `mt.translate_segments` (nepalez)
9
+ * Operation `prices.details` (nepalez)
10
+ * Validation of locales following IANA & RFC-5646 (nepalez)
11
+
12
+ ### Deleted
13
+
14
+ * Namespace `orders` (nepalez)
15
+ * Remove :version settings (nepalez)
16
+ Every operation has its own version. No global API version is supported.
17
+ When necessary, a version will be send to the operation.
18
+
19
+ ### Internal
20
+
21
+ * Added support for query part of a request (nepalez)
22
+
23
+ [Compare v0.0.3...v0.0.4](https://github.com/nepalez/abbyy-cloud/compare/v0.0.3...v0.0.4)
24
+
1
25
  # [v0.0.3 2016-08-18](https://github.com/nepalez/abbyy-cloud/tree/v0.0.3)
2
26
 
3
27
  ### Bugs Fixed
data/README.md CHANGED
@@ -22,20 +22,31 @@ require "abbyy/cloud"
22
22
  CLIENT = ABBYY::Cloud.new(id: "foo", token: "bar")
23
23
  ```
24
24
 
25
- The only supported API version is `0`. By default the translation engine is set to "Sandbox".
26
-
27
25
  You can set these options explicitly:
28
26
 
29
27
  ```ruby
30
28
  CLIENT = ABBYY::Cloud.new id: "foo",
31
29
  token: "bar",
32
- engine: "Sandbox", # default engine for translations
33
- version: 0 # the only supported version
30
+ engine: "Sandbox" # default engine for translations
31
+ ```
32
+
33
+ And then use the client to provide requests:
34
+
35
+ ```ruby
36
+ res = CLIENT.mt.translate("To be or not to be", from: :en, to: :ru)
37
+ res.translation # => "Быть или не быть"
38
+
39
+ res = CLIENT.mt.translate_segments ["To be or not to be", "That is the question"], from: "en", to: "ru"
40
+ res.map(&:text) # => ["Быть или не быть", "Это вопрос"]
34
41
  ```
35
42
 
43
+ ## Namespaces and Operations
44
+
36
45
  ### Machine Translations
37
46
 
38
- #### Engines
47
+ The namespace `mt` contains (synchronous) operations with machine translation.
48
+
49
+ #### engines
39
50
 
40
51
  See [the specification](https://api.abbyy.cloud/swagger/ui/index#!/MachineTranslation)
41
52
 
@@ -44,7 +55,7 @@ result = CLIENT.mt.engines
44
55
  # => [#<ABBYY::Cloud::Models::Engine @name="Sandbox">]
45
56
  ```
46
57
 
47
- #### Engine
58
+ #### engine
48
59
 
49
60
  This operation is built on top of the previous one and simply takes settings for the specified engine:
50
61
 
@@ -59,14 +70,24 @@ result.to_h
59
70
  # => { name: "Sandbox", languages: ["en", "ru"], translation_directions: [{ source: "en", target: "ru" }] }
60
71
  ```
61
72
 
62
- ### Orders
73
+ #### default_engine
74
+
75
+ Returns settings for the engine used in the initializer
76
+
77
+ ```ruby
78
+ CLIENT = ABBYY::Cloud.new(id: "foo", token: "bar", engine: "Bing")
79
+
80
+ settings_for_bing = CLIENT.mt.default_engine
81
+ ```
82
+
83
+ #### translate
63
84
 
64
- #### Instant Translation
85
+ Translates a string.
65
86
 
66
87
  See [the specification](https://api.abbyy.cloud/swagger/ui/index#!/Order/Order_Translate).
67
88
 
68
89
  ```ruby
69
- result = CLIENT.orders.translate("To be or not to be", from: :en, to: :ru)
90
+ result = CLIENT.mt.translate("To be or not to be", from: :en, to: :ru)
70
91
 
71
92
  result.class # => ABBYY::Cloud::Models::Translation
72
93
  result.translation # => "Быть или не быть"
@@ -74,42 +95,48 @@ result.id # => "2832934"
74
95
  result.to_h # => { id: "2832934", translation: "Быть или не быть" }
75
96
  ```
76
97
 
77
- You can specify an engine (different from default):
98
+ #### translate_segments
78
99
 
79
- ```ruby
80
- CLIENT.orders.translate("To be or not to be", from: :en, to: :ru, engine: "Bing")
81
- ```
100
+ Translates an array of strings in one request
82
101
 
83
- The method raises an exception in case the cloud responded with error.
102
+ See [the specification](https://api.abbyy.cloud/swagger/ui/index#!/Order/Order_TranslateSegments)
84
103
 
85
104
  ```ruby
86
- error = \
87
- begin
88
- CLIENT.orders.translate("To be or not to be")
89
- rescue ABBYY::Cloud::Error => error
90
- error
91
- end
92
-
93
- error.class # => ABBYY::Cloud::ResponceError
94
- error.status # => 400
105
+ result = CLIENT.mt.translate_segments(["To be", "or not to be"], from: :en, to: :ru)
106
+
107
+ result.class # => ABBYY::Cloud::Models::TranslationSequence
108
+ result.map(&:text) # => ["Быть", "или не быть"]
95
109
  ```
96
110
 
97
- The exception carries returned error model in its `#data` attribute:
111
+ ### Prices
112
+
113
+ The namespace `prices` contains operations with prices details.
114
+
115
+ #### details
116
+
117
+ See [the specification](https://api.abbyy.cloud/swagger/ui/index#!/Prices/Prices_GetAccountPrices).
98
118
 
99
119
  ```ruby
100
- error.data # => ABBYY::Cloud::Models::Error
101
- error.data.to_h
102
- # => {
103
- # model_state: {},
104
- # requiest_id: "string",
105
- # error: "error message",
106
- # error_description: "some details"
120
+ list = CLIENT.prices.details
121
+
122
+ list.first.to_h
123
+ # {
124
+ # id: "foo",
125
+ # account_id: "bar",
126
+ # type: "qux",
127
+ # from: "ru",
128
+ # to: "en",
129
+ # unit_prices: [{ unit_type: "Words", currency: "USD", amount: 0.03 }],
130
+ # discounts: [{ discount_type: "TMTextMatch", discount: 0.01 }],
131
+ # created: Time.now
107
132
  # }
108
133
 
109
- error.data.error # => "error message"
110
- # etc.
111
134
  ```
112
135
 
136
+ The number of items can be several thousands. You can specify `skip` and `take` options to take necessary items only, otherwise it will return all prices.
137
+
138
+ Notice, though, that every single request can return no more than 1000 items. If you request more prices, several requests will be made one-by-one. Parsing all the results can be pretty slow.
139
+
113
140
  ## Compatibility
114
141
 
115
142
  [WIP] Compatible to [ABBYY Cloud API v.0][abbyy-api].
data/abbyy-cloud.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |gem|
2
2
  gem.name = "abbyy-cloud"
3
- gem.version = "0.0.3"
3
+ gem.version = "0.0.4"
4
4
  gem.authors = ["Andrew Kozin"]
5
5
  gem.email = ["andrew.kozin@gmail.com"]
6
6
  gem.summary = "HTTP client to ABBYY Cloud API"
data/lib/abbyy/cloud.rb CHANGED
@@ -11,22 +11,12 @@ module ABBYY
11
11
  require_relative "cloud/connection"
12
12
  require_relative "cloud/settings"
13
13
 
14
- require_relative "cloud/exceptions/response_error"
15
- require_relative "cloud/exceptions/argument_error"
16
- require_relative "cloud/exceptions/type_error"
17
-
18
- require_relative "cloud/models/error"
19
- require_relative "cloud/models/translation"
20
- require_relative "cloud/models/direction"
21
- require_relative "cloud/models/engine"
22
-
23
- require_relative "cloud/operations/base"
24
- require_relative "cloud/operations/translate"
25
- require_relative "cloud/operations/engines"
26
-
27
- require_relative "cloud/namespaces/base"
28
- require_relative "cloud/namespaces/orders"
29
- require_relative "cloud/namespaces/machine_translations"
14
+ Dir[
15
+ "lib/abbyy/cloud/exceptions/*.rb",
16
+ "lib/abbyy/cloud/models/*.rb",
17
+ "lib/abbyy/cloud/operations/*.rb",
18
+ "lib/abbyy/cloud/namespaces/*.rb"
19
+ ].each { |f| require File.expand_path(f) }
30
20
 
31
21
  attr_reader :settings
32
22
 
@@ -38,6 +28,10 @@ module ABBYY
38
28
  Namespaces::Orders.new(settings)
39
29
  end
40
30
 
31
+ def prices
32
+ Namespaces::Prices.new(settings)
33
+ end
34
+
41
35
  private
42
36
 
43
37
  def initialize(*args)
@@ -7,35 +7,49 @@
7
7
  class ABBYY::Cloud
8
8
  class Connection
9
9
  include Dry::Initializer.define -> do
10
- option :version
11
10
  option :id
12
11
  option :token
13
12
  end
14
13
 
15
- def call(http_method, path, body: nil, headers: nil)
16
- uri = root.merge(path).tap { |item| item.scheme = "https" }
17
- req = prepare_request(http_method, uri, JSON(body.to_h), headers.to_h)
14
+ attr_reader :root
18
15
 
19
- Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
20
- handle_response http.request(req)
16
+ def call(http_method, path, **options)
17
+ uri = prepare_uri(path, options)
18
+ req = Net::HTTP.const_get(http_method.capitalize).new(uri)
19
+ setup_headers(req, options)
20
+ setup_body(req, options)
21
+
22
+ res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
23
+ http.request(req)
21
24
  end
25
+ handle_response(res)
22
26
  end
23
27
 
24
28
  private
25
29
 
26
- def root
27
- @root ||= URI("https://api.abbyy.cloud").merge("v#{version}/")
30
+ def initialize(*)
31
+ super
32
+ @root = URI("https://api.abbyy.cloud").tap { |obj| obj.scheme = "https" }
28
33
  end
29
34
 
30
- def prepare_request(http_method, uri, body, headers)
31
- Net::HTTP.const_get(http_method.capitalize).new(uri).tap do |req|
32
- req.body = body
33
- req.basic_auth id, token
34
- req["accept-charset"] = "utf-8"
35
- req["accept"] = "application/json"
36
- req["content-type"] = "application/json"
37
- headers.each { |key, value| req[key.to_s] = value }
38
- end
35
+ def prepare_uri(path, query: nil, **)
36
+ uri = root.merge(path)
37
+ query = query.to_h.map { |k, v| "#{k}=#{v}" if v }.compact.join("&")
38
+ uri.query = query unless query.empty?
39
+ uri
40
+ end
41
+
42
+ def setup_headers(req, headers: nil, **)
43
+ req.basic_auth id, token
44
+ req["accept-charset"] = "utf-8"
45
+ req["accept"] = "application/json"
46
+ req["content-type"] = "application/json"
47
+ headers.to_h.each { |key, value| req[key.to_s] = value }
48
+ end
49
+
50
+ def setup_body(req, body: nil, **)
51
+ return unless req["content-type"] == "application/json"
52
+ req.body = JSON(body.to_h)
39
53
  end
40
54
 
41
55
  def handle_response(response)
@@ -1,9 +1,11 @@
1
+ require_relative "locale"
2
+
1
3
  class ABBYY::Cloud
2
4
  module Models
3
5
  # Description of the translation direction
4
6
  class Direction < Struct
5
- attribute :source, Types::Language
6
- attribute :target, Types::Language
7
+ attribute :source, Types::Locale
8
+ attribute :target, Types::Locale
7
9
  end
8
10
 
9
11
  # Registers type Types::Direction
@@ -0,0 +1,12 @@
1
+ class ABBYY::Cloud
2
+ module Models
3
+ # Description of the price discount
4
+ class Discount < Struct
5
+ attribute :discount_type, Types::DiscountType
6
+ attribute :discount, Types::Coercible::Float
7
+ end
8
+
9
+ # Registers type Types::Discount
10
+ Types.register_type Discount
11
+ end
12
+ end
@@ -1,10 +1,13 @@
1
+ require_relative "locale"
2
+ require_relative "direction"
3
+
1
4
  class ABBYY::Cloud
2
5
  # Collection of models returned in requests
3
6
  module Models
4
7
  # Description of the engine
5
8
  class Engine < Struct
6
9
  attribute :name, Types::Strict::String
7
- attribute :languages, Types::Array.member(Types::Language)
10
+ attribute :languages, Types::Array.member(Types::Locale)
8
11
  attribute :translation_directions, Types::Array.member(Types::Direction)
9
12
  end
10
13
 
@@ -0,0 +1,23 @@
1
+ class ABBYY::Cloud
2
+ module Models
3
+ class Locale < String
4
+ FORMAT = /\A[A-Za-z0-9]{2,}(-[A-Za-z0-9]+)*\z|\A[i|x](-[A-Za-z0-9]+)+\z/
5
+
6
+ class << self
7
+ def new(value)
8
+ return unless value
9
+ return super if value[FORMAT]
10
+ raise <<-MESSAGE.gsub(" +\|", "")
11
+ |'#{value}' is not a valid locale. See:
12
+ | RFC-5656 (https://tools.ietf.org/html/rfc5646) for valid format
13
+ | Full list of locales at http://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
14
+ MESSAGE
15
+ end
16
+ alias_method :[], :new
17
+ end
18
+ end
19
+
20
+ # Registers type Types::Locale
21
+ Types.register_type Locale
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ require_relative "locale"
2
+ require_relative "unit_price"
3
+ require_relative "discount"
4
+
5
+ class ABBYY::Cloud
6
+ module Models
7
+ # Price details
8
+ class Price < Struct
9
+ attribute :id, Types::Strict::String
10
+ attribute :account_id, Types::Strict::String
11
+ attribute :type, Types::Strict::String
12
+ attribute :from, Types::Locale
13
+ attribute :to, Types::Locale
14
+ attribute :unit_prices, Types::Array.member(Types::UnitPrice)
15
+ attribute :discounts, Types::Array.member(Types::Discount)
16
+ attribute :created, Types::Coercible::Time
17
+ end
18
+
19
+ # Registers type Types::Price
20
+ Types.register_type Price
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ require_relative "source_tag"
2
+
3
+ class ABBYY::Cloud
4
+ module Models
5
+ # A segment for the translation
6
+ class SourceSegment < Struct
7
+ attribute :text, Types::Strict::String
8
+ attribute :tags, Types::Array.member(Types::SourceTag).default([])
9
+ end
10
+
11
+ # Registers type Types::SourceSegment
12
+ Types.register_type SourceSegment
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ class ABBYY::Cloud
2
+ module Models
3
+ TYPES = %w(Start End Placeholder).freeze
4
+
5
+ # Tag for translation source/target
6
+ class SourceTag < Struct
7
+ attribute :number, Types::Strict::Int
8
+ attribute :position, Types::Strict::Int
9
+ attribute :type, Types::Strict::String.constrained(included_in: TYPES)
10
+ end
11
+
12
+ # Registers type Types::SourceTag
13
+ Types.register_type SourceTag
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ class ABBYY::Cloud
2
+ module Models
3
+ TYPES = %w(Start End Placeholder).freeze
4
+
5
+ # Tag for translation source/target
6
+ class TransferData < Struct
7
+ attribute :position, Types::Strict::Int
8
+ attribute :order, Types::Strict::Int
9
+ end
10
+
11
+ # Registers type Types::TransferData
12
+ Types.register_type TransferData
13
+ end
14
+ end