artisan-repository 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,51 @@
1
+ module Artisan
2
+ class RecordNotFound < RuntimeError
3
+ attr_reader :base
4
+
5
+ def initialize(base = nil)
6
+ @base = base
7
+ end
8
+ end
9
+
10
+ class Repository
11
+ def self.register_repo(repo)
12
+ @repo = repo
13
+ end
14
+
15
+ def self.story
16
+ repo.story
17
+ end
18
+
19
+ def self.project
20
+ repo.project
21
+ end
22
+
23
+ def self.iteration
24
+ repo.iteration
25
+ end
26
+
27
+ def self.user
28
+ repo.user
29
+ end
30
+
31
+ def self.future_user
32
+ repo.future_user
33
+ end
34
+
35
+ def self.project_configuration
36
+ repo.project_configuration
37
+ end
38
+
39
+ def self.change
40
+ repo.change
41
+ end
42
+
43
+ def self.member
44
+ repo.member
45
+ end
46
+
47
+ def self.repo
48
+ @repo
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,23 @@
1
+ shared_examples "change repository" do
2
+ let (:repo) { described_class.new }
3
+
4
+ it "has a project change" do
5
+ repo.create_project_change(:source_id => 3, :user_id => 2, :event => :second, :project_id => 123).type.should == "ProjectChange"
6
+ end
7
+
8
+ it "has an iteration change" do
9
+ repo.create_iteration_change(:source_id => 3, :user_id => 2, :event => :second, :project_id => 123).type.should == "IterationChange"
10
+ end
11
+
12
+ it "has a story change" do
13
+ repo.create_story_change(:source_id => 3, :user_id => 2, :event => :second, :project_id => 123).type.should == "StoryChange"
14
+ end
15
+
16
+ it "orders by created_at project" do
17
+ second = repo.create_project_change(:source_id => 3, :user_id => 2, :event => "second", :project_id => 123, :created_at => Time.now)
18
+ first = repo.create_project_change(:source_id => 1, :user_id => 2, :event => "first", :project_id => 123, :created_at => (Time.now - 3.seconds))
19
+
20
+ repo.find_all_by_project_id(123).map(&:event).should == ["second", "first"]
21
+ end
22
+
23
+ end
@@ -0,0 +1,40 @@
1
+ shared_examples "future user repository" do
2
+ let (:project) { Artisan::Repository.project.create(:name => "Artisan") }
3
+ let (:attributes) { {:email => "person@test.com", :project_id => project.id} }
4
+ let (:repo) { described_class.new }
5
+
6
+ it "news a future user" do
7
+ future_user = repo.new(attributes)
8
+ future_user.email.should == "person@test.com"
9
+ future_user.project_id == project.id
10
+ end
11
+
12
+ it "creates a record" do
13
+ future_user = repo.create(attributes)
14
+ future_user.id.should_not be_nil
15
+ end
16
+
17
+ it "raises an exception if the email is not unique" do
18
+ repo.create(attributes)
19
+ lambda { future_user = repo.create(attributes) }.should raise_exception
20
+ end
21
+
22
+ it "finds a future user account by email" do
23
+ created_future_user = repo.create(:email => "person@test.com")
24
+ found_future_user = repo.find_by_email("person@test.com")
25
+ created_future_user.should == found_future_user
26
+ end
27
+
28
+ it "finds a future user account by project" do
29
+ created_future_user = repo.create(attributes)
30
+ found_future_user = repo.find_by_project_id(project.id)
31
+ created_future_user.should == found_future_user
32
+ end
33
+
34
+ it "deletes future users" do
35
+ future_user = repo.create(:email => "person@test.com")
36
+ repo.find(future_user.id).should_not be_nil
37
+ repo.delete(future_user.id)
38
+ lambda { repo.find(future_user.id).should }.should raise_exception Artisan::RecordNotFound
39
+ end
40
+ end
@@ -0,0 +1,47 @@
1
+ shared_examples "iteration repository" do
2
+ let (:repo) { described_class.new }
3
+
4
+ it "news an iteration" do
5
+ iteration = repo.new(:number => 1)
6
+ iteration.number.should == 1
7
+ end
8
+
9
+ it "finds an iteration" do
10
+ iteration = repo.new(:number => 1)
11
+ repo.save(iteration)
12
+ repo.find(iteration.id).number.should == 1
13
+ end
14
+
15
+ describe "with project" do
16
+ let(:project) {Artisan::Repository.project.create(:name => "name", :description => "123")}
17
+
18
+ it "should find the project associated with this iteration" do
19
+ iteration = repo.create_for_project(project, :start_date => "11/05/2010", :finish_date => "11/06/2010")
20
+ iteration.project.should == project
21
+ project.iterations.should be_include(iteration)
22
+ end
23
+
24
+ it "finds an iteration by number" do
25
+ one = repo.create_for_project(project, :number => 1)
26
+ two = repo.create_for_project(project, :number => 2)
27
+
28
+ repo.find_by_number(project, 2).should == two
29
+ end
30
+
31
+ it "orders by finish date" do
32
+ iteration2 = repo.create_for_project(project, :start_date => "11/05/2010", :finish_date => "11/06/2010")
33
+ iteration1 = repo.create_for_project(project, :start_date => "11/05/2010", :finish_date => "11/06/2009")
34
+ iteration3 = repo.create_for_project(project, :start_date => "11/05/2010", :finish_date => "11/06/2011")
35
+ repo.by_project(project).size.should == 3
36
+ repo.by_project_by_finish_date(project).map(&:id).should == [iteration3.id, iteration2.id, iteration1.id]
37
+ end
38
+
39
+ it "orders iterations" do
40
+ i1 = repo.create_for_project(project, :number => 2)
41
+ i2 = repo.create_for_project(project, :number => 1)
42
+ i3 = repo.create_for_project(project, :number => 3)
43
+
44
+ repo.by_project(project).should == [i3, i1, i2]
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,156 @@
1
+ require 'artisan/repository'
2
+
3
+ def destroy
4
+ repo.destroy_all
5
+ user_repo.destroy_all
6
+ end
7
+
8
+ shared_examples "project repository" do
9
+ let (:repo) { described_class.new }
10
+ let (:user_repo) { Artisan::Repository.user }
11
+
12
+ before(:each) do
13
+ destroy
14
+ end
15
+
16
+ it "news a project" do
17
+ project = repo.new(:name => "Artisan")
18
+ project.name.should == "Artisan"
19
+ repo.new.should_not be_nil
20
+ end
21
+
22
+ it "finds a project" do
23
+ project = repo.new(:name => "Artisan")
24
+ repo.save(project)
25
+ repo.find(project.id).name.should == "Artisan"
26
+ end
27
+
28
+ it "finds a project by api key" do
29
+ project = repo.create(:name => "Artibomb", :api_key => "keytomyheart")
30
+ repo.find_by_api_key("keytomyheart").should == project
31
+ end
32
+
33
+ it "finds a project by name" do
34
+ project = repo.create(:name => "Artibomb")
35
+ repo.find_by_name("Artibomb").should == project
36
+ end
37
+
38
+ it "finds each" do
39
+ project0 = repo.create(:name => "Artibomb")
40
+ project1 = repo.create(:name => "Artiboom")
41
+ project2 = repo.create(:name => "Artiawesome")
42
+ yielded_projects = []
43
+ repo.find_each do |p|
44
+ yielded_projects << p
45
+ end
46
+ yielded_projects.size.should == 3
47
+ yielded_projects.include?(project0).should be_true
48
+ yielded_projects.include?(project1).should be_true
49
+ yielded_projects.include?(project2).should be_true
50
+ end
51
+
52
+ it "creates a project configuration" do
53
+ project = repo.create
54
+ repo.create_project_configuration(project)
55
+ project.project_configuration.should_not be_nil
56
+ end
57
+
58
+ describe "archiving" do
59
+ before(:each) do
60
+ @archived_project = repo.create(:name => "first", :archived => true)
61
+ @unarchived_project = repo.create(:name => "second")
62
+ end
63
+
64
+ it "should exclude archived projects on unarchived" do
65
+ repo.unarchived.should === [@unarchived_project]
66
+ end
67
+
68
+ it "should order them by last update on unarchived" do
69
+ unarchived_project_two = repo.create(:name => "third", :updated_at => Time.now + 10)
70
+ repo.unarchived.should == [@unarchived_project, unarchived_project_two]
71
+ end
72
+
73
+ it "should exclude unarchived projects on archived" do
74
+ repo.archived.should == [@archived_project]
75
+ end
76
+
77
+ it "should order them by named on archived" do
78
+ archived_project_two = repo.create(:name => "third", :updated_at => Time.now + 10, :archived => true)
79
+ repo.archived.should == [@archived_project, archived_project_two]
80
+ end
81
+
82
+ it "should treat nil as false for archived" do
83
+ unarchived_project_two = repo.create(:name => "third", :updated_at => Time.now + 10, :archived => nil)
84
+ repo.unarchived.should == [@unarchived_project, unarchived_project_two]
85
+ end
86
+ end
87
+
88
+ it "returns projects ordered by name" do
89
+ three = repo.create(:name => "C")
90
+ one = repo.create(:name => "A")
91
+ two = repo.create(:name => "B")
92
+ repo.order_by_name.should == [one, two, three]
93
+ end
94
+
95
+ it "unarchived orders by name" do
96
+ c = repo.create(:name => "C")
97
+ a = repo.create(:name => "A")
98
+ b = repo.create(:name => "B")
99
+ repo.unarchived.should == [a, b, c]
100
+ end
101
+
102
+ it "orders iterations" do
103
+ project = repo.create(:name => "A")
104
+ iteration_repo = Artisan::Repository.iteration
105
+ i2 = repo.add_iteration(project, iteration_repo.new(:number => 2))
106
+ i1 = repo.add_iteration(project, iteration_repo.new(:number => 1))
107
+ i3 = repo.add_iteration(project, iteration_repo.new(:number => 3))
108
+
109
+ repo.save(project)
110
+
111
+ project = repo.find(project.id)
112
+ project.iterations.should == [i3, i2, i1]
113
+ end
114
+
115
+ describe "membership" do
116
+ let(:project) { repo.create(:name => "A") }
117
+ let(:user) { user_repo.create(:name => "Doug", :email => "doug!@bradbury.com", :password => "ilikeplanes", :full_name => "Doug Bradbury", :login => "Doug")}
118
+
119
+ it "adds members to the project" do
120
+ repo.add_member(project, user, false)
121
+
122
+ repo.is_member?(project, user).should be_true
123
+ repo.is_owner?(project, user).should be_false
124
+
125
+ # project = repo.find(project.id)
126
+ # project.users.should == [user]
127
+ end
128
+
129
+ it "adds owner to the project" do
130
+ repo.add_member(project, user, true)
131
+
132
+ repo.is_owner?(project, user).should be_true
133
+ end
134
+
135
+ it "is not a member of the project" do
136
+ repo.is_member?(project, user).should be_false
137
+ repo.is_owner?(project, user).should be_false
138
+ end
139
+
140
+ it "removes from project" do
141
+ repo.add_member(project, user, true)
142
+ repo.remove_member(project, user)
143
+
144
+ repo.is_member?(project, user).should be_false
145
+ repo.is_owner?(project, user).should be_false
146
+ end
147
+
148
+ it "lists owners" do
149
+ repo.add_member(project, user, true)
150
+ repo.owners(project).should == [user]
151
+ end
152
+
153
+ end
154
+
155
+
156
+ end
@@ -0,0 +1,113 @@
1
+ require 'artisan/repository'
2
+
3
+ shared_examples "story repository" do
4
+ let (:repo) { described_class.new }
5
+ let (:project) { Artisan::Repository.project.create(:name => "proj") }
6
+ let (:user) { Artisan::Repository.user.create(:full_name => "Test User", :login => "user", :email => "test@example.com", :password => "sample") }
7
+
8
+ before(:each) do
9
+ repo.destroy_all
10
+ Artisan::Repository.user.destroy_all
11
+ end
12
+
13
+ it "news a story" do
14
+ story = repo.new(:name => "World Peace")
15
+ story.name.should == "World Peace"
16
+ end
17
+
18
+ it "finds a story" do
19
+ story = repo.new(:name => "Artisan", :project => project)
20
+ repo.save(story)
21
+ repo.find(story.number, project).name.should == "Artisan"
22
+ end
23
+
24
+ it "returns stories for the current user" do
25
+ story = repo.create(:name => "sample", :assigned_user => user)
26
+ repo.for_user(user).should == [story]
27
+ end
28
+
29
+ it "scopes by project" do
30
+ repo.create(name: "first", :project => Artisan::Repository.project.create)
31
+ story = repo.create(name: "sample", :project => project)
32
+ repo.by_project(project).should == [story]
33
+ end
34
+
35
+ it "allows duplicate story names in a single project" do
36
+ repo.create_for_project(project, :name => "story")
37
+ story_two = repo.create_for_project(project, :name => "story")
38
+
39
+ story_two.should be_valid
40
+ end
41
+
42
+ it "gets stories for a project" do
43
+ story_one = repo.create_for_project(project, :name => "story 1")
44
+ story_two = repo.create_for_project(project, :name => "story 2")
45
+ story_three = repo.create_for_project(Artisan::Repository.project.create(:name => "not the projecT"), :name => "story 3")
46
+
47
+ repo.by_project(project).should be_include(story_one)
48
+ repo.by_project(project).should be_include(story_two)
49
+ repo.by_project(project).should_not be_include(story_three)
50
+ end
51
+
52
+ it "doesn't destroy story record, flags as deleted" do
53
+ story = repo.create_for_project(project, :name => "i'm gonna be deleted")
54
+ result = repo.delete(story)
55
+ result.should be_deleted
56
+ -> {repo.find(story.number, story.project)}.should raise_error(Artisan::RecordNotFound)
57
+ end
58
+
59
+ describe "workflow scopes" do
60
+
61
+ before :each do
62
+ repo.destroy_all
63
+ @assigned = repo.create(:name => "assigned", :optimistic => 1, :pessimistic => 2, :realistic => 3, :assigned_user => user)
64
+ @completed = repo.create(:name => "completed", :optimistic => 1, :pessimistic => 2, :realistic => 3, :complete => true)
65
+ @ready = repo.create(:name => "ready",:optimistic => 1, :pessimistic => 2, :realistic => 3)
66
+
67
+ iteration_repo = Artisan::Repository.iteration
68
+ @iteration = iteration_repo.create
69
+
70
+ repo.add_to_iteration(@iteration, @assigned)
71
+ repo.add_to_iteration(@iteration, @completed)
72
+ repo.add_to_iteration(@iteration, @ready)
73
+ end
74
+
75
+ it "a ready story" do
76
+ repo.ready(@iteration).should == [@ready]
77
+ end
78
+
79
+ it "a working story" do
80
+ repo.working(@iteration).should == [@assigned]
81
+ end
82
+
83
+ it "a completed story" do
84
+ repo.completed(@iteration).should == [@completed]
85
+ end
86
+
87
+ it "all stories" do
88
+ repo.all(@iteration).size.should == 3
89
+ repo.all(@iteration).should be_include(@ready)
90
+ repo.all(@iteration).should be_include(@completed)
91
+ repo.all(@iteration).should be_include(@assigned)
92
+ end
93
+
94
+ it "removes a story from an iteration" do
95
+ repo.remove_from_iteration(@ready)
96
+ repo.ready(@iteration).should_not be_include(@ready)
97
+ end
98
+
99
+ it "doesn't add the same story to an iteration twice" do
100
+ repo.add_to_iteration(@iteration, @ready)
101
+
102
+ repo.ready(@iteration).size.should == 1
103
+ end
104
+ end
105
+
106
+ describe "backlog scopes" do
107
+ it "a ready story" do
108
+ @backlog = repo.create_for_project(project, :name => "assigned", :optimistic => 1, :pessimistic => 2, :realistic => 3, :assigned_user => user, :iteration => nil)
109
+ @ready = repo.create_for_project(project, :name => "ready",:optimistic => 1, :pessimistic => 2, :realistic => 3, :iteration => Artisan::Repository.iteration.new)
110
+ repo.backlog(project).should == [@backlog]
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,69 @@
1
+ shared_examples "user repository" do
2
+ let(:repo) {described_class.new}
3
+ let(:attrs) { { :full_name => "test user", :email => "test@example.com", :password => "secret", :login => "tester" } }
4
+ let(:user) { repo.create(attrs) }
5
+
6
+ before do
7
+ repo.destroy_all
8
+ user
9
+ end
10
+
11
+ it "creates" do
12
+ user.should_not be_nil
13
+ end
14
+
15
+ it "has an id" do
16
+ user.id.should_not be_nil
17
+ end
18
+
19
+ it "finds by email" do
20
+ repo.find_by_email(attrs[:email]).should == user
21
+ end
22
+
23
+ it "finds by login" do
24
+ repo.find_by_login(attrs[:login]).should == user
25
+ end
26
+
27
+ it "requires full name" do
28
+ user = repo.new
29
+ user.should_not be_valid
30
+ user.errors[:full_name].size.should == 1
31
+ user.errors[:full_name][0].should == "can't be blank"
32
+ end
33
+
34
+ it "validates unique login" do
35
+ user = repo.create(:email => "test1@example.com", :login => "login", :password => "pass", :password_confirmation => "pass", :full_name => "some name")
36
+ lambda { repeat = repo.create(:email => "test2@example.com", :login => "login", :password => "pass", :password_confirmation => "pass", :full_name => "some name") }.should raise_exception
37
+ end
38
+
39
+ it "updates the password" do
40
+ user = repo.create(:email => "test1@example.com", :login => "login", :password => "pass", :password_confirmation => "pass", :full_name => "some name")
41
+ user.update_attributes(:password => "123456", :password_confirmation => "123456")
42
+ user.password.should == "123456"
43
+ end
44
+
45
+ it "validates unique login...case sensitive style" do
46
+ user = repo.create(:email => "test1@example.com", :login => "login", :password => "pass", :password_confirmation => "pass", :full_name => "some name")
47
+ lambda { repeat = repo.create(:email => "test2@example.com", :login => "Login", :password => "pass", :password_confirmation => "pass", :full_name => "some name") }.should raise_exception
48
+ end
49
+
50
+ it "gets the user's stories" do
51
+ user = repo.create(:email => "test1@example.com", :login => "login", :password => "pass", :password_confirmation => "pass", :full_name => "some name")
52
+
53
+ project = Artisan::Repository.project.create
54
+ iteration = Artisan::Repository.iteration.create(:project => project)
55
+ story = Artisan::Repository.story.create(:assigned_user => user, :project => project, :iteration => iteration)
56
+ repo.active_stories_for(user).should == [story]
57
+ end
58
+
59
+ context "validates login" do
60
+ it "is too short" do
61
+ repo.new(:login => "ab", :full_name => "some name").should_not be_valid
62
+ end
63
+
64
+ it "has wierd characters" do
65
+ repo.new(:login => "*()241ab", :full_name => "some name").should_not be_valid
66
+ end
67
+ end
68
+ end
69
+
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: artisan-repository
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - 8th Light Craftsmen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2012-10-10 00:00:00 Z
14
+ dependencies: []
15
+
16
+ description: An interface to the Artisan persistance layer
17
+ email: paul@8thlight.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - lib/artisan/repository.rb
26
+ - lib/artisan/shared_examples/change_examples.rb
27
+ - lib/artisan/shared_examples/future_user_examples.rb
28
+ - lib/artisan/shared_examples/iteration_examples.rb
29
+ - lib/artisan/shared_examples/project_examples.rb
30
+ - lib/artisan/shared_examples/story_examples.rb
31
+ - lib/artisan/shared_examples/user_examples.rb
32
+ homepage: http://8thlight.com
33
+ licenses: []
34
+
35
+ post_install_message:
36
+ rdoc_options: []
37
+
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 853314355555588589
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ requirements: []
56
+
57
+ rubyforge_project:
58
+ rubygems_version: 1.8.24
59
+ signing_key:
60
+ specification_version: 3
61
+ summary: Artisan Repository
62
+ test_files: []
63
+