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.
Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/lib/nrser/char/alpha_numeric_sub.rb +9 -19
  3. data/lib/nrser/char/special.rb +5 -5
  4. data/lib/nrser/core_ext/array.rb +36 -13
  5. data/lib/nrser/core_ext/enumerable.rb +1 -0
  6. data/lib/nrser/core_ext/enumerable/find_map.rb +1 -1
  7. data/lib/nrser/core_ext/hash/bury.rb +3 -0
  8. data/lib/nrser/core_ext/hash/extract_values_at.rb +2 -2
  9. data/lib/nrser/core_ext/method/full_name.rb +1 -1
  10. data/lib/nrser/core_ext/module/method_objects.rb +1 -1
  11. data/lib/nrser/core_ext/module/source_locations.rb +27 -15
  12. data/lib/nrser/core_ext/object/lazy_var.rb +1 -1
  13. data/lib/nrser/core_ext/pathname.rb +67 -12
  14. data/lib/nrser/core_ext/pathname/subpath.rb +86 -0
  15. data/lib/nrser/core_ext/string.rb +28 -1
  16. data/lib/nrser/core_ext/symbol.rb +11 -12
  17. data/lib/nrser/errors/README.md +154 -0
  18. data/lib/nrser/errors/attr_error.rb +146 -53
  19. data/lib/nrser/errors/count_error.rb +61 -12
  20. data/lib/nrser/errors/nicer_error.rb +42 -71
  21. data/lib/nrser/errors/value_error.rb +53 -58
  22. data/lib/nrser/functions.rb +0 -2
  23. data/lib/nrser/functions/enumerable.rb +5 -17
  24. data/lib/nrser/functions/enumerable/associate.rb +14 -5
  25. data/lib/nrser/functions/enumerable/find_all_map.rb +1 -1
  26. data/lib/nrser/functions/enumerable/include_slice/array_include_slice.rb +1 -1
  27. data/lib/nrser/functions/hash/bury.rb +2 -12
  28. data/lib/nrser/functions/merge_by.rb +2 -2
  29. data/lib/nrser/functions/module/method_objects.rb +2 -2
  30. data/lib/nrser/functions/path.rb +185 -165
  31. data/lib/nrser/functions/path/normalized.rb +84 -0
  32. data/lib/nrser/functions/string.rb +4 -4
  33. data/lib/nrser/functions/text/README.md +4 -0
  34. data/lib/nrser/functions/text/format.rb +53 -0
  35. data/lib/nrser/functions/text/indentation.rb +6 -6
  36. data/lib/nrser/functions/text/word_wrap.rb +2 -2
  37. data/lib/nrser/functions/tree/map_leaves.rb +3 -3
  38. data/lib/nrser/functions/tree/map_tree.rb +2 -2
  39. data/lib/nrser/functions/tree/transform.rb +1 -18
  40. data/lib/nrser/gem_ext/README.md +4 -0
  41. data/lib/nrser/labs/README.md +8 -0
  42. data/lib/nrser/labs/config.rb +163 -0
  43. data/lib/nrser/labs/i8.rb +49 -159
  44. data/lib/nrser/labs/i8/struct.rb +167 -0
  45. data/lib/nrser/labs/i8/struct/hash.rb +140 -0
  46. data/lib/nrser/labs/i8/struct/vector.rb +149 -0
  47. data/lib/nrser/labs/i8/surjection.rb +211 -0
  48. data/lib/nrser/labs/lots/consumer.rb +19 -0
  49. data/lib/nrser/labs/lots/parser.rb +21 -1
  50. data/lib/nrser/labs/stash.rb +4 -4
  51. data/lib/nrser/log.rb +25 -21
  52. data/lib/nrser/log/appender/sync.rb +15 -11
  53. data/lib/nrser/log/formatters/color.rb +0 -3
  54. data/lib/nrser/log/formatters/mixin.rb +4 -4
  55. data/lib/nrser/log/logger.rb +54 -6
  56. data/lib/nrser/log/mixin.rb +2 -1
  57. data/lib/nrser/log/plugin.rb +6 -6
  58. data/lib/nrser/log/types.rb +46 -29
  59. data/lib/nrser/mean_streak.rb +0 -8
  60. data/lib/nrser/mean_streak/document.rb +1 -4
  61. data/lib/nrser/message.rb +3 -3
  62. data/lib/nrser/meta/README.md +4 -0
  63. data/lib/nrser/meta/lazy_attr.rb +2 -2
  64. data/lib/nrser/meta/source/location.rb +1 -1
  65. data/lib/nrser/props.rb +34 -3
  66. data/lib/nrser/props/class_methods.rb +2 -1
  67. data/lib/nrser/props/instance_methods.rb +9 -9
  68. data/lib/nrser/props/metadata.rb +4 -12
  69. data/lib/nrser/props/mutable/stash.rb +5 -2
  70. data/lib/nrser/props/prop.rb +10 -19
  71. data/lib/nrser/rspex.rb +1 -20
  72. data/lib/nrser/rspex/example_group/describe_attribute.rb +3 -0
  73. data/lib/nrser/rspex/example_group/describe_called_with.rb +9 -4
  74. data/lib/nrser/rspex/example_group/describe_case.rb +1 -0
  75. data/lib/nrser/rspex/example_group/describe_class.rb +2 -0
  76. data/lib/nrser/rspex/example_group/describe_group.rb +1 -1
  77. data/lib/nrser/rspex/example_group/describe_instance.rb +3 -1
  78. data/lib/nrser/rspex/example_group/describe_message.rb +1 -1
  79. data/lib/nrser/rspex/example_group/describe_method.rb +64 -30
  80. data/lib/nrser/rspex/example_group/describe_response_to.rb +1 -1
  81. data/lib/nrser/rspex/example_group/describe_section.rb +4 -1
  82. data/lib/nrser/rspex/example_group/describe_sent_to.rb +1 -1
  83. data/lib/nrser/rspex/example_group/describe_setup.rb +1 -0
  84. data/lib/nrser/rspex/example_group/describe_source_file.rb +1 -1
  85. data/lib/nrser/rspex/example_group/describe_spec_file.rb +4 -2
  86. data/lib/nrser/rspex/example_group/describe_when.rb +2 -1
  87. data/lib/nrser/rspex/example_group/describe_x.rb +5 -5
  88. data/lib/nrser/rspex/format.rb +0 -15
  89. data/lib/nrser/sugar/method_missing_forwarder.rb +3 -3
  90. data/lib/nrser/sys/env/path.rb +2 -28
  91. data/lib/nrser/types.rb +63 -12
  92. data/lib/nrser/types/README.md +76 -0
  93. data/lib/nrser/types/arrays.rb +192 -137
  94. data/lib/nrser/types/attributes.rb +269 -0
  95. data/lib/nrser/types/booleans.rb +134 -83
  96. data/lib/nrser/types/bounded.rb +110 -47
  97. data/lib/nrser/types/collections.rb +119 -0
  98. data/lib/nrser/types/combinators.rb +283 -196
  99. data/lib/nrser/types/doc/display_table.md +66 -0
  100. data/lib/nrser/types/eqiuvalent.rb +91 -0
  101. data/lib/nrser/types/errors/check_error.rb +5 -11
  102. data/lib/nrser/types/errors/from_string_error.rb +3 -3
  103. data/lib/nrser/types/factory.rb +287 -20
  104. data/lib/nrser/types/hashes.rb +227 -179
  105. data/lib/nrser/types/in.rb +73 -36
  106. data/lib/nrser/types/is.rb +67 -60
  107. data/lib/nrser/types/is_a.rb +141 -84
  108. data/lib/nrser/types/labels.rb +45 -16
  109. data/lib/nrser/types/maybe.rb +6 -3
  110. data/lib/nrser/types/nil.rb +64 -27
  111. data/lib/nrser/types/not.rb +92 -34
  112. data/lib/nrser/types/numbers.rb +224 -169
  113. data/lib/nrser/types/pairs.rb +113 -89
  114. data/lib/nrser/types/paths.rb +250 -137
  115. data/lib/nrser/types/responds.rb +167 -89
  116. data/lib/nrser/types/selector.rb +234 -0
  117. data/lib/nrser/types/shape.rb +136 -65
  118. data/lib/nrser/types/strings.rb +189 -63
  119. data/lib/nrser/types/symbols.rb +83 -33
  120. data/lib/nrser/types/top.rb +89 -0
  121. data/lib/nrser/types/tuples.rb +134 -98
  122. data/lib/nrser/types/type.rb +617 -505
  123. data/lib/nrser/types/when.rb +123 -98
  124. data/lib/nrser/types/where.rb +182 -91
  125. data/lib/nrser/version.rb +1 -1
  126. data/spec/lib/nrser/core_ext/pathname/subpath_spec.rb +22 -0
  127. data/spec/lib/nrser/errors/attr_error_spec.rb +68 -0
  128. data/spec/lib/nrser/errors/count_error_spec.rb +69 -0
  129. data/spec/lib/nrser/functions/path/normalize_path_spec.rb +35 -0
  130. data/spec/lib/nrser/functions/tree/map_tree_spec.rb +74 -96
  131. data/spec/lib/nrser/functions/tree/transform_spec.rb +11 -11
  132. data/spec/lib/nrser/labs/config_spec.rb +22 -0
  133. data/spec/lib/nrser/labs/i8/struct_spec.rb +39 -0
  134. data/spec/lib/nrser/types/display_spec.rb +50 -0
  135. data/spec/lib/nrser/types/paths_spec.rb +16 -10
  136. data/spec/lib/nrser/types/selector_spec.rb +125 -0
  137. data/spec/spec_helper.rb +4 -5
  138. metadata +105 -22
  139. data/lib/nrser/types/any.rb +0 -41
  140. data/lib/nrser/types/attrs.rb +0 -213
  141. 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] *prefixes
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
- # See {NRSER.retriever}.
4
- def to_retriever
5
- NRSER.retriever self
6
- end
7
-
8
-
9
- # Alias 'sender' methods to built-in {#to_proc} so symbols can behave like
10
- # arrays in this way
11
- alias_method :to_sender, :to_proc
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 NRSER::AttrError < NRSER::ValueError
8
-
9
- # Name of attribute that has invalid value.
20
+ class AttrError < ValueError
21
+
22
+ # @!method name?
23
+ # Is there an `:name` key in {#context}?
24
+ #
25
+ # @return [Boolean]
10
26
  #
11
- # @return [Symbol]
12
- #
13
- attr_reader :symbol
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
- # If not provided at construction, will be retrieved by sending {#symbol}
19
- # to {#subject} in {#initialize}.
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
- # @return [Object]
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
- attr_reader :actual
24
-
25
-
26
- # An optional expected value to use in {#build_message}.
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
- attr_reader :expected
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 initialize message = nil, symbol:, subject:, **options
37
- @symbol = symbol.to_sym
38
-
39
- @actual = if options.key?( :actual )
40
- options[:actual]
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
- @has_expected = options.key? :expected
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
- def build_message
56
- headline = if has_expected?
57
- "#{ subject.class } object has invalid ##{ symbol }: " +
58
- "expected #{ expected }, found #{ actual }"
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
- "#{ subject.class } object has invalid ##{ symbol } (found #{ actual })"
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 NRSER::CountError
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
- def initialize message = nil, subject:, expected:, count: nil
9
- super message,
10
- subject: subject,
11
- symbol: :count,
12
- actual: (count || subject.count),
13
- expected: expected
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
- def count
17
- actual
18
- end
19
- end # class NRSER::CountError
59
+ # Alias for {#actual}.
60
+ def count; actual; end
61
+
62
+ end # class CountError
63
+
64
+
65
+ # /Namespace
66
+ # ========================================================================
67
+
68
+ end # module NRSER