nrser 0.3.9 → 0.3.10

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 (141) hide show
  1. checksums.yaml +4 -4
  2. data/lib/nrser/char/alpha_numeric_sub.rb +9 -19
  3. data/lib/nrser/char/special.rb +5 -5
  4. data/lib/nrser/core_ext/array.rb +36 -13
  5. data/lib/nrser/core_ext/enumerable.rb +1 -0
  6. data/lib/nrser/core_ext/enumerable/find_map.rb +1 -1
  7. data/lib/nrser/core_ext/hash/bury.rb +3 -0
  8. data/lib/nrser/core_ext/hash/extract_values_at.rb +2 -2
  9. data/lib/nrser/core_ext/method/full_name.rb +1 -1
  10. data/lib/nrser/core_ext/module/method_objects.rb +1 -1
  11. data/lib/nrser/core_ext/module/source_locations.rb +27 -15
  12. data/lib/nrser/core_ext/object/lazy_var.rb +1 -1
  13. data/lib/nrser/core_ext/pathname.rb +67 -12
  14. data/lib/nrser/core_ext/pathname/subpath.rb +86 -0
  15. data/lib/nrser/core_ext/string.rb +28 -1
  16. data/lib/nrser/core_ext/symbol.rb +11 -12
  17. data/lib/nrser/errors/README.md +154 -0
  18. data/lib/nrser/errors/attr_error.rb +146 -53
  19. data/lib/nrser/errors/count_error.rb +61 -12
  20. data/lib/nrser/errors/nicer_error.rb +42 -71
  21. data/lib/nrser/errors/value_error.rb +53 -58
  22. data/lib/nrser/functions.rb +0 -2
  23. data/lib/nrser/functions/enumerable.rb +5 -17
  24. data/lib/nrser/functions/enumerable/associate.rb +14 -5
  25. data/lib/nrser/functions/enumerable/find_all_map.rb +1 -1
  26. data/lib/nrser/functions/enumerable/include_slice/array_include_slice.rb +1 -1
  27. data/lib/nrser/functions/hash/bury.rb +2 -12
  28. data/lib/nrser/functions/merge_by.rb +2 -2
  29. data/lib/nrser/functions/module/method_objects.rb +2 -2
  30. data/lib/nrser/functions/path.rb +185 -165
  31. data/lib/nrser/functions/path/normalized.rb +84 -0
  32. data/lib/nrser/functions/string.rb +4 -4
  33. data/lib/nrser/functions/text/README.md +4 -0
  34. data/lib/nrser/functions/text/format.rb +53 -0
  35. data/lib/nrser/functions/text/indentation.rb +6 -6
  36. data/lib/nrser/functions/text/word_wrap.rb +2 -2
  37. data/lib/nrser/functions/tree/map_leaves.rb +3 -3
  38. data/lib/nrser/functions/tree/map_tree.rb +2 -2
  39. data/lib/nrser/functions/tree/transform.rb +1 -18
  40. data/lib/nrser/gem_ext/README.md +4 -0
  41. data/lib/nrser/labs/README.md +8 -0
  42. data/lib/nrser/labs/config.rb +163 -0
  43. data/lib/nrser/labs/i8.rb +49 -159
  44. data/lib/nrser/labs/i8/struct.rb +167 -0
  45. data/lib/nrser/labs/i8/struct/hash.rb +140 -0
  46. data/lib/nrser/labs/i8/struct/vector.rb +149 -0
  47. data/lib/nrser/labs/i8/surjection.rb +211 -0
  48. data/lib/nrser/labs/lots/consumer.rb +19 -0
  49. data/lib/nrser/labs/lots/parser.rb +21 -1
  50. data/lib/nrser/labs/stash.rb +4 -4
  51. data/lib/nrser/log.rb +25 -21
  52. data/lib/nrser/log/appender/sync.rb +15 -11
  53. data/lib/nrser/log/formatters/color.rb +0 -3
  54. data/lib/nrser/log/formatters/mixin.rb +4 -4
  55. data/lib/nrser/log/logger.rb +54 -6
  56. data/lib/nrser/log/mixin.rb +2 -1
  57. data/lib/nrser/log/plugin.rb +6 -6
  58. data/lib/nrser/log/types.rb +46 -29
  59. data/lib/nrser/mean_streak.rb +0 -8
  60. data/lib/nrser/mean_streak/document.rb +1 -4
  61. data/lib/nrser/message.rb +3 -3
  62. data/lib/nrser/meta/README.md +4 -0
  63. data/lib/nrser/meta/lazy_attr.rb +2 -2
  64. data/lib/nrser/meta/source/location.rb +1 -1
  65. data/lib/nrser/props.rb +34 -3
  66. data/lib/nrser/props/class_methods.rb +2 -1
  67. data/lib/nrser/props/instance_methods.rb +9 -9
  68. data/lib/nrser/props/metadata.rb +4 -12
  69. data/lib/nrser/props/mutable/stash.rb +5 -2
  70. data/lib/nrser/props/prop.rb +10 -19
  71. data/lib/nrser/rspex.rb +1 -20
  72. data/lib/nrser/rspex/example_group/describe_attribute.rb +3 -0
  73. data/lib/nrser/rspex/example_group/describe_called_with.rb +9 -4
  74. data/lib/nrser/rspex/example_group/describe_case.rb +1 -0
  75. data/lib/nrser/rspex/example_group/describe_class.rb +2 -0
  76. data/lib/nrser/rspex/example_group/describe_group.rb +1 -1
  77. data/lib/nrser/rspex/example_group/describe_instance.rb +3 -1
  78. data/lib/nrser/rspex/example_group/describe_message.rb +1 -1
  79. data/lib/nrser/rspex/example_group/describe_method.rb +64 -30
  80. data/lib/nrser/rspex/example_group/describe_response_to.rb +1 -1
  81. data/lib/nrser/rspex/example_group/describe_section.rb +4 -1
  82. data/lib/nrser/rspex/example_group/describe_sent_to.rb +1 -1
  83. data/lib/nrser/rspex/example_group/describe_setup.rb +1 -0
  84. data/lib/nrser/rspex/example_group/describe_source_file.rb +1 -1
  85. data/lib/nrser/rspex/example_group/describe_spec_file.rb +4 -2
  86. data/lib/nrser/rspex/example_group/describe_when.rb +2 -1
  87. data/lib/nrser/rspex/example_group/describe_x.rb +5 -5
  88. data/lib/nrser/rspex/format.rb +0 -15
  89. data/lib/nrser/sugar/method_missing_forwarder.rb +3 -3
  90. data/lib/nrser/sys/env/path.rb +2 -28
  91. data/lib/nrser/types.rb +63 -12
  92. data/lib/nrser/types/README.md +76 -0
  93. data/lib/nrser/types/arrays.rb +192 -137
  94. data/lib/nrser/types/attributes.rb +269 -0
  95. data/lib/nrser/types/booleans.rb +134 -83
  96. data/lib/nrser/types/bounded.rb +110 -47
  97. data/lib/nrser/types/collections.rb +119 -0
  98. data/lib/nrser/types/combinators.rb +283 -196
  99. data/lib/nrser/types/doc/display_table.md +66 -0
  100. data/lib/nrser/types/eqiuvalent.rb +91 -0
  101. data/lib/nrser/types/errors/check_error.rb +5 -11
  102. data/lib/nrser/types/errors/from_string_error.rb +3 -3
  103. data/lib/nrser/types/factory.rb +287 -20
  104. data/lib/nrser/types/hashes.rb +227 -179
  105. data/lib/nrser/types/in.rb +73 -36
  106. data/lib/nrser/types/is.rb +67 -60
  107. data/lib/nrser/types/is_a.rb +141 -84
  108. data/lib/nrser/types/labels.rb +45 -16
  109. data/lib/nrser/types/maybe.rb +6 -3
  110. data/lib/nrser/types/nil.rb +64 -27
  111. data/lib/nrser/types/not.rb +92 -34
  112. data/lib/nrser/types/numbers.rb +224 -169
  113. data/lib/nrser/types/pairs.rb +113 -89
  114. data/lib/nrser/types/paths.rb +250 -137
  115. data/lib/nrser/types/responds.rb +167 -89
  116. data/lib/nrser/types/selector.rb +234 -0
  117. data/lib/nrser/types/shape.rb +136 -65
  118. data/lib/nrser/types/strings.rb +189 -63
  119. data/lib/nrser/types/symbols.rb +83 -33
  120. data/lib/nrser/types/top.rb +89 -0
  121. data/lib/nrser/types/tuples.rb +134 -98
  122. data/lib/nrser/types/type.rb +617 -505
  123. data/lib/nrser/types/when.rb +123 -98
  124. data/lib/nrser/types/where.rb +182 -91
  125. data/lib/nrser/version.rb +1 -1
  126. data/spec/lib/nrser/core_ext/pathname/subpath_spec.rb +22 -0
  127. data/spec/lib/nrser/errors/attr_error_spec.rb +68 -0
  128. data/spec/lib/nrser/errors/count_error_spec.rb +69 -0
  129. data/spec/lib/nrser/functions/path/normalize_path_spec.rb +35 -0
  130. data/spec/lib/nrser/functions/tree/map_tree_spec.rb +74 -96
  131. data/spec/lib/nrser/functions/tree/transform_spec.rb +11 -11
  132. data/spec/lib/nrser/labs/config_spec.rb +22 -0
  133. data/spec/lib/nrser/labs/i8/struct_spec.rb +39 -0
  134. data/spec/lib/nrser/types/display_spec.rb +50 -0
  135. data/spec/lib/nrser/types/paths_spec.rb +16 -10
  136. data/spec/lib/nrser/types/selector_spec.rb +125 -0
  137. data/spec/spec_helper.rb +4 -5
  138. metadata +105 -22
  139. data/lib/nrser/types/any.rb +0 -41
  140. data/lib/nrser/types/attrs.rb +0 -213
  141. data/lib/nrser/types/trees.rb +0 -42
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8924f7337f324ced68cc42837909ecd01e31cbed
4
- data.tar.gz: 9967780c03770b6f18214d6800107046db3ba3ae
3
+ metadata.gz: 2c105c78f752949b6b6f96460bb5369e3fa55097
4
+ data.tar.gz: a41c0ab138a2ce53510199cdc1fb48da0cc3e77d
5
5
  SHA512:
6
- metadata.gz: e8bc8cfb3460f2c1bba1aeec16f5e9f7f56d431a5caddd01fea73422ddafb1dbe11503664a91103be82be48c51e7620794e11a052f414656baff4726bd271f3e
7
- data.tar.gz: 5c48ccefb961b1308c8adf7b11aa225ce7a932ddc663c99d62e425ae7dacda93f572187fdacc86795b990950e7caff23b8e208a10b5b5484b3de4b03abcb7624
6
+ metadata.gz: d435115336cdf3abc0b2119c8748f7d2d440b6e327a55d7e27ed561df7d2648da4a4f6718b697daf5e73316a56b0d663cd0b87a141ec8220277b51431e89f550
7
+ data.tar.gz: fd2b59def500f548e4b774c880bbd9e98dfa0442ddb4c1253230c3e7cdadf4184b24440b60132ad58655a30d76510d7d1b85bf0762c7c94478adc9856212cf41
@@ -141,21 +141,19 @@ class NRSER::Char::AlphaNumericSub
141
141
  # Constructor
142
142
  # ======================================================================
143
143
 
144
- # Instantiate a new `Special`.
144
+ # Instantiate a new `AlphaNumericSub`.
145
145
  #
146
- # @param [String] char:
147
- # The actual character as a length 1 UTF-8 string.
146
+ # @param [String] sub_a
147
+ # Character the lower-case `a` ASCII character gets replaced with.
148
148
  #
149
- # @param [nil | String] caret:
150
- # Optional `^X` replacement for control characters, see {#caret} for
151
- # details.
149
+ # @param [String] sub_A
150
+ # Character the upper-case `A` ASCII character gets replaced with.
152
151
  #
153
- # @param [Array<#to_s>] names:
154
- # Optional names this character goes by.
152
+ # @param [String] sub_0
153
+ # Character the `0` gets subbed out for.
155
154
  #
156
- # @param [nil | String] symbol:
157
- # Optional printable unicode character replacement, see {#symbol} for
158
- # details.
155
+ # @param [Hash?] exceptions
156
+ # I don't know just read the source.
159
157
  #
160
158
  def initialize sub_a: nil,
161
159
  sub_A: nil,
@@ -185,14 +183,6 @@ class NRSER::Char::AlphaNumericSub
185
183
  # Instance Methods
186
184
  # ======================================================================
187
185
 
188
- # The first of {#names} (if any).
189
- #
190
- # @return [nil]
191
- # When {#names} is empty.
192
- #
193
- # @return [String]
194
- # When {#names} is not empty.
195
- #
196
186
  def sub src
197
187
  dest = src.dup
198
188
 
@@ -90,17 +90,17 @@ class NRSER::Char::Special
90
90
 
91
91
  # Instantiate a new `Special`.
92
92
  #
93
- # @param [String] char:
93
+ # @param [String] char
94
94
  # The actual character as a length 1 UTF-8 string.
95
95
  #
96
- # @param [nil | String] caret:
96
+ # @param [nil | String] caret
97
97
  # Optional `^X` replacement for control characters, see {#caret} for
98
98
  # details.
99
99
  #
100
- # @param [Array<#to_s>] names:
100
+ # @param [Array<#to_s>] names
101
101
  # Optional names this character goes by.
102
102
  #
103
- # @param [nil | String] symbol:
103
+ # @param [nil | String] symbol
104
104
  # Optional printable unicode character replacement, see {#symbol} for
105
105
  # details.
106
106
  #
@@ -177,7 +177,7 @@ class NRSER::Char::Special
177
177
  # @param [String] string
178
178
  # String to replace this character in.
179
179
  #
180
- # @param [Symbol | #to_s] with:
180
+ # @param [Symbol | #to_s] with
181
181
  # What to replace the character with:
182
182
  #
183
183
  # 1. {Symbol} - this method will be called on the instance and the
@@ -76,7 +76,7 @@ class Array
76
76
  # [:fetch, :x].sender.call x: 'ex'
77
77
  # # => 'ex'
78
78
  #
79
- # @param [Boolean] publicly:
79
+ # @param [Boolean] publicly
80
80
  # When `true`, uses `#public_send` in liu of `#send`.
81
81
  #
82
82
  # @return [Proc]
@@ -93,28 +93,51 @@ class Array
93
93
  end # #to_chainer
94
94
 
95
95
 
96
- # Returns a lambda that calls accepts a single arg and calls `#dig` on it
97
- # with the elements of *this* array as arguments.
96
+ # Returns a lambda that calls accepts a single arg and calls either:
97
+ #
98
+ # 1. `#[self.first]` if this array has only one entry.
99
+ # 2. `#dig( *self )` if this array has more than one entry.
98
100
  #
99
101
  # @example
100
102
  # list = [{id: 1, name: "Neil"}, {id: 2, name: "Mica"}]
101
- # list.assoc_by &[:id].to_digger
103
+ # list.assoc_by &[:id]
102
104
  # # => {
103
105
  # # 1 => {id: 1, name: "Neil"},
104
106
  # # 2 => {id: 2, name: "Mica"},
105
107
  # # }
106
108
  #
107
- # @todo
108
- # I wanted to use `#to_proc` so that you could use `&[:id]`, but unary
109
- # `&` doesn't invoke refinements, and I don't really want to monkey-patch
110
- # anything, especially something as core as `#to_proc` and `Array`.
111
- #
112
109
  # @return [Proc]
113
- # Lambda proc that accepts a single argument and calls `#dig` with this
114
- # array's contents as the `#dig` arguments.
110
+ # Lambda proc that accepts a single argument and calls `#[]` or `#dig with
111
+ # this array's contents as the arguments.
112
+ #
113
+ def to_proc
114
+ method_name = case count
115
+ when 0
116
+ raise NRSER::CountError.new \
117
+ "Can not create getter proc from empty array",
118
+ value: self,
119
+ expected: '> 0',
120
+ count: count
121
+ when 1
122
+ :[]
123
+ else
124
+ :dig
125
+ end
126
+
127
+ NRSER::Message.new( method_name, *self ).to_proc
128
+ end # #to_proc
129
+
130
+
131
+ # Old name for {#to_proc}.
132
+ #
133
+ # @deprecated
115
134
  #
116
135
  def to_digger
117
- NRSER::Message.new( :dig, *self ).to_proc
118
- end # #to_digger
136
+ NRSER.logger.deprecated \
137
+ method: "#{ self.class.name }##{ __method__ }",
138
+ alternative: "#{ self.class.name }#to_proc"
139
+
140
+ to_proc
141
+ end
119
142
 
120
143
  end # class Array
@@ -1,3 +1,4 @@
1
+ require 'nrser/functions/enumerable/associate'
1
2
  require_relative './enumerable/find_map'
2
3
 
3
4
 
@@ -18,7 +18,7 @@ module Enumerable
18
18
  # @param [nil | Proc<()=>DEFAULT>] ifnone
19
19
  # Optional lambda to call for the return value when no match is found.
20
20
  #
21
- # @param [Proc<(E)=>RESLUT>] &block
21
+ # @param [Proc<(E)=>RESLUT>] block
22
22
  # Block mapping entires to results.
23
23
  #
24
24
  # @return [nil]
@@ -1,3 +1,6 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
1
4
  require 'active_support/core_ext/object/deep_dup'
2
5
 
3
6
  class Hash
@@ -31,10 +31,10 @@ class Hash
31
31
  # hash
32
32
  # # => {:c=>3, :d=>4}
33
33
  #
34
- # @param *keys
34
+ # @param keys
35
35
  # Hash keys to extract.
36
36
  #
37
- # @param [#<<] into:
37
+ # @param [#<<] into
38
38
  # Object to extract values at `keys` into.
39
39
  #
40
40
  # @return [into]
@@ -3,7 +3,7 @@ require_relative '../module/names'
3
3
 
4
4
  class Method
5
5
 
6
- # Returns the method's {#receiver} and {#name} in the common
6
+ # Returns the method's {::Method#receiver} and {::Method#name} in the common
7
7
  # `A.cls_meth` / `A#inst_meth` format.
8
8
  #
9
9
  def full_name
@@ -46,7 +46,7 @@ class Module
46
46
  # @param include_super (see NRSER.method_objects_for)
47
47
  # @param sort: (see NRSER.method_objects_for)
48
48
  #
49
- # @param [Boolean] include_initialize:
49
+ # @param [Boolean] include_initialize
50
50
  # When `true`, include `#initialize` method if it's defined, which is
51
51
  # normally excluded from {Module#instance_methods}.
52
52
  #
@@ -108,27 +108,39 @@ class Module
108
108
  end
109
109
 
110
110
 
111
- # Get *all* source locations for that module (or class) methods.
111
+ # Get *all* source locations for that module (or class) methods - class
112
+ # *and* instance methods.
112
113
  #
113
- # @param [type] arg_name
114
- # @todo Add name param description.
114
+ # @param [Boolean] only_valid
115
+ # Filter results to only valid source locations.
115
116
  #
116
117
  # @return [Hash<Method, Array<String, Fixnum>>]
117
- # @todo Document return value.
118
118
  #
119
119
  def method_locations only_valid: false
120
120
  # Get all the src locs for own methods
121
- own_class_method_locations( only_valid: only_valid ).
122
- map { |name, location|
123
- [".#{ name }", location]
124
- }.
125
- to_h.
126
- merge! \
127
- own_instance_method_locations( only_valid: only_valid,
128
- include_initialize: true ).
129
- map { |name, location|
130
- ["##{ name }", location]
131
- }.to_h
121
+ # own_class_method_locations( only_valid: only_valid ).
122
+ # map { |name, location|
123
+ # [".#{ name }", location]
124
+ # }.
125
+ # to_h.
126
+ # merge! \
127
+ # own_instance_method_locations( only_valid: only_valid,
128
+ # include_initialize: true ).
129
+ # map { |name, location|
130
+ # ["##{ name }", location]
131
+ # }.to_h
132
+
133
+ [
134
+ [ '.', own_class_method_locations( only_valid: only_valid ) ],
135
+
136
+ [ '#', own_instance_method_locations( only_valid: only_valid,
137
+ include_initialize: true ) ],
138
+
139
+ ].each_with_object( {} ) do |(prefix, method_locations), result|
140
+ method_locations.each do |name, location|
141
+ result["#{ prefix }#{ name }"] = location
142
+ end
143
+ end
132
144
  end # .module_source_locations
133
145
 
134
146
 
@@ -14,7 +14,7 @@ class Object
14
14
  # The name of the instance variable. Needs to have that `@` on the
15
15
  # front, like `:@x`.
16
16
  #
17
- # @param [Proc<() => VALUE>] &block
17
+ # @param [Proc<() => VALUE>] block
18
18
  # The block to call to get the value.
19
19
  #
20
20
  # @return [VALUE]
@@ -1,10 +1,31 @@
1
+ # frozen_string_literal: true
2
+ # encoding: UTF-8
3
+
4
+ # Requirements
5
+ # ========================================================================
6
+
7
+ # Stdlib
8
+ # ------------------------------------------------------------------------
9
+
1
10
  require 'pathname'
2
11
 
12
+ # Project / Package
13
+ # ------------------------------------------------------------------------
14
+
15
+
16
+ # Definitions
17
+ # ========================================================================
18
+
19
+ # NRSER's extensions to the stdlib's `Pathname` class.
20
+ #
21
+ # @see https://ruby-doc.org/stdlib/libdoc/pathname/rdoc/Pathname.html
22
+ # Pathname
23
+ #
3
24
  class Pathname
4
25
 
5
26
  # override to accept Pathname instances.
6
27
  #
7
- # @param [String] *prefixes
28
+ # @param [String] prefixes
8
29
  # the prefixes to see if the Pathname starts with.
9
30
  #
10
31
  # @return [Boolean]
@@ -21,26 +42,50 @@ class Pathname
21
42
  end
22
43
 
23
44
 
24
- alias_method :_original_sub, :sub
45
+ # @!method _core_sub *args, &block
46
+ # An `alias_method` reference to the `#sub` method as we found it, which
47
+ # we'll use inside our override of {#sub}... and now you can too!
48
+ #
49
+ # Arguments are the same as [String#sub][].
50
+ #
51
+ # [String#sub]: https://ruby-doc.org/core/String.html#method-i-sub
52
+ #
53
+ # @see https://ruby-doc.org/stdlib/libdoc/pathname/rdoc/Pathname.html#method-i-sub
54
+ # Ruby Stdlib Pathname#sub
55
+ #
56
+ # @return [Pathname]
57
+ #
58
+ alias_method :_core_sub, :sub
25
59
 
26
60
 
27
- # override sub to support Pathname instances as patterns.
61
+ # Our override of `#sub` to support {Pathname} instances as patterns.
62
+ #
63
+ # Just calls `#to_s` on `pattern` if it's a {Pathname} before passing down
64
+ # to {#_core_sub}.
28
65
  #
29
66
  # @param [String | Regexp | Pathname] pattern
30
- # thing to replace.
67
+ # Thing to replace.
31
68
  #
32
- # @param [String | Hash] replacement
33
- # thing to replace it with.
69
+ # @param args
70
+ # See Ruby core's [String#sub][], which [Pathname#sub][] calls between
71
+ # stringifying and re-wrapping in a {Pathname} (core's [String#sub][] is
72
+ # overloaded).
73
+ #
74
+ # [String#sub]: https://ruby-doc.org/core/String.html#method-i-sub
75
+ # [Pathname#sub]: https://ruby-doc.org/stdlib/libdoc/pathname/rdoc/Pathname.html#method-i-sub
76
+ #
77
+ # @param [Proc] block
78
+ # See [String#sub][].
34
79
  #
35
80
  # @return [Pathname]
36
- # new Pathname.
81
+ # A brand new Pathname boys and girls!
37
82
  #
38
- def sub pattern, replacement
83
+ def sub pattern, *args, &block
39
84
  case pattern
40
85
  when Pathname
41
- _original_sub pattern.to_s, replacement
86
+ _core_sub pattern.to_s, *args, &block
42
87
  else
43
- _original_sub pattern, replacement
88
+ _core_sub pattern, *args, &block
44
89
  end
45
90
  end
46
91
 
@@ -72,10 +117,10 @@ class Pathname
72
117
  # Shortcut to convert into a relative pathname, by default from the working
73
118
  # directory, with option to `./` prefix.
74
119
  #
75
- # @param [Pathname] base_dir:
120
+ # @param [Pathname] base_dir
76
121
  # Directory you want the result to be relative to.
77
122
  #
78
- # @param [Boolean] dot_slash:
123
+ # @param [Boolean] dot_slash
79
124
  # When `true` will prepend `./` to the resulting path, unless it already
80
125
  # starts with `../`.
81
126
  #
@@ -122,5 +167,15 @@ class Pathname
122
167
  def to_dot_rel_s **kwds
123
168
  to_rel_s( **kwds, dot_slash: true ).to_s
124
169
  end
170
+
171
+
172
+ # The "closest" directory - which is `self` if the instance is a
173
+ # {#directory?}, otherwise it's {#dirname}.
174
+ #
175
+ # @return [Pathname]
176
+ #
177
+ def closest_dir
178
+ directory? ? self : dirname
179
+ end
125
180
 
126
181
  end # class Pathname
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+ # encoding: UTF-8
3
+
4
+ # Requirements
5
+ # ========================================================================
6
+
7
+ # Stdlib
8
+ # ------------------------------------------------------------------------
9
+
10
+ require 'pathname'
11
+
12
+ # Project / Package
13
+ # ------------------------------------------------------------------------
14
+
15
+ # Need {ValueError}
16
+ require 'nrser/errors/value_error'
17
+
18
+
19
+ # Definitions
20
+ # ========================================================================
21
+
22
+ class Pathname
23
+
24
+ # Is `other` a subpath of `self`?
25
+ #
26
+ # Which - it turns out - is a bit of a ricky question! Who knew?!
27
+ #
28
+ # Maybe that's why it's not in the stand' lib.
29
+ #
30
+ # Here's how we gonna go:
31
+ #
32
+ # 1. Raise a {NRSER::ValueError} unless `self` is a {#directory?} and is
33
+ # {#absolute?}.
34
+ #
35
+ # I don't think it make any sense to ask about subpaths of something that
36
+ # is not a directory, and things just get too messy unless it's absolute
37
+ # since we need to expand `other` to make sure it doesn't dot-dot-dig
38
+ # it's way outta there.
39
+ #
40
+ # 2.
41
+ #
42
+ # @param [Boolean] strict
43
+ # Decides behavior when `other` expands to the same directory as `self`:
44
+ #
45
+ # 1. When `strict: false` (the default) a directory **is** considered a
46
+ # subpath of itself.
47
+ #
48
+ # 2. When `strict: true`, a directory **is not** considered a subpath of
49
+ # itself.
50
+ #
51
+ # @return [Boolean]
52
+ # `true` if `other` is a path inside `self`.
53
+ #
54
+ # See the `strict` parameter for behavior when `other` expands to `self`.
55
+ #
56
+ # @raise [NRSER::ValueError]
57
+ # If `self` is not a {#directory?}.
58
+ #
59
+ # @raise [NRSER::ValueError]
60
+ # If `self` is not {#absolute?}.
61
+ #
62
+ def subpath? other, root: nil, strict: false
63
+ unless directory?
64
+ raise NRSER::ValueError.new \
65
+ "Receiver {Pathname}", self, "must be a {#directory} in order to test",
66
+ "for subpaths",
67
+ value: self
68
+ end
69
+
70
+ unless absolute?
71
+ raise NRSER::ValueError.new \
72
+ "Receiver {Pathname}", self, "must be {#absolute?} in order to test",
73
+ "for subpaths",
74
+ value: self
75
+ end
76
+
77
+ abs_other = other.to_pn.expand_path root
78
+
79
+ # Deal with easy case first, when they're the same dir
80
+ return !strict if self == abs_other
81
+
82
+ # Ok, now see if they prefix match
83
+ abs_other.start_with? self
84
+ end # #subpath?
85
+
86
+ end # class Pathname