Module: NRSER::RSpex::ExampleGroup
- Defined in:
- lib/nrser/rspex/example_group.rb,
lib/nrser/rspex/example_group/describe_x.rb,
lib/nrser/rspex/example_group/describe_when.rb,
lib/nrser/rspex/example_group/describe_setup.rb,
lib/nrser/rspex/example_group/describe_instance.rb,
lib/nrser/rspex/example_group/describe_use_case.rb,
lib/nrser/rspex/example_group/describe_spec_file.rb,
lib/nrser/rspex/example_group/describe_instance_method.rb
Overview
Instance methods to extend examples groups with. Also included globally so they’re available at the top-level in files.
Instance Method Summary collapse
-
#context_where(description = nil, **bindings, &body) ⇒ Object
Define a ‘context` block with `let` bindings and evaluate the `body` block in it.
- #describe_attribute(symbol, **metadata, &block) ⇒ Object (also: #describe_attr)
-
#describe_called_with(*args, &body) ⇒ Object
(also: #called_with, #when_called_with)
Create a new RSpec.describe section where the subject is set by calling the parent subject with ‘args` and evaluate `block` in it.
- #describe_class(klass, bind_subject: true, **metadata, &block) ⇒ Object
- #describe_file(path, **metadata, &body) ⇒ Object
- #describe_group(title, **metadata, &block) ⇒ Object
- #describe_instance(*constructor_args, &body) ⇒ return_type
- #describe_instance_method(name, **metadata, &block) ⇒ Object
- #describe_message(symbol, *args, &body) ⇒ Object
- #describe_method(name, **metadata, &block) ⇒ Object
- #describe_module(mod, bind_subject: true, **metadata, &block) ⇒ Object
- #describe_return_value(*args, &body) ⇒ Object
-
#describe_section(title, **metadata, &block) ⇒ Object
(also: #describe_topic)
Describe a “section”.
-
#describe_sent_to(receiver, publicly: true, &block) ⇒ Object
(also: #sent_to, #when_sent_to)
For use when ‘subject` is a Message.
-
#describe_setup(*description, **metadata, &body) ⇒ void
(also: #setup)
Setup describes what’s going to be done in all child examples.
-
#describe_spec_file(description: nil, spec_path:, bind_subject: true, **metadata, &body) ⇒ nil
EXPERIMENTAL.
- #describe_use_case(*description, where: {}, **metadata, &body) ⇒ void
-
#describe_when(*description, **bindings, &body) ⇒ Object
Define a example group block with ‘let` bindings and evaluate the `body` block in it.
-
#describe_x(*description, type:, metadata: {}, bindings: {}, add_binding_desc: true, subject_block: nil, &body) ⇒ return_type
(also: #describe_x_type)
The core, mostly internal method that all RSpex’s description methods lead back too (or should / will when refactoring is done).
- #described_class ⇒ Object
Instance Method Details
#context_where(description = nil, **bindings, &body) ⇒ Object
Define a ‘context` block with `let` bindings and evaluate the `body` block in it.
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 |
# File 'lib/nrser/rspex/example_group.rb', line 242 def context_where description = nil, **bindings, &body if description.nil? description = bindings.map { |name, value| "#{ name }: #{ NRSER::RSpex.short_s value }" }.join( ", " ) end context "△ #{ description }", type: :where do bindings.each { |name, value| let( name ) { unwrap value, context: self } } module_exec &body end end |
#describe_attribute(symbol, **metadata, &block) ⇒ Object Also known as: describe_attr
215 216 217 218 219 220 221 222 223 224 |
# File 'lib/nrser/rspex/example_group.rb', line 215 def describe_attribute symbol, **, &block describe( "#{ NRSER::RSpex::PREFIXES[:attribute] } ##{ symbol }", type: :attribute, ** ) do subject { super().public_send symbol } module_exec &block end end |
#describe_called_with(*args, &body) ⇒ Object Also known as: called_with, when_called_with
Create a new RSpec.describe section where the subject is set by calling the parent subject with ‘args` and evaluate `block` in it.
28 29 30 31 32 33 |
# File 'lib/nrser/rspex/example_group.rb', line 28 def describe_called_with *args, &body describe_x_type "called with", List(*args), type: :invocation, subject_block: -> { super().call *args }, &body end |
#describe_class(klass, bind_subject: true, **metadata, &block) ⇒ Object
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/nrser/rspex/example_group.rb', line 165 def describe_class klass, bind_subject: true, **, &block description = "#{ NRSER::RSpex::PREFIXES[:class] } #{ klass.name }" describe( description, type: :class, class: klass, ** ) do if bind_subject subject { klass } end module_exec &block end end |
#describe_file(path, **metadata, &body) ⇒ Object
135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/nrser/rspex/example_group.rb', line 135 def describe_file path, **, &body title = path describe( "#{ NRSER::RSpex::PREFIXES[:file] } #{ title }", type: :file, file: path, ** ) do module_exec &body end end |
#describe_group(title, **metadata, &block) ⇒ Object
188 189 190 191 192 193 194 195 196 |
# File 'lib/nrser/rspex/example_group.rb', line 188 def describe_group title, **, &block describe( "#{ NRSER::RSpex::PREFIXES[:group] } #{ title }", type: :group, ** ) do module_exec &block end end |
#describe_instance(*constructor_args, &body) ⇒ return_type
Document describe_instance method.
Returns @todo Document return value.
13 14 15 16 17 18 19 20 21 22 |
# File 'lib/nrser/rspex/example_group/describe_instance.rb', line 13 def describe_instance *constructor_args, &body describe_x_type ".new(", Args(*constructor_args), ")", type: :instance, metadata: { constructor_args: constructor_args, }, # subject_block: -> { super().new *described_args }, subject_block: -> { super().new *described_constructor_args }, &body end |
#describe_instance_method(name, **metadata, &block) ⇒ Object
5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# File 'lib/nrser/rspex/example_group/describe_instance_method.rb', line 5 def describe_instance_method name, **, &block describe( "#{ NRSER::RSpex::PREFIXES[:method] } #{ name }", type: :method, method_name: name, ** ) do if name.is_a? Symbol subject { super().method name } end module_exec &block end end |
#describe_message(symbol, *args, &body) ⇒ Object
44 45 46 47 48 49 50 51 52 |
# File 'lib/nrser/rspex/example_group.rb', line 44 def symbol, *args, &body description = \ "message #{ [symbol, *args].map( &NRSER::RSpex.method( :short_s ) ).join( ', ' ) }" describe description, type: :message do subject { NRSER::Message.new symbol, *args } module_exec &body end end |
#describe_method(name, **metadata, &block) ⇒ Object
199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/nrser/rspex/example_group.rb', line 199 def describe_method name, **, &block describe( "#{ NRSER::RSpex::PREFIXES[:method] } #{ name }", type: :method, method_name: name, ** ) do if name.is_a? Symbol subject { super().method name } end module_exec &block end end |
#describe_module(mod, bind_subject: true, **metadata, &block) ⇒ Object
149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/nrser/rspex/example_group.rb', line 149 def describe_module mod, bind_subject: true, **, &block describe( "#{ NRSER::RSpex::PREFIXES[:module] } #{ mod.name }", type: :module, module: mod, ** ) do if bind_subject subject { mod } end module_exec &block end end |
#describe_return_value(*args, &body) ⇒ Object
91 92 93 94 95 96 97 98 |
# File 'lib/nrser/rspex/example_group.rb', line 91 def describe_return_value *args, &body msg = NRSER::Message.from *args describe "return value from #{ msg }" do subject { msg.send_to super() } module_exec &body end # "return value from #{ msg }" end |
#describe_section(title, **metadata, &block) ⇒ Object Also known as: describe_topic
Describe a “section”. Just like RSpec.describe except it:
-
Expects a string title.
-
Prepends a little section squiggle ‘§` to the title so sections are easier to pick out visually.
-
Adds ‘type: :section` metadata.
121 122 123 124 125 126 127 128 129 |
# File 'lib/nrser/rspex/example_group.rb', line 121 def describe_section title, **, &block describe( "#{ NRSER::RSpex::PREFIXES[:section] } #{ title }", type: :section, ** ) do module_exec &block end end |
#describe_sent_to(receiver, publicly: true, &block) ⇒ Object Also known as: sent_to, when_sent_to
For use when ‘subject` is a Message. Create a new context for the `receiver` where the subject is the result of sending that message to the receiver.
69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/nrser/rspex/example_group.rb', line 69 def describe_sent_to receiver, publicly: true, &block mode = if publicly "publicly" else "privately" end describe "sent to #{ receiver } (#{ mode })" do subject { super().send_to unwrap( receiver, context: self ) } module_exec &block end end |
#describe_setup(*description, **metadata, &body) ⇒ void Also known as: setup
This method returns an undefined value.
Setup describes what’s going to be done in all child examples.
It’s where you setup your ‘subject`, usually depending on `let` bindings that are provided in the children.
12 13 14 15 16 17 18 |
# File 'lib/nrser/rspex/example_group/describe_setup.rb', line 12 def describe_setup *description, **, &body describe_x \ *description, type: :setup, metadata: , &body end |
#describe_spec_file(description: nil, spec_path:, bind_subject: true, **metadata, &body) ⇒ nil
This is totally just a one-off right now… would need to be generalized quite a bit…
-
Extraction of module, class, etc from metadata should be flexible
-
Built description would need to be conditional on what metadata was found.
EXPERIMENTAL
Example group helper for use at the top level of each spec file to set a bunch of stuff up and build a helpful description.
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/nrser/rspex/example_group/describe_spec_file.rb', line 29 def describe_spec_file description: nil, spec_path:, bind_subject: true, **, &body if [:module] && [:method] meth = [:module].method [:method] file, line = meth.source_location path = Pathname.new file loc = "./#{ path.relative_path_from Pathname.getwd }:#{ line }" spec_rel_path = \ "./#{ Pathname.new( spec_path ).relative_path_from Pathname.getwd }" desc = [ "#{ [:module].name }.#{ [:method] }", "(#{ loc })", description, "Spec (#{ spec_rel_path})" ].compact.join " " subj = meth elsif [:class] klass = [:class] if [:instance_method] instance_method = klass.instance_method [:instance_method] file, line = instance_method.source_location name = "#{ klass.name }##{ [:instance_method] }" else name = klass.name # Get a reasonable file and line for the class file, line = klass. # Get an array of all instance methods, excluding inherited ones # (the `false` arg) instance_methods( false ). # Add `#initialize` since it isn't in `#instance_methods` for some # reason <<( :initialize ). # Map those to their {UnboundMethod} objects map { |sym| klass.instance_method sym }. # Toss any `nil` values compact. # Get the source locations map( &:source_location ). # Get the first line in the shortest path min_by { |(path, line)| [path.length, line] } # Another approach I thought of... (untested) # # Get the path # # Get frequency of the paths # count_by { |(path, line)| path }. # # Get the one with the most occurrences # max_by { |path, count| count }. # # Get just the path (not the count) # first end location = if file "(#{ NRSER::RSpex.dot_rel_path file }:#{ line })" end desc = [ "𝑆𝑃𝐸𝐶 𝐹𝐼𝐿𝐸 `#{ NRSER::RSpex.dot_rel_path spec_path }` 𝐹𝑂𝑅", name, location, description, ].compact.join " " subj = klass else # TODO Make this work! raise ArgumentError.new binding.erb <<-END Not yet able to handle metadata: <%= metadata.pretty_inspect %> END end describe desc, ** do if bind_subject subject { subj } end module_exec &body end nil end |
#describe_use_case(*description, where: {}, **metadata, &body) ⇒ void
Document describe_use_case method.
This method returns an undefined value.
9 10 11 12 13 14 15 16 |
# File 'lib/nrser/rspex/example_group/describe_use_case.rb', line 9 def describe_use_case *description, where: {}, **, &body describe_x \ *description, type: :use_case, bindings: where, metadata: , &body end |
#describe_when(*description, **bindings, &body) ⇒ Object
Define a example group block with ‘let` bindings and evaluate the `body` block in it.
17 18 19 20 21 22 23 |
# File 'lib/nrser/rspex/example_group/describe_when.rb', line 17 def describe_when *description, **bindings, &body describe_x \ *description, type: :when, bindings: bindings, &body end |
#describe_x(*description, type:, metadata: {}, bindings: {}, add_binding_desc: true, subject_block: nil, &body) ⇒ return_type Also known as: describe_x_type
The core, mostly internal method that all RSpex’s description methods lead back too (or should / will when refactoring is done).
Keyword options are explicitly broken out in this method, versus the sugary ones that call it, so ‘metadata` can be set without restriction (save the `type` key, which is also it’s own keyword here). You can use this method if you want the RSpex functionality but absolutely have to set some metadata key that we use for something else.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/nrser/rspex/example_group/describe_x.rb', line 40 def describe_x *description, type:, metadata: {}, bindings: {}, add_binding_desc: true, subject_block: nil, &body # Check that `metadata` doesn't have a `:type` value too... although we # allow it if's equal to `type` or `nil` 'cause why not I guess? # if .key?( :type ) && [:type] != nil && [:type] != type raise ArgumentError.new binding.erb <<-END `metadata:` keyword argument may not have a `:type` key that conflicts with the `type:` keyword argument. Received: `type`: <%= type.inspect %> `metadata[:type]`: <%= metadata[:type].pretty_inspect %> END end unless bindings.empty? || add_binding_desc == false # bindings_desc = NRSER::RSpex::Opts[bindings].to_desc bindings_desc = ["(", bindings.ai( multiline: false ), ")"] if description.empty? description = bindings.ai( multiline: false ) else description += ["(", bindings.ai( multiline: false ), ")"] end end formatted = NRSER::RSpex::Format.description *description, type: type describe formatted, **, type: type do subject( &subject_block ) if subject_block unless bindings.empty? bindings.each { |name, value| let( name ) { unwrap value, context: self } } end module_exec &body end # description, end |
#described_class ⇒ Object
183 184 185 |
# File 'lib/nrser/rspex/example_group.rb', line 183 def described_class [:class] || super() end |