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,167 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
# Project / Package
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
require 'nrser/errors/argument_error'
|
10
|
+
require 'nrser/labs/i8'
|
11
|
+
|
12
|
+
require_relative './struct/hash'
|
13
|
+
require_relative './struct/vector'
|
14
|
+
|
15
|
+
|
16
|
+
# Refinements
|
17
|
+
# ========================================================================
|
18
|
+
|
19
|
+
require 'nrser/refinements/types'
|
20
|
+
using NRSER::Types
|
21
|
+
|
22
|
+
|
23
|
+
# Namespace
|
24
|
+
# ========================================================================
|
25
|
+
|
26
|
+
module I8
|
27
|
+
|
28
|
+
|
29
|
+
# Definitions
|
30
|
+
# ========================================================================
|
31
|
+
|
32
|
+
# `I8::Struct` is an immutable rendition of the Ruby standard lib `::Struct`
|
33
|
+
# using the {NRSER::Props} system.
|
34
|
+
#
|
35
|
+
# It's intended to help make it quick and easy to create little immutable
|
36
|
+
# propertied objects, with all the type-checking and serialization stuff
|
37
|
+
# that comes with {NRSER::Props}.
|
38
|
+
#
|
39
|
+
# `Struct` itself is a module with a {.new} method that creates new subclasses
|
40
|
+
# of either {I8::Struct::Hash} or {I8::Struct::Vector}, which themselves
|
41
|
+
# are respective subclasses of {I8::Hash} and {I8::Vector}, and include
|
42
|
+
# {NRSER::Props::Immutable::Hash} and {NRSER::Props::Immutable::Vector}.
|
43
|
+
#
|
44
|
+
# ### Identifying Classes Built by `I8::Struct`
|
45
|
+
#
|
46
|
+
# Both {I8::Struct::Hash} and {I8::Struct::Vector} also include `I8::Struct`
|
47
|
+
# itself for the convenience of shit like:
|
48
|
+
#
|
49
|
+
# Point = I8::Struct.new x: t.int, y: t.int
|
50
|
+
#
|
51
|
+
# Point.included_modules.include? I8::Struct
|
52
|
+
# # => true
|
53
|
+
#
|
54
|
+
# p = Point.new x: 1, y: 2
|
55
|
+
# p.is_a? I8::Struct
|
56
|
+
# # => true
|
57
|
+
#
|
58
|
+
# `I8::Struct` has only class (static) methods, so no functionality is
|
59
|
+
# actually added from `include I8::Struct`.
|
60
|
+
#
|
61
|
+
# ### Gotchas
|
62
|
+
#
|
63
|
+
# The code below *doesn't* work how you might want or expect it:
|
64
|
+
#
|
65
|
+
# Point = I8::Struct.new x: t.int, y: t.int
|
66
|
+
# Point.is_a? I8::Struct
|
67
|
+
# # => false
|
68
|
+
#
|
69
|
+
# Opposed to how {Class} works:
|
70
|
+
#
|
71
|
+
# C = Class.new
|
72
|
+
# C.is_a? Class
|
73
|
+
# # => true
|
74
|
+
#
|
75
|
+
# However, this *is* the same as how the stdlib's [::Struct][] behaves:
|
76
|
+
#
|
77
|
+
# S = ::Struct.new :x
|
78
|
+
# S.is_a? ::Struct
|
79
|
+
# # => false
|
80
|
+
#
|
81
|
+
# [::Struct]: https://ruby-doc.org/core/Struct.html
|
82
|
+
#
|
83
|
+
# @example One-Liner
|
84
|
+
# Person = I8::Struct.new name: t.non_empty_str, age: t.non_neg_int
|
85
|
+
# nrser = Person.new name: "Neil", age: 34
|
86
|
+
#
|
87
|
+
# @example Extend a `I8::Struct` to add methods
|
88
|
+
# class Rectangle \
|
89
|
+
# < I8::Struct.new( width: t.non_neg_int, length: t.non_neg_int )
|
90
|
+
#
|
91
|
+
# def area
|
92
|
+
# width * length
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# end # class Rectangle
|
96
|
+
#
|
97
|
+
module Struct
|
98
|
+
|
99
|
+
# Check args that were passed to {.new}.
|
100
|
+
#
|
101
|
+
# @!visibility private
|
102
|
+
#
|
103
|
+
# @param vector_prop_defs (see .new)
|
104
|
+
# @param hash_prop_defs (see .new)
|
105
|
+
#
|
106
|
+
def self.check_new_args! vector_prop_defs, hash_prop_defs
|
107
|
+
|
108
|
+
unless (vector_prop_defs.empty? && !hash_prop_defs.empty?) ||
|
109
|
+
(!vector_prop_defs.empty? && hash_prop_defs.empty?)
|
110
|
+
|
111
|
+
raise NRSER::ArgumentError.new \
|
112
|
+
"Exactly one of *args or **kwds must be empty",
|
113
|
+
|
114
|
+
args: vector_prop_defs,
|
115
|
+
|
116
|
+
kwds: hash_prop_defs,
|
117
|
+
|
118
|
+
details: -> {%{
|
119
|
+
{I8::Struct.new} proxies to either
|
120
|
+
|
121
|
+
1. {I8::Struct::Vector.new}
|
122
|
+
2. {I8::Struct::Hash.new}
|
123
|
+
|
124
|
+
depending on *where* the property definitions are passed:
|
125
|
+
|
126
|
+
1. Positionally in `*args` -> {I8::Struct::Vector.new}
|
127
|
+
2. By name in `**kwds` -> {I8::Struct::Hash.new}
|
128
|
+
|
129
|
+
Examples:
|
130
|
+
|
131
|
+
1. Create a Point struct backed by an {I8::Vector}:
|
132
|
+
|
133
|
+
Point = I8::Struct.new [x: t.int], [y: t.int]
|
134
|
+
|
135
|
+
2. Create a Point struct backed by an {I8::Hash}:
|
136
|
+
|
137
|
+
Point = I8::Struct.new x: t.int, y: t.int
|
138
|
+
|
139
|
+
}}
|
140
|
+
|
141
|
+
end # unless vector_prop_defs.empty? XOR hash_prop_defs.empty?
|
142
|
+
|
143
|
+
end # .check_new_args!
|
144
|
+
|
145
|
+
private_class_method :check_new_args!
|
146
|
+
|
147
|
+
|
148
|
+
def self.new *vector_prop_defs, **hash_prop_defs, &class_body
|
149
|
+
check_new_args! vector_prop_defs, hash_prop_defs
|
150
|
+
|
151
|
+
if !vector_prop_defs.empty?
|
152
|
+
raise NotImplementedError.new "I8::Struct::Vector is TODO, sorry"
|
153
|
+
# I8::Struct::Vector.new *vector_prop_defs, &class_body
|
154
|
+
else
|
155
|
+
I8::Struct::Hash.new **hash_prop_defs, &class_body
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
end # module Struct
|
161
|
+
|
162
|
+
|
163
|
+
# /Namespace
|
164
|
+
# ========================================================================
|
165
|
+
|
166
|
+
end # module I8
|
167
|
+
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
# Project / Package
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
|
10
|
+
require 'nrser/errors/argument_error'
|
11
|
+
require 'nrser/props/immutable/hash'
|
12
|
+
|
13
|
+
|
14
|
+
# Refinements
|
15
|
+
# ========================================================================
|
16
|
+
|
17
|
+
require 'nrser/refinements/types'
|
18
|
+
using NRSER::Types
|
19
|
+
|
20
|
+
|
21
|
+
# Namespace
|
22
|
+
# ========================================================================
|
23
|
+
|
24
|
+
module I8
|
25
|
+
module Struct
|
26
|
+
|
27
|
+
|
28
|
+
# Definitions
|
29
|
+
# ========================================================================
|
30
|
+
|
31
|
+
# Base class for {I8::Hash}-based "propertied" ({NRSER::Props}) structs
|
32
|
+
# created by {I8::Struct.new}.
|
33
|
+
#
|
34
|
+
# @see I8::Struct
|
35
|
+
# @see NRSER::Props
|
36
|
+
# @see NRSER::Props::Immutable::Hash
|
37
|
+
#
|
38
|
+
class Hash < I8::Hash
|
39
|
+
|
40
|
+
include I8::Struct
|
41
|
+
include NRSER::Props::Immutable::Hash
|
42
|
+
|
43
|
+
# This method does two totally different things depending on what `self`
|
44
|
+
# is:
|
45
|
+
#
|
46
|
+
# 1. If `self` is {I8::Struct::Hash}, we want to build a new struct class.
|
47
|
+
#
|
48
|
+
# 2. Otherwise, we want to defer up to `super` to create a new instance
|
49
|
+
# of `self`.
|
50
|
+
#
|
51
|
+
# @overload self.new **prop_defs, &class_body
|
52
|
+
# When `self` **is** {I8::Struct::Hash}, the method builds a new
|
53
|
+
# subclass, along the lines of how {I8::Struct.new} and `::Struct.new`
|
54
|
+
# work.
|
55
|
+
#
|
56
|
+
# @example
|
57
|
+
# Point = I8::Struct::Hash.new x: t.int, y: t.int
|
58
|
+
# # => Point
|
59
|
+
#
|
60
|
+
# @param [Hash<Symbol, (NRSER::Types::Type | Hash<Symbol, Object>)>] prop_defs
|
61
|
+
# Map of property names to the value(s) needed to create them.
|
62
|
+
#
|
63
|
+
# `prop_defs` values can each be:
|
64
|
+
#
|
65
|
+
# 1. {NRSER::Types::Type} - used as the {NRSER::Props::Prop#type}, with
|
66
|
+
# all the {NRSER::Props::Prop}'s other values left as defaults.
|
67
|
+
#
|
68
|
+
# 2. {Hash<Symbol, Object>} - full prop configuration, passed in to
|
69
|
+
# {NRSER::Props::Metadata#prop}.
|
70
|
+
#
|
71
|
+
# @param [Proc?] class_body
|
72
|
+
# Optional block to evaluate as the new class's body.
|
73
|
+
#
|
74
|
+
# @return [Class<I8::Struct::Hash>]
|
75
|
+
# New structure class.
|
76
|
+
#
|
77
|
+
# @overload self.new *args, **kwds, &block
|
78
|
+
# When `self` **is not** {I8::Struct::Hash}, this method simply forwards
|
79
|
+
# all parameters up to it's super method, which will create a new
|
80
|
+
# instance as usual.
|
81
|
+
#
|
82
|
+
# @example
|
83
|
+
# Point < I8::Struct::Hash
|
84
|
+
# # => true
|
85
|
+
#
|
86
|
+
# Point.new x: 1, y: 2 # Passes through to super method to construct
|
87
|
+
# # => Point[:y => 2, :x => 1]
|
88
|
+
#
|
89
|
+
# @return [I8::Struct::Hash]
|
90
|
+
# New instance.
|
91
|
+
#
|
92
|
+
def self.new *args, **kwds, &block
|
93
|
+
# Are we {I8::Struct::Hash}? (See method doc).
|
94
|
+
if self == I8::Struct::Hash
|
95
|
+
# Yes, we are. Time to build a new struct class.
|
96
|
+
|
97
|
+
# Make sure we weren't given an positional `args`.
|
98
|
+
unless args.empty?
|
99
|
+
raise NRSER::ArgumentError.new \
|
100
|
+
"Can not supply positional args when building new",
|
101
|
+
"{I8::Struct::Hash}",
|
102
|
+
args: args,
|
103
|
+
kwds: kwds
|
104
|
+
end
|
105
|
+
|
106
|
+
# Create the new subclass
|
107
|
+
Class.new( I8::Struct::Hash ) do
|
108
|
+
kwds.each do |name, value|
|
109
|
+
prop_kwds = t.match value,
|
110
|
+
t.type, ->( type ) {{ type: type }},
|
111
|
+
t.hash_, value
|
112
|
+
|
113
|
+
prop name, **prop_kwds
|
114
|
+
end
|
115
|
+
|
116
|
+
class_exec &block if block
|
117
|
+
end
|
118
|
+
|
119
|
+
else
|
120
|
+
# No, we are a built struct. Defer up to `super` to create an instance.
|
121
|
+
|
122
|
+
# NOTE Weirdness ahead. See NOTE in {I8::Struct::Vector.new}
|
123
|
+
if kwds.empty?
|
124
|
+
super( *args, &block )
|
125
|
+
else
|
126
|
+
super( *args, **kwds, &block )
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end # .new
|
131
|
+
|
132
|
+
end # class Hash
|
133
|
+
|
134
|
+
|
135
|
+
# /Namespace
|
136
|
+
# ========================================================================
|
137
|
+
|
138
|
+
end # module Struct
|
139
|
+
end # module I8
|
140
|
+
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
# Project / Package
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
|
10
|
+
require 'nrser/errors/argument_error'
|
11
|
+
require 'nrser/props/immutable/vector'
|
12
|
+
|
13
|
+
|
14
|
+
# Refinements
|
15
|
+
# ========================================================================
|
16
|
+
|
17
|
+
require 'nrser/refinements/types'
|
18
|
+
using NRSER::Types
|
19
|
+
|
20
|
+
|
21
|
+
# Namespace
|
22
|
+
# ========================================================================
|
23
|
+
|
24
|
+
module I8
|
25
|
+
module Struct
|
26
|
+
|
27
|
+
|
28
|
+
# Definitions
|
29
|
+
# ========================================================================
|
30
|
+
|
31
|
+
# Base class for {I8::Vector}-based "propertied" ({NRSER::Props}) structs
|
32
|
+
# created by {I8::Struct.new}.
|
33
|
+
#
|
34
|
+
# @see I8::Struct
|
35
|
+
# @see NRSER::Props
|
36
|
+
# @see NRSER::Props::Immutable::Vector
|
37
|
+
#
|
38
|
+
class Vector < I8::Vector
|
39
|
+
include I8::Struct
|
40
|
+
include NRSER::Props::Immutable::Vector
|
41
|
+
|
42
|
+
# Check out {I8::Struct::Hash} for a general idea of how this method works,
|
43
|
+
# I don't want to duplicate the explanation.
|
44
|
+
#
|
45
|
+
# @overload self.new *prop_defs, &class_body
|
46
|
+
# Create a new struct class.
|
47
|
+
#
|
48
|
+
# @example Using array-wrapping for prop defs
|
49
|
+
# Point = I8::Struct::Vector.new [x: t.int], [y: t.int]
|
50
|
+
# # => Point
|
51
|
+
#
|
52
|
+
# @example Using hashes for prop defs
|
53
|
+
# Point = I8::Struct::Vector.new( {x: t.int}, {y: t.int} )
|
54
|
+
# # => Point
|
55
|
+
#
|
56
|
+
# @example Providing additional prop options
|
57
|
+
# Point = I8::Struct::Vector.new \
|
58
|
+
# [x: {type: t.int, default: 0}],
|
59
|
+
# [y: {type: t.int, default: 0}]
|
60
|
+
# # => Point
|
61
|
+
#
|
62
|
+
# @param [Array] prop_defs
|
63
|
+
# Each entry must be a pair; the first entry must be the name as a
|
64
|
+
# symbol, the second is either the prop's type or a hash of options
|
65
|
+
# for creating the prop.
|
66
|
+
#
|
67
|
+
# Look at the examples.
|
68
|
+
#
|
69
|
+
# @param [Proc?] class_body
|
70
|
+
# Optional block to evaluate as the new class's body.
|
71
|
+
#
|
72
|
+
# @return [Class<I8::Struct::Vector>]
|
73
|
+
# New structure class.
|
74
|
+
#
|
75
|
+
# @overload self.new *args, **kwds, &block
|
76
|
+
# Create a new instance.
|
77
|
+
#
|
78
|
+
# @return [I8::Struct::Vector]
|
79
|
+
# New instance.
|
80
|
+
#
|
81
|
+
def self.new *args, **kwds, &block
|
82
|
+
# Are we {I8::Struct::Vector}? (See method doc).
|
83
|
+
if self == I8::Struct::Vector
|
84
|
+
unless kwds.empty?
|
85
|
+
raise NRSER::ArgumentError.new \
|
86
|
+
"Can not supply keyword args",
|
87
|
+
args: args,
|
88
|
+
kwds: kwds
|
89
|
+
end
|
90
|
+
|
91
|
+
# Unwrap `[name: type]` format
|
92
|
+
prop_defs = args.map { |prop_def|
|
93
|
+
if ::Array === prop_def &&
|
94
|
+
prop_def.length == 1 &&
|
95
|
+
::Hash === prop_def[0]
|
96
|
+
prop_def[0]
|
97
|
+
else
|
98
|
+
prop_def
|
99
|
+
end
|
100
|
+
}
|
101
|
+
|
102
|
+
# Check we have a list of pairs with label keys
|
103
|
+
t.array( t.pair( key: t.label ) ).check! prop_defs
|
104
|
+
|
105
|
+
Class.new( I8::Struct::Vector ) do
|
106
|
+
prop_defs.each_with_index do |pair, index|
|
107
|
+
name, value = pair.first
|
108
|
+
|
109
|
+
kwds = t.match value,
|
110
|
+
t.type, ->( type ) {{ type: type }},
|
111
|
+
t.hash_, value
|
112
|
+
|
113
|
+
prop name, **kwds, index: index
|
114
|
+
end
|
115
|
+
|
116
|
+
class_exec &block if block
|
117
|
+
end
|
118
|
+
|
119
|
+
else
|
120
|
+
# No, we are a built struct. Defer up to `super` to create an instance.
|
121
|
+
|
122
|
+
# NOTE This is... weird. Just doing the normal
|
123
|
+
#
|
124
|
+
# super( *args, **kwds, &block )
|
125
|
+
#
|
126
|
+
# results in `*args` becoming `[*args, {}]` up the super chain
|
127
|
+
# when `kwds` is empty.
|
128
|
+
#
|
129
|
+
# I can't say I can understand it, but I seem to be able to fix
|
130
|
+
# it.
|
131
|
+
#
|
132
|
+
if kwds.empty?
|
133
|
+
super( *args, &block )
|
134
|
+
else
|
135
|
+
super( *args, **kwds, &block )
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
end # .new
|
140
|
+
|
141
|
+
end # class Struct::Vector
|
142
|
+
|
143
|
+
|
144
|
+
# /Namespace
|
145
|
+
# ========================================================================
|
146
|
+
|
147
|
+
end # module Struct
|
148
|
+
end # module I8
|
149
|
+
|