nrser 0.0.25 → 0.0.26
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +39 -11
- data/lib/nrser.rb +5 -1
- data/lib/nrser/array.rb +10 -53
- data/lib/nrser/enumerable.rb +21 -0
- data/lib/nrser/hash.rb +13 -476
- data/lib/nrser/hash/bury.rb +154 -0
- data/lib/nrser/hash/deep_merge.rb +57 -0
- data/lib/nrser/hash/except_keys.rb +42 -0
- data/lib/nrser/hash/guess_label_key_type.rb +37 -0
- data/lib/nrser/hash/slice_keys.rb +41 -0
- data/lib/nrser/hash/stringify_keys.rb +37 -0
- data/lib/nrser/hash/symbolize_keys.rb +41 -0
- data/lib/nrser/hash/transform_keys.rb +45 -0
- data/lib/nrser/merge_by.rb +26 -0
- data/lib/nrser/message.rb +125 -0
- data/lib/nrser/meta/props.rb +2 -2
- data/lib/nrser/meta/props/prop.rb +5 -2
- data/lib/nrser/object.rb +5 -0
- data/lib/nrser/object/as_array.rb +37 -0
- data/lib/nrser/object/as_hash.rb +101 -0
- data/lib/nrser/{truthy.rb → object/truthy.rb} +0 -0
- data/lib/nrser/proc.rb +132 -0
- data/lib/nrser/refinements.rb +1 -2
- data/lib/nrser/refinements/array.rb +94 -5
- data/lib/nrser/refinements/enumerable.rb +5 -0
- data/lib/nrser/refinements/hash.rb +43 -6
- data/lib/nrser/refinements/object.rb +22 -2
- data/lib/nrser/refinements/symbol.rb +12 -0
- data/lib/nrser/refinements/tree.rb +41 -0
- data/lib/nrser/rspex.rb +329 -0
- data/lib/nrser/string.rb +3 -0
- data/lib/nrser/string/looks_like.rb +51 -0
- data/lib/nrser/temp/where.rb +52 -0
- data/lib/nrser/tree.rb +86 -0
- data/lib/nrser/tree/leaves.rb +92 -0
- data/lib/nrser/tree/map_leaves.rb +63 -0
- data/lib/nrser/tree/transform.rb +30 -0
- data/lib/nrser/types.rb +9 -4
- data/lib/nrser/types/any.rb +1 -1
- data/lib/nrser/types/array.rb +167 -25
- data/lib/nrser/types/{hash.rb → hashes.rb} +19 -5
- data/lib/nrser/types/in.rb +47 -0
- data/lib/nrser/types/is_a.rb +2 -2
- data/lib/nrser/types/labels.rb +49 -0
- data/lib/nrser/types/numbers.rb +63 -27
- data/lib/nrser/types/pairs.rb +109 -0
- data/lib/nrser/types/responds.rb +2 -3
- data/lib/nrser/types/strings.rb +17 -18
- data/lib/nrser/types/symbols.rb +39 -0
- data/lib/nrser/types/trees.rb +93 -0
- data/lib/nrser/types/tuples.rb +116 -0
- data/lib/nrser/types/type.rb +26 -2
- data/lib/nrser/version.rb +1 -1
- data/spec/nrser/hash/{guess_name_type_spec.rb → guess_label_key_type_spec.rb} +3 -3
- data/spec/nrser/hash_spec.rb +0 -20
- data/spec/nrser/merge_by_spec.rb +73 -0
- data/spec/nrser/meta/props_spec.rb +136 -43
- data/spec/nrser/op/message_spec.rb +62 -0
- data/spec/nrser/refinements/array_spec.rb +36 -0
- data/spec/nrser/refinements/hash_spec.rb +34 -0
- data/spec/nrser/string/looks_like_spec.rb +31 -0
- data/spec/nrser/tree/each_branch_spec.rb +82 -0
- data/spec/nrser/tree/leaves_spec.rb +112 -0
- data/spec/nrser/tree/transform_spec.rb +165 -0
- data/spec/nrser/types/array_spec.rb +82 -0
- data/spec/nrser/types/attrs_spec.rb +4 -4
- data/spec/nrser/types/pairs_spec.rb +41 -0
- data/spec/nrser/types/paths_spec.rb +3 -3
- data/spec/nrser/types/strings_spec.rb +66 -0
- data/spec/nrser/types/symbols_spec.rb +38 -0
- data/spec/nrser/types/tuples_spec.rb +37 -0
- data/spec/nrser/types_spec.rb +0 -13
- data/spec/spec_helper.rb +71 -22
- metadata +58 -10
- data/lib/nrser/spex.rb +0 -68
- data/lib/nrser/types/symbol.rb +0 -23
data/lib/nrser/refinements.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'nrser'
|
2
|
-
|
3
1
|
require_relative './refinements/object'
|
4
2
|
require_relative './refinements/string'
|
5
3
|
require_relative './refinements/array'
|
@@ -10,3 +8,4 @@ require_relative './refinements/binding'
|
|
10
8
|
require_relative './refinements/set'
|
11
9
|
require_relative './refinements/open_struct'
|
12
10
|
require_relative './refinements/enumerator'
|
11
|
+
require_relative './refinements/symbol'
|
@@ -1,8 +1,19 @@
|
|
1
|
+
# Requirements
|
2
|
+
# =======================================================================
|
3
|
+
|
4
|
+
# Project / Package
|
5
|
+
# -----------------------------------------------------------------------
|
1
6
|
require_relative './enumerable'
|
7
|
+
require_relative './tree'
|
8
|
+
|
9
|
+
|
10
|
+
# Definitions
|
11
|
+
# =======================================================================
|
2
12
|
|
3
13
|
module NRSER
|
4
14
|
refine ::Array do
|
5
15
|
include NRSER::Refinements::Enumerable
|
16
|
+
include NRSER::Refinements::Tree
|
6
17
|
|
7
18
|
|
8
19
|
# @return [Array]
|
@@ -14,6 +25,83 @@ module NRSER
|
|
14
25
|
end # #rest
|
15
26
|
|
16
27
|
|
28
|
+
# `to_*` Converters
|
29
|
+
# =====================================================================
|
30
|
+
|
31
|
+
# Checks that length is 2 and returns `self`.
|
32
|
+
#
|
33
|
+
# @return [Array]
|
34
|
+
# Array of length 2.
|
35
|
+
#
|
36
|
+
# @raise [TypeError]
|
37
|
+
# If length is not 2.
|
38
|
+
#
|
39
|
+
def to_pair
|
40
|
+
unless length == 2
|
41
|
+
raise TypeError,
|
42
|
+
"Array is not of length 2: #{ self.inspect }"
|
43
|
+
end
|
44
|
+
|
45
|
+
self
|
46
|
+
end # #to_pair
|
47
|
+
|
48
|
+
|
49
|
+
# To Operation Objects
|
50
|
+
# ---------------------------------------------------------------------
|
51
|
+
|
52
|
+
# Creates a new {NRSER::Message} from the array.
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
#
|
56
|
+
# message = [:fetch, :x].to_message
|
57
|
+
# message.send_to x: 'ex', y: 'why?'
|
58
|
+
# # => 'ex'
|
59
|
+
#
|
60
|
+
# @return [NRSER::Message]
|
61
|
+
#
|
62
|
+
def to_message
|
63
|
+
NRSER::Message.new *self
|
64
|
+
end # #to_message
|
65
|
+
|
66
|
+
alias_method :to_m, :to_message
|
67
|
+
|
68
|
+
|
69
|
+
# Create a {Proc} that accepts a single `receiver` and provides this array's
|
70
|
+
# entries as the arguments to `#public_send` (or `#send` if the `publicly`
|
71
|
+
# option is `false`).
|
72
|
+
#
|
73
|
+
# Equivalent to
|
74
|
+
#
|
75
|
+
# to_message.to_proc publicly: boolean
|
76
|
+
#
|
77
|
+
# @example
|
78
|
+
#
|
79
|
+
# [:fetch, :x].sender.call x: 'ex'
|
80
|
+
# # => 'ex'
|
81
|
+
#
|
82
|
+
# @param [Boolean] publicly:
|
83
|
+
# When `true`, uses `#public_send` in liu of `#send`.
|
84
|
+
#
|
85
|
+
# @return [Proc]
|
86
|
+
#
|
87
|
+
def to_sender publicly: true
|
88
|
+
to_message.to_proc publicly: publicly
|
89
|
+
end
|
90
|
+
|
91
|
+
alias_method :sender, :to_sender
|
92
|
+
alias_method :sndr, :to_sender
|
93
|
+
|
94
|
+
|
95
|
+
# See {NRSER.chainer}.
|
96
|
+
#
|
97
|
+
def to_chainer publicly: true
|
98
|
+
NRSER.chainer self, publicly: publicly
|
99
|
+
end # #to_chainer
|
100
|
+
|
101
|
+
alias_method :chainer, :to_chainer
|
102
|
+
alias_method :chnr, :to_chainer
|
103
|
+
|
104
|
+
|
17
105
|
# Returns a lambda that calls accepts a single arg and calls `#dig` on it
|
18
106
|
# with the elements of *this* array as arguments.
|
19
107
|
#
|
@@ -34,11 +122,12 @@ module NRSER
|
|
34
122
|
# Lambda proc that accepts a single argument and calls `#dig` with this
|
35
123
|
# array's contents as the `#dig` arguments.
|
36
124
|
#
|
37
|
-
def
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
125
|
+
def to_digger
|
126
|
+
NRSER::Message.new( :dig, *self ).to_proc
|
127
|
+
end # #to_digger
|
128
|
+
|
129
|
+
alias_method :digger, :to_digger
|
130
|
+
alias_method :dggr, :to_digger
|
42
131
|
|
43
132
|
|
44
133
|
end # refine ::Array
|
@@ -1,9 +1,21 @@
|
|
1
|
+
# Requirements
|
2
|
+
# =======================================================================
|
3
|
+
|
4
|
+
# Project / Package
|
5
|
+
# -----------------------------------------------------------------------
|
1
6
|
require_relative './enumerable'
|
7
|
+
require_relative './tree'
|
8
|
+
|
9
|
+
|
10
|
+
# Definitions
|
11
|
+
# =======================================================================
|
2
12
|
|
3
13
|
module NRSER
|
4
14
|
|
5
15
|
refine ::Hash do
|
6
16
|
include NRSER::Refinements::Enumerable
|
17
|
+
include NRSER::Refinements::Tree
|
18
|
+
|
7
19
|
|
8
20
|
# See {NRSER.except_keys!}.
|
9
21
|
def except! *keys
|
@@ -27,12 +39,6 @@ module NRSER
|
|
27
39
|
end
|
28
40
|
|
29
41
|
|
30
|
-
# See {NRSER.leaves}.
|
31
|
-
def leaves
|
32
|
-
NRSER.leaves self
|
33
|
-
end # #leaves
|
34
|
-
|
35
|
-
|
36
42
|
# See {NRSER.transform_keys!}
|
37
43
|
def transform_keys! &block
|
38
44
|
return enum_for(:transform_keys!) { size } unless block_given?
|
@@ -89,5 +95,36 @@ module NRSER
|
|
89
95
|
clobber: clobber
|
90
96
|
end
|
91
97
|
|
98
|
+
|
99
|
+
# Checks that `self` contains a single key/value pair (`#length` of 1)
|
100
|
+
# and returns it as an array of length 2.
|
101
|
+
#
|
102
|
+
# @return [Array]
|
103
|
+
# Array of length 2.
|
104
|
+
#
|
105
|
+
# @raise [TypeError]
|
106
|
+
# If `self` has more than one key/value pair.
|
107
|
+
#
|
108
|
+
def to_pair
|
109
|
+
unless length == 1
|
110
|
+
raise TypeError,
|
111
|
+
"Hash has more than one pair: #{ self.inspect }"
|
112
|
+
end
|
113
|
+
|
114
|
+
first
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
# See {NRSER.deep_merge}
|
119
|
+
def deep_merge other_hash, &block
|
120
|
+
NRSER.deep_merge self, other_hash, &block
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
# See {NRSER.deep_merge!}
|
125
|
+
def deep_merge! other_hash, &block
|
126
|
+
NRSER.deep_merge! self, other_hash, &block
|
127
|
+
end
|
128
|
+
|
92
129
|
end # refine ::Hash
|
93
130
|
end # NRSER
|
@@ -1,24 +1,44 @@
|
|
1
|
+
# Requirements
|
2
|
+
# =======================================================================
|
3
|
+
|
4
|
+
# Stdlib
|
5
|
+
# -----------------------------------------------------------------------
|
6
|
+
|
7
|
+
# Deps
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
|
10
|
+
# Project / Package
|
11
|
+
# -----------------------------------------------------------------------
|
12
|
+
require 'nrser/object'
|
13
|
+
|
14
|
+
|
15
|
+
# Definitions
|
16
|
+
# =======================================================================
|
17
|
+
|
1
18
|
module NRSER
|
2
19
|
refine Object do
|
20
|
+
# Yield `self`. Analogous to {#tap} but returns the result of the invoked
|
21
|
+
# block.
|
3
22
|
def pipe
|
4
23
|
yield self
|
5
24
|
end
|
6
25
|
|
26
|
+
# See {NRSER.truthy?}.
|
7
27
|
def truthy?
|
8
28
|
NRSER.truthy? self
|
9
29
|
end
|
10
30
|
|
31
|
+
# See {NRSER.falsy?}.
|
11
32
|
def falsy?
|
12
33
|
NRSER.falsy? self
|
13
34
|
end
|
14
35
|
|
15
36
|
# Calls {NRSER.as_hash} on `self` with the provided `key`.
|
16
|
-
#
|
17
37
|
def as_hash key = nil
|
18
38
|
NRSER.as_hash self, key
|
19
39
|
end
|
20
40
|
|
21
|
-
#
|
41
|
+
# Call {NRSER.as_array} on `self`.
|
22
42
|
def as_array
|
23
43
|
NRSER.as_array self
|
24
44
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# Requirements
|
2
|
+
# =======================================================================
|
3
|
+
|
4
|
+
# Stdlib
|
5
|
+
# -----------------------------------------------------------------------
|
6
|
+
|
7
|
+
# Deps
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
|
10
|
+
# Project / Package
|
11
|
+
# -----------------------------------------------------------------------
|
12
|
+
|
13
|
+
|
14
|
+
# Declarations
|
15
|
+
# =======================================================================
|
16
|
+
|
17
|
+
module NRSER; end
|
18
|
+
module NRSER::Refinements; end
|
19
|
+
|
20
|
+
|
21
|
+
# Definitions
|
22
|
+
# =======================================================================
|
23
|
+
|
24
|
+
# Instance methods that are refined in to the Ruby built-ins that we consider
|
25
|
+
# trees: {Array}, {Hash} and {OpenStruct}.
|
26
|
+
#
|
27
|
+
module NRSER::Refinements::Tree
|
28
|
+
|
29
|
+
# Sends `self` to {NRSER.leaves}.
|
30
|
+
def leaves
|
31
|
+
NRSER.leaves self
|
32
|
+
end # #leaves
|
33
|
+
|
34
|
+
|
35
|
+
# Sends `self` and the optional `block` to {NRSER.each_branch}.
|
36
|
+
def each_branch &block
|
37
|
+
NRSER.each_branch self, &block
|
38
|
+
end
|
39
|
+
|
40
|
+
end # module NRSER::Refinements::Tree
|
41
|
+
|
data/lib/nrser/rspex.rb
ADDED
@@ -0,0 +1,329 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
##############################################################################
|
4
|
+
# RSpec helpers, shared examples, extensions, and other goodies.
|
5
|
+
#
|
6
|
+
# This file is *not* required by default when `nrser` is since it **defines
|
7
|
+
# global methods** and is not needed unless you're in [Rspec][].
|
8
|
+
#
|
9
|
+
# [Rspec]: http://rspec.info/
|
10
|
+
#
|
11
|
+
##############################################################################
|
12
|
+
|
13
|
+
|
14
|
+
# Requirements
|
15
|
+
# =======================================================================
|
16
|
+
|
17
|
+
# Stdlib
|
18
|
+
# -----------------------------------------------------------------------
|
19
|
+
|
20
|
+
# Deps
|
21
|
+
# -----------------------------------------------------------------------
|
22
|
+
|
23
|
+
# Project / Package
|
24
|
+
# -----------------------------------------------------------------------
|
25
|
+
require_relative './message'
|
26
|
+
|
27
|
+
|
28
|
+
# Helpers
|
29
|
+
# =====================================================================
|
30
|
+
|
31
|
+
# Merge "expectation" hashes by appending all clauses for each state.
|
32
|
+
#
|
33
|
+
# @example
|
34
|
+
#
|
35
|
+
#
|
36
|
+
# @param [Array<Hash>] *expectations
|
37
|
+
# Splat of "expectation" hashes - see the examples.
|
38
|
+
#
|
39
|
+
def merge_expectations *expectations
|
40
|
+
Hash.new { |result, state|
|
41
|
+
result[state] = []
|
42
|
+
}.tap { |result|
|
43
|
+
expectations.each { |ex|
|
44
|
+
ex.each { |state, clauses|
|
45
|
+
result[state] += clauses.to_a
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
class Wrapper
|
52
|
+
def initialize description: nil, &block
|
53
|
+
@description = description
|
54
|
+
@block = block
|
55
|
+
end
|
56
|
+
|
57
|
+
def unwrap context: nil
|
58
|
+
if context
|
59
|
+
context.instance_exec &@block
|
60
|
+
else
|
61
|
+
@block.call
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_s
|
66
|
+
if @description
|
67
|
+
@description.to_s
|
68
|
+
else
|
69
|
+
"#<Wrapper ?>"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def wrap description = nil, &block
|
75
|
+
Wrapper.new description: description, &block
|
76
|
+
end
|
77
|
+
|
78
|
+
def unwrap obj, context: nil
|
79
|
+
if obj.is_a? Wrapper
|
80
|
+
obj.unwrap context: context
|
81
|
+
else
|
82
|
+
obj
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Extensions
|
87
|
+
# =====================================================================
|
88
|
+
|
89
|
+
module NRSER; end
|
90
|
+
|
91
|
+
module NRSER::RSpex
|
92
|
+
PREFIXES = {
|
93
|
+
# module: "𝓜 𝓸𝓭𝓾𝓵𝓮",
|
94
|
+
module: "𝞛",
|
95
|
+
section: '§',
|
96
|
+
method: '𝞴',
|
97
|
+
}
|
98
|
+
|
99
|
+
# Instance methods to extend example groups with.
|
100
|
+
#
|
101
|
+
module ExampleGroup
|
102
|
+
|
103
|
+
# Create a new {RSpec.describe} section where the subject is set by
|
104
|
+
# calling the parent subject with `args` and evaluate `block` in it.
|
105
|
+
#
|
106
|
+
# @example
|
107
|
+
# describe "hi sayer" do
|
108
|
+
# subject{ ->( name ) { "Hi #{ name }!" } }
|
109
|
+
#
|
110
|
+
# describe_called_with 'Mom' do
|
111
|
+
# it { is_expected.to eq 'Hi Mom!' }
|
112
|
+
# end
|
113
|
+
# end
|
114
|
+
#
|
115
|
+
# @param [Array] *args
|
116
|
+
# Arguments to call `subject` with to produce the new subject.
|
117
|
+
#
|
118
|
+
# @param [#call] &block
|
119
|
+
# Block to execute in the context of the example group after refining
|
120
|
+
# the subject.
|
121
|
+
#
|
122
|
+
def describe_called_with *args, &block
|
123
|
+
describe "called with #{ args.map( &:inspect ).join( ', ' ) }" do
|
124
|
+
subject { super().call *args }
|
125
|
+
instance_exec &block
|
126
|
+
end
|
127
|
+
end # #describe_called_with
|
128
|
+
|
129
|
+
# Aliases to other names I was using at first... not preferring their use
|
130
|
+
# at the moment.
|
131
|
+
#
|
132
|
+
# The `when_` one sucks because Atom de-dents the line, and `describe_`
|
133
|
+
# is just clearer what the block is doing for people reading it.
|
134
|
+
alias_method :called_with, :describe_called_with
|
135
|
+
alias_method :when_called_with, :describe_called_with
|
136
|
+
|
137
|
+
|
138
|
+
def describe_message symbol, *args, &body
|
139
|
+
description = \
|
140
|
+
"message #{ [symbol, *args].map( &:inspect ).join( ', ' ) }"
|
141
|
+
|
142
|
+
describe description, type: :message do
|
143
|
+
subject { NRSER::Message.new symbol, *args }
|
144
|
+
instance_exec &body
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
# For use when `subject` is a {NRSER::Message}. Create a new context for
|
150
|
+
# the `receiver` where the subject is the result of sending that message
|
151
|
+
# to the receiver.
|
152
|
+
#
|
153
|
+
# @param [Object] receiver
|
154
|
+
# Object that will receive the message to create the new subject.
|
155
|
+
#
|
156
|
+
# @param [Boolean] publicly:
|
157
|
+
# Send message publicly via {Object#public_send} (default) or privately
|
158
|
+
# via {Object.send}.
|
159
|
+
#
|
160
|
+
# @return
|
161
|
+
# Whatever the `context` call returns.
|
162
|
+
#
|
163
|
+
def describe_sent_to receiver, publicly: true, &block
|
164
|
+
mode = if publicly
|
165
|
+
"publicly"
|
166
|
+
else
|
167
|
+
"privately"
|
168
|
+
end
|
169
|
+
|
170
|
+
describe "sent to #{ receiver } (#{ mode })" do
|
171
|
+
subject { super().send_to unwrap( receiver, context: self ) }
|
172
|
+
instance_exec &block
|
173
|
+
end
|
174
|
+
end # #describe_sent_to
|
175
|
+
|
176
|
+
# Aliases to other names I was using at first... not preferring their use
|
177
|
+
# at the moment.
|
178
|
+
#
|
179
|
+
# The `when_` one sucks because Atom de-dents the line, and `describe_`
|
180
|
+
# is just clearer what the block is doing for people reading it.
|
181
|
+
alias_method :sent_to, :describe_sent_to
|
182
|
+
alias_method :when_sent_to, :describe_sent_to
|
183
|
+
|
184
|
+
|
185
|
+
# Describe a "section". Just like {RSpec.describe} except it:
|
186
|
+
#
|
187
|
+
# 1. Expects a string title.
|
188
|
+
#
|
189
|
+
# 2. Prepends a little section squiggle `§` to the title so sections are
|
190
|
+
# easier to pick out visually.
|
191
|
+
#
|
192
|
+
# 3. Adds `type: :section` metadata.
|
193
|
+
#
|
194
|
+
# @param [String] title
|
195
|
+
# String title for the section.
|
196
|
+
#
|
197
|
+
# @param [Hash<Symbol, Object>] **metadata
|
198
|
+
# Additional [RSpec metadata][] for the example group.
|
199
|
+
#
|
200
|
+
# [RSpec metadata]: https://relishapp.com/rspec/rspec-core/docs/metadata/user-defined-metadata
|
201
|
+
#
|
202
|
+
# @return
|
203
|
+
# Whatever {RSpec.describe} returns.
|
204
|
+
#
|
205
|
+
def describe_section title, **metadata, &block
|
206
|
+
describe(
|
207
|
+
"#{ NRSER::RSpex::PREFIXES[:section] } #{ title }",
|
208
|
+
type: :section,
|
209
|
+
**metadata
|
210
|
+
) do
|
211
|
+
instance_exec &block
|
212
|
+
end
|
213
|
+
end # #describe_section
|
214
|
+
|
215
|
+
# Old name
|
216
|
+
alias_method :describe_topic, :describe_section
|
217
|
+
|
218
|
+
|
219
|
+
def describe_module mod, **metadata, &block
|
220
|
+
describe(
|
221
|
+
"#{ NRSER::RSpex::PREFIXES[:module] } #{ mod.name }",
|
222
|
+
type: :module,
|
223
|
+
**metadata
|
224
|
+
) do
|
225
|
+
instance_exec &block
|
226
|
+
end
|
227
|
+
end # #describe_module
|
228
|
+
|
229
|
+
|
230
|
+
def describe_method name, **metadata, &block
|
231
|
+
describe(
|
232
|
+
"#{ NRSER::RSpex::PREFIXES[:method] } #{ name }",
|
233
|
+
type: :method,
|
234
|
+
**metadata
|
235
|
+
) do
|
236
|
+
instance_exec &block
|
237
|
+
end
|
238
|
+
end # #describe_section
|
239
|
+
|
240
|
+
|
241
|
+
# Define a `context` block with `let` bindings and evaluate the `body`
|
242
|
+
# block in it.
|
243
|
+
#
|
244
|
+
# @param [Hash<Symbol, Object>] **bindings
|
245
|
+
# Map of symbol names to value to bind using `let`.
|
246
|
+
#
|
247
|
+
# @param [#call] &body
|
248
|
+
# Body block to evaluate in the context.
|
249
|
+
#
|
250
|
+
# @return
|
251
|
+
# Whatever `context` returns.
|
252
|
+
#
|
253
|
+
def context_where **bindings, &body
|
254
|
+
description = bindings.map { |name, value|
|
255
|
+
"let #{ name } = #{ value }"
|
256
|
+
}.join( ', ' )
|
257
|
+
|
258
|
+
context "| #{ description } |", type: :where do
|
259
|
+
bindings.each { |name, value|
|
260
|
+
let( name ) { unwrap value, context: self }
|
261
|
+
}
|
262
|
+
|
263
|
+
instance_exec &body
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
|
268
|
+
end # module ExampleGroup
|
269
|
+
|
270
|
+
end # module NRSER:RSpex
|
271
|
+
|
272
|
+
RSpec.configure do |config|
|
273
|
+
config.extend NRSER::RSpex::ExampleGroup
|
274
|
+
end
|
275
|
+
|
276
|
+
|
277
|
+
include NRSER::RSpex::ExampleGroup
|
278
|
+
|
279
|
+
|
280
|
+
# Shared Examples
|
281
|
+
# =====================================================================
|
282
|
+
|
283
|
+
shared_examples "expect subject" do |*expectations|
|
284
|
+
merge_expectations( *expectations ).each { |state, specs|
|
285
|
+
specs.each { |verb, noun|
|
286
|
+
it {
|
287
|
+
# like: is_expected.to(include(noun))
|
288
|
+
is_expected.send state, self.send(verb, noun)
|
289
|
+
}
|
290
|
+
}
|
291
|
+
}
|
292
|
+
end # is expected
|
293
|
+
|
294
|
+
|
295
|
+
# Shared example for a functional method that compares input and output pairs.
|
296
|
+
#
|
297
|
+
shared_examples "function" do |mapping: {}, raising: {}|
|
298
|
+
mapping.each { |args, expected|
|
299
|
+
args = NRSER.as_array args
|
300
|
+
|
301
|
+
context "called with #{ args.map( &:inspect ).join ', ' }" do
|
302
|
+
subject { super().call *args }
|
303
|
+
|
304
|
+
it {
|
305
|
+
expected = unwrap expected, context: self
|
306
|
+
|
307
|
+
matcher = if expected.respond_to?( :matches? )
|
308
|
+
expected
|
309
|
+
elsif expected.is_a? NRSER::Message
|
310
|
+
expected.send_to self
|
311
|
+
else
|
312
|
+
eq expected
|
313
|
+
end
|
314
|
+
|
315
|
+
is_expected.to matcher
|
316
|
+
}
|
317
|
+
end
|
318
|
+
}
|
319
|
+
|
320
|
+
raising.each { |args, error|
|
321
|
+
args = NRSER.as_array args
|
322
|
+
|
323
|
+
context "called with #{ args.map( &:inspect ).join ', ' }" do
|
324
|
+
# it "rejects #{ args.map( &:inspect ).join ', ' }" do
|
325
|
+
it { expect { subject.call *args }.to raise_error( *error ) }
|
326
|
+
end
|
327
|
+
}
|
328
|
+
end # function
|
329
|
+
|