sjain-natural_key 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ pkg/*
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 0.0.1 2009-01-07
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/Manifest.txt ADDED
@@ -0,0 +1,14 @@
1
+ .gitignore
2
+ History.txt
3
+ lib/natural_key/natural_key.rb
4
+ lib/natural_key.rb
5
+ Manifest.txt
6
+ PostInstall.txt
7
+ Rakefile
8
+ README.rdoc
9
+ test/database.yml
10
+ test/fixtures/schema.rb
11
+ test/lib/activerecord_test_case.rb
12
+ test/lib/activerecord_test_connector.rb
13
+ test/test_helper.rb
14
+ test/test_natural_key.rb
data/PostInstall.txt ADDED
@@ -0,0 +1,7 @@
1
+
2
+ For more information on ar_natural_key_utils, see http://ar_natural_key_utils.rubyforge.org
3
+
4
+ NOTE: Change this information in PostInstall.txt
5
+ You can also delete it if you don't want it.
6
+
7
+
data/README.rdoc ADDED
@@ -0,0 +1,55 @@
1
+ = natural_key
2
+
3
+ * http://www.pathf.com
4
+
5
+ == DESCRIPTION:
6
+
7
+ This gem adds create_or_update functionality to ActiveRecord based on a user-defined natural-key.
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ * TODO
12
+
13
+ == SYNOPSIS:
14
+
15
+ #
16
+ # Table users(first_name varchar, last_name varchar, age integer, address string, salary integer)
17
+ #
18
+ class User < ActiveRecord::Base
19
+ natural_key :first_name, :last_name
20
+ end
21
+
22
+ User.create_or_update_by_natural_key(:first_name => 'John', :last_name => "Smith", :age => 25, :address => "New York")
23
+
24
+ == REQUIREMENTS:
25
+
26
+ * TODO
27
+
28
+ == INSTALL:
29
+
30
+ * gem install natural_key; rake gems:unpack GEM=natural_key
31
+
32
+ == LICENSE:
33
+
34
+ (The MIT License)
35
+
36
+ Copyright (c) 2009 FIXME full name
37
+
38
+ Permission is hereby granted, free of charge, to any person obtaining
39
+ a copy of this software and associated documentation files (the
40
+ 'Software'), to deal in the Software without restriction, including
41
+ without limitation the rights to use, copy, modify, merge, publish,
42
+ distribute, sublicense, and/or sell copies of the Software, and to
43
+ permit persons to whom the Software is furnished to do so, subject to
44
+ the following conditions:
45
+
46
+ The above copyright notice and this permission notice shall be
47
+ included in all copies or substantial portions of the Software.
48
+
49
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
50
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
51
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
52
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
53
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
54
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
55
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ %w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
2
+ require File.dirname(__FILE__) + '/lib/natural_key'
3
+
4
+ # Generate all the Rake tasks
5
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
6
+ $hoe = Hoe.new('natural_key', NaturalKey::VERSION) do |p|
7
+ p.developer('Pathfinder Associates', 'info@pathf.com')
8
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
9
+ p.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
10
+ p.rubyforge_name = p.name # TODO this is default value
11
+ # p.extra_deps = [
12
+ # ['activesupport','>= 2.0.2'],
13
+ # ]
14
+ p.extra_dev_deps = [
15
+ ['newgem', ">= #{::Newgem::VERSION}"]
16
+ ]
17
+
18
+ p.clean_globs |= %w[**/.DS_Store tmp *.log]
19
+ path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
20
+ p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
21
+ p.rsync_args = '-av --delete --ignore-errors'
22
+ end
23
+
24
+ require 'newgem/tasks' # load /tasks/*.rake
25
+ Dir['tasks/**/*.rake'].each { |t| load t }
26
+
27
+ # TODO - want other tests/tasks run by default? Add them to the list
28
+ # task :default => [:spec, :features]
@@ -0,0 +1,37 @@
1
+ module ActiveRecord
2
+ class Base
3
+ class << self
4
+ def natural_key(*key_attributes)
5
+ # TODO validate the supplied key_attributes are subset of all attributes
6
+ # TODO key_attributes should default to primary_key/surrogate_key (:id)
7
+ # TODO if natural_key is composed of non-primary-key, then it should not contain primary_key
8
+ raise "natural key attributes cannot be empty" if key_attributes.empty?
9
+ @@key_attributes = key_attributes
10
+ end
11
+
12
+ # can't use method "create_or_update" since there is already a private method with that name
13
+ # in ActiveRecord::Base
14
+ # TODO The following method should only be made available when natural_key is called with proper
15
+ # attributes. (hint: use class_eval?)
16
+ def create_or_update_by_natural_key(options)
17
+ #TODO options should contain all key_attributes, and their values should be non-nil
18
+ key_options = options.reject { |k,v| !@@key_attributes.include?(k) }
19
+ record = find(:first, :conditions => key_options)
20
+ if(record.nil?)
21
+ record = create(options)
22
+ else
23
+ record.update_attributes!(options)
24
+ end
25
+ record
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ #module NaturalKey
32
+ # def self.included other
33
+ # other.extend self
34
+ # end
35
+ #end
36
+ #
37
+ #ActiveRecord::Base.send :include, NaturalKey
@@ -0,0 +1,8 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'natural_key/natural_key'
5
+
6
+ module NaturalKey
7
+ VERSION = '0.0.1'
8
+ end
data/test/database.yml ADDED
@@ -0,0 +1,23 @@
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
@@ -0,0 +1,9 @@
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
@@ -0,0 +1,36 @@
1
+ require 'lib/activerecord_test_connector'
2
+
3
+ class ActiveRecordTestCase < Test::Unit::TestCase
4
+ # Set our fixture path
5
+ if ActiveRecordTestConnector.able_to_connect
6
+ self.fixture_path = File.join(File.dirname(__FILE__), '..', 'fixtures')
7
+ self.use_transactional_fixtures = true
8
+ end
9
+
10
+ def self.fixtures(*args)
11
+ super if ActiveRecordTestConnector.connected
12
+ end
13
+
14
+ def run(*args)
15
+ super if ActiveRecordTestConnector.connected
16
+ end
17
+
18
+ # Default so Test::Unit::TestCase doesn't complain
19
+ def test_truth
20
+ end
21
+
22
+ protected
23
+
24
+ def assert_queries(num = 1)
25
+ $query_count = 0
26
+ yield
27
+ ensure
28
+ assert_equal num, $query_count, "#{$query_count} instead of #{num} queries were executed."
29
+ end
30
+
31
+ def assert_no_queries(&block)
32
+ assert_queries(0, &block)
33
+ end
34
+ end
35
+
36
+ ActiveRecordTestConnector.setup
@@ -0,0 +1,75 @@
1
+ require 'active_record'
2
+ require 'active_record/version'
3
+ require 'active_record/fixtures'
4
+
5
+ class ActiveRecordTestConnector
6
+ cattr_accessor :able_to_connect
7
+ cattr_accessor :connected
8
+
9
+ FIXTURES_PATH = File.join(File.dirname(__FILE__), '..', 'fixtures')
10
+
11
+ # Set our defaults
12
+ self.connected = false
13
+ self.able_to_connect = true
14
+
15
+ def self.setup
16
+ unless self.connected || !self.able_to_connect
17
+ setup_connection
18
+ load_schema
19
+ add_load_path FIXTURES_PATH
20
+ self.connected = true
21
+ end
22
+ rescue Exception => e # errors from ActiveRecord setup
23
+ $stderr.puts "\nSkipping ActiveRecord tests: #{e}\n\n"
24
+ self.able_to_connect = false
25
+ end
26
+
27
+ private
28
+
29
+ def self.add_load_path(path)
30
+ dep = defined?(ActiveSupport::Dependencies) ? ActiveSupport::Dependencies : ::Dependencies
31
+ dep.load_paths.unshift path
32
+ end
33
+
34
+ def self.setup_connection
35
+ db = ENV['DB'].blank?? 'mysql' : ENV['DB']
36
+
37
+ configurations = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'database.yml'))
38
+ raise "no configuration for '#{db}'" unless configurations.key? db
39
+ configuration = configurations[db]
40
+
41
+ ActiveRecord::Base.logger = Logger.new(STDOUT) if $0 == 'irb'
42
+ puts "using #{configuration['adapter']} adapter" unless ENV['DB'].blank?
43
+
44
+ gem 'sqlite3-ruby' if 'sqlite3' == db
45
+
46
+ ActiveRecord::Base.establish_connection(configuration)
47
+ ActiveRecord::Base.configurations = { db => configuration }
48
+ prepare ActiveRecord::Base.connection
49
+
50
+ unless Object.const_defined?(:QUOTED_TYPE)
51
+ Object.send :const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type')
52
+ end
53
+ end
54
+
55
+ def self.load_schema
56
+ ActiveRecord::Base.silence do
57
+ ActiveRecord::Migration.verbose = false
58
+ load File.join(FIXTURES_PATH, 'schema.rb')
59
+ end
60
+ end
61
+
62
+ def self.prepare(conn)
63
+ class << conn
64
+ IGNORED_SQL = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SHOW FIELDS /]
65
+
66
+ def execute_with_counting(sql, name = nil, &block)
67
+ $query_count ||= 0
68
+ $query_count += 1 unless IGNORED_SQL.any? { |r| sql =~ r }
69
+ execute_without_counting(sql, name, &block)
70
+ end
71
+
72
+ alias_method_chain :execute, :counting
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,14 @@
1
+ require 'stringio'
2
+ require 'test/unit'
3
+ require 'lib/activerecord_test_case'
4
+ require File.dirname(__FILE__) + '/../lib/natural_key'
5
+
6
+ # gem install redgreen for colored test output
7
+ begin require 'redgreen'; rescue LoadError; end
8
+
9
+ # The following is not required since we use active-record gem installed on the system
10
+ #require 'boot' unless defined?(ActiveRecord)
11
+
12
+ class Test::Unit::TestCase
13
+ # any test helper methods can go here
14
+ end
@@ -0,0 +1,22 @@
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_update_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 => 'John', :last_name => "Smith", :age => 25, :address => "New York")
11
+ assert_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_create_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 => 'Different', :last_name => "Smith", :age => 25, :address => "New York")
18
+ assert_not_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
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sjain-natural_key
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Pathfinder Associates
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-09 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: newgem
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.2.3
23
+ version:
24
+ - !ruby/object:Gem::Dependency
25
+ name: hoe
26
+ version_requirement:
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: 1.8.0
32
+ version:
33
+ description: This gem adds create_or_update functionality to ActiveRecord based on a user-defined natural-key.
34
+ email:
35
+ - info@pathf.com
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files:
41
+ - History.txt
42
+ - Manifest.txt
43
+ - PostInstall.txt
44
+ - README.rdoc
45
+ files:
46
+ - .gitignore
47
+ - History.txt
48
+ - lib/natural_key/natural_key.rb
49
+ - lib/natural_key.rb
50
+ - Manifest.txt
51
+ - PostInstall.txt
52
+ - Rakefile
53
+ - README.rdoc
54
+ - test/database.yml
55
+ - test/fixtures/schema.rb
56
+ - test/lib/activerecord_test_case.rb
57
+ - test/lib/activerecord_test_connector.rb
58
+ - test/test_helper.rb
59
+ - test/test_natural_key.rb
60
+ has_rdoc: true
61
+ homepage: http://www.pathf.com
62
+ post_install_message: PostInstall.txt
63
+ rdoc_options:
64
+ - --main
65
+ - README.rdoc
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ version:
80
+ requirements: []
81
+
82
+ rubyforge_project: natural_key
83
+ rubygems_version: 1.2.0
84
+ signing_key:
85
+ specification_version: 2
86
+ summary: This gem adds create_or_update functionality to ActiveRecord based on a user-defined natural-key.
87
+ test_files:
88
+ - test/test_helper.rb
89
+ - test/test_natural_key.rb