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
@@ -112,7 +112,7 @@ module NRSER
|
|
112
112
|
# @param [Fixnum] max
|
113
113
|
# Max length to allow for the output string.
|
114
114
|
#
|
115
|
-
# @param [String] omission
|
115
|
+
# @param [String] omission
|
116
116
|
# The string to stick in the middle where original contents were
|
117
117
|
# removed. Defaults to the unicode ellipsis since I'm targeting the CLI
|
118
118
|
# at the moment and it saves precious characters.
|
@@ -128,7 +128,7 @@ module NRSER
|
|
128
128
|
def self.ellipsis source, max, omission: UNICODE_ELLIPSIS
|
129
129
|
return source unless source.length > max
|
130
130
|
|
131
|
-
trim_to = max - omission.length
|
131
|
+
trim_to = max - ( String === source ? omission.length : 1 )
|
132
132
|
middle = trim_to / 2
|
133
133
|
remainder = trim_to % 2
|
134
134
|
|
@@ -175,12 +175,12 @@ module NRSER
|
|
175
175
|
# Max length to allow for the output string. Result will usually be
|
176
176
|
# *less* than this unless the fallback to {NRSER.ellipsis} kicks in.
|
177
177
|
#
|
178
|
-
# @param [String] omission
|
178
|
+
# @param [String] omission
|
179
179
|
# The string to stick in the middle where original contents were
|
180
180
|
# removed. Defaults to the unicode ellipsis since I'm targeting the CLI
|
181
181
|
# at the moment and it saves precious characters.
|
182
182
|
#
|
183
|
-
# @param [String] split
|
183
|
+
# @param [String] split
|
184
184
|
# The string to tokenize the `string` parameter by. If you pass a
|
185
185
|
# {Regexp} here it might work, it might loop out, maybe.
|
186
186
|
#
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module NRSER
|
2
|
+
|
3
|
+
# Format a segment of a message.
|
4
|
+
#
|
5
|
+
# If `segment` responds to `#to_summary`, it will be called and the
|
6
|
+
# result will be returned.
|
7
|
+
#
|
8
|
+
# Strings are simply returned. Other things are inspected (for now).
|
9
|
+
#
|
10
|
+
# @param [Object] segment
|
11
|
+
# The segment.
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
# The formatted string for the segment.
|
15
|
+
#
|
16
|
+
def self.fmt_msg_segment segment
|
17
|
+
return segment.to_summary.to_s if segment.respond_to?( :to_summary )
|
18
|
+
|
19
|
+
return segment if String === segment
|
20
|
+
|
21
|
+
# TODO Do better!
|
22
|
+
segment.inspect
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
# Provides simple formatting for messages constructed as a list of
|
27
|
+
# segments.
|
28
|
+
#
|
29
|
+
# Allows you to do this sort of thing:
|
30
|
+
#
|
31
|
+
# NRSER.fmt_msg "Some stuff went wrong with the", thing,
|
32
|
+
# "and we're figuring it out, sorry. Maybe take a look at",
|
33
|
+
# something_else
|
34
|
+
#
|
35
|
+
# Which I find easier than interpolation since you quite often have to split
|
36
|
+
# across lines anyways.
|
37
|
+
#
|
38
|
+
# See {.fmt_msg_segment} for info about how each segment is formatted.
|
39
|
+
#
|
40
|
+
# This methods joins the results together
|
41
|
+
#
|
42
|
+
# @param [Array] segments
|
43
|
+
# Message segments.
|
44
|
+
#
|
45
|
+
# @return [String]
|
46
|
+
# Formatted and joined message ready to pass up to the built-in
|
47
|
+
# exception's `#initialize`.
|
48
|
+
#
|
49
|
+
def self.fmt_msg *segments
|
50
|
+
segments.map { |segment| fmt_msg_segment segment }.join( ' ' )
|
51
|
+
end # .words
|
52
|
+
|
53
|
+
end # module NRSER
|
@@ -120,11 +120,11 @@ module NRSER
|
|
120
120
|
# @param [String] text
|
121
121
|
# String text to indent tag.
|
122
122
|
#
|
123
|
-
# @param [String] marker
|
123
|
+
# @param [String] marker
|
124
124
|
# Special string to mark the start of tagged lines. If interpolated text
|
125
125
|
# lines start with this string you're going to have a bad time.
|
126
126
|
#
|
127
|
-
# @param [String] separator
|
127
|
+
# @param [String] separator
|
128
128
|
# Special string to separate the leading indent from the rest of the line.
|
129
129
|
#
|
130
130
|
# @return [String]
|
@@ -151,10 +151,10 @@ module NRSER
|
|
151
151
|
# @param [String] text
|
152
152
|
# Tagged text string.
|
153
153
|
#
|
154
|
-
# @param [String] marker
|
154
|
+
# @param [String] marker
|
155
155
|
# Must be the marker used to tag the text.
|
156
156
|
#
|
157
|
-
# @param [String] separator
|
157
|
+
# @param [String] separator
|
158
158
|
# Must be the separator used to tag the text.
|
159
159
|
#
|
160
160
|
# @return [String]
|
@@ -182,11 +182,11 @@ module NRSER
|
|
182
182
|
# Indent tag a some text via {NRSER.indent_tag}, call the block with it,
|
183
183
|
# then pass the result through {NRSER.indent_untag} and return that.
|
184
184
|
#
|
185
|
-
# @param [String] marker
|
185
|
+
# @param [String] marker
|
186
186
|
# Special string to mark the start of tagged lines. If interpolated text
|
187
187
|
# lines start with this string you're going to have a bad time.
|
188
188
|
#
|
189
|
-
# @param [String] separator
|
189
|
+
# @param [String] separator
|
190
190
|
# Must be the separator used to tag the text.
|
191
191
|
#
|
192
192
|
# @return [String]
|
@@ -9,10 +9,10 @@ module NRSER
|
|
9
9
|
# @param [String] text
|
10
10
|
# Text to word wrap.
|
11
11
|
#
|
12
|
-
# @param [Fixnum] line_width
|
12
|
+
# @param [Fixnum] line_width
|
13
13
|
# Line with in number of character to wrap at.
|
14
14
|
#
|
15
|
-
# @param [String] break_sequence
|
15
|
+
# @param [String] break_sequence
|
16
16
|
# String to join lines with.
|
17
17
|
#
|
18
18
|
# @return [String]
|
@@ -14,11 +14,11 @@ module NRSER
|
|
14
14
|
# @param [#each_pair | (#each_index & #each_with_index)] tree
|
15
15
|
# Tree to walk.
|
16
16
|
#
|
17
|
-
# @param [Array]
|
17
|
+
# @param [Array] key_path
|
18
18
|
# Key path down to `tree`.
|
19
19
|
#
|
20
|
-
# @param [
|
21
|
-
#
|
20
|
+
# @param [Proc] block
|
21
|
+
# Called with each `(key_path, value)` pair.
|
22
22
|
#
|
23
23
|
# @return [nil]
|
24
24
|
#
|
@@ -23,7 +23,7 @@ module NRSER
|
|
23
23
|
#
|
24
24
|
# @param tree (see NRSER.each_branch)
|
25
25
|
#
|
26
|
-
# @param [Boolean] prune
|
26
|
+
# @param [Boolean] prune
|
27
27
|
# When `true`, prunes out values whose labels end with `?` and values are
|
28
28
|
# `nil`.
|
29
29
|
#
|
@@ -57,7 +57,7 @@ module NRSER
|
|
57
57
|
pruned = {}
|
58
58
|
|
59
59
|
mapped.each { |key, value|
|
60
|
-
if Types.
|
60
|
+
if Types.Label.test( key ) &&
|
61
61
|
key.to_s.end_with?( '?' )
|
62
62
|
unless value.nil?
|
63
63
|
new_key = key.to_s[0..-2]
|
@@ -1,13 +1,6 @@
|
|
1
1
|
module NRSER
|
2
2
|
|
3
|
-
|
4
|
-
#
|
5
|
-
# @param [type] arg_name
|
6
|
-
# @todo Add name param description.
|
7
|
-
#
|
8
|
-
# @return [return_type]
|
9
|
-
# @todo Document return value.
|
10
|
-
#
|
3
|
+
|
11
4
|
def self.transform tree, source
|
12
5
|
map_tree( tree, prune: true ) { |value|
|
13
6
|
if value.is_a? Proc
|
@@ -39,15 +32,6 @@ module NRSER
|
|
39
32
|
end
|
40
33
|
|
41
34
|
|
42
|
-
|
43
|
-
# @todo Document transformer method.
|
44
|
-
#
|
45
|
-
# @param [type] arg_name
|
46
|
-
# @todo Add name param description.
|
47
|
-
#
|
48
|
-
# @return [return_type]
|
49
|
-
# @todo Document return value.
|
50
|
-
#
|
51
35
|
def self.transformer &block
|
52
36
|
map_tree( block.call SendSerializer.new ) { |value|
|
53
37
|
if value.is_a? SendSerializer
|
@@ -59,5 +43,4 @@ module NRSER
|
|
59
43
|
end # .transformer
|
60
44
|
|
61
45
|
|
62
|
-
|
63
46
|
end # module NRSER
|
@@ -0,0 +1,8 @@
|
|
1
|
+
`lib/nrser/labs` Directory
|
2
|
+
========================================================================
|
3
|
+
|
4
|
+
Ideas I'm trying out. No consideration for stability at all. Anything in here may be completely changed or totally disappear at any time with no warning.
|
5
|
+
|
6
|
+
**_Don't use if you want any sort of stability._**
|
7
|
+
|
8
|
+
Stuff that makes it over the "Ok, this seems like not the worst idea, I'm willing to go with it at least for now" hump will be moved out of here.
|
@@ -0,0 +1,163 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
# Stdlib
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
|
10
|
+
# Deps
|
11
|
+
# -----------------------------------------------------------------------
|
12
|
+
|
13
|
+
# Project / Package
|
14
|
+
# -----------------------------------------------------------------------
|
15
|
+
|
16
|
+
|
17
|
+
# Refinements
|
18
|
+
# =======================================================================
|
19
|
+
|
20
|
+
|
21
|
+
# Namespace
|
22
|
+
# =======================================================================
|
23
|
+
|
24
|
+
module NRSER
|
25
|
+
|
26
|
+
|
27
|
+
# Definitions
|
28
|
+
# =======================================================================
|
29
|
+
|
30
|
+
# @todo document Config class.
|
31
|
+
class Config
|
32
|
+
|
33
|
+
# Constants
|
34
|
+
# ========================================================================
|
35
|
+
|
36
|
+
|
37
|
+
# Mixins
|
38
|
+
# ========================================================================
|
39
|
+
|
40
|
+
include Hamster::Immutable
|
41
|
+
include Hamster::Enumerable
|
42
|
+
include Hamster::Associable
|
43
|
+
|
44
|
+
|
45
|
+
# Class Methods
|
46
|
+
# ========================================================================
|
47
|
+
|
48
|
+
def self.deep_trie_merge trie, source, &block
|
49
|
+
to_put = {}
|
50
|
+
|
51
|
+
source.each_pair do |key, source_value|
|
52
|
+
_, trie_value = trie.get key
|
53
|
+
|
54
|
+
to_put[ key ] = if [ trie_value, source_value ].all? { |value|
|
55
|
+
NRSER.hash_like?( value ) && value.respond_to?( :deep_merge )
|
56
|
+
}
|
57
|
+
trie_value.deep_merge source_value, &block
|
58
|
+
elsif block
|
59
|
+
block.call key, trie_value, source_value
|
60
|
+
else
|
61
|
+
source_value
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
trie.bulk_put to_put
|
66
|
+
end # .deep_trie_merge
|
67
|
+
|
68
|
+
|
69
|
+
# Attributes
|
70
|
+
# ========================================================================
|
71
|
+
|
72
|
+
|
73
|
+
# Construction
|
74
|
+
# ========================================================================
|
75
|
+
|
76
|
+
# Instantiate a new `Config`.
|
77
|
+
def initialize *sources
|
78
|
+
@sources = sources
|
79
|
+
@trie = sources.reduce( Hamster::EmptyTrie ) { |trie, source|
|
80
|
+
self.class.deep_trie_merge trie, source
|
81
|
+
}
|
82
|
+
|
83
|
+
end # #initialize
|
84
|
+
|
85
|
+
|
86
|
+
# Instance Methods
|
87
|
+
# ========================================================================
|
88
|
+
|
89
|
+
# Retrieve the value corresponding to the provided key object. If not found,
|
90
|
+
# and this `Hash` has a default block, the default block is called to provide
|
91
|
+
# the value. Otherwise, return `nil`.
|
92
|
+
#
|
93
|
+
# @example
|
94
|
+
# h = Hamster::Hash["A" => 1, "B" => 2, "C" => 3]
|
95
|
+
# h["B"] # => 2
|
96
|
+
# h.get("B") # => 2
|
97
|
+
# h.get("Elephant") # => nil
|
98
|
+
#
|
99
|
+
# # Hamster Hash with a default proc:
|
100
|
+
# h = Hamster::Hash.new("A" => 1, "B" => 2, "C" => 3) { |key| key.size }
|
101
|
+
# h.get("B") # => 2
|
102
|
+
# h.get("Elephant") # => 8
|
103
|
+
#
|
104
|
+
# @param [Array<Object>] key_path
|
105
|
+
# The key to look up
|
106
|
+
# @return [Object]
|
107
|
+
#
|
108
|
+
def get *key_path, type: nil, default: nil
|
109
|
+
first, *rest = key_path
|
110
|
+
entry = @trie.get first
|
111
|
+
|
112
|
+
value = if entry
|
113
|
+
current = entry[ 1 ]
|
114
|
+
|
115
|
+
while !current.nil? && !rest.empty?
|
116
|
+
first, *rest = rest
|
117
|
+
|
118
|
+
current = if current.respond_to? :dig
|
119
|
+
rest = [] # Short-circuit
|
120
|
+
current.dig *rest
|
121
|
+
|
122
|
+
elsif current.respond_to? :[]
|
123
|
+
current[ first ]
|
124
|
+
|
125
|
+
elsif current.respond_to? :get
|
126
|
+
current.get first
|
127
|
+
|
128
|
+
else
|
129
|
+
rest = []
|
130
|
+
default
|
131
|
+
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
current
|
136
|
+
|
137
|
+
else
|
138
|
+
default
|
139
|
+
end
|
140
|
+
|
141
|
+
parse_and_check key_path, value, type: type
|
142
|
+
|
143
|
+
end
|
144
|
+
alias :[] :get
|
145
|
+
alias :dig :get
|
146
|
+
|
147
|
+
|
148
|
+
def parse_and_check key_path, value, type: nil
|
149
|
+
return value if type.nil?
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
def each *args, &block
|
154
|
+
@trie.each *args, &block
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
end # class Config
|
159
|
+
|
160
|
+
# /Namespace
|
161
|
+
# =======================================================================
|
162
|
+
|
163
|
+
end # module NRSER
|
data/lib/nrser/labs/i8.rb
CHANGED
@@ -15,8 +15,6 @@ require 'hamster'
|
|
15
15
|
# Project / Package
|
16
16
|
# -----------------------------------------------------------------------
|
17
17
|
require 'nrser/errors/type_error'
|
18
|
-
require 'nrser/props/immutable/hash'
|
19
|
-
require 'nrser/props/immutable/vector'
|
20
18
|
|
21
19
|
require 'nrser/refinements/types'
|
22
20
|
using NRSER::Types
|
@@ -33,171 +31,63 @@ module I8
|
|
33
31
|
|
34
32
|
# Easy way to get the class names shorter..?
|
35
33
|
class Vector < Hamster::Vector; end
|
34
|
+
|
35
|
+
|
36
36
|
class Hash < Hamster::Hash; end
|
37
|
-
|
38
|
-
class SortedSet < Hamster::SortedSet; end
|
39
|
-
# class List < Hamster::List; end # Not a class! Ugh...
|
40
|
-
|
41
|
-
|
42
|
-
module Struct
|
43
|
-
|
44
|
-
def self.check_new_args! vector_prop_defs, hash_prop_defs
|
45
|
-
|
46
|
-
unless (vector_prop_defs.empty? && !hash_prop_defs.empty?) ||
|
47
|
-
(!vector_prop_defs.empty? && hash_prop_defs.empty?)
|
48
|
-
|
49
|
-
raise NRSER::ArgumentError.new \
|
50
|
-
"Exactly one of *args or **kwds must be empty",
|
51
|
-
|
52
|
-
args: vector_prop_defs,
|
53
|
-
|
54
|
-
kwds: hash_prop_defs,
|
55
|
-
|
56
|
-
details: -> {%{
|
57
|
-
{I8::Struct.define} proxies to either
|
58
|
-
|
59
|
-
1. {I8::Struct::Vector.define}
|
60
|
-
2. {I8::Struct::Hash.define}
|
61
|
-
|
62
|
-
depending on *where* the property definitions are passed:
|
63
|
-
|
64
|
-
1. Positionally in `*args` -> {I8::Struct::Vector.new}
|
65
|
-
2. By name in `**kwds` -> {I8::Struct::Hash.new}
|
66
|
-
|
67
|
-
Examples:
|
68
|
-
|
69
|
-
1. Create a Point struct backed by an {I8::Vector}:
|
70
|
-
|
71
|
-
Point = I8::Struct.define [x: t.int], [y: t.int]
|
72
|
-
|
73
|
-
2. Create a Point struct backed by an {I8::Hash}:
|
74
|
-
|
75
|
-
Point = I8::Struct.define x: t.int, y: t.int
|
76
|
-
|
77
|
-
}}
|
78
|
-
|
79
|
-
end # unless vector_prop_defs.empty? XOR hash_prop_defs.empty?
|
80
|
-
|
81
|
-
end # .check_new_args!
|
82
|
-
|
83
|
-
private_class_method :check_new_args!
|
84
|
-
|
85
|
-
|
86
|
-
def self.define *vector_prop_defs, **hash_prop_defs, &body
|
87
|
-
check_new_args! vector_prop_defs, hash_prop_defs
|
88
|
-
|
89
|
-
if !vector_prop_defs.empty?
|
90
|
-
raise "not implemented"
|
91
|
-
# I8::Struct::Vector.new
|
92
|
-
else
|
93
|
-
I8::Struct::Hash.new **hash_prop_defs, &body
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
singleton_class.send :alias_method, :new, :define
|
98
|
-
|
99
|
-
|
100
|
-
end # module Struct
|
101
|
-
|
37
|
+
|
102
38
|
|
103
|
-
class
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
39
|
+
class Set < Hamster::Set
|
40
|
+
|
41
|
+
# Get a {I8::Set} containing `items`.
|
42
|
+
#
|
43
|
+
# Overridden to...
|
44
|
+
#
|
45
|
+
# 1. Return `items` if items is already a {I8::Set}... sort of like a copy
|
46
|
+
# constructor that doesn't actually copy because the instances are
|
47
|
+
# immutable.
|
48
|
+
#
|
49
|
+
# 2. Return an instance of `self` pointing to `items`'s {Hamster::Trie}
|
50
|
+
# if `items` is a {Hamster::Set}; this way you get an instance of
|
51
|
+
# the correct class but don't do any additional instantiation.
|
52
|
+
#
|
53
|
+
# 3. Returns {.empty} if `items` responds to `#empty?` truthfully.
|
54
|
+
#
|
55
|
+
# Otherwise, defers to `super`.
|
56
|
+
#
|
57
|
+
# @param [#each] items
|
58
|
+
# Items for the new set to contain.
|
59
|
+
#
|
60
|
+
# @return [I8::Set]
|
61
|
+
#
|
62
|
+
def self.new items = []
|
63
|
+
case items
|
64
|
+
when self
|
65
|
+
items
|
66
|
+
when Hamster::Set
|
67
|
+
alloc items.instance_variable_get( :@trie )
|
124
68
|
else
|
125
|
-
|
126
|
-
|
127
|
-
super( *args, &block )
|
69
|
+
if items.respond_to?( :empty? ) && items.empty?
|
70
|
+
self.empty
|
128
71
|
else
|
129
|
-
super
|
72
|
+
super items
|
130
73
|
end
|
131
74
|
end
|
132
75
|
end
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
# Unwrap `[name: type]` format
|
142
|
-
prop_defs.map! { |prop_def|
|
143
|
-
if ::Array === prop_def &&
|
144
|
-
prop_def.length == 1 &&
|
145
|
-
::Hash === prop_def[0]
|
146
|
-
prop_def[0]
|
147
|
-
else
|
148
|
-
prop_def
|
149
|
-
end
|
150
|
-
}
|
151
|
-
|
152
|
-
# Check we have a list of pairs with label keys
|
153
|
-
t.array( t.pair( key: t.label ) ).check! prop_defs
|
154
|
-
|
155
|
-
Class.new( I8::Struct::Vector ) do
|
156
|
-
prop_defs.each_with_index do |pair, index|
|
157
|
-
name, settings = pair.first
|
158
|
-
|
159
|
-
kwds = t.match settings,
|
160
|
-
t.type, ->( type ) {{ type: type }},
|
161
|
-
t.hash_, settings
|
162
|
-
|
163
|
-
prop name, **kwds, index: index
|
164
|
-
end
|
165
|
-
|
166
|
-
class_exec &body if body
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
|
171
|
-
def self.new *args, **kwds, &block
|
172
|
-
if self == I8::Struct::Vector
|
173
|
-
unless kwds.empty?
|
174
|
-
raise NRSER::ArgumentError.new \
|
175
|
-
"Can not supply keyword args",
|
176
|
-
args: args,
|
177
|
-
kwds: kwds
|
178
|
-
end
|
179
|
-
|
180
|
-
define *args, &block
|
181
|
-
else
|
182
|
-
# NOTE This is... weird. Just doing the normal
|
183
|
-
#
|
184
|
-
# super( *args, **kwds, &block )
|
185
|
-
#
|
186
|
-
# results in `*args` becoming `[*args, {}]` up the super chain
|
187
|
-
# when `kwds` is empty.
|
188
|
-
#
|
189
|
-
# I can't say I can understand it, but I seem to be able to fix
|
190
|
-
# it.
|
191
|
-
#
|
192
|
-
if kwds.empty?
|
193
|
-
super( *args, &block )
|
194
|
-
else
|
195
|
-
super( *args, **kwds, &block )
|
196
|
-
end
|
197
|
-
end
|
76
|
+
|
77
|
+
# Override to build our empty set through {.alloc} so that we can return
|
78
|
+
# it in {.new}.
|
79
|
+
#
|
80
|
+
# @return [I8::Set]
|
81
|
+
#
|
82
|
+
def self.empty
|
83
|
+
@empty ||= alloc Hamster::Trie.new( 0 )
|
198
84
|
end
|
199
|
-
|
200
|
-
end # class
|
85
|
+
|
86
|
+
end # class Set
|
87
|
+
|
88
|
+
|
89
|
+
class SortedSet < Hamster::SortedSet; end
|
90
|
+
# class List < Hamster::List; end # Not a class! Ugh...
|
201
91
|
|
202
92
|
|
203
93
|
def self.[] value
|