nrser 0.2.2 → 0.3.0

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.
Files changed (188) hide show
  1. checksums.yaml +4 -4
  2. data/lib/nrser/char/alpha_numeric_sub.rb +1 -2
  3. data/lib/nrser/char.rb +0 -6
  4. data/lib/nrser/core_ext/array.rb +120 -0
  5. data/lib/nrser/core_ext/binding.rb +44 -0
  6. data/lib/nrser/{functions → core_ext}/enumerable/find_map.rb +18 -15
  7. data/lib/nrser/{ext → core_ext}/enumerable.rb +10 -24
  8. data/lib/nrser/core_ext/exception.rb +30 -0
  9. data/lib/nrser/core_ext/hash/extract_values_at.rb +49 -0
  10. data/lib/nrser/core_ext/hash/transform_values_with_keys.rb +24 -0
  11. data/lib/nrser/core_ext/hash.rb +50 -0
  12. data/lib/nrser/core_ext/module/method_objects.rb +96 -0
  13. data/lib/nrser/core_ext/module/names.rb +69 -0
  14. data/lib/nrser/core_ext/module/source_locations.rb +214 -0
  15. data/lib/nrser/core_ext/module.rb +2 -0
  16. data/lib/nrser/core_ext/object/lazy_var.rb +31 -0
  17. data/lib/nrser/core_ext/object.rb +46 -0
  18. data/lib/nrser/core_ext/open_struct.rb +6 -0
  19. data/lib/nrser/{ext → core_ext}/pathname.rb +8 -5
  20. data/lib/nrser/{ext → core_ext}/string.rb +6 -12
  21. data/lib/nrser/core_ext/symbol.rb +13 -0
  22. data/lib/nrser/core_ext/time.rb +46 -0
  23. data/lib/nrser/core_ext.rb +13 -0
  24. data/lib/nrser/errors/abstract_method_error.rb +150 -0
  25. data/lib/nrser/errors/argument_error.rb +42 -0
  26. data/lib/nrser/errors/nicer_error.rb +298 -72
  27. data/lib/nrser/errors/type_error.rb +46 -0
  28. data/lib/nrser/errors.rb +4 -53
  29. data/lib/nrser/ext/tree.rb +3 -0
  30. data/lib/nrser/functions/enumerable/associate.rb +6 -9
  31. data/lib/nrser/functions/enumerable/include_slice.rb +2 -3
  32. data/lib/nrser/functions/enumerable.rb +1 -3
  33. data/lib/nrser/functions/exception.rb +1 -1
  34. data/lib/nrser/functions/hash.rb +0 -6
  35. data/lib/nrser/functions/merge_by.rb +2 -2
  36. data/lib/nrser/functions/module/method_objects.rb +77 -0
  37. data/lib/nrser/functions/module.rb +1 -2
  38. data/lib/nrser/functions/open_struct.rb +25 -35
  39. data/lib/nrser/functions/proc.rb +1 -6
  40. data/lib/nrser/functions/string/looks_like.rb +32 -1
  41. data/lib/nrser/functions/string.rb +1 -40
  42. data/lib/nrser/functions/text/lines.rb +2 -1
  43. data/lib/nrser/functions.rb +0 -1
  44. data/lib/nrser/graph/tsorter.rb +41 -0
  45. data/lib/nrser/labs/core_ext/binding.rb +37 -0
  46. data/lib/nrser/labs/stash.rb +372 -0
  47. data/lib/nrser/{logging → log}/appender/sync.rb +3 -3
  48. data/lib/nrser/log/appender.rb +3 -0
  49. data/lib/nrser/{logging → log}/formatters/color.rb +47 -20
  50. data/lib/nrser/log/formatters/mixin.rb +270 -0
  51. data/lib/nrser/{logging → log}/formatters.rb +0 -0
  52. data/lib/nrser/log/logger.rb +229 -0
  53. data/lib/nrser/log/mixin.rb +56 -0
  54. data/lib/nrser/log.rb +723 -0
  55. data/lib/nrser/message.rb +24 -3
  56. data/lib/nrser/meta/source/location.rb +158 -0
  57. data/lib/nrser/meta.rb +1 -1
  58. data/lib/nrser/props/class_methods.rb +118 -0
  59. data/lib/nrser/props/immutable/hash.rb +111 -0
  60. data/lib/nrser/props/immutable/hash_variable.rb +82 -0
  61. data/lib/nrser/props/immutable/instance_variables.rb +48 -0
  62. data/lib/nrser/props/immutable/vector.rb +107 -0
  63. data/lib/nrser/props/instance_methods.rb +184 -0
  64. data/lib/nrser/props/metadata.rb +359 -0
  65. data/lib/nrser/props/mutable/instance_variables.rb +60 -0
  66. data/lib/nrser/props/mutable/stash.rb +199 -0
  67. data/lib/nrser/{meta/props → props}/prop.rb +217 -112
  68. data/lib/nrser/props/storage/instance_variable.rb +85 -0
  69. data/lib/nrser/props/storage/instance_variables.rb +67 -0
  70. data/lib/nrser/props/storage/key.rb +88 -0
  71. data/lib/nrser/props.rb +9 -0
  72. data/lib/nrser/refinements/sugar.rb +41 -0
  73. data/lib/nrser/refinements/types.rb +2 -2
  74. data/lib/nrser/refinements.rb +14 -16
  75. data/lib/nrser/rspex/example_group/describe_attribute.rb +24 -0
  76. data/lib/nrser/rspex/example_group/describe_called_with.rb +1 -6
  77. data/lib/nrser/rspex/example_group/{describe_use_case.rb → describe_case.rb} +6 -3
  78. data/lib/nrser/rspex/example_group/describe_class.rb +1 -0
  79. data/lib/nrser/rspex/example_group/describe_group.rb +29 -0
  80. data/lib/nrser/rspex/example_group/describe_instance_method.rb +2 -2
  81. data/lib/nrser/rspex/example_group/describe_message.rb +35 -0
  82. data/lib/nrser/rspex/example_group/describe_method.rb +23 -2
  83. data/lib/nrser/rspex/example_group/describe_module.rb +19 -0
  84. data/lib/nrser/rspex/example_group/describe_response_to.rb +32 -0
  85. data/lib/nrser/rspex/example_group/describe_section.rb +38 -0
  86. data/lib/nrser/rspex/example_group/describe_sent_to.rb +52 -0
  87. data/lib/nrser/rspex/example_group/describe_source_file.rb +49 -0
  88. data/lib/nrser/rspex/example_group/describe_spec_file.rb +41 -108
  89. data/lib/nrser/rspex/example_group/describe_when.rb +14 -7
  90. data/lib/nrser/rspex/example_group/describe_x.rb +39 -12
  91. data/lib/nrser/rspex/example_group/overrides.rb +66 -0
  92. data/lib/nrser/rspex/example_group.rb +20 -252
  93. data/lib/nrser/rspex/format.rb +83 -17
  94. data/lib/nrser/rspex.rb +4 -34
  95. data/lib/nrser/sugar/method_missing_forwarder.rb +50 -0
  96. data/lib/nrser/{env → sys/env}/path.rb +1 -2
  97. data/lib/nrser/{env.rb → sys/env.rb} +2 -1
  98. data/lib/nrser/sys.rb +5 -0
  99. data/lib/nrser/types/any.rb +36 -7
  100. data/lib/nrser/types/{array.rb → arrays.rb} +32 -81
  101. data/lib/nrser/types/attrs.rb +68 -15
  102. data/lib/nrser/types/booleans.rb +95 -34
  103. data/lib/nrser/types/bounded.rb +12 -10
  104. data/lib/nrser/types/combinators.rb +74 -37
  105. data/lib/nrser/types/errors/check_error.rb +86 -0
  106. data/lib/nrser/types/errors/from_string_error.rb +82 -0
  107. data/lib/nrser/types/factory.rb +91 -0
  108. data/lib/nrser/types/hashes.rb +171 -26
  109. data/lib/nrser/types/in.rb +25 -12
  110. data/lib/nrser/types/is.rb +50 -18
  111. data/lib/nrser/types/is_a.rb +52 -33
  112. data/lib/nrser/types/labels.rb +6 -33
  113. data/lib/nrser/types/maybe.rb +12 -4
  114. data/lib/nrser/types/nil.rb +24 -4
  115. data/lib/nrser/types/not.rb +6 -16
  116. data/lib/nrser/types/numbers.rb +94 -57
  117. data/lib/nrser/types/pairs.rb +57 -57
  118. data/lib/nrser/types/paths.rb +112 -133
  119. data/lib/nrser/types/responds.rb +64 -74
  120. data/lib/nrser/types/shape.rb +29 -24
  121. data/lib/nrser/types/strings.rb +25 -17
  122. data/lib/nrser/types/symbols.rb +19 -17
  123. data/lib/nrser/types/trees.rb +18 -70
  124. data/lib/nrser/types/tuples.rb +36 -40
  125. data/lib/nrser/types/type.rb +342 -91
  126. data/lib/nrser/types/when.rb +40 -18
  127. data/lib/nrser/types/where.rb +94 -9
  128. data/lib/nrser/types.rb +72 -63
  129. data/lib/nrser/version.rb +1 -1
  130. data/lib/nrser.rb +18 -18
  131. data/spec/lib/nrser/{functions/binding/template_spec.rb → core_ext/binding/erb_spec.rb} +5 -5
  132. data/spec/lib/nrser/{functions → core_ext}/enumerable/find_map_spec.rb +8 -6
  133. data/spec/lib/nrser/{refinements → core_ext}/hash_spec.rb +9 -22
  134. data/spec/lib/nrser/errors/abstract_method_error_spec.rb +12 -5
  135. data/spec/lib/nrser/functions/enumerable/{to_h_by_spec.rb → associate_spec.rb} +1 -1
  136. data/spec/lib/nrser/functions/merge_by_spec.rb +1 -1
  137. data/spec/lib/nrser/functions/tree/each_branch_spec.rb +3 -3
  138. data/spec/lib/nrser/functions/tree/transform_spec.rb +14 -15
  139. data/spec/lib/nrser/gem_ext/hamster/json_spec.rb +4 -0
  140. data/spec/lib/nrser/meta/source/location_spec.rb +86 -0
  141. data/spec/lib/nrser/props/immutable/hash_spec.rb +297 -0
  142. data/spec/lib/nrser/props/immutable/vector_spec.rb +296 -0
  143. data/spec/lib/nrser/{meta/props_spec.rb → props/original_props_spec.rb} +11 -16
  144. data/spec/lib/nrser/{meta/props → props}/to_and_from_data_spec.rb +10 -8
  145. data/spec/lib/nrser/refinements/array_spec.rb +2 -15
  146. data/spec/lib/nrser/refinements/erb_spec.rb +5 -7
  147. data/spec/lib/nrser/refinements/set_spec.rb +2 -15
  148. data/spec/lib/nrser/{env → sys/env}/path/insert_spec.rb +4 -2
  149. data/spec/lib/nrser/{env → sys/env}/path_spec.rb +4 -2
  150. data/spec/lib/nrser/types/array_spec.rb +8 -8
  151. data/spec/lib/nrser/types/paths_spec.rb +15 -18
  152. data/spec/spec_helper.rb +4 -0
  153. metadata +109 -69
  154. data/lib/nrser/ext/binding.rb +0 -36
  155. data/lib/nrser/ext/module.rb +0 -62
  156. data/lib/nrser/ext.rb +0 -8
  157. data/lib/nrser/functions/binding.rb +0 -76
  158. data/lib/nrser/functions/enumerable/map_keys.rb +0 -0
  159. data/lib/nrser/functions/enumerable/map_values.rb +0 -94
  160. data/lib/nrser/functions/hash/deep_merge.rb +0 -57
  161. data/lib/nrser/functions/hash/except_keys.rb +0 -44
  162. data/lib/nrser/functions/hash/slice_keys.rb +0 -43
  163. data/lib/nrser/functions/hash/stringify_keys.rb +0 -55
  164. data/lib/nrser/functions/hash/symbolize_keys.rb +0 -57
  165. data/lib/nrser/functions/hash/transform_keys.rb +0 -140
  166. data/lib/nrser/functions/module/methods.rb +0 -206
  167. data/lib/nrser/functions/module/source_locations.rb +0 -213
  168. data/lib/nrser/logging/appender.rb +0 -3
  169. data/lib/nrser/logging.rb +0 -353
  170. data/lib/nrser/meta/props/base.rb +0 -31
  171. data/lib/nrser/meta/props.rb +0 -357
  172. data/lib/nrser/refinements/array.rb +0 -133
  173. data/lib/nrser/refinements/binding.rb +0 -6
  174. data/lib/nrser/refinements/enumerator.rb +0 -5
  175. data/lib/nrser/refinements/exception.rb +0 -35
  176. data/lib/nrser/refinements/hash.rb +0 -150
  177. data/lib/nrser/refinements/module.rb +0 -5
  178. data/lib/nrser/refinements/object.rb +0 -42
  179. data/lib/nrser/refinements/open_struct.rb +0 -28
  180. data/lib/nrser/refinements/pathname.rb +0 -5
  181. data/lib/nrser/refinements/set.rb +0 -5
  182. data/lib/nrser/refinements/string.rb +0 -5
  183. data/lib/nrser/refinements/symbol.rb +0 -20
  184. data/lib/nrser/rspex/described.rb +0 -99
  185. data/spec/design/mapping_spec.rb +0 -42
  186. data/spec/lib/nrser/functions/hash_spec.rb +0 -41
  187. data/spec/lib/nrser/functions/string/truncate_spec.rb +0 -11
  188. data/spec/lib/nrser/refinements/truncate_spec.rb +0 -10
@@ -0,0 +1,49 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ module NRSER::RSpex::ExampleGroup
5
+
6
+ # Create an example group covering a source file.
7
+ #
8
+ # Useful for when method implementations are spread out across multiple
9
+ # files but you want to group examples by the source file they're in.
10
+ #
11
+ # @note
12
+ # Honestly, now that modules, classes and methods described through RSpex
13
+ # add their source locations, this is not all that useful. But it was
14
+ # there from before that, which is why for the moment it's still here.
15
+ #
16
+ # @see #describe_x
17
+ #
18
+ # @param [String | Pathname] path
19
+ # File path.
20
+ #
21
+ # @param *description (see #describe_x)
22
+ #
23
+ # @param [Hash<Symbol, Object>] **metadata
24
+ # RSpec metadata to set for the example group.
25
+ #
26
+ # See the `metadata` keyword argument to {#describe_x}.
27
+ #
28
+ # A `file` key is added pointed to the {Pathname} for `path` before
29
+ # passing up to {#describe_x}.
30
+ #
31
+ # @param &body (see #describe_x)
32
+ #
33
+ # @return (see #describe_x)
34
+ #
35
+ def describe_source_file path, *description, **metadata, &body
36
+ path = path.to_pn
37
+
38
+ describe_x \
39
+ path,
40
+ *description,
41
+ type: :source_file,
42
+ metadata: {
43
+ source_file: path,
44
+ **metadata,
45
+ },
46
+ &body
47
+ end
48
+
49
+ end # module NRSER::RSpex::ExampleGroup
@@ -4,6 +4,26 @@ using NRSER
4
4
 
5
5
  module NRSER::RSpex::ExampleGroup
6
6
 
7
+ def dive_x current, *rest, **kwds, &body
8
+ type, data = current
9
+
10
+ method_name = "describe_#{ type }"
11
+
12
+ block = if rest.empty?
13
+ body
14
+ else
15
+ -> { dive_x *rest, &body }
16
+ end
17
+
18
+ begin
19
+ public_send method_name, data, **kwds, &block
20
+ rescue NoMethodError => error
21
+ pp self.methods
22
+ raise error
23
+ end
24
+ end
25
+
26
+
7
27
  # **EXPERIMENTAL**
8
28
  #
9
29
  # Example group helper for use at the top level of each spec file to
@@ -26,7 +46,7 @@ module NRSER::RSpex::ExampleGroup
26
46
  #
27
47
  # Probably possible to extract this somehow without having to provide it?
28
48
  #
29
- # @return [nil]
49
+ # @return (see #describe_x)
30
50
  #
31
51
  def describe_spec_file description: nil,
32
52
  spec_path:,
@@ -34,118 +54,31 @@ module NRSER::RSpex::ExampleGroup
34
54
  **metadata,
35
55
  &body
36
56
 
37
- if metadata[:module] && metadata[:method]
38
- meth = metadata[:module].method metadata[:method]
39
- file, line = meth.source_location
40
- path = Pathname.new file
41
- loc = "./#{ path.relative_path_from Pathname.getwd }:#{ line }"
42
-
43
- spec_rel_path = \
44
- "./#{ Pathname.new( spec_path ).relative_path_from Pathname.getwd }"
45
-
46
- desc = [
47
- "#{ metadata[:module].name }.#{ metadata[:method] }",
48
- "(#{ loc })",
49
- description,
50
- "Spec (#{ spec_rel_path})"
51
- ].compact.join " "
52
-
53
- subj = meth
57
+ chain = []
54
58
 
55
- elsif metadata[:class]
56
- klass = metadata[:class]
57
-
58
- if metadata[:instance_method]
59
- instance_method = klass.instance_method metadata[:instance_method]
60
-
61
- file, line = instance_method.source_location
62
-
63
- name = "#{ klass.name }##{ metadata[:instance_method] }"
64
-
65
- elsif metadata[:method]
66
- # Class method
67
- meth = metadata[:class].method metadata[:method]
68
- file, line = meth.source_location
69
- path = Pathname.new file
70
- loc = "./#{ path.relative_path_from Pathname.getwd }:#{ line }"
71
-
72
- spec_rel_path = \
73
- "./#{ Pathname.new( spec_path ).relative_path_from Pathname.getwd }"
74
-
75
- desc = [
76
- "#{ metadata[:class].name }.#{ metadata[:method] }",
77
- "(#{ loc })",
78
- description,
79
- "Spec (#{ spec_rel_path})"
80
- ].compact.join " "
81
-
82
- subj = meth
83
-
84
- else
85
- name = klass.name
86
-
87
- # Get a reasonable file and line for the class
88
- file, line = klass.
89
- # Get an array of all instance methods, excluding inherited ones
90
- # (the `false` arg)
91
- instance_methods( false ).
92
- # Add `#initialize` since it isn't in `#instance_methods` for some
93
- # reason
94
- <<( :initialize ).
95
- # Map those to their {UnboundMethod} objects
96
- map { |sym| klass.instance_method sym }.
97
- # Toss any `nil` values
98
- compact.
99
- # Get the source locations
100
- map( &:source_location ).
101
- # Get rid of `[nil, nil]` results, which seems to come from C exts
102
- reject { |(path, line)| path.nil? || line.nil? }.
103
- # Get the first line in the shortest path
104
- min_by { |(path, line)| [path.length, line] }
105
-
106
- # Another approach I thought of... (untested)
107
- #
108
- # Get the path
109
- # # Get frequency of the paths
110
- # count_by { |(path, line)| path }.
111
- # # Get the one with the most occurrences
112
- # max_by { |path, count| count }.
113
- # # Get just the path (not the count)
114
- # first
115
- end
116
-
117
- location = if file
118
- "(#{ NRSER::RSpex.dot_rel_path file }:#{ line })"
59
+ [
60
+ :source_file,
61
+ :module,
62
+ :class,
63
+ :instance,
64
+ :method,
65
+ :instance_method,
66
+ :called_with,
67
+ :attribute,
68
+ ].each do |type|
69
+ if data = metadata.delete( type )
70
+ chain << [type, data]
119
71
  end
120
-
121
- desc = [
122
- "𝑆𝑃𝐸𝐶 𝐹𝐼𝐿𝐸 `#{ NRSER::RSpex.dot_rel_path spec_path }` 𝐹𝑂𝑅",
123
- name,
124
- location,
125
- description,
126
- ].compact.join " "
127
-
128
- subj = klass
129
-
130
- else
131
- # TODO Make this work!
132
- raise ArgumentError.new binding.erb <<-END
133
- Not yet able to handle metadata:
134
-
135
- <%= metadata.pretty_inspect %>
136
-
137
- END
138
72
  end
139
73
 
140
- describe desc, **metadata do
141
- if bind_subject
142
- subject { subj }
143
- end
144
-
145
- module_exec &body
74
+ describe_x(
75
+ NRSER::RSpex.dot_rel_path( spec_path ),
76
+ *description,
77
+ type: :spec_file,
78
+ metadata: metadata,
79
+ ) do
80
+ dive_x *chain, bind_subject: bind_subject, &body
146
81
  end
147
-
148
- nil
149
82
  end # #describe_spec_file
150
83
 
151
84
  end # module NRSER::RSpex::ExampleGroup
@@ -1,18 +1,20 @@
1
+ # encoding: UTF-8
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module NRSER::RSpex::ExampleGroup
4
5
 
5
- # Define a example group block with `let` bindings and evaluate the `body`
6
- # block in it.
6
+ # Define a example group with the keyword args as bindings.
7
+ #
8
+ # @see #describe_x
9
+ #
10
+ # @param *description (see #describe_x)
7
11
  #
8
12
  # @param [Hash<Symbol, Object>] **bindings
9
- # Map of symbol names to value to bind using `let`.
13
+ # See the `bindings` keyword arg in {#describe_x}.
10
14
  #
11
- # @param [#call] &body
12
- # Body block to evaluate in the context.
15
+ # @param &body (see #describe_x)
13
16
  #
14
- # @return
15
- # Whatever `context` returns.
17
+ # @return (see #describe_x)
16
18
  #
17
19
  def describe_when *description, **bindings, &body
18
20
  describe_x \
@@ -22,4 +24,9 @@ module NRSER::RSpex::ExampleGroup
22
24
  &body
23
25
  end
24
26
 
27
+ # Old name (used to be different method)
28
+
29
+ alias_method :context_where, :describe_when
30
+
31
+
25
32
  end # module NRSER::RSpex::ExampleGroup
@@ -23,25 +23,38 @@ module NRSER::RSpex::ExampleGroup
23
23
  # key.
24
24
  #
25
25
  # @param [Hash<Symbol, Object>] metadata:
26
- # Metadata to add to the new example group.
26
+ # [RSpec metadata][] to add to the new example group.
27
27
  #
28
28
  # In addition to the keys RSpec will reject, we prohibit `:type` *unless*
29
29
  # it is the same as the `type` keyword argument or `nil`.
30
30
  #
31
31
  # In either of these cases, the `type` keyword arg will be used for the new
32
32
  # example group's `:type` metadata value.
33
+ #
34
+ # [RSpec metadata]: https://relishapp.com/rspec/rspec-core/docs/metadata/user-defined-metadata
33
35
  #
34
36
  # @param [Hash<Symbol, Object>] bindings:
37
+ # Name to value pairs to bind in the new example group.
35
38
  #
39
+ # All values will be bound at the example group and example levels -
40
+ # though if they are {Wrapper}, that wrapper will be available at the
41
+ # group level, while they will be automatically unwrapped at the
42
+ # example level (as the requisite context is available there).
43
+ #
44
+ # @param [Boolean] bind_subject:
45
+ # When `true` (and there is a `subject_block`) bind the `subject` inside
46
+ # the new example group.
47
+ #
48
+ #
36
49
  #
37
- # @return [return_type]
38
- # @todo Document return value.
50
+ # @return [void]
39
51
  #
40
52
  def describe_x *description,
41
53
  type:,
42
54
  metadata: {},
43
55
  bindings: {},
44
56
  add_binding_desc: true,
57
+ bind_subject: true,
45
58
  subject_block: nil,
46
59
  &body
47
60
 
@@ -67,30 +80,44 @@ module NRSER::RSpex::ExampleGroup
67
80
  END
68
81
  end
69
82
 
83
+ # Add description of the bindings, if we have any and were told to
70
84
  unless bindings.empty? || add_binding_desc == false
71
- # bindings_desc = NRSER::RSpex::Opts[bindings].to_desc
72
- bindings_desc = ["(", bindings.ai( multiline: false ), ")"]
85
+ bindings_desc = NRSER::RSpex::Format.md_code_quote \
86
+ bindings.map { |name, value|
87
+ "#{ name } = #{ value.inspect }"
88
+ }.join( '; ' )
73
89
 
74
90
  if description.empty?
75
- description = bindings.ai( multiline: false )
91
+ description = bindings_desc
76
92
  else
77
- description += ["(", bindings.ai( multiline: false ), ")"]
93
+ description << "(" + bindings_desc + ")"
78
94
  end
79
95
  end
80
96
 
81
- formatted = NRSER::RSpex::Format.description *description, type: type
82
-
83
- describe formatted, **metadata, type: type do
84
- subject( &subject_block ) if subject_block
97
+ # Call up to RSpec's `#describe` method
98
+ describe(
99
+ NRSER::RSpex::Format.description( *description, type: type ),
100
+ **metadata,
101
+ type: type,
102
+ ) do
103
+ if subject_block && bind_subject
104
+ subject &subject_block
105
+ end
85
106
 
107
+ # Bind bindings
86
108
  unless bindings.empty?
87
109
  bindings.each { |name, value|
110
+ # Example-level binding
88
111
  let( name ) { unwrap value, context: self }
112
+
113
+ # Example group-level binding (which may return a {Wrapper} that
114
+ # of course can not be unwrapped at the group level)
115
+ define_singleton_method( name ) { value }
89
116
  }
90
117
  end
91
118
 
92
119
  module_exec &body
93
- end # description,
120
+ end # describe
94
121
 
95
122
  end # #describe_x
96
123
 
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+
5
+ # Definitions
6
+ # =======================================================================
7
+
8
+ module NRSER::RSpex::ExampleGroup
9
+
10
+ # HACK HACK HACK-ITY HACK - Allow for overriding RSpec methods
11
+ #
12
+ # Yeah, it has to do with mixin mixing-in ordering - seems to be that when
13
+ #
14
+ # config.extend NRSER::RSpex::ExampleGroup
15
+ #
16
+ # {NRSER::RSpex::ExampleGroup} gets mixed in *very early* in the chain,
17
+ # before {RSpec::Core::ExampleGroup}... why you would provide an explicit
18
+ # extension mechanism and not give those extensions priority I'm not sure,
19
+ # but I'm sure I shouldn't be looking into it right now, so here we are:
20
+ #
21
+ # It turns out that {NRSER::RSpex::Example}, which gets mixed with
22
+ #
23
+ # config.include NRSER::RSpex::Example
24
+ #
25
+ # gets mixed *last*, so by using it's {NRSER::RSpex::Example.included}
26
+ # hook we can use
27
+ #
28
+ # base#extend NRSER::RSpex::ExampleGroup::Overrides
29
+ #
30
+ # to mix these guys over the top of RSpec's methods.
31
+ #
32
+ # Seems like we could just mix all of {NRSER::RSpex::ExampleGroup} there
33
+ # to get the behavior I would have expected all along, but maybe it's better
34
+ # to have these explicit notes for the moment and not change much else until
35
+ # I get the chance to really check out what's going on.
36
+ #
37
+ # And really it's all to override `.described_class` to pick up our
38
+ # metadata if it's there, but that approach is in quite a bit of use at
39
+ # this point, and, no, I have no idea how it seemed to work up until this
40
+ # point :/
41
+ #
42
+ module Overrides
43
+
44
+ # Override {RSpec::Core::ExampleGroup.described_class} to use RSpex's
45
+ # `:class` metadata if it's present.
46
+ #
47
+ # Because I can't figure out how to feed RSpec the described class
48
+ # without it being the description, and we want better descriptions.
49
+ #
50
+ # Some hackery could def do it, this is RUBY after all, but whatever this
51
+ # works for now and may even be less fragile.
52
+ #
53
+ # @return [Class]
54
+ # If there's a `:class` in the metadata, or if RSpec has on through the
55
+ # standard means (`describe MyClass do ...`).
56
+ #
57
+ # @return [nil]
58
+ # If we don't have a class context around.
59
+ #
60
+ def described_class
61
+ metadata[:class] || super()
62
+ end
63
+
64
+ end # module Overrides
65
+
66
+ end # module NRSER:RSpex::ExampleGroup