nrser 0.3.9 → 0.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|