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.
Files changed (188) hide show
  1. checksums.yaml +4 -4
  2. data/lib/nrser/char/alpha_numeric_sub.rb +1 -2
  3. data/lib/nrser/char.rb +0 -6
  4. data/lib/nrser/core_ext/array.rb +120 -0
  5. data/lib/nrser/core_ext/binding.rb +44 -0
  6. data/lib/nrser/{functions → core_ext}/enumerable/find_map.rb +18 -15
  7. data/lib/nrser/{ext → core_ext}/enumerable.rb +10 -24
  8. data/lib/nrser/core_ext/exception.rb +30 -0
  9. data/lib/nrser/core_ext/hash/extract_values_at.rb +49 -0
  10. data/lib/nrser/core_ext/hash/transform_values_with_keys.rb +24 -0
  11. data/lib/nrser/core_ext/hash.rb +50 -0
  12. data/lib/nrser/core_ext/module/method_objects.rb +96 -0
  13. data/lib/nrser/core_ext/module/names.rb +69 -0
  14. data/lib/nrser/core_ext/module/source_locations.rb +214 -0
  15. data/lib/nrser/core_ext/module.rb +2 -0
  16. data/lib/nrser/core_ext/object/lazy_var.rb +31 -0
  17. data/lib/nrser/core_ext/object.rb +46 -0
  18. data/lib/nrser/core_ext/open_struct.rb +6 -0
  19. data/lib/nrser/{ext → core_ext}/pathname.rb +8 -5
  20. data/lib/nrser/{ext → core_ext}/string.rb +6 -12
  21. data/lib/nrser/core_ext/symbol.rb +13 -0
  22. data/lib/nrser/core_ext/time.rb +46 -0
  23. data/lib/nrser/core_ext.rb +13 -0
  24. data/lib/nrser/errors/abstract_method_error.rb +150 -0
  25. data/lib/nrser/errors/argument_error.rb +42 -0
  26. data/lib/nrser/errors/nicer_error.rb +298 -72
  27. data/lib/nrser/errors/type_error.rb +46 -0
  28. data/lib/nrser/errors.rb +4 -53
  29. data/lib/nrser/ext/tree.rb +3 -0
  30. data/lib/nrser/functions/enumerable/associate.rb +6 -9
  31. data/lib/nrser/functions/enumerable/include_slice.rb +2 -3
  32. data/lib/nrser/functions/enumerable.rb +1 -3
  33. data/lib/nrser/functions/exception.rb +1 -1
  34. data/lib/nrser/functions/hash.rb +0 -6
  35. data/lib/nrser/functions/merge_by.rb +2 -2
  36. data/lib/nrser/functions/module/method_objects.rb +77 -0
  37. data/lib/nrser/functions/module.rb +1 -2
  38. data/lib/nrser/functions/open_struct.rb +25 -35
  39. data/lib/nrser/functions/proc.rb +1 -6
  40. data/lib/nrser/functions/string/looks_like.rb +32 -1
  41. data/lib/nrser/functions/string.rb +1 -40
  42. data/lib/nrser/functions/text/lines.rb +2 -1
  43. data/lib/nrser/functions.rb +0 -1
  44. data/lib/nrser/graph/tsorter.rb +41 -0
  45. data/lib/nrser/labs/core_ext/binding.rb +37 -0
  46. data/lib/nrser/labs/stash.rb +372 -0
  47. data/lib/nrser/{logging → log}/appender/sync.rb +3 -3
  48. data/lib/nrser/log/appender.rb +3 -0
  49. data/lib/nrser/{logging → log}/formatters/color.rb +47 -20
  50. data/lib/nrser/log/formatters/mixin.rb +270 -0
  51. data/lib/nrser/{logging → log}/formatters.rb +0 -0
  52. data/lib/nrser/log/logger.rb +229 -0
  53. data/lib/nrser/log/mixin.rb +56 -0
  54. data/lib/nrser/log.rb +723 -0
  55. data/lib/nrser/message.rb +24 -3
  56. data/lib/nrser/meta/source/location.rb +158 -0
  57. data/lib/nrser/meta.rb +1 -1
  58. data/lib/nrser/props/class_methods.rb +118 -0
  59. data/lib/nrser/props/immutable/hash.rb +111 -0
  60. data/lib/nrser/props/immutable/hash_variable.rb +82 -0
  61. data/lib/nrser/props/immutable/instance_variables.rb +48 -0
  62. data/lib/nrser/props/immutable/vector.rb +107 -0
  63. data/lib/nrser/props/instance_methods.rb +184 -0
  64. data/lib/nrser/props/metadata.rb +359 -0
  65. data/lib/nrser/props/mutable/instance_variables.rb +60 -0
  66. data/lib/nrser/props/mutable/stash.rb +199 -0
  67. data/lib/nrser/{meta/props → props}/prop.rb +217 -112
  68. data/lib/nrser/props/storage/instance_variable.rb +85 -0
  69. data/lib/nrser/props/storage/instance_variables.rb +67 -0
  70. data/lib/nrser/props/storage/key.rb +88 -0
  71. data/lib/nrser/props.rb +9 -0
  72. data/lib/nrser/refinements/sugar.rb +41 -0
  73. data/lib/nrser/refinements/types.rb +2 -2
  74. data/lib/nrser/refinements.rb +14 -16
  75. data/lib/nrser/rspex/example_group/describe_attribute.rb +24 -0
  76. data/lib/nrser/rspex/example_group/describe_called_with.rb +1 -6
  77. data/lib/nrser/rspex/example_group/{describe_use_case.rb → describe_case.rb} +6 -3
  78. data/lib/nrser/rspex/example_group/describe_class.rb +1 -0
  79. data/lib/nrser/rspex/example_group/describe_group.rb +29 -0
  80. data/lib/nrser/rspex/example_group/describe_instance_method.rb +2 -2
  81. data/lib/nrser/rspex/example_group/describe_message.rb +35 -0
  82. data/lib/nrser/rspex/example_group/describe_method.rb +23 -2
  83. data/lib/nrser/rspex/example_group/describe_module.rb +19 -0
  84. data/lib/nrser/rspex/example_group/describe_response_to.rb +32 -0
  85. data/lib/nrser/rspex/example_group/describe_section.rb +38 -0
  86. data/lib/nrser/rspex/example_group/describe_sent_to.rb +52 -0
  87. data/lib/nrser/rspex/example_group/describe_source_file.rb +49 -0
  88. data/lib/nrser/rspex/example_group/describe_spec_file.rb +41 -108
  89. data/lib/nrser/rspex/example_group/describe_when.rb +14 -7
  90. data/lib/nrser/rspex/example_group/describe_x.rb +39 -12
  91. data/lib/nrser/rspex/example_group/overrides.rb +66 -0
  92. data/lib/nrser/rspex/example_group.rb +20 -252
  93. data/lib/nrser/rspex/format.rb +83 -17
  94. data/lib/nrser/rspex.rb +4 -34
  95. data/lib/nrser/sugar/method_missing_forwarder.rb +50 -0
  96. data/lib/nrser/{env → sys/env}/path.rb +1 -2
  97. data/lib/nrser/{env.rb → sys/env.rb} +2 -1
  98. data/lib/nrser/sys.rb +5 -0
  99. data/lib/nrser/types/any.rb +36 -7
  100. data/lib/nrser/types/{array.rb → arrays.rb} +32 -81
  101. data/lib/nrser/types/attrs.rb +68 -15
  102. data/lib/nrser/types/booleans.rb +95 -34
  103. data/lib/nrser/types/bounded.rb +12 -10
  104. data/lib/nrser/types/combinators.rb +74 -37
  105. data/lib/nrser/types/errors/check_error.rb +86 -0
  106. data/lib/nrser/types/errors/from_string_error.rb +82 -0
  107. data/lib/nrser/types/factory.rb +91 -0
  108. data/lib/nrser/types/hashes.rb +171 -26
  109. data/lib/nrser/types/in.rb +25 -12
  110. data/lib/nrser/types/is.rb +50 -18
  111. data/lib/nrser/types/is_a.rb +52 -33
  112. data/lib/nrser/types/labels.rb +6 -33
  113. data/lib/nrser/types/maybe.rb +12 -4
  114. data/lib/nrser/types/nil.rb +24 -4
  115. data/lib/nrser/types/not.rb +6 -16
  116. data/lib/nrser/types/numbers.rb +94 -57
  117. data/lib/nrser/types/pairs.rb +57 -57
  118. data/lib/nrser/types/paths.rb +112 -133
  119. data/lib/nrser/types/responds.rb +64 -74
  120. data/lib/nrser/types/shape.rb +29 -24
  121. data/lib/nrser/types/strings.rb +25 -17
  122. data/lib/nrser/types/symbols.rb +19 -17
  123. data/lib/nrser/types/trees.rb +18 -70
  124. data/lib/nrser/types/tuples.rb +36 -40
  125. data/lib/nrser/types/type.rb +342 -91
  126. data/lib/nrser/types/when.rb +40 -18
  127. data/lib/nrser/types/where.rb +94 -9
  128. data/lib/nrser/types.rb +72 -63
  129. data/lib/nrser/version.rb +1 -1
  130. data/lib/nrser.rb +18 -18
  131. data/spec/lib/nrser/{functions/binding/template_spec.rb → core_ext/binding/erb_spec.rb} +5 -5
  132. data/spec/lib/nrser/{functions → core_ext}/enumerable/find_map_spec.rb +8 -6
  133. data/spec/lib/nrser/{refinements → core_ext}/hash_spec.rb +9 -22
  134. data/spec/lib/nrser/errors/abstract_method_error_spec.rb +12 -5
  135. data/spec/lib/nrser/functions/enumerable/{to_h_by_spec.rb → associate_spec.rb} +1 -1
  136. data/spec/lib/nrser/functions/merge_by_spec.rb +1 -1
  137. data/spec/lib/nrser/functions/tree/each_branch_spec.rb +3 -3
  138. data/spec/lib/nrser/functions/tree/transform_spec.rb +14 -15
  139. data/spec/lib/nrser/gem_ext/hamster/json_spec.rb +4 -0
  140. data/spec/lib/nrser/meta/source/location_spec.rb +86 -0
  141. data/spec/lib/nrser/props/immutable/hash_spec.rb +297 -0
  142. data/spec/lib/nrser/props/immutable/vector_spec.rb +296 -0
  143. data/spec/lib/nrser/{meta/props_spec.rb → props/original_props_spec.rb} +11 -16
  144. data/spec/lib/nrser/{meta/props → props}/to_and_from_data_spec.rb +10 -8
  145. data/spec/lib/nrser/refinements/array_spec.rb +2 -15
  146. data/spec/lib/nrser/refinements/erb_spec.rb +5 -7
  147. data/spec/lib/nrser/refinements/set_spec.rb +2 -15
  148. data/spec/lib/nrser/{env → sys/env}/path/insert_spec.rb +4 -2
  149. data/spec/lib/nrser/{env → sys/env}/path_spec.rb +4 -2
  150. data/spec/lib/nrser/types/array_spec.rb +8 -8
  151. data/spec/lib/nrser/types/paths_spec.rb +15 -18
  152. data/spec/spec_helper.rb +4 -0
  153. metadata +109 -69
  154. data/lib/nrser/ext/binding.rb +0 -36
  155. data/lib/nrser/ext/module.rb +0 -62
  156. data/lib/nrser/ext.rb +0 -8
  157. data/lib/nrser/functions/binding.rb +0 -76
  158. data/lib/nrser/functions/enumerable/map_keys.rb +0 -0
  159. data/lib/nrser/functions/enumerable/map_values.rb +0 -94
  160. data/lib/nrser/functions/hash/deep_merge.rb +0 -57
  161. data/lib/nrser/functions/hash/except_keys.rb +0 -44
  162. data/lib/nrser/functions/hash/slice_keys.rb +0 -43
  163. data/lib/nrser/functions/hash/stringify_keys.rb +0 -55
  164. data/lib/nrser/functions/hash/symbolize_keys.rb +0 -57
  165. data/lib/nrser/functions/hash/transform_keys.rb +0 -140
  166. data/lib/nrser/functions/module/methods.rb +0 -206
  167. data/lib/nrser/functions/module/source_locations.rb +0 -213
  168. data/lib/nrser/logging/appender.rb +0 -3
  169. data/lib/nrser/logging.rb +0 -353
  170. data/lib/nrser/meta/props/base.rb +0 -31
  171. data/lib/nrser/meta/props.rb +0 -357
  172. data/lib/nrser/refinements/array.rb +0 -133
  173. data/lib/nrser/refinements/binding.rb +0 -6
  174. data/lib/nrser/refinements/enumerator.rb +0 -5
  175. data/lib/nrser/refinements/exception.rb +0 -35
  176. data/lib/nrser/refinements/hash.rb +0 -150
  177. data/lib/nrser/refinements/module.rb +0 -5
  178. data/lib/nrser/refinements/object.rb +0 -42
  179. data/lib/nrser/refinements/open_struct.rb +0 -28
  180. data/lib/nrser/refinements/pathname.rb +0 -5
  181. data/lib/nrser/refinements/set.rb +0 -5
  182. data/lib/nrser/refinements/string.rb +0 -5
  183. data/lib/nrser/refinements/symbol.rb +0 -20
  184. data/lib/nrser/rspex/described.rb +0 -99
  185. data/spec/design/mapping_spec.rb +0 -42
  186. data/spec/lib/nrser/functions/hash_spec.rb +0 -41
  187. data/spec/lib/nrser/functions/string/truncate_spec.rb +0 -11
  188. data/spec/lib/nrser/refinements/truncate_spec.rb +0 -10
@@ -1,29 +1,13 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
1
4
  # Requirements
2
5
  # =======================================================================
3
6
 
4
- # Stdlib
5
- # -----------------------------------------------------------------------
6
-
7
- # Deps
8
- # -----------------------------------------------------------------------
9
-
10
7
  # Project / Package
11
8
  # -----------------------------------------------------------------------
12
- require 'nrser/types/type'
13
- require 'nrser/types/is_a'
14
-
15
-
16
- # Refinements
17
- # =======================================================================
18
-
19
- require 'nrser/refinements'
20
- using NRSER
21
9
 
22
-
23
- # Declarations
24
- # =======================================================================
25
-
26
- module NRSER; end
10
+ require_relative './is_a'
27
11
 
28
12
 
29
13
  # Definitions
@@ -36,25 +20,16 @@ module NRSER::Types
36
20
  # does is not recognized as an encoding format (as of writing, JSON is
37
21
  # the only format we attempt to detect).
38
22
  #
39
- # Splits
23
+ # Splits
40
24
  DEFAULT_SPLIT_WITH = /\,\s*/m
41
25
 
42
- attr_reader :item_type
43
-
44
26
  def initialize split_with: DEFAULT_SPLIT_WITH, **options
45
27
  super ::Array, **options
46
28
  @split_with = split_with
47
29
  end
48
30
 
49
31
 
50
- def default_name
51
- self.class.short_name
52
- end
53
-
54
-
55
- def item_type
56
- NRSER::Types.any
57
- end
32
+ def item_type; NRSER::Types.any; end
58
33
 
59
34
 
60
35
  # Called on an array of string items that have been split
@@ -73,40 +48,29 @@ module NRSER::Types
73
48
  end
74
49
 
75
50
 
76
- def from_s s
77
- # Use custom {@from_s} if we have one.
78
- return check( @from_s.call s ) unless @from_s.nil?
79
-
51
+ def custom_from_s string
80
52
  # Does it looks like a JSON array?
81
- if NRSER.looks_like_json_array? s
53
+ if NRSER.looks_like_json_array? string
82
54
  # It does! Load it
83
55
  begin
84
- array = JSON.load( s )
56
+ return JSON.load( string )
85
57
  rescue
86
58
  # pass - if we failed to load as JSON, it may just not be JSON, and
87
59
  # we can try the split approach below.
88
- else
89
- # Check value and return. If we fail the check here let the error
90
- # bubble up
91
- return check array
92
60
  end
93
61
  end
94
62
 
95
63
  # Split it with the splitter and check that
96
- check items_from_strings( s.split( @split_with ) )
64
+ items_from_strings( string.split( @split_with ) )
97
65
  end
98
66
 
99
67
  end # ArrayType
100
68
 
101
69
 
102
- # Static instance that is satisfied by anything that is an {Array}.
103
- ARRAY = ArrayType.new.freeze
104
-
105
-
106
70
  # Type for arrays where every entry satisfies a specific type.
107
71
  #
108
72
  # Broken out from {ArrayType} so that {TupleType} can inherit from
109
- # {ArrayType} and get share it's string handling functionality without
73
+ # {ArrayType} and get share it's string handling functionality without
110
74
  # receiving the entry type stuff (which it handles differently).
111
75
  #
112
76
  class ArrayOfType < ArrayType
@@ -135,12 +99,12 @@ module NRSER::Types
135
99
  # Instance Methods
136
100
  # ======================================================================
137
101
 
138
- def default_name
139
- "#{ super() }<#{ @item_type }>"
102
+ def explain
103
+ "#{ super() }<#{ item_type.explain }>"
140
104
  end
141
105
 
142
106
 
143
- def test value
107
+ def test? value
144
108
  # Check the super method first, which will test if `value` is an Array
145
109
  # instance, and return `false` if it's not.
146
110
  return false unless super( value )
@@ -156,7 +120,7 @@ module NRSER::Types
156
120
  # @return [Boolean]
157
121
  #
158
122
  def has_from_s?
159
- @item_type.has_from_s?
123
+ @from_s || @item_type.has_from_s?
160
124
  end
161
125
 
162
126
 
@@ -168,7 +132,7 @@ module NRSER::Types
168
132
  # @todo
169
133
  # I'm not even sure why this is implemented... was it used somewhere?
170
134
  #
171
- # It doesn't seems too well thought out... seems like the reality of
135
+ # It doesn't seems too well thought out... seems like the reality of
172
136
  # comparing types is much more complicated?
173
137
  #
174
138
  def == other
@@ -180,35 +144,22 @@ module NRSER::Types
180
144
  end # class ArrayOfType
181
145
 
182
146
 
183
- # Eigenclass (Singleton Class)
184
- # ========================================================================
147
+ # {NRSER::Types::ArrayType} / {NRSER::Types::ArrayOfType} factory function.
185
148
  #
186
- class << self
187
-
188
- # @!group Type Factory Functions
189
-
190
- # {NRSER::Types::ArrayType} / {NRSER::Types::ArrayOfType} factory function.
191
- #
192
- # @param [Type | Object] item_type
193
- # Optional type of items.
194
- #
195
- # @return [NRSER::Types::Type]
196
- #
197
- def array item_type = any, **options
198
- if item_type == any
199
- if options.empty?
200
- ARRAY
201
- else
202
- ArrayType.new **options
203
- end
204
- else
205
- ArrayOfType.new item_type, **options
206
- end
207
- end # #array
208
-
209
- alias_method :list, :array
210
-
211
- end # class << self (Eigenclass)
212
-
149
+ # @param [Type | Object] item_type
150
+ # Optional type of items.
151
+ #
152
+ # @return [NRSER::Types::Type]
153
+ #
154
+ def_factory(
155
+ :array,
156
+ aliases: [:list],
157
+ ) do |item_type = any, **options|
158
+ if item_type == any
159
+ ArrayType.new **options
160
+ else
161
+ ArrayOfType.new item_type, **options
162
+ end
163
+ end # #array
213
164
 
214
165
  end # NRSER::Types
@@ -1,11 +1,37 @@
1
- require 'nrser/refinements'
2
- require 'nrser/types/type'
3
- require 'nrser/types/combinators'
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
4
3
 
5
- using NRSER
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
+
17
+
18
+ # Definitions
19
+ # ========================================================================
6
20
 
7
21
  module NRSER::Types
8
- class Attrs < NRSER::Types::Type
22
+
23
+ # Specify types for value attributes.
24
+ #
25
+ class AttrsType < NRSER::Types::Type
26
+
27
+ # Construct an `AttrsType`.
28
+ #
29
+ # @param [Hash<Symbol, TYPE>] attrs
30
+ # Map of attribute names to their types (`TYPE` values will be passed
31
+ # through {NRSER::Types.make} to get a type instance).
32
+ #
33
+ # May not be empty.
34
+ #
9
35
  def initialize attrs, **options
10
36
  super **options
11
37
 
@@ -14,12 +40,15 @@ module NRSER::Types
14
40
  "Must provide at least one attribute name/type pair"
15
41
  end
16
42
 
17
- @attrs = NRSER.map_values(attrs) { |name, type|
18
- NRSER::Types.make type
19
- }
43
+ @attrs = attrs.transform_values &NRSER::Types.maker
20
44
  end
21
45
 
22
- def default_name
46
+
47
+ # @see NRSER::Types::Type#explain
48
+ #
49
+ # @return [String]
50
+ #
51
+ def explain
23
52
  attrs_str = @attrs.map { |name, type|
24
53
  "##{ name }#{ RESPONDS_WITH }#{ type.name }"
25
54
  }.join(', ')
@@ -31,12 +60,19 @@ module NRSER::Types
31
60
  end
32
61
  end
33
62
 
34
- def test value
63
+
64
+ # @see NRSER::Types::Type#test
65
+ #
66
+ # @return [Boolean]
67
+ #
68
+ def test? value
35
69
  @attrs.all? { |name, type|
36
- value.respond_to?(name) && type.test(value.method(name).call)
70
+ value.respond_to?( name ) &&
71
+ type.test?( value.method( name ).call )
37
72
  }
38
73
  end
39
- end # Attrs
74
+
75
+ end # AttrsType
40
76
 
41
77
 
42
78
  # @!group Type Factory Functions
@@ -46,8 +82,20 @@ module NRSER::Types
46
82
  # @example Type where first element of an Enumerable is a String
47
83
  # string_first = intersection Enumerable, attrs(first: String)
48
84
  #
49
- def_factory :attrs do |attrs, **options|
50
- Attrs.new attrs, **options
85
+ def_factory :attrs do |*args|
86
+ case args.length
87
+ when 0
88
+ raise NRSER::ArgumentError.new \
89
+ "requires at least one argument"
90
+ when 1
91
+ attrs = args[0]
92
+ options = {}
93
+ when 2
94
+ attrs = args[0]
95
+ options = args[1]
96
+ end
97
+
98
+ AttrsType.new attrs, **options
51
99
  end
52
100
 
53
101
 
@@ -114,11 +162,16 @@ module NRSER::Types
114
162
  case args[0]
115
163
  when ::Integer
116
164
  # It's just a length
165
+ return attrs(
166
+ { length: is( non_neg_int.check!( args[0] ) ) },
167
+ **options
168
+ )
169
+
117
170
  bounds[:min] = bounds[:max] = non_neg_int.check args[0]
118
171
 
119
172
  when ::Hash
120
173
  # It's keyword args
121
- kwds = NRSER.symbolize_keys args[0]
174
+ kwds = args[0].sym_keys
122
175
 
123
176
  # Pull any :min and :max in the keywords
124
177
  bounds[:min] = kwds.delete :min
@@ -1,47 +1,108 @@
1
- require 'nrser/refinements'
2
- require 'nrser/types/type'
3
- require 'nrser/types/is'
4
- require 'nrser/types/combinators'
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ # Need truthy and falsy parse values
5
+ require 'nrser/functions/object/truthy'
6
+
7
+ require_relative './type'
8
+ require_relative './is'
9
+ require_relative './combinators'
5
10
 
6
- using NRSER
7
11
 
8
12
  module NRSER::Types
9
- # booleans
10
- # ========
11
-
12
- TRUE = is true, name: 'true', from_s: ->(string) {
13
- if ['true', 't', '1', 'yes', 'y', 'on'].include? string.downcase
14
- true
15
- else
16
- raise TypeError, "can not convert to true: #{ string.inspect }"
17
- end
18
- }
19
-
20
- def self.true
21
- TRUE
22
- end
23
13
 
24
- FALSE = is false, name: 'false', from_s: ->(string) {
25
- if ['false', 'f', '0', 'no', 'n', 'off'].include? string.downcase
26
- false
27
- else
28
- raise TypeError, "can not convert to true: #{ string.inspect }"
29
- end
30
- }
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
+
54
+
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.
59
+ #
60
+ class TrueType < BooleanType
61
+
62
+ STRINGS = NRSER::TRUTHY_STRINGS
63
+
64
+ # Instantiate a new `TrueType`.
65
+ #
66
+ def initialize **options
67
+ super true, **options
68
+ end # #initialize
69
+
70
+ end # class TrueType
31
71
 
32
- def self.false
33
- FALSE
72
+
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
81
+
82
+ # Instantiate a new `TrueType`.
83
+ #
84
+ def initialize **options
85
+ super false, **options
86
+ end # #initialize
87
+
88
+ end # class FalseType
89
+
90
+
91
+ def_factory :true do |**options|
92
+ TrueType.new **options
34
93
  end
35
94
 
36
- BOOL = union TRUE, FALSE
37
95
 
38
- # true or false
39
- def self.bool
40
- BOOL
96
+ def_factory :false do |**options|
97
+ FalseType.new **options
41
98
  end
42
99
 
43
- def self.boolean
44
- bool
100
+
101
+ def_factory(
102
+ :bool,
103
+ aliases: [ :boolean ],
104
+ ) do |**options|
105
+ union self.true, self.false, **options
45
106
  end
46
107
 
47
108
  end # NRSER::Types
@@ -6,15 +6,17 @@ using NRSER
6
6
  module NRSER::Types
7
7
  class Bounded < NRSER::Types::Type
8
8
 
9
- # @!attribute [r] min
10
- # @return [Number]
11
- # Minimum value.
9
+ # Minimum value.
10
+ #
11
+ # @return [Number]
12
+ #
12
13
  attr_reader :min
13
14
 
14
15
 
15
- # @!attribute [r] max
16
- # @return [Number]
17
- # Minimum value.
16
+ # Minimum value.
17
+ #
18
+ # @return [Number]
19
+ #
18
20
  attr_reader :max
19
21
 
20
22
 
@@ -27,13 +29,13 @@ module NRSER::Types
27
29
  @max = max
28
30
  end
29
31
 
30
- def test value
32
+ def test? value
31
33
  return false if @min && value < @min
32
34
  return false if @max && value > @max
33
35
  true
34
36
  end
35
37
 
36
- def default_name
38
+ def explain
37
39
  attrs_str = ['min', 'max'].map {|name|
38
40
  [name, instance_variable_get("@#{ name }")]
39
41
  }.reject {|name, value|
@@ -42,12 +44,12 @@ module NRSER::Types
42
44
  "#{ name }=#{ value }"
43
45
  }.join(', ')
44
46
 
45
- "#{ self.class.short_name } #{ attrs_str }"
47
+ "#{ self.class.demod_name }<#{ attrs_str }>"
46
48
  end
47
49
 
48
50
  end # Bounded
49
51
 
50
- def self.bounded **options
52
+ def_factory :bounded do |**options|
51
53
  Bounded.new **options
52
54
  end
53
55
 
@@ -1,31 +1,37 @@
1
1
  # encoding: UTF-8
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'nrser/refinements'
5
4
  require 'nrser/types/type'
6
5
 
7
- using NRSER
8
-
9
6
  # base class for Union and Intersection which combine over a set of types.
10
7
  module NRSER::Types
8
+
9
+ # Abstract base class for logically combining types to create new ones.
10
+ #
11
11
  class Combinator < NRSER::Types::Type
12
+
13
+ # The parametrized types, in the order they will be tested.
14
+ #
15
+ # @return [Array<NRSER::Types::Type>]
16
+ #
12
17
  attr_reader :types
13
18
 
14
19
 
15
20
  def initialize *types, **options
16
21
  super **options
17
- @types = types.map {|type| NRSER::Types.make type}
22
+ @types = types.map { |type| NRSER::Types.make type }
18
23
  end
19
24
 
20
25
 
21
- def default_name
26
+ def explain
22
27
  if self.class::JOIN_SYMBOL
23
- NRSER::Types::L_PAREN +
24
- @types.map { |type| type.name }.join( self.class::JOIN_SYMBOL ) +
28
+ NRSER::Types::L_PAREN + # ' ' +
29
+ @types.map { |type| type.explain }.join( self.class::JOIN_SYMBOL ) +
30
+ # ' ' +
25
31
  NRSER::Types::R_PAREN
26
32
  else
27
- "#{ self.class.short_name }<" +
28
- @types.map {|type| type.name }.join(',') +
33
+ "#{ self.class.demod_name }<" +
34
+ @types.map { |type| type.explain }.join( ',' ) +
29
35
  ">"
30
36
  end
31
37
  end
@@ -59,7 +65,7 @@ module NRSER::Types
59
65
  # @raise [TypeError]
60
66
  # See write up above.
61
67
  #
62
- def from_s s
68
+ def custom_from_s s
63
69
  unless @from_s.nil?
64
70
  return check @from_s.call( s )
65
71
  end
@@ -92,10 +98,39 @@ module NRSER::Types
92
98
  # @return [Boolean]
93
99
  #
94
100
  def has_from_s?
95
- super() || @types.any? { |type| type.has_from_s? }
101
+ !@from_s.nil? || @types.any? { |type| type.has_from_s? }
96
102
  end # has_from_s
97
103
 
98
104
 
105
+ def has_from_data?
106
+ @types.any? { |type| type.has_from_data? }
107
+ end
108
+
109
+
110
+ # Overridden to
111
+ def from_data data
112
+ unless has_from_data?
113
+ raise NoMethodError, "#from_data not defined"
114
+ end
115
+
116
+ errors = []
117
+
118
+ types.each do |type|
119
+ if type.has_from_data?
120
+ begin
121
+ return check!( type.from_data data )
122
+ rescue Exception => error
123
+ errors << error
124
+ end
125
+ end
126
+ end
127
+
128
+ raise NRSER::MultipleErrors.new \
129
+ errors,
130
+ headline: "No type successfully loaded data"
131
+ end
132
+
133
+
99
134
  # Overridden to delegate functionality to the combined types:
100
135
  #
101
136
  # A combinator can convert a value to data if *any* of it's types can.
@@ -120,7 +155,7 @@ module NRSER::Types
120
155
  #
121
156
  def to_data value
122
157
  @types.each { |type|
123
- if type.respond_to? :to_data
158
+ if type.has_to_data?
124
159
  return type.to_data value
125
160
  end
126
161
  }
@@ -134,57 +169,59 @@ module NRSER::Types
134
169
  other.class == self.class && other.types == @types
135
170
  )
136
171
  end
137
- end
172
+
173
+ end # class Combinator
174
+
138
175
 
139
176
  class Union < Combinator
140
- JOIN_SYMBOL = ' ⋁ '
177
+ JOIN_SYMBOL = ' | ' # ' ⋁ '
141
178
 
142
- def test value
143
- @types.any? {|type| type.test value}
179
+ def test? value
180
+ @types.any? { |type| type.test value }
144
181
  end
145
- end # Union
182
+ end # class Union
183
+
146
184
 
147
185
  # match any of the types
148
- def self.union *types, **options
149
- NRSER::Types::Union.new *types, **options
186
+ def_factory(
187
+ :union,
188
+ aliases: [:one_of, :or],
189
+ ) do |*types, **options|
190
+ Union.new *types, **options
150
191
  end
151
192
 
152
- singleton_class.send :alias_method, :one_of, :union
153
- singleton_class.send :alias_method, :or, :union
154
193
 
155
194
  class Intersection < Combinator
156
- # JOIN_SYMBOL = ', '
157
- JOIN_SYMBOL = ' ⋀ '
195
+ JOIN_SYMBOL = ' & ' # ' ⋀ '
158
196
 
159
- def test value
160
- @types.all? { |type| type.test value}
197
+ def test? value
198
+ @types.all? { |type| type.test? value }
161
199
  end
162
- end
200
+ end # class Intersection
201
+
163
202
 
164
203
  # match all of the types
165
- def self.intersection *types, **options
204
+ def_factory(
205
+ :intersection,
206
+ aliases: [:all_of, :and],
207
+ ) do |*types, **options|
166
208
  Intersection.new *types, **options
167
209
  end
168
210
 
169
- singleton_class.send :alias_method, :all_of, :intersection
170
- singleton_class.send :alias_method, :and, :intersection
171
-
172
211
 
173
212
  class XOR < Combinator
174
213
  JOIN_SYMBOL = ' ⊕ '
175
214
 
176
- def test value
215
+ def test? value
177
216
  @types.count { |type| type === value } == 1
178
217
  end
179
-
180
- # def default_name
181
- # '⊕'
182
- # "( #{ @types.map { |t| t.name }.join ' ⊕ ' } )"
183
- # end
184
218
  end
185
219
 
186
220
 
187
- def self.xor *types, **options
221
+ def_factory(
222
+ :xor,
223
+ aliases: [ :exclusive_or, :only_one_of ],
224
+ ) do |*types, **options|
188
225
  XOR.new *types, **options
189
226
  end
190
227