nrser 0.3.9 → 0.3.10

Sign up to get free protection for your applications and to get access to all the features.
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