nrser 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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