Skip to content

Commit

Permalink
Add UUID predefined type (#19)
Browse files Browse the repository at this point in the history
* Add UUID predefined type
* Add pattern caster
  • Loading branch information
mechnicov authored May 7, 2024
1 parent 0fcd9a3 commit 33673ff
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 1 deletion.
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ It is currently used in production in several projects (mainly as request parame
- [`hash_with_symbolized_keys(error_key = nil)`](#hash_with_symbolized_keyserror_key--nil)
- [`integer32(error_key = nil)`](#integer32error_key--nil)
- [`non_empty_string(error_key = nil)`](#non_empty_stringerror_key--nil)
- [`pattern(regexp, error_key = nil)`](#patternregexp-error_key--nil)
- [`uuid(error_key = nil)`](#uuiderror_key--nil)
- [Special types](#special-types)
- [`absent(error_key = nil, on: nil)`](#absenterror_key--nil-on-nil)
- [`any(error_key = nil)`](#anyerror_key--nil)
Expand Down Expand Up @@ -525,9 +527,29 @@ I18n keys:

Returns ValidResult if and only if provided value is a string and is not empty. Doesn't transform the value.

I18n keys:

* not a string – `error_key`, `'.string'`, `'datacaster.errors.string'`
* is empty – `error_key`, `'.non_empty_string'`, `'datacaster.errors.non_empty_string'`

#### `pattern(regexp, error_key = nil)`

Returns ValidResult if and only if provided value is a string and satisfies regexp. Doesn't transform the value. Don't forget to provide start/end markers in the regexp if needed, e.g. `/\A\d+\z/` for digits-only string.

I18n keys:

* not a string – `error_key`, `'.string'`, `'datacaster.errors.string'`
* doesn't satisfy the regexp – `error_key`, `'.pattern'`, `'datacaster.errors.pattern'`

#### `uuid(error_key = nil)`

Returns ValidResult if and only if provided value is a string and UUID. Doesn't transform the value.

I18n keys:

* not a string – `error_key`, `'.string'`, `'datacaster.errors.string'`
* not UUID – `error_key`, `'.uuid'`, `'datacaster.errors.uuid'`

### Special types

#### `absent(error_key = nil, on: nil)`
Expand Down
2 changes: 2 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ en:
integer32: is not a 32-bit integer
iso8601: is not a string with ISO-8601 date and time
must_be: "is not %{reference}"
pattern: has invalid format
relate: "%{left} should be %{op} %{right}"
responds_to: "does not respond to %{reference}"
string: is not a string
Expand All @@ -25,3 +26,4 @@ en:
non_empty_string: should be non-empty string
switch: is invalid
try: raised an error
uuid: is not UUID
12 changes: 12 additions & 0 deletions lib/datacaster/predefined.rb
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,12 @@ def float(error_key = nil)
check { |x| x.is_a?(Float) }.i18n_key(*error_keys)
end

def pattern(regexp, error_key = nil)
error_keys = ['.pattern', 'datacaster.errors.pattern']
error_keys.unshift(error_key) if error_key
string(error_key) & check { |x| x.match?(regexp) }.i18n_key(*error_keys, reference: regexp.inspect)
end

# 'hash' would be a bad method name, because it would override built in Object#hash
def hash_value(error_key = nil)
error_keys = ['.hash_value', 'datacaster.errors.hash_value']
Expand Down Expand Up @@ -360,6 +366,12 @@ def non_empty_string(error_key = nil)
string(error_key) & check { |x| !x.empty? }.i18n_key(*error_keys)
end

def uuid(error_key = nil)
error_keys = ['.uuid', 'datacaster.errors.uuid']
error_keys.unshift(error_key) if error_key
string(error_key) & pattern(/\A\h{8}-\h{4}-\h{4}-\h{4}-\h{12}\z/).i18n_key(*error_keys)
end

# Form request types

def iso8601(error_key = nil)
Expand Down
2 changes: 1 addition & 1 deletion lib/datacaster/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Datacaster
VERSION = "3.2.7"
VERSION = "3.2.8"
end
33 changes: 33 additions & 0 deletions spec/datacaster_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,26 @@
end
end

describe "UUID string typecasting" do
subject { described_class.schema { uuid } }

it "passes UUID strings" do
uuid = "58724b11-ff06-485e-bf67-410c96f606d7"

expect(subject.(uuid).to_dry_result).to eq Success(uuid)
end

it "returns Failure on integers" do
expect(subject.(1).to_dry_result).to eq Failure(["is not a string"])
end

it "returns Failure on non-UUID strings" do
uuid_without_last_symbol = "58724b11-ff06-485e-bf67-410c96f606d"

expect(subject.(uuid_without_last_symbol).to_dry_result).to eq Failure(["is not UUID"])
end
end

describe "decimal typecasting" do
subject { described_class.schema { decimal } }

Expand Down Expand Up @@ -168,6 +188,19 @@
end
end

describe "pattern typecasting" do
subject { described_class.schema { pattern(/\A\d+\z/) } }

it "passes correctly formatted strings" do
expect(subject.("123").to_dry_result).to eq Success("123")
expect(subject.("ab123").to_dry_result).to eq Failure(["has invalid format"])
end

it "doesn't pass non-strings" do
expect(subject.(:'123').to_dry_result).to eq Failure(["is not a string"])
end
end

describe "optional string typecasting" do
subject { described_class.schema { optional(string) } }

Expand Down

0 comments on commit 33673ff

Please sign in to comment.