unique_by 1.0.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/README.md +85 -55
- data/lib/unique_by/version.rb +1 -1
- data/lib/unique_by.rb +38 -42
- data/spec/unique_by_spec.rb +114 -46
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4839ad7e8c93eabad52a34ae43774c3a4fa31ead
|
4
|
+
data.tar.gz: d205bd87ab905c57bbc620df6400a36fe9c95fba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: afe1110aa03ea678e269655cbbd8d10ff7cbca5406b62a5193724f5617789db734d93e033a56d6077611e3ef9c54ead59dc5a1f80035c74a73ccbcf29cd5deba
|
7
|
+
data.tar.gz: fe7ac2951507f1b2a709f905469881f3e29b4c67d3c1a110b3bd8448d82d869932a13a3758c9de217121b296e989ee50366b17f2cea089ef35deeb1b5babefa4
|
data/README.md
CHANGED
@@ -12,7 +12,9 @@ When do you need this?
|
|
12
12
|
|
13
13
|
Add this line to your application's Gemfile:
|
14
14
|
|
15
|
-
|
15
|
+
```ruby
|
16
|
+
gem 'unique_by'
|
17
|
+
```
|
16
18
|
|
17
19
|
And then execute:
|
18
20
|
|
@@ -28,84 +30,112 @@ Or install it yourself as:
|
|
28
30
|
|
29
31
|
You first need to specify a unique group in your model:
|
30
32
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
```ruby
|
34
|
+
# == Schema Info
|
35
|
+
#
|
36
|
+
# Table name: medical_bills
|
37
|
+
#
|
38
|
+
# id :integer(11) not null, primary key
|
39
|
+
# client_id :integer(11)
|
40
|
+
#
|
38
41
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
+
class MedicalBill < ActiveRecord::Base
|
43
|
+
unique_by client_id: 50 # total of 50 clients
|
44
|
+
end
|
45
|
+
```
|
42
46
|
|
43
47
|
then, you can use these basic methods:
|
44
48
|
|
45
|
-
|
46
|
-
|
49
|
+
```ruby
|
50
|
+
bill1 = MedicalBill.find(123) # from a DB shard for client_id = 1
|
51
|
+
bill2 = MedicalBill.find(123) # from a DB shard for client_id = 2
|
47
52
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
bill1.unique_id
|
54
|
+
=> 7873
|
55
|
+
bill2.unique_id
|
56
|
+
=> 7874
|
57
|
+
MedicalBill.find_by_unique_id(7873) # from DB shard for client_id = 1
|
58
|
+
=> #<MedicalBill id: 123, client_id: 1>
|
59
|
+
MedicalBill.find_by_unique_id(7874) # from DB shard for client_id = 2
|
60
|
+
=> #<MedicalBill id: 123, client_id: 2>
|
61
|
+
```
|
56
62
|
|
57
63
|
You can use the internal methods:
|
58
64
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
class MedicalBill < ActiveRecord::Base
|
69
|
-
unique_by :client_id, bits: 6 # equivalent to total: 64
|
70
|
-
end
|
65
|
+
```ruby
|
66
|
+
MedicalBill.unique_id_from(123, client_id: 1) # gives the unique_id
|
67
|
+
=> 7873
|
68
|
+
MedicalBill.id_from(7873) # gives the id
|
69
|
+
=> 123
|
70
|
+
MedicalBill.id_group_from(7874) # gives the client_id
|
71
|
+
=> { client_id: 2 }
|
72
|
+
```
|
71
73
|
|
72
74
|
You can specify multiple unique group attributes:
|
73
75
|
|
74
|
-
|
75
|
-
|
76
|
-
|
76
|
+
```ruby
|
77
|
+
class MedicalBill < ActiveRecord::Base
|
78
|
+
unique_by client_id: 50, client_part: 5 # total of 50 clients and 5 parts
|
79
|
+
end
|
80
|
+
```
|
77
81
|
|
78
82
|
### Multiple tables example
|
79
83
|
|
80
|
-
You can supply a block to give
|
81
|
-
group:
|
84
|
+
You can supply a block to give a custom mechanism for determining the group:
|
82
85
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
86
|
+
```ruby
|
87
|
+
class MedicalBill < ActiveRecord::Base
|
88
|
+
unique_by(type: 2) { { type: 1 } }
|
89
|
+
end
|
90
|
+
class UtilityBill < ActiveRecord::Base
|
91
|
+
unique_by(type: 2) { { type: 2 } }
|
92
|
+
end
|
93
|
+
```
|
89
94
|
|
90
95
|
You can supply both group attributes and a block, and the block can also
|
91
|
-
return
|
96
|
+
return more than one field:
|
92
97
|
|
93
|
-
|
94
|
-
|
95
|
-
|
98
|
+
```ruby
|
99
|
+
class MedicalBill < ActiveRecord::Base
|
100
|
+
unique_by(client_id: 50, client_part: 5, xy: 10, halfz: 20) do
|
101
|
+
{ xy: self.x * self.y, halfz: self.z / 2 }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
```
|
96
105
|
|
97
106
|
## Not ActiveRecord
|
98
107
|
|
99
108
|
The generator module is already included in `ActiveRecord::Base`, but if
|
100
109
|
you want the above methods in another class you can extend it:
|
101
110
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
111
|
+
```ruby
|
112
|
+
class MyClass
|
113
|
+
extend UniqueBy::Generator
|
114
|
+
|
115
|
+
def self.primary_key
|
116
|
+
:id # or 'id'
|
117
|
+
end
|
118
|
+
end
|
119
|
+
```
|
120
|
+
|
121
|
+
## See also
|
122
|
+
|
123
|
+
After adding the unique groups to the id, the unique_id might turn out pretty
|
124
|
+
large. You could use [rebase_attr](https://github.com/odedniv/rebase_attr) to
|
125
|
+
fix that:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
class MedicalBill < ActiveRecord::Base
|
129
|
+
unique_by client_id: 500
|
130
|
+
rebase_attr :unique_id, to: 32, readable: true
|
131
|
+
end
|
132
|
+
|
133
|
+
bill = MedicalBill.find(3528918) # from a DB shard for client_id = 1
|
134
|
+
bill.unique_id
|
135
|
+
=> "ywr3bxx"
|
136
|
+
MedicalBill.find_by_unique_id(MedicalBill.decode_unique_id("ywr3bxx"))
|
137
|
+
=> #<MedicalBill id: 3528918, client_id: 1>
|
138
|
+
```
|
109
139
|
|
110
140
|
## Contributing
|
111
141
|
|
data/lib/unique_by/version.rb
CHANGED
data/lib/unique_by.rb
CHANGED
@@ -11,69 +11,65 @@ module UniqueBy
|
|
11
11
|
# #unique_id => unique_id
|
12
12
|
# ::find_by_unique_id(unique_id) => find_by_id(id_from(unique_id))
|
13
13
|
# ::find_by_unique_id!(unique_id) => find_by_id!(id_from(unique_id))
|
14
|
-
def unique_by(
|
15
|
-
|
14
|
+
def unique_by(**group_totals, &group_block)
|
15
|
+
raise ArgumentError, "must pass a group definition (Hash of name => total)" if group_totals.empty?
|
16
|
+
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) }
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
raise ArgumentError, "both total (#{total.inspect}) and bits (#{bits.inspect}) passed to #unique_by" \
|
20
|
-
if total.any? and bits.any?
|
21
|
-
raise ArgumentError, "must pass a group generator block" \
|
22
|
-
unless group_block_names.any? or block_given?
|
23
|
-
raise ArgumentError, "amount of group names (#{group_block_names.length}) doesn't match total/bits (#{total.length + bits.length})" \
|
24
|
-
if (not block_given? and group_block_names.length != total.length + bits.length) or \
|
25
|
-
(block_given? and group_block_names.length > total.length + bits.length)
|
26
|
-
|
27
|
-
bits = total.map { |t| Math.log2(t).ceil } if bits.empty?
|
28
|
-
total = bits.map { |b| 2 ** b }
|
18
|
+
bits = Hash[group_totals.map { |k, t| [k, Math.log2(t).ceil] }]
|
19
|
+
totals = Hash[bits.map { |k, b| [k, 2 ** b] }] # real total
|
29
20
|
|
30
21
|
pk = primary_key # converting to a local variable
|
31
22
|
|
32
|
-
define_singleton_method :"#{pk}_group_value_from" do
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
23
|
+
define_singleton_method :"#{pk}_group_value_from" do |**group|
|
24
|
+
raise ArgumentError, "unknown #{pk} group keys: #{group.keys - group_totals.keys}" if (group.keys - group_totals.keys).any?
|
25
|
+
raise ArgumentError, "missing #{pk} group keys: #{group_totals.keys - group.keys}" if (group_totals.keys - group.keys).any?
|
26
|
+
group_totals.keys.reduce(0) do |group_value, group_name|
|
27
|
+
g = group[group_name]
|
28
|
+
raise TypeError, "#{pk} group #{group_name} must not be nil" if g.nil?
|
29
|
+
raise TypeError, "#{pk} group #{group_name} must implement #to_i, #{g.inspect} given" unless g.respond_to?(:to_i)
|
30
|
+
(group_value << bits[group_name]) + (g.to_i % totals[group_name])
|
37
31
|
end
|
38
32
|
end
|
39
33
|
|
40
|
-
define_singleton_method :"unique_#{pk}_from" do |id, group|
|
41
|
-
|
34
|
+
define_singleton_method :"unique_#{pk}_from" do |id, **group|
|
35
|
+
break nil if id.nil?
|
36
|
+
raise TypeError, "#{pk} must implement #to_i, #{id.inspect} given" unless id.respond_to?(:to_i)
|
37
|
+
(id.to_i << bits.values.inject(&:+)) + send(:"#{pk}_group_value_from", **group)
|
42
38
|
end
|
43
39
|
|
44
|
-
define_singleton_method :"#{pk}_from" do |
|
45
|
-
|
40
|
+
define_singleton_method :"#{pk}_from" do |unique_id|
|
41
|
+
break nil if unique_id.nil?
|
42
|
+
raise TypeError, "unique_#{pk} must implement #to_i, #{unique_id.inspect} given" unless unique_id.respond_to?(:to_i)
|
43
|
+
unique_id.to_i >> bits.values.inject(&:+)
|
46
44
|
end
|
47
45
|
|
48
|
-
define_singleton_method :"#{pk}_group_from" do |
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
g
|
53
|
-
|
54
|
-
|
46
|
+
define_singleton_method :"#{pk}_group_from" do |unique_id|
|
47
|
+
break nil if unique_id.nil?
|
48
|
+
raise TypeError, "unique_#{pk} must implement #to_i, #{unique_id.inspect} given" unless unique_id.respond_to?(:to_i)
|
49
|
+
Hash[group_totals.keys.reverse.map do |group_name|
|
50
|
+
g = unique_id & (totals[group_name] - 1)
|
51
|
+
unique_id >>= bits[group_name]
|
52
|
+
[group_name, g]
|
53
|
+
end.reverse]
|
55
54
|
end
|
56
55
|
|
57
56
|
define_method :"#{pk}_group" do
|
58
|
-
|
59
|
-
group.
|
60
|
-
raise ArgumentError, "
|
61
|
-
|
57
|
+
group_from_block = group_block ? instance_eval(&group_block) : {}
|
58
|
+
raise TypeError, "#{pk} 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)
|
59
|
+
raise ArgumentError, "unknown #{pk} group passed to block: #{group_from_block.keys - group_totals.keys}" if (group_from_block.keys - group_totals.keys).any?
|
60
|
+
Hash[(group_totals.keys - group_from_block.keys).map { |group_name| [group_name, send(group_name)] }].merge(group_from_block)
|
62
61
|
end
|
63
62
|
|
64
63
|
define_method :"unique_#{pk}" do
|
65
|
-
|
66
|
-
raise TypeError, "#{pk} must implement #to_i, #{primary_key.inspect} given" \
|
67
|
-
unless primary_key.respond_to?(:to_i)
|
68
|
-
self.class.send(:"unique_#{pk}_from", primary_key.to_i, send(:"#{pk}_group"))
|
64
|
+
self.class.send(:"unique_#{pk}_from", send(pk), **send(:"#{pk}_group"))
|
69
65
|
end
|
70
66
|
|
71
|
-
define_singleton_method :"find_by_unique_#{pk}" do |
|
72
|
-
send(:"find_by_#{pk}", send(:"#{pk}_from",
|
67
|
+
define_singleton_method :"find_by_unique_#{pk}" do |unique_id|
|
68
|
+
send(:"find_by_#{pk}", send(:"#{pk}_from", unique_id))
|
73
69
|
end
|
74
70
|
|
75
|
-
define_singleton_method :"find_by_unique_#{pk}!" do |
|
76
|
-
send(:"find_by_#{pk}!", send(:"#{pk}_from",
|
71
|
+
define_singleton_method :"find_by_unique_#{pk}!" do |unique_id|
|
72
|
+
send(:"find_by_#{pk}!", send(:"#{pk}_from", unique_id))
|
77
73
|
end
|
78
74
|
end
|
79
75
|
end
|
data/spec/unique_by_spec.rb
CHANGED
@@ -44,7 +44,7 @@ describe UniqueBy::Generator do
|
|
44
44
|
let(:klass) do
|
45
45
|
Class.new(Struct.new(:bill_id, :client_id)) do
|
46
46
|
include BaseBill
|
47
|
-
unique_by(
|
47
|
+
unique_by(client_id: 10)
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
@@ -57,17 +57,28 @@ describe UniqueBy::Generator do
|
|
57
57
|
subject { bill1 }
|
58
58
|
|
59
59
|
describe "class methods" do
|
60
|
-
specify { expect(klass.bill_id_group_value_from(2)).to eq(2 % 16) }
|
61
|
-
specify { expect(klass.unique_bill_id_from(431, 2)).to eq(unique_id) }
|
60
|
+
specify { expect(klass.bill_id_group_value_from(client_id: 2)).to eq(2 % 16) }
|
61
|
+
specify { expect(klass.unique_bill_id_from(431, client_id: 2)).to eq(unique_id) }
|
62
62
|
specify { expect(klass.bill_id_from(unique_id)).to eq(431) }
|
63
|
-
specify { expect(klass.bill_id_group_from(unique_id)).to eq(2 % 16) }
|
63
|
+
specify { expect(klass.bill_id_group_from(unique_id)).to eq(client_id: 2 % 16) }
|
64
|
+
|
65
|
+
context "nil id" do
|
66
|
+
specify { expect(klass.unique_bill_id_from(nil, client_id: 2)).to be_nil }
|
67
|
+
specify { expect(klass.bill_id_from(nil)).to be_nil }
|
68
|
+
specify { expect(klass.bill_id_group_from(nil)).to be_nil }
|
69
|
+
end
|
64
70
|
|
65
71
|
include_context "finder methods"
|
66
72
|
end
|
67
73
|
|
68
74
|
describe "instance methods" do
|
69
|
-
its(:bill_id_group) { should == 2 }
|
75
|
+
its(:bill_id_group) { should == { client_id: 2 } }
|
70
76
|
its(:unique_bill_id) { should == unique_id }
|
77
|
+
|
78
|
+
context "nil id" do
|
79
|
+
before { bill1.bill_id = nil }
|
80
|
+
its(:unique_bill_id) { should be_nil }
|
81
|
+
end
|
71
82
|
end
|
72
83
|
end
|
73
84
|
|
@@ -76,16 +87,16 @@ describe UniqueBy::Generator do
|
|
76
87
|
subject { bill2 }
|
77
88
|
|
78
89
|
describe "class methods" do
|
79
|
-
specify { expect(klass.bill_id_group_value_from(7)).to eq(7 % 16) }
|
80
|
-
specify { expect(klass.unique_bill_id_from(431, 7)).to eq(unique_id) }
|
90
|
+
specify { expect(klass.bill_id_group_value_from(client_id: 7)).to eq(7 % 16) }
|
91
|
+
specify { expect(klass.unique_bill_id_from(431, client_id: 7)).to eq(unique_id) }
|
81
92
|
specify { expect(klass.bill_id_from(unique_id)).to eq(431) }
|
82
|
-
specify { expect(klass.bill_id_group_from(unique_id)).to eq(7 % 16) }
|
93
|
+
specify { expect(klass.bill_id_group_from(unique_id)).to eq(client_id: 7 % 16) }
|
83
94
|
|
84
95
|
include_context "finder methods"
|
85
96
|
end
|
86
97
|
|
87
98
|
describe "instance methods" do
|
88
|
-
its(:bill_id_group) { should == 7 }
|
99
|
+
its(:bill_id_group) { should == { client_id: 7 } }
|
89
100
|
its(:unique_bill_id) { should == unique_id }
|
90
101
|
end
|
91
102
|
end
|
@@ -94,12 +105,12 @@ describe UniqueBy::Generator do
|
|
94
105
|
context "tables" do
|
95
106
|
let(:medical_klass) do
|
96
107
|
Class.new(TablesBase) do
|
97
|
-
unique_by(
|
108
|
+
unique_by(type: 2) { { type: 10 } }
|
98
109
|
end
|
99
110
|
end
|
100
111
|
let(:utility_klass) do
|
101
112
|
Class.new(TablesBase) do
|
102
|
-
unique_by(
|
113
|
+
unique_by(type: 2) { { type: 11 } }
|
103
114
|
end
|
104
115
|
end
|
105
116
|
|
@@ -113,16 +124,16 @@ describe UniqueBy::Generator do
|
|
113
124
|
subject { medical_bill }
|
114
125
|
|
115
126
|
describe "class methods" do
|
116
|
-
specify { expect(medical_klass.bill_id_group_value_from(10)).to eq(10 % 2) }
|
117
|
-
specify { expect(medical_klass.unique_bill_id_from(839, 10)).to eq(unique_id) }
|
127
|
+
specify { expect(medical_klass.bill_id_group_value_from(type: 10)).to eq(10 % 2) }
|
128
|
+
specify { expect(medical_klass.unique_bill_id_from(839, type: 10)).to eq(unique_id) }
|
118
129
|
specify { expect(medical_klass.bill_id_from(unique_id)).to eq(839) }
|
119
|
-
specify { expect(medical_klass.bill_id_group_from(unique_id)).to eq(10 % 2) }
|
130
|
+
specify { expect(medical_klass.bill_id_group_from(unique_id)).to eq(type: 10 % 2) }
|
120
131
|
|
121
132
|
include_context "finder methods"
|
122
133
|
end
|
123
134
|
|
124
135
|
describe "instance methods" do
|
125
|
-
its(:bill_id_group) { should == 10 }
|
136
|
+
its(:bill_id_group) { should == { type: 10 } }
|
126
137
|
its(:unique_bill_id) { should == unique_id }
|
127
138
|
end
|
128
139
|
end
|
@@ -133,16 +144,16 @@ describe UniqueBy::Generator do
|
|
133
144
|
subject { utility_bill }
|
134
145
|
|
135
146
|
describe "class methods" do
|
136
|
-
specify { expect(utility_klass.bill_id_group_value_from(11)).to eq(11 % 2) }
|
137
|
-
specify { expect(utility_klass.unique_bill_id_from(839, 11)).to eq(unique_id) }
|
147
|
+
specify { expect(utility_klass.bill_id_group_value_from(type: 11)).to eq(11 % 2) }
|
148
|
+
specify { expect(utility_klass.unique_bill_id_from(839, type: 11)).to eq(unique_id) }
|
138
149
|
specify { expect(utility_klass.bill_id_from(unique_id)).to eq(839) }
|
139
|
-
specify { expect(utility_klass.bill_id_group_from(unique_id)).to eq(11 % 2) }
|
150
|
+
specify { expect(utility_klass.bill_id_group_from(unique_id)).to eq(type: 11 % 2) }
|
140
151
|
|
141
152
|
include_context "finder methods"
|
142
153
|
end
|
143
154
|
|
144
155
|
describe "instance methods" do
|
145
|
-
its(:bill_id_group) { should == 11 }
|
156
|
+
its(:bill_id_group) { should == { type: 11 } }
|
146
157
|
its(:unique_bill_id) { should == unique_id }
|
147
158
|
end
|
148
159
|
end
|
@@ -150,9 +161,8 @@ describe UniqueBy::Generator do
|
|
150
161
|
|
151
162
|
context "sharded tables" do
|
152
163
|
let(:medical_klass) do
|
153
|
-
|
154
164
|
Class.new(ShardedTablesBase) do
|
155
|
-
unique_by(:
|
165
|
+
unique_by(client_id: 10, x: 200, type: 2, y: 20) { { type: 10, y: y } }
|
156
166
|
def x
|
157
167
|
53
|
158
168
|
end
|
@@ -164,7 +174,7 @@ describe UniqueBy::Generator do
|
|
164
174
|
|
165
175
|
let(:utility_klass) do
|
166
176
|
Class.new(ShardedTablesBase) do
|
167
|
-
unique_by(:
|
177
|
+
unique_by(client_id: 2**4, x: 2**8, type: 2**1, y: 2**5) { { type: 11, y: y } }
|
168
178
|
def x
|
169
179
|
853
|
170
180
|
end
|
@@ -178,17 +188,17 @@ describe UniqueBy::Generator do
|
|
178
188
|
let(:utility_bill) { utility_klass.new(9428, 8, 255) }
|
179
189
|
let(:id) { 9428 }
|
180
190
|
|
181
|
-
context "
|
191
|
+
context "medical bill" do
|
182
192
|
let(:klass) { medical_klass }
|
183
193
|
subject { medical_bill }
|
184
194
|
|
185
|
-
let(:tempered_group) {
|
195
|
+
let(:tempered_group) { { client_id: 5 % 16, x: 53 % 256, type: 10 % 2, y: 20 % 32 } }
|
186
196
|
let(:group_value) { ((5 % 16) << 14) + ((53 % 256) << 6) + ((10 % 2) << 5) + (20 % 32) }
|
187
197
|
let(:unique_id) { (9428 << 18) + group_value }
|
188
198
|
|
189
199
|
describe "class methods" do
|
190
|
-
specify { expect(medical_klass.bill_id_group_value_from(
|
191
|
-
specify { expect(medical_klass.unique_bill_id_from(9428,
|
200
|
+
specify { expect(medical_klass.bill_id_group_value_from(client_id: 5, x: 53, type: 10, y: 20)).to eq(group_value) }
|
201
|
+
specify { expect(medical_klass.unique_bill_id_from(9428, client_id: 5, x: 53, type: 10, y: 20)).to eq(unique_id) }
|
192
202
|
specify { expect(medical_klass.bill_id_from(unique_id)).to eq(9428) }
|
193
203
|
specify { expect(medical_klass.bill_id_group_from(unique_id)).to eq(tempered_group) }
|
194
204
|
|
@@ -196,22 +206,22 @@ describe UniqueBy::Generator do
|
|
196
206
|
end
|
197
207
|
|
198
208
|
describe "instance methods" do
|
199
|
-
its(:bill_id_group) { should ==
|
209
|
+
its(:bill_id_group) { should == { client_id: 5, x: 53, type: 10, y: 20 } }
|
200
210
|
its(:unique_bill_id) { should == unique_id }
|
201
211
|
end
|
202
212
|
end
|
203
213
|
|
204
|
-
context "
|
214
|
+
context "utility bill" do
|
205
215
|
let(:klass) { utility_klass }
|
206
216
|
subject { utility_bill }
|
207
217
|
|
208
|
-
let(:tempered_group) {
|
218
|
+
let(:tempered_group) { { client_id: 8 % 16, x: 853 % 256, type: 11 % 2, y: 40 % 32 } }
|
209
219
|
let(:group_value) { ((8 % 16) << 14) + ((853 % 256) << 6) + ((11 % 2) << 5) + (40 % 32) }
|
210
220
|
let(:unique_id) { (9428 << 18) + group_value }
|
211
221
|
|
212
222
|
describe "class methods" do
|
213
|
-
specify { expect(utility_klass.bill_id_group_value_from(
|
214
|
-
specify { expect(utility_klass.unique_bill_id_from(9428,
|
223
|
+
specify { expect(utility_klass.bill_id_group_value_from(client_id: 8, x: 853, type: 11, y: 40)).to eq(group_value) }
|
224
|
+
specify { expect(utility_klass.unique_bill_id_from(9428, client_id: 8, x: 853, type: 11, y: 40)).to eq(unique_id) }
|
215
225
|
specify { expect(utility_klass.bill_id_from(unique_id)).to eq(9428) }
|
216
226
|
specify { expect(utility_klass.bill_id_group_from(unique_id)).to eq(tempered_group) }
|
217
227
|
|
@@ -219,35 +229,93 @@ describe UniqueBy::Generator do
|
|
219
229
|
end
|
220
230
|
|
221
231
|
describe "instance methods" do
|
222
|
-
its(:bill_id_group) { should ==
|
232
|
+
its(:bill_id_group) { should == { client_id: 8, x: 853, type: 11, y: 40 } }
|
223
233
|
its(:unique_bill_id) { should == unique_id }
|
224
234
|
end
|
225
235
|
end
|
226
236
|
end
|
227
237
|
|
228
238
|
context "errors" do
|
229
|
-
|
230
|
-
|
231
|
-
|
239
|
+
describe "#unique_by" do
|
240
|
+
let(:klass) do
|
241
|
+
Class.new do
|
242
|
+
include BaseBill
|
243
|
+
end
|
232
244
|
end
|
233
|
-
end
|
234
245
|
|
235
|
-
|
236
|
-
specify { expect { klass.unique_by(:
|
237
|
-
specify { expect { klass.unique_by(:x, total: [5, 4], bits: [2, 7]) }.to raise_error(ArgumentError, "both total ([5, 4]) and bits ([2, 7]) passed to #unique_by") }
|
238
|
-
specify { expect { klass.unique_by(total: 5) }.to raise_error(ArgumentError, "must pass a group generator block") }
|
239
|
-
specify { expect { klass.unique_by(:x, :y, total: 5) }.to raise_error(ArgumentError, "amount of group names (2) doesn't match total/bits (1)") }
|
240
|
-
specify { expect { klass.unique_by(:x, :y, total: [3, 2, 5]) }.to raise_error(ArgumentError, "amount of group names (2) doesn't match total/bits (3)") }
|
241
|
-
specify { expect { klass.unique_by(:x, :y, total: [3, 2, 5]) { } }.not_to raise_error }
|
242
|
-
specify { expect { klass.unique_by(:x, :y, :z, bits: [3, 2]) { } }.to raise_error(ArgumentError, "amount of group names (3) doesn't match total/bits (2)") }
|
246
|
+
specify { expect { klass.unique_by }.to raise_error(ArgumentError, "must pass a group definition (Hash of name => total)") }
|
247
|
+
specify { expect { klass.unique_by(x: :a) }.to raise_error(ArgumentError, "group definition must be a Hash of name => Fixnum, {:x=>:a} given") }
|
243
248
|
end
|
244
249
|
|
245
250
|
describe "class methods" do
|
246
|
-
|
251
|
+
let(:klass) do
|
252
|
+
Class.new(Struct.new(:bill_id, :client_id)) do
|
253
|
+
include BaseBill
|
254
|
+
unique_by client_id: 10
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
specify { expect { klass.bill_id_group_value_from(x: 2) }.to raise_error(ArgumentError, "unknown bill_id group keys: [:x]") }
|
259
|
+
specify { expect { klass.bill_id_group_value_from(client_id: 5, x: 2) }.to raise_error(ArgumentError, "unknown bill_id group keys: [:x]") }
|
260
|
+
specify { expect { klass.bill_id_group_value_from() }.to raise_error(ArgumentError, "missing bill_id group keys: [:client_id]") }
|
261
|
+
specify { expect { klass.bill_id_group_value_from(client_id: nil) }.to raise_error(TypeError, "bill_id group client_id must not be nil") }
|
262
|
+
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") }
|
263
|
+
specify { expect { klass.unique_bill_id_from(431, client_id: nil) }.to raise_error(TypeError, "bill_id group client_id must not be nil") }
|
264
|
+
specify { expect { klass.unique_bill_id_from(431, client_id: :a) }.to raise_error(TypeError, "bill_id group client_id must implement #to_i, :a given") }
|
265
|
+
specify { expect { klass.unique_bill_id_from(:a, client_id: 5) }.to raise_error(TypeError, "bill_id must implement #to_i, :a given") }
|
266
|
+
specify { expect { klass.bill_id_from(:a) }.to raise_error(TypeError, "unique_bill_id must implement #to_i, :a given") }
|
267
|
+
specify { expect { klass.bill_id_group_from(:a) }.to raise_error(TypeError, "unique_bill_id must implement #to_i, :a given") }
|
247
268
|
end
|
248
269
|
|
249
270
|
describe "instance methods" do
|
250
|
-
|
271
|
+
let(:klass) do
|
272
|
+
Class.new(Struct.new(:bill_id, :client_id, :block)) do
|
273
|
+
include BaseBill
|
274
|
+
unique_by(client_id: 10, x: 5) { block }
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
context "nil group" do
|
279
|
+
let(:bill) { klass.new(431, nil, { x: 2 }) }
|
280
|
+
specify { expect { bill.unique_bill_id }.to raise_error(TypeError, "bill_id group client_id must not be nil") }
|
281
|
+
end
|
282
|
+
|
283
|
+
context "invalid group" do
|
284
|
+
let(:bill) { klass.new(431, :a, { x: 2 }) }
|
285
|
+
specify { expect { bill.unique_bill_id }.to raise_error(TypeError, "bill_id group client_id must implement #to_i, :a given") }
|
286
|
+
end
|
287
|
+
|
288
|
+
context "nil block group" do
|
289
|
+
let(:bill) { klass.new(431, 5, { x: nil }) }
|
290
|
+
specify { expect { bill.unique_bill_id }.to raise_error(TypeError, "bill_id group x must not be nil") }
|
291
|
+
end
|
292
|
+
|
293
|
+
context "invalid block group" do
|
294
|
+
let(:bill) { klass.new(431, 5, :a) }
|
295
|
+
specify { expect { bill.unique_bill_id }.to raise_error(TypeError, "bill_id group block must return a Hash with any of the following keys: [:client_id, :x], :a given") }
|
296
|
+
end
|
297
|
+
|
298
|
+
context "invalid block group value" do
|
299
|
+
let(:bill) { klass.new(431, 5, { x: :a }) }
|
300
|
+
specify { expect { bill.unique_bill_id }.to raise_error(TypeError, "bill_id group x must implement #to_i, :a given") }
|
301
|
+
end
|
302
|
+
|
303
|
+
context "unknown block group keys" do
|
304
|
+
context "too few" do
|
305
|
+
let(:bill) { klass.new(431, 5, { }) }
|
306
|
+
specify { expect { bill.unique_bill_id }.to raise_error(NameError, "undefined method `x' for #<struct bill_id=431, client_id=5, block={}>") }
|
307
|
+
end
|
308
|
+
|
309
|
+
context "too many" do
|
310
|
+
let(:bill) { klass.new(431, 5, { x: 2, y: 12 }) }
|
311
|
+
specify { expect { bill.unique_bill_id }.to raise_error(ArgumentError, "unknown bill_id group passed to block: [:y]") }
|
312
|
+
end
|
313
|
+
|
314
|
+
context "different" do
|
315
|
+
let(:bill) { klass.new(431, 5, { y: 12 }) }
|
316
|
+
specify { expect { bill.unique_bill_id }.to raise_error(ArgumentError, "unknown bill_id group passed to block: [:y]") }
|
317
|
+
end
|
318
|
+
end
|
251
319
|
end
|
252
320
|
end
|
253
321
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unique_by
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.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-09-
|
11
|
+
date: 2014-09-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|