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
@@ -16,10 +16,10 @@ module NRSER
16
16
  # @param [Boolean] include_super
17
17
  # When `true`, includes inherited class methods.
18
18
  #
19
- # @param [:class | :instance] type:
19
+ # @param [:class | :instance] type
20
20
  # Get class or instance methods.
21
21
  #
22
- # @param [Boolean] sort:
22
+ # @param [Boolean] sort
23
23
  # If `true`, will sort the methods by name, which is usually
24
24
  # the useful way to look at and use them.
25
25
  #
@@ -1,175 +1,195 @@
1
- module NRSER
2
- # @!group Path Functions
3
-
4
- # @return [Pathname]
5
- #
6
- def self.pn_from path
7
- if path.is_a? Pathname
8
- path
9
- else
10
- Pathname.new path
11
- end
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ # Requirements
5
+ # =======================================================================
6
+
7
+ # Stdlib
8
+ # -----------------------------------------------------------------------
9
+ require 'pathname'
10
+
11
+ # Deps
12
+ # -----------------------------------------------------------------------
13
+
14
+ # Project / Package
15
+ # -----------------------------------------------------------------------
16
+
17
+ require_relative './path/normalized'
18
+
19
+ # Namespace
20
+ # =======================================================================
21
+
22
+ module NRSER
23
+
24
+
25
+ # Definitions
26
+ # =======================================================================
27
+
28
+ # @!group Path Functions
29
+
30
+ # @return [Pathname]
31
+ #
32
+ def self.pn_from path
33
+ if path.is_a? Pathname
34
+ path
35
+ else
36
+ Pathname.new path
12
37
  end
38
+ end
39
+
40
+
41
+ # Get the directory for a path - if the path is a directory, it's returned
42
+ # (converted to a {Pathname}). It's not a directory, it's {Pathname#dirname}
43
+ # will be returned.
44
+ #
45
+ # Expands the path (so that `~` paths work).
46
+ #
47
+ # @param [String | Pathname] path
48
+ # File or directory path.
49
+ #
50
+ # @return [Pathname]
51
+ # Absolute directory path.
52
+ #
53
+ def self.dir_from path
54
+ pn = pn_from( path ).expand_path
13
55
 
56
+ if pn.directory?
57
+ pn
58
+ else
59
+ pn.dirname
60
+ end
61
+ end # .dir_from
62
+
63
+
64
+ def self.looks_globish? path
65
+ %w|* ? [ {|.any? &path.to_s.method( :include? )
66
+ end # .glob?
67
+
68
+
69
+ # Ascend the directory tree starting at `from` (defaults to working
70
+ # directory) looking for a relative path.
71
+ #
72
+ # How it works and what it returns is dependent on the sent options.
73
+ #
74
+ # In the simplest / default case:
75
+ #
76
+ # 1.
77
+ #
78
+ # @param [String | Pathname] rel_path
79
+ # Relative path to search for. Can contains glob patterns; see the `glob`
80
+ # keyword.
81
+ #
82
+ # @param [String | Pathname] from
83
+ # Where to start the search. This is the first directory checked.
84
+ #
85
+ # @param [Boolean | :guess] glob
86
+ # Controls file-glob behavior with respect to `rel_path`:
87
+ #
88
+ # - `:guess` (default) - boolean value is computed by passing `rel_path`
89
+ # to {.looks_globish?}.
90
+ #
91
+ # - `true` - {Pathname.glob} is used to search for `rel_path` in each
92
+ # directory, and the first glob result that passes the test is
93
+ # considered the match.
94
+ #
95
+ # - `false` - `rel_path` is used as a literal file path (if it has a `*`
96
+ # character it will only match paths with a literal `*` character,
97
+ # etc.)
98
+ #
99
+ # **Be mindful that glob searches can easily consume significant resources
100
+ # when using broad patterns and/or large file trees.**
101
+ #
102
+ # Basically, you probably don't *ever* want to use `**` - we walk all the
103
+ # way up to the file system root, so it would be equivalent to searching
104
+ # *the entire filesystem*.
105
+ #
106
+ # @todo
107
+ # There should be a way to cut the search off early or detect `**` in
108
+ # the `rel_path` and error out or something to prevent full FS search.
109
+ #
110
+ # @param [Symbol] test
111
+ # The test to perform on pathnames to see if they match. Defaults to
112
+ # `:exist?` - which calls {Pathname#exist?} - but could be `:directory?`
113
+ # or anything else that makes sense.
114
+ #
115
+ # @param [Symbol] result
116
+ # What information to return:
117
+ #
118
+ # - `:common_root` (default) - return the directory that the match was
119
+ # relative to, so the return value is `from` or a ancestor of it.
120
+ #
121
+ # - `:path` - return the full path that was matched.
122
+ #
123
+ # - `:pair` - return the `:common_root` value followed by the `:path`
124
+ # value in a two-element {Array}.
125
+ #
126
+ # @return [nil]
127
+ # When no match is found.
128
+ #
129
+ # @return [Pathname]
130
+ # When a match is found and `result` keyword is
131
+ #
132
+ # - `:common_root` - the directory in `from.ascend` the match was made
133
+ # from.
134
+ #
135
+ # - `:path` - the path to the matched file.
136
+ #
137
+ # @return [Array<(Pathname, Pathname)>]
138
+ # When a match is found and `result` keyword is `:pair`, the directory
139
+ # the match was relative to followed by the matched path.
140
+ #
141
+ def self.find_up(
142
+ rel_path,
143
+ from: Pathname.pwd,
144
+ glob: :guess,
145
+ test: :exist?,
146
+ result: :common_root
147
+ )
148
+ # If `glob` is `:guess`, override `glob` with the result of
149
+ # {.looks_globish?}
150
+ #
151
+ glob = looks_globish?( rel_path ) if glob == :guess
14
152
 
15
- # Get the directory for a path - if the path is a directory, it's returned
16
- # (converted to a {Pathname}). It's not a directory, it's {Pathname#dirname}
17
- # will be returned.
18
- #
19
- # Expands the path (so that `~` paths work).
20
- #
21
- # @param [String | Pathname] path
22
- # File or directory path.
23
- #
24
- # @return [Pathname]
25
- # Absolute directory path.
26
- #
27
- def self.dir_from path
28
- pn = pn_from( path ).expand_path
153
+ found = pn_from( from ).ascend.find_map { |dir|
154
+ path = dir / rel_path
29
155
 
30
- if pn.directory?
31
- pn
156
+ found_path = if glob
157
+ Pathname.glob( path ).find { |match_path|
158
+ match_path.public_send test
159
+ }
160
+ elsif path.public_send( test )
161
+ path
32
162
  else
33
- pn.dirname
163
+ nil
34
164
  end
35
- end # .dir_from
36
-
37
-
38
- # @todo Document glob? method.
39
- #
40
- # @param [type] arg_name
41
- # @todo Add name param description.
42
- #
43
- # @return [return_type]
44
- # @todo Document return value.
45
- #
46
- def self.looks_globish? path
47
- %w|* ? [ {|.any? &path.to_s.method( :include? )
48
- end # .glob?
49
-
50
-
51
- # Ascend the directory tree starting at `from` (defaults to working
52
- # directory) looking for a relative path.
53
- #
54
- # How it works and what it returns is dependent on the sent options.
55
- #
56
- # In the simplest / default case:
57
- #
58
- # 1.
59
- #
60
- # @param [String | Pathname] rel_path
61
- # Relative path to search for. Can contains glob patterns; see the `glob`
62
- # keyword.
63
- #
64
- # @param [String | Pathname] from:
65
- # Where to start the search. This is the first directory checked.
66
- #
67
- # @param [Boolean | :guess] glob:
68
- # Controls file-glob behavior with respect to `rel_path`:
69
- #
70
- # - `:guess` (default) - boolean value is computed by passing `rel_path`
71
- # to {.looks_globish?}.
72
- #
73
- # - `true` - {Pathname.glob} is used to search for `rel_path` in each
74
- # directory, and the first glob result that passes the test is
75
- # considered the match.
76
- #
77
- # - `false` - `rel_path` is used as a literal file path (if it has a `*`
78
- # character it will only match paths with a literal `*` character,
79
- # etc.)
80
- #
81
- # **Be mindful that glob searches can easily consume significant resources
82
- # when using broad patterns and/or large file trees.**
83
- #
84
- # Basically, you probably don't *ever* want to use `**` - we walk all the
85
- # way up to the file system root, so it would be equivalent to searching
86
- # *the entire filesystem*.
87
- #
88
- # @todo
89
- # There should be a way to cut the search off early or detect `**` in
90
- # the `rel_path` and error out or something to prevent full FS search.
91
- #
92
- # @param [Symbol] test:
93
- # The test to perform on pathnames to see if they match. Defaults to
94
- # `:exist?` - which calls {Pathname#exist?} - but could be `:directory?`
95
- # or anything else that makes sense.
96
- #
97
- # @param [Symbol] result:
98
- # What information to return:
99
- #
100
- # - `:common_root` (default) - return the directory that the match was
101
- # relative to, so the return value is `from` or a ancestor of it.
102
- #
103
- # - `:path` - return the full path that was matched.
104
- #
105
- # - `:pair` - return the `:common_root` value followed by the `:path`
106
- # value in a two-element {Array}.
107
- #
108
- # @return [nil]
109
- # When no match is found.
110
- #
111
- # @return [Pathname]
112
- # When a match is found and `result` keyword is
113
- #
114
- # - `:common_root` - the directory in `from.ascend` the match was made
115
- # from.
116
- #
117
- # - `:path` - the path to the matched file.
118
- #
119
- # @return [Array<(Pathname, Pathname)>]
120
- # When a match is found and `result` keyword is `:pair`, the directory
121
- # the match was relative to followed by the matched path.
122
- #
123
- def self.find_up(
124
- rel_path,
125
- from: Pathname.pwd,
126
- glob: :guess,
127
- test: :exist?,
128
- result: :common_root
129
- )
130
- # If `glob` is `:guess`, override `glob` with the result of
131
- # {.looks_globish?}
132
- #
133
- glob = looks_globish?( rel_path ) if glob == :guess
134
-
135
- found = pn_from( from ).ascend.find_map { |dir|
136
- path = dir / rel_path
137
-
138
- found_path = if glob
139
- Pathname.glob( path ).find { |match_path|
140
- match_path.public_send test
141
- }
142
- elsif path.public_send( test )
143
- path
144
- else
145
- nil
146
- end
147
-
148
- unless found_path.nil?
149
- [dir, found_path]
150
- end
151
- }
152
-
153
- return nil if found.nil?
154
165
 
155
- dir, path = found
156
-
157
- Types.match result,
158
- :common_root, dir,
159
- :pair, found,
160
- :path, path
161
- end
166
+ unless found_path.nil?
167
+ [dir, found_path]
168
+ end
169
+ }
162
170
 
171
+ return nil if found.nil?
163
172
 
164
- # Exactly like {NRSER.find_up} but raises if nothing is found.
165
- #
166
- def self.find_up! *args
167
- find_up( *args ).tap { |result|
168
- if result.nil?
169
- raise "HERE! #{ args.inspect }"
170
- end
171
- }
172
- end
173
+ dir, path = found
173
174
 
174
-
175
- end # module NRSER
175
+ Types.match result,
176
+ :common_root, dir,
177
+ :pair, found,
178
+ :path, path
179
+ end
180
+
181
+
182
+ # Exactly like {NRSER.find_up} but raises if nothing is found.
183
+ #
184
+ def self.find_up! *args
185
+ find_up( *args ).tap { |result|
186
+ if result.nil?
187
+ raise "HERE! #{ args.inspect }"
188
+ end
189
+ }
190
+ end
191
+
192
+ # /Namespace
193
+ # =======================================================================
194
+
195
+ end # module NRSER
@@ -0,0 +1,84 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ # Requirements
5
+ # =======================================================================
6
+
7
+ # Stdlib
8
+ # -----------------------------------------------------------------------
9
+ require 'pathname'
10
+
11
+ # Project / Package
12
+ # -----------------------------------------------------------------------
13
+ require 'nrser/errors/type_error'
14
+
15
+
16
+ # Namespace
17
+ # =======================================================================
18
+
19
+ module NRSER
20
+
21
+
22
+ # Definitions
23
+ # =======================================================================
24
+
25
+ # Test if a path is what I'm calling "normalized" - generally free of any
26
+ # `.`, `..` or empty segments, with specific exceptions for `'/'` and `'.'`.
27
+ #
28
+ # @param [String | Pathname] path
29
+ # Path to test.
30
+ #
31
+ # @return [Boolean]
32
+ # `true` if we consider the path "normalized".
33
+ #
34
+ # @raise [NRSER::TypeError]
35
+ # If `path` is not a {String} or {Pathname}.
36
+ #
37
+ def self.normalized_path? path
38
+ string = case path
39
+ when String
40
+ path
41
+ when Pathname
42
+ path.to_s
43
+ else
44
+ raise NRSER::TypeError.new \
45
+ "path must be String or Pathname, found", path,
46
+ expected: [ String, Pathname ],
47
+ found: path
48
+ end
49
+
50
+ # Examine each segment
51
+
52
+ # NOTE The `-1` is *extremely* important - it stops suppression of empty
53
+ # entries in the result, and we need them!
54
+ segments = string.split File::SEPARATOR, -1
55
+
56
+ segments.
57
+ # We need the indexes, since the first and last segments can be empty,
58
+ # corresponding to `/...` and `.../` paths, respectively.
59
+ each_with_index.
60
+ # See if they all meet the requirements
61
+ all? { |segment, index|
62
+ (
63
+ segment != '.' || # Can't have any `.../x/./y/...` business
64
+ index == 0 # But we can have `./x/y/` and such
65
+ ) &&
66
+ segment != '..' && # Can't have any `.../x/../y/...` crap either
67
+ (
68
+ # and, finally, the segment can't be empty
69
+ segment != '' ||
70
+ # unless it's the first (`/x/...` case)
71
+ index == 0 ||
72
+ # or the last segment (`.../z/` case)
73
+ index == segments.length - 1
74
+ )
75
+ }
76
+ end # .normalized_path?
77
+
78
+ singleton_class.send :alias_method, :norm_path?, :normalized_path?
79
+
80
+
81
+ # /Namespace
82
+ # =======================================================================
83
+
84
+ end # module NRSER