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.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in contract_acceptance_framework.gemspec
4
+ gemspec
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
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -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,8 @@
1
+ class ContractAcceptance < ActiveRecord::Base
2
+ belongs_to :acceptable, :polymorphic => true
3
+ belongs_to :contract
4
+
5
+ validates_presence_of :acceptable_id
6
+ validates_presence_of :acceptable_type
7
+ validates_presence_of :contract_id
8
+ end
@@ -0,0 +1,3 @@
1
+ module ContractAcceptanceFramework
2
+ VERSION = "0.0.1"
3
+ 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
+
@@ -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
+