110 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Ruby
		
	
	
	
			
		
		
	
	
			110 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Ruby
		
	
	
	
| # frozen_string_literal: true
 | |
| 
 | |
| # A serializer for boolean values being stored in Redis.
 | |
| #
 | |
| # This is to ensure that booleans are stored in a consistent and
 | |
| # testable way when being stored as strings in Redis.
 | |
| #
 | |
| # Examples:
 | |
| #
 | |
| #     bool = Gitlab::Redis::Boolean.new(true)
 | |
| #     bool.to_s == "_b:1"
 | |
| #
 | |
| #     Gitlab::Redis::Boolean.encode(true)
 | |
| #     => "_b:1"
 | |
| #
 | |
| #     Gitlab::Redis::Boolean.decode("_b:1")
 | |
| #     => true
 | |
| #
 | |
| #     Gitlab::Redis::Boolean.true?("_b:1")
 | |
| #     => true
 | |
| #
 | |
| #     Gitlab::Redis::Boolean.true?("_b:0")
 | |
| #     => false
 | |
| 
 | |
| module Gitlab
 | |
|   module Redis
 | |
|     class Boolean
 | |
|       LABEL = "_b"
 | |
|       DELIMITER = ":"
 | |
|       TRUE_STR = "1"
 | |
|       FALSE_STR = "0"
 | |
| 
 | |
|       BooleanError = Class.new(StandardError)
 | |
|       NotABooleanError = Class.new(BooleanError)
 | |
|       NotAnEncodedBooleanStringError = Class.new(BooleanError)
 | |
| 
 | |
|       def initialize(value)
 | |
|         @value = value
 | |
|       end
 | |
| 
 | |
|       # @return [String] the encoded boolean
 | |
|       def to_s
 | |
|         self.class.encode(@value)
 | |
|       end
 | |
| 
 | |
|       class << self
 | |
|         # Turn a boolean into a string for storage in Redis
 | |
|         #
 | |
|         # @param value [Boolean] true or false
 | |
|         # @return [String] the encoded boolean
 | |
|         # @raise [NotABooleanError] if the value isn't true or false
 | |
|         def encode(value)
 | |
|           raise NotABooleanError, value unless bool?(value)
 | |
| 
 | |
|           [LABEL, to_string(value)].join(DELIMITER)
 | |
|         end
 | |
| 
 | |
|         # Decode a boolean string
 | |
|         #
 | |
|         # @param value [String] the stored boolean string
 | |
|         # @return [Boolean] true or false
 | |
|         # @raise [NotAnEncodedBooleanStringError] if the provided value isn't an encoded boolean
 | |
|         def decode(value)
 | |
|           raise NotAnEncodedBooleanStringError, value.class unless value.is_a?(String)
 | |
| 
 | |
|           label, bool_str = *value.split(DELIMITER, 2)
 | |
| 
 | |
|           raise NotAnEncodedBooleanStringError, label unless label == LABEL
 | |
| 
 | |
|           from_string(bool_str)
 | |
|         end
 | |
| 
 | |
|         # Decode a boolean string, then test if it's true
 | |
|         #
 | |
|         # @param value [String] the stored boolean string
 | |
|         # @return [Boolean] is the value true?
 | |
|         # @raise [NotAnEncodedBooleanStringError] if the provided value isn't an encoded boolean
 | |
|         def true?(encoded_value)
 | |
|           decode(encoded_value)
 | |
|         end
 | |
| 
 | |
|         # Decode a boolean string, then test if it's false
 | |
|         #
 | |
|         # @param value [String] the stored boolean string
 | |
|         # @return [Boolean] is the value false?
 | |
|         # @raise [NotAnEncodedBooleanStringError] if the provided value isn't an encoded boolean
 | |
|         def false?(encoded_value)
 | |
|           !true?(encoded_value)
 | |
|         end
 | |
| 
 | |
|         private
 | |
| 
 | |
|         def bool?(value)
 | |
|           [true, false].include?(value)
 | |
|         end
 | |
| 
 | |
|         def to_string(bool)
 | |
|           bool ? TRUE_STR : FALSE_STR
 | |
|         end
 | |
| 
 | |
|         def from_string(str)
 | |
|           raise NotAnEncodedBooleanStringError, str unless [TRUE_STR, FALSE_STR].include?(str)
 | |
| 
 | |
|           str == TRUE_STR
 | |
|         end
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| end
 |