cloudinary 1.28.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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