obsidian 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,4 @@
1
+ 2008-03-28
2
+ * Added model_update_tracker
3
+ * Added example rails applicaion in branch example
4
+
@@ -0,0 +1,9 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/obsidian.rb
6
+ lib/obsidian/rails/model_update_tracker.rb
7
+ test/obsidian_test.rb
8
+ test/test_helper.rb
9
+ test/obsidian/rails/model_update_tracker_test.rb
@@ -0,0 +1,76 @@
1
+ = Obsidian
2
+
3
+ http://opensource.thinkrelevance.com
4
+
5
+ == DESCRIPTION:
6
+
7
+ Obsidian. It's metastable.
8
+ Chunks of Ruby code we have found helpful.
9
+
10
+ == FEATURES/PROBLEMS:
11
+
12
+ === Model Update Tracker
13
+ This library allows you to functionally test updates to models with clearer and more focused intent.
14
+ It forces you to have a better understanding of how your Objects interact and let's you demonstrate
15
+ that knowledge by putting it in your tests. For example instead of writing a test like so
16
+
17
+ assert_difference Asset :count do
18
+ post :create, :asset => {}
19
+ end
20
+
21
+ you would write your test like so
22
+
23
+ assert_models_created(Asset) do
24
+ post :create, :asset => {}
25
+ end
26
+
27
+ Now if an asset really created multiple other objects such as an asset owner and a location the above
28
+ test would fail stating that it expected more to happen. This is where you excercise your deep domain
29
+ knowledge muscles and make your new obsidian powered test pass.
30
+
31
+ assert_models_saved(Asset, AssetOwner, Location) do
32
+ post: create, :asset => {}
33
+ end
34
+
35
+ You have just done youself a great service. If for some reason you change code that affects your
36
+ object model and things fall out of place this test will catch that regression error where the original
37
+ assert_difference may not. There are also a whole host of other methods you can use with model update
38
+ tracker that provide functionality for updates, deletes, and no_difference assertions.
39
+
40
+ * assert_models_created(models)
41
+ * assert_models_updated(models)
42
+ * assert_models_destroyed(models)
43
+ * assert_no_models_created
44
+ * assert_no_models_destroyed
45
+ * assert_no_models_updated
46
+
47
+ == INSTALL:
48
+
49
+ git clone git://github.com/relevance/obsidian.git
50
+ rake gem
51
+ sudo gem install pkg/#{pkg_name}
52
+
53
+ == LICENSE:
54
+
55
+ (The MIT License)
56
+
57
+ Copyright (c) 2008 Relevance, Inc.
58
+
59
+ Permission is hereby granted, free of charge, to any person obtaining
60
+ a copy of this software and associated documentation files (the
61
+ 'Software'), to deal in the Software without restriction, including
62
+ without limitation the rights to use, copy, modify, merge, publish,
63
+ distribute, sublicense, and/or sell copies of the Software, and to
64
+ permit persons to whom the Software is furnished to do so, subject to
65
+ the following conditions:
66
+
67
+ The above copyright notice and this permission notice shall be
68
+ included in all copies or substantial portions of the Software.
69
+
70
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
71
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
72
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
73
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
74
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
75
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
76
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,58 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+ require 'hoe'
6
+ require 'lib/obsidian'
7
+
8
+ desc 'Default: run unit tests.'
9
+ task :default => :test
10
+
11
+ Hoe.new('obsidian', Obsidian::VERSION) do |p|
12
+ p.rubyforge_name = "thinkrelevance"
13
+ p.description = "It's metastable"
14
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
15
+ p.name = 'obsidian'
16
+ p.summary = "It's metastable"
17
+ p.author = "Relevance"
18
+ p.email = "opensource@thinkrelevance.com"
19
+ p.url = "http://opensource.thinkrelevance.com"
20
+ end
21
+
22
+ desc 'Test obsidian.'
23
+ Rake::TestTask.new(:test) do |t|
24
+ t.libs << 'lib'
25
+ t.pattern = 'test/**/*_test.rb'
26
+ t.verbose = true
27
+ end
28
+
29
+ begin
30
+ require 'rcov'
31
+ require "rcov/rcovtask"
32
+
33
+ namespace :coverage do
34
+ rcov_output = ENV["CC_BUILD_ARTIFACTS"] || 'tmp/coverage'
35
+ rcov_exclusions = %w{
36
+ }.join(',')
37
+
38
+ desc "Delete aggregate coverage data."
39
+ task(:clean) { rm_f "rcov_tmp" }
40
+
41
+ Rcov::RcovTask.new(:unit => :clean) do |t|
42
+ t.test_files = FileList['test/**/*_test.rb']
43
+ t.rcov_opts = ["--sort coverage", "--aggregate 'rcov_tmp'", "--html", "--rails", "--exclude '/Library'"]
44
+ t.output_dir = rcov_output + '/unit'
45
+ end
46
+
47
+ desc "Generate and open coverage report"
48
+ task(:all => [:unit]) do
49
+ system("open #{rcov_output}/unit/index.html") if PLATFORM['darwin']
50
+ end
51
+ end
52
+ rescue LoadError
53
+ if RUBY_PLATFORM =~ /java/
54
+ puts 'running in jruby - rcov tasks not available'
55
+ else
56
+ puts 'sudo gem install rcov # if you want the rcov tasks'
57
+ end
58
+ end
@@ -0,0 +1,3 @@
1
+ module Obsidian
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,182 @@
1
+ if defined? RAILS_ENV
2
+ raise "For testing only!" unless RAILS_ENV=="test"
3
+ end
4
+
5
+ module Obsidian::Rails
6
+ module ModelUpdateTracker
7
+ class Delta
8
+ attr_accessor :committed, :uncommitted
9
+ def initialize
10
+ reset
11
+ end
12
+
13
+ def reset
14
+ @committed = []
15
+ @uncommitted = []
16
+ end
17
+
18
+ def << (obj)
19
+ @uncommitted << obj
20
+ end
21
+
22
+ def transaction_committed
23
+ @committed = @committed + @uncommitted
24
+ @uncommitted = []
25
+ end
26
+
27
+ def transaction_rolled_back
28
+ @uncommitted = []
29
+ end
30
+
31
+ def instances
32
+ @committed + @uncommitted
33
+ end
34
+
35
+ def class_names
36
+ set = instances.inject(Set.new) do |set,inst|
37
+ set << inst.class.to_s
38
+ set
39
+ end
40
+ set
41
+ end
42
+ end
43
+ class << self
44
+ attr_accessor :created_delta, :destroyed_delta, :updated_delta
45
+ def reset
46
+ created_delta.reset
47
+ destroyed_delta.reset
48
+ updated_delta.reset
49
+ end
50
+
51
+ def after_create(model)
52
+ log("Model create #{model} is a #{model.class}")
53
+ created_delta << model
54
+ end
55
+
56
+ def after_update(model)
57
+ log("Model update #{model}")
58
+ updated_delta << model
59
+ end
60
+
61
+ def after_destroy(model)
62
+ log("Model destroy #{model}")
63
+ destroyed_delta << model
64
+ end
65
+
66
+ def after_transaction_commit
67
+ log("Commit transaction")
68
+ created_delta.transaction_committed
69
+ updated_delta.transaction_committed
70
+ destroyed_delta.transaction_committed
71
+ end
72
+
73
+ def after_transaction_rollback
74
+ log("Rollback of transaction}")
75
+ created_delta.transaction_rolled_back
76
+ updated_delta.transaction_rolled_back
77
+ destroyed_delta.transaction_rolled_back
78
+ end
79
+
80
+ def after_transaction_exception
81
+ log("Exception in transaction}")
82
+ created_delta.transaction_rolled_back
83
+ updated_delta.transaction_rolled_back
84
+ destroyed_delta.transaction_rolled_back
85
+ end
86
+
87
+ def log(msg)
88
+ # puts msg
89
+ end
90
+ end
91
+ self.created_delta = Delta.new
92
+ self.updated_delta = Delta.new
93
+ self.destroyed_delta = Delta.new
94
+ self.reset
95
+ end
96
+ end
97
+
98
+ # not using normal after save hooks because of initialization order issues
99
+ class ActiveRecord::Base
100
+ def create_with_model_update_tracker(*args,&blk)
101
+ result = create_without_model_update_tracker(*args,&blk)
102
+ Obsidian::Rails::ModelUpdateTracker.after_create(self) if result
103
+ result
104
+ end
105
+
106
+ alias_method_chain :create, :model_update_tracker
107
+
108
+ def update_with_model_update_tracker(*args,&blk)
109
+ result = update_without_model_update_tracker(*args,&blk)
110
+ Obsidian::Rails::ModelUpdateTracker.after_update(self) if result
111
+ result
112
+ end
113
+
114
+ alias_method_chain :update, :model_update_tracker
115
+
116
+ def destroy_with_model_destroy_tracker(*args,&blk)
117
+ result = destroy_without_model_destroy_tracker(*args,&blk)
118
+ Obsidian::Rails::ModelUpdateTracker.after_destroy(self) if result
119
+ result
120
+ end
121
+
122
+ alias_method_chain :destroy, :model_destroy_tracker
123
+ end
124
+
125
+ class Test::Unit::TestCase
126
+ def assert_no_models_created(&blk)
127
+ assert_models_created(&blk)
128
+ end
129
+
130
+ def assert_no_models_destroyed(&blk)
131
+ assert_models_destroyed(&blk)
132
+ end
133
+
134
+ def assert_no_models_updated(&blk)
135
+ assert_models_updated(&blk)
136
+ end
137
+
138
+ def assert_models_destroyed(*models, &blk)
139
+ Obsidian::Rails::ModelUpdateTracker.reset
140
+ blk.call
141
+ assert_equal(Set.new(models.map(&:to_s)), Obsidian::Rails::ModelUpdateTracker.destroyed_delta.class_names)
142
+ end
143
+
144
+ def assert_models_updated(*models, &blk)
145
+ Obsidian::Rails::ModelUpdateTracker.reset
146
+ blk.call
147
+ assert_equal(Set.new(models.map(&:to_s)), Obsidian::Rails::ModelUpdateTracker.updated_delta.class_names)
148
+ end
149
+
150
+ def assert_models_created(*models, &blk)
151
+ Obsidian::Rails::ModelUpdateTracker.reset
152
+ blk.call
153
+ assert_equal(Set.new(models.map(&:to_s)), Obsidian::Rails::ModelUpdateTracker.created_delta.class_names)
154
+ end
155
+ end
156
+
157
+ module ActiveRecord
158
+ module ConnectionAdapters # :nodoc:
159
+ module DatabaseStatements
160
+ def transaction_with_model_update_tracker(*args,&blk)
161
+ transaction_without_model_update_tracker(*args,&blk)
162
+ rescue
163
+ Obsidian::Rails::ModelUpdateTracker.after_transaction_exception
164
+ raise
165
+ end
166
+
167
+ def rollback_db_transaction_with_model_update_tracker
168
+ rollback_db_transaction_without_model_update_tracker
169
+ Obsidian::Rails::ModelUpdateTracker.after_transaction_rollback
170
+ end
171
+
172
+ def commit_db_transaction_with_model_update_tracker
173
+ commit_db_transaction_without_model_update_tracker
174
+ Obsidian::Rails::ModelUpdateTracker.after_transaction_commit
175
+ end
176
+
177
+ alias_method_chain :transaction, :model_update_tracker
178
+ alias_method_chain :rollback_db_transaction, :model_update_tracker
179
+ alias_method_chain :commit_db_transaction, :model_update_tracker
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,50 @@
1
+ require File.join(File.dirname(__FILE__), "../..", "test_helper.rb")
2
+ require 'obsidian/rails/model_update_tracker'
3
+ include Obsidian::Rails::ModelUpdateTracker
4
+
5
+ describe "ModelUpdateTracker" do
6
+ describe "Runtime" do
7
+ xit "Raises an error if anything but test environment is running"
8
+ end
9
+
10
+ describe "Delta" do
11
+ it "adds uncommitted objects with <<" do
12
+ delta = Delta.new
13
+ delta << "Foo"
14
+ delta.uncommitted.should == ["Foo"]
15
+ end
16
+
17
+ it "moves uncommitted objects to committed on commit" do
18
+ delta = Delta.new
19
+ delta << "Foo"
20
+ delta.transaction_committed
21
+ delta << "Bar"
22
+ delta.transaction_committed
23
+ delta << "Quux"
24
+ delta.committed.should == ["Foo", "Bar"]
25
+ delta.uncommitted.should == ["Quux"]
26
+ end
27
+
28
+ it "moves uncommitted objects to committed on rollback" do
29
+ delta = Delta.new
30
+ delta << "Foo"
31
+ delta.transaction_rolled_back
32
+ delta.committed.should == []
33
+ delta.uncommitted.should == []
34
+ end
35
+
36
+ it "gathers both committed and uncommitted changes into instances" do
37
+ delta = Delta.new
38
+ delta.committed = ["Foo"]
39
+ delta.uncommitted = ["Bar"]
40
+ delta.instances.should == ["Foo", "Bar"]
41
+ end
42
+
43
+ it "gathers the class names of modified instances" do
44
+ delta = Delta.new
45
+ delta.committed = ["String"]
46
+ delta.uncommitted = [10]
47
+ delta.class_names.should == Set.new(["Fixnum", "String"])
48
+ end
49
+ end
50
+ end
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), "test_helper.rb")
@@ -0,0 +1,14 @@
1
+ basedir = File.dirname(__FILE__)
2
+ $:.unshift "#{basedir}/../lib"
3
+ require 'rubygems'
4
+ gem 'test-spec'
5
+ gem 'activesupport'
6
+ gem 'actionpack'
7
+ gem 'activerecord'
8
+
9
+ require 'test/spec'
10
+ require 'mocha'
11
+ require 'ostruct'
12
+ require 'activerecord'
13
+ require 'obsidian'
14
+
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: obsidian
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Relevance
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-04-04 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hoe
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.5.1
23
+ version:
24
+ description: It's metastable
25
+ email: opensource@thinkrelevance.com
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files:
31
+ - History.txt
32
+ - Manifest.txt
33
+ - README.txt
34
+ files:
35
+ - History.txt
36
+ - Manifest.txt
37
+ - README.txt
38
+ - Rakefile
39
+ - lib/obsidian.rb
40
+ - lib/obsidian/rails/model_update_tracker.rb
41
+ - test/obsidian_test.rb
42
+ - test/test_helper.rb
43
+ - test/obsidian/rails/model_update_tracker_test.rb
44
+ has_rdoc: true
45
+ homepage: http://opensource.thinkrelevance.com
46
+ post_install_message:
47
+ rdoc_options:
48
+ - --main
49
+ - README.txt
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ requirements: []
65
+
66
+ rubyforge_project: thinkrelevance
67
+ rubygems_version: 1.0.1
68
+ signing_key:
69
+ specification_version: 2
70
+ summary: It's metastable
71
+ test_files:
72
+ - test/test_helper.rb