Class: NRSER::Types::Combinator
- Defined in:
- lib/nrser/types/combinators.rb
Overview
Abstract base class for logically combining types to create new ones.
Direct Known Subclasses
Instance Attribute Summary collapse
-
#types ⇒ Array<NRSER::Types::Type>
readonly
The parameterized types, in the order they will be tested.
Instance Method Summary collapse
- #==(other) ⇒ Object
-
#custom_from_s(string) ⇒ Object
Parse a satisfying value from a String or raise a NRSER::TypeError.
- #default_symbolic ⇒ Object
- #explain ⇒ Object
-
#from_data(data) ⇒ Object
Overridden to.
- #has_from_data? ⇒ Boolean
-
#has_from_s? ⇒ Boolean
Overridden to delegate functionality to the combined types.
-
#has_to_data? ⇒ Boolean
Overridden to delegate functionality to the combined types:.
-
#initialize(*types, **options) ⇒ Combinator
constructor
A new instance of Combinator.
- #string_format(method) ⇒ Object
-
#to_data(value) ⇒ Object
Overridden to delegate functionality to the combined types:.
Methods inherited from Type
#===, #builtin_inspect, #check, #check!, #default_name, #from_s, #inspect, #intersection, #name, #not, #respond_to?, #symbolic, #test, #test?, #to_proc, #to_s, #union, #xor
Constructor Details
#initialize(*types, **options) ⇒ Combinator
Returns a new instance of Combinator.
33 34 35 36 |
# File 'lib/nrser/types/combinators.rb', line 33 def initialize *types, ** super ** @types = types.map { |type| NRSER::Types.make type }.freeze end |
Instance Attribute Details
#types ⇒ Array<NRSER::Types::Type> (readonly)
The parameterized types, in the order they will be tested.
30 31 32 |
# File 'lib/nrser/types/combinators.rb', line 30 def types @types end |
Instance Method Details
#==(other) ⇒ Object
198 199 200 201 202 |
# File 'lib/nrser/types/combinators.rb', line 198 def == other equal?(other) || ( other.class == self.class && other.types == @types ) end |
#custom_from_s(string) ⇒ Object
Parse a satisfying value from a NRSER::Types.String or raise a NRSER::TypeError.
If this type has it’s own ‘@from_s` that was provided via the `from_s:` keyword at construction, then that and only that is always used
-
the type will never try any of the combined types’ ‘#from_s`.
It’s considered the way to parse a string into a value that satisfies the type. If it fails, a NRSER::TypeError will be raised (or any error the ‘@from_s` proc itself raises before we get to checking it).
If the type doesn’t have it’s own ‘@from_s`, each of the combined types’ ‘#from_s` will be tried in sequence, and the first value that satisfies the combined type will be returned.
This is obviously much less efficient, but provides a nice automatic mechanism for parsing from strings for combined types. If none of the combined types’ ‘#from_s` succeed (or if there are none) a NRSER::TypeError is raised.
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/nrser/types/combinators.rb', line 86 def custom_from_s string # If we have an explicit `@from_s` then use that and that only. unless @from_s.nil? return check! @from_s.call( string ) end errors_by_type = {} types.each { |type| if type.has_from_s? begin return check! type.from_s( string ) # We want to catch any standard error here so `from_s` implementations # can kinda "code without care" and if one fails we will move on to # try the next. rescue StandardError => error errors_by_type[type] = error end else errors_by_type[type] = "Does not {#has_from_s?}" end } # TODO This should be "nicer"... teach {NRSER::MultipleErrors} about # {NRSER::NicerError}? raise TypeError.new \ "none of combinator", self.to_s, "types could convert", string.inspect, string: string, errors_by_type: errors_by_type end |
#default_symbolic ⇒ Object
48 49 50 |
# File 'lib/nrser/types/combinators.rb', line 48 def default_symbolic string_format( :to_s ) end |
#explain ⇒ Object
53 54 55 |
# File 'lib/nrser/types/combinators.rb', line 53 def explain return string_format( :explain ) end |
#from_data(data) ⇒ Object
Overridden to
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/nrser/types/combinators.rb', line 142 def from_data data unless has_from_data? raise NoMethodError, "#from_data not defined" end errors = [] types.each do |type| if type.has_from_data? begin return check!( type.from_data data ) rescue StandardError => error errors << error end end end raise NRSER::MultipleErrors.new \ errors, headline: "No type successfully loaded data" end |
#has_from_data? ⇒ Boolean
136 137 138 |
# File 'lib/nrser/types/combinators.rb', line 136 def has_from_data? @types.any? { |type| type.has_from_data? } end |
#has_from_s? ⇒ Boolean
Overridden to delegate functionality to the combined types.
A combinator may attempt to parse from a string if:
-
It has it’s own ‘@from_s` provided at construction.
-
Any of it’s combined types can parse from a string.
See Type#from_s for details of how it actually happens.
131 132 133 |
# File 'lib/nrser/types/combinators.rb', line 131 def has_from_s? !@from_s.nil? || @types.any? { |type| type.has_from_s? } end |
#has_to_data? ⇒ Boolean
Overridden to delegate functionality to the combined types:
A combinator can convert a value to data if any of it’s types can.
171 172 173 |
# File 'lib/nrser/types/combinators.rb', line 171 def has_to_data? @types.any? { |type| type.has_to_data? } end |
#string_format(method) ⇒ Object
39 40 41 42 43 44 45 |
# File 'lib/nrser/types/combinators.rb', line 39 def string_format method NRSER::Types::L_PAREN + # ' ' + no spaces @types.map { |type| type.send method }.join( self.class::JOIN_SYMBOL ) + # ' ' + no spaces NRSER::Types::R_PAREN end |
#to_data(value) ⇒ Object
Overridden to delegate functionality to the combined types:
The first of the combined types that responds to ‘#to_data` is used to dump the value.
187 188 189 190 191 192 193 194 195 |
# File 'lib/nrser/types/combinators.rb', line 187 def to_data value @types.each { |type| if type.has_to_data? return type.to_data value end } raise NoMethodError, "#to_data not defined" end |