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
@@ -1,53 +1,116 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ # Requirements
5
+ # ========================================================================
6
+
7
+ # Project / Package
8
+ # ------------------------------------------------------------------------
9
+
1
10
  require 'nrser/types/type'
11
+
12
+
13
+ # Namespace
14
+ # ========================================================================
15
+
16
+ module NRSER
17
+ module Types
18
+
19
+
20
+ # Definitions
21
+ # ========================================================================
22
+
23
+ # Types whose members satisfy a {#min}, {#max} or both (inclusive).
24
+ #
25
+ # @note
26
+ # Construct {Bounded} types using the {.Bounded} factory.
27
+ #
28
+ class Bounded < Type
2
29
 
3
- module NRSER::Types
4
- class Bounded < NRSER::Types::Type
5
-
6
- # Minimum value.
7
- #
8
- # @return [Number]
9
- #
10
- attr_reader :min
11
-
12
-
13
- # Minimum value.
14
- #
15
- # @return [Number]
16
- #
17
- attr_reader :max
18
-
19
-
20
- def initialize min: nil,
21
- max: nil,
22
- **options
23
- super **options
24
-
25
- @min = min
26
- @max = max
27
- end
28
-
29
- def test? value
30
- return false if @min && value < @min
31
- return false if @max && value > @max
32
- true
33
- end
30
+ # Minimum value.
31
+ #
32
+ # @return [Number]
33
+ #
34
+ attr_reader :min
35
+
36
+
37
+ # Minimum value.
38
+ #
39
+ # @return [Number]
40
+ #
41
+ attr_reader :max
42
+
43
+
44
+ def initialize min: nil,
45
+ max: nil,
46
+ **options
47
+ super **options
34
48
 
35
- def explain
36
- attrs_str = ['min', 'max'].map {|name|
37
- [name, instance_variable_get("@#{ name }")]
38
- }.reject {|name, value|
39
- value.nil?
40
- }.map {|name, value|
41
- "#{ name }=#{ value }"
42
- }.join(', ')
43
-
44
- "#{ self.class.demod_name }<#{ attrs_str }>"
49
+ @min = min
50
+ @max = max
51
+ end
52
+
53
+ def test? value
54
+ return false if @min && value < @min
55
+ return false if @max && value > @max
56
+ true
57
+ end
58
+
59
+ def symbolic
60
+ if min
61
+ if max
62
+ # has min and max, use range notation
63
+ "(#{ min.inspect }..#{ max.inspect })"
64
+ else
65
+ # only has min
66
+ "(#{ min.inspect }..)"
67
+ # "{ x : x #{ NRSER::Types::GEQ } #{ min } }"
68
+ end
69
+ else
70
+ # only has max
71
+ "(..#{ max.inspect })"
72
+ # "{ x : x #{ NRSER::Types::LEQ } #{ max } }"
45
73
  end
46
-
47
- end # Bounded
74
+ end
48
75
 
49
- def_factory :bounded do |**options|
50
- Bounded.new **options
76
+ def explain
77
+ attrs_str = ['min', 'max'].map {|name|
78
+ [name, instance_variable_get("@#{ name }")]
79
+ }.reject {|name, value|
80
+ value.nil?
81
+ }.map {|name, value|
82
+ "#{ name }=#{ value }"
83
+ }.join(', ')
84
+
85
+ "#{ self.class.demod_name }<#{ attrs_str }>"
51
86
  end
52
-
53
- end # NRSER::Types
87
+
88
+ end # Bounded
89
+
90
+
91
+ # @!group Bounded Type Factories
92
+ # ----------------------------------------------------------------------------
93
+
94
+ #@!method self.Bounded **options
95
+ # Create a {Bounded} type instance that matches values between `min` and
96
+ # `max` (inclusive).
97
+ #
98
+ # @param [Hash] options
99
+ # Passed to {Type#initialize}.
100
+ #
101
+ # @return [Type]
102
+ #
103
+ def_type :Bounded,
104
+ parameterize: [ :min, :max ],
105
+ &->( min: nil, max: nil, **options ) do
106
+ Bounded.new min: min, max: max, **options
107
+ end # .Bounded
108
+
109
+ # @!endgroup Bounded Type Factories # ****************************************
110
+
111
+
112
+ # /Namespace
113
+ # ========================================================================
114
+
115
+ end # module Types
116
+ end # module NRSER
@@ -0,0 +1,119 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+
5
+ # Requirements
6
+ # =======================================================================
7
+
8
+ # Project / Package
9
+ # -----------------------------------------------------------------------
10
+ require_relative './combinators'
11
+ require_relative './responds'
12
+ require_relative './is_a'
13
+
14
+
15
+ # Namespace
16
+ # ========================================================================
17
+
18
+ module NRSER
19
+ module Types
20
+
21
+
22
+ # Definitions
23
+ # =======================================================================
24
+
25
+ # @!group Collection Type Factories
26
+ # ----------------------------------------------------------------------------
27
+
28
+ #@!method self.Vector **options
29
+ # An "array-like" {Enumerable} that responds to `#each_index` and
30
+ # `#slice` / `#[]`.
31
+ #
32
+ # @param [Hash] options
33
+ # Passed to {Type#initialize}.
34
+ #
35
+ # @return [Type]
36
+ #
37
+ def_type :Vector,
38
+ aliases: [ :array_like ],
39
+ &->( **options ) do
40
+ intersection \
41
+ is_a( Enumerable ),
42
+ respond_to( :each_index ),
43
+ respond_to( :slice ),
44
+ respond_to( :[] ),
45
+ name: name,
46
+ **options
47
+ end # .Vector
48
+
49
+
50
+ #@!method self.Map **options
51
+ # A "hash-like" {Enumerable} that responds to `#each_pair` and `#[]`.
52
+ #
53
+ # @param [Hash] options
54
+ # Passed to {Type#initialize}.
55
+ #
56
+ # @return [Type]
57
+ #
58
+ def_type :Map,
59
+ aliases: [ :hash_like, :assoc ],
60
+ &->( **options ) do
61
+ intersection \
62
+ is_a( Enumerable ),
63
+ respond_to( :each_pair ),
64
+ respond_to( :[] ),
65
+ name: name,
66
+ **options
67
+ end # .Map
68
+
69
+
70
+ #@!method self.Bag **options
71
+ # An {Enumerable} that does **not** respond to `#each_pair`.
72
+ #
73
+ # Meant to encompass {Set}, {Array} and the like *without* {Hash} and other
74
+ # associative containers.
75
+ #
76
+ # Elements may or may not be indexed.
77
+ #
78
+ # @param [Hash] options
79
+ # Passed to {Type#initialize}.
80
+ #
81
+ # @return [Type]
82
+ #
83
+ def_type :Bag,
84
+ &->( **options ) do
85
+ intersection \
86
+ is_a( Enumerable ),
87
+ self.not( respond_to( :each_pair ) ),
88
+ name: name,
89
+ **options
90
+ end # .Bag
91
+
92
+
93
+ #@!method self.Tree **options
94
+ # Either a {.Vector} or {.Map} - {Enumerable} collections with indexed
95
+ # elements that work with the {NRSER} "tree" functions.
96
+ #
97
+ # @param [Hash] options
98
+ # Passed to {Type#initialize}.
99
+ #
100
+ # @return [Type]
101
+ #
102
+ def_type :Tree,
103
+ &->( **options ) do
104
+ union \
105
+ array_like,
106
+ hash_like,
107
+ name: name,
108
+ **options
109
+ end # .Tree
110
+
111
+ # @!endgroup Collection Type Factories # *************************************
112
+
113
+
114
+ # /Namespace
115
+ # ========================================================================
116
+
117
+ end # module Types
118
+ end # module NRSER
119
+
@@ -3,226 +3,313 @@
3
3
 
4
4
  require 'nrser/types/type'
5
5
 
6
- # base class for Union and Intersection which combine over a set of types.
7
- module NRSER::Types
6
+
7
+
8
+ # Namespace
9
+ # ========================================================================
10
+
11
+ module NRSER
12
+ module Types
13
+
14
+
15
+ # Definitions
16
+ # ========================================================================
17
+
18
+ # Abstract base class for logically combining types to create new ones.
19
+ #
20
+ # @see Union
21
+ # @see Intersection
22
+ # @see XOR
23
+ #
24
+ class Combinator < Type
8
25
 
9
- # Abstract base class for logically combining types to create new ones.
26
+ # The parameterized types, in the order they will be tested.
10
27
  #
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
- #
17
- attr_reader :types
18
-
19
-
20
- def initialize *types, **options
21
- super **options
22
- @types = types.map { |type| NRSER::Types.make type }
28
+ # @return [Array<NRSER::Types::Type>]
29
+ #
30
+ attr_reader :types
31
+
32
+
33
+ def initialize *types, **options
34
+ super **options
35
+ @types = types.map { |type| NRSER::Types.make type }.freeze
36
+ end
37
+
38
+
39
+ def string_format method
40
+ NRSER::Types::L_PAREN +
41
+ # ' ' + no spaces
42
+ @types.map { |type| type.send method }.join( self.class::JOIN_SYMBOL ) +
43
+ # ' ' + no spaces
44
+ NRSER::Types::R_PAREN
45
+ end
46
+
47
+
48
+ def default_symbolic
49
+ string_format( :to_s )
50
+ end
51
+
52
+
53
+ def explain
54
+ return string_format( :explain )
55
+ end
56
+
57
+
58
+ # Parse a satisfying value from a {String} or raise a {TypeError}.
59
+ #
60
+ # If this type has it's own `@from_s` that was provided via the `from_s:`
61
+ # keyword at construction, then that and **only** that is **always** used
62
+ # - the type will never try any of the combined types' `#from_s`.
63
+ #
64
+ # It's considered *the* way to parse a string into a value that satisfies
65
+ # the type. If it fails, a {TypeError} will be raised (or any error the
66
+ # `@from_s` proc itself raises before we get to checking it).
67
+ #
68
+ # If the type doesn't have it's own `@from_s`, each of the combined types'
69
+ # `#from_s` will be tried in sequence, and the first value that satisfies
70
+ # the combined type will be returned.
71
+ #
72
+ # This is obviously much less efficient, but provides a nice automatic
73
+ # mechanism for parsing from strings for combined types. If none of the
74
+ # combined types' `#from_s` succeed (or if there are none) a {TypeError}
75
+ # is raised.
76
+ #
77
+ # @param [String] s
78
+ # String to parse.
79
+ #
80
+ # @return [Object]
81
+ # Object that satisfies the type.
82
+ #
83
+ # @raise [TypeError]
84
+ # See write up above.
85
+ #
86
+ def custom_from_s string
87
+ # If we have an explicit `@from_s` then use that and that only.
88
+ unless @from_s.nil?
89
+ return check! @from_s.call( string )
23
90
  end
91
+
92
+ errors_by_type = {}
24
93
 
25
-
26
- def explain
27
- if self.class::JOIN_SYMBOL
28
- NRSER::Types::L_PAREN + # ' ' +
29
- @types.map { |type| type.explain }.join( self.class::JOIN_SYMBOL ) +
30
- # ' ' +
31
- NRSER::Types::R_PAREN
94
+ types.each { |type|
95
+ if type.has_from_s?
96
+ begin
97
+ return check! type.from_s( string )
98
+
99
+ # We want to catch any standard error here so `from_s` implementations
100
+ # can kinda "code without care" and if one fails we will move on to
101
+ # try the next.
102
+ rescue StandardError => error
103
+ errors_by_type[type] = error
104
+ end
32
105
  else
33
- "#{ self.class.demod_name }<" +
34
- @types.map { |type| type.explain }.join( ',' ) +
35
- ">"
106
+ errors_by_type[type] = "Does not {#has_from_s?}"
36
107
  end
37
- end
38
-
39
-
40
- # Parse a satisfying value from a {String} or raise a {TypeError}.
41
- #
42
- # If this type has it's own `@from_s` that was provided via the `from_s:`
43
- # keyword at construction, then that and **only** that is **always** used
44
- # - the type will never try any of the combined types' `#from_s`.
45
- #
46
- # It's considered *the* way to parse a string into a value that satisfies
47
- # the type. If it fails, a {TypeError} will be raised (or any error the
48
- # `@from_s` proc itself raises before we get to checking it).
49
- #
50
- # If the type doesn't have it's own `@from_s`, each of the combined types'
51
- # `#from_s` will be tried in sequence, and the first value that satisfies
52
- # the combined type will be returned.
53
- #
54
- # This is obviously much less efficient, but provides a nice automatic
55
- # mechanism for parsing from strings for combined types. If none of the
56
- # combined types' `#from_s` succeed (or if there are none) a {TypeError}
57
- # is raised.
58
- #
59
- # @param [String] s
60
- # String to parse.
61
- #
62
- # @return [Object]
63
- # Object that satisfies the type.
64
- #
65
- # @raise [TypeError]
66
- # See write up above.
67
- #
68
- def custom_from_s s
69
- unless @from_s.nil?
70
- return check @from_s.call( s )
71
- end
72
-
73
- @types.each { |type|
74
- if type.has_from_s?
75
- begin
76
- return check type.from_s(s)
77
- rescue TypeError => e
78
- # pass
79
- end
80
- end
81
- }
82
-
83
- raise TypeError,
84
- "none of combinator #{ self.to_s } types could convert #{ s.inspect }"
85
- end
86
-
108
+ }
87
109
 
88
- # Overridden to delegate functionality to the combined types.
89
- #
90
- # A combinator may attempt to parse from a string if:
91
- #
92
- # 1. It has it's own `@from_s` provided at construction.
93
- #
94
- # 2. Any of it's combined types can parse from a string.
95
- #
96
- # See {#from_s} for details of how it actually happens.
97
- #
98
- # @return [Boolean]
99
- #
100
- def has_from_s?
101
- !@from_s.nil? || @types.any? { |type| type.has_from_s? }
102
- end # has_from_s
103
-
104
-
105
- def has_from_data?
106
- @types.any? { |type| type.has_from_data? }
110
+ # TODO This should be "nicer"... teach {NRSER::MultipleErrors} about
111
+ # {NRSER::NicerError}?
112
+ raise TypeError.new \
113
+ "none of combinator", self.to_s, "types could convert", string.inspect,
114
+ string: string,
115
+ errors_by_type: errors_by_type
116
+ end
117
+
118
+
119
+ # Overridden to delegate functionality to the combined types.
120
+ #
121
+ # A combinator may attempt to parse from a string if:
122
+ #
123
+ # 1. It has it's own `@from_s` provided at construction.
124
+ #
125
+ # 2. Any of it's combined types can parse from a string.
126
+ #
127
+ # See {#from_s} for details of how it actually happens.
128
+ #
129
+ # @return [Boolean]
130
+ #
131
+ def has_from_s?
132
+ !@from_s.nil? || @types.any? { |type| type.has_from_s? }
133
+ end # has_from_s
134
+
135
+
136
+ def has_from_data?
137
+ @types.any? { |type| type.has_from_data? }
138
+ end
139
+
140
+
141
+ # Overridden to
142
+ def from_data data
143
+ unless has_from_data?
144
+ raise NoMethodError, "#from_data not defined"
107
145
  end
108
146
 
147
+ errors = []
109
148
 
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 StandardError => error
123
- errors << error
124
- end
149
+ types.each do |type|
150
+ if type.has_from_data?
151
+ begin
152
+ return check!( type.from_data data )
153
+ rescue StandardError => error
154
+ errors << error
125
155
  end
126
156
  end
127
-
128
- raise NRSER::MultipleErrors.new \
129
- errors,
130
- headline: "No type successfully loaded data"
131
157
  end
132
158
 
133
-
134
- # Overridden to delegate functionality to the combined types:
135
- #
136
- # A combinator can convert a value to data if *any* of it's types can.
137
- #
138
- # @return [Boolean]
139
- #
140
- def has_to_data?
141
- @types.any? { |type| type.has_to_data? }
142
- end # #has_to_data
143
-
144
-
145
- # Overridden to delegate functionality to the combined types:
146
- #
147
- # The first of the combined types that responds to `#to_data` is used to
148
- # dump the value.
149
- #
150
- # @param [Object] value
151
- # Value of this type (though it is *not* checked).
152
- #
153
- # @return [Object]
154
- # The data representation of the value.
155
- #
156
- def to_data value
157
- @types.each { |type|
158
- if type.has_to_data?
159
- return type.to_data value
160
- end
161
- }
162
-
163
- raise NoMethodError, "#to_data not defined"
164
- end # #to_data
165
-
166
-
167
- def == other
168
- equal?(other) || (
169
- other.class == self.class && other.types == @types
170
- )
171
- end
172
-
173
- end # class Combinator
174
-
175
-
176
- class Union < Combinator
177
- JOIN_SYMBOL = ' | ' # ' ⋁ '
178
-
179
- def test? value
180
- @types.any? { |type| type.test value }
181
- end
182
- end # class Union
159
+ raise NRSER::MultipleErrors.new \
160
+ errors,
161
+ headline: "No type successfully loaded data"
162
+ end
183
163
 
184
164
 
185
- # match any of the types
186
- def_factory(
187
- :union,
188
- aliases: [:one_of, :or],
189
- ) do |*types, **options|
190
- Union.new *types, **options
191
- end
165
+ # Overridden to delegate functionality to the combined types:
166
+ #
167
+ # A combinator can convert a value to data if *any* of it's types can.
168
+ #
169
+ # @return [Boolean]
170
+ #
171
+ def has_to_data?
172
+ @types.any? { |type| type.has_to_data? }
173
+ end # #has_to_data
192
174
 
193
175
 
194
- class Intersection < Combinator
195
- JOIN_SYMBOL = ' & ' # ' ⋀ '
176
+ # Overridden to delegate functionality to the combined types:
177
+ #
178
+ # The first of the combined types that responds to `#to_data` is used to
179
+ # dump the value.
180
+ #
181
+ # @param [Object] value
182
+ # Value of this type (though it is *not* checked).
183
+ #
184
+ # @return [Object]
185
+ # The data representation of the value.
186
+ #
187
+ def to_data value
188
+ @types.each { |type|
189
+ if type.has_to_data?
190
+ return type.to_data value
191
+ end
192
+ }
196
193
 
197
- def test? value
198
- @types.all? { |type| type.test? value }
199
- end
200
- end # class Intersection
194
+ raise NoMethodError, "#to_data not defined"
195
+ end # #to_data
201
196
 
202
197
 
203
- # match all of the types
204
- def_factory(
205
- :intersection,
206
- aliases: [:all_of, :and],
207
- ) do |*types, **options|
208
- Intersection.new *types, **options
198
+ def == other
199
+ equal?(other) || (
200
+ other.class == self.class && other.types == @types
201
+ )
209
202
  end
203
+
204
+ end # class Combinator *****************************************************
205
+
206
+
207
+ # Concrete Implementation Classes
208
+ # ----------------------------------------------------------------------------
209
+
210
+
211
+ # Union combinator. (`union`, `one_of`, `or`, `|`).
212
+ #
213
+ class Union < Combinator
214
+ JOIN_SYMBOL = ' | ' # ' ⋁ '
210
215
 
211
-
212
- class XOR < Combinator
213
- JOIN_SYMBOL = ' ⊕ '
214
-
215
- def test? value
216
- @types.count { |type| type === value } == 1
217
- end
216
+ def test? value
217
+ @types.any? { |type| type.test value }
218
218
  end
219
+ end # class Union
220
+
221
+
222
+ # Intersection combinator (`intersection`, `all_of`, `and`, `&).
223
+ #
224
+ class Intersection < Combinator
225
+ JOIN_SYMBOL = ' & ' # ' ⋀ '
219
226
 
220
-
221
- def_factory(
222
- :xor,
223
- aliases: [ :exclusive_or, :only_one_of ],
224
- ) do |*types, **options|
225
- XOR.new *types, **options
227
+ def test? value
228
+ @types.all? { |type| type.test? value }
226
229
  end
230
+ end # class Intersection
231
+
232
+
233
+ # XOR combinator - Exclusive Or (`xor`).
234
+ #
235
+ class XOR < Combinator
236
+ JOIN_SYMBOL = ' ⊕ '
227
237
 
228
- end # NRSER::Types
238
+ def test? value
239
+ @types.count { |type| type === value } == 1
240
+ end
241
+ end
242
+
243
+
244
+ # @!group Combinator Type Factories
245
+ # ----------------------------------------------------------------------------
246
+
247
+
248
+ #@!method self.Union *types, **options
249
+ # Match any of the types.
250
+ #
251
+ # @param [Type | Object] types
252
+ # Types to combine over. Objects that are not {Type} instances will me
253
+ # made into them via {.make}.
254
+ #
255
+ # @param [Hash] options
256
+ # Passed to {Type#initialize}.
257
+ #
258
+ # @return [Type]
259
+ #
260
+ def_type :Union,
261
+ aliases: [ :one_of, :or ],
262
+ parameterize: [ :types ],
263
+ &->( *types, **options ) do
264
+ Union.new *types, **options
265
+ end # .Union
266
+
267
+
268
+ #@!method self.Intersection *types, **options
269
+ # Match all of the types
270
+ #
271
+ # @param [Type | Object] types
272
+ # Types to combine over. Objects that are not {Type} instances will me
273
+ # made into them via {.make}.
274
+ #
275
+ # @param [Hash] options
276
+ # Passed to {Type#initialize}.
277
+ #
278
+ # @return [Type]
279
+ #
280
+ def_type :Intersection,
281
+ aliases: [ :all_of, :and ],
282
+ parameterize: [ :types ],
283
+ &->( *types, **options ) do
284
+ Intersection.new *types, **options
285
+ end # .Intersection
286
+
287
+
288
+ #@!method self.XOR *types, **options
289
+ # Match one of the types only.
290
+ #
291
+ # @param [Type | Object] types
292
+ # Types to combine over. Objects that are not {Type} instances will me
293
+ # made into them via {.make}.
294
+ #
295
+ # @param [Hash] options
296
+ # Passed to {Type#initialize}.
297
+ #
298
+ # @return [Type]
299
+ #
300
+ def_type :XOR,
301
+ aliases: [ :exclusive_or, :only_one_of ],
302
+ parameterize: [ :types ],
303
+ &->( *types, **options ) do
304
+ XOR.new *types, **options
305
+ end # .XOR
306
+
307
+ # @!endgroup Combinator Type Factories # *************************************
308
+
309
+
310
+ # /Namespace
311
+ # ========================================================================
312
+
313
+ end # module Types
314
+ end # module NRSER
315
+