youyouaidi-revised 1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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