nrser 0.1.1 β 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/nrser/env/path.rb +325 -0
- data/lib/nrser/env.rb +12 -0
- data/lib/nrser/errors/attr_error.rb +73 -0
- data/lib/nrser/errors/count_error.rb +19 -0
- data/lib/nrser/errors/nicer_error.rb +110 -0
- data/lib/nrser/errors/value_error.rb +72 -0
- data/lib/nrser/errors.rb +23 -6
- data/lib/nrser/functions/enumerable.rb +9 -2
- data/lib/nrser/functions/path.rb +3 -1
- data/lib/nrser/functions/string.rb +28 -11
- data/lib/nrser/functions/text/indentation.rb +16 -4
- data/lib/nrser/mean_streak/document.rb +151 -0
- data/lib/nrser/mean_streak.rb +95 -0
- data/lib/nrser/refinements/array.rb +6 -0
- data/lib/nrser/refinements/string.rb +6 -0
- data/lib/nrser/rspex/example_group/describe_instance.rb +24 -0
- data/lib/nrser/rspex/example_group/describe_instance_method.rb +20 -0
- data/lib/nrser/rspex/example_group/describe_setup.rb +22 -0
- data/lib/nrser/rspex/example_group/describe_spec_file.rb +127 -0
- data/lib/nrser/rspex/example_group/describe_use_case.rb +18 -0
- data/lib/nrser/rspex/example_group/describe_when.rb +25 -0
- data/lib/nrser/rspex/example_group/describe_x.rb +100 -0
- data/lib/nrser/rspex/example_group.rb +270 -0
- data/lib/nrser/rspex/format.rb +174 -0
- data/lib/nrser/rspex.rb +31 -395
- data/lib/nrser/types/paths.rb +2 -3
- data/lib/nrser/types.rb +5 -1
- data/lib/nrser/version.rb +1 -1
- data/lib/nrser.rb +3 -1
- data/spec/nrser/env/path/insert_spec.rb +65 -0
- data/spec/nrser/env/path_spec.rb +12 -0
- metadata +99 -8
data/lib/nrser/functions/path.rb
CHANGED
@@ -121,10 +121,18 @@ module NRSER
|
|
121
121
|
end # .truncate
|
122
122
|
|
123
123
|
|
124
|
-
# Cut the middle out of a
|
124
|
+
# Cut the middle out of a sliceable object with length and stick an ellipsis
|
125
|
+
# in there instead.
|
125
126
|
#
|
126
|
-
#
|
127
|
-
#
|
127
|
+
# Categorized with {String} functions 'cause that's where it started, and
|
128
|
+
# that's probably how it will primarily continue to be used, but tested to
|
129
|
+
# work on {Array} and should for other classes that satisfy the same
|
130
|
+
# slice and interface.
|
131
|
+
#
|
132
|
+
# @param [V & #length & #slice & #<< & #+] source
|
133
|
+
# Source object. In practice, {String} and {Array} work. In theory,
|
134
|
+
# anything that responds to `#length`, `#slice`, `#<<` and `#+` with the
|
135
|
+
# same semantics will work.
|
128
136
|
#
|
129
137
|
# @param [Fixnum] max
|
130
138
|
# Max length to allow for the output string.
|
@@ -134,18 +142,27 @@ module NRSER
|
|
134
142
|
# removed. Defaults to the unicode ellipsis since I'm targeting the CLI
|
135
143
|
# at the moment and it saves precious characters.
|
136
144
|
#
|
137
|
-
# @return [
|
138
|
-
#
|
139
|
-
# to do so
|
140
|
-
|
141
|
-
|
145
|
+
# @return [V]
|
146
|
+
# Object of the same type as `source` of at most `max` length with the
|
147
|
+
# middle chopped out if needed to do so.\*
|
148
|
+
#
|
149
|
+
# \* Really, it has to do with how all the used methods are implemented,
|
150
|
+
# but we hope that conforming classes will return instances of their own
|
151
|
+
# class like {String} and {Array} do.
|
152
|
+
#
|
153
|
+
def self.ellipsis source, max, omission: UNICODE_ELLIPSIS
|
154
|
+
return source unless source.length > max
|
142
155
|
|
143
156
|
trim_to = max - omission.length
|
157
|
+
middle = trim_to / 2
|
158
|
+
remainder = trim_to % 2
|
144
159
|
|
145
|
-
start =
|
146
|
-
|
160
|
+
start = source.slice( 0, middle + remainder )
|
161
|
+
start << omission
|
147
162
|
|
148
|
-
|
163
|
+
finish = source.slice( -( middle - remainder )..-1 )
|
164
|
+
|
165
|
+
start + finish
|
149
166
|
end # .ellipsis
|
150
167
|
|
151
168
|
|
@@ -52,10 +52,16 @@ module NRSER
|
|
52
52
|
end
|
53
53
|
|
54
54
|
|
55
|
-
def self.dedent text,
|
55
|
+
def self.dedent text,
|
56
|
+
ignore_whitespace_lines: true,
|
57
|
+
return_lines: false
|
56
58
|
return text if text.empty?
|
57
59
|
|
58
|
-
all_lines = text.
|
60
|
+
all_lines = if text.is_a?( Array )
|
61
|
+
text
|
62
|
+
else
|
63
|
+
text.lines
|
64
|
+
end
|
59
65
|
|
60
66
|
indent_significant_lines = if ignore_whitespace_lines
|
61
67
|
all_lines.reject { |line| whitespace? line }
|
@@ -67,7 +73,7 @@ module NRSER
|
|
67
73
|
|
68
74
|
return text if indent.empty?
|
69
75
|
|
70
|
-
all_lines.map { |line|
|
76
|
+
dedented_lines = all_lines.map { |line|
|
71
77
|
if line.start_with? indent
|
72
78
|
line[indent.length..-1]
|
73
79
|
elsif line.end_with? "\n"
|
@@ -75,7 +81,13 @@ module NRSER
|
|
75
81
|
else
|
76
82
|
""
|
77
83
|
end
|
78
|
-
}
|
84
|
+
}
|
85
|
+
|
86
|
+
if return_lines
|
87
|
+
dedented_lines
|
88
|
+
else
|
89
|
+
dedented_lines.join
|
90
|
+
end
|
79
91
|
end # .dedent
|
80
92
|
|
81
93
|
# I like dedent better, but other libs seems to call it deindent
|
@@ -0,0 +1,151 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Requirements
|
4
|
+
# =======================================================================
|
5
|
+
|
6
|
+
# Stdlib
|
7
|
+
# -----------------------------------------------------------------------
|
8
|
+
|
9
|
+
# Deps
|
10
|
+
# -----------------------------------------------------------------------
|
11
|
+
|
12
|
+
# Project / Package
|
13
|
+
# -----------------------------------------------------------------------
|
14
|
+
|
15
|
+
|
16
|
+
# Refinements
|
17
|
+
# =======================================================================
|
18
|
+
|
19
|
+
|
20
|
+
# Declarations
|
21
|
+
# =======================================================================
|
22
|
+
|
23
|
+
|
24
|
+
# Definitions
|
25
|
+
# =======================================================================
|
26
|
+
|
27
|
+
|
28
|
+
# @todo document NRSER::MeanStreak::Document class.
|
29
|
+
class NRSER::MeanStreak::Document
|
30
|
+
|
31
|
+
# Constants
|
32
|
+
# ======================================================================
|
33
|
+
|
34
|
+
|
35
|
+
# Class Methods
|
36
|
+
# ======================================================================
|
37
|
+
|
38
|
+
# @todo Document from method.
|
39
|
+
#
|
40
|
+
# @param [type] arg_name
|
41
|
+
# @todo Add name param description.
|
42
|
+
#
|
43
|
+
# @return [NRSER::MeanStreak::Document]
|
44
|
+
# @todo Document return value.
|
45
|
+
#
|
46
|
+
def self.parse source,
|
47
|
+
mean_streak:,
|
48
|
+
cm_options: :DEFAULT,
|
49
|
+
cm_extensions: []
|
50
|
+
new mean_streak: mean_streak,
|
51
|
+
source: source,
|
52
|
+
doc: CommonMarker.render_doc( source, options, extensions )
|
53
|
+
end # .parse
|
54
|
+
|
55
|
+
singleton_class.send :alias_method, :from_string, :parse
|
56
|
+
singleton_class.send :alias_method, :from_s, :parse
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
# Attributes
|
61
|
+
# ======================================================================
|
62
|
+
|
63
|
+
# The {NRSER::MeanStreak} instance associated with this document, which
|
64
|
+
# contains the rendering configuration.
|
65
|
+
#
|
66
|
+
# @return [NRSER::MeanStreak]
|
67
|
+
#
|
68
|
+
attr_reader :mean_streak
|
69
|
+
|
70
|
+
|
71
|
+
# The source string.
|
72
|
+
#
|
73
|
+
# @return [String]
|
74
|
+
#
|
75
|
+
attr_reader :source
|
76
|
+
|
77
|
+
|
78
|
+
# The root {CommonMarker::Node} (with {CommonMarker::Node#type}=`:document`).
|
79
|
+
#
|
80
|
+
# @return [CommonMarker::Node]
|
81
|
+
#
|
82
|
+
attr_reader :doc
|
83
|
+
|
84
|
+
|
85
|
+
# Constructor
|
86
|
+
# ======================================================================
|
87
|
+
|
88
|
+
# Instantiate a new `NRSER::MeanStreak::Document`.
|
89
|
+
#
|
90
|
+
# @param mean_streak
|
91
|
+
# See {NRSER::MeanStreak::Document#mean_streak}
|
92
|
+
#
|
93
|
+
def initialize mean_streak:, source:, doc:
|
94
|
+
@mean_streak = mean_streak
|
95
|
+
@source = source.dup.freeze
|
96
|
+
@doc = doc
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
# Instance Methods
|
101
|
+
# ======================================================================
|
102
|
+
|
103
|
+
# The lines in {#source} as a {Hamster::Vector} of frozen strings.
|
104
|
+
#
|
105
|
+
# @return [Hamster::Vector<String>]
|
106
|
+
#
|
107
|
+
def source_lines
|
108
|
+
@source_lines = Hamster::Vector.new source.lines.map( &:freeze )
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
# Get the substring of the source that a node came from (via its
|
113
|
+
# `#sourcepos`).
|
114
|
+
#
|
115
|
+
# @return [String]
|
116
|
+
#
|
117
|
+
def source_for_node node
|
118
|
+
pos = node.sourcepos
|
119
|
+
|
120
|
+
if pos[:start_line] == pos[:end_line]
|
121
|
+
source_lines[pos[:start_line] - 1][
|
122
|
+
(pos[:start_column] - 1)...pos[:end_column]
|
123
|
+
]
|
124
|
+
else
|
125
|
+
lines = source_lines[(pos[:start_line] - 1)...pos[:end_line]]
|
126
|
+
|
127
|
+
# Trim the start off the first line, unless the start column is 1
|
128
|
+
unless pos[:start_column] == 1
|
129
|
+
lines[0] = lines[0][(pos[:start_column] - 1)..-1]
|
130
|
+
end
|
131
|
+
|
132
|
+
# Trim the end off the first line, unless the end column is the last
|
133
|
+
# line's length
|
134
|
+
unless pos[:end_column] == lines[-1].length
|
135
|
+
lines[-1] = lines[-1][0...pos[:end_column]]
|
136
|
+
end
|
137
|
+
|
138
|
+
lines.join
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
def render_node node, output = ''
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
end # class NRSER::MeanStreak::Document
|
148
|
+
|
149
|
+
|
150
|
+
# Post-Processing
|
151
|
+
# =======================================================================
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Requirements
|
4
|
+
# =======================================================================
|
5
|
+
|
6
|
+
# Stdlib
|
7
|
+
# -----------------------------------------------------------------------
|
8
|
+
|
9
|
+
# Deps
|
10
|
+
# -----------------------------------------------------------------------
|
11
|
+
require 'commonmarker'
|
12
|
+
|
13
|
+
# Project / Package
|
14
|
+
# -----------------------------------------------------------------------
|
15
|
+
|
16
|
+
# Refinements
|
17
|
+
# =======================================================================
|
18
|
+
|
19
|
+
|
20
|
+
# Declarations
|
21
|
+
# =======================================================================
|
22
|
+
|
23
|
+
|
24
|
+
# Definitions
|
25
|
+
# =======================================================================
|
26
|
+
|
27
|
+
|
28
|
+
# Tag up terminals with color and style. Uses {CommonMarker} for the parsing
|
29
|
+
# (Markdown / CommonMark / GFM syntax).
|
30
|
+
#
|
31
|
+
# {NRSER::MeanStreak} instances hold configuration and provide functionality
|
32
|
+
# through instance methods, making it easy to use multiple configurations or
|
33
|
+
# subclass {NRSER::MeanStreak} to further customize functionality.
|
34
|
+
#
|
35
|
+
# An instance with default configuration is available via the {.default}
|
36
|
+
# class method, and additional class methods are provided that proxy to the
|
37
|
+
# default's instance methods, providing convenient use of the default config.
|
38
|
+
#
|
39
|
+
class NRSER::MeanStreak
|
40
|
+
|
41
|
+
# Class Methods
|
42
|
+
# ======================================================================
|
43
|
+
|
44
|
+
# Get the default instance, which has the default configuration and is
|
45
|
+
# used by the class methods.
|
46
|
+
#
|
47
|
+
# @return [NRSER::MeanStreak]
|
48
|
+
#
|
49
|
+
def self.default
|
50
|
+
# TODO cache?
|
51
|
+
new
|
52
|
+
end # .default
|
53
|
+
|
54
|
+
|
55
|
+
# Public: Parses a Markdown string into a `document` node.
|
56
|
+
#
|
57
|
+
# string - {String} to be parsed
|
58
|
+
# option - A {Symbol} or {Array of Symbol}s indicating the parse options
|
59
|
+
# extensions - An {Array of Symbol}s indicating the extensions to use
|
60
|
+
#
|
61
|
+
# @return [CommonMarker::Node]
|
62
|
+
# The `document` node.
|
63
|
+
#
|
64
|
+
def self.parse text, options = :DEFAULT, extensions = []
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
# Instance Methods
|
70
|
+
# ============================================================================
|
71
|
+
|
72
|
+
|
73
|
+
# @todo Document parse method.
|
74
|
+
#
|
75
|
+
# @param [type] arg_name
|
76
|
+
# @todo Add name param description.
|
77
|
+
#
|
78
|
+
# @return [return_type]
|
79
|
+
# @todo Document return value.
|
80
|
+
#
|
81
|
+
def parse source, **options
|
82
|
+
NRSER::MeanStreak::Document.parse \
|
83
|
+
source,
|
84
|
+
**options,
|
85
|
+
mean_streak: self
|
86
|
+
end # #parse
|
87
|
+
|
88
|
+
|
89
|
+
end # class NRSER::ShellDown
|
90
|
+
|
91
|
+
|
92
|
+
# Post-Processing
|
93
|
+
# =======================================================================
|
94
|
+
|
95
|
+
require_relative './mean_streak/document'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NRSER::RSpex::ExampleGroup
|
4
|
+
|
5
|
+
# @todo Document describe_instance method.
|
6
|
+
#
|
7
|
+
# @param [type] arg_name
|
8
|
+
# @todo Add name param description.
|
9
|
+
#
|
10
|
+
# @return [return_type]
|
11
|
+
# @todo Document return value.
|
12
|
+
#
|
13
|
+
def describe_instance *constructor_args, &body
|
14
|
+
describe_x_type ".new(", Args(*constructor_args), ")",
|
15
|
+
type: :instance,
|
16
|
+
metadata: {
|
17
|
+
constructor_args: constructor_args,
|
18
|
+
},
|
19
|
+
# subject_block: -> { super().new *described_args },
|
20
|
+
subject_block: -> { super().new *described_constructor_args },
|
21
|
+
&body
|
22
|
+
end # #describe_instance
|
23
|
+
|
24
|
+
end # module NRSER::RSpex::ExampleGroup
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NRSER::RSpex::ExampleGroup
|
4
|
+
|
5
|
+
def describe_instance_method name, **metadata, &block
|
6
|
+
describe(
|
7
|
+
"#{ NRSER::RSpex::PREFIXES[:method] } #{ name }",
|
8
|
+
type: :method,
|
9
|
+
method_name: name,
|
10
|
+
**metadata
|
11
|
+
) do
|
12
|
+
if name.is_a? Symbol
|
13
|
+
subject { super().method name }
|
14
|
+
end
|
15
|
+
|
16
|
+
module_exec &block
|
17
|
+
end
|
18
|
+
end # #describe_method
|
19
|
+
|
20
|
+
end # module NRSER::RSpex::ExampleGroup
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NRSER::RSpex::ExampleGroup
|
4
|
+
|
5
|
+
# Setup describes what's going to be *done* in all child examples.
|
6
|
+
#
|
7
|
+
# It's where you setup your `subject`, usually depending on `let`
|
8
|
+
# bindings that are provided in the children.
|
9
|
+
#
|
10
|
+
# @return [void]
|
11
|
+
#
|
12
|
+
def describe_setup *description, **metadata, &body
|
13
|
+
describe_x \
|
14
|
+
*description,
|
15
|
+
type: :setup,
|
16
|
+
metadata: metadata,
|
17
|
+
&body
|
18
|
+
end # #describe_setup
|
19
|
+
|
20
|
+
alias_method :setup, :describe_setup
|
21
|
+
|
22
|
+
end # module NRSER::RSpex::ExampleGroup
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NRSER::RSpex::ExampleGroup
|
4
|
+
|
5
|
+
# **EXPERIMENTAL**
|
6
|
+
#
|
7
|
+
# Example group helper for use at the top level of each spec file to
|
8
|
+
# set a bunch of stuff up and build a helpful description.
|
9
|
+
#
|
10
|
+
# @todo
|
11
|
+
# This is totally just a one-off right now... would need to be
|
12
|
+
# generalized quite a bit...
|
13
|
+
#
|
14
|
+
# 1. Extraction of module, class, etc from metadata should be flexible
|
15
|
+
#
|
16
|
+
# 2. Built description would need to be conditional on what metadata
|
17
|
+
# was found.
|
18
|
+
#
|
19
|
+
# @param [String] description:
|
20
|
+
# A description of the spec file to add to the RSpec description.
|
21
|
+
#
|
22
|
+
# @param [String] spec_path:
|
23
|
+
# The path to the spec file (just feed it `__FILE__`).
|
24
|
+
#
|
25
|
+
# Probably possible to extract this somehow without having to provide it?
|
26
|
+
#
|
27
|
+
# @return [nil]
|
28
|
+
#
|
29
|
+
def describe_spec_file description: nil,
|
30
|
+
spec_path:,
|
31
|
+
bind_subject: true,
|
32
|
+
**metadata,
|
33
|
+
&body
|
34
|
+
|
35
|
+
if metadata[:module] && metadata[:method]
|
36
|
+
meth = metadata[:module].method metadata[:method]
|
37
|
+
file, line = meth.source_location
|
38
|
+
path = Pathname.new file
|
39
|
+
loc = "./#{ path.relative_path_from Pathname.getwd }:#{ line }"
|
40
|
+
|
41
|
+
spec_rel_path = \
|
42
|
+
"./#{ Pathname.new( spec_path ).relative_path_from Pathname.getwd }"
|
43
|
+
|
44
|
+
desc = [
|
45
|
+
"#{ metadata[:module].name }.#{ metadata[:method] }",
|
46
|
+
"(#{ loc })",
|
47
|
+
description,
|
48
|
+
"Spec (#{ spec_rel_path})"
|
49
|
+
].compact.join " "
|
50
|
+
|
51
|
+
subj = meth
|
52
|
+
|
53
|
+
elsif metadata[:class]
|
54
|
+
klass = metadata[:class]
|
55
|
+
|
56
|
+
if metadata[:instance_method]
|
57
|
+
instance_method = klass.instance_method metadata[:instance_method]
|
58
|
+
|
59
|
+
file, line = instance_method.source_location
|
60
|
+
|
61
|
+
name = "#{ klass.name }##{ metadata[:instance_method] }"
|
62
|
+
else
|
63
|
+
name = klass.name
|
64
|
+
|
65
|
+
# Get a reasonable file and line for the class
|
66
|
+
file, line = klass.
|
67
|
+
# Get an array of all instance methods, excluding inherited ones
|
68
|
+
# (the `false` arg)
|
69
|
+
instance_methods( false ).
|
70
|
+
# Add `#initialize` since it isn't in `#instance_methods` for some
|
71
|
+
# reason
|
72
|
+
<<( :initialize ).
|
73
|
+
# Map those to their {UnboundMethod} objects
|
74
|
+
map { |sym| klass.instance_method sym }.
|
75
|
+
# Toss any `nil` values
|
76
|
+
compact.
|
77
|
+
# Get the source locations
|
78
|
+
map( &:source_location ).
|
79
|
+
# Get the first line in the shortest path
|
80
|
+
min_by { |(path, line)| [path.length, line] }
|
81
|
+
|
82
|
+
# Another approach I thought of... (untested)
|
83
|
+
#
|
84
|
+
# Get the path
|
85
|
+
# # Get frequency of the paths
|
86
|
+
# count_by { |(path, line)| path }.
|
87
|
+
# # Get the one with the most occurrences
|
88
|
+
# max_by { |path, count| count }.
|
89
|
+
# # Get just the path (not the count)
|
90
|
+
# first
|
91
|
+
end
|
92
|
+
|
93
|
+
location = if file
|
94
|
+
"(#{ NRSER::RSpex.dot_rel_path file }:#{ line })"
|
95
|
+
end
|
96
|
+
|
97
|
+
desc = [
|
98
|
+
"πππΈπΆ πΉπΌπΏπΈ `#{ NRSER::RSpex.dot_rel_path spec_path }` πΉππ
",
|
99
|
+
name,
|
100
|
+
location,
|
101
|
+
description,
|
102
|
+
].compact.join " "
|
103
|
+
|
104
|
+
subj = klass
|
105
|
+
|
106
|
+
else
|
107
|
+
# TODO Make this work!
|
108
|
+
raise ArgumentError.new binding.erb <<-END
|
109
|
+
Not yet able to handle metadata:
|
110
|
+
|
111
|
+
<%= metadata.pretty_inspect %>
|
112
|
+
|
113
|
+
END
|
114
|
+
end
|
115
|
+
|
116
|
+
describe desc, **metadata do
|
117
|
+
if bind_subject
|
118
|
+
subject { subj }
|
119
|
+
end
|
120
|
+
|
121
|
+
module_exec &body
|
122
|
+
end
|
123
|
+
|
124
|
+
nil
|
125
|
+
end # #describe_spec_file
|
126
|
+
|
127
|
+
end # module NRSER::RSpex::ExampleGroup
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NRSER::RSpex::ExampleGroup
|
4
|
+
|
5
|
+
# @todo Document describe_use_case method.
|
6
|
+
#
|
7
|
+
# @return [void]
|
8
|
+
#
|
9
|
+
def describe_use_case *description, where: {}, **metadata, &body
|
10
|
+
describe_x \
|
11
|
+
*description,
|
12
|
+
type: :use_case,
|
13
|
+
bindings: where,
|
14
|
+
metadata: metadata,
|
15
|
+
&body
|
16
|
+
end # #describe_use_case
|
17
|
+
|
18
|
+
end # module NRSER::RSpex::ExampleGroup
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NRSER::RSpex::ExampleGroup
|
4
|
+
|
5
|
+
# Define a example group block with `let` bindings and evaluate the `body`
|
6
|
+
# block in it.
|
7
|
+
#
|
8
|
+
# @param [Hash<Symbol, Object>] **bindings
|
9
|
+
# Map of symbol names to value to bind using `let`.
|
10
|
+
#
|
11
|
+
# @param [#call] &body
|
12
|
+
# Body block to evaluate in the context.
|
13
|
+
#
|
14
|
+
# @return
|
15
|
+
# Whatever `context` returns.
|
16
|
+
#
|
17
|
+
def describe_when *description, **bindings, &body
|
18
|
+
describe_x \
|
19
|
+
*description,
|
20
|
+
type: :when,
|
21
|
+
bindings: bindings,
|
22
|
+
&body
|
23
|
+
end
|
24
|
+
|
25
|
+
end # module NRSER::RSpex::ExampleGroup
|