unique_by 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4360207db16c47e063005d3f50983411710de6f8
4
+ data.tar.gz: f2aa0cb2ff36558ca288fe4f8397645edd55a28a
5
+ SHA512:
6
+ metadata.gz: 2e91b8a6f86e7b1fb936807adf396e63ccecba95f3b8ab9ae892e17f6671ecfaba7928b960a6e581a9a8455f4a3a0e48635033fa5d2dfcbad783fdf94d001daf
7
+ data.tar.gz: ad167e6e1778ed2d855144b1c548a330e2b293664d5234746119dc5026a84497448c9f937a475d8e42616c6fcf3d774563482bd8c124de433f4f9bb78f1f4829
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in unique_by.gemspec
4
+ gemspec
@@ -0,0 +1,116 @@
1
+ # unique_by [![Gem Version](https://badge.fury.io/rb/unique_by.svg)](http://badge.fury.io/rb/unique_by)
2
+
3
+ This simple gem allows specifying uniqueness groups for an attribute, giving
4
+ you something to expose to the outside world.
5
+
6
+ When do you need this?
7
+
8
+ - If you're sharding your database.
9
+ - If you have multiple tables that you want to expose a unique ID for.
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem 'unique_by'
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install unique_by
24
+
25
+ ## Usage
26
+
27
+ ### Sharding example
28
+
29
+ You first need to specify a unique group in your model:
30
+
31
+ # == Schema Info
32
+ #
33
+ # Table name: medical_bills
34
+ #
35
+ # id :integer(11) not null, primary key
36
+ # client_id :integer(11)
37
+ #
38
+
39
+ class MedicalBill < ActiveRecord::Base
40
+ unique_by :client_id, total: 50
41
+ end
42
+
43
+ then, you can use these basic methods:
44
+
45
+ bill1 = MedicalBill.find(123) # from a DB shard for client_id = 1
46
+ bill2 = MedicalBill.find(123) # from a DB shard for client_id = 2
47
+
48
+ bill1.unique_id
49
+ => "62p"
50
+ bill2.unique_id
51
+ => "62q"
52
+ MedicalBill.find_by_unique_id("62p") # from DB shard for client_id = 1
53
+ => #<MedicalBill id: 123, client_id: 1>
54
+ MedicalBill.find_by_unique_id("62q") # from DB shard for client_id = 2
55
+ => #<MedicalBill id: 123, client_id: 2>
56
+
57
+ You can use the internal methods:
58
+
59
+ MedicalBill.unique_id_from(1, 123) # gives the unique_id from client_id, id
60
+ => "62p"
61
+ MedicalBill.id_from("62p") # gives the id
62
+ => 123
63
+ MedicalBill.id_group_from("62q") # gives the client_id
64
+ => 2
65
+
66
+ And use bits instead of total:
67
+
68
+ class MedicalBill < ActiveRecord::Base
69
+ unique_by :client_id, bits: 6 # equivalent to total: 64
70
+ end
71
+
72
+ You can specify multiple unique group attributes:
73
+
74
+ class MedicalBill < ActiveRecord::Base
75
+ unique_by :client_id, :client_part, total: [50, 5]
76
+ end
77
+
78
+ ### Multiple tables example
79
+
80
+ You can supply a block to give your own mechanism for determining the
81
+ group:
82
+
83
+ class MedicalBill < ActiveRecord::Base
84
+ unique_by(total: 2) { 1 }
85
+ end
86
+ class UtilityBill < ActiveRecord::Base
87
+ unique_by(total: 2) { 2 }
88
+ end
89
+
90
+ You can supply both group attributes and a block, and the block can also
91
+ return an array:
92
+
93
+ class MedicalBill < ActiveRecord::Base
94
+ unique(:client_id, :client_part, total: [50, 5, 10, 20]) { [self.x * self.y, self.z / 2] }
95
+ end
96
+
97
+ ## Not ActiveRecord
98
+
99
+ The generator module is already included in `ActiveRecord::Base`, but if
100
+ you want the above methods in another class you can extend it:
101
+
102
+ class MyClass
103
+ extend UniqueBy::Generator
104
+
105
+ def self.primary_key
106
+ :id # or 'id'
107
+ end
108
+ end
109
+
110
+ ## Contributing
111
+
112
+ 1. Fork it ( https://github.com/odedniv/unique_by/fork )
113
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
114
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
115
+ 4. Push to the branch (`git push origin my-new-feature`)
116
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <http://unlicense.org/>
@@ -0,0 +1,73 @@
1
+ require "unique_by/version"
2
+
3
+ module UniqueBy
4
+ module Generator
5
+ # For a primary_key 'id', generates:
6
+ # ::unique_id_from(group, id) => unique_id
7
+ # ::id_from(unique_id) => id
8
+ # ::id_group_from(unique_id) => group
9
+ # #id_group => group
10
+ # #unique_id => unique_id
11
+ # ::find_by_unique_id(unique_id) => find_by_id(id_from(unique_id))
12
+ # ::find_by_unique_id!(unique_id) => find_by_id!(id_from(unique_id))
13
+ def unique_by(*group_block_names, total: nil, bits: nil, &group_block)
14
+ bits, total = Array(bits), Array(total)
15
+
16
+ raise ArgumentError, "must pass either bits or total to #unique_by" \
17
+ unless bits.any? or total.any?
18
+ raise ArgumentError, "both bits (#{bits.inspect}) and total (#{total.inspect}) passed to #unique_by" \
19
+ if bits.any? and total.any?
20
+ raise ArgumentError, "must pass a group generator block" \
21
+ unless group_block_names.any? or block_given?
22
+ raise ArgumentError, "amount of group names (#{group_block_names.length}) doesn't match amount of bits/total (#{bits.length + total.length})" \
23
+ if group_block_names.any? and not block_given? and group_block_names.length != bits.length + total.length
24
+
25
+ bits = total.map { |t| Math.log2(t).ceil } if bits.empty?
26
+ total = bits.map { |b| 2 ** b }
27
+
28
+ pk = primary_key # converting to a local variable
29
+
30
+ define_singleton_method :"unique_#{pk}_from" do |group_value, value|
31
+ (value.to_i << bits.sum) + group_value.to_i
32
+ end
33
+
34
+ define_singleton_method :"#{pk}_from" do |value|
35
+ value.to_i >> bits
36
+ end
37
+
38
+ define_singleton_method :"#{pk}_group_from" do |value|
39
+ value.to_i & ((2 ** bits.sum) - 1)
40
+ end
41
+
42
+ define_method :"#{pk}_group" do
43
+ group_values = group_block_names.map { |group_block_name| send(group_block_name) }
44
+ group_values.push(*Array(instance_eval(group_block))) if group_block
45
+ raise "amount of groups (#{group_values.length}) doesn't match amount of bits/total (#{bits.length})" if group_values.length != bits.length
46
+ group_values.each_with_index.reduce(0) do |group, (group_value, i)|
47
+ raise "group must implement #to_i, #{group_value} given" \
48
+ unless group_value.respond_to?(&:to_i)
49
+ (group << bits[i]) + (group_value.to_i % total[i])
50
+ end
51
+ end
52
+
53
+ define_method :"unique_#{pk}" do
54
+ primary_key = send(pk)
55
+ raise "#{pk} must implement #to_i, #{primary_key.inspect} given" \
56
+ unless primary_key.respond_to?(:to_i)
57
+ self.class.send(:"unique_#{pk}_from", send(:"#{pk}_group"), primary_key.to_i)
58
+ end
59
+
60
+ define_singleton_method :"find_by_unique_#{pk}" do |value|
61
+ send(:"find_by_#{pk}". send(:"#{pk}_from", value))
62
+ end
63
+
64
+ define_singleton_method :"find_by_unique_#{pk}!" do |value|
65
+ send(:"find_by_#{pk}!". send(:"#{pk}_from", value))
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ if defined?(ActiveRecord::Base)
72
+ ActiveRecord::Base.extend(UniqueBy::Generator)
73
+ end
@@ -0,0 +1,3 @@
1
+ module UniqueBy
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'unique_by/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "unique_by"
8
+ spec.version = UniqueBy::VERSION
9
+ spec.authors = ["Oded Niv"]
10
+ spec.email = ["oded.niv@gmail.com"]
11
+ spec.summary = %q{Specify uniqueness group for an attribute.}
12
+ spec.description = %q{Allows uniqueness of a record when sharding (specifying the shard ID as the group) or span accross tables (receipts).}
13
+ spec.homepage = ""
14
+ spec.license = "UNLICENSE"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rspec", "~> 3.1"
23
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: unique_by
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Oded Niv
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '3.1'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '3.1'
41
+ description: Allows uniqueness of a record when sharding (specifying the shard ID
42
+ as the group) or span accross tables (receipts).
43
+ email:
44
+ - oded.niv@gmail.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - .gitignore
50
+ - Gemfile
51
+ - README.md
52
+ - Rakefile
53
+ - UNLICENSE
54
+ - lib/unique_by.rb
55
+ - lib/unique_by/version.rb
56
+ - unique_by.gemspec
57
+ homepage: ''
58
+ licenses:
59
+ - UNLICENSE
60
+ metadata: {}
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubyforge_project:
77
+ rubygems_version: 2.2.2
78
+ signing_key:
79
+ specification_version: 4
80
+ summary: Specify uniqueness group for an attribute.
81
+ test_files: []