nrser 0.3.9 → 0.3.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/lib/nrser/char/alpha_numeric_sub.rb +9 -19
  3. data/lib/nrser/char/special.rb +5 -5
  4. data/lib/nrser/core_ext/array.rb +36 -13
  5. data/lib/nrser/core_ext/enumerable.rb +1 -0
  6. data/lib/nrser/core_ext/enumerable/find_map.rb +1 -1
  7. data/lib/nrser/core_ext/hash/bury.rb +3 -0
  8. data/lib/nrser/core_ext/hash/extract_values_at.rb +2 -2
  9. data/lib/nrser/core_ext/method/full_name.rb +1 -1
  10. data/lib/nrser/core_ext/module/method_objects.rb +1 -1
  11. data/lib/nrser/core_ext/module/source_locations.rb +27 -15
  12. data/lib/nrser/core_ext/object/lazy_var.rb +1 -1
  13. data/lib/nrser/core_ext/pathname.rb +67 -12
  14. data/lib/nrser/core_ext/pathname/subpath.rb +86 -0
  15. data/lib/nrser/core_ext/string.rb +28 -1
  16. data/lib/nrser/core_ext/symbol.rb +11 -12
  17. data/lib/nrser/errors/README.md +154 -0
  18. data/lib/nrser/errors/attr_error.rb +146 -53
  19. data/lib/nrser/errors/count_error.rb +61 -12
  20. data/lib/nrser/errors/nicer_error.rb +42 -71
  21. data/lib/nrser/errors/value_error.rb +53 -58
  22. data/lib/nrser/functions.rb +0 -2
  23. data/lib/nrser/functions/enumerable.rb +5 -17
  24. data/lib/nrser/functions/enumerable/associate.rb +14 -5
  25. data/lib/nrser/functions/enumerable/find_all_map.rb +1 -1
  26. data/lib/nrser/functions/enumerable/include_slice/array_include_slice.rb +1 -1
  27. data/lib/nrser/functions/hash/bury.rb +2 -12
  28. data/lib/nrser/functions/merge_by.rb +2 -2
  29. data/lib/nrser/functions/module/method_objects.rb +2 -2
  30. data/lib/nrser/functions/path.rb +185 -165
  31. data/lib/nrser/functions/path/normalized.rb +84 -0
  32. data/lib/nrser/functions/string.rb +4 -4
  33. data/lib/nrser/functions/text/README.md +4 -0
  34. data/lib/nrser/functions/text/format.rb +53 -0
  35. data/lib/nrser/functions/text/indentation.rb +6 -6
  36. data/lib/nrser/functions/text/word_wrap.rb +2 -2
  37. data/lib/nrser/functions/tree/map_leaves.rb +3 -3
  38. data/lib/nrser/functions/tree/map_tree.rb +2 -2
  39. data/lib/nrser/functions/tree/transform.rb +1 -18
  40. data/lib/nrser/gem_ext/README.md +4 -0
  41. data/lib/nrser/labs/README.md +8 -0
  42. data/lib/nrser/labs/config.rb +163 -0
  43. data/lib/nrser/labs/i8.rb +49 -159
  44. data/lib/nrser/labs/i8/struct.rb +167 -0
  45. data/lib/nrser/labs/i8/struct/hash.rb +140 -0
  46. data/lib/nrser/labs/i8/struct/vector.rb +149 -0
  47. data/lib/nrser/labs/i8/surjection.rb +211 -0
  48. data/lib/nrser/labs/lots/consumer.rb +19 -0
  49. data/lib/nrser/labs/lots/parser.rb +21 -1
  50. data/lib/nrser/labs/stash.rb +4 -4
  51. data/lib/nrser/log.rb +25 -21
  52. data/lib/nrser/log/appender/sync.rb +15 -11
  53. data/lib/nrser/log/formatters/color.rb +0 -3
  54. data/lib/nrser/log/formatters/mixin.rb +4 -4
  55. data/lib/nrser/log/logger.rb +54 -6
  56. data/lib/nrser/log/mixin.rb +2 -1
  57. data/lib/nrser/log/plugin.rb +6 -6
  58. data/lib/nrser/log/types.rb +46 -29
  59. data/lib/nrser/mean_streak.rb +0 -8
  60. data/lib/nrser/mean_streak/document.rb +1 -4
  61. data/lib/nrser/message.rb +3 -3
  62. data/lib/nrser/meta/README.md +4 -0
  63. data/lib/nrser/meta/lazy_attr.rb +2 -2
  64. data/lib/nrser/meta/source/location.rb +1 -1
  65. data/lib/nrser/props.rb +34 -3
  66. data/lib/nrser/props/class_methods.rb +2 -1
  67. data/lib/nrser/props/instance_methods.rb +9 -9
  68. data/lib/nrser/props/metadata.rb +4 -12
  69. data/lib/nrser/props/mutable/stash.rb +5 -2
  70. data/lib/nrser/props/prop.rb +10 -19
  71. data/lib/nrser/rspex.rb +1 -20
  72. data/lib/nrser/rspex/example_group/describe_attribute.rb +3 -0
  73. data/lib/nrser/rspex/example_group/describe_called_with.rb +9 -4
  74. data/lib/nrser/rspex/example_group/describe_case.rb +1 -0
  75. data/lib/nrser/rspex/example_group/describe_class.rb +2 -0
  76. data/lib/nrser/rspex/example_group/describe_group.rb +1 -1
  77. data/lib/nrser/rspex/example_group/describe_instance.rb +3 -1
  78. data/lib/nrser/rspex/example_group/describe_message.rb +1 -1
  79. data/lib/nrser/rspex/example_group/describe_method.rb +64 -30
  80. data/lib/nrser/rspex/example_group/describe_response_to.rb +1 -1
  81. data/lib/nrser/rspex/example_group/describe_section.rb +4 -1
  82. data/lib/nrser/rspex/example_group/describe_sent_to.rb +1 -1
  83. data/lib/nrser/rspex/example_group/describe_setup.rb +1 -0
  84. data/lib/nrser/rspex/example_group/describe_source_file.rb +1 -1
  85. data/lib/nrser/rspex/example_group/describe_spec_file.rb +4 -2
  86. data/lib/nrser/rspex/example_group/describe_when.rb +2 -1
  87. data/lib/nrser/rspex/example_group/describe_x.rb +5 -5
  88. data/lib/nrser/rspex/format.rb +0 -15
  89. data/lib/nrser/sugar/method_missing_forwarder.rb +3 -3
  90. data/lib/nrser/sys/env/path.rb +2 -28
  91. data/lib/nrser/types.rb +63 -12
  92. data/lib/nrser/types/README.md +76 -0
  93. data/lib/nrser/types/arrays.rb +192 -137
  94. data/lib/nrser/types/attributes.rb +269 -0
  95. data/lib/nrser/types/booleans.rb +134 -83
  96. data/lib/nrser/types/bounded.rb +110 -47
  97. data/lib/nrser/types/collections.rb +119 -0
  98. data/lib/nrser/types/combinators.rb +283 -196
  99. data/lib/nrser/types/doc/display_table.md +66 -0
  100. data/lib/nrser/types/eqiuvalent.rb +91 -0
  101. data/lib/nrser/types/errors/check_error.rb +5 -11
  102. data/lib/nrser/types/errors/from_string_error.rb +3 -3
  103. data/lib/nrser/types/factory.rb +287 -20
  104. data/lib/nrser/types/hashes.rb +227 -179
  105. data/lib/nrser/types/in.rb +73 -36
  106. data/lib/nrser/types/is.rb +67 -60
  107. data/lib/nrser/types/is_a.rb +141 -84
  108. data/lib/nrser/types/labels.rb +45 -16
  109. data/lib/nrser/types/maybe.rb +6 -3
  110. data/lib/nrser/types/nil.rb +64 -27
  111. data/lib/nrser/types/not.rb +92 -34
  112. data/lib/nrser/types/numbers.rb +224 -169
  113. data/lib/nrser/types/pairs.rb +113 -89
  114. data/lib/nrser/types/paths.rb +250 -137
  115. data/lib/nrser/types/responds.rb +167 -89
  116. data/lib/nrser/types/selector.rb +234 -0
  117. data/lib/nrser/types/shape.rb +136 -65
  118. data/lib/nrser/types/strings.rb +189 -63
  119. data/lib/nrser/types/symbols.rb +83 -33
  120. data/lib/nrser/types/top.rb +89 -0
  121. data/lib/nrser/types/tuples.rb +134 -98
  122. data/lib/nrser/types/type.rb +617 -505
  123. data/lib/nrser/types/when.rb +123 -98
  124. data/lib/nrser/types/where.rb +182 -91
  125. data/lib/nrser/version.rb +1 -1
  126. data/spec/lib/nrser/core_ext/pathname/subpath_spec.rb +22 -0
  127. data/spec/lib/nrser/errors/attr_error_spec.rb +68 -0
  128. data/spec/lib/nrser/errors/count_error_spec.rb +69 -0
  129. data/spec/lib/nrser/functions/path/normalize_path_spec.rb +35 -0
  130. data/spec/lib/nrser/functions/tree/map_tree_spec.rb +74 -96
  131. data/spec/lib/nrser/functions/tree/transform_spec.rb +11 -11
  132. data/spec/lib/nrser/labs/config_spec.rb +22 -0
  133. data/spec/lib/nrser/labs/i8/struct_spec.rb +39 -0
  134. data/spec/lib/nrser/types/display_spec.rb +50 -0
  135. data/spec/lib/nrser/types/paths_spec.rb +16 -10
  136. data/spec/lib/nrser/types/selector_spec.rb +125 -0
  137. data/spec/spec_helper.rb +4 -5
  138. metadata +105 -22
  139. data/lib/nrser/types/any.rb +0 -41
  140. data/lib/nrser/types/attrs.rb +0 -213
  141. 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/nicer_error'
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 **kwds
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 **kwds
59
+ # @param [Hash] kwds
60
60
  # See {NRSER::NicerError#initialize}
61
61
  #
62
62
  def initialize *message, string:, type:, **kwds
@@ -7,43 +7,40 @@
7
7
  # Stdlib
8
8
  # -----------------------------------------------------------------------
9
9
 
10
- # Deps
11
- # -----------------------------------------------------------------------
10
+ require 'set'
12
11
 
13
12
  # Project / Package
14
13
  # -----------------------------------------------------------------------
15
14
 
15
+ require 'nrser/errors/type_error'
16
16
 
17
- # Refinements
17
+ # Namespace
18
18
  # =======================================================================
19
19
 
20
-
21
- # Declarations
22
- # =======================================================================
20
+ module NRSER
21
+ module Types
23
22
 
24
23
 
25
24
  # Definitions
26
25
  # =======================================================================
27
26
 
28
-
29
- # @todo document NRSER::Types::Factory module.
30
- module NRSER::Types::Factory
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
- # @!macro [attach] factory
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
- singleton_class.send :alias_method, "#{ alias_name }?", maybe_name
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
- end
347
+
348
+ nil
349
+ end # #def_type
350
+
92
351
 
93
- end # module NRSER::Types::Factory
352
+ end # module Factory
353
+
354
+
355
+ # /Namespace
356
+ # =======================================================================
357
+
358
+ end # module Types
359
+ end # module NRSER
360
+