types 0.2.0 → 0.4.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/agent.md +47 -0
- data/context/usage.md +195 -0
- data/lib/types/any.rb +41 -43
- data/lib/types/array.rb +33 -20
- data/lib/types/block.rb +28 -20
- data/lib/types/boolean.rb +25 -20
- data/lib/types/class.rb +46 -22
- data/lib/types/decimal.rb +25 -24
- data/lib/types/float.rb +24 -20
- data/lib/types/generic.rb +17 -22
- data/lib/types/hash.rb +32 -20
- data/lib/types/integer.rb +24 -20
- data/lib/types/interface.rb +100 -0
- data/lib/types/lambda.rb +23 -21
- data/lib/types/method.rb +35 -22
- data/lib/types/named.rb +106 -0
- data/lib/types/nil.rb +24 -20
- data/lib/types/numeric.rb +13 -20
- data/lib/types/string.rb +23 -20
- data/lib/types/symbol.rb +23 -20
- data/lib/types/tuple.rb +32 -21
- data/lib/types/version.rb +3 -20
- data/lib/types.rb +52 -38
- data/license.md +21 -0
- data/readme.md +71 -0
- data.tar.gz.sig +0 -0
- metadata +37 -34
- metadata.gz.sig +0 -0
data/lib/types/class.rb
CHANGED
@@ -1,56 +1,71 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2022-2025, by Samuel Williams.
|
22
5
|
|
23
|
-
require_relative
|
6
|
+
require_relative "generic"
|
24
7
|
|
25
8
|
module Types
|
9
|
+
# Represents a class type, optionally constrained to a base class.
|
10
|
+
#
|
11
|
+
# ```ruby
|
12
|
+
# type = Types::Class(String)
|
13
|
+
# type.parse("Array") # => Array
|
14
|
+
# ```
|
26
15
|
class Class
|
27
16
|
extend Generic
|
28
17
|
include Generic
|
29
18
|
|
19
|
+
# @parameter base [Class] The base class constraint.
|
30
20
|
def initialize(base)
|
31
21
|
@base = base
|
32
22
|
end
|
33
23
|
|
24
|
+
# @returns [Class] the base class constraint.
|
34
25
|
attr :base
|
35
26
|
|
27
|
+
# @returns [Boolean] true if this is a composite type.
|
36
28
|
def composite?
|
37
29
|
true
|
38
30
|
end
|
39
31
|
|
32
|
+
# Resolve the base class if possible.
|
33
|
+
# @returns [Class] the resolved base class.
|
34
|
+
def resolve
|
35
|
+
Object.const_get(@base.to_s)
|
36
|
+
rescue NameError
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
|
40
|
+
# Parses the input as a class, optionally checking the base class constraint.
|
41
|
+
# @parameter input [String] The class name to parse.
|
42
|
+
# @returns [Class] the parsed class.
|
43
|
+
# @raises [ArgumentError] if the class is not a subclass of the base.
|
40
44
|
def parse(input)
|
41
45
|
klass = Object.const_get(input)
|
46
|
+
base = self.resolve
|
42
47
|
|
43
|
-
if
|
44
|
-
raise ArgumentError, "Class #{klass} is not a subclass of #{
|
48
|
+
if base and !klass.ancestors.include?(base)
|
49
|
+
raise ArgumentError, "Class #{klass} is not a subclass of #{base}!"
|
45
50
|
end
|
46
51
|
|
47
52
|
return klass
|
48
53
|
end
|
49
54
|
|
55
|
+
# @returns [Boolean] false for the class type itself.
|
50
56
|
def self.composite?
|
51
57
|
false
|
52
58
|
end
|
53
59
|
|
60
|
+
# @returns [String] the RBS type string, e.g. `Class`.
|
61
|
+
def to_rbs
|
62
|
+
"Class"
|
63
|
+
end
|
64
|
+
|
65
|
+
# Parses the input as a class, raising if not a class.
|
66
|
+
# @parameter input [String] The class name to parse.
|
67
|
+
# @returns [Class] the parsed class.
|
68
|
+
# @raises [ArgumentError] if the constant is not a class.
|
54
69
|
def self.parse(input)
|
55
70
|
klass = Object.const_get(input)
|
56
71
|
|
@@ -60,8 +75,17 @@ module Types
|
|
60
75
|
|
61
76
|
return klass
|
62
77
|
end
|
78
|
+
|
79
|
+
# Resolves to the actual Ruby Class class.
|
80
|
+
# @returns [Class] The Class class.
|
81
|
+
def self.resolve
|
82
|
+
::Class
|
83
|
+
end
|
63
84
|
end
|
64
85
|
|
86
|
+
# Constructs a {Class} type with an optional base class constraint.
|
87
|
+
# @parameter base [Class] The base class constraint.
|
88
|
+
# @returns [Class] a new {Class} type.
|
65
89
|
def self.Class(base = Object)
|
66
90
|
Class.new(base)
|
67
91
|
end
|
data/lib/types/decimal.rb
CHANGED
@@ -1,40 +1,41 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2022-2025, by Samuel Williams.
|
22
5
|
|
23
|
-
require_relative
|
24
|
-
|
25
|
-
require 'bigdecimal'
|
6
|
+
require_relative "generic"
|
7
|
+
require "bigdecimal"
|
26
8
|
|
27
9
|
module Types
|
10
|
+
# Represents a decimal type using BigDecimal.
|
11
|
+
#
|
12
|
+
# ```ruby
|
13
|
+
# type = Types::Decimal
|
14
|
+
# type.parse("3.14") # => #<BigDecimal ...>
|
15
|
+
# ```
|
28
16
|
module Decimal
|
29
17
|
extend Generic
|
30
18
|
|
19
|
+
# Parses the input as a BigDecimal.
|
20
|
+
# @parameter input [Object] The value to parse.
|
21
|
+
# @returns [BigDecimal] The parsed decimal value.
|
22
|
+
# @raises [ArgumentError] if the input cannot be converted to a BigDecimal.
|
31
23
|
def self.parse(input)
|
32
24
|
case input
|
33
25
|
when ::Float
|
34
|
-
BigDecimal(input, ::Float::DIG+1)
|
26
|
+
Kernel.BigDecimal(input, ::Float::DIG+1)
|
35
27
|
else
|
36
|
-
BigDecimal(input)
|
28
|
+
Kernel.BigDecimal(input)
|
37
29
|
end
|
38
30
|
end
|
31
|
+
|
32
|
+
# Resolves to the actual Ruby BigDecimal class.
|
33
|
+
# @returns [Class] The BigDecimal class.
|
34
|
+
def self.resolve
|
35
|
+
::BigDecimal
|
36
|
+
end
|
39
37
|
end
|
38
|
+
|
39
|
+
# Alias for the Decimal type.
|
40
|
+
BigDecimal = Decimal
|
40
41
|
end
|
data/lib/types/float.rb
CHANGED
@@ -1,33 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2022-2025, by Samuel Williams.
|
22
5
|
|
23
|
-
require_relative
|
6
|
+
require_relative "generic"
|
24
7
|
|
25
8
|
module Types
|
9
|
+
# Represents a floating point type.
|
10
|
+
#
|
11
|
+
# ```ruby
|
12
|
+
# type = Types::Float
|
13
|
+
# type.parse("3.14") # => 3.14
|
14
|
+
# ```
|
26
15
|
module Float
|
27
16
|
extend Generic
|
28
17
|
|
18
|
+
# Parses the input as a float.
|
19
|
+
# @parameter input [Object] The value to parse.
|
20
|
+
# @returns [Float] The parsed float value.
|
21
|
+
# @raises [ArgumentError] if the input cannot be converted to a float.
|
29
22
|
def self.parse(input)
|
30
23
|
Float(input)
|
31
24
|
end
|
25
|
+
|
26
|
+
# @returns [String] the RBS type string, e.g. `Float`.
|
27
|
+
def self.to_rbs
|
28
|
+
"Float"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Resolves to the actual Ruby Float class.
|
32
|
+
# @returns [Class] The Float class.
|
33
|
+
def self.resolve
|
34
|
+
::Float
|
35
|
+
end
|
32
36
|
end
|
33
37
|
end
|
data/lib/types/generic.rb
CHANGED
@@ -1,43 +1,38 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2022-2025, by Samuel Williams.
|
22
5
|
|
23
|
-
require_relative
|
6
|
+
require_relative "any"
|
24
7
|
|
25
8
|
module Types
|
26
9
|
# An extension module which allows constructing `Any` types using the `|` operator.
|
10
|
+
#
|
11
|
+
# ```ruby
|
12
|
+
# type = Types::String | Types::Integer
|
13
|
+
# ```
|
27
14
|
module Generic
|
28
15
|
# Create an instance of `Any` with the arguments as types.
|
29
16
|
# @parameter other [Type] the alternative type to match.
|
17
|
+
# @returns [Any] a new {Any} type representing the union.
|
30
18
|
def | other
|
31
19
|
Any.new([self, other])
|
32
20
|
end
|
33
21
|
|
34
|
-
#
|
22
|
+
# @returns [String] the RBS representation of this type as a string.
|
23
|
+
# By default, this is the same as to_s, but can be overridden by composite types.
|
24
|
+
def to_rbs
|
25
|
+
to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
# @returns [Boolean] whether a type contains nested types or not.
|
35
29
|
def composite?
|
36
30
|
false
|
37
31
|
end
|
38
32
|
|
33
|
+
# @returns [String] the string representation of the type.
|
39
34
|
def to_s
|
40
|
-
self.name.rpartition(
|
35
|
+
self.name.rpartition("::").last
|
41
36
|
end
|
42
37
|
end
|
43
38
|
end
|
data/lib/types/hash.rb
CHANGED
@@ -1,40 +1,36 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2022-2025, by Samuel Williams.
|
22
5
|
|
23
|
-
require_relative
|
6
|
+
require_relative "generic"
|
24
7
|
|
25
8
|
module Types
|
9
|
+
# Represents a hash type with key and value types.
|
10
|
+
#
|
11
|
+
# ```ruby
|
12
|
+
# type = Types::Hash(Types::String, Types::Integer)
|
13
|
+
# type.parse({"foo" => "42"}) # => {"foo" => 42}
|
14
|
+
# ```
|
26
15
|
class Hash
|
27
16
|
include Generic
|
28
17
|
|
18
|
+
# @parameter key_type [Type] The type of the hash keys.
|
19
|
+
# @parameter value_type [Type] The type of the hash values.
|
29
20
|
def initialize(key_type, value_type)
|
30
21
|
@key_type = key_type
|
31
22
|
@value_type = value_type
|
32
23
|
end
|
33
24
|
|
25
|
+
# @returns [Boolean] true if this is a composite type.
|
34
26
|
def composite?
|
35
27
|
true
|
36
28
|
end
|
37
29
|
|
30
|
+
# Parses the input as a hash with the specified key and value types.
|
31
|
+
# @parameter input [Object] The value to parse.
|
32
|
+
# @returns [Hash] The parsed hash.
|
33
|
+
# @raises [ArgumentError] if the input cannot be converted to a hash.
|
38
34
|
def parse(input)
|
39
35
|
case input
|
40
36
|
when ::String
|
@@ -46,10 +42,22 @@ module Types
|
|
46
42
|
end
|
47
43
|
end
|
48
44
|
|
45
|
+
# @returns [String] the string representation of the hash type.
|
49
46
|
def to_s
|
50
47
|
"Hash(#{@key_type}, #{@value_type})"
|
51
48
|
end
|
52
49
|
|
50
|
+
# @returns [String] the RBS type string, e.g. `{ String => Integer }`.
|
51
|
+
def to_rbs
|
52
|
+
"{ #{@key_type.to_rbs} => #{@value_type.to_rbs} }"
|
53
|
+
end
|
54
|
+
|
55
|
+
# Resolves to the actual Ruby Hash class.
|
56
|
+
# @returns [Class] The Hash class.
|
57
|
+
def resolve
|
58
|
+
::Hash
|
59
|
+
end
|
60
|
+
|
53
61
|
private
|
54
62
|
|
55
63
|
def parse_string(input)
|
@@ -61,6 +69,10 @@ module Types
|
|
61
69
|
end
|
62
70
|
end
|
63
71
|
|
72
|
+
# Constructs a {Hash} type from the given key and value types.
|
73
|
+
# @parameter key_type [Type] The type of the hash keys.
|
74
|
+
# @parameter value_type [Type] The type of the hash values.
|
75
|
+
# @returns [Hash] a new {Hash} type.
|
64
76
|
def self.Hash(key_type, value_type)
|
65
77
|
Hash.new(key_type, value_type)
|
66
78
|
end
|
data/lib/types/integer.rb
CHANGED
@@ -1,33 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2022-2025, by Samuel Williams.
|
22
5
|
|
23
|
-
require_relative
|
6
|
+
require_relative "generic"
|
24
7
|
|
25
8
|
module Types
|
9
|
+
# Represents an integer type.
|
10
|
+
#
|
11
|
+
# ```ruby
|
12
|
+
# type = Types::Integer
|
13
|
+
# type.parse("42") # => 42
|
14
|
+
# ```
|
26
15
|
module Integer
|
27
16
|
extend Generic
|
28
17
|
|
18
|
+
# Parses the input as an integer.
|
19
|
+
# @parameter input [Object] The value to parse.
|
20
|
+
# @returns [Integer] The parsed integer value.
|
21
|
+
# @raises [ArgumentError] if the input cannot be converted to an integer.
|
29
22
|
def self.parse(input)
|
30
23
|
Integer(input)
|
31
24
|
end
|
25
|
+
|
26
|
+
# @returns [String] the RBS type string, e.g. `Integer`.
|
27
|
+
def self.to_rbs
|
28
|
+
"Integer"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Resolves to the actual Ruby Integer class.
|
32
|
+
# @returns [Class] The Integer class.
|
33
|
+
def self.resolve
|
34
|
+
::Integer
|
35
|
+
end
|
32
36
|
end
|
33
37
|
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2024-2025, by Samuel Williams.
|
5
|
+
|
6
|
+
require_relative "generic"
|
7
|
+
require_relative "method"
|
8
|
+
require_relative "any"
|
9
|
+
|
10
|
+
module Types
|
11
|
+
# Represents an interface type, defined by required method names.
|
12
|
+
#
|
13
|
+
# ```ruby
|
14
|
+
# type = Types::Interface(
|
15
|
+
# foo: Method.new(Any, returns: Any),
|
16
|
+
# bar: Method.new(Any, returns: Any)
|
17
|
+
# )
|
18
|
+
# type.valid?(obj) # => true if obj responds to :foo and :bar
|
19
|
+
# ```
|
20
|
+
class Interface
|
21
|
+
extend Generic
|
22
|
+
|
23
|
+
# @parameter methods [Array(Symbol)] The required method names.
|
24
|
+
def initialize(methods)
|
25
|
+
@methods = methods
|
26
|
+
end
|
27
|
+
|
28
|
+
# @returns [Array(Symbol)] The required method names.
|
29
|
+
attr :methods
|
30
|
+
|
31
|
+
# @returns [Boolean] true if this is a composite type.
|
32
|
+
def composite?
|
33
|
+
true
|
34
|
+
end
|
35
|
+
|
36
|
+
# @returns [String] the string representation of the interface type.
|
37
|
+
def to_s
|
38
|
+
buffer = ::String.new
|
39
|
+
|
40
|
+
buffer << "Interface("
|
41
|
+
|
42
|
+
if @methods&.any?
|
43
|
+
first = true
|
44
|
+
@methods.each do |name, method|
|
45
|
+
if first
|
46
|
+
first = false
|
47
|
+
else
|
48
|
+
buffer << ", "
|
49
|
+
end
|
50
|
+
|
51
|
+
buffer << "#{name}: #{method}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
buffer << ")"
|
56
|
+
|
57
|
+
return buffer
|
58
|
+
end
|
59
|
+
|
60
|
+
# Checks if the given instance responds to all required methods.
|
61
|
+
# @parameter instance [Object] The object to check.
|
62
|
+
# @returns [Boolean] true if the instance responds to all methods.
|
63
|
+
def valid?(instance)
|
64
|
+
@methods.all? do |name, method|
|
65
|
+
instance.respond_to?(name)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Parses the input as an object and checks if it matches the interface.
|
70
|
+
# @parameter input [Object] The value to parse.
|
71
|
+
# @returns [Object] the input if it matches the interface.
|
72
|
+
# @raises [ArgumentError] if the input does not match the interface.
|
73
|
+
def parse(input)
|
74
|
+
case input
|
75
|
+
when ::String
|
76
|
+
instance = eval(input)
|
77
|
+
else
|
78
|
+
instance = input
|
79
|
+
end
|
80
|
+
|
81
|
+
if valid?(instance)
|
82
|
+
return instance
|
83
|
+
else
|
84
|
+
raise ArgumentError, "Cannot coerce #{input.inspect} into #{self}!"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Constructs an {Interface} type from the given method names.
|
90
|
+
# @parameter methods [Array(Symbol)] The required method names.
|
91
|
+
# @returns [Interface] a new {Interface} type.
|
92
|
+
def self.Interface(*names, **methods)
|
93
|
+
# This is a deprecated way to create an interfaces with names only. Ideally, we actually need to know the methods.
|
94
|
+
names.each do |name|
|
95
|
+
methods[name.to_sym] = Method.new(Any(), [], Any())
|
96
|
+
end
|
97
|
+
|
98
|
+
Interface.new(methods)
|
99
|
+
end
|
100
|
+
end
|
data/lib/types/lambda.rb
CHANGED
@@ -1,44 +1,38 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2022-2025, by Samuel Williams.
|
22
5
|
|
23
|
-
require_relative
|
6
|
+
require_relative "generic"
|
24
7
|
|
25
8
|
module Types
|
26
|
-
#
|
9
|
+
# Represents a lambda (function) type with argument and return types.
|
10
|
+
#
|
11
|
+
# ```ruby
|
12
|
+
# type = Types::Lambda(Types::String, Types::Integer, returns: Types::String)
|
13
|
+
# type.to_s # => "Lambda(String, Integer, returns: String)"
|
14
|
+
# ```
|
27
15
|
class Lambda
|
28
16
|
include Generic
|
29
17
|
|
18
|
+
# @parameter argument_types [Array(Type)] The types of the lambda arguments.
|
19
|
+
# @parameter return_type [Type | Nil] The return type of the lambda.
|
30
20
|
def initialize(argument_types, return_type)
|
31
21
|
@argument_types = argument_types
|
32
22
|
@return_type = return_type
|
33
23
|
end
|
34
24
|
|
25
|
+
# @returns [Array(Type)] The types of the lambda arguments.
|
35
26
|
attr :argument_types
|
27
|
+
# @returns [Type | Nil] The return type of the lambda.
|
36
28
|
attr :return_type
|
37
29
|
|
30
|
+
# @returns [Boolean] true if this is a composite type.
|
38
31
|
def composite?
|
39
32
|
true
|
40
33
|
end
|
41
34
|
|
35
|
+
# @returns [String] the string representation of the lambda type.
|
42
36
|
def to_s
|
43
37
|
if @return_type
|
44
38
|
"Lambda(#{@argument_types.join(', ')}, returns: #{@return_type})"
|
@@ -47,6 +41,10 @@ module Types
|
|
47
41
|
end
|
48
42
|
end
|
49
43
|
|
44
|
+
# Parses the input as a lambda/proc.
|
45
|
+
# @parameter input [Object] The value to parse.
|
46
|
+
# @returns [Proc] the parsed lambda/proc.
|
47
|
+
# @raises [ArgumentError] if the input cannot be converted to a lambda.
|
50
48
|
def parse(input)
|
51
49
|
case input
|
52
50
|
when ::String
|
@@ -59,6 +57,10 @@ module Types
|
|
59
57
|
end
|
60
58
|
end
|
61
59
|
|
60
|
+
# Constructs a {Lambda} type from the given argument and return types.
|
61
|
+
# @parameter argument_types [Array(Type)] The types of the lambda arguments.
|
62
|
+
# @parameter returns [Type | Nil] The return type of the lambda.
|
63
|
+
# @returns [Lambda] a new {Lambda} type.
|
62
64
|
def self.Lambda(*argument_types, returns: nil)
|
63
65
|
Lambda.new(argument_types, returns)
|
64
66
|
end
|