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
@@ -20,7 +20,7 @@ module NRSER::RSpex::ExampleGroup
20
20
  #
21
21
  # @param *description (see #describe_x)
22
22
  #
23
- # @param [Hash<Symbol, Object>] **metadata
23
+ # @param [Hash<Symbol, Object>] metadata
24
24
  # RSpec metadata to set for the example group.
25
25
  #
26
26
  # See the `metadata` keyword argument to {#describe_x}.
@@ -38,10 +38,10 @@ module NRSER::RSpex::ExampleGroup
38
38
  # 2. Built description would need to be conditional on what metadata
39
39
  # was found.
40
40
  #
41
- # @param [String] description:
41
+ # @param [String] description
42
42
  # A description of the spec file to add to the RSpec description.
43
43
  #
44
- # @param [String] spec_path:
44
+ # @param [String] spec_path
45
45
  # The path to the spec file (just feed it `__FILE__`).
46
46
  #
47
47
  # Probably possible to extract this somehow without having to provide it?
@@ -85,5 +85,7 @@ module NRSER::RSpex::ExampleGroup
85
85
  &describe_x_body
86
86
 
87
87
  end # #describe_spec_file
88
+
89
+ alias_method :SPEC_FILE, :describe_spec_file
88
90
 
89
91
  end # module NRSER::RSpex::ExampleGroup
@@ -9,7 +9,7 @@ module NRSER::RSpex::ExampleGroup
9
9
  #
10
10
  # @param *description (see #describe_x)
11
11
  #
12
- # @param [Hash<Symbol, Object>] **bindings
12
+ # @param [Hash<Symbol, Object>] bindings
13
13
  # See the `bindings` keyword arg in {#describe_x}.
14
14
  #
15
15
  # @param &body (see #describe_x)
@@ -30,6 +30,7 @@ module NRSER::RSpex::ExampleGroup
30
30
  # Short names (need `_` pre 'cause of `when` Ruby keyword, and suffix fucks
31
31
  # up auto-indent in Atom/VSCode)
32
32
  alias_method :_when, :describe_when
33
+ alias_method :WHEN, :describe_when
33
34
 
34
35
 
35
36
  end # module NRSER::RSpex::ExampleGroup
@@ -11,18 +11,18 @@ module NRSER::RSpex::ExampleGroup
11
11
  # if you want the RSpex functionality but absolutely have to set some
12
12
  # metadata key that we use for something else.
13
13
  #
14
- # @param [Array] *description
14
+ # @param [Array] description
15
15
  # Optional list of elements that compose the custom description.
16
16
  #
17
17
  # Will be passed to {NRSER::RSpex::Format.description} to produce the
18
18
  # string value that is in turn passed to {RSpec.describe}.
19
19
  #
20
- # @param [Symbol] type:
20
+ # @param [Symbol] type
21
21
  # The RSpex "type" of the example group, which is used to determine the
22
22
  # prefix of the final description and is assigned to the `:type` metadata
23
23
  # key.
24
24
  #
25
- # @param [Hash<Symbol, Object>] metadata:
25
+ # @param [Hash<Symbol, Object>] metadata
26
26
  # [RSpec metadata][] to add to the new example group.
27
27
  #
28
28
  # In addition to the keys RSpec will reject, we prohibit `:type` *unless*
@@ -33,7 +33,7 @@ module NRSER::RSpex::ExampleGroup
33
33
  #
34
34
  # [RSpec metadata]: https://relishapp.com/rspec/rspec-core/docs/metadata/user-defined-metadata
35
35
  #
36
- # @param [Hash<Symbol, Object>] bindings:
36
+ # @param [Hash<Symbol, Object>] bindings
37
37
  # Name to value pairs to bind in the new example group.
38
38
  #
39
39
  # All values will be bound at the example group and example levels -
@@ -41,7 +41,7 @@ module NRSER::RSpex::ExampleGroup
41
41
  # group level, while they will be automatically unwrapped at the
42
42
  # example level (as the requisite context is available there).
43
43
  #
44
- # @param [Boolean] bind_subject:
44
+ # @param [Boolean] bind_subject
45
45
  # When `true` (and there is a `subject_block`) bind the `subject` inside
46
46
  # the new example group.
47
47
  #
@@ -114,14 +114,6 @@ module NRSER::RSpex::Format
114
114
  end
115
115
 
116
116
 
117
- # @todo Document format_type method.
118
- #
119
- # @param [type] arg_name
120
- # @todo Add name param description.
121
- #
122
- # @return [return_type]
123
- # @todo Document return value.
124
- #
125
117
  def self.prepend_type type, description
126
118
  return description if type.nil?
127
119
 
@@ -160,13 +152,6 @@ module NRSER::RSpex::Format
160
152
  end
161
153
 
162
154
 
163
- # @todo Document format method.
164
- #
165
- # @param [type] arg_name
166
- # @todo Add name param description.
167
- #
168
- # @return [String]
169
- #
170
155
  def self.description *parts, type: nil
171
156
  parts.
172
157
  flat_map { |part|
@@ -21,7 +21,7 @@ class NRSER::MethodMissingForwarder < BasicObject
21
21
  # Instantiate a new `NRSER::MethodMissingForwarder` holding the forwarding
22
22
  # block.
23
23
  #
24
- # @param [Proc<(symbol:Symbol, *args, &block)>] &forwarder
24
+ # @param [Proc<(symbol:Symbol, *args, &block)>] forwarder
25
25
  # Block that will receive all calls to {#method_missing}.
26
26
  #
27
27
  def initialize &forwarder
@@ -37,10 +37,10 @@ class NRSER::MethodMissingForwarder < BasicObject
37
37
  # @param [Symbol] symbol
38
38
  # The name of the method that was called.
39
39
  #
40
- # @param [Array] *args
40
+ # @param [Array] args
41
41
  # Any parameters the missing method was called with.
42
42
  #
43
- # @param [Proc?] &block
43
+ # @param [Proc?] block
44
44
  # The block the method was called with, if any.
45
45
  #
46
46
  def method_missing symbol, *args, &block
@@ -92,7 +92,7 @@ class NRSER::Sys::Env::Path
92
92
  # @param [String] path
93
93
  # Path to test against.
94
94
  #
95
- # @param [Array<String | Proc<String=>Boolean> | Regexp>] *patterns
95
+ # @param [Array<String | Proc<String=>Boolean> | Regexp>] patterns
96
96
  # Patterns to test:
97
97
  #
98
98
  # - `String` - test if it and `path` are equal (`==`)
@@ -126,14 +126,6 @@ class NRSER::Sys::Env::Path
126
126
  end # .matches_pattern?
127
127
 
128
128
 
129
- # @todo Document from_env method.
130
- #
131
- # @param [type] arg_name
132
- # @todo Add name param description.
133
- #
134
- # @return [return_type]
135
- # @todo Document return value.
136
- #
137
129
  def self.from_ENV env_key
138
130
  new ENV[env_key.to_s], env_key: env_key
139
131
  end # .from_env
@@ -260,7 +252,7 @@ class NRSER::Sys::Env::Path
260
252
  #
261
253
  # @see http://www.rubydoc.info/gems/hamster/Hamster/Vector#each-instance_method
262
254
  #
263
- # @param [nil | Proc<(String)=>*>] &block
255
+ # @param [nil | Proc<(String)=>*>] block
264
256
  # When present, block will be called once for each string path in this
265
257
  # object. First path is most prominent, down to least last.
266
258
  #
@@ -302,23 +294,5 @@ class NRSER::Sys::Env::Path
302
294
  @value.to_a
303
295
  end
304
296
 
305
- protected
306
- # ========================================================================
307
-
308
- # Internal method to remove paths that have already been normalized.
309
- #
310
- # @param [type] arg_name
311
- # @todo Add name param description.
312
- #
313
- # @return [return_type]
314
- # @todo Document return value.
315
- #
316
- def remove_paths paths
317
- # method body...
318
- end # #remove_paths
319
-
320
-
321
- # end protected
322
-
323
297
 
324
298
  end # class NRSER::Env::Path
data/lib/nrser/types.rb CHANGED
@@ -15,7 +15,7 @@ require 'nrser/log'
15
15
 
16
16
  # Stuff to help you define, test, check and match types in Ruby.
17
17
  #
18
- # {include:file:lib/nrser/types/README.md}
18
+ # Read the documentation {file:lib/nrser/types/README.md here}.
19
19
  #
20
20
  module NRSER::Types
21
21
 
@@ -29,7 +29,10 @@ module NRSER::Types
29
29
  # Mixins
30
30
  # ========================================================================
31
31
 
32
+ # Add `.def_type` to define type factories
32
33
  extend Factory
34
+
35
+ # Add `.logger` and `#logger`.
33
36
  include NRSER::Log::Mixin
34
37
 
35
38
 
@@ -38,8 +41,18 @@ module NRSER::Types
38
41
 
39
42
  L_PAREN = '(' # '❪'
40
43
  R_PAREN = ')' # '❫'
41
- RESPONDS_WITH = '→'
42
- ASSOC = '=>'
44
+ RESPONDS_WITH = '→' # '->'
45
+ ASSOC = '=>' # terrible, don't use: '⇒'
46
+ LEQ = '≤'
47
+ GEQ = '≥'
48
+ COMPLEXES = 'ℂ'
49
+ REALS = 'ℝ'
50
+ INTEGERS = 'ℤ'
51
+ RATIONALS = 'ℚ'
52
+ UNION = '∪'
53
+ AND = '&'
54
+ NOT = '¬' # '~'
55
+ COMPLEMENT = '∖'
43
56
 
44
57
 
45
58
  # Module Methods
@@ -67,11 +80,11 @@ module NRSER::Types
67
80
  #
68
81
  def self.make value
69
82
  if value.nil?
70
- self.nil
83
+ self.Nil
71
84
  elsif value.is_a? NRSER::Types::Type
72
85
  value
73
86
  else
74
- self.when value
87
+ self.When value
75
88
  end
76
89
  end
77
90
 
@@ -104,13 +117,34 @@ module NRSER::Types
104
117
  make( type ).check! value
105
118
  end
106
119
 
107
- # Old name
108
- singleton_class.send :alias_method, :check, :check!
120
+
121
+ # Old bang-less name for {.check!}. We like out bangs around here.
122
+ #
123
+ # @deprecated
124
+ #
125
+ # @param (see .check!)
126
+ # @return (see .check!)
127
+ # @raise (see .check!)
128
+ #
129
+ def self.check value, type
130
+ logger.deprecated \
131
+ method: __method__,
132
+ alternative: "NRSER::Types.check!"
133
+
134
+ check! value, type
135
+ end
109
136
 
110
137
 
111
138
  # Create a {NRSER::Types::Type} from `type` with {.make} and test if
112
139
  # `value` satisfies it.
113
140
  #
141
+ # @param [Object] value
142
+ # Value to test for membership.
143
+ #
144
+ # @param [TYPE] type
145
+ # Type to see if value satisfies. Passed through {.make} to make sure it's
146
+ # a {Type} first.
147
+ #
114
148
  # @return [Boolean]
115
149
  # `true` if `value` satisfies `type`.
116
150
  #
@@ -118,13 +152,29 @@ module NRSER::Types
118
152
  make(type).test value
119
153
  end
120
154
 
155
+
156
+ # Old question-less name for {.test?}. We like our marks around here.
157
+ #
158
+ # @param (see .test?)
159
+ # @return (see .test?)
160
+ # @raise (see .test?)
161
+ #
162
+ def self.test value, type
163
+ logger.deprecated \
164
+ method: __method__,
165
+ alternative: "NRSER::Types.test?"
166
+
167
+ test? value, type
168
+ end # .test
169
+
121
170
  # Old name
122
171
  singleton_class.send :alias_method, :test, :test?
123
172
 
124
173
 
174
+ # My own shitty version of pattern matching!
175
+ #
125
176
  # @todo
126
- # Switch {NRSER::Types.match} to use `===`! Should allow us to avoid
127
- # making types for everything?
177
+ # Doc this crap.
128
178
  #
129
179
  def self.match value, *clauses
130
180
  if clauses.empty?
@@ -213,11 +263,11 @@ require_relative './types/is_a'
213
263
  require_relative './types/where'
214
264
  require_relative './types/combinators'
215
265
  require_relative './types/maybe'
216
- require_relative './types/attrs'
266
+ require_relative './types/attributes'
217
267
  require_relative './types/in'
218
268
 
219
269
  require_relative './types/when'
220
- require_relative './types/any'
270
+ require_relative './types/top'
221
271
  require_relative './types/booleans'
222
272
 
223
273
  # Requires `booleans`
@@ -232,5 +282,6 @@ require_relative './types/hashes'
232
282
  require_relative './types/paths'
233
283
  require_relative './types/tuples'
234
284
  require_relative './types/pairs'
235
- require_relative './types/trees'
285
+ require_relative './types/collections'
236
286
  require_relative './types/shape'
287
+ require_relative './types/selector'
@@ -0,0 +1,76 @@
1
+ About NRSER::Types
2
+ ========================================================================
3
+
4
+ Ah, Neil's Shitty Type System (NSTS).
5
+
6
+ Kinda like [tcomb][], but for for Ruby, and worse.
7
+
8
+ Anyways I needed this because I needed some re-usable way for things to make sure they were in some reasonable state at runtime. And it kind-of works for that so far.
9
+
10
+ [tcomb]: https://github.com/gcanti/tcomb
11
+
12
+
13
+ Structure & Design
14
+ ------------------------------------------------------------------------
15
+
16
+ At the bottom of everything, there are *type classes*... which are Ruby classes
17
+ that descend from {NRSER::Types::Type}. We call instances of these classes
18
+ *types*.
19
+
20
+ Types essentially do one thing: they have a {NRSER::Types::Type#test?} method
21
+ that accepts a single arguments and returns a boolean. If the type returns
22
+ `true` when `#test?` is called with an object, then that object is a member of
23
+ that type. That's it.
24
+
25
+ Some of those classes, like the universal type {NRSER::Types::Top} - of which
26
+ every object is a member ({NRSER::Types::Top#test?} always returns `true`) - are
27
+ essentially singletons, but many type classes parameterize over values that
28
+ instances hold as variables.
29
+
30
+ Types are designed to fundamentally immutable once constructed, through the
31
+ standard practice of storing state in instance variables without write
32
+ functions (of course, use of methods like `#instance_variable_set` will still
33
+ mutate types - please don't do this, since any future caching will likely
34
+ reuse instances).
35
+
36
+ API is basically a collection of module class methods attached to
37
+ {NRSER::Types}, like {NRSER::Types.str} or {NRSER::Types.non_neg_int}.
38
+
39
+
40
+ ### Type Maker Method Names
41
+
42
+ I generally went with "short" type names, IDK, to keep things short, and maybe to conflict a bit less with other common names in Ruby.
43
+
44
+ Some examples:
45
+
46
+ - `str`
47
+ - `bool`
48
+ - `non_neg_int`
49
+
50
+ You get the idea. Many have their longer names added as aliases, which I like... would rather have it "just work" with what you type than have to remember what exactly we chose to call stuff.
51
+
52
+
53
+ ### What to Expect
54
+
55
+ These method should all return {NRSER::Types::Type} instances, though many will use a refined subclass of {NRSER::Types::Type} like {NRSER::Types::Bounded} or whatever.
56
+
57
+ I picked this functional approach over a more I guess standard object-oriented architecture - where every type would be it's own class and you would instantiate them - because it's along the line of how [tcomb][] is designed and I think it works pretty well there. It also provides a lot of flexibility as far as combinators and such: we will return a {NRSER::Types::Type} that meets your needs, making no further contract, which allows us a lot more freedom to muck around in the back end.
58
+
59
+
60
+ ### Them Options
61
+
62
+ The {NRSER::Types} module methods should all accept a `options` hash as the last argument that will eventually find it's way up to {NRSER::Types::Type#initialize}. Many should accept other arguments as it makes sense.
63
+
64
+ In cases where the type maker method wants a keyword hash of it's own, I think I've been separating them out into two arguments, like:
65
+
66
+ def some_type kwds, options = {}
67
+ ...
68
+ end
69
+
70
+ which is a bit of a pain 'cause you gotta use parens if you want to pass options as well as keywords:
71
+
72
+ some_type( {x: 1, y: 3}, name: 'SomeType' )
73
+
74
+ but you don't run into any conflicts between options and keywords or whatever else, and it's nice to just pick a style and stick with it rather than have to do one or two different 'cause of a conflict.
75
+
76
+
@@ -8,161 +8,216 @@
8
8
  # -----------------------------------------------------------------------
9
9
 
10
10
  require_relative './is_a'
11
+ require_relative './top'
12
+
13
+
14
+ # Namespace
15
+ # ========================================================================
16
+
17
+ module NRSER
18
+ module Types
11
19
 
12
20
 
13
21
  # Definitions
14
22
  # =======================================================================
23
+
24
+ # Arrays!
25
+ #
26
+ # @note
27
+ # Construct {ArrayType} types using the {.Array} factory.
28
+ #
29
+ # @todo
30
+ # Just call this Array?!
31
+ #
32
+ # Combine with arrays of a type?!
33
+ #
34
+ class ArrayType < IsA
35
+ # Default value to split strings with in {#from_s} if the string provided
36
+ # does is not recognized as an encoding format (as of writing, JSON is
37
+ # the only format we attempt to detect).
38
+ #
39
+ # Splits
40
+ DEFAULT_SPLIT_WITH = /\,\s*/m
15
41
 
16
- module NRSER::Types
42
+ def initialize split_with: DEFAULT_SPLIT_WITH, **options
43
+ super ::Array, **options
44
+ @split_with = split_with
45
+ end
17
46
 
18
- class ArrayType < IsA
19
- # Default value to split strings with in {#from_s} if the string provided
20
- # does is not recognized as an encoding format (as of writing, JSON is
21
- # the only format we attempt to detect).
22
- #
23
- # Splits
24
- DEFAULT_SPLIT_WITH = /\,\s*/m
25
-
26
- def initialize split_with: DEFAULT_SPLIT_WITH, **options
27
- super ::Array, **options
28
- @split_with = split_with
29
- end
30
-
31
-
32
- def item_type; NRSER::Types.any; end
33
-
34
-
35
- # Called on an array of string items that have been split
36
- # from a single string by {#from_s} to convert each individual item before
37
- # {#check} is called on the value.
38
- #
39
- # {NRSER::Types::ArrayType} implementation is a no-op that just returns
40
- # `items` - this method is in place for subclasses to override.
41
- #
42
- # @param [Array<String>] items
43
- #
44
- # @return [Array]
45
- #
46
- def items_from_strings items
47
- items
48
- end
49
-
50
-
51
- def custom_from_s string
52
- # Does it looks like a JSON array?
53
- if NRSER.looks_like_json_array? string
54
- # It does! Load it
55
- begin
56
- return JSON.load( string )
57
- rescue
58
- # pass - if we failed to load as JSON, it may just not be JSON, and
59
- # we can try the split approach below.
60
- end
61
- end
62
-
63
- # Split it with the splitter and check that
64
- items_from_strings( string.split( @split_with ) )
47
+
48
+ def item_type; NRSER::Types.Top; end
49
+
50
+
51
+ # @!group Display Instance Methods
52
+ # ------------------------------------------------------------------------
53
+
54
+ def default_name
55
+ if item_type == NRSER::Types.Top
56
+ 'Array'
57
+ else
58
+ "Array<#{ item_type.name }>"
65
59
  end
66
-
67
- end # ArrayType
60
+ end
61
+
62
+
63
+ def default_symbolic
64
+ "[#{ item_type.symbolic }]"
65
+ end
66
+
67
+ # @!endgroup Display Instance Methods # ************************************
68
68
 
69
69
 
70
- # Type for arrays where every entry satisfies a specific type.
70
+ # Called on an array of string items that have been split
71
+ # from a single string by {#from_s} to convert each individual item before
72
+ # {#check} is called on the value.
71
73
  #
72
- # Broken out from {ArrayType} so that {TupleType} can inherit from
73
- # {ArrayType} and get share it's string handling functionality without
74
- # receiving the entry type stuff (which it handles differently).
74
+ # {NRSER::Types::ArrayType} implementation is a no-op that just returns
75
+ # `items` - this method is in place for subclasses to override.
75
76
  #
76
- class ArrayOfType < ArrayType
77
-
78
- # Attributes
79
- # ======================================================================
80
-
81
- # Type that all items must satisfy for an array to be a member of this
82
- # type.
83
- #
84
- # @return [NRSER::Types::Type]
85
- #
86
- attr_reader :item_type
87
-
88
-
89
- # Constructor
90
- # ======================================================================
91
-
92
- # Instantiate a new `ArrayOfType`.
93
- def initialize item_type, **options
94
- super **options
95
- @item_type = NRSER::Types.make item_type
96
- end # #initialize
97
-
98
-
99
- # Instance Methods
100
- # ======================================================================
101
-
102
- def explain
103
- "#{ super() }<#{ item_type.explain }>"
104
- end
105
-
106
-
107
- def test? value
108
- # Check the super method first, which will test if `value` is an Array
109
- # instance, and return `false` if it's not.
110
- return false unless super( value )
111
-
112
- # Otherwise test all the items
113
- value.all? &@item_type.method( :test )
114
- end
115
-
116
-
117
- # {ArrayOfType} can convert values from strings if it's {#item_type}
118
- # can convert values from strings.
119
- #
120
- # @return [Boolean]
121
- #
122
- def has_from_s?
123
- @from_s || @item_type.has_from_s?
124
- end
125
-
126
-
127
- def items_from_strings items
128
- items.map &@item_type.method( :from_s )
129
- end
130
-
131
-
132
- # @todo
133
- # I'm not even sure why this is implemented... was it used somewhere?
134
- #
135
- # It doesn't seems too well thought out... seems like the reality of
136
- # comparing types is much more complicated?
137
- #
138
- def == other
139
- equal?(other) || (
140
- other.class == self.class && @item_type == other.item_type
141
- )
77
+ # @param [Array<String>] items
78
+ #
79
+ # @return [Array]
80
+ #
81
+ def items_from_strings items
82
+ items
83
+ end
84
+
85
+
86
+ def custom_from_s string
87
+ # Does it looks like a JSON array?
88
+ if NRSER.looks_like_json_array? string
89
+ # It does! Load it
90
+ begin
91
+ return JSON.load( string )
92
+ rescue
93
+ # pass - if we failed to load as JSON, it may just not be JSON, and
94
+ # we can try the split approach below.
95
+ end
142
96
  end
143
97
 
144
- end # class ArrayOfType
98
+ # Split it with the splitter and check that
99
+ items_from_strings( string.split( @split_with ) )
100
+ end
101
+
102
+ end # ArrayType
103
+
104
+
105
+ # Type for arrays where every entry satisfies a specific type.
106
+ #
107
+ # Broken out from {ArrayType} so that {TupleType} can inherit from
108
+ # {ArrayType} and get share it's string handling functionality without
109
+ # receiving the entry type stuff (which it handles differently).
110
+ #
111
+ class ArrayOfType < ArrayType
145
112
 
113
+ # Attributes
114
+ # ======================================================================
146
115
 
147
- # {NRSER::Types::ArrayType} / {NRSER::Types::ArrayOfType} factory function.
148
- #
149
- # @param [Type | Object] item_type
150
- # Optional type of items.
116
+ # Type that all items must satisfy for an array to be a member of this
117
+ # type.
151
118
  #
152
119
  # @return [NRSER::Types::Type]
120
+ #
121
+ attr_reader :item_type
122
+
123
+
124
+ # Constructor
125
+ # ======================================================================
126
+
127
+ # Instantiate a new `ArrayOfType`.
128
+ def initialize item_type, **options
129
+ super **options
130
+ @item_type = NRSER::Types.make item_type
131
+ end # #initialize
132
+
133
+
134
+ # Instance Methods
135
+ # ======================================================================
136
+
137
+ # @!group Display Instance Methods
138
+ # ------------------------------------------------------------------------
139
+
140
+ def explain
141
+ "Array<#{ item_type.explain }>"
142
+ end
143
+
144
+ # @!endgroup Display Instance Methods # ************************************
145
+
146
+
147
+ def test? value
148
+ # Check the super method first, which will test if `value` is an Array
149
+ # instance, and return `false` if it's not.
150
+ return false unless super( value )
151
+
152
+ # Otherwise test all the items
153
+ value.all? &@item_type.method( :test )
154
+ end
155
+
156
+
157
+ # {ArrayOfType} can convert values from strings if it's {#item_type}
158
+ # can convert values from strings.
153
159
  #
160
+ # @return [Boolean]
161
+ #
162
+ def has_from_s?
163
+ @from_s || @item_type.has_from_s?
164
+ end
165
+
166
+
167
+ def items_from_strings items
168
+ items.map &@item_type.method( :from_s )
169
+ end
170
+
171
+
154
172
  # @todo
155
- # Make `list` into it's own looser interface for "array-like" object API.
173
+ # I'm not even sure why this is implemented... was it used somewhere?
174
+ #
175
+ # It doesn't seems too well thought out... seems like the reality of
176
+ # comparing types is much more complicated?
156
177
  #
157
- def_factory(
158
- :array,
159
- aliases: [:list],
160
- ) do |item_type = any, **options|
161
- if item_type == any
162
- ArrayType.new **options
163
- else
164
- ArrayOfType.new item_type, **options
165
- end
166
- end # #array
178
+ def == other
179
+ equal?(other) || (
180
+ other.class == self.class && @item_type == other.item_type
181
+ )
182
+ end
167
183
 
168
- end # NRSER::Types
184
+ end # class ArrayOfType
185
+
186
+
187
+ # @!group Array Type Factories
188
+ # ----------------------------------------------------------------------------
189
+
190
+ # @!method self.Array item_type = self.Top, **options
191
+ # {NRSER::Types::ArrayType} / {NRSER::Types::ArrayOfType} factory function.
192
+ #
193
+ # @param [Type | Object] item_type
194
+ # Optional type of items. If this is not a {Type}, one will be created from
195
+ # it via {NRSER::Types.make}.
196
+ #
197
+ # @param [Hash] options
198
+ # Passed to {Type#initialize}.
199
+ #
200
+ # @return [NRSER::Types::Type]
201
+ #
202
+ # @todo
203
+ # Make `list` into it's own looser interface for "array-like" object API.
204
+ #
205
+ def_type :Array,
206
+ parameterize: :item_type,
207
+ aliases: [ :list ],
208
+ &->( item_type = self.Top, **options ) do
209
+ if item_type == self.Top
210
+ ArrayType.new **options
211
+ else
212
+ ArrayOfType.new item_type, **options
213
+ end
214
+ end # .Array
215
+
216
+ # @!endgroup Array Type Factories # ******************************************
217
+
218
+
219
+ # /Namespace
220
+ # ========================================================================
221
+
222
+ end # module Types
223
+ end # module NRSER