nrser 0.3.9 → 0.3.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/nrser/char/alpha_numeric_sub.rb +9 -19
- data/lib/nrser/char/special.rb +5 -5
- data/lib/nrser/core_ext/array.rb +36 -13
- data/lib/nrser/core_ext/enumerable.rb +1 -0
- data/lib/nrser/core_ext/enumerable/find_map.rb +1 -1
- data/lib/nrser/core_ext/hash/bury.rb +3 -0
- data/lib/nrser/core_ext/hash/extract_values_at.rb +2 -2
- data/lib/nrser/core_ext/method/full_name.rb +1 -1
- data/lib/nrser/core_ext/module/method_objects.rb +1 -1
- data/lib/nrser/core_ext/module/source_locations.rb +27 -15
- data/lib/nrser/core_ext/object/lazy_var.rb +1 -1
- data/lib/nrser/core_ext/pathname.rb +67 -12
- data/lib/nrser/core_ext/pathname/subpath.rb +86 -0
- data/lib/nrser/core_ext/string.rb +28 -1
- data/lib/nrser/core_ext/symbol.rb +11 -12
- data/lib/nrser/errors/README.md +154 -0
- data/lib/nrser/errors/attr_error.rb +146 -53
- data/lib/nrser/errors/count_error.rb +61 -12
- data/lib/nrser/errors/nicer_error.rb +42 -71
- data/lib/nrser/errors/value_error.rb +53 -58
- data/lib/nrser/functions.rb +0 -2
- data/lib/nrser/functions/enumerable.rb +5 -17
- data/lib/nrser/functions/enumerable/associate.rb +14 -5
- data/lib/nrser/functions/enumerable/find_all_map.rb +1 -1
- data/lib/nrser/functions/enumerable/include_slice/array_include_slice.rb +1 -1
- data/lib/nrser/functions/hash/bury.rb +2 -12
- data/lib/nrser/functions/merge_by.rb +2 -2
- data/lib/nrser/functions/module/method_objects.rb +2 -2
- data/lib/nrser/functions/path.rb +185 -165
- data/lib/nrser/functions/path/normalized.rb +84 -0
- data/lib/nrser/functions/string.rb +4 -4
- data/lib/nrser/functions/text/README.md +4 -0
- data/lib/nrser/functions/text/format.rb +53 -0
- data/lib/nrser/functions/text/indentation.rb +6 -6
- data/lib/nrser/functions/text/word_wrap.rb +2 -2
- data/lib/nrser/functions/tree/map_leaves.rb +3 -3
- data/lib/nrser/functions/tree/map_tree.rb +2 -2
- data/lib/nrser/functions/tree/transform.rb +1 -18
- data/lib/nrser/gem_ext/README.md +4 -0
- data/lib/nrser/labs/README.md +8 -0
- data/lib/nrser/labs/config.rb +163 -0
- data/lib/nrser/labs/i8.rb +49 -159
- data/lib/nrser/labs/i8/struct.rb +167 -0
- data/lib/nrser/labs/i8/struct/hash.rb +140 -0
- data/lib/nrser/labs/i8/struct/vector.rb +149 -0
- data/lib/nrser/labs/i8/surjection.rb +211 -0
- data/lib/nrser/labs/lots/consumer.rb +19 -0
- data/lib/nrser/labs/lots/parser.rb +21 -1
- data/lib/nrser/labs/stash.rb +4 -4
- data/lib/nrser/log.rb +25 -21
- data/lib/nrser/log/appender/sync.rb +15 -11
- data/lib/nrser/log/formatters/color.rb +0 -3
- data/lib/nrser/log/formatters/mixin.rb +4 -4
- data/lib/nrser/log/logger.rb +54 -6
- data/lib/nrser/log/mixin.rb +2 -1
- data/lib/nrser/log/plugin.rb +6 -6
- data/lib/nrser/log/types.rb +46 -29
- data/lib/nrser/mean_streak.rb +0 -8
- data/lib/nrser/mean_streak/document.rb +1 -4
- data/lib/nrser/message.rb +3 -3
- data/lib/nrser/meta/README.md +4 -0
- data/lib/nrser/meta/lazy_attr.rb +2 -2
- data/lib/nrser/meta/source/location.rb +1 -1
- data/lib/nrser/props.rb +34 -3
- data/lib/nrser/props/class_methods.rb +2 -1
- data/lib/nrser/props/instance_methods.rb +9 -9
- data/lib/nrser/props/metadata.rb +4 -12
- data/lib/nrser/props/mutable/stash.rb +5 -2
- data/lib/nrser/props/prop.rb +10 -19
- data/lib/nrser/rspex.rb +1 -20
- data/lib/nrser/rspex/example_group/describe_attribute.rb +3 -0
- data/lib/nrser/rspex/example_group/describe_called_with.rb +9 -4
- data/lib/nrser/rspex/example_group/describe_case.rb +1 -0
- data/lib/nrser/rspex/example_group/describe_class.rb +2 -0
- data/lib/nrser/rspex/example_group/describe_group.rb +1 -1
- data/lib/nrser/rspex/example_group/describe_instance.rb +3 -1
- data/lib/nrser/rspex/example_group/describe_message.rb +1 -1
- data/lib/nrser/rspex/example_group/describe_method.rb +64 -30
- data/lib/nrser/rspex/example_group/describe_response_to.rb +1 -1
- data/lib/nrser/rspex/example_group/describe_section.rb +4 -1
- data/lib/nrser/rspex/example_group/describe_sent_to.rb +1 -1
- data/lib/nrser/rspex/example_group/describe_setup.rb +1 -0
- data/lib/nrser/rspex/example_group/describe_source_file.rb +1 -1
- data/lib/nrser/rspex/example_group/describe_spec_file.rb +4 -2
- data/lib/nrser/rspex/example_group/describe_when.rb +2 -1
- data/lib/nrser/rspex/example_group/describe_x.rb +5 -5
- data/lib/nrser/rspex/format.rb +0 -15
- data/lib/nrser/sugar/method_missing_forwarder.rb +3 -3
- data/lib/nrser/sys/env/path.rb +2 -28
- data/lib/nrser/types.rb +63 -12
- data/lib/nrser/types/README.md +76 -0
- data/lib/nrser/types/arrays.rb +192 -137
- data/lib/nrser/types/attributes.rb +269 -0
- data/lib/nrser/types/booleans.rb +134 -83
- data/lib/nrser/types/bounded.rb +110 -47
- data/lib/nrser/types/collections.rb +119 -0
- data/lib/nrser/types/combinators.rb +283 -196
- data/lib/nrser/types/doc/display_table.md +66 -0
- data/lib/nrser/types/eqiuvalent.rb +91 -0
- data/lib/nrser/types/errors/check_error.rb +5 -11
- data/lib/nrser/types/errors/from_string_error.rb +3 -3
- data/lib/nrser/types/factory.rb +287 -20
- data/lib/nrser/types/hashes.rb +227 -179
- data/lib/nrser/types/in.rb +73 -36
- data/lib/nrser/types/is.rb +67 -60
- data/lib/nrser/types/is_a.rb +141 -84
- data/lib/nrser/types/labels.rb +45 -16
- data/lib/nrser/types/maybe.rb +6 -3
- data/lib/nrser/types/nil.rb +64 -27
- data/lib/nrser/types/not.rb +92 -34
- data/lib/nrser/types/numbers.rb +224 -169
- data/lib/nrser/types/pairs.rb +113 -89
- data/lib/nrser/types/paths.rb +250 -137
- data/lib/nrser/types/responds.rb +167 -89
- data/lib/nrser/types/selector.rb +234 -0
- data/lib/nrser/types/shape.rb +136 -65
- data/lib/nrser/types/strings.rb +189 -63
- data/lib/nrser/types/symbols.rb +83 -33
- data/lib/nrser/types/top.rb +89 -0
- data/lib/nrser/types/tuples.rb +134 -98
- data/lib/nrser/types/type.rb +617 -505
- data/lib/nrser/types/when.rb +123 -98
- data/lib/nrser/types/where.rb +182 -91
- data/lib/nrser/version.rb +1 -1
- data/spec/lib/nrser/core_ext/pathname/subpath_spec.rb +22 -0
- data/spec/lib/nrser/errors/attr_error_spec.rb +68 -0
- data/spec/lib/nrser/errors/count_error_spec.rb +69 -0
- data/spec/lib/nrser/functions/path/normalize_path_spec.rb +35 -0
- data/spec/lib/nrser/functions/tree/map_tree_spec.rb +74 -96
- data/spec/lib/nrser/functions/tree/transform_spec.rb +11 -11
- data/spec/lib/nrser/labs/config_spec.rb +22 -0
- data/spec/lib/nrser/labs/i8/struct_spec.rb +39 -0
- data/spec/lib/nrser/types/display_spec.rb +50 -0
- data/spec/lib/nrser/types/paths_spec.rb +16 -10
- data/spec/lib/nrser/types/selector_spec.rb +125 -0
- data/spec/spec_helper.rb +4 -5
- metadata +105 -22
- data/lib/nrser/types/any.rb +0 -41
- data/lib/nrser/types/attrs.rb +0 -213
- data/lib/nrser/types/trees.rb +0 -42
@@ -6,6 +6,33 @@ require 'nrser/sys/env'
|
|
6
6
|
# Extension methods for {String}
|
7
7
|
#
|
8
8
|
class String
|
9
|
+
|
10
|
+
# The method I alias as unary `~`, with a full-name so I can find it and
|
11
|
+
# such, I guess.
|
12
|
+
#
|
13
|
+
# It's a string formatter. Right now, it just calls {#squish}, but I would
|
14
|
+
# like to make it a bit smarter soon so it can be used on
|
15
|
+
# paragraph-structured text too.
|
16
|
+
#
|
17
|
+
# It's meant to be used with the `%{}` string quote form, because that allows
|
18
|
+
# multi-line strings, but nothing stopping it from being used elsewhere too.
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
#
|
22
|
+
# ~%{
|
23
|
+
# Hey there, here's some "stuff",
|
24
|
+
# and here's some MORE!
|
25
|
+
# }
|
26
|
+
# # => "Hey there, here's some \"stuff\", and here's some MORE!"
|
27
|
+
#
|
28
|
+
# @return [String]
|
29
|
+
#
|
30
|
+
def squiggle
|
31
|
+
squish
|
32
|
+
end
|
33
|
+
|
34
|
+
alias_method :~@, :squiggle
|
35
|
+
|
9
36
|
|
10
37
|
def unblock
|
11
38
|
NRSER.unblock self
|
@@ -72,7 +99,7 @@ class String
|
|
72
99
|
#
|
73
100
|
# Use {Regexp} ones at your own pleasure and peril.
|
74
101
|
#
|
75
|
-
# @param [String | Regexp]
|
102
|
+
# @param [String | Regexp] prefixes
|
76
103
|
# Strings behave as usual per the standard lib.
|
77
104
|
#
|
78
105
|
# Regexp sources are used to create a new Regexp with `\A` at the start -
|
@@ -1,13 +1,12 @@
|
|
1
1
|
class Symbol
|
2
|
-
|
3
|
-
#
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
#
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end # NRSER
|
2
|
+
|
3
|
+
# Proxy through to built-in {#to_proc} so symbols match the {Array#to_sender}
|
4
|
+
# API. I guess.
|
5
|
+
#
|
6
|
+
# @return [Proc]
|
7
|
+
# Accepts one argument and sends itself to that object, returning the
|
8
|
+
# result.
|
9
|
+
#
|
10
|
+
def to_sender; self.to_proc; end
|
11
|
+
|
12
|
+
end # class Symbol
|
@@ -0,0 +1,154 @@
|
|
1
|
+
About `nrser/errors`
|
2
|
+
==============================================================================
|
3
|
+
|
4
|
+
{NRSER}'s error pseudo-module (everything in this directory is namespaced
|
5
|
+
directly under {NRSER} for brevity) is centered around the {NicerError}
|
6
|
+
mixin, which, well... tries to make working with errors a little nicer.
|
7
|
+
|
8
|
+
It includes:
|
9
|
+
|
10
|
+
1. "Nice" extensions of some builtin error classes:
|
11
|
+
1. {NRSER::AbstractMethodError} < {::NotImplementedError}
|
12
|
+
- For when an abstract method is mistakenly called.
|
13
|
+
2. {NRSER::ArgumentError} < {::ArgumentError}
|
14
|
+
- A nice extensions of a familiar favorite.
|
15
|
+
3. {NRSER::TypeError} < {::TypeError}
|
16
|
+
- A nice why to say they're not my type. Used extensively in
|
17
|
+
{NRSER::Types}, which is kind of like Tinder profiles for Ruby
|
18
|
+
objects.
|
19
|
+
2. New "nice" extensions of {::StandardError}, and extensions of them:
|
20
|
+
1. {NRSER::ValueError} < {::StandardError}>
|
21
|
+
- For when a problem is discovered with a value that is not an
|
22
|
+
argument, and the problem is not it's type.
|
23
|
+
2. {NRSER::AttrError} < {NRSER::ValueError}
|
24
|
+
- Raise me when there's an issue with a attribute of an object.
|
25
|
+
3. {NRSER::CountError} < {NRSER::AttrError}
|
26
|
+
- For when `#count` doesn't add up. I know, this one is weirdly
|
27
|
+
specific, but it solved something from what I remember.
|
28
|
+
|
29
|
+
You can check out the doc-strings to those various classes for details. For the
|
30
|
+
rest of this I'm going to focus on what the {NRSER::NicerError} mixin brings to
|
31
|
+
the table.
|
32
|
+
|
33
|
+
Let's check out some of the nicer features!
|
34
|
+
|
35
|
+
|
36
|
+
1.) API Compatibility with Built-In Errors
|
37
|
+
------------------------------------------------------------------------------
|
38
|
+
|
39
|
+
This one is important. {NRSER::NicerError} strictly enhances the standard Ruby
|
40
|
+
{Exception} API, meaning those classes can still be constructed with the
|
41
|
+
|
42
|
+
MyError.new( message_string )
|
43
|
+
|
44
|
+
form, and produce the error they should show at `MyError#message` and
|
45
|
+
`MyError#to_s`. Everything else is added on and optional, should you chose to
|
46
|
+
use it, though you will of course pay some slight performance penalty using
|
47
|
+
nicer errors in that way over the built-in classes.
|
48
|
+
|
49
|
+
I also want to stick with this policy for mixing classes unless they are very
|
50
|
+
specifically focused, like {NRSER::Types::CheckError}, which requires `value`
|
51
|
+
and `type` keyword arguments, and things like a hypothetical HTTP error that
|
52
|
+
requires the status code, etc., and want to extend the policy to cover the
|
53
|
+
{NRSER::NicerError} general construction form:
|
54
|
+
|
55
|
+
MyError.new *message, details:, **context
|
56
|
+
|
57
|
+
With general errors for general use, I've found it sucks to try and remember
|
58
|
+
various parameter forms and how they get stitched together when you're on a
|
59
|
+
roll or in a hurry, and I know it will impose even more overhead on people that
|
60
|
+
didn't write the library.
|
61
|
+
|
62
|
+
Errors should be easy as possible to use; they're already kind-of a pain as is.
|
63
|
+
|
64
|
+
|
65
|
+
2.) Splat `message`
|
66
|
+
------------------------------------------------------------------------------
|
67
|
+
|
68
|
+
Accept an variable amount of positional arguments as a `message` {Array}
|
69
|
+
instead of just a string, dumping non-string values and joining everything
|
70
|
+
together.
|
71
|
+
|
72
|
+
This lets you deal with printing/dumping all in one place instead of
|
73
|
+
adding `#to_s`, `#inspect`, `#pretty_inspect`, etc. all over the place.
|
74
|
+
|
75
|
+
Write things like:
|
76
|
+
|
77
|
+
MyError.new "The value", value, "sucks, it should be", expected
|
78
|
+
|
79
|
+
This should cut down the amount of typing when raising as well, which is
|
80
|
+
always welcome.
|
81
|
+
|
82
|
+
It also allows for a future where we get smarter about dumping things, offer
|
83
|
+
configuration options, switch on environments. For example, you might want to
|
84
|
+
produce rich messages with detailed dumps that take more time to format and
|
85
|
+
space to store while developing and produce concise messages that are cheap
|
86
|
+
to produce and store in production.
|
87
|
+
|
88
|
+
> Of course, in line with (1), you can always string-format elements of
|
89
|
+
> `message` yourself, and the resulting strings will be joined into the final
|
90
|
+
> message. You can also just pass a single string like Ruby's builtin
|
91
|
+
> exceptions, maintaining the same API.
|
92
|
+
|
93
|
+
|
94
|
+
3.) "Extended" Messages - `details` and `context`
|
95
|
+
------------------------------------------------------------------------------
|
96
|
+
|
97
|
+
The normal message that we talked about in (2) - that we call the *summary
|
98
|
+
message* or *super-message* (since it gets passed up to the built-in
|
99
|
+
{StandardError#initialize}) - is intended to be:
|
100
|
+
|
101
|
+
1. Very concise
|
102
|
+
- A single line well under 80 characters if possible.
|
103
|
+
|
104
|
+
- This just seems like how Ruby exception messages were meant to be, I
|
105
|
+
guess, and in many situations it's all you would want or need
|
106
|
+
(production, just gets rescued anyways, there's no one there to read it,
|
107
|
+
etc.).
|
108
|
+
|
109
|
+
2. Cheap to render and store.
|
110
|
+
- We may be trying to do lot very quickly on a production system.
|
111
|
+
|
112
|
+
However - especially when developing - it can be really nice to add
|
113
|
+
considerably more detail and feedback to errors.
|
114
|
+
|
115
|
+
To support this important use case as well, {NRSER::NicerError} introduces the
|
116
|
+
idea of an *extended message* that does not need to be rendered and
|
117
|
+
output along with the *summary/super-message*.
|
118
|
+
|
119
|
+
Extended messages are rendered on-demand, so systems that are not configured to
|
120
|
+
use it will pay a minimal cost for it's existence.
|
121
|
+
|
122
|
+
> See {NRSER::NicerError#extended_message}.
|
123
|
+
|
124
|
+
The extended message is composed of:
|
125
|
+
|
126
|
+
1. Text *details*, optionally rendered via {Binding#erb} when a
|
127
|
+
binding is provided.
|
128
|
+
|
129
|
+
2. A *context* of name and value pairs to dump.
|
130
|
+
|
131
|
+
Both are provided as optional keyword parameters to
|
132
|
+
{NRSER::NicerError#initialize}.
|
133
|
+
|
134
|
+
Those values may be accessed via {NRSER::NicerError#details} and
|
135
|
+
{NRSER::NicerError#context}, and rendered to strings
|
136
|
+
|
137
|
+
|
138
|
+
3.) Default Message
|
139
|
+
------------------------------------------------------------------------------
|
140
|
+
|
141
|
+
While (1) lets you know you should always be able to use the Ruby and nicer
|
142
|
+
construction forms on all but super-specific errors, {NRSER::NicerError} also
|
143
|
+
gives you the option of brevity with support for *default messages*, which
|
144
|
+
are constructed when no positional `message` arguments are passed to its
|
145
|
+
constructor.
|
146
|
+
|
147
|
+
Default messages presumably use the values of some well-known context values to
|
148
|
+
render the user-facing string, and degrade into some sort of complaint if
|
149
|
+
they're absent (someone could always be a wanker and call `MyError.new`, in
|
150
|
+
which case you're left with little resort but tell them so).
|
151
|
+
|
152
|
+
You can define default message behavior by overriding `#default_message` after
|
153
|
+
mixing-in {NRSER::NicerError}. Please practice caution in this - as well as
|
154
|
+
all error methods: don't cause errors when handling errors.
|
@@ -1,73 +1,166 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# ========================================================================
|
6
|
+
|
7
|
+
require_relative './value_error'
|
8
|
+
|
9
|
+
|
10
|
+
# Namespace
|
11
|
+
# ========================================================================
|
12
|
+
|
13
|
+
module NRSER
|
14
|
+
|
2
15
|
|
3
16
|
# Raised when we expected `#count` to be something it's not.
|
4
17
|
#
|
5
18
|
# Extends {NRSER::ValueError}, and the {#value} must be the instance that
|
6
19
|
#
|
7
|
-
class
|
8
|
-
|
9
|
-
#
|
20
|
+
class AttrError < ValueError
|
21
|
+
|
22
|
+
# @!method name?
|
23
|
+
# Is there an `:name` key in {#context}?
|
24
|
+
#
|
25
|
+
# @return [Boolean]
|
10
26
|
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
# Actual invalid value of the subject's attribute.
|
27
|
+
# @!method name
|
28
|
+
# Name of attribute that has invalid value, which can be provided via
|
29
|
+
# the `:name` key in the {#context}.
|
30
|
+
#
|
31
|
+
# @return [Symbol | String]
|
17
32
|
#
|
18
|
-
|
19
|
-
|
33
|
+
def_context_delegator keys: :name
|
34
|
+
|
35
|
+
|
36
|
+
# @!method expected?
|
37
|
+
# Is there an `:expected` key in {#context}?
|
38
|
+
#
|
39
|
+
# @return [Boolean]
|
40
|
+
#
|
41
|
+
# @!method expected
|
42
|
+
# Optional information about what the attribute value was expected to be,
|
43
|
+
# which can be provided via the `:expected` key in {#context}.
|
44
|
+
#
|
45
|
+
# @return [Object]
|
20
46
|
#
|
21
|
-
|
47
|
+
def_context_delegator keys: :expected
|
48
|
+
|
49
|
+
|
50
|
+
# @!method initialize *message, **kwds
|
51
|
+
# Create a new {AttrError}.
|
52
|
+
#
|
53
|
+
# This method does nothing but call `super`. It's here only for doc's sake.
|
54
|
+
#
|
55
|
+
# @note
|
56
|
+
# If you provide the `:name` and `:value` keyword arguments, but *not*
|
57
|
+
# `:actual` then {#actual} will attempt to retrieve the attribute's value
|
58
|
+
# by
|
22
59
|
#
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
#
|
60
|
+
# value.public_send name
|
61
|
+
#
|
62
|
+
# This really *shouldn't* be problematic - if attempting to access a public
|
63
|
+
# attribute can cause serious side-effects, you may want to re-think your
|
64
|
+
# design. However, I still felt like I should note it here.
|
65
|
+
#
|
66
|
+
# The call is wrapped in a `rescue StandardError`, so you **don't** need
|
67
|
+
# to worry about anything mundane like an error being raised.
|
68
|
+
#
|
69
|
+
# @param [Array] message
|
70
|
+
# See {NicerError#initialize}.
|
71
|
+
#
|
72
|
+
# @param [Hash<Symbol, Object>] kwds
|
73
|
+
# Except as called out below, other keywords are passed up to
|
74
|
+
# {NicerError#initialize}.
|
75
|
+
#
|
76
|
+
# @option kwds [Symbol | String] :name
|
77
|
+
# The name of the attribute in question.
|
78
|
+
#
|
79
|
+
# @option kwds [Object] :value
|
80
|
+
# The value that has the bad attribute.
|
81
|
+
#
|
82
|
+
# @option kwds [Object | NRSER::Types::Type | String] :expected
|
83
|
+
# Encouraged to be one of:
|
84
|
+
#
|
85
|
+
# 1. The {Object} you wanted the attribute to respond with.
|
86
|
+
#
|
87
|
+
# 2. A {NRSER::Types::Type} satisfied by what you would have been satisfied
|
88
|
+
# with.
|
89
|
+
#
|
90
|
+
# 3. A {String} explanation of the condition.
|
91
|
+
#
|
92
|
+
# @option kwds [Object] :actual
|
93
|
+
# The actual attribute value.
|
94
|
+
#
|
95
|
+
|
96
|
+
|
97
|
+
# Tests if an 'actual' value was provided in the {#context}.
|
98
|
+
#
|
99
|
+
# @return [Boolean]
|
100
|
+
#
|
101
|
+
def actual?
|
102
|
+
context.key?( :actual ) || ( value? && name? && value.respond_to?( name ) )
|
103
|
+
rescue StandardError => error
|
104
|
+
false
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
# Get an optional actual value for the attribute, from `context[:actual]`
|
109
|
+
# if it exists or by sending {#name} to {#value} if it works.
|
110
|
+
#
|
111
|
+
# @return [nil]
|
112
|
+
# If {#context} does not have an `:actual` value and {#value} raises
|
113
|
+
# a {StandardError}.
|
27
114
|
#
|
28
115
|
# @return [Object]
|
29
|
-
#
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
# @param [Object] subject:
|
34
|
-
# The object that has the invalid attribute value.
|
116
|
+
# The value of {#context}'s `:actual` key, if any, otherwise {#value}'s
|
117
|
+
# response to {#name}.
|
35
118
|
#
|
36
|
-
def
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
else
|
42
|
-
value.send @symbol
|
119
|
+
def actual
|
120
|
+
if context.key? :actual
|
121
|
+
context[ :actual ]
|
122
|
+
elsif value? && name?
|
123
|
+
value.public_send name
|
43
124
|
end
|
44
|
-
|
45
|
-
|
46
|
-
@expected = options[:expected]
|
47
|
-
|
48
|
-
super message, subject: subject
|
49
|
-
end
|
50
|
-
|
51
|
-
def has_expected?
|
52
|
-
@has_expected
|
125
|
+
rescue StandardError => error
|
126
|
+
nil
|
53
127
|
end
|
128
|
+
|
54
129
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
130
|
+
# Create a default message if none was provided.
|
131
|
+
#
|
132
|
+
# Uses whatever recognized {#context} values are present, falling back
|
133
|
+
# to {NicerError#default_message} if none are.
|
134
|
+
#
|
135
|
+
# @return [String]
|
136
|
+
#
|
137
|
+
def default_message
|
138
|
+
message = []
|
139
|
+
|
140
|
+
if value? && name?
|
141
|
+
message << format_message( value.class, "object", value.inspect,
|
142
|
+
"has invalid ##{ name } attribute" )
|
143
|
+
end
|
144
|
+
|
145
|
+
if expected?
|
146
|
+
message << format_message( "expected", expected )
|
147
|
+
end
|
148
|
+
|
149
|
+
if actual?
|
150
|
+
message << format_message( "found", actual )
|
151
|
+
end
|
152
|
+
|
153
|
+
if message.empty?
|
154
|
+
super
|
59
155
|
else
|
60
|
-
|
156
|
+
message.join ', '
|
61
157
|
end
|
62
|
-
|
63
|
-
binding.erb <<-END
|
64
|
-
<%= headline %>
|
65
|
-
|
66
|
-
Subject:
|
67
|
-
|
68
|
-
<%= subject.pretty_inspect %>
|
69
|
-
|
70
|
-
END
|
71
158
|
end
|
72
159
|
|
73
|
-
end # class
|
160
|
+
end # class AttrError
|
161
|
+
|
162
|
+
|
163
|
+
# /Namespace
|
164
|
+
# ========================================================================
|
165
|
+
|
166
|
+
end # module NRSER
|
@@ -1,19 +1,68 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# ========================================================================
|
6
|
+
|
7
|
+
# Project / Package
|
8
|
+
# ------------------------------------------------------------------------
|
9
|
+
|
10
|
+
require_relative './attr_error'
|
11
|
+
|
12
|
+
|
13
|
+
# Namespace
|
14
|
+
# ========================================================================
|
15
|
+
|
16
|
+
module NRSER
|
17
|
+
|
18
|
+
|
19
|
+
# Definitions
|
20
|
+
# ========================================================================
|
2
21
|
|
3
22
|
# Raised when we expected `#count` to be something it's not.
|
4
23
|
#
|
5
|
-
# Extends {NRSER::ValueError}, and the {#value} must be the instance that
|
6
|
-
#
|
7
24
|
class NRSER::CountError < NRSER::AttrError
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
25
|
+
|
26
|
+
# Create a new {CountError}.
|
27
|
+
#
|
28
|
+
# @param [Array] message
|
29
|
+
# See {NicerError#initialize}.
|
30
|
+
#
|
31
|
+
# @param [Hash<Symbol, Object>] kwds
|
32
|
+
# Except as called out below, other keywords are passed up to
|
33
|
+
# {NicerError#initialize}.
|
34
|
+
#
|
35
|
+
# @option kwds [Object] :value
|
36
|
+
# The value that has the bad `#count`.
|
37
|
+
#
|
38
|
+
# @option kwds [Integer | NRSER::Types::Type | String] :expected
|
39
|
+
# Encouraged to be one of:
|
40
|
+
#
|
41
|
+
# 1. An exact {Integer} that you were looking for.
|
42
|
+
#
|
43
|
+
# 2. A {NRSER::Types::Type} satisfied by what you would have been satisfied
|
44
|
+
# with.
|
45
|
+
#
|
46
|
+
# 3. A {String} explanation of the condition.
|
47
|
+
#
|
48
|
+
# @option kwds [Integer] :actual
|
49
|
+
# The actual count.
|
50
|
+
#
|
51
|
+
def initialize *message, **kwds
|
52
|
+
kwds[:actual] = kwds.delete( :count ) if kwds.key?( :count )
|
53
|
+
super *message, **kwds, name: :count
|
14
54
|
end
|
55
|
+
|
56
|
+
# Alias for {#actual?}.
|
57
|
+
def count?; actual?; end
|
15
58
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end # class
|
59
|
+
# Alias for {#actual}.
|
60
|
+
def count; actual; end
|
61
|
+
|
62
|
+
end # class CountError
|
63
|
+
|
64
|
+
|
65
|
+
# /Namespace
|
66
|
+
# ========================================================================
|
67
|
+
|
68
|
+
end # module NRSER
|