lab42_data_class 0.7.1 → 0.7.2

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: 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: []