contract_acceptance_framework 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/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README +53 -0
- data/Rakefile +2 -0
- data/contract_acceptance_framework.gemspec +28 -0
- data/lib/contract_acceptance_framework.rb +24 -0
- data/lib/contract_acceptance_framework/contract.rb +26 -0
- data/lib/contract_acceptance_framework/contract_acceptance.rb +8 -0
- data/lib/contract_acceptance_framework/version.rb +3 -0
- data/spec/contract_acceptance_framework_spec.rb +39 -0
- data/spec/spec_helper.rb +26 -0
- metadata +161 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
== ContractAcceptanceFramework
|
2
|
+
|
3
|
+
This gem is meant to be used to allow ActiveRecord objects to signify agreement with versioned contracts. It requires some database tables.
|
4
|
+
|
5
|
+
To that end, you need a migration that looks something like this:
|
6
|
+
|
7
|
+
class CreateContractAcceptanceFrameworkTables < ActiveRecord::Migration
|
8
|
+
def self.up
|
9
|
+
create_table :contracts do |t|
|
10
|
+
t.string :key
|
11
|
+
t.text :content
|
12
|
+
t.integer :major_version
|
13
|
+
t.integer :minor_version
|
14
|
+
t.integer :maintenance_version
|
15
|
+
t.timestamps
|
16
|
+
end
|
17
|
+
add_index :contracts, [:major_version, :minor_version, :maintenance_version, :key], :name => 'contracts_version_index'
|
18
|
+
add_index :contracts, [:key]
|
19
|
+
|
20
|
+
create_table :contract_acceptances do |t|
|
21
|
+
t.integer :contract_id
|
22
|
+
t.timestamps
|
23
|
+
t.integer :acceptable_id
|
24
|
+
t.string :acceptable_type
|
25
|
+
end
|
26
|
+
add_index :contract_acceptances, [:acceptable_id, :acceptable_type]
|
27
|
+
add_index :contract_acceptances, :contract_id
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.down
|
31
|
+
remove_index :contract_acceptances, :column => :contract_id
|
32
|
+
remove_index :contract_acceptances, :column => [:acceptable_id, :acceptable_type]
|
33
|
+
drop_table :contract_acceptances
|
34
|
+
|
35
|
+
remove_index :contracts, :column => [:key]
|
36
|
+
remove_index :contracts, 'contracts_version_index'
|
37
|
+
drop_table :contracts
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
After that, you just include a module in your class that accepts contracts like so:
|
42
|
+
|
43
|
+
class SomeClass < ActiveRecord::Base
|
44
|
+
include ContractAcceptanceFramework
|
45
|
+
end
|
46
|
+
|
47
|
+
That's it, you're done. Now the class will respond to the following methods:
|
48
|
+
|
49
|
+
# where version looks like '1.2.3' and will be parsed into the appropriate major, minor, maintenance query
|
50
|
+
- has_agreed_to?(contract)
|
51
|
+
- agree_to!(contract)
|
52
|
+
|
53
|
+
If you've already agreed to a contract and try to agree again, it will raise a ContractDuplicateAgreementError
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "contract_acceptance_framework/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "contract_acceptance_framework"
|
7
|
+
s.version = ContractAcceptanceFramework::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Josh Adams"]
|
10
|
+
s.email = ["josh@isotope11.com"]
|
11
|
+
s.homepage = "http://rubygems.org/gems/contract_acceptance_framework"
|
12
|
+
s.summary = %q{Allow rails objects to agree to versioned contracts}
|
13
|
+
|
14
|
+
s.required_rubygems_version = ">= 1.3.6"
|
15
|
+
s.rubyforge_project = "contract_acceptance_framework"
|
16
|
+
|
17
|
+
s.add_development_dependency "bundler", ">= 1.0.0.rc.6"
|
18
|
+
s.add_development_dependency "rspec", "~> 2.4.0"
|
19
|
+
s.add_development_dependency "sqlite3", "~> 1.3.3"
|
20
|
+
|
21
|
+
s.add_dependency 'activesupport', '~> 3.0.0'
|
22
|
+
s.add_dependency 'activerecord', '~> 3.0.0'
|
23
|
+
|
24
|
+
s.files = `git ls-files`.split("\n")
|
25
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
26
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
27
|
+
s.require_paths = ["lib"]
|
28
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'contract_acceptance_framework/contract'
|
2
|
+
require 'contract_acceptance_framework/contract_acceptance'
|
3
|
+
|
4
|
+
module ContractAcceptanceFramework
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
raise "class must inherit from ActiveRecord::Base" unless self < ActiveRecord::Base
|
9
|
+
|
10
|
+
has_many :contract_acceptances, :as => :acceptable
|
11
|
+
has_many :contracts, :through => :contract_acceptances
|
12
|
+
|
13
|
+
def has_agreed_to?(contract)
|
14
|
+
contracts.include?(contract)
|
15
|
+
end
|
16
|
+
|
17
|
+
def agree_to!(contract)
|
18
|
+
raise ContractDuplicateAgreementError if has_agreed_to?(contract)
|
19
|
+
contract_acceptances.create(:contract => contract)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class ContractDuplicateAgreementError < StandardError; end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Contract < ActiveRecord::Base
|
2
|
+
has_many :contract_acceptances
|
3
|
+
|
4
|
+
validates :maintenance_version, :uniqueness => { :scope => [:minor_version, :major_version, :key] }
|
5
|
+
validates :maintenance_version, :minor_version, :major_version, :key, :content, :presence => true
|
6
|
+
|
7
|
+
scope :accepted_by, lambda{|acceptable| joins(:contract_acceptances).where({ :contract_acceptances => { :acceptable_id => acceptable.id, :acceptable_type => acceptable.type } }) }
|
8
|
+
scope :for_key, lambda{|key| where("`key` = ?", key) }
|
9
|
+
scope :by_version, order("major_version DESC, minor_version DESC, maintenance_version DESC")
|
10
|
+
|
11
|
+
# Find the latest contract for a given key, by version number
|
12
|
+
def self.latest(key)
|
13
|
+
for_key(key).by_version.find(:first)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Find the latest accepted contract for a given acceptable, by key
|
17
|
+
def self.latest_accepted(key, acceptable)
|
18
|
+
accepted_by(acceptable).for_key(key).by_version.find(:first)
|
19
|
+
end
|
20
|
+
|
21
|
+
def version=(version_string) # Expects "1.0.2"
|
22
|
+
versions = version_string.split(".")
|
23
|
+
raise "invalid version_string" unless versions.size == 3
|
24
|
+
self.major_version, self.minor_version, self.maintenance_version = versions
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Contract Acceptance Framework' do
|
4
|
+
let(:person) { Person.create }
|
5
|
+
let(:contract) do
|
6
|
+
Contract.create(:major_version => 0, :minor_version => 0,
|
7
|
+
:maintenance_version => 0, :key => 'unique string',
|
8
|
+
:content => 'content')
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '.agree_to!' do
|
12
|
+
it 'should agree to the contract' do
|
13
|
+
person.agree_to!(contract)
|
14
|
+
person.contracts.include?(contract).should be_true
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'when the contract has been previously agreed to' do
|
18
|
+
before { person.agree_to!(contract) }
|
19
|
+
|
20
|
+
it 'should raise a contract duplicate agreement error' do
|
21
|
+
lambda { person.agree_to!(contract) }.should raise_error ContractDuplicateAgreementError
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '.has_agreed_to?' do
|
27
|
+
subject { person.has_agreed_to?(contract) }
|
28
|
+
|
29
|
+
context 'when the contract has been agreed to' do
|
30
|
+
before { person.agree_to!(contract) }
|
31
|
+
it { should be_true }
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'when the contract has not been agreed to' do
|
35
|
+
it { should be_false }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'contract_acceptance_framework'
|
3
|
+
|
4
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
5
|
+
|
6
|
+
ActiveRecord::Base.connection.create_table(:contracts) do |t|
|
7
|
+
t.string :key
|
8
|
+
t.text :content
|
9
|
+
t.integer :major_version
|
10
|
+
t.integer :minor_version
|
11
|
+
t.integer :maintenance_version
|
12
|
+
t.timestamps
|
13
|
+
end
|
14
|
+
|
15
|
+
ActiveRecord::Base.connection.create_table(:contract_acceptances) do |t|
|
16
|
+
t.integer :contract_id
|
17
|
+
t.integer :acceptable_id
|
18
|
+
t.string :acceptable_type
|
19
|
+
end
|
20
|
+
|
21
|
+
ActiveRecord::Base.connection.create_table(:people)
|
22
|
+
|
23
|
+
class Person < ActiveRecord::Base
|
24
|
+
include ContractAcceptanceFramework
|
25
|
+
end
|
26
|
+
|
metadata
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: contract_acceptance_framework
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Josh Adams
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-02-11 00:00:00 -06:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: bundler
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 15424057
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 0
|
33
|
+
- 0
|
34
|
+
- rc
|
35
|
+
- 6
|
36
|
+
version: 1.0.0.rc.6
|
37
|
+
type: :development
|
38
|
+
version_requirements: *id001
|
39
|
+
- !ruby/object:Gem::Dependency
|
40
|
+
name: rspec
|
41
|
+
prerelease: false
|
42
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
hash: 31
|
48
|
+
segments:
|
49
|
+
- 2
|
50
|
+
- 4
|
51
|
+
- 0
|
52
|
+
version: 2.4.0
|
53
|
+
type: :development
|
54
|
+
version_requirements: *id002
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sqlite3
|
57
|
+
prerelease: false
|
58
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ~>
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
hash: 29
|
64
|
+
segments:
|
65
|
+
- 1
|
66
|
+
- 3
|
67
|
+
- 3
|
68
|
+
version: 1.3.3
|
69
|
+
type: :development
|
70
|
+
version_requirements: *id003
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: activesupport
|
73
|
+
prerelease: false
|
74
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ~>
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
hash: 7
|
80
|
+
segments:
|
81
|
+
- 3
|
82
|
+
- 0
|
83
|
+
- 0
|
84
|
+
version: 3.0.0
|
85
|
+
type: :runtime
|
86
|
+
version_requirements: *id004
|
87
|
+
- !ruby/object:Gem::Dependency
|
88
|
+
name: activerecord
|
89
|
+
prerelease: false
|
90
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ~>
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
hash: 7
|
96
|
+
segments:
|
97
|
+
- 3
|
98
|
+
- 0
|
99
|
+
- 0
|
100
|
+
version: 3.0.0
|
101
|
+
type: :runtime
|
102
|
+
version_requirements: *id005
|
103
|
+
description:
|
104
|
+
email:
|
105
|
+
- josh@isotope11.com
|
106
|
+
executables: []
|
107
|
+
|
108
|
+
extensions: []
|
109
|
+
|
110
|
+
extra_rdoc_files: []
|
111
|
+
|
112
|
+
files:
|
113
|
+
- .gitignore
|
114
|
+
- Gemfile
|
115
|
+
- README
|
116
|
+
- Rakefile
|
117
|
+
- contract_acceptance_framework.gemspec
|
118
|
+
- lib/contract_acceptance_framework.rb
|
119
|
+
- lib/contract_acceptance_framework/contract.rb
|
120
|
+
- lib/contract_acceptance_framework/contract_acceptance.rb
|
121
|
+
- lib/contract_acceptance_framework/version.rb
|
122
|
+
- spec/contract_acceptance_framework_spec.rb
|
123
|
+
- spec/spec_helper.rb
|
124
|
+
has_rdoc: true
|
125
|
+
homepage: http://rubygems.org/gems/contract_acceptance_framework
|
126
|
+
licenses: []
|
127
|
+
|
128
|
+
post_install_message:
|
129
|
+
rdoc_options: []
|
130
|
+
|
131
|
+
require_paths:
|
132
|
+
- lib
|
133
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
134
|
+
none: false
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
hash: 3
|
139
|
+
segments:
|
140
|
+
- 0
|
141
|
+
version: "0"
|
142
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
143
|
+
none: false
|
144
|
+
requirements:
|
145
|
+
- - ">="
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
hash: 23
|
148
|
+
segments:
|
149
|
+
- 1
|
150
|
+
- 3
|
151
|
+
- 6
|
152
|
+
version: 1.3.6
|
153
|
+
requirements: []
|
154
|
+
|
155
|
+
rubyforge_project: contract_acceptance_framework
|
156
|
+
rubygems_version: 1.4.2
|
157
|
+
signing_key:
|
158
|
+
specification_version: 3
|
159
|
+
summary: Allow rails objects to agree to versioned contracts
|
160
|
+
test_files: []
|
161
|
+
|