nrser 0.0.29 → 0.0.30

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2273f6424356766a1849b35fc437b13942f15af1
4
- data.tar.gz: 901f479555218cc42909235832f2271ca8f61579
3
+ metadata.gz: e894a45a17099589d7b23f53b7b2c416d448b6d3
4
+ data.tar.gz: 9e66a57ccee2dba38b1bf16e45a55197fa80ccac
5
5
  SHA512:
6
- metadata.gz: 87482595ba0e8a8fec1b3e7c3b3c368432a5edbef62a2704d721e61199177446a6d0e28ca4c2f1119db5d7adb8da8666ded661f3c79f20f44dbccee48b756e80
7
- data.tar.gz: 412d7fdbe26337164955f5a52e6bc70370f2bd5c1282797e66c91b794fa2b8471e2dc9865e9210b822490799194a90102242466967e233a23630f773ac6cf33b
6
+ metadata.gz: 1132214b192658affc169b261f8d9840cbae0d2f3c33e2a7f48c64e2bfb6876411b50e5a3aa0b22a5245d82aa5dae5b48ef3c16fee9fa4b1ab295793b9ff7413
7
+ data.tar.gz: 1676e9d23b8182bc24447008410498aeace1b57a5c0400f02da39cb1e2e64cb2f24099253dc0ad3815c9fb00e9de24e899ee5a5c6389cffc219aa1e711211a6e
@@ -204,5 +204,85 @@ module NRSER
204
204
  end # #enumerate_as_values
205
205
 
206
206
 
207
+ # Count entries in an {Enumerable} by the value returned when they are
208
+ # passed to the block.
209
+ #
210
+ # @example Count array entries by class
211
+ #
212
+ # [1, 2, :three, 'four', 5, :six].count_by &:class
213
+ # # => {Fixnum=>3, Symbol=>2, String=>1}
214
+ #
215
+ # @param [Enumerable<E>] enum
216
+ # {Enumerable} (or other object with compatible `#each_with_object` and
217
+ # `#to_enum` methods) you want to count.
218
+ #
219
+ # @param [Proc<(E)=>C>] &block
220
+ # Block mapping entries in `enum` to the group to count them in.
221
+ #
222
+ # @return [Hash{C=>Integer}]
223
+ # Hash mapping groups to positive integer counts.
224
+ #
225
+ def count_by enum, &block
226
+ enum.each_with_object( Hash.new 0 ) do |entry, hash|
227
+ hash[block.call entry] += 1
228
+ end
229
+ end
230
+
231
+
232
+ # Like `Enumerable#find`, but wraps each call to `&block` in a
233
+ # `begin` / `rescue`, returning the result of the first call that doesn't
234
+ # raise an error.
235
+ #
236
+ # If no calls succeed, raises a {NRSER::MultipleErrors} containing the
237
+ # errors from the block calls.
238
+ #
239
+ # @param [Enumerable<E>] enum
240
+ # Values to call `&block` with.
241
+ #
242
+ # @param [Proc<E=>V>] &block
243
+ # Block to call, which is expected to raise an error if it fails.
244
+ #
245
+ # @return [V]
246
+ # Result of first call to `&block` that doesn't raise.
247
+ #
248
+ # @raise [ArgumentError]
249
+ # If `enum` was empty (`enum#each` never yielded).
250
+ #
251
+ # @raise [NRSER::MultipleErrors]
252
+ # If all calls to `&block` failed.
253
+ #
254
+ def try_find enum, &block
255
+ errors = []
256
+
257
+ enum.each do |*args|
258
+ begin
259
+ result = block.call *args
260
+ rescue Exception => error
261
+ errors << error
262
+ else
263
+ return result
264
+ end
265
+ end
266
+
267
+ if errors.empty?
268
+ raise ArgumentError,
269
+ "Appears that enumerable was empty: #{ enum.inspect }"
270
+ else
271
+ raise NRSER::MultipleErrors.new errors
272
+ end
273
+ end
274
+
275
+
276
+ # TODO It would be nice for this to work...
277
+ #
278
+ # def to_enum object, meth, *args
279
+ # unless object.respond_to?( meth )
280
+ # object = NRSER::Enumerable.new object
281
+ # end
282
+ #
283
+ # object.to_enum meth, *args
284
+ # end
285
+
286
+
207
287
  end # class << self (Eigenclass)
208
288
  end # module NRSER
@@ -55,5 +55,52 @@ module NRSER
55
55
  end # #initialize
56
56
 
57
57
  end # class AbstractMethodError
58
+
59
+
60
+ # A wrapper error around a list of other errors.
61
+ #
62
+ class MultipleErrors < StandardError
63
+
64
+ # Attributes
65
+ # ======================================================================
66
+
67
+ # The individual errors that occurred.
68
+ #
69
+ # @return [Array<Exception>]
70
+ #
71
+ attr_reader :errors
72
+
73
+
74
+ # Constructor
75
+ # ======================================================================
76
+
77
+ # Instantiate a new `MultipleErrors`.
78
+ def initialize errors, headline: nil
79
+ @errors = errors
80
+
81
+ if headline.nil?
82
+ class_counts = NRSER.count_by( errors, &:class ).
83
+ map { |klass, count| "#{ klass } (#{ count })" }.
84
+ join( ', ' )
85
+
86
+ headline = "#{ errors.count } error(s) occurred - #{ class_counts }"
87
+ end
88
+
89
+ message = NRSER.erb binding, <<-END
90
+ <%= headline %>
91
+
92
+ <% errors.each_with_index do |error, index| %>
93
+ <%= (index.succ.to_s + ".").ljust( 3 ) %> <%= error.message %> (<%= error.class %>):
94
+ <%= error.backtrace.join( $/ ) %>
95
+ <% end %>
96
+
97
+ END
98
+
99
+ super message
100
+ end # #initialize
101
+
102
+
103
+ end # class MultipleErrors
104
+
58
105
 
59
106
  end # module NRSER
@@ -32,20 +32,34 @@ module NRSER::Refinements::Enumerable
32
32
  NRSER.to_h_by self, &block
33
33
  end
34
34
 
35
+
35
36
  # See {NRSER.enumerate_as_values}
36
37
  def enumerate_as_values
37
38
  NRSER.enumerate_as_values self
38
39
  end
39
40
 
41
+
40
42
  # Calls {NRSER.only} on `self`.
41
43
  def only **options
42
44
  NRSER.only self, **options
43
45
  end
44
46
 
47
+
45
48
  # See {NRSER.only!}
46
49
  def only!
47
50
  NRSER.only! self
48
51
  end
49
52
 
53
+
54
+ # See {NRSER.count_by}
55
+ def count_by &block
56
+ NRSER.count_by self, &block
57
+ end
58
+
59
+
60
+ # See {NRSER.try_find}
61
+ def try_find &block
62
+ NRSER.try_find self, &block
63
+ end
64
+
50
65
  end # module NRSER::Refinements::Enumerable
51
-
@@ -272,7 +272,58 @@ module NRSER::RSpex
272
272
  module_exec &body
273
273
  end # description,
274
274
 
275
- end # #describe_x
275
+ end # #describe_x_type
276
+
277
+
278
+ # **EXPERIMENTAL**
279
+ #
280
+ # Example group helper for use at the top level of each spec file to
281
+ # set a bunch of stuff up and build a helpful description.
282
+ #
283
+ # @todo
284
+ # This is totally just a one-off right now... would need to be
285
+ # generalized quite a bit...
286
+ #
287
+ # 1. Extraction of module, class, etc from metadata should be flexible
288
+ #
289
+ # 2. Built description would need to be conditional on what metadata
290
+ # was found.
291
+ #
292
+ # @param [String] description:
293
+ # A description of the spec file to add to the RSpec description.
294
+ #
295
+ # @param [String] spec_path:
296
+ # The path to the spec file (just feed it `__FILE__`).
297
+ #
298
+ # Probably possible to extract this somehow without having to provide it?
299
+ #
300
+ # @return [nil]
301
+ #
302
+ def describe_spec_file description:,
303
+ spec_path:,
304
+ bind_subject: true,
305
+ **metadata,
306
+ &body
307
+
308
+ meth = metadata[:module].method metadata[:method]
309
+ file, line = meth.source_location
310
+ path = Pathname.new file
311
+ loc = "./#{ path.relative_path_from Pathname.getwd }:#{ line }"
312
+
313
+ spec_rel_path = "./#{ Pathname.new( spec_path ).relative_path_from Pathname.getwd }"
314
+
315
+ desc = "#{ metadata[:module].name }.#{ metadata[:method] } (#{ loc }) #{ description } Spec (#{ spec_rel_path})"
316
+
317
+ describe desc, **metadata do
318
+ if bind_subject
319
+ subject { meth }
320
+ end
321
+
322
+ module_exec &body
323
+ end
324
+
325
+ nil
326
+ end # #describe_spec_file
276
327
 
277
328
 
278
329
  # @todo Document describe_instance method.
@@ -435,12 +486,17 @@ module NRSER::RSpex
435
486
  end
436
487
 
437
488
 
438
- def describe_module mod, **metadata, &block
489
+ def describe_module mod, bind_subject: true, **metadata, &block
439
490
  describe(
440
491
  "#{ NRSER::RSpex::PREFIXES[:module] } #{ mod.name }",
441
492
  type: :module,
493
+ module: mod,
442
494
  **metadata
443
495
  ) do
496
+ if bind_subject
497
+ subject { mod }
498
+ end
499
+
444
500
  module_exec &block
445
501
  end
446
502
  end # #describe_module
@@ -567,6 +623,8 @@ RSpec.configure do |config|
567
623
  config.add_setting :x_type_prefixes
568
624
  config.x_type_prefixes = \
569
625
  NRSER::RSpex::PREFIXES_BASE.merge( NRSER::RSpex::PREFIXES_MATH_ITALIC )
626
+
627
+ config.add_setting :x_type_prefixes
570
628
  end
571
629
 
572
630
  # Make available at the top-level
@@ -1,5 +1,5 @@
1
1
  module NRSER
2
- VERSION = "0.0.29"
2
+ VERSION = "0.0.30"
3
3
 
4
4
  module Version
5
5
 
@@ -0,0 +1,61 @@
1
+ describe_spec_file(
2
+ description: "Gotchas",
3
+ spec_path: __FILE__,
4
+ module: NRSER,
5
+ method: :dedent,
6
+ ) do
7
+
8
+ describe_section "Newline literals in HEREDOCs" do
9
+ # ========================================================================
10
+
11
+ subject do
12
+ super().call input
13
+ end
14
+
15
+ describe_group "when a HEREDOC has a with literal \\n" do
16
+ # ========================================================================
17
+
18
+ let :input do
19
+ <<-END
20
+ <%= headline %>
21
+
22
+ <% errors.each_with_index do |error, index| %>
23
+ <%= (index.succ.to_s + ".").ljust( 3 ) %> <%= error.message %> (<%= error.class %>):
24
+ <%= error.backtrace.join( "\n" ) %>
25
+ <% end %>
26
+
27
+ END
28
+ end
29
+
30
+ it "should NOT produce the desired dedent" do
31
+ expect( subject.lines.first ).not_to match /\A\S+/
32
+ end
33
+
34
+ end
35
+ # ************************************************************************
36
+
37
+
38
+ describe_group "when the HEREDOC uses $/ instead of \\n" do
39
+ let :input do
40
+ <<-END
41
+ <%= headline %>
42
+
43
+ <% errors.each_with_index do |error, index| %>
44
+ <%= (index.succ.to_s + ".").ljust( 3 ) %> <%= error.message %> (<%= error.class %>):
45
+ <%= error.backtrace.join( $/ ) %>
46
+ <% end %>
47
+
48
+ END
49
+ end
50
+
51
+ it "should produce the desired dedent" do
52
+ expect( subject.lines.first ).to match /\A\S+/
53
+ end
54
+
55
+ end # Group "when the HEREDOC uses $/ instead of \\n" Description
56
+
57
+ end # section Newline literals in HEREDOCs
58
+ # ************************************************************************
59
+
60
+ end # describe_spec_file
61
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nrser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.29
4
+ version: 0.0.30
5
5
  platform: ruby
6
6
  authors:
7
7
  - nrser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-21 00:00:00.000000000 Z
11
+ date: 2018-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -254,6 +254,7 @@ files:
254
254
  - spec/nrser/string/common_prefix_spec.rb
255
255
  - spec/nrser/string/looks_like_spec.rb
256
256
  - spec/nrser/template_spec.rb
257
+ - spec/nrser/text/dedent/gotchas_spec.rb
257
258
  - spec/nrser/text/dedent_spec.rb
258
259
  - spec/nrser/tree/each_branch_spec.rb
259
260
  - spec/nrser/tree/leaves_spec.rb
@@ -335,6 +336,7 @@ test_files:
335
336
  - spec/nrser/string/common_prefix_spec.rb
336
337
  - spec/nrser/string/looks_like_spec.rb
337
338
  - spec/nrser/template_spec.rb
339
+ - spec/nrser/text/dedent/gotchas_spec.rb
338
340
  - spec/nrser/text/dedent_spec.rb
339
341
  - spec/nrser/tree/each_branch_spec.rb
340
342
  - spec/nrser/tree/leaves_spec.rb