rmtools 2.0.0 → 2.1.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.
- data/README.md +12 -0
- data/ext/rmtools.cpp +8 -3
- data/lib/rmtools/active_record/base.rb +7 -2
- data/lib/rmtools/enumerable/array.rb +10 -63
- data/lib/rmtools/enumerable/array_iterators.rb +14 -6
- data/lib/rmtools/enumerable/set.rb +8 -0
- data/lib/rmtools/enumerable/set_ops.rb +69 -0
- data/lib/rmtools/version.rb +1 -1
- metadata +4 -2
data/README.md
CHANGED
@@ -27,6 +27,18 @@ It's still randomly documented since it's just my working tool.
|
|
27
27
|
|
28
28
|
### CHANGES
|
29
29
|
|
30
|
+
##### Version 2.1.0
|
31
|
+
|
32
|
+
* Array
|
33
|
+
* For ruby >= 1.9.3 #uniq_by[!] is alias of #uniq[!] itself, since it’s native implementation appears to be ~1.4x faster
|
34
|
+
* A bit better english singularizer for iterators
|
35
|
+
* Added #partition_by iterator
|
36
|
+
* Enumerable
|
37
|
+
* Generalized faster set operations for Array and Set (see rmtools/enumerable/set_ops)
|
38
|
+
* Boosted &-operator
|
39
|
+
* ActiveRecord::Base
|
40
|
+
* Added #update_attributes?
|
41
|
+
|
30
42
|
##### Version 2.0.0
|
31
43
|
|
32
44
|
* Array Meta-iterators
|
data/ext/rmtools.cpp
CHANGED
@@ -199,6 +199,9 @@ static VALUE rb_str_conjunction(VALUE self, VALUE str)
|
|
199
199
|
*/
|
200
200
|
static VALUE rb_ary_uniq_by_bang(VALUE ary)
|
201
201
|
{
|
202
|
+
long len = RARRAY_LEN(ary);
|
203
|
+
if (len < 2)
|
204
|
+
return Qnil;
|
202
205
|
if (!rb_block_given_p())
|
203
206
|
return rb_ary_new4(RARRAY_LEN(ary), RARRAY_PTR(ary));
|
204
207
|
VALUE hash, res_hash, res, el;
|
@@ -206,7 +209,7 @@ static VALUE rb_ary_uniq_by_bang(VALUE ary)
|
|
206
209
|
|
207
210
|
hash = rb_hash_new();
|
208
211
|
res_hash = rb_hash_new();
|
209
|
-
for (i=j=0; i<
|
212
|
+
for (i=j=0; i<len; i++) {
|
210
213
|
// We store an element itself and so we won't calculate function of it
|
211
214
|
// other time we'll find it in source. Ruby store function is very fast,
|
212
215
|
// so we can neglect its runtime even if source array is allready uniq
|
@@ -220,7 +223,7 @@ static VALUE rb_ary_uniq_by_bang(VALUE ary)
|
|
220
223
|
}
|
221
224
|
ARY_SET_LEN(ary, j);
|
222
225
|
|
223
|
-
return ary;
|
226
|
+
return j == len ? Qnil : ary;
|
224
227
|
}
|
225
228
|
|
226
229
|
/*
|
@@ -228,7 +231,9 @@ static VALUE rb_ary_uniq_by_bang(VALUE ary)
|
|
228
231
|
*/
|
229
232
|
static VALUE rb_ary_uniq_by(VALUE ary)
|
230
233
|
{
|
231
|
-
|
234
|
+
VALUE ary_dup = rb_ary_dup(ary);
|
235
|
+
rb_ary_uniq_by_bang(ary_dup);
|
236
|
+
return ary_dup;
|
232
237
|
}
|
233
238
|
|
234
239
|
/*
|
@@ -152,7 +152,7 @@ module ActiveRecord
|
|
152
152
|
id ?
|
153
153
|
delete_with_id :
|
154
154
|
field ?
|
155
|
-
self.class.delete_all(field =>
|
155
|
+
self.class.delete_all(field => self[field]) :
|
156
156
|
self.class.delete_all(attributes)
|
157
157
|
end
|
158
158
|
|
@@ -160,7 +160,7 @@ module ActiveRecord
|
|
160
160
|
id ?
|
161
161
|
destroy_with_id :
|
162
162
|
field ?
|
163
|
-
self.class.destroy_all(field =>
|
163
|
+
self.class.destroy_all(field => self[field]) :
|
164
164
|
self.class.destroy_all(attributes)
|
165
165
|
end
|
166
166
|
|
@@ -171,6 +171,11 @@ module ActiveRecord
|
|
171
171
|
def with_same(attr)
|
172
172
|
self.class.where(attr => self[attr])
|
173
173
|
end
|
174
|
+
|
175
|
+
def update_attributes?(hash)
|
176
|
+
hash.each {|k, v| self[k] = v}
|
177
|
+
changed? && save
|
178
|
+
end
|
174
179
|
|
175
180
|
end
|
176
181
|
|
@@ -1,71 +1,10 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'active_support/core_ext/array'
|
3
3
|
RMTools::require 'functional/fold'
|
4
|
+
RMTools::require 'enumerable/set_ops'
|
4
5
|
|
5
6
|
class Array
|
6
|
-
|
7
|
-
# why should we do zillions of cycles just for ensure A | [] = A - [] = A or A & [] = []
|
8
|
-
# though - and & should be improved within C-extension to break loop when no items have lost in self
|
9
|
-
alias union |
|
10
|
-
alias coallition +
|
11
|
-
alias subtraction -
|
12
|
-
alias intersection &
|
13
|
-
private :union, :coallition, :subtraction, :intersection
|
14
|
-
|
15
|
-
def |(ary)
|
16
|
-
if empty?
|
17
|
-
ary.uniq
|
18
|
-
elsif ary.respond_to? :empty? and ary.empty?
|
19
|
-
dup
|
20
|
-
else union(ary)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def +(ary)
|
25
|
-
if empty?
|
26
|
-
if ary.respond_to? :empty? and ary.empty?
|
27
|
-
[]
|
28
|
-
else ary.dup
|
29
|
-
end
|
30
|
-
elsif ary.respond_to? :empty? and ary.empty?
|
31
|
-
dup
|
32
|
-
else coallition(ary)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def -(ary)
|
37
|
-
if empty?
|
38
|
-
[]
|
39
|
-
elsif ary.respond_to? :empty? and ary.empty?
|
40
|
-
dup
|
41
|
-
else subtraction(ary)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def &(ary)
|
46
|
-
if empty? or (ary.respond_to? :empty? and ary.empty?)
|
47
|
-
[]
|
48
|
-
else intersection(ary)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def ^(ary)
|
53
|
-
if empty? or (ary.respond_to? :empty? and ary.empty?)
|
54
|
-
[dup, ary.dup]
|
55
|
-
elsif self == ary
|
56
|
-
[[], []]
|
57
|
-
else
|
58
|
-
common = intersection ary
|
59
|
-
[self - common, ary - common]
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
alias diff ^
|
64
|
-
|
65
|
-
def intersects?(ary)
|
66
|
-
(self & ary).any?
|
67
|
-
end
|
68
|
-
alias :x? :intersects?
|
7
|
+
include RMTools::SmarterSetOps
|
69
8
|
|
70
9
|
# arithmetics
|
71
10
|
def avg
|
@@ -184,6 +123,14 @@ class Array
|
|
184
123
|
reject {|e| e.__send__(key) == value}
|
185
124
|
end
|
186
125
|
|
126
|
+
def partition_by(key, value)
|
127
|
+
partition {|e| e.__send__(key) == value}
|
128
|
+
end
|
129
|
+
|
130
|
+
if RUBY_VERSION >= '1.9.3'
|
131
|
+
alias :uniq_by :uniq
|
132
|
+
alias :uniq_by! :uniq!
|
133
|
+
end
|
187
134
|
|
188
135
|
# uniqs
|
189
136
|
def uniq?
|
@@ -15,6 +15,14 @@ class Array
|
|
15
15
|
mattr_reader :iterators_names, :iterators_pattern
|
16
16
|
@@iterators_names = []
|
17
17
|
|
18
|
+
private
|
19
|
+
def simple_inplace_singularize!(noun)
|
20
|
+
noun.sub!(/(ss|[sc]h|[xo])es([=!?]?)$/, '\1\2') or
|
21
|
+
noun.sub!(/ies([=!?]?)$/, 'y\1') or
|
22
|
+
noun.sub!(/ves([=!?]?)$/, 'f\1') or
|
23
|
+
noun.sub!(/s([=!?]?)$/, '\1')
|
24
|
+
end
|
25
|
+
|
18
26
|
class << self
|
19
27
|
|
20
28
|
def add_iterator_name(name_or_list)
|
@@ -65,7 +73,7 @@ class Array
|
|
65
73
|
|
66
74
|
return case iterator
|
67
75
|
when :sum, :sort_along_by; __send__(iterator, args.shift) {|i| i.__send__ meth, *args, &block}
|
68
|
-
when :find_by, :select_by, :reject_by; __send__(iterator, meth, *args)
|
76
|
+
when :find_by, :select_by, :reject_by, :partition_by; __send__(iterator, meth, *args)
|
69
77
|
else __send__(iterator) {|i| i.__send__ meth, *args, &block}
|
70
78
|
end
|
71
79
|
rescue NoMethodError => e
|
@@ -73,7 +81,7 @@ class Array
|
|
73
81
|
raise e
|
74
82
|
end
|
75
83
|
|
76
|
-
elsif
|
84
|
+
elsif simple_inplace_singularize!(meth)
|
77
85
|
assignment = meth =~ /=$/
|
78
86
|
meth = meth.to_sym
|
79
87
|
|
@@ -100,7 +108,7 @@ class Array
|
|
100
108
|
|
101
109
|
end # << self
|
102
110
|
|
103
|
-
add_iterator_name(instance_methods.grep(/_by$/)+%w{every no select reject partition find_all find sum foldr foldl fold count rand_by})
|
111
|
+
add_iterator_name(instance_methods.grep(/_by$/)+%w{every no which select reject partition find_all find sum foldr foldl fold count rand_by})
|
104
112
|
|
105
113
|
# Benchmark 2:
|
106
114
|
#
|
@@ -161,7 +169,7 @@ class Array
|
|
161
169
|
end
|
162
170
|
end
|
163
171
|
|
164
|
-
elsif
|
172
|
+
elsif simple_inplace_singularize!(meth)
|
165
173
|
assignment = meth =~ /=$/
|
166
174
|
meth = meth.to_sym
|
167
175
|
|
@@ -236,7 +244,7 @@ class Array
|
|
236
244
|
err.message << " (`#{method}' interpreted as decorator-function `#{meth}')"
|
237
245
|
raise err
|
238
246
|
end}
|
239
|
-
when :find_by, :rfind_by
|
247
|
+
when :find_by, :rfind_by, :select_by, :reject_by, :partition_by
|
240
248
|
Array.class_eval %{
|
241
249
|
def #{method}(val)
|
242
250
|
# select_by_count(max_count) =>
|
@@ -258,7 +266,7 @@ class Array
|
|
258
266
|
end}
|
259
267
|
end
|
260
268
|
|
261
|
-
elsif
|
269
|
+
elsif simple_inplace_singularize!(meth)
|
262
270
|
assignment = meth =~ /=$/
|
263
271
|
meth = meth.to_sym
|
264
272
|
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module RMTools
|
3
|
+
|
4
|
+
# Builtin methods overwrite.
|
5
|
+
# Why should we do zillions of cycles just for ensure
|
6
|
+
# `A | [] = A - [] = A or A & [] = []`
|
7
|
+
# ?
|
8
|
+
# Though #- and #& should be improved within C-extension to break loop when no items have had lost in self (Or not? Don't remember what I had on my mind while I've being writing this)
|
9
|
+
module SmarterSetOps
|
10
|
+
|
11
|
+
def self.included(acceptor)
|
12
|
+
acceptor.class_eval {
|
13
|
+
alias :union :|
|
14
|
+
alias :coallition :+
|
15
|
+
alias :subtraction :-
|
16
|
+
alias :intersection :&
|
17
|
+
protected :union, :coallition, :subtraction, :intersection
|
18
|
+
|
19
|
+
def |(ary)
|
20
|
+
return ary.uniq if empty?
|
21
|
+
return uniq if ary.respond_to? :empty? and ary.empty?
|
22
|
+
|
23
|
+
union ary
|
24
|
+
end
|
25
|
+
|
26
|
+
def +(ary)
|
27
|
+
if empty?
|
28
|
+
return [] if ary.respond_to? :empty? and ary.empty?
|
29
|
+
ary.dup
|
30
|
+
end
|
31
|
+
return dup if ary.respond_to? :empty? and ary.empty?
|
32
|
+
|
33
|
+
coallition ary
|
34
|
+
end
|
35
|
+
|
36
|
+
def -(ary)
|
37
|
+
return [] if empty?
|
38
|
+
return dup if ary.respond_to? :empty? and ary.empty?
|
39
|
+
|
40
|
+
subtraction ary
|
41
|
+
end
|
42
|
+
|
43
|
+
def &(ary)
|
44
|
+
return [] if empty? or (ary.respond_to? :empty? and ary.empty?)
|
45
|
+
return ary.intersection self if size < ary.size
|
46
|
+
|
47
|
+
intersection ary
|
48
|
+
end
|
49
|
+
|
50
|
+
def ^(ary)
|
51
|
+
return [dup, ary.dup] if empty? or (ary.respond_to? :empty? and ary.empty?)
|
52
|
+
return [[], []] if self == ary
|
53
|
+
|
54
|
+
common = intersection ary
|
55
|
+
[self - common, ary - common]
|
56
|
+
end
|
57
|
+
|
58
|
+
alias diff ^
|
59
|
+
|
60
|
+
def intersects?(ary)
|
61
|
+
(self & ary).any?
|
62
|
+
end
|
63
|
+
alias :x? :intersects?
|
64
|
+
}
|
65
|
+
super
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
data/lib/rmtools/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rmtools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-06-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -124,6 +124,8 @@ files:
|
|
124
124
|
- lib/rmtools/enumerable/hash.rb
|
125
125
|
- lib/rmtools/enumerable/object_space.rb
|
126
126
|
- lib/rmtools/enumerable/range.rb
|
127
|
+
- lib/rmtools/enumerable/set.rb
|
128
|
+
- lib/rmtools/enumerable/set_ops.rb
|
127
129
|
- lib/rmtools/enumerable/traversal.rb
|
128
130
|
- lib/rmtools/fs.rb
|
129
131
|
- lib/rmtools/fs/dir.rb
|