thefox-ext 1.9.0 → 2.0.0
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 +4 -4
- data/.github/workflows/ci.yml +1 -1
- data/CHANGELOG-v1.md +5 -0
- data/CHANGELOG-v2.md +8 -0
- data/README.md +2 -3
- data/bin/dev +4 -7
- data/bin/test.sh +1 -0
- data/lib/thefox-ext.rb +13 -1
- data/lib/thefox-ext/ext/string.rb +0 -67
- data/lib/thefox-ext/range/lexer/base.rb +69 -0
- data/lib/thefox-ext/range/lexer/block.rb +10 -0
- data/lib/thefox-ext/range/lexer/block_down.rb +21 -0
- data/lib/thefox-ext/range/lexer/block_stack.rb +44 -0
- data/lib/thefox-ext/range/lexer/block_up.rb +21 -0
- data/lib/thefox-ext/range/lexer/interval.rb +32 -0
- data/lib/thefox-ext/range/lexer/lexer.rb +284 -0
- data/lib/thefox-ext/range/lexer/number.rb +56 -0
- data/lib/thefox-ext/range/lexer/operator.rb +20 -0
- data/lib/thefox-ext/range/lexer/range.rb +41 -0
- data/lib/thefox-ext/range/lexer/scope.rb +9 -0
- data/lib/thefox-ext/range/lexer/separator.rb +19 -0
- data/lib/thefox-ext/range/resolver.rb +39 -0
- data/lib/thefox-ext/version.rb +2 -2
- data/thefox-ext.gemspec +2 -2
- metadata +20 -7
- data/lib/thefox-ext/ext/array.rb +0 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: da29c60568cd97ae87c97b6d299215f77c4ab55ad711bbae6793d762b441fcce
|
4
|
+
data.tar.gz: 1a31f430986f74719a80e3900152acfb7b714f553a1b26204dc6b615f2f7455e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f014e0cfd460e98cec083744b72a40bdd73d4b2558ce921c7ac003b0aad7eadd9f73deafc1a8bff5392206eabb51b9f8442b8f034c512227b4afc7ad94622bc
|
7
|
+
data.tar.gz: f559019dcc8cb52656b785b71db0fd91cfc786b7246b22c4b533a7b5584317ac9114f0b32c0de38c1a2ce277fe7ff8ec231fdbebb1e436b3c602d7775644957d
|
data/.github/workflows/ci.yml
CHANGED
data/CHANGELOG-v1.md
CHANGED
data/CHANGELOG-v2.md
ADDED
data/README.md
CHANGED
@@ -21,7 +21,7 @@ gem install thefox-ext
|
|
21
21
|
or via `Gemfile`:
|
22
22
|
|
23
23
|
```ruby
|
24
|
-
gem 'thefox-ext', '~>
|
24
|
+
gem 'thefox-ext', '~>2.0'
|
25
25
|
```
|
26
26
|
|
27
27
|
Use it in your sources:
|
@@ -40,10 +40,9 @@ require 'thefox-ext'
|
|
40
40
|
- Date
|
41
41
|
- `today?`
|
42
42
|
- Get week array for a specific date.
|
43
|
-
- Array
|
44
|
-
- Range String Resolver
|
45
43
|
- Hash
|
46
44
|
- Recursive Merge
|
45
|
+
- Range String Resolver
|
47
46
|
|
48
47
|
## Project Links
|
49
48
|
|
data/bin/dev
CHANGED
@@ -4,10 +4,7 @@
|
|
4
4
|
require 'thefox-ext'
|
5
5
|
require 'pp'
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
# pp '3, 4'.resolve_range()
|
12
|
-
# pp '3, 4'.resolve_range()
|
13
|
-
# pp '3, 4'.resolve_range2()
|
7
|
+
s = '99-110/4'
|
8
|
+
s = '99-110/*'
|
9
|
+
rr = TheFox::Range::Resolver.new(s)
|
10
|
+
pp rr.to_a
|
data/bin/test.sh
CHANGED
data/lib/thefox-ext.rb
CHANGED
@@ -8,6 +8,18 @@ require 'thefox-ext/ext/integer'
|
|
8
8
|
require 'thefox-ext/ext/nil'
|
9
9
|
require 'thefox-ext/ext/string'
|
10
10
|
require 'thefox-ext/ext/true'
|
11
|
-
require 'thefox-ext/ext/array'
|
12
11
|
|
13
12
|
require 'thefox-ext/console'
|
13
|
+
require 'thefox-ext/range/resolver'
|
14
|
+
require 'thefox-ext/range/lexer/lexer'
|
15
|
+
require 'thefox-ext/range/lexer/base'
|
16
|
+
require 'thefox-ext/range/lexer/scope'
|
17
|
+
require 'thefox-ext/range/lexer/separator'
|
18
|
+
require 'thefox-ext/range/lexer/operator'
|
19
|
+
require 'thefox-ext/range/lexer/block'
|
20
|
+
require 'thefox-ext/range/lexer/block_down'
|
21
|
+
require 'thefox-ext/range/lexer/block_up'
|
22
|
+
require 'thefox-ext/range/lexer/block_stack'
|
23
|
+
require 'thefox-ext/range/lexer/range'
|
24
|
+
require 'thefox-ext/range/lexer/interval'
|
25
|
+
require 'thefox-ext/range/lexer/number'
|
@@ -63,71 +63,4 @@ class String
|
|
63
63
|
self.force_encoding('ISO-8859-1').encode('UTF-8')
|
64
64
|
end
|
65
65
|
end
|
66
|
-
|
67
|
-
# Resolve a range string to an array.
|
68
|
-
# A range string can be like '1, 3..5, 9-11, 12+, 14++, 17+++'.
|
69
|
-
# Which will be resolved to [1, 3, 4, 5, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20].
|
70
|
-
def resolve_range(prefix = '')
|
71
|
-
# puts '-> resolve_range: %s {%s}' % [self, prefix]
|
72
|
-
|
73
|
-
rv = Array.new
|
74
|
-
|
75
|
-
items1 = self.split(',')
|
76
|
-
# pp items1
|
77
|
-
|
78
|
-
items2 = []
|
79
|
-
is_sub_range = false
|
80
|
-
sub_item = []
|
81
|
-
items1.each do |item|
|
82
|
-
if item.count('{') > 0
|
83
|
-
is_sub_range = true
|
84
|
-
end
|
85
|
-
if is_sub_range
|
86
|
-
sub_item.push(item)
|
87
|
-
else
|
88
|
-
items2.push(item)
|
89
|
-
end
|
90
|
-
if item.count('}') > 0
|
91
|
-
is_sub_range = false
|
92
|
-
items2.push(sub_item.join(','))
|
93
|
-
sub_item = []
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
# pp items2
|
98
|
-
|
99
|
-
items2.map{ |item|
|
100
|
-
item_striped = item.strip
|
101
|
-
if range_match = item_striped.match(/(\d+)\{([\d\-\+,]+)\}/)
|
102
|
-
range_match[2].resolve_range(range_match[1])
|
103
|
-
elsif /\.\./.match(item_striped) # ( . )( . ) <--- BOOBS
|
104
|
-
Range.new(*item_striped.split('..', 2).map{ |range| range.to_i })
|
105
|
-
elsif /-/.match(item_striped)
|
106
|
-
Range.new(*item_striped.split('-', 2).map{ |range| range.to_i })
|
107
|
-
elsif /\+/.match(item_striped)
|
108
|
-
items = item_striped.split('+')
|
109
|
-
range_begin = items[0].to_i
|
110
|
-
range_end = range_begin + item_striped.count('+')
|
111
|
-
Range.new(range_begin, range_end)
|
112
|
-
else
|
113
|
-
item_striped.to_i
|
114
|
-
end
|
115
|
-
}.each{ |range|
|
116
|
-
if range.is_a?(Range)
|
117
|
-
rv.push(*range.to_a)
|
118
|
-
elsif range.is_a?(Array)
|
119
|
-
rv.push(*range)
|
120
|
-
else
|
121
|
-
rv << range
|
122
|
-
end
|
123
|
-
}
|
124
|
-
|
125
|
-
if !prefix.empty?
|
126
|
-
rv = rv.map { |i|
|
127
|
-
(prefix + i.to_s).to_i
|
128
|
-
}
|
129
|
-
end
|
130
|
-
|
131
|
-
rv
|
132
|
-
end
|
133
66
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
|
2
|
+
module TheFox
|
3
|
+
module Range
|
4
|
+
module Lexer
|
5
|
+
class Base
|
6
|
+
def initialize(symbole = nil)
|
7
|
+
# puts '-> Base.initialize'
|
8
|
+
@symbole = symbole
|
9
|
+
@prev_item = nil
|
10
|
+
@next_item = nil
|
11
|
+
|
12
|
+
@parent_item = nil
|
13
|
+
@children = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def chain(item)
|
17
|
+
self.next_item = item
|
18
|
+
item.prev_item = self
|
19
|
+
end
|
20
|
+
|
21
|
+
def symbole()
|
22
|
+
@symbole
|
23
|
+
end
|
24
|
+
|
25
|
+
def prev_item()
|
26
|
+
@prev_item
|
27
|
+
end
|
28
|
+
def prev_item=(prev_item)
|
29
|
+
@prev_item = prev_item
|
30
|
+
end
|
31
|
+
|
32
|
+
def next_item()
|
33
|
+
@next_item
|
34
|
+
end
|
35
|
+
def next_item=(next_item)
|
36
|
+
@next_item = next_item
|
37
|
+
end
|
38
|
+
|
39
|
+
def parent_item()
|
40
|
+
@parent_item
|
41
|
+
end
|
42
|
+
def parent_item=(parent_item)
|
43
|
+
@parent_item = parent_item
|
44
|
+
end
|
45
|
+
def has_parent_item()
|
46
|
+
!@parent_item.nil?
|
47
|
+
end
|
48
|
+
|
49
|
+
def children()
|
50
|
+
@children
|
51
|
+
end
|
52
|
+
def add_child(child)
|
53
|
+
@children.push(child)
|
54
|
+
end
|
55
|
+
def has_children()
|
56
|
+
@children.length > 1
|
57
|
+
end
|
58
|
+
|
59
|
+
def dup()
|
60
|
+
# puts '-> Base.dup'
|
61
|
+
o = super()
|
62
|
+
o.prev_item = nil
|
63
|
+
o.next_item = nil
|
64
|
+
o
|
65
|
+
end
|
66
|
+
end # Base
|
67
|
+
end # Lexer
|
68
|
+
end # Range
|
69
|
+
end # TheFox
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
module TheFox
|
3
|
+
module Range
|
4
|
+
module Lexer
|
5
|
+
# {
|
6
|
+
class BlockDown < Block
|
7
|
+
def initialize(level)
|
8
|
+
super()
|
9
|
+
# puts '-> BlockDown.initialize(%d)' % [level]
|
10
|
+
@level = level
|
11
|
+
end
|
12
|
+
|
13
|
+
# :nocov:
|
14
|
+
def inspect()
|
15
|
+
'BlockDown(%d)' % [@level]
|
16
|
+
end
|
17
|
+
# :nocov:
|
18
|
+
end # BlockDown
|
19
|
+
end # Lexer
|
20
|
+
end # Range
|
21
|
+
end # TheFox
|
@@ -0,0 +1,44 @@
|
|
1
|
+
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
module TheFox
|
5
|
+
module Range
|
6
|
+
module Lexer
|
7
|
+
# 0123456789
|
8
|
+
class BlockStack
|
9
|
+
def initialize()
|
10
|
+
# puts '-> BlockStack.initialize()'
|
11
|
+
@stack = []
|
12
|
+
end
|
13
|
+
|
14
|
+
# :nocov:
|
15
|
+
def inspect()
|
16
|
+
'BlockStack(%d)' % [@stack.length]
|
17
|
+
end
|
18
|
+
# :nocov:
|
19
|
+
|
20
|
+
def push(item)
|
21
|
+
@stack.push(item)
|
22
|
+
end
|
23
|
+
|
24
|
+
def pop()
|
25
|
+
@stack.pop
|
26
|
+
end
|
27
|
+
|
28
|
+
def curr()
|
29
|
+
@stack.last
|
30
|
+
end
|
31
|
+
|
32
|
+
def length()
|
33
|
+
@stack.length
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_child(item)
|
37
|
+
if !@stack.last.nil? && !item.nil?
|
38
|
+
@stack.last.add_child(item)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end # BlockStack
|
42
|
+
end # Lexer
|
43
|
+
end # Range
|
44
|
+
end # TheFox
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
module TheFox
|
3
|
+
module Range
|
4
|
+
module Lexer
|
5
|
+
# }
|
6
|
+
class BlockUp < Block
|
7
|
+
def initialize(level)
|
8
|
+
super()
|
9
|
+
# puts '-> BlockUp.initialize(%d)' % [level]
|
10
|
+
@level = level
|
11
|
+
end
|
12
|
+
|
13
|
+
# :nocov:
|
14
|
+
def inspect()
|
15
|
+
'BlockUp(%d)' % [@level]
|
16
|
+
end
|
17
|
+
# :nocov:
|
18
|
+
end # BlockUp
|
19
|
+
end # Lexer
|
20
|
+
end # Range
|
21
|
+
end # TheFox
|
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
module TheFox
|
3
|
+
module Range
|
4
|
+
module Lexer
|
5
|
+
# /n
|
6
|
+
class Interval < Base
|
7
|
+
def initialize()
|
8
|
+
super()
|
9
|
+
# puts '-> Interval.initialize()'
|
10
|
+
@number = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
# :nocov:
|
14
|
+
def inspect()
|
15
|
+
if @number.nil?
|
16
|
+
'Interval()'
|
17
|
+
else
|
18
|
+
'Interval(%s)' % [@number.inspect]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
# :nocov:
|
22
|
+
|
23
|
+
def number=(number)
|
24
|
+
@number = number
|
25
|
+
end
|
26
|
+
def number()
|
27
|
+
@number
|
28
|
+
end
|
29
|
+
end # Interval
|
30
|
+
end # Lexer
|
31
|
+
end # Range
|
32
|
+
end # TheFox
|
@@ -0,0 +1,284 @@
|
|
1
|
+
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
module TheFox
|
5
|
+
module Range
|
6
|
+
module Lexer
|
7
|
+
class Lexer
|
8
|
+
def initialize(chars)
|
9
|
+
# puts '-> Lexer.initialize'
|
10
|
+
@chars = chars
|
11
|
+
# pp @chars
|
12
|
+
end
|
13
|
+
|
14
|
+
def resolve()
|
15
|
+
# puts
|
16
|
+
# puts '-> Lexer.resolve L1'
|
17
|
+
|
18
|
+
position = 0
|
19
|
+
prev_item = nil
|
20
|
+
block_level = 0
|
21
|
+
items1 = []
|
22
|
+
@chars.each do |char|
|
23
|
+
position += 1
|
24
|
+
|
25
|
+
curr_item = case char
|
26
|
+
when ','
|
27
|
+
Separator.new()
|
28
|
+
when '{'
|
29
|
+
block_level += 1
|
30
|
+
BlockDown.new(block_level)
|
31
|
+
when '}'
|
32
|
+
org_level = block_level
|
33
|
+
block_level -= 1
|
34
|
+
BlockUp.new(org_level)
|
35
|
+
when '+'
|
36
|
+
Operator.new()
|
37
|
+
when '-', '.'
|
38
|
+
Range.new(char)
|
39
|
+
when '/'
|
40
|
+
Interval.new()
|
41
|
+
when '0'..'9'
|
42
|
+
Number.new(char)
|
43
|
+
else
|
44
|
+
raise 'Unknown character at position %d: %s' % [position, char]
|
45
|
+
end
|
46
|
+
|
47
|
+
if !prev_item.nil?
|
48
|
+
prev_item.chain(curr_item)
|
49
|
+
end
|
50
|
+
items1.push(curr_item)
|
51
|
+
prev_item = curr_item
|
52
|
+
end
|
53
|
+
|
54
|
+
# pp items1.map{ |item| item.inspect }
|
55
|
+
|
56
|
+
# puts
|
57
|
+
# puts '-> Lexer.resolve L2'
|
58
|
+
curr_item = nil
|
59
|
+
prev_item = nil
|
60
|
+
items2 = []
|
61
|
+
items1.each do |item|
|
62
|
+
# puts '--> L2 item: %s' % [item.inspect]
|
63
|
+
|
64
|
+
append_dup = false
|
65
|
+
|
66
|
+
case item
|
67
|
+
when Number
|
68
|
+
if curr_item.nil?
|
69
|
+
# New Number
|
70
|
+
curr_item = item.dup
|
71
|
+
if !prev_item.nil?
|
72
|
+
prev_item.chain(curr_item)
|
73
|
+
end
|
74
|
+
items2.push(curr_item)
|
75
|
+
prev_item = curr_item
|
76
|
+
else
|
77
|
+
# Append Number
|
78
|
+
if curr_item.is_a?(Number)
|
79
|
+
curr_item.append(item.char)
|
80
|
+
else
|
81
|
+
raise 'Do not know what to do'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
when Range
|
85
|
+
if prev_item.is_a?(Range) && prev_item.symbole == '.' && item.symbole == '.'
|
86
|
+
# skip
|
87
|
+
else
|
88
|
+
append_dup = true
|
89
|
+
end
|
90
|
+
else
|
91
|
+
# puts '--> L2 ELSE'
|
92
|
+
|
93
|
+
append_dup = true
|
94
|
+
end
|
95
|
+
|
96
|
+
if append_dup
|
97
|
+
curr_item = item.dup
|
98
|
+
if !prev_item.nil?
|
99
|
+
prev_item.chain(curr_item)
|
100
|
+
end
|
101
|
+
items2.push(curr_item)
|
102
|
+
prev_item = curr_item
|
103
|
+
|
104
|
+
curr_item = nil
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# pp items2.map{ |item| item.inspect }
|
109
|
+
|
110
|
+
# puts
|
111
|
+
# puts '-> Lexer.resolve L3'
|
112
|
+
append_dub_f = nil
|
113
|
+
append_prev_f = nil
|
114
|
+
prev_item = nil
|
115
|
+
block_stack = BlockStack.new
|
116
|
+
items3 = []
|
117
|
+
items2.each do |item|
|
118
|
+
# puts '--> L3 %20s bs=%d' % [item.inspect, block_stack.length]
|
119
|
+
|
120
|
+
append_dup = false
|
121
|
+
append_prev = false
|
122
|
+
|
123
|
+
case item
|
124
|
+
when Number
|
125
|
+
if item.next_item.is_a?(Range) || item.prev_item.is_a?(Range) || item.prev_item.is_a?(Interval)
|
126
|
+
# skip
|
127
|
+
else
|
128
|
+
append_dup = true
|
129
|
+
end
|
130
|
+
when Range
|
131
|
+
if item.prev_item.is_a?(Number) && item.next_item.is_a?(Number)
|
132
|
+
# puts '--> Range normal'
|
133
|
+
append_dub_f = -> (curr_item){
|
134
|
+
curr_item.left_item = item.prev_item.dup
|
135
|
+
curr_item.right_item = item.next_item.dup
|
136
|
+
|
137
|
+
curr_item.left_item.parent_item = block_stack.curr
|
138
|
+
curr_item.right_item.parent_item = block_stack.curr
|
139
|
+
|
140
|
+
block_stack.add_child(curr_item.left_item)
|
141
|
+
block_stack.add_child(curr_item.right_item)
|
142
|
+
}
|
143
|
+
append_dup = true
|
144
|
+
else
|
145
|
+
raise 'Invalid Range: %s %s' % [
|
146
|
+
item.prev_item.inspect,
|
147
|
+
item.next_item.inspect,
|
148
|
+
]
|
149
|
+
end
|
150
|
+
when Interval
|
151
|
+
if !item.next_item.is_a?(Number)
|
152
|
+
raise 'Invalid Interval: %s' % [item.next_item.inspect]
|
153
|
+
end
|
154
|
+
|
155
|
+
append_dub_f = ->(curr_item){ curr_item.number = item.next_item.dup }
|
156
|
+
append_dup = true
|
157
|
+
when Operator
|
158
|
+
if prev_item.is_a?(Number)
|
159
|
+
append_prev_f = -> (curr_item){ curr_item.inc }
|
160
|
+
append_prev = true
|
161
|
+
end
|
162
|
+
when BlockDown
|
163
|
+
#block_stack.push(item.dup)
|
164
|
+
append_dub_f = ->(curr_item){ block_stack.push(curr_item) }
|
165
|
+
append_dup = true
|
166
|
+
when BlockUp
|
167
|
+
block_stack.pop
|
168
|
+
append_dup = true
|
169
|
+
else
|
170
|
+
# puts '--> L3 ELSE'
|
171
|
+
append_dup = true
|
172
|
+
end
|
173
|
+
|
174
|
+
# Append Dup
|
175
|
+
if append_dup
|
176
|
+
# Dup
|
177
|
+
curr_item = item.dup
|
178
|
+
# Function
|
179
|
+
if !append_dub_f.nil?
|
180
|
+
append_dub_f.call(curr_item)
|
181
|
+
append_dub_f = nil
|
182
|
+
end
|
183
|
+
# Chain
|
184
|
+
if !prev_item.nil?
|
185
|
+
prev_item.chain(curr_item)
|
186
|
+
end
|
187
|
+
# Block
|
188
|
+
if !item.is_a?(Block)
|
189
|
+
# puts '---> set Parent: %s' % [block_stack.curr.inspect]
|
190
|
+
curr_item.parent_item = block_stack.curr
|
191
|
+
block_stack.add_child(curr_item)
|
192
|
+
end
|
193
|
+
# Append
|
194
|
+
items3.push(curr_item)
|
195
|
+
# Prev Item
|
196
|
+
prev_item = curr_item
|
197
|
+
end
|
198
|
+
|
199
|
+
# Append Prev
|
200
|
+
if append_prev && !prev_item.nil?
|
201
|
+
# Dup
|
202
|
+
curr_item = prev_item.dup
|
203
|
+
# Function
|
204
|
+
if !append_prev_f.nil?
|
205
|
+
append_prev_f.call(curr_item)
|
206
|
+
append_prev_f = nil
|
207
|
+
end
|
208
|
+
# Chain
|
209
|
+
prev_item.chain(curr_item)
|
210
|
+
# Block
|
211
|
+
if !item.is_a?(Block)
|
212
|
+
curr_item.parent_item = block_stack.curr
|
213
|
+
block_stack.add_child(curr_item)
|
214
|
+
end
|
215
|
+
# Append
|
216
|
+
items3.push(curr_item)
|
217
|
+
# Prev Item
|
218
|
+
prev_item = curr_item
|
219
|
+
end
|
220
|
+
|
221
|
+
# Block
|
222
|
+
if item.is_a?(Block)
|
223
|
+
# puts '--> L3 set parent block for block'
|
224
|
+
item.parent_item = block_stack.curr
|
225
|
+
block_stack.add_child(item)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
# pp items3.map{ |item| item.inspect }
|
230
|
+
|
231
|
+
# puts
|
232
|
+
# puts '-> Lexer.resolve L4 [convert to int]'
|
233
|
+
items4 = []
|
234
|
+
items3.each do |item|
|
235
|
+
# puts '--> L4 %20s %20s c: %d' % [item.inspect, item.parent_item.inspect, item.children.length]
|
236
|
+
|
237
|
+
case item
|
238
|
+
when Number
|
239
|
+
if item.next_item.is_a?(BlockDown)
|
240
|
+
# skip
|
241
|
+
# puts '---> skip'
|
242
|
+
else
|
243
|
+
items4.push(item.char.to_i)
|
244
|
+
end
|
245
|
+
when Range
|
246
|
+
r_begin = item.left_item.char.to_i
|
247
|
+
r_end = item.right_item.char.to_i
|
248
|
+
r = ::Range.new(r_begin, r_end)
|
249
|
+
|
250
|
+
if item.next_item.is_a?(Interval)
|
251
|
+
# Interval Range
|
252
|
+
n = item.next_item.number.char.to_i
|
253
|
+
c = 0
|
254
|
+
r.each do |i|
|
255
|
+
if c == 0
|
256
|
+
items4.push(i)
|
257
|
+
end
|
258
|
+
c += 1
|
259
|
+
if c == n
|
260
|
+
c = 0
|
261
|
+
end
|
262
|
+
end
|
263
|
+
else
|
264
|
+
# Normal Range
|
265
|
+
items4.push(*r.to_a)
|
266
|
+
end
|
267
|
+
when Interval
|
268
|
+
# puts '---> skip Interval'
|
269
|
+
when Separator
|
270
|
+
# puts '---> skip Separator'
|
271
|
+
when Block
|
272
|
+
# puts '---> skip Block'
|
273
|
+
else
|
274
|
+
raise 'Implementation missing for: %s' % [item.inspect]
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
# pp items4
|
279
|
+
items4
|
280
|
+
end
|
281
|
+
end # Lexer
|
282
|
+
end # Lexer
|
283
|
+
end # Range
|
284
|
+
end # TheFox
|
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
module TheFox
|
5
|
+
module Range
|
6
|
+
module Lexer
|
7
|
+
# 0123456789
|
8
|
+
class Number < Base
|
9
|
+
def initialize(char)
|
10
|
+
super()
|
11
|
+
# puts '-> Number.initialize(%s)' % [char]
|
12
|
+
@char = char
|
13
|
+
end
|
14
|
+
|
15
|
+
# :nocov:
|
16
|
+
def inspect()
|
17
|
+
'Number(%s,^%s)' % [@char, @parent_item.inspect]
|
18
|
+
end
|
19
|
+
# :nocov:
|
20
|
+
|
21
|
+
def char()
|
22
|
+
# puts '-> %s.char' % [self.inspect]
|
23
|
+
if self.has_parent_item
|
24
|
+
# puts '-> %s.char has parent' % [self.inspect]
|
25
|
+
if self.parent_item.is_a?(Block)
|
26
|
+
# puts '-> %s.char parent is a %s' % [self.inspect, self.parent_item.inspect]
|
27
|
+
if self.parent_item.prev_item.is_a?(Number)
|
28
|
+
# puts '-> %s.char parent Prev is a %s' % [self.inspect, self.parent_item.prev_item.inspect]
|
29
|
+
'%s%s' % [self.parent_item.prev_item.char, @char]
|
30
|
+
else
|
31
|
+
raise 'Parent Prev item for %s is not a Block: %s' % [
|
32
|
+
self.inspect,
|
33
|
+
self.parent_item.prev_item.inspect,
|
34
|
+
]
|
35
|
+
end
|
36
|
+
else
|
37
|
+
raise 'Parent item for %s is not a Block: %s' % [self.inspect, self.parent_item.inspect]
|
38
|
+
end
|
39
|
+
else
|
40
|
+
# puts '-> %s.char char' % [self.inspect]
|
41
|
+
@char
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def append(char)
|
46
|
+
@char += char
|
47
|
+
end
|
48
|
+
|
49
|
+
def inc()
|
50
|
+
f = '%%0%dd' % [@char.length]
|
51
|
+
@char = f % [@char.to_i + 1]
|
52
|
+
end
|
53
|
+
end # Number
|
54
|
+
end # Lexer
|
55
|
+
end # Range
|
56
|
+
end # TheFox
|
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
module TheFox
|
3
|
+
module Range
|
4
|
+
module Lexer
|
5
|
+
# +
|
6
|
+
class Operator < Base
|
7
|
+
def initialize()
|
8
|
+
super()
|
9
|
+
# puts '-> Operator.initialize'
|
10
|
+
end
|
11
|
+
|
12
|
+
# :nocov:
|
13
|
+
def inspect()
|
14
|
+
'Operator()'
|
15
|
+
end
|
16
|
+
# :nocov:
|
17
|
+
end # Operator
|
18
|
+
end # Lexer
|
19
|
+
end # Range
|
20
|
+
end # TheFox
|
@@ -0,0 +1,41 @@
|
|
1
|
+
|
2
|
+
module TheFox
|
3
|
+
module Range
|
4
|
+
module Lexer
|
5
|
+
# -
|
6
|
+
class Range < Base
|
7
|
+
def initialize(symbole)
|
8
|
+
super(symbole)
|
9
|
+
# puts '-> Range.initialize(%s)' % [symbole]
|
10
|
+
|
11
|
+
@left_item = nil
|
12
|
+
@right_item = nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def left_item()
|
16
|
+
@left_item
|
17
|
+
end
|
18
|
+
def left_item=(left_item)
|
19
|
+
@left_item = left_item
|
20
|
+
end
|
21
|
+
|
22
|
+
def right_item()
|
23
|
+
@right_item
|
24
|
+
end
|
25
|
+
def right_item=(right_item)
|
26
|
+
@right_item = right_item
|
27
|
+
end
|
28
|
+
|
29
|
+
# :nocov:
|
30
|
+
def inspect()
|
31
|
+
if !@left_item.nil? && !@right_item.nil?
|
32
|
+
'Range(%s, %s, %s)' % [@symbole, @left_item.inspect, @right_item.inspect]
|
33
|
+
else
|
34
|
+
'Range(%s)' % [@symbole]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
# :nocov:
|
38
|
+
end # Range
|
39
|
+
end # Lexer
|
40
|
+
end # Range
|
41
|
+
end # TheFox
|
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
module TheFox
|
3
|
+
module Range
|
4
|
+
module Lexer
|
5
|
+
class Separator < Scope
|
6
|
+
def initialize()
|
7
|
+
super()
|
8
|
+
# puts '-> Separator.initialize()'
|
9
|
+
end
|
10
|
+
|
11
|
+
# :nocov:
|
12
|
+
def inspect()
|
13
|
+
'Separator'
|
14
|
+
end
|
15
|
+
# :nocov:
|
16
|
+
end # Separator
|
17
|
+
end # Lexer
|
18
|
+
end # Range
|
19
|
+
end # TheFox
|
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
module TheFox
|
5
|
+
module Range
|
6
|
+
# Resolve a range string to an array.
|
7
|
+
# A range string can be like '1, 3..5, 9-11, 12+, 14++, 17+++'.
|
8
|
+
# Which will be resolved to [1, 3, 4, 5, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20].
|
9
|
+
# '1' -> [1]
|
10
|
+
# '1,3,99' -> [1, 3, 99]
|
11
|
+
# '1-5' -> [1, 2, 3, 4, 5]
|
12
|
+
# '1+,5++' -> [1, 2, 5, 6, 7]
|
13
|
+
# '1-10/2' -> [1, 3, 5, 7, 9]
|
14
|
+
# '1{1}' -> [11]
|
15
|
+
# '1{5-7}' -> [15, 16, 17]
|
16
|
+
# '1{1,02}' -> [11, 102]
|
17
|
+
# '2{3{4,5},6}' -> [234, 235, 26]
|
18
|
+
# '1-3/1' -> [1, 2, 3]
|
19
|
+
# '1-10/2' -> [1, 3, 5, 7, 9]
|
20
|
+
# '2{10-20/2}' -> [210, 212, 214, 216, 218, 220]
|
21
|
+
class Resolver
|
22
|
+
def initialize(original = nil)
|
23
|
+
# puts '-> TheFox::Range::Resolver.initialize'
|
24
|
+
@original = original
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_a
|
28
|
+
# puts '-> TheFox::Range::Resolver.to_a'
|
29
|
+
|
30
|
+
if @original.is_a?(String)
|
31
|
+
lexer = Lexer::Lexer.new(@original.split(''))
|
32
|
+
lexer.resolve
|
33
|
+
else
|
34
|
+
[]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end # Resolver
|
38
|
+
end # Range
|
39
|
+
end # TheFox
|
data/lib/thefox-ext/version.rb
CHANGED
data/thefox-ext.gemspec
CHANGED
@@ -19,9 +19,9 @@ Gem::Specification.new do |spec|
|
|
19
19
|
|
20
20
|
spec.files = `git ls-files -z`.split("\x0").reject{ |f| f.match(%r{^(test|spec|features)/}) }
|
21
21
|
spec.require_paths = ['lib']
|
22
|
-
spec.required_ruby_version = ['>=2.
|
22
|
+
spec.required_ruby_version = ['>=2.4.0']
|
23
23
|
|
24
24
|
spec.add_development_dependency 'minitest', '~>5.8'
|
25
|
-
spec.add_development_dependency 'simplecov', '~>0.
|
25
|
+
spec.add_development_dependency 'simplecov', '~>0.18'
|
26
26
|
spec.add_development_dependency 'simplecov-phpunit', '~>1.0'
|
27
27
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thefox-ext
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christian Mayer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-04-
|
11
|
+
date: 2021-04-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '0.
|
33
|
+
version: '0.18'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '0.
|
40
|
+
version: '0.18'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: simplecov-phpunit
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -64,6 +64,7 @@ files:
|
|
64
64
|
- ".github/workflows/release.yml"
|
65
65
|
- ".gitignore"
|
66
66
|
- CHANGELOG-v1.md
|
67
|
+
- CHANGELOG-v2.md
|
67
68
|
- Gemfile
|
68
69
|
- LICENSE
|
69
70
|
- README.md
|
@@ -75,7 +76,6 @@ files:
|
|
75
76
|
- bin/uninstall.sh
|
76
77
|
- lib/thefox-ext.rb
|
77
78
|
- lib/thefox-ext/console.rb
|
78
|
-
- lib/thefox-ext/ext/array.rb
|
79
79
|
- lib/thefox-ext/ext/date.rb
|
80
80
|
- lib/thefox-ext/ext/false.rb
|
81
81
|
- lib/thefox-ext/ext/hash.rb
|
@@ -83,6 +83,19 @@ files:
|
|
83
83
|
- lib/thefox-ext/ext/nil.rb
|
84
84
|
- lib/thefox-ext/ext/string.rb
|
85
85
|
- lib/thefox-ext/ext/true.rb
|
86
|
+
- lib/thefox-ext/range/lexer/base.rb
|
87
|
+
- lib/thefox-ext/range/lexer/block.rb
|
88
|
+
- lib/thefox-ext/range/lexer/block_down.rb
|
89
|
+
- lib/thefox-ext/range/lexer/block_stack.rb
|
90
|
+
- lib/thefox-ext/range/lexer/block_up.rb
|
91
|
+
- lib/thefox-ext/range/lexer/interval.rb
|
92
|
+
- lib/thefox-ext/range/lexer/lexer.rb
|
93
|
+
- lib/thefox-ext/range/lexer/number.rb
|
94
|
+
- lib/thefox-ext/range/lexer/operator.rb
|
95
|
+
- lib/thefox-ext/range/lexer/range.rb
|
96
|
+
- lib/thefox-ext/range/lexer/scope.rb
|
97
|
+
- lib/thefox-ext/range/lexer/separator.rb
|
98
|
+
- lib/thefox-ext/range/resolver.rb
|
86
99
|
- lib/thefox-ext/version.rb
|
87
100
|
- thefox-ext.code-workspace
|
88
101
|
- thefox-ext.gemspec
|
@@ -98,14 +111,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
98
111
|
requirements:
|
99
112
|
- - ">="
|
100
113
|
- !ruby/object:Gem::Version
|
101
|
-
version: 2.
|
114
|
+
version: 2.4.0
|
102
115
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
116
|
requirements:
|
104
117
|
- - ">="
|
105
118
|
- !ruby/object:Gem::Version
|
106
119
|
version: '0'
|
107
120
|
requirements: []
|
108
|
-
rubygems_version: 3.2.
|
121
|
+
rubygems_version: 3.2.15
|
109
122
|
signing_key:
|
110
123
|
specification_version: 4
|
111
124
|
summary: Extended Ruby Classes
|
data/lib/thefox-ext/ext/array.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
|
2
|
-
class Array
|
3
|
-
|
4
|
-
# DEPRECATED: will be removed in v1.10.0.
|
5
|
-
def self.resolve_range_str(original_str, prefix = '')
|
6
|
-
warn "[DEPRECATION] `Array.resolve_range_str` is deprecated. Please use `String.resolve_range` instead."
|
7
|
-
|
8
|
-
rv = Array.new
|
9
|
-
if !original_str.is_a?(String)
|
10
|
-
return rv
|
11
|
-
end
|
12
|
-
|
13
|
-
original_str.split(',').map{ |item|
|
14
|
-
item_striped = item.strip
|
15
|
-
if /\.\./.match(item_striped) # ( . )( . ) <--- BOOBS
|
16
|
-
Range.new(*item_striped.split('..', 2).map{ |range| range.to_i })
|
17
|
-
elsif /-/.match(item_striped)
|
18
|
-
Range.new(*item_striped.split('-', 2).map{ |range| range.to_i })
|
19
|
-
elsif /\+/.match(item_striped)
|
20
|
-
items = item_striped.split('+')
|
21
|
-
range_begin = items[0].to_i
|
22
|
-
range_end = range_begin + item_striped.count('+')
|
23
|
-
Range.new(range_begin, range_end)
|
24
|
-
else
|
25
|
-
item_striped.to_i
|
26
|
-
end
|
27
|
-
}.each{ |range|
|
28
|
-
if range.is_a?(Range)
|
29
|
-
rv.push(*range.to_a)
|
30
|
-
else
|
31
|
-
rv << range
|
32
|
-
end
|
33
|
-
}
|
34
|
-
|
35
|
-
rv
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|