ruby-lokalise-api 2.8.0 → 3.1.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 (114) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODE_OF_CONDUCT.md +1 -1
  3. data/.github/CONTRIBUTING.md +2 -2
  4. data/CHANGELOG.md +46 -0
  5. data/Gemfile +2 -0
  6. data/README.md +293 -178
  7. data/Rakefile +6 -1
  8. data/lib/ruby-lokalise-api.rb +4 -0
  9. data/lib/ruby-lokalise-api/client.rb +18 -4
  10. data/lib/ruby-lokalise-api/collections/base.rb +6 -2
  11. data/lib/ruby-lokalise-api/collections/branch.rb +3 -1
  12. data/lib/ruby-lokalise-api/collections/contributor.rb +2 -0
  13. data/lib/ruby-lokalise-api/collections/custom_translation_status.rb +3 -1
  14. data/lib/ruby-lokalise-api/collections/file.rb +2 -0
  15. data/lib/ruby-lokalise-api/collections/key.rb +2 -0
  16. data/lib/ruby-lokalise-api/collections/key_comment.rb +2 -0
  17. data/lib/ruby-lokalise-api/collections/order.rb +2 -0
  18. data/lib/ruby-lokalise-api/collections/payment_card.rb +2 -0
  19. data/lib/ruby-lokalise-api/collections/project.rb +2 -0
  20. data/lib/ruby-lokalise-api/collections/project_comment.rb +2 -0
  21. data/lib/ruby-lokalise-api/collections/project_language.rb +2 -0
  22. data/lib/ruby-lokalise-api/collections/queued_process.rb +15 -0
  23. data/lib/ruby-lokalise-api/collections/screenshot.rb +2 -0
  24. data/lib/ruby-lokalise-api/collections/snapshot.rb +2 -0
  25. data/lib/ruby-lokalise-api/collections/system_language.rb +2 -0
  26. data/lib/ruby-lokalise-api/collections/task.rb +2 -0
  27. data/lib/ruby-lokalise-api/collections/team.rb +2 -0
  28. data/lib/ruby-lokalise-api/collections/team_user.rb +2 -0
  29. data/lib/ruby-lokalise-api/collections/team_user_group.rb +3 -1
  30. data/lib/ruby-lokalise-api/collections/translation.rb +2 -0
  31. data/lib/ruby-lokalise-api/collections/translation_provider.rb +2 -0
  32. data/lib/ruby-lokalise-api/collections/webhook.rb +2 -0
  33. data/lib/ruby-lokalise-api/connection.rb +3 -1
  34. data/lib/ruby-lokalise-api/data/attributes.json +28 -13
  35. data/lib/ruby-lokalise-api/error.rb +2 -0
  36. data/lib/ruby-lokalise-api/json_handler.rb +4 -0
  37. data/lib/ruby-lokalise-api/request.rb +10 -1
  38. data/lib/ruby-lokalise-api/resources/base.rb +53 -21
  39. data/lib/ruby-lokalise-api/resources/branch.rb +3 -1
  40. data/lib/ruby-lokalise-api/resources/contributor.rb +4 -2
  41. data/lib/ruby-lokalise-api/resources/custom_translation_status.rb +4 -2
  42. data/lib/ruby-lokalise-api/resources/file.rb +5 -1
  43. data/lib/ruby-lokalise-api/resources/key.rb +3 -1
  44. data/lib/ruby-lokalise-api/resources/key_comment.rb +5 -3
  45. data/lib/ruby-lokalise-api/resources/order.rb +4 -0
  46. data/lib/ruby-lokalise-api/resources/payment_card.rb +3 -1
  47. data/lib/ruby-lokalise-api/resources/project.rb +3 -1
  48. data/lib/ruby-lokalise-api/resources/project_comment.rb +3 -1
  49. data/lib/ruby-lokalise-api/resources/project_language.rb +5 -3
  50. data/lib/ruby-lokalise-api/resources/queued_process.rb +18 -0
  51. data/lib/ruby-lokalise-api/resources/screenshot.rb +3 -1
  52. data/lib/ruby-lokalise-api/resources/snapshot.rb +5 -1
  53. data/lib/ruby-lokalise-api/resources/system_language.rb +3 -1
  54. data/lib/ruby-lokalise-api/resources/task.rb +3 -1
  55. data/lib/ruby-lokalise-api/resources/team.rb +2 -0
  56. data/lib/ruby-lokalise-api/resources/team_user.rb +4 -2
  57. data/lib/ruby-lokalise-api/resources/team_user_group.rb +6 -3
  58. data/lib/ruby-lokalise-api/resources/translation.rb +3 -1
  59. data/lib/ruby-lokalise-api/resources/translation_provider.rb +5 -0
  60. data/lib/ruby-lokalise-api/resources/webhook.rb +13 -3
  61. data/lib/ruby-lokalise-api/rest/branches.rb +2 -0
  62. data/lib/ruby-lokalise-api/rest/comments.rb +7 -5
  63. data/lib/ruby-lokalise-api/rest/contributors.rb +7 -5
  64. data/lib/ruby-lokalise-api/rest/custom_translation_statuses.rb +8 -6
  65. data/lib/ruby-lokalise-api/rest/files.rb +5 -3
  66. data/lib/ruby-lokalise-api/rest/keys.rb +9 -7
  67. data/lib/ruby-lokalise-api/rest/languages.rb +8 -6
  68. data/lib/ruby-lokalise-api/rest/orders.rb +2 -0
  69. data/lib/ruby-lokalise-api/rest/payment_cards.rb +5 -3
  70. data/lib/ruby-lokalise-api/rest/projects.rb +8 -6
  71. data/lib/ruby-lokalise-api/rest/queued_processes.rb +26 -0
  72. data/lib/ruby-lokalise-api/rest/screenshots.rb +7 -5
  73. data/lib/ruby-lokalise-api/rest/snapshots.rb +6 -4
  74. data/lib/ruby-lokalise-api/rest/tasks.rb +7 -5
  75. data/lib/ruby-lokalise-api/rest/team_user_group.rb +6 -4
  76. data/lib/ruby-lokalise-api/rest/team_users.rb +6 -4
  77. data/lib/ruby-lokalise-api/rest/teams.rb +3 -1
  78. data/lib/ruby-lokalise-api/rest/translation_providers.rb +4 -2
  79. data/lib/ruby-lokalise-api/rest/translations.rb +5 -3
  80. data/lib/ruby-lokalise-api/rest/webhooks.rb +18 -5
  81. data/lib/ruby-lokalise-api/utils/attribute_helpers.rb +2 -0
  82. data/lib/ruby-lokalise-api/utils/endpoint_helpers.rb +2 -0
  83. data/lib/ruby-lokalise-api/utils/string_utils.rb +2 -0
  84. data/lib/ruby-lokalise-api/version.rb +3 -1
  85. data/ruby-lokalise-api.gemspec +9 -5
  86. data/spec/lib/ruby-lokalise-api/connection_spec.rb +10 -7
  87. data/spec/lib/ruby-lokalise-api/custom_json_parser_spec.rb +9 -5
  88. data/spec/lib/ruby-lokalise-api/error_spec.rb +15 -4
  89. data/spec/lib/ruby-lokalise-api/rest/branches_spec.rb +19 -5
  90. data/spec/lib/ruby-lokalise-api/rest/comments_spec.rb +19 -5
  91. data/spec/lib/ruby-lokalise-api/rest/contributors_spec.rb +18 -4
  92. data/spec/lib/ruby-lokalise-api/rest/custom_translation_statuses_spec.rb +18 -4
  93. data/spec/lib/ruby-lokalise-api/rest/files_spec.rb +21 -11
  94. data/spec/lib/ruby-lokalise-api/rest/keys_spec.rb +46 -26
  95. data/spec/lib/ruby-lokalise-api/rest/languages_spec.rb +20 -6
  96. data/spec/lib/ruby-lokalise-api/rest/orders_spec.rb +16 -2
  97. data/spec/lib/ruby-lokalise-api/rest/payment_cards_spec.rb +21 -5
  98. data/spec/lib/ruby-lokalise-api/rest/projects_spec.rb +18 -4
  99. data/spec/lib/ruby-lokalise-api/rest/queued_processes_spec.rb +57 -0
  100. data/spec/lib/ruby-lokalise-api/rest/screenshots_spec.rb +18 -4
  101. data/spec/lib/ruby-lokalise-api/rest/snapshots_spec.rb +31 -4
  102. data/spec/lib/ruby-lokalise-api/rest/tasks_spec.rb +18 -4
  103. data/spec/lib/ruby-lokalise-api/rest/team_user_groups_spec.rb +92 -6
  104. data/spec/lib/ruby-lokalise-api/rest/team_users_spec.rb +19 -4
  105. data/spec/lib/ruby-lokalise-api/rest/teams_spec.rb +2 -0
  106. data/spec/lib/ruby-lokalise-api/rest/translation_providers_spec.rb +9 -2
  107. data/spec/lib/ruby-lokalise-api/rest/translations_spec.rb +20 -6
  108. data/spec/lib/ruby-lokalise-api/rest/webhooks_spec.rb +54 -2
  109. data/spec/lib/ruby-lokalise-api/utils/snakecase_spec.rb +2 -0
  110. data/spec/lib/ruby-lokalise-api_spec.rb +12 -9
  111. data/spec/spec_helper.rb +8 -1
  112. data/spec/support/test_client.rb +2 -0
  113. data/spec/support/vcr.rb +2 -0
  114. metadata +59 -12
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rake'
2
4
 
3
5
  begin
@@ -13,4 +15,7 @@ require 'rspec/core/rake_task'
13
15
  RSpec::Core::RakeTask.new(:spec)
14
16
 
15
17
  require 'rubocop/rake_task'
16
- RuboCop::RakeTask.new
18
+ RuboCop::RakeTask.new do |task|
19
+ task.requires << 'rubocop-performance'
20
+ task.requires << 'rubocop-rspec'
21
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'faraday'
2
4
  require 'yaml'
3
5
  require 'addressable'
@@ -15,6 +17,7 @@ require 'ruby-lokalise-api/resources/base'
15
17
  require 'ruby-lokalise-api/resources/branch'
16
18
  require 'ruby-lokalise-api/resources/project'
17
19
  require 'ruby-lokalise-api/resources/project_language'
20
+ require 'ruby-lokalise-api/resources/queued_process'
18
21
  require 'ruby-lokalise-api/resources/key_comment'
19
22
  require 'ruby-lokalise-api/resources/contributor'
20
23
  require 'ruby-lokalise-api/resources/file'
@@ -41,6 +44,7 @@ require 'ruby-lokalise-api/collections/team'
41
44
  require 'ruby-lokalise-api/collections/system_language'
42
45
  require 'ruby-lokalise-api/collections/project_language'
43
46
  require 'ruby-lokalise-api/collections/project_comment'
47
+ require 'ruby-lokalise-api/collections/queued_process'
44
48
  require 'ruby-lokalise-api/collections/key_comment'
45
49
  require 'ruby-lokalise-api/collections/key'
46
50
  require 'ruby-lokalise-api/collections/contributor'
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'ruby-lokalise-api/rest/branches'
2
4
  require 'ruby-lokalise-api/rest/languages'
3
5
  require 'ruby-lokalise-api/rest/teams'
4
6
  require 'ruby-lokalise-api/rest/projects'
7
+ require 'ruby-lokalise-api/rest/queued_processes'
5
8
  require 'ruby-lokalise-api/rest/comments'
6
9
  require 'ruby-lokalise-api/rest/keys'
7
10
  require 'ruby-lokalise-api/rest/contributors'
@@ -25,14 +28,25 @@ module Lokalise
25
28
 
26
29
  def initialize(token, params = {})
27
30
  @token = token
28
- @timeout = params.fetch(:timeout) { nil }
29
- @open_timeout = params.fetch(:open_timeout) { nil }
31
+ @timeout = params.fetch(:timeout, nil)
32
+ @open_timeout = params.fetch(:open_timeout, nil)
30
33
  end
31
34
 
32
- def construct_request(klass, method, endpoint_ids, params = {}, object_key = nil)
35
+ # rubocop:disable Metrics/ParameterLists
36
+ # Constructs request to perform the specified action
37
+ # @param klass The actual class to call the method upon
38
+ # @param method [Symbol] The method to call (:new, :update, :create etc)
39
+ # @param endpoint_ids [Array, Hash] IDs that are used to generate the proper path to the endpoint
40
+ # @param params [Array, Hash] Request parameters
41
+ # @param object_key [String, Symbol] Key that should be used to wrap parameters into
42
+ # @param initial_ids [Array] IDs that should be used to generate base endpoint path. The base path is used for method chaining
43
+ def construct_request(klass, method, endpoint_ids, params = {}, object_key = nil, initial_ids = nil)
33
44
  path = klass.endpoint(*endpoint_ids)
34
- klass.send method, self, path, format_params(params, object_key)
45
+ formatted_params = format_params(params, object_key)
46
+ formatted_params[:_initial_path] = klass.endpoint(*initial_ids) if initial_ids
47
+ klass.send method, self, path, formatted_params
35
48
  end
49
+ # rubocop:enable Metrics/ParameterLists
36
50
 
37
51
  # Converts `params` to hash with arrays under the `object_key` key.
38
52
  # Used in bulk operations
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class Base
@@ -7,7 +9,7 @@ module Lokalise
7
9
  extend Lokalise::Utils::EndpointHelpers
8
10
 
9
11
  attr_reader :total_pages, :total_results, :results_per_page, :current_page, :collection,
10
- :project_id, :team_id, :request_params, :client, :path
12
+ :project_id, :team_id, :request_params, :client, :path, :branch, :user_id
11
13
 
12
14
  # Initializes a new collection based on the response
13
15
  #
@@ -17,9 +19,11 @@ module Lokalise
17
19
  def initialize(response, params = {})
18
20
  produce_collection_for response
19
21
  populate_pagination_data_for response
20
- # Project and team id may not be present in some cases
22
+ # Project, team id, user id, and branch may not be present in some cases
21
23
  @project_id = response['content']['project_id']
22
24
  @team_id = response['content']['team_id']
25
+ @user_id = response['content']['user_id']
26
+ @branch = response['content']['branch']
23
27
  @request_params = params
24
28
  @client = response['client']
25
29
  @path = response['path']
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class Branch < Base
4
- DATA_KEY_PLURAL = 'Branches'.freeze
6
+ DATA_KEY_PLURAL = 'Branches'
5
7
 
6
8
  class << self
7
9
  def endpoint(project_id, *_args)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class Contributor < Base
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class CustomTranslationStatus < Base
4
- DATA_KEY_PLURAL = 'CustomTranslationStatuses'.freeze
6
+ DATA_KEY_PLURAL = 'CustomTranslationStatuses'
5
7
 
6
8
  class << self
7
9
  def endpoint(project_id, *_args)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class File < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class Key < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class KeyComment < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class Order < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class PaymentCard < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class Project < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class ProjectComment < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class ProjectLanguage < Base
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lokalise
4
+ module Collections
5
+ class QueuedProcess < Base
6
+ DATA_KEY_PLURAL = 'Processes'
7
+
8
+ class << self
9
+ def endpoint(project_id, *_args)
10
+ path_from projects: [project_id, 'processes']
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class Screenshot < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class Snapshot < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class SystemLanguage < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class Task < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class Team < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class TeamUser < Base
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class TeamUserGroup < Base
4
- DATA_KEY = 'UserGroup'.freeze
6
+ DATA_KEY = 'UserGroup'
5
7
 
6
8
  class << self
7
9
  def endpoint(team_id, *_args)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class Translation < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class TranslationProvider < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Collections
3
5
  class Webhook < Base
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Connection
3
- BASE_URL = 'https://api.lokalise.co/api2/'.freeze
5
+ BASE_URL = 'https://api.lokalise.com/api2/'
4
6
 
5
7
  def connection(client)
6
8
  options = {
@@ -21,11 +21,11 @@
21
21
  "email",
22
22
  "fullname",
23
23
  "created_at",
24
+ "created_at_timestamp",
24
25
  "is_admin",
25
26
  "is_reviewer",
26
27
  "languages",
27
- "admin_rights",
28
- "created_at_timestamp"
28
+ "admin_rights"
29
29
  ],
30
30
  "custom_translation_status": [
31
31
  "status_id",
@@ -39,6 +39,7 @@
39
39
  "key": [
40
40
  "key_id",
41
41
  "created_at",
42
+ "created_at_timestamp",
42
43
  "key_name",
43
44
  "filenames",
44
45
  "description",
@@ -55,7 +56,10 @@
55
56
  "base_words",
56
57
  "char_limit",
57
58
  "custom_attributes",
58
- "created_at_timestamp"
59
+ "modified_at",
60
+ "modified_at_timestamp",
61
+ "translations_modified_at",
62
+ "translations_modified_at_timestamp"
59
63
  ],
60
64
  "language": [
61
65
  "lang_id",
@@ -70,6 +74,7 @@
70
74
  "card_id",
71
75
  "status",
72
76
  "created_at",
77
+ "created_at_timestamp",
73
78
  "created_by",
74
79
  "created_by_email",
75
80
  "source_language_iso",
@@ -81,8 +86,7 @@
81
86
  "translation_tier",
82
87
  "translation_tier_name",
83
88
  "briefing",
84
- "total",
85
- "created_at_timestamp"
89
+ "total"
86
90
  ],
87
91
  "payment_card": [
88
92
  "card_id",
@@ -96,15 +100,26 @@
96
100
  "name",
97
101
  "description",
98
102
  "created_at",
103
+ "created_at_timestamp",
99
104
  "created_by",
100
105
  "created_by_email",
101
106
  "team_id",
102
- "created_at_timestamp",
103
107
  "base_language_id",
104
108
  "base_language_iso",
105
109
  "settings",
106
110
  "statistics"
107
111
  ],
112
+ "queued_process": [
113
+ "process_id",
114
+ "type",
115
+ "status",
116
+ "message",
117
+ "created_by",
118
+ "created_by_email",
119
+ "created_at",
120
+ "created_at_timestamp",
121
+ "details"
122
+ ],
108
123
  "screenshot": [
109
124
  "screenshot_id",
110
125
  "key_ids",
@@ -121,9 +136,9 @@
121
136
  "snapshot_id",
122
137
  "title",
123
138
  "created_at",
139
+ "created_at_timestamp",
124
140
  "created_by",
125
- "created_by_email",
126
- "created_at_timestamp"
141
+ "created_by_email"
127
142
  ],
128
143
  "task": [
129
144
  "task_id",
@@ -157,18 +172,18 @@
157
172
  "team_id",
158
173
  "name",
159
174
  "created_at",
175
+ "created_at_timestamp",
160
176
  "plan",
161
177
  "quota_usage",
162
- "quota_allowed",
163
- "created_at_timestamp"
178
+ "quota_allowed"
164
179
  ],
165
180
  "team_user": [
166
181
  "user_id",
167
182
  "email",
168
183
  "fullname",
169
184
  "created_at",
170
- "role",
171
- "created_at_timestamp"
185
+ "created_at_timestamp",
186
+ "role"
172
187
  ],
173
188
  "team_user_group": [
174
189
  "group_id",
@@ -211,4 +226,4 @@
211
226
  "events",
212
227
  "event_lang_map"
213
228
  ]
214
- }
229
+ }
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  class Error < StandardError
3
5
  ClientError = Class.new(self)
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
1
5
  module Lokalise
2
6
  module JsonHandler
3
7
  # JSON custom parser. Uses built-in JSON by default but can be overridden to any other parser
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lokalise
2
4
  module Request
3
5
  include Lokalise::Connection
@@ -27,6 +29,13 @@ module Lokalise
27
29
  )
28
30
  end
29
31
 
32
+ def patch(path, client, params = {})
33
+ respond_with(
34
+ connection(client).patch(prepare(path), params.any? ? custom_dump(params) : nil),
35
+ client
36
+ )
37
+ end
38
+
30
39
  def delete(path, client, params = {})
31
40
  respond_with(
32
41
  # Rubocop tries to replace `delete` with `gsub` but that's a different method here!
@@ -43,7 +52,7 @@ module Lokalise
43
52
 
44
53
  # Get rid of double slashes in the `path`, leading and trailing slash
45
54
  def prepare(path)
46
- path.gsub(%r{\A/}, '').gsub(%r{//}, '/').gsub(%r{/+\z}, '')
55
+ path.delete_prefix('/').gsub(%r{//}, '/').gsub(%r{/+\z}, '')
47
56
  end
48
57
 
49
58
  def respond_with(response, client)