definition 0.6.0 → 0.7.1

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: b4e5ac14f31ff6bdd8bab587f652fa408ac28285c92bedf457ded9383cc8a5a9
4
- data.tar.gz: 8ed978aa993d0b68fd95dbc24e5800ab38b416c39798a33c8f6f039dfce201d7
3
+ metadata.gz: b16eba88381d8ea5594b51e4855b3ca4f0684196bf552f5498a5eb43f67458bd
4
+ data.tar.gz: 238611bb117e46b6701fae5d6236b66ab9754424dd88a6363dd091601ee2b249
5
5
  SHA512:
6
- metadata.gz: 63f912d53159f378ec03ff69d9907978e739f96bb994f89f9131d3ee53f2b07ce0621aa2cae6ddf5b81d475dc63543b24f1da2474476e96c62f22e3f7d5ae3b3
7
- data.tar.gz: 60234129f0693be1e83b1265c3a435bbf3e3cea4990a882a722722f022f31b02736378c53cfc9f17d4ada50163d0bfc33f14c21b92899466110ab9ce53461bac
6
+ metadata.gz: e4a1d3d64e85ba1a43356adf08413a6469d8f0f59acf35f395c43adc44320557e562a90b54c49f51236664ce94201f65b18a8e9c288edb709cf3ab85102dc12c
7
+ data.tar.gz: 3e753b50686933ddb0c83afbcd394ce0a98b5f16fe9cee7799df94f3b968489f6e0828332b01f4c444ccc86ca575f3af27e6b35a34f391306c5328f721ee2906
@@ -0,0 +1,53 @@
1
+ # Use the latest 2.1 version of CircleCI pipeline process engine.
2
+ # See: https://circleci.com/docs/2.0/configuration-reference
3
+ version: 2.1
4
+
5
+ # Orbs are reusable packages of CircleCI configuration that you may share across projects, enabling you to create encapsulated, parameterized commands, jobs, and executors that can be used across multiple projects.
6
+ # See: https://circleci.com/docs/2.0/orb-intro/
7
+ orbs:
8
+ ruby: circleci/ruby@1.4.0
9
+
10
+ # Define a job to be invoked later in a workflow.
11
+ # See: https://circleci.com/docs/2.0/configuration-reference/#jobs
12
+ jobs:
13
+ test:
14
+ parameters:
15
+ ruby_version:
16
+ type: string
17
+ docker:
18
+ - image: cimg/base:stable
19
+ steps:
20
+ - ruby/install:
21
+ version: << parameters.ruby_version >>
22
+ - checkout
23
+ - run: rm Gemfile.lock
24
+ - run: gem install bundler
25
+ - run: bundle install
26
+ - ruby/rspec-test
27
+ linting:
28
+ docker:
29
+ - image: 'cimg/base:stable'
30
+ steps:
31
+ - checkout
32
+ - ruby/install:
33
+ version: "3.0"
34
+ - ruby/install-deps
35
+ - ruby/rubocop-check:
36
+ format: progress
37
+ label: Inspecting with Rubocop
38
+
39
+ # Invoke jobs via workflows
40
+ # See: https://circleci.com/docs/2.0/configuration-reference/#workflows
41
+ workflows:
42
+ test: # This is the name of the workflow, feel free to change it to better match your workflow.
43
+ # Inside the workflow, you define the jobs you want to run.
44
+ jobs:
45
+ - test:
46
+ matrix:
47
+ parameters:
48
+ ruby_version:
49
+ - "2.6"
50
+ - "2.7"
51
+ - "3.0"
52
+ - "jruby-9.3.3.0"
53
+ - linting
data/.gitignore CHANGED
@@ -1,6 +1,5 @@
1
1
  /.bundle/
2
2
  /.yardoc
3
- /Gemfile.lock
4
3
  /_yardoc/
5
4
  /coverage/
6
5
  /doc/
@@ -9,4 +8,5 @@
9
8
  /tmp/
10
9
  /bin/
11
10
  *.swp
11
+ .approvals
12
12
  spec/examples.txt
data/.rubocop.yml CHANGED
@@ -2,7 +2,7 @@ require:
2
2
  - rubocop-rspec
3
3
 
4
4
  AllCops:
5
- TargetRubyVersion: 2.3
5
+ TargetRubyVersion: 2.6
6
6
 
7
7
  Metrics/LineLength:
8
8
  Max: 119
data/Changelog.md CHANGED
@@ -4,7 +4,27 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [0.4.0] - 2020-03-21
7
+ ## Unreleased
8
+
9
+ ## [0.7.1] - 2022-03-04
10
+ ### Fixed
11
+ - Float coercion: check for nil before coercion
12
+
13
+ ## [0.7.0] - 2022-02-25
14
+ ### Added
15
+ - Lambda definitions can now be failed with custom error messages
16
+ - Compatibility with Ruby 3.0
17
+ ### Fixed
18
+ - In some cases errors from nested `Keys` definitions inside `Or` definitions got lost when listing the validation errors via the `error_hash` method on the conform result object.
19
+ ### Changed
20
+ - When no sub-definition of an `Or` conforms, then only the errors of the last definition of the `Or` are collected. Previously the errors of all sub-definitions were collected.
21
+ - Translated error messages have been improved to be more suitable to be used as end user error messages
22
+
23
+ ## [0.6.1] - 2021-12-14
24
+ ### Fixed
25
+ - The `Keys` definition crashed with an error if the input was not a Hash
26
+
27
+ ## [0.6.0] - 2020-03-21
8
28
  ### Added
9
29
  - Added include method to Keys Definition that allows to inline other `Keys` Definitions into each other
10
30
 
data/Gemfile.lock ADDED
@@ -0,0 +1,138 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ definition (0.7.1)
5
+ activesupport
6
+ i18n
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activesupport (7.0.2.2)
12
+ concurrent-ruby (~> 1.0, >= 1.0.2)
13
+ i18n (>= 1.6, < 2)
14
+ minitest (>= 5.1)
15
+ tzinfo (~> 2.0)
16
+ approvals (0.0.25)
17
+ nokogiri (~> 1.8)
18
+ thor (~> 1.0)
19
+ ast (2.4.2)
20
+ awesome_print (1.9.2)
21
+ benchmark-ips (2.10.0)
22
+ coderay (1.1.3)
23
+ concurrent-ruby (1.1.9)
24
+ diff-lcs (1.5.0)
25
+ ffi (1.15.5)
26
+ formatador (1.1.0)
27
+ fuubar (2.5.1)
28
+ rspec-core (~> 3.0)
29
+ ruby-progressbar (~> 1.4)
30
+ guard (2.18.0)
31
+ formatador (>= 0.2.4)
32
+ listen (>= 2.7, < 4.0)
33
+ lumberjack (>= 1.0.12, < 2.0)
34
+ nenv (~> 0.1)
35
+ notiffany (~> 0.0)
36
+ pry (>= 0.13.0)
37
+ shellany (~> 0.0)
38
+ thor (>= 0.18.1)
39
+ guard-compat (1.2.1)
40
+ guard-rspec (4.7.3)
41
+ guard (~> 2.1)
42
+ guard-compat (~> 1.1)
43
+ rspec (>= 2.99.0, < 4.0)
44
+ i18n (1.10.0)
45
+ concurrent-ruby (~> 1.0)
46
+ jaro_winkler (1.5.4)
47
+ listen (3.7.1)
48
+ rb-fsevent (~> 0.10, >= 0.10.3)
49
+ rb-inotify (~> 0.9, >= 0.9.10)
50
+ lumberjack (1.2.8)
51
+ method_source (1.0.0)
52
+ mini_portile2 (2.8.0)
53
+ minitest (5.15.0)
54
+ nenv (0.3.0)
55
+ nokogiri (1.13.3)
56
+ mini_portile2 (~> 2.8.0)
57
+ racc (~> 1.4)
58
+ nokogiri (1.13.3-x86_64-linux)
59
+ racc (~> 1.4)
60
+ notiffany (0.1.3)
61
+ nenv (~> 0.1)
62
+ shellany (~> 0.0)
63
+ parallel (1.21.0)
64
+ parser (3.1.0.0)
65
+ ast (~> 2.4.1)
66
+ pry (0.14.1)
67
+ coderay (~> 1.1)
68
+ method_source (~> 1.0)
69
+ psych (4.0.3)
70
+ stringio
71
+ racc (1.6.0)
72
+ rainbow (3.1.1)
73
+ rake (13.0.6)
74
+ rb-fsevent (0.11.1)
75
+ rb-inotify (0.10.1)
76
+ ffi (~> 1.0)
77
+ rspec (3.11.0)
78
+ rspec-core (~> 3.11.0)
79
+ rspec-expectations (~> 3.11.0)
80
+ rspec-mocks (~> 3.11.0)
81
+ rspec-core (3.11.0)
82
+ rspec-support (~> 3.11.0)
83
+ rspec-expectations (3.11.0)
84
+ diff-lcs (>= 1.2.0, < 2.0)
85
+ rspec-support (~> 3.11.0)
86
+ rspec-its (1.3.0)
87
+ rspec-core (>= 3.0.0)
88
+ rspec-expectations (>= 3.0.0)
89
+ rspec-mocks (3.11.0)
90
+ diff-lcs (>= 1.2.0, < 2.0)
91
+ rspec-support (~> 3.11.0)
92
+ rspec-support (3.11.0)
93
+ rspec_junit_formatter (0.5.1)
94
+ rspec-core (>= 2, < 4, != 2.12.0)
95
+ rubocop (0.66.0)
96
+ jaro_winkler (~> 1.5.1)
97
+ parallel (~> 1.10)
98
+ parser (>= 2.5, != 2.5.1.1)
99
+ psych (>= 3.1.0)
100
+ rainbow (>= 2.2.2, < 4.0)
101
+ ruby-progressbar (~> 1.7)
102
+ unicode-display_width (>= 1.4.0, < 1.6)
103
+ rubocop-rspec (1.32.0)
104
+ rubocop (>= 0.60.0)
105
+ rubocop_runner (2.2.0)
106
+ ruby-progressbar (1.11.0)
107
+ shellany (0.0.1)
108
+ stringio (3.0.1)
109
+ thor (1.2.1)
110
+ timecop (0.9.4)
111
+ tzinfo (2.0.4)
112
+ concurrent-ruby (~> 1.0)
113
+ unicode-display_width (1.5.0)
114
+
115
+ PLATFORMS
116
+ ruby
117
+ x86_64-linux
118
+
119
+ DEPENDENCIES
120
+ approvals (~> 0.0)
121
+ awesome_print
122
+ benchmark-ips
123
+ definition!
124
+ fuubar
125
+ guard
126
+ guard-rspec
127
+ pry
128
+ rake (~> 13.0)
129
+ rspec (~> 3.0)
130
+ rspec-its (~> 1.2)
131
+ rspec_junit_formatter
132
+ rubocop (= 0.66.0)
133
+ rubocop-rspec (= 1.32.0)
134
+ rubocop_runner
135
+ timecop
136
+
137
+ BUNDLED WITH
138
+ 2.3.7
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Definition
2
2
 
3
- [![Build Status](https://travis-ci.org/Goltergaul/definition.svg?branch=master)][travis]
3
+ [![Build Status](https://circleci.com/gh/Goltergaul/definition.svg?style=svg)][circleci]
4
4
  [![Gem Version](https://badge.fury.io/rb/definition.svg)][rubygems]
5
5
 
6
6
  Simple and composable validation and coercion of data structures. It also includes a ValueObject for convenience.
@@ -255,6 +255,24 @@ either be the original value or any transformed version of it. By not calling
255
255
  The first argument of `Definition.Lambda` is a name you can give this definition.
256
256
  It will only be used in the error message to make it more readable.
257
257
 
258
+ If you want to provide detailed custom error messages you can use `fail_with`:
259
+
260
+ ```ruby
261
+ Definition.Lambda(:password) do |value|
262
+ if !value.match(/[a-z]+/)
263
+ fail_with("must contain at least one lower case letter")
264
+ elsif !value.match(/[A-Z]+/)
265
+ fail_with("must contain at least one upper case letter")
266
+ elsif !value.match(/\d+/)
267
+ fail_with("must contain at least one digit")
268
+ elsif value.size < 6 || value.size > 50
269
+ fail_with("must be between 6 and 50 characters long")
270
+ else
271
+ conform_with(value)
272
+ end
273
+ end
274
+ ```
275
+
258
276
  ### Composing Definitions
259
277
 
260
278
  Definitions are reusable and can be easily composed:
@@ -423,5 +441,5 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
423
441
 
424
442
  Bug reports and pull requests are welcome on GitHub at https://github.com/Goltergaul/definition.
425
443
 
426
- [travis]: https://travis-ci.org/Goltergaul/definition
444
+ [circleci]: https://circleci.com/gh/Goltergaul/definition
427
445
  [rubygems]: https://rubygems.org/gems/definition
@@ -1,22 +1,22 @@
1
1
  en:
2
2
  definition:
3
- max_size: "Value is bigger then %{max_size}"
4
- min_size: "Value is smaller then %{min_size}"
5
- greater_then: "Value must be greater then %{min_value}"
6
- greater_then_equal: "Value must be greater or eqaul to %{min_value}"
7
- less_then: "Value must be less then %{max_value}"
8
- less_then_equal: "Value must be less or eqaul to %{max_value}"
3
+ max_size: "Value is bigger than %{max_size}"
4
+ min_size: "Value is smaller than %{min_size}"
5
+ greater_then: "Value must be greater than %{min_value}"
6
+ greater_then_equal: "Value must be greater or equal to %{min_value}"
7
+ less_then: "Value must be less than %{max_value}"
8
+ less_then_equal: "Value must be less or equal to %{max_value}"
9
9
  equal: "Value must be equal to '%{expected_value}'"
10
10
  empty: "Value must be empty"
11
11
  non_empty: "Value must not be empty"
12
12
  nil: "Value must be nil"
13
+ each: "Is not an Array"
14
+ include: "Does not include %{value}"
13
15
  type: "Value is of wrong type, needs to be a %{class}"
14
16
  enum: "Value is not one of: %{allowed_values}"
15
- each: "Not all values are valid"
16
- and: "Not all definitions conform"
17
- or: "None of the definitions conform"
18
17
  non_empty_string: "Value must be a non empty string"
19
- regex: "Value dos not match regex %{regex}"
18
+ regex: "Value does not match regex %{regex}"
20
19
  keys:
21
- has_extra_key: "Hash has unexpected key %{key}"
22
- has_missing_key: "Hash is missing key %{key}"
20
+ has_extra_key: "Is unexpected"
21
+ has_missing_key: "Is missing"
22
+ not_a_hash: "Is not a Hash"
data/definition.gemspec CHANGED
@@ -31,9 +31,10 @@ Gem::Specification.new do |spec|
31
31
  spec.add_development_dependency "guard"
32
32
  spec.add_development_dependency "guard-rspec"
33
33
  spec.add_development_dependency "pry"
34
- spec.add_development_dependency "rake", "~> 10.0"
34
+ spec.add_development_dependency "rake", "~> 13.0"
35
35
  spec.add_development_dependency "rspec", "~> 3.0"
36
36
  spec.add_development_dependency "rspec-its", "~> 1.2"
37
+ spec.add_development_dependency "rspec_junit_formatter"
37
38
  spec.add_development_dependency "rubocop", "0.66.0"
38
39
  spec.add_development_dependency "rubocop-rspec", "1.32.0"
39
40
  spec.add_development_dependency "rubocop_runner"
@@ -4,16 +4,18 @@ require "i18n"
4
4
 
5
5
  module Definition
6
6
  class ConformError
7
- def initialize(definition, message, sub_errors: [], i18n_key: definition.name)
7
+ def initialize(definition, message, sub_errors: [], **options)
8
8
  self.definition = definition
9
9
  self.message = message
10
10
  self.sub_errors = sub_errors
11
- self.i18n_key = i18n_key
11
+ self.i18n_key = options.fetch(:i18n_key, definition.name)
12
+ self.i18n_context = options.fetch(:i18n_context, {})
13
+ self.translated_error = options.fetch(:translated_message, nil)
12
14
  assign_parents
13
15
  end
14
16
 
15
- attr_accessor :definition, :sub_errors, :parent, :i18n_key
16
- attr_writer :message
17
+ attr_accessor :definition, :sub_errors, :parent, :i18n_key, :i18n_context
18
+ attr_writer :message, :translated_error
17
19
 
18
20
  def message
19
21
  if sub_errors.empty?
@@ -50,10 +52,8 @@ module Definition
50
52
  sub_errors.map(&:leaf_errors).flatten
51
53
  end
52
54
 
53
- def translated_error(namespace = "definition", vars: {})
54
- namespace ||= "definition"
55
- vars[:key] = key if respond_to?(:key)
56
- ::I18n.t("#{namespace}.#{i18n_key}", definition.context.merge!(vars))
55
+ def translated_error(namespace = "definition")
56
+ @translated_error ||= definition.error_renderer.new(self, i18n_namespace: namespace).translated_error
57
57
  end
58
58
 
59
59
  private
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/hash"
3
+ require "active_support"
4
4
 
5
5
  module Definition
6
6
  class ConformResult
@@ -41,11 +41,9 @@ module Definition
41
41
  "a primitive that has a coercion function defined")
42
42
  end
43
43
  Types::Type.new(:type, klass) do |value|
44
- begin
45
- method(klass.name).call(value)
46
- rescue ArgumentError
47
- value
48
- end
44
+ method(klass.name).call(value)
45
+ rescue ArgumentError
46
+ value
49
47
  end
50
48
  end
51
49
 
@@ -4,9 +4,9 @@ require "definition/conform_error"
4
4
 
5
5
  module Definition
6
6
  class KeyConformError < ConformError
7
- def initialize(definition, message, key:, sub_errors: [], i18n_key: definition.name)
7
+ def initialize(definition, message, key:, sub_errors: [], **options)
8
8
  self.key = key
9
- super(definition, message, sub_errors: sub_errors, i18n_key: i18n_key)
9
+ super(definition, message, sub_errors: sub_errors, **options)
10
10
  end
11
11
 
12
12
  attr_accessor :key
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "definition/types/base"
4
+ require "definition/types/error_renderers/leaf"
4
5
 
5
6
  module Definition
6
7
  module Types
@@ -23,6 +24,10 @@ module Definition
23
24
  Conformer.new(self).conform(value)
24
25
  end
25
26
 
27
+ def error_renderer
28
+ ErrorRenderers::Leaf
29
+ end
30
+
26
31
  class Conformer
27
32
  def initialize(definition)
28
33
  self.definition = definition
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "definition/conform_result"
4
4
  require "definition/conform_error"
5
+ require "definition/types/error_renderers/standard"
5
6
 
6
7
  module Definition
7
8
  module Types
@@ -23,6 +24,10 @@ module Definition
23
24
  def conform(_value)
24
25
  raise NotImplementedError
25
26
  end
27
+
28
+ def error_renderer
29
+ ErrorRenderers::Standard
30
+ end
26
31
  end
27
32
  end
28
33
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "definition/types/base"
4
+ require "definition/types/error_renderers/leaf"
4
5
 
5
6
  module Definition
6
7
  module Types
@@ -16,6 +17,10 @@ module Definition
16
17
  Conformer.new(self).conform(value)
17
18
  end
18
19
 
20
+ def error_renderer
21
+ ErrorRenderers::Leaf
22
+ end
23
+
19
24
  class Conformer
20
25
  def initialize(definition)
21
26
  self.definition = definition
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "definition/types/error_renderers/standard"
4
+
5
+ module Definition
6
+ module Types
7
+ module ErrorRenderers
8
+ class Lambda < Standard
9
+ def default
10
+ "Did not pass test for '#{conform_error.definition.name}'"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "definition/types/error_renderers/standard"
4
+
5
+ module Definition
6
+ module Types
7
+ module ErrorRenderers
8
+ class Leaf < Standard
9
+ def translated_error(_namespace = "definition")
10
+ # When there are no sub errors, proceeding gets us into an infinite loop.
11
+ return i18n_error if conform_error.sub_errors.empty?
12
+
13
+ conform_error.leaf_errors.map(&:translated_error).join(", ")
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Definition
4
+ module Types
5
+ module ErrorRenderers
6
+ class Standard
7
+ def initialize(conform_error, i18n_namespace:)
8
+ self.conform_error = conform_error
9
+ self.i18n_namespace = i18n_namespace
10
+ end
11
+
12
+ def translated_error
13
+ i18n_error
14
+ end
15
+
16
+ private
17
+
18
+ def i18n_error
19
+ ::I18n.t("#{i18n_namespace}.#{conform_error.i18n_key}",
20
+ **i18n_vars)
21
+ end
22
+
23
+ def i18n_vars
24
+ conform_error.definition.context.merge(
25
+ conform_error.i18n_context
26
+ ).tap do |vars|
27
+ vars[:default] = default if default
28
+ end
29
+ end
30
+
31
+ def default
32
+ nil
33
+ end
34
+
35
+ attr_accessor :conform_error, :i18n_namespace
36
+ end
37
+ end
38
+ end
39
+ end
@@ -38,7 +38,8 @@ module Definition
38
38
  definition.required_items.map do |item|
39
39
  next if value.include?(item)
40
40
 
41
- KeyConformError.new(definition, "#{definition.name} does not include #{item.inspect}", key: item)
41
+ KeyConformError.new(definition, "#{definition.name} does not include #{item.inspect}",
42
+ key: item, i18n_context: { value: item.inspect })
42
43
  end.compact
43
44
  end
44
45
 
@@ -84,9 +84,15 @@ module Definition
84
84
  end
85
85
 
86
86
  def conform
87
- add_extra_key_errors unless definition.ignore_extra_keys
88
- add_missing_key_errors
89
- values = conform_all_keys
87
+ if valid_input_type?
88
+ add_extra_key_errors unless definition.ignore_extra_keys
89
+ add_missing_key_errors
90
+ values = conform_all_keys
91
+ else
92
+ errors.push(ConformError.new(definition,
93
+ "#{definition.name} is not a Hash",
94
+ i18n_key: "keys.not_a_hash"))
95
+ end
90
96
 
91
97
  ConformResult.new(values, errors: errors)
92
98
  end
@@ -95,6 +101,10 @@ module Definition
95
101
 
96
102
  attr_accessor :errors
97
103
 
104
+ def valid_input_type?
105
+ value.is_a?(Hash)
106
+ end
107
+
98
108
  def add_extra_key_errors
99
109
  extra_keys = value.keys - all_keys
100
110
  return if extra_keys.empty?
@@ -1,34 +1,65 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "definition/types/base"
4
+ require "definition/types/error_renderers/lambda"
4
5
 
5
6
  module Definition
6
7
  module Types
7
8
  class Lambda < Base
8
- module Dsl
9
- def conform_with(value)
10
- ConformResult.new(value)
11
- end
12
- end
13
- include Dsl
9
+ attr_accessor :conformity_test_lambda
14
10
 
15
- def initialize(name, context: {}, &test_lambda)
16
- self.test_lambda = test_lambda
11
+ def initialize(name, context: {}, &conformity_test_lambda)
12
+ self.conformity_test_lambda = conformity_test_lambda
17
13
  super(name, context: context)
18
14
  end
19
15
 
20
16
  def conform(value)
21
- lambda_result = instance_exec(value, &test_lambda)
22
- return lambda_result if lambda_result.is_a?(ConformResult)
17
+ Conformer.new(self).conform(value)
18
+ end
23
19
 
24
- ConformResult.new(value, errors: [
25
- ConformError.new(self, "Did not pass test for #{name}")
26
- ])
20
+ def error_renderer
21
+ ErrorRenderers::Lambda
27
22
  end
28
23
 
29
- private
24
+ class Conformer
25
+ module Dsl
26
+ def conform_with(value)
27
+ ConformResult.new(value)
28
+ end
29
+
30
+ def fail_with(error_message)
31
+ self.error_message = error_message
32
+ end
33
+ end
34
+ include Dsl
35
+
36
+ def initialize(definition)
37
+ self.definition = definition
38
+ end
39
+
40
+ def conform(value)
41
+ lambda_result = instance_exec(value, &definition.conformity_test_lambda)
42
+ return lambda_result if lambda_result.is_a?(ConformResult)
30
43
 
31
- attr_accessor :test, :test_lambda
44
+ failure_result_with(value, error_message)
45
+ end
46
+
47
+ private
48
+
49
+ attr_accessor :definition, :error_message
50
+
51
+ def standard_error_message
52
+ "Did not pass test for #{definition.name}"
53
+ end
54
+
55
+ def failure_result_with(value, error_message)
56
+ ConformResult.new(value, errors: [
57
+ ConformError.new(definition,
58
+ standard_error_message,
59
+ translated_message: error_message)
60
+ ])
61
+ end
62
+ end
32
63
  end
33
64
  end
34
65
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "definition/types/base"
4
+ require "definition/types/error_renderers/leaf"
4
5
 
5
6
  module Definition
6
7
  module Types
@@ -23,6 +24,10 @@ module Definition
23
24
  Conformer.new(self).conform(value)
24
25
  end
25
26
 
27
+ def error_renderer
28
+ ErrorRenderers::Leaf
29
+ end
30
+
26
31
  class Conformer
27
32
  def initialize(definition)
28
33
  self.definition = definition
@@ -34,7 +39,8 @@ module Definition
34
39
  result
35
40
  else
36
41
  error = ConformError.new(definition,
37
- "None of the definitions are valid for '#{definition.name}'",
42
+ "None of the definitions are valid for '#{definition.name}'."\
43
+ " Errors for last tested definition:",
38
44
  sub_errors: result)
39
45
  ConformResult.new(value, errors: [error])
40
46
  end
@@ -48,7 +54,7 @@ module Definition
48
54
  result = definition.conform(value)
49
55
  return result if result.passed?
50
56
 
51
- errors.push(result.error_tree)
57
+ errors = result.error_tree
52
58
  end
53
59
 
54
60
  errors.flatten
@@ -14,7 +14,7 @@ module Definition
14
14
  end
15
15
 
16
16
  def conform(value)
17
- value = coerce.call(value) if coerce && !valid?(value)
17
+ value = coerce.call(value) if value && coerce && !valid?(value)
18
18
 
19
19
  try_conform(value)
20
20
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Definition
4
- VERSION = "0.6.0"
4
+ VERSION = "0.7.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: definition
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dominik Goltermann
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-29 00:00:00.000000000 Z
11
+ date: 2022-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -142,14 +142,14 @@ dependencies:
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: '10.0'
145
+ version: '13.0'
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: '10.0'
152
+ version: '13.0'
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: rspec
155
155
  requirement: !ruby/object:Gem::Requirement
@@ -178,6 +178,20 @@ dependencies:
178
178
  - - "~>"
179
179
  - !ruby/object:Gem::Version
180
180
  version: '1.2'
181
+ - !ruby/object:Gem::Dependency
182
+ name: rspec_junit_formatter
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
181
195
  - !ruby/object:Gem::Dependency
182
196
  name: rubocop
183
197
  requirement: !ruby/object:Gem::Requirement
@@ -234,20 +248,20 @@ dependencies:
234
248
  - - ">="
235
249
  - !ruby/object:Gem::Version
236
250
  version: '0'
237
- description:
251
+ description:
238
252
  email:
239
253
  - dominik@goltermann.cc
240
254
  executables: []
241
255
  extensions: []
242
256
  extra_rdoc_files: []
243
257
  files:
244
- - ".approvals"
258
+ - ".circleci/config.yml"
245
259
  - ".gitignore"
246
260
  - ".rspec"
247
261
  - ".rubocop.yml"
248
- - ".travis.yml"
249
262
  - Changelog.md
250
263
  - Gemfile
264
+ - Gemfile.lock
251
265
  - Guardfile
252
266
  - LICENSE
253
267
  - README.md
@@ -271,6 +285,9 @@ files:
271
285
  - lib/definition/types/and.rb
272
286
  - lib/definition/types/base.rb
273
287
  - lib/definition/types/each.rb
288
+ - lib/definition/types/error_renderers/lambda.rb
289
+ - lib/definition/types/error_renderers/leaf.rb
290
+ - lib/definition/types/error_renderers/standard.rb
274
291
  - lib/definition/types/include.rb
275
292
  - lib/definition/types/keys.rb
276
293
  - lib/definition/types/lambda.rb
@@ -283,7 +300,7 @@ homepage: https://github.com/Goltergaul/definition
283
300
  licenses:
284
301
  - MIT
285
302
  metadata: {}
286
- post_install_message:
303
+ post_install_message:
287
304
  rdoc_options: []
288
305
  require_paths:
289
306
  - lib
@@ -298,9 +315,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
298
315
  - !ruby/object:Gem::Version
299
316
  version: '0'
300
317
  requirements: []
301
- rubyforge_project:
302
- rubygems_version: 2.7.6
303
- signing_key:
318
+ rubygems_version: 3.1.2
319
+ signing_key:
304
320
  specification_version: 4
305
321
  summary: Simple and composable validation and coercion of data structures inspired
306
322
  by clojure specs
data/.approvals DELETED
File without changes
data/.travis.yml DELETED
@@ -1,18 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - jruby-9.1.17.0 # ruby 2.3
4
- - jruby-9.2.11.1 # ruby 2.5.7
5
- - 2.3.0
6
- - 2.7.0
7
- jobs:
8
- include:
9
- - stage: linting
10
- rvm: 2.7.0
11
- script: bundle exec rake rubocop
12
- - stage: benchmark
13
- script: bundle exec ruby benchmark/complex_example.rb
14
- rvm: 2.7.0
15
- - script: bundle exec ruby benchmark/coercion.rb
16
- rvm: 2.7.0
17
- - script: bundle exec ruby benchmark/validation_only.rb
18
- rvm: 2.7.0