camaraderie 0.1.3 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 2.0.0
5
+ - 1.9.3
6
+
7
+ gemfile:
8
+ - gemfiles/Gemfile.activerecord-4.0
9
+ - gemfiles/Gemfile.activerecord-3.2.x
10
+
11
+ script: "echo 'DO IT' && bundle exec rake spec"
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Camaraderie
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/camaraderie.png)](https://rubygems.org/gems/camaraderie)
4
+ [![Build Status](https://travis-ci.org/mirego/camaraderie.png?branch=master)](https://travis-ci.org/mirego/camaraderie)
4
5
 
5
6
  Camaraderie takes away the pain of managing membership stuff between users and organizations.
6
7
 
@@ -24,7 +25,14 @@ First, you have to configure which type of memberships you want. Usually, you’
24
25
 
25
26
  ```ruby
26
27
  Camaraderie.configure do |config|
28
+ # The different types of memberships (defaults to `['admin']`)
27
29
  config.membership_types = %w(admin moderator member)
30
+
31
+ # The class name of the organization model (defaults to `'Organization'`)
32
+ config.organization_class = 'Company'
33
+
34
+ # The class name of the user model (defaults to `'User'`)
35
+ config.user_class = 'Employee'
28
36
  end
29
37
  ```
30
38
 
@@ -59,6 +67,10 @@ organization.members.create(user: user)
59
67
  # Check whether the user is an admin
60
68
  user.admin_of?(organization)
61
69
  # => true
70
+
71
+ # List all the admins for the organization
72
+ organization.admin_users
73
+ # => #<ActiveRecord::Relation [<User id=1>]>
62
74
  ```
63
75
 
64
76
  ## License
data/Rakefile CHANGED
@@ -1 +1,11 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler'
2
+ require 'rake'
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ task default: :spec
7
+
8
+ desc 'Run all specs'
9
+ RSpec::Core::RakeTask.new(:spec) do |task|
10
+ task.pattern = 'spec/**/*_spec.rb'
11
+ end
data/camaraderie.gemspec CHANGED
@@ -20,6 +20,8 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_development_dependency 'bundler', '~> 1.3'
22
22
  spec.add_development_dependency 'rake'
23
+ spec.add_development_dependency 'sqlite3'
24
+ spec.add_development_dependency 'rspec', '~> 2.14'
23
25
 
24
26
  spec.add_dependency 'activerecord', '>= 3.0.0'
25
27
  spec.add_dependency 'activesupport', '>= 3.0.0'
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '../'
4
+
5
+ gem 'activerecord', '~> 3.2.0'
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '../'
4
+
5
+ gem 'activerecord', '~> 4.0.0'
@@ -3,8 +3,8 @@ module Camaraderie
3
3
  extend ActiveSupport::Concern
4
4
  included do
5
5
  # Associations
6
- belongs_to :user, validate: true
7
- belongs_to :organization
6
+ belongs_to :user, validate: true, class_name: Camaraderie.user_class, inverse_of: :memberships
7
+ belongs_to :organization, class_name: Camaraderie.organization_class, inverse_of: :memberships
8
8
 
9
9
  # Validations
10
10
  validates :user, presence: true
@@ -4,8 +4,8 @@ module Camaraderie
4
4
 
5
5
  included do
6
6
  # Associations
7
- has_many :memberships, dependent: :destroy
8
- has_many :users, through: :memberships
7
+ has_many :memberships, dependent: :destroy, foreign_key: :organization_id, class_name: 'Membership', inverse_of: :organization
8
+ has_many :users, through: :memberships, class_name: Camaraderie.user_class, inverse_of: :organizations
9
9
 
10
10
  # Define a method for each type of membership
11
11
  #
@@ -17,6 +17,10 @@ module Camaraderie
17
17
  def #{type.pluralize}
18
18
  memberships.#{type.pluralize}
19
19
  end
20
+
21
+ def #{type}_users
22
+ Camaraderie.user_class.constantize.where(id: #{type.pluralize}.pluck(:user_id))
23
+ end
20
24
  RUBY
21
25
  end
22
26
  end
@@ -4,13 +4,13 @@ module Camaraderie
4
4
 
5
5
  included do
6
6
  # Associations
7
- has_many :memberships, dependent: :destroy
8
- has_many :organizations, through: :memberships
7
+ has_many :memberships, dependent: :destroy, foreign_key: :user_id, class_name: 'Membership', inverse_of: :user
8
+ has_many :organizations, through: :memberships, class_name: Camaraderie.organization_class, inverse_of: :users
9
9
 
10
10
  Camaraderie.membership_types.each do |type|
11
11
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
12
12
  def #{type}_of?(organization)
13
- !!memberships.#{type.pluralize}.where(organization: organization).exists?
13
+ !!memberships.#{type.pluralize}.where(organization_id: organization.id).exists?
14
14
  end
15
15
  RUBY
16
16
  end
@@ -1,3 +1,3 @@
1
1
  module Camaraderie
2
- VERSION = '0.1.3'
2
+ VERSION = '0.2'
3
3
  end
data/lib/camaraderie.rb CHANGED
@@ -1,5 +1,9 @@
1
1
  require 'camaraderie/version'
2
2
 
3
+ require 'active_support'
4
+ require 'active_record'
5
+ require 'ostruct'
6
+
3
7
  require 'camaraderie/user'
4
8
  require 'camaraderie/organization'
5
9
  require 'camaraderie/membership'
@@ -13,7 +17,17 @@ module Camaraderie
13
17
 
14
18
  # Return the allowed membership types
15
19
  def self.membership_types
16
- @configuration.membership_types
20
+ @configuration.membership_types.try(:map, &:to_s) || %w(member)
21
+ end
22
+
23
+ # Return the class name to use for the organizations association
24
+ def self.organization_class
25
+ @configuration.organization_class.try(:to_s) || 'Organization'
26
+ end
27
+
28
+ # Return the class name to use for the users association
29
+ def self.user_class
30
+ @configuration.user_class.try(:to_s) || 'User'
17
31
  end
18
32
 
19
33
  # Return a block that can be injected into a class
@@ -0,0 +1,93 @@
1
+ require 'spec_helper'
2
+
3
+ describe Camaraderie::Membership do
4
+ before do
5
+ Camaraderie.configure { |config| config.membership_types = %w(admin member) }
6
+ spawn_membership_model
7
+ spawn_organization_model
8
+ spawn_user_model
9
+
10
+ run_migration do
11
+ create_table(:users, force: true)
12
+ create_table(:organizations, force: true)
13
+ end
14
+ end
15
+
16
+ describe :Scopes do
17
+ let(:user1) { User.create }
18
+ let(:user2) { User.create }
19
+
20
+ let(:organization1) { Organization.create }
21
+ let(:organization2) { Organization.create }
22
+
23
+ before do
24
+ Membership.create(user: user1, organization: organization1, membership_type: 'admin')
25
+ Membership.create(user: user2, organization: organization2, membership_type: 'admin')
26
+ Membership.create(user: user1, organization: organization2, membership_type: 'member')
27
+ end
28
+
29
+ describe :admins do
30
+ subject { Membership.admins }
31
+
32
+ it { should be_an_instance_of(relation_class(Membership)) }
33
+ it { should have(2).items }
34
+ end
35
+
36
+ describe :members do
37
+ subject { Membership.members }
38
+
39
+ it { should be_an_instance_of(relation_class(Membership)) }
40
+ it { should have(1).item }
41
+ end
42
+ end
43
+
44
+ describe :Validations do
45
+ let(:membership) { Membership.create(attributes) }
46
+ subject { membership }
47
+
48
+ context 'with missing user' do
49
+ let(:attributes) { { organization: Organization.create, membership_type: 'admin' } }
50
+ it { should_not be_valid }
51
+
52
+ describe :errors do
53
+ subject { membership.errors }
54
+ it { should have(1).item }
55
+ its(:full_messages) { should include "User can't be blank" }
56
+ end
57
+ end
58
+
59
+ context 'with missing organization' do
60
+ let(:attributes) { { user: User.create, membership_type: 'admin' } }
61
+ it { should_not be_valid }
62
+
63
+ describe :errors do
64
+ subject { membership.errors }
65
+ it { should have(1).item }
66
+ its(:full_messages) { should include "Organization can't be blank" }
67
+ end
68
+ end
69
+
70
+ context 'with missing membership type' do
71
+ let(:attributes) { { user: User.create, organization: Organization.create } }
72
+ it { should_not be_valid }
73
+
74
+ describe :errors do
75
+ subject { membership.errors }
76
+ it { should have(2).item }
77
+ its(:full_messages) { should include "Membership type can't be blank" }
78
+ its(:full_messages) { should include "Membership type is not included in the list" }
79
+ end
80
+ end
81
+
82
+ context 'with wrong membership type' do
83
+ let(:attributes) { { membership_type: 'super_admin', user: User.create, organization: Organization.create } }
84
+ it { should_not be_valid }
85
+
86
+ describe :errors do
87
+ subject { membership.errors }
88
+ it { should have(1).item }
89
+ its(:full_messages) { should include "Membership type is not included in the list" }
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ describe Camaraderie::Organization do
4
+ before do
5
+ Camaraderie.configure { |config| config.membership_types = %w(admin member) }
6
+ spawn_membership_model
7
+ spawn_organization_model
8
+ spawn_user_model
9
+
10
+ run_migration do
11
+ create_table(:users, force: true)
12
+ create_table(:organizations, force: true)
13
+ end
14
+ end
15
+
16
+ describe :InstanceMethods do
17
+ let(:organization) { Organization.create }
18
+ let(:user1) { User.create }
19
+ let(:user2) { User.create }
20
+ let(:user3) { User.create }
21
+
22
+ before do
23
+ organization.admins.create(user: user1)
24
+ organization.members.create(user: user2)
25
+ organization.members.create(user: user3)
26
+ end
27
+
28
+ describe :admins do
29
+ subject { organization.admins }
30
+ it { should be_an_instance_of(relation_class(Membership)) }
31
+ it { should have(1).item }
32
+ end
33
+
34
+ describe :members do
35
+ subject { organization.members }
36
+ it { should be_an_instance_of(relation_class(Membership)) }
37
+ it { should have(2).items }
38
+ end
39
+
40
+ describe :admin_users do
41
+ subject { organization.admin_users }
42
+ it { should be_an_instance_of(relation_class(User)) }
43
+ it { should have(1).item }
44
+ it { should include user1 }
45
+ end
46
+
47
+ describe :member_users do
48
+ subject { organization.member_users }
49
+ it { should be_an_instance_of(relation_class(User)) }
50
+ it { should have(2).items }
51
+ it { should include user2, user3 }
52
+ end
53
+ end
54
+
55
+ describe :Associations do
56
+ let(:organization) { Organization.create }
57
+ let(:user1) { User.create }
58
+ let(:user2) { User.create }
59
+ let(:user3) { User.create }
60
+
61
+ before do
62
+ organization.admins.create(user: user1)
63
+ organization.members.create(user: user2)
64
+ organization.members.create(user: user3)
65
+ end
66
+
67
+ describe :users do
68
+ subject { organization.users }
69
+ it { should have(3).items }
70
+
71
+ describe :DestroyDependent do
72
+ specify do
73
+ expect { organization.destroy }.to change { Membership.count }.from(3).to(0)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe Camaraderie::User do
4
+ before do
5
+ Camaraderie.configure { |config| config.membership_types = %w(admin member) }
6
+ spawn_membership_model
7
+ spawn_organization_model
8
+ spawn_user_model
9
+
10
+ run_migration do
11
+ create_table(:users, force: true)
12
+ create_table(:organizations, force: true)
13
+ end
14
+ end
15
+
16
+ describe :InstanceMethods do
17
+ subject do
18
+ User.create.tap do |user|
19
+ organization1.admins.create(user: user)
20
+ organization2.members.create(user: user)
21
+ end
22
+ end
23
+
24
+ let(:organization1) { Organization.create }
25
+ let(:organization2) { Organization.create }
26
+ let(:organization3) { Organization.create }
27
+
28
+ describe :admin_of? do
29
+ it{ should be_admin_of(organization1) }
30
+ it{ should_not be_admin_of(organization2) }
31
+ it{ should_not be_admin_of(organization3) }
32
+ end
33
+
34
+ describe :member_of? do
35
+ it{ should be_member_of(organization2) }
36
+ it{ should_not be_member_of(organization1) }
37
+ it{ should_not be_member_of(organization3) }
38
+ end
39
+ end
40
+
41
+ describe :Associations do
42
+ subject { user }
43
+ let(:user) { User.create }
44
+
45
+ before do
46
+ Organization.create.admins.create(user: user)
47
+ Organization.create.members.create(user: user)
48
+ end
49
+
50
+ describe :organizations do
51
+ its(:organizations) { should have(2).items }
52
+
53
+ describe :DestroyDependent do
54
+ specify do
55
+ expect { user.destroy }.to change { Membership.count }.from(2).to(0)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe Camaraderie do
4
+ describe 'Custom model classes' do
5
+ before do
6
+ Camaraderie.configure do |config|
7
+ config.organization_class = 'Company'
8
+ config.user_class = 'Employee'
9
+ config.membership_types = %w(admin member)
10
+ end
11
+
12
+ spawn_organization_model 'Company'
13
+ spawn_user_model 'Employee'
14
+ spawn_membership_model
15
+
16
+ run_migration do
17
+ create_table(:employees, force: true)
18
+ create_table(:companies, force: true)
19
+ end
20
+ end
21
+
22
+ let(:user) { Employee.create }
23
+ let(:organization) { Company.create }
24
+
25
+ before do
26
+ # FIXME Why doesn't this work?
27
+ # It bypasses `class_name: 'Employee'` and tries to use 'User'
28
+ #
29
+ # organization.admins.create(user: user)
30
+
31
+ # We'll have to use this for now
32
+ Membership.create(membership_type: 'admin', user: user, organization: organization)
33
+ end
34
+
35
+ it { expect(user).to be_admin_of(organization) }
36
+ it { expect(organization.admin_users).to include(user) }
37
+ end
38
+ end
@@ -0,0 +1,41 @@
1
+ $:.unshift File.expand_path('../lib', __FILE__)
2
+
3
+ require 'rspec'
4
+ require 'sqlite3'
5
+
6
+ require 'camaraderie'
7
+
8
+ # Require our macros and extensions
9
+ Dir[File.expand_path('../../spec/support/macros/*.rb', __FILE__)].map(&method(:require))
10
+
11
+ # Inject our methods into ActiveRecord (like our railtie does)
12
+ ActiveRecord::Base.class_eval(&Camaraderie.inject_into_active_record)
13
+
14
+ RSpec.configure do |config|
15
+ # Include our macros
16
+ config.include DatabaseMacros
17
+ config.include ModelMacros
18
+ config.include RailsMacros
19
+
20
+ config.before(:each) do
21
+ # Create the SQLite database
22
+ setup_database
23
+
24
+ # Run our migration
25
+ run_default_migration
26
+
27
+ # Reset Camaraderie.configuration
28
+ Camaraderie.instance_variable_set(:@configuration, nil)
29
+
30
+ # Prepare our models array
31
+ @spawned_models = []
32
+ end
33
+
34
+ config.after(:each) do
35
+ # Make sure we remove our test database file
36
+ cleanup_database
37
+
38
+ # Remove our models
39
+ @spawned_models.each { |model| Object.instance_eval { remove_const model.name.to_sym } }
40
+ end
41
+ end
@@ -0,0 +1,39 @@
1
+ module DatabaseMacros
2
+ # Run migrations in the test database
3
+ def run_migration(&block)
4
+ # Create a new migration class
5
+ klass = Class.new(ActiveRecord::Migration)
6
+
7
+ # Create a new `up` that executes the argument
8
+ klass.send(:define_method, :up) { self.instance_exec(&block) }
9
+
10
+ # Create a new instance of it and execute its `up` method
11
+ klass.new.up
12
+ end
13
+
14
+ def self.database_file
15
+ @database_file || File.expand_path('../test.db', __FILE__)
16
+ end
17
+
18
+ def setup_database
19
+ # Make sure the test database file is gone
20
+ cleanup_database
21
+
22
+ # Establish the connection
23
+ SQLite3::Database.new FileUtils.touch(DatabaseMacros.database_file).first
24
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: DatabaseMacros.database_file)
25
+
26
+ # Silence everything
27
+ ActiveRecord::Base.logger = ActiveRecord::Migration.verbose = false
28
+ end
29
+
30
+ def cleanup_database
31
+ FileUtils.rm(DatabaseMacros.database_file) if File.exists?(DatabaseMacros.database_file)
32
+ end
33
+
34
+ # Run the built-in migration
35
+ def run_default_migration
36
+ load File.expand_path('../../../../lib/generators/camaraderie/templates/migration.rb', __FILE__)
37
+ AddCamaraderie.new.up
38
+ end
39
+ end
@@ -0,0 +1,33 @@
1
+ module ModelMacros
2
+ # Create a new organization model
3
+ def spawn_organization_model(klass_name = 'Organization', &block)
4
+ spawn_model klass_name, ActiveRecord::Base do
5
+ acts_as_organization
6
+ instance_exec(&block) if block
7
+ end
8
+ end
9
+
10
+ # Create a new user model
11
+ def spawn_user_model(klass_name = 'User', &block)
12
+ spawn_model klass_name, ActiveRecord::Base do
13
+ acts_as_user
14
+ instance_exec(&block) if block
15
+ end
16
+ end
17
+
18
+ def spawn_membership_model(klass_name = 'Membership', &block)
19
+ spawn_model 'Membership', ActiveRecord::Base do
20
+ acts_as_membership
21
+ instance_exec(&block) if block
22
+ end
23
+ end
24
+
25
+ protected
26
+
27
+ # Create a new model class
28
+ def spawn_model(klass_name, parent_klass, &block)
29
+ Object.instance_eval { remove_const klass_name } if Object.const_defined?(klass_name)
30
+ @spawned_models << Object.const_set(klass_name, Class.new(parent_klass))
31
+ Object.const_get(klass_name).class_eval(&block) if block_given?
32
+ end
33
+ end
@@ -0,0 +1,9 @@
1
+ module RailsMacros
2
+ def relation_class(klass)
3
+ if ActiveRecord::VERSION::MAJOR == 3
4
+ ActiveRecord::Relation
5
+ else
6
+ "ActiveRecord::Relation::ActiveRecord_Relation_#{klass.name}".constantize
7
+ end
8
+ end
9
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: camaraderie
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: '0.2'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-08-10 00:00:00.000000000 Z
12
+ date: 2013-08-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -43,6 +43,38 @@ dependencies:
43
43
  - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: sqlite3
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '2.14'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '2.14'
46
78
  - !ruby/object:Gem::Dependency
47
79
  name: activerecord
48
80
  requirement: !ruby/object:Gem::Requirement
@@ -84,11 +116,15 @@ extensions: []
84
116
  extra_rdoc_files: []
85
117
  files:
86
118
  - .gitignore
119
+ - .rspec
120
+ - .travis.yml
87
121
  - Gemfile
88
122
  - LICENSE.md
89
123
  - README.md
90
124
  - Rakefile
91
125
  - camaraderie.gemspec
126
+ - gemfiles/Gemfile.activerecord-3.2.x
127
+ - gemfiles/Gemfile.activerecord-4.0
92
128
  - lib/camaraderie.rb
93
129
  - lib/camaraderie/membership.rb
94
130
  - lib/camaraderie/organization.rb
@@ -99,6 +135,14 @@ files:
99
135
  - lib/generators/camaraderie/install_generator.rb
100
136
  - lib/generators/camaraderie/templates/migration.rb
101
137
  - lib/generators/camaraderie/templates/model.rb
138
+ - spec/camaraderie/membership_spec.rb
139
+ - spec/camaraderie/organization_spec.rb
140
+ - spec/camaraderie/user_spec.rb
141
+ - spec/camaraderie_spec.rb
142
+ - spec/spec_helper.rb
143
+ - spec/support/macros/database_macros.rb
144
+ - spec/support/macros/model_macros.rb
145
+ - spec/support/macros/rails_macros.rb
102
146
  homepage: https://github.com/mirego/camaraderie
103
147
  licenses:
104
148
  - BSD 3-Clause
@@ -114,7 +158,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
114
158
  version: '0'
115
159
  segments:
116
160
  - 0
117
- hash: -1376039277595789238
161
+ hash: -3093721818560586396
118
162
  required_rubygems_version: !ruby/object:Gem::Requirement
119
163
  none: false
120
164
  requirements:
@@ -123,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
167
  version: '0'
124
168
  segments:
125
169
  - 0
126
- hash: -1376039277595789238
170
+ hash: -3093721818560586396
127
171
  requirements: []
128
172
  rubyforge_project:
129
173
  rubygems_version: 1.8.23
@@ -131,4 +175,12 @@ signing_key:
131
175
  specification_version: 3
132
176
  summary: Camaraderie takes away the pain of managing membership stuff between users
133
177
  and organizations.
134
- test_files: []
178
+ test_files:
179
+ - spec/camaraderie/membership_spec.rb
180
+ - spec/camaraderie/organization_spec.rb
181
+ - spec/camaraderie/user_spec.rb
182
+ - spec/camaraderie_spec.rb
183
+ - spec/spec_helper.rb
184
+ - spec/support/macros/database_macros.rb
185
+ - spec/support/macros/model_macros.rb
186
+ - spec/support/macros/rails_macros.rb