lab42_checked_class 0.1.1 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d6a2f963809a4e9d945d7f856d5ed6e8bd2af2462e6af8f1c27ec666900adf89
4
- data.tar.gz: b40b601f78decd3af0d7ee5e24e097f64bd546381e92b7d17cd6be532de80431
3
+ metadata.gz: ff1daba1d7c01bd5f4af095171c104f71fdaa6d180659ebdf6fdbb86a6f9c6e9
4
+ data.tar.gz: ac04957601c51e0a505dfb2621a5f44ff3664aeb09a0e00d412fba45de71bc33
5
5
  SHA512:
6
- metadata.gz: 909347acc4fe94f3573718e6a74f325a438dbd4c05af727356c2defce73cac2e4a8e0e80748f6c0333e5cb0b3aff25da52433ab836d76701caf0a33bcca5949d
7
- data.tar.gz: 66921f5b30a49125c5a437a494260dd7c5602e27088d0b34c280cb6eccee9b151cac5582fb15a1ba5e0af224895ca367ce33765614fbca0a00bed3c077b4d6e7
6
+ metadata.gz: cae9380f7d40546c63af28f0abdb59bca958298208cc9b9ec39b1d0ca93acbdfd3eeec642af53e9eeceae9c75259abe79ce7b313dd6be33e6a4d52da7c94755c
7
+ data.tar.gz: a57c32b8094f45501ca71c7bbcf77fa3880732ecadcff5b56ce44a50df824b458cdc6ba4a391c2f12ce58dc32416776b833e0d9ca1f6ab1b159716bf17aead7d
data/README.md CHANGED
@@ -58,8 +58,27 @@ These specs assume the following setup code
58
58
  require 'lab42/checked_class'
59
59
  CheckedClass = Lab42::CheckedClass
60
60
  ConstraintError = CheckedClass::ConstraintError
61
+ Constraint = CheckedClass::Constraint
61
62
  ```
63
+ This is realized in the spec_helper, but if you want to have these three constants in your namespace you can
64
+ do the following:
62
65
 
66
+ ## Context: Importing constants into your namespace
67
+
68
+ Then we will get them loaded
69
+ ```ruby
70
+ expected_output = <<~EOT
71
+ #{ENV["PWD"]}/lib/lab42/checked_class/all.rb:5: warning: already initialized constant CheckedClass
72
+ #{ENV["PWD"]}/spec/spec_helper.rb:36: warning: previous definition of CheckedClass was here
73
+ #{ENV["PWD"]}/lib/lab42/checked_class/all.rb:6: warning: already initialized constant Constraint
74
+ #{ENV["PWD"]}/spec/spec_helper.rb:37: warning: previous definition of Constraint was here
75
+ #{ENV["PWD"]}/lib/lab42/checked_class/all.rb:7: warning: already initialized constant ConstraintError
76
+ #{ENV["PWD"]}/spec/spec_helper.rb:38: warning: previous definition of ConstraintError was here
77
+ EOT
78
+ expect {
79
+ require 'lab42/checked_class/all'
80
+ }.to output(expected_output).to_stderr
81
+ ```
63
82
  ## Context: Attribute definitions and constraints
64
83
 
65
84
  Given a checked class
@@ -119,7 +138,40 @@ And also we cannot create an instance that violates the constraints
119
138
  expect { MyChecked.new(a: 10, c: -4, e: 90, f: 0) }.to raise_error(ConstraintError, "a + b > e")
120
139
  ```
121
140
 
122
- ## Context: More on constraints
141
+ ### Context: Defining attributes with `method` missing.
142
+
143
+ As long as a method is called that is not defined inside the `attributes` block, it will be
144
+ interpreted as an attribute definition, as it cannot have a default value assigned, we can
145
+ also use the `defaults` macro
146
+
147
+ Given such implicit attribute definitions
148
+ ```ruby
149
+ Implicit = Class.new do
150
+ extend CheckedClass
151
+ attributes do
152
+ alpha Numeric
153
+ beta Constraint.bool?
154
+
155
+ defaults alpha: 0, beta: true
156
+ end
157
+ end
158
+ let(:instance) { Implicit.new }
159
+ ```
160
+
161
+ Then we can access the implicitly defined attributes
162
+ ```ruby
163
+ expect(instance.to_h).to eq(alpha: 0, beta: true)
164
+ ```
165
+ And we will get a constraint error as expeced
166
+ ```ruby
167
+ expected_message = "bool? constraint for beta"
168
+ expect { instance.update(beta: 42) }
169
+ .to raise_error(ConstraintError, expected_message)
170
+ ```
171
+
172
+ You can see all predefined builtin constraints [here](speculations/built_in_constraints.md)
173
+
174
+ ## Context: Runtime Semantics of Constraints
123
175
 
124
176
  ### Context: Checked und unchecked attribute updates
125
177
 
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lab42/checked_class'
4
+
5
+ CheckedClass = Lab42::CheckedClass
6
+ Constraint = CheckedClass::Constraint
7
+ ConstraintError = CheckedClass::ConstraintError
8
+
9
+ # SPDX-License-Identifier: AGPL-3.0-or-later
@@ -0,0 +1,24 @@
1
+
2
+ # frozen_string_literal: true
3
+ module Lab42
4
+ module CheckedClass
5
+ class Constraint
6
+ module Predefined
7
+
8
+ def bool? =
9
+ tagged('bool?') { [false, true].member? it }
10
+
11
+ def match?(rgx) =
12
+ tagged("match?(#{rgx}") { rgx === it rescue false }
13
+
14
+ def member?(container) =
15
+ tagged("member?(#{container.inspect}") { container.member? it }
16
+
17
+ private
18
+ def tagged(name, &blk) = [self, blk, name]
19
+
20
+ end
21
+ end
22
+ end
23
+ end
24
+ # SPDX-License-Identifier: AGPL-3.0-or-later
@@ -1,7 +1,10 @@
1
1
  # frozen_string_literal: true
2
+ require_relative 'constraint/predefined'
2
3
  module Lab42
3
4
  module CheckedClass
4
5
  class Constraint
6
+ extend Predefined
7
+
5
8
 
6
9
  def check(subject)
7
10
  subject = @attr ? subject[@attr] : subject
@@ -31,6 +34,9 @@ module Lab42
31
34
  -> { it.send(*args) }
32
35
  in Module
33
36
  -> { constraint === it }
37
+ in [Predefined, blk, name]
38
+ @name = [name, @name].join(' ')
39
+ blk
34
40
  in nil
35
41
  blk
36
42
  in _
@@ -59,6 +59,13 @@ module Lab42
59
59
  constraint_checker.check!(self)
60
60
  end
61
61
 
62
+ define_method :legal? do
63
+ check!
64
+ true
65
+ rescue ConstraintError
66
+ false
67
+ end
68
+
62
69
  define_method :to_h do
63
70
  attributes.inject(Hash.new) { |result, ele|
64
71
  result.update(ele => self[ele])
@@ -52,12 +52,24 @@ module Lab42
52
52
  _constraints["object"] << Constraint.new(name:, &blk)
53
53
  end
54
54
 
55
+ def defaults(**params)
56
+ params.each do |k, v|
57
+ raise ArgumentError, "must not redefine default for key #{k.inspect}" if _defaults.has_key?(k)
58
+
59
+ _defaults[k] = v
60
+ end
61
+ end
62
+
55
63
  def init(&blk)
56
64
  raise ArgumentError, "init needs a block" unless blk
57
65
 
58
66
  @init = blk
59
67
  end
60
68
 
69
+ def method_missing(name, *a, **k, &b)
70
+ attr(name, *a, **k, &b)
71
+ end
72
+
61
73
  def _define_att(name, constraint = nil, default: None, &blk)
62
74
  _attributes << name
63
75
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  module Lab42
3
3
  module CheckedClass
4
- VERSION = '0.1.1'
4
+ VERSION = '0.2.0'
5
5
  end
6
6
  end
7
7
  # SPDX-License-Identifier: AGPL-3.0-or-later
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lab42_checked_class
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Dober
@@ -20,8 +20,10 @@ files:
20
20
  - LICENSE
21
21
  - README.md
22
22
  - lib/lab42/checked_class.rb
23
+ - lib/lab42/checked_class/all.rb
23
24
  - lib/lab42/checked_class/argument_checker.rb
24
25
  - lib/lab42/checked_class/constraint.rb
26
+ - lib/lab42/checked_class/constraint/predefined.rb
25
27
  - lib/lab42/checked_class/constraint_checker.rb
26
28
  - lib/lab42/checked_class/constraint_error.rb
27
29
  - lib/lab42/checked_class/injector.rb