literal 0.2.1 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e6311063a2b1bdfdd56033d0e740020927e58e4488405804c2f3e97ca9aad22b
4
- data.tar.gz: fa4abc6e6c791b36a22b28c2b5b47ea0e7bd6d8f6e57b81f6b4104260989f836
3
+ metadata.gz: 75c7cc8853143bd8f4ac74b7fc4a5b5d2812bd39c0b4f696a87c2ffc0fb31046
4
+ data.tar.gz: 7781d6362e9ae8f75d0156809f95b0c1f8a37df855356173c9b6f09428419bc0
5
5
  SHA512:
6
- metadata.gz: 3b1dd9ad76a1552039a277b597c24b4e5ebf04d0edac5b86ae138d4d0e98b02bb6fc8e3ffc5fec63cc9d5d233c9865a90f0c29ad0a87cac2083b5a150a0e3ea4
7
- data.tar.gz: 9162543b6590028e0118d9c0e52f7d1eb58122db513c76b3ea7eff3d722df811b4227c8b32d01fe471861029a352ce85c366a32778ccccb0aaff988d5647959f
6
+ metadata.gz: 6acc2552c11ff3c5f12877b5597f9a6a138bf4901f5fce3801004e286b522c6263fa2454621ac4f5511f553af073d5113d96cd1af1045bc9e44c014c15ab7420
7
+ data.tar.gz: 6f9b205b3343426385185ebd0ea0e04164f6a06f9d42d6cb34c542c8d12a98ab327e274b336fb13d389e7380f5bd79831eb2b508f2d019cd6143658db40f3195
data/README.md CHANGED
@@ -1,158 +1,3 @@
1
1
  # A Literal Ruby Gem [WIP]
2
2
 
3
- ## Types
4
-
5
- Literal uses Ruby-native types. Any method that responds to `===(value)` is considered a type. Note, this is how Ruby’s case statements and pattern matching work. It’s also how `Array#any?` and `Array#all?` work. Essentially all Ruby objects are types and just work the way you’d expect them to. A few examples:
6
-
7
- - On a `Range`, `===(value)` checks if the value is within the range.
8
- - On a `Regexp`, `===(value)` checks if the value matches the pattern.
9
- - On a `Class`, `===(value)` checks if the value is an instance of the class.
10
- - On a `Proc`, `===(value)` calls the proc with the value.
11
- - On a `String`, `===(value)` checks if the value is equal to the string.
12
- - On the class `String`, `===(value)` checks if the value is a string.
13
-
14
- Literal extends this idea with the concept of generics or _parameterised_ types. A generic is a method that returns an object that respond to `===(value)`.
15
-
16
- If we want to check that a given value is an `Array`, we could do this:
17
-
18
- ```ruby
19
- Array === [1, 2, 3]
20
- ```
21
-
22
- But what if we want to check that it’s an Array of Integers? Literal provides a library of special types that can be composed for this purpose. In this case, we can use the type `_Array(Integer)`.
23
-
24
- ```ruby
25
- _Array(Integer) === [1, 2, 3]
26
- ```
27
-
28
- These special types are defined on the `Literal::Types` module. To access them in a class, you can `extend` this module. To access them on an instance, you can `include` the module. If you want to use them globally, you can `extend` the module at the root.
29
-
30
- ```ruby
31
- extend Literal::Types
32
- ```
33
-
34
- This is recommended for applications, but not for libraries, as we don’t want to pollute the global namespace from library code.
35
-
36
- `Literal::Properties`, `Literal::Object`, `Literal::Struct` and `Literal::Data` already extend `Literal::Types`, so you don’t need to extend `Literal::Types` yourself if you’re only using literal types for literal properties.
37
-
38
- ## Properties
39
-
40
- `Literal::Properties` is a mixin that allows you to define the structure of an object. Properties are defined using the `prop` method.
41
-
42
- The first argument is the name of the property as a `Symbol`. The second argument is the _type_ of the property. Remember, the type can be any object that responds to `===(value)`.
43
-
44
- The third argument is optional. You can set this to `:*`, `:**`, `:&`, or `:positional` to change the kind of initializer parameter.
45
-
46
- ```ruby
47
- class Person
48
- extend Literal::Properties
49
-
50
- prop :name, String
51
- prop :age, Integer
52
- end
53
- ```
54
-
55
- You can also use keyword arguments to define _readers_ and _writers_. These can be set to `false`, `:public`, `:protected`, or `:private` and default to `false`.
56
-
57
- ```ruby
58
- class Person
59
- extend Literal::Properties
60
-
61
- prop :name, String, reader: :public
62
- prop :age, Integer, writer: :protected
63
- end
64
- ```
65
-
66
- Properties are required by deafult. To make them optional, set the type to a that responds to `===(nil)` with `true`. `Literal::Types` provides a special types for this purpose. Let’s make the age optional by setting its type to a `_Nilable(Integer)`:
67
-
68
- ```ruby
69
- class Person
70
- extend Literal::Properties
71
-
72
- prop :name, String
73
- prop :age, _Nilable(Integer)
74
- end
75
- ```
76
-
77
- Alternatively, you can give the property a default value. This default value must match the type of the property.
78
-
79
- ```ruby
80
- class Person
81
- extend Literal::Properties
82
-
83
- prop :name, String, default: "John Doe"
84
- prop :age, _Nilable(Integer)
85
- end
86
- ```
87
-
88
- Note, the above example will fail unless you have frozen string literals enabled. (Which, honestly, you should.) Default values must be frozen. If you can’t use a frozen value, you can pass a proc instead.
89
-
90
- ```ruby
91
- class Person
92
- extend Literal::Properties
93
-
94
- prop :name, String, default: -> { "John Doe" }
95
- prop :age, _Nilable(Integer)
96
- end
97
- ```
98
-
99
- The proc will be called to generate the default value.
100
-
101
- You can also pass a block to the `prop` method. This block will be called with the value of the property when it’s set, which is useful for coercion.
102
-
103
- ```ruby
104
- class Person
105
- extend Literal::Properties
106
-
107
- prop :name, String
108
- prop :age, Integer do |value|
109
- value.to_i
110
- end
111
- end
112
- ```
113
-
114
- Coercion takes place prior to type-checking, so you can safely coerce a value to a different type in the block.
115
-
116
- You can use properties that conflict with ruby keywords. Literal will handle everything for you automatically.
117
-
118
- ```ruby
119
- class Person
120
- extend Literal::Properties
121
-
122
- prop :class, String, :positional
123
- prop :end, Integer
124
- end
125
- ```
126
-
127
- If you’d prefer to subclass than extend a module, you can use the `Literal::Object` class instead. `Literal::Object` literally extends `Literal::Properties`.
128
-
129
- ```ruby
130
- class Person < Literal::Object
131
- prop :name, String
132
- prop :age, Integer
133
- end
134
- ```
135
-
136
- ## Structs
137
-
138
- `Literal::Struct` is like `Literal::Object`, but it also provides a few extras.
139
-
140
- Structs implement `==` so you can compare one struct to another. They also implement `hash`. Structs also have public _readers_ and _writers_ by default.
141
-
142
- ```ruby
143
- class Person < Literal::Struct
144
- prop :name, String
145
- prop :age, Integer
146
- end
147
- ```
148
-
149
- ## Data
150
-
151
- `Literal::Data` is like `Literal::Struct`, but you can’t define _writers_. Additionally, objects are _frozen_ after initialization. Additionally any non-frozen properties are duplicated and frozen.
152
-
153
- ```ruby
154
- class Person < Literal::Data
155
- prop :name, String
156
- prop :age, Integer
157
- end
158
- ```
3
+ See the website for [documentation](https://literal.fun/docs).
@@ -10,25 +10,18 @@ class Literal::DataStructure
10
10
  object
11
11
  end
12
12
 
13
- def ==(other)
14
- if Literal::DataStructure === other
15
- to_h == other.to_h
16
- else
17
- false
18
- end
19
- end
20
-
21
- def hash
22
- [self.class, to_h].hash
23
- end
24
-
25
13
  def [](key)
26
- instance_variable_get("@#{key}")
14
+ instance_variable_get(:"@#{key}")
27
15
  end
28
16
 
29
17
  def []=(key, value)
30
- @literal_properties[key].check(value)
31
- instance_variable_set("@#{key}", value)
18
+ # TODO: Sync error array w/ generated setter
19
+ @literal_properties[key].check(value) { |c| raise NotImplementedError }
20
+ instance_variable_set(:"@#{key}", value)
21
+ end
22
+
23
+ def to_h
24
+ {}
32
25
  end
33
26
 
34
27
  def deconstruct
@@ -57,4 +50,20 @@ class Literal::DataStructure
57
50
  def marshal_dump
58
51
  [1, to_h, frozen?]
59
52
  end
53
+
54
+ def hash
55
+ self.class.hash
56
+ end
57
+
58
+ def ==(other)
59
+ other.is_a?(self.class) && other.class.literal_properties.empty?
60
+ end
61
+ alias eql? ==
62
+
63
+ def self.__generate_literal_methods__(new_property, buffer = +"")
64
+ super
65
+ literal_properties.generate_hash(buffer)
66
+ literal_properties.generate_eq(buffer)
67
+ buffer
68
+ end
60
69
  end
data/lib/literal/enum.rb CHANGED
@@ -21,6 +21,15 @@ class Literal::Enum
21
21
  @indexes = {}
22
22
  @index = {}
23
23
  end
24
+
25
+ if RUBY_ENGINE != "truffleruby"
26
+ TracePoint.trace(:end) do |tp|
27
+ if tp.self == subclass
28
+ tp.self.__after_defined__
29
+ tp.disable
30
+ end
31
+ end
32
+ end
24
33
  end
25
34
 
26
35
  def index(name, type, unique: true, &block)
@@ -34,9 +43,9 @@ class Literal::Enum
34
43
 
35
44
  key, value = kwargs.first
36
45
 
37
- unless (type = @indexes.fetch(key)[0]) === value
38
- raise Literal::TypeError.expected(value, to_be_a: type)
39
- end
46
+ types = @indexes.fetch(key)
47
+ type = types.first
48
+ Literal.check(actual: value, expected: type) { |c| raise NotImplementedError }
40
49
 
41
50
  @index.fetch(key)[value]
42
51
  end
@@ -90,6 +99,10 @@ class Literal::Enum
90
99
  def __after_defined__
91
100
  raise ArgumentError if frozen?
92
101
 
102
+ if RUBY_VERSION < "3.2"
103
+ constants(false).each { |name| const_added(name) }
104
+ end
105
+
93
106
  @indexes.each do |name, (type, unique, block)|
94
107
  index = @members.group_by(&block).freeze
95
108
 
@@ -111,8 +124,8 @@ class Literal::Enum
111
124
  freeze
112
125
  end
113
126
 
114
- def each(&)
115
- @members.each(&)
127
+ def each
128
+ @members.each { |member| yield(member) }
116
129
  end
117
130
 
118
131
  def each_value(&)
@@ -166,11 +179,3 @@ class Literal::Enum
166
179
  Marshal.dump(@value)
167
180
  end
168
181
  end
169
-
170
- TracePoint.trace(:end) do |tp|
171
- it = tp.self
172
-
173
- if Class === it && it < Literal::Enum
174
- it.__after_defined__
175
- end
176
- end
@@ -1,10 +1,83 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Literal::TypeError < TypeError
4
+ INDENT = " "
5
+
4
6
  include Literal::Error
5
7
 
6
- def self.expected(value, to_be_a:)
7
- type = to_be_a
8
- new("Expected `#{value.inspect}` to be of type: `#{type.inspect}`.")
8
+ class Context
9
+ attr_reader :receiver, :method, :label, :expected, :actual, :children
10
+
11
+ def initialize(
12
+ receiver: nil, # _Nilable(Object)
13
+ method: nil, # _Nilable(String)
14
+ label: nil, # _Nilable(String)
15
+ expected: nil, # _Nilable(_Any)
16
+ actual: nil, # _Nilable(_Any)
17
+ parent: nil # _Nilable(Context)
18
+ )
19
+ @receiver = receiver
20
+ @method = method
21
+ @label = label
22
+ @expected = expected
23
+ @actual = actual
24
+ @children = []
25
+ end
26
+
27
+ def descend(level = 0, &blk)
28
+ yield self, level
29
+ @children.each { |child| child.descend(level + 1, &blk) }
30
+ nil
31
+ end
32
+
33
+ def fill_receiver(receiver:, method:, label: nil)
34
+ @receiver = receiver
35
+ @method = method
36
+ @label = label
37
+ end
38
+
39
+ def add_child(expected: nil, **kwargs)
40
+ child = self.class.new(expected:, **kwargs)
41
+ expected.record_literal_type_errors(child) if expected.respond_to?(:record_literal_type_errors)
42
+ @children << child
43
+ end
44
+ end
45
+
46
+ def initialize(context:)
47
+ @context = context
48
+
49
+ super()
50
+ end
51
+
52
+ def message
53
+ message = +"Type mismatch\n\n"
54
+
55
+ @context.descend do |c, level|
56
+ idt = INDENT * level
57
+ if c.receiver || c.method
58
+ message << idt
59
+ message << c.receiver.class.inspect if c.receiver
60
+ message << c.method if c.method
61
+ message << " (from #{backtrace[1]})" if level.zero?
62
+ message << "\n"
63
+ end
64
+ if c.label
65
+ idt << INDENT
66
+ message << idt << c.label << "\n"
67
+ end
68
+ if c.expected && c.children.empty?
69
+ message << idt << " Expected: #{c.expected.inspect}\n"
70
+ message << idt << " Actual (#{c.actual.class}): #{c.actual.inspect}\n"
71
+ end
72
+ end
73
+ message
74
+ end
75
+
76
+ def deconstruct_keys(keys)
77
+ to_h.slice(*keys)
78
+ end
79
+
80
+ def to_h
81
+ @context.to_h
9
82
  end
10
83
  end
@@ -1,9 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Literal::Properties::DataSchema < Literal::Properties::Schema
4
- def generate_initializer_body(buffer = +"")
5
- buffer << "properties = self.class.literal_properties.properties_index\n"
6
- generate_initializer_handle_properties(@sorted_properties, buffer)
7
- buffer << "after_initialize if respond_to?(:after_initialize)\nfreeze\n"
4
+ def generate_after_initializer(buffer = +"")
5
+ super
6
+ buffer << " freeze\n"
8
7
  end
9
8
  end
@@ -19,7 +19,9 @@ class Literal::Properties::Schema
19
19
  def <<(value)
20
20
  @mutex.synchronize do
21
21
  @properties_index[value.name] = value
22
- @sorted_properties = @properties_index.values.sort!
22
+ # ruby's sort is unstable, this trick makes it stable
23
+ n = 0
24
+ @sorted_properties = @properties_index.values.sort_by! { |it| n += 1; [it, n] }
23
25
  end
24
26
 
25
27
  self
@@ -40,24 +42,71 @@ class Literal::Properties::Schema
40
42
  @sorted_properties.size
41
43
  end
42
44
 
45
+ def empty?
46
+ @sorted_properties.empty?
47
+ end
48
+
43
49
  def generate_initializer(buffer = +"")
50
+ buffer << "alias initialize initialize\n"
44
51
  buffer << "def initialize(#{generate_initializer_params})\n"
45
52
  generate_initializer_body(buffer)
53
+ buffer << "" \
54
+ "rescue Literal::TypeError => error\n" \
55
+ " error.set_backtrace(caller(2))\n" \
56
+ " raise\n" \
57
+ "else\n"
58
+ generate_after_initializer(buffer)
46
59
  buffer << "end\n"
47
60
  end
48
61
 
62
+ def generate_after_initializer(buffer = +"")
63
+ buffer << " after_initialize if respond_to?(:after_initialize)\n"
64
+ end
65
+
49
66
  def generate_to_h(buffer = +"")
50
- buffer << "def to_h\n" << "{\n"
67
+ buffer << "alias to_h to_h\n"
68
+ buffer << "def to_h\n" << " {\n"
51
69
 
52
70
  sorted_properties = @sorted_properties
53
71
  i, n = 0, sorted_properties.size
54
72
  while i < n
55
73
  property = sorted_properties[i]
56
- buffer << property.name.name << ": @" << property.name.name << ",\n"
74
+ buffer << " " << property.name.name << ": @" << property.name.name << ",\n"
57
75
  i += 1
58
76
  end
59
77
 
60
- buffer << "}\n" << "end\n"
78
+ buffer << " }\n" << "end\n"
79
+ end
80
+
81
+ def generate_hash(buffer = +"")
82
+ buffer << "def hash\n [self.class,\n"
83
+
84
+ sorted_properties = @sorted_properties
85
+ i, n = 0, sorted_properties.size
86
+ while i < n
87
+ property = sorted_properties[i]
88
+ buffer << " @" << property.name.name << ",\n"
89
+ i += 1
90
+ end
91
+
92
+ buffer << " ].hash\n" << "end\n"
93
+ end
94
+
95
+ def generate_eq(buffer = +"")
96
+ buffer << "def ==(other)\n"
97
+ buffer << " return false unless other.is_a?(self.class) && other.class.literal_properties.size == self.class.literal_properties.size\n"
98
+
99
+ sorted_properties = @sorted_properties
100
+ i, n = 0, sorted_properties.size
101
+ while i < n
102
+ property = sorted_properties[i]
103
+ buffer << " @" << property.name.name << " == other.#{property.escaped_name}"
104
+ buffer << " &&\n " if i < n - 1
105
+ i += 1
106
+ end
107
+ buffer << " true" if n.zero?
108
+ buffer << "\nend\n"
109
+ buffer << "alias eql? ==\n"
61
110
  end
62
111
 
63
112
  private
@@ -83,7 +132,7 @@ class Literal::Properties::Schema
83
132
  else # required
84
133
  buffer << property.escaped_name
85
134
  end
86
- else # keyword
135
+ when :keyword
87
136
  if property.default?
88
137
  buffer << property.name.name << ": Literal::Null"
89
138
  elsif property.type === nil
@@ -91,6 +140,8 @@ class Literal::Properties::Schema
91
140
  else # required
92
141
  buffer << property.name.name << ":"
93
142
  end
143
+ else
144
+ raise "You should never see this error."
94
145
  end
95
146
 
96
147
  i += 1
@@ -101,9 +152,8 @@ class Literal::Properties::Schema
101
152
  end
102
153
 
103
154
  def generate_initializer_body(buffer = +"")
104
- buffer << "properties = self.class.literal_properties.properties_index\n"
155
+ buffer << " properties = self.class.literal_properties.properties_index\n"
105
156
  generate_initializer_handle_properties(@sorted_properties, buffer)
106
- buffer << "after_initialize if respond_to?(:after_initialize)\n"
107
157
  end
108
158
 
109
159
  def generate_initializer_handle_properties(properties, buffer = +"")
@@ -6,6 +6,11 @@ module Literal::Properties
6
6
 
7
7
  include Literal::Types
8
8
 
9
+ def self.extended(base)
10
+ super
11
+ base.include(base.__send__(:__literal_extension__))
12
+ end
13
+
9
14
  def prop(name, type, kind = :keyword, reader: false, writer: false, predicate: false, default: nil, &coercion)
10
15
  if default && !(Proc === default || default.frozen?)
11
16
  raise Literal::ArgumentError.new("The default must be a frozen object or a Proc.")
@@ -66,16 +71,25 @@ module Literal::Properties
66
71
  end
67
72
 
68
73
  def __define_literal_methods__(new_property)
69
- __literal_extension__.module_eval(
70
- __generate_literal_methods__(new_property),
71
- )
74
+ code = __generate_literal_methods__(new_property)
75
+ __literal_extension__.module_eval(code)
72
76
  end
73
77
 
74
78
  def __literal_extension__
75
79
  if defined?(@__literal_extension__)
76
80
  @__literal_extension__
77
81
  else
78
- @__literal_extension__ = Module.new
82
+ @__literal_extension__ = Module.new do
83
+ def initialize
84
+ after_initialize if respond_to?(:after_initialize)
85
+ end
86
+
87
+ def to_h
88
+ {}
89
+ end
90
+
91
+ set_temporary_name "Literal::Properties(Extension)" if respond_to?(:set_temporary_name)
92
+ end
79
93
  end
80
94
  end
81
95
 
@@ -51,7 +51,24 @@ class Literal::Property
51
51
  end
52
52
 
53
53
  def default?
54
- nil != @default
54
+ nil != @default
55
+ end
56
+
57
+ def param
58
+ case @kind
59
+ when :*
60
+ "*#{escaped_name}"
61
+ when :**
62
+ "**#{escaped_name}"
63
+ when :&
64
+ "&#{escaped_name}"
65
+ when :positional
66
+ escaped_name
67
+ when :keyword
68
+ "#{@name.name}:"
69
+ else
70
+ raise "You should never see this error."
71
+ end
55
72
  end
56
73
 
57
74
  def <=>(other)
@@ -77,18 +94,28 @@ class Literal::Property
77
94
  end
78
95
  end
79
96
 
80
- def check(value)
81
- Literal.check(value, @type)
97
+ def check(value, &)
98
+ raise ArgumentError.new("Cannot check type without a block") unless block_given?
99
+
100
+ Literal.check(actual: value, expected: @type, &)
101
+ end
102
+
103
+ def check_writer(receiver, value)
104
+ Literal.check(actual: value, expected: @type) { |c| c.fill_receiver(receiver:, method: "##{@name.name}=(value)") }
105
+ end
106
+
107
+ def check_initializer(receiver, value)
108
+ Literal.check(actual: value, expected: @type) { |c| c.fill_receiver(receiver:, method: "#initialize", label: param) }
82
109
  end
83
110
 
84
111
  def generate_reader_method(buffer = +"")
85
112
  buffer <<
86
113
  (@reader ? @reader.name : "public") <<
87
- " def " <<
114
+ "\ndef " <<
88
115
  @name.name <<
89
- "\nvalue = @" <<
116
+ "\n value = @" <<
90
117
  @name.name <<
91
- "\nvalue\nend\n"
118
+ "\n value\nend\n"
92
119
  end
93
120
 
94
121
  if Literal::TYPE_CHECKS_DISABLED
@@ -98,7 +125,7 @@ class Literal::Property
98
125
  " def " <<
99
126
  @name.name <<
100
127
  "=(value)\n" <<
101
- "@#{@name.name} = value\nend\n"
128
+ " @#{@name.name} = value\nend\n"
102
129
  end
103
130
  else # type checks are enabled
104
131
  def generate_writer_method(buffer = +"")
@@ -107,10 +134,12 @@ class Literal::Property
107
134
  " def " <<
108
135
  @name.name <<
109
136
  "=(value)\n" <<
110
- "self.class.literal_properties[:" <<
137
+ " self.class.literal_properties[:" <<
111
138
  @name.name <<
112
- "].check(value)\n" <<
113
- "@#{@name.name} = value\nend\n"
139
+ "].check_writer(self, value)\n" <<
140
+ " @" << @name.name << " = value\n" <<
141
+ "rescue Literal::TypeError => error\n error.set_backtrace(caller(1))\n raise\n" <<
142
+ "end\n"
114
143
  end
115
144
  end
116
145
 
@@ -120,15 +149,15 @@ class Literal::Property
120
149
  " def " <<
121
150
  @name.name <<
122
151
  "?\n" <<
123
- "!!@" <<
152
+ " !!@" <<
124
153
  @name.name <<
125
154
  "\n" <<
126
155
  "end\n"
127
156
  end
128
157
 
129
158
  def generate_initializer_handle_property(buffer = +"")
130
- buffer << "# " << @name.name << "\n" <<
131
- "property = properties[:" << @name.name << "]\n"
159
+ buffer << " # " << @name.name << "\n" <<
160
+ " property = properties[:" << @name.name << "]\n"
132
161
 
133
162
  if @kind == :keyword && ruby_keyword?
134
163
  generate_initializer_escape_keyword(buffer)
@@ -169,25 +198,23 @@ class Literal::Property
169
198
 
170
199
  def generate_initializer_assign_default(buffer = +"")
171
200
  buffer <<
172
- "if " <<
201
+ " if " <<
173
202
  ((@kind == :&) ? "nil" : "Literal::Null") <<
174
203
  " == " <<
175
204
  escaped_name <<
176
- "\n" <<
205
+ "\n " <<
177
206
  escaped_name <<
178
- " = property.default_value\nend\n"
207
+ " = property.default_value\n end\n"
179
208
  end
180
209
 
181
210
  def generate_initializer_check_type(buffer = +"")
182
211
  buffer <<
183
- "unless property.type === " << escaped_name << "\n" <<
184
- "raise Literal::TypeError.expected(" << escaped_name << ", to_be_a: property.type)\n" <<
185
- "end\n"
212
+ " property.check_initializer(self, " << escaped_name << ")\n"
186
213
  end
187
214
 
188
215
  def generate_initializer_assign_value(buffer = +"")
189
216
  buffer <<
190
- "@" <<
217
+ " @" <<
191
218
  @name.name <<
192
219
  " = " <<
193
220
  escaped_name <<
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Literal::Rails::EnumSerializer < ActiveJob::Serializers::ObjectSerializer
4
+ def serialize?(object)
5
+ Literal::Enum === object
6
+ end
7
+
8
+ def serialize(object)
9
+ super([
10
+ 0,
11
+ object.class.name,
12
+ object.value,
13
+ ])
14
+ end
15
+
16
+ def deserialize(payload)
17
+ _version, class_name, value = payload
18
+ class_name.constantize[value]
19
+ end
20
+ end