Class: NRSER::Types::Combinator

Inherits:
Type show all
Defined in:
lib/nrser/types/combinators.rb

Overview

Abstract base class for logically combining types to create new ones.

Direct Known Subclasses

Intersection, Union, XOR

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Type

#===, #builtin_inspect, #check, #check!, #from_s, #inspect, #intersection, #name, #not, #respond_to?, #test, #test?, #to_s, #union, #xor

Constructor Details

#initialize(*types, **options) ⇒ Combinator

Returns a new instance of Combinator.



20
21
22
23
# File 'lib/nrser/types/combinators.rb', line 20

def initialize *types, **options
  super **options
  @types = types.map { |type| NRSER::Types.make type }
end

Instance Attribute Details

#typesArray<NRSER::Types::Type> (readonly)

The parametrized types, in the order they will be tested.



17
18
19
# File 'lib/nrser/types/combinators.rb', line 17

def types
  @types
end

Instance Method Details

#==(other) ⇒ Object



167
168
169
170
171
# File 'lib/nrser/types/combinators.rb', line 167

def == other
  equal?(other) || (
    other.class == self.class && other.types == @types
  )
end

#custom_from_s(s) ⇒ Object

Parse a satisfying value from a 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.

Parameters:

  • s (String)

    String to parse.

Returns:

  • (Object)

    Object that satisfies the type.

Raises:



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/nrser/types/combinators.rb', line 68

def custom_from_s s
  unless @from_s.nil?
    return check @from_s.call( s )
  end
  
  @types.each { |type|
    if type.has_from_s?
      begin
        return check type.from_s(s)
      rescue TypeError => e
        # pass
      end
    end
  }
  
  raise TypeError,
    "none of combinator #{ self.to_s } types could convert #{ s.inspect }"
end

#explainObject



26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/nrser/types/combinators.rb', line 26

def explain
  if self.class::JOIN_SYMBOL
    NRSER::Types::L_PAREN + # ' ' +
    @types.map { |type| type.explain }.join( self.class::JOIN_SYMBOL ) +
    # ' ' +
    NRSER::Types::R_PAREN
  else
    "#{ self.class.demod_name }<" +
      @types.map { |type| type.explain }.join( ',' ) +
    ">"
  end
end

#from_data(data) ⇒ Object

Overridden to



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/nrser/types/combinators.rb', line 111

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

Returns:

  • (Boolean)


105
106
107
# File 'lib/nrser/types/combinators.rb', line 105

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:

  1. It has it’s own ‘@from_s` provided at construction.

  2. Any of it’s combined types can parse from a string.

See Type#from_s for details of how it actually happens.

Returns:

  • (Boolean)


100
101
102
# File 'lib/nrser/types/combinators.rb', line 100

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.

Returns:

  • (Boolean)


140
141
142
# File 'lib/nrser/types/combinators.rb', line 140

def has_to_data?
  @types.any? { |type| type.has_to_data? }
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.

Parameters:

  • value (Object)

    Value of this type (though it is not checked).

Returns:

  • (Object)

    The data representation of the value.

Raises:

  • (NoMethodError)


156
157
158
159
160
161
162
163
164
# File 'lib/nrser/types/combinators.rb', line 156

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