nrser 0.0.25 → 0.0.26
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/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
|
+
|