is_unique 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.
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gemspec|
4
+ gemspec.name = "is_unique"
5
+ gemspec.summary = "ActiveRecord extension to prevent duplicate records"
6
+ gemspec.description = "Makes ActiveRecord return existing records instead of creating duplicates"
7
+ gemspec.email = "eugene.bolshakov@gmail.com"
8
+ gemspec.homepage = "http://github.com/loco2/is_unique"
9
+ gemspec.authors = ["Eugene Bolshakov"]
10
+ gemspec.add_dependency 'activerecord', '2.3.5'
11
+ end
12
+ Jeweler::GemcutterTasks.new
13
+ rescue LoadError
14
+ puts "Jeweler not available. Install it with: gem install jeweler"
15
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,16 @@
1
+ class IsUniqueGenerator < Rails::Generator::NamedBase
2
+ def manifest
3
+ record do |m|
4
+ m.migration_template 'is_unique_migration.rb', 'db/migrate',
5
+ :assigns => {:unique_hash_column => actions.first || 'unique_hash' }
6
+ end
7
+ end
8
+
9
+ def banner
10
+ "Usage: #{$0} #{spec.name} ModelName [custom_unique_has_column_name] [options]"
11
+ end
12
+
13
+ def file_name
14
+ "add_unique_hash_column_to_#{@plural_name}"
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ class <%= file_name.camelcase %> < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :<%= table_name %>, :<%= unique_hash_column %>, :integer
4
+ add_index :<%= table_name %>, :<%= unique_hash_column %>
5
+ end
6
+
7
+ def self.down
8
+ remove_column :<%= table_name %>, :<%= unique_hash_column %>
9
+ end
10
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), 'lib', 'is_unique')
data/is_unique.gemspec ADDED
@@ -0,0 +1,51 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{is_unique}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Eugene Bolshakov"]
12
+ s.date = %q{2010-03-22}
13
+ s.description = %q{Makes ActiveRecord return existing records instead of creating duplicates}
14
+ s.email = %q{eugene.bolshakov@gmail.com}
15
+ s.files = [
16
+ "Rakefile",
17
+ "VERSION",
18
+ "generators/is_unique/is_unique_generator.rb",
19
+ "generators/is_unique/templates/is_unique_migration.rb",
20
+ "init.rb",
21
+ "is_unique.gemspec",
22
+ "lib/is_unique.rb",
23
+ "spec/spec_helper.rb",
24
+ "spec/support/db.rb",
25
+ "spec/unique_model_spec.rb"
26
+ ]
27
+ s.homepage = %q{http://github.com/loco2/is_unique}
28
+ s.rdoc_options = ["--charset=UTF-8"]
29
+ s.require_paths = ["lib"]
30
+ s.rubygems_version = %q{1.3.6}
31
+ s.summary = %q{ActiveRecord extension to prevent duplicate records}
32
+ s.test_files = [
33
+ "spec/unique_model_spec.rb",
34
+ "spec/support/db.rb",
35
+ "spec/spec_helper.rb"
36
+ ]
37
+
38
+ if s.respond_to? :specification_version then
39
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
40
+ s.specification_version = 3
41
+
42
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
43
+ s.add_runtime_dependency(%q<activerecord>, ["= 2.3.5"])
44
+ else
45
+ s.add_dependency(%q<activerecord>, ["= 2.3.5"])
46
+ end
47
+ else
48
+ s.add_dependency(%q<activerecord>, ["= 2.3.5"])
49
+ end
50
+ end
51
+
data/lib/is_unique.rb ADDED
@@ -0,0 +1,61 @@
1
+ module IsUnique
2
+ def self.included(base)
3
+ base.extend ClassMethods
4
+ end
5
+
6
+ module ClassMethods
7
+ def is_unique(options = {})
8
+
9
+ write_inheritable_attribute :is_unique_hash_column, options[:hash_column] || 'unique_hash'
10
+ class_inheritable_reader :is_unique_hash_column
11
+
12
+ write_inheritable_attribute :is_unique_ignore, [
13
+ primary_key,
14
+ is_unique_hash_column.to_s,
15
+ 'created_at',
16
+ 'updated_at'
17
+ ].concat(Array(options[:ignore]).map(&:to_s))
18
+
19
+ self.class_eval do
20
+ include InstanceMethods
21
+
22
+ before_save :calculate_unique_hash
23
+ end
24
+ end
25
+ end
26
+
27
+ module InstanceMethods
28
+ private
29
+
30
+ def is_unique_hash
31
+ send(self.class.is_unique_hash_column)
32
+ end
33
+
34
+ def is_unique_hash=(value)
35
+ send("#{self.class.is_unique_hash_column}=", value)
36
+ end
37
+
38
+ def create
39
+ if existing = self.class.find(:first, :conditions => {self.class.is_unique_hash_column => is_unique_hash})
40
+ self.id = existing.id
41
+ @new_record = false
42
+ reload
43
+ id
44
+ else
45
+ super
46
+ end
47
+ end
48
+
49
+ def calculate_unique_hash
50
+ self.is_unique_hash = unique_attributes.hash
51
+ end
52
+
53
+ def unique_attributes
54
+ attributes.except(*self.class.read_inheritable_attribute(:is_unique_ignore))
55
+ end
56
+ end
57
+ end
58
+
59
+ ActiveRecord::Base.class_eval do
60
+ include IsUnique
61
+ end
@@ -0,0 +1,5 @@
1
+ require 'active_record'
2
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/is_unique")
3
+ require 'spec'
4
+
5
+ Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
@@ -0,0 +1,31 @@
1
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
2
+
3
+ def suppress_stdout
4
+ tmp = $stdout
5
+ $stdout = StringIO.new
6
+ yield
7
+ $stdout = tmp
8
+ end
9
+
10
+ def setup_db
11
+ ActiveRecord::Schema.define(:version => 1) do
12
+ create_table :locations do |t|
13
+ t.string :name
14
+ t.float :lat, :lng
15
+ t.string :alias
16
+ t.integer :unique_hash
17
+ t.timestamps
18
+ end
19
+ end
20
+ end
21
+
22
+ def teardown_db
23
+ ActiveRecord::Base.connection.tables.each do |table|
24
+ ActiveRecord::Base.connection.drop_table(table)
25
+ end
26
+ end
27
+
28
+ Spec::Runner.configure do |config|
29
+ config.before(:all) { suppress_stdout { setup_db } }
30
+ config.after(:all) { suppress_stdout { teardown_db } }
31
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ class Location < ActiveRecord::Base
4
+ # String name
5
+ # Float lat
6
+ # Float lng
7
+ # String alias
8
+ # Integer unique_hash
9
+
10
+ is_unique :ignore => :alias
11
+ end
12
+
13
+ describe "A unique model" do
14
+ before(:each) do
15
+ @it = Location.create(
16
+ :name => 'London',
17
+ :lat => '51.5084152563931',
18
+ :lng => '-0.125532746315002',
19
+ :alias => 'Londinium'
20
+ )
21
+ end
22
+
23
+ it "should not create a new record with the same attributes" do
24
+ new_record = @it.clone
25
+ lambda { new_record.save! }.
26
+ should_not change(Location, :count)
27
+ end
28
+
29
+ it "should not create a new record with a different ignored attribute" do
30
+ new_record = @it.clone
31
+ new_record.alias = 'Greater London'
32
+ lambda { new_record.save! }.
33
+ should_not change(Location, :count)
34
+ end
35
+
36
+ it "should return the existing record on creation" do
37
+ new_record = @it.clone
38
+ new_record.save!
39
+ new_record.should == @it
40
+ end
41
+
42
+ it "should allow to create a record with different attributes" do
43
+ new_record = @it.clone
44
+ new_record.name = 'Greater London'
45
+ lambda { new_record.save! }.
46
+ should change(Location, :count).by(1)
47
+ new_record.should_not == @it
48
+ end
49
+
50
+ it "should allow to create a record with original attributes when an existing record is updated" do
51
+ new_record = @it.clone
52
+ @it.update_attribute(:name, 'Greater London')
53
+ lambda { new_record.save! }.
54
+ should change(Location, :count).by(1)
55
+ new_record.should_not == @it
56
+ end
57
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: is_unique
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Eugene Bolshakov
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-03-22 00:00:00 +03:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: activerecord
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 2
29
+ - 3
30
+ - 5
31
+ version: 2.3.5
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ description: Makes ActiveRecord return existing records instead of creating duplicates
35
+ email: eugene.bolshakov@gmail.com
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files: []
41
+
42
+ files:
43
+ - Rakefile
44
+ - VERSION
45
+ - generators/is_unique/is_unique_generator.rb
46
+ - generators/is_unique/templates/is_unique_migration.rb
47
+ - init.rb
48
+ - is_unique.gemspec
49
+ - lib/is_unique.rb
50
+ - spec/spec_helper.rb
51
+ - spec/support/db.rb
52
+ - spec/unique_model_spec.rb
53
+ has_rdoc: true
54
+ homepage: http://github.com/loco2/is_unique
55
+ licenses: []
56
+
57
+ post_install_message:
58
+ rdoc_options:
59
+ - --charset=UTF-8
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ segments:
67
+ - 0
68
+ version: "0"
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ requirements: []
77
+
78
+ rubyforge_project:
79
+ rubygems_version: 1.3.6
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: ActiveRecord extension to prevent duplicate records
83
+ test_files:
84
+ - spec/unique_model_spec.rb
85
+ - spec/support/db.rb
86
+ - spec/spec_helper.rb