lab42_data_class 0.7.1 → 0.7.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8fdfa61b721a7e006b42dd59c3dc61c4f3442faaa0d50feeaa5ed4b20ea5838c
4
- data.tar.gz: fa5d7ab0e6133c398caaaa1762e75a5820123e67088acc4750c36e9246ff2dc0
3
+ metadata.gz: 746ce73ef4464de258f683f0d8366f15799cb8e3ea34a062cc6f4deb34f0a60d
4
+ data.tar.gz: 96c679474b72b872f4885ab2c98f7ddfd5f914268b3a9da5ba59f7ae026e5eed
5
5
  SHA512:
6
- metadata.gz: 53af67931648a621cd0ff18912ce191dc2d0a005eacfd4df741bbdf8a58a9c695e168055129c76be08efcb4810d3910a5df362512996c8d2375da6ff17b61be8
7
- data.tar.gz: c65a655f447f154b1a4e7584393fe3058403ef53cf5651a51fd39e5af7ebbd88768e90dc9b8d1a7d582316a35d2786abff6c6a04cc2f445f8d725657773c9a21
6
+ metadata.gz: 184dc66df2185e0869a5cbce9811c8bedf685123037fadf8d17c30bfd762884b9f0d0756bc0d43787dce2586c8094bb2a798aba9b54087198b59a1a0d95023c0
7
+ data.tar.gz: 859c555137b976c4885157c5b39d42393c528adf94abb3dd28b9cbd3e38625d3bccac9b5cf5e317cdf3dddb08494fa989dd11523902f79402ed915822d616a64
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "constraint"
4
+ require_relative "constraints/kernel"
5
+
6
+ module Lab42
7
+ module DataClass
8
+ module BuiltinConstraints
9
+ extend self
10
+ end
11
+ end
12
+ end
13
+
14
+ # SPDX-License-Identifier: Apache-2.0
@@ -0,0 +1,30 @@
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
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kernel
4
+ Constraint = Lab42::DataClass::Constraint
5
+ Maker = Lab42::DataClass::Proxy::Constraints::Maker # TODO: Move Maker to Lab42::DataClass:ConstraintMaker
6
+ Anything = Constraint.new(name: "Anything", function: ->(_) { true })
7
+ Boolean = Constraint.new(name: "Boolean", function: -> { [false, true].member?(_1) })
8
+
9
+ def All?(constraint = nil, &blk)
10
+ constraint = Maker.make_constraint(constraint, &blk)
11
+ f = -> do
12
+ _1.all?(&constraint)
13
+ end
14
+ Constraint.new(name: "All?(#{constraint})", function: f)
15
+ end
16
+
17
+ def Any?(constraint = nil, &blk)
18
+ constraint = Maker.make_constraint(constraint, &blk)
19
+ f = -> do
20
+ _1.any?(&constraint)
21
+ end
22
+ Constraint.new(name: "Any?(#{constraint})", function: f)
23
+ end
24
+
25
+ def Choice(*constraints)
26
+ constraints = constraints.map{ Maker.make_constraint _1 }
27
+ f = ->(value) do
28
+ constraints.any?{ _1.(value) }
29
+ end
30
+ Constraint.new(name: "Choice(#{constraints.join(', ')})", function: f)
31
+ end
32
+
33
+ def Contains(str)
34
+ f = -> { _1.include?(str) rescue false }
35
+ Constraint.new(name: "Contains(#{str})", function: f)
36
+ end
37
+
38
+ def EndsWith(str)
39
+ f = -> { _1.end_with?(str) rescue false }
40
+ Constraint.new(name: "EndsWith(#{str})", function: f)
41
+ end
42
+
43
+ def Lambda(arity)
44
+ f = -> do
45
+ _1.arity == arity rescue false
46
+ end
47
+ Constraint.new(name: "Lambda(#{arity})", function: f)
48
+ end
49
+
50
+ def NilOr(constraint = nil, &blk)
51
+ constraint = Maker.make_constraint(constraint, &blk)
52
+ f = -> { _1.nil? || constraint.(_1) }
53
+ Constraint.new(name: "NilOr(#{constraint})", function: f)
54
+ end
55
+
56
+ def Not(constraint = nil, &blk)
57
+ constraint = Maker.make_constraint(constraint, &blk)
58
+ f = -> { !constraint.(_1) }
59
+ Constraint.new(name: "Not(#{constraint})", function: f)
60
+ end
61
+
62
+ def PairOf(fst, snd)
63
+ fst_constraint = Maker.make_constraint(fst)
64
+ snd_constraint = Maker.make_constraint(snd)
65
+ f = -> do
66
+ Lab42::Pair === _1 && fst_constraint.(_1.first) && snd_constraint.(_1.second)
67
+ end
68
+ Constraint.new(name: "PairOf(#{fst_constraint}, #{snd_constraint})", function: f)
69
+ end
70
+
71
+ def StartsWith(str)
72
+ f = -> { _1.start_with?(str) rescue false }
73
+ Constraint.new(name: "StartsWith(#{str})", function: f)
74
+ end
75
+
76
+ def TripleOf(fst, snd, trd)
77
+ fst_constraint = Maker.make_constraint(fst)
78
+ snd_constraint = Maker.make_constraint(snd)
79
+ trd_constraint = Maker.make_constraint(trd)
80
+ f = -> do
81
+ Lab42::Triple === _1 && fst_constraint.(_1.first) && snd_constraint.(_1.second) && trd_constraint.(_1.third)
82
+ end
83
+ Constraint.new(name: "TripleOf(#{fst_constraint}, #{snd_constraint}, #{trd_constraint})", function: f)
84
+ end
85
+ end
86
+ # SPDX-License-Identifier: Apache-2.0
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "lab42/data_class/constraint"
3
4
  module Lab42
4
5
  module DataClass
5
6
  class Proxy
@@ -7,9 +8,17 @@ module Lab42
7
8
  module Maker
8
9
  extend self
9
10
 
10
- def make_constraint(constraint)
11
+ def make_constraint(constraint, &blk)
12
+ raise ArgumentError, "must not pass a callable #{constraint} and a block" if constraint && blk
13
+
14
+ _make_constraint(constraint || blk)
15
+ end
16
+
17
+ private
18
+
19
+ def _make_constraint(constraint)
11
20
  case constraint
12
- when Proc, Method
21
+ when Lab42::DataClass::Constraint, Proc, Method
13
22
  constraint
14
23
  when Symbol
15
24
  -> { _1.send(constraint) }
@@ -26,8 +35,6 @@ module Lab42
26
35
  end
27
36
  end
28
37
 
29
- private
30
-
31
38
  def _make_member_constraint(constraint)
32
39
  if constraint.respond_to?(:member?)
33
40
  -> { constraint.member?(_1) }
@@ -30,12 +30,11 @@ module Lab42
30
30
  end
31
31
  end
32
32
 
33
- def check!(**params)
34
- @actual_params = params
33
+ def check!(params, merge_with = defaults)
35
34
  raise ArgumentError, "missing initializers for #{_missing_initializers}" unless _missing_initializers.empty?
36
35
  raise ArgumentError, "illegal initializers #{_illegal_initializers}" unless _illegal_initializers.empty?
37
36
 
38
- _check_constraints!(defaults.merge(params))
37
+ _check_constraints!(merge_with.merge(params))
39
38
  end
40
39
 
41
40
  def define_class!
@@ -63,6 +62,10 @@ module Lab42
63
62
  _init(data_class, defaults.merge(params))
64
63
  end
65
64
 
65
+ def set_actual_params(params)
66
+ @actual_params = params
67
+ end
68
+
66
69
  def to_hash(data_class_instance)
67
70
  all_attributes
68
71
  .inject({}) { |result, (k, _)| result.merge(k => data_class_instance[k]) }
@@ -96,15 +99,40 @@ module Lab42
96
99
 
97
100
  def _define_derived_attribute(name, &blk)
98
101
  ->(*) do
102
+ if instance_methods.include?(name)
103
+ begin
104
+ remove_method(name)
105
+ rescue StandardError
106
+ nil
107
+ end
108
+ end
99
109
  define_method(name) { blk.call(self) }
100
110
  end
101
111
  end
102
112
 
103
113
  def _define_freezing_constructor
114
+ proxy = self
115
+ ->(*) do
116
+ define_method :new do |**params, &b|
117
+ allocate.tap do |o|
118
+ proxy.set_actual_params(params)
119
+ proxy.check!(params)
120
+ o.send(:initialize, **params, &b)
121
+ end.freeze
122
+ end
123
+ end
124
+ end
125
+
126
+ def _define_merging_constructor
127
+ proxy = self
104
128
  ->(*) do
105
- define_method :new do |*a, **p, &b|
106
- super(*a, **p, &b).freeze
129
+ define_method :_new_from_merge do |new_params, params|
130
+ allocate.tap do |o|
131
+ proxy.check!(new_params, {})
132
+ o.send(:initialize, **params)
133
+ end.freeze
107
134
  end
135
+ private :_new_from_merge
108
136
  end
109
137
  end
110
138
 
@@ -112,7 +140,6 @@ module Lab42
112
140
  proxy = self
113
141
  ->(*) do
114
142
  define_method :initialize do |**params|
115
- proxy.check!(**params)
116
143
  proxy.init(self, **params)
117
144
  proxy.validate!(self)
118
145
  end
@@ -123,7 +150,7 @@ module Lab42
123
150
  ->(*) do
124
151
  define_method :merge do |**params|
125
152
  values = to_h.merge(params)
126
- self.class.new(**values)
153
+ self.class.send(:_new_from_merge, params, values)
127
154
  end
128
155
  end
129
156
  end
@@ -137,6 +164,7 @@ module Lab42
137
164
 
138
165
  def _define_singleton_methods(singleton)
139
166
  singleton.module_eval(&_define_freezing_constructor)
167
+ singleton.module_eval(&_define_merging_constructor)
140
168
  singleton.module_eval(&_define_to_proc)
141
169
  singleton.module_eval(&_define_with_constraint)
142
170
  singleton.module_eval(&_define_derived)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Lab42
4
4
  module DataClass
5
- VERSION = "0.7.1"
5
+ VERSION = "0.7.2"
6
6
  end
7
7
  end
8
8
  # SPDX-License-Identifier: Apache-2.0
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.7.1
4
+ version: 0.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Dober
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-28 00:00:00.000000000 Z
11
+ date: 2022-03-03 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
14
  An Immutable DataClass for Ruby
@@ -24,7 +24,10 @@ files:
24
24
  - LICENSE
25
25
  - README.md
26
26
  - lib/lab42/data_class.rb
27
+ - lib/lab42/data_class/builtin_constraints.rb
28
+ - lib/lab42/data_class/constraint.rb
27
29
  - lib/lab42/data_class/constraint_error.rb
30
+ - lib/lab42/data_class/constraints/kernel.rb
28
31
  - lib/lab42/data_class/duplicate_definition_error.rb
29
32
  - lib/lab42/data_class/kernel.rb
30
33
  - lib/lab42/data_class/proxy.rb
@@ -44,7 +47,7 @@ homepage: https://github.com/robertdober/lab42_data_class
44
47
  licenses:
45
48
  - Apache-2.0
46
49
  metadata: {}
47
- post_install_message:
50
+ post_install_message:
48
51
  rdoc_options: []
49
52
  require_paths:
50
53
  - lib
@@ -60,7 +63,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
60
63
  version: '0'
61
64
  requirements: []
62
65
  rubygems_version: 3.3.3
63
- signing_key:
66
+ signing_key:
64
67
  specification_version: 4
65
68
  summary: Finally a dataclass in ruby
66
69
  test_files: []