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,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
|
+
|