youyouaidi-revised 1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0d00be139d3bf97f8c7e3dacd0877003cd2eb582c8ce08397dcd12a4f7dc7df7
4
+ data.tar.gz: 6b0a86e0cb1a3e1e416a3167fa00a0fcb99f2f8b4bab381f48def1fda72daa8e
5
+ SHA512:
6
+ metadata.gz: b1c691c8e485b3954e1bc79316f70147c9207b56ff378ab1eaceba6faf06f478b7dcc51b866b884098e053b463baef709471206ec8501764f30245d5e119e747
7
+ data.tar.gz: b7049ffa8d4c7c805b0edc1426ff63dc5fe3d60a70389f333967fd6086346dfc94374cf034888f3e739a4d99a3dd171e545bca062a367eb328cc6b2ba7d743e8
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --backtrace
data/.rubocop.yml ADDED
@@ -0,0 +1,80 @@
1
+ # .rubocop.yml
2
+ AllCops:
3
+ TargetRubyVersion: 2.7
4
+
5
+ Style/Documentation:
6
+ Enabled: false
7
+
8
+
9
+ Gemspec/DateAssignment: # (new in 1.10)
10
+ Enabled: true
11
+ Layout/LineEndStringConcatenationIndentation: # (new in 1.18)
12
+ Enabled: true
13
+ Layout/SpaceBeforeBrackets: # (new in 1.7)
14
+ Enabled: true
15
+ Lint/AmbiguousAssignment: # (new in 1.7)
16
+ Enabled: true
17
+ Lint/DeprecatedConstants: # (new in 1.8)
18
+ Enabled: true
19
+ Lint/DuplicateBranch: # (new in 1.3)
20
+ Enabled: true
21
+ Lint/DuplicateRegexpCharacterClassElement: # (new in 1.1)
22
+ Enabled: true
23
+ Lint/EmptyBlock: # (new in 1.1)
24
+ Enabled: true
25
+ Lint/EmptyClass: # (new in 1.3)
26
+ Enabled: true
27
+ Lint/EmptyInPattern: # (new in 1.16)
28
+ Enabled: true
29
+ Lint/LambdaWithoutLiteralBlock: # (new in 1.8)
30
+ Enabled: true
31
+ Lint/NoReturnInBeginEndBlocks: # (new in 1.2)
32
+ Enabled: true
33
+ Lint/NumberedParameterAssignment: # (new in 1.9)
34
+ Enabled: true
35
+ Lint/OrAssignmentToConstant: # (new in 1.9)
36
+ Enabled: true
37
+ Lint/RedundantDirGlobSort: # (new in 1.8)
38
+ Enabled: true
39
+ Lint/SymbolConversion: # (new in 1.9)
40
+ Enabled: true
41
+ Lint/ToEnumArguments: # (new in 1.1)
42
+ Enabled: true
43
+ Lint/TripleQuotes: # (new in 1.9)
44
+ Enabled: true
45
+ Lint/UnexpectedBlockArity: # (new in 1.5)
46
+ Enabled: true
47
+ Lint/UnmodifiedReduceAccumulator: # (new in 1.1)
48
+ Enabled: true
49
+ Naming/InclusiveLanguage: # (new in 1.18)
50
+ Enabled: true
51
+ Style/ArgumentsForwarding: # (new in 1.1)
52
+ Enabled: true
53
+ Style/CollectionCompact: # (new in 1.2)
54
+ Enabled: true
55
+ Style/DocumentDynamicEvalDefinition: # (new in 1.1)
56
+ Enabled: true
57
+ Style/EndlessMethod: # (new in 1.8)
58
+ Enabled: true
59
+ Style/HashConversion: # (new in 1.10)
60
+ Enabled: true
61
+ Style/HashExcept: # (new in 1.7)
62
+ Enabled: true
63
+ Style/IfWithBooleanLiteralBranches: # (new in 1.9)
64
+ Enabled: true
65
+ Style/InPatternThen: # (new in 1.16)
66
+ Enabled: true
67
+ Style/MultilineInPatternThen: # (new in 1.16)
68
+ Enabled: true
69
+ Style/NegatedIfElseCondition: # (new in 1.2)
70
+ Enabled: true
71
+ Style/NilLambda: # (new in 1.3)
72
+ Enabled: true
73
+ Style/QuotedSymbols: # (new in 1.16)
74
+ Enabled: true
75
+ Style/RedundantArgument: # (new in 1.4)
76
+ Enabled: true
77
+ Style/StringChars: # (new in 1.12)
78
+ Enabled: true
79
+ Style/SwapValues: # (new in 1.1)
80
+ Enabled: true
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.0
4
+ - 2.0.0
5
+ - 1.9.3
6
+ - jruby-19mode
7
+ - rbx
8
+ - ruby-head
9
+ - jruby-head
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ group :test do
6
+ gem 'coveralls', require: false
7
+ gem 'pry'
8
+ gem 'rake', '~> 10.1'
9
+ gem 'rspec'
10
+ gem 'rspec-collection_matchers'
11
+ gem 'rspec-its'
12
+ end
13
+
14
+ # Specify your gem's dependencies in youyouaidi.gemspec
15
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Nicolas Fricke
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # Youyouaidi revised
2
+
3
+ `Youyouaidi revised` is a Ruby Gem that offers a UUID class for **generating**, **parsing**, **validating** and **converting** UUIDs into / from **shorter representations**.
4
+
5
+ This gem is a fork of the unmaintained repo at http://github.com/nicolas-fricke/youyouaidi. Many thanks to the original author! 😊
6
+
7
+ While a **UUID consists of 36 characters** – 32 hexadecimal characters, divided by four dashes into five subgroups – the **short representation** (invoked via `#to_short_string`) consists of exactly **22 digit and lower- and uppercase characters**.
8
+
9
+ This is what a valid, random (version 4) UUID looks like:
10
+ ```
11
+ version either 8, 9
12
+ number a, or b
13
+ ▼ ▼
14
+ caed3f49-b0ca-454b-adf8-5ee2a1764759
15
+ # chars in group: 8 | 4 | 4 | 4 | 12
16
+ ```
17
+ As shown, the first digit of the third group indicates the UUID version.
18
+ The first digit of the fourth group always has to be one of either `8`, `9`, `a`, or `b`.
19
+ All other digits are randomly assigned hexadecimals.
20
+
21
+ And this is the same UUID in its short format: `6aUS5foeLu2VGDspRPc7bz`.
22
+
23
+ For UUID generation, the `SecureRandom.uuid` method is used which generates valid, random *version 4* UUIDs.
24
+
25
+ Find out more about UUIDs and the different versions on [Wikipedia](https://en.wikipedia.org/wiki/Uuid).
26
+
27
+ ## Installation
28
+
29
+ Add this line to your application's Gemfile:
30
+
31
+ gem 'youyouaidi-revised'
32
+
33
+ And then execute:
34
+
35
+ $ bundle
36
+
37
+ Or install it yourself as:
38
+
39
+ $ gem install youyouaidi-revised
40
+
41
+ ## Usage
42
+
43
+ `UUID(...)` **was** patched in the kernel. Not anymore. We don't patch the kernel unless we have no other choice.
44
+
45
+ ### Initializing UUIDs
46
+
47
+ ```ruby
48
+ uuid_string = '550e8400-e29b-41d4-a716-446655440000' # A valid UUID in string format, has exactly 32 hexadecimal characters in 5 groups
49
+ uuid_short = '2AuYQJcZeiIeCymkJ7tzTW' # Same UUID in its short format, has exactly 22 characters of [0-9a-zA-Z]
50
+
51
+ uuid = Youyouaidi::UUID uuid_string # creates new Youyouaidi::UUID object
52
+ # => #<Youyouaidi::UUID:0x000001021f2590 @converter=Youyouaidi::Converter, @uuid="550e8400-e29b-41d4-a716-446655440000">
53
+
54
+ # Alternatively a short UUID can be passed:
55
+ uuid = Youyouaidi::UUID uuid_short # creates similar Youyouaidi::UUID object
56
+ # => #<Youyouaidi::UUID:0x00000102201b80 @converter=Youyouaidi::Converter, @uuid="550e8400-e29b-41d4-a716-446655440000">
57
+
58
+ # To generate a new random UUID simply do not pass a parameter:
59
+ new_uuid = Youyouaidi::UUID.new # generates a random UUID version 4 using the SecureRandom.uuid method
60
+ # => #<Youyouaidi::UUID:0x00000102201b80 @converter=Youyouaidi::Converter, @uuid="27f8bc29-be8e-4dc7-ab30-0295b2a5e902">
61
+ ```
62
+
63
+
64
+ ### Validity check and conversions
65
+
66
+ The validity check `Youyouaidi::UUID.valid? uuid_string` checks, if UUID contains exactly 32 hexadecimal characters which are divided by four dashes ('-') into five groups of sizes 8, 4, 4, 4, and 12.
67
+ Also, it validates that the first character of the fourth group is either a `8`, `9`, an `a`, or a `b`.
68
+
69
+ ```ruby
70
+ uuid_string = '550e8400-e29b-41d4-a716-446655440000' # A valid UUID in string format
71
+ uuid = Youyouaidi::UUID uuid_string
72
+
73
+ Youyouaidi::UUID.valid? uuid_string # Checks if `uuid_string' is a valid UUID, same as Youyouaidi::UUID.valid? uuid_string
74
+ # => true
75
+
76
+ uuid.to_s # Returns the string representation of the UUID object
77
+ # => '550e8400-e29b-41d4-a716-446655440000'
78
+
79
+ uuid.to_short_string # Returns the short string representation of the UUID object, #to_param is an alias for this method
80
+ # => '2AuYQJcZeiIeCymkJ7tzTW'
81
+ ```
82
+
83
+
84
+ ### Comparing UUIDs
85
+
86
+ ```ruby
87
+ uuid_string = '550e8400-e29b-41d4-a716-446655440000' # A valid UUID in string format
88
+ uuid = Youyouaidi::UUID.parse uuid_string
89
+ similar_uuid = Youyouaidi::UUID.parse uuid_string
90
+ other_uuid = Youyouaidi::UUID.parse '00000000-1111-2222-aaaa-eeeeeeeeeeee'
91
+
92
+ uuid == similar_uuid # Two UUID objects representing same UUID (#=== behaves similar for this)
93
+ # => true
94
+
95
+ uuid == other_uuid # Two UUID objects representing different UUIDs (#=== behaves similar for this)
96
+ # => false
97
+
98
+ uuid == uuid_string # Comparing a UUID object and its string representation with `=='
99
+ # => false
100
+
101
+ uuid === uuid_string # Comparing a UUID object and its string representation with `===' (case insensetive)
102
+ # => true
103
+ ```
104
+
105
+ ## Contributing
106
+
107
+ 1. Fork it ( http://github.com/lorankloeze/youyouaidi-revised/fork )
108
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
109
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
110
+ 4. Push to the branch (`git push origin my-new-feature`)
111
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+ task default: :spec
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Based on Base62 module by sinefunc
4
+ # => https://github.com/sinefunc/base62
5
+ module Youyouaidi
6
+ class Converter
7
+ class << self
8
+ def encode(uuid)
9
+ base_encode uuid.to_i
10
+ end
11
+
12
+ def decode(encoded_uuid)
13
+ encoded_uuid = encoded_uuid.to_s
14
+ unless encoded_uuid.length == ENCODED_LENGTH
15
+ raise Youyouaidi::InvalidUUIDError,
16
+ "`#{encoded_uuid}' needs to have exactly #{ENCODED_LENGTH} characters (has #{encoded_uuid.length})"
17
+ end
18
+
19
+ begin
20
+ Youyouaidi::UUID.new convert_bignum_to_uuid_string base_decode encoded_uuid
21
+ rescue Youyouaidi::InvalidUUIDError => e
22
+ raise Youyouaidi::InvalidUUIDError, "`#{encoded_uuid}' could not be decoded to a valid UUID (#{e.message})"
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ BASE = ('0'..'9').to_a + ('a'..'z').to_a + ('A'..'Z').to_a
29
+ ENCODED_LENGTH = 22 # Needs to be greater than `(Math.log 2**128, BASE.length).floor + 1`
30
+
31
+ def base_encode(numeric)
32
+ raise Youyouaidi::InvalidUUIDError, "`#{numeric}' needs to be a Numeric" unless numeric.is_a? Numeric
33
+
34
+ return '0' if numeric.zero?
35
+
36
+ s = String.new
37
+
38
+ while numeric.positive?
39
+ s << BASE[numeric.modulo(BASE.size)]
40
+ numeric /= BASE.size
41
+ end
42
+ s << BASE[0] while s.length < ENCODED_LENGTH
43
+ s.reverse
44
+ end
45
+
46
+ def base_decode(encoded_numeric)
47
+ s = encoded_numeric.to_s.reverse.chars
48
+
49
+ total = 0
50
+ s.each_with_index do |char, index|
51
+ ord = BASE.index(char)
52
+ unless ord
53
+ (raise Youyouaidi::InvalidUUIDError, "`#{encoded_numeric}' has `#{char}' which is not a valid character")
54
+ end
55
+
56
+ total += ord * (BASE.size**index)
57
+ end
58
+ total
59
+ end
60
+
61
+ def convert_bignum_to_uuid_string(decoded_uuid_bignum)
62
+ decoded_uuid = decoded_uuid_bignum.to_i.to_s(16).rjust(32, '0')
63
+ "#{decoded_uuid[0,
64
+ 8]}-#{decoded_uuid[8, 4]}-#{decoded_uuid[12, 4]}-#{decoded_uuid[16, 4]}-#{decoded_uuid[20, 12]}"
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Youyouaidi
4
+ class InvalidUUIDError < TypeError
5
+ end
6
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module Youyouaidi
6
+ # Main class
7
+ class UUID
8
+ attr_reader :uuid
9
+
10
+ def initialize(uuid_string = nil, options = {})
11
+ @converter = options[:converter] || Youyouaidi::Converter
12
+ if uuid_string
13
+ initialize_with_uuid_string uuid_string
14
+ else
15
+ initialize_without_param
16
+ end
17
+ end
18
+
19
+ def ==(other)
20
+ return false unless other.is_a? self.class
21
+
22
+ to_s == other.to_s
23
+ end
24
+
25
+ def ===(other_object)
26
+ return true if self == other_object
27
+
28
+ to_s == other_object.to_s.downcase
29
+ end
30
+
31
+ def to_i
32
+ @uuid.gsub('-', '').hex
33
+ end
34
+
35
+ def to_s
36
+ @uuid
37
+ end
38
+
39
+ def to_short_string
40
+ @converter.encode self
41
+ end
42
+ alias to_param to_short_string
43
+
44
+ private
45
+
46
+ def initialize_without_param
47
+ @uuid = SecureRandom.uuid
48
+ end
49
+
50
+ def initialize_with_uuid_string(uuid_string)
51
+ unless self.class.valid? uuid_string
52
+ raise Youyouaidi::InvalidUUIDError, "`#{uuid_string}' does not look like a valid UUID"
53
+ end
54
+
55
+ @uuid = uuid_string.to_s.downcase
56
+ end
57
+
58
+ class << self
59
+ def parse(uuid_param = nil, options = {})
60
+ @converter = options[:converter] || Youyouaidi::Converter
61
+ if valid? uuid_param
62
+ new uuid_param.to_s, options
63
+ elsif uuid_param.nil?
64
+ new nil, options
65
+ else
66
+ @converter.decode uuid_param
67
+ end
68
+ end
69
+
70
+ def valid?(uuid_canidate)
71
+ !(uuid_canidate.to_s =~ /^[\da-f]{8}(-[\da-f]{4}){2}-[89ab][\da-f]{3}-[\da-f]{12}$/i).nil?
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Youyouaidi
4
+ VERSION = '1.0'
5
+ end
data/lib/youyouaidi.rb ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'youyouaidi/version'
4
+
5
+ module Youyouaidi
6
+ # Your code goes here...
7
+ require 'youyouaidi/uuid'
8
+ require 'youyouaidi/invalid_uuid'
9
+ require 'youyouaidi/converter'
10
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Kernel do
6
+ describe '.UUID' do
7
+ it 'is removed' do
8
+ expect { UUID }.to raise_error(NameError)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec'
4
+ require 'rspec/its'
5
+ require 'rspec/collection_matchers'
6
+ require 'pry'
7
+
8
+ # Code coverage statistics at coveralls.io: https://coveralls.io/r/nicolas-fricke/youyouaidi
9
+ # Do not generate coverage when using Rubinius, see: https://github.com/lemurheavy/coveralls-public/issues/144
10
+ if ENV['CI'] || (defined?(:RUBY_ENGINE) && RUBY_ENGINE != 'rbx')
11
+ require 'coveralls'
12
+ Coveralls.wear! do
13
+ add_filter 'spec'
14
+ end
15
+ end
16
+
17
+ require 'bundler'
18
+ Bundler.require
19
+
20
+ require 'youyouaidi'
21
+
22
+ RSpec.configure do |config|
23
+ # ## Mock Framework
24
+ #
25
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
26
+ #
27
+ # config.mock_with :mocha
28
+ # config.mock_with :flexmock
29
+ # config.mock_with :rr
30
+
31
+ # Run specs in random order to surface order dependencies. If you find an
32
+ # order dependency and want to debug it, you can fix the order by providing
33
+ # the seed, which is printed after each run.
34
+ # --seed 1234
35
+ config.order = 'random'
36
+
37
+ # Raise error when using old :should expectation syntax.
38
+ # config.raise_errors_for_deprecations!
39
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ # rubocop:disable Metrics/BlockLength
6
+ describe Youyouaidi::Converter do
7
+ shared_examples_for 'a call that raises a Youyouaidi::InvalidUUIDError with a meaningful error message' do
8
+ describe 'raises error' do
9
+ subject { -> { action } }
10
+ it { should raise_error Youyouaidi::InvalidUUIDError }
11
+ describe 'error message' do
12
+ let(:caught_error) do
13
+ action
14
+ return nil
15
+ rescue Youyouaidi::InvalidUUIDError => e
16
+ return e
17
+ end
18
+ subject { caught_error }
19
+ it { should_not be_nil }
20
+ its(:message) { should include(*error_message_includes) }
21
+ end
22
+ end
23
+ end
24
+
25
+ let(:uuid) { Youyouaidi::UUID.new uuid_string }
26
+ let(:uuid_string) { '550e8400-e29b-41d4-a716-446655440000' }
27
+ let(:encoded_uuid) { '2AuYQJcZeiIeCymkJ7tzTW' }
28
+
29
+ uuids_with_encoding = {
30
+ '550e8400-e29b-41d4-a716-446655440000' => '2AuYQJcZeiIeCymkJ7tzTW',
31
+ '00000000-bbbb-2222-8888-000000000000' => '000001dyObGywDRlcScExy'
32
+ }
33
+
34
+ describe 'use case' do
35
+ subject { described_class.decode described_class.encode(uuid) }
36
+
37
+ it { should be_a Youyouaidi::UUID }
38
+ its(:to_s) { should eq uuid_string }
39
+ end
40
+
41
+ describe 'methods' do
42
+ describe '.encode' do
43
+ subject { described_class.encode uuid }
44
+
45
+ uuids_with_encoding.each do |valid_uuid, encoded_uuid|
46
+ context "for uuid `#{valid_uuid}'" do
47
+ let(:uuid_string) { valid_uuid }
48
+ it { should have(22).characters }
49
+ it { should eq encoded_uuid }
50
+ end
51
+ end
52
+ end
53
+
54
+ describe '.decode' do
55
+ let(:action) { described_class.decode encoded_param }
56
+
57
+ context 'with valid param' do
58
+ subject { action }
59
+
60
+ uuids_with_encoding.each do |valid_uuid, encoded_uuid|
61
+ context "for encoded uuid `#{encoded_uuid}'" do
62
+ let(:encoded_param) { encoded_uuid }
63
+ it { should be_a Youyouaidi::UUID }
64
+ its(:to_s) { should eq valid_uuid }
65
+ end
66
+ end
67
+ end
68
+
69
+ context 'with invalid param' do
70
+ subject { -> { action } }
71
+ context 'looking correct but converting to a non-valid UUID' do
72
+ let(:encoded_param) { 'qEsRTcgdJFVugbBqtaEoNf' }
73
+ let(:decoded_invalid_uuid) { '36bb9153-3a5a-1570-de9d-6faed4f1ceb0' }
74
+ let(:error_message_includes) { ["`#{encoded_param}'", "`#{decoded_invalid_uuid}'"] }
75
+ it_behaves_like 'a call that raises a Youyouaidi::InvalidUUIDError with a meaningful error message'
76
+ end
77
+
78
+ context 'with invalid characters' do
79
+ let(:invalid_char) { '_' }
80
+ let(:encoded_param) { "#{invalid_char}#{encoded_uuid[1..]}" }
81
+ let(:error_message_includes) { ["`#{encoded_param}'", "`#{invalid_char}'"] }
82
+ it_behaves_like 'a call that raises a Youyouaidi::InvalidUUIDError with a meaningful error message'
83
+ end
84
+
85
+ shared_examples_for 'a call with incorrect param string length' do
86
+ let(:error_message_includes) { ["`#{encoded_param}'", '22', encoded_param.length.to_s] }
87
+ it_behaves_like 'a call that raises a Youyouaidi::InvalidUUIDError with a meaningful error message'
88
+ end
89
+
90
+ context 'with too long encoded param' do
91
+ let(:encoded_param) { "#{encoded_uuid}abc" }
92
+ it_behaves_like 'a call with incorrect param string length'
93
+ end
94
+
95
+ context 'with too short encoded param' do
96
+ let(:encoded_param) { encoded_uuid[0..-3].to_s }
97
+ it_behaves_like 'a call with incorrect param string length'
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ # rubocop:enable Metrics/BlockLength
@@ -0,0 +1,261 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ # rubocop:disable Metrics/BlockLength
6
+ describe Youyouaidi::UUID do
7
+ shared_examples_for 'a call that raises a Youyouaidi::InvalidUUIDError with a meaningful error message' do
8
+ describe 'raises error' do
9
+ subject { -> { action } }
10
+ it { should raise_error Youyouaidi::InvalidUUIDError }
11
+ describe 'error message' do
12
+ let(:caught_error) do
13
+ action
14
+ return nil
15
+ rescue Youyouaidi::InvalidUUIDError => e
16
+ return e
17
+ end
18
+ subject { caught_error }
19
+ it { should_not be_nil }
20
+ its(:message) { should include(*error_message_includes) }
21
+ end
22
+ end
23
+ end
24
+
25
+ describe '.new' do
26
+ let(:param) { '' }
27
+ let(:action) { Youyouaidi::UUID.new param }
28
+ subject { -> { action } }
29
+
30
+ context 'without a param' do
31
+ let(:action) { Youyouaidi::UUID.new }
32
+ subject { action }
33
+
34
+ it { should be_a Youyouaidi::UUID }
35
+ describe 'having a valid UUID version 4' do
36
+ subject { action.to_s }
37
+
38
+ it { should be_a String }
39
+ it { should have(36).characters }
40
+ it { should match(/[\da-f]{8}-[\da-f]{4}-4[\da-f]{3}-[89ab][\da-f]{3}-[\da-f]{12}/i) }
41
+ end
42
+ end
43
+
44
+ context 'with valid uuid string' do
45
+ subject { action }
46
+
47
+ valid_uuids = %w[550e8400-e29b-41d4-a716-446655440000
48
+ 00000000-bbbb-2222-8888-000000000000]
49
+
50
+ valid_uuids.each do |valid_uuid|
51
+ context "for uuid `#{valid_uuid}'" do
52
+ let(:param) { valid_uuid }
53
+ it { should be_a Youyouaidi::UUID }
54
+ its(:to_s) { should eq param }
55
+ end
56
+ end
57
+ end
58
+
59
+ context 'with valid uuid in short format' do
60
+ let(:param) { '2AuYQJcZeiIeCymkJ7tzTW' }
61
+ let(:error_message_includes) { "`#{param}'" }
62
+ it_behaves_like 'a call that raises a Youyouaidi::InvalidUUIDError with a meaningful error message'
63
+ end
64
+
65
+ context 'with invalid uuid string' do
66
+ let(:param) { 'Kekse' }
67
+ let(:error_message_includes) { "`#{param}'" }
68
+ it_behaves_like 'a call that raises a Youyouaidi::InvalidUUIDError with a meaningful error message'
69
+ end
70
+
71
+ context 'with non-uuid-string input' do
72
+ let(:param) { 1234 }
73
+ let(:error_message_includes) { "`#{param}'" }
74
+ it_behaves_like 'a call that raises a Youyouaidi::InvalidUUIDError with a meaningful error message'
75
+ end
76
+ end
77
+
78
+ describe '.parse' do
79
+ let(:param) { '' }
80
+ let(:action) { Youyouaidi::UUID.parse param }
81
+ subject { action }
82
+
83
+ context 'with valid uuid string' do
84
+ let(:param) { '550e8400-e29b-41d4-a716-446655440000' }
85
+
86
+ it { should be_a Youyouaidi::UUID }
87
+ end
88
+
89
+ context 'with uuid in short format' do
90
+ let(:param) { '2AuYQJcZeiIeCymkJ7tzTW' }
91
+ let(:decoded_uuid) { '550e8400-e29b-41d4-a716-446655440000' }
92
+
93
+ it { should be_a Youyouaidi::UUID }
94
+ its(:to_s) { should eq decoded_uuid }
95
+ end
96
+
97
+ context 'with invalid uuid string' do
98
+ let(:param) { 'Kekse' }
99
+ let(:error_message_includes) { "`#{param}'" }
100
+ it_behaves_like 'a call that raises a Youyouaidi::InvalidUUIDError with a meaningful error message'
101
+ end
102
+
103
+ context 'with non-string input' do
104
+ let(:param) { 1234 }
105
+ let(:error_message_includes) { "`#{param}'" }
106
+ it_behaves_like 'a call that raises a Youyouaidi::InvalidUUIDError with a meaningful error message'
107
+ end
108
+ end
109
+
110
+ shared_examples_for 'equality check for two UUID objects' do
111
+ let(:first_uuid_string) { 'aaaaaaaa-eeee-4444-aaaa-444444444444' }
112
+ let(:second_uuid_string) { '00000000-bbbb-2222-8888-000000000000' }
113
+ let(:first_uuid) { Youyouaidi::UUID.new first_uuid_string }
114
+ let(:second_uuid) { Youyouaidi::UUID.new second_uuid_string }
115
+
116
+ subject { action }
117
+
118
+ context 'passing a UUID object' do
119
+ context 'when comparing same instance' do
120
+ let(:action) { first_uuid.send described_method, first_uuid }
121
+ it { should be_truthy }
122
+ end
123
+
124
+ context 'when comparing different instances' do
125
+ let(:action) { first_uuid.send described_method, second_uuid }
126
+ context 'with same UUID strings' do
127
+ let(:second_uuid_string) { first_uuid_string }
128
+ it { should be_truthy }
129
+ end
130
+
131
+ context 'with different UUID strings' do
132
+ it { should be_falsey }
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ describe '#== (equal operator)' do
139
+ let(:uuid_string) { 'aaaaaaaa-eeee-4444-aaaa-444444444444' }
140
+ let(:uuid) { Youyouaidi::UUID.new uuid_string }
141
+
142
+ let(:described_method) { :== }
143
+ it_behaves_like 'equality check for two UUID objects'
144
+
145
+ subject { action }
146
+
147
+ context 'passing a non-UUID object' do
148
+ let(:action) { uuid == test_object }
149
+
150
+ context 'when this is the UUID as string' do
151
+ let(:test_object) { uuid_string }
152
+ it { should be_falsey }
153
+ end
154
+
155
+ context 'when this is a random other object' do
156
+ let(:test_object) { '123' }
157
+ it { should be_falsey }
158
+ end
159
+ end
160
+ end
161
+
162
+ describe '#=== (equal operator)' do
163
+ let(:uuid_string) { 'aaaaaaaa-eeee-4444-aaaa-444444444444' }
164
+ let(:uuid) { Youyouaidi::UUID.new uuid_string }
165
+
166
+ let(:described_method) { :=== }
167
+ it_behaves_like 'equality check for two UUID objects'
168
+
169
+ subject { action }
170
+
171
+ context 'passing a non-UUID object' do
172
+ # rubocop:disable Style/CaseEquality
173
+ let(:action) { uuid === test_object }
174
+ # rubocop:enable Style/CaseEquality
175
+
176
+ context 'when this is the same UUID as string' do
177
+ context 'when string is upcase' do
178
+ let(:test_object) { uuid_string.upcase }
179
+ it { should be_truthy }
180
+ end
181
+ context 'when string is downcase' do
182
+ let(:test_object) { uuid_string.downcase }
183
+ it { should be_truthy }
184
+ end
185
+ end
186
+
187
+ context 'when this is a random other object' do
188
+ let(:test_object) { '123' }
189
+ it { should be_falsey }
190
+ end
191
+ end
192
+ end
193
+
194
+ describe '#to_s' do
195
+ let(:uuid_string) { '550e8400-e29b-41d4-a716-446655440000' }
196
+ let(:uuid) { Youyouaidi::UUID.new uuid_string }
197
+ subject { uuid.to_s }
198
+
199
+ it { should be_a String }
200
+ it { should eq uuid_string }
201
+ end
202
+
203
+ describe '#to_i' do
204
+ let(:uuid_string) { '550e8400-e29b-41d4-a716-446655440000' }
205
+ let(:uuid) { Youyouaidi::UUID.new uuid_string }
206
+ subject { uuid.to_i }
207
+
208
+ it { should be_a Integer }
209
+ it { should eq 113_059_749_145_936_325_402_354_257_176_981_405_696 }
210
+ end
211
+
212
+ shared_examples_for 'method for short format' do
213
+ let(:uuid_string) { '550e8400-e29b-41d4-a716-446655440000' }
214
+ let(:encoded_uuid) { '2AuYQJcZeiIeCymkJ7tzTW' }
215
+ let(:uuid) { Youyouaidi::UUID.new uuid_string }
216
+
217
+ let(:action) { uuid.send method }
218
+ subject { action }
219
+
220
+ it { should be_a String }
221
+ it { should eq encoded_uuid }
222
+ end
223
+ describe '#to_short_string' do
224
+ let(:method) { :to_short_string }
225
+ it_behaves_like 'method for short format'
226
+ end
227
+ describe '#to_param' do
228
+ let(:method) { :to_param }
229
+ it_behaves_like 'method for short format'
230
+ end
231
+
232
+ describe '.valid?' do
233
+ let(:param) { '' }
234
+ subject { Youyouaidi::UUID.valid? param }
235
+
236
+ context 'with valid uuid' do
237
+ valid_uuids = %w[550e8400-e29b-41d4-a716-446655440000
238
+ 27f8bc29-be8e-4dc7-8b30-0295b2a5e902]
239
+
240
+ valid_uuids.each do |valid_uuid|
241
+ it "should return true for `#{valid_uuid}`" do
242
+ expect(Youyouaidi::UUID.valid?(valid_uuid)).to eq true
243
+ end
244
+ end
245
+ end
246
+
247
+ context 'with invalid uuid' do
248
+ uuid_string = '550e8400-e29b-41d4-a716-446655440000'
249
+ encoded_uuid = '2AuYQJcZeiIeCymkJ7tzTW'
250
+ invalid_uuids = ['Kekse', "aa#{uuid_string}", "#{uuid_string}bb",
251
+ encoded_uuid.to_s, '550e8400-e29b-41d4-2716-446655440000']
252
+
253
+ invalid_uuids.each do |invalid_uuid|
254
+ it "should return false for `#{invalid_uuid}`" do
255
+ expect(Youyouaidi::UUID.valid?(invalid_uuid)).to eq false
256
+ end
257
+ end
258
+ end
259
+ end
260
+ end
261
+ # rubocop:enable Metrics/BlockLength
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'youyouaidi/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'youyouaidi-revised'
9
+ spec.version = Youyouaidi::VERSION
10
+ spec.authors = ['Nicolas Fricke', 'Loran Kloeze']
11
+ spec.email = ['mail@nicolasfricke.de', 'loran@freedomnet.nl']
12
+ spec.summary = 'UUID class'
13
+ spec.description = 'Youyouaidi offers a UUID class for parsing, validating and encoding UUIDs'
14
+ spec.homepage = 'https://github.com/LoranKloeze/youyouaidi-revised'
15
+ spec.license = 'MIT'
16
+ spec.required_ruby_version = '>= 2.7.4'
17
+
18
+ spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.add_development_dependency 'bundler', '~> 2.0'
24
+ spec.add_development_dependency 'rake', '~> 10.5'
25
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: youyouaidi-revised
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.0'
5
+ platform: ruby
6
+ authors:
7
+ - Nicolas Fricke
8
+ - Loran Kloeze
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2021-11-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '2.0'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '2.0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '10.5'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '10.5'
42
+ description: Youyouaidi offers a UUID class for parsing, validating and encoding UUIDs
43
+ email:
44
+ - mail@nicolasfricke.de
45
+ - loran@freedomnet.nl
46
+ executables: []
47
+ extensions: []
48
+ extra_rdoc_files: []
49
+ files:
50
+ - ".gitignore"
51
+ - ".rspec"
52
+ - ".rubocop.yml"
53
+ - ".travis.yml"
54
+ - Gemfile
55
+ - LICENSE.txt
56
+ - README.md
57
+ - Rakefile
58
+ - lib/youyouaidi.rb
59
+ - lib/youyouaidi/converter.rb
60
+ - lib/youyouaidi/invalid_uuid.rb
61
+ - lib/youyouaidi/uuid.rb
62
+ - lib/youyouaidi/version.rb
63
+ - spec/kernel_patch_spec.rb
64
+ - spec/spec_helper.rb
65
+ - spec/youyouaidi/converter_spec.rb
66
+ - spec/youyouaidi/uuid_spec.rb
67
+ - youyouaidi-revised.gemspec
68
+ homepage: https://github.com/LoranKloeze/youyouaidi-revised
69
+ licenses:
70
+ - MIT
71
+ metadata: {}
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: 2.7.4
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ requirements: []
87
+ rubygems_version: 3.1.6
88
+ signing_key:
89
+ specification_version: 4
90
+ summary: UUID class
91
+ test_files:
92
+ - spec/kernel_patch_spec.rb
93
+ - spec/spec_helper.rb
94
+ - spec/youyouaidi/converter_spec.rb
95
+ - spec/youyouaidi/uuid_spec.rb