nrser 0.3.9 → 0.3.10
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/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
|