natural_key 0.2.2 → 1.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.
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