Class: NRSER::Types::Type

Inherits:
Object
  • Object
show all
Defined in:
lib/nrser/types/type.rb

Direct Known Subclasses

Attrs, Bounded, Combinator, Is, IsA, Responds, Where

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name: nil, from_s: nil, to_data: nil, from_data: nil) ⇒ Type

Instantiate a new ‘NRSER::Types::Type`.

Parameters:

  • name: (nil | String) (defaults to: nil)

    Name that will be used when displaying the type, or ‘nil` to use a default generated name.

  • from_s: (nil | #call) (defaults to: nil)

    Callable that will be passed a String and should return an object that satisfies the type if it possible to create one.

    The returned value will be checked against the type, so returning a value that doesn’t satisfy will result in a TypeError being raised by #from_s.

  • to_data: (nil | #call | #to_proc) (defaults to: nil)


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/nrser/types/type.rb', line 38

def initialize name: nil, from_s: nil, to_data: nil, from_data: nil
  @name = name
  @from_s = from_s
  
  @to_data = if to_data.nil?
    nil
  elsif to_data.respond_to?( :call )
    to_data
  elsif to_data.respond_to?( :to_proc )
    to_data.to_proc
  else
    raise TypeError.new binding.erb <<-ERB
      `to_data:` keyword arg must be `nil`, respond to `#call` or respond
      to `#to_proc`.
      
      Found value:
      
          <%= to_data.pretty_inspect %>
      
      (type <%= to_data.class %>)
      
    ERB
  end
  
  @from_data = if from_data.nil?
    nil
  elsif from_data.respond_to?( :call )
    from_data
  elsif from_data.respond_to?( :to_proc )
    from_data.to_proc
  else
    raise TypeError.new binding.erb <<-ERB
      `to_data:` keyword arg must be `nil`, respond to `#call` or respond
      to `#to_proc`.
      
      Found value:
      
          <%= from_data.pretty_inspect %>
      
      (type <%= from_data.class %>)
      
    ERB
  end
end

Class Method Details

.short_nameObject



13
14
15
# File 'lib/nrser/types/type.rb', line 13

def self.short_name
  name.split('::').last
end

Instance Method Details

#check(value, &make_fail_message) ⇒ Object



97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/nrser/types/type.rb', line 97

def check value, &make_fail_message
  # success case
  return value if test value
  
  msg = if make_fail_message
    make_fail_message.call type: self, value: value
  else
    NRSER.squish <<-END
      value #{ value.inspect } failed check #{ self.to_s }
    END
  end
  
  raise TypeError.new msg
end

#default_nameObject



88
89
90
# File 'lib/nrser/types/type.rb', line 88

def default_name
  self.class.short_name
end

#from_data(data) ⇒ Object



182
183
184
185
186
187
188
# File 'lib/nrser/types/type.rb', line 182

def from_data data
  if @from_data.nil?
    raise NoMethodError, "#from_data not defined"
  end
  
  check @from_data.call( data )
end

#from_s(s) ⇒ Object

Load a value of this type from a string representation by passing ‘s` to the @from_s Proc.

Checks the value @from_s returns with #check before returning it, so you know it satisfies this type.

Parameters:

  • s (String)

    String representation.

Returns:

  • (Object)

    Value that has passed #check.

Raises:

  • (NoMethodError)

    If this type doesn’t know how to load values from strings.

    In basic types this happens when #initialize was not provided a ‘from_s:` Proc argument.

    NRSER::Types::Type subclasses may override #from_s entirely, divorcing it from the ‘from_s:` constructor argument and internal @from_s instance variable (which is why @from_s is not publicly exposed - it should not be assumed to dictate #from_s behavior in general).

  • (TypeError)

    If the value loaded does not pass #check.



173
174
175
176
177
178
179
# File 'lib/nrser/types/type.rb', line 173

def from_s s
  if @from_s.nil?
    raise NoMethodError, "#from_s not defined"
  end
  
  check @from_s.call( s )
end

#has_from_data?Boolean

Returns:

  • (Boolean)


215
216
217
# File 'lib/nrser/types/type.rb', line 215

def has_from_data?
  ! @from_data.nil?
end

#has_from_s?Boolean

Test if the type knows how to load values from strings.

If this method returns ‘true`, then we expect #from_s to succeed.

Returns:

  • (Boolean)


197
198
199
# File 'lib/nrser/types/type.rb', line 197

def has_from_s?
  ! @from_s.nil?
end

#has_to_data?Boolean

Test if the type has custom information about how to convert it’s values into “data” - structures and values suitable for transportation and storage (JSON, etc.).

If this method returns ‘true` then #to_data should succeed.

Returns:

  • (Boolean)


210
211
212
# File 'lib/nrser/types/type.rb', line 210

def has_to_data?
  ! @to_data.nil?
end

#nameObject



84
85
86
# File 'lib/nrser/types/type.rb', line 84

def name
  @name || default_name
end

#respond_to?(name, include_all = false) ⇒ Boolean

Overridden to customize behavior for the #from_s and #to_data methods - those methods are always defined, but we have #respond_to? return ‘false` if they lack the underlying instance variables needed to execute.

Examples:

t1 = t.where { |value| true }
t1.respond_to? :from_s
# => false

t2 = t.where( from_s: ->(s){ s.split ',' } ) { |value| true }
t2.respond_to? :from_s
# => true

Parameters:

  • name (Symbol | String)

    Method name to ask about.

  • include_all (Boolean) (defaults to: false)

    IDK, part of Ruby API that is passed up to ‘super`.

Returns:

  • (Boolean)


135
136
137
138
139
140
141
142
143
# File 'lib/nrser/types/type.rb', line 135

def respond_to? name, include_all = false
  if name == :from_s || name == 'from_s'
    has_from_s?
  elsif name == :to_data || name == 'to_data'
    has_to_data?
  else
    super name, include_all
  end
end

#test(value) ⇒ Object

Raises:

  • (NotImplementedError)


92
93
94
# File 'lib/nrser/types/type.rb', line 92

def test value
  raise NotImplementedError
end

#to_data(value) ⇒ Object

Dumps a value of this type to “data” - structures and values suitable for transport and storage, such as dumping to JSON or YAML, etc.

Parameters:

  • value (Object)

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

Returns:

  • (Object)

    The data representation of the value.



229
230
231
232
233
234
235
# File 'lib/nrser/types/type.rb', line 229

def to_data value
  if @to_data.nil?
    raise NoMethodError, "#to_data not defined"
  end
  
  @to_data.call value
end

#to_sString Also known as: inspect

Returns a brief string description of the type - just it’s #name surrounded by some back-ticks to make it easy to see where it starts and stops.

Returns:

  • (String)

    a brief string description of the type - just it’s #name surrounded by some back-ticks to make it easy to see where it starts and stops.



246
247
248
# File 'lib/nrser/types/type.rb', line 246

def to_s
  "`#{ name }`"
end