encoded_id 1.0.0.rc5 → 1.0.0.rc6

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.
@@ -1,12 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  # Hashid with a reduced character set Crockford alphabet and split groups
4
6
  # See: https://www.crockford.com/wrmg/base32.html
5
- # Build with https://hashids.org
6
- # Note hashIds already has a built in profanity limitation algorithm
7
+ # Build with support for https://hashids.org and https://sqids.org
7
8
  module EncodedId
9
+ # @rbs!
10
+ # type encodeableValue = Array[String | Integer] | String | Integer
11
+
8
12
  class ReversibleId
9
- def initialize(salt:, length: 8, split_at: 4, split_with: "-", alphabet: Alphabet.modified_crockford, hex_digit_encoding_group_size: 4, max_length: 128, max_inputs_per_id: 32)
13
+ # @rbs VALID_ENCODERS: Array[Symbol]
14
+ VALID_ENCODERS = [:hashids, :sqids].freeze
15
+ # @rbs DEFAULT_ENCODER: Symbol
16
+ DEFAULT_ENCODER = :hashids
17
+
18
+ # @rbs @alphabet: Alphabet
19
+ # @rbs @salt: String
20
+ # @rbs @length: Integer
21
+ # @rbs @split_at: Integer?
22
+ # @rbs @split_with: String?
23
+ # @rbs @hex_represention_encoder: HexRepresentation
24
+ # @rbs @max_length: Integer?
25
+ # @rbs @max_inputs_per_id: Integer
26
+ # @rbs @blocklist: Blocklist
27
+ # @rbs @encoder: Encoders::Base
28
+
29
+ # @rbs (salt: String, ?length: Integer, ?split_at: Integer?, ?split_with: String?, ?alphabet: Alphabet, ?hex_digit_encoding_group_size: Integer, ?max_length: Integer?, ?max_inputs_per_id: Integer, ?encoder: Symbol | Encoders::Base, ?blocklist: Blocklist | Array[String] | Set[String] | nil) -> void
30
+ def initialize(salt:, length: 8, split_at: 4, split_with: "-", alphabet: Alphabet.modified_crockford, hex_digit_encoding_group_size: 4, max_length: 128, max_inputs_per_id: 32, encoder: DEFAULT_ENCODER, blocklist: Blocklist.empty)
10
31
  @alphabet = validate_alphabet(alphabet)
11
32
  @salt = validate_salt(salt)
12
33
  @length = validate_length(length)
@@ -15,13 +36,27 @@ module EncodedId
15
36
  @hex_represention_encoder = HexRepresentation.new(hex_digit_encoding_group_size)
16
37
  @max_length = validate_max_length(max_length)
17
38
  @max_inputs_per_id = validate_max_input(max_inputs_per_id)
39
+ @blocklist = validate_blocklist(blocklist)
40
+ @encoder = create_encoder(validate_encoder(encoder))
18
41
  end
19
42
 
43
+ # Accessors for introspection
44
+ attr_reader :salt #: String
45
+ attr_reader :length #: Integer
46
+ attr_reader :alphabet #: Alphabet
47
+ attr_reader :split_at #: Integer?
48
+ attr_reader :split_with #: String?
49
+ attr_reader :hex_represention_encoder #: HexRepresentation
50
+ attr_reader :max_length #: Integer?
51
+ attr_reader :blocklist #: Blocklist
52
+ attr_reader :encoder #: Encoders::Base
53
+
20
54
  # Encode the input values into a hash
55
+ # @rbs (encodeableValue values) -> String
21
56
  def encode(values)
22
57
  inputs = prepare_input(values)
23
- encoded_id = encoded_id_generator.encode(inputs)
24
- encoded_id = humanize_length(encoded_id) unless split_with.nil? || split_at.nil?
58
+ encoded_id = encoder.encode(inputs)
59
+ encoded_id = humanize_length(encoded_id) if split_with && split_at
25
60
 
26
61
  raise EncodedIdLengthError if max_length_exceeded?(encoded_id)
27
62
 
@@ -29,78 +64,83 @@ module EncodedId
29
64
  end
30
65
 
31
66
  # Encode hex strings into a hash
67
+ # @rbs (encodeableHexValue hexs) -> String
32
68
  def encode_hex(hexs)
33
69
  encode(hex_represention_encoder.hex_as_integers(hexs))
34
70
  end
35
71
 
36
72
  # Decode the hash to original array
73
+ # @rbs (String str, ?downcase: bool) -> Array[Integer]
37
74
  def decode(str, downcase: true)
38
75
  raise EncodedIdFormatError, "Max length of input exceeded" if max_length_exceeded?(str)
39
76
 
40
- encoded_id_generator.decode(convert_to_hash(str, downcase))
77
+ encoder.decode(convert_to_hash(str, downcase))
41
78
  rescue InvalidInputError => e
42
79
  raise EncodedIdFormatError, e.message
43
80
  end
44
81
 
45
82
  # Decode hex strings from a hash
83
+ # @rbs (String str, ?downcase: bool) -> Array[String]
46
84
  def decode_hex(str, downcase: true)
47
- integers = encoded_id_generator.decode(convert_to_hash(str, downcase))
85
+ integers = encoder.decode(convert_to_hash(str, downcase))
48
86
  hex_represention_encoder.integers_as_hex(integers)
49
87
  end
50
88
 
51
89
  private
52
90
 
53
- attr_reader :salt,
54
- :length,
55
- :alphabet,
56
- :split_at,
57
- :split_with,
58
- :hex_represention_encoder,
59
- :max_length
60
-
91
+ # @rbs (Alphabet alphabet) -> Alphabet
61
92
  def validate_alphabet(alphabet)
62
93
  return alphabet if alphabet.is_a?(Alphabet)
63
94
  raise InvalidAlphabetError, "alphabet must be an instance of Alphabet"
64
95
  end
65
96
 
97
+ # @rbs (String salt) -> String
66
98
  def validate_salt(salt)
67
99
  return salt if salt.is_a?(String) && salt.size > 3
68
100
  raise InvalidConfigurationError, "Salt must be a string and longer than 3 characters"
69
101
  end
70
102
 
71
103
  # Target length of the encoded string (the minimum but not maximum length)
104
+ # @rbs (Integer length) -> Integer
72
105
  def validate_length(length)
73
106
  return length if valid_integer_option?(length)
74
107
  raise InvalidConfigurationError, "Length must be an integer greater than 0"
75
108
  end
76
109
 
110
+ # @rbs (Integer? max_length) -> Integer?
77
111
  def validate_max_length(max_length)
78
112
  return max_length if valid_integer_option?(max_length) || max_length.nil?
79
113
  raise InvalidConfigurationError, "Max length must be an integer greater than 0"
80
114
  end
81
115
 
116
+ # @rbs (Integer max_inputs_per_id) -> Integer
82
117
  def validate_max_input(max_inputs_per_id)
83
118
  return max_inputs_per_id if valid_integer_option?(max_inputs_per_id)
84
119
  raise InvalidConfigurationError, "Max inputs per ID must be an integer greater than 0"
85
120
  end
86
121
 
87
122
  # Split the encoded string into groups of this size
123
+ # @rbs (Integer? split_at) -> Integer?
88
124
  def validate_split_at(split_at)
89
125
  return split_at if valid_integer_option?(split_at) || split_at.nil?
90
126
  raise InvalidConfigurationError, "Split at must be an integer greater than 0 or nil"
91
127
  end
92
128
 
129
+ # @rbs (String? split_with, Alphabet alphabet) -> String?
93
130
  def validate_split_with(split_with, alphabet)
94
131
  return split_with if split_with.nil? || (split_with.is_a?(String) && !alphabet.characters.include?(split_with))
95
132
  raise InvalidConfigurationError, "Split with must be a string and not part of the alphabet or nil"
96
133
  end
97
134
 
135
+ # @rbs (Integer? value) -> bool
98
136
  def valid_integer_option?(value)
99
137
  value.is_a?(Integer) && value > 0
100
138
  end
101
139
 
140
+ # @rbs (encodeableValue value) -> Array[Integer]
102
141
  def prepare_input(value)
103
142
  inputs = value.is_a?(Array) ? value.map(&:to_i) : [value.to_i]
143
+ raise ::EncodedId::InvalidInputError, "Cannot encode an empty array" if inputs.empty?
104
144
  raise ::EncodedId::InvalidInputError, "Integer IDs to be encoded can only be positive" if inputs.any?(&:negative?)
105
145
 
106
146
  raise ::EncodedId::InvalidInputError, "%d integer IDs provided, maximum amount of IDs is %d" % [inputs.length, @max_inputs_per_id] if inputs.length > @max_inputs_per_id
@@ -108,24 +148,69 @@ module EncodedId
108
148
  inputs
109
149
  end
110
150
 
111
- def encoded_id_generator
112
- @encoded_id_generator ||= HashId.new(salt, length, alphabet)
151
+ # @rbs (Symbol | Encoders::Base encoder) -> Encoders::Base
152
+ def create_encoder(encoder)
153
+ # If an encoder instance was provided, return it directly
154
+ return @encoder if defined?(@encoder) && @encoder.is_a?(Encoders::Base)
155
+ return encoder if encoder.is_a?(Encoders::Base)
156
+
157
+ case encoder
158
+ when :sqids
159
+ if defined?(Encoders::Sqids)
160
+ Encoders::Sqids.new(salt, length, alphabet, @blocklist)
161
+ else
162
+ raise InvalidConfigurationError, "Sqids encoder requested but the sqids gem is not available. Please add 'gem \"sqids\"' to your Gemfile."
163
+ end
164
+ when :hashids
165
+ Encoders::HashId.new(salt, length, alphabet, @blocklist)
166
+ else
167
+ raise InvalidConfigurationError, "The encoder name is not supported '#{encoder}'"
168
+ end
169
+ end
170
+
171
+ # @rbs (Symbol | Encoders::Base encoder) -> (Symbol | Encoders::Base)
172
+ def validate_encoder(encoder)
173
+ # Accept either a valid symbol or an Encoders::Base instance
174
+ return encoder if VALID_ENCODERS.include?(encoder) || encoder.is_a?(Encoders::Base)
175
+ raise InvalidConfigurationError, "Encoder must be one of: #{VALID_ENCODERS.join(", ")} or an instance of EncodedId::Encoders::Base"
113
176
  end
114
177
 
115
- def split_regex
116
- @split_regex ||= /.{#{split_at}}(?=.)/
178
+ # @rbs (Blocklist | Array[String] | Set[String] | nil blocklist) -> Blocklist
179
+ def validate_blocklist(blocklist)
180
+ return blocklist if blocklist.is_a?(Blocklist)
181
+ return Blocklist.empty if blocklist.nil?
182
+
183
+ return Blocklist.new(blocklist) if blocklist.is_a?(Array) || blocklist.is_a?(Set)
184
+
185
+ raise InvalidConfigurationError, "Blocklist must be an instance of Blocklist, a Set, or an Array of strings"
117
186
  end
118
187
 
188
+ # @rbs (String hash) -> String
119
189
  def humanize_length(hash)
120
- hash.gsub(split_regex, "\\0#{split_with}")
190
+ len = hash.length
191
+ at = split_at #: Integer
192
+ with = split_with #: String
193
+ return hash if len <= at
194
+
195
+ separator_count = (len - 1) / at
196
+ result = hash.dup
197
+ insert_offset = 0
198
+ (1..separator_count).each do |i|
199
+ insert_pos = i * at + insert_offset
200
+ result.insert(insert_pos, with)
201
+ insert_offset += with.length
202
+ end
203
+ result
121
204
  end
122
205
 
206
+ # @rbs (String str, bool downcase) -> String
123
207
  def convert_to_hash(str, downcase)
124
- clean = str.gsub(split_with, "")
125
- clean = clean.downcase if downcase
126
- map_equivalent_characters(clean)
208
+ str = str.gsub(split_with, "") if split_with
209
+ str = str.downcase if downcase
210
+ map_equivalent_characters(str)
127
211
  end
128
212
 
213
+ # @rbs (String str) -> String
129
214
  def map_equivalent_characters(str)
130
215
  return str unless alphabet.equivalences
131
216
 
@@ -135,6 +220,7 @@ module EncodedId
135
220
  end
136
221
  end
137
222
 
223
+ # @rbs (String str) -> bool
138
224
  def max_length_exceeded?(str)
139
225
  return false if max_length.nil?
140
226
 
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  module EncodedId
4
- VERSION = "1.0.0.rc5"
6
+ # @rbs VERSION: String
7
+ VERSION = "1.0.0.rc6"
5
8
  end
data/lib/encoded_id.rb CHANGED
@@ -1,26 +1,59 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  require_relative "encoded_id/version"
4
6
  require_relative "encoded_id/alphabet"
5
7
  require_relative "encoded_id/hex_representation"
6
-
7
- require_relative "encoded_id/hash_id_salt"
8
- require_relative "encoded_id/hash_id_consistent_shuffle"
9
- require_relative "encoded_id/ordinal_alphabet_separator_guards"
10
- require_relative "encoded_id/hash_id"
8
+ require_relative "encoded_id/blocklist"
9
+
10
+ # Load the encoder framework
11
+ require_relative "encoded_id/encoders/base"
12
+ require_relative "encoded_id/encoders/hash_id_salt"
13
+ require_relative "encoded_id/encoders/hash_id_consistent_shuffle"
14
+ require_relative "encoded_id/encoders/hash_id_ordinal_alphabet_separator_guards"
15
+ require_relative "encoded_id/encoders/hash_id"
16
+
17
+ # Only load Sqids encoder if the gem is available
18
+ begin
19
+ require "sqids"
20
+ require_relative "encoded_id/encoders/my_sqids"
21
+ require_relative "encoded_id/encoders/sqids"
22
+ rescue LoadError
23
+ # Sqids gem not available, encoder will not be loaded
24
+ end
11
25
 
12
26
  require_relative "encoded_id/reversible_id"
13
27
 
28
+ # @rbs!
29
+ # class Integer
30
+ # MAX: Integer
31
+ # end
32
+ #
33
+ # # Optional Sqids gem support
34
+ # module Sqids
35
+ # DEFAULT_BLOCKLIST: Array[String]
36
+ # end
37
+
14
38
  module EncodedId
39
+ # @rbs InvalidConfigurationError: singleton(StandardError)
15
40
  class InvalidConfigurationError < StandardError; end
16
41
 
42
+ # @rbs InvalidAlphabetError: singleton(ArgumentError)
17
43
  class InvalidAlphabetError < ArgumentError; end
18
44
 
45
+ # @rbs EncodedIdFormatError: singleton(ArgumentError)
19
46
  class EncodedIdFormatError < ArgumentError; end
20
47
 
48
+ # @rbs EncodedIdLengthError: singleton(ArgumentError)
21
49
  class EncodedIdLengthError < ArgumentError; end
22
50
 
51
+ # @rbs InvalidInputError: singleton(ArgumentError)
23
52
  class InvalidInputError < ArgumentError; end
24
53
 
54
+ # @rbs BlocklistError: singleton(StandardError)
55
+ class BlocklistError < StandardError; end
56
+
57
+ # @rbs SaltError: singleton(ArgumentError)
25
58
  class SaltError < ArgumentError; end
26
59
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: encoded_id
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.rc5
4
+ version: 1.0.0.rc6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Ierodiaconou
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
10
+ date: 2025-11-17 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: Encode your numerical IDs (eg record primary keys) into obfuscated strings
13
13
  that can be used in URLs. The obfuscated strings are reversible, so you can decode
@@ -20,54 +20,45 @@ executables: []
20
20
  extensions: []
21
21
  extra_rdoc_files: []
22
22
  files:
23
- - ".devcontainer/Dockerfile"
24
- - ".devcontainer/compose.yml"
25
- - ".devcontainer/devcontainer.json"
26
- - ".standard.yml"
27
23
  - CHANGELOG.md
28
- - Gemfile
29
24
  - LICENSE.txt
30
25
  - README.md
31
- - Rakefile
32
- - Steepfile
33
- - ext/encoded_id/extconf.rb
34
- - ext/encoded_id/extension.c
35
- - ext/encoded_id/hashids.c
36
- - ext/encoded_id/hashids.h
26
+ - context/encoded_id.md
37
27
  - lib/encoded_id.rb
38
28
  - lib/encoded_id/alphabet.rb
39
- - lib/encoded_id/hash_id.rb
40
- - lib/encoded_id/hash_id_consistent_shuffle.rb
41
- - lib/encoded_id/hash_id_salt.rb
29
+ - lib/encoded_id/blocklist.rb
30
+ - lib/encoded_id/encoders/base.rb
31
+ - lib/encoded_id/encoders/hash_id.rb
32
+ - lib/encoded_id/encoders/hash_id_consistent_shuffle.rb
33
+ - lib/encoded_id/encoders/hash_id_ordinal_alphabet_separator_guards.rb
34
+ - lib/encoded_id/encoders/hash_id_salt.rb
35
+ - lib/encoded_id/encoders/my_sqids.rb
36
+ - lib/encoded_id/encoders/sqids.rb
42
37
  - lib/encoded_id/hex_representation.rb
43
- - lib/encoded_id/ordinal_alphabet_separator_guards.rb
44
38
  - lib/encoded_id/reversible_id.rb
45
39
  - lib/encoded_id/version.rb
46
- - rbs_collection.yaml
47
- - sig/encoded_id.rbs
48
40
  homepage: https://github.com/stevegeek/encoded_id
49
41
  licenses:
50
42
  - MIT
51
43
  metadata:
52
44
  homepage_uri: https://github.com/stevegeek/encoded_id
53
45
  source_code_uri: https://github.com/stevegeek/encoded_id
54
- changelog_uri: https://github.com/stevegeek/encoded_id/blob/master/CHANGELOG.md
46
+ changelog_uri: https://github.com/stevegeek/encoded_id/blob/main/CHANGELOG.md
55
47
  rdoc_options: []
56
48
  require_paths:
57
49
  - lib
58
- - ext
59
50
  required_ruby_version: !ruby/object:Gem::Requirement
60
51
  requirements:
61
52
  - - ">="
62
53
  - !ruby/object:Gem::Version
63
- version: 2.7.0
54
+ version: 3.2.0
64
55
  required_rubygems_version: !ruby/object:Gem::Requirement
65
56
  requirements:
66
57
  - - ">="
67
58
  - !ruby/object:Gem::Version
68
59
  version: '0'
69
60
  requirements: []
70
- rubygems_version: 3.6.7
61
+ rubygems_version: 3.6.2
71
62
  specification_version: 4
72
63
  summary: EncodedId is a gem for creating reversible obfuscated IDs from numerical
73
64
  IDs. It uses an implementation of Hash IDs under the hood.
@@ -1,9 +0,0 @@
1
- # Make sure RUBY_VERSION matches the Ruby version in .ruby-version or gemspec
2
- ARG RUBY_VERSION=3.4.2
3
- FROM ghcr.io/rails/devcontainer/images/ruby:$RUBY_VERSION
4
-
5
- USER vscode
6
-
7
- # Ensure binding is always 0.0.0.0
8
- # Binds the server to all IP addresses of the container, so it can be accessed from outside the container.
9
- ENV BINDING="0.0.0.0"
@@ -1,8 +0,0 @@
1
- name: "encoded_id"
2
-
3
- services:
4
- encoded-id-dev-env:
5
- container_name: encoded-id-dev-env
6
- build:
7
- context: ..
8
- dockerfile: .devcontainer/Dockerfile
@@ -1,8 +0,0 @@
1
- {
2
- "name": "Encoded ID Gem Development",
3
- "dockerComposeFile": "compose.yml",
4
- "service": "encoded-id-dev-env",
5
- "postCreateCommand": "bundle install",
6
- "postStartCommand": "bundle exec rake test",
7
- "remoteUser": "vscode"
8
- }
data/.standard.yml DELETED
@@ -1,2 +0,0 @@
1
- parallel: true # default: false
2
- ruby_version: 3.3
data/Gemfile DELETED
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source "https://rubygems.org"
4
-
5
- # Specify your gem's dependencies in encoded_id.gemspec
6
- gemspec
7
-
8
- gem "rake"
9
-
10
- gem "minitest"
11
-
12
- gem "standard"
13
-
14
- # gem "rbs"
15
- #
16
- # gem "steep"
17
-
18
- gem "simplecov"
19
-
20
- gem "benchmark-ips"
21
-
22
- gem "benchmark-memory"
23
-
24
- gem "fuzzbert"
25
-
26
- gem "singed"
27
-
28
- gem "memory_profiler"
29
-
30
- gem "hashids" # For benchmarking against
31
-
32
- gem "base64"
33
-
34
- # gem "pf2", require: false, github: "osyoyu/pf2", branch: "main"
35
-
36
- # gem "vernier", require: false
data/Rakefile DELETED
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "bundler/gem_tasks"
4
- require "rake/testtask"
5
-
6
- Rake::TestTask.new(:test) do |t|
7
- t.libs << "test"
8
- t.libs << "lib"
9
- t.test_files = FileList["test/**/test_*.rb"]
10
- end
11
-
12
- task default: %i[test standard]
13
-
14
- task :compile_ext do
15
- puts "Compiling extension"
16
- `cd ext/encoded_id && make clean`
17
- `cd ext/encoded_id && ruby extconf.rb`
18
- `cd ext/encoded_id && make`
19
- puts "Done"
20
- end
data/Steepfile DELETED
@@ -1,5 +0,0 @@
1
- target :lib do
2
- signature "sig"
3
-
4
- check "lib"
5
- end
@@ -1,3 +0,0 @@
1
- require "mkmf"
2
-
3
- create_makefile "encoded_id/extension"
@@ -1,123 +0,0 @@
1
- #include "ruby/ruby.h"
2
- #include "hashids.h"
3
-
4
- void wrapped_hashids_free(void* data)
5
- {
6
- hashids_free(data);
7
- }
8
-
9
- size_t wrapped_hashids_size(const void* data)
10
- {
11
- return sizeof(hashids_t);
12
- }
13
-
14
- static const rb_data_type_t wrapped_hashids_type = {
15
- .wrap_struct_name = "hashids_t",
16
- .function = {
17
- .dmark = NULL,
18
- .dfree = wrapped_hashids_free,
19
- .dsize = wrapped_hashids_size,
20
- },
21
- .data = NULL,
22
- .flags = RUBY_TYPED_FREE_IMMEDIATELY,
23
- };
24
-
25
- VALUE hashids_alloc(VALUE self)
26
- {
27
- hashids_t *data = hashids_init("salt!");
28
- return TypedData_Wrap_Struct(self, &wrapped_hashids_type, data);
29
- }
30
-
31
- //VALUE rb_hashids_m_initialize(VALUE self, VALUE val)
32
- //{
33
- // return self;
34
- //}
35
-
36
-
37
- static VALUE rb_hash_id_c_encode(VALUE self, VALUE ids) {
38
- Check_Type(ids, T_ARRAY);
39
-
40
- long length = RARRAY_LEN(ids);
41
-
42
- unsigned long long* inputs = ALLOC_N(unsigned long long, length);
43
-
44
- for (long i = 0; i < length; i++) {
45
- VALUE rb_element = rb_ary_entry(ids, i);
46
- Check_Type(rb_element, T_FIXNUM);
47
- inputs[i] = NUM2ULL(rb_element);
48
- }
49
-
50
- hashids_t* hashids;
51
-
52
- TypedData_Get_Struct(self, hashids_t, &wrapped_hashids_type, hashids);
53
-
54
- size_t bytes_encoded;
55
-
56
- size_t bytes_needed;
57
- bytes_needed = hashids_estimate_encoded_size(hashids, sizeof(&inputs) / sizeof(unsigned long long), &inputs);
58
- char *hash = ALLOC_N(char, bytes_needed);
59
-
60
- // unsigned long long numbers[] = {1ull, 2ull, 3ull, 4ull, 5ull};
61
-
62
- // printf("length: %ld\n", length);
63
- // printf("inputs[0]: %llu\n", inputs[0]);
64
- // printf("inputs[1]: %llu\n", inputs[1]);
65
- // printf("inputs[2]: %llu\n", inputs[2]);
66
- // printf("inputs[3]: %llu\n", inputs[3]);
67
- // printf("inputs[4]: %llu\n", inputs[4]);
68
- //
69
- // printf("hashids: %p\n", hashids);
70
- // printf("hashids->alphabet: %s\n", hashids->alphabet);
71
- // printf("hashids->salt: %s\n", hashids->salt);
72
- // printf("hashids->min_hash_length: %lu\n", hashids->min_hash_length);
73
- // printf("numbers: %p\n", numbers);
74
- // printf("numbers[0]: %llu\n", numbers[0]);
75
- // printf("numbers[1]: %llu\n", numbers[1]);
76
- // printf("numbers[2]: %llu\n", numbers[2]);
77
- // printf("numbers[3]: %llu\n", numbers[3]);
78
- // printf("numbers[4]: %llu\n", numbers[4]);
79
- //
80
- // printf("sizeof(*inputs) / sizeof(unsigned long long): %lu\n", sizeof(*inputs) / sizeof(unsigned long long));
81
- // printf("sizeof(numbers) / sizeof(unsigned long long): %lu\n", sizeof(numbers) / sizeof(unsigned long long));
82
- // bytes_encoded = hashids_encode(hashids, hash, sizeof(numbers) / sizeof(unsigned long long), numbers);
83
- bytes_encoded = hashids_encode(hashids, hash, length, inputs);
84
-
85
- ruby_xfree(inputs);
86
- VALUE return_value = rb_str_new2(hash);
87
- ruby_xfree(hash);
88
- return return_value;
89
- }
90
-
91
- static VALUE rb_hash_id_c_decode(VALUE self, VALUE str) {
92
- Check_Type(str, T_STRING);
93
-
94
- hashids_t* hashids;
95
-
96
- TypedData_Get_Struct(self, hashids_t, &wrapped_hashids_type, hashids);
97
-
98
- size_t numbers_count = hashids_numbers_count(hashids, RSTRING_PTR(str));
99
-
100
- unsigned long long* numbers = ALLOC_N(unsigned long long, numbers_count);
101
-
102
- hashids_decode_safe(hashids, RSTRING_PTR(str), numbers, numbers_count);
103
-
104
- VALUE rb_numbers = rb_ary_new_capa(numbers_count);
105
-
106
- for (size_t i = 0; i < numbers_count; i++) {
107
- rb_ary_push(rb_numbers, ULL2NUM(numbers[i]));
108
- }
109
-
110
- ruby_xfree(numbers);
111
- return rb_numbers;
112
- }
113
-
114
- void Init_extension(void) {
115
- VALUE EncodedId = rb_define_module("EncodedId");
116
- VALUE HashIdC = rb_define_class_under(EncodedId, "HashIdC", rb_cObject);
117
-
118
- rb_define_alloc_func(HashIdC, hashids_alloc);
119
- // rb_define_method(HashIdC, "initialize", rb_hashids_m_initialize, 1);
120
-
121
- rb_define_method(HashIdC, "encode", rb_hash_id_c_encode, 1);
122
- rb_define_method(HashIdC, "decode", rb_hash_id_c_decode, 1);
123
- }