nrser 0.3.9 → 0.3.10

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,269 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+
5
+ # Requirements
6
+ # ========================================================================
7
+
8
+ # Project / Package
9
+ # ------------------------------------------------------------------------
10
+
11
+ require 'nrser/core_ext/hash'
12
+
13
+ require_relative './type'
14
+ require_relative './combinators'
15
+ require_relative './is'
16
+ require_relative './bounded'
17
+
18
+
19
+ # Namespace
20
+ # ========================================================================
21
+
22
+ module NRSER
23
+ module Types
24
+
25
+
26
+ # Definitions
27
+ # ========================================================================
28
+
29
+ # Specify types for value attributes.
30
+ #
31
+ # @note
32
+ # Construct {Attributes} types using the {.Attributes} factory.
33
+ #
34
+ class Attributes < Type
35
+
36
+ # Attributes
37
+ # ========================================================================
38
+
39
+ # Attribute types by name.
40
+ #
41
+ # @return [Hash<Symbol, Type>]
42
+ #
43
+ attr_reader :types
44
+
45
+
46
+ # Construct an `AttrsType`.
47
+ #
48
+ # @param [Hash<#to_sym, TYPE>] attrs
49
+ # Map of attribute names to their types (`TYPE` values will be passed
50
+ # through {NRSER::Types.make} to get a type instance).
51
+ #
52
+ # May not be empty.
53
+ #
54
+ def initialize attrs, **options
55
+ super **options
56
+
57
+ if attrs.empty?
58
+ raise ArgumentError,
59
+ "Must provide at least one attribute name/type pair"
60
+ end
61
+
62
+ @types = attrs.map { |k, v|
63
+ [ k.to_sym, NRSER::Types.make( v ) ]
64
+ }.to_h.freeze
65
+ end
66
+
67
+
68
+ # @!group Display Instance Methods
69
+ # --------------------------------------------------------------------------
70
+
71
+ def type_strings method:
72
+ types.map { |name, type|
73
+ "##{ name }#{ RESPONDS_WITH }#{ type.public_send method }"
74
+ }
75
+ end
76
+
77
+
78
+ def default_name
79
+ type_strings = self.type_strings method: :name
80
+
81
+ if type_strings.length == 1
82
+ type_strings[0]
83
+ else
84
+ L_PAREN + type_strings.join( " #{ AND } " ) + R_PAREN
85
+ end
86
+ end
87
+
88
+
89
+ def default_symbolic
90
+ type_strings = self.type_strings method: :symbolic
91
+
92
+ if type_strings.length == 1
93
+ type_strings[0]
94
+ else
95
+ L_PAREN + type_strings.join( " #{ AND } " ) + R_PAREN
96
+ end
97
+ end
98
+
99
+
100
+ # @see NRSER::Types::Type#explain
101
+ #
102
+ # @return [String]
103
+ #
104
+ def explain
105
+ "#{ self.class.demod_name }<" +
106
+ type_strings( method: :explain ).join( ', ' ) +
107
+ ">"
108
+ end
109
+
110
+
111
+ # @see NRSER::Types::Type#test
112
+ #
113
+ # @return [Boolean]
114
+ #
115
+ def test? value
116
+ types.all? { |name, type|
117
+ value.respond_to?( name ) &&
118
+ type.test?( value.method( name ).call )
119
+ }
120
+ end
121
+
122
+ end # Attributes
123
+
124
+
125
+ # @!group Attributes Type Factories
126
+ # ----------------------------------------------------------------------------
127
+
128
+ # @!method self.Attributes attrs, **options
129
+ # Get a {Type} that checks the types of one or more attributes on values.
130
+ #
131
+ # @example Type where first element of an Enumerable is a String
132
+ # string_first = intersection Enumerable, attrs(first: String)
133
+ #
134
+ # @param [Hash<#to_sym, (Type | Object)>] attrs
135
+ #
136
+ #
137
+ def_type :Attributes,
138
+ parameterize: :attributes,
139
+ aliases: [ :attrs, ],
140
+ &->( attributes, **options ) do
141
+ Attributes.new attributes, **options
142
+ end
143
+
144
+
145
+ # @!method self.Length **options
146
+ #
147
+ # @overload length exact, options = {}
148
+ # Get a length attribute type that specifies an `exact` value.
149
+ #
150
+ # @example
151
+ # only_type = NRSER::Types.length 1
152
+ #
153
+ # only_type.test []
154
+ # # => false
155
+ #
156
+ # only_type.test [:x]
157
+ # # => true
158
+ #
159
+ # only_type.test [:x, :y]
160
+ # # => false
161
+ #
162
+ # @param [Integer] exact
163
+ # Exact non-negative integer that the length must be to satisfy the
164
+ # type created.
165
+ #
166
+ # @param [Hash] options
167
+ # Options hash passed up to {NRSER::Types::Type} constructor.
168
+ #
169
+ # @return [NRSER::Types::Attributes]
170
+ # Type satisfied by a `#length` attribute that is exactly `exact`.
171
+ #
172
+ #
173
+ # @overload length bounds, options = {}
174
+ # Get a length attribute type satisfied by values within a `:min` and
175
+ # `:max` (inclusive).
176
+ #
177
+ # @example
178
+ # three_to_five = NRSER::Types.length( {min: 3, max: 5}, name: '3-5' )
179
+ # three_to_five.test [1, 2] # => false
180
+ # three_to_five.test [1, 2, 3] # => true
181
+ # three_to_five.test [1, 2, 3, 4] # => true
182
+ # three_to_five.test [1, 2, 3, 4, 5] # => true
183
+ # three_to_five.test [1, 2, 3, 4, 5, 6] # => false
184
+ #
185
+ # @param [Hash] bounds
186
+ #
187
+ # @option bounds [Integer] :min
188
+ # An optional minimum value that the `#length` should not be less than.
189
+ #
190
+ # @option bounds [Integer] :max
191
+ # An optional maximum value that the `#length` should not be more than.
192
+ #
193
+ # @option bounds [Integer] :length
194
+ # An optional value for both the minimum and maximum.
195
+ #
196
+ # @param [Hash] options
197
+ # Options hash passed up to {NRSER::Types::Type} constructor.
198
+ #
199
+ # @return [NRSER::Types::Attributes]
200
+ # Type satisfied by a `#length` attribute between the `:min` and `:max`
201
+ # (inclusive).
202
+ #
203
+ def_type :Length,
204
+ # TODO This would need special attention if we ever started using the
205
+ # `parameterize` data for anything...
206
+ parameterize: :args,
207
+ &->( *args ) do
208
+ bounds = {}
209
+ options = if args[1].is_a?( Hash ) then args[1] else {} end
210
+
211
+ case args[0]
212
+ when ::Integer
213
+ # It's just a length
214
+ return attrs(
215
+ { length: is( non_neg_int.check!( args[0] ) ) },
216
+ **options
217
+ )
218
+
219
+ bounds[:min] = bounds[:max] = non_neg_int.check args[0]
220
+
221
+ when ::Hash
222
+ # It's keyword args
223
+ kwds = args[0].sym_keys
224
+
225
+ # Pull any :min and :max in the keywords
226
+ bounds[:min] = kwds.delete :min
227
+ bounds[:max] = kwds.delete :max
228
+
229
+ # But override with :length if we got it
230
+ if length = kwds.delete(:length)
231
+ bounds[:min] = length
232
+ bounds[:max] = length
233
+ end
234
+
235
+ # (Reverse) merge anything else into the options (options hash values
236
+ # take precedence)
237
+ options = kwds.merge options
238
+
239
+ else
240
+ raise ArgumentError, <<-END.squish
241
+ arg must be positive integer or option hash, found:
242
+ #{ args[0].inspect } of type #{ args[0].class }
243
+ END
244
+
245
+ end
246
+
247
+ bounded_type = self.Bounded bounds
248
+
249
+ length_type = if !bounded_type.min.nil? && bounded_type.min >= 0
250
+ # We don't need the non-neg check
251
+ bounded_type
252
+ else
253
+ # We do need the non-neg check
254
+ intersection(non_neg_int, bounded_type)
255
+ end
256
+
257
+ options[:name] ||= "Length<#{ bounded_type.name }>"
258
+
259
+ self.Attributes({ length: length_type }, options)
260
+ end # .Length
261
+
262
+ # @!endgroup Attributes Type Factories # *************************************
263
+
264
+
265
+ # /Namespace
266
+ # ========================================================================
267
+
268
+ end # module Types
269
+ end # module NRSER
@@ -1,6 +1,12 @@
1
1
  # encoding: UTF-8
2
2
  # frozen_string_literal: true
3
3
 
4
+ # Requirements
5
+ # ========================================================================
6
+
7
+ # Project / Package
8
+ # ------------------------------------------------------------------------
9
+
4
10
  # Need truthy and falsy parse values
5
11
  require 'nrser/functions/object/truthy'
6
12
 
@@ -9,100 +15,145 @@ require_relative './is'
9
15
  require_relative './combinators'
10
16
 
11
17
 
12
- module NRSER::Types
13
-
14
- # Abstract base class for {TrueType} and {FalseType}.
15
- #
16
- class BooleanType < Is
17
-
18
- # Instantiate a new `BooleanType`.
19
- #
20
- def initialize value, **options
21
- # Check it's a boolean
22
- unless true.equal?( value ) || false.equal?( value )
23
- raise ArgumentError.new \
24
- "`value` arg must be `true` or `false`, found #{ value.inspect }"
25
- end
26
-
27
- super value, **options
28
- end # #initialize
29
-
30
-
31
- protected
32
- # ========================================================================
33
-
34
- def custom_from_s string
35
- return value if self::STRINGS.include?( string.downcase )
36
-
37
- raise NRSER::Types::FromStringError.new \
38
- type: self,
39
- string: string,
40
- binding: binding,
41
- details: -> {
42
- <<~END
43
- Down-cased `string` must be one of:
44
-
45
- <%= self::STRINGS.to_a %>
46
- END
47
- }
48
- end
49
-
50
- public # end protected *****************************************************
51
-
52
- end # class TrueType
53
-
18
+ # Namespace
19
+ # ========================================================================
20
+
21
+ module NRSER
22
+ module Types
23
+
24
+
25
+ # Definitions
26
+ # ========================================================================
27
+
28
+ # Abstract base class for {True} and {False}.
29
+ #
30
+ class Boolean < Is
54
31
 
55
- # A type for only the `true`.
56
- #
57
- # Provides a {#custom_from_s} to load from CLI options and ENV var-like
58
- # string values.
32
+ # Instantiate a new `Boolean`.
59
33
  #
60
- class TrueType < BooleanType
61
-
62
- STRINGS = NRSER::TRUTHY_STRINGS
34
+ def initialize value, **options
35
+ # Check it's a boolean
36
+ unless true.equal?( value ) || false.equal?( value )
37
+ raise ArgumentError.new \
38
+ "`value` arg must be `true` or `false`, found #{ value.inspect }"
39
+ end
63
40
 
64
- # Instantiate a new `TrueType`.
65
- #
66
- def initialize **options
67
- super true, **options
68
- end # #initialize
69
-
70
- end # class TrueType
41
+ super value, **options
42
+ end # #initialize
71
43
 
72
44
 
73
- # A type for only `false`.
74
- #
75
- # Provides a {#custom_from_s} to load from CLI options and ENV var-like
76
- # string values.
77
- #
78
- class FalseType < BooleanType
79
-
80
- STRINGS = NRSER::FALSY_STRINGS
45
+ protected
46
+ # ========================================================================
81
47
 
82
- # Instantiate a new `TrueType`.
83
- #
84
- def initialize **options
85
- super false, **options
86
- end # #initialize
48
+ def custom_from_s string
49
+ return value if self::STRINGS.include?( string.downcase )
50
+
51
+ raise NRSER::Types::FromStringError.new \
52
+ type: self,
53
+ string: string,
54
+ binding: binding,
55
+ details: -> {
56
+ <<~END
57
+ Down-cased `string` must be one of:
58
+
59
+ <%= self::STRINGS.to_a %>
60
+ END
61
+ }
62
+ end
87
63
 
88
- end # class FalseType
64
+ public # end protected *****************************************************
89
65
 
66
+ end # class Boolean
67
+
68
+
69
+ # @!group Boolean Type Factories
70
+ # ----------------------------------------------------------------------------
71
+
72
+ # A type for only the `true`.
73
+ #
74
+ # Provides a {#custom_from_s} to load from CLI options and ENV var-like
75
+ # string values.
76
+ #
77
+ class True < Boolean
90
78
 
91
- def_factory :true do |**options|
92
- TrueType.new **options
93
- end
79
+ STRINGS = NRSER::TRUTHY_STRINGS
94
80
 
81
+ # Instantiate a new `True` type.
82
+ #
83
+ def initialize **options
84
+ super true, **options
85
+ end # #initialize
95
86
 
96
- def_factory :false do |**options|
97
- FalseType.new **options
98
- end
87
+ end # class True
88
+
89
+
90
+ # A type for only `false`.
91
+ #
92
+ # Provides a {#custom_from_s} to load from CLI options and ENV var-like
93
+ # string values.
94
+ #
95
+ class False < Boolean
99
96
 
97
+ STRINGS = NRSER::FALSY_STRINGS
100
98
 
101
- def_factory(
102
- :bool,
103
- aliases: [ :boolean ],
104
- ) do |**options|
105
- union self.true, self.false, **options
106
- end
99
+ # Instantiate a new `True` type.
100
+ #
101
+ def initialize **options
102
+ super false, **options
103
+ end # #initialize
107
104
 
108
- end # NRSER::Types
105
+ end # class FalseType
106
+
107
+
108
+ #@!method self.True **options
109
+ # A type whose only member is `true` and loads from common CLI and ENV
110
+ # var string representations (see {True} and {True::STRINGS}).
111
+ #
112
+ # @param [Hash] options
113
+ # Passed to {Type#initialize}.
114
+ #
115
+ # @return [Type]
116
+ #
117
+ def_type :True,
118
+ &->( **options ) do
119
+ True.new **options
120
+ end
121
+
122
+
123
+ #@!method self.False **options
124
+ # A type whose only member is `false` and loads from common CLI and ENV
125
+ # var string representations (see {False} and {False::STRINGS}).
126
+ #
127
+ # @param [Hash] options
128
+ # Passed to {Type#initialize}.
129
+ #
130
+ # @return [Type]
131
+ #
132
+ def_type :False,
133
+ &->( **options ) do
134
+ False.new **options
135
+ end # .False
136
+
137
+
138
+ #@!method self.Boolean **options
139
+ # {.True} or {.False}.
140
+ #
141
+ # @param [Hash] options
142
+ # Passed to {Type#initialize}.
143
+ #
144
+ # @return [Type]
145
+ #
146
+ def_type :Boolean,
147
+ aliases: [ :bool ],
148
+ &->( **options ) do
149
+ union self.True, self.False, **options
150
+ end # .Boolean
151
+
152
+ # @!endgroup Boolean Type Factories # ****************************************
153
+
154
+
155
+ # /Namespace
156
+ # ========================================================================
157
+
158
+ end # module Types
159
+ end # module NRSER