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 ‘#inspect` method, 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 ‘value` satisfies 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 ‘string` to 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 ‘case` statements! 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 ‘false` if 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 ‘self` and all of `others`.
-
#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 ‘self` or and of `others`.
-
#xor(*others) ⇒ NRSER::Types::Intersection
(also: #^)
Return an *exclusive or* type satisfied by values that satisfy either ‘self` or `other` *but 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 |