cloudinary 1.28.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97b754051e806086f5dfb98479292bb84bed48968c242d8c55dfa073a8d90e52
4
- data.tar.gz: 6a6484d454b0b074fa177b68e90bb62a100c90aa3f4b3ab33dad9acd64d7ec4d
3
+ metadata.gz: 6d6f32cb53d97a60e6d0ec304b1dbee2a80e7d1610c9007a9a0331bf80c3f882
4
+ data.tar.gz: 29863f2c682c9800cef486624985a8d4f8959b7da19ce0f53b4377bdc0312eaf
5
5
  SHA512:
6
- metadata.gz: dd822c6ec7144df3f7ab863d834802c486bc31ef5051cafbb9d331279a0f3092906990c211ccf1802515d53d51f64e71fd1bd73acc8a2f368c22bddd90ea3a38
7
- data.tar.gz: cc2299facddd71188d08c0f934ad8483bc0c9414364699e3f84a20eee489f0883adca4ba838a9534d417e11580ff194761d0d26cc978079c9e3b2f42cceeaa48
6
+ metadata.gz: 8b7ac1b9edaeb3d8faad6dc1d75442f41cadef751400840c27ff176d370ca0739f68eda398c05efe56b7bfaa04376a0154f17840e15ac670fd4cc9d673527cb0
7
+ data.tar.gz: c3ba9122af7accec3abf2b9388b62be44e1e483a6f229e13ba40d1d283e9eef75c7179235b2674011e7d49d1fc12284c83b59f0dcfb0eed38e73195815123294
data/.travis.yml CHANGED
@@ -1,22 +1,16 @@
1
- dist: focal
1
+ dist: jammy
2
2
  language: ruby
3
3
  rvm:
4
- - 2.6.7
5
- - 2.7.4
6
- - 3.0.2
4
+ - 3.1.4
5
+ - 3.2.2
6
+ - 3.3.0
7
7
 
8
8
  matrix:
9
9
  include:
10
- - name: "Ruby 1.9"
11
- dist: precise
12
- rvm: 1.9.3
13
- before_install:
14
- - gem install bundler -v 1.17.3
15
- - name: "Ruby 2.5.9"
16
- dist: xenial
17
- rvm: ruby-2.5.9
18
- before_install:
19
- - gem install bundler -v 2.3.26
10
+ # There is an OpenSSL issue on Jammy with Ruby 3.0
11
+ - name: "Ruby: 3.0.6"
12
+ dist: focal
13
+ rvm: 3.0.6
20
14
 
21
15
  before_script: >
22
16
  export CLOUDINARY_URL=$(bash tools/get_test_cloud.sh);
data/CHANGELOG.md CHANGED
@@ -1,3 +1,54 @@
1
+ 2.0.0 / 2024-04-08
2
+ ==================
3
+
4
+ Breaking Changes
5
+ ----------------
6
+
7
+ * Set minimal Ruby version to `3.0`
8
+ * For older Rubies use version `1.x` of this library
9
+ * Replace `rest-client` with `faraday`
10
+ * Set config `secure` to `true` by default
11
+ * All delivery URLs are set to be `https://` by default
12
+ * To disable - set `secure` to `false` in config/options
13
+ * Add support for URL Analytics
14
+ * Adds analytics signature query parameter to the delivery URLs
15
+ * To disable - set `analytics` to `false` in config/options
16
+ * Remove deprecated methods
17
+ * `Cloudinary::Utils.unsigned_download_url`
18
+ * use `Cloudinary::Utils.cloudinary_url` instead
19
+ * `Cloudinary::Utils.signed_download_url`
20
+ * use `Cloudinary::Utils.cloudinary_url` instead
21
+ * `Cloudinary::Utils.zip_download_url`
22
+ * use `Cloudinary::Utils.download_zip_url` instead
23
+ * `cl_zip_download_url`
24
+ * use `cl_download_zip_url` instead
25
+ * Remove deprecated constants
26
+
27
+ New functionality and features
28
+ ------------------------------
29
+
30
+ * Add support for `analyze` API
31
+ * Support chunked uploads with CarrierWave
32
+ * Filter users by last login in `users` Provisioning API
33
+
34
+ 1.29.0 / 2024-02-26
35
+ ==================
36
+
37
+ New functionality and features
38
+ ------------------------------
39
+
40
+ * Add support for `context` parameter in `url_for_direct_upload`
41
+ * Add support for `use_fetch_format` parameter in `cl_video_tag`
42
+ * Add support for `fields` parameter in Search and Admin APIs
43
+ * Add support for access keys management in Account Provisioning API
44
+
45
+ Other Changes
46
+ -------------
47
+
48
+ * Avoid early loading of `ActionView::Base`
49
+ * Fix `sqlite3` dependency version
50
+ * Add Rails 7.x to supported versions on `README.md`
51
+
1
52
  1.28.0 / 2023-11-06
2
53
  ==================
3
54
 
data/README.md CHANGED
@@ -40,11 +40,13 @@ the [Ruby on Rails SDK Guide](https://cloudinary.com/documentation/rails_integra
40
40
 
41
41
  | SDK Version | Ruby 1.9.3 | Ruby 2.x | Ruby 3.x |
42
42
  |-------------|------------|----------|----------|
43
- | 1.x | v | v | v |
43
+ | 1.x | | | |
44
+ | 2.x | ✘ | ✘ | ✔ |
44
45
 
45
- | SDK Version | Rails 5.x | Rails 6.x |
46
- |-------------|-----------|-----------|
47
- | 1.x | v | v |
46
+ | SDK Version | Rails 5.x | Rails 6.x | Rails 7.x |
47
+ |-------------|-----------|-----------|-----------|
48
+ | 1.x | | | ✔ |
49
+ | 2.x | ✘ | ✔ | ✔ |
48
50
 
49
51
  ## Installation
50
52
 
@@ -64,7 +66,7 @@ require 'cloudinary'
64
66
  - [See full documentation](https://cloudinary.com/documentation/rails_image_manipulation).
65
67
 
66
68
  ```ruby
67
- cl_image_tag("sample.jpg", :width => 100, :height => 150, :crop => :fill)
69
+ cl_image_tag("sample.jpg", width: 100, height: 150, crop: "fill")
68
70
  ```
69
71
 
70
72
  ### Upload
data/cloudinary.gemspec CHANGED
@@ -7,63 +7,33 @@ Gem::Specification.new do |s|
7
7
  s.version = Cloudinary::VERSION
8
8
  s.authors = ["Nadav Soferman","Itai Lahan","Tal Lev-Ami"]
9
9
  s.email = ["nadav.soferman@cloudinary.com","itai.lahan@cloudinary.com","tal.levami@cloudinary.com"]
10
- s.homepage = "http://cloudinary.com"
10
+ s.homepage = "https://cloudinary.com"
11
11
  s.license = "MIT"
12
12
 
13
13
  s.summary = %q{Client library for easily using the Cloudinary service}
14
14
  s.description = %q{Client library for easily using the Cloudinary service}
15
15
 
16
- s.rubyforge_project = "cloudinary"
17
-
18
- s.files = `git ls-files`.split("\n").select { |f| !f.start_with?("test", "spec", "features", "samples") } + Dir.glob("vendor/assets/javascripts/*/*") + Dir.glob("vendor/assets/html/*")
16
+ s.files = `git ls-files`.split("\n").select { |f| !f.start_with?("test", "spec", "features", "samples") } +
17
+ Dir.glob("vendor/assets/javascripts/*/*") + Dir.glob("vendor/assets/html/*")
19
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
19
  s.require_paths = ["lib"]
21
20
 
22
- s.add_dependency "aws_cf_signer"
23
-
24
- if RUBY_VERSION >= "2.0.0"
25
- s.add_dependency "rest-client", ">= 2.0.0"
26
- else
27
- s.add_dependency "rest-client"
28
- end
29
-
30
- if RUBY_VERSION >= "3.0.0"
31
- s.add_development_dependency "rexml"
32
- end
33
-
34
- s.add_development_dependency "actionpack"
35
- s.add_development_dependency "nokogiri"
36
-
37
- if RUBY_VERSION >= "2.2.0"
38
- s.add_development_dependency "rake", ">= 13.0.1"
39
- else
40
- s.add_development_dependency "rake", "<= 12.2.1"
41
- end
42
- if RUBY_VERSION >= "2.7.0"
43
- s.add_development_dependency "sqlite3"
44
- else
45
- s.add_development_dependency "sqlite3", "< 1.6.0"
46
- end
47
-
48
- s.add_development_dependency "rspec", '>=3.5'
49
- s.add_development_dependency "rspec-retry"
50
-
51
- if RUBY_VERSION >= "3.0.0"
52
- s.add_development_dependency "rails", "~> 6.0.3"
53
- elsif RUBY_VERSION >= "2.2.2"
54
- s.add_development_dependency "rails", "~> 5.2"
55
- end
56
-
57
- s.add_development_dependency "railties", "<= 4.2.7" if RUBY_VERSION <= "1.9.3"
58
- s.add_development_dependency "rspec-rails"
59
-
60
- s.add_development_dependency "rubyzip"
61
-
62
- if RUBY_VERSION <= "2.4.0"
63
- s.add_development_dependency "simplecov", "<= 0.17.1" # support testing Ruby 1.9
64
- s.add_development_dependency 'loofah', '~>2.19.1'
65
- s.add_development_dependency "rails-html-sanitizer", "<1.5.0"
66
- else
67
- s.add_development_dependency "simplecov", "> 0.18.0"
68
- end
21
+ s.required_ruby_version = '~> 3'
22
+
23
+ s.add_dependency "faraday", ">= 2.0.1", "< 3.0.0"
24
+ s.add_dependency "faraday-multipart", "~> 1.0", ">= 1.0.4"
25
+
26
+ s.add_development_dependency 'faraday-follow_redirects', '~> 0.3.0'
27
+ s.add_development_dependency "rails", ">= 6.1.7", "< 8.0.0"
28
+ s.add_development_dependency "rexml", ">= 3.2.5", "< 4.0.0"
29
+ s.add_development_dependency "actionpack", ">= 6.1.7", "< 8.0.0"
30
+ s.add_development_dependency "nokogiri", ">= 1.12.5", "< 2.0.0"
31
+ s.add_development_dependency "rake", ">= 13.0.6", "< 14.0.0"
32
+ s.add_development_dependency "sqlite3", ">= 1.4.2", "< 2.0.0"
33
+ s.add_development_dependency "rspec", ">= 3.11.2", "< 4.0.0"
34
+ s.add_development_dependency "rspec-retry", ">= 0.6.2", "< 1.0.0"
35
+ s.add_development_dependency "railties", ">= 6.0.4", "< 8.0.0"
36
+ s.add_development_dependency "rspec-rails", ">= 6.0.4", "< 7.0.0"
37
+ s.add_development_dependency "rubyzip", ">= 2.3.0", "< 3.0.0"
38
+ s.add_development_dependency "simplecov", ">= 0.21.2", "< 1.0.0"
69
39
  end
@@ -39,10 +39,12 @@ module ActiveStorage
39
39
  begin
40
40
  extra_headers = checksum.nil? ? {} : {Headers::CONTENT_MD5 => checksum}
41
41
  options = @options.merge(options)
42
+ resource_type = resource_type(io, key)
43
+ options[:format] = ext_for_file(key) if resource_type == "raw"
42
44
  Cloudinary::Uploader.upload_large(
43
45
  io,
44
46
  public_id: public_id_internal(key),
45
- resource_type: resource_type(io, key),
47
+ resource_type: resource_type,
46
48
  context: {active_storage_key: key, checksum: checksum},
47
49
  extra_headers: extra_headers,
48
50
  **options
@@ -81,7 +83,9 @@ module ActiveStorage
81
83
  # through direct upload (client side js), filename is missing, and that leads to inconsistent/broken URLs.
82
84
  # To avoid that, we explicitly pass file format in options.
83
85
  options[:format] = ext_for_file(key) if options[:resource_type] == "raw"
86
+ context = options.delete(:context)
84
87
  options[:context] = {active_storage_key: key}
88
+ options[:context].reverse_merge!(context) if context.respond_to?(:merge)
85
89
  options.delete(:file)
86
90
  payload[:url] = api_uri("upload", options)
87
91
  end
@@ -147,7 +151,7 @@ module ActiveStorage
147
151
 
148
152
  # Return the partial content in the byte +range+ of the file at the +key+.
149
153
  def download_chunk(key, range)
150
- url = Cloudinary::Utils.unsigned_download_url(public_id(key), resource_type: resource_type(nil, key))
154
+ url = Cloudinary::Utils.cloudinary_url(public_id(key), resource_type: resource_type(nil, key))
151
155
  uri = URI(url)
152
156
  instrument :download, key: key do
153
157
  req = Net::HTTP::Get.new(uri)
@@ -13,10 +13,10 @@ class Cloudinary::AccountApi
13
13
  # @param [Object] options additional options
14
14
  def self.create_sub_account(name, cloud_name = nil, custom_attributes = {}, enabled = nil, base_account = nil, options = {})
15
15
  params = {
16
- name: name,
17
- cloud_name: cloud_name,
18
- custom_attributes: custom_attributes,
19
- enabled: enabled,
16
+ name: name,
17
+ cloud_name: cloud_name,
18
+ custom_attributes: custom_attributes,
19
+ enabled: enabled,
20
20
  base_sub_account_id: base_account
21
21
  }
22
22
 
@@ -35,10 +35,10 @@ class Cloudinary::AccountApi
35
35
  # @param [Object] options additional options
36
36
  def self.update_sub_account(sub_account_id, name = nil, cloud_name = nil, custom_attributes = nil, enabled = nil, options = {})
37
37
  params = {
38
- name: name,
39
- cloud_name: cloud_name,
38
+ name: name,
39
+ cloud_name: cloud_name,
40
40
  custom_attributes: custom_attributes,
41
- enabled: enabled
41
+ enabled: enabled
42
42
  }
43
43
 
44
44
  call_account_api(:put, ['sub_accounts', sub_account_id], params, options.merge(content_type: :json))
@@ -53,8 +53,8 @@ class Cloudinary::AccountApi
53
53
  def self.sub_accounts(enabled = nil, ids = [], prefix = nil, options = {})
54
54
  params = {
55
55
  enabled: enabled,
56
- ids: ids,
57
- prefix: prefix
56
+ ids: ids,
57
+ prefix: prefix
58
58
  }
59
59
 
60
60
  call_account_api(:get, 'sub_accounts', params, options.merge(content_type: :json))
@@ -84,9 +84,9 @@ class Cloudinary::AccountApi
84
84
  # @param [Object] options additional options
85
85
  def self.create_user(name, email, role, sub_account_ids = [], options = {})
86
86
  params = {
87
- name: name,
88
- email: email,
89
- role: role,
87
+ name: name,
88
+ email: email,
89
+ role: role,
90
90
  sub_account_ids: sub_account_ids
91
91
  }
92
92
 
@@ -111,9 +111,9 @@ class Cloudinary::AccountApi
111
111
  # @param [Object] options additional options
112
112
  def self.update_user(user_id, name = nil, email = nil, role = nil, sub_account_ids = nil, options = {})
113
113
  params = {
114
- name: name,
115
- email: email,
116
- role: role,
114
+ name: name,
115
+ email: email,
116
+ role: role,
117
117
  sub_account_ids: sub_account_ids
118
118
  }
119
119
 
@@ -127,18 +127,30 @@ class Cloudinary::AccountApi
127
127
  call_account_api(:get, ['users', user_id], {}, options.merge(content_type: :json))
128
128
  end
129
129
 
130
- # Lists users in the account.
131
- # @param [Boolean] pending Limit results to pending users (true), users that are not pending (false), or all users (nil, the default)
132
- # @param [Array<String>] user_ids A list of up to 100 user IDs. When provided, other parameters are ignored.
133
- # @param [String] prefix Returns users where the name or email address begins with the specified case-insensitive string.
134
- # @param [String] sub_account_id Only returns users who have access to the specified account.
135
- # @param [Object] options additional options
130
+ # Get a list of the users according to filters.
131
+ #
132
+ # @param [Boolean] pending Optional. Limit results to pending users (true), users that are not pending (false), or all users (null)
133
+ # @param [Array<String>] user_ids Optional. List of user IDs. Up to 100
134
+ # @param [String] prefix Optional. Search by prefix of the user's name or email. Case-insensitive
135
+ # @param [String] sub_account_id Optional. Return only users who have access to the given sub-account
136
+ # @param [Object] options Generic advanced options map, see online documentation.
137
+ # @option options [Boolean] :last_login Optional. Return only users that last logged in in the specified range of dates (true),
138
+ # users that didn't last logged in in that range (false), or all users (null).
139
+ # @option options [Date] :from Optional. Last login start date.
140
+ # @option options [Date] :to Optional. Last login end date.
141
+ #
142
+ # @return [Cloudinary::Api::Response] the users' details.
143
+ #
144
+ # @raise [Cloudinary::Api::Error] If the request fails.
136
145
  def self.users(pending = nil, user_ids = [], prefix = nil, sub_account_id = nil, options = {})
137
146
  params = {
138
- ids: user_ids,
139
- prefix: prefix,
147
+ ids: user_ids,
148
+ prefix: prefix,
140
149
  sub_account_id: sub_account_id,
141
- pending: pending
150
+ pending: pending,
151
+ last_login: options[:last_login].to_s,
152
+ from: Cloudinary::Utils.to_usage_api_date_format(options[:from]),
153
+ to: Cloudinary::Utils.to_usage_api_date_format(options[:to])
142
154
  }
143
155
 
144
156
  call_account_api(:get, 'users', params, options.merge(content_type: :json))
@@ -210,16 +222,55 @@ class Cloudinary::AccountApi
210
222
  call_account_api(:get, ['user_groups', group_id, 'users'], {}, options.merge(content_type: :json))
211
223
  end
212
224
 
225
+ # Lists access keys.
226
+ #
227
+ # @param [String] sub_account_id The ID of the sub-account.
228
+ # @param [Object] options Additional options.
229
+ def self.access_keys(sub_account_id, options = {})
230
+ params = Cloudinary::Api.only(options, :page_size, :page, :sort_by, :sort_order)
231
+ call_account_api(:get, ['sub_accounts', sub_account_id, 'access_keys'], params, options)
232
+ end
233
+
234
+ # Generates access key.
235
+ #
236
+ # @param [String] sub_account_id The ID of the sub-account.
237
+ # @param [String] name The display name as shown in the management console.
238
+ # @param [Boolean] enabled Whether to create the access key as enabled (default is enabled).
239
+ # @param [Object] options Additional options.
240
+ def self.generate_access_key(sub_account_id, name = nil, enabled = nil, options = {})
241
+ params = {
242
+ name: name,
243
+ enabled: enabled,
244
+ }
245
+ call_account_api(:post, ['sub_accounts', sub_account_id, 'access_keys'], params, options.merge(content_type: :json))
246
+ end
247
+
248
+ # Updates access key.
249
+ #
250
+ # @param [String] sub_account_id The ID of the sub-account.
251
+ # @param [String] api_key The API key.
252
+ # @param [String] name The display name as shown in the management console.
253
+ # @param [Boolean] enabled Enable or disable the access key.
254
+ # @param [Object] options Additional options.
255
+ def self.update_access_key(sub_account_id, api_key, name = nil, enabled = nil, options = {})
256
+ params = {
257
+ name: name,
258
+ enabled: enabled,
259
+ }
260
+ call_account_api(:put, ['sub_accounts', sub_account_id, 'access_keys', api_key], params, options.merge(content_type: :json))
261
+ end
262
+
213
263
  def self.call_account_api(method, uri, params, options)
214
264
  account_id = options[:account_id] || Cloudinary.account_config.account_id || raise('Must supply account_id')
215
265
  api_key = options[:provisioning_api_key] || Cloudinary.account_config.provisioning_api_key || raise('Must supply provisioning api_key')
216
266
  api_secret = options[:provisioning_api_secret] || Cloudinary.account_config.provisioning_api_secret || raise('Must supply provisioning api_secret')
267
+ api_version = options[:api_version] || Cloudinary.config.api_version || 'v1_1'
217
268
 
218
269
  params.reject! { |_, v| v.nil? }
219
270
  auth = { :key => api_key, :secret => api_secret }
220
271
 
221
272
  call_cloudinary_api(method, uri, auth, params, options) do |cloudinary, inner_uri|
222
- [cloudinary, 'v1_1', 'provisioning', 'accounts', account_id, inner_uri]
273
+ [cloudinary, api_version, 'provisioning', 'accounts', account_id, inner_uri]
223
274
  end
224
275
  end
225
276
 
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cloudinary
4
+ module Analytics
5
+ extend self
6
+
7
+ QUERY_KEY = '_a'
8
+ ALGO_VERSION = 'B' # The version of the algorithm
9
+ SDK_CODE = 'C' # Cloudinary Ruby SDK
10
+
11
+ @product = 'A' # Official SDK. Set to 'B' for integrations.
12
+ @sdk_code = SDK_CODE
13
+ @sdk_version = Cloudinary::VERSION
14
+ @tech_version = "#{RUBY_VERSION[/\d+\.\d+/]}"
15
+
16
+ CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
17
+ BINARY_PAD_SIZE = 6
18
+
19
+ @char_codes = nil
20
+ @signature = nil
21
+
22
+ # Gets the SDK analytics signature query parameter.
23
+ #
24
+ # @return [String] The SDK signature query parameter.
25
+ def sdk_analytics_query_param
26
+ "#{QUERY_KEY}=#{self.sdk_analytics_signature}"
27
+ end
28
+
29
+ # Gets the SDK signature by encoding the SDK version and tech version.
30
+ #
31
+ # @return [String] The SDK signature.
32
+ def sdk_analytics_signature
33
+ return @signature unless @signature.nil?
34
+
35
+ begin
36
+ @signature = ALGO_VERSION + @product + @sdk_code + encode_version(@sdk_version) + encode_version(@tech_version)
37
+ rescue RangeError
38
+ @signature = 'E'
39
+ end
40
+
41
+ @signature
42
+ end
43
+
44
+ # Sets the product code.
45
+ #
46
+ # Used for integrations.
47
+ #
48
+ # @param [String] product The product code to set. 'A' is for the official SDK. 'B' for integrations.
49
+ #
50
+ # @return [void]
51
+ #
52
+ # @internal
53
+ def product(product)
54
+ @product = product
55
+ end
56
+
57
+ # Sets the SDK code.
58
+ #
59
+ # Used for integrations.
60
+ #
61
+ # @param [String] sdk_code The SDK code to set.
62
+ #
63
+ # @return [void]
64
+ #
65
+ # @internal
66
+ def sdk_code(sdk_code)
67
+ @sdk_code = sdk_code
68
+ end
69
+
70
+ # Sets the SDK version.
71
+ #
72
+ # Used for integrations.
73
+ #
74
+ # @param [String] sdk_version The SDK version to set (MAJOR.MINOR.PATCH), for example: "1.0.0".
75
+ #
76
+ # @return [void]
77
+ #
78
+ # @internal
79
+ def sdk_version(sdk_version)
80
+ @sdk_version = sdk_version
81
+ end
82
+
83
+ # Sets the tech version.
84
+ #
85
+ # Used for integrations.
86
+ #
87
+ # @param [String] tech_version The tech version to set (MAJOR.MINOR), for example: "1.0".
88
+ #
89
+ # @return [void]
90
+ #
91
+ # @internal
92
+ def tech_version(tech_version)
93
+ @tech_version = tech_version.split('.').first(2).join('.')
94
+ end
95
+
96
+ # Encodes a semVer-like version string.
97
+ #
98
+ # Example:
99
+ # input: '1.24.0'
100
+ # explode: ['1','24','0']
101
+ # pad: ['01','24','00']
102
+ # reverse: ['00', '24', '01']
103
+ # implode: '002401'
104
+ # int: 2401
105
+ # binary: '100101100001'
106
+ # padded: '000000100101100001'
107
+ # str_split: ['000000', '100101', '100001']
108
+ # getKey: ['A', 'l', 'h']
109
+ # implode: 'Alh'
110
+ #
111
+ # @param [String] version Can be either x.y.z or x.y
112
+ #
113
+ # @return [String] A string built from 3 characters of the base64 table
114
+ #
115
+ # @raise [RangeError] when version is larger than 43.21.26
116
+ def encode_version(version)
117
+ parts = version.split('.')
118
+
119
+ padded_parts = parts.map { |part| part.rjust(2, '0') }
120
+ number = padded_parts.reverse.join.to_i
121
+ padded_binary = int_to_padded_bin(number, parts.length * BINARY_PAD_SIZE)
122
+
123
+ raise RangeError, 'Version must be smaller than 43.21.26' if padded_binary.length % BINARY_PAD_SIZE != 0
124
+
125
+ encoded_chars = padded_binary.chars.each_slice(BINARY_PAD_SIZE).map { |slice| get_key(slice.join) }
126
+
127
+ encoded_chars.join
128
+ end
129
+
130
+ # Gets the key for binary value.
131
+ #
132
+ # @param [String] binary_value The value.
133
+ #
134
+ # @return [Array, Object] The key for the binary value.
135
+ def get_key(binary_value)
136
+ @char_codes ||= initialize_char_codes
137
+
138
+ @char_codes[binary_value] || ''
139
+ end
140
+
141
+ def initialize_char_codes
142
+ char_codes = {}
143
+ CHARS.chars.each_with_index { |char, idx| char_codes[int_to_padded_bin(idx, BINARY_PAD_SIZE)] = char }
144
+ char_codes
145
+ end
146
+
147
+ # Converts integer to left padded binary string.
148
+ #
149
+ # @param [Integer] integer The input.
150
+ # @param [Integer] pad_num The num of padding chars.
151
+ #
152
+ # @return [String] The padded binary string.
153
+ def int_to_padded_bin(integer, pad_num)
154
+ integer.to_s(2).rjust(pad_num, '0')
155
+ end
156
+ end
157
+ end