nrser 0.3.7 → 0.3.8
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/core_ext/pathname.rb +22 -2
- data/lib/nrser/ext/tree.rb +27 -3
- data/lib/nrser/gem_ext/hamster/hash.rb +53 -0
- data/lib/nrser/gem_ext/hamster/set.rb +69 -0
- data/lib/nrser/gem_ext/hamster/sorted_set.rb +69 -0
- data/lib/nrser/gem_ext/hamster/vector.rb +53 -0
- data/lib/nrser/gem_ext/hamster.rb +36 -0
- data/lib/nrser/labs/i8.rb +233 -0
- data/lib/nrser/log/types.rb +82 -0
- data/lib/nrser/log.rb +9 -8
- data/lib/nrser/rspex/example_group/describe_called_with.rb +22 -1
- data/lib/nrser/rspex/example_group/describe_instance.rb +5 -5
- data/lib/nrser/types/combinators.rb +1 -1
- data/lib/nrser/types/factory.rb +3 -1
- data/lib/nrser/types/is_a.rb +6 -0
- data/lib/nrser/types/maybe.rb +87 -14
- data/lib/nrser/types/paths.rb +6 -5
- data/lib/nrser/version.rb +1 -1
- data/lib/nrser.rb +2 -0
- data/spec/lib/nrser/functions/tree/{map_branch_spec.rb → map_branches_spec.rb} +0 -0
- data/spec/lib/nrser/gem_ext/hamster/to_mutable_spec.rb +114 -0
- data/spec/lib/nrser/props/immutable/vector_spec.rb +1 -1
- data/spec/spec_helper.rb +7 -0
- metadata +13 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 20a9f5822833e3797ebf2ec2ba0b6e430ad7346e
|
4
|
+
data.tar.gz: 0dc5e6c87d30f0d9ed99692b33da84a4f2584db9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 374129784c79fe2897c078beed6e4d7c168e9b2e79027bf293df15403eac73a505176db6238f2c9b14ba8d2ecbda399e61c5f2a57cce4b8ec79a0c7a12ec031e
|
7
|
+
data.tar.gz: ae5a9bb34f77b6d35976fbed02fa85b8267a34b9cfb0a0ec0b4db6b39bae1d38ed08c3c994f27439f437580ebc9023c6d23c19ef827b58691a5aca0969f4e17a
|
@@ -92,6 +92,16 @@ class Pathname
|
|
92
92
|
end
|
93
93
|
|
94
94
|
|
95
|
+
# Shortcut to call {#to_rel} with `dot_slash=true`.
|
96
|
+
#
|
97
|
+
# @param base_dir: (see .to_rel)
|
98
|
+
# @return (see .to_rel)
|
99
|
+
#
|
100
|
+
def to_dot_rel **kwds
|
101
|
+
to_rel **kwds, dot_slash: true
|
102
|
+
end # #to_dot_rel
|
103
|
+
|
104
|
+
|
95
105
|
# Just a quick cut for `.to_rel.to_s`, since I seem to use that sort of form
|
96
106
|
# a lot.
|
97
107
|
#
|
@@ -99,8 +109,18 @@ class Pathname
|
|
99
109
|
#
|
100
110
|
# @return [String]
|
101
111
|
#
|
102
|
-
def to_rel_s
|
103
|
-
to_rel(
|
112
|
+
def to_rel_s **kwds
|
113
|
+
to_rel( **kwds ).to_s
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
# Shortcut to call {#to_rel_s} with `dot_slash=true`.
|
118
|
+
#
|
119
|
+
# @param base_dir: (see .to_rel_s)
|
120
|
+
# @return (see .to_rel_s)
|
121
|
+
#
|
122
|
+
def to_dot_rel_s **kwds
|
123
|
+
to_rel_s( **kwds, dot_slash: true ).to_s
|
104
124
|
end
|
105
125
|
|
106
126
|
end # class Pathname
|
data/lib/nrser/ext/tree.rb
CHANGED
@@ -1,10 +1,27 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
|
5
|
+
# Requirements
|
6
|
+
# ========================================================================
|
7
|
+
|
8
|
+
# Project / Package
|
9
|
+
# ------------------------------------------------------------------------
|
10
|
+
|
11
|
+
require 'nrser/functions/tree'
|
12
|
+
|
13
|
+
|
14
|
+
# Namespace
|
15
|
+
# ========================================================================
|
16
|
+
|
17
|
+
module NRSER
|
18
|
+
module Ext
|
2
19
|
|
3
20
|
|
4
21
|
# Instance methods that are refined in to the Ruby built-ins that we consider
|
5
22
|
# trees: {Array}, {Hash} and {OpenStruct}.
|
6
23
|
#
|
7
|
-
module
|
24
|
+
module Tree
|
8
25
|
|
9
26
|
# Sends `self` to {NRSER.leaves}.
|
10
27
|
def leaves
|
@@ -39,4 +56,11 @@ module NRSER::Ext::Tree
|
|
39
56
|
NRSER.map_tree self, **options, &block
|
40
57
|
end
|
41
58
|
|
42
|
-
end # module
|
59
|
+
end # module Tree
|
60
|
+
|
61
|
+
|
62
|
+
# /Namespace
|
63
|
+
# ========================================================================
|
64
|
+
|
65
|
+
end # module Ext
|
66
|
+
end # module NRSER
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
# Deps
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
|
10
|
+
require 'hamster'
|
11
|
+
|
12
|
+
require 'nrser/ext/tree'
|
13
|
+
|
14
|
+
|
15
|
+
# Namespace
|
16
|
+
# =======================================================================
|
17
|
+
|
18
|
+
module Hamster
|
19
|
+
|
20
|
+
|
21
|
+
# Definitions
|
22
|
+
# =======================================================================
|
23
|
+
|
24
|
+
class Hash
|
25
|
+
|
26
|
+
include NRSER::Ext::Tree
|
27
|
+
|
28
|
+
# Instance Methods
|
29
|
+
# ========================================================================
|
30
|
+
|
31
|
+
def to_mutable
|
32
|
+
each_with_object( {} ) { |(key, value), hash|
|
33
|
+
hash[ Hamster.to_mutable key ] = Hamster.to_mutable value
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def as_json options = nil
|
39
|
+
to_h.as_json options
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def to_yaml *args, &block
|
44
|
+
to_mutable.to_yaml *args, &block
|
45
|
+
end
|
46
|
+
|
47
|
+
end # class Hash
|
48
|
+
|
49
|
+
|
50
|
+
# /Namespace
|
51
|
+
# =======================================================================
|
52
|
+
|
53
|
+
end # module Hamster
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
# Stdlib
|
8
|
+
# ----------------------------------------------------------------------------
|
9
|
+
|
10
|
+
require 'set'
|
11
|
+
|
12
|
+
# Deps
|
13
|
+
# -----------------------------------------------------------------------
|
14
|
+
|
15
|
+
require 'hamster'
|
16
|
+
|
17
|
+
require 'nrser/ext/tree'
|
18
|
+
|
19
|
+
|
20
|
+
# Namespace
|
21
|
+
# =======================================================================
|
22
|
+
|
23
|
+
module Hamster
|
24
|
+
|
25
|
+
|
26
|
+
# Definitions
|
27
|
+
# =======================================================================
|
28
|
+
|
29
|
+
class Set
|
30
|
+
|
31
|
+
# Instance Methods
|
32
|
+
# ========================================================================
|
33
|
+
|
34
|
+
def to_mutable
|
35
|
+
each_with_object( ::Set[] ) { |member, set|
|
36
|
+
set << Hamster.to_mutable( member )
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def to_mutable_array
|
42
|
+
each_with_object( [] ) { |member, array|
|
43
|
+
array << Hamster.to_mutable( member )
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def to_h
|
49
|
+
each_with_object( {} ) { |member, hash| hash[member] = true }
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def as_json options = nil
|
54
|
+
to_mutable_array.to_json options
|
55
|
+
# { '$set' => to_h.as_json( options ) }
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
def to_yaml *args, &block
|
60
|
+
to_mutable.to_yaml *args, &block
|
61
|
+
end
|
62
|
+
|
63
|
+
end # class Hash
|
64
|
+
|
65
|
+
|
66
|
+
# /Namespace
|
67
|
+
# =======================================================================
|
68
|
+
|
69
|
+
end # module Hamster
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
# Stdlib
|
8
|
+
# ----------------------------------------------------------------------------
|
9
|
+
|
10
|
+
require 'set'
|
11
|
+
|
12
|
+
# Deps
|
13
|
+
# -----------------------------------------------------------------------
|
14
|
+
|
15
|
+
require 'hamster'
|
16
|
+
|
17
|
+
require 'nrser/ext/tree'
|
18
|
+
|
19
|
+
|
20
|
+
# Namespace
|
21
|
+
# =======================================================================
|
22
|
+
|
23
|
+
module Hamster
|
24
|
+
|
25
|
+
|
26
|
+
# Definitions
|
27
|
+
# =======================================================================
|
28
|
+
|
29
|
+
class SortedSet
|
30
|
+
|
31
|
+
# Instance Methods
|
32
|
+
# ========================================================================
|
33
|
+
|
34
|
+
def to_mutable
|
35
|
+
each_with_object( ::SortedSet[] ) { |member, set|
|
36
|
+
set << Hamster.to_mutable( member )
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def to_mutable_array
|
42
|
+
each_with_object( [] ) { |member, array|
|
43
|
+
array << Hamster.to_mutable( member )
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def to_h
|
49
|
+
each_with_object( {} ) { |member, hash| hash[member] = true }
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def as_json options = nil
|
54
|
+
to_mutable_array.to_json options
|
55
|
+
# { '$set' => to_h.as_json( options ) }
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
def to_yaml *args, &block
|
60
|
+
to_mutable.to_yaml *args, &block
|
61
|
+
end
|
62
|
+
|
63
|
+
end # class Hash
|
64
|
+
|
65
|
+
|
66
|
+
# /Namespace
|
67
|
+
# =======================================================================
|
68
|
+
|
69
|
+
end # module Hamster
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
# Deps
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
|
10
|
+
require 'hamster'
|
11
|
+
|
12
|
+
require 'nrser/ext/tree'
|
13
|
+
|
14
|
+
|
15
|
+
# Namespace
|
16
|
+
# =======================================================================
|
17
|
+
|
18
|
+
module Hamster
|
19
|
+
|
20
|
+
|
21
|
+
# Definitions
|
22
|
+
# =======================================================================
|
23
|
+
|
24
|
+
class Vector
|
25
|
+
|
26
|
+
include NRSER::Ext::Tree
|
27
|
+
|
28
|
+
# Instance Methods
|
29
|
+
# ========================================================================
|
30
|
+
|
31
|
+
def to_mutable
|
32
|
+
each_with_object( [] ) { |entry, array|
|
33
|
+
array << Hamster.to_mutable( entry )
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def as_json options = nil
|
39
|
+
to_mutable.as_json options
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def to_yaml *args, &block
|
44
|
+
to_mutable.to_yaml *args, &block
|
45
|
+
end
|
46
|
+
|
47
|
+
end # class Hash
|
48
|
+
|
49
|
+
|
50
|
+
# /Namespace
|
51
|
+
# =======================================================================
|
52
|
+
|
53
|
+
end # module Hamster
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
require 'hamster'
|
4
|
+
require_relative './hamster/hash'
|
5
|
+
require_relative './hamster/vector'
|
6
|
+
require_relative './hamster/set'
|
7
|
+
require_relative './hamster/sorted_set'
|
8
|
+
|
9
|
+
module Hamster
|
10
|
+
# def self.regrow each_pair: ::Hash, each_index: ::Array, each:
|
11
|
+
|
12
|
+
def self.to_mutable obj
|
13
|
+
if obj.respond_to? :to_mutable
|
14
|
+
obj.to_mutable
|
15
|
+
|
16
|
+
elsif ::Array === obj
|
17
|
+
obj.map { |e| to_mutable e }
|
18
|
+
|
19
|
+
elsif ::Hash === obj
|
20
|
+
obj.each_with_object( {} ) { |(k, v), h|
|
21
|
+
h[ to_mutable k ] = to_mutable v
|
22
|
+
}
|
23
|
+
|
24
|
+
elsif ::SortedSet === obj
|
25
|
+
::SortedSet.new obj.map { |m| to_mutable m }
|
26
|
+
|
27
|
+
elsif ::Set === obj
|
28
|
+
::Set.new obj.map { |m| to_mutable m }
|
29
|
+
|
30
|
+
else
|
31
|
+
obj
|
32
|
+
|
33
|
+
end
|
34
|
+
end # .to_mutable
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,233 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
# Stdlib
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
require 'set'
|
10
|
+
|
11
|
+
# Deps
|
12
|
+
# -----------------------------------------------------------------------
|
13
|
+
require 'hamster'
|
14
|
+
|
15
|
+
# Project / Package
|
16
|
+
# -----------------------------------------------------------------------
|
17
|
+
require 'nrser/errors/type_error'
|
18
|
+
require 'nrser/props/immutable/hash'
|
19
|
+
require 'nrser/props/immutable/vector'
|
20
|
+
|
21
|
+
require 'nrser/refinements/types'
|
22
|
+
using NRSER::Types
|
23
|
+
|
24
|
+
|
25
|
+
# Definitions
|
26
|
+
# =======================================================================
|
27
|
+
|
28
|
+
# Sick of typing "Hamster::Hash"...
|
29
|
+
#
|
30
|
+
# Experimental Hamster sugary sweet builder shortcut things.
|
31
|
+
#
|
32
|
+
module I8
|
33
|
+
|
34
|
+
# Easy way to get the class names shorter..?
|
35
|
+
class Vector < Hamster::Vector; end
|
36
|
+
class Hash < Hamster::Hash; end
|
37
|
+
class Set < Hamster::Set; end
|
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
|
+
|
102
|
+
|
103
|
+
class Struct::Hash < I8::Hash
|
104
|
+
include I8::Struct
|
105
|
+
include NRSER::Props::Immutable::Hash
|
106
|
+
|
107
|
+
def self.define **prop_defs, &body
|
108
|
+
Class.new( I8::Struct::Hash ) do
|
109
|
+
prop_defs.each do |name, settings|
|
110
|
+
kwds = t.match settings,
|
111
|
+
t.type, ->( type ) {{ type: type }},
|
112
|
+
t.hash_, settings
|
113
|
+
|
114
|
+
prop name, **kwds
|
115
|
+
end
|
116
|
+
|
117
|
+
class_exec &body if body
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.new *args, **kwds, &block
|
122
|
+
if self == I8::Struct::Hash
|
123
|
+
define *args, **kwds, &block
|
124
|
+
else
|
125
|
+
# See NOTE in {I8::Struct::Vector.new}
|
126
|
+
if kwds.empty?
|
127
|
+
super( *args, &block )
|
128
|
+
else
|
129
|
+
super( *args, **kwds, &block )
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
class Struct::Vector < I8::Vector
|
137
|
+
include I8::Struct
|
138
|
+
include NRSER::Props::Immutable::Vector
|
139
|
+
|
140
|
+
def self.define *prop_defs, &body
|
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
|
198
|
+
end
|
199
|
+
|
200
|
+
end # class Struct::Vector
|
201
|
+
|
202
|
+
|
203
|
+
def self.[] value
|
204
|
+
case value
|
205
|
+
when Hamster::Hash,
|
206
|
+
Hamster::Vector,
|
207
|
+
Hamster::Set,
|
208
|
+
Hamster::SortedSet,
|
209
|
+
Hamster::List
|
210
|
+
value
|
211
|
+
when ::Hash
|
212
|
+
I8::Hash[value]
|
213
|
+
when ::Array
|
214
|
+
I8::Vector.new value
|
215
|
+
when ::Set
|
216
|
+
I8::Set.new value
|
217
|
+
when ::SortedSet
|
218
|
+
I8::SortedSet.new value
|
219
|
+
else
|
220
|
+
raise NRSER::TypeError.new \
|
221
|
+
"Value must be Hash, Array, Set or SortedSet",
|
222
|
+
found: value
|
223
|
+
end
|
224
|
+
end # .[]
|
225
|
+
|
226
|
+
end # module I8
|
227
|
+
|
228
|
+
|
229
|
+
# Method proxy to {I8.[]} allowing for different syntaxes.
|
230
|
+
#
|
231
|
+
def I8 value = nil
|
232
|
+
I8[ value || yield ]
|
233
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Requirements
|
5
|
+
# =======================================================================
|
6
|
+
|
7
|
+
# Deps
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
|
10
|
+
# Need {SemanticLogger::LEVELS}
|
11
|
+
require 'semantic_logger'
|
12
|
+
|
13
|
+
|
14
|
+
# Refinements
|
15
|
+
# =======================================================================
|
16
|
+
|
17
|
+
require 'nrser/refinements/types'
|
18
|
+
using NRSER::Types
|
19
|
+
|
20
|
+
|
21
|
+
# Namespace
|
22
|
+
# =======================================================================
|
23
|
+
|
24
|
+
module NRSER
|
25
|
+
module Log
|
26
|
+
|
27
|
+
|
28
|
+
# Definitions
|
29
|
+
# =======================================================================
|
30
|
+
|
31
|
+
# Types for logging type things.
|
32
|
+
#
|
33
|
+
# @note
|
34
|
+
# This module is **NOT** required when loading {NRSER::Log}, and it **NEVER**
|
35
|
+
# should be! It is here for *other* gems and apps that depend on {NRSER}
|
36
|
+
# to use.
|
37
|
+
#
|
38
|
+
# Core logging should have the absolute minimal dependencies, because it's
|
39
|
+
# pretty much always going to be loaded and nothing it depends on can use
|
40
|
+
# it when loading up.
|
41
|
+
#
|
42
|
+
module Types
|
43
|
+
extend NRSER::Types::Factory
|
44
|
+
|
45
|
+
def_factory :level do |
|
46
|
+
name: 'LogLevel',
|
47
|
+
from_s: ->( string ) { string.to_sym },
|
48
|
+
**options
|
49
|
+
|
|
50
|
+
t.in SemanticLogger::LEVELS, from_s: from_s, name: name, **options
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def_factory :stdio do |
|
55
|
+
name: 'StdIO',
|
56
|
+
|
57
|
+
from_s: ->( string ) {
|
58
|
+
case string
|
59
|
+
when '$stdout'
|
60
|
+
$stdout
|
61
|
+
when '$stderr'
|
62
|
+
$stderr
|
63
|
+
when 'STDOUT'
|
64
|
+
STDOUT
|
65
|
+
when 'STDERR'
|
66
|
+
STDERR
|
67
|
+
end
|
68
|
+
},
|
69
|
+
|
70
|
+
**options
|
71
|
+
|
|
72
|
+
t.is_a IO, name: name, from_s: from_s, **options
|
73
|
+
end
|
74
|
+
|
75
|
+
end # module Types
|
76
|
+
|
77
|
+
|
78
|
+
# /Namespace
|
79
|
+
# =======================================================================
|
80
|
+
|
81
|
+
end # module Log
|
82
|
+
end # module NRSER
|
data/lib/nrser/log.rb
CHANGED
@@ -19,6 +19,8 @@ require "concurrent/map"
|
|
19
19
|
# Project / Package
|
20
20
|
# -----------------------------------------------------------------------
|
21
21
|
|
22
|
+
# Using {NRSER.truthy?} for ENV var values.
|
23
|
+
require 'nrser/functions/object/truthy'
|
22
24
|
|
23
25
|
# Definitions
|
24
26
|
# =======================================================================
|
@@ -38,10 +40,6 @@ module NRSER::Log
|
|
38
40
|
require_relative './log/appender'
|
39
41
|
|
40
42
|
|
41
|
-
# Constants
|
42
|
-
# ========================================================================
|
43
|
-
|
44
|
-
|
45
43
|
# Mixins
|
46
44
|
# ========================================================================
|
47
45
|
|
@@ -359,14 +357,14 @@ module NRSER::Log
|
|
359
357
|
# @param (see .setup!)
|
360
358
|
# @return (see .setup!)
|
361
359
|
#
|
362
|
-
def self.
|
360
|
+
def self.setup_for_cli! dest: $stderr,
|
363
361
|
sync: true,
|
364
362
|
**kwds
|
365
363
|
setup! dest: dest, sync: sync, **kwds
|
366
|
-
end # .
|
364
|
+
end # .setup_for_cli!
|
367
365
|
|
368
|
-
#
|
369
|
-
singleton_class.send :alias_method, :
|
366
|
+
# Was the new name, then realized it was dumb and switched back :D
|
367
|
+
singleton_class.send :alias_method, :setup_for_CLI!, :setup_for_cli!
|
370
368
|
|
371
369
|
|
372
370
|
# Call {.setup!} with some default keywords that are nice for interactive
|
@@ -696,6 +694,9 @@ module NRSER::Log
|
|
696
694
|
old_appender = @appender
|
697
695
|
|
698
696
|
@appender = case dest
|
697
|
+
when false
|
698
|
+
# Used to remove the appender and set {.appender} to `nil`.
|
699
|
+
nil
|
699
700
|
when SemanticLogger::Subscriber, Hash
|
700
701
|
# Can be handled directly
|
701
702
|
SemanticLogger.add_appender dest
|
@@ -18,7 +18,7 @@ module NRSER::RSpex::ExampleGroup
|
|
18
18
|
# @param [Array] *args
|
19
19
|
# Arguments to call `subject` with to produce the new subject.
|
20
20
|
#
|
21
|
-
# @param [#call] &
|
21
|
+
# @param [#call] &body
|
22
22
|
# Block to execute in the context of the example group after refining
|
23
23
|
# the subject.
|
24
24
|
#
|
@@ -34,4 +34,25 @@ module NRSER::RSpex::ExampleGroup
|
|
34
34
|
# Short / old name
|
35
35
|
alias_method :called_with, :describe_called_with
|
36
36
|
|
37
|
+
|
38
|
+
# Version of {#describe_called_with} for when you have no arguments.
|
39
|
+
#
|
40
|
+
# @param [#call] &body
|
41
|
+
# Block to execute in the context of the example group after refining
|
42
|
+
# the subject.
|
43
|
+
#
|
44
|
+
# @return [void]
|
45
|
+
#
|
46
|
+
def describe_called &body
|
47
|
+
describe_x Args(),
|
48
|
+
type: :called_with,
|
49
|
+
subject_block: -> { super().call },
|
50
|
+
&body
|
51
|
+
end
|
52
|
+
|
53
|
+
alias_method :called, :describe_called
|
54
|
+
alias_method :when_called, :describe_called
|
55
|
+
|
56
|
+
|
57
|
+
|
37
58
|
end # module NRSER::RSpex::ExampleGroup
|
@@ -2,13 +2,13 @@
|
|
2
2
|
|
3
3
|
module NRSER::RSpex::ExampleGroup
|
4
4
|
|
5
|
-
#
|
5
|
+
# Describe an instance of the described class by providing arguments for
|
6
|
+
# it's construction.
|
6
7
|
#
|
7
|
-
# @param [
|
8
|
-
#
|
8
|
+
# @param [Array] *constructor_args
|
9
|
+
# Arguments to pass to `.new` on {#described_class} to create instances.
|
9
10
|
#
|
10
|
-
# @return [
|
11
|
-
# @todo Document return value.
|
11
|
+
# @return [void]
|
12
12
|
#
|
13
13
|
def describe_instance *constructor_args, &body
|
14
14
|
describe_x ".new", Args(*constructor_args),
|
data/lib/nrser/types/factory.rb
CHANGED
@@ -78,7 +78,9 @@ module NRSER::Types::Factory
|
|
78
78
|
maybe_options = options.slice *maybe_option_keys
|
79
79
|
factory_options = options.except *maybe_option_keys
|
80
80
|
|
81
|
-
maybe
|
81
|
+
NRSER::Types.maybe \
|
82
|
+
public_send( name, *args, **factory_options ),
|
83
|
+
**maybe_options
|
82
84
|
end
|
83
85
|
|
84
86
|
aliases.each do |alias_name|
|
data/lib/nrser/types/is_a.rb
CHANGED
data/lib/nrser/types/maybe.rb
CHANGED
@@ -1,18 +1,91 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# Requirements
|
2
|
+
# ========================================================================
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
# Project / Package
|
5
|
+
# ------------------------------------------------------------------------
|
6
|
+
|
7
|
+
require_relative './is_a'
|
8
|
+
|
9
|
+
|
10
|
+
# Namespace
|
11
|
+
# ========================================================================
|
12
|
+
|
13
|
+
module NRSER
|
14
|
+
module Types
|
15
|
+
|
16
|
+
|
17
|
+
# Definitions
|
18
|
+
# ========================================================================
|
19
|
+
|
20
|
+
class Maybe < Type
|
21
|
+
|
22
|
+
# Attributes
|
23
|
+
# ========================================================================
|
24
|
+
|
25
|
+
# The type of all members besides `nil`.
|
7
26
|
#
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
27
|
+
# @return [Type]
|
28
|
+
#
|
29
|
+
attr_reader :type
|
30
|
+
|
31
|
+
|
32
|
+
# Constructor
|
33
|
+
# ======================================================================
|
34
|
+
|
35
|
+
# Instantiate a new `NRSER::Types::Maybe`.
|
36
|
+
def initialize type, **options
|
37
|
+
super **options
|
38
|
+
@type = NRSER::Types.make type
|
39
|
+
end # #initialize
|
40
|
+
|
41
|
+
|
42
|
+
# Instance Methods
|
43
|
+
# ========================================================================
|
44
|
+
|
45
|
+
def test? value
|
46
|
+
value.nil? || @type.test?( value )
|
16
47
|
end
|
17
48
|
|
18
|
-
|
49
|
+
|
50
|
+
def explain
|
51
|
+
"#{ @type.name }?"
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def has_from_s?
|
56
|
+
!@from_s.nil? || type.has_from_s?
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def custom_from_s string
|
61
|
+
type.from_s string
|
62
|
+
end
|
63
|
+
|
64
|
+
end # class Maybe
|
65
|
+
|
66
|
+
|
67
|
+
# @!group Type Factory Functions
|
68
|
+
# ----------------------------------------------------------------------------
|
69
|
+
|
70
|
+
# @!method
|
71
|
+
# Type satisfied by `nil` or the parametrized type.
|
72
|
+
#
|
73
|
+
# @param [Type] type
|
74
|
+
# The type values must be if they are not `nil`.
|
75
|
+
#
|
76
|
+
# @param **options (see Type.initialize)
|
77
|
+
#
|
78
|
+
# @return [Type]
|
79
|
+
#
|
80
|
+
def_factory :maybe do |type, **options|
|
81
|
+
Maybe.new type, **options
|
82
|
+
end
|
83
|
+
|
84
|
+
# @!endgroup Type Factory Functions # ****************************************
|
85
|
+
|
86
|
+
|
87
|
+
# /Namespace
|
88
|
+
# ========================================================================
|
89
|
+
|
90
|
+
end # module Types
|
91
|
+
end # module NRSER
|
data/lib/nrser/types/paths.rb
CHANGED
@@ -44,11 +44,12 @@ module NRSER::Types
|
|
44
44
|
end
|
45
45
|
|
46
46
|
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
47
|
+
# @!method
|
48
|
+
# A path is a non-empty {String} or {Pathname}.
|
49
|
+
#
|
50
|
+
# @param **options see NRSER::Types::Type#initialize
|
51
|
+
#
|
52
|
+
# @return [NRSER::Types::Type]
|
52
53
|
#
|
53
54
|
def_factory :path do |name: 'Path', **options|
|
54
55
|
one_of \
|
data/lib/nrser/version.rb
CHANGED
data/lib/nrser.rb
CHANGED
@@ -69,6 +69,8 @@ require_relative './nrser/core_ext/binding'
|
|
69
69
|
# Then everything else...
|
70
70
|
require_relative './nrser/char'
|
71
71
|
require_relative './nrser/errors'
|
72
|
+
require 'nrser/gem_ext/hamster'
|
73
|
+
|
72
74
|
require_relative './nrser/no_arg'
|
73
75
|
require_relative './nrser/message'
|
74
76
|
require_relative './nrser/collection'
|
File without changes
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'nrser/labs/i8'
|
2
|
+
|
3
|
+
describe_spec_file(
|
4
|
+
spec_path: __FILE__,
|
5
|
+
module: Hamster,
|
6
|
+
) do
|
7
|
+
|
8
|
+
describe_setup %{
|
9
|
+
Converting Hamsters to regular structures with their `#to_mutable`
|
10
|
+
}.squish do
|
11
|
+
|
12
|
+
it %{ gets immutable objects nested inside mutable ones } do
|
13
|
+
|
14
|
+
# Because `I8({ x: 1 }) == { x: 1 }` (which is usually probably very nice
|
15
|
+
# to have) we have to do more than just compare with `==`.
|
16
|
+
#
|
17
|
+
# I *think* this accomplishes what we want...
|
18
|
+
#
|
19
|
+
def class_match actual, expected
|
20
|
+
return false unless actual == expected &&
|
21
|
+
actual.class == expected.class &&
|
22
|
+
actual.eql?( expected ) # This alone is prob
|
23
|
+
# enough...
|
24
|
+
|
25
|
+
case expected
|
26
|
+
when ::Hash, ::Array
|
27
|
+
expected.each_branch do |key, expected_value|
|
28
|
+
return false unless class_match( expected_value, actual[key] )
|
29
|
+
end
|
30
|
+
when ::Set
|
31
|
+
expected.each do |expected_value|
|
32
|
+
return false unless actual.include?( expected_value )
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
expect(
|
40
|
+
class_match(
|
41
|
+
I8({ x: { y: I8({ z: 1 }) } }).to_mutable,
|
42
|
+
{ x: { y: { z: 1 } } }
|
43
|
+
)
|
44
|
+
).to be true
|
45
|
+
|
46
|
+
expect(
|
47
|
+
class_match(
|
48
|
+
I8({ x: { y: I8({ z: 1 }) } }).to_mutable,
|
49
|
+
{ x: { y: { z: 1 } } },
|
50
|
+
)
|
51
|
+
).to be true
|
52
|
+
|
53
|
+
expect(
|
54
|
+
class_match(
|
55
|
+
I8({ items: [ I8({ id: 1 }), I8({ id: 2 }) ] }).to_mutable,
|
56
|
+
{ items: [ { id: 1 }, {id: 2 } ] },
|
57
|
+
)
|
58
|
+
).to be true
|
59
|
+
|
60
|
+
expect(
|
61
|
+
class_match(
|
62
|
+
I8({ items: Set[ I8({ id: 1 }), I8({ id: 2 }) ] }).to_mutable,
|
63
|
+
{ items: Set[ { id: 1 }, {id: 2 } ] },
|
64
|
+
)
|
65
|
+
).to be true
|
66
|
+
end
|
67
|
+
|
68
|
+
end # setup
|
69
|
+
|
70
|
+
|
71
|
+
describe_class Hamster::Hash do
|
72
|
+
describe_instance x: 1, y: 2, z: 3 do
|
73
|
+
describe_method :to_mutable do
|
74
|
+
when_called do
|
75
|
+
it { is_expected.to be_a( ::Hash ).and eq( {x: 1, y: 2, z: 3} ) }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
describe_class Hamster::Vector do
|
83
|
+
describe_instance [1, 2, 3] do
|
84
|
+
describe_method :to_mutable do
|
85
|
+
when_called do
|
86
|
+
it { is_expected.to be_a( ::Array ).and eq [1, 2, 3] }
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
describe_class Hamster::Set do
|
94
|
+
describe_instance [1, 2, 3] do
|
95
|
+
describe_instance_method :to_mutable do
|
96
|
+
when_called {
|
97
|
+
it { is_expected.to be_a( ::Set ).and eq ::Set[1, 2, 3] }
|
98
|
+
}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
describe_class Hamster::SortedSet do
|
105
|
+
describe_instance [1, 2, 3] do
|
106
|
+
describe_instance_method :to_mutable do
|
107
|
+
when_called {
|
108
|
+
it { is_expected.to be_a( ::SortedSet ).and eq ::SortedSet[1, 2, 3] }
|
109
|
+
}
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end # Spec File Description
|
@@ -57,7 +57,7 @@ describe NRSER::Props::Immutable::Vector do
|
|
57
57
|
# defined classes.
|
58
58
|
def self.name; 'Point2DInt'; end
|
59
59
|
|
60
|
-
# It's vital that we include the `
|
60
|
+
# It's vital that we include the `index:` keyword argument, and that the
|
61
61
|
# values are non-negative integer indexes for the vector.
|
62
62
|
prop :x, type: t.int, index: 0
|
63
63
|
prop :y, type: t.int, index: 1
|
data/spec/spec_helper.rb
CHANGED
@@ -32,6 +32,13 @@ RSpec.configure do |config|
|
|
32
32
|
|
33
33
|
config.example_status_persistence_file_path = \
|
34
34
|
NRSER::ROOT / 'tmp' / ".rspec_status"
|
35
|
+
|
36
|
+
# This allows you to limit a spec run to individual examples or groups
|
37
|
+
# you care about by tagging them with `:focus` metadata. When nothing
|
38
|
+
# is tagged with `:focus`, all examples get run. RSpec also provides
|
39
|
+
# aliases for `it`, `describe`, and `context` that include `:focus`
|
40
|
+
# metadata: `fit`, `fdescribe` and `fcontext`, respectively.
|
41
|
+
config.filter_run_when_matching :focus
|
35
42
|
end
|
36
43
|
|
37
44
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nrser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- nrser
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-06
|
11
|
+
date: 2018-07-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hamster
|
@@ -317,10 +317,16 @@ files:
|
|
317
317
|
- lib/nrser/functions/tree/map_leaves.rb
|
318
318
|
- lib/nrser/functions/tree/map_tree.rb
|
319
319
|
- lib/nrser/functions/tree/transform.rb
|
320
|
+
- lib/nrser/gem_ext/hamster.rb
|
321
|
+
- lib/nrser/gem_ext/hamster/hash.rb
|
322
|
+
- lib/nrser/gem_ext/hamster/set.rb
|
323
|
+
- lib/nrser/gem_ext/hamster/sorted_set.rb
|
324
|
+
- lib/nrser/gem_ext/hamster/vector.rb
|
320
325
|
- lib/nrser/graph/tsorter.rb
|
321
326
|
- lib/nrser/labs.rb
|
322
327
|
- lib/nrser/labs/core_ext/binding.rb
|
323
328
|
- lib/nrser/labs/globlin.rb
|
329
|
+
- lib/nrser/labs/i8.rb
|
324
330
|
- lib/nrser/labs/index.rb
|
325
331
|
- lib/nrser/labs/stash.rb
|
326
332
|
- lib/nrser/log.rb
|
@@ -332,6 +338,7 @@ files:
|
|
332
338
|
- lib/nrser/log/logger.rb
|
333
339
|
- lib/nrser/log/mixin.rb
|
334
340
|
- lib/nrser/log/plugin.rb
|
341
|
+
- lib/nrser/log/types.rb
|
335
342
|
- lib/nrser/mean_streak.rb
|
336
343
|
- lib/nrser/mean_streak/document.rb
|
337
344
|
- lib/nrser/message.rb
|
@@ -443,11 +450,12 @@ files:
|
|
443
450
|
- spec/lib/nrser/functions/text/words_spec.rb
|
444
451
|
- spec/lib/nrser/functions/tree/each_branch_spec.rb
|
445
452
|
- spec/lib/nrser/functions/tree/leaves_spec.rb
|
446
|
-
- spec/lib/nrser/functions/tree/
|
453
|
+
- spec/lib/nrser/functions/tree/map_branches_spec.rb
|
447
454
|
- spec/lib/nrser/functions/tree/map_tree_spec.rb
|
448
455
|
- spec/lib/nrser/functions/tree/transform_spec.rb
|
449
456
|
- spec/lib/nrser/functions/tree/transformer_spec.rb
|
450
457
|
- spec/lib/nrser/gem_ext/hamster/json_spec.rb
|
458
|
+
- spec/lib/nrser/gem_ext/hamster/to_mutable_spec.rb
|
451
459
|
- spec/lib/nrser/labs/globlin_spec.rb
|
452
460
|
- spec/lib/nrser/labs/index_spec.rb
|
453
461
|
- spec/lib/nrser/mean_streak/design_spec.rb
|
@@ -535,11 +543,12 @@ test_files:
|
|
535
543
|
- spec/lib/nrser/functions/text/words_spec.rb
|
536
544
|
- spec/lib/nrser/functions/tree/each_branch_spec.rb
|
537
545
|
- spec/lib/nrser/functions/tree/leaves_spec.rb
|
538
|
-
- spec/lib/nrser/functions/tree/
|
546
|
+
- spec/lib/nrser/functions/tree/map_branches_spec.rb
|
539
547
|
- spec/lib/nrser/functions/tree/map_tree_spec.rb
|
540
548
|
- spec/lib/nrser/functions/tree/transform_spec.rb
|
541
549
|
- spec/lib/nrser/functions/tree/transformer_spec.rb
|
542
550
|
- spec/lib/nrser/gem_ext/hamster/json_spec.rb
|
551
|
+
- spec/lib/nrser/gem_ext/hamster/to_mutable_spec.rb
|
543
552
|
- spec/lib/nrser/labs/globlin_spec.rb
|
544
553
|
- spec/lib/nrser/labs/index_spec.rb
|
545
554
|
- spec/lib/nrser/mean_streak/design_spec.rb
|