nrser 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/nrser.rb +10 -12
- data/lib/nrser/ext.rb +1 -0
- data/lib/nrser/ext/enumerable.rb +6 -0
- data/lib/nrser/ext/string.rb +62 -0
- data/lib/nrser/functions/enumerable.rb +1 -0
- data/lib/nrser/functions/enumerable/include_slice.rb +84 -0
- data/lib/nrser/functions/enumerable/include_slice/array_include_slice.rb +80 -0
- data/lib/nrser/functions/text.rb +1 -0
- data/lib/nrser/functions/text/words.rb +23 -0
- data/lib/nrser/labs.rb +13 -0
- data/lib/nrser/labs/globlin.rb +106 -0
- data/lib/nrser/labs/index.rb +89 -0
- data/lib/nrser/{temp → labs}/unicode_math.rb +2 -2
- data/lib/nrser/{temp → labs}/where.rb +2 -4
- data/lib/nrser/meta/props.rb +13 -7
- data/lib/nrser/meta/props/prop.rb +144 -86
- data/lib/nrser/refinements/exception.rb +2 -2
- data/lib/nrser/refinements/string.rb +1 -51
- data/lib/nrser/rspex/example_group/describe_spec_file.rb +20 -0
- data/lib/nrser/version.rb +21 -1
- data/spec/nrser/functions/enumerable/include_slice_spec.rb +28 -0
- data/spec/nrser/functions/text/words_spec.rb +17 -0
- data/spec/nrser/labs/globlin_spec.rb +61 -0
- data/spec/nrser/labs/index_spec.rb +87 -0
- data/spec/spec_helper.rb +16 -0
- metadata +19 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 10930bb8b3998cc81f95333c8eb86a102262d84e
|
4
|
+
data.tar.gz: ff5057aead5992fe1d053e814afd120278b80a4c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f64f47ddbbb195eb13f072aec1f0beb8ff8299dbf9bc40838a2dcb078fd401fc03509c6566f497041ca0b3d5fc95f4b0baee0e7cb390e7238182a0e14e51ee50
|
7
|
+
data.tar.gz: ba2da8fe57e5d3e9f2c1439fa978957327982624c1a536b1bbf950901783d66808c44042d0f01f4ce7c8ec4333a93fb29904878c3165bc010dd099eddd864265
|
data/lib/nrser.rb
CHANGED
@@ -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
|
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
|
-
#
|
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
|
-
#
|
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'
|
data/lib/nrser/ext.rb
CHANGED
data/lib/nrser/ext/enumerable.rb
CHANGED
@@ -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
|
@@ -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
|
data/lib/nrser/functions/text.rb
CHANGED
@@ -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
|
data/lib/nrser/labs.rb
ADDED
@@ -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
|