rmtools 1.3.3 → 2.0.0.rc5
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.
- data/.gitignore +22 -0
- data/Gemfile +2 -0
- data/LICENSE +20 -14
- data/README.md +75 -24
- data/Rakefile +1 -37
- data/lib/rmtools/{db/active_record.rb → active_record/base.rb} +7 -3
- data/lib/rmtools/active_record/declarative.rb +153 -0
- data/lib/rmtools/conversions/enum.rb +14 -2
- data/lib/rmtools/{b.rb → core/b.rb} +9 -2
- data/lib/rmtools/core/class.rb +7 -0
- data/lib/rmtools/core/js.rb +13 -10
- data/lib/rmtools/core/kernel.rb +5 -3
- data/lib/rmtools/core/proc.rb +12 -3
- data/lib/rmtools/core/symbol.rb +22 -0
- data/lib/rmtools/db.rb +1 -1
- data/lib/rmtools/dev/highlight.rb +1 -1
- data/lib/rmtools/dev/logging.rb +17 -4
- data/lib/rmtools/dev/timer.rb +6 -1
- data/lib/rmtools/dev/trace_format.rb +40 -9
- data/lib/rmtools/dev/{blackhole.rb → void.rb} +6 -4
- data/lib/rmtools/enumerable/array.rb +12 -2
- data/lib/rmtools/enumerable/array_iterators.rb +287 -44
- data/lib/rmtools/enumerable/hash.rb +1 -0
- data/lib/rmtools/enumerable/range.rb +128 -77
- data/lib/rmtools/enumerable/traversal.rb +2 -2
- data/lib/rmtools/functional/unfold.rb +6 -8
- data/lib/rmtools/rand/array.rb +16 -14
- data/lib/rmtools/time/{global.rb → helpers.rb} +0 -0
- data/lib/rmtools/version.rb +3 -0
- data/lib/rmtools.rb +10 -2
- data/lib/rmtools_dev.rb +3 -6
- data/rmtools.gemspec +28 -0
- metadata +103 -120
- data/Manifest.txt +0 -98
- data/lib/rmtools/dev/observing.rb +0 -115
- data/lib/rmtools/dev/traceback.rb +0 -41
- data/lib/rmtools/dev_min.rb +0 -2
- data/lib/rmtools/init.rb +0 -13
- data/lib/rmtools/ip.rb +0 -2
@@ -3,103 +3,143 @@ unless defined? Inf
|
|
3
3
|
Inf = 1.0/0
|
4
4
|
end
|
5
5
|
|
6
|
+
# Range in Ruby can have at least 2 meanings:
|
7
|
+
# 1) interval of real numbers
|
8
|
+
# (0...2).include? 1.6 # => true
|
9
|
+
# 2) lazy list of array indices (included integers):
|
10
|
+
# [0,1,2,3,4,5][1..4] # => [1, 2, 3, 4]
|
11
|
+
#
|
12
|
+
# There is some basic problems.
|
13
|
+
# 1) For the first way of using, Range doesn't have Set operations. Further more Range can not be complex.
|
14
|
+
# There is "intervals" gem that partially solves these problems, but it's arithmetic is not Set compatible:
|
15
|
+
# -Interval[1,2] # => Interval[-2, -1]
|
16
|
+
# instead of
|
17
|
+
# # => Interval[[-Inf, -2], [-1, +Inf]]
|
18
|
+
# 2) Hardly we can use Range second way, when it defined by non-integers:
|
19
|
+
# [0,1,2,3,4,5][1.9..4] # => [1, 2, 3, 4]
|
20
|
+
# (1.9...4.1).include? 4 # => true, BUT
|
21
|
+
# [0,1,2,3,4,5][1.9...4.1] # => [1, 2, 3]
|
22
|
+
#
|
23
|
+
# This extension leaves the first problem for a purpose of solving the second, saving the capability of a Range syntactic sugar. The present extension applies Set operations to ranges considered as lists of contained integers.
|
24
|
+
# It means:
|
25
|
+
# (x..y) equivalent (x...y+0.5) equivalent (x...y+1) equivalent [x, x+1, ..., y]
|
26
|
+
# Note quantity of dots (end exclusion)
|
6
27
|
class Range
|
7
28
|
|
8
|
-
|
9
|
-
|
10
|
-
# BUT
|
11
|
-
# -(1..2)
|
12
|
-
### => XRange(-∞..0, 3..∞)
|
13
|
-
# i.e. all excluding these: (0; 1], [1; 2], [2; 3)
|
14
|
-
def -@
|
15
|
-
self_begin = self.begin
|
16
|
-
self_begin -= 1 if Integer === self_begin
|
17
|
-
self_end = include_end.end
|
18
|
-
self_end += 1 if Integer === self_end
|
19
|
-
XRange(-Inf..self_begin, self_end..Inf)
|
29
|
+
def included_end
|
30
|
+
exclude_end? ? last.integer? ? last - 1 : last.to_i : last
|
20
31
|
end
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end_ = [self.include_end.end, range.include_end.end].min
|
25
|
-
beg > end_ ? nil : beg..end_
|
32
|
+
|
33
|
+
def include_end
|
34
|
+
exclude_end? ? first..included_end : self
|
26
35
|
end
|
27
36
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
37
|
+
# Since it's not represent an interval...
|
38
|
+
# (0..0).size # => 1 (equivalent list of one zero)
|
39
|
+
# (0...0).size # => 0 (equivalent empty list)
|
40
|
+
# There is no empty ranges with end included (since it includes at least an end, right?)
|
41
|
+
def size
|
42
|
+
exclude_end? ? (last - first).abs : (last - first).abs+1
|
43
|
+
end
|
44
|
+
|
45
|
+
def empty?
|
46
|
+
exclude_end? && last == first
|
34
47
|
end
|
35
48
|
|
49
|
+
def b
|
50
|
+
!empty? && self
|
51
|
+
end
|
52
|
+
|
53
|
+
# Let significant content of a range used this way be:
|
54
|
+
def integers
|
55
|
+
(first.ceil..included_end).to_a
|
56
|
+
end
|
57
|
+
alias :to_is :integers
|
58
|
+
|
59
|
+
# -(1..2)
|
60
|
+
# -(0.5..2.1)
|
61
|
+
# i.e. all excluding these lazy indices: [1, 2]
|
62
|
+
### => XRange(-∞..0, 3..∞)
|
63
|
+
def -@
|
64
|
+
XRange(-Inf..first.ceil-1, (exclude_end? && last.integer? ? last : last.to_i+1)..Inf)
|
65
|
+
end
|
66
|
+
|
67
|
+
def &(range)
|
68
|
+
return range & self if range.is XRange
|
69
|
+
fst = [first, range.first].max
|
70
|
+
lst = [included_end, range.included_end].min
|
71
|
+
fst > lst ? nil : fst..lst
|
72
|
+
end
|
36
73
|
|
37
74
|
# On the basis of #-@ for non-integers,
|
38
|
-
# (0..
|
39
|
-
|
40
|
-
|
41
|
-
### => XRange(0..0)
|
42
|
-
# (0..1) - (1.0..2)
|
43
|
-
### => XRange(0..1.0)
|
44
|
-
# (0..1.0) - (1.0..2)
|
45
|
-
### => XRange(0..1.0)
|
75
|
+
# (0..3) - (0.5..2.1)
|
76
|
+
# (0..3) - (1..2)
|
77
|
+
### => XRange(0..0, 3..3.0)
|
46
78
|
def -(range)
|
47
79
|
self & -range
|
48
80
|
end
|
49
81
|
|
50
|
-
|
51
|
-
|
52
|
-
|
82
|
+
alias :include_number? :include?
|
83
|
+
# This function corresponds with ruby's default one in that we consider any number as a point on a segment.
|
84
|
+
# Thus, any of these 0..1, 0..1.0
|
85
|
+
# would return true as for 1 so as for 1.0
|
86
|
+
def include?(number_or_range)
|
87
|
+
if Numeric === number_or_range
|
88
|
+
include_number? number_or_range
|
89
|
+
elsif XRange === number_or_range
|
90
|
+
number_or_range.include? self
|
91
|
+
else
|
92
|
+
include_number? number_or_range.first and include_number? number_or_range.last
|
93
|
+
end
|
53
94
|
end
|
54
95
|
|
55
|
-
# Statement about non-integers is made with presumption that float presentation of number is a neighborhood of it.
|
56
|
-
# Thus, "1.0" lies in the neighborhood of "1"; [0..1.0] is, mathematically, [0; 1) that not intersects with (1; 2]
|
57
|
-
# and thereby (0..1.0).x?(1.0..2) should be false, although (0..1).x?(1..2) should be true
|
58
96
|
def x?(range)
|
97
|
+
return false if empty?
|
59
98
|
return range.x? self if range.is XRange
|
60
|
-
range_end = range.
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
99
|
+
range_end = range.included_end
|
100
|
+
if range_end < range.first
|
101
|
+
return x?(range_end..range.first)
|
102
|
+
end
|
103
|
+
self_end = included_end
|
104
|
+
if self_end < first
|
105
|
+
return (first..self_end).x?(range)
|
106
|
+
end
|
107
|
+
case self_end <=> range_end
|
108
|
+
when -1
|
109
|
+
self_end >= range.first
|
110
|
+
when 1
|
111
|
+
first <= range_end >= first
|
68
112
|
else
|
69
|
-
|
70
|
-
range_end >= self.begin
|
71
|
-
else
|
72
|
-
range_end > self.begin
|
73
|
-
end
|
113
|
+
true
|
74
114
|
end
|
75
115
|
end
|
76
116
|
alias :intersects? :x?
|
77
|
-
|
78
|
-
def
|
79
|
-
|
117
|
+
|
118
|
+
def |(range)
|
119
|
+
return range | self if range.is XRange
|
120
|
+
range = range.include_end
|
121
|
+
self_ = self.include_end
|
122
|
+
return XRange.new self, range if !x?(range)
|
123
|
+
[self.begin, range.begin].min..[self_.end, range.end].max
|
80
124
|
end
|
81
125
|
|
82
|
-
def
|
83
|
-
|
126
|
+
def ^(range)
|
127
|
+
common = self & range
|
128
|
+
self - common | range - common
|
129
|
+
end
|
130
|
+
|
131
|
+
def <=>(range)
|
132
|
+
(first <=> range.first).b || included_end <=> range.included_end
|
84
133
|
end
|
85
134
|
|
86
135
|
def center
|
87
|
-
(first + last
|
136
|
+
(first + include_end.last)/2
|
88
137
|
end
|
89
138
|
|
90
139
|
def part(i, j)
|
91
140
|
first + (i-1)*size/j .. first - 1 + i*size/j unless i < 1 or j < 1 or j < i
|
92
141
|
end
|
93
142
|
|
94
|
-
def size
|
95
|
-
(last - first).abs + (!exclude_end?).to_i
|
96
|
-
end
|
97
|
-
|
98
|
-
# Irrespective of include_end to be able to determne ranges created in any way
|
99
|
-
def b
|
100
|
-
self.begin != self.end && self
|
101
|
-
end
|
102
|
-
|
103
143
|
def div(n)
|
104
144
|
unless n < 1
|
105
145
|
rarray = []
|
@@ -141,7 +181,7 @@ class Range
|
|
141
181
|
ie*(ie+1)/2 - (1..self.begin-1).sum
|
142
182
|
end
|
143
183
|
|
144
|
-
# monotone function definition interval
|
184
|
+
# minimum of monotone function definition interval
|
145
185
|
def min(&fun)
|
146
186
|
return first if yield first
|
147
187
|
return unless yield last
|
@@ -152,6 +192,7 @@ class Range
|
|
152
192
|
end
|
153
193
|
end
|
154
194
|
|
195
|
+
# maximum of monotone function definition interval
|
155
196
|
def max(&fun)
|
156
197
|
return last if yield last
|
157
198
|
return unless yield first
|
@@ -190,7 +231,7 @@ class XRange
|
|
190
231
|
if range.is Range
|
191
232
|
XRange.new *intersect(range)
|
192
233
|
else
|
193
|
-
@ranges.map {|r| range & r}.foldl(:|)
|
234
|
+
@ranges.map {|r| range & r}.foldl(:|) || XRange.new
|
194
235
|
end
|
195
236
|
end
|
196
237
|
|
@@ -204,7 +245,7 @@ class XRange
|
|
204
245
|
end
|
205
246
|
|
206
247
|
def -@
|
207
|
-
@ranges.map {|r| -r}.foldl(:&)
|
248
|
+
@ranges.map {|r| -r}.foldl(:&) || XRange.new(-Inf..+Inf)
|
208
249
|
end
|
209
250
|
|
210
251
|
def -(range)
|
@@ -240,31 +281,41 @@ public
|
|
240
281
|
end
|
241
282
|
|
242
283
|
def of(ary)
|
243
|
-
@ranges.
|
284
|
+
@ranges.sum_of(ary)
|
285
|
+
end
|
286
|
+
|
287
|
+
def size
|
288
|
+
@size ||= @ranges.sum_size
|
244
289
|
end
|
245
290
|
|
291
|
+
# XRange doesn't support ranges with end excluded, so it's empty only if contains nothing
|
246
292
|
def empty?
|
247
293
|
@ranges.empty?
|
248
294
|
end
|
249
295
|
|
296
|
+
def b
|
297
|
+
!@ranges.empty? && self
|
298
|
+
end
|
299
|
+
|
250
300
|
def include?(number_or_range)
|
251
|
-
@ranges.
|
301
|
+
@ranges.find_include?(number_or_range)
|
252
302
|
end
|
253
303
|
|
254
304
|
def begin
|
255
|
-
@ranges
|
305
|
+
@begin ||= @ranges.first && @ranges.first.begin
|
256
306
|
end
|
257
307
|
|
258
308
|
def end
|
259
|
-
@ranges
|
309
|
+
@end ||= @ranges.last && @ranges.last.end
|
260
310
|
end
|
261
311
|
|
262
|
-
|
263
|
-
|
312
|
+
alias :to_a_first :first
|
313
|
+
def first(count=nil)
|
314
|
+
count ? to_a_first(count) : self.begin
|
264
315
|
end
|
265
|
-
|
266
|
-
def
|
267
|
-
|
316
|
+
|
317
|
+
def last(count=nil)
|
318
|
+
count ? to_a.last(count) : self.end
|
268
319
|
end
|
269
320
|
|
270
321
|
def div(n)
|
@@ -125,7 +125,7 @@ module RMTools
|
|
125
125
|
|
126
126
|
class ValueTraversable < Array
|
127
127
|
include ValueTraversal
|
128
|
-
__init__
|
128
|
+
__init__
|
129
129
|
|
130
130
|
private
|
131
131
|
alias :array_plus :+
|
@@ -145,7 +145,7 @@ module RMTools
|
|
145
145
|
|
146
146
|
class KeyValueTraversable < Hash
|
147
147
|
include KeyValueTraversal
|
148
|
-
__init__
|
148
|
+
__init__
|
149
149
|
|
150
150
|
def +(enum)
|
151
151
|
if Hash === enum
|
@@ -1,15 +1,13 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
class Object
|
3
3
|
|
4
|
-
#
|
5
|
-
|
4
|
+
# @ breaker must be callable that returns true value if that's it
|
5
|
+
# @ &splitter must return a pair
|
6
|
+
def unfold(breaker=lambda{|x|x.b}, &splitter)
|
6
7
|
obj, container = self, []
|
7
|
-
until
|
8
|
-
|
9
|
-
|
10
|
-
break_if[result[0]]
|
11
|
-
end
|
12
|
-
obj = result[0]
|
8
|
+
until breaker.call obj
|
9
|
+
obj, next_element = splitter[obj]
|
10
|
+
container.unshift next_element
|
13
11
|
end
|
14
12
|
container
|
15
13
|
end
|
data/lib/rmtools/rand/array.rb
CHANGED
@@ -18,26 +18,28 @@ class Array
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def rand
|
21
|
-
|
22
|
-
h, ua = {}, uniq
|
23
|
-
s = ua.size
|
24
|
-
loop {
|
25
|
-
i = Kernel.rand size
|
26
|
-
if h[i]
|
27
|
-
return if h.size == s
|
28
|
-
elsif yield(e = ua[i])
|
29
|
-
return e
|
30
|
-
else h[i] = true
|
31
|
-
end
|
32
|
-
}
|
33
|
-
else self[Kernel.rand(size)]
|
34
|
-
end
|
21
|
+
self[Kernel.rand(size)]
|
35
22
|
end
|
36
23
|
|
37
24
|
def rand!
|
38
25
|
delete_at Kernel.rand size
|
39
26
|
end
|
40
27
|
|
28
|
+
def rand_by
|
29
|
+
return if empty?
|
30
|
+
set, ua = Set.new, uniq
|
31
|
+
s = ua.size
|
32
|
+
loop {
|
33
|
+
i = Kernel.rand size
|
34
|
+
if set.include? i
|
35
|
+
return if set.size == s
|
36
|
+
elsif yield(e = ua[i])
|
37
|
+
return e
|
38
|
+
else set << i
|
39
|
+
end
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
41
43
|
def randdiv(int)
|
42
44
|
dup.randdiv!(int)
|
43
45
|
end
|
File without changes
|
data/lib/rmtools.rb
CHANGED
@@ -1,2 +1,10 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__
|
2
|
+
$__MAIN__ = self
|
3
|
+
require 'active_support'
|
4
|
+
require 'rmtools/require'
|
5
|
+
%w[version core enumerable text time functional
|
6
|
+
conversions lang rand console
|
7
|
+
fs db xml dev
|
8
|
+
../rmtools.so
|
9
|
+
].each {|file| RMTools::require file}
|
10
|
+
class Object; include RMTools end
|
data/lib/rmtools_dev.rb
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
|
2
|
-
$
|
3
|
-
require 'rmtools
|
4
|
-
RMTools::require 'dev'
|
5
|
-
|
6
|
-
unless defined? Rails; class Object; include RMTools end end
|
1
|
+
$stderr.puts 'require "rmtools_dev" is deprecated since 2.0.0. Please require "rmtools"'
|
2
|
+
$stderr.puts "called from #{caller(1).find {|line| line !~ /dependencies.rb/}}"
|
3
|
+
require 'rmtools'
|
data/rmtools.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rmtools/version'
|
5
|
+
#require 'rmtools/install'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "rmtools"
|
9
|
+
spec.version = RMTools::VERSION
|
10
|
+
spec.authors = ["Sergey Baev"]
|
11
|
+
spec.email = ["tinbka@gmail.com"]
|
12
|
+
spec.description = %q{RMTools is a collection of helpers for debug, text/array/file processing and simply easing a coding process}
|
13
|
+
spec.summary = %q{Collection of helpers for debug, text/array/file processing and simply easing a coding process}
|
14
|
+
spec.homepage = "https://github.com/tinbka/rmtools"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files`.split($/)
|
18
|
+
# nonetheless, for this gem spec.files() returns [] after installation
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency "activesupport"
|
22
|
+
#unless ext_files_not_modified 'rmtools', RMTools::VERSION
|
23
|
+
spec.extensions << 'ext/extconf.rb'
|
24
|
+
#end
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
27
|
+
spec.add_development_dependency "rake"
|
28
|
+
end
|