natural_key 0.2.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -24,7 +24,7 @@ With this in place, a method 'create_or_update_by_natural_key' can be used to in
24
24
  == INSTALL:
25
25
 
26
26
  gem sources -a http://gems.github.com
27
- gem install sjain-natural_key
27
+ gem install natural_key
28
28
 
29
29
  == LICENSE:
30
30
 
data/Rakefile CHANGED
@@ -1,3 +1,12 @@
1
1
  #!/usr/bin/env rake
2
2
  require "bundler/gem_tasks"
3
- #require "test/unit"
3
+ require 'rspec/core/rake_task'
4
+
5
+ desc 'Default: run specs.'
6
+ task :default => :spec
7
+
8
+ desc "Run specs"
9
+ RSpec::Core::RakeTask.new do |t|
10
+ t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
11
+ # Put spec opts in a file named .rspec in root
12
+ end
data/lib/natural_key.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  require 'natural_key/version'
2
+ require 'natural_key/base'
2
3
 
3
4
  module NaturalKey
4
5
  # Your code goes here...
5
6
  end
6
-
7
- require 'natural_key/base'
@@ -16,18 +16,35 @@ module ActiveRecord
16
16
  # TODO The following method should only be made available when natural_key is called with proper
17
17
  # attributes. (hint: use class_eval?)
18
18
  def create_or_update_by_natural_key(options)
19
- options.symbolize_keys!
20
- #TODO options should contain all key_attributes, and their values should be non-nil
21
- key_options = options.reject { |k,v| !key_attributes.include?(k) }
22
- raise "key_options cannot be empty" if key_options.empty?
23
- record = find(:first, :conditions => key_options)
19
+ record = locate_record(options)
24
20
  if(record.nil?)
25
21
  record = create(options)
22
+ else
23
+ record.update_attributes(options)
24
+ end
25
+ record
26
+ end
27
+
28
+ def create_or_update_by_natural_key!(options)
29
+ record = locate_record(options)
30
+ if(record.nil?)
31
+ record = create!(options)
26
32
  else
27
33
  record.update_attributes!(options)
28
34
  end
29
35
  record
30
36
  end
37
+
38
+ private
39
+
40
+ def locate_record(options)
41
+ options.symbolize_keys!
42
+ #TODO options should contain all key_attributes, and their values should be non-nil
43
+ key_options = options.reject { |k,v| !key_attributes.include?(k) }
44
+ raise "key_options cannot be empty" if key_options.empty?
45
+ find(:first, :conditions => key_options)
46
+ end
47
+
31
48
  end
32
49
  end
33
50
  end
@@ -1,3 +1,3 @@
1
1
  module NaturalKey
2
- VERSION = "0.2.2"
2
+ VERSION = "1.0.0"
3
3
  end
data/natural_key.gemspec CHANGED
@@ -13,40 +13,11 @@ Gem::Specification.new do |gem|
13
13
  gem.name = "natural_key"
14
14
  gem.require_paths = ["lib"]
15
15
  gem.version = NaturalKey::VERSION
16
+
16
17
  gem.add_dependency "activerecord", "~> 3.2.0"
18
+
17
19
  gem.add_development_dependency "rake", "~> 0.9.2.2"
18
- gem.add_development_dependency "minitest", "~> 3.0.0"
20
+ gem.add_development_dependency "rspec"
21
+ gem.add_development_dependency "sqlite3"
22
+ #gem.add_development_dependency "mocha"
19
23
  end
20
-
21
-
22
- # -*- encoding: utf-8 -*-
23
-
24
- #Gem::Specification.new do |s|
25
- #s.name = %q{natural_key}
26
- #s.version = NaturalKey::VERSION
27
-
28
- #s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
29
- #s.authors = ["Sharad Jain"]
30
- #s.date = %q{2010-02-26}
31
- #s.description = %q{ActiveRecord.create_or_update based on a user-defined natural-key}
32
- #s.email = %q{shaanjain@gmail.com}
33
- #s.extra_rdoc_files = ["CHANGELOG", "README.rdoc", "lib/natural_key.rb", "lib/natural_key/base.rb"]
34
- #s.files = ["CHANGELOG", "Manifest", "README.rdoc", "Rakefile", "VERSION.yml", "lib/natural_key.rb", "lib/natural_key/base.rb", "natural_key.gemspec", "test/database.yml", "test/fixtures/schema.rb", "test/lib/activerecord_test_case.rb", "test/lib/activerecord_test_connector.rb", "test/test_helper.rb", "test/test_natural_key.rb"]
35
- #s.homepage = %q{http://github.com/sjain/natural_key}
36
- #s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Natural_key", "--main", "README.rdoc"]
37
- #s.require_paths = ["lib"]
38
- #s.rubyforge_project = %q{natural_key}
39
- #s.rubygems_version = %q{1.3.5}
40
- #s.summary = %q{ActiveRecord.create_or_update based on a user-defined natural-key}
41
- #s.test_files = ["test/test_helper.rb", "test/test_natural_key.rb"]
42
-
43
- #if s.respond_to? :specification_version then
44
- # current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
45
- # s.specification_version = 3
46
- #
47
- # if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
48
- # else
49
- # end
50
- #else
51
- #end
52
- #end
@@ -0,0 +1,108 @@
1
+ require 'spec_helper'
2
+
3
+ class User < ActiveRecord::Base
4
+ #include NaturalKey
5
+ natural_key :first_name, :last_name
6
+
7
+ attr_accessor :age_required
8
+
9
+ validates :first_name, :presence => true
10
+ validates :age, :presence => true, :if => 'age_required == true'
11
+ end
12
+
13
+ describe NaturalKey do
14
+
15
+ before do
16
+ User.destroy_all
17
+ end
18
+
19
+ it "should create by natural key" do
20
+ created_record = User.create(:first_name => 'John', :last_name => "Smith", :age => 21, :address => "Chicago")
21
+ updated_record = User.create_or_update_by_natural_key(:first_name => 'Different', :last_name => "Smith", :age => 25, :address => "New York")
22
+ updated_record.id.should_not == created_record.id
23
+ updated_record.age.should == 25
24
+ updated_record.address.should == "New York"
25
+ end
26
+
27
+ it "should update by natural key" do
28
+ created_record = User.create(:first_name => 'John', :last_name => "Smith", :age => 21, :address => "Chicago")
29
+ updated_record = User.create_or_update_by_natural_key(:first_name => 'John', :last_name => "Smith", :age => 25, :address => "New York")
30
+ updated_record.id.should == created_record.id
31
+ updated_record.age.should == 25
32
+ updated_record.address.should == "New York"
33
+ end
34
+
35
+ it "should update by natural key when keys are strings instead of symbols" do
36
+ User.create(:first_name => 'Mary', :last_name => "Beth", :age => 21, :address => "Chicago")
37
+ john_smith = User.create(:first_name => 'John', :last_name => "Smith", :age => 21, :address => "Chicago")
38
+ updated_record = User.create_or_update_by_natural_key(
39
+ 'first_name' => 'John',
40
+ 'last_name' => "Smith",
41
+ 'age' => 25,
42
+ 'address' => "New York"
43
+ )
44
+ updated_record.id.should == john_smith.id
45
+ updated_record.age.should == 25
46
+ updated_record.address.should == "New York"
47
+ end
48
+
49
+ context 'returning invalid record on validation failure' do
50
+ it "should return invalid record with creation fails validation" do
51
+ record = User.create_or_update_by_natural_key(
52
+ :first_name => nil, # validation failure
53
+ )
54
+ record.should_not be_valid
55
+ record.errors.get(:first_name).should == ["can't be blank"]
56
+ end
57
+
58
+ it "should return invalid record with update fails validation" do
59
+ User.create(
60
+ :first_name => 'John',
61
+ :last_name => "Smith",
62
+ :age => 21,
63
+ :address => "Chicago"
64
+ )
65
+ updated_record = User.create_or_update_by_natural_key(
66
+ :first_name => 'John',
67
+ :last_name => "Smith",
68
+ :age_required => true,
69
+ :age => nil
70
+ )
71
+ updated_record.should_not be_valid
72
+ updated_record.errors.get(:age).should == ["can't be blank"]
73
+ end
74
+ end
75
+
76
+ context 'raise error on validation failure' do
77
+ it "should raise error on creation when validation fails" do
78
+ begin
79
+ User.create_or_update_by_natural_key!(
80
+ :first_name => nil, # validation failure
81
+ )
82
+ fail("Expected ActiveRecord exception, found none.")
83
+ rescue ActiveRecord::RecordInvalid => e
84
+ # expected
85
+ end
86
+ end
87
+ it "should raise error on update validation fails" do
88
+ User.create(
89
+ :first_name => 'John',
90
+ :last_name => "Smith",
91
+ :age => 21,
92
+ :address => "Chicago"
93
+ )
94
+ begin
95
+ User.create_or_update_by_natural_key!(
96
+ :first_name => 'John',
97
+ :last_name => "Smith",
98
+ :age_required => true,
99
+ :age => nil
100
+ )
101
+ rescue ActiveRecord::RecordInvalid
102
+ # expected
103
+ end
104
+ end
105
+ end
106
+
107
+
108
+ end
data/spec/schema.rb ADDED
@@ -0,0 +1,13 @@
1
+ ActiveRecord::Base.establish_connection(
2
+ adapter: "sqlite3",
3
+ database: ":memory:"
4
+ )
5
+
6
+ ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'users'")
7
+ ActiveRecord::Base.connection.create_table(:users) do |t|
8
+ t.string :first_name
9
+ t.string :last_name
10
+ t.integer :age
11
+ t.string :address
12
+ t.integer :salary, :default => 70000
13
+ end
@@ -0,0 +1,7 @@
1
+ require 'natural_key'
2
+ #require 'mocha'
3
+ require 'schema'
4
+
5
+ RSpec.configure do |config|
6
+ # nothing yet
7
+ end
metadata CHANGED
@@ -1,81 +1,68 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: natural_key
3
- version: !ruby/object:Gem::Version
4
- hash: 19
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 2
9
- - 2
10
- version: 0.2.2
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Sharad Jain
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2012-05-10 00:00:00 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- version_requirements: &id001 !ruby/object:Gem::Requirement
12
+ date: 2012-06-05 00:00:00.000000000 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activerecord
17
+ requirement: &2157335700 !ruby/object:Gem::Requirement
22
18
  none: false
23
- requirements:
19
+ requirements:
24
20
  - - ~>
25
- - !ruby/object:Gem::Version
26
- hash: 15
27
- segments:
28
- - 3
29
- - 2
30
- - 0
21
+ - !ruby/object:Gem::Version
31
22
  version: 3.2.0
32
- prerelease: false
33
- requirement: *id001
34
23
  type: :runtime
35
- name: activerecord
36
- - !ruby/object:Gem::Dependency
37
- version_requirements: &id002 !ruby/object:Gem::Requirement
24
+ prerelease: false
25
+ version_requirements: *2157335700
26
+ - !ruby/object:Gem::Dependency
27
+ name: rake
28
+ requirement: &2157334880 !ruby/object:Gem::Requirement
38
29
  none: false
39
- requirements:
30
+ requirements:
40
31
  - - ~>
41
- - !ruby/object:Gem::Version
42
- hash: 11
43
- segments:
44
- - 0
45
- - 9
46
- - 2
47
- - 2
32
+ - !ruby/object:Gem::Version
48
33
  version: 0.9.2.2
49
- prerelease: false
50
- requirement: *id002
51
34
  type: :development
52
- name: rake
53
- - !ruby/object:Gem::Dependency
54
- version_requirements: &id003 !ruby/object:Gem::Requirement
35
+ prerelease: false
36
+ version_requirements: *2157334880
37
+ - !ruby/object:Gem::Dependency
38
+ name: rspec
39
+ requirement: &2157334200 !ruby/object:Gem::Requirement
55
40
  none: false
56
- requirements:
57
- - - ~>
58
- - !ruby/object:Gem::Version
59
- hash: 7
60
- segments:
61
- - 3
62
- - 0
63
- - 0
64
- version: 3.0.0
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ type: :development
65
46
  prerelease: false
66
- requirement: *id003
47
+ version_requirements: *2157334200
48
+ - !ruby/object:Gem::Dependency
49
+ name: sqlite3
50
+ requirement: &2157332480 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
67
56
  type: :development
68
- name: minitest
57
+ prerelease: false
58
+ version_requirements: *2157332480
69
59
  description: ActiveRecord.create_or_update based on a user-defined natural-key
70
- email:
60
+ email:
71
61
  - shaanjain@gmail.com
72
62
  executables: []
73
-
74
63
  extensions: []
75
-
76
64
  extra_rdoc_files: []
77
-
78
- files:
65
+ files:
79
66
  - .gitignore
80
67
  - Gemfile
81
68
  - README.rdoc
@@ -86,49 +73,41 @@ files:
86
73
  - natural_key.gemspec
87
74
  - script/console
88
75
  - script/console.cmd
89
- - test/database.yml
90
- - test/fixtures/schema.rb
91
- - test/lib/activerecord_test_case.rb
92
- - test/lib/activerecord_test_connector.rb
93
- - test/test_helper.rb
94
- - test/test_natural_key.rb
76
+ - spec/natural_key/base_spec.rb
77
+ - spec/schema.rb
78
+ - spec/spec_helper.rb
79
+ has_rdoc: true
95
80
  homepage: http://github.com/sjain/natural_key
96
81
  licenses: []
97
-
98
82
  post_install_message:
99
83
  rdoc_options: []
100
-
101
- require_paths:
84
+ require_paths:
102
85
  - lib
103
- required_ruby_version: !ruby/object:Gem::Requirement
86
+ required_ruby_version: !ruby/object:Gem::Requirement
104
87
  none: false
105
- requirements:
106
- - - ">="
107
- - !ruby/object:Gem::Version
108
- hash: 3
109
- segments:
88
+ requirements:
89
+ - - ! '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ segments:
110
93
  - 0
111
- version: "0"
112
- required_rubygems_version: !ruby/object:Gem::Requirement
94
+ hash: 743010638410990413
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
96
  none: false
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- hash: 3
118
- segments:
97
+ requirements:
98
+ - - ! '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ segments:
119
102
  - 0
120
- version: "0"
103
+ hash: 743010638410990413
121
104
  requirements: []
122
-
123
105
  rubyforge_project:
124
- rubygems_version: 1.8.11
106
+ rubygems_version: 1.6.2
125
107
  signing_key:
126
108
  specification_version: 3
127
109
  summary: ActiveRecord.create_or_update based on a user-defined natural-key
128
- test_files:
129
- - test/database.yml
130
- - test/fixtures/schema.rb
131
- - test/lib/activerecord_test_case.rb
132
- - test/lib/activerecord_test_connector.rb
133
- - test/test_helper.rb
134
- - test/test_natural_key.rb
110
+ test_files:
111
+ - spec/natural_key/base_spec.rb
112
+ - spec/schema.rb
113
+ - spec/spec_helper.rb
data/test/database.yml DELETED
@@ -1,23 +0,0 @@
1
- mysql:
2
- adapter: mysql
3
- username: arnk
4
- password: arnk
5
- encoding: utf8
6
- database: ar_natural_key_test
7
- host: 127.0.0.1
8
-
9
- sqlite3:
10
- database: ":memory:"
11
- adapter: sqlite3
12
- timeout: 500
13
-
14
- sqlite2:
15
- database: ":memory:"
16
- adapter: sqlite2
17
-
18
- postgres:
19
- adapter: postgresql
20
- username: postgres
21
- password: postgres
22
- database: arnk_test
23
- min_messages: warning
@@ -1,9 +0,0 @@
1
- ActiveRecord::Schema.define do
2
- create_table :users, :force => true do |t|
3
- t.string :first_name
4
- t.string :last_name
5
- t.integer :age
6
- t.string :address
7
- t.integer :salary, :default => 70000
8
- end
9
- end
@@ -1,34 +0,0 @@
1
- require 'lib/activerecord_test_connector'
2
-
3
- class ActiveRecordTestCase < ActiveRecord::TestCase
4
- include ActiveRecord::TestFixtures
5
-
6
- # Set our fixture path
7
- if ActiveRecordTestConnector.able_to_connect
8
- self.fixture_path = File.join(File.dirname(__FILE__), '..', 'fixtures')
9
- self.use_transactional_fixtures = true
10
- end
11
-
12
- def self.fixtures(*args)
13
- super if ActiveRecordTestConnector.connected
14
- end
15
-
16
- def run(*args)
17
- super if ActiveRecordTestConnector.connected
18
- end
19
-
20
- protected
21
-
22
- def assert_queries(num = 1)
23
- $query_count = 0
24
- yield
25
- ensure
26
- assert_equal num, $query_count, "#{$query_count} instead of #{num} queries were executed."
27
- end
28
-
29
- def assert_no_queries(&block)
30
- assert_queries(0, &block)
31
- end
32
- end
33
-
34
- ActiveRecordTestConnector.setup
@@ -1,76 +0,0 @@
1
- require 'rubygems'
2
- require 'active_record'
3
- require 'active_record/version'
4
- require 'active_record/fixtures'
5
-
6
- class ActiveRecordTestConnector
7
- cattr_accessor :able_to_connect
8
- cattr_accessor :connected
9
-
10
- FIXTURES_PATH = File.join(File.dirname(__FILE__), '..', 'fixtures')
11
-
12
- # Set our defaults
13
- self.connected = false
14
- self.able_to_connect = true
15
-
16
- def self.setup
17
- unless self.connected || !self.able_to_connect
18
- setup_connection
19
- load_schema
20
- add_load_path FIXTURES_PATH
21
- self.connected = true
22
- end
23
- rescue Exception => e # errors from ActiveRecord setup
24
- $stderr.puts "\nSkipping ActiveRecord tests: #{e}\n\n"
25
- self.able_to_connect = false
26
- end
27
-
28
- private
29
-
30
- def self.add_load_path(path)
31
- dep = defined?(ActiveSupport::Dependencies) ? ActiveSupport::Dependencies : ::Dependencies
32
- dep.load_paths.unshift path
33
- end
34
-
35
- def self.setup_connection
36
- db = ENV['DB'].blank?? 'sqlite3' : ENV['DB']
37
-
38
- configurations = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'database.yml'))
39
- raise "no configuration for '#{db}'" unless configurations.key? db
40
- configuration = configurations[db]
41
-
42
- ActiveRecord::Base.logger = Logger.new(STDOUT) if $0 == 'irb'
43
- puts "using #{configuration['adapter']} adapter" unless ENV['DB'].blank?
44
-
45
- gem 'sqlite3-ruby' if 'sqlite3' == db
46
-
47
- ActiveRecord::Base.establish_connection(configuration)
48
- ActiveRecord::Base.configurations = { db => configuration }
49
- prepare ActiveRecord::Base.connection
50
-
51
- unless Object.const_defined?(:QUOTED_TYPE)
52
- Object.send :const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type')
53
- end
54
- end
55
-
56
- def self.load_schema
57
- ActiveRecord::Base.silence do
58
- ActiveRecord::Migration.verbose = false
59
- load File.join(FIXTURES_PATH, 'schema.rb')
60
- end
61
- end
62
-
63
- def self.prepare(conn)
64
- class << conn
65
- IGNORED_SQL = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SHOW FIELDS /]
66
-
67
- def execute_with_counting(sql, name = nil, &block)
68
- $query_count ||= 0
69
- $query_count += 1 unless IGNORED_SQL.any? { |r| sql =~ r }
70
- execute_without_counting(sql, name, &block)
71
- end
72
-
73
- alias_method_chain :execute, :counting
74
- end
75
- end
76
- end
data/test/test_helper.rb DELETED
@@ -1,16 +0,0 @@
1
- $:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
2
-
3
- require 'stringio'
4
- #require 'test/unit'
5
- require 'lib/activerecord_test_case'
6
- #require File.dirname(__FILE__) + '/../lib/natural_key'
7
-
8
- # gem install redgreen for colored test output
9
- #begin require 'redgreen'; rescue LoadError; end
10
-
11
- # The following is not required since we use active-record gem installed on the system
12
- #require 'boot' unless defined?(ActiveRecord)
13
-
14
- class Test::Unit::TestCase
15
- # any test helper methods can go here
16
- end
@@ -1,33 +0,0 @@
1
- require File.dirname(__FILE__) + '/test_helper.rb'
2
-
3
- class User < ActiveRecord::Base
4
- natural_key :first_name, :last_name
5
- end
6
-
7
- class TestNaturalKey < ActiveRecordTestCase
8
- def test_create_by_natural_key
9
- created_record = User.create(:first_name => 'John', :last_name => "Smith", :age => 21, :address => "Chicago")
10
- updated_record = User.create_or_update_by_natural_key(:first_name => 'Different', :last_name => "Smith", :age => 25, :address => "New York")
11
- assert_not_equal(created_record.id, updated_record.id)
12
- assert_equal(25, updated_record.age)
13
- assert_equal("New York", updated_record.address)
14
- end
15
- def test_update_by_natural_key
16
- created_record = User.create(:first_name => 'John', :last_name => "Smith", :age => 21, :address => "Chicago")
17
- updated_record = User.create_or_update_by_natural_key(:first_name => 'John', :last_name => "Smith", :age => 25, :address => "New York")
18
- assert_equal(created_record.id, updated_record.id)
19
- assert_equal(25, updated_record.age)
20
- assert_equal("New York", updated_record.address)
21
- end
22
- def test_update_by_natural_key_when_keys_are_strings_instead_of_symbols
23
- User.create(:first_name => 'Mary', :last_name => "Beth", :age => 21, :address => "Chicago")
24
- john_smith = User.create(:first_name => 'John', :last_name => "Smith", :age => 21, :address => "Chicago")
25
- updated_record = User.create_or_update_by_natural_key('first_name' => 'John',
26
- 'last_name' => "Smith",
27
- 'age' => 25,
28
- 'address' => "New York")
29
- assert_equal(john_smith.id, updated_record.id)
30
- assert_equal(25, updated_record.age)
31
- assert_equal("New York", updated_record.address)
32
- end
33
- end