Class: NRSER::Types::Type
Overview
Definitions
Direct Known Subclasses
Attributes, Bounded, Combinator, Equivalent, Is, IsA, Maybe, Not, Respond, Shape, Top, When, Where
Display Instance Methods collapse
-
#builtin_inspect ⇒ String
The built-in
#inspectmethod, aliased before we override it so it's available here if you should want it. -
#default_name ⇒ nil, String
Optional support for generated names to use when no name is explicitly provided at initialization instead of falling back to #explain.
-
#default_symbolic ⇒ nil, String
Optional support for generated symbolic names to use when no symbolic name is provided at initialization instead of falling back to #name.
-
#explain ⇒ String
A verbose breakdown of the implementation internals of the type.
-
#inspect ⇒ String
Overridden to point to #to_s.
-
#name ⇒ String
The name is the type as you would write it out in documentation.
-
#symbolic ⇒ String
A set theory-esque symbolic representation of the type, if available.
-
#to_s ⇒ String
How to display the type.
Validation Instance Methods collapse
-
#check(*args, &block) ⇒ Object
Old name for #check! without the bang.
-
#check!(value, &details) ⇒ Object
Check that a
valuesatisfies the type. - #test(value) ⇒ Boolean deprecated Deprecated.
-
#test?(value) ⇒ Boolean
See if a value satisfies the type.
Loading Values Instance Methods collapse
- #from_data(data) ⇒ Object
-
#from_s(string) ⇒ Object
Load a value of this type from a string representation by passing
stringto the @from_s Proc. - #has_from_data? ⇒ Boolean
-
#has_from_s? ⇒ Boolean
Test if the type knows how to load values from strings.
Dumping Values Instance Methods collapse
-
#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.).
-
#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.
Language Integration Instance Methods collapse
-
#===(value) ⇒ Boolean
Hook into Ruby's case subsumption operator to allow usage in
casestatements! Forwards to #test?. -
#respond_to?(name, include_all = false) ⇒ Boolean
Overridden to customize behavior for the #from_s, #from_data and #to_data methods - those methods are always defined, but we have #respond_to? return
falseif they lack the underlying instance variables needed to execute. -
#to_proc ⇒ Proc<(Object)=>Boolean>
This small method is extremely useful - it lets you easily use types to in Enumerable#select and similar by returning a Proc that runs #test? on the values it receives.
Derivation Instance Methods collapse
-
#intersection(*others) ⇒ NRSER::Types::Intersection
(also: #&, #and)
Return an intersection type satisfied by values that satisfy both
selfand all ofothers. -
#not ⇒ NRSER::Types::Not
(also: #~)
Return a "negation" type satisfied by all values that do not satisfy
self. -
#union(*others) ⇒ Union
(also: #|, #or)
Return a union type satisfied by values that satisfy either
selfor and ofothers. -
#xor(*others) ⇒ NRSER::Types::Intersection
(also: #^)
Return an exclusive or type satisfied by values that satisfy either
selforotherbut not both.
Instance Method Summary collapse
-
#initialize(name: nil, symbolic: nil, from_s: nil, to_data: nil, from_data: nil) ⇒ Type
constructor
Instantiate a new
NRSER::Types::Type.
Constructor Details
#initialize(name: nil, symbolic: nil, from_s: nil, to_data: nil, from_data: nil) ⇒ Type
Instantiate a new NRSER::Types::Type.
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 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/nrser/types/type.rb', line 54 def initialize name: nil, symbolic: nil, from_s: nil, to_data: nil, from_data: nil @name = name.nil? ? nil : name.to_s @from_s = from_s @symbolic = symbolic @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 |
Instance Method Details
#===(value) ⇒ Boolean
Hook into Ruby's case subsumption operator to allow usage in case
statements! Forwards to #test?.
506 507 508 |
# File 'lib/nrser/types/type.rb', line 506 def === value test? value end |
#builtin_inspect ⇒ String
The built-in #inspect method, aliased before we override it so it's
available here if you should want it.
See #inspect for rationale.
236 |
# File 'lib/nrser/types/type.rb', line 236 alias_method :builtin_inspect, :inspect |
#check(*args, &block) ⇒ Object
Old name for #check! without the bang.
316 |
# File 'lib/nrser/types/type.rb', line 316 def check *args, █ check! *args, █ end |
#check!(value, &details) ⇒ Object
Check that a value satisfies the type.
305 306 307 308 309 310 311 312 313 |
# File 'lib/nrser/types/type.rb', line 305 def check! value, &details # success case return value if test? value raise NRSER::Types::CheckError.new \ value: value, type: self, details: details end |
#default_name ⇒ nil, String
Optional support for generated names to use when no name is explicitly provided at initialization instead of falling back to #explain.
Realizing subclasses SHOULD override this method IF they are able to generate meaningful names.
The #default_name implementation returns nil indicating it is not
able to generate names.
130 131 132 |
# File 'lib/nrser/types/type.rb', line 130 def default_name nil end |
#default_symbolic ⇒ nil, String
Optional support for generated symbolic names to use when no symbolic name is provided at initialization instead of falling back to #name.
Realizing subclasses SHOULD override this method IF they are able to generate meaningful symbolic names.
The #default_symbolic implementation returns nil indicating it is
not able to generate names.
162 163 164 |
# File 'lib/nrser/types/type.rb', line 162 def default_symbolic nil end |
#explain ⇒ String
A verbose breakdown of the implementation internals of the type.
Realizing classes SHOULD override this method with a precise implementation.
The #explain implementation dumps all instance variables that
appear to have accessor methods and whose names to not start with _.
Check out the display table for examples.
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/nrser/types/type.rb', line 192 def explain @_explain ||= begin s = "#{ self.class.demod_name }<" ivars = instance_variables. # each_with_object( {} ) { |var_name, hash| each_with_object( [] ) { |var_name, array| method_name = var_name.to_s[1..-1] if method_name.start_with?( '_' ) || !respond_to?( method_name ) next end value = instance_variable_get var_name unless value.nil? array << "#{ var_name }=#{ value.inspect }" end }.join( ', ' ) s += " #{ ivars }" unless ivars.empty? s += '>' s end end |
#from_data(data) ⇒ Object
Try to load a value from "data" - basic values and collections like NRSER::Types.Array and NRSER::Types.Hash forming tree-like structures.
444 445 446 447 448 449 450 451 452 453 454 455 456 |
# File 'lib/nrser/types/type.rb', line 444 def from_data data unless has_from_data? raise NoMethodError, "#from_data not defined" end value = if @from_data @from_data.call data else custom_from_data data end check! value end |
#from_s(string) ⇒ Object
Load a value of this type from a string representation by passing
string to the @from_s Proc.
Checks the value @from_s returns with #check! before returning it, so you know it satisfies this type.
Realizing classes should not need to override this - they can define
a #custom_from_s instance method for it to use, allowing individual
types to still override that by providing a from_s: proc keyword
arg at construction. This also lets them avoid checking the returned
value, since we do so here.
402 403 404 405 406 407 408 409 410 411 412 413 414 |
# File 'lib/nrser/types/type.rb', line 402 def from_s string unless has_from_s? raise NoMethodError, "#from_s not defined for type #{ name }" end value = if @from_s @from_s.call string else custom_from_s string end check! value end |
#has_from_data? ⇒ Boolean
Test if the type can load values from "data" - basic values and collections like NRSER::Types.Array and NRSER::Types.Hash forming tree-like structures.
Realizing classes may need to override this to limited or expand responses relative to parameterized types.
425 426 427 428 429 |
# File 'lib/nrser/types/type.rb', line 425 def has_from_data? !@from_data.nil? || # Need the `true` second arg to include protected methods respond_to?( :custom_from_data, true ) end |
#has_from_s? ⇒ Boolean
When this method returns true it simply indicates that some method
of loading from strings exists - the load itself can of course still
fail.
Test if the type knows how to load values from strings.
Looks for the @from_s instance variable or a #custom_from_s
method.
Realizing classes should only need to override this method to limited or expand the scope relative to parameterized types.
362 363 364 365 366 |
# File 'lib/nrser/types/type.rb', line 362 def has_from_s? !@from_s.nil? || # Need the `true` second arg to include protected methods respond_to?( :custom_from_s, true ) 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.
472 473 474 |
# File 'lib/nrser/types/type.rb', line 472 def has_to_data? ! @to_data.nil? end |
#inspect ⇒ String
Overridden to point to #to_s.
Due to their combinatoric nature, types can quickly become large data hierarchies, and the built-in #inspect will produce a massive dump that's distracting and hard to decipher.
#inspect is readily used in tools like pry and rspec, significantly
impacting their usefulness when working with types.
As a solution, we alias the built-in #inspect as #builtin_inspect,
so it's available in situations where you really want all those gory
details, and point #inspect to #to_s.
254 255 256 |
# File 'lib/nrser/types/type.rb', line 254 def inspect to_s end |
#intersection(*others) ⇒ NRSER::Types::Intersection Also known as: &, and
Return an intersection type satisfied by values that satisfy both
self and all of others.
597 598 599 600 601 |
# File 'lib/nrser/types/type.rb', line 597 def intersection *others require_relative './combinators' NRSER::Types.intersection self, *others end |
#name ⇒ String
The name is the type as you would write it out in documentation.
Prefers an explicit @name set at initialization, falling back first
to #default_name, then to #explain.
142 143 144 |
# File 'lib/nrser/types/type.rb', line 142 def name @name || default_name || explain end |
#not ⇒ NRSER::Types::Not Also known as: ~
Return a "negation" type satisfied by all values that do not satisfy
self.
629 630 631 632 633 |
# File 'lib/nrser/types/type.rb', line 629 def not require_relative './not' NRSER::Types.not self end |
#respond_to?(name, include_all = false) ⇒ Boolean
Overridden to customize behavior for the #from_s, #from_data 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.
533 534 535 536 537 538 539 540 541 542 543 544 |
# File 'lib/nrser/types/type.rb', line 533 def respond_to? name, include_all = false case name.to_sym when :from_s has_from_s? when :from_data has_from_data? when :to_data has_to_data? else super name, include_all end end |
#symbolic ⇒ String
A set theory-esque symbolic representation of the type, if available.
Prefers an explicit @symbolic set at initialization, falling back to an
explicit @name, then to #default_symbolic and finally #name.
174 175 176 |
# File 'lib/nrser/types/type.rb', line 174 def symbolic @symbolic || @name || default_symbolic || name end |
#test(value) ⇒ Boolean
Old name for #test?.
292 |
# File 'lib/nrser/types/type.rb', line 292 def test value; test? value; end |
#test?(value) ⇒ Boolean
See if a value satisfies the type.
Realizing classes must implement this method.
This implementation just defines the API; it always raises AbstractMethodError.
280 281 282 |
# File 'lib/nrser/types/type.rb', line 280 def test? value raise NRSER::AbstractMethodError.new( self, __method__ ) 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.
486 487 488 489 490 491 492 |
# File 'lib/nrser/types/type.rb', line 486 def to_data value if @to_data.nil? raise NoMethodError, "#to_data not defined" end @to_data.call value end |
#to_proc ⇒ Proc<(Object)=>Boolean>
This small method is extremely useful - it lets you easily use types to in Enumerable#select and similar by returning a Proc that runs #test? on the values it receives.
Pretty cool, right?
558 559 560 |
# File 'lib/nrser/types/type.rb', line 558 def to_proc ->( value ) { test? value } end |
#to_s ⇒ String
How to display the type. Proxies to #symbolic.
224 225 226 |
# File 'lib/nrser/types/type.rb', line 224 def to_s symbolic end |
#union(*others) ⇒ Union Also known as: |, or
Return a union type satisfied by values that satisfy either self
or and of others.
579 580 581 582 583 |
# File 'lib/nrser/types/type.rb', line 579 def union *others require_relative './combinators' NRSER::Types.union self, *others end |
#xor(*others) ⇒ NRSER::Types::Intersection Also known as: ^
Return an exclusive or type satisfied by values that satisfy either
self or other but not both.
615 616 617 618 619 |
# File 'lib/nrser/types/type.rb', line 615 def xor *others require_relative './combinators' NRSER::Types.xor self, *others end |