nrser 0.1.3 → 0.1.4

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: 1518d7452a93418bee72c151693e9f6499a41d6a
4
- data.tar.gz: 5139a61976788fb0bb8c397a40eec24d20c695d7
3
+ metadata.gz: 10930bb8b3998cc81f95333c8eb86a102262d84e
4
+ data.tar.gz: ff5057aead5992fe1d053e814afd120278b80a4c
5
5
  SHA512:
6
- metadata.gz: eb32f1311827dc0190db71434a798953282e3d258b3059aea03b86f6e56b57f871b7c5e8dcfe4b99844db1ec65b8782bf0c7ef3a099f1423ceeddcdf8b5ea16b
7
- data.tar.gz: 67aad6c06d72fb6123dc74294e113bd9f2862a9eca317e64277aae9fb68169e9c48dc5e9248788ca475e1d30f2314b7cdd6958ee12792880be4ccc859c5fa6b8
6
+ metadata.gz: f64f47ddbbb195eb13f072aec1f0beb8ff8299dbf9bc40838a2dcb078fd401fc03509c6566f497041ca0b3d5fc95f4b0baee0e7cb390e7238182a0e14e51ee50
7
+ data.tar.gz: ba2da8fe57e5d3e9f2c1439fa978957327982624c1a536b1bbf950901783d66808c44042d0f01f4ce7c8ec4333a93fb29904878c3165bc010dd099eddd864265
@@ -17,10 +17,11 @@ require 'yaml'
17
17
  require 'logger'
18
18
  require 'singleton'
19
19
 
20
-
21
20
  # Deps
22
21
  # -----------------------------------------------------------------------
23
22
  require 'hamster'
23
+ require 'semantic_logger'
24
+
24
25
 
25
26
  # Hi there!
26
27
  #
@@ -47,28 +48,25 @@ require 'hamster'
47
48
  # Enjoy!
48
49
  #
49
50
  module NRSER
50
-
51
- # Absolute, expanded path to the gem's root directory.
52
- #
53
- # @return [Pathname]
54
- #
55
- ROOT = ( Pathname.new(__FILE__).dirname / '..' ).expand_path
56
-
51
+ include SemanticLogger::Loggable
57
52
  end
58
53
 
59
- # 1. Load up extension mixins first - they don't invoke anything, just define
54
+ # 1. Load up version, which has {NRSER::ROOT} in it and depends on nothing
55
+ # else
56
+ require_relative './nrser/version'
57
+
58
+ # 2. Load up extension mixins first - they don't invoke anything, just define
60
59
  # methods
61
60
  require_relative './nrser/ext'
62
61
 
63
- # 2. Then load up the refinements, which either include the extension mixins
62
+ # 3. Then load up the refinements, which either include the extension mixins
64
63
  # or directly define proxies and methods (but don't execute them).
65
64
  #
66
65
  # This way everything else should be able to use them.
67
66
  #
68
67
  require_relative './nrser/refinements'
69
68
 
70
- # 3. Then everything else...
71
- require_relative './nrser/version'
69
+ # 4. Then everything else...
72
70
  require_relative './nrser/char'
73
71
  require_relative './nrser/errors'
74
72
  require_relative './nrser/no_arg'
@@ -3,3 +3,4 @@ module NRSER::Ext; end
3
3
  require_relative './ext/enumerable'
4
4
  require_relative './ext/tree'
5
5
  require_relative './ext/pathname'
6
+ require_relative './ext/string'
@@ -64,4 +64,10 @@ module NRSER::Ext::Enumerable
64
64
  NRSER.find_map self, *args, &block
65
65
  end
66
66
 
67
+ # See {NRSER.slice?}
68
+ def slice? *args, &block
69
+ NRSER.slice? self, *args, &block
70
+ end
71
+
72
+
67
73
  end # module NRSER::Ext::Enumerable
@@ -0,0 +1,62 @@
1
+ # Extension methods for {String}
2
+ #
3
+ module NRSER::Ext::String
4
+
5
+ def squish
6
+ NRSER.squish self
7
+ end
8
+
9
+
10
+ def unblock
11
+ NRSER.unblock self
12
+ end
13
+
14
+
15
+ def dedent
16
+ NRSER.dedent self
17
+ end
18
+
19
+
20
+ def indent *args
21
+ NRSER.indent self, *args
22
+ end
23
+
24
+
25
+ def truncate *args
26
+ NRSER.truncate self, *args
27
+ end
28
+
29
+
30
+ # See {NRSER.constantize}
31
+ def constantize
32
+ NRSER.constantize self
33
+ end
34
+
35
+ alias_method :to_const, :constantize
36
+
37
+
38
+ # @return [Pathname]
39
+ # Convert self into a {Pathname}
40
+ #
41
+ def to_pn
42
+ Pathname.new self
43
+ end
44
+
45
+
46
+ def whitespace?
47
+ NRSER.whitespace? self
48
+ end
49
+
50
+
51
+ # Calls {NRSER.ellipsis} on `self`.
52
+ def ellipsis *args
53
+ NRSER.ellipsis self, *args
54
+ end
55
+
56
+
57
+ # Calls {NRSER.words} on `self`
58
+ def words *args, &block
59
+ NRSER::words self, *args, &block
60
+ end
61
+
62
+ end # module NRSER::Ext::String
@@ -1,5 +1,6 @@
1
1
  require_relative './enumerable/find_map'
2
2
  require_relative './enumerable/find_all_map'
3
+ require_relative './enumerable/include_slice'
3
4
 
4
5
  module NRSER
5
6
 
@@ -0,0 +1,84 @@
1
+ require_relative './include_slice/array_include_slice'
2
+
3
+ using NRSER
4
+
5
+ module NRSER
6
+
7
+ # @!group Enumerable Functions
8
+
9
+ # See if an `enum` includes a `slice`, using an optional block to do custom
10
+ # matching.
11
+ #
12
+ # @example Order matters
13
+ # NRSER.slice? [1, 2, 3], [2, 3]
14
+ # # => true
15
+ #
16
+ # NRSER.slice? [1, 2, 3], [3, 2]
17
+ # # => false
18
+ #
19
+ # @example The empty slice is always present
20
+ # NRSER.slice? [1, 2, 3], []
21
+ # # => true
22
+ #
23
+ # NRSER.slice? [], []
24
+ # # => true
25
+ #
26
+ # @example Custom `&is_match` block to prefix-match
27
+ # NRSER.slice?(
28
+ # ['neil', 'mica', 'hudie'],
29
+ # ['m', 'h']
30
+ # ) { |enum_entry, slice_entry|
31
+ # enum_entry.start_with? slice_entry
32
+ # }
33
+ # # => true
34
+ #
35
+ # @note
36
+ # Right now, just forwards to {NRSER.array_include_slice?}, which requires
37
+ # that the {Enumerable}s support {Array}-like `#length` and `#slice`. I
38
+ # took a swing at the general case but it came out messy and only partially
39
+ # correct.
40
+ #
41
+ # @param [Enumerable] enum
42
+ # Sequence to search in.
43
+ #
44
+ # @param [Enumerable] slice
45
+ # Slice to search for.
46
+ #
47
+ # @return [Boolean]
48
+ # `true` if `enum` has a slice matching `slice`.
49
+ #
50
+ def self.include_slice? enum, slice, &is_match
51
+ # Check that both args are {Enumerable}
52
+ unless Enumerable === enum &&
53
+ Enumerable === slice
54
+ raise TypeError.new binding.erb <<-END
55
+ Both `enum` and `slice` must be {Enumerable}
56
+
57
+ enum (<%= enum.class.name %>):
58
+
59
+ <%= enum.pretty_inspect %>
60
+
61
+ slice (<%= slice.class.name %>):
62
+
63
+ <%= slice.pretty_inspect %>
64
+
65
+ END
66
+ end
67
+
68
+ if [enum, slice].all? { |e|
69
+ e.respond_to?( :length ) && e.respond_to?( :slice )
70
+ }
71
+ return array_include_slice? enum, slice, &is_match
72
+ end
73
+
74
+ raise NotImplementedError.new binding.erb <<-END
75
+ Sorry, but general {Enumerable} slice include has not been implemented
76
+
77
+ It's kinda complicated, or at least seems that way at first, so I'm
78
+ going to punt for now...
79
+ END
80
+ end
81
+
82
+ singleton_class.send :alias_method, :slice?, :include_slice?
83
+
84
+ end # module NRSER
@@ -0,0 +1,80 @@
1
+
2
+ module NRSER
3
+
4
+ # @!group Enumerable Functions
5
+
6
+ # Test slice inclusion when both the `slice` and the `enum` that we're
7
+ # going to look for it in support `#length` and `#slice`
8
+ # in the same manner that {Array} does (hence the name).
9
+ #
10
+ # This is much simpler and more efficient than the "general" {Enumerable}
11
+ # case where we can't necessarily find out how many entries are in the
12
+ # enumerables or really do much of anything with them except iterate through
13
+ # (at least, with my current grasp of {Enumerable} and {Enumerator} it
14
+ # seems painfully complex... in fact it may never terminate for infinite
15
+ # enumerables).
16
+ #
17
+ # @param [Enumerable<E> & #length & #slice] enum
18
+ # The {Enumerable} that we want test for `slice` inclusion. Must
19
+ # support `#length` and `#slice` like {Array} does.
20
+ #
21
+ # @param [Enumerable<S> & #length & #slice] slice
22
+ # The {Enumerable} slice that we want to see if `enum` includes. Must
23
+ # support `#length` and `#slice` like {Array} does.
24
+ #
25
+ # @param [Proc<(E, S)=>Boolean>] &is_match
26
+ # Optional {Proc} that accepts an entry from `enum` and an entry from
27
+ # `slice` and returns if they match.
28
+ #
29
+ # @return [Boolean]
30
+ # `true` if there is a slice of `enum` for which each entry matches the
31
+ # corresponding entry in `slice` according to `&is_match`.
32
+ #
33
+ def self.array_include_slice? enum, slice, &is_match
34
+ slice_length = slice.length
35
+
36
+ # Short-circuit on empty slice - it's *always* present
37
+ return true if slice_length == 0
38
+
39
+ enum_length = enum.length
40
+
41
+ # Short-circuit if slice is longer than enum since we can't possibly
42
+ # match
43
+ return false if slice_length > enum_length
44
+
45
+ # Create a default `#==` matcher if we weren't provided one.
46
+ if is_match.nil?
47
+ is_match = ->(enum_entry, slice_entry) {
48
+ enum_entry == slice_entry
49
+ }
50
+ end
51
+
52
+ enum.each_with_index do |enum_entry, enum_start_index|
53
+ # Compute index in `enum` that we would need to match up to
54
+ enum_end_index = enum_start_index + slice_length - 1
55
+
56
+ # Short-circuit if can't match (more slice entries than enum ones left)
57
+ return false if enum_end_index >= enum_length
58
+
59
+ # Create the slice to test against
60
+ enum_slice = enum[enum_start_index..enum_end_index]
61
+
62
+ # See if every entry in the slice from `enum` matches the corresponding
63
+ # one in `slice`
64
+ return true if enum_slice.zip( slice ).all?( &is_match )
65
+
66
+ # Otherwise, just continue on through `enum` looking for that first
67
+ # match until the number of `enum` entries left is too few for `slice`
68
+ # to possibly match
69
+ end
70
+
71
+ # We never matched the first `slice` entry to a `enum` entry (and `slice`
72
+ # had to be of length 1 so that the "too long" short-circuit never fired).
73
+ #
74
+ # So, we don't have a match.
75
+ false
76
+ end
77
+
78
+ singleton_class.send :alias_method, :array_slice?, :array_include_slice?
79
+
80
+ end # module NRSER
@@ -1,3 +1,4 @@
1
1
  require_relative './text/lines'
2
2
  require_relative './text/word_wrap'
3
3
  require_relative './text/indentation'
4
+ require_relative './text/words'
@@ -0,0 +1,23 @@
1
+ module NRSER
2
+
3
+ # Regexp {NRSER.words} uses to split strings. Probably not great but it's
4
+ # what I have for the moment.
5
+ #
6
+ # @return {Regexp}
7
+ #
8
+ SPLIT_WORDS_RE = /[\W_\-\/]+/
9
+
10
+
11
+ # Split a string into 'words' for word-based matching.
12
+ #
13
+ # @param [String] string
14
+ # Input string.
15
+ #
16
+ # @return [Array<String>]
17
+ # Array of non-empty words in `string`.
18
+ #
19
+ def self.words string
20
+ string.split(/[\W_\-\/]+/).reject { |w| w.empty? }
21
+ end # .words
22
+
23
+ end # module NRSER
@@ -0,0 +1,13 @@
1
+ # Namespace for new ideas I'm trying out. Totally unstable. May be gone
2
+ # completely tomorrow, etc.
3
+ #
4
+ # While, yes, the entire package is alpha, and there is no guarantee against
5
+ # change and breakage, I'm generally at a point where I'm trying to keep
6
+ # things that work mostly working.
7
+ #
8
+ # Stuff in here has no such consideration.
9
+ #
10
+ # There may be some tests for it, but they are going to be skipped by default
11
+ # and certainly won't prevent releases, if they're even run at all.
12
+ #
13
+ module NRSER::Labs; end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Requirements
4
+ # =======================================================================
5
+
6
+ # Stdlib
7
+ # -----------------------------------------------------------------------
8
+
9
+ # Deps
10
+ # -----------------------------------------------------------------------
11
+
12
+ # Project / Package
13
+ # -----------------------------------------------------------------------
14
+
15
+
16
+ # Refinements
17
+ # =======================================================================
18
+
19
+
20
+ # Declarations
21
+ # =======================================================================
22
+
23
+ module NRSER::Labs; end
24
+
25
+
26
+ # Definitions
27
+ # =======================================================================
28
+
29
+
30
+ # @todo document NRSER::Labs::Globlin class.
31
+ class NRSER::Labs::Globlin
32
+
33
+
34
+ # @todo document Matcher class.
35
+ class Matcher
36
+ def match entry
37
+ if entry.is_a?( NRSER::Globlin )
38
+
39
+ else
40
+
41
+ end
42
+ end
43
+ end # class Matcher
44
+
45
+
46
+ # Constants
47
+ # ======================================================================
48
+
49
+
50
+ # Class Methods
51
+ # ======================================================================
52
+
53
+
54
+ # Attributes
55
+ # ======================================================================
56
+
57
+
58
+ # Constructor
59
+ # ======================================================================
60
+
61
+ # Instantiate a new `NRSER:Globlin`.
62
+ def initialize split:, ignore: nil
63
+ @split = Array split
64
+
65
+
66
+ end # #initialize
67
+
68
+
69
+ # Instance Methods
70
+ # ======================================================================
71
+
72
+ def matcher_for search_string
73
+ @split.each
74
+ end
75
+
76
+
77
+ def find_only! search_string
78
+ matcher = matcher_for search_string
79
+
80
+ # Search entries that have the same seg count first
81
+ found = @seg_count_index[matcher.seg_count].find_all_map { |entry|
82
+ matcher.match entry
83
+ }
84
+
85
+ case found.length
86
+ when 0
87
+ # move on..
88
+ when 1
89
+ return found[0]
90
+ else
91
+ raise TooManyError.new found
92
+ end
93
+
94
+ # Ok, try slice matches for entries with *more* segments only
95
+ slice_matches = @seg_count_index.keys.
96
+ select { |count| count > matcher.seg_count }.
97
+ map { |key| @seg_count_index[key] }.
98
+ reduce( :+ ).
99
+ select { |entry|
100
+ matcher.match_slice entry
101
+ }
102
+
103
+
104
+ end
105
+
106
+ end # class NRSER::Labs::Globlin