artisan-repository 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,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
+