Module: NRSER::Types
- Extended by:
- Factory
- Includes:
- Log::Mixin
- Defined in:
- lib/nrser/types/not.rb,
lib/nrser/types/in.rb,
lib/nrser/types/is.rb,
lib/nrser/types/any.rb,
lib/nrser/types/nil.rb,
lib/nrser/types/is_a.rb,
lib/nrser/types/type.rb,
lib/nrser/types/when.rb,
lib/nrser/types/attrs.rb,
lib/nrser/types/maybe.rb,
lib/nrser/types/pairs.rb,
lib/nrser/types/paths.rb,
lib/nrser/types/shape.rb,
lib/nrser/types/trees.rb,
lib/nrser/types/where.rb,
lib/nrser/types/arrays.rb,
lib/nrser/types/hashes.rb,
lib/nrser/types/labels.rb,
lib/nrser/types/tuples.rb,
lib/nrser/types/bounded.rb,
lib/nrser/types/numbers.rb,
lib/nrser/types/strings.rb,
lib/nrser/types/symbols.rb,
lib/nrser/types/booleans.rb,
lib/nrser/types/responds.rb,
lib/nrser/refinements/types.rb,
lib/nrser/types/combinators.rb,
lib/nrser/types.rb
Overview
Stuff to help you define, test, check and match types in Ruby.
Defined Under Namespace
Modules: Factory Classes: AnyType, ArrayOfType, ArrayType, AttrsType, BooleanType, Bounded, CheckError, Combinator, FalseType, FromStringError, HashOfType, HashType, Intersection, Is, IsA, Maybe, Not, Respond, Shape, TrueType, TupleType, Type, Union, When, Where, XOR
Constant Summary collapse
- L_PAREN =
Constants
'('
- R_PAREN =
‘❪’
')'
- RESPONDS_WITH =
‘❫’
'→'
- ASSOC =
'=>'
Type Factory Functions collapse
- .length(*args) ⇒ Object
-
#dir_path ⇒ NRSER::Types::Type
A path that is a directory.
-
#maybe ⇒ Type
Type satisfied by ‘nil` or the parametrized type.
- #path ⇒ NRSER::Types::Type
Class Method Summary collapse
-
.check!(value, type) ⇒ Object
Create a Type from ‘type` with Types.make and check that `value` satisfies it, raising if it doesn’t.
-
.from_repr(repr) ⇒ Object
make a type instance from a object representation that can come from a YAML or JSON declaration.
-
.make(value) ⇒ NRSER::Types::Type
Make a Type from a value.
-
.maker ⇒ Method
The Types.make method reference; for easy map and such.
- .match(value, *clauses) ⇒ Object
-
.parse_number(string) ⇒ Integer, Float
Parse a string into a number.
-
.test?(value, type) ⇒ Boolean
Create a Type from ‘type` with Types.make and test if `value` satisfies it.
Instance Method Summary collapse
-
#array ⇒ NRSER::Types::Type
ArrayType / ArrayOfType factory function.
-
#hash_type ⇒ NRSER::Types::HASH, NRSER::Types::Type
Type satisfied by Hash instances.
-
#in ⇒ NRSER::Types::Type
Type that tests value for membership in a group object via that object’s ‘#include?` method.
-
#tuple ⇒ NRSER::Types::Type
Get a tuple type.
Methods included from Factory
Methods included from Log::Mixin
Class Method Details
.check!(value, type) ⇒ Object
103 104 105 |
# File 'lib/nrser/types.rb', line 103 def self.check! value, type make( type ).check! value end |
.from_repr(repr) ⇒ Object
make a type instance from a object representation that can come from a YAML or JSON declaration.
189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/nrser/types.rb', line 189 def self.from_repr repr match repr, { str => ->(string) { NRSER::Types.method(string.downcase).call }, Hash => ->(hash) { raise NotImplementedError, "Haven't gotten to it yet!" }, } end |
.length(exact, options = {}) ⇒ NRSER::Types::Attrs .length(bounds, options = {}) ⇒ NRSER::Types::Attrs
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/nrser/types/attrs.rb', line 158 def self.length *args bounds = {} = if args[1].is_a?( Hash ) then args[1] else {} end case args[0] when ::Integer # It's just a length return attrs( { length: is( non_neg_int.check!( args[0] ) ) }, ** ) bounds[:min] = bounds[:max] = non_neg_int.check args[0] when ::Hash # It's keyword args kwds = args[0].sym_keys # Pull any :min and :max in the keywords bounds[:min] = kwds.delete :min bounds[:max] = kwds.delete :max # But override with :length if we got it if length = kwds.delete(:length) bounds[:min] = length bounds[:max] = length end # (Reverse) merge anything else into the options (options hash values # take precedence) = kwds.merge else raise ArgumentError, <<-END.squish arg must be positive integer or option hash, found: #{ args[0].inspect } of type #{ args[0].class } END end bounded_type = bounded bounds length_type = if !bounded_type.min.nil? && bounded_type.min >= 0 # We don't need the non-neg check bounded_type else # We do need the non-neg check intersection(non_neg_int, bounded_type) end [:name] ||= "Length<#{ bounded_type.name }>" attrs({ length: length_type }, ) end |
.make(value) ⇒ NRSER::Types::Type
68 69 70 71 72 73 74 75 76 |
# File 'lib/nrser/types.rb', line 68 def self.make value if value.nil? self.nil elsif value.is_a? NRSER::Types::Type value else self.when value end end |
.maker ⇒ Method
The make method reference; for easy map and such.
83 84 85 |
# File 'lib/nrser/types.rb', line 83 def self.maker method :make end |
.match(value, *clauses) ⇒ Object
Switch match to use ‘===`! Should allow us to avoid making types for everything?
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/nrser/types.rb', line 129 def self.match value, *clauses if clauses.empty? raise ArgumentError.new NRSER.dedent <<-END Must supply either a single {type => expression} hash argument or a even amount of arguments representing (type, expression) pairs after `value`. #{ NRSER::Version.doc_url 'NRSER/Types#match-class_method' } END end enum = if clauses.length == 1 && clauses.first.respond_to?(:each_pair) clauses.first.each_pair else unless clauses.length % 2 == 0 raise TypeError.new NRSER.dedent <<-END When passing a list of clauses, it must be an even length representing (type, expression) pairs. Found an argument list with length #{ clauses.length }: #{ clauses } END end clauses.each_slice(2) end enum.each { |type, expression| if test? value, type # OK, we matched! Is the corresponding expression callable? if expression.respond_to? :call # It is; invoke and return result. if expression.arity == 0 return expression.call else return expression.call value end else # It's not; assume it's a value and return it. return expression end end } raise TypeError, <<-END.dedent Could not match value #{ value.inspect } to any of types #{ enum.map {|type, expression| "\n #{ type.inspect }"}.join '' } END end |
.parse_number(string) ⇒ Integer, Float
Parse a string into a number.
16 17 18 19 20 |
# File 'lib/nrser/types/numbers.rb', line 16 def self.parse_number string float = Float string int = float.to_i if float == int then int else float end end |
Instance Method Details
#array ⇒ NRSER::Types::Type
Make ‘list` into it’s own looser interface for “array-like” object API.
ArrayType / ArrayOfType factory function.
157 158 159 160 161 162 163 164 165 166 |
# File 'lib/nrser/types/arrays.rb', line 157 def_factory( :array, aliases: [:list], ) do |item_type = any, **| if item_type == any ArrayType.new ** else ArrayOfType.new item_type, ** end end |
#dir_path ⇒ NRSER::Types::Type
A path that is a directory.
111 112 113 114 115 116 117 118 |
# File 'lib/nrser/types/paths.rb', line 111 def_factory :dir_path do |name: 'DirPath', **| intersection \ path, # TODO How to change this from {.where}? where { |path| File.directory? path }, name: name, ** end |
#hash_type ⇒ NRSER::Types::HASH, NRSER::Types::Type
Make ‘map` into it’s own looser interface for “hash-like” object API.
Type satisfied by Hash instances.
197 198 199 200 201 202 203 204 205 206 |
# File 'lib/nrser/types/hashes.rb', line 197 def_factory( :hash_type, aliases: [ :dict, :hash_, :map ] ) do |**kwds| if kwds.key?( :keys ) || kwds.key?( :values ) HashOfType.new **kwds else HashType.new **kwds end end |
#in ⇒ NRSER::Types::Type
I think I want to get rid of where… which would elevate this to it’s own class as a “fundamental” concept (I guess)… not so sure, really. The idea of membership is pretty wide-spread and important, but it’s a bit a vague and inconsistently implemented things.
Type that tests value for membership in a group object via that object’s ‘#include?` method.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/nrser/types/in.rb', line 20 def_factory( :in, aliases: [ :member_of ], ) do |group, **| unless group.respond_to? :include? raise NRSER::ArgumentError, "In `group` must respond to `:include?`", group: group end # Provide a some-what useful default name [:name] ||= "In<#{ NRSER.smart_ellipsis group.inspect, 64 }>" # Unless a `from_s` is provided, just use the identity [:from_s] ||= ->( s ) { s } where( ** ) { |value| group.include? value } end |
#maybe ⇒ Type
Type satisfied by ‘nil` or the parametrized type.
80 81 82 |
# File 'lib/nrser/types/maybe.rb', line 80 def_factory :maybe do |type, **| Maybe.new type, ** end |
#path ⇒ NRSER::Types::Type
54 55 56 57 58 59 60 |
# File 'lib/nrser/types/paths.rb', line 54 def_factory :path do |name: 'Path', **| one_of \ non_empty_str, non_empty_pathname, name: name, ** end |
#tuple ⇒ NRSER::Types::Type
Get a tuple type.
113 114 115 |
# File 'lib/nrser/types/tuples.rb', line 113 def_factory :tuple do |*types, **| TupleType.new *types, ** end |