ruby-lokalise-api 1.1.0 → 2.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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -2
  3. data/README.md +172 -10
  4. data/lib/ruby-lokalise-api.rb +2 -0
  5. data/lib/ruby-lokalise-api/client.rb +18 -0
  6. data/lib/ruby-lokalise-api/collections/base.rb +11 -10
  7. data/lib/ruby-lokalise-api/collections/contributor.rb +1 -3
  8. data/lib/ruby-lokalise-api/collections/file.rb +1 -3
  9. data/lib/ruby-lokalise-api/collections/key.rb +8 -3
  10. data/lib/ruby-lokalise-api/collections/key_comment.rb +2 -3
  11. data/lib/ruby-lokalise-api/collections/project.rb +1 -3
  12. data/lib/ruby-lokalise-api/collections/project_comment.rb +1 -3
  13. data/lib/ruby-lokalise-api/collections/project_language.rb +1 -3
  14. data/lib/ruby-lokalise-api/collections/screenshot.rb +1 -3
  15. data/lib/ruby-lokalise-api/collections/snapshot.rb +1 -3
  16. data/lib/ruby-lokalise-api/collections/system_language.rb +1 -3
  17. data/lib/ruby-lokalise-api/collections/task.rb +1 -3
  18. data/lib/ruby-lokalise-api/collections/team.rb +1 -3
  19. data/lib/ruby-lokalise-api/collections/team_user.rb +1 -3
  20. data/lib/ruby-lokalise-api/collections/translation.rb +1 -3
  21. data/lib/ruby-lokalise-api/error.rb +2 -0
  22. data/lib/ruby-lokalise-api/request.rb +11 -3
  23. data/lib/ruby-lokalise-api/resources/base.rb +51 -41
  24. data/lib/ruby-lokalise-api/resources/contributor.rb +6 -4
  25. data/lib/ruby-lokalise-api/resources/file.rb +7 -12
  26. data/lib/ruby-lokalise-api/resources/key.rb +5 -4
  27. data/lib/ruby-lokalise-api/resources/key_comment.rb +6 -4
  28. data/lib/ruby-lokalise-api/resources/project.rb +10 -7
  29. data/lib/ruby-lokalise-api/resources/project_language.rb +5 -4
  30. data/lib/ruby-lokalise-api/resources/screenshot.rb +5 -4
  31. data/lib/ruby-lokalise-api/resources/snapshot.rb +10 -5
  32. data/lib/ruby-lokalise-api/resources/task.rb +5 -4
  33. data/lib/ruby-lokalise-api/resources/team_user.rb +6 -4
  34. data/lib/ruby-lokalise-api/resources/translation.rb +5 -4
  35. data/lib/ruby-lokalise-api/rest/comments.rb +6 -6
  36. data/lib/ruby-lokalise-api/rest/contributors.rb +6 -6
  37. data/lib/ruby-lokalise-api/rest/files.rb +3 -3
  38. data/lib/ruby-lokalise-api/rest/keys.rb +9 -9
  39. data/lib/ruby-lokalise-api/rest/languages.rb +7 -7
  40. data/lib/ruby-lokalise-api/rest/projects.rb +7 -7
  41. data/lib/ruby-lokalise-api/rest/screenshots.rb +6 -6
  42. data/lib/ruby-lokalise-api/rest/snapshots.rb +5 -5
  43. data/lib/ruby-lokalise-api/rest/tasks.rb +6 -6
  44. data/lib/ruby-lokalise-api/rest/team_users.rb +5 -5
  45. data/lib/ruby-lokalise-api/rest/teams.rb +1 -1
  46. data/lib/ruby-lokalise-api/rest/translations.rb +3 -3
  47. data/lib/ruby-lokalise-api/utils/attribute_helpers.rb +19 -5
  48. data/lib/ruby-lokalise-api/utils/endpoint_helpers.rb +12 -0
  49. data/lib/ruby-lokalise-api/utils/string_utils.rb +4 -0
  50. data/lib/ruby-lokalise-api/version.rb +1 -1
  51. data/ruby-lokalise-api.gemspec +1 -0
  52. data/spec/lib/ruby-lokalise-api/rest/comments_spec.rb +22 -5
  53. data/spec/lib/ruby-lokalise-api/rest/contributors_spec.rb +35 -2
  54. data/spec/lib/ruby-lokalise-api/rest/keys_spec.rb +55 -4
  55. data/spec/lib/ruby-lokalise-api/rest/languages_spec.rb +31 -2
  56. data/spec/lib/ruby-lokalise-api/rest/projects_spec.rb +36 -2
  57. data/spec/lib/ruby-lokalise-api/rest/screenshots_spec.rb +45 -8
  58. data/spec/lib/ruby-lokalise-api/rest/snapshots_spec.rb +25 -2
  59. data/spec/lib/ruby-lokalise-api/rest/tasks_spec.rb +38 -2
  60. data/spec/lib/ruby-lokalise-api/rest/team_users_spec.rb +25 -2
  61. data/spec/lib/ruby-lokalise-api/rest/translations_spec.rb +17 -3
  62. metadata +17 -2
@@ -2,10 +2,8 @@ module Lokalise
2
2
  module Collections
3
3
  class Contributor < Base
4
4
  class << self
5
- private
6
-
7
5
  def endpoint(project_id, *_args)
8
- "projects/#{project_id}/contributors"
6
+ path_from projects: [project_id, 'contributors']
9
7
  end
10
8
  end
11
9
  end
@@ -2,10 +2,8 @@ module Lokalise
2
2
  module Collections
3
3
  class File < Base
4
4
  class << self
5
- private
6
-
7
5
  def endpoint(project_id, *_args)
8
- "projects/#{project_id}/files"
6
+ path_from projects: [project_id, 'files']
9
7
  end
10
8
  end
11
9
  end
@@ -1,11 +1,16 @@
1
1
  module Lokalise
2
2
  module Collections
3
3
  class Key < Base
4
- class << self
5
- private
4
+ # Destroys all keys in the collection
5
+ # @return [Hash]
6
+ def destroy_all
7
+ keys = collection.collect(&:key_id)
8
+ Lokalise::Resources::Key.destroy @client, @path, keys: keys
9
+ end
6
10
 
11
+ class << self
7
12
  def endpoint(project_id, *_args)
8
- "projects/#{project_id}/keys"
13
+ path_from projects: [project_id, 'keys']
9
14
  end
10
15
  end
11
16
  end
@@ -2,10 +2,9 @@ module Lokalise
2
2
  module Collections
3
3
  class KeyComment < Base
4
4
  class << self
5
- private
6
-
7
5
  def endpoint(project_id, key_id, *_args)
8
- "projects/#{project_id}/keys/#{key_id}/comments"
6
+ path_from projects: project_id,
7
+ keys: [key_id, 'comments']
9
8
  end
10
9
  end
11
10
  end
@@ -2,10 +2,8 @@ module Lokalise
2
2
  module Collections
3
3
  class Project < Base
4
4
  class << self
5
- private
6
-
7
5
  def endpoint(*_args)
8
- 'projects'
6
+ path_from projects: nil
9
7
  end
10
8
  end
11
9
  end
@@ -2,10 +2,8 @@ module Lokalise
2
2
  module Collections
3
3
  class ProjectComment < Base
4
4
  class << self
5
- private
6
-
7
5
  def endpoint(project_id, *_args)
8
- "projects/#{project_id}/comments"
6
+ path_from projects: [project_id, 'comments']
9
7
  end
10
8
  end
11
9
  end
@@ -2,10 +2,8 @@ module Lokalise
2
2
  module Collections
3
3
  class ProjectLanguage < Base
4
4
  class << self
5
- private
6
-
7
5
  def endpoint(project_id, *_args)
8
- "projects/#{project_id}/languages"
6
+ path_from projects: [project_id, 'languages']
9
7
  end
10
8
  end
11
9
  end
@@ -2,10 +2,8 @@ module Lokalise
2
2
  module Collections
3
3
  class Screenshot < Base
4
4
  class << self
5
- private
6
-
7
5
  def endpoint(project_id, *_args)
8
- "projects/#{project_id}/screenshots"
6
+ path_from projects: [project_id, 'screenshots']
9
7
  end
10
8
  end
11
9
  end
@@ -2,10 +2,8 @@ module Lokalise
2
2
  module Collections
3
3
  class Snapshot < Base
4
4
  class << self
5
- private
6
-
7
5
  def endpoint(project_id, *_args)
8
- "projects/#{project_id}/snapshots"
6
+ path_from projects: [project_id, 'snapshots']
9
7
  end
10
8
  end
11
9
  end
@@ -2,10 +2,8 @@ module Lokalise
2
2
  module Collections
3
3
  class SystemLanguage < Base
4
4
  class << self
5
- private
6
-
7
5
  def endpoint(*_args)
8
- 'system/languages'
6
+ path_from system: 'languages'
9
7
  end
10
8
  end
11
9
  end
@@ -2,10 +2,8 @@ module Lokalise
2
2
  module Collections
3
3
  class Task < Base
4
4
  class << self
5
- private
6
-
7
5
  def endpoint(project_id, *_args)
8
- "projects/#{project_id}/tasks"
6
+ path_from projects: [project_id, 'tasks']
9
7
  end
10
8
  end
11
9
  end
@@ -2,10 +2,8 @@ module Lokalise
2
2
  module Collections
3
3
  class Team < Base
4
4
  class << self
5
- private
6
-
7
5
  def endpoint(*_args)
8
- 'teams'
6
+ path_from teams: nil
9
7
  end
10
8
  end
11
9
  end
@@ -2,10 +2,8 @@ module Lokalise
2
2
  module Collections
3
3
  class TeamUser < Base
4
4
  class << self
5
- private
6
-
7
5
  def endpoint(team_id, *_args)
8
- "teams/#{team_id}/users"
6
+ path_from teams: [team_id, 'users']
9
7
  end
10
8
  end
11
9
  end
@@ -2,10 +2,8 @@ module Lokalise
2
2
  module Collections
3
3
  class Translation < Base
4
4
  class << self
5
- private
6
-
7
5
  def endpoint(project_id, *_args)
8
- "projects/#{project_id}/translations"
6
+ path_from projects: [project_id, 'translations']
9
7
  end
10
8
  end
11
9
  end
@@ -11,6 +11,7 @@ module Lokalise
11
11
  TooManyRequests = Class.new(ClientError)
12
12
  Forbidden = Class.new(ClientError)
13
13
  Locked = Class.new(ClientError)
14
+ MethodNowAllowed = Class.new(ClientError)
14
15
 
15
16
  NotImplemented = Class.new(ServerError)
16
17
  BadGateway = Class.new(ServerError)
@@ -22,6 +23,7 @@ module Lokalise
22
23
  401 => Lokalise::Error::Unauthorized,
23
24
  403 => Lokalise::Error::Forbidden,
24
25
  404 => Lokalise::Error::NotFound,
26
+ 405 => Lokalise::Error::MethodNowAllowed,
25
27
  406 => Lokalise::Error::NotAcceptable,
26
28
  409 => Lokalise::Error::Conflict,
27
29
  423 => Lokalise::Error::Locked,
@@ -38,18 +38,26 @@ module Lokalise
38
38
 
39
39
  private
40
40
 
41
+ # Get rid of double slashes in the `path` and leading slash
41
42
  def prepare(path)
42
- path.gsub %r{//}, '/'
43
+ path.gsub(%r{\A/}, '').gsub %r{//}, '/'
43
44
  end
44
45
 
45
46
  def respond_with(response, client)
46
47
  body = MultiJson.load response.body
48
+ uri = Addressable::URI.parse response.env.url
47
49
  respond_with_error(response.status, body) if body.respond_to?(:has_key?) && body.key?('error')
50
+ extract_headers_from(response).
51
+ merge('content' => body,
52
+ 'client' => client,
53
+ 'path' => uri.path.gsub(%r{/api2/}, ''))
54
+ end
55
+
56
+ def extract_headers_from(response)
48
57
  response.
49
58
  headers.
50
59
  to_h.
51
- keep_if { |k, _v| PAGINATION_HEADERS.include?(k) }.
52
- merge('content' => body, 'client' => client)
60
+ keep_if { |k, _v| PAGINATION_HEADERS.include?(k) }
53
61
  end
54
62
 
55
63
  def respond_with_error(code, body)
@@ -4,8 +4,9 @@ module Lokalise
4
4
  extend Lokalise::Request
5
5
  extend Lokalise::Utils::AttributeHelpers
6
6
  include Lokalise::Utils::AttributeHelpers
7
+ extend Lokalise::Utils::EndpointHelpers
7
8
 
8
- attr_reader :raw_data, :project_id, :client
9
+ attr_reader :raw_data, :project_id, :client, :path
9
10
 
10
11
  # Initializes a new resource based on the response
11
12
  #
@@ -17,6 +18,7 @@ module Lokalise
17
18
  @raw_data = response['content']
18
19
  @project_id = response['content']['project_id']
19
20
  @client = response['client']
21
+ @path = infer_path_from response
20
22
  end
21
23
 
22
24
  class << self
@@ -33,68 +35,53 @@ module Lokalise
33
35
  super
34
36
  end
35
37
 
38
+ # Defines common CRUD instance methods
39
+ # Usage: `supports :update, :destroy`
40
+ def supports(*methods)
41
+ methods.each do |method_name|
42
+ define_method method_name do |params = {}|
43
+ self.class.send method_name,
44
+ instance_variable_get(:@client),
45
+ instance_variable_get(:@path),
46
+ params
47
+ end
48
+ end
49
+ end
50
+
36
51
  # Fetches a single record
37
- def find(client, endpoint_ids, resource_id = '', params = {})
38
- new get("#{endpoint(*endpoint_ids)}/#{resource_id}",
39
- client,
40
- params)
52
+ def find(client, path, params = {})
53
+ new get(path, client, params)
41
54
  end
42
55
 
43
56
  # Creates one or multiple records
44
- def create(client, endpoint_ids, params, object_key = nil)
45
- response = post(endpoint(*endpoint_ids),
46
- client,
47
- body_from(params, object_key))
57
+ def create(client, path, params)
58
+ response = post path, client, params
48
59
 
49
- object_from response, params, endpoint_ids
60
+ object_from response, params
50
61
  end
51
62
 
52
63
  # Updates one or multiple records
53
- def update(client, endpoint_ids, resource_id, params, object_key = nil)
54
- response = put("#{endpoint(*endpoint_ids)}/#{resource_id}",
55
- client,
56
- body_from(params, object_key))
64
+ def update(client, path, params)
65
+ response = put path, client, params
57
66
 
58
- object_from response, params, endpoint_ids
67
+ object_from response, params
59
68
  end
60
69
 
61
70
  # Destroys records by given ids
62
- #
63
- # @param client [Lokalise::Client]
64
- # @return [Hash]
65
- # @param endpoint_ids [String, Integer, Array]
66
- # @param resource_id [String, Integer, Hash<Array>]
67
- def destroy(client, endpoint_ids, resource_id)
68
- path = endpoint(*endpoint_ids).to_s
69
- if resource_id.is_a?(Hash)
70
- delete path, client, resource_id
71
- else
72
- delete "#{path}/#{resource_id}", client
73
- end['content']
71
+ def destroy(client, path, params = {})
72
+ delete(path, client, params)['content']
74
73
  end
75
74
 
76
75
  private
77
76
 
78
- # Converts `params` to hash with arrays under the `object_key` key.
79
- # Used in bulk operations
80
- #
81
- # @return [Hash]
82
- def body_from(params, object_key)
83
- return params unless object_key
84
-
85
- params = [params] unless params.is_a?(Array)
86
- Hash[object_key, params]
87
- end
88
-
89
77
  # Instantiates a new resource or collection based on the given response
90
- def object_from(response, params, endpoint_ids)
78
+ def object_from(response, params)
91
79
  model_class = name.base_class_name
92
80
  data_key_plural = data_key_for model_class, true
93
81
 
94
82
  if response['content'].key? data_key_plural
95
83
  Module.const_get("Lokalise::Collections::#{model_class}").new response,
96
- params,
97
- endpoint_ids
84
+ params
98
85
  else
99
86
  new response
100
87
  end
@@ -103,6 +90,29 @@ module Lokalise
103
90
 
104
91
  private
105
92
 
93
+ # Generates path for the individual resource based on the path for the collection
94
+ def infer_path_from(response)
95
+ id_key = id_key_for self.class.name.base_class_name
96
+ data_key = data_key_for self.class.name.base_class_name
97
+
98
+ path_with_id response, id_key, data_key
99
+ end
100
+
101
+ def path_with_id(response, id_key, data_key)
102
+ # Some resources do not have ids at all
103
+ return nil unless response['content'].key?(id_key) || response['content'].key?(data_key)
104
+
105
+ # Content may be `{"project_id": '123', ...}` or {"snapshot": {"snapshot_id": '123', ...}}
106
+ id = response['content'][id_key] || response['content'][data_key][id_key]
107
+
108
+ path = response['path'] || response['base_path']
109
+ # If path already has id - just return it
110
+ return path if path.match?(/#{id}\z/)
111
+
112
+ # Otherwise this seems like a collection path, so append the resource id to it
113
+ path.remove_trailing_slash + "/#{id}"
114
+ end
115
+
106
116
  # Store all resources attributes under the corresponding instance variables.
107
117
  # `ATTRIBUTES` is defined inside resource-specific classes
108
118
  def populate_attributes_for(content)
@@ -1,11 +1,13 @@
1
1
  module Lokalise
2
2
  module Resources
3
3
  class Contributor < Base
4
- class << self
5
- private
4
+ ID_KEY = 'user'.freeze
5
+ supports :update, :destroy
6
6
 
7
- def endpoint(project_id)
8
- "projects/#{project_id}/contributors"
7
+ class << self
8
+ def endpoint(project_id, contributor_id = nil)
9
+ path_from projects: project_id,
10
+ contributors: contributor_id
9
11
  end
10
12
  end
11
13
  end
@@ -2,22 +2,17 @@ module Lokalise
2
2
  module Resources
3
3
  class File < Base
4
4
  class << self
5
- def download(client, project_id, params)
6
- up_down client, endpoint(project_id), params, 'download'
5
+ def download(client, path, params)
6
+ post(path, client, params)['content']
7
7
  end
8
8
 
9
- def upload(client, project_id, params)
10
- up_down client, endpoint(project_id), params, 'upload'
9
+ def upload(client, path, params)
10
+ post(path, client, params)['content']
11
11
  end
12
12
 
13
- private
14
-
15
- def up_down(client, path, params, action)
16
- post("#{path}/#{action}", client, params)['content']
17
- end
18
-
19
- def endpoint(project_id)
20
- "projects/#{project_id}/files"
13
+ def endpoint(project_id, action = '')
14
+ path_from projects: project_id,
15
+ files: action
21
16
  end
22
17
  end
23
18
  end
@@ -1,11 +1,12 @@
1
1
  module Lokalise
2
2
  module Resources
3
3
  class Key < Base
4
- class << self
5
- private
4
+ supports :update, :destroy
6
5
 
7
- def endpoint(project_id)
8
- "projects/#{project_id}/keys"
6
+ class << self
7
+ def endpoint(project_id, key_id = nil)
8
+ path_from projects: project_id,
9
+ keys: key_id
9
10
  end
10
11
  end
11
12
  end