nrser 0.2.2 → 0.3.0
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 +1 -2
- data/lib/nrser/char.rb +0 -6
- data/lib/nrser/core_ext/array.rb +120 -0
- data/lib/nrser/core_ext/binding.rb +44 -0
- data/lib/nrser/{functions → core_ext}/enumerable/find_map.rb +18 -15
- data/lib/nrser/{ext → core_ext}/enumerable.rb +10 -24
- data/lib/nrser/core_ext/exception.rb +30 -0
- data/lib/nrser/core_ext/hash/extract_values_at.rb +49 -0
- data/lib/nrser/core_ext/hash/transform_values_with_keys.rb +24 -0
- data/lib/nrser/core_ext/hash.rb +50 -0
- data/lib/nrser/core_ext/module/method_objects.rb +96 -0
- data/lib/nrser/core_ext/module/names.rb +69 -0
- data/lib/nrser/core_ext/module/source_locations.rb +214 -0
- data/lib/nrser/core_ext/module.rb +2 -0
- data/lib/nrser/core_ext/object/lazy_var.rb +31 -0
- data/lib/nrser/core_ext/object.rb +46 -0
- data/lib/nrser/core_ext/open_struct.rb +6 -0
- data/lib/nrser/{ext → core_ext}/pathname.rb +8 -5
- data/lib/nrser/{ext → core_ext}/string.rb +6 -12
- data/lib/nrser/core_ext/symbol.rb +13 -0
- data/lib/nrser/core_ext/time.rb +46 -0
- data/lib/nrser/core_ext.rb +13 -0
- data/lib/nrser/errors/abstract_method_error.rb +150 -0
- data/lib/nrser/errors/argument_error.rb +42 -0
- data/lib/nrser/errors/nicer_error.rb +298 -72
- data/lib/nrser/errors/type_error.rb +46 -0
- data/lib/nrser/errors.rb +4 -53
- data/lib/nrser/ext/tree.rb +3 -0
- data/lib/nrser/functions/enumerable/associate.rb +6 -9
- data/lib/nrser/functions/enumerable/include_slice.rb +2 -3
- data/lib/nrser/functions/enumerable.rb +1 -3
- data/lib/nrser/functions/exception.rb +1 -1
- data/lib/nrser/functions/hash.rb +0 -6
- data/lib/nrser/functions/merge_by.rb +2 -2
- data/lib/nrser/functions/module/method_objects.rb +77 -0
- data/lib/nrser/functions/module.rb +1 -2
- data/lib/nrser/functions/open_struct.rb +25 -35
- data/lib/nrser/functions/proc.rb +1 -6
- data/lib/nrser/functions/string/looks_like.rb +32 -1
- data/lib/nrser/functions/string.rb +1 -40
- data/lib/nrser/functions/text/lines.rb +2 -1
- data/lib/nrser/functions.rb +0 -1
- data/lib/nrser/graph/tsorter.rb +41 -0
- data/lib/nrser/labs/core_ext/binding.rb +37 -0
- data/lib/nrser/labs/stash.rb +372 -0
- data/lib/nrser/{logging → log}/appender/sync.rb +3 -3
- data/lib/nrser/log/appender.rb +3 -0
- data/lib/nrser/{logging → log}/formatters/color.rb +47 -20
- data/lib/nrser/log/formatters/mixin.rb +270 -0
- data/lib/nrser/{logging → log}/formatters.rb +0 -0
- data/lib/nrser/log/logger.rb +229 -0
- data/lib/nrser/log/mixin.rb +56 -0
- data/lib/nrser/log.rb +723 -0
- data/lib/nrser/message.rb +24 -3
- data/lib/nrser/meta/source/location.rb +158 -0
- data/lib/nrser/meta.rb +1 -1
- data/lib/nrser/props/class_methods.rb +118 -0
- data/lib/nrser/props/immutable/hash.rb +111 -0
- data/lib/nrser/props/immutable/hash_variable.rb +82 -0
- data/lib/nrser/props/immutable/instance_variables.rb +48 -0
- data/lib/nrser/props/immutable/vector.rb +107 -0
- data/lib/nrser/props/instance_methods.rb +184 -0
- data/lib/nrser/props/metadata.rb +359 -0
- data/lib/nrser/props/mutable/instance_variables.rb +60 -0
- data/lib/nrser/props/mutable/stash.rb +199 -0
- data/lib/nrser/{meta/props → props}/prop.rb +217 -112
- data/lib/nrser/props/storage/instance_variable.rb +85 -0
- data/lib/nrser/props/storage/instance_variables.rb +67 -0
- data/lib/nrser/props/storage/key.rb +88 -0
- data/lib/nrser/props.rb +9 -0
- data/lib/nrser/refinements/sugar.rb +41 -0
- data/lib/nrser/refinements/types.rb +2 -2
- data/lib/nrser/refinements.rb +14 -16
- data/lib/nrser/rspex/example_group/describe_attribute.rb +24 -0
- data/lib/nrser/rspex/example_group/describe_called_with.rb +1 -6
- data/lib/nrser/rspex/example_group/{describe_use_case.rb → describe_case.rb} +6 -3
- data/lib/nrser/rspex/example_group/describe_class.rb +1 -0
- data/lib/nrser/rspex/example_group/describe_group.rb +29 -0
- data/lib/nrser/rspex/example_group/describe_instance_method.rb +2 -2
- data/lib/nrser/rspex/example_group/describe_message.rb +35 -0
- data/lib/nrser/rspex/example_group/describe_method.rb +23 -2
- data/lib/nrser/rspex/example_group/describe_module.rb +19 -0
- data/lib/nrser/rspex/example_group/describe_response_to.rb +32 -0
- data/lib/nrser/rspex/example_group/describe_section.rb +38 -0
- data/lib/nrser/rspex/example_group/describe_sent_to.rb +52 -0
- data/lib/nrser/rspex/example_group/describe_source_file.rb +49 -0
- data/lib/nrser/rspex/example_group/describe_spec_file.rb +41 -108
- data/lib/nrser/rspex/example_group/describe_when.rb +14 -7
- data/lib/nrser/rspex/example_group/describe_x.rb +39 -12
- data/lib/nrser/rspex/example_group/overrides.rb +66 -0
- data/lib/nrser/rspex/example_group.rb +20 -252
- data/lib/nrser/rspex/format.rb +83 -17
- data/lib/nrser/rspex.rb +4 -34
- data/lib/nrser/sugar/method_missing_forwarder.rb +50 -0
- data/lib/nrser/{env → sys/env}/path.rb +1 -2
- data/lib/nrser/{env.rb → sys/env.rb} +2 -1
- data/lib/nrser/sys.rb +5 -0
- data/lib/nrser/types/any.rb +36 -7
- data/lib/nrser/types/{array.rb → arrays.rb} +32 -81
- data/lib/nrser/types/attrs.rb +68 -15
- data/lib/nrser/types/booleans.rb +95 -34
- data/lib/nrser/types/bounded.rb +12 -10
- data/lib/nrser/types/combinators.rb +74 -37
- data/lib/nrser/types/errors/check_error.rb +86 -0
- data/lib/nrser/types/errors/from_string_error.rb +82 -0
- data/lib/nrser/types/factory.rb +91 -0
- data/lib/nrser/types/hashes.rb +171 -26
- data/lib/nrser/types/in.rb +25 -12
- data/lib/nrser/types/is.rb +50 -18
- data/lib/nrser/types/is_a.rb +52 -33
- data/lib/nrser/types/labels.rb +6 -33
- data/lib/nrser/types/maybe.rb +12 -4
- data/lib/nrser/types/nil.rb +24 -4
- data/lib/nrser/types/not.rb +6 -16
- data/lib/nrser/types/numbers.rb +94 -57
- data/lib/nrser/types/pairs.rb +57 -57
- data/lib/nrser/types/paths.rb +112 -133
- data/lib/nrser/types/responds.rb +64 -74
- data/lib/nrser/types/shape.rb +29 -24
- data/lib/nrser/types/strings.rb +25 -17
- data/lib/nrser/types/symbols.rb +19 -17
- data/lib/nrser/types/trees.rb +18 -70
- data/lib/nrser/types/tuples.rb +36 -40
- data/lib/nrser/types/type.rb +342 -91
- data/lib/nrser/types/when.rb +40 -18
- data/lib/nrser/types/where.rb +94 -9
- data/lib/nrser/types.rb +72 -63
- data/lib/nrser/version.rb +1 -1
- data/lib/nrser.rb +18 -18
- data/spec/lib/nrser/{functions/binding/template_spec.rb → core_ext/binding/erb_spec.rb} +5 -5
- data/spec/lib/nrser/{functions → core_ext}/enumerable/find_map_spec.rb +8 -6
- data/spec/lib/nrser/{refinements → core_ext}/hash_spec.rb +9 -22
- data/spec/lib/nrser/errors/abstract_method_error_spec.rb +12 -5
- data/spec/lib/nrser/functions/enumerable/{to_h_by_spec.rb → associate_spec.rb} +1 -1
- data/spec/lib/nrser/functions/merge_by_spec.rb +1 -1
- data/spec/lib/nrser/functions/tree/each_branch_spec.rb +3 -3
- data/spec/lib/nrser/functions/tree/transform_spec.rb +14 -15
- data/spec/lib/nrser/gem_ext/hamster/json_spec.rb +4 -0
- data/spec/lib/nrser/meta/source/location_spec.rb +86 -0
- data/spec/lib/nrser/props/immutable/hash_spec.rb +297 -0
- data/spec/lib/nrser/props/immutable/vector_spec.rb +296 -0
- data/spec/lib/nrser/{meta/props_spec.rb → props/original_props_spec.rb} +11 -16
- data/spec/lib/nrser/{meta/props → props}/to_and_from_data_spec.rb +10 -8
- data/spec/lib/nrser/refinements/array_spec.rb +2 -15
- data/spec/lib/nrser/refinements/erb_spec.rb +5 -7
- data/spec/lib/nrser/refinements/set_spec.rb +2 -15
- data/spec/lib/nrser/{env → sys/env}/path/insert_spec.rb +4 -2
- data/spec/lib/nrser/{env → sys/env}/path_spec.rb +4 -2
- data/spec/lib/nrser/types/array_spec.rb +8 -8
- data/spec/lib/nrser/types/paths_spec.rb +15 -18
- data/spec/spec_helper.rb +4 -0
- metadata +109 -69
- data/lib/nrser/ext/binding.rb +0 -36
- data/lib/nrser/ext/module.rb +0 -62
- data/lib/nrser/ext.rb +0 -8
- data/lib/nrser/functions/binding.rb +0 -76
- data/lib/nrser/functions/enumerable/map_keys.rb +0 -0
- data/lib/nrser/functions/enumerable/map_values.rb +0 -94
- data/lib/nrser/functions/hash/deep_merge.rb +0 -57
- data/lib/nrser/functions/hash/except_keys.rb +0 -44
- data/lib/nrser/functions/hash/slice_keys.rb +0 -43
- data/lib/nrser/functions/hash/stringify_keys.rb +0 -55
- data/lib/nrser/functions/hash/symbolize_keys.rb +0 -57
- data/lib/nrser/functions/hash/transform_keys.rb +0 -140
- data/lib/nrser/functions/module/methods.rb +0 -206
- data/lib/nrser/functions/module/source_locations.rb +0 -213
- data/lib/nrser/logging/appender.rb +0 -3
- data/lib/nrser/logging.rb +0 -353
- data/lib/nrser/meta/props/base.rb +0 -31
- data/lib/nrser/meta/props.rb +0 -357
- data/lib/nrser/refinements/array.rb +0 -133
- data/lib/nrser/refinements/binding.rb +0 -6
- data/lib/nrser/refinements/enumerator.rb +0 -5
- data/lib/nrser/refinements/exception.rb +0 -35
- data/lib/nrser/refinements/hash.rb +0 -150
- data/lib/nrser/refinements/module.rb +0 -5
- data/lib/nrser/refinements/object.rb +0 -42
- data/lib/nrser/refinements/open_struct.rb +0 -28
- data/lib/nrser/refinements/pathname.rb +0 -5
- data/lib/nrser/refinements/set.rb +0 -5
- data/lib/nrser/refinements/string.rb +0 -5
- data/lib/nrser/refinements/symbol.rb +0 -20
- data/lib/nrser/rspex/described.rb +0 -99
- data/spec/design/mapping_spec.rb +0 -42
- data/spec/lib/nrser/functions/hash_spec.rb +0 -41
- data/spec/lib/nrser/functions/string/truncate_spec.rb +0 -11
- data/spec/lib/nrser/refinements/truncate_spec.rb +0 -10
data/lib/nrser/types/type.rb
CHANGED
@@ -1,8 +1,21 @@
|
|
1
|
-
#
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Requirements
|
2
5
|
# =======================================================================
|
3
6
|
|
4
|
-
|
5
|
-
|
7
|
+
# Stdlib
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
|
10
|
+
# Deps
|
11
|
+
# -----------------------------------------------------------------------
|
12
|
+
|
13
|
+
# Project / Package
|
14
|
+
# -----------------------------------------------------------------------
|
15
|
+
|
16
|
+
# Just require the errors here so we don't need to do it everywhere
|
17
|
+
require_relative './errors/check_error'
|
18
|
+
require_relative './errors/from_string_error'
|
6
19
|
|
7
20
|
|
8
21
|
# Definitions
|
@@ -10,10 +23,6 @@ using NRSER
|
|
10
23
|
|
11
24
|
module NRSER::Types
|
12
25
|
class Type
|
13
|
-
def self.short_name
|
14
|
-
name.split('::').last
|
15
|
-
end
|
16
|
-
|
17
26
|
|
18
27
|
# Constructor
|
19
28
|
# =====================================================================
|
@@ -82,88 +91,183 @@ module NRSER::Types
|
|
82
91
|
end # #initialize
|
83
92
|
|
84
93
|
|
94
|
+
# Instance Methods
|
95
|
+
# ========================================================================
|
96
|
+
|
97
|
+
# @!group Display Instance Methods
|
98
|
+
# ------------------------------------------------------------------------
|
99
|
+
|
100
|
+
# What this type likes to be called (and displayed as by default).
|
101
|
+
#
|
102
|
+
# Custom names can be provided when constructing most types via the
|
103
|
+
# `name:` keyword, which allows thinking about composite and complicated
|
104
|
+
# types in simpler and application-specific terms.
|
105
|
+
#
|
106
|
+
# Realizing subclasses **should not** override this method - they should
|
107
|
+
# pass a `name:` keyword up to {#initialize}, which sets the `@name`
|
108
|
+
# instance variable that is then used here.
|
109
|
+
#
|
110
|
+
# If no name is provided to {#initialize}, this method will fall back to
|
111
|
+
# {#explain}.
|
112
|
+
#
|
113
|
+
# @return [String]
|
114
|
+
#
|
85
115
|
def name
|
86
|
-
@name ||
|
116
|
+
@name || explain
|
87
117
|
end
|
88
118
|
|
89
|
-
|
90
|
-
|
119
|
+
|
120
|
+
# A string that gives our best concise description of the type's logic,
|
121
|
+
# in particular exposing any composite types that it's made up of.
|
122
|
+
#
|
123
|
+
# Used as the {#name} when a custom one is not provided.
|
124
|
+
#
|
125
|
+
# Meant for inline display, so the result *should not* contain newlines.
|
126
|
+
#
|
127
|
+
# Realizing subclasses **should** override this method, as this
|
128
|
+
# implementation only returns the class' name (and just the last segment,
|
129
|
+
# for brevity's sake).
|
130
|
+
#
|
131
|
+
# @example Base implementation is not very interesting
|
132
|
+
# MyType = Class.new NRSER::Types::Type
|
133
|
+
# my_type = MyType.new
|
134
|
+
# my_type.explain
|
135
|
+
# # => "MyType"
|
136
|
+
#
|
137
|
+
# @return [String]
|
138
|
+
#
|
139
|
+
def explain
|
140
|
+
self.class.demod_name
|
91
141
|
end
|
92
142
|
|
143
|
+
# @!endgroup Display Instance Methods # **********************************
|
144
|
+
|
145
|
+
|
146
|
+
# @!group Validation Instance Methods
|
147
|
+
# ------------------------------------------------------------------------
|
148
|
+
#
|
149
|
+
# The core of what a type does.
|
150
|
+
#
|
93
151
|
|
94
152
|
# See if a value satisfies the type.
|
95
153
|
#
|
154
|
+
# Realizing classes **must** implement this method.
|
155
|
+
#
|
156
|
+
# This implementation just defines the API; it always raises
|
157
|
+
# {NRSER::AbstractMethodError}.
|
158
|
+
#
|
96
159
|
# @param [Object] value
|
97
160
|
# Value to test for type satisfaction.
|
98
161
|
#
|
99
162
|
# @return [Boolean]
|
100
163
|
# `true` if the `value` satisfies the type.
|
101
164
|
#
|
102
|
-
def test value
|
103
|
-
raise
|
165
|
+
def test? value
|
166
|
+
raise NRSER::AbstractMethodError.new( self, __method__ )
|
104
167
|
end
|
105
168
|
|
169
|
+
# Old name for {#test?}.
|
170
|
+
#
|
171
|
+
# @deprecated
|
172
|
+
#
|
173
|
+
# @param (see #test?)
|
174
|
+
# @return (see #test?)
|
175
|
+
# @raise (see #test?)
|
176
|
+
#
|
177
|
+
def test value; test? value; end
|
106
178
|
|
107
|
-
|
179
|
+
|
180
|
+
# Check that a `value` satisfies the type.
|
181
|
+
#
|
182
|
+
# @see #test?
|
183
|
+
#
|
184
|
+
# @return [Object]
|
185
|
+
# The value itself.
|
186
|
+
#
|
187
|
+
# @raise [NRSER::Types::CheckError]
|
188
|
+
# If the value does not satisfy this type.
|
189
|
+
#
|
190
|
+
def check! value, &details
|
108
191
|
# success case
|
109
|
-
return value if test value
|
110
|
-
|
111
|
-
msg = if make_fail_message
|
112
|
-
make_fail_message.call type: self, value: value
|
113
|
-
else
|
114
|
-
NRSER.squish <<-END
|
115
|
-
value #{ value.inspect } failed check #{ self.to_s }
|
116
|
-
END
|
117
|
-
end
|
192
|
+
return value if test? value
|
118
193
|
|
119
|
-
raise
|
194
|
+
raise NRSER::Types::CheckError.new \
|
195
|
+
value: value,
|
196
|
+
type: self,
|
197
|
+
details: details
|
120
198
|
end
|
121
199
|
|
200
|
+
# Old name for {#check!} without the bang.
|
201
|
+
def check *args, █ check! *args, █ end
|
202
|
+
|
203
|
+
# @!endgroup Validation Instance Methods # *******************************
|
122
204
|
|
123
|
-
|
124
|
-
#
|
125
|
-
#
|
126
|
-
# to execute.
|
205
|
+
|
206
|
+
# @!group Loading Values Instance Methods
|
207
|
+
# ------------------------------------------------------------------------
|
127
208
|
#
|
128
|
-
#
|
129
|
-
#
|
130
|
-
# t1.respond_to? :from_s
|
131
|
-
# # => false
|
132
|
-
#
|
133
|
-
# t2 = t.where( from_s: ->(s){ s.split ',' } ) { |value| true }
|
134
|
-
# t2.respond_to? :from_s
|
135
|
-
# # => true
|
209
|
+
# Types include facilities for loading values from representations and
|
210
|
+
# encodings.
|
136
211
|
#
|
137
|
-
#
|
138
|
-
#
|
212
|
+
# This was initially driven by the desire to use types to
|
213
|
+
# declare CLI parameter schemas, as way to dispatch with the often
|
214
|
+
# limited and arbitrary support most "CLI frameworks" have for declaring
|
215
|
+
# option types - things like "you can have an integer, and you can
|
216
|
+
# have an array, but you can't have an array of integers".
|
139
217
|
#
|
140
|
-
#
|
141
|
-
#
|
218
|
+
# By using compossible types that can load values from strings we get a
|
219
|
+
# system where you can easily declare whatever complex and granular types
|
220
|
+
# you desire and have the machine automatically load and validate them,
|
221
|
+
# as well as provide reasonable generated feedback when something doesn't
|
222
|
+
# meet expectations, which has worked out quite well so far start to cut
|
223
|
+
# down the amount of repetitive and error-prone "did I get what I need?
|
224
|
+
# No, did I get exactly what I need?" bullshit in receiving data.
|
225
|
+
#
|
226
|
+
# This approach is now being expanded to "data" - an ill-formed concept
|
227
|
+
# I've been brewing of "reasonable common and portable data
|
228
|
+
# representation" and the {NRSER::Props} system, which has been coming
|
229
|
+
# along as well.
|
230
|
+
#
|
231
|
+
|
232
|
+
# Test if the type knows how to load values from strings.
|
233
|
+
#
|
234
|
+
# Looks for the `@from_s` instance variable or a `#custom_from_s`
|
235
|
+
# method.
|
236
|
+
#
|
237
|
+
# @note
|
238
|
+
# When this method returns `true` it simply indicates that some method
|
239
|
+
# of loading from strings exists - the load itself can of course still
|
240
|
+
# fail.
|
241
|
+
#
|
242
|
+
# Realizing classes should only need to override this method to limited or
|
243
|
+
# expand the scope relative to parameterized types.
|
142
244
|
#
|
143
245
|
# @return [Boolean]
|
144
246
|
#
|
145
|
-
def
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
else
|
151
|
-
super name, include_all
|
152
|
-
end
|
153
|
-
end # #respond_to?
|
247
|
+
def has_from_s?
|
248
|
+
!@from_s.nil? ||
|
249
|
+
# Need the `true` second arg to include protected methods
|
250
|
+
respond_to?( :custom_from_s, true )
|
251
|
+
end
|
154
252
|
|
155
253
|
|
156
|
-
# Load a value of this type from a string representation by passing
|
157
|
-
# to the {@from_s} {Proc}.
|
254
|
+
# Load a value of this type from a string representation by passing
|
255
|
+
# `string` to the {@from_s} {Proc}.
|
158
256
|
#
|
159
|
-
# Checks the value {@from_s} returns with {#check} before returning it, so
|
257
|
+
# Checks the value {@from_s} returns with {#check!} before returning it, so
|
160
258
|
# you know it satisfies this type.
|
161
259
|
#
|
162
|
-
#
|
260
|
+
# Realizing classes **should not** need to override this - they can define
|
261
|
+
# a `#custom_from_s` instance method for it to use, allowing individual
|
262
|
+
# types to still override that by providing a `from_s:` proc keyword
|
263
|
+
# arg at construction. This also lets them avoid checking the returned
|
264
|
+
# value, since we do so here.
|
265
|
+
#
|
266
|
+
# @param [String] string
|
163
267
|
# String representation.
|
164
268
|
#
|
165
269
|
# @return [Object]
|
166
|
-
# Value that has passed {#check}.
|
270
|
+
# Value that has passed {#check!}.
|
167
271
|
#
|
168
272
|
# @raise [NoMethodError]
|
169
273
|
# If this type doesn't know how to load values from strings.
|
@@ -180,34 +284,67 @@ module NRSER::Types
|
|
180
284
|
# @raise [TypeError]
|
181
285
|
# If the value loaded does not pass {#check}.
|
182
286
|
#
|
183
|
-
def from_s
|
184
|
-
|
185
|
-
raise NoMethodError, "#from_s not defined"
|
287
|
+
def from_s string
|
288
|
+
unless has_from_s?
|
289
|
+
raise NoMethodError, "#from_s not defined for type #{ name }"
|
186
290
|
end
|
187
291
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
def from_data data
|
193
|
-
if @from_data.nil?
|
194
|
-
raise NoMethodError, "#from_data not defined"
|
292
|
+
value = if @from_s
|
293
|
+
@from_s.call string
|
294
|
+
else
|
295
|
+
custom_from_s string
|
195
296
|
end
|
196
297
|
|
197
|
-
check
|
298
|
+
check! value
|
198
299
|
end
|
199
300
|
|
200
301
|
|
201
|
-
# Test if the type
|
302
|
+
# Test if the type can load values from "data" - basic values and
|
303
|
+
# collections like {Array} and {Hash} forming tree-like structures.
|
202
304
|
#
|
203
|
-
#
|
305
|
+
# Realizing classes *may* need to override this to limited or expand
|
306
|
+
# responses relative to parameterized types.
|
204
307
|
#
|
205
308
|
# @return [Boolean]
|
206
309
|
#
|
207
|
-
def
|
208
|
-
|
310
|
+
def has_from_data?
|
311
|
+
!@from_data.nil? ||
|
312
|
+
# Need the `true` second arg to include protected methods
|
313
|
+
respond_to?( :custom_from_data, true )
|
314
|
+
end
|
315
|
+
|
316
|
+
|
317
|
+
# Try to load a value from "data" - basic values and
|
318
|
+
# collections like {Array} and {Hash} forming tree-like structures.
|
319
|
+
#
|
320
|
+
# @param [*] data
|
321
|
+
# Data to try to load from.
|
322
|
+
#
|
323
|
+
# @raise [NoMethodError]
|
324
|
+
# If {#has_from_data?} returns `false`.
|
325
|
+
#
|
326
|
+
# @raise [NRSER::Types::CheckError]
|
327
|
+
# If the load result does not satisfy the type (see {#check!}).
|
328
|
+
#
|
329
|
+
def from_data data
|
330
|
+
unless has_from_data?
|
331
|
+
raise NoMethodError, "#from_data not defined"
|
332
|
+
end
|
333
|
+
|
334
|
+
value = if @from_data
|
335
|
+
@from_data.call data
|
336
|
+
else
|
337
|
+
custom_from_data data
|
338
|
+
end
|
339
|
+
|
340
|
+
check! value
|
209
341
|
end
|
210
342
|
|
343
|
+
# @!endgroup Loading Values Instance Methods # ***************************
|
344
|
+
|
345
|
+
|
346
|
+
# @!group Dumping Values Instance Methods
|
347
|
+
# ------------------------------------------------------------------------
|
211
348
|
|
212
349
|
# Test if the type has custom information about how to convert it's values
|
213
350
|
# into "data" - structures and values suitable for transportation and
|
@@ -222,11 +359,6 @@ module NRSER::Types
|
|
222
359
|
end # #has_to_data?
|
223
360
|
|
224
361
|
|
225
|
-
def has_from_data?
|
226
|
-
! @from_data.nil?
|
227
|
-
end
|
228
|
-
|
229
|
-
|
230
362
|
# Dumps a value of this type to "data" - structures and values suitable
|
231
363
|
# for transport and storage, such as dumping to JSON or YAML, etc.
|
232
364
|
#
|
@@ -244,22 +376,67 @@ module NRSER::Types
|
|
244
376
|
@to_data.call value
|
245
377
|
end # #to_data
|
246
378
|
|
379
|
+
# @!endgroup Dumping Values Instance Methods # ***************************
|
247
380
|
|
248
|
-
# Language Inter-Op
|
249
|
-
# =====================================================================
|
250
381
|
|
382
|
+
# @!group Language Integration Instance Methods
|
383
|
+
# ------------------------------------------------------------------------
|
251
384
|
|
385
|
+
# Proxies to {#name}.
|
386
|
+
#
|
252
387
|
# @return [String]
|
253
|
-
# a brief string description of the type - just it's {#name} surrounded
|
254
|
-
# by some back-ticks to make it easy to see where it starts and stops.
|
255
388
|
#
|
256
|
-
def to_s
|
257
|
-
|
389
|
+
def to_s; name; end
|
390
|
+
|
391
|
+
|
392
|
+
# Hook into Ruby's *case subsumption* operator to allow usage in `case`
|
393
|
+
# statements! Forwards to {#test?}.
|
394
|
+
#
|
395
|
+
# @param value (see #test?)
|
396
|
+
# @return (see #test?)
|
397
|
+
#
|
398
|
+
def === value
|
399
|
+
test? value
|
258
400
|
end
|
259
401
|
|
260
402
|
|
261
|
-
#
|
262
|
-
#
|
403
|
+
# Overridden to customize behavior for the {#from_s}, {#from_data} and
|
404
|
+
# {#to_data} methods - those methods are always defined, but we have
|
405
|
+
# {#respond_to?} return `false` if they lack the underlying instance
|
406
|
+
# variables needed to execute.
|
407
|
+
#
|
408
|
+
# @example
|
409
|
+
# t1 = t.where { |value| true }
|
410
|
+
# t1.respond_to? :from_s
|
411
|
+
# # => false
|
412
|
+
#
|
413
|
+
# t2 = t.where( from_s: ->(s){ s.split ',' } ) { |value| true }
|
414
|
+
# t2.respond_to? :from_s
|
415
|
+
# # => true
|
416
|
+
#
|
417
|
+
# @param [Symbol | String] name
|
418
|
+
# Method name to ask about.
|
419
|
+
#
|
420
|
+
# @param [Boolean] include_all
|
421
|
+
# IDK, part of Ruby API that is passed up to `super`.
|
422
|
+
#
|
423
|
+
# @return [Boolean]
|
424
|
+
#
|
425
|
+
def respond_to? name, include_all = false
|
426
|
+
case name.to_sym
|
427
|
+
when :from_s
|
428
|
+
has_from_s?
|
429
|
+
when :from_data
|
430
|
+
has_from_data?
|
431
|
+
when :to_data
|
432
|
+
has_to_data?
|
433
|
+
else
|
434
|
+
super name, include_all
|
435
|
+
end
|
436
|
+
end # #respond_to?
|
437
|
+
|
438
|
+
|
439
|
+
### Inspecting
|
263
440
|
#
|
264
441
|
# Due to their combinatoric nature, types can quickly become large data
|
265
442
|
# hierarchies, and the built-in {#inspect} will produce a massive dump
|
@@ -270,24 +447,98 @@ module NRSER::Types
|
|
270
447
|
#
|
271
448
|
# As a solution, we alias the built-in `#inspect` as {#builtin_inspect},
|
272
449
|
# so it's available in situations where you really want all those gory
|
273
|
-
# details, and point {#inspect} to {#
|
450
|
+
# details, and point {#inspect} to {#explain}.
|
274
451
|
#
|
275
452
|
|
276
453
|
alias_method :builtin_inspect, :inspect
|
277
|
-
|
454
|
+
def inspect
|
455
|
+
name = self.name
|
456
|
+
explain = self.explain
|
457
|
+
|
458
|
+
if name == explain
|
459
|
+
explain
|
460
|
+
else
|
461
|
+
"#{ name } := #{ explain }"
|
462
|
+
end
|
463
|
+
end
|
278
464
|
|
465
|
+
# @!endgroup Language Integration Instance Methods # *********************
|
279
466
|
|
280
|
-
|
281
|
-
#
|
467
|
+
|
468
|
+
# @!group Derivation Instance Methods
|
469
|
+
# ------------------------------------------------------------------------
|
282
470
|
#
|
283
|
-
#
|
471
|
+
# Methods for deriving new types from `self`.
|
284
472
|
#
|
285
|
-
|
286
|
-
#
|
287
|
-
#
|
288
|
-
|
289
|
-
|
473
|
+
|
474
|
+
# Return a *union* type satisfied by values that satisfy either `self`
|
475
|
+
# *or* and of `others`.
|
476
|
+
#
|
477
|
+
# @param [*] other
|
478
|
+
# Values passed through {NRSER::Types.make} to create the other types.
|
479
|
+
#
|
480
|
+
# @return [NRSER::Types::Union]
|
481
|
+
#
|
482
|
+
def union *others
|
483
|
+
require_relative './combinators'
|
484
|
+
|
485
|
+
NRSER::Types.union self, *others
|
486
|
+
end # #union
|
487
|
+
|
488
|
+
alias_method :|, :union
|
489
|
+
alias_method :or, :union
|
490
|
+
|
491
|
+
|
492
|
+
# Return an *intersection* type satisfied by values that satisfy both
|
493
|
+
# `self` *and* all of `others`.
|
494
|
+
#
|
495
|
+
# @param [Array] *others
|
496
|
+
# Values passed through {NRSER::Types.make} to create the other types.
|
497
|
+
#
|
498
|
+
# @return [NRSER::Types::Intersection]
|
499
|
+
#
|
500
|
+
def intersection *others
|
501
|
+
require_relative './combinators'
|
502
|
+
|
503
|
+
NRSER::Types.intersection self, *others
|
504
|
+
end # #intersection
|
505
|
+
|
506
|
+
alias_method :&, :intersection
|
507
|
+
alias_method :and, :intersection
|
508
|
+
|
509
|
+
|
510
|
+
# Return an *exclusive or* type satisfied by values that satisfy either
|
511
|
+
# `self` *or* `other` *but not both*.
|
512
|
+
#
|
513
|
+
# @param [*] other
|
514
|
+
# Value passed through {NRSER::Types.make} to create the other type.
|
515
|
+
#
|
516
|
+
# @return [NRSER::Types::Intersection]
|
517
|
+
#
|
518
|
+
def xor *others
|
519
|
+
require_relative './combinators'
|
520
|
+
|
521
|
+
NRSER::Types.xor self, *others
|
522
|
+
end # #^
|
523
|
+
|
524
|
+
alias_method :^, :xor
|
525
|
+
|
526
|
+
|
527
|
+
# Return a "negation" type satisfied by all values that do *not* satisfy
|
528
|
+
# `self`.
|
529
|
+
#
|
530
|
+
# @return [NRSER::Types::Not]
|
531
|
+
#
|
532
|
+
def not
|
533
|
+
require_relative './not'
|
534
|
+
|
535
|
+
NRSER::Types.not self
|
290
536
|
end
|
291
537
|
|
538
|
+
alias_method :~, :not
|
539
|
+
|
540
|
+
# @!endgroup Derivation Instance Methods # *******************************
|
541
|
+
|
542
|
+
|
292
543
|
end # Type
|
293
544
|
end # NRSER::Types
|
data/lib/nrser/types/when.rb
CHANGED
@@ -1,24 +1,13 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
4
|
# Requirements
|
4
5
|
# =======================================================================
|
5
6
|
|
6
|
-
# Stdlib
|
7
|
-
# -----------------------------------------------------------------------
|
8
|
-
|
9
|
-
# Deps
|
10
|
-
# -----------------------------------------------------------------------
|
11
|
-
|
12
7
|
# Project / Package
|
13
8
|
# -----------------------------------------------------------------------
|
14
9
|
|
15
|
-
|
16
|
-
# Refinements
|
17
|
-
# =======================================================================
|
18
|
-
|
19
|
-
|
20
|
-
# Declarations
|
21
|
-
# =======================================================================
|
10
|
+
require_relative './type'
|
22
11
|
|
23
12
|
|
24
13
|
# Definitions
|
@@ -26,9 +15,31 @@
|
|
26
15
|
|
27
16
|
module NRSER::Types
|
28
17
|
|
18
|
+
# Wraps an object as a type, using Ruby's "case equality" `===` to test
|
19
|
+
# membership (like a `when` clause in a `case` expression).
|
20
|
+
#
|
21
|
+
# Deals with some data loading too.
|
22
|
+
#
|
23
|
+
# @note
|
24
|
+
# This was kinda hacked in when my idiot-ass figured out that all this
|
25
|
+
# types BS could fit in real well with Ruby's `===`, allowing types to
|
26
|
+
# be used in `when` clauses.
|
27
|
+
#
|
28
|
+
# Previously, {NRSER::Types.make} used to see if something was a module,
|
29
|
+
# and turn those into `is_a` types, and turn everything else into
|
30
|
+
# `is`, but this kind of sucked for a bunch of reasons I don't totally
|
31
|
+
# remember.
|
32
|
+
#
|
33
|
+
# Now, if a value is not a special case (like `nil`) or already a type,
|
34
|
+
# {NRSER::Types.make} turns it into a {When}.
|
35
|
+
#
|
36
|
+
# {When} instances are totally Ruby-centric, and are thus mostly to
|
37
|
+
# support in-runtime testing - you wouldn't want a {When} type to
|
38
|
+
# be part of an API schema or something - but they're really nice for
|
39
|
+
# the internal stuff.
|
40
|
+
#
|
29
41
|
class When < Type
|
30
42
|
|
31
|
-
|
32
43
|
# The wrapped {Object} whose `#===` will be used to test membership.
|
33
44
|
#
|
34
45
|
# @return [Object]
|
@@ -49,15 +60,26 @@ module NRSER::Types
|
|
49
60
|
# Instance Methods
|
50
61
|
# ======================================================================
|
51
62
|
|
52
|
-
def test value
|
63
|
+
def test? value
|
53
64
|
@object === value
|
54
65
|
end
|
55
66
|
|
56
67
|
|
57
|
-
def
|
58
|
-
@object.
|
68
|
+
def explain
|
69
|
+
@object.inspect
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
def has_from_s?
|
74
|
+
@from_s || object.respond_to?( :from_s )
|
59
75
|
end
|
60
76
|
|
77
|
+
|
78
|
+
def custom_from_s string
|
79
|
+
object.from_s string
|
80
|
+
end
|
81
|
+
|
82
|
+
|
61
83
|
# If {#object} responds to `#from_data`, call that and check results.
|
62
84
|
#
|
63
85
|
# Otherwise, forward up to {NRSER::Types::Type#from_data}.
|
@@ -95,7 +117,7 @@ module NRSER::Types
|
|
95
117
|
end # class When
|
96
118
|
|
97
119
|
|
98
|
-
|
120
|
+
def_factory :when do |value, **options|
|
99
121
|
When.new value, **options
|
100
122
|
end
|
101
123
|
|