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
@@ -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