nrser 0.3.9 → 0.3.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/nrser/char/alpha_numeric_sub.rb +9 -19
- data/lib/nrser/char/special.rb +5 -5
- data/lib/nrser/core_ext/array.rb +36 -13
- data/lib/nrser/core_ext/enumerable.rb +1 -0
- data/lib/nrser/core_ext/enumerable/find_map.rb +1 -1
- data/lib/nrser/core_ext/hash/bury.rb +3 -0
- data/lib/nrser/core_ext/hash/extract_values_at.rb +2 -2
- data/lib/nrser/core_ext/method/full_name.rb +1 -1
- data/lib/nrser/core_ext/module/method_objects.rb +1 -1
- data/lib/nrser/core_ext/module/source_locations.rb +27 -15
- data/lib/nrser/core_ext/object/lazy_var.rb +1 -1
- data/lib/nrser/core_ext/pathname.rb +67 -12
- data/lib/nrser/core_ext/pathname/subpath.rb +86 -0
- data/lib/nrser/core_ext/string.rb +28 -1
- data/lib/nrser/core_ext/symbol.rb +11 -12
- data/lib/nrser/errors/README.md +154 -0
- data/lib/nrser/errors/attr_error.rb +146 -53
- data/lib/nrser/errors/count_error.rb +61 -12
- data/lib/nrser/errors/nicer_error.rb +42 -71
- data/lib/nrser/errors/value_error.rb +53 -58
- data/lib/nrser/functions.rb +0 -2
- data/lib/nrser/functions/enumerable.rb +5 -17
- data/lib/nrser/functions/enumerable/associate.rb +14 -5
- data/lib/nrser/functions/enumerable/find_all_map.rb +1 -1
- data/lib/nrser/functions/enumerable/include_slice/array_include_slice.rb +1 -1
- data/lib/nrser/functions/hash/bury.rb +2 -12
- data/lib/nrser/functions/merge_by.rb +2 -2
- data/lib/nrser/functions/module/method_objects.rb +2 -2
- data/lib/nrser/functions/path.rb +185 -165
- data/lib/nrser/functions/path/normalized.rb +84 -0
- data/lib/nrser/functions/string.rb +4 -4
- data/lib/nrser/functions/text/README.md +4 -0
- data/lib/nrser/functions/text/format.rb +53 -0
- data/lib/nrser/functions/text/indentation.rb +6 -6
- data/lib/nrser/functions/text/word_wrap.rb +2 -2
- data/lib/nrser/functions/tree/map_leaves.rb +3 -3
- data/lib/nrser/functions/tree/map_tree.rb +2 -2
- data/lib/nrser/functions/tree/transform.rb +1 -18
- data/lib/nrser/gem_ext/README.md +4 -0
- data/lib/nrser/labs/README.md +8 -0
- data/lib/nrser/labs/config.rb +163 -0
- data/lib/nrser/labs/i8.rb +49 -159
- data/lib/nrser/labs/i8/struct.rb +167 -0
- data/lib/nrser/labs/i8/struct/hash.rb +140 -0
- data/lib/nrser/labs/i8/struct/vector.rb +149 -0
- data/lib/nrser/labs/i8/surjection.rb +211 -0
- data/lib/nrser/labs/lots/consumer.rb +19 -0
- data/lib/nrser/labs/lots/parser.rb +21 -1
- data/lib/nrser/labs/stash.rb +4 -4
- data/lib/nrser/log.rb +25 -21
- data/lib/nrser/log/appender/sync.rb +15 -11
- data/lib/nrser/log/formatters/color.rb +0 -3
- data/lib/nrser/log/formatters/mixin.rb +4 -4
- data/lib/nrser/log/logger.rb +54 -6
- data/lib/nrser/log/mixin.rb +2 -1
- data/lib/nrser/log/plugin.rb +6 -6
- data/lib/nrser/log/types.rb +46 -29
- data/lib/nrser/mean_streak.rb +0 -8
- data/lib/nrser/mean_streak/document.rb +1 -4
- data/lib/nrser/message.rb +3 -3
- data/lib/nrser/meta/README.md +4 -0
- data/lib/nrser/meta/lazy_attr.rb +2 -2
- data/lib/nrser/meta/source/location.rb +1 -1
- data/lib/nrser/props.rb +34 -3
- data/lib/nrser/props/class_methods.rb +2 -1
- data/lib/nrser/props/instance_methods.rb +9 -9
- data/lib/nrser/props/metadata.rb +4 -12
- data/lib/nrser/props/mutable/stash.rb +5 -2
- data/lib/nrser/props/prop.rb +10 -19
- data/lib/nrser/rspex.rb +1 -20
- data/lib/nrser/rspex/example_group/describe_attribute.rb +3 -0
- data/lib/nrser/rspex/example_group/describe_called_with.rb +9 -4
- data/lib/nrser/rspex/example_group/describe_case.rb +1 -0
- data/lib/nrser/rspex/example_group/describe_class.rb +2 -0
- data/lib/nrser/rspex/example_group/describe_group.rb +1 -1
- data/lib/nrser/rspex/example_group/describe_instance.rb +3 -1
- data/lib/nrser/rspex/example_group/describe_message.rb +1 -1
- data/lib/nrser/rspex/example_group/describe_method.rb +64 -30
- data/lib/nrser/rspex/example_group/describe_response_to.rb +1 -1
- data/lib/nrser/rspex/example_group/describe_section.rb +4 -1
- data/lib/nrser/rspex/example_group/describe_sent_to.rb +1 -1
- data/lib/nrser/rspex/example_group/describe_setup.rb +1 -0
- data/lib/nrser/rspex/example_group/describe_source_file.rb +1 -1
- data/lib/nrser/rspex/example_group/describe_spec_file.rb +4 -2
- data/lib/nrser/rspex/example_group/describe_when.rb +2 -1
- data/lib/nrser/rspex/example_group/describe_x.rb +5 -5
- data/lib/nrser/rspex/format.rb +0 -15
- data/lib/nrser/sugar/method_missing_forwarder.rb +3 -3
- data/lib/nrser/sys/env/path.rb +2 -28
- data/lib/nrser/types.rb +63 -12
- data/lib/nrser/types/README.md +76 -0
- data/lib/nrser/types/arrays.rb +192 -137
- data/lib/nrser/types/attributes.rb +269 -0
- data/lib/nrser/types/booleans.rb +134 -83
- data/lib/nrser/types/bounded.rb +110 -47
- data/lib/nrser/types/collections.rb +119 -0
- data/lib/nrser/types/combinators.rb +283 -196
- data/lib/nrser/types/doc/display_table.md +66 -0
- data/lib/nrser/types/eqiuvalent.rb +91 -0
- data/lib/nrser/types/errors/check_error.rb +5 -11
- data/lib/nrser/types/errors/from_string_error.rb +3 -3
- data/lib/nrser/types/factory.rb +287 -20
- data/lib/nrser/types/hashes.rb +227 -179
- data/lib/nrser/types/in.rb +73 -36
- data/lib/nrser/types/is.rb +67 -60
- data/lib/nrser/types/is_a.rb +141 -84
- data/lib/nrser/types/labels.rb +45 -16
- data/lib/nrser/types/maybe.rb +6 -3
- data/lib/nrser/types/nil.rb +64 -27
- data/lib/nrser/types/not.rb +92 -34
- data/lib/nrser/types/numbers.rb +224 -169
- data/lib/nrser/types/pairs.rb +113 -89
- data/lib/nrser/types/paths.rb +250 -137
- data/lib/nrser/types/responds.rb +167 -89
- data/lib/nrser/types/selector.rb +234 -0
- data/lib/nrser/types/shape.rb +136 -65
- data/lib/nrser/types/strings.rb +189 -63
- data/lib/nrser/types/symbols.rb +83 -33
- data/lib/nrser/types/top.rb +89 -0
- data/lib/nrser/types/tuples.rb +134 -98
- data/lib/nrser/types/type.rb +617 -505
- data/lib/nrser/types/when.rb +123 -98
- data/lib/nrser/types/where.rb +182 -91
- data/lib/nrser/version.rb +1 -1
- data/spec/lib/nrser/core_ext/pathname/subpath_spec.rb +22 -0
- data/spec/lib/nrser/errors/attr_error_spec.rb +68 -0
- data/spec/lib/nrser/errors/count_error_spec.rb +69 -0
- data/spec/lib/nrser/functions/path/normalize_path_spec.rb +35 -0
- data/spec/lib/nrser/functions/tree/map_tree_spec.rb +74 -96
- data/spec/lib/nrser/functions/tree/transform_spec.rb +11 -11
- data/spec/lib/nrser/labs/config_spec.rb +22 -0
- data/spec/lib/nrser/labs/i8/struct_spec.rb +39 -0
- data/spec/lib/nrser/types/display_spec.rb +50 -0
- data/spec/lib/nrser/types/paths_spec.rb +16 -10
- data/spec/lib/nrser/types/selector_spec.rb +125 -0
- data/spec/spec_helper.rb +4 -5
- metadata +105 -22
- data/lib/nrser/types/any.rb +0 -41
- data/lib/nrser/types/attrs.rb +0 -213
- data/lib/nrser/types/trees.rb +0 -42
@@ -0,0 +1,66 @@
|
|
1
|
+
NRSER::Types Display Table
|
2
|
+
==============================================================================
|
3
|
+
|
4
|
+
Example table of `source` code creating types to the output of the various display
|
5
|
+
methods:
|
6
|
+
|
7
|
+
1. {NRSER::Types::Type#name}
|
8
|
+
1. {NRSER::Types::Type#symbolic}
|
9
|
+
1. {NRSER::Types::Type#explain}
|
10
|
+
|
11
|
+
### Verification
|
12
|
+
|
13
|
+
These values are verified in `//spec/lib/nrser/types/display_spec.rb`, so they
|
14
|
+
should remain accurate.
|
15
|
+
|
16
|
+
### Adding & Updating
|
17
|
+
|
18
|
+
**_Don't update the values here, they will get overwritten!_**
|
19
|
+
|
20
|
+
I keep the values in a Quip doc at
|
21
|
+
|
22
|
+
<https://beiarea.quip.com/iBBRAuEZyxui>
|
23
|
+
|
24
|
+
because it's just a lot easier to manage in an actual spreadsheet (generally,
|
25
|
+
there have been some weird corner cases like columns not liking the word "true"
|
26
|
+
to be spelled like anything other than "TRUE", weird Unicode whitespace that
|
27
|
+
Quip sticks in that needs to be sub'd out, etc.).
|
28
|
+
|
29
|
+
There's a script at
|
30
|
+
|
31
|
+
[//dev/packages/gems/nrser/dev/bin/pull_types_display_table.rb][pull script]
|
32
|
+
|
33
|
+
[pull script]: ../../../../dev/bin/pull_types_display_table.rb
|
34
|
+
|
35
|
+
that will pull the Quip spreadsheet contents and **overwrite** what's here. Even
|
36
|
+
though the spreadsheet is world-viewable, you still seem to nee a Quip API token
|
37
|
+
to access it via the API.
|
38
|
+
|
39
|
+
> ##### NOTE #####
|
40
|
+
>
|
41
|
+
> The `source` column assumes you have {NRSER::Types} available as `t`, as
|
42
|
+
>
|
43
|
+
> require 'nrser/refinements/types'
|
44
|
+
> using NRSER::Types
|
45
|
+
>
|
46
|
+
> provides. Due to how refinements bind, you may need to set `t` up as a global
|
47
|
+
> in certain testing, REPL or other funky situations.
|
48
|
+
|
49
|
+
| `source` | `#name` | `#symbolic` | `#explain` |
|
50
|
+
| -------------------------------------------- | ---------------------------- | ---------------------- | ------------------------------------------------------------- |
|
51
|
+
| `t.Numeric` | `Numeric` | `Numeric` | `Numeric` |
|
52
|
+
| `t.Integer` | `Integer` | `ℤ` | `Integer` |
|
53
|
+
| `t.PositiveInteger` | `PositiveInteger` | `ℤ⁺` | `(Integer & Bounded<min=1>)` |
|
54
|
+
| `t.NegativeInteger` | `NegativeInteger` | `ℤ⁻` | `(Integer & Bounded<max=-1>)` |
|
55
|
+
| `t.NonNegativeInteger` | `NonNegativeInteger` | `ℕ⁰` | `(Integer & Bounded<min=0>)` |
|
56
|
+
| `t.Boolean` | `Boolean` | `Boolean` | `(Is<true> \| Is<false>)` |
|
57
|
+
| `t.Bounded( min: 1, max: 2 )` | `Bounded<min=1, max=2>` | `(1..2)` | `Bounded<min=1, max=2>` |
|
58
|
+
| `t.Bounded( min: 1 )` | `Bounded<min=1>` | `(1..)` | `Bounded<min=1>` |
|
59
|
+
| `t.Array` | `Array` | `[*]` | `Array` |
|
60
|
+
| `t.Array( t.Integer )` | `Array<Integer>` | `[ℤ]` | `Array<Integer>` |
|
61
|
+
| `t.Attributes(x: t.Integer, y: t.String)` | `(#x→Integer & #y→String)` | `(#x→ℤ & #y→String)` | `Attributes<#x→Integer, #y→String>` |
|
62
|
+
| `~t.Integer` | `¬Integer` | `*∖ℤ` | `Not<Integer>` |
|
63
|
+
| `t.ArrayPair` | `Array<(*, *)>` | `[*, *]` | `Array<(Top, Top)>` |
|
64
|
+
| `t.HashPair` | `Hash<(*, *)>` | `(*=>*)` | `(Hash & Attributes<#length→Is<1>>)` |
|
65
|
+
| `t.Pair` | `Pair` | `(*, *)` | `(Array<(Top, Top)> \| (Hash & Attributes<#length→Is<1>>))` |
|
66
|
+
| `t.Hash keys: t.String, values: t.Integer` | `Hash<String, Integer>` | `{String=>ℤ}` | `Hash<String, Integer>` |
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# ========================================================================
|
6
|
+
|
7
|
+
# Project / Package
|
8
|
+
# ------------------------------------------------------------------------
|
9
|
+
|
10
|
+
require_relative './type'
|
11
|
+
|
12
|
+
|
13
|
+
# Namespace
|
14
|
+
# ========================================================================
|
15
|
+
|
16
|
+
module NRSER
|
17
|
+
module Types
|
18
|
+
|
19
|
+
|
20
|
+
# Definitions
|
21
|
+
# ========================================================================
|
22
|
+
|
23
|
+
# Type satisfied only by anything `#==` it's {#value}.
|
24
|
+
#
|
25
|
+
class Equivalent < Type
|
26
|
+
|
27
|
+
# Attributes
|
28
|
+
# ========================================================================
|
29
|
+
|
30
|
+
attr_reader :value
|
31
|
+
|
32
|
+
def initialize value, **options
|
33
|
+
super **options
|
34
|
+
@value = value
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def explain
|
39
|
+
"Equivalent<#{ value.inspect }>"
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def test? value
|
44
|
+
@value.equal? value
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def == other
|
49
|
+
equal?(other) ||
|
50
|
+
( self.class == other.class &&
|
51
|
+
@value == other.value )
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def default_symbolic
|
56
|
+
"{ x : #{ value.inspect }==x }"
|
57
|
+
end
|
58
|
+
|
59
|
+
end # class Equivalent
|
60
|
+
|
61
|
+
|
62
|
+
# @!group Equivalent Type Factories
|
63
|
+
# ----------------------------------------------------------------------------
|
64
|
+
|
65
|
+
# @!method self.Equivalent value, **options
|
66
|
+
# Satisfied by values that `value` is `#==` to (`{ x : value == x }`).
|
67
|
+
#
|
68
|
+
# @param [Object] value
|
69
|
+
# Value that all members of the type will be equal to.
|
70
|
+
#
|
71
|
+
# @param [Hash] options
|
72
|
+
# Passed to {Type#initialize}.
|
73
|
+
#
|
74
|
+
# @return [Type]
|
75
|
+
# A type whose members are all instances of Ruby's {Numeric} class.
|
76
|
+
#
|
77
|
+
def_type :Equivalent,
|
78
|
+
aliases: [ :eq ],
|
79
|
+
parameterize: :value,
|
80
|
+
&->( value, **options ) do
|
81
|
+
Equivalent.new value, **options
|
82
|
+
end
|
83
|
+
|
84
|
+
# @!endgroup Equivalent Type Factories # *************************************
|
85
|
+
|
86
|
+
|
87
|
+
# /Namespace
|
88
|
+
# ========================================================================
|
89
|
+
|
90
|
+
end # module Types
|
91
|
+
end # module NRSER
|
@@ -6,7 +6,7 @@
|
|
6
6
|
|
7
7
|
# Project / Package
|
8
8
|
# -----------------------------------------------------------------------
|
9
|
-
require 'nrser/errors/
|
9
|
+
require 'nrser/errors/type_error'
|
10
10
|
|
11
11
|
|
12
12
|
# Definitions
|
@@ -15,13 +15,7 @@ require 'nrser/errors/nicer_error'
|
|
15
15
|
# This error (or a subclass) is thrown when types fail to
|
16
16
|
# {NRSER::Types::Type.check!}.
|
17
17
|
#
|
18
|
-
class NRSER::Types::CheckError < ::TypeError
|
19
|
-
|
20
|
-
# Mixins
|
21
|
-
# ==========================================================================
|
22
|
-
|
23
|
-
include NRSER::NicerError
|
24
|
-
|
18
|
+
class NRSER::Types::CheckError < NRSER::TypeError
|
25
19
|
|
26
20
|
# Attributes
|
27
21
|
# ========================================================================
|
@@ -45,15 +39,15 @@ class NRSER::Types::CheckError < ::TypeError
|
|
45
39
|
|
46
40
|
# Construct a `NicerError`.
|
47
41
|
#
|
48
|
-
# @param [*] value
|
42
|
+
# @param [*] value
|
49
43
|
# The {#value} that failed the check.
|
50
44
|
#
|
51
|
-
# @param [NRSER::Types::Type] type
|
45
|
+
# @param [NRSER::Types::Type] type
|
52
46
|
# The type that was checked.
|
53
47
|
#
|
54
48
|
# @param details: (see NRSER::NicerError#initialize)
|
55
49
|
#
|
56
|
-
# @param
|
50
|
+
# @param [Hash] kwds
|
57
51
|
# See {NRSER::NicerError#initialize}
|
58
52
|
#
|
59
53
|
def initialize *message, value:, type:, details: nil, **kwds
|
@@ -50,13 +50,13 @@ class NRSER::Types::FromStringError < ::ArgumentError
|
|
50
50
|
#
|
51
51
|
# @param *message (see NRSER::NicerError#initialize)
|
52
52
|
#
|
53
|
-
# @param [String] string
|
53
|
+
# @param [String] string
|
54
54
|
# The string the type was trying to load a value from.
|
55
55
|
#
|
56
|
-
# @param [NRSER::Types::Type] type
|
56
|
+
# @param [NRSER::Types::Type] type
|
57
57
|
# The type that was trying to load.
|
58
58
|
#
|
59
|
-
# @param
|
59
|
+
# @param [Hash] kwds
|
60
60
|
# See {NRSER::NicerError#initialize}
|
61
61
|
#
|
62
62
|
def initialize *message, string:, type:, **kwds
|
data/lib/nrser/types/factory.rb
CHANGED
@@ -7,43 +7,40 @@
|
|
7
7
|
# Stdlib
|
8
8
|
# -----------------------------------------------------------------------
|
9
9
|
|
10
|
-
|
11
|
-
# -----------------------------------------------------------------------
|
10
|
+
require 'set'
|
12
11
|
|
13
12
|
# Project / Package
|
14
13
|
# -----------------------------------------------------------------------
|
15
14
|
|
15
|
+
require 'nrser/errors/type_error'
|
16
16
|
|
17
|
-
#
|
17
|
+
# Namespace
|
18
18
|
# =======================================================================
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
# =======================================================================
|
20
|
+
module NRSER
|
21
|
+
module Types
|
23
22
|
|
24
23
|
|
25
24
|
# Definitions
|
26
25
|
# =======================================================================
|
27
26
|
|
28
|
-
|
29
|
-
#
|
30
|
-
|
27
|
+
# Mixin that provides {#def_type} to create type factory class methods.
|
28
|
+
#
|
29
|
+
# Mixed in to {NRSER::Types}, but can also be mixed in by libraries using
|
30
|
+
# the types system to define their own types.
|
31
|
+
#
|
32
|
+
module Factory
|
31
33
|
|
32
34
|
# Define a type factory.
|
33
35
|
#
|
34
|
-
#
|
35
|
-
# @param [Hash] **options
|
36
|
-
# Common type construction options, see {Type#initialize}.
|
37
|
-
#
|
38
|
-
# @return [NRSER::Types::Type]
|
39
|
-
# The type.
|
36
|
+
# @deprecated Use {#def_type}
|
40
37
|
#
|
41
38
|
def def_factory name, maybe: true, aliases: [], &body
|
42
39
|
define_singleton_method name, &body
|
43
|
-
|
40
|
+
|
44
41
|
aliases.each do |alias_name|
|
45
42
|
if self.respond_to? alias_name
|
46
|
-
alias_name = alias_name + '_'
|
43
|
+
alias_name = alias_name.to_s + '_'
|
47
44
|
end
|
48
45
|
|
49
46
|
singleton_class.send :alias_method, alias_name, name
|
@@ -84,10 +81,280 @@ module NRSER::Types::Factory
|
|
84
81
|
end
|
85
82
|
|
86
83
|
aliases.each do |alias_name|
|
87
|
-
|
84
|
+
maybe_alias_name = "#{ alias_name }?"
|
85
|
+
|
86
|
+
if self.respond_to? maybe_alias_name
|
87
|
+
maybe_alias_name = "#{ alias_name }_?"
|
88
|
+
end
|
89
|
+
|
90
|
+
singleton_class.send :alias_method, maybe_alias_name, maybe_name
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end # #def_factory
|
95
|
+
|
96
|
+
|
97
|
+
# Define a new type factory class method.
|
98
|
+
#
|
99
|
+
# @param [#to_s] name
|
100
|
+
# The name of the type. Will be normalized to a string via it's `#to_s`
|
101
|
+
# method.
|
102
|
+
#
|
103
|
+
# @param [Enumerable<#to_s>] aliases
|
104
|
+
# Aliases to add for the type factory method. Normalized to a {Set} of
|
105
|
+
# strings before use.
|
106
|
+
#
|
107
|
+
# @param [nil | Proc<(s:String): MEMBER>] from_s
|
108
|
+
# Optional function to load type members from strings.
|
109
|
+
#
|
110
|
+
# @param [Boolean] maybe
|
111
|
+
# When `true` will add `?`-suffixed versions of the factory that
|
112
|
+
# create {.Maybe} versions of the type.
|
113
|
+
#
|
114
|
+
# @param [nil | false | Proc<(*args, &block): String>] default_name
|
115
|
+
#
|
116
|
+
# Controls what - if anything - is done with the `name:` value in
|
117
|
+
# `options` when the factory method is called.
|
118
|
+
#
|
119
|
+
# Everything here is done *before* the `options` are passed to the
|
120
|
+
# factory method's `&body`, so the body will see any `name:` option that
|
121
|
+
# is filled in.
|
122
|
+
#
|
123
|
+
# When...
|
124
|
+
#
|
125
|
+
# - `nil` - when...
|
126
|
+
# - `parameterize:` is `nil` - `name` will be used as the created
|
127
|
+
# type's {Type#name} unless a `name:` option is explicitly
|
128
|
+
# provided by the factory caller.
|
129
|
+
#
|
130
|
+
# This situation covers "static" types that will only differ by
|
131
|
+
# their `options` - things like custom {Type#from_s},
|
132
|
+
# {Type#to_data}, etc.. Really, these are more like aliases since
|
133
|
+
# their member sets are identical.
|
134
|
+
#
|
135
|
+
# - `parameterize:` is *not* `nil` - the `name:` option will be left
|
136
|
+
# as `nil` if none is provided by the factory caller.
|
137
|
+
#
|
138
|
+
# - `false` - the `name:` option will not be touched - it will stay `nil`
|
139
|
+
# unless the factory caller provides a value.
|
140
|
+
#
|
141
|
+
# - `Proc<(*args, &block)->String>` - when the factory caller does not
|
142
|
+
# provide a `name:` option this function will be called with the
|
143
|
+
# arguments (including `options`) and block (if any) that the
|
144
|
+
# factory method was called with, and is expected to return a {String}
|
145
|
+
# that will be set as the `name:` option.
|
146
|
+
#
|
147
|
+
# @param [nil | Symbol | Array<Symbol>] parameterize
|
148
|
+
# Indicates if the type is parameterized, and, if so, what arguments
|
149
|
+
# it's parameterized over.
|
150
|
+
#
|
151
|
+
# Right now, just prevents the `name:` being assigned as the type's name
|
152
|
+
# when one isn't specified (see the `default_name:` parameter a
|
153
|
+
# complete(-ly confusing) explanation.
|
154
|
+
#
|
155
|
+
# The hope was to use this for something useful in the future, but who the
|
156
|
+
# hell knows to be honest.
|
157
|
+
#
|
158
|
+
# @param [nil | String | Proc<(*args, &block): String>] symbolic
|
159
|
+
# Controls what's done with the `symbolic:` option - which affects what
|
160
|
+
# the new type's {Type#symbolic} will return - when the factory methods
|
161
|
+
# are called with the `symbolic:` option `nil` or missing:
|
162
|
+
#
|
163
|
+
# - `nil` - nothing changes. `nil` goes in to the type initialization
|
164
|
+
# method, and should end up as a `symbolic: nil` option in
|
165
|
+
# {Type#initialize}.
|
166
|
+
#
|
167
|
+
# - `String` - This value is used. Makes sense for `static` types
|
168
|
+
# who only accept options that don't affect the members of the types
|
169
|
+
# they produce.
|
170
|
+
#
|
171
|
+
# - `Proc<(*args, &block)->String>` - Gets called with the arguments
|
172
|
+
# (including `options`) and block (if any) the factory method is called
|
173
|
+
# with and is expected to return the symbolic string representation.
|
174
|
+
#
|
175
|
+
# @param [nil | Proc<(MEMBER): DATA>] to_data
|
176
|
+
# I'm getting tired of writing this shit so I'm going to be brief here -
|
177
|
+
# provides a value that will get set as the `to_data:` option and become
|
178
|
+
# responsible for turning type member values into "data" (think things
|
179
|
+
# you can JSON encode).
|
180
|
+
#
|
181
|
+
# @param [Proc] body
|
182
|
+
# The type factory method body. **MUST** return a {Type} instance.
|
183
|
+
#
|
184
|
+
# @return [nil]
|
185
|
+
# Just creates class methods on whatever it's mixed in to.
|
186
|
+
#
|
187
|
+
def def_type name,
|
188
|
+
aliases: [],
|
189
|
+
from_s: nil,
|
190
|
+
maybe: true,
|
191
|
+
default_name: nil,
|
192
|
+
parameterize: nil,
|
193
|
+
symbolic: nil,
|
194
|
+
to_data: nil,
|
195
|
+
&body
|
196
|
+
# Normalize to strings
|
197
|
+
name = name.to_s
|
198
|
+
aliases = aliases.map( &:to_s ).to_set
|
199
|
+
|
200
|
+
unless default_name.nil? ||
|
201
|
+
default_name == false ||
|
202
|
+
default_name.is_a?( Proc )
|
203
|
+
raise NRSER::TypeError,
|
204
|
+
"`default_name:` keyword argument must be {nil}, {false} or a {Proc},",
|
205
|
+
"found", default_name,
|
206
|
+
expected: [ nil, false, Proc ],
|
207
|
+
received: default_name
|
208
|
+
end
|
209
|
+
|
210
|
+
# Count the required params so we know if we can take the last one as
|
211
|
+
# options or not.
|
212
|
+
#
|
213
|
+
# For this to work, {#def_type} has to be called like
|
214
|
+
#
|
215
|
+
# def_type name,
|
216
|
+
# &->( arg, **option ) do
|
217
|
+
# # ...
|
218
|
+
# end
|
219
|
+
#
|
220
|
+
# because the `do |arg, **option|` form marks *all* arguments as optional.
|
221
|
+
#
|
222
|
+
num_req_params = body.parameters.count { |type, name| type == :req }
|
223
|
+
|
224
|
+
define_singleton_method name, &->(*args, &block) do
|
225
|
+
if args.length > num_req_params &&
|
226
|
+
args[-1].is_a?( Hash ) &&
|
227
|
+
args[-1].keys.all? { |k| k.is_a? Symbol }
|
228
|
+
options = args[-1]
|
229
|
+
args = args[0..-2]
|
230
|
+
else
|
231
|
+
options = {}
|
232
|
+
end
|
233
|
+
|
234
|
+
if args.length < num_req_params
|
235
|
+
raise ArgumentError,
|
236
|
+
"wrong number of arguments (given #{ args.length }, " +
|
237
|
+
"expected #{ num_req_params })"
|
238
|
+
end
|
239
|
+
|
240
|
+
# If `default_name` is {false} it means we don't fuck with the name at
|
241
|
+
# all, and if it's not `nil` it's been user-set.
|
242
|
+
if options[:name].nil? && default_name != false
|
243
|
+
if default_name.is_a? Proc
|
244
|
+
options[:name] = default_name.call *args, &block
|
245
|
+
|
246
|
+
# The "old" (like, two days ago) way of signalling not to write `name`
|
247
|
+
# in (before we had `default_name=false`) was to tell {#def_type} that
|
248
|
+
# you were parameterizing, in which case it wouldn't make any sense
|
249
|
+
# to write `name` in for all the types coming out.
|
250
|
+
#
|
251
|
+
# And it still doesn't, though - despite high hopes for a future of
|
252
|
+
# parameterized enlightenment - that's all we've been using
|
253
|
+
# `parameterize` for at the time, and there will def be some argument
|
254
|
+
# structure kinks to work out in order to actually do something useful
|
255
|
+
# with the information, though I'm sure that is solvable.
|
256
|
+
#
|
257
|
+
# So I'm saying I wouldn't be surprised if `parameterize` ended up
|
258
|
+
# never really going anywhere except away.
|
259
|
+
elsif parameterize.nil?
|
260
|
+
options[:name] = name
|
261
|
+
end
|
262
|
+
end # if options[:name].nil? && default_name != false
|
263
|
+
|
264
|
+
options[:from_s] ||= from_s
|
265
|
+
|
266
|
+
options[:symbolic] ||= case symbolic
|
267
|
+
when Proc
|
268
|
+
symbolic.call *args, &block
|
269
|
+
else
|
270
|
+
symbolic
|
271
|
+
end
|
272
|
+
|
273
|
+
options[:to_data] ||= to_data
|
274
|
+
|
275
|
+
body.call( *args, **options, &block ).tap { |type|
|
276
|
+
unless type.is_a? Type
|
277
|
+
raise NRSER::TypeError.new \
|
278
|
+
"Type factory method #{ self.safe_name }.#{ __method__ } did",
|
279
|
+
"not return a {NRSER::Types::Type}! All type factory methods",
|
280
|
+
"**MUST** always return type instances. This method needs to be",
|
281
|
+
"fixed."
|
282
|
+
end
|
283
|
+
}
|
284
|
+
end
|
285
|
+
|
286
|
+
underscored = name.underscore
|
287
|
+
|
288
|
+
# Underscored names are also available!
|
289
|
+
unless name == underscored ||
|
290
|
+
aliases.include?( underscored )
|
291
|
+
aliases << underscored
|
292
|
+
end
|
293
|
+
|
294
|
+
aliases.each do |alias_name|
|
295
|
+
if self.respond_to? alias_name
|
296
|
+
alias_name = alias_name.to_s + '_'
|
297
|
+
end
|
298
|
+
|
299
|
+
singleton_class.send :alias_method, alias_name, name
|
300
|
+
end
|
301
|
+
|
302
|
+
if maybe && !name.end_with?( '?' )
|
303
|
+
maybe_name = "#{ name }?"
|
304
|
+
|
305
|
+
if self.respond_to? maybe_name
|
306
|
+
maybe_name = "#{ name }_?"
|
307
|
+
end
|
308
|
+
|
309
|
+
# HACK Ugh maybe I wrote this quick to fix it, not sure if it's a decent
|
310
|
+
# idea.. basically, need to figure out what `options` keys go
|
311
|
+
# to {.maybe} and which ones go to the regular factory... matters
|
312
|
+
# for shit like {.attrs} and {.hash_type} 'cause they use option
|
313
|
+
# keys (whether they *should* is something I've debated... sigh,
|
314
|
+
# it is what it is for now).
|
315
|
+
#
|
316
|
+
# So the options that go to {.maybe} just go strait through to
|
317
|
+
# {Type#initialize}, so just grab that method, see what keys it
|
318
|
+
# takes, and then can slice and dice off that...
|
319
|
+
#
|
320
|
+
maybe_option_keys = Set.new \
|
321
|
+
NRSER::Types::Type.
|
322
|
+
instance_method( :initialize ).
|
323
|
+
parameters.
|
324
|
+
select { |param_type, name| param_type == :key }.
|
325
|
+
map { |param_type, name| name }
|
326
|
+
|
327
|
+
define_singleton_method maybe_name do |*args, **options|
|
328
|
+
maybe_options = options.slice *maybe_option_keys
|
329
|
+
factory_options = options.except *maybe_option_keys
|
330
|
+
|
331
|
+
NRSER::Types.maybe \
|
332
|
+
public_send( name, *args, **factory_options ),
|
333
|
+
**maybe_options
|
334
|
+
end
|
335
|
+
|
336
|
+
aliases.each do |alias_name|
|
337
|
+
maybe_alias_name = "#{ alias_name }?"
|
338
|
+
|
339
|
+
if self.respond_to? maybe_alias_name
|
340
|
+
maybe_alias_name = "#{ alias_name }_?"
|
341
|
+
end
|
342
|
+
|
343
|
+
singleton_class.send :alias_method, maybe_alias_name, maybe_name
|
88
344
|
end
|
89
345
|
|
90
346
|
end
|
91
|
-
|
347
|
+
|
348
|
+
nil
|
349
|
+
end # #def_type
|
350
|
+
|
92
351
|
|
93
|
-
end # module
|
352
|
+
end # module Factory
|
353
|
+
|
354
|
+
|
355
|
+
# /Namespace
|
356
|
+
# =======================================================================
|
357
|
+
|
358
|
+
end # module Types
|
359
|
+
end # module NRSER
|
360
|
+
|