Skip to content

Commit f5f3bea

Browse files
authored
Merge pull request #3 from omc/kinduff/type
Adds type methods for objects
2 parents 8c28031 + 49c1630 commit f5f3bea

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

lib/errgonomic.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
# A more opinionated blend with Rails presence.
66
require_relative 'errgonomic/presence'
77

8+
# Bring in a subtle and manual type checker.
9+
require_relative 'errgonomic/type'
10+
811
# Bring in our Option and Result.
912
require_relative 'errgonomic/option'
1013
require_relative 'errgonomic/result'

lib/errgonomic/type.rb

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# frozen_string_literal: true
2+
3+
class Object
4+
# Returns the receiver if it matches the expected type, otherwise raises a TypeMismatchError.
5+
# This is useful for enforcing type expectations in method arguments.
6+
#
7+
# @param type [Class] The expected type or module the receiver should be.
8+
# @param message [String] Optional error message to raise if type doesn't match.
9+
# @return [Object] The receiver if it is of the expected type.
10+
# @example
11+
# 'hello'.type_or_raise!(String) #=> "hello"
12+
# 123.type_or_raise!(String, "We need a string!") #=> raise Errgonomic::TypeMismatchError, "We need a string!"
13+
# 123.type_or_raise!(String) #=> raise Errgonomic::TypeMismatchError, "Expected String but got Integer"
14+
def type_or_raise!(type, message = nil)
15+
message ||= "Expected #{type} but got #{self.class}"
16+
raise Errgonomic::TypeMismatchError, message unless is_a?(type)
17+
18+
self
19+
end
20+
21+
alias type_or_raise type_or_raise!
22+
23+
# Returns the receiver if it matches the expected type, otherwise returns the default value.
24+
#
25+
# @param type [Class] The expected type or module the receiver should be.
26+
# @param default [Object] The value to return if type doesn't match.
27+
# @return [Object] The receiver if it is of the expected type, otherwise the default value.
28+
# @example
29+
# 'hello'.type_or(String, 'default') # => "hello"
30+
# 123.type_or(String, 'default') # => "default"
31+
def type_or(type, default)
32+
return self if is_a?(type)
33+
34+
default
35+
end
36+
37+
# Returns the receiver if it matches the expected type, otherwise returns the result of the block.
38+
# Useful when constructing the default value is expensive.
39+
#
40+
# @param type [Class] The expected type or module the receiver should be.
41+
# @param block [Proc] The block to call if type doesn't match.
42+
# @return [Object] The receiver if it is of the expected type, otherwise the block result.
43+
# @example
44+
# 'hello'.type_or_else(String) { 'default' } # => "hello"
45+
# 123.type_or_else(String) { 'default' } # => "default"
46+
def type_or_else(type, &block)
47+
return self if is_a?(type)
48+
49+
block.call
50+
end
51+
52+
# Returns the receiver if it does not match the expected type, otherwise raises a TypeMismatchError.
53+
#
54+
# @param type [Class] The type or module the receiver should not be.
55+
# @param message [String] Optional error message to raise if type matches.
56+
# @return [Object] The receiver if it is not of the specified type.
57+
# @example
58+
# 'hello'.not_type_or_raise!(Integer) #=> "hello"
59+
# 123.not_type_or_raise!(Integer, "We dont want an integer!") #=> raise Errgonomic::TypeMismatchError, "We dont want an integer!"
60+
# 123.not_type_or_raise!(Integer) #=> raise Errgonomic::TypeMismatchError, "Expected anything but Integer but got Integer"
61+
def not_type_or_raise!(type, message = nil)
62+
message ||= "Expected anything but #{type} but got #{self.class}"
63+
raise Errgonomic::TypeMismatchError, message if is_a?(type)
64+
65+
self
66+
end
67+
end

0 commit comments

Comments
 (0)