unique_by 2.1.0 → 3.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/CHANGELOG.md +38 -0
- data/README.md +43 -11
- data/lib/unique_by.rb +46 -27
- data/lib/unique_by/version.rb +1 -1
- data/spec/unique_by_spec.rb +134 -98
- data/unique_by.gemspec +4 -0
- metadata +18 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3318e49786c29b9bc711ccd7cedf5b62b0795ddf
|
4
|
+
data.tar.gz: 33d06afb8219b74f89614b0bf30f2d2d1f65aadb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 30fa8eeaf072a6b026a68a9b12868eb9d8069419f586b0521941756071cb7b9a5b4c940954ddfea4ef6dcf8ce57dcebe5253d8620e13aa8be35e83f1a165288f
|
7
|
+
data.tar.gz: 0b27d32f656175a51bd363f85f741bf8b3bf3e094b98db695d75c128170e57429d0cce02429c770a09322fc3504c59511efd4618b0253f6407b984dd6e5bb272
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
**3.0.0**
|
2
|
+
* Calculate unique value by multiplying in exact total rather closest power of
|
3
|
+
2 (bitwise).
|
4
|
+
|
5
|
+
***INCOMPATIBLE:*** when your totals are not powers of 2. If you already depend
|
6
|
+
on previous values of this gem, change your values to the
|
7
|
+
closest power of 2.
|
8
|
+
|
9
|
+
For example:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
unique_by client_id: 500
|
13
|
+
```
|
14
|
+
|
15
|
+
Should be:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
unique_by client_id: 512
|
19
|
+
```
|
20
|
+
|
21
|
+
* Allow passing `:primary_key` explicitly.
|
22
|
+
|
23
|
+
*MINOR INCOMPATIBLE:* if your group was named `primary_key`.
|
24
|
+
|
25
|
+
**2.1.0**
|
26
|
+
* Remove useless finder methods, you should create your own based on the group.
|
27
|
+
|
28
|
+
*MINOR INCOMPATIBLE:* if you used the finder methods.
|
29
|
+
* Using `generate_method` gem, which means generated methods are 'inherited'
|
30
|
+
instead of defined in the class itself.
|
31
|
+
|
32
|
+
*MINOR INCOMPATIBLE:* when expected to override your methods.
|
33
|
+
|
34
|
+
**2.0.0**
|
35
|
+
* *MINOR INCOMPATIBLE:* key-value arguments instead of totals/bits.
|
36
|
+
|
37
|
+
**1.0.0**
|
38
|
+
* First stable version.
|
data/README.md
CHANGED
@@ -56,7 +56,7 @@ bill2.unique_id
|
|
56
56
|
=> 7874
|
57
57
|
```
|
58
58
|
|
59
|
-
You can use the
|
59
|
+
You can use the singleton methods:
|
60
60
|
|
61
61
|
```ruby
|
62
62
|
MedicalBill.unique_id_from(123, client_id: 1) # gives the unique_id
|
@@ -96,22 +96,39 @@ You can supply a block to give a custom mechanism for determining the group:
|
|
96
96
|
|
97
97
|
```ruby
|
98
98
|
class MedicalBill < ActiveRecord::Base
|
99
|
-
unique_by(
|
99
|
+
unique_by(type_index: 2) { { type_index: 0 } }
|
100
100
|
end
|
101
101
|
class UtilityBill < ActiveRecord::Base
|
102
|
-
unique_by(
|
102
|
+
unique_by(type_index: 2) { { type_index: 1 } }
|
103
103
|
end
|
104
104
|
```
|
105
105
|
|
106
|
-
|
107
|
-
return more than one field:
|
106
|
+
Groups can also be served as a singleton method:
|
108
107
|
|
109
108
|
```ruby
|
110
109
|
class MedicalBill < ActiveRecord::Base
|
111
|
-
unique_by
|
112
|
-
|
110
|
+
unique_by type_index: 2
|
111
|
+
def self.type_index
|
112
|
+
0
|
113
113
|
end
|
114
114
|
end
|
115
|
+
class UtilityBill < ActiveRecord::Base
|
116
|
+
unique_by type_index: 2
|
117
|
+
def self.type_index
|
118
|
+
1
|
119
|
+
end
|
120
|
+
end
|
121
|
+
```
|
122
|
+
|
123
|
+
In either case, if all the groups are specified as singleton methods or served
|
124
|
+
within the block WITHOUT using the instance (`self`), you can use the singleton
|
125
|
+
methods without explicitly specifying the groups for this class:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
MedicalBill.unique_id_from(123)
|
129
|
+
=> 247
|
130
|
+
UtilityBill.unique_id_from(123)
|
131
|
+
=> 246
|
115
132
|
```
|
116
133
|
|
117
134
|
It is recommended to create finder methods that will find records according to
|
@@ -121,14 +138,25 @@ their id group, like so:
|
|
121
138
|
module Bill
|
122
139
|
module_function
|
123
140
|
def find_by_unique_id(unique_id)
|
124
|
-
case MedicalBill.id_group_from(unique_id)[:
|
125
|
-
when
|
126
|
-
when
|
141
|
+
case MedicalBill.id_group_from(unique_id)[:type_index]
|
142
|
+
when MedicalBill.type_index then MedicalBill.find(MedicalBill.id_from(unique_id))
|
143
|
+
when UtilityBill.type_index then UtilityBill.find(UtilityBill.id_from(unique_id))
|
127
144
|
end
|
128
145
|
end
|
129
146
|
end
|
130
147
|
```
|
131
148
|
|
149
|
+
You can supply both group attributes and a block, and the block can also
|
150
|
+
return more than one field:
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
class MedicalBill < ActiveRecord::Base
|
154
|
+
unique_by(client_id: 50, client_part: 5, xy: 10, halfz: 20) do
|
155
|
+
{ xy: self.x * self.y, halfz: self.z / 2 }
|
156
|
+
end
|
157
|
+
end
|
158
|
+
```
|
159
|
+
|
132
160
|
## Not ActiveRecord
|
133
161
|
|
134
162
|
The generator module is already included in `ActiveRecord::Base`, but if
|
@@ -138,6 +166,10 @@ you want the above methods in another class you can extend it:
|
|
138
166
|
class MyClass
|
139
167
|
extend UniqueBy::Generator
|
140
168
|
|
169
|
+
unique_by ..., primary_key: :id
|
170
|
+
#
|
171
|
+
# OR
|
172
|
+
#
|
141
173
|
def self.primary_key
|
142
174
|
:id # or 'id'
|
143
175
|
end
|
@@ -152,7 +184,7 @@ fix that:
|
|
152
184
|
|
153
185
|
```ruby
|
154
186
|
class MedicalBill < ActiveRecord::Base
|
155
|
-
unique_by client_id:
|
187
|
+
unique_by client_id: 32**2 # two base32 letters
|
156
188
|
rebase_attr :unique_id, to: 32, readable: true # digits and leters, without '0', 'o', '1' and 'l'
|
157
189
|
end
|
158
190
|
|
data/lib/unique_by.rb
CHANGED
@@ -12,60 +12,79 @@ module UniqueBy
|
|
12
12
|
# #unique_id => unique_id
|
13
13
|
# ::find_by_unique_id(unique_id) => find_by_id(id_from(unique_id))
|
14
14
|
# ::find_by_unique_id!(unique_id) => find_by_id!(id_from(unique_id))
|
15
|
-
def unique_by(**group_totals, &group_block)
|
15
|
+
def unique_by(primary_key: self.primary_key, **group_totals, &group_block)
|
16
16
|
raise ArgumentError, "must pass a group definition (Hash of name => total)" if group_totals.empty?
|
17
17
|
raise ArgumentError, "group definition must be a Hash of name => Fixnum, #{group_totals.inspect} given" unless group_totals.values.all? { |t| t.is_a?(Fixnum) }
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
generate_singleton_methods do
|
20
|
+
define_method :"#{primary_key}_group" do |**group|
|
21
|
+
raise ArgumentError, "unknown #{primary_key} group keys: #{group.keys - group_totals.keys}" if (group.keys - group_totals.keys).any?
|
22
|
+
next group if (group_totals.keys - group.keys).none?
|
21
23
|
|
22
|
-
|
24
|
+
group_from_block = group_block ? instance_eval(&group_block) : {}
|
25
|
+
raise TypeError, "#{primary_key} group block must return a Hash with any of the following keys: #{group_totals.keys}, #{group_from_block.inspect} given" unless group_from_block.is_a?(Hash)
|
26
|
+
raise ArgumentError, "unknown #{primary_key} group passed to block: #{group_from_block.keys - group_totals.keys}" if (group_from_block.keys - group_totals.keys).any?
|
27
|
+
group.update(group_from_block)
|
28
|
+
next group if (group_totals.keys - group.keys).none?
|
23
29
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
30
|
+
group.update(Hash[(group_totals.keys - group.keys).map { |group_name| [group_name, send(group_name)] }])
|
31
|
+
|
32
|
+
group
|
33
|
+
end
|
34
|
+
|
35
|
+
define_method :"#{primary_key}_group_value_from" do |**group|
|
36
|
+
group = send(:"#{primary_key}_group", **group)
|
28
37
|
group_totals.keys.reduce(0) do |group_value, group_name|
|
29
38
|
g = group[group_name]
|
30
|
-
raise TypeError, "#{
|
31
|
-
raise TypeError, "#{
|
32
|
-
(group_value
|
39
|
+
raise TypeError, "#{primary_key} group #{group_name} must not be nil" if g.nil?
|
40
|
+
raise TypeError, "#{primary_key} group #{group_name} must implement #to_i, #{g.inspect} given" unless g.respond_to?(:to_i)
|
41
|
+
(group_value * group_totals[group_name]) + (g.to_i % group_totals[group_name])
|
33
42
|
end
|
34
43
|
end
|
35
44
|
|
36
|
-
define_method :"unique_#{
|
45
|
+
define_method :"unique_#{primary_key}_from" do |id, **group|
|
37
46
|
break nil if id.nil?
|
38
|
-
raise TypeError, "#{
|
39
|
-
(id.to_i
|
47
|
+
raise TypeError, "#{primary_key} must implement #to_i, #{id.inspect} given" unless id.respond_to?(:to_i)
|
48
|
+
(id.to_i * group_totals.values.inject(&:*)) + send(:"#{primary_key}_group_value_from", **group)
|
40
49
|
end
|
41
50
|
|
42
|
-
define_method :"#{
|
51
|
+
define_method :"#{primary_key}_from" do |unique_id|
|
43
52
|
break nil if unique_id.nil?
|
44
|
-
raise TypeError, "unique_#{
|
45
|
-
unique_id.to_i
|
53
|
+
raise TypeError, "unique_#{primary_key} must implement #to_i, #{unique_id.inspect} given" unless unique_id.respond_to?(:to_i)
|
54
|
+
unique_id.to_i / group_totals.values.inject(&:*)
|
46
55
|
end
|
47
56
|
|
48
|
-
define_method :"#{
|
57
|
+
define_method :"#{primary_key}_group_from" do |unique_id|
|
49
58
|
break nil if unique_id.nil?
|
50
|
-
raise TypeError, "unique_#{
|
59
|
+
raise TypeError, "unique_#{primary_key} must implement #to_i, #{unique_id.inspect} given" unless unique_id.respond_to?(:to_i)
|
51
60
|
Hash[group_totals.keys.reverse.map do |group_name|
|
52
|
-
g = unique_id
|
53
|
-
unique_id
|
61
|
+
g = unique_id % group_totals[group_name]
|
62
|
+
unique_id /= group_totals[group_name]
|
54
63
|
[group_name, g]
|
55
64
|
end.reverse]
|
56
65
|
end
|
57
66
|
end
|
58
67
|
|
59
68
|
generate_methods do
|
60
|
-
define_method :"#{
|
69
|
+
define_method :"#{primary_key}_group" do
|
61
70
|
group_from_block = group_block ? instance_eval(&group_block) : {}
|
62
|
-
raise TypeError, "#{
|
63
|
-
raise ArgumentError, "unknown #{
|
64
|
-
|
71
|
+
raise TypeError, "#{primary_key} group block must return a Hash with any of the following keys: #{group_totals.keys}, #{group_from_block.inspect} given" unless group_from_block.is_a?(Hash)
|
72
|
+
raise ArgumentError, "unknown #{primary_key} group passed to block: #{group_from_block.keys - group_totals.keys}" if (group_from_block.keys - group_totals.keys).any?
|
73
|
+
group = group_from_block.merge( # like reverse_merge, as we don't set keys that were in the block
|
74
|
+
Hash[
|
75
|
+
(group_totals.keys - group_from_block.keys).map do |group_name|
|
76
|
+
[
|
77
|
+
group_name,
|
78
|
+
(respond_to?(group_name) or not self.class.respond_to?(group_name)) ? send(group_name) : self.class.send(group_name) # would rather crash on instance method missing
|
79
|
+
]
|
80
|
+
end
|
81
|
+
]
|
82
|
+
)
|
83
|
+
group
|
65
84
|
end
|
66
85
|
|
67
|
-
define_method :"unique_#{
|
68
|
-
self.class.send(:"unique_#{
|
86
|
+
define_method :"unique_#{primary_key}" do
|
87
|
+
self.class.send(:"unique_#{primary_key}_from", send(primary_key), **send(:"#{primary_key}_group"))
|
69
88
|
end
|
70
89
|
end
|
71
90
|
end
|
data/lib/unique_by/version.rb
CHANGED
data/spec/unique_by_spec.rb
CHANGED
@@ -23,6 +23,31 @@ class ShardedTablesBase < Struct.new(:bill_id, :client_id, :x)
|
|
23
23
|
end
|
24
24
|
|
25
25
|
describe UniqueBy::Generator do
|
26
|
+
shared_examples_for "unique by" do |id:, group:, tempered_group:, group_value:, unique_id:|
|
27
|
+
describe "class methods" do
|
28
|
+
specify { expect(klass.bill_id_group_value_from(group)).to eq(group_value) }
|
29
|
+
specify { expect(klass.unique_bill_id_from(id, **group)).to eq(unique_id) }
|
30
|
+
specify { expect(klass.bill_id_from(unique_id)).to eq(id) }
|
31
|
+
specify { expect(klass.bill_id_group_from(unique_id)).to eq(tempered_group) }
|
32
|
+
|
33
|
+
context "nil id" do
|
34
|
+
specify { expect(klass.unique_bill_id_from(nil, client_id: 2)).to be_nil }
|
35
|
+
specify { expect(klass.bill_id_from(nil)).to be_nil }
|
36
|
+
specify { expect(klass.bill_id_group_from(nil)).to be_nil }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "instance methods" do
|
41
|
+
its(:bill_id_group) { should == group }
|
42
|
+
its(:unique_bill_id) { should == unique_id }
|
43
|
+
|
44
|
+
context "nil id" do
|
45
|
+
before { bill.bill_id = nil }
|
46
|
+
its(:unique_bill_id) { should be_nil }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
26
51
|
context "shards" do
|
27
52
|
let(:klass) do
|
28
53
|
Class.new(Struct.new(:bill_id, :client_id)) do
|
@@ -33,51 +58,29 @@ describe UniqueBy::Generator do
|
|
33
58
|
|
34
59
|
let(:bill1) { klass.new(431, 2) }
|
35
60
|
let(:bill2) { klass.new(431, 7) }
|
36
|
-
let(:id) { 431 }
|
37
61
|
|
38
62
|
context "bill1" do
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
context "nil id" do
|
49
|
-
specify { expect(klass.unique_bill_id_from(nil, client_id: 2)).to be_nil }
|
50
|
-
specify { expect(klass.bill_id_from(nil)).to be_nil }
|
51
|
-
specify { expect(klass.bill_id_group_from(nil)).to be_nil }
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
describe "instance methods" do
|
56
|
-
its(:bill_id_group) { should == { client_id: 2 } }
|
57
|
-
its(:unique_bill_id) { should == unique_id }
|
58
|
-
|
59
|
-
context "nil id" do
|
60
|
-
before { bill1.bill_id = nil }
|
61
|
-
its(:unique_bill_id) { should be_nil }
|
62
|
-
end
|
63
|
-
end
|
63
|
+
subject(:bill) { bill1 }
|
64
|
+
|
65
|
+
it_behaves_like "unique by", {
|
66
|
+
id: 431,
|
67
|
+
group: { client_id: 2 },
|
68
|
+
tempered_group: { client_id: 2 % 10 },
|
69
|
+
group_value: group_value = 2 % 10,
|
70
|
+
unique_id: (431 * 10) + group_value,
|
71
|
+
}
|
64
72
|
end
|
65
73
|
|
66
74
|
context "bill2" do
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
describe "instance methods" do
|
78
|
-
its(:bill_id_group) { should == { client_id: 7 } }
|
79
|
-
its(:unique_bill_id) { should == unique_id }
|
80
|
-
end
|
75
|
+
subject(:bill) { bill2 }
|
76
|
+
|
77
|
+
it_behaves_like "unique by", {
|
78
|
+
id: 431,
|
79
|
+
group: { client_id: 7 },
|
80
|
+
tempered_group: { client_id: 7 % 10 },
|
81
|
+
group_value: group_value = 7 % 10,
|
82
|
+
unique_id: (431 * 10) + group_value,
|
83
|
+
}
|
81
84
|
end
|
82
85
|
end
|
83
86
|
|
@@ -95,49 +98,38 @@ describe UniqueBy::Generator do
|
|
95
98
|
|
96
99
|
let(:medical_bill) { medical_klass.new(839) }
|
97
100
|
let(:utility_bill) { utility_klass.new(839) }
|
98
|
-
let(:id) { 839 }
|
99
101
|
|
100
102
|
context "medical bill" do
|
101
103
|
let(:klass) { medical_klass }
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
describe "instance methods" do
|
113
|
-
its(:bill_id_group) { should == { type: 10 } }
|
114
|
-
its(:unique_bill_id) { should == unique_id }
|
115
|
-
end
|
104
|
+
subject(:bill) { medical_bill }
|
105
|
+
|
106
|
+
it_behaves_like "unique by", {
|
107
|
+
id: 839,
|
108
|
+
group: { type: 10 },
|
109
|
+
tempered_group: { type: 10 % 2 },
|
110
|
+
group_value: group_value = (10 % 2),
|
111
|
+
unique_id: (839 * 2) + group_value,
|
112
|
+
}
|
116
113
|
end
|
117
114
|
|
118
115
|
context "utility bill" do
|
119
116
|
let(:klass) { utility_klass }
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
describe "instance methods" do
|
131
|
-
its(:bill_id_group) { should == { type: 11 } }
|
132
|
-
its(:unique_bill_id) { should == unique_id }
|
133
|
-
end
|
117
|
+
subject(:bill) { utility_bill }
|
118
|
+
|
119
|
+
it_behaves_like "unique by", {
|
120
|
+
id: 839,
|
121
|
+
group: { type: 11 },
|
122
|
+
tempered_group: { type: 11 % 2 },
|
123
|
+
group_value: group_value = (11 % 2),
|
124
|
+
unique_id: (839 * 2) + group_value,
|
125
|
+
}
|
134
126
|
end
|
135
127
|
end
|
136
128
|
|
137
129
|
context "sharded tables" do
|
138
130
|
let(:medical_klass) do
|
139
131
|
Class.new(ShardedTablesBase) do
|
140
|
-
unique_by(client_id: 10, x: 200, type: 2, y:
|
132
|
+
unique_by(client_id: 10, x: 200, type: 2, y: 30) { { type: 10, y: y } }
|
141
133
|
def x
|
142
134
|
53
|
143
135
|
end
|
@@ -149,7 +141,7 @@ describe UniqueBy::Generator do
|
|
149
141
|
|
150
142
|
let(:utility_klass) do
|
151
143
|
Class.new(ShardedTablesBase) do
|
152
|
-
unique_by(client_id:
|
144
|
+
unique_by(client_id: 10, x: 200, type: 2, y: 30) { { type: 11, y: y } }
|
153
145
|
def x
|
154
146
|
853
|
155
147
|
end
|
@@ -161,48 +153,92 @@ describe UniqueBy::Generator do
|
|
161
153
|
|
162
154
|
let(:medical_bill) { medical_klass.new(9428, 5, 128) }
|
163
155
|
let(:utility_bill) { utility_klass.new(9428, 8, 255) }
|
164
|
-
let(:id) { 9428 }
|
165
156
|
|
166
157
|
context "medical bill" do
|
167
158
|
let(:klass) { medical_klass }
|
168
|
-
subject { medical_bill }
|
159
|
+
subject(:bill) { medical_bill }
|
160
|
+
|
161
|
+
it_behaves_like "unique by", {
|
162
|
+
id: 9428,
|
163
|
+
group: { client_id: 5, x: 53, type: 10, y: 20 },
|
164
|
+
tempered_group: { client_id: 5 % 10, x: 53 % 200, type: 10 % 2, y: 20 % 30 },
|
165
|
+
group_value: group_value = ((5 % 10) * 200*2*30) + ((53 % 200) * 2*30) + ((10 % 2) * 30) + (20 % 30),
|
166
|
+
unique_id: (9428 * 10*200*2*30) + group_value,
|
167
|
+
}
|
168
|
+
end
|
169
|
+
|
170
|
+
context "utility bill" do
|
171
|
+
let(:klass) { utility_klass }
|
172
|
+
subject(:bill) { utility_bill }
|
173
|
+
|
174
|
+
it_behaves_like "unique by", {
|
175
|
+
id: 9428,
|
176
|
+
group: { client_id: 8, x: 853, type: 11, y: 40 },
|
177
|
+
tempered_group: { client_id: 8 % 10, x: 853 % 200, type: 11 % 2, y: 40 % 30 },
|
178
|
+
group_value: group_value = ((8 % 10) * 200*2*30) + ((853 % 200) * 2*30) + ((11 % 2) * 30) + (40 % 30),
|
179
|
+
unique_id: (9428 * 10*200*2*30) + group_value,
|
180
|
+
}
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
context "override primary key" do
|
185
|
+
let(:klass) do
|
186
|
+
Class.new(Struct.new(:bill_id, :client_id)) do
|
187
|
+
extend UniqueBy::Generator
|
188
|
+
unique_by(client_id: 10, primary_key: :bill_id)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
subject(:bill) { klass.new(431, 2) }
|
192
|
+
|
193
|
+
it_behaves_like "unique by", {
|
194
|
+
id: 431,
|
195
|
+
group: { client_id: 2 },
|
196
|
+
tempered_group: { client_id: 2 % 10 },
|
197
|
+
group_value: group_value = 2 % 10,
|
198
|
+
unique_id: (431 * 10) + group_value,
|
199
|
+
}
|
200
|
+
end
|
169
201
|
|
170
|
-
|
171
|
-
|
172
|
-
let(:unique_id) { (9428 << 18) + group_value }
|
202
|
+
context "constant groups" do
|
203
|
+
let(:instance) { klass.new(49, 5) }
|
173
204
|
|
205
|
+
shared_examples_for "unique by" do
|
174
206
|
describe "class methods" do
|
175
|
-
|
176
|
-
|
177
|
-
specify { expect(
|
178
|
-
specify { expect(medical_klass.bill_id_group_from(unique_id)).to eq(tempered_group) }
|
207
|
+
subject { klass }
|
208
|
+
its(:id_group_value_from) { should == 5 }
|
209
|
+
specify { expect(klass.unique_id_from(49)).to eq(495) }
|
179
210
|
end
|
180
211
|
|
181
212
|
describe "instance methods" do
|
182
|
-
|
183
|
-
its(:
|
213
|
+
subject { instance }
|
214
|
+
its(:id_group) { should == { type: 5 } }
|
215
|
+
its(:unique_id) { should == 495 }
|
184
216
|
end
|
185
217
|
end
|
186
218
|
|
187
|
-
context "
|
188
|
-
let(:klass)
|
189
|
-
|
219
|
+
context "in static method" do
|
220
|
+
let(:klass) do
|
221
|
+
Class.new(Struct.new(:id, :type)) do
|
222
|
+
extend UniqueBy::Generator
|
223
|
+
unique_by(type: 10, primary_key: :id)
|
224
|
+
def self.type
|
225
|
+
5
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
190
229
|
|
191
|
-
|
192
|
-
|
193
|
-
let(:unique_id) { (9428 << 18) + group_value }
|
230
|
+
it_behaves_like "unique by"
|
231
|
+
end
|
194
232
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
233
|
+
context "in block" do
|
234
|
+
let(:klass) do
|
235
|
+
Class.new(Struct.new(:id, :type)) do
|
236
|
+
extend UniqueBy::Generator
|
237
|
+
unique_by(type: 10, primary_key: :id) { { type: 5 } }
|
238
|
+
end
|
200
239
|
end
|
201
240
|
|
202
|
-
|
203
|
-
its(:bill_id_group) { should == { client_id: 8, x: 853, type: 11, y: 40 } }
|
204
|
-
its(:unique_bill_id) { should == unique_id }
|
205
|
-
end
|
241
|
+
it_behaves_like "unique by"
|
206
242
|
end
|
207
243
|
end
|
208
244
|
|
@@ -228,7 +264,7 @@ describe UniqueBy::Generator do
|
|
228
264
|
|
229
265
|
specify { expect { klass.bill_id_group_value_from(x: 2) }.to raise_error(ArgumentError, "unknown bill_id group keys: [:x]") }
|
230
266
|
specify { expect { klass.bill_id_group_value_from(client_id: 5, x: 2) }.to raise_error(ArgumentError, "unknown bill_id group keys: [:x]") }
|
231
|
-
specify { expect { klass.bill_id_group_value_from() }.to raise_error(
|
267
|
+
specify { expect { klass.bill_id_group_value_from() }.to raise_error(NoMethodError, /^undefined method `client_id' for/) }
|
232
268
|
specify { expect { klass.bill_id_group_value_from(client_id: nil) }.to raise_error(TypeError, "bill_id group client_id must not be nil") }
|
233
269
|
specify { expect { klass.bill_id_group_value_from(client_id: :a) }.to raise_error(TypeError, "bill_id group client_id must implement #to_i, :a given") }
|
234
270
|
specify { expect { klass.unique_bill_id_from(431, client_id: nil) }.to raise_error(TypeError, "bill_id group client_id must not be nil") }
|
data/unique_by.gemspec
CHANGED
@@ -12,6 +12,10 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.description = %q{Allows uniqueness of a record when sharding (specifying the shard ID as the group) or span accross tables (receipts).}
|
13
13
|
spec.homepage = "https://github.com/odedniv/unique_by"
|
14
14
|
spec.license = "UNLICENSE"
|
15
|
+
spec.post_install_message = <<MSG
|
16
|
+
Upgrading from a previous major version could have destructive results.
|
17
|
+
Make sure you go through all INCOMPATIBLEs mentioned in the changelog!
|
18
|
+
MSG
|
15
19
|
|
16
20
|
spec.files = `git ls-files -z`.split("\x0")
|
17
21
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
metadata
CHANGED
@@ -1,69 +1,69 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unique_by
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oded Niv
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-11
|
11
|
+
date: 2014-12-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: generate_method
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '1.6'
|
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
40
|
version: '1.6'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '3.1'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '3.1'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rspec-its
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - ~>
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '1.0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - ~>
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '1.0'
|
69
69
|
description: Allows uniqueness of a record when sharding (specifying the shard ID
|
@@ -74,8 +74,9 @@ executables: []
|
|
74
74
|
extensions: []
|
75
75
|
extra_rdoc_files: []
|
76
76
|
files:
|
77
|
-
- .gitignore
|
78
|
-
- .rspec
|
77
|
+
- ".gitignore"
|
78
|
+
- ".rspec"
|
79
|
+
- CHANGELOG.md
|
79
80
|
- Gemfile
|
80
81
|
- README.md
|
81
82
|
- Rakefile
|
@@ -89,18 +90,20 @@ homepage: https://github.com/odedniv/unique_by
|
|
89
90
|
licenses:
|
90
91
|
- UNLICENSE
|
91
92
|
metadata: {}
|
92
|
-
post_install_message:
|
93
|
+
post_install_message: |
|
94
|
+
Upgrading from a previous major version could have destructive results.
|
95
|
+
Make sure you go through all INCOMPATIBLEs mentioned in the changelog!
|
93
96
|
rdoc_options: []
|
94
97
|
require_paths:
|
95
98
|
- lib
|
96
99
|
required_ruby_version: !ruby/object:Gem::Requirement
|
97
100
|
requirements:
|
98
|
-
- -
|
101
|
+
- - ">="
|
99
102
|
- !ruby/object:Gem::Version
|
100
103
|
version: '0'
|
101
104
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
105
|
requirements:
|
103
|
-
- -
|
106
|
+
- - ">="
|
104
107
|
- !ruby/object:Gem::Version
|
105
108
|
version: '0'
|
106
109
|
requirements: []
|