rmtools 1.3.3 → 2.0.0.rc5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|