lab42_data_class 0.7.2 → 0.8.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
- data/README.md +51 -0
- data/lib/lab42/data_class/builtin_constraints.rb +4 -1
- data/lib/lab42/data_class/constraints/attribute_setters/attribute_setter.rb +29 -0
- data/lib/lab42/data_class/constraints/attribute_setters/list_of_attribute_setter.rb +26 -0
- data/lib/lab42/data_class/constraints/attribute_setters/pair_of_attribute_setter.rb +28 -0
- data/lib/lab42/data_class/constraints/attribute_setters/triple_of_attribute_setter.rb +34 -0
- data/lib/lab42/data_class/constraints/constraint.rb +28 -0
- data/lib/lab42/data_class/constraints/kernel.rb +25 -5
- data/lib/lab42/data_class/constraints/list_of_constraint.rb +17 -0
- data/lib/lab42/data_class/constraints/pair_of_constraint.rb +17 -0
- data/lib/lab42/data_class/constraints/setter_constraint.rb +28 -0
- data/lib/lab42/data_class/constraints/triple_of_constraint.rb +17 -0
- data/lib/lab42/data_class/kernel.rb +7 -0
- data/lib/lab42/data_class/proxy/constraints/maker.rb +2 -2
- data/lib/lab42/data_class/proxy/constraints.rb +20 -12
- data/lib/lab42/data_class/proxy/memos.rb +2 -0
- data/lib/lab42/data_class/proxy.rb +13 -0
- data/lib/lab42/data_class/undefined_setter_error.rb +9 -0
- data/lib/lab42/data_class/version.rb +1 -1
- data/lib/lab42/data_class.rb +3 -0
- data/lib/lab42/list/class_methods.rb +37 -0
- data/lib/lab42/list.rb +33 -0
- data/lib/lab42/nil.rb +13 -0
- data/lib/lab42/pair.rb +3 -0
- data/lib/lab42/triple.rb +4 -0
- metadata +15 -3
- data/lib/lab42/data_class/constraint.rb +0 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 50100679a9eb64c9e3b2df3a77a3a845d6fe4e8ec2e606d2ffb0bd59c183e4ba
|
4
|
+
data.tar.gz: f4be63d0eba008e9ce4b867a6b016aff7c0afa6d7a1dc6b67c8989fc2ad5d671
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ae62d41abf7ee6eab00668cb7112afd0a0182baf98f1b1dd09768b349a0f8cb8cea62561e4cf8bfeb1d9ad3c157d563373775193f7e21d06b462d0056d10d52
|
7
|
+
data.tar.gz: 53809601ba8a2b3284c0767a22f6dd07a9eb93d8f564d73107d9c53d41153599403f3e1b833fda0531628b3f87ca15105d2ba41c6c1ace33b753a901274b5426
|
data/README.md
CHANGED
@@ -235,6 +235,57 @@ And of course the factory functions are equivalent to the constructors
|
|
235
235
|
expect(node).to eq(Lab42::Triple.new("42", 4, 2))
|
236
236
|
```
|
237
237
|
|
238
|
+
#### Context: Pseudo Assignments
|
239
|
+
|
240
|
+
... in reality return a new object
|
241
|
+
|
242
|
+
Given an instance of `Pair`
|
243
|
+
```ruby
|
244
|
+
let(:original) { Pair(1, 1) }
|
245
|
+
```
|
246
|
+
|
247
|
+
And one of `Triple`
|
248
|
+
```ruby
|
249
|
+
let(:xyz) { Triple(1, 1, 1) }
|
250
|
+
```
|
251
|
+
|
252
|
+
Then
|
253
|
+
```ruby
|
254
|
+
second = original.set_first(2)
|
255
|
+
third = second.set_second(2)
|
256
|
+
expect(original).to eq( Pair(1, 1) )
|
257
|
+
expect(second).to eq(Pair(2, 1))
|
258
|
+
expect(third).to eq(Pair(2, 2))
|
259
|
+
```
|
260
|
+
|
261
|
+
And also
|
262
|
+
```ruby
|
263
|
+
second = xyz.set_first(2)
|
264
|
+
third = second.set_second(2)
|
265
|
+
fourth = third.set_third(2)
|
266
|
+
expect(xyz).to eq(Triple(1, 1, 1))
|
267
|
+
expect(second).to eq(Triple(2, 1, 1))
|
268
|
+
expect(third).to eq(Triple(2, 2, 1))
|
269
|
+
expect(fourth).to eq(Triple(2, 2, 2))
|
270
|
+
```
|
271
|
+
|
272
|
+
## Context: `List`
|
273
|
+
|
274
|
+
A `List` is what a _list_ is in Lisp or Elixir it exposes the following API
|
275
|
+
|
276
|
+
Given such a _list_
|
277
|
+
```ruby
|
278
|
+
let(:three) { List(*%w[a b c]) }
|
279
|
+
```
|
280
|
+
|
281
|
+
Then this becomes really a _linked_list_
|
282
|
+
```ruby
|
283
|
+
expect(three.car).to eq("a")
|
284
|
+
expect(three.cdr).to eq(List(*%w[b c]))
|
285
|
+
```
|
286
|
+
|
287
|
+
For all details please consult the [List speculations](speculations/LIST.md)
|
288
|
+
|
238
289
|
# LICENSE
|
239
290
|
|
240
291
|
Copyright 2022 Robert Dober robert.dober@gmail.com
|
@@ -1,6 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "constraint"
|
3
|
+
require_relative "constraints/constraint"
|
4
|
+
require_relative "constraints/list_of_constraint"
|
5
|
+
require_relative "constraints/pair_of_constraint"
|
6
|
+
require_relative "constraints/triple_of_constraint"
|
4
7
|
require_relative "constraints/kernel"
|
5
8
|
|
6
9
|
module Lab42
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lab42
|
4
|
+
module DataClass
|
5
|
+
module Constraints
|
6
|
+
module AttributeSetters
|
7
|
+
module AttributeSetter
|
8
|
+
attr_reader :attribute, :constraint, :instance
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def initialize(attribute:, constraint:, instance:)
|
13
|
+
@attribute = attribute
|
14
|
+
@constraint = constraint
|
15
|
+
@instance = instance
|
16
|
+
end
|
17
|
+
|
18
|
+
def _set_attr!(value)
|
19
|
+
new_values = instance.to_h.merge(attribute => value)
|
20
|
+
instance.class.send(:_new_from_merge, {}, new_values)
|
21
|
+
end
|
22
|
+
|
23
|
+
def _value = @___value__ ||= instance[attribute]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
# SPDX-License-Identifier: Apache-2.0
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "attribute_setter"
|
4
|
+
module Lab42
|
5
|
+
module DataClass
|
6
|
+
module Constraints
|
7
|
+
module AttributeSetters
|
8
|
+
class ListOfAttributeSetter
|
9
|
+
include AttributeSetter
|
10
|
+
|
11
|
+
def cons(value)
|
12
|
+
constraint.constraint.(value) or raise ConstraintError,
|
13
|
+
"cannot set value #{value} in set(#{attribute}).cons"
|
14
|
+
|
15
|
+
_set_attr!(_value.cons(value))
|
16
|
+
end
|
17
|
+
|
18
|
+
def cdr
|
19
|
+
_set_attr!(_value.cdr)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
# SPDX-License-Identifier: Apache-2.0
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "attribute_setter"
|
4
|
+
module Lab42
|
5
|
+
module DataClass
|
6
|
+
module Constraints
|
7
|
+
module AttributeSetters
|
8
|
+
class PairOfAttributeSetter
|
9
|
+
include AttributeSetter
|
10
|
+
|
11
|
+
def first_element(value)
|
12
|
+
constraint.constraint.first.(value) or raise ConstraintError,
|
13
|
+
"cannot set value #{value} in set(#{attribute}).first_element"
|
14
|
+
|
15
|
+
_set_attr!(_value.set_first(value))
|
16
|
+
end
|
17
|
+
|
18
|
+
def second_element(value)
|
19
|
+
constraint.constraint.last.(value) or raise ConstraintError,
|
20
|
+
"cannot set value #{value} in set(#{attribute}).second_element"
|
21
|
+
_set_attr!(_value.set_second(value))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
# SPDX-License-Identifier: Apache-2.0
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "attribute_setter"
|
4
|
+
module Lab42
|
5
|
+
module DataClass
|
6
|
+
module Constraints
|
7
|
+
module AttributeSetters
|
8
|
+
class TripleOfAttributeSetter
|
9
|
+
include AttributeSetter
|
10
|
+
|
11
|
+
def first_element(value)
|
12
|
+
constraint.constraint.first.(value) or raise ConstraintError,
|
13
|
+
"cannot set value #{value} in set(#{attribute}).first_element"
|
14
|
+
|
15
|
+
_set_attr!(_value.set_first(value))
|
16
|
+
end
|
17
|
+
|
18
|
+
def second_element(value)
|
19
|
+
constraint.constraint[1].(value) or raise ConstraintError,
|
20
|
+
"cannot set value #{value} in set(#{attribute}).second_element"
|
21
|
+
_set_attr!(_value.set_second(value))
|
22
|
+
end
|
23
|
+
|
24
|
+
def third_element(value)
|
25
|
+
constraint.constraint.last.(value) or raise ConstraintError,
|
26
|
+
"cannot set value #{value} in set(#{attribute}).third_element"
|
27
|
+
_set_attr!(_value.set_third(value))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
# SPDX-License-Identifier: Apache-2.0
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "lab42/data_class"
|
4
|
+
module Lab42
|
5
|
+
module DataClass
|
6
|
+
module Constraints
|
7
|
+
class Constraint
|
8
|
+
attr_reader :name, :function
|
9
|
+
|
10
|
+
def call(value) = function.(value)
|
11
|
+
def setter_constraint? = false
|
12
|
+
def to_s = "Constraint<#{name}>"
|
13
|
+
|
14
|
+
private
|
15
|
+
def initialize(name:, function:)
|
16
|
+
raise ArgumentError, "name not a String, but #{name}" unless String === name
|
17
|
+
unless function.respond_to?(:arity) && function.arity == 1
|
18
|
+
raise ArgumentError, "function not a callable with arity 1 #{function}"
|
19
|
+
end
|
20
|
+
|
21
|
+
@name = name
|
22
|
+
@function = function
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
# SPDX-License-Identifier: Apache-2.0
|
@@ -1,7 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Kernel
|
4
|
-
|
4
|
+
Constraints = Lab42::DataClass::Constraints
|
5
|
+
Constraint = Constraints::Constraint
|
6
|
+
ListOfConstraint = Constraints::ListOfConstraint
|
7
|
+
PairOfConstraint = Constraints::PairOfConstraint
|
8
|
+
TripleOfConstraint = Constraints::TripleOfConstraint
|
9
|
+
|
5
10
|
Maker = Lab42::DataClass::Proxy::Constraints::Maker # TODO: Move Maker to Lab42::DataClass:ConstraintMaker
|
6
11
|
Anything = Constraint.new(name: "Anything", function: ->(_) { true })
|
7
12
|
Boolean = Constraint.new(name: "Boolean", function: -> { [false, true].member?(_1) })
|
@@ -41,10 +46,19 @@ module Kernel
|
|
41
46
|
end
|
42
47
|
|
43
48
|
def Lambda(arity)
|
44
|
-
|
49
|
+
function = -> do
|
45
50
|
_1.arity == arity rescue false
|
46
51
|
end
|
47
|
-
Constraint.new(name: "Lambda(#{arity})", function:
|
52
|
+
Constraint.new(name: "Lambda(#{arity})", function:)
|
53
|
+
end
|
54
|
+
|
55
|
+
def ListOf(constraint, &blk)
|
56
|
+
constraint = Maker.make_constraint(constraint, &blk)
|
57
|
+
function = -> do
|
58
|
+
(Lab42::List === _1 || Lab42::Nil == _1) &&
|
59
|
+
_1.all?(&constraint)
|
60
|
+
end
|
61
|
+
ListOfConstraint.new(name: "ListOf(#{constraint})", constraint:, function:)
|
48
62
|
end
|
49
63
|
|
50
64
|
def NilOr(constraint = nil, &blk)
|
@@ -62,10 +76,11 @@ module Kernel
|
|
62
76
|
def PairOf(fst, snd)
|
63
77
|
fst_constraint = Maker.make_constraint(fst)
|
64
78
|
snd_constraint = Maker.make_constraint(snd)
|
79
|
+
constraint = [fst_constraint, snd_constraint]
|
65
80
|
f = -> do
|
66
81
|
Lab42::Pair === _1 && fst_constraint.(_1.first) && snd_constraint.(_1.second)
|
67
82
|
end
|
68
|
-
|
83
|
+
PairOfConstraint.new(name: "PairOf(#{fst_constraint}, #{snd_constraint})", function: f, constraint:)
|
69
84
|
end
|
70
85
|
|
71
86
|
def StartsWith(str)
|
@@ -77,10 +92,15 @@ module Kernel
|
|
77
92
|
fst_constraint = Maker.make_constraint(fst)
|
78
93
|
snd_constraint = Maker.make_constraint(snd)
|
79
94
|
trd_constraint = Maker.make_constraint(trd)
|
95
|
+
constraint = [fst_constraint, snd_constraint, trd_constraint]
|
80
96
|
f = -> do
|
81
97
|
Lab42::Triple === _1 && fst_constraint.(_1.first) && snd_constraint.(_1.second) && trd_constraint.(_1.third)
|
82
98
|
end
|
83
|
-
|
99
|
+
TripleOfConstraint.new(
|
100
|
+
name: "TripleOf(#{fst_constraint}, #{snd_constraint}, #{trd_constraint})",
|
101
|
+
function: f,
|
102
|
+
constraint:
|
103
|
+
)
|
84
104
|
end
|
85
105
|
end
|
86
106
|
# SPDX-License-Identifier: Apache-2.0
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "constraint"
|
4
|
+
require_relative "setter_constraint"
|
5
|
+
require_relative "attribute_setters/list_of_attribute_setter"
|
6
|
+
module Lab42
|
7
|
+
module DataClass
|
8
|
+
module Constraints
|
9
|
+
class ListOfConstraint < Constraint
|
10
|
+
include SetterConstraint
|
11
|
+
|
12
|
+
def attribute_setter = AttributeSetters::ListOfAttributeSetter
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
# SPDX-License-Identifier: Apache-2.0
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "constraint"
|
4
|
+
require_relative "setter_constraint"
|
5
|
+
require_relative "attribute_setters/pair_of_attribute_setter"
|
6
|
+
module Lab42
|
7
|
+
module DataClass
|
8
|
+
module Constraints
|
9
|
+
class PairOfConstraint < Constraint
|
10
|
+
include SetterConstraint
|
11
|
+
|
12
|
+
def attribute_setter = AttributeSetters::PairOfAttributeSetter
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
# SPDX-License-Identifier: Apache-2.0
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lab42
|
4
|
+
module DataClass
|
5
|
+
module Constraints
|
6
|
+
module SetterConstraint
|
7
|
+
attr_reader :constraint
|
8
|
+
|
9
|
+
def setter_constraint? = true
|
10
|
+
|
11
|
+
def setter_for(attribute:, instance:)
|
12
|
+
attribute_setter.new(
|
13
|
+
attribute:,
|
14
|
+
constraint: self,
|
15
|
+
instance:
|
16
|
+
)
|
17
|
+
end
|
18
|
+
private
|
19
|
+
|
20
|
+
def initialize(constraint:, **other)
|
21
|
+
super(**other)
|
22
|
+
@constraint = constraint
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
# SPDX-License-Identifier: Apache-2.0
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "constraint"
|
4
|
+
require_relative "setter_constraint"
|
5
|
+
require_relative "attribute_setters/triple_of_attribute_setter"
|
6
|
+
module Lab42
|
7
|
+
module DataClass
|
8
|
+
module Constraints
|
9
|
+
class TripleOfConstraint < Constraint
|
10
|
+
include SetterConstraint
|
11
|
+
|
12
|
+
def attribute_setter = AttributeSetters::TripleOfAttributeSetter
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
# SPDX-License-Identifier: Apache-2.0
|
@@ -1,11 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative '../nil'
|
3
4
|
module Kernel
|
5
|
+
Nil = Lab42::Nil
|
6
|
+
|
4
7
|
def DataClass(*args, **kwds, &blk)
|
5
8
|
proxy = Lab42::DataClass::Proxy.new(*args, **kwds, &blk)
|
6
9
|
proxy.define_class!
|
7
10
|
end
|
8
11
|
|
12
|
+
def List(*elements)
|
13
|
+
Lab42::List.new(*elements)
|
14
|
+
end
|
15
|
+
|
9
16
|
def Pair(first, second)
|
10
17
|
Lab42::Pair.new(first, second)
|
11
18
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "lab42/data_class/constraint"
|
3
|
+
require "lab42/data_class/constraints/constraint"
|
4
4
|
module Lab42
|
5
5
|
module DataClass
|
6
6
|
class Proxy
|
@@ -18,7 +18,7 @@ module Lab42
|
|
18
18
|
|
19
19
|
def _make_constraint(constraint)
|
20
20
|
case constraint
|
21
|
-
when Lab42::DataClass::Constraint, Proc, Method
|
21
|
+
when Lab42::DataClass::Constraints::Constraint, Proc, Method
|
22
22
|
constraint
|
23
23
|
when Symbol
|
24
24
|
-> { _1.send(constraint) }
|
@@ -12,19 +12,8 @@ module Lab42
|
|
12
12
|
raise ConstraintError, errors.join("\n\n") unless errors.empty?
|
13
13
|
end
|
14
14
|
|
15
|
-
def define_constraint
|
16
|
-
->((attr, constraint)) do
|
17
|
-
if members!.member?(attr)
|
18
|
-
constraints[attr] << Maker.make_constraint(constraint)
|
19
|
-
nil
|
20
|
-
else
|
21
|
-
attr
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
15
|
def define_constraints(constraints)
|
27
|
-
errors = constraints.map(&
|
16
|
+
errors = constraints.map(&_define_constraint).compact
|
28
17
|
unless errors.empty?
|
29
18
|
raise UndefinedAttributeError,
|
30
19
|
"constraints cannot be defined for undefined attributes #{errors.inspect}"
|
@@ -74,6 +63,19 @@ module Lab42
|
|
74
63
|
raise ConstraintError, errors.join("\n\n") unless errors.empty?
|
75
64
|
end
|
76
65
|
|
66
|
+
def _define_constraint
|
67
|
+
->((attr, constraint)) do
|
68
|
+
if members!.member?(attr)
|
69
|
+
constraint = Maker.make_constraint(constraint)
|
70
|
+
_maybe_define_setter_constraint(attr, constraint)
|
71
|
+
constraints[attr] << constraint
|
72
|
+
nil
|
73
|
+
else
|
74
|
+
attr
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
77
79
|
def _define_with_constraint
|
78
80
|
proxy = self
|
79
81
|
->(*) do
|
@@ -83,6 +85,12 @@ module Lab42
|
|
83
85
|
end
|
84
86
|
end
|
85
87
|
end
|
88
|
+
|
89
|
+
def _maybe_define_setter_constraint(attr, constraint)
|
90
|
+
if Lab42::DataClass::Constraints::Constraint === constraint && constraint.setter_constraint?
|
91
|
+
setter_attributes.update(attr => constraint)
|
92
|
+
end
|
93
|
+
end
|
86
94
|
end
|
87
95
|
end
|
88
96
|
end
|
@@ -160,6 +160,7 @@ module Lab42
|
|
160
160
|
klass.module_eval(&_define_access)
|
161
161
|
klass.module_eval(&_define_to_h)
|
162
162
|
klass.module_eval(&_define_merge)
|
163
|
+
klass.module_eval(&_define_set)
|
163
164
|
end
|
164
165
|
|
165
166
|
def _define_singleton_methods(singleton)
|
@@ -198,6 +199,18 @@ module Lab42
|
|
198
199
|
end
|
199
200
|
end
|
200
201
|
|
202
|
+
def _define_set
|
203
|
+
proxy = self
|
204
|
+
->(*) do
|
205
|
+
define_method :set do |attribute|
|
206
|
+
setter_constraint = proxy.setter_attributes.fetch(attribute) do
|
207
|
+
raise UndefinedSetterError, "There is no constraint implementing a setter for attribute #{attribute}"
|
208
|
+
end
|
209
|
+
setter_constraint.setter_for(attribute:, instance: self)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
201
214
|
def _init(data_class_instance, params)
|
202
215
|
params.each do |key, value|
|
203
216
|
data_class_instance.instance_variable_set("@#{key}", value)
|
data/lib/lab42/data_class.rb
CHANGED
@@ -4,8 +4,11 @@ require_relative './data_class/constraint_error'
|
|
4
4
|
require_relative './data_class/duplicate_definition_error'
|
5
5
|
require_relative './data_class/kernel'
|
6
6
|
require_relative './data_class/undefined_attribute_error'
|
7
|
+
require_relative './data_class/undefined_setter_error'
|
7
8
|
require_relative './data_class/validation_error'
|
8
9
|
require_relative './data_class/proxy'
|
10
|
+
require_relative './list'
|
11
|
+
require_relative './nil'
|
9
12
|
require_relative './pair'
|
10
13
|
require_relative './triple'
|
11
14
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lab42
|
4
|
+
class List
|
5
|
+
module ClassMethods
|
6
|
+
def cons(element, list)
|
7
|
+
raise ArgumentError, "list needs to be a list instance" unless list?(list)
|
8
|
+
|
9
|
+
allocate.tap do |o|
|
10
|
+
o.instance_variable_set("@car", element)
|
11
|
+
o.instance_variable_set("@cdr", list)
|
12
|
+
o.instance_variable_set("@length", list.length.succ)
|
13
|
+
o.freeze
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def each(subject, &blk)
|
18
|
+
unless subject.empty?
|
19
|
+
blk.(subject.car)
|
20
|
+
each(subject.cdr, &blk)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def list?(subject)
|
25
|
+
self === subject || Nil == subject
|
26
|
+
end
|
27
|
+
|
28
|
+
def new(*elements)
|
29
|
+
elements.reverse.inject(Nil) do |list, element|
|
30
|
+
cons(element, list)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
extend ClassMethods
|
35
|
+
end
|
36
|
+
end
|
37
|
+
# SPDX-License-Identifier: Apache-2.0
|
data/lib/lab42/list.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "nil"
|
4
|
+
require_relative "list/class_methods"
|
5
|
+
module Lab42
|
6
|
+
class List
|
7
|
+
include Enumerable
|
8
|
+
attr_reader :car, :cdr, :length
|
9
|
+
|
10
|
+
def ==(other) =
|
11
|
+
self.class.list?(other) &&
|
12
|
+
length == other.length &&
|
13
|
+
car == other.car &&
|
14
|
+
cdr == other.cdr
|
15
|
+
|
16
|
+
def cadr = cdr.car
|
17
|
+
|
18
|
+
def caddr = cdr.cdr.car
|
19
|
+
|
20
|
+
def cddr = cdr.cdr
|
21
|
+
|
22
|
+
def cdddr = cdr.cdr.cdr
|
23
|
+
|
24
|
+
def cons(new_head) = self.class.cons(new_head, self)
|
25
|
+
|
26
|
+
def deconstruct = [car, cdr]
|
27
|
+
|
28
|
+
def each(&blk) = self.class.each(self, &blk)
|
29
|
+
|
30
|
+
def empty? = false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
# SPDX-License-Identifier: Apache-2.0
|
data/lib/lab42/nil.rb
ADDED
data/lib/lab42/pair.rb
CHANGED
data/lib/lab42/triple.rb
CHANGED
@@ -10,6 +10,10 @@ module Lab42
|
|
10
10
|
[first, second, third]
|
11
11
|
end
|
12
12
|
|
13
|
+
def set_first(new_first) = self.class.new(new_first, second, third)
|
14
|
+
def set_second(new_second) = self.class.new(first, new_second, third)
|
15
|
+
def set_third(new_third) = self.class.new(first, second, new_third)
|
16
|
+
|
13
17
|
private
|
14
18
|
|
15
19
|
def initialize(first, second, third)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lab42_data_class
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Dober
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-03-
|
11
|
+
date: 2022-03-06 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |
|
14
14
|
An Immutable DataClass for Ruby
|
@@ -25,9 +25,17 @@ files:
|
|
25
25
|
- README.md
|
26
26
|
- lib/lab42/data_class.rb
|
27
27
|
- lib/lab42/data_class/builtin_constraints.rb
|
28
|
-
- lib/lab42/data_class/constraint.rb
|
29
28
|
- lib/lab42/data_class/constraint_error.rb
|
29
|
+
- lib/lab42/data_class/constraints/attribute_setters/attribute_setter.rb
|
30
|
+
- lib/lab42/data_class/constraints/attribute_setters/list_of_attribute_setter.rb
|
31
|
+
- lib/lab42/data_class/constraints/attribute_setters/pair_of_attribute_setter.rb
|
32
|
+
- lib/lab42/data_class/constraints/attribute_setters/triple_of_attribute_setter.rb
|
33
|
+
- lib/lab42/data_class/constraints/constraint.rb
|
30
34
|
- lib/lab42/data_class/constraints/kernel.rb
|
35
|
+
- lib/lab42/data_class/constraints/list_of_constraint.rb
|
36
|
+
- lib/lab42/data_class/constraints/pair_of_constraint.rb
|
37
|
+
- lib/lab42/data_class/constraints/setter_constraint.rb
|
38
|
+
- lib/lab42/data_class/constraints/triple_of_constraint.rb
|
31
39
|
- lib/lab42/data_class/duplicate_definition_error.rb
|
32
40
|
- lib/lab42/data_class/kernel.rb
|
33
41
|
- lib/lab42/data_class/proxy.rb
|
@@ -38,9 +46,13 @@ files:
|
|
38
46
|
- lib/lab42/data_class/proxy/mixin.rb
|
39
47
|
- lib/lab42/data_class/proxy/validations.rb
|
40
48
|
- lib/lab42/data_class/undefined_attribute_error.rb
|
49
|
+
- lib/lab42/data_class/undefined_setter_error.rb
|
41
50
|
- lib/lab42/data_class/validation_error.rb
|
42
51
|
- lib/lab42/data_class/version.rb
|
43
52
|
- lib/lab42/eq_and_patterns.rb
|
53
|
+
- lib/lab42/list.rb
|
54
|
+
- lib/lab42/list/class_methods.rb
|
55
|
+
- lib/lab42/nil.rb
|
44
56
|
- lib/lab42/pair.rb
|
45
57
|
- lib/lab42/triple.rb
|
46
58
|
homepage: https://github.com/robertdober/lab42_data_class
|
@@ -1,30 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "lab42/data_class"
|
4
|
-
module Lab42
|
5
|
-
module DataClass
|
6
|
-
class Constraint
|
7
|
-
attr_reader :name, :function
|
8
|
-
|
9
|
-
def call(value)
|
10
|
-
function.(value)
|
11
|
-
end
|
12
|
-
|
13
|
-
def to_s
|
14
|
-
"Constraint<#{name}>"
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
def initialize(name:, function:)
|
19
|
-
raise ArgumentError, "name not a String, but #{name}" unless String === name
|
20
|
-
unless function.respond_to?(:arity) && function.arity == 1
|
21
|
-
raise ArgumentError, "function not a callable with arity 1 #{function}"
|
22
|
-
end
|
23
|
-
|
24
|
-
@name = name
|
25
|
-
@function = function
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
# SPDX-License-Identifier: Apache-2.0
|