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 +4 -4
- data/lib/lab42/data_class/builtin_constraints.rb +14 -0
- data/lib/lab42/data_class/constraint.rb +30 -0
- data/lib/lab42/data_class/constraints/kernel.rb +86 -0
- data/lib/lab42/data_class/proxy/constraints/maker.rb +11 -4
- data/lib/lab42/data_class/proxy.rb +35 -7
- data/lib/lab42/data_class/version.rb +1 -1
- metadata +8 -5
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 746ce73ef4464de258f683f0d8366f15799cb8e3ea34a062cc6f4deb34f0a60d
         | 
| 4 | 
            +
              data.tar.gz: 96c679474b72b872f4885ab2c98f7ddfd5f914268b3a9da5ba59f7ae026e5eed
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 184dc66df2185e0869a5cbce9811c8bedf685123037fadf8d17c30bfd762884b9f0d0756bc0d43787dce2586c8094bb2a798aba9b54087198b59a1a0d95023c0
         | 
| 7 | 
            +
              data.tar.gz: 859c555137b976c4885157c5b39d42393c528adf94abb3dd28b9cbd3e38625d3bccac9b5cf5e317cdf3dddb08494fa989dd11523902f79402ed915822d616a64
         | 
| @@ -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!( | 
| 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!( | 
| 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 : | 
| 106 | 
            -
                         | 
| 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. | 
| 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)
         | 
    
        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. | 
| 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- | 
| 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: []
         |