literal 1.0.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -11,4 +11,10 @@ class Literal::Types::NilableType
11
11
  def ===(value)
12
12
  nil === value || @type === value
13
13
  end
14
+
15
+ def record_literal_type_errors(ctx)
16
+ @type.record_literal_type_errors(ctx) if @type.respond_to?(:record_literal_type_errors)
17
+ end
18
+
19
+ freeze
14
20
  end
@@ -17,4 +17,14 @@ class Literal::Types::SetType
17
17
 
18
18
  true
19
19
  end
20
+
21
+ def record_literal_type_errors(context)
22
+ return unless Set === context.actual
23
+
24
+ context.actual.each do |actual|
25
+ unless @type === actual
26
+ context.add_child(label: "[]", expected: @type, actual:)
27
+ end
28
+ end
29
+ end
20
30
  end
@@ -23,4 +23,20 @@ class Literal::Types::TupleType
23
23
 
24
24
  true
25
25
  end
26
+
27
+ def record_literal_type_errors(context)
28
+ return unless Array === context.actual
29
+
30
+ len = [@types.size, context.actual.size].max
31
+ i = 0
32
+ while i < len
33
+ actual = context.actual[i]
34
+ if !(expected = @types[i])
35
+ context.add_child(label: "[#{i}]", expected: Literal::Types::NeverType, actual:)
36
+ elsif !(expected === actual)
37
+ context.add_child(label: "[#{i}]", expected:, actual:)
38
+ end
39
+ i += 1
40
+ end
41
+ end
26
42
  end
@@ -39,6 +39,13 @@ class Literal::Types::UnionType
39
39
  end
40
40
  end
41
41
 
42
+ def record_literal_type_errors(ctx)
43
+ @types.each do |type|
44
+ ctx.add_child(label: type.inspect, expected: type, actual: ctx.actual)
45
+ end
46
+ ctx.children.clear if ctx.children.none? { |c| c.children.any? }
47
+ end
48
+
42
49
  protected
43
50
 
44
51
  attr_reader :types
data/lib/literal/types.rb CHANGED
@@ -32,15 +32,15 @@ module Literal::Types
32
32
  autoload :UnionType, "literal/types/union_type"
33
33
  autoload :VoidType, "literal/types/void_type"
34
34
 
35
- NilableBooleanType = NilableType.new(BooleanType)
36
- NilableCallableType = NilableType.new(CallableType)
37
- NilableJSONDataType = NilableType.new(JSONDataType)
38
- NilableLambdaType = NilableType.new(LambdaType)
39
- NilableProcableType = NilableType.new(ProcableType)
35
+ NilableBooleanType = NilableType.new(BooleanType::Instance).freeze
36
+ NilableCallableType = NilableType.new(CallableType::Instance).freeze
37
+ NilableJSONDataType = NilableType.new(JSONDataType).freeze
38
+ NilableLambdaType = NilableType.new(LambdaType).freeze
39
+ NilableProcableType = NilableType.new(ProcableType).freeze
40
40
 
41
- # Matches any value except `nil`. Use `_Any?` or `_Unit` to match any value including `nil`.
41
+ # Matches any value except `nil`. Use `_Any?` or `_Void` to match any value including `nil`.
42
42
  def _Any
43
- AnyType
43
+ AnyType::Instance
44
44
  end
45
45
 
46
46
  def _Any?
@@ -61,7 +61,7 @@ module Literal::Types
61
61
 
62
62
  # Matches if the value is `true` or `false`.
63
63
  def _Boolean
64
- BooleanType
64
+ BooleanType::Instance
65
65
  end
66
66
 
67
67
  # Nilable version of `_Boolean`
@@ -71,7 +71,7 @@ module Literal::Types
71
71
 
72
72
  # Matches if the value responds to `#call`.
73
73
  def _Callable
74
- CallableType
74
+ CallableType::Instance
75
75
  end
76
76
 
77
77
  # Nilabl version of `_Callable`
@@ -131,7 +131,7 @@ module Literal::Types
131
131
 
132
132
  # Matches *"falsy"* values (`nil` and `false`).
133
133
  def _Falsy
134
- FalsyType
134
+ FalsyType::Instance
135
135
  end
136
136
 
137
137
  # Matches if the value is a `Float` and matches the given constraint.
@@ -166,9 +166,9 @@ module Literal::Types
166
166
  end
167
167
 
168
168
  # Nilable version of `_Hash`
169
- def _Hash?
169
+ def _Hash?(...)
170
170
  NilableType.new(
171
- HashType.new,
171
+ HashType.new(...),
172
172
  )
173
173
  end
174
174
 
@@ -184,7 +184,7 @@ module Literal::Types
184
184
  # Nilable version of `_Integer`
185
185
  def _Integer?(...)
186
186
  NilableType.new(
187
- IntegerType(...),
187
+ IntegerType.new(...),
188
188
  )
189
189
  end
190
190
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Literal
4
- VERSION = "1.0.0"
4
+ VERSION = "1.2.0"
5
5
  end
data/lib/literal.rb CHANGED
@@ -3,15 +3,24 @@
3
3
  module Literal
4
4
  TYPE_CHECKS_DISABLED = ENV["LITERAL_TYPE_CHECKS"] == "false"
5
5
 
6
+ autoload :Array, "literal/array"
6
7
  autoload :Data, "literal/data"
7
8
  autoload :DataProperty, "literal/data_property"
8
9
  autoload :DataStructure, "literal/data_structure"
9
10
  autoload :Enum, "literal/enum"
11
+ autoload :Flags, "literal/flags"
12
+ autoload :Flags16, "literal/flags"
13
+ autoload :Flags32, "literal/flags"
14
+ autoload :Flags64, "literal/flags"
15
+ autoload :Flags8, "literal/flags"
16
+ autoload :Hash, "literal/hash"
10
17
  autoload :Null, "literal/null"
11
18
  autoload :Object, "literal/object"
12
19
  autoload :Properties, "literal/properties"
13
20
  autoload :Property, "literal/property"
21
+ autoload :Set, "literal/set"
14
22
  autoload :Struct, "literal/struct"
23
+ autoload :Type, "literal/type"
15
24
  autoload :Types, "literal/types"
16
25
 
17
26
  # Errors
@@ -19,12 +28,89 @@ module Literal
19
28
  autoload :TypeError, "literal/errors/type_error"
20
29
  autoload :ArgumentError, "literal/errors/argument_error"
21
30
 
31
+ TRANSFORMS = {
32
+ Integer => {
33
+ abs: Integer,
34
+ ceil: Integer,
35
+ chr: String,
36
+ denominator: Integer,
37
+ even?: Types::BooleanType::Instance,
38
+ floor: Integer,
39
+ hash: Integer,
40
+ inspect: String,
41
+ integer?: true,
42
+ magnitude: Integer,
43
+ negative?: Types::BooleanType::Instance,
44
+ next: Integer,
45
+ nonzero?: Types::BooleanType::Instance,
46
+ numerator: Integer,
47
+ odd?: Types::BooleanType::Instance,
48
+ ord: Integer,
49
+ positive?: Types::BooleanType::Instance,
50
+ pred: Integer,
51
+ round: Integer,
52
+ size: Integer,
53
+ succ: Integer,
54
+ to_f: Float,
55
+ to_i: Integer,
56
+ to_int: Integer,
57
+ to_r: Rational,
58
+ to_s: String,
59
+ truncate: Integer,
60
+ zero?: Types::BooleanType::Instance,
61
+ },
62
+ String => {
63
+ ascii_only?: Types::BooleanType::Instance,
64
+ bytesize: Integer,
65
+ capitalize: String,
66
+ chomp: String,
67
+ chop: String,
68
+ downcase: String,
69
+ dump: String,
70
+ empty?: Types::BooleanType::Instance,
71
+ hash: Integer,
72
+ inspect: String,
73
+ length: Integer,
74
+ lstrip: String,
75
+ ord: Integer,
76
+ reverse: String,
77
+ rstrip: String,
78
+ scrub: String,
79
+ size: Integer,
80
+ strip: String,
81
+ swapcase: String,
82
+ to_str: String,
83
+ upcase: String,
84
+ valid_encoding?: Types::BooleanType::Instance,
85
+ },
86
+ Array => {
87
+ size: Integer,
88
+ length: Integer,
89
+ empty?: Types::BooleanType::Instance,
90
+ sort: Array,
91
+ to_a: Array,
92
+ to_ary: Array,
93
+ },
94
+ }.transform_values! { |it| it.transform_keys(&:to_proc) }.freeze
95
+
22
96
  def self.Enum(type)
23
97
  Class.new(Literal::Enum) do
24
98
  prop :value, type, :positional
25
99
  end
26
100
  end
27
101
 
102
+ def self.Array(type)
103
+ Literal::Array::Generic.new(type)
104
+ end
105
+
106
+ def self.Set(type)
107
+ Literal::Set::Generic.new(type)
108
+ end
109
+
110
+ def self.Hash(key_type, value_type)
111
+ Literal::Hash::Generic.new(key_type, value_type)
112
+ end
113
+
28
114
  def self.check(actual:, expected:)
29
115
  if expected === actual
30
116
  true
@@ -35,6 +121,17 @@ module Literal
35
121
  raise Literal::TypeError.new(context:)
36
122
  end
37
123
  end
124
+
125
+ def self.subtype?(type, of:)
126
+ (of == type) || case of
127
+ when Literal::Type, Module
128
+ of >= type
129
+ when Range
130
+ of.cover?(type)
131
+ else
132
+ false
133
+ end
134
+ end
38
135
  end
39
136
 
40
137
  require_relative "literal/rails" if defined?(Rails)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: literal
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joel Drapper
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-11-01 00:00:00.000000000 Z
11
+ date: 2024-11-22 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A literal Ruby gem.
14
14
  email:
@@ -20,6 +20,7 @@ files:
20
20
  - LICENSE.txt
21
21
  - README.md
22
22
  - lib/literal.rb
23
+ - lib/literal/array.rb
23
24
  - lib/literal/data.rb
24
25
  - lib/literal/data_property.rb
25
26
  - lib/literal/data_structure.rb
@@ -27,6 +28,8 @@ files:
27
28
  - lib/literal/errors/argument_error.rb
28
29
  - lib/literal/errors/error.rb
29
30
  - lib/literal/errors/type_error.rb
31
+ - lib/literal/flags.rb
32
+ - lib/literal/hash.rb
30
33
  - lib/literal/null.rb
31
34
  - lib/literal/object.rb
32
35
  - lib/literal/properties.rb
@@ -36,9 +39,12 @@ files:
36
39
  - lib/literal/rails.rb
37
40
  - lib/literal/rails/enum_serializer.rb
38
41
  - lib/literal/rails/enum_type.rb
42
+ - lib/literal/rails/flags_type.rb
39
43
  - lib/literal/rails/patches/active_record.rb
40
44
  - lib/literal/railtie.rb
45
+ - lib/literal/set.rb
41
46
  - lib/literal/struct.rb
47
+ - lib/literal/type.rb
42
48
  - lib/literal/types.rb
43
49
  - lib/literal/types/any_type.rb
44
50
  - lib/literal/types/array_type.rb